Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Triage — AI ingestion & action pipeline

A scalable B2B pipeline that ingests raw customer requests, analyses them with an AI agent into structured data (urgency 1–10, category, summary), caches LLM responses, and fires automated actions (webhook / e-mail) for high-urgency items.

            ┌───────────┐   raw text / JSON
  client ──▶│  Ingest   │  POST /api/v1/ingest
            │   API     │
            └─────┬─────┘
                  │ persist (Postgres)
                  ▼
            ┌───────────┐   structured output (urgency, category, summary)
            │ AI Agent  │  Spring AI ▸ Anthropic  ─ Redis cache (skip repeats)
            └─────┬─────┘
                  │ persist analysis
                  ▼
            ┌───────────┐   urgency ≥ threshold?
            │  Action   │  ── Webhook ▸ customer endpoint
            │ Dispatcher│  └─ Email   ▸ alert inbox
            └───────────┘
                  │
                  ▼
            Next.js dashboard  ◀── GET /api/v1/metrics, /ingestions

Stack

Layer Tech
Backend Spring Boot 3.4, Java 17, Spring AI (Anthropic)
Data & cache PostgreSQL (Flyway), Redis (LLM response cache + rate limiting)
Frontend Next.js (App Router), TailwindCSS, Recharts

Architecture (backend)

Clean, layered, provider-agnostic:

  • domain/ — entities (Ingestion, Analysis, ActionExecution) + enums. No framework leakage.
  • ai/ — the Analyzer port and its Anthropic implementation (AnthropicAnalyzer). Structured output is enforced by Spring AI's BeanOutputConverter against the AiAnalysis record, so the model can only return valid {urgencyScore, category, summary}.
  • action/ — the ActionDispatcher port + async webhook/e-mail handlers.
  • service/ — the IngestionService use case orchestrating the flow. The external LLM call runs outside any DB transaction so a slow response never holds a pooled connection.
  • repository/ — Spring Data JPA + read projections for the dashboard.
  • api/ — REST controllers, DTOs, and a global error handler.

Why Redis

  • LLM response cache — identical inputs are hashed (SHA-256); a hit skips the model call entirely (cost + latency win), and the fromCache flag is surfaced in metrics.
  • Rate limiting — a per-tenant fixed-window counter (atomic INCR) that is correct across instances.

Run it

1. Dependencies

docker compose up -d        # Postgres :5432, Redis :6379, Mailhog :8025

2. Backend

cd backend
export ANTHROPIC_API_KEY=sk-ant-...        # required
# optional: export TRIAGE_MODEL=claude-haiku-4-5   (cheaper, high-volume)
# optional: export TRIAGE_WEBHOOK_URL=https://example.com/hook
# optional: export TRIAGE_ALERT_EMAIL=alerts@example.com
mvn spring-boot:run        # Maven 3.9+ and JDK 17 required
# (no wrapper bundled — generate one with `mvn -N wrapper:wrapper` if you prefer ./mvnw)

The default model is claude-opus-4-8; set TRIAGE_MODEL to switch.

3. Dashboard

cd frontend
cp .env.local.example .env.local
npm install && npm run dev        # http://localhost:3000

API

Ingest (JSON):

curl -X POST http://localhost:8080/api/v1/ingest \
  -H "Content-Type: application/json" \
  -H "X-Tenant-Id: acme" \
  -d '{"content":"Our checkout has been down for 2 hours, customers cannot pay!","source":"email"}'
{
  "ingestionId": "",
  "analysisId": "",
  "urgencyScore": 9,
  "category": "BUG_REPORT",
  "summary": "Checkout outage for ~2h blocking all payments; needs immediate attention.",
  "fromCache": false,
  "actionsTriggered": true
}

Ingest (raw text): POST /api/v1/ingest with Content-Type: text/plain.

Metrics: GET /api/v1/metrics · Recent feed: GET /api/v1/ingestions?limit=25

Configuration

Env var Default Purpose
ANTHROPIC_API_KEY Anthropic API access (required)
TRIAGE_MODEL claude-opus-4-8 Analysis model
TRIAGE_WEBHOOK_URL Webhook target for urgent items
TRIAGE_ALERT_EMAIL Alert inbox for urgent items
DB_URL / DB_USER / DB_PASSWORD local Postgres Database connection
REDIS_HOST / REDIS_PORT localhost:6379 Cache & rate limiter

Urgency threshold, cache TTL, and rate limit live under triage.* in application.yml.

This is an MVP template — production would add auth/multi-tenant isolation, an outbox for exactly-once actions, retries/DLQ, and observability.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages