Skip to content

Latest commit

 

History

History
38 lines (26 loc) · 1.75 KB

File metadata and controls

38 lines (26 loc) · 1.75 KB

apps/backend — NestJS

A standard Nest module layout (words, user, auth, supabase, config, common). Details and environment variables are in apps/backend/README.md.

Supabase and RLS

SupabaseService is the only place clients are created:

  • getAuthClient() — verifies tokens;
  • getClientForUser(token) — returns an RLS-scoped client for the caller.

There is deliberately no service-role key. A service-role client would bypass RLS on every request.

Auth is a global AuthGuard (opt out with @Public()) that attaches { id, email, accessToken }, read in handlers via @CurrentUser().

No Scope.REQUEST, no auth in provider factories

Keep the provider graph free of Scope.REQUEST, and never authenticate inside a provider factory. A request-scoped Supabase client used to throw UnauthorizedException from its factory; because Nest resolves request-scoped providers before guards run, that throw short-circuited the guard chain and the global ThrottlerGuard never executed on protected routes. The 401 looked correct, so nothing surfaced it. Covered by apps/backend/test/rate-limit.e2e.test.ts.

Env validation

Environment is validated at startup (src/config/env.validation.ts): missing vars exit the process with a readable message instead of failing on the first request.

Generated types and contract

  • generate-types (in apps/backend) regenerates database.types.ts and copies it into packages/api. Do not edit those files (they are eslint-ignored, so lint:fix cannot reformat them).
  • The API contract is generated separately — see api-contract.md.
  • Backend lint is check-only; use lint:fix to autofix (same split as every other package).