-- Migration 083: Vereins-Kontingent-Bypass über Capability-System (kein Parallel-Schema) -- Ersetzt platform_role_club_feature_exemptions / profile_club_feature_exemptions aus 082. -- Einzelprofil-Grants (ergänzt portal_role_capability_grants) CREATE TABLE IF NOT EXISTS profile_capability_grants ( profile_id INT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE, capability_id TEXT NOT NULL REFERENCES capabilities(id) ON DELETE CASCADE, reason TEXT, granted_by_profile_id INT REFERENCES profiles(id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (profile_id, capability_id) ); CREATE INDEX IF NOT EXISTS idx_profile_capability_grants_cap ON profile_capability_grants(capability_id); -- Bypass-Capabilities (CAPABILITY_CATALOG — konfigurierbar via portal/profile grants) INSERT INTO capabilities (id, name, domain, min_account_state, linked_feature_id) VALUES ( 'platform.club_quota.bypass', 'Vereins-Kontingent umgehen (alle Features)', 'platform', 'platform_admin', NULL ) ON CONFLICT (id) DO NOTHING; -- Superadmin: alle Plattform-Capabilities inkl. bypass (079-Seed deckt domain=platform ab) INSERT INTO portal_role_capability_grants (portal_role, capability_id) SELECT 'superadmin', 'platform.club_quota.bypass' WHERE NOT EXISTS ( SELECT 1 FROM portal_role_capability_grants WHERE portal_role = 'superadmin' AND capability_id = 'platform.club_quota.bypass' ); -- ── Daten aus 082 übernehmen (falls vorhanden) ───────────────────────────── DO $migrate082$ DECLARE r RECORD; cap_id TEXT; BEGIN IF NOT EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'platform_role_club_feature_exemptions' ) THEN RETURN; END IF; FOR r IN SELECT portal_role, feature_id, note FROM platform_role_club_feature_exemptions LOOP IF r.feature_id IS NULL THEN cap_id := 'platform.club_quota.bypass'; ELSE cap_id := 'platform.club_quota.bypass.' || r.feature_id; INSERT INTO capabilities (id, name, domain, min_account_state, linked_feature_id) VALUES ( cap_id, 'Vereins-Kontingent umgehen: ' || r.feature_id, 'quota_bypass', 'active_member', r.feature_id ) ON CONFLICT (id) DO NOTHING; END IF; INSERT INTO portal_role_capability_grants (portal_role, capability_id) VALUES (lower(trim(r.portal_role)), cap_id) ON CONFLICT DO NOTHING; END LOOP; FOR r IN SELECT profile_id, feature_id, reason, set_by_profile_id FROM profile_club_feature_exemptions LOOP IF r.feature_id IS NULL THEN cap_id := 'platform.club_quota.bypass'; ELSE cap_id := 'platform.club_quota.bypass.' || r.feature_id; INSERT INTO capabilities (id, name, domain, min_account_state, linked_feature_id) VALUES ( cap_id, 'Vereins-Kontingent umgehen: ' || r.feature_id, 'quota_bypass', 'active_member', r.feature_id ) ON CONFLICT (id) DO NOTHING; END IF; INSERT INTO profile_capability_grants ( profile_id, capability_id, reason, granted_by_profile_id ) VALUES (r.profile_id, cap_id, r.reason, r.set_by_profile_id) ON CONFLICT DO NOTHING; END LOOP; DROP TABLE IF EXISTS profile_club_feature_exemptions; DROP TABLE IF EXISTS platform_role_club_feature_exemptions; END $migrate082$;