Files
support_frontend/specs/001-agent-admin-ui/tasks.md
T
saqib mirandClaude Sonnet 5 b20bcc7aff feat(001-agent-admin-ui): User Stories 1-3 (dashboard, workbench, support-org admin)
Completes this feature's P1 MVP scope. Agent dashboard (US1) consumes
011-agent-ticket-queue's new endpoint with a distinct "no agent profile
linked" state, never conflated with a genuine empty list. Ticket
workbench (US2) covers messages (customer-visible vs internal notes),
status transitions, manual escalation, and the full investigation ->
root-cause -> solution -> implementation -> verification -> resolution
workflow, every stage surfacing the backend's own 409/400 rejection
verbatim rather than pre-validating order client-side. Support-org admin
(US3) covers team/agent/skill CRUD, linking an agent's account (011's
new PATCH field), and a hierarchy-node editor with real cycle-detection
error surfacing.

Two real backend-contract mismatches caught and fixed before shipping,
found by re-verifying schemas directly against the actual branch after
an isolated research agent (run in a worktree based on stale main,
missing the unmerged 009-problem-resolution branch) reported wrong
information: getTicketMessages was hitting the customer-safe endpoint
instead of the agent-facing one that includes internal notes, and
postMessage's body shape didn't match the real {type, body} schema.

Verified with 8 real Playwright E2E scenarios against a live, locally-
running supporthub-api (not mocks), plus 18 unit/integration tests.

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

14 KiB

