Files
2026-05-27 23:29:53 +01:00

180 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tasks — complete-react-auth
**Change ID**: complete-react-auth
**Package**: `@suaveplan/react-auth`
**Target path**: `packages/auth/react-auth/`
Pre-flight: `@suaveplan/types`, `@suaveplan/error`, `@suaveplan/events`, `@suaveplan/logger`, `@suaveplan/i18n`, `@suaveplan/webauthn`, `@suaveplan/oauth-client`, `@suaveplan/srp`, `@suaveplan/otp`, `@suaveplan/hibp`, `@suaveplan/password-strength`, `@suaveplan/password-generator`, `@suaveplan/react-ui` — all ✅ on Verdaccio.
---
## 0. Pre-flight (non-negotiable)
- [ ] 0.1 Confirm clean working tree (`git status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in each)
- [ ] 0.2 If any worktrees exist under `.claude/worktrees/`, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (`git worktree remove`) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
- [ ] 0.3 Confirm the package set in `MANIFEST.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest.
## 1. Scaffold
- [ ] Create directory tree per `design.md` § File layout.
- [ ] Write `package.json` at `0.1.0`, `"sideEffects": false`, `react ^19.0.0` peer, every internal dep as `workspace:^`, every external dep via catalog.
- [ ] Write `tsconfig.json` (extends `@suaveplan/typescript-config/browser-react.json`), `vitest.config.ts` (forks pool, fileParallelism false, istanbul 100/100/100/100), `playwright.config.ts` via `@suaveplan/testing-e2e` factory.
- [ ] Write `README.md` at package root — overview, install, quick-start (provider + sign-in form), Modules section linking every co-located `.md`.
## 2. Types + schemas + errors
- [ ] `src/types/auth-user.ts`, `auth-state.ts`, `auth-backend.ts`, `session.ts`, `idle-config.ts`, `permission-resolver.ts` — each with sibling `.md` (≥ 200 words).
- [ ] `src/schemas/schemas.ts` — Zod schemas for every hook option bag (`SignInOptions`, `SignUpOptions`, `UsePasskeyAutofillOptions`, `UseOAuthSignInOptions`, …). Sibling `.md`, `schemas.test.ts`.
- [ ] `src/errors/errors.ts` — `defineCodes("REACT_AUTH", [...])` for the 29 codes in `design.md` § Error code namespace. Export `ReactAuthError`. Sibling `.md`, `errors.test.ts` covering: every code reachable from a production path; translation helpers preserve `cause`.
## 3. Utilities
- [ ] `src/utils/compose-signals.ts` (+ `.md`, `.test.ts`) — `AbortController` composition (any abort → composed abort).
- [ ] `src/utils/is-ssr.ts` (+ `.md`, `.test.ts`).
- [ ] `src/utils/announce.ts` (+ `.md`, `.test.ts`) — ARIA live-region helper (creates a single shared `aria-live="polite"` node on first call).
## 4. Session — storage, broadcast, idle, refresh, forced-logout
- [ ] `src/session/storage/memory/memory.ts` (+ `.md`, `.test.ts`).
- [ ] `src/session/storage/local/local.ts` (+ `.md`, `.test.ts`).
- [ ] `src/session/storage/session/session.ts` (+ `.md`, `.test.ts`).
- [ ] `src/session/broadcast-channel.ts` (+ `.md`, `.test.ts`) — typed envelope, factory injection, SSR no-op.
- [ ] `src/session/auto-refresh.ts` (+ `.md`, `.test.ts`) — schedule via injected `Clock`; cancels on every state update.
- [ ] `src/session/idle-timer.ts` (+ `.md`, `.test.ts`) — pointer/key/visibility listeners; debounced; `onWarn`/`onTimeout`.
- [ ] `src/session/forced-logout.ts` (+ `.md`, `.test.ts`) — broadcasts + clears storage synchronously.
## 5. Provider + context
- [ ] `src/auth-provider/auth-context.ts` (+ `.md`, `.test.ts`).
- [ ] `src/auth-provider/use-auth-context.ts` (+ `.md`, `.test.ts`) — throws `REACT_AUTH.CONTEXT_MISSING` outside provider.
- [ ] `src/auth-provider/load-persisted-session.ts` (+ `.md`, `.test.ts`).
- [ ] `src/auth-provider/auth-provider.tsx` (+ `.md`, `.test.tsx`, `.stories.tsx`) — wires backend + storage + broadcast + idle + auto-refresh; deterministic SSR render; effect-only DOM access.
## 6. Lifecycle hooks
- [ ] `src/hooks/use-auth/` (+ `.md`, `.test.ts`).
- [ ] `src/hooks/use-user/` (+ `.md`, `.test.ts`).
- [ ] `src/hooks/use-is-authenticated/` (+ `.md`, `.test.ts`).
- [ ] `src/hooks/use-session/` (+ `.md`, `.test.ts`).
- [ ] `src/hooks/use-sign-in/` (+ `.md`, `.test.ts`) — supports password, SRP, passkey result handoff.
- [ ] `src/hooks/use-sign-up/` (+ `.md`, `.test.ts`).
- [ ] `src/hooks/use-sign-out/` (+ `.md`, `.test.ts`) — broadcasts `signed-out`.
- [ ] `src/hooks/use-refresh-token/` (+ `.md`, `.test.ts`).
## 7. Password hooks + components
- [ ] `src/hooks/use-change-password/` (+ `.md`, `.test.ts`).
- [ ] `src/hooks/use-password-reset/` (+ `.md`, `.test.ts`) — `request` + `confirm`.
- [ ] `src/components/password-strength-meter/` (+ `.md`, `.test.tsx`, `.stories.tsx`) — wraps `password-strength.assessReactive`; cancels on unmount.
- [ ] `src/components/hibp-pwned-indicator/` (+ `.md`, `.test.tsx`, `.stories.tsx`) — debounced ≥ 500 ms; SSR no-op; injected `HibpClient`.
- [ ] `src/components/password-input/` (+ `.md`, `.test.tsx`, `.stories.tsx`) — show/hide, label association, `aria-describedby`, optional strength + HIBP slots.
- [ ] `src/components/password-generator-button/` (+ `.md`, `.test.tsx`, `.stories.tsx`) — popover via `@suaveplan/react-ui` `<Popover>`; passphrase/chars/pin modes.
## 8. Passkey hooks + components
- [ ] `src/hooks/use-register-passkey/` (+ `.md`, `.test.ts`).
- [ ] `src/hooks/use-authenticate-with-passkey/` (+ `.md`, `.test.ts`) — modal mediation.
- [ ] `src/hooks/use-passkey-autofill/` (+ `.md`, `.test.tsx`) — folded from superseded autofill change; SSR-safe; `isConditionalMediationAvailable` feature-detect; composed `AbortController`; stable `abort`.
- [ ] `src/components/passkey-autofill-field/` (+ `.md`, `.test.tsx`, `.stories.tsx`) — `<input autocomplete="username webauthn">` wrapper; blur cancels when no credential delivered.
- [ ] `src/components/passkey-list/` (+ `.md`, `.test.tsx`, `.stories.tsx`) — lists from `backend.listPasskeys`; per-row revoke with accessible confirm dialog.
## 9. OAuth
- [ ] `src/oauth/provider-registry.ts` (+ `.md`, `.test.ts`) — `register / get / has / list / unregister`; descriptor includes label key + icon slot + scopes.
- [ ] `src/oauth/popup.ts` (+ `.md`, `.test.ts`) — centred-window helper; `postMessage` origin check; popup-blocked detection.
- [ ] `src/oauth/redirect.ts` (+ `.md`, `.test.ts`) — `sessionStorage` return-state persist; `window.location.assign`.
- [ ] `src/oauth/handle-callback.ts` (+ `.md`, `.test.ts`) — parses query, validates state, exchanges code, dispatches result; idempotent on remount.
- [ ] `src/hooks/use-oauth-sign-in/` (+ `.md`, `.test.ts`) — popup + redirect modes; PKCE via `@suaveplan/oauth-client`.
- [ ] `src/components/oauth-provider-button/` (+ `.md`, `.test.tsx`, `.stories.tsx`).
## 10. MFA
- [ ] `src/hooks/use-enroll-totp/` (+ `.md`, `.test.ts`) — `begin` + `finish`.
- [ ] `src/hooks/use-verify-totp/` (+ `.md`, `.test.ts`).
- [ ] `src/hooks/use-enroll-webauthn-second-factor/` (+ `.md`, `.test.ts`) — wraps `register` with `authenticatorSelection.authenticatorAttachment`.
- [ ] `src/hooks/use-recovery-codes/` (+ `.md`, `.test.ts`) — `generate` + `verify`.
- [ ] `src/components/totp-enrollment-panel/` (+ `.md`, `.test.tsx`, `.stories.tsx`) — orchestrates secret display → caller-provided QR slot → code entry → recovery-codes reveal.
- [ ] `src/components/recovery-codes-panel/` (+ `.md`, `.test.tsx`, `.stories.tsx`) — copy / download / acknowledge before dismiss.
## 11. Verification flows
- [ ] `src/hooks/use-email-verification/` (+ `.md`, `.test.ts`).
- [ ] `src/hooks/use-phone-verification/` (+ `.md`, `.test.ts`).
- [ ] `src/components/email-verification-view/` (+ `.md`, `.test.tsx`, `.stories.tsx`) — resend cooldown timer.
- [ ] `src/components/phone-verification-view/` (+ `.md`, `.test.tsx`, `.stories.tsx`) — `inputMode="numeric"`, `autocomplete="one-time-code"`.
## 12. Guards
- [ ] `src/hooks/use-permission/` (+ `.md`, `.test.ts`).
- [ ] `src/hooks/use-auth-guard/` (+ `.md`, `.test.ts`).
- [ ] `src/components/auth-guard/` (+ `.md`, `.test.tsx`, `.stories.tsx`) — `withAuth` HOC alongside component.
- [ ] `src/components/permission-gate/` (+ `.md`, `.test.tsx`, `.stories.tsx`).
## 13. Error boundary
- [ ] `src/components/auth-error-boundary/` (+ `.md`, `.test.tsx`, `.stories.tsx`) — catches `SuaveplanError` whose code starts `REACT_AUTH.`; renders i18n-keyed fallback; re-throws everything else.
## 14. i18n
- [ ] `src/i18n/en-gb/index.ts` (+ `.md`) — canonical catalogue with every `react-auth.*` key used in the package.
- [ ] `src/i18n/cy-gb/index.ts` (+ `.md`) — full Welsh translation.
- [ ] `src/i18n/zh-cn/index.ts` (+ `.md`) — full Simplified Chinese translation.
- [ ] `src/i18n/parity.test.ts` — asserts every locale has the same key set as `en-GB`; fails CI on drift.
- [ ] `src/i18n/no-hardcoded-strings.test.ts` — scans `components/**/*.tsx` for hardcoded user-visible strings; allowlist limited to test fixtures.
## 15. Index + subpath exports
- [ ] `src/index.ts` — explicit named re-exports (rule 6a); namespace re-exports for `errors` and `schemas`.
- [ ] `package.json` `exports` map — one entry per subpath per `proposal.md`.
- [ ] Type-only re-exports separated via `export { type X }`.
## 16. Playwright E2E
- [ ] `e2e/fixtures/app.tsx` — minimal test app wiring an in-memory `AuthBackend`.
- [ ] `e2e/password-sign-in.spec.ts`, `sign-up.spec.ts`, `password-reset.spec.ts`, `change-password.spec.ts`.
- [ ] `e2e/passkey-register.spec.ts`, `passkey-autofill.spec.ts`, `passkey-modal-authenticate.spec.ts` (virtual-authenticator via Playwright CDP).
- [ ] `e2e/oauth-popup.spec.ts`, `oauth-redirect.spec.ts` — stubbed authorization endpoint.
- [ ] `e2e/totp-enroll-verify.spec.ts`, `recovery-codes.spec.ts`.
- [ ] `e2e/email-verification.spec.ts`, `phone-verification.spec.ts`.
- [ ] `e2e/multi-tab-sync.spec.ts` — two browser contexts share the same backend; sign-out in tab A propagates to tab B.
- [ ] `e2e/idle-timeout.spec.ts` — idle config fires `onTimeout` after configured ms; user is forced out.
- [ ] `e2e/error-boundary.spec.ts` — triggers a `BACKEND_ERROR`; verifies the boundary fallback renders.
- [ ] `e2e/rtl-locale.spec.ts` — renders with an RTL locale (e.g. `ar`) via the parent app; verifies `dir="rtl"` propagates.
- [ ] `e2e/accessibility.spec.ts` — `@axe-core/playwright` sweep across every canonical page; zero serious / critical violations.
## 17. Spec reconciliation (CLAUDE.md §13 step 0)
- [ ] Open `specs/react-auth/spec.md`. Walk every `### Requirement` and `#### Scenario`. For each `**Verified by:**` path, confirm the test file exists and the test name matches verbatim.
- [ ] Confirm every error code in `defineCodes("REACT_AUTH", …)` is reached from a real production path (not just a registry entry).
## 18. Pre-publish gates
- [ ] `bunx turbo lint typecheck test --filter=@suaveplan/react-auth` — green.
- [ ] `bunx turbo test:coverage --filter=@suaveplan/react-auth` — 100/100/100/100.
- [ ] `bunx turbo build --filter=@suaveplan/react-auth` — green.
- [ ] Banned-pattern scan zero (`@deprecated|TODO|FIXME|ts-ignore|ts-expect-error|\.skip|\.only|console\.log`).
- [ ] Barrel-shape scan zero (`export *` only in `src/index.ts` namespace forms).
- [ ] Test-runner import scan zero (`from "vitest"` / `from "bun:test"` outside the exempt allowlist).
- [ ] Missing-`.md` scan zero.
- [ ] Bare-version scan zero.
- [ ] Subpath export count matches feature-module count.
- [ ] React version check: `find . -path "*/node_modules/react/package.json"` returns a single version.
## 19. Root-doc refresh
- [ ] `bun scripts/folder-reorg/generate-manifest.ts` (refresh `MANIFEST.md`).
- [ ] `bun scripts/generate-missing.ts` (refresh `MISSING.yml`).
- [ ] Edit `STATUS.md` — move `@suaveplan/react-auth` from `–` to ✅; add summary paragraph.
- [ ] Edit `SUMMARY.md` — add per-package paragraph (features, deps, decisions).
- [ ] `bunx markdownlint-cli2 --fix` — touched files.
## 20. Supersede existing change folders
- [ ] `mv openspec/changes/enterprise-react-auth openspec/changes/_superseded-narrow-deferrals-2026-05-17/enterprise-react-auth` — fold under the existing supersede bucket.
## 21. Fold spec delta + archive
- [ ] Fold `specs/react-auth/spec.md` into `openspec/specs/react-auth/spec.md` (canonical home).
- [ ] `mv openspec/changes/complete-react-auth openspec/archive/<yyyy-mm-dd>-complete-react-auth/`.
- [ ] `bun scripts/publish.ts --package @suaveplan/react-auth`.