docs: task breakdown for support organization feature
33 tasks across setup, foundational schema work, and four user stories (teams/agents, skills/availability, the dynamic hierarchy tree, and a capability-eligibility read path for the future orchestration phase). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
c18e203ad1
commit
e703f826de
@@ -0,0 +1,271 @@
|
||||
---
|
||||
description: "Task list for 006-support-organization"
|
||||
---
|
||||
|
||||
# Tasks: Support Organization
|
||||
|
||||
**Input**: Design documents from `specs/006-support-organization/`
|
||||
|
||||
**Prerequisites**: [plan.md](./plan.md), [spec.md](./spec.md), [research.md](./research.md),
|
||||
[data-model.md](./data-model.md), [contracts/support-org-contract.md](./contracts/support-org-contract.md),
|
||||
[quickstart.md](./quickstart.md)
|
||||
|
||||
**Tests**: Included as first-class tasks — this feature has two genuinely extractable pure
|
||||
functions (cycle detection, capability-matching predicate) alongside the thin-Prisma-query CRUD
|
||||
that dominated 004's test shape.
|
||||
|
||||
**Organization**: Tasks are grouped by user story (US1 = P1 teams/agents, US2 = P1 skills/
|
||||
availability, US3 = P2 hierarchy tree, US4 = P3 capability-eligibility lookup).
|
||||
|
||||
## Format: `[ID] [P?] [Story] Description`
|
||||
|
||||
All file paths are relative to `supporthub-api/` (repo root).
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Setup
|
||||
|
||||
- [ ] T001 [P] Populate `src/modules/identity/teams/` with the standard module shape
|
||||
(`controller/`, `routes/`, `schema/`, `repository/`, `service/`, `types/`, `mapper/`,
|
||||
`constants/`, `index.ts`) — this directory currently has no files
|
||||
- [ ] T002 [P] Replace `src/modules/identity/agents/`'s existing `User`-based stub content
|
||||
(`repository/agents.repository.ts`, `service/agents.service.ts`,
|
||||
`schema/agents.schema.ts`) — keep the module's file layout, replace what each file does
|
||||
- [ ] T003 [P] Populate `src/modules/orchestration/hierarchy/` with the standard module shape —
|
||||
this directory currently only has an empty `index.ts`
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (Blocking Prerequisites)
|
||||
|
||||
**Purpose**: Schema for all five entities, shared by every user story.
|
||||
|
||||
**⚠️ CRITICAL**: No user-story stage work can begin until this phase is complete.
|
||||
|
||||
- [ ] T004 Add `Team`, `Agent`, `AgentSkill`, `AgentAvailability`, `HierarchyNode` models to
|
||||
`prisma/schema.prisma` per data-model.md (including `@@unique([agentId, skillTag])` on
|
||||
`AgentSkill`, `agentId @unique` on `AgentAvailability`, the `HierarchyTree` self-relation
|
||||
on `HierarchyNode`, and the `(teamId, active)`/`(parentId, order)`/`(active)` indexes)
|
||||
(depends on T001-T003)
|
||||
- [ ] T005 Run `npm run prisma:generate` and create the migration (`npm run prisma:migrate`) for
|
||||
T004 (depends on T004)
|
||||
|
||||
**Checkpoint**: Schema migrated. User stories can now be built.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 - An admin builds out teams and agents (Priority: P1) 🎯 MVP
|
||||
|
||||
**Goal**: Team and agent CRUD with active/inactive state, never deletion; team deactivation
|
||||
never cascades.
|
||||
|
||||
**Independent Test**: Quickstart Scenario 1.
|
||||
|
||||
### Tests for User Story 1
|
||||
|
||||
- [ ] T006 [US1] Integration test covering Quickstart Scenario 1 (create team/agent, agent
|
||||
appears in roster, deactivate excludes from active listing without deleting, reactivate
|
||||
restores it, team deactivation doesn't cascade) against a real Postgres in
|
||||
`tests/integration/support-org-teams-agents.test.ts`
|
||||
|
||||
### Implementation for User Story 1
|
||||
|
||||
- [ ] T007 [P] [US1] Add `TeamsRepository`/`TeamsService` (create; update; findById with agent
|
||||
roster; findAll) in `src/modules/identity/teams/repository/teams.repository.ts` +
|
||||
`service/teams.service.ts` (depends on T005)
|
||||
- [ ] T008 [US1] Add `AgentsRepository`/`AgentsService` (create; update; findById; findAll with
|
||||
`active`/`teamId` filters) — replacing the existing `User`-based stub — in
|
||||
`src/modules/identity/agents/repository/agents.repository.ts` +
|
||||
`service/agents.service.ts` (depends on T005, T007 for the `teamId` FK)
|
||||
- [ ] T009 [US1] Add Zod schemas + routes: `POST /admin/teams`, `PATCH /admin/teams/:teamId`,
|
||||
`GET /admin/teams/:teamId`, `GET /admin/teams` (gated by `fastify.authenticate`) in
|
||||
`identity/teams/schema/` + `routes/`, registered from `src/api/routes.ts` (depends on T007)
|
||||
- [ ] T010 [US1] Add Zod schemas + routes: `POST /admin/teams/:teamId/agents`,
|
||||
`PATCH /admin/agents/:agentId`, `GET /admin/agents/:agentId`, `GET /admin/agents` (gated by
|
||||
`fastify.authenticate`) in `identity/agents/schema/` + `routes/`, registered from
|
||||
`src/api/routes.ts` (depends on T008, T009)
|
||||
- [ ] T011 [US1] Run Quickstart Scenario 1 locally and confirm all 5 steps pass
|
||||
|
||||
**Checkpoint**: Teams and agents can be created, updated, and deactivated/reactivated without
|
||||
ever losing history. Usable as the foundation every later story needs.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 - An admin manages agent skills and availability (Priority: P1)
|
||||
|
||||
**Goal**: Skill tags (upsert-not-duplicate) and a single current availability record per agent.
|
||||
|
||||
**Independent Test**: Quickstart Scenario 2.
|
||||
|
||||
### Tests for User Story 2
|
||||
|
||||
- [ ] T012 [US2] Integration test covering Quickstart Scenario 2 (skill upsert doesn't
|
||||
duplicate, availability upsert stays single-record, invalid status rejected) against a
|
||||
real Postgres in `tests/integration/support-org-skills-availability.test.ts`
|
||||
|
||||
### Implementation for User Story 2
|
||||
|
||||
- [ ] T013 [P] [US2] Add `AgentSkillsRepository`/`AgentSkillsService` (`upsert(agentId,
|
||||
skillTag, level)`; `findAllByAgent`) in
|
||||
`src/modules/identity/agents/repository/agent-skills.repository.ts` +
|
||||
`service/agent-skills.service.ts` (depends on T005)
|
||||
- [ ] T014 [P] [US2] Add `AgentAvailabilityRepository`/`AgentAvailabilityService`
|
||||
(`upsert(agentId, status, workingHours, currentLoad?)`; `findByAgent`) — `status` validated
|
||||
against the fixed `available`/`busy`/`away`/`offline` set at the Zod schema layer (FR-008)
|
||||
— in `src/modules/identity/agents/repository/agent-availability.repository.ts` +
|
||||
`service/agent-availability.service.ts` (depends on T005)
|
||||
- [ ] T015 [US2] Add Zod schemas + routes: `PUT /admin/agents/:agentId/skills/:skillTag`,
|
||||
`GET /admin/agents/:agentId/skills`, `PUT /admin/agents/:agentId/availability`,
|
||||
`GET /admin/agents/:agentId/availability` (gated by `fastify.authenticate`) in
|
||||
`identity/agents/schema/` + `routes/` (depends on T013, T014)
|
||||
- [ ] T016 [US2] Run Quickstart Scenario 2 locally and confirm all 5 steps pass
|
||||
|
||||
**Checkpoint**: Agents carry real, current skill and availability data — everything a future
|
||||
capability/assignment lookup needs to read.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 3 - An admin configures the dynamic support hierarchy (Priority: P2)
|
||||
|
||||
**Goal**: A nestable, cycle-safe, orderable, audited hierarchy tree — every field stored as
|
||||
opaque data for a future orchestration engine.
|
||||
|
||||
**Independent Test**: Quickstart Scenario 3.
|
||||
|
||||
### Tests for User Story 3
|
||||
|
||||
- [ ] T017 [P] [US3] Unit tests for the pure cycle-detection function — a direct self-reference
|
||||
rejected, a transitive cycle (A's new parent is A's own descendant) rejected, a legitimate
|
||||
reparent to an unrelated node accepted — in `tests/unit/support-org/cycle-check.test.ts`
|
||||
- [ ] T018 [US3] Integration test covering Quickstart Scenario 3 (parent/child creation, order
|
||||
preserved, nonexistent `parentId` rejected, self-reparent rejected, deactivation doesn't
|
||||
cascade) against a real Postgres in `tests/integration/support-org-hierarchy.test.ts`
|
||||
|
||||
### Implementation for User Story 3
|
||||
|
||||
- [ ] T019 [P] [US3] Add the pure cycle-detection function `wouldCreateCycle(nodeId,
|
||||
candidateParentId, ancestorChainOf: (id) => string[]) => boolean` in
|
||||
`src/modules/orchestration/hierarchy/service/cycle-check.ts` (no dependencies — pure
|
||||
function, takes the ancestor-lookup as an injected function so it's testable without a
|
||||
database)
|
||||
- [ ] T020 [US3] Add `HierarchyAuditLogRepository.writeHierarchyAuditEvent(...)` (research.md,
|
||||
same shape as `catalog/products`' `writeIntegrationAuditEvent`) in
|
||||
`src/modules/orchestration/hierarchy/repository/hierarchy-audit-log.repository.ts`
|
||||
(depends on T005)
|
||||
- [ ] T021 [US3] Add `HierarchyRepository` (create — validates `parentId` exists, `404` if not;
|
||||
`updateById` — validates via T019 before applying a `parentId` change; `findById`;
|
||||
`findChildren(parentId, ordered)`; `findAll(activeOnly?)`; `setActive`) +
|
||||
`HierarchyService` (wraps the repository, calls T020 on every create/edit/activate/
|
||||
deactivate — FR-017) in
|
||||
`src/modules/orchestration/hierarchy/repository/hierarchy.repository.ts` +
|
||||
`service/hierarchy.service.ts` (depends on T019, T020)
|
||||
- [ ] T022 [US3] Add Zod schemas + routes: `POST /admin/hierarchy-nodes`,
|
||||
`PUT /admin/hierarchy-nodes/:nodeId`, `PATCH .../activate`, `PATCH .../deactivate`,
|
||||
`GET /admin/hierarchy-nodes/:nodeId`, `GET .../children`, `GET /admin/hierarchy-nodes`
|
||||
(gated by `fastify.authenticate`) in `orchestration/hierarchy/schema/` + `routes/`,
|
||||
registered from `src/api/routes.ts` (depends on T021)
|
||||
- [ ] T023 [US3] Run Quickstart Scenario 3 locally and confirm all 6 steps pass
|
||||
|
||||
**Checkpoint**: The dynamic support hierarchy — this feature's core differentiator — is fully
|
||||
configurable, cycle-safe, and audited.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: User Story 4 - A capability-eligibility lookup for a future caller to use (Priority: P3)
|
||||
|
||||
**Goal**: A read-only endpoint composing hierarchy scope with skill matching, deliberately
|
||||
excluding availability.
|
||||
|
||||
**Independent Test**: Quickstart Scenario 4.
|
||||
|
||||
### Tests for User Story 4
|
||||
|
||||
- [ ] T024 [P] [US4] Unit tests for the pure capability-matching predicate (agent skill set is a
|
||||
superset of the required set → eligible; missing one required skill → not eligible; empty
|
||||
hierarchy scope matches any product/category/priority) in
|
||||
`tests/unit/support-org/capability-match.test.ts`
|
||||
- [ ] T025 [US4] Integration test covering Quickstart Scenario 4 (skill-only match; availability
|
||||
never filters; inactive agent excluded; empty result on no match, never an error;
|
||||
hierarchy-scope skill composition) against a real Postgres in
|
||||
`tests/integration/support-org-capability-lookup.test.ts`
|
||||
|
||||
### Implementation for User Story 4
|
||||
|
||||
- [ ] T026 [P] [US4] Add the pure capability-matching predicate `isCapabilityEligible(agentSkills:
|
||||
string[], requiredSkills: string[]) => boolean` in
|
||||
`src/modules/orchestration/hierarchy/service/capability-match.ts` (no dependencies)
|
||||
- [ ] T027 [US4] Add `CapabilityLookupService.findEligibleAgents(skills, productId?, categoryId?,
|
||||
priorityId?)`: finds active `HierarchyNode`s whose scope arrays are empty-or-matching for
|
||||
each given context value, unions their `skills` into the requested set, queries active
|
||||
agents (active team) via T026's predicate applied to each candidate's `AgentSkill` tags —
|
||||
in `src/modules/orchestration/hierarchy/service/capability-lookup.service.ts` (depends on
|
||||
T026, and on `identity/agents`' repository being queryable — reuses its exported
|
||||
repository rather than duplicating the query)
|
||||
- [ ] T028 [US4] Add Zod schema + `GET /support-org/capability-eligibility` route (no
|
||||
`fastify.authenticate` gate — research.md "Admin endpoint authentication") in
|
||||
`orchestration/hierarchy/schema/` + `routes/`, registered from `src/api/routes.ts`
|
||||
(depends on T027)
|
||||
- [ ] T029 [US4] Run Quickstart Scenario 4 locally and confirm all 5 steps pass
|
||||
|
||||
**Checkpoint**: All four user stories work independently and together — a full support
|
||||
organization (teams, agents, skills, availability, hierarchy) exists and is queryable by
|
||||
capability, ready for Phase 7's orchestration engine to build on.
|
||||
|
||||
---
|
||||
|
||||
## Phase 7: Polish & Cross-Cutting Concerns
|
||||
|
||||
- [ ] T030 [P] Add a "Support Organization" section to `README.md` describing the admin CRUD,
|
||||
the cycle-safety/audit guarantees on hierarchy nodes, and the capability-eligibility
|
||||
contract (explicitly noting what it does *not* do — availability filtering, assignment)
|
||||
- [ ] T031 [P] Update `specs/006-support-organization/checklists/requirements.md` Notes with any
|
||||
implementation-time findings
|
||||
- [ ] T032 Run `npx tsx scripts/check-architecture.ts` and `npm run lint`/`npm run typecheck`
|
||||
- [ ] T033 Full regression: `npm run test:unit` (scoped to `tests/unit`) to confirm nothing broke
|
||||
elsewhere, then the full integration suite against real Docker-provisioned infra
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### Phase Dependencies
|
||||
|
||||
- **Setup (Phase 1)**: No dependencies
|
||||
- **Foundational (Phase 2)**: Depends on Setup — BLOCKS all user stories
|
||||
- **User Story 1 (Phase 3)**: Depends on Foundational — no dependency on US2-US4
|
||||
- **User Story 2 (Phase 4)**: Depends on US1 (agents must exist to attach skills/availability to)
|
||||
- **User Story 3 (Phase 5)**: Depends on Foundational and, loosely, on US1 (`teamId` FK) — no
|
||||
dependency on US2
|
||||
- **User Story 4 (Phase 6)**: Depends on US2 (skills to match on) and US3 (hierarchy nodes to
|
||||
compose scope from) — genuinely the last story, unlike 004's US3 which only needed US1
|
||||
- **Polish (Phase 7)**: Depends on all four user stories
|
||||
|
||||
### Parallel Opportunities
|
||||
|
||||
- T001/T002/T003 (independent scaffolding across three separate module directories)
|
||||
- T007 (Teams) before T008 (Agents) strictly (FK), but both alongside T017/T019 (US3's pure
|
||||
functions, independent of US1/US2 entirely) once T005 exists
|
||||
- T013/T014 (independent repositories) in parallel
|
||||
- T024/T026 (pure function + its test) independent of T017/T019
|
||||
- T030/T031 in Polish
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### MVP First (User Story 1 Only)
|
||||
|
||||
1. Setup + Foundational (T001-T005)
|
||||
2. User Story 1 (T006-T011)
|
||||
3. **STOP and VALIDATE**: Quickstart Scenario 1 passes — teams and agents exist with correct
|
||||
active/inactive semantics. Usable as the foundation for every later phase even before skills,
|
||||
availability, hierarchy, or capability lookup exist.
|
||||
|
||||
### Incremental Delivery
|
||||
|
||||
1. Setup + Foundational → schema migrated
|
||||
2. Add User Story 1 → teams and agents exist (MVP)
|
||||
3. Add User Story 2 → agents carry real skill/availability data
|
||||
4. Add User Story 3 → the dynamic support hierarchy is fully configurable and audited
|
||||
5. Add User Story 4 → a real capability-eligibility read path, ready for Phase 7
|
||||
6. Polish → docs and full regression
|
||||
Reference in New Issue
Block a user