Files
support_backend/specs/011-agent-ticket-queue/tasks.md
T
saqib mirandClaude Sonnet 5 fb9606b6aa feat(011-agent-ticket-queue): link agents to accounts, list assigned tickets
Extends PATCH /admin/agents/:agentId with an optional userId to finally
wire Agent.userId (added in 010-identity-auth as schema-only, never
consumed by any workflow), with proactive role/duplicate-link checks
mirroring UsersService.create's own pre-check style.

Adds GET /agents/me/tickets and GET /admin/agents/:agentId/tickets,
sharing one TicketsService.listAssignedTo method, returning a dashboard-
ready summary (product, customer, priority, severity, status, SLA state)
of every ticket currently assigned to an agent — no such query existed
anywhere in the ticketing or orchestration modules before this. Backed by
a new Assignment @@index([agentId, isCurrent]).

Discovered while starting supporthub-web's 001-agent-admin-ui: its agent-
dashboard user story had no backend data source without this.

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

5.5 KiB

description
description
Task list for 011-agent-ticket-queue

Tasks: Agent Ticket Queue

Input: Design documents from specs/011-agent-ticket-queue/

Prerequisites: plan.md, spec.md, research.md, data-model.md, contracts/agent-ticket-queue-contract.md, quickstart.md

Organization: Tasks are grouped by user story (US1 = P1 linking, US2 = P1 ticket listing). US2 depends on a helper US1 also needs, so despite being nominally independent, build US1 first.

Format: [ID] [P?] [Story] Description

All file paths are relative to supporthub-api/ (repo root).


Phase 1: Foundational (Blocking Prerequisites)

  • T001 Add Assignment @@index([agentId, isCurrent]) to prisma/schema.prisma; generate the migration (prisma migrate diff → hand-write migration.sqlprisma migrate deploy, this session's established non-interactive workaround) and run npm run prisma:generate

Checkpoint: Index in place. Both user stories can now be built.


Phase 2: User Story 1 - An admin links a staff account to its agent roster entry (Priority: P1)

Goal: Agent.userId becomes settable through the existing update endpoint, with the rejection rules FR-001 requires.

Independent Test: Quickstart Scenario 1.

Tests for User Story 1

  • T002 [P] [US1] Integration test covering Quickstart Scenario 1 (link succeeds; non-AGENT role rejected 400; already-linked-elsewhere rejected 409) in tests/integration/agent-ticket-queue.test.ts (depends on T001)

Implementation for User Story 1

  • T003 [US1] Add AgentsRepository.findByUserId(userId) in src/modules/identity/agents/repository/agents.repository.ts — shared by this story's own duplicate-link check and by User Story 2's agent-self route (T010)
  • T004 [US1] Add userId: z.string().min(1).nullable().optional() to updateAgentSchema in src/modules/identity/agents/schema/agents.schema.ts
  • T005 [US1] In AgentsService.update (src/modules/identity/agents/service/agents.service.ts), when data.userId !== undefined: if non-null, look up the target User (via a small UsersRepository.findById) — 404 if missing, reject with a ValidationError if its role isn't AGENT; look up any Agent already linked to that userId (T003's findByUserId) — ConflictError if it's a different agent than agentId (depends on T003, T004)
  • T006 [US1] Run Quickstart Scenario 1 locally and confirm all 3 steps pass

Checkpoint: An agent's login can now be resolved to its roster row.


Phase 3: User Story 2 - An agent retrieves their own currently-assigned tickets (Priority: P1)

Goal: Both list endpoints return the same summarized projection, correctly scoped per caller.

Independent Test: Quickstart Scenarios 2-3.

Tests for User Story 2

  • T007 [P] [US2] Unit test: given a User id with no linked Agent, the service throws the specific NotFoundError — in tests/unit/identity/agent-ticket-queue-guard.test.ts
  • T008 [US2] Integration test covering Quickstart Scenarios 2-3 (agent sees exactly their own current assignments; list updates after a reassignment; no-linked-agent session gets 404 not []; admin route returns the same shape for an explicit agentId; non-admin calling the admin route for another agent gets 403) in tests/integration/agent-ticket-queue.test.ts (depends on T006)

Implementation for User Story 2

  • T009 [US2] Add TicketsRepository.findAssignedToAgent(agentId) in src/modules/ticketing/tickets/repository/tickets.repository.ts — one query joining current Assignment (via orchestration's public repository/service surface) to Ticket with product/customer/sLARun relations (depends on T001)
  • T010 [US2] Add TicketsService.listAssignedTo(agentId) mapping each row to the AssignedTicketSummary shape (data-model.md) in src/modules/ticketing/tickets/service/tickets.service.ts (depends on T009)
  • T011 [US2] Add GET /agents/me/tickets (fastify.authenticate only; resolves agentId via agentsService's findByUserId (T003) against request.user.id, throwing the FR-006 NotFoundError if none) and GET /admin/agents/:agentId/tickets (fastify.authenticate + requireRole('ADMIN')) in src/modules/ticketing/tickets/ controller/ + routes/, registered from src/api/routes.ts (depends on T003, T010)
  • T012 [US2] Run Quickstart Scenarios 2-3 locally and confirm all steps pass

Checkpoint: supporthub-web's agent dashboard now has a real data source.


Phase 4: Polish & Cross-Cutting Concerns

  • T013 [P] Update specs/011-agent-ticket-queue/checklists/requirements.md Notes with any implementation-time findings
  • T014 Run npx tsx scripts/check-architecture.ts and npm run lint/npm run typecheck
  • T015 Full regression: npm run test:unit then the full integration suite against real Docker-provisioned Postgres/Redis, confirming nothing outside this feature regressed

Dependencies & Execution Order

  • Foundational (Phase 1): No dependencies — BLOCKS both user stories
  • User Story 1 (Phase 2): Depends on Foundational
  • User Story 2 (Phase 3): Depends on Foundational and on T003 (built in Phase 2) — build Phase 2 before Phase 3 despite the two stories being otherwise independent
  • Polish (Phase 4): Depends on both user stories