Files
suaveplan/openspec/changes/_superseded-narrow-deferrals-2026-05-17/enterprise-react-auth/tasks.md
2026-05-27 23:29:53 +01:00

3.4 KiB

Tasks: enterprise-react-auth

Change ID: enterprise-react-auth Package: @suaveplan/react-auth Target path: react/auth/react-auth Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/types, @suaveplan/events, @suaveplan/oauth-client, @suaveplan/react-translate


1. Scaffold

  • Create directory tree per proposal layout.
  • Write package.json at 0.1.0 with "sideEffects": false, exports map.
  • Dependencies: @suaveplan/error workspace:^, @suaveplan/types workspace:^, @suaveplan/events workspace:^, @suaveplan/oauth-client workspace:^, @suaveplan/react-translate workspace:^, zod catalog:forms, @opentelemetry/api catalog:observability, tslib catalog:build.
  • Write tsconfig.json, vitest.config.ts, scripts.

2. Error codes and types

  • Define AuthError extending SuaveplanError; codes: AUTH_UNAUTHENTICATED, AUTH_TOKEN_EXPIRED, AUTH_REFRESH_FAILED, AUTH_CONTEXT_MISSING.
  • Define AuthUser, AuthState, AuthConfig, AuthContextValue, AuthProviderProps, AuthGuardProps, SignInOptions, SignOutOptions.
  • Write AuthConfigSchema Zod schema.

3. Token utilities

  • src/utils/token-storage/ — createTokenStorage(adapter: 'memory' | 'localStorage' | 'sessionStorage'): setTokens(tokens), getTokens(), clearTokens().
  • src/utils/session-persistence/ — saveSession(user), loadSession(): AuthUser | null, clearSession().
  • Write tests + md for each.

4. AuthContext + AuthProvider

  • State: user: AuthUser | null, isLoading, isAuthenticated.
  • signIn(options: SignInOptions) — calls @suaveplan/oauth-client authorization + token exchange; stores tokens; emits @suaveplan/events auth:signed_in. OTel auth.sign_in span.
  • signOut(options?) — clears tokens + session; emits auth:signed_out. OTel auth.sign_out span.
  • refreshToken() — calls @suaveplan/oauth-client token refresh; on failure throws AuthError(AUTH_REFRESH_FAILED). OTel auth.token_refresh span.
  • Auto-refresh: installs a timer to refresh before expiry.
  • useAuth() throws AuthError(AUTH_CONTEXT_MISSING) outside provider.
  • Write auth-context.test.tsx (≤500 lines): sign-in, sign-out, refresh, auto-refresh timer, context missing. { timeout: 10000 }.
  • Write auth-context.md.

5. Hooks

  • useUser(): AuthUser | null — from context.
  • useIsAuthenticated(): boolean.
  • useAuthToken(): string | null — current access token.
  • Write tests + md for each.

6. AuthGuard + withAuth

  • AuthGuard — renders children when authenticated; calls onUnauthenticated (default: throws AuthError(AUTH_UNAUTHENTICATED)) when not.
  • withAuth(Component) — HOC wrapping AuthGuard.
  • Write tests, stories (authenticated, unauthenticated-redirect, loading), md.

7. E2E

  • e2e/auth.spec.ts — Playwright with injected mock @suaveplan/oauth-client:
    • Render AuthGuard while unauthenticated → onUnauthenticated fires.
    • Call signIn() → user set in context → AuthGuard renders children.
    • Call signOut() → user cleared.

8. Verify and publish

  • bunx turbo lint typecheck test --filter=@suaveplan/react-auth — green.
  • bunx turbo test:coverage --filter=@suaveplan/react-auth — 100%.
  • bun scripts/publish.ts --package @suaveplan/react-auth.
  • Archive change folder.