TeamVis Self-Host-Bundle v0.56.2
This commit is contained in:
1 parent
f53579d3a4
commit
6da3cc2283
11 files changed
+432
-30
No files matched your search
@@ -0,0 +1,103 @@
|
||||
-- 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$;
|
||||
@@ -0,0 +1,29 @@
|
||||
-- ====================================================================
|
||||
-- 0068_dark_theme — dunkle Darstellung je Mandant (Portal und Karte)
|
||||
-- ====================================================================
|
||||
-- Drei optionale Farben. Leer = aus der hellen Palette abgeleitet
|
||||
-- (lib/branding.ts, darkTheme()):
|
||||
-- dark_bg Seitengrund Default: Sekundär tief
|
||||
-- dark_surface Karten, Felder Default: Sekundär dunkel
|
||||
-- dark_accent Schrift, Links, Fokus, Linien in Markenfarbe
|
||||
-- Default: Primärfarbe aufgehellt bis 4,5:1 auf dark_surface
|
||||
-- Die Primärfarbe selbst bleibt im Dunkeln reine Fläche (Buttons, Kopf) —
|
||||
-- auf dunklem Grund reicht ihr Kontrast als Schrift in der Regel nicht.
|
||||
--
|
||||
-- Nur additiv. Anon-Lesezugriff ausschließlich auf die drei neuen Spalten
|
||||
-- (die öffentliche Karte liest site_settings über den anon-Client); die
|
||||
-- bestehenden Spalten-Grants bleiben unberührt.
|
||||
|
||||
alter table public.site_settings
|
||||
add column if not exists dark_bg text,
|
||||
add column if not exists dark_surface text,
|
||||
add column if not exists dark_accent text;
|
||||
|
||||
comment on column public.site_settings.dark_bg is
|
||||
'Dunkle Darstellung: Seitengrund (Hex). Leer = Sekundär tief.';
|
||||
comment on column public.site_settings.dark_surface is
|
||||
'Dunkle Darstellung: Karten und Felder (Hex). Leer = Sekundär dunkel.';
|
||||
comment on column public.site_settings.dark_accent is
|
||||
'Dunkle Darstellung: Markenfarbe für Schrift, Links und Linien (Hex). Leer = aufgehellte Primärfarbe.';
|
||||
|
||||
grant select (dark_bg, dark_surface, dark_accent) on public.site_settings to anon;
|
||||
@@ -0,0 +1,21 @@
|
||||
-- ====================================================================
|
||||
-- 0069_theme_default — Standard-Darstellung je Mandant
|
||||
-- ====================================================================
|
||||
-- Was Portal und Karte zeigen, solange jemand im Portal unter „Darstellung"
|
||||
-- nichts gewählt hat: 'light' (Vorgabe), 'dark' oder 'system' (folgt der
|
||||
-- Geräteeinstellung). Eine eigene Wahl (Cookie tv_theme) geht immer vor.
|
||||
-- Additiv; anon-Lesezugriff nur auf diese Spalte (die Karte liest anon).
|
||||
|
||||
alter table public.site_settings
|
||||
add column if not exists theme_default text not null default 'light';
|
||||
|
||||
alter table public.site_settings
|
||||
drop constraint if exists site_settings_theme_default_check;
|
||||
alter table public.site_settings
|
||||
add constraint site_settings_theme_default_check
|
||||
check (theme_default in ('light', 'dark', 'system'));
|
||||
|
||||
comment on column public.site_settings.theme_default is
|
||||
'Standard-Darstellung von Portal und Karte: light | dark | system.';
|
||||
|
||||
grant select (theme_default) on public.site_settings to anon;
|
||||
@@ -0,0 +1,17 @@
|
||||
-- ====================================================================
|
||||
-- 0070_dark_brand — eigene Markenfläche für die dunkle Darstellung
|
||||
-- ====================================================================
|
||||
-- Die Primärfarbe trägt auf dunklem Grund oft nicht als Fläche (Stadtwerk:
|
||||
-- #931041 wirkt auf #11181f fast schwarz). dark_brand ist die Farbe für
|
||||
-- Buttons, Badges und aktive Markierungen im Dunkeln, immer mit weißer
|
||||
-- Schrift. Leer = Primärfarbe. Stadtwerk-Festlegung (überarbeitet
|
||||
-- 26.09.2026): #a5204d.
|
||||
-- Additiv; anon-Lesezugriff nur auf diese Spalte.
|
||||
|
||||
alter table public.site_settings
|
||||
add column if not exists dark_brand text;
|
||||
|
||||
comment on column public.site_settings.dark_brand is
|
||||
'Dunkle Darstellung: Markenfläche für Buttons und Badges (Hex, weiße Schrift). Leer = Primärfarbe.';
|
||||
|
||||
grant select (dark_brand) on public.site_settings to anon;
|
||||
Reference in new issue
Block a user