Production Safety
RLS, grants, webhook idempotency, cron auth, outbox workers, request ids, and retention jobs are the production guardrails to preserve.
On this page
Production safety source map
Database security baseline
The baseline migration owns grants, RLS enablement, policies, RPC functions, and service-role privileges for the Supabase schema.
supabase/migrations/20260426000000_init.sql
Webhook request guard
Webhook utilities centralize rate limiting, raw body reading, payload size limits, structured logging, and request id context.
src/lib/security/webhooks/request.tssrc/lib/security/webhooks/processing.ts
Cron guard
Cron services reject missing or placeholder secrets, compare authorization safely, rate-limit scheduler calls, and log job outcomes.
src/lib/security/cron-secret.tssrc/features/notifications/server/outbox/services/cron.ts
Outbox and retention operations
Background workers claim batches, retry safely, dead-letter exhausted work, and run retention cleanup behind protected cron routes.
src/features/notifications/server/outbox/services/worker.tssrc/features/compliance/server/retention/service.ts
Supabase server boundaries
Server helpers keep user-scoped Supabase access separate from service-role work and preserve request id propagation.
src/lib/supabase/server.tssrc/lib/supabase/proxy.ts
Production safety flow
- 1
Define durable database invariants
Create tables, constraints, grants, RLS policies, RPC functions, and service-role access in migrations instead of relying on runtime assumptions.
supabase/migrations/20260426000000_init.sql
- 2
Preserve request context
API and webhook routes carry request ids through logs so failures can be traced across rate limits, provider calls, database writes, and jobs.
src/lib/security/webhooks/request.tssrc/lib/supabase/proxy.ts
- 3
Claim before processing external events
Webhook handlers verify signatures, store event rows, reject duplicate processed events, and reclaim only stale processing leases.
src/lib/security/webhooks/request.tssrc/lib/security/webhooks/processing.ts
- 4
Protect scheduled work
Cron services validate CRON_SECRET, reject placeholder values, compare authorization without leaking timing, and rate-limit scheduler calls.
src/lib/security/cron-secret.tssrc/features/notifications/server/outbox/services/cron.ts
- 5
Retry through outbox state
Workers claim a bounded batch, record success or failure, back off transient errors, and dead-letter rows after repeated failures.
src/features/notifications/server/outbox/services/worker.ts
Cron secrets fail closed
Source: src/lib/security/cron-secret.ts
A configured but obvious placeholder secret is treated the same as a missing secret.
export function readValidatedCronSecret(value: string | undefined = process.env.CRON_SECRET): string | null {
const secret = value?.trim();
if (!secret) {
return null;
}
if (PLACEHOLDER_CRON_SECRETS.has(secret.toLowerCase())) {
return null;
}
return secret;
}Webhook stale lease
Source: src/lib/security/webhooks/processing.ts
A processing row can be retried only after the lease timeout, which protects against duplicate live workers and crashed workers.
const WEBHOOK_PROCESSING_STALE_AFTER_MS = 15 * 60 * 1000;
export function isWebhookProcessingStale(
processingStartedAt: string | null | undefined,
nowMs: number = Date.now(),
staleAfterMs: number = WEBHOOK_PROCESSING_STALE_AFTER_MS,
): boolean {
if (!processingStartedAt) {
return true;
}
const startedAtMs = Date.parse(processingStartedAt);
if (!Number.isFinite(startedAtMs)) {
return true;
}
return nowMs - startedAtMs >= staleAfterMs;
}Recipe: add a production-safe table
Add a Supabase table that works in production without accidental public access, broken generated types, or missing operational docs.
Inspect
- supabase/migrations/20260426000000_init.sql
- src/lib/supabase/server.ts
- src/lib/supabase/proxy.ts
Edit
- supabase/migrations/<timestamp>_<change>.sql
- src/lib/supabase/types.ts
- src/features/<domain>/server/persistence/<table>.ts
Steps
- Create the table, indexes, foreign keys, and durable constraints in a migration.
- Enable RLS and write policies before exposing user-scoped reads or writes.
- Grant only the roles that need access, and keep service-role writes server-only.
- Regenerate Supabase types and route all access through feature-owned persistence helpers.
- Document any env vars, cron routes, webhooks, or retention behavior introduced by the table.
Verify
- pnpm run contract:migrations
- pnpm run supabase:types
- pnpm run test:features
- pnpm run quality
Common mistakes
- Do not add a table without RLS decisions.
- Do not put service-role reads in client-reachable code.
- Do not skip generated type refresh after schema changes.
AI prompt: production safety review
Review this change for production safety. Inspect migrations, RLS, grants, webhook/event idempotency, cron authentication, outbox retry behavior, request id logging, generated Supabase types, tests, and deployment checklist impact. Fail closed on auth, billing, admin, webhook, and cron boundaries.Inspect first
- supabase/migrations/20260426000000_init.sql
- src/lib/security/webhooks/request.ts
- src/lib/security/cron-secret.ts
Verify
- pnpm run contract:migrations
- pnpm run test:features
- pnpm run quality