-- Backfill the new `documents.edit` and `files.edit` permission keys on -- every existing row in `roles.permissions`. The schema (RolePermissions -- in src/lib/db/schema/users.ts) added these keys to close the silent-403 -- traps on PATCH /api/v1/documents/[id], /cancel, /remind, /watchers, and -- PATCH /api/v1/files/[id] — each used a permission key that did not exist -- in the schema, so withPermission()'s `resourcePerms[action]` returned -- undefined and 403'd every non-superadmin call. -- -- Backfill rule: -- documents.edit ← documents.create (anyone who can create can edit) -- files.edit ← files.upload (same rationale) -- -- jsonb_set with create_missing=true (the default) inserts the key only -- when it's absent, so re-runs are idempotent and the migration is safe -- against a partial run. UPDATE roles SET permissions = jsonb_set( permissions, '{documents,edit}', COALESCE(permissions->'documents'->'create', 'false'::jsonb), true ) WHERE permissions->'documents' IS NOT NULL AND NOT (permissions->'documents' ? 'edit'); UPDATE roles SET permissions = jsonb_set( permissions, '{files,edit}', COALESCE(permissions->'files'->'upload', 'false'::jsonb), true ) WHERE permissions->'files' IS NOT NULL AND NOT (permissions->'files' ? 'edit'); -- Same backfill on per-port overrides (`port_role_overrides.permissions`) -- so an override that flipped a sibling permission stays consistent. UPDATE port_role_overrides SET permissions = jsonb_set( permissions, '{documents,edit}', COALESCE(permissions->'documents'->'create', 'false'::jsonb), true ) WHERE permissions->'documents' IS NOT NULL AND NOT (permissions->'documents' ? 'edit'); UPDATE port_role_overrides SET permissions = jsonb_set( permissions, '{files,edit}', COALESCE(permissions->'files'->'upload', 'false'::jsonb), true ) WHERE permissions->'files' IS NOT NULL AND NOT (permissions->'files' ? 'edit');