docs(011-agent-ticket-queue): task breakdown
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
23fadebb5c
commit
d574af087a
@@ -0,0 +1,119 @@
|
||||
---
|
||||
description: "Task list for 011-agent-ticket-queue"
|
||||
---
|
||||
|
||||
# Tasks: Agent Ticket Queue
|
||||
|
||||
**Input**: Design documents from `specs/011-agent-ticket-queue/`
|
||||
|
||||
**Prerequisites**: [plan.md](./plan.md), [spec.md](./spec.md), [research.md](./research.md),
|
||||
[data-model.md](./data-model.md),
|
||||
[contracts/agent-ticket-queue-contract.md](./contracts/agent-ticket-queue-contract.md),
|
||||
[quickstart.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.sql` → `prisma 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
|
||||
Reference in New Issue
Block a user