Files
paliad/internal/db/migrations/062_approval_policy_unit_defaults.down.sql
m e92c56b5f8 feat(t-paliad-154) commit 1.5: extend migration 062 with policy_audit_log
Q8 of locked design: policy CRUD audits to /admin/audit-log only, NOT
to per-project /verlauf. The 4 existing audit sources (project_events,
caldav_sync_log, reminder_log, partner_unit_events) don't fit cleanly:
project_events would surface on /verlauf (rejected by Q8); partner_unit_events
constrains event_type and requires unit_name + a non-null partner_unit_id
which doesn't fit project-scoped policy changes.

Added paliad.policy_audit_log as a fifth audit source — admin-only, scoped
either to a project or a partner unit, snapshots scope_name so post-cascade
rows still render. RLS: select for any authenticated user (route gate is
the actual control); write for global_admin only.

AuditService.ListEntries will union this source in commit 2 of this PR.

Validated insert/select live in BEGIN ... ROLLBACK.
2026-05-08 02:13:58 +02:00

60 lines
2.5 KiB
SQL

-- t-paliad-154 down migration. Reverses 062_approval_policy_unit_defaults.up.sql.
--
-- Order is the reverse of up:
-- 0. Drop policy_audit_log table.
-- 1. Drop seeded unit-default rows (anything where partner_unit_id IS NOT NULL).
-- 2. Drop the resolver function.
-- 3. Restore required_role CHECK without 'none'.
-- 4. Drop the two partial unique indexes + restore the original UNIQUE composite.
-- 5. Drop XOR check + partner_unit_id column.
-- 6. Restore project_id NOT NULL.
-- 0. Drop the audit table.
DROP TABLE IF EXISTS paliad.policy_audit_log;
--
-- Best-effort reversibility: any project-specific row with required_role='none'
-- will fail the CHECK restoration. We coerce those to 'associate' before
-- restoring the CHECK so the migration can roll back without data loss.
-- 1. Drop unit-default rows. Keep project rows intact (they pre-date 062).
DELETE FROM paliad.approval_policies WHERE partner_unit_id IS NOT NULL;
-- 2. Drop resolver.
DROP FUNCTION IF EXISTS paliad.approval_policy_effective(uuid, text, text);
-- 3. Coerce 'none' rows to 'associate' so the restored CHECK passes.
UPDATE paliad.approval_policies
SET required_role = 'associate'
WHERE required_role = 'none';
ALTER TABLE paliad.approval_policies
DROP CONSTRAINT IF EXISTS approval_policies_required_role_check;
ALTER TABLE paliad.approval_policies
ADD CONSTRAINT approval_policies_required_role_check
CHECK (required_role IN (
'partner', 'of_counsel', 'associate', 'senior_pa', 'pa'
));
-- 4. Drop partial unique indexes; restore composite UNIQUE on project rows
-- (down migration leaves the column NOT NULL so the unique-on-project_id
-- composite is sound again).
DROP INDEX IF EXISTS paliad.approval_policies_project_unique;
DROP INDEX IF EXISTS paliad.approval_policies_unit_unique;
DROP INDEX IF EXISTS paliad.approval_policies_unit_idx;
-- 5. Drop XOR check + partner_unit_id column.
ALTER TABLE paliad.approval_policies
DROP CONSTRAINT IF EXISTS approval_policies_scope_xor;
ALTER TABLE paliad.approval_policies
DROP COLUMN IF EXISTS partner_unit_id;
-- 6. Restore NOT NULL on project_id (no rows should be NULL by now since
-- step 1 deleted every unit-default row).
ALTER TABLE paliad.approval_policies
ALTER COLUMN project_id SET NOT NULL;
-- Restore composite UNIQUE constraint name to match migration 054.
ALTER TABLE paliad.approval_policies
ADD CONSTRAINT approval_policies_project_id_entity_type_lifecycle_event_key
UNIQUE (project_id, entity_type, lifecycle_event);