325c5ddbf2
- Reminder-Tabelle mit Zeilenschutz (Mandant+Benutzer, Systemlesen fuer den E-Mail-Planer), API reminders (Liste, Anlegen) - Kachel "Erinnerungen", globaler Melder im Portalrahmen (Browser und Desktop, je Faelligkeit einmal) - Desktop: Laufzeit-Berechtigung fuer Benachrichtigungen nur fuer die gespeicherte Server-Adresse - Zugriffsklassifikation nachgemessen Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
74 lines
3.2 KiB
SQL
74 lines
3.2 KiB
SQL
-- 260929-if2 — Erinnerungen: persoenliche, einmalige Erinnerungen je Benutzer.
|
|
--
|
|
-- Zweck: die Tabelle "Reminder" traegt die Erinnerungen des Dashboard-Widgets
|
|
-- „Erinnerungen“ (Titel, Beschreibung, Faelligkeit, optional E-Mail). Es gibt
|
|
-- keine Wiederholung (D-01) und keine Historie: „Erledigt“ loescht die Zeile.
|
|
--
|
|
-- Besitz: eine Erinnerung gehoert genau einem Benutzer (gleicher Mandant UND
|
|
-- gleicher Benutzer, D-05). Faellt der Benutzer weg, fallen seine Erinnerungen
|
|
-- mit (ON DELETE CASCADE). Die Anwendung antwortet fuer fremde Kennungen mit
|
|
-- 404 (nie 403).
|
|
--
|
|
-- Spuren des E-Mail-Planers: "emailSentAt" ist der ANSPRUCH auf den Versand
|
|
-- (wird vor dem Senden gesetzt, damit mehrere API-Instanzen nicht doppelt
|
|
-- senden), "emailAttempts" zaehlt die Versuche (hoechstens 3). Ein Verschieben
|
|
-- der Faelligkeit setzt beide zurueck.
|
|
--
|
|
-- Zeilenschutz, zwei Regeln:
|
|
-- tenant_isolation_policy — Mandant UND Benutzer (Form aus DashboardImage,
|
|
-- 20260921120000_dashboard_image): ohne gesetzten Benutzer (Hintergrund-
|
|
-- dienst, der je Mandant gebunden schreibt) gilt nur der Mandant, mit
|
|
-- Benutzer zusaetzlich "userId".
|
|
-- system_read_policy — NUR FOR SELECT, Form aus 20260914120000_rls_system_
|
|
-- context_read. Sie bedient allein die Kandidatenabfrage des E-Mail-
|
|
-- Planers (reminder-mail.scheduler.ts), der einmal ueber ALLE Mandanten
|
|
-- liest und dann je Zeile gebunden anspricht. Schreiben bleibt der
|
|
-- Mandantenregel vorbehalten.
|
|
--
|
|
-- Rechte fuer die Anwendungsrolle tessera_app: kommen ueber ALTER DEFAULT
|
|
-- PRIVILEGES aus 20260909130000_rls_app_role automatisch — hier nichts zu tun.
|
|
--
|
|
-- WICHTIG: wie alle RLS-Regeln dieses Schemas wirken diese erst, wenn die
|
|
-- Anwendung als Rolle ohne Umgehungsrecht verbindet (Schalter heute AUS, siehe
|
|
-- docs/mandantentrennung-datenbankrolle.md). Bis dahin tragen die
|
|
-- Anwendungspruefungen im Dienst den Schutz allein.
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "Reminder" (
|
|
"id" TEXT NOT NULL,
|
|
"tenantId" TEXT NOT NULL,
|
|
"userId" TEXT NOT NULL,
|
|
"title" TEXT NOT NULL,
|
|
"description" TEXT NOT NULL DEFAULT '',
|
|
"dueAt" TIMESTAMP(3) NOT NULL,
|
|
"emailEnabled" BOOLEAN NOT NULL DEFAULT false,
|
|
"emailSentAt" TIMESTAMP(3),
|
|
"emailAttempts" INTEGER NOT NULL DEFAULT 0,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "Reminder_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Reminder_tenantId_userId_dueAt_idx" ON "Reminder"("tenantId", "userId", "dueAt");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "Reminder_dueAt_idx" ON "Reminder"("dueAt");
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "Reminder" ADD CONSTRAINT "Reminder_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- Zeilenschutz: Mandant UND Benutzer (Muster 20260921120000)
|
|
ALTER TABLE "Reminder" ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE "Reminder" FORCE ROW LEVEL SECURITY;
|
|
CREATE POLICY tenant_isolation_policy ON "Reminder"
|
|
USING (
|
|
"tenantId" = current_tenant_id()
|
|
AND (current_user_id() IS NULL OR "userId" = current_user_id())
|
|
);
|
|
|
|
-- Systemkontext: nur Lesen, fuer die Kandidatenabfrage des E-Mail-Planers
|
|
CREATE POLICY system_read_policy ON "Reminder"
|
|
FOR SELECT USING (is_system_context());
|