supporthub-api's 010-identity-auth (built after this spec's initial approval) established that agent/admin login is supporthub-api's own authentication, never SaaS-delegated — this spec and the project constitution's Principle I still assumed the opposite. Adds User Story 0 (sign-in, P1) and FR-000/SC-006 for the login screen and session-guard this frontend must now own, and rewords FR-011/the affected Edge Case to reference the supporthub-api session role instead of a "SaaS-provided role." Only end-customer identity remains SaaS-delegated. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
8.6 KiB
SupportHub Web Constitution
Core Principles
I. Each Identity Has Exactly One Authority, and the Frontend Is Never It (NON-NEGOTIABLE)
supporthub-web MUST NOT implement its own user authentication, session management, or
role-based access control for either identity this project serves. It reads, and only reads,
whichever authority already owns that identity: for end-customers, that's the parent SaaS host,
via the documented token mechanism (X-SaaS-User-Token, per README.md); for agents/admins,
that's supporthub-api's own login (POST /auth/login, specs/010-identity-auth in
supporthub-api) — SupportHub is the sole authority for its own support-org structure and staff
accounts, exactly as supporthub-api's own Principle I defines, and was never SaaS-delegated.
Neither identity's role or session state is ever re-derived, cached as a second source of
truth, or locally overridden by this frontend. Rationale: an authentication or role system
duplicated on the frontend is worse than none — it creates a second place authorization can
silently disagree with whichever backend already decided it, and conflating the two identities'
different authorities is exactly the kind of drift Principle I exists to prevent.
II. The Backend Is the Sole Source of Business Logic
supporthub-web MUST NOT re-implement ticket lifecycle state machines, SLA due-date or pause/resume math, escalation rule evaluation, assignment/routing logic, or any other business rule supporthub-api already owns. The frontend renders the state the API returns and calls the API to change it — it never computes a business decision the backend is authoritative for, even as a "just for the UI" shortcut (e.g. a client-side guess at whether a status transition is valid). Rationale: two implementations of the same rule (one in Fastify, one in React) will drift the moment either one changes; the API is already the tested, audited source of truth.
III. Strict Portal Boundaries
The four route groups — (public), (customer), (support), (admin) — are distinct
surfaces with different audiences and trust levels. Components, data, and navigation MUST NOT
leak across portal boundaries: an admin-only data shape (e.g. escalation policy internals) MUST
NOT be fetched or rendered from a customer-facing route, and customer-portal code MUST NOT
import agent- or admin-portal features. Shared UI primitives live in components/ui and are
portal-agnostic; portal-specific composition lives under each route group or its matching
features/ module. Rationale: this is the frontend analogue of supporthub-api's module
boundaries (its own Principle III) — without an enforced seam, a support-agent-only view of a
ticket inevitably ends up reachable from the customer portal by accident.
IV. Typed API Boundary, No Ad Hoc Fetching
Every call to supporthub-api goes through a single typed API client layer (lib/api), with
request/response shapes kept in sync with the backend's own contracts
(specs/*/contracts/*.md in supporthub-api). Components and features/ modules MUST NOT call
fetch/axios directly — all server state flows through TanStack Query hooks built on that
client layer, giving one consistent place for auth headers, error handling, and retry/caching
policy. Rationale: a typed, single-entry-point client is what keeps a contract change on the
backend from becoming a silent runtime break scattered across dozens of components.
V. Configuration Over Hardcoding
Anything the backend exposes as admin-configurable — SLA policies, escalation rules, routing/assignment strategy, support hierarchy — MUST be rendered and edited generically from what the API returns, never hardcoded as frontend constants or duplicated enums that could drift from the backend's own validated values (e.g. root-cause types, verification methods, escalation trigger types). Rationale: mirrors supporthub-api's own Principle II — a value the business can change from an admin screen must never require a frontend deploy to keep it in sync with the backend's own enum.
VI. Accessible, Responsive, Enterprise-Grade UI
Every screen MUST be usable via keyboard, meet WCAG AA contrast, and remain usable down to a reasonable minimum viewport. This is an enterprise support tool used for hours at a time by agents and admins, not a marketing site — interaction patterns (tables, forms, workflows) MUST prioritize density and speed of task completion over decorative polish. Rationale: an inaccessible or slow-to-use agent workspace directly costs support throughput and SLA compliance — this is a productivity tool first.
VII. Testing Gates
Required test categories: unit tests (Vitest) for hooks, utilities, and business-facing component logic; integration tests for each portal's critical flows; Playwright E2E for the two cross-cutting journeys that matter most — (A) a customer submitting and tracking a ticket through to resolution/confirmation, and (B) an agent working an escalated ticket through investigation to resolution. Typecheck and lint MUST be clean before any feature is considered done, matching supporthub-api's own quality-gate discipline. Rationale: a frontend regression that silently breaks the agent workspace or the customer submission flow is a direct support- capacity or customer-trust incident, not a cosmetic bug.
Technology & Platform Constraints
- Stack: Next.js 14 (App Router), React 18, TypeScript, TanStack Query, Tailwind CSS, axios (wrapped by the typed client layer, Principle IV), Vitest, Playwright.
- Architecture style: route groups as portals (
(public),(customer),(support),(admin)), domain-organizedfeatures/modules, portal-agnosticcomponents/ui. Do not introduce a second frontend framework or a competing state-management paradigm without a constitution amendment — one server-state layer (TanStack Query) and one client-state approach (stores/) keep data flow predictable. - Every environment (
development,test,production) has its own.env.*file, matching the existing convention — no secrets committed to the repository.
Development Workflow & Quality Gates
npm run typecheckandnpm run lintMUST pass before a feature is considered done.npm run test(Vitest) covers unit/integration-level logic;npm run test:e2e(Playwright) covers the two cross-cutting journeys named in Principle VII, plus any portal-specific critical flow a feature's own spec identifies.- New pages/features are built against the existing scaffold (route groups,
features/modules) — replacing a placeholder page's content, not restructuring the route tree, unless a spec explicitly calls for a structural change.
Governance
This constitution supersedes ad hoc conventions and undocumented team habits for supporthub-web. All PRs and code reviews MUST verify compliance with the principles above before merge.
Amendments require: a documented rationale for the change, a version bump under the semantic versioning rule below, and an updated Sync Impact Report prepended to this file. MAJOR = a backward-incompatible principle removal or redefinition. MINOR = a new principle added, or existing guidance materially expanded. PATCH = clarification, wording, or typo fixes with no semantic change. Any exception to a MUST/MUST NOT rule requires explicit written justification in the relevant PR description and is expected to be rare, not routine.
This project is a sibling to, and a pure consumer of, supporthub-api — that project's own
constitution and docs/00-INDEX.md through docs/10-implementation-roadmap.md remain the
authority for backend and product-domain design; this constitution governs only how
supporthub-web is engineered.
Version: 1.1.0 | Ratified: 2026-09-07 | Last Amended: 2026-09-07