added in-app notification system

This commit is contained in:
Rajpreet0 2026-08-28 18:20:28 +02:00
parent d1b47e7ce8
commit 7c5b0cc40f
20 changed files with 1381 additions and 29 deletions

View file

@ -0,0 +1,22 @@
-- AlterTable
ALTER TABLE "Business" ADD COLUMN "notificationSettings" JSONB;
-- CreateTable
CREATE TABLE "Notification" (
"id" TEXT NOT NULL,
"recipientId" TEXT NOT NULL,
"type" TEXT NOT NULL,
"title" TEXT NOT NULL,
"body" TEXT NOT NULL,
"linkUrl" TEXT,
"readAt" TIMESTAMP(3),
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "Notification_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "Notification_recipientId_readAt_idx" ON "Notification"("recipientId", "readAt");
-- CreateIndex
CREATE INDEX "Notification_recipientId_createdAt_idx" ON "Notification"("recipientId", "createdAt");

View file

@ -97,27 +97,28 @@ model Manager {
}
model Business {
id String @id @default(uuid())
managerId String
name String
address String
email String
title String
ustId String?
banking String?
plan String?
subscription Json?
slug String? @unique
isPublic Boolean @default(false)
stripeAccountId String? @unique // Stripe Connect Account ID
stripeAccountStatus String? // "pending" | "active" | "restricted"
invoiceCounter Int @default(0) // Fortlaufender Zähler für Rechnungsnummern
cancellationPolicy Json? // { tiers: [{ hoursBeforeStart: number, refundPercent: number }, ...] }, absteigend sortiert. null = immer 100% Rückerstattung.
branding Json? // { companyName, logoUrl, primaryColor, accentColor }. null = Kumasy-Standardbranding (siehe KUMASY_BRANDING).
manager Manager @relation(fields: [managerId], references: [id])
courses Course[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
id String @id @default(uuid())
managerId String
name String
address String
email String
title String
ustId String?
banking String?
plan String?
subscription Json?
slug String? @unique
isPublic Boolean @default(false)
stripeAccountId String? @unique // Stripe Connect Account ID
stripeAccountStatus String? // "pending" | "active" | "restricted"
invoiceCounter Int @default(0) // Fortlaufender Zähler für Rechnungsnummern
cancellationPolicy Json? // { tiers: [{ hoursBeforeStart: number, refundPercent: number }, ...] }, absteigend sortiert. null = immer 100% Rückerstattung.
branding Json? // { companyName, logoUrl, primaryColor, accentColor }. null = Kumasy-Standardbranding (siehe KUMASY_BRANDING).
notificationSettings Json? // { "booking.created": true, ... } Opt-out pro In-App-Benachrichtigungstyp. null / fehlender Key = Registry-Default (siehe NOTIFICATION_TYPES).
manager Manager @relation(fields: [managerId], references: [id])
courses Course[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([managerId])
}
@ -225,3 +226,22 @@ model CourseWaitlistEntry {
@@index([courseId])
@@index([userId])
}
// In-App-Benachrichtigungen für die Studio-Seite (Manager/Employee).
// recipientId ist bewusst polymorph ohne Relation (wie Employee.createdBy /
// CourseBooking.cancelledBy): Empfänger kann je nach Typ Manager oder Employee
// sein, perspektivisch auch User. Keine FK, damit kein Modell-Join nötig ist
// und ein späterer Kunden-Empfänger keine Migration braucht.
model Notification {
id String @id @default(uuid())
recipientId String // Manager- oder Employee-ID
type String // Schlüssel aus NOTIFICATION_TYPES (src/modules/notifications/lib/notification-types.ts)
title String
body String
linkUrl String? // Ziel beim Klick, z.B. /courses/edit/<id>
readAt DateTime? // null = ungelesen
createdAt DateTime @default(now())
@@index([recipientId, readAt])
@@index([recipientId, createdAt])
}