96 lines
4.3 KiB
Plaintext
96 lines
4.3 KiB
Plaintext
enum NotificationDeliveryStatus {
|
|
PENDING
|
|
SENT
|
|
FAILED
|
|
SKIPPED
|
|
READ
|
|
}
|
|
|
|
enum NotificationPreferenceChannel {
|
|
IN_APP
|
|
EMAIL
|
|
}
|
|
|
|
model NotificationDelivery {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
tenantId String?
|
|
userId String?
|
|
adminUserId String?
|
|
channel NotificationPreferenceChannel
|
|
category String
|
|
messageKey String
|
|
sourceKey String?
|
|
status NotificationDeliveryStatus @default(PENDING)
|
|
attemptsMade Int @default(0)
|
|
providerMessageId String?
|
|
lastError String?
|
|
payloadMetadata Json?
|
|
sentAt DateTime?
|
|
readAt DateTime?
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)
|
|
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
|
adminUser AdminUser? @relation(fields: [adminUserId], references: [id], onDelete: SetNull)
|
|
|
|
@@index([tenantId, userId, status], name: "notification_delivery_tenant_user_status_idx")
|
|
@@index([tenantId, channel, category], name: "notification_delivery_tenant_channel_category_idx")
|
|
@@index([userId, channel, sourceKey], name: "notification_delivery_platform_source_lookup_idx")
|
|
@@index([adminUserId, status, createdAt(sort: Desc)], name: "notification_delivery_admin_status_time_idx")
|
|
@@index([status, updatedAt], name: "notification_delivery_status_updated_at_idx")
|
|
@@index([providerMessageId], name: "notification_delivery_provider_message_id_idx")
|
|
/// Tenant delivery uniqueness is covered by this composite key. Platform
|
|
/// delivery uniqueness additionally requires the merge-migration-managed
|
|
/// partial unique index `notification_delivery_platform_source_key` on
|
|
/// (userId, channel, sourceKey) WHERE tenantId IS NULL because PostgreSQL
|
|
/// treats NULL values as distinct and Prisma cannot declare partial indexes.
|
|
@@unique([tenantId, userId, channel, sourceKey], name: "notification_delivery_source_key")
|
|
@@unique([adminUserId, channel, sourceKey], name: "notification_delivery_admin_source_key")
|
|
}
|
|
|
|
model UserNotificationPreference {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
tenantId String
|
|
userId String
|
|
channel NotificationPreferenceChannel
|
|
category String
|
|
enabled Boolean @default(true)
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([tenantId, userId, channel, category], name: "user_notification_preference_scope_key")
|
|
@@index([tenantId, userId, category], name: "user_notification_preference_tenant_user_category_idx")
|
|
@@index([tenantId, category], name: "user_notification_preference_tenant_category_idx")
|
|
}
|
|
|
|
// DeviceToken for PWA Web Push registrations.
|
|
//
|
|
// Tracks active Web Push tokens per user. The
|
|
// register-device API endpoint upserts by `token` (globally unique).
|
|
// `lastSeenAt` is bumped on every successful send so an out-of-band
|
|
// cron can prune tokens older than 90d without disrupting active users.
|
|
// `revokedAt` is set when the provider returns `Unregistered` or
|
|
// `InvalidRegistration`; the worker job filters on `revokedAt IS NULL`.
|
|
model DeviceToken {
|
|
id String @id @default(cuid())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
userId String
|
|
tenantId String?
|
|
platform String // 'ios' | 'android' | 'web'
|
|
token String @unique
|
|
pushProvider String // 'webpush'
|
|
appVersion String?
|
|
lastSeenAt DateTime @default(now())
|
|
revokedAt DateTime?
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)
|
|
|
|
@@index([userId, tenantId], name: "device_token_user_tenant_idx")
|
|
@@index([tenantId, platform], name: "device_token_tenant_platform_idx")
|
|
@@index([revokedAt], name: "device_token_revoked_at_idx")
|
|
}
|