Analysis: New User Creation / Test Org Auto-Provisioning Issue
Branch: 260505 / 260506
Date: 2026-05-06
Status: Resolved — userModel rolled back; user management is fully delegated to Clerk
Resolution
The userModel created commit (b5526513) introduced a MongoDB users embedded array on the Organization document and a separate User model, intended to mirror Clerk membership in MongoDB. This caused several problems:
- New Clerk users had no corresponding MongoDB User record →
getUserIdByEmailalways returnednull→org.userswas always empty - The admin reconciliation logic in
organizationUpdate.jsdepended onorg.usersto enforce Clerk role parity for test orgs - The CSV import/export format changed in a breaking way (
admins→userswith ObjectId format)
Decision: The userModel approach was rolled back entirely. User management — including roles (org:admin / org:member) and membership — is delegated fully to Clerk. MongoDB stores no parallel user or admin data.
Original Problem Statement
When a new user signed up in Clerk:
- DEV: "organization reference inconsistencies" (no test org was provisioned)
- PROD: A Clerk-native "organization setup modal" appeared, asking the user to create an org manually
Previously the user.created Clerk webhook automatically created a test-NNNN org and redirected the user to it.
Root Cause
Problem 1: Empty org.users for all new Clerk users
getUserIdByEmail(adminEmail) queried a MongoDB User collection that had no records for Clerk-managed users. New signups never had a User document, so org.users was always [].
Problem 2: PROD "organization setup modal"
Two likely causes:
- Clerk dashboard has "Force organization selection" or "Create organization after sign-up" enabled. Since the
user.createdwebhook fires asynchronously, there is a race window where the user has no active org and Clerk shows its native create-org UI. afterSignUpUrlwas not set inClerkProvider, so Clerk fell back to its dashboard-configured redirect.
Problem 3: DEV webhooks don't reach localhost
Clerk cannot deliver webhooks to localhost:3000 without a tunnel (ngrok, Clerk dev proxy, etc.). Without the webhook, no test org is created and newTenantSlug is never written.
Architecture (Current, Post-Rollback)
User roles and membership are managed entirely by Clerk:
getOrgMembership(shortName)insrc/lib/auth/requireOrgAccess.jscalls the Clerk backend API to verify membership- The
organization.updatedwebhook handles logo sync, slug rollback, and test-org name/logo lock — no admin reconciliation - The MongoDB
Organizationdocument has nousers,admins, or role fields
For the PROD modal and DEV webhook issues, see the recommendations below.
Remaining Recommendations
Prevent Clerk's "force org" modal in PROD
Add afterSignUpUrl to ClerkProvider in src/app/[locale]/layout.jsx:
<ClerkProvider
afterSignUpUrl="/"
afterSignOutUrl={`/${locale}/event/sign-out`}
...
>
Also verify in the Clerk PROD dashboard:
- "Force users to select an organization" → OFF
- "After sign-up, redirect to" → must NOT point to
/create-organization
DEV webhook delivery
Use Clerk's local dev proxy or ngrok to forward webhooks to localhost:
# Clerk CLI
clerk proxy http://localhost:3000
# or
ngrok http 3000 # then update Clerk webhook endpoint