# Specification Quality Checklist: Identity and Authentication **Purpose**: Validate specification completeness and quality before proceeding to planning **Created**: 2026-09-07 **Feature**: [spec.md](../spec.md) ## Content Quality - [x] No implementation details (languages, frameworks, APIs) - [x] Focused on user value and business needs - [x] Written for non-technical stakeholders - [x] All mandatory sections completed ## Requirement Completeness - [x] No [NEEDS CLARIFICATION] markers remain - [x] Requirements are testable and unambiguous - [x] Success criteria are measurable - [x] Success criteria are technology-agnostic (no implementation details) - [x] All acceptance scenarios are defined - [x] Edge cases are identified - [x] Scope is clearly bounded - [x] Dependencies and assumptions identified ## Feature Readiness - [x] All functional requirements have clear acceptance criteria - [x] User scenarios cover primary flows - [x] Feature meets measurable outcomes defined in Success Criteria - [x] No implementation details leak into specification ## Notes - This feature was not on the original 11-phase roadmap — it surfaced as a genuine blocking gap while planning supporthub-web's `001-agent-admin-ui`: `fastify.authenticate` has been a complete no-op stub since 002, and `identity/auth`'s login endpoint has never taken a password. Numbered 010 in supporthub-api's own sequence since it's a real, immediately-needed backend prerequisite, not deferred hardening. - `User`/`UserRole` (with two seeded-but-passwordless demo accounts, `admin@supporthub.internal`/`agent@supporthub.internal`) and the `AuthUser`/`JwtPayload` types in `src/common/types` were all found already scaffolded, unwired, and clearly intended for exactly this feature since the original pre-speckit scaffold — this is a "finish the originally-intended wiring" feature, not a new design invented from nothing. - Scope is deliberately narrow: real login + real route gating + role checks + a self-identity endpoint + admin-created accounts + logout. Password reset, MFA, rate-limiting, and registration are explicitly out of scope (Assumptions), matching Phase 11's own "security hardening pass" as the more appropriate later home for those. - All items pass; no revision iterations were needed. - **Implementation-time finding**: making `fastify.authenticate` genuinely reject invalid/missing tokens (FR-004) had a far larger blast radius than this feature's own tasks.md anticipated. Dozens of routes across features 002-009 were already declared with `fastify.authenticate` as a preHandler — safe to write against a no-op stub, but every one of those pre-existing integration tests had been calling them with no `Authorization` header. Making the check real broke ~18 integration test files suite-wide, requiring a `tests/helpers/auth.ts` (`loginAs`/ `authHeader`) and a file-by-file pass adding real bearer tokens, well beyond the mechanical `requireRole('ADMIN')` rollout research.md had scoped for. A related, recurring bug: several files already declared a local `const token = issueIntegrationToken(...)` for the unrelated 002 customer-trust-boundary flow, and naming the new admin/agent token variable `token` in the same scope produced a `ReferenceError: Cannot access 'token' before initialization` — a genuine temporal-dead-zone collision, not a tooling bug — fixed by using a non-colliding name (`authToken`/`adminToken`/`agentToken`) per file. - A second, subtler implementation-time finding: once admin-setup calls in test `beforeAll` blocks started actually succeeding (previously they silently 401'd against the no-op stub), wildcard/global SLA policies created by one integration test file could genuinely match tickets created by another file running against the same shared throwaway Postgres, leaving orphaned `sla_run` rows that RESTRICT-violated the FK on cleanup. Fixed by widening the affected files' `afterAll` cleanup to delete `sla_run` rows by `ticketId` *and* by `policyId`, not just one or the other.