-- ============================================================================= -- Phase 7: Mandantentrennung und die Regeln fuer Termine und Zustellung. -- -- 1. Row Level Security fuer die sechs neuen Tabellen. -- -- 2. Bedingungen, die Unmoegliches abweisen: ein Termin, der endet, bevor er -- beginnt; ein Teilnehmerlimit von null; ein Anmeldeschluss nach dem -- Termin. -- -- 3. Teilindizes fuer die beiden Abfragen, die staendig laufen: was steht an -- (kommende Termine) und was ist noch zu verschicken (offene -- Benachrichtigungen). -- -- 4. Ein zugestellter Eintrag wird nicht geloescht. Er ist der Nachweis -- dafuer, wer wann worueber informiert wurde — und wer nicht. -- ============================================================================= -- ----------------------------------------------------------------------------- -- Row Level Security -- ----------------------------------------------------------------------------- DO $$ DECLARE tabelle text; BEGIN FOREACH tabelle IN ARRAY ARRAY[ 'benachrichtigungsvorlage', 'zustellkanal', 'benachrichtigung', 'termin', 'terminanmeldung', 'kalenderzugang' ] LOOP EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', tabelle); EXECUTE format( 'CREATE POLICY %I ON %I FOR ALL ' 'USING ("organisationId" = aktuelle_organisation()) ' 'WITH CHECK ("organisationId" = aktuelle_organisation())', tabelle || '_mandant', tabelle ); END LOOP; END; $$; -- ----------------------------------------------------------------------------- -- Was es nicht geben darf -- ----------------------------------------------------------------------------- ALTER TABLE "termin" ADD CONSTRAINT "termin_ende_nach_beginn" CHECK ( "ende" IS NULL OR "ende" >= "beginn" ); ALTER TABLE "termin" ADD CONSTRAINT "termin_limit_sinnvoll" CHECK ( "teilnehmerLimit" IS NULL OR "teilnehmerLimit" > 0 ); -- Ein Anmeldeschluss nach dem Termin ist keiner. ALTER TABLE "termin" ADD CONSTRAINT "termin_anmeldeschluss_vorher" CHECK ( "anmeldeschluss" IS NULL OR "anmeldeschluss" <= "beginn" ); ALTER TABLE "benachrichtigung" ADD CONSTRAINT "benachrichtigung_versuche_plausibel" CHECK ( "versuche" >= 0 AND "versuche" <= 100 ); -- ----------------------------------------------------------------------------- -- Teilindizes fuer den laufenden Betrieb -- ----------------------------------------------------------------------------- -- Was noch raus muss. Die Tabelle waechst ueber Jahre, die Warteschlange ist -- immer kurz. CREATE INDEX "benachrichtigung_offen" ON "benachrichtigung" ("organisationId", "erstelltAm") WHERE "stand" = 'WARTET'; -- Was ansteht. Abgesagte und geloeschte Termine stehen im Kalender nicht mehr. CREATE INDEX "termin_kommend" ON "termin" ("organisationId", "beginn") WHERE "geloeschtAm" IS NULL AND "abgesagtAm" IS NULL; -- Wer sich zu was gemeldet hat — fuer die Anwesenheitsliste. CREATE INDEX "terminanmeldung_zugesagt" ON "terminanmeldung" ("terminId") WHERE "stand" = 'ZUGESAGT'; -- ----------------------------------------------------------------------------- -- Volltextsuche ueber Termine -- ----------------------------------------------------------------------------- CREATE INDEX "termin_suche_titel" ON "termin" USING GIN ("titel" gin_trgm_ops); -- ----------------------------------------------------------------------------- -- Rechte fuer die Anwendungsrolle -- -- Eine zugestellte Benachrichtigung wird nicht geloescht: sie ist der Nachweis -- dafuer, wer wann worueber informiert wurde. Geaendert werden darf sie, denn -- der Hintergrundprozess traegt Zustellstand und Fehlversuche nach. -- ----------------------------------------------------------------------------- DO $$ BEGIN IF EXISTS (SELECT FROM pg_roles WHERE rolname = 'florian_app') THEN EXECUTE 'GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO florian_app'; EXECUTE 'GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO florian_app'; EXECUTE 'REVOKE INSERT, UPDATE, DELETE ON "berechtigung" FROM florian_app'; EXECUTE 'REVOKE UPDATE, DELETE ON "audit_log" FROM florian_app'; EXECUTE 'REVOKE UPDATE, DELETE ON "kiosk_vorgang" FROM florian_app'; EXECUTE 'REVOKE UPDATE, DELETE ON "druckmessung" FROM florian_app'; EXECUTE 'REVOKE UPDATE, DELETE ON "atemschutz_ereignis" FROM florian_app'; EXECUTE 'REVOKE DELETE ON "benachrichtigung" FROM florian_app'; ELSE RAISE NOTICE 'Rolle florian_app nicht vorhanden — Rechtevergabe uebersprungen.'; END IF; END; $$;