Files
multica/server/migrations/049_audit_legacy_reserved_slugs.up.sql
devv-eve c0be1b7ce9 fix(slugs): audit admin/multica/new/www + reserve in slug list (MUL-972) (#1359)
Follow-up to PR #1188 / migration 047, which intentionally omitted the
five historical conflict slugs (admin / multica / new / setup / www) from
the reserved-slug audit because each had one production workspace using
it at the time and we did not want to block deploy on owner outreach.

MUL-972 closed that loop on prd for four of the five:

  * admin   (99cd10e4-…) → renamed to legacy-admin-99cd10e4
  * multica (dcd796aa-…) → renamed to legacy-multica-dcd796aa
  * new     (e391e3ed-…) → renamed to legacy-new-e391e3ed
  * www     (5e8d38b2-…) → workspace deleted (was empty: 0 issues /
                           projects / agents, owner-only member; 18
                           workspace-FK relations all CASCADE)

This PR:

1. Adds migration 049_audit_legacy_reserved_slugs which audits those
   four slugs against workspace.slug at startup. If any future workspace
   slips in with one of them, startup fails loudly via RAISE EXCEPTION
   instead of being silently shadowed by a global route. Mirrors the
   structure of 047.

2. Adds 'multica' / 'www' / 'new' to the reserved-slug allow-deny list
   in both the Go handler and the shared TS list (admin was already in
   both). Keeps the two lists in lockstep per the convention enforced
   in workspace_reserved_slugs.go header.

setup is STILL exempt from the audit and is intentionally NOT added to
the reserved list. The setup workspace (b43f0bc2-…) is a real production
user (owner: Roberto Betancourth, building a chants/Alabanzas app) and
is being handled out-of-band via owner outreach. A separate follow-up
migration will fold setup into the audit once that workspace's slug has
been migrated.

Migration is intentionally shipped AFTER the prd data fix (not before):
049 will RAISE EXCEPTION on any remaining conflict, so we want the data
state clean first. Rollout order:
  prd data fix (done by db-boy on 2026-04-20) → this PR.

Tested:
  - go test ./server/internal/handler/ -run TestReserved → pass
  - pnpm --filter @multica/core test consistency → pass (4/4 in
    consistency.test.ts; global-prefix↔reserved invariant holds)

Co-authored-by: Devv <devv@Devvs-Mac-mini.local>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-19 23:21:31 -07:00

49 lines
1.9 KiB
SQL

-- Audit `admin`, `multica`, `new`, `www` against the workspace.slug column.
--
-- Follow-up to migration 047 (extended reserved slugs). 047 intentionally
-- omitted these four slugs from its audit because each had one conflicting
-- workspace in production at the time, and blocking deploy on owner outreach
-- was deemed unacceptable. MUL-972 closed that loop on prd:
--
-- * `admin` (99cd10e4-…) → renamed to `legacy-admin-99cd10e4`
-- * `multica` (dcd796aa-…) → renamed to `legacy-multica-dcd796aa`
-- * `new` (e391e3ed-…) → renamed to `legacy-new-e391e3ed`
-- * `www` (5e8d38b2-…) → workspace deleted (was empty: 0 issues /
-- projects / agents, owner-only member)
--
-- With the prd data clean, this migration promotes those four slugs into the
-- audit set so any future workspace that slips in with one of them fails
-- startup loudly instead of being silently shadowed by a global route.
--
-- `setup` is STILL omitted from this audit. The `setup` workspace
-- (b43f0bc2-…) is a real production user (Roberto Betancourth, building a
-- chants/Alabanzas app) and is being handled out-of-band via owner outreach
-- to negotiate a rename. A separate follow-up migration will fold `setup`
-- into the audit once that workspace's slug has been migrated.
--
-- Keep this slug list aligned with:
-- - server/internal/handler/workspace_reserved_slugs.go
-- - packages/core/paths/reserved-slugs.ts
DO $$
DECLARE
conflict_count INT;
conflict_list TEXT;
BEGIN
SELECT
COUNT(*),
string_agg(slug, ', ' ORDER BY slug)
INTO conflict_count, conflict_list
FROM workspace
WHERE slug IN (
'admin',
'multica',
'new',
'www'
);
IF conflict_count > 0 THEN
RAISE EXCEPTION 'Found % workspace(s) with slugs that collide with the legacy reserved-slug audit set: %. Rename or delete before deploying (see MUL-972 for the playbook).', conflict_count, conflict_list;
END IF;
END $$;