Organization-scoped role-based access control
0003. Organization-scoped role-based access control
Section titled “0003. Organization-scoped role-based access control”- Status: accepted
- Date: 2026-07-21
- Deciders: FRAME maintainers
Context
Section titled “Context”FRAME has two authorization scopes. A global user role controls access to platform administration, while organization membership roles control tenant data and organization management. Relying on route visibility or controller guards alone would allow authorization rules and tenant isolation to drift between Next.js, NestJS, and PostgreSQL.
Decision
Section titled “Decision”Use packages/auth/src/permissions.ts as the canonical organization permission vocabulary. Better Auth evaluates the same access-control definition on the client and server. NestJS remains the enforcement authority for product APIs, and every tenant-owned repository operation also filters by the active organizationId. PostgreSQL constraints prevent relationships between records from different organizations.
The global user.role = 'admin' role is independent from an organization member role. It grants access to /admin; it does not implicitly grant access to an organization’s data.
Standard organization roles
Section titled “Standard organization roles”| Resource | Owner | Admin | Member |
|---|---|---|---|
| Organization | Update, delete | Update | None |
| Members | Create, update, delete | Create, update, delete | None |
| Invitations | Create, cancel | Create, cancel | None |
| Cats | Create, read, update, delete | Create, read, update, delete | Read |
| Owners | Create, read, update, delete | Create, read, update, delete | Read |
Better Auth dynamic organization roles may add permissions. NestJS resolves those stored role definitions after evaluating the standard roles.
Consequences
Section titled “Consequences”- Positive: Permission names, standard roles, UI visibility, and API enforcement share one typed contract.
- Positive: Tenant isolation remains effective even if a controller is wired incorrectly because repository queries and database relationships are organization-scoped.
- Positive: Dynamic roles can extend permissions without changing controller code.
- Negative / trade-offs: Adding a tenant resource requires coordinated auth, API, persistence, migration, UI, and test changes.
- Negative / trade-offs: UI permission checks are asynchronous and may briefly hide actions while the active organization is resolved.
- Follow-ups: Add cross-tenant integration coverage when the organization test-data harness supports isolated memberships.
- Auth architecture: Authorization architecture
- Nest authorization: Nest authorization
- Models architecture: Models architecture
- Related skills / AGENTS:
.agents/skills/auth-security/SKILL.md,apps/nest/.agents/skills/frame-nest/SKILL.md,packages/models/.agents/skills/postgres-drizzle/SKILL.md