Skip to content

Repository files navigation

SignalDesk

SignalDesk is a Spring Boot backend for triaging messy inbound support and operations requests into structured, reviewable case analysis.

It accepts raw text such as:

Customer says payment failed twice, they are threatening to cancel, engineering says no outage, finance says retry later.

SignalDesk turns that into:

  • A concise summary
  • A category
  • A priority and risk score
  • A suggested owner or team
  • Recommended next actions
  • A draft customer-safe reply
  • Audit warnings
  • Live progress events over Server-Sent Events (SSE)

The current implementation uses deterministic heuristics rather than an external LLM, but the analysis layer is already abstracted so a real provider can be added later.

Features

  • Async case intake and analysis pipeline
  • Deterministic AI-style triage using maintainable heuristics
  • Structured analysis results persisted in PostgreSQL
  • Audit logging across pipeline stages
  • Reviewer approval and edit workflow
  • Live analysis progress streaming with Spring MVC SseEmitter
  • Swagger UI / OpenAPI documentation
  • Lightweight Thymeleaf admin UI for manual testing and demos
  • Development data seeding for realistic sample cases

Architecture

SignalDesk follows a layered Spring Boot architecture:

  • controller: REST APIs and server-rendered MVC controllers
  • service: business workflows and orchestration
  • service.impl: concrete implementations
  • service.ai: pluggable AI analysis abstraction
  • repository: Spring Data JPA repositories
  • entity: JPA persistence models
  • dto: request and response models
  • mapper: DTO mapping logic
  • config: async, OpenAPI, and dev seed configuration
  • exception: consistent API error handling
  • enums: domain enums for status, category, stage, and severity

High-level flow:

  1. A client submits case text.
  2. IntakeService stores a CaseRecord with status NEW.
  3. AnalysisOrchestratorService runs asynchronously.
  4. The case moves to IN_PROGRESS.
  5. Stage services classify, score priority, recommend an owner, generate a draft reply, and create audit logs.
  6. Progress events are published over SSE.
  7. AnalysisResult is persisted and the case moves to ANALYZED.
  8. A reviewer can approve or edit the final output.

Tech Stack

  • Java 21
  • Spring Boot 4
  • Maven
  • PostgreSQL
  • Spring Data JPA
  • Spring Web MVC
  • Spring Validation
  • Lombok
  • Thymeleaf
  • springdoc-openapi / Swagger UI
  • JUnit + Spring Boot Test + MockMvc

Package Structure

src/main/java/com/example/signaldesk
├── config
├── controller
├── dto
│   ├── request
│   └── response
├── entity
├── enums
├── exception
├── mapper
├── repository
├── service
│   ├── ai
│   │   └── model
│   ├── impl
│   └── model
└── SignaldeskApplication.java

API Endpoints

REST API

Method Path Purpose
POST /api/cases Create a case and trigger async analysis
GET /api/cases/{id} Fetch full case details, including partial data while analysis is running
GET /api/cases/{id}/stream Subscribe to live SSE progress events for a case
POST /api/cases/{id}/review Save reviewer approval or edits
GET /api/dashboard/cases List dashboard cases, optionally filtered by status

Server-rendered UI

Path Purpose
/ui/cases/new Create a new case from a simple form
/ui/cases/{id} View case details, progress, analysis, audit logs, and review form
/ui/dashboard Browse the queue in a simple admin dashboard

API Docs

  • Swagger UI: http://localhost:8080/swagger-ui.html

Running Locally in IntelliJ

1. Prerequisites

  • IntelliJ IDEA
  • Java 21 SDK configured in IntelliJ
  • PostgreSQL running locally

2. Clone and open

Open the project root in IntelliJ:

C:\Users\dhruv\Desktop\signaldesk

3. Configure the database

Create a local PostgreSQL database and set Spring datasource properties in IntelliJ using one of these approaches:

  • Run configuration environment variables
  • VM options with -D...
  • A local application-local.properties file

Example properties:

spring.datasource.url=jdbc:postgresql://localhost:5432/signaldesk
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
spring.jpa.show-sql=false

4. Optional: enable dev seeding

To load sample cases automatically, run with the dev profile:

SPRING_PROFILES_ACTIVE=dev

The dev profile enables the seeded sample cases through:

signaldesk.seed.enabled=true

5. Run the app

Run SignaldeskApplication from IntelliJ, or use Maven:

./mvnw spring-boot:run

On Windows PowerShell:

.\mvnw.cmd spring-boot:run

6. Useful local URLs

  • REST base: http://localhost:8080/api
  • Admin UI: http://localhost:8080/ui/dashboard
  • Swagger UI: http://localhost:8080/swagger-ui.html

PostgreSQL Setup

Example SQL:

CREATE DATABASE signaldesk;
CREATE USER signaldesk_user WITH PASSWORD 'signaldesk_password';
GRANT ALL PRIVILEGES ON DATABASE signaldesk TO signaldesk_user;

Then use:

spring.datasource.url=jdbc:postgresql://localhost:5432/signaldesk
spring.datasource.username=signaldesk_user
spring.datasource.password=signaldesk_password

For local development, spring.jpa.hibernate.ddl-auto=update is the simplest option. For production, a migration tool such as Flyway should be added.

Sample API Usage

Submit a case

POST /api/cases
Content-Type: application/json

{
  "source": "EMAIL",
  "rawText": "Customer says payment failed twice, they are threatening to cancel, engineering says no outage, finance says retry later."
}

Response:

{
  "caseId": "8d0c12f0-9f27-4dd9-9478-5d5c1b8aa4e1",
  "status": "NEW",
  "createdAt": "2026-03-22T18:15:42.194395Z"
}

