Configures both previously-empty test runners (vitest.config.ts, playwright.config.ts) and adds the typed lib/api client layer (axios + interceptors), the session-cookie plumbing (lib/auth), TanStack Query infrastructure (lib/query, providers), and a real sign-in flow consuming supporthub-api's own login (010-identity-auth) - the true foundation every other user story in this feature depends on. Two structural fixes to the existing scaffold, both found only by running the app rather than by inspection: middleware.ts belongs at src/middleware.ts under this project's src/ layout, not the repo root; and next.config.mjs's output:'export' is incompatible with Next.js Middleware outright (the dev server refuses to start it), so this app now runs as a standard Next.js server - confirmed with the user before making that deployment-mode change. Verified end-to-end with a real, locally-running supporthub-api: all 5 Playwright scenarios (unauthenticated redirect, sign-in, wrong-password generic error, non-admin role gating, sign-out) pass against a live backend, not a mock. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
11 KiB
Implementation Plan: Agent and Admin UI
Branch: 001-agent-admin-ui | Date: 2026-09-07 | Spec: spec.md
Input: Feature specification from specs/001-agent-admin-ui/spec.md
Summary
Builds the (support)/(admin) portals against the existing Next.js scaffold: a sign-in flow
consuming supporthub-api's own login (010-identity-auth, User Story 0 — this feature's true
foundation), an agent dashboard and ticket workbench (011-agent-ticket-queue plus the existing
ticketing/problem-resolution endpoints), and admin configuration screens for support
organization, SLA/calendars, escalation, and (P3) catalog/knowledge governance. Every screen
reads and writes through one typed API client layer (lib/api) via TanStack Query — no business
logic is computed client-side (Constitution Principle II).
Technical Context
Language/Version: TypeScript 5.5, Node.js 22 (per package.json engines), Next.js 14
(App Router), React 18. next.config.mjs's output: 'export' (static HTML export) is removed
by this feature — Next.js Middleware, which FR-000's sign-in guard requires, cannot run under
static export (confirmed by the dev server itself refusing to start it); this app now runs as a
standard Next.js server (next build && next start), a deployment-mode change, not just a code
change.
Primary Dependencies: @tanstack/react-query (server state), axios (wrapped by lib/api),
tailwindcss (styling, already configured), clsx/tailwind-merge (already present),
lucide-react (icons, already present). New: js-cookie (small, typed cookie read/write for
the session token — the codebase has no cookie helper today) and jose (Edge-runtime-safe JWT
payload decode for middleware.ts — jsonwebtoken depends on Node APIs middleware.ts cannot
use).
Storage: N/A (server state is supporthub-api's; the only client-side state is the session
cookie itself, research.md).
Testing: Vitest (unit — hooks, lib/api functions, the query-state helper; integration —
per-portal critical flows against a mocked API layer) + Playwright (E2E — the two journeys
Constitution Principle VII names, plus this feature's own: an agent signing in and resolving a
ticket end-to-end, User Stories 0-2). vitest.config.ts and playwright.config.ts are both
currently empty stubs — this feature is the first to configure either.
Target Platform: Browser (desktop-first, responsive down to a reasonable minimum per Principle VI), served by the existing Next.js app.
Project Type: Web frontend — single Next.js project, consuming a separately-deployed supporthub-api.
Performance Goals: SC-001 — dashboard-open to message-post in under 15 seconds of active use (excluding backend response time), meaning the UI itself must not introduce avoidable extra round trips or re-renders on that path.
Constraints: FR-012/Principle II — no business decision (transition validity, SLA due dates, most-specific-policy resolution, escalation matching) is computed client-side, only rendered from what the API returns. FR-000/Principle I — this frontend never verifies a JWT signature itself (research.md); the unverified middleware decode is UX-only.
Scale/Scope: Eight user stories (US0 sign-in + US1-US7), against ~30 existing placeholder
page.tsx files across four route groups, all of lib/api/lib/auth/lib/query/hooks/
stores/providers/features/* currently empty. Given the size, this plan's own Project
Structure section scopes Phase 1 (Setup) and User Stories 0-3 (the P1 MVP: sign-in, dashboard,
ticket workbench, support-org admin) as the immediate implementation target; User Stories 4-7
(P2/P3) follow the identical pattern once the MVP is verified, per the Implementation Strategy
below — matching this project's own established phase-by-phase, checkpoint-then-continue
discipline (mirrors supporthub-api's own MVP-first pattern, e.g. 010's own tasks.md).
Constitution Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
| Principle | Check | Result |
|---|---|---|
| I. Each Identity Has Exactly One Authority | US0 consumes supporthub-api's own login (010) for agent/admin identity, never re-implementing or re-deriving it; the (public)/(customer) portals (SaaS-delegated identity) are explicitly out of scope for this feature (Assumptions), so no conflict between the two identities' authorities arises here. |
PASS |
| II. The Backend Is the Sole Source of Business Logic | FR-012 is this principle restated as a testable requirement; every user story's Acceptance Scenarios that touch a business-rule rejection (US2 scenario 2, US3 scenario 3, US5 scenario 3) exist specifically to keep it enforced. | PASS |
| III. Strict Portal Boundaries | This feature only touches (support)/(admin) — (public)/(customer) are untouched (Assumptions). Shared primitives stay in components/ui; portal-specific composition lives in features/* and each route group. |
PASS |
| IV. Typed API Boundary, No Ad Hoc Fetching | lib/api is the single client layer (research.md); every features/* module consumes it only through TanStack Query hooks. |
PASS |
| V. Configuration Over Hardcoding | Support hierarchy, SLA policies, escalation rules, and skills are rendered/edited generically from what the API returns — no frontend-duplicated enum for root-cause types, verification methods, escalation trigger types, etc. | PASS |
| VI. Accessible, Responsive, Enterprise-Grade UI | Existing components/ui primitives (already built, this session's earlier scaffold work) are the basis for every new screen; density/keyboard-usability is a per-task acceptance bar, not a separate follow-up. |
PASS |
| VII. Testing Gates | This plan's Testing section above configures both currently-empty test runners as part of Setup, not deferred — Vitest unit/integration plus the two Playwright E2E journeys (one of which, agent resolving an escalated ticket, is this feature's own US0-US2). | PASS |
No violations requiring Complexity Tracking justification.
Post-Design Constitution Re-check
All gates above remain PASS after Phase 1 design (data-model.md, contracts, quickstart.md). One principle is worth restating post-design: Principle I's redefinition (this session's own constitution amendment, 1.0.0 → 1.1.0) is what makes User Story 0 exist at all — without it, this plan would have wrongly assumed no sign-in screen was needed.
Project Structure
Documentation (this feature)
specs/001-agent-admin-ui/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
└── tasks.md
Source Code (repository root)
supporthub-web/
├── src/middleware.ts # MODIFIED (was an empty file at repo root — moved
│ under src/, required by this project's src/
│ directory layout) — session presence + role
│ redirect for (support)/(admin), FR-000/research.md
├── vitest.config.ts # MODIFIED (was empty) — first real test config
├── playwright.config.ts # MODIFIED (was empty) — first real E2E config
├── src/
│ ├── lib/
│ │ ├── env/index.ts # MODIFIED (was empty) — typed env accessor
│ │ ├── auth/ # MODIFIED (was empty) — session cookie read/write/
│ │ │ │ clear, decode-for-display helpers
│ │ │ └── (session.ts, use-session.ts)
│ │ ├── api/ # MODIFIED (was empty) — axios instance + interceptors
│ │ │ │ (client.ts) + one file per domain (auth.ts,
│ │ │ │ agents.ts, tickets.ts, teams.ts, hierarchy.ts,
│ │ │ │ sla.ts, escalation.ts, problems.ts, ...)
│ │ │ └── types/ # response/request shapes, kept in sync with
│ │ │ supporthub-api's own contracts/*.md
│ │ └── query/ # MODIFIED (was empty) — QueryClient config,
│ │ │ query-state.ts (research.md's discriminated union)
│ │ └── keys.ts # centralized TanStack Query key factory
│ ├── providers/ # MODIFIED — QueryClientProvider, SessionProvider
│ ├── hooks/ # MODIFIED — use-session, use-query-state re-exports
│ ├── features/
│ │ ├── auth/ # NEW — sign-in form + its own mutation hook (US0)
│ │ ├── tickets/ # MODIFIED (was empty) — dashboard list, workbench
│ │ │ detail, message thread, status/escalate actions
│ │ ├── problems/ # MODIFIED — investigation/root-cause/solution/
│ │ │ verification/resolution recording (US2)
│ │ ├── teams/ # MODIFIED — team/agent/skill admin (US3)
│ │ ├── orchestration/ # MODIFIED — hierarchy-node admin (US3)
│ │ ├── settings/ # MODIFIED — SLA/calendar admin (US4, deferred)
│ │ └── ... # escalation/reports/knowledge/products: US5-US7,
│ │ deferred past this plan's immediate MVP scope
│ └── app/
│ ├── (support)/
│ │ ├── layout.tsx # MODIFIED — session-aware shell (nav, sign-out)
│ │ └── support/
│ │ ├── dashboard/page.tsx # MODIFIED (was a placeholder) — US1
│ │ └── agent-tickets/[ticketId]/page.tsx # MODIFIED — US2
│ └── (admin)/
│ ├── layout.tsx # MODIFIED — admin-only shell
│ └── admin/
│ ├── teams/page.tsx # MODIFIED — US3
│ └── hierarchy/page.tsx # MODIFIED — US3
└── tests/
├── unit/ # lib/api functions, query-state, session helpers
├── integration/ # per-portal critical flows (mocked API layer)
└── e2e/ # Playwright — Principle VII's two journeys
Structure Decision: Single Next.js project, built entirely against the existing scaffold
(no new route groups or top-level directories) per the constitution's own Development Workflow
rule — replacing placeholder pages, not restructuring the route tree. This plan's own immediate
implementation scope is Setup + User Stories 0-3 (P1 MVP); features/ subdirectories for
US4-US7 are named above for completeness but not built until those stories' own turn.
Complexity Tracking
No constitution violations — table intentionally omitted.