Add announcement editing and reliable per-recipient mail delivery

This commit is contained in:
t.indorf
2026-10-13 08:53:22 +02:00
parent 661776e609
commit 1472779781
22 changed files with 1655 additions and 190 deletions
@@ -0,0 +1,23 @@
BEGIN;
ALTER TABLE "announcements" ADD COLUMN "revision" INTEGER NOT NULL DEFAULT 1,
ADD COLUMN "editedAt" TIMESTAMP(3), ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, ADD COLUMN "emailReady" BOOLEAN NOT NULL DEFAULT true;
UPDATE "announcements" SET "updatedAt" = "createdAt";
CREATE INDEX "announcements_kitaId_updatedAt_idx" ON "announcements"("kitaId", "updatedAt");
CREATE TABLE "announcement_emails" (
"id" TEXT NOT NULL, "kitaId" TEXT NOT NULL, "announcementId" TEXT NOT NULL, "userId" TEXT NOT NULL,
"revision" INTEGER NOT NULL, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"nextAttemptAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "attempts" INTEGER NOT NULL DEFAULT 0,
"leaseUntil" TIMESTAMP(3), "claimToken" TEXT, "sentAt" TIMESTAMP(3), "skippedAt" TIMESTAMP(3),
"failed" BOOLEAN NOT NULL DEFAULT false, "lastError" TEXT,
CONSTRAINT "announcement_emails_pkey" PRIMARY KEY ("id"),
CONSTRAINT "announcement_emails_revision_check" CHECK ("revision" > 0)
);
CREATE UNIQUE INDEX "announcement_emails_announcementId_revision_userId_key" ON "announcement_emails"("announcementId", "revision", "userId");
CREATE INDEX "announcement_emails_kitaId_announcementId_revision_idx" ON "announcement_emails"("kitaId", "announcementId", "revision");
CREATE INDEX "announcement_emails_sentAt_skippedAt_nextAttemptAt_idx" ON "announcement_emails"("sentAt", "skippedAt", "nextAttemptAt");
ALTER TABLE "announcement_emails" ADD CONSTRAINT "announcement_emails_kitaId_fkey" FOREIGN KEY ("kitaId") REFERENCES "kitas"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "announcement_emails" ADD CONSTRAINT "announcement_emails_announcementId_fkey" FOREIGN KEY ("announcementId") REFERENCES "announcements"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "announcement_emails" ADD CONSTRAINT "announcement_emails_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "announcement_emails" ADD CONSTRAINT "announcement_emails_announcementId_tenant_fkey" FOREIGN KEY ("announcementId", "kitaId") REFERENCES "announcements"("id", "kitaId") ON DELETE NO ACTION ON UPDATE NO ACTION;
ALTER TABLE "announcement_emails" ADD CONSTRAINT "announcement_emails_userId_tenant_fkey" FOREIGN KEY ("userId", "kitaId") REFERENCES "users"("id", "kitaId") ON DELETE NO ACTION ON UPDATE NO ACTION;
COMMIT;
+33
View File
@@ -155,6 +155,7 @@ model Kita {
dutyAssignments DutyAssignment[]
absences Absence[]
announcements Announcement[]
announcementEmails AnnouncementEmail[]
invitations Invitation[]
termine Termin[]
mitbringselItems MitbringselItem[]
@@ -280,6 +281,7 @@ model User {
alarmNotifications NotdienstAlarmNotification[]
alarmEmails NotdienstAlarmEmail[]
notdienstEmails NotdienstEmail[]
announcementEmails AnnouncementEmail[]
@@index([kitaId])
@@index([familyId])
@@ -697,6 +699,10 @@ model Announcement {
title String
content String
audience AnnouncementAudience @default(ALLE)
revision Int @default(1)
editedAt DateTime?
updatedAt DateTime @default(now())
emailReady Boolean @default(true)
authorId String
author User @relation("AnnouncementAuthor", fields: [authorId], references: [id], onDelete: Cascade)
@@ -705,13 +711,40 @@ model Announcement {
attachments Attachment[]
reads AnnouncementRead[]
emails AnnouncementEmail[]
@@index([kitaId, createdAt])
@@index([kitaId, updatedAt])
@@index([authorId])
@@unique([id, kitaId])
@@map("announcements")
}
model AnnouncementEmail {
id String @id @default(cuid())
kitaId String
kita Kita @relation(fields: [kitaId], references: [id], onDelete: Cascade)
announcementId String
announcement Announcement @relation(fields: [announcementId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
revision Int
createdAt DateTime @default(now())
nextAttemptAt DateTime @default(now())
attempts Int @default(0)
leaseUntil DateTime?
claimToken String?
sentAt DateTime?
skippedAt DateTime?
failed Boolean @default(false)
lastError String?
@@unique([announcementId, revision, userId])
@@index([kitaId, announcementId, revision])
@@index([sentAt, skippedAt, nextAttemptAt])
@@map("announcement_emails")
}
model Attachment {
id String @id @default(cuid())
announcementId String