Files
support_backend/specs/011-agent-ticket-queue/plan.md
T
saqib mirandClaude Sonnet 5 23fadebb5c docs(011-agent-ticket-queue): plan, research, data model, contract, quickstart
Extends the existing PATCH /admin/agents/:agentId with an optional userId
to finish wiring 010's Agent.userId link, and adds GET /agents/me/tickets
+ GET /admin/agents/:agentId/tickets sharing one ticketing/tickets service
method, backed by a new Assignment @@index([agentId, isCurrent]).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 12:58:25 +05:30

5.8 KiB

Implementation Plan: Agent Ticket Queue

Branch: 011-agent-ticket-queue | Date: 2026-09-07 | Spec: spec.md

Input: Feature specification from specs/011-agent-ticket-queue/spec.md

Summary

Finishes wiring Agent.userId (added in 010-identity-auth as schema-only) by extending the existing PATCH /admin/agents/:agentId with an optional userId, then adds the ticket-query this unblocks: GET /agents/me/tickets (agent's own session) and GET /admin/agents/:agentId/tickets (admin, explicit agent) — both returning the same summarized, dashboard-ready projection of every ticket currently assigned to that agent.

Technical Context

Language/Version: TypeScript 5.4 / Node.js 20+ (unchanged).

Primary Dependencies: None new — reuses Prisma, the existing identity/agents and ticketing/tickets modules, and 010's requireRole.

Storage: PostgreSQL via Prisma. Adds one index (Assignment @@index([agentId, isCurrent])) — the query this feature introduces (all current assignments for one agent) has no supporting index today; the existing [ticketId, isCurrent] index doesn't serve an agent-first lookup.

Testing: Vitest — unit test for the "no linked Agent" rejection path; integration tests against real Postgres/Redis for linking, the agent's-own-session query, the admin explicit- agent query, and cross-agent isolation (one agent never sees another's tickets).

Target Platform: Same Fastify modular monolith. Modifies identity/agents (linking endpoint, userId already returned by existing reads) and ticketing/tickets (new summary query + routes) — no new module, since "list my tickets" is a ticketing concern reading orchestration's Assignment state, matching 003's existing module boundary (ticketing already depends on orchestration's public surface for status-transition side effects).

Project Type: Backend service — single project.

Performance Goals: The ticket-summary query is one indexed query for current assignments plus a single batched fetch of their tickets (with product/customer/SLA-run relations) — no N+1 per-ticket round trip, matching FR-003/SC-001's "single request" requirement.

Constraints: MUST NOT let an agent's own-session call accept a client-supplied agentId (FR-004 — always resolved from the session's own linked Agent row). MUST reject a session with no linked Agent row distinguishably from an empty list (FR-006).

Scale/Scope: One new admin endpoint (link), two new read endpoints (agent-self, admin- explicit) sharing one service method, one new Prisma index. Explicitly excludes: a general ticket search/filter endpoint, pagination, and self-service linking (spec.md Assumptions).

Constitution Check

GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.

Principle / Section Check Result
I. SaaS Is the Sole Identity & Access Authority Purely internal to SupportHub's own domain (agent roster, ticket assignment) — no SaaS/customer identity involved. PASS — N/A
II. Configuration Over Hardcoding No new configurable values introduced. PASS — N/A
III. Layered Architecture With Enforced Module Boundaries The new query lives in ticketing/tickets (the module that owns Ticket), reading Assignment via orchestration's own public index.ts export — no reach-through to orchestration's internals. The link endpoint lives in identity/agents, alongside its existing agent CRUD. PASS
IV. AI Recommends, Deterministic Policy Decides Not applicable. PASS — N/A
V. Evidence-Based Verification Not applicable. PASS — N/A
VI. Durable Audit & History No new mutable state beyond the Agent.userId link itself, which Agent's own updatedAt already timestamps. PASS
VII. Concurrency-Safe, Durable Job Handling Read-only queries plus one simple linking write guarded by the existing @unique constraint on Agent.userId (a concurrent double-link race is rejected by the database itself, not application logic). PASS
VIII. Problem and Ticket Are Separate, Related Entities Not applicable — no problem-management involvement. PASS — N/A
Technology & Platform Constraints No new dependencies or infrastructure. PASS

No violations requiring Complexity Tracking justification.

Project Structure

Documentation (this feature)

specs/011-agent-ticket-queue/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
└── tasks.md

Source Code (repository root)

supporthub-api/
├── prisma/
│   └── schema.prisma                              # MODIFIED — Assignment @@index([agentId, isCurrent])
└── src/
    └── modules/
        ├── identity/
        │   └── agents/                            # MODIFIED — link-user endpoint alongside existing agent CRUD
        │       ├── controller/ routes/ schema/
        │       └── service/
        └── ticketing/
            └── tickets/                            # MODIFIED — new agent-assigned-tickets summary query
                ├── controller/ routes/ schema/
                └── service/ mapper/
└── tests/
    ├── unit/identity/                              # "no linked Agent" rejection unit test
    └── integration/                                # linking flow + both list endpoints + cross-agent isolation

Structure Decision: Single project, no new module. The link endpoint extends identity/agents (already owns agent CRUD); the ticket-summary query extends ticketing/tickets (already owns Ticket) rather than a new module, since this is one small read query, not a new bounded concern.

Complexity Tracking

No constitution violations — table intentionally omitted.