86 lines
3.6 KiB
Plaintext
86 lines
3.6 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?
|
|
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)
|
|
|
|
@@index([tenantId, userId, status], name: "notification_delivery_tenant_user_status_idx")
|
|
@@index([tenantId, channel, category], name: "notification_delivery_tenant_channel_category_idx")
|
|
@@index([status, updatedAt], name: "notification_delivery_status_updated_at_idx")
|
|
@@index([providerMessageId], name: "notification_delivery_provider_message_id_idx")
|
|
@@unique([tenantId, userId, channel, sourceKey], name: "notification_delivery_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 (Phase 08 #65 — Capacitor mobile wrapper).
|
|
//
|
|
// Tracks active APNs / FCM / WebPush device 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 // 'fcm' | 'apns' | '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")
|
|
}
|