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>
167 lines
11 KiB
Markdown
167 lines
11 KiB
Markdown
# Implementation Plan: Agent and Admin UI
|
|
|
|
**Branch**: `001-agent-admin-ui` | **Date**: 2026-09-07 | **Spec**: [spec.md](./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)
|
|
|
|
```text
|
|
specs/001-agent-admin-ui/
|
|
├── plan.md
|
|
├── research.md
|
|
├── data-model.md
|
|
├── quickstart.md
|
|
├── contracts/
|
|
└── tasks.md
|
|
```
|
|
|
|
### Source Code (repository root)
|
|
|
|
```text
|
|
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.*
|