-- Die Auswahl der Kolleg:innen gilt jetzt für Notizen **und** Entwürfe. -- -- ═══ 1. Der Name stimmt nicht mehr ═══════════════════════════════ -- -- `note_subscriptions` hiess nach dem, wofür die Auswahl gestern allein -- galt. Sie steuert ab jetzt zwei Listen; ein Name, der nur eine davon -- nennt, führt beim nächsten Lesen in die Irre. alter table note_subscriptions rename to colleague_subscriptions; alter index idx_note_subscriptions_user rename to idx_colleague_subscriptions_user; alter table colleague_subscriptions rename constraint chk_note_abos_nicht_selbst to chk_kollegen_abos_nicht_selbst; drop policy if exists "note_subscriptions_owner" on colleague_subscriptions; drop policy if exists "colleague_subscriptions_owner" on colleague_subscriptions; create policy "colleague_subscriptions_owner" on colleague_subscriptions for all using (user_id = app_current_user_id() and is_hr_user()) with check (user_id = app_current_user_id() and is_hr_user()); comment on table colleague_subscriptions is 'Hinzugewählte Kolleg:innen je Person. Eine Zeile holt deren Notizen und Entwürfe in die Ansicht von user_id. Ohne Zeile sieht man nur die eigenen.'; -- ═══ 2. Entwürfe: lesen weiter, schreiben eng ════════════════════ -- -- Bisher stand über hire_drafts eine einzige Regel `for all`. Sie wird in -- vier zerlegt, weil Lesen und Schreiben ab jetzt verschieden weit reichen: -- -- lesen — die eigenen und die der hinzugewählten Kolleg:innen -- anlegen — nur auf den eigenen Namen -- ändern — nur die eigenen -- löschen — nur die eigenen -- -- Warum das Schreiben eng bleibt: ein Entwurf ist unfertige Arbeit. Zwei -- Personen, die abwechselnd in derselben Zeile schreiben, überschreiben -- einander lautlos — es gibt keine Sperre und keine Historie, die das -- auffangen könnte. Wer einen fremden Entwurf übernehmen soll, braucht dafür -- einen eigenen Vorgang, keine stillschweigend geöffnete Regel. -- -- ═══ Was das erzwingt ═══ -- -- Solange fremde Entwürfe unsichtbar waren, konnte niemand versuchen, einen -- zu speichern. Jetzt schon — und ein UPDATE, das die Regel abweist, trifft -- keine Zeile und meldet trotzdem keinen Fehler. Die Anwendung muss die Zahl -- der geänderten Zeilen prüfen (actions/hireDrafts.ts), sonst sähe die -- Person „gespeichert", und nichts wäre gespeichert. drop policy if exists "hire_drafts_owner" on hire_drafts; drop policy if exists "hire_drafts_select" on hire_drafts; create policy "hire_drafts_select" on hire_drafts for select using ( is_hr_user() and ( created_by = app_current_user_id() or exists ( select 1 from colleague_subscriptions s where s.user_id = app_current_user_id() and s.author_user_id = hire_drafts.created_by ) ) ); drop policy if exists "hire_drafts_insert" on hire_drafts; create policy "hire_drafts_insert" on hire_drafts for insert with check (created_by = app_current_user_id() and is_hr_user()); drop policy if exists "hire_drafts_update" on hire_drafts; create policy "hire_drafts_update" on hire_drafts for update using (created_by = app_current_user_id() and is_hr_user()) with check (created_by = app_current_user_id() and is_hr_user()); drop policy if exists "hire_drafts_delete" on hire_drafts; create policy "hire_drafts_delete" on hire_drafts for delete using (created_by = app_current_user_id() and is_hr_user()); -- ═══ Gegenprobe ═══════════════════════════════════════════════════ do $$ declare anzahl int; begin if exists (select 1 from pg_tables where tablename = 'note_subscriptions') then raise exception 'note_subscriptions steht noch — die Umbenennung hat nicht gegriffen.'; end if; if not exists ( select 1 from pg_policies where tablename = 'colleague_subscriptions' and policyname = 'colleague_subscriptions_owner' ) then raise exception 'Die Eigentuemerregel auf colleague_subscriptions fehlt.'; end if; -- Die alte Sammelregel darf nicht übrigbleiben: sie erlaubte `for all` -- und machte die vier neuen wirkungslos, weil Policies sich addieren. if exists (select 1 from pg_policies where tablename = 'hire_drafts' and policyname = 'hire_drafts_owner') then raise exception 'hire_drafts_owner steht noch — die alte Sammelregel wuerde die neuen aushebeln.'; end if; select count(*) into anzahl from pg_policies where tablename = 'hire_drafts'; if anzahl <> 4 then raise exception 'hire_drafts hat % Regeln, erwartet werden 4 (select, insert, update, delete).', anzahl; end if; -- Keine der drei Schreibregeln darf die Abos kennen. Stünde dort dieselbe -- Bedingung wie beim Lesen, liesse sich ein fremder Entwurf überschreiben. if exists ( select 1 from pg_policies where tablename = 'hire_drafts' and cmd in ('INSERT', 'UPDATE', 'DELETE') and coalesce(qual, '') || coalesce(with_check, '') like '%colleague_subscriptions%' ) then raise exception 'Eine Schreibregel auf hire_drafts kennt die Abos — Schreiben muss eigentuemergebunden bleiben.'; end if; end $$;