104 lines
4.4 KiB
PL/PgSQL
104 lines
4.4 KiB
PL/PgSQL
-- Karten-Analytics: Aufbewahrungsfrist und namentliche Auswertung
|
|
-- ====================================================================
|
|
-- Zwei Datenschutz-Lücken aus 0017 werden hier geschlossen:
|
|
--
|
|
-- 1. Die dort angekündigte Aufbewahrung von 365 Tagen war nur ein
|
|
-- Kommentar — es gab keine Löschroutine, die Protokolle wuchsen
|
|
-- unbegrenzt. Jetzt: konfigurierbare Frist (Default 90 Tage) plus
|
|
-- `purge_card_view_log()`, die der Anwendungscode regelmäßig ruft
|
|
-- und die zusätzlich per pg_cron laufen kann.
|
|
--
|
|
-- 2. Die namentliche Auswertung je Beschäftigtem (Rangliste unter
|
|
-- /admin/analytics) war ohne Schalter immer aktiv. Sie ist ab
|
|
-- jetzt ein bewusstes Opt-in, Default AUS — auch für
|
|
-- Bestandsinstanzen. Wo eine Belegschaft vertreten ist, ist die
|
|
-- Auswertung mitbestimmungspflichtig (technische Einrichtung,
|
|
-- geeignet zur Verhaltens- und Leistungskontrolle); sie darf
|
|
-- deshalb nicht stillschweigend voreingestellt sein.
|
|
|
|
alter table public.site_settings
|
|
add column if not exists analytics_employee_breakdown boolean not null default false,
|
|
add column if not exists analytics_retention_days integer not null default 90;
|
|
|
|
comment on column public.site_settings.analytics_employee_breakdown is
|
|
'Namentliche Auswertung der Kartenaufrufe je Beschäftigtem im Admin-Backend. Opt-in, mitbestimmungspflichtig.';
|
|
comment on column public.site_settings.analytics_retention_days is
|
|
'Aufbewahrungsfrist für card_view_log in Tagen. Ältere Zeilen werden gelöscht.';
|
|
|
|
-- Plausibilitätsgrenzen: mindestens eine Woche (sonst ist die Statistik
|
|
-- sinnlos), höchstens zwei Jahre (darüber ist die Erforderlichkeit für
|
|
-- eine reine Aufrufzählung nicht mehr begründbar).
|
|
alter table public.site_settings
|
|
drop constraint if exists site_settings_analytics_retention_days_check;
|
|
alter table public.site_settings
|
|
add constraint site_settings_analytics_retention_days_check
|
|
check (analytics_retention_days between 7 and 730);
|
|
|
|
-- --------------------------------------------------------------------
|
|
-- Löschroutine
|
|
-- --------------------------------------------------------------------
|
|
-- Ohne Argument gilt die in site_settings hinterlegte Frist. Rückgabe
|
|
-- ist die Anzahl gelöschter Zeilen, damit ein Cron-Lauf etwas zu
|
|
-- protokollieren hat.
|
|
create or replace function public.purge_card_view_log(retention_days integer default null)
|
|
returns integer
|
|
language plpgsql
|
|
security definer
|
|
set search_path = public
|
|
as $fn$
|
|
declare
|
|
days integer;
|
|
removed integer;
|
|
begin
|
|
days := coalesce(
|
|
retention_days,
|
|
(select s.analytics_retention_days from public.site_settings s where s.singleton limit 1),
|
|
90
|
|
);
|
|
|
|
delete from public.card_view_log
|
|
where occurred_at < now() - make_interval(days => days);
|
|
|
|
get diagnostics removed = row_count;
|
|
return removed;
|
|
end;
|
|
$fn$;
|
|
|
|
comment on function public.purge_card_view_log(integer) is
|
|
'Löscht Einträge aus card_view_log, die älter als die Aufbewahrungsfrist sind. Ohne Argument gilt site_settings.analytics_retention_days.';
|
|
|
|
-- Die Funktion fasst personenbeziehbare Protokolle an — kein Zugriff
|
|
-- für anon/authenticated.
|
|
revoke all on function public.purge_card_view_log(integer) from public;
|
|
revoke all on function public.purge_card_view_log(integer) from anon;
|
|
revoke all on function public.purge_card_view_log(integer) from authenticated;
|
|
grant execute on function public.purge_card_view_log(integer) to service_role;
|
|
|
|
-- --------------------------------------------------------------------
|
|
-- Zeitplan, sofern pg_cron vorhanden ist
|
|
-- --------------------------------------------------------------------
|
|
-- Die Anwendung löscht ohnehin selbst (siehe lib/analytics.ts), das hier
|
|
-- ist der saubere Weg für Instanzen mit pg_cron: die Frist greift dann
|
|
-- auch, wenn die Karten längere Zeit nicht aufgerufen werden. Fehlt die
|
|
-- Extension oder fehlen die Rechte, bleibt es beim App-seitigen Lauf —
|
|
-- die Migration darf daran nicht scheitern.
|
|
do $cron$
|
|
begin
|
|
if exists (select 1 from pg_extension where extname = 'pg_cron') then
|
|
begin
|
|
perform cron.unschedule('teamvis-purge-card-view-log');
|
|
exception when others then
|
|
null;
|
|
end;
|
|
|
|
perform cron.schedule(
|
|
'teamvis-purge-card-view-log',
|
|
'30 3 * * *',
|
|
'select public.purge_card_view_log();'
|
|
);
|
|
end if;
|
|
exception when others then
|
|
raise notice 'pg_cron-Zeitplan nicht eingerichtet (%). Die Anwendung löscht selbst.', sqlerrm;
|
|
end;
|
|
$cron$;
|