Files
support_backend/specs/006-support-organization/tasks.md
T
saqib mirandClaude Sonnet 5 a0c1a9aa33 feat: implement support organization (006) — teams, agents, hierarchy, capability lookup
Phase 6 of the roadmap. Populates the identity/teams and
orchestration/hierarchy module directories (previously empty or
near-empty scaffold stubs) and replaces identity/agents' pre-existing
placeholder, which queried a generic User/UserRole model unrelated to
this system's real architecture (nothing since 002-saas-integration's
CustomerReference has used it).

Teams and agents: active/inactive CRUD, never hard deletion; team
deactivation never cascades to its agents. Skills: compound-unique
upsert on (agentId, skillTag), never duplicates. Availability: a single
current record per agent, deliberately last-write-wins rather than
optimistic-locked — operational telemetry, not a durable business
record. The dynamic hierarchy: a nestable, orderable HierarchyNode tree
with every field (scope, assignment strategy reference, entry/exit
conditions) stored as opaque admin-set data; cycle detection runs only
on reparenting edits (a new node can't form a cycle); every
create/edit/activate/deactivate is audited via AuditLog, reusing
002's existing writer pattern. A capability-eligibility read path
composes hierarchy scope with caller-supplied skills for the future
orchestration/assignment phase (Phase 7) to call, deliberately
excluding availability per doc 05's own capability-before-availability
ordering.

Found and fixed a real bug before it reached tests: the initial
availability upsert reset currentLoad to 0 on every update, not just
creation.

Adds 11 unit tests (cycle detection, capability matching) and 4
integration test files covering all four user stories. Full regression
(every pre-existing 002-005 integration test plus all new ones) run
against real Postgres/Redis/MinIO: 107 passed, 9 skipped (005's
AI-key-gated tests, unrelated), 0 failed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 18:12:26 +05:30

14 KiB

description
description
Task list for 006-support-organization

Tasks: Support Organization

Input: Design documents from specs/006-support-organization/

Prerequisites: plan.md, spec.md, research.md, data-model.md, contracts/support-org-contract.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 HierarchyNodes 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