description
description
Task list for 001-agent-admin-ui (Setup + User Stories 0-3, this plan's immediate scope)

Tasks: Agent and Admin UI (Setup + User Stories 0-3)

Input: Design documents from specs/001-agent-admin-ui/

Prerequisites: plan.md, spec.md, research.md, data-model.md, contracts/api-client-contract.md, quickstart.md

Scope note: Per plan.md's own Technical Context, this task list covers Setup + User Stories 0-3 (the P1 MVP) only. User Stories 4-7 (P2/P3) get their own tasks.md continuation once this scope is verified — the identical pattern established here (lib/api function → TanStack Query hook → feature component → page) applies directly.

Organization: Tasks are grouped by user story. US0 blocks every other story (no session, no data). US1-US3 are independent of each other once US0 exists.

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

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


Phase 1: Setup

  • T001 [P] Add js-cookie + @types/js-cookie and jose to package.json
  • T002 [P] Populate src/lib/env/index.ts — typed accessor over the existing NEXT_PUBLIC_* env vars (zod-validated, matching supporthub-api's own env.ts pattern), exporting env.apiUrl etc.
  • T003 [P] Configure vitest.config.ts (currently empty) — environment: 'jsdom', path aliases matching tsconfig.json, tests/unit + tests/integration include globs
  • T004 [P] Configure playwright.config.ts (currently empty) — base URL from NEXT_PUBLIC_APP_URL, tests/e2e test dir
  • T005 [P] Add @testing-library/react, @testing-library/jest-dom, jsdom as dev dependencies (needed by T003's jsdom environment; not yet present in package.json)

Checkpoint: Both test runners actually run (even with zero tests) and env is typed.


Phase 2: Foundational (Blocking Prerequisites)

Purpose: The typed client layer, session plumbing, and query infrastructure every user story is built on.

⚠️ CRITICAL: No user-story work can begin until this phase is complete.

  • T006 Add lib/auth/session-cookie.tsgetSessionToken()/setSessionToken(token)/ clearSessionToken() using js-cookie (sh_session, Secure in production, SameSite=Lax) (depends on T001)
  • T007 Add lib/api/client.ts — axios instance (baseURL: env.apiUrl), a request interceptor attaching Authorization: Bearer <token> from T006, a response interceptor throwing a typed ApiError (data-model.md) and clearing the session + redirecting to /sign-in on 401 (depends on T002, T006)
  • T008 [P] Add lib/api/types/Session, ApiError, AssignedTicketSummary (011's contract), and the ticket/message/problem-resolution/team/agent/hierarchy types data-model.md names, each referencing its source backend contract in a comment
  • T009 Add lib/api/auth.tslogin, getCurrentSession, logout per contracts/api-client-contract.md (depends on T007, T008)
  • T010 Add lib/query/query-client.ts (the shared QueryClient instance) and lib/query/query-state.ts (research.md's 'loading'|'empty'|'error'|'ready' discriminated union helper, taking a UseQueryResult and an optional isEmpty(data) predicate)
  • T011 Add providers/query-provider.tsx (QueryClientProvider wrapping T010's client) and providers/session-provider.tsx (calls getCurrentSession on mount via TanStack Query, exposes useSession(); the query's own onError for a 401 clears the session and redirects, per contracts/api-client-contract.md's "Session guard contract") (depends on T009, T010)
  • T012 Wire both providers into src/app/layout.tsx (currently the root layout with no providers)
  • T013 Write src/middleware.ts (this project's src/ layout requires middleware there, not at the repo root — an empty root-level middleware.ts had been scaffolded in the wrong place) — no sh_session cookie on a (support)/(admin) path → redirect to /sign-in?from=<path>; cookie present but jose-decoded role isn't ADMIN on an (admin) path → redirect to /support/dashboard (research.md's unverified-decode decision) (depends on T001). Also requires removing next.config.mjs's output: 'export' — incompatible with Middleware (discovered by actually running the dev server, not by inspection).

Checkpoint: A session can be established, read, and cleared; every subsequent API call carries it; an unauthenticated or wrongly-roled request never reaches portal content.


Phase 3: User Story 0 - An agent or admin signs in (Priority: P1)

Goal: A real sign-in screen and the redirect/guard behavior FR-000 requires.

Independent Test: Quickstart Scenario 0.

Tests for User Story 0

  • T014 [P] [US0] Unit test for lib/query/query-state.ts's discriminated-union logic (loading/empty/error/ready, each input combination) in tests/unit/lib/query-state.test.ts
  • T015 [US0] Integration test (mocked lib/api/auth.ts) covering Quickstart Scenario 0 steps 2-3 (successful sign-in redirects and stores a session; wrong credentials show one generic error) in tests/integration/auth/sign-in.test.tsx (depends on T009)
  • T016 [US0] Playwright E2E covering Quickstart Scenario 0 end-to-end against a real supporthub-api (redirect-when-unauthenticated, sign-in, role-gated redirect, sign-out) in tests/e2e/agent-sign-in-and-resolve.spec.ts — this is also Constitution Principle VII's journey (B), continued by User Story 2's own steps once that story is built

Implementation for User Story 0

  • T017 [US0] Add features/auth/sign-in-form.tsx + features/auth/use-login.ts (a TanStack useMutation wrapping lib/api/auth.ts's login, redirecting to a role-appropriate landing page on success) (depends on T009, T011)
  • T018 [US0] Add the /sign-in page (src/app/sign-in/page.tsx, new — outside every existing route group, since it's neither an admin nor support surface) rendering T017's form
  • T019 [US0] Add a sign-out action (features/auth/use-logout.ts, wrapping lib/api/auth.ts's logout) wired into both (support)/layout.tsx and (admin)/layout.tsx's existing nav shells (depends on T009, T011)
  • T020 [US0] Run Quickstart Scenario 0 locally and confirm all 5 steps pass

Checkpoint: A real session exists end-to-end. Every other user story can now consume one.


Phase 4: User Story 1 - An agent sees and opens their assigned work (Priority: P1)

Goal: The agent dashboard, backed by 011's new endpoint.

Independent Test: Quickstart Scenario 1.

Tests for User Story 1

  • T021 [P] [US1] Integration test (mocked lib/api/tickets.ts) covering Quickstart Scenario 1's three states (populated list, empty state, list reflects reassignment after refetch) in tests/integration/tickets/agent-dashboard.test.tsx

Implementation for User Story 1

  • T022 [US1] Add lib/api/tickets.ts's getMyAssignedTickets (depends on T007, T008)
  • T023 [US1] Add features/tickets/use-my-tickets.ts (TanStack useQuery + query-state.ts) and features/tickets/agent-dashboard.tsx (the list itself — customer/ product/priority/status/SLA time-remaining per row, per FR-001) (depends on T010, T022)
    • Sub-note: a 404 from getMyAssignedTickets (011's "no linked agent" rejection) renders as its own distinct message, not the generic empty state (contracts/api-client- contract.md)
  • T024 [US1] Replace the placeholder src/app/(support)/support/dashboard/page.tsx with T023's component (depends on T023)
  • T025 [US1] Run Quickstart Scenario 1 locally and confirm all 3 steps pass

Checkpoint: An agent has a real, live dashboard.


Phase 5: User Story 2 - An agent works a ticket end-to-end (Priority: P1)

Goal: The ticket workbench — messages, status transitions, the full problem-resolution workflow — surfacing every backend rejection verbatim.

Independent Test: Quickstart Scenario 2.

Tests for User Story 2

  • T026 [P] [US2] Integration test (mocked lib/api/tickets.ts + lib/api/problems.ts) covering Quickstart Scenario 2's three steps, including the 409 precondition-rejection case rendered verbatim, in tests/integration/tickets/workbench.test.tsx
  • T027 [US2] Extend tests/e2e/agent-sign-in-and-resolve.spec.ts (T016) with the full investigation→root-cause→solution→implementation→verification→resolution flow against a real supporthub-api ticket already in HUMAN_ESCALATION

Implementation for User Story 2

  • T028 [US2] Add lib/api/tickets.ts's getTicket/getTicketMessages/postMessage/ updateTicketStatus/escalateTicket and lib/api/problems.ts's full set (per contracts/api-client-contract.md) (depends on T007, T008)
  • T029 [US2] Add features/tickets/ticket-header.tsx (status, priority, SLA, escalate action) and features/tickets/message-thread.tsx (customer/AI/agent messages + internal notes, visually distinct, per FR-002) (depends on T028)
  • T030 [US2] Add features/problems/investigation-form.tsx through features/problems/resolution-form.tsx (one per stage, FR-003) — each renders its own 409 precondition rejection from ApiError verbatim, never a client-side pre-check of "is there an investigation on file yet" (depends on T028)
  • T031 [US2] Replace the placeholder src/app/(support)/support/agent-tickets/[ticketId]/page.tsx composing T029-T030 (depends on T029, T030)
  • T032 [US2] Run Quickstart Scenario 2 locally and confirm all 3 steps pass

Checkpoint: An agent can resolve a real customer problem end-to-end from the UI alone.


Phase 6: User Story 3 - An admin sets up the support organization (Priority: P1)

Goal: Teams/agents/skills/hierarchy admin screens, replacing every placeholder under (admin)/admin/{teams,agents,hierarchy}.

Independent Test: Quickstart Scenario 3.

Tests for User Story 3

  • T033 [P] [US3] Integration test (mocked lib/api/teams.ts + lib/api/hierarchy.ts) covering Quickstart Scenario 3's three steps, including the cycle-detection rejection rendered verbatim, in tests/integration/teams/support-org-admin.test.tsx

Implementation for User Story 3

  • T034 [US3] Add lib/api/teams.ts and lib/api/hierarchy.ts per contracts/api-client-contract.md, including 011's linkAgentAccount (depends on T007, T008)
  • T035 [US3] Add features/teams/team-roster.tsx (create team, add agent, upsert skill, link an agent's account per FR-005) (depends on T034)
  • T036 [US3] Add features/orchestration/hierarchy-editor.tsx (create/view a node with scope/skills/strategy, rendered as a tree by parentId, per FR-005) (depends on T034)
  • T037 [US3] Replace the placeholder src/app/(admin)/admin/teams/page.tsx and src/app/(admin)/admin/hierarchy/page.tsx with T035/T036 (depends on T035, T036)
  • T038 [US3] Run Quickstart Scenario 3 locally and confirm all 3 steps pass

Checkpoint: All four Phase 3-6 stories (US0-US3, this plan's full immediate scope) work independently and together — this is the feature's P1 MVP.


Phase 7: Polish & Cross-Cutting Concerns (this scope's own)

  • T039 [P] Update specs/001-agent-admin-ui/checklists/requirements.md Notes with any implementation-time findings
  • T040 Run npm run typecheck and npm run lint
  • T041 Run npm run test (all unit + integration) and npm run test:e2e (both Playwright journeys) against a real, locally-running supporthub-api

Dependencies & Execution Order

  • Setup (Phase 1): No dependencies
  • Foundational (Phase 2): Depends on Setup — BLOCKS every user story
  • User Story 0 (Phase 3): Depends on Foundational — BLOCKS User Stories 1-3 (no session, no data)
  • User Stories 1-3 (Phases 4-6): Each depends on US0 only — independent of each other, parallelizable once US0 is done
  • Polish (Phase 7): Depends on all of Phases 3-6

Parallel Opportunities

  • T001-T005 (Setup, all independent)
  • T008 (types) alongside T006-T007 (client plumbing) once T002 exists
  • Once US0 (Phase 3) is complete: Phases 4, 5, and 6 can proceed in parallel — they touch disjoint features/* subdirectories and disjoint page files

Implementation Strategy

MVP First (User Story 0 alone is not shippable — it has no destination)

  1. Setup + Foundational (T001-T013)
  2. User Story 0 (T014-T020) → a real session exists
  3. STOP and VALIDATE: Quickstart Scenario 0 passes end-to-end against a real supporthub-api, including the redirect-on-401 path (contracts/api-client-contract.md's "Session guard contract" — this is the one behavior that can't be verified by a mocked-API integration test alone).
  4. User Stories 1-3 (T021-T038), in any order or in parallel — this plan's full P1 MVP
  5. Polish (T039-T041)

Continuing past this plan's scope

User Stories 4-7 (SLA/calendar config, escalation config, monitoring views, catalog/knowledge governance) follow the identical lib/api function → TanStack Query hook → features/* component → page pattern established above, against their own backend contracts (specs/008-sla-escalation, specs/004-product-knowledge in supporthub-api) — deferred to a tasks.md continuation once this scope is verified, per plan.md's own Technical Context.