History

Org slugs: mint at insert, drop lazy minting, make the column NOT NULL

The org-slug column was nullable and the runtime self-healed it: every resolveOrganization (and the SSR gate) lazily minted a slug for any row that lacked one. That left a permanent nullable state and a heal-on-read cost. Move slug generation to the single moment a row is inserted — upsertOrganization mints the slug at INSERT (ON CONFLICT DO NOTHING absorbs the id/slug races, retrying with a fresh candidate) and keeps the existing slug on conflict. The three insert sites (createOrganization, acceptInvitation, the WorkOS-fallback upsert in resolveOrganization) all get a slug for free; resolveOrganization and the SSR gate's organizationDisplay no longer heal. The schema column is now NOT NULL (migration 0004), backfilled once for legacy rows. Deploy order matters and is documented in the backfill script: backfill → deploy this code → apply 0004. The old code inserts a NULL slug then heals, so NOT NULL cannot land while it still serves. Also adds e2e/cloud/auth-routing-flow.test.ts: one browser session walking the whole arc — signed out → /login → hosted-AuthKit sign-in → org-less onboarding → create org → canonical /<slug> dashboard — through the real dev-server SSR gate. The hops are covered piecewise elsewhere; this is the narrative regression guard and the only test pinning the bare-/ → /<slug>/ dashboard canonicalization a fresh login lands on.

Rhys Sullivan committed 5 months ago

Commit da0a4cc1 parent 1f9bfe013 files · +1429 −88Browse files

Showing the changes to apps/cloud/src/api (1 of 13 files). Show all

Unified · Split

apps/cloud/src/api/protected-api-key-auth.node.test.ts+1−6
@@ -50,7 +50,7 @@ const stubUsers = Layer.succeed(UserStoreService)({ · 49 unmodified lines
50 getAccount: async (id: string) => ({ id, createdAt }),50 getAccount: async (id: string) => ({ id, createdAt }),
51 upsertOrganization: async (org: { id: string; name: string }) => ({51 upsertOrganization: async (org: { id: string; name: string }) => ({
52 ...org,52 ...org,
53 slug: null,53 slug: `org-slug-${org.id}`,
54 createdAt,54 createdAt,
55 }),55 }),
56 getOrganization: async (id: string) => ({56 getOrganization: async (id: string) => ({
@@ -65,11 +65,6 @@ const stubUsers = Layer.succeed(UserStoreService)({ · 8 unmodified lines
65 slug,65 slug,
66 createdAt,66 createdAt,
67 }),67 }),
68 ensureOrganizationSlug: async (org: { id: string; name: string; slug: string | null }) => ({
69 ...org,
70 slug: org.slug ?? `org-slug-${org.id}`,
71 createdAt,
72 }),
73 }),68 }),
74 ),69 ),
75});70});

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t