Problem
A user or team can claim control, delivery, observe, signup, oauth, storage, forgot-password or reset-password as their slug. control is the default landing page for every scope (app/(dashboard)/[scope]/page.tsx:12 redirects there), so a collision makes one of the two surfaces unreachable.
Root cause: lib/dashboard-rescue.ts:8-20 is a hand-maintained list of the dashboard route segments, and lib/reserved-slugs.ts:15 spreads that list into RESERVED. The filesystem has 15 segments under app/(dashboard)/[scope]/; the list has 12. The top-level app/ directories were never added at all.
Where
lib/dashboard-rescue.ts:8-20 (DASHBOARD_SCOPED_FIRST_SEGMENTS)
lib/reserved-slugs.ts:15-56 (RESERVED)
- Route directories:
ls app/\(dashboard\)/\[scope\]/ and ls app/
Fix
- Add the three missing dashboard segments to
DASHBOARD_SCOPED_FIRST_SEGMENTS.
- Add the five missing top-level routes to
RESERVED.
- Write a unit test that reads the two directories from disk at test time and asserts every directory name that is not a route group (
(...)) or dynamic segment ([...]) is present in RESERVED. This is the guard that stops the list drifting again.
Exit criteria
Out of scope
Mirroring the list into the database function is_reserved_slug(). The comment at lib/reserved-slugs.ts:10-14 already records that as a separate migration. Open a follow-up issue if you want to take it.
https://claude.ai/code/session_01SQ4nS96XYRztd5w9QkubPf
Problem
A user or team can claim
control,delivery,observe,signup,oauth,storage,forgot-passwordorreset-passwordas their slug.controlis the default landing page for every scope (app/(dashboard)/[scope]/page.tsx:12redirects there), so a collision makes one of the two surfaces unreachable.Root cause:
lib/dashboard-rescue.ts:8-20is a hand-maintained list of the dashboard route segments, andlib/reserved-slugs.ts:15spreads that list intoRESERVED. The filesystem has 15 segments underapp/(dashboard)/[scope]/; the list has 12. The top-levelapp/directories were never added at all.Where
lib/dashboard-rescue.ts:8-20(DASHBOARD_SCOPED_FIRST_SEGMENTS)lib/reserved-slugs.ts:15-56(RESERVED)ls app/\(dashboard\)/\[scope\]/andls app/Fix
DASHBOARD_SCOPED_FIRST_SEGMENTS.RESERVED.(...)) or dynamic segment ([...]) is present inRESERVED. This is the guard that stops the list drifting again.Exit criteria
tests/unit/reserved-slugs.test.ts(or extends the existing reserved-slug test), fails onmain, passes after.isReservedSlug("control")andisReservedSlug("signup")return true (add both as explicit cases).control(manual check on preview, or an e2e case in the existing team-settings spec).pnpm lint,pnpm typecheck,pnpm test:unitpass.Out of scope
Mirroring the list into the database function
is_reserved_slug(). The comment atlib/reserved-slugs.ts:10-14already records that as a separate migration. Open a follow-up issue if you want to take it.https://claude.ai/code/session_01SQ4nS96XYRztd5w9QkubPf