URL: https://mkdocs.justinsforge.com/memory/general/reference_creatortrack_handles/
CreatorTrack Public Handle Namespace¶
Status: DEPLOYED to prod 2026-07-14 (merge bd7ac71). See [[reference_creatortrack_scheduling]] for the module it serves.
Model¶
core.handles: one ACTIVE handle per workspace (claim/change in Settings > Profile). Changing never recycles: old row keeps itsreleased_atstamp. Uniqueness is a PARTIAL index (WHERE released_at IS NULL) so released handles are reclaimable. citext, regex^[a-z0-9][a-z0-9-]{1,28}[a-z0-9]$(TS + DB CHECK agree vialib/handles-reserved.ts).core.handle_slugs: ONE typed slug table per handle,UNIQUE(handle_id, slug), kindbio_page|booking_link|shop, softtarget_idpointer. Bio pages / booking links / future shop can therefore never collide on a URL.workspace_iddenormalized for RLS (core.apply_workspace_rlschild-table pattern).- Resolution:
resolveHandleSlug(handle, slug)inlib/handles.ts, service-identity read scoped only by the two URL strings.
Reserved words (HANDLE level only, nothing reserved inside a handle)¶
lib/handles-reserved.ts RESERVED_HANDLES = auth/marketing/service paths PLUS every top-level app route segment (tasks, dashboard, profile, sales...). Two load-bearing reasons: Next static routes beat the dynamic [handle]/[slug] match (a handle named "tasks" would be permanently shadowed), and proxy.ts must keep 308ing apex deep links like creatortrack.ai/tasks/123 to the app host (host-pinned auth/PKCE). KEEP IN SYNC when adding a top-level route dir. Separately RESERVED_BOOKING_SLUGS blocks slugs matching (suite)/[ws] sub-route names.
Proxy routing (proxy.ts)¶
isHandleCandidate(path): EXACTLY two segments, first matches handle regex and is not reserved, path not in PUBLIC_PATHS//api/. Candidates pass through (apex host: served in place instead of 308; session-less: no login redirect). Single-segment paths keep every pre-existing behavior. The module is DB-import-free so the proxy can load it.