Turn the note filter around: yours by default, colleagues added
Yesterday's version had it the other way — everyone visible, untick to
hide. The decision from the business side is the opposite: you see your
own notes, and you tick the colleagues you also want. So note_mutes
becomes note_subscriptions and the predicate flips from `not exists` to
`exists`.
The existing rows are not carried over. The meaning inverts rather than
the sign: converting faithfully ("everyone except the muted") would write
almost the whole roster into the new table and reproduce exactly the state
the change is meant to end. Anyone opening the setting tomorrow would
think it had not taken effect. The table is a day old; what is lost is a
few ticks from trying it out.
What this costs is worth saying plainly: the silent case that could not
happen under exceptions can happen now. Do not tick a colleague and you
will not see her follow-ups — not while she is on holiday either. That is
the flip side of the decision, and it is written down in the migration
rather than discovered later.
Each note now says who wrote it. Own notes read "von mir" rather than
repeating your own name, which would sit on every second line and tell
nobody anything. The flag is computed on the server: the user id is
already there, and threading it through four components for one word is a
poor trade. The counter on the button follows the same turn — "+2" for
what you added, nothing when you added nothing.
Verified: 21 tests, five mutation-checked (restoring `not exists`,
dropping the own-notes clause, inverting the default, hiding the author,
and printing your own name instead of "von mir" each turn them red). 489
tests, typecheck, lint, schema drift and build clean. The migration is
reviewed but not run — no reachable database here.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
91
db/migrations/20260910100000_notiz_abos_statt_ausnahmen.sql
Normal file
91
db/migrations/20260910100000_notiz_abos_statt_ausnahmen.sql
Normal file
@@ -0,0 +1,91 @@
|
||||
-- Die Sichtbarkeit dreht sich um: **wer hinzugewählt ist**, nicht wer
|
||||
-- ausgeblendet ist.
|
||||
--
|
||||
-- ═══ Was sich ändert ═══
|
||||
--
|
||||
-- Bisher (note_mutes): sichtbar war alles, eine Zeile blendete eine Person
|
||||
-- aus. Ab jetzt (note_subscriptions): sichtbar sind die eigenen Notizen, und
|
||||
-- eine Zeile holt eine Kollegin dazu.
|
||||
--
|
||||
-- ═══ Warum die alten Zeilen nicht übernommen werden ═══
|
||||
--
|
||||
-- Die Bedeutung kehrt sich um, nicht bloss das Vorzeichen. Eine wörtliche
|
||||
-- Übernahme — „alle ausser den Abgewählten" — trüge jeden Bestand in die
|
||||
-- neue Tabelle und stellte damit genau den Zustand her, den die Umstellung
|
||||
-- abschaffen soll: alle sehen alle. Wer die Einstellung morgen aufschlägt,
|
||||
-- hielte die Änderung für wirkungslos.
|
||||
--
|
||||
-- Also fängt jede Person bei sich selbst an und wählt hinzu, wen sie
|
||||
-- braucht. Die Tabelle ist einen Tag alt; was dabei verlorengeht, sind ein
|
||||
-- paar Haken aus dem Ausprobieren.
|
||||
--
|
||||
-- ═══ Was das kostet ═══
|
||||
--
|
||||
-- Der stille Fall, der bei den Ausnahmen nicht auftreten konnte, tritt jetzt
|
||||
-- auf: wer eine Kollegin nicht hinzuwählt, sieht deren Wiedervorlagen nicht —
|
||||
-- auch nicht im Urlaubsfall. Das ist die Kehrseite der Entscheidung und
|
||||
-- gehört benannt, nicht versteckt.
|
||||
|
||||
drop table if exists note_mutes;
|
||||
|
||||
create table if not exists note_subscriptions (
|
||||
-- Wessen Einstellung das ist.
|
||||
user_id uuid not null references app_users(id) on delete cascade,
|
||||
-- Wessen Notizen zusätzlich erscheinen sollen.
|
||||
author_user_id uuid not null references app_users(id) on delete cascade,
|
||||
created_at timestamptz not null default now(),
|
||||
|
||||
primary key (user_id, author_user_id),
|
||||
|
||||
-- Sich selbst hinzuzuwählen ergibt keinen Sinn: die eigenen Notizen sind
|
||||
-- ohnehin immer dabei. Eine Zeile dafür wäre ein Haken, der nichts tut,
|
||||
-- und ein Haken, der sich entfernen liesse, ohne dass etwas geschieht.
|
||||
constraint chk_note_abos_nicht_selbst check (user_id <> author_user_id)
|
||||
);
|
||||
|
||||
comment on table note_subscriptions is
|
||||
'Hinzugewählte Kolleg:innen je Person. Eine Zeile holt die Notizen von author_user_id in die Glocke von user_id. Ohne Zeile sieht man nur die eigenen.';
|
||||
|
||||
-- Der Zugriffsweg fragt immer „meine Auswahl": ohne Index ein Tabellenscan
|
||||
-- je Seitenaufruf, mit ihm ein Indexzugriff.
|
||||
create index if not exists idx_note_subscriptions_user on note_subscriptions (user_id);
|
||||
|
||||
alter table note_subscriptions enable row level security;
|
||||
|
||||
-- Eigentümergebunden wie hire_drafts und saved_reports: man sieht und ändert
|
||||
-- ausschliesslich die eigenen Zeilen.
|
||||
drop policy if exists "note_subscriptions_owner" on note_subscriptions;
|
||||
create policy "note_subscriptions_owner" on note_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());
|
||||
|
||||
-- ═══ Gegenprobe ═══════════════════════════════════════════════════
|
||||
do $$
|
||||
begin
|
||||
if exists (select 1 from pg_tables where tablename = 'note_mutes') then
|
||||
raise exception 'note_mutes steht noch — die alte Tabelle wurde nicht entfernt.';
|
||||
end if;
|
||||
|
||||
if not exists (
|
||||
select 1 from pg_tables where tablename = 'note_subscriptions' and rowsecurity
|
||||
) then
|
||||
raise exception 'note_subscriptions hat keinen Zeilenschutz.';
|
||||
end if;
|
||||
|
||||
if not exists (
|
||||
select 1 from pg_policies
|
||||
where tablename = 'note_subscriptions' and policyname = 'note_subscriptions_owner'
|
||||
) then
|
||||
raise exception 'Die Eigentuemerregel auf note_subscriptions fehlt.';
|
||||
end if;
|
||||
|
||||
begin
|
||||
insert into note_subscriptions (user_id, author_user_id)
|
||||
values ('00000000-0000-0000-0000-000000000001', '00000000-0000-0000-0000-000000000001');
|
||||
raise exception 'Eine Person kann sich selbst hinzuwaehlen — die Pruefbedingung greift nicht.';
|
||||
exception
|
||||
when check_violation then null;
|
||||
when foreign_key_violation then null;
|
||||
end;
|
||||
end $$;
|
||||
Reference in New Issue
Block a user