Skip to main content

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

  1. Can the owner get in without touching the database?
  2. How many errors are we generating before revenue?
  3. What percentage of infrastructure is wired, not just built?
  4. Which ventures are waiting on this to ship?
  5. 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?)
1Pain: 5 — owner locked out NOWPrinciples: 5 — incident documented, root cause known
2Demand: 3 — table stakes, every venture needs authPerformance: 3 — MT checklist at 22%, target 80%
3Edge: 2 — commodity infrastructure, 80% already builtPlatform: 4 — Clerk + schema + middleware all exist
4Trend: 3 — stable B2B marketProtocols: 3 — 5 tiers defined, not executed
5Conversion: 4 — direct path to revenue (unblocks CRM)Players: 5 — roles/permissions fully specified
MetricTargetNow
Owner dashboard accessNo manual DBPASS — 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 unblocked41 (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

TierEffortWhatAcceptance
T01 dayUnblock owner — fix 22P02, break redirect, seed rolesOwner logs in without DB intervention
T11 dayBootstrap admin — auto-provision, ADMIN_EMAILS, error pagesFirst user auto-gets Admin role
T23 daysEnforce RBAC — roles, canI() checks, org isolationRole X cannot access resource Y
T33 daysMulti-org & invites — invite flow, org switcher, member mgmtInvite → accept → membership works
T45 daysBilling & settings — Stripe, seat counting, org settingsSubscription lifecycle works
T5TBDHardening — security tests, audit trail, SSONegative security tests pass

Total: ~13 days T0-T4. T5 is ongoing hardening.

Features

Tier 0: Unblock Owner (1 day)

  • Fix User-Role query: use systemUserId not Clerk userId (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_EMAILS env var in Vercel production — Not verified
  • Seed Admin/Member/Viewer roles in org_rolesREGRESSION 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_rolesCommissioned 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_EMAILS during 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: false in 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 organisationId on 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 stripeCustomerId to 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

Context