Notes:

  • The endpoint returns 202 Accepted.
  • Analysis starts asynchronously after the case is created.
  • The case status will move from NEW to IN_PROGRESS to ANALYZED.

Fetch case details

GET /api/cases/8d0c12f0-9f27-4dd9-9478-5d5c1b8aa4e1

Example response after analysis:

{
  "caseId": "8d0c12f0-9f27-4dd9-9478-5d5c1b8aa4e1",
  "source": "EMAIL",
  "rawText": "Customer says payment failed twice, they are threatening to cancel, engineering says no outage, finance says retry later.",
  "status": "ANALYZED",
  "createdAt": "2026-03-22T18:15:42.194395Z",
  "updatedAt": "2026-03-22T18:15:43.508211Z",
  "analysisResult": {
    "id": "6e5b7be4-7170-45fa-bc17-5ab1ab0d8d2b",
    "summary": "Customer reports repeated payment failures and churn risk with no confirmed outage.",
    "category": "BILLING",
    "priority": "HIGH",
    "riskScore": 0.84,
    "suggestedOwner": "Billing Ops",
    "suggestedActions": "1. Confirm payment gateway behavior and invoice state\n2. Contact Billing Ops for immediate review\n3. Respond to the customer with a status update",
    "draftReply": "Thanks for flagging this. We are reviewing the payment failure details with our billing team and will follow up as soon as we have a concrete update.",
    "confidenceScore": 88,
    "createdAt": "2026-03-22T18:15:43.204933Z",
    "updatedAt": "2026-03-22T18:15:43.204933Z"
  },
  "auditLogs": [
    {
      "id": "5a2c7bd6-4827-4258-b0b1-b952b79f109a",
      "stage": "CLASSIFICATION",
      "severity": "INFO",
      "message": "Category inferred as BILLING.",
      "createdAt": "2026-03-22T18:15:42.702139Z"
    },
    {
      "id": "e23705fc-345c-4cb8-973f-22d31c04d0d9",
      "stage": "AUDIT",
      "severity": "WARNING",
      "message": "Critical cases should include an explicit urgent action phrase.",
      "createdAt": "2026-03-22T18:15:43.410150Z"
    }
  ],
  "reviewDecision": null
}

While analysis is still running, analysisResult and reviewDecision may be null, and auditLogs may be partially populated. The endpoint is designed to return partial case details safely during processing.

Submit a review decision

POST /api/cases/8d0c12f0-9f27-4dd9-9478-5d5c1b8aa4e1/review
Content-Type: application/json

{
  "approved": true,
  "finalPriority": "HIGH",
  "finalOwner": "Billing Ops",
  "editedReply": "Thanks for your patience. We have escalated this to Billing Ops for immediate review and will update you as soon as we have confirmed next steps.",
  "reviewerNotes": "Approved with slightly clearer customer wording."
}

SSE Progress Streaming

SignalDesk exposes live analysis progress over Server-Sent Events:

GET /api/cases/{id}/stream
Accept: text/event-stream

The in-memory progress stream service supports:

  • Subscribe by case ID
  • Publish stage updates
  • Publish error events
  • Complete and clean up streams safely

The orchestrator publishes these stages:

  • INTAKE
  • CLASSIFICATION
  • PRIORITY_SCORING
  • OWNER_RECOMMENDATION
  • DRAFT_GENERATION
  • AUDIT
  • COMPLETED

Example SSE event payload:

{
  "caseId": "8d0c12f0-9f27-4dd9-9478-5d5c1b8aa4e1",
  "stage": "PRIORITY_SCORING",
  "message": "Priority set to HIGH with risk score 0.84.",
  "timestamp": "2026-03-22T18:15:42.918Z"
}

Example with curl:

curl -N http://localhost:8080/api/cases/8d0c12f0-9f27-4dd9-9478-5d5c1b8aa4e1/stream

This is intentionally simple for local and interview/demo use. It avoids external infrastructure while keeping a clean seam for future background job or event-bus integration.

Heuristic Analysis Rules

Current analysis is deterministic and keyword-driven:

  • Billing: payment, invoice, billing, refund
  • Account access: login, password, access, sign in
  • Incident: outage, down, unavailable, incident
  • Retention: cancel, churn, leaving, disappointed
  • Compliance: exposed, leaked, wrong client, compliance, legal
  • Fallback: GENERAL

Priority and risk score are based on signals such as:

  • Threatening to cancel
  • Payroll urgency
  • Security or leaked-data language
  • Repeated failures

Development Notes

  • Constructor injection is used throughout the app.
  • Entities are not returned directly from controllers; responses are mapped through DTOs.
  • The analysis pipeline is synchronous at the service level and asynchronous at the request boundary.
  • AiAnalysisProvider keeps the current heuristic implementation replaceable with a future LLM-backed provider.

Testing

Run all tests:

.\mvnw.cmd test

Current test coverage includes:

  • Heuristic service tests
  • MockMvc controller integration tests for core case and review endpoints

Future Improvements

  • Add Flyway or Liquibase migrations
  • Replace heuristic AI provider with a real LLM-backed provider
  • Add authentication and reviewer roles
  • Add pagination and richer filtering on the dashboard
  • Split suggested actions into a first-class structured collection
  • Persist SSE/job progress for reconnect support
  • Add observability with metrics and tracing
  • Add Docker and docker-compose support for local startup
  • Harden production config and deployment profiles

Why This Project Exists

SignalDesk is intentionally built to feel like a production-style backend rather than a toy CRUD app. It demonstrates:

  • Layered Spring architecture
  • Async workflow orchestration
  • Safe DTO boundaries
  • Practical SSE streaming
  • Deterministic AI-style business logic
  • A clean path toward future LLM integration

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages