CaseLens

I built CaseLens to help support teams understand why a ticket received its priority, which evidence supports the result, and how to recover failed processing.

Operators need evidence, processing history, and a safe recovery path.

A priority label is not enough when an operator must decide what to do next or explain what happened later.

Trust
The recommendation needs quoted evidence, policy, and a reason that a reviewer can inspect.
Continuity
Queue and provider failures need durable processing history, bounded retry behavior, and a safe recovery path.
Control
A reviewer must be able to correct the result without erasing the original decision or its trace.

Durable delivery

PostgreSQL commits the triage request and outbox event in one transaction. A relay publishes the event to SQS, and workers use conditional job claims to handle duplicate delivery.

Constrained AI

The provider receives redacted ticket text and returns structured output. CaseLens validates quoted evidence and policy IDs, calculates priority with application rules, and falls back to deterministic triage after provider or validation failure.

Human correction

Reviewers can correct urgency without rewriting the original result. Evaluation metrics report category and urgency agreement, correction rate, latency, provider, and model version.

Inspectable failure

The demo records a synthetic provider timeout as a retryable failure. A reviewer can replay the work and inspect the failure and recovery records without using real customer data.

PostgreSQL remains the source of truth.

  1. 01React reviewerisolated synthetic workspace
  2. 02Spring Boot APIvalidation and domain rules
  3. 03Outbox + SQSdurable asynchronous delivery
  4. 04Triage workerprovider validation or fallback
  5. 05Review + recoverytrace, feedback, replay

Tests cover normal processing, failure, and recovery.

Tests cover duplicate delivery, invalid model evidence, provider failure, operator replay, workspace isolation, queue integration, infrastructure validation, scans, and deployed browser flows.

114backend tests
12frontend tests
2browser journeys
AWSlive in ca-central-1

Application

Java 21, Spring Boot, React 19, TypeScript, TanStack Query, PostgreSQL 16, Flyway.

AWS

API Gateway, Lambda with SnapStart, S3, CloudFront, SQS/DLQ, EventBridge, CloudWatch, Secrets Manager.

Delivery

Terraform, GitHub Actions OIDC, Docker, LocalStack, Testcontainers, Trivy, protected teardown.

Decisions and trade-offs

  • Modular monolith, with one deliberate asynchronous boundary.

    I kept the first release in one backend so its domain flow, transaction boundaries, and recovery path stay easy to trace. SQS separates triage processing from the request without adding a fleet of services to deploy and operate.

  • The outbox protects the database-to-queue handoff.

    CaseLens commits the ticket, job, and outbox event in the same PostgreSQL transaction. The relay can retry publication until SQS accepts it, avoiding a stored ticket whose processing message was lost between two separate writes.

  • Queue messages carry identifiers, not ticket content.

    Workers receive workspace, case, and job identifiers, then reload the current record from PostgreSQL. This keeps the database authoritative, reduces data copied through SQS, and lets the worker apply current validation and redaction rules.

  • Application rules own priority and fallback behavior.

    The model proposes structured evidence, category, urgency, and actions. CaseLens validates that output and applies deterministic priority and fallback rules, keeping operational decisions reproducible when provider output is invalid or unavailable.

  • The demo favors low idle cost over constant warmth.

    Lambda and Neon suit an infrequently reviewed portfolio system, but they introduce cold starts and database connection limits. The deployment bounds connection use and accepts a slower first request rather than paying for always-on capacity.