# Organizations are the tenant

The repository's architectural decision, rationale and consequences.

# Organizations are the tenant

The template is a SaaS starter on one Neon database. Several people need to share todos and files without seeing each other's work.

We use Better Auth's organization plugin (`organization` / `member` / `invitation` + `session.activeOrganizationId`) instead of a custom tenant table. Shared schema, row-level `organizationId`. Teams and dynamic org roles stay off.

We already generated these tables once and dropped them as unused (`20260825200958`). This time the plugin is wired, domain tables are scoped, and signup creates a personal Organization.

Platform admin (`user.role`) stays global. Org roles do not grant `/admin`.

Files live on Cloudflare R2. The Worker credential is one bucket
(`STORAGE_BUCKET`). Isolation is the server-enforced prefix
`orgs/<organizationId>/` plus a membership check (`getActiveMember` reads
`member`; the 5-minute cookie cache is not authorization). The client cannot
supply or escape the prefix. Never fall back to `users/<userId>/`.
Minting a bucket per Organization would 500 with a bucket-scoped R2 token.
Neon stays one shared database with row-level `organizationId`.

