ADR-0021: Clerk Organization Model — Shared App Now, Separate Apps Later¶
Status: Accepted Date: 2026-04-24 Session: 70
Context¶
Curaway has 7 actor types (patients, providers, coordinators, MSO doctors, facilitators, platform admins, super admins) accessing 5 different portal apps. Each needs authentication and tenant-scoped authorization.
Clerk supports two models: - One Clerk app + Organizations — all users in one pool, grouped by org with roles - Separate Clerk apps — one app per portal, fully isolated user pools
Decision¶
Phase 1 (Now): One Clerk App + Organizations¶
Use a single Clerk application with Clerk Organizations for multi-tenancy.
| Curaway Concept | Clerk Concept |
|---|---|
| Hospital/clinic tenant | Clerk Organization |
| Actor type (provider/coordinator/MSO) | Organization role |
| Patient | User (no org, personal context) |
| Super admin (SD) | User in multiple orgs with admin role |
| New hospital onboarding | Create new Clerk Organization via API |
Org roles defined in Clerk:
- org:provider:admin — hospital admin, manages staff
- org:provider:staff — hospital staff, views cases
- org:coordinator — Curaway ops staff
- org:mso:doctor — second-opinion doctor
- org:facilitator — external agent
- org:admin — platform admin
Why now:
- Single Clerk dashboard for all user management
- Users can belong to multiple orgs (SD is coordinator + admin)
- One publishable key shared across all portal apps
- No additional Clerk cost (orgs included in plan)
- Fastest path to working auth across all portals
- Clerk's <OrganizationSwitcher> component handles multi-org UX
Phase 2 (Later): Separate Clerk Apps Per Stakeholder¶
When the platform scales and requires full isolation, migrate to separate Clerk apps:
| Portal | Clerk App | Domain | When |
|---|---|---|---|
| Patient | Clerk App 1 | app.curaway.ai | Current |
| Provider | Clerk App 2 | provider.curaway.ai | Post-Series A |
| Coordinator | Clerk App 3 | ops.curaway.ai | Post-Series A |
| MSO | Clerk App 4 | mso.curaway.ai | Post-Series A |
| Admin | Clerk App 5 | admin.curaway.ai | Post-Series A |
Why later: - Full isolation: provider users physically cannot access coordinator auth - Separate branding per portal (different logos, colors, SSO providers) - Separate rate limits and security policies - Independent scaling and billing - Compliance: some providers may require their own identity provider
Migration path:
1. Export users from shared Clerk app
2. Create per-portal Clerk apps
3. Import users to appropriate apps
4. Update env vars per portal deployment
5. Backend maps clerk_app_id + clerk_user_id → Curaway user (instead of just clerk_user_id)
Trigger for Phase 2: - Provider requests SSO integration with their own IdP - Compliance requirement for isolated identity stores - Scale beyond 50 organizations in single Clerk app - Different auth requirements per portal (e.g., MFA mandatory for MSO, optional for facilitators)
Consequences¶
Positive (Phase 1): - Single point of user management - Fast implementation (1 publishable key for all portals) - SD can switch between orgs without separate logins - Clerk handles role management, org invites, member lists
Negative (Phase 1): - All portals share auth boundary — a provider could visit coordinator URL (RBAC blocks access, but the Clerk sign-in page is shared) - If Clerk app is compromised, all portals are affected - Clerk org limits may apply at high scale
Positive (Phase 2 migration):
- Clean separation is possible because backend already uses tenant_id + clerk_org_id — the mapping layer is abstracted
- Patient app already runs its own Clerk app — the pattern exists
Risk: - Phase 2 migration requires downtime or dual-auth period - User accounts need re-creation or import in new Clerk apps - Must maintain backward compatibility in backend JWT validation
References¶
- ADR-0018: Multi-tenancy platform architecture
- Clerk Organizations docs: https://clerk.com/docs/organizations
- Current patient-app Clerk setup:
apps/patient-app/src/App.tsx - RBAC middleware:
app/middleware/rbac_middleware.py