Adds paliad.users.profession (firm-wide career tier) and paliad.project_teams.responsibility
(per-project responsibility, default 'member'). Backfills both from the legacy
project_teams.role column — highest-tier-per-user for profession, single-row map
for responsibility (lead→lead, observer→observer, local_counsel/expert→external,
others→member).
Updates paliad.approval_role_level to recognise 'partner' as the new ceiling
(replaces 'lead' as the firm-tier ceiling), keeping 'lead' at level 5 as a
deprecated-shadow row until follow-up migration 058 retires project_teams.role.
Updates paliad.approval_role_from_unit_role: lead → partner.
Creates paliad.user_project_authority_level(user_id, project_id) — the
tuple-with-gate ladder. Returns profession_level if responsibility ∈ {lead,member}
else 0; max with derived authority via partner-unit attachments where
derive_grants_authority=true.
Updates approval_policies.required_role + approval_requests.required_role CHECK
constraints (drop 'lead', add 'partner'); backfills any existing rows.
Rewrites project_partner_units write RLS policy to read pt.responsibility='lead'
instead of pt.role='lead'.
Live-DB BEGIN/ROLLBACK dry-run verified: 2 users get profession='partner'
(matthias.siebels, tester@hlc.de — the only users currently on project_teams),
45 users get profession=NULL (admin fills via /admin/team).
project_teams.role kept as deprecated shadow column. Drop in follow-up migration 058.
125 lines
5.4 KiB
PL/PgSQL
125 lines
5.4 KiB
PL/PgSQL
-- Reverse of 057_profession_vs_responsibility.up.sql.
|
|
--
|
|
-- Best-effort rollback. The new columns are dropped; the legacy
|
|
-- project_teams.role column is re-derived from (responsibility, profession).
|
|
-- Down-migration loses information on edges:
|
|
-- * external responsibility → role='local_counsel' (loses expert distinction)
|
|
-- * member + profession=partner → role='of_counsel' (no legacy 'partner'
|
|
-- existed in project_teams.role; closest legacy ceiling)
|
|
-- * member + profession=paralegal → role='pa' (no legacy paralegal)
|
|
-- * member + profession=NULL → role='associate' (safe default, matches
|
|
-- the legacy RoleAssociate default)
|
|
-- These edges are documented; if the down is run on real production data,
|
|
-- review per-row before commit.
|
|
|
|
-- ============================================================================
|
|
-- 1. Restore approval_role_level to point at legacy ladder values.
|
|
-- ============================================================================
|
|
|
|
CREATE OR REPLACE FUNCTION paliad.approval_role_level(role text)
|
|
RETURNS int LANGUAGE SQL IMMUTABLE AS $$
|
|
SELECT CASE role
|
|
WHEN 'lead' THEN 5
|
|
WHEN 'of_counsel' THEN 4
|
|
WHEN 'associate' THEN 3
|
|
WHEN 'senior_pa' THEN 2
|
|
WHEN 'pa' THEN 1
|
|
ELSE 0
|
|
END
|
|
$$;
|
|
|
|
-- ============================================================================
|
|
-- 2. Restore approval_role_from_unit_role lead → lead.
|
|
-- ============================================================================
|
|
|
|
CREATE OR REPLACE FUNCTION paliad.approval_role_from_unit_role(unit_role text)
|
|
RETURNS text LANGUAGE SQL IMMUTABLE AS $$
|
|
SELECT CASE unit_role
|
|
WHEN 'lead' THEN 'lead'
|
|
WHEN 'attorney' THEN 'associate'
|
|
WHEN 'senior_pa' THEN 'senior_pa'
|
|
WHEN 'pa' THEN 'pa'
|
|
ELSE 'observer'
|
|
END
|
|
$$;
|
|
|
|
-- ============================================================================
|
|
-- 3. Re-derive project_teams.role from (responsibility, profession).
|
|
-- ============================================================================
|
|
|
|
UPDATE paliad.project_teams pt
|
|
SET role = CASE
|
|
WHEN pt.responsibility = 'lead' THEN 'lead'
|
|
WHEN pt.responsibility = 'observer' THEN 'observer'
|
|
WHEN pt.responsibility = 'external' THEN 'local_counsel'
|
|
ELSE COALESCE(
|
|
(SELECT CASE u.profession
|
|
WHEN 'partner' THEN 'of_counsel' -- best-effort: no legacy 'partner' role
|
|
WHEN 'of_counsel' THEN 'of_counsel'
|
|
WHEN 'associate' THEN 'associate'
|
|
WHEN 'senior_pa' THEN 'senior_pa'
|
|
WHEN 'pa' THEN 'pa'
|
|
WHEN 'paralegal' THEN 'pa' -- closest legacy fit
|
|
END
|
|
FROM paliad.users u WHERE u.id = pt.user_id),
|
|
'associate'
|
|
)
|
|
END;
|
|
|
|
-- ============================================================================
|
|
-- 4. Restore approval_policies + approval_requests CHECK constraints.
|
|
-- ============================================================================
|
|
|
|
UPDATE paliad.approval_policies
|
|
SET required_role = 'lead'
|
|
WHERE required_role = 'partner';
|
|
|
|
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 ('lead', 'of_counsel', 'associate', 'senior_pa', 'pa'));
|
|
|
|
UPDATE paliad.approval_requests
|
|
SET required_role = 'lead'
|
|
WHERE required_role = 'partner';
|
|
|
|
ALTER TABLE paliad.approval_requests DROP CONSTRAINT IF EXISTS approval_requests_required_role_check;
|
|
ALTER TABLE paliad.approval_requests ADD CONSTRAINT approval_requests_required_role_check
|
|
CHECK (required_role IN ('lead', 'of_counsel', 'associate', 'senior_pa', 'pa'));
|
|
|
|
-- ============================================================================
|
|
-- 5. Restore project_partner_units RLS to read pt.role = 'lead'.
|
|
-- ============================================================================
|
|
|
|
DROP POLICY IF EXISTS project_partner_units_write ON paliad.project_partner_units;
|
|
|
|
CREATE POLICY project_partner_units_write
|
|
ON paliad.project_partner_units FOR ALL
|
|
USING (
|
|
EXISTS (SELECT 1 FROM paliad.users u
|
|
WHERE u.id = auth.uid() AND u.global_role = 'global_admin')
|
|
OR EXISTS (SELECT 1 FROM paliad.project_teams pt
|
|
WHERE pt.user_id = auth.uid()
|
|
AND pt.project_id = project_partner_units.project_id
|
|
AND pt.role = 'lead')
|
|
)
|
|
WITH CHECK (
|
|
EXISTS (SELECT 1 FROM paliad.users u
|
|
WHERE u.id = auth.uid() AND u.global_role = 'global_admin')
|
|
OR EXISTS (SELECT 1 FROM paliad.project_teams pt
|
|
WHERE pt.user_id = auth.uid()
|
|
AND pt.project_id = project_partner_units.project_id
|
|
AND pt.role = 'lead')
|
|
);
|
|
|
|
-- ============================================================================
|
|
-- 6. Drop the new function and columns.
|
|
-- ============================================================================
|
|
|
|
DROP FUNCTION IF EXISTS paliad.user_project_authority_level(uuid, uuid);
|
|
|
|
DROP INDEX IF EXISTS paliad.project_teams_responsibility_idx;
|
|
ALTER TABLE paliad.project_teams DROP COLUMN IF EXISTS responsibility;
|
|
|
|
DROP INDEX IF EXISTS paliad.users_profession_idx;
|
|
ALTER TABLE paliad.users DROP COLUMN IF EXISTS profession;
|