fix notifications
Build & Push / Pipeline Tests (push) Failing after 1m8s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Successful in 53s
Test / API Unit Tests (push) Failing after 52s
Test / Homepage Unit Tests (push) Successful in 46s
Test / Carplace Unit Tests (push) Successful in 43s
Test / Admin Unit Tests (push) Successful in 43s
Test / Dashboard Unit Tests (push) Successful in 46s
Test / API Integration Tests (push) Successful in 1m7s
Build & Push / Pipeline Tests (push) Failing after 1m8s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Successful in 53s
Test / API Unit Tests (push) Failing after 52s
Test / Homepage Unit Tests (push) Successful in 46s
Test / Carplace Unit Tests (push) Successful in 43s
Test / Admin Unit Tests (push) Successful in 43s
Test / Dashboard Unit Tests (push) Successful in 46s
Test / API Integration Tests (push) Successful in 1m7s
This commit is contained in:
+105
@@ -0,0 +1,105 @@
|
||||
-- Durable, recipient-safe notification model. The legacy notifications table is
|
||||
-- intentionally retained for rollback and audit during the migration window.
|
||||
|
||||
CREATE TYPE "NotificationRecipientType" AS ENUM ('EMPLOYEE', 'RENTER');
|
||||
CREATE TYPE "NotificationDeliveryStatus" AS ENUM ('PENDING', 'QUEUED', 'SENT', 'DELIVERED', 'FAILED', 'SKIPPED', 'DEAD_LETTER');
|
||||
CREATE TYPE "NotificationOutboxStatus" AS ENUM ('PENDING', 'PUBLISHED', 'FAILED');
|
||||
|
||||
CREATE TABLE "notification_events" (
|
||||
"id" TEXT NOT NULL,
|
||||
"companyId" TEXT NOT NULL,
|
||||
"type" "NotificationType" NOT NULL,
|
||||
"templateKey" TEXT,
|
||||
"locale" TEXT NOT NULL DEFAULT 'en',
|
||||
"title" TEXT NOT NULL,
|
||||
"body" TEXT NOT NULL,
|
||||
"data" JSONB,
|
||||
"sourceType" TEXT NOT NULL,
|
||||
"sourceId" TEXT NOT NULL,
|
||||
"idempotencyKey" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "notification_events_pkey" PRIMARY KEY ("id"),
|
||||
CONSTRAINT "notification_events_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "companies"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE "notification_recipients" (
|
||||
"id" TEXT NOT NULL,
|
||||
"notificationEventId" TEXT NOT NULL,
|
||||
"recipientType" "NotificationRecipientType" NOT NULL,
|
||||
"employeeId" TEXT,
|
||||
"renterId" TEXT,
|
||||
"readAt" TIMESTAMP(3),
|
||||
"archivedAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "notification_recipients_pkey" PRIMARY KEY ("id"),
|
||||
CONSTRAINT "notification_recipients_notificationEventId_fkey" FOREIGN KEY ("notificationEventId") REFERENCES "notification_events"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "notification_recipients_employeeId_fkey" FOREIGN KEY ("employeeId") REFERENCES "employees"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "notification_recipients_renterId_fkey" FOREIGN KEY ("renterId") REFERENCES "renters"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "notification_recipients_exactly_one_identity_chk" CHECK (
|
||||
(CASE WHEN "employeeId" IS NULL THEN 0 ELSE 1 END) +
|
||||
(CASE WHEN "renterId" IS NULL THEN 0 ELSE 1 END) = 1
|
||||
),
|
||||
CONSTRAINT "notification_recipients_type_identity_chk" CHECK (
|
||||
("recipientType" = 'EMPLOYEE' AND "employeeId" IS NOT NULL AND "renterId" IS NULL) OR
|
||||
("recipientType" = 'RENTER' AND "renterId" IS NOT NULL AND "employeeId" IS NULL)
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE "notification_deliveries" (
|
||||
"id" TEXT NOT NULL,
|
||||
"notificationRecipientId" TEXT NOT NULL,
|
||||
"channel" "NotificationChannel" NOT NULL,
|
||||
"status" "NotificationDeliveryStatus" NOT NULL DEFAULT 'PENDING',
|
||||
"attemptCount" INTEGER NOT NULL DEFAULT 0,
|
||||
"lastAttemptAt" TIMESTAMP(3),
|
||||
"nextAttemptAt" TIMESTAMP(3),
|
||||
"provider" TEXT,
|
||||
"providerMessageId" TEXT,
|
||||
"failureCode" TEXT,
|
||||
"failureReason" TEXT,
|
||||
"preferenceDecision" TEXT,
|
||||
"sentAt" TIMESTAMP(3),
|
||||
"deliveredAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "notification_deliveries_pkey" PRIMARY KEY ("id"),
|
||||
CONSTRAINT "notification_deliveries_notificationRecipientId_fkey" FOREIGN KEY ("notificationRecipientId") REFERENCES "notification_recipients"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE "notification_outbox" (
|
||||
"id" TEXT NOT NULL,
|
||||
"notificationEventId" TEXT NOT NULL,
|
||||
"status" "NotificationOutboxStatus" NOT NULL DEFAULT 'PENDING',
|
||||
"payload" JSONB NOT NULL,
|
||||
"publishedAt" TIMESTAMP(3),
|
||||
"failureReason" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "notification_outbox_pkey" PRIMARY KEY ("id"),
|
||||
CONSTRAINT "notification_outbox_notificationEventId_fkey" FOREIGN KEY ("notificationEventId") REFERENCES "notification_events"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE "company_notification_preferences" (
|
||||
"id" TEXT NOT NULL,
|
||||
"companyId" TEXT NOT NULL,
|
||||
"notificationType" "NotificationType" NOT NULL,
|
||||
"channel" "NotificationChannel" NOT NULL,
|
||||
"enabled" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "company_notification_preferences_pkey" PRIMARY KEY ("id"),
|
||||
CONSTRAINT "company_notification_preferences_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "companies"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX "notification_events_companyId_idempotencyKey_key" ON "notification_events"("companyId", "idempotencyKey");
|
||||
CREATE INDEX "notification_events_companyId_type_createdAt_idx" ON "notification_events"("companyId", "type", "createdAt");
|
||||
CREATE INDEX "notification_recipients_employeeId_readAt_createdAt_idx" ON "notification_recipients"("employeeId", "readAt", "createdAt");
|
||||
CREATE INDEX "notification_recipients_renterId_readAt_createdAt_idx" ON "notification_recipients"("renterId", "readAt", "createdAt");
|
||||
CREATE INDEX "notification_recipients_notificationEventId_idx" ON "notification_recipients"("notificationEventId");
|
||||
CREATE UNIQUE INDEX "notification_deliveries_notificationRecipientId_channel_key" ON "notification_deliveries"("notificationRecipientId", "channel");
|
||||
CREATE INDEX "notification_deliveries_channel_status_nextAttemptAt_idx" ON "notification_deliveries"("channel", "status", "nextAttemptAt");
|
||||
CREATE INDEX "notification_outbox_status_createdAt_idx" ON "notification_outbox"("status", "createdAt");
|
||||
CREATE UNIQUE INDEX "company_notification_preferences_companyId_notificationType_channel_key" ON "company_notification_preferences"("companyId", "notificationType", "channel");
|
||||
Reference in New Issue
Block a user