-- AlterTable -- NOTIFY-02 (D-04): Sofort-Alert pro Profil, Default AUS. ALTER TABLE "TenderSavedSearch" ADD COLUMN IF NOT EXISTS "instantAlert" BOOLEAN NOT NULL DEFAULT false; -- CreateTable -- NOTIFY-03 Kern-Invariante — der "getroffen"-Datensatz (D-06). Ein Row je -- (tender x savedSearch)-Paar. EIN einziges "notifiedAt" ist das -- Eligibility-Gate: NULL = noch nicht benachrichtigt, gesetzt (instant -- ODER digest) = das Paar wird NIE wieder benachrichtigt. Match-Erzeugung -- ist ein idempotenter Upsert auf @@unique(tenderId, savedSearchId) mit -- update:{} — ein Re-Match bewahrt ein bereits gesetztes notifiedAt. -- Scoping wie TenderTriage/TenderSavedSearch: userId ist das Scoping-Feld -- fuer Reads (where:{userId}, IDOR-Schutz), tenantId zusaetzlich fuer die -- Mandanten-SMTP-Auflösung im Digest/Instant-Versand — KEIN forTenant()/RLS. CREATE TABLE IF NOT EXISTS "TenderMatch" ( "id" TEXT NOT NULL, "tenderId" TEXT NOT NULL, "savedSearchId" TEXT NOT NULL, "userId" TEXT NOT NULL, "tenantId" TEXT NOT NULL, "matchedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "notifiedAt" TIMESTAMP(3), "notifiedChannel" TEXT, CONSTRAINT "TenderMatch_pkey" PRIMARY KEY ("id"), CONSTRAINT "TenderMatch_tenderId_fkey" FOREIGN KEY ("tenderId") REFERENCES "Tender"("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "TenderMatch_savedSearchId_fkey" FOREIGN KEY ("savedSearchId") REFERENCES "TenderSavedSearch"("id") ON DELETE CASCADE ON UPDATE CASCADE ); -- CreateTable -- NOTIFY-01 (D-03) — Digest-Intervall ist eine per-USER Einstellung, nicht -- pro Profil. Default 'daily' (D-01). CREATE TABLE IF NOT EXISTS "TenderNotificationPref" ( "id" TEXT NOT NULL, "userId" TEXT NOT NULL, "tenantId" TEXT NOT NULL, "digestInterval" TEXT NOT NULL DEFAULT 'daily', "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, CONSTRAINT "TenderNotificationPref_pkey" PRIMARY KEY ("id") ); -- CreateIndex -- Upsert-Target — ein Match je (tender x savedSearch)-Paar, idempotent. CREATE UNIQUE INDEX IF NOT EXISTS "TenderMatch_tenderId_savedSearchId_key" ON "TenderMatch"("tenderId", "savedSearchId"); -- CreateIndex CREATE INDEX IF NOT EXISTS "TenderMatch_userId_idx" ON "TenderMatch"("userId"); -- CreateIndex CREATE INDEX IF NOT EXISTS "TenderMatch_notifiedAt_idx" ON "TenderMatch"("notifiedAt"); -- CreateIndex -- Ein Pref-Row je Nutzer. CREATE UNIQUE INDEX IF NOT EXISTS "TenderNotificationPref_userId_key" ON "TenderNotificationPref"("userId"); -- CreateIndex CREATE INDEX IF NOT EXISTS "TenderNotificationPref_userId_idx" ON "TenderNotificationPref"("userId");