Identity & Access
Who are you, and what are you allowed to do here?
Problem
Situation: Platform owner locked out of own dashboard. Infinite redirect loop — 789 errors in 30 minutes. Auth says "you're in." Authz says "no you're not." 80% built, 0% wired.
Intention: Multi-tenant SaaS where every user lands in the right org with the right permissions — no lockouts, no data leakage, no manual DB intervention.
Obstacle: PostgreSQL 22P02 — User-Role query passes Clerk userId (string) where systemUserId (UUID) expected. Roles table empty. Auto-provision creates user but assigns no role.
Hardest Thing: 80% of the infrastructure is built. The schema is right. The middleware is right. The adapter is right. But three wiring gaps make the whole system useless. The owner can't get into their own app.
Priorities
- Can the owner get in without touching the database?
- How many errors are we generating before revenue?
- What percentage of infrastructure is wired, not just built?
- Which ventures are waiting on this to ship?
- Who fixes, who commissions, who's locked out?
Proposal
Scorecard
Priority Score: 360 (Pain 5 x Demand 3 x Edge 2 x Trend 3 x Conversion 4) — full evidence
| # | Priority (should we?) | Preparedness (can we?) |
|---|---|---|
| 1 | Pain: 5 — owner locked out NOW | Principles: 5 — incident documented, root cause known |
| 2 | Demand: 3 — table stakes, every venture needs auth | Performance: 3 — MT checklist at 22%, target 80% |
| 3 | Edge: 2 — commodity infrastructure, 80% already built | Platform: 4 — Clerk + schema + middleware all exist |
| 4 | Trend: 3 — stable B2B market | Protocols: 3 — 5 tiers defined, not executed |
| 5 | Conversion: 4 — direct path to revenue (unblocks CRM) | Players: 5 — roles/permissions fully specified |
| Metric | Target | Now |
|---|---|---|
| Owner dashboard access | No manual DB | PASS — owner logs in, Admin role auto-assigned, all pages accessible |
| MT checklist pass rate | > 80% | ~40% (T0 pass, T1 partial, T2 partial — DB reset lost Editor/Viewer roles) |
| Downstream PRDs unblocked | 4 | 1 (Sales CRM unblocked — owner can access CRM data) |
Remaining blockers: Invitations page crashes. Only Admin role seeded (Editor/Viewer missing). ADMIN_EMAILS env var not verified. Previous 25 agent profiles lost — DB appears reset, auto-repair created 1 profile for owner. Kill date: 2026-03-24.
Kill signal: if invitations can't onboard a second user, multi-tenancy is untestable.
Blocks: Sales CRM, Sales Dev Agent, Agent Platform, Content Amplifier.
Build Order
| Tier | Effort | What | Acceptance |
|---|---|---|---|
| T0 | 1 day | Unblock owner — fix 22P02, break redirect, seed roles | Owner logs in without DB intervention |
| T1 | 1 day | Bootstrap admin — auto-provision, ADMIN_EMAILS, error pages | First user auto-gets Admin role |
| T2 | 3 days | Enforce RBAC — roles, canI() checks, org isolation | Role X cannot access resource Y |
| T3 | 3 days | Multi-org & invites — invite flow, org switcher, member mgmt | Invite → accept → membership works |
| T4 | 5 days | Billing & settings — Stripe, seat counting, org settings | Subscription lifecycle works |
| T5 | TBD | Hardening — security tests, audit trail, SSO | Negative security tests pass |
Total: ~13 days T0-T4. T5 is ongoing hardening.
Features
Tier 0: Unblock Owner (1 day)
- Fix User-Role query: use
systemUserIdnot ClerkuserId(22P02 crash) — PR #312: auto-repair integration spec - Break redirect loop: show error page, not infinite redirect — Commissioned 2026-02-27: inline AccessDenied, no redirect
- Set
ADMIN_EMAILSenv var in Vercel production — Not verified - Seed Admin/Member/Viewer roles in
org_roles— REGRESSION 2026-02-28: DB reset — now 1 role (Admin), 18 permissions. Editor/Viewer missing. Was 3 roles, 82 permissions on 2026-02-27. - Assign Admin role to owner in
governance_user_roles— Commissioned 2026-02-28: owner has Admin via auto-repair ("missing agent profile for existing user"), effective 2/28/2026 - Verify via browser commissioning (dream team, not builder) — Commissioned 2026-02-28: 10 pages verified, owner accesses dashboard + CRM + RFP + settings without access denied
Tier 1: Bootstrap Admin (1 day) — BLOCKING
- Auto-provision Admin role to first user in org on first login — Commissioned 2026-02-28: auto-repair mechanism works — created agent profile + assigned Admin on login
- Check
ADMIN_EMAILSduring provision — if match, assign Admin — Not verified - Show meaningful error when
admin_access_required(not redirect) — Commissioned 2026-02-27: "You don't have permission to read contact" inline - Add admin status indicator to user profile/settings — Commissioned 2026-02-28: Settings overview shows Org "Dreamineering", Role "Admin"
- Verify auto-provision is transactional (rollback on failure) — Not verified
Tier 2: Enforce RBAC (3 days) — PASS
- Define three roles with permissions: Admin (full), Member (CRUD), Viewer (read) — REGRESSION 2026-02-28: only Admin role exists (18 permissions). Editor/Viewer not seeded after DB reset.
- Switch
defaultAllow: falsein PolicyEngine — Commissioned 2026-02-27: no-role user denied CRM access - Add
canI()checks to all server actions — PR #312: marketing + workflow actions gated. RFP not yet gated. - Route-level permission guards in layout components — Commissioned 2026-02-27: inline AccessDenied, no redirect
- Base repository enforces
organisationIdon every query — Not verified (needs code audit) - Integration tests: role X cannot access resource Y — PR #312: workflow-orchestration + marketing integration specs
- Cross-tenant isolation test: org1 user cannot see org2 data — Not verified (single org)
Tier 3: Multi-Org & Invites (3 days) — UI PASS, flow not exercised
- Invite-by-email flow (admin settings) — REGRESSION 2026-02-28: /settings/governance/invitations returns error page. Was working 2026-02-27.
- Pending invite → accepted → membership with role — PR #312: schema + actions + /invite/[token] acceptance page
- Org switcher for multi-org users — Commissioned 2026-02-27: "Personal Workspace" in header (single org, no dropdown needed)
- Org creation flow — Not verified
- Member management (view, remove, change role) — Commissioned 2026-02-28: UserRolesTable renders with 1 assignment (auto-repaired owner). Was 25 assignments on 2026-02-27 — DB reset.
- Sync Clerk orgs with internal orgs (webhook) — Not verified
- Database-level RLS policies (defense-in-depth) — Not verified
Tier 4: Billing & Settings (5 days)
- Wire
stripeCustomerIdto org - Seat counting from memberships
- Subscription lifecycle (create, upgrade, cancel)
- Org-level settings page
- Per-user-per-org settings on
agent_profile - Analytics events include
organisationId - Org-scoped activity dashboard
Tier 5: Hardening
- Negative security tests per endpoint
- Fail-closed on missing org context
- Audit trail UI — Commissioned 2026-02-28: /settings/governance/audit renders with 7-column table, Allowed/Denied filter, 0 entries
- Soft-delete consistency audit
- Document enforcement approach in tech decisions
- Parent/child orgs (enterprise)
- SSO/SAML per org via Clerk