Security and privacy architecture

Personal finance data is sensitive, so authentication, authorization, billing state, AI access, and API abuse controls are treated as product functionality.

Server-first auth boundary

Protected routes verify the Supabase session before rendering private dashboard UI.

RLS ownership model

Profiles, households, and memberships are scoped to the authenticated user and household roles.

Secret separation

Client code uses only the public Supabase URL and anon key. Service role credentials remain server-only.

Server-owned billing state

Stripe webhooks verify signatures before customer and subscription state is written through a server-only Supabase client.

Guarded AI endpoints

AI routes require authentication, plan access, usage tracking, rate limits, minimized finance summaries, and structured output validation.

Abuse-resistant mutations

Sensitive API routes reject cross-origin mutations, enforce request limits, and validate identifiers against the authenticated household.

Security questions

Clear boundaries for sensitive operations.

Can browser code access the Supabase service-role key?

No. The service-role key is read only by server code and is not exposed through public environment variables.

Can a user select another household in an API request?

Private routes resolve the authenticated user and household on the server. They do not trust a client-provided household or billing plan.

How are Stripe webhooks protected?

The webhook route verifies Stripe's signature against the raw request body, rejects oversized payloads, and records processed event IDs for idempotency.