Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/prisma/schema/adminEmail.prisma
T

463 lines
16 KiB
Plaintext

// VA-P28c: tenant-less email workspace for HiveGrid's own sales team.
//
// Every row is owned by an active AdminUser. Worker-readable rows repeat the
// owner id deliberately so Postgres RLS can enforce the boundary without a
// tenant context or an unreviewable join chain.
enum AdminMailboxStatus {
connecting
active
degraded
revoked
}
enum AdminMailboxSyncStatus {
pending
running
complete
failed
}
enum AdminEmailDirection {
inbound
outbound
}
enum AdminEmailMatchStatus {
matched
ambiguous
unmatched
manual
}
enum AdminEmailEventType {
queued
sent
delivered
bounced
opened
clicked
replied
}
enum AdminScheduledEmailStatus {
draft
blocked
queued
sending
sent
cancelled
failed
}
enum AdminNoReplyReminderStatus {
pending
fired
dismissed
cancelled
}
enum AdminBulkEmailRunStatus {
draft
blocked
queued
running
complete
cancelled
failed
}
enum AdminSendingDomainStatus {
pending
verified
degraded
revoked
}
model AdminMailbox {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
archivedAt DateTime?
adminUserId String
connectionId String @unique
emailAddress String
normalizedEmail String
displayName String?
providerAccountId String
status AdminMailboxStatus @default(connecting)
lastSyncAt DateTime?
lastRecoveryPollAt DateTime?
webhookExpiresAt DateTime?
lastErrorMessageKey String?
adminUser AdminUser @relation(fields: [adminUserId], references: [id], onDelete: Restrict)
connection AdminDataConnection @relation(fields: [connectionId], references: [id], onDelete: Restrict)
syncCursors AdminMailboxSyncCursor[]
webhookEvents AdminMailboxWebhookEvent[]
threads AdminEmailThread[]
messages AdminEmailMessage[]
scheduled AdminScheduledEmail[]
bulkRuns AdminBulkEmailRun[]
bccAddresses AdminBccAddress[]
@@unique([adminUserId, normalizedEmail], name: "admin_mailbox_owner_email_key")
@@index([adminUserId, status, archivedAt], name: "admin_mailbox_owner_status_idx")
@@index([status, lastSyncAt], name: "admin_mailbox_recovery_poll_idx")
}
model AdminMailboxSyncCursor {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
adminUserId String
mailboxId String
externalFolderId String
cursorToken String?
syncStatus AdminMailboxSyncStatus @default(pending)
recoveryGeneration Int @default(0)
lastAttemptAt DateTime?
lastSuccessAt DateTime?
lastErrorMessageKey String?
mailbox AdminMailbox @relation(fields: [mailboxId], references: [id], onDelete: Cascade)
@@unique([mailboxId, externalFolderId], name: "admin_mailbox_cursor_folder_key")
@@index([adminUserId, syncStatus, lastAttemptAt], name: "admin_mailbox_cursor_owner_status_idx")
}
model AdminMailboxWebhookEvent {
id String @id @default(cuid())
createdAt DateTime @default(now())
processedAt DateTime?
failedAt DateTime?
adminUserId String
mailboxId String
providerEventId String
idempotencyKey String @unique
payload Json
lastErrorMessageKey String?
mailbox AdminMailbox @relation(fields: [mailboxId], references: [id], onDelete: Cascade)
@@unique([mailboxId, providerEventId], name: "admin_mailbox_webhook_provider_event_key")
@@index([adminUserId, processedAt, createdAt], name: "admin_mailbox_webhook_pending_idx")
}
model AdminEmailThread {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
archivedAt DateTime?
adminUserId String
mailboxId String
providerThreadId String
normalizedSubject String?
latestMessageAt DateTime
messageCount Int @default(0)
unreadCount Int @default(0)
mailbox AdminMailbox @relation(fields: [mailboxId], references: [id], onDelete: Cascade)
messages AdminEmailMessage[]
scheduled AdminScheduledEmail[]
@@unique([mailboxId, providerThreadId], name: "admin_email_thread_provider_key")
@@index([adminUserId, latestMessageAt(sort: Desc)], name: "admin_email_thread_owner_latest_idx")
}
model AdminEmailMessage {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
adminUserId String
mailboxId String
threadId String
providerMessageId String
internetMessageId String?
direction AdminEmailDirection
fromAddress String
subject String?
snippet String?
bodyHtml String?
bodyText String?
sentAt DateTime
receivedAt DateTime?
isRead Boolean @default(false)
isNewsletter Boolean @default(false)
providerLabels String[] @default([])
matchStatus AdminEmailMatchStatus @default(unmatched)
matchedContactId String?
matchedLeadId String?
matchedDealId String?
matchedAt DateTime?
matchedByAdminUserId String?
matchingReason String?
matchingCandidates Json?
mailbox AdminMailbox @relation(fields: [mailboxId], references: [id], onDelete: Cascade)
thread AdminEmailThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
matchedContact AdminContact? @relation(fields: [matchedContactId], references: [id], onDelete: SetNull)
matchedLead AdminLead? @relation(fields: [matchedLeadId], references: [id], onDelete: SetNull)
matchedDeal AdminDeal? @relation(fields: [matchedDealId], references: [id], onDelete: SetNull)
participants AdminEmailParticipant[]
attachments AdminEmailAttachment[]
events AdminEmailEvent[]
links AdminEmailLink[]
activities AdminActivity[]
reminders AdminNoReplyReminder[]
@@unique([mailboxId, providerMessageId], name: "admin_email_message_provider_key")
@@index([mailboxId, internetMessageId], name: "admin_email_message_rfc_id_idx")
@@index([adminUserId, matchStatus, receivedAt(sort: Desc)], name: "admin_email_message_match_queue_idx")
@@index([matchedContactId, sentAt(sort: Desc)], name: "admin_email_message_contact_time_idx")
@@index([matchedLeadId, sentAt(sort: Desc)], name: "admin_email_message_lead_time_idx")
@@index([matchedDealId, sentAt(sort: Desc)], name: "admin_email_message_deal_time_idx")
}
model AdminEmailParticipant {
id String @id @default(cuid())
createdAt DateTime @default(now())
adminUserId String
messageId String
kind String
emailAddress String
displayName String?
message AdminEmailMessage @relation(fields: [messageId], references: [id], onDelete: Cascade)
@@unique([messageId, kind, emailAddress], name: "admin_email_participant_message_kind_address_key")
@@index([adminUserId, emailAddress], name: "admin_email_participant_owner_address_idx")
}
model AdminEmailAttachment {
id String @id @default(cuid())
createdAt DateTime @default(now())
adminUserId String
messageId String
providerAttachmentId String?
filename String
mimeType String?
sizeBytes Int
storageBucket String
storageKey String
checksumSha256 String
scannedAt DateTime
linkedDealId String?
message AdminEmailMessage @relation(fields: [messageId], references: [id], onDelete: Cascade)
@@unique([messageId, checksumSha256], name: "admin_email_attachment_message_checksum_key")
@@index([adminUserId, linkedDealId, createdAt], name: "admin_email_attachment_owner_deal_idx")
}
model AdminEmailEvent {
id String @id @default(cuid())
createdAt DateTime @default(now())
adminUserId String
messageId String
type AdminEmailEventType
providerEventId String?
recipient String?
linkId String?
occurredAt DateTime
rawExpiresAt DateTime?
metadata Json?
message AdminEmailMessage @relation(fields: [messageId], references: [id], onDelete: Cascade)
link AdminEmailLink? @relation(fields: [linkId], references: [id], onDelete: SetNull)
@@unique([messageId, type, providerEventId], name: "admin_email_event_provider_key")
@@index([adminUserId, type, occurredAt(sort: Desc)], name: "admin_email_event_owner_type_idx")
@@index([rawExpiresAt], name: "admin_email_event_retention_idx")
}
model AdminEmailLink {
id String @id @default(cuid())
createdAt DateTime @default(now())
adminUserId String
messageId String
destinationUrl String
trackingTokenHash String @unique
message AdminEmailMessage @relation(fields: [messageId], references: [id], onDelete: Cascade)
events AdminEmailEvent[]
@@index([adminUserId, messageId], name: "admin_email_link_owner_message_idx")
}
model AdminEmailTemplate {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
archivedAt DateTime?
adminUserId String
name String
subjectTemplate String
htmlTemplate String
textTemplate String?
allowedPlaceholders String[] @default([])
version Int @default(1)
@@unique([adminUserId, name, version], name: "admin_email_template_owner_name_version_key")
@@index([adminUserId, archivedAt, name], name: "admin_email_template_owner_archive_idx")
}
model AdminEmailSnippet {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
archivedAt DateTime?
adminUserId String
shortcut String
title String
content String
@@unique([adminUserId, shortcut], name: "admin_email_snippet_owner_shortcut_key")
@@index([adminUserId, archivedAt, title], name: "admin_email_snippet_owner_archive_idx")
}
model AdminEmailSignature {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
adminUserId String @unique
html String
text String?
@@index([adminUserId, updatedAt], name: "admin_email_signature_owner_updated_idx")
}
model AdminEmailOutboundPolicy {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
adminUserId String @unique
timeZone String
workdayStartMinutes Int
workdayEndMinutes Int
allowedWeekDays Int[] @default([])
dailySendLimit Int
bulkDailySendLimit Int
consentRulesConfigured Boolean @default(false)
trackingEnabled Boolean @default(false)
liveOpenEnabled Boolean @default(false)
trackingRetentionDays Int @default(180)
configuredAt DateTime?
@@index([adminUserId, configuredAt], name: "admin_email_outbound_policy_owner_config_idx")
}
model AdminScheduledEmail {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
adminUserId String
mailboxId String
contactId String?
leadId String?
dealId String?
threadId String?
bulkRunId String?
toAddresses String[]
ccAddresses String[] @default([])
bccAddresses String[] @default([])
subject String
bodyHtml String
bodyText String?
scheduledFor DateTime
timeZone String
noReplyAfterDays Int?
status AdminScheduledEmailStatus @default(draft)
idempotencyKey String @unique
claimedAt DateTime?
sentAt DateTime?
sendAttemptCount Int @default(0)
providerMessageId String?
sentMessageId String?
lastErrorMessageKey String?
mailbox AdminMailbox @relation(fields: [mailboxId], references: [id], onDelete: Restrict)
thread AdminEmailThread? @relation(fields: [threadId], references: [id], onDelete: SetNull)
bulkRun AdminBulkEmailRun? @relation(fields: [bulkRunId], references: [id], onDelete: SetNull)
@@index([adminUserId, status, scheduledFor], name: "admin_scheduled_email_due_idx")
@@index([dealId, scheduledFor], name: "admin_scheduled_email_deal_idx")
@@index([bulkRunId, status], name: "admin_scheduled_email_bulk_status_idx")
}
model AdminNoReplyReminder {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
adminUserId String
outboundMessageId String
dueAt DateTime
status AdminNoReplyReminderStatus @default(pending)
taskId String?
idempotencyKey String @unique
outboundMessage AdminEmailMessage @relation(fields: [outboundMessageId], references: [id], onDelete: Cascade)
@@index([adminUserId, status, dueAt], name: "admin_no_reply_reminder_due_idx")
}
model AdminBulkEmailRun {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
adminUserId String
mailboxId String
name String
selectedContactIds String[] @default([])
templateId String?
status AdminBulkEmailRunStatus @default(draft)
scheduledFor DateTime?
timeZone String
recipientCount Int @default(0)
sentCount Int @default(0)
failedCount Int @default(0)
idempotencyKey String @unique
lastErrorMessageKey String?
mailbox AdminMailbox @relation(fields: [mailboxId], references: [id], onDelete: Restrict)
scheduled AdminScheduledEmail[]
@@index([adminUserId, status, scheduledFor], name: "admin_bulk_email_run_due_idx")
}
model AdminSendingDomain {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
archivedAt DateTime?
adminUserId String
domain String @unique
spfRecordName String
spfExpectedValue String
dkimRecordName String
dkimExpectedValue String
status AdminSendingDomainStatus @default(pending)
spfStatus String
dkimStatus String
lastCheckedAt DateTime?
lastErrorMessageKey String?
@@index([adminUserId, status, archivedAt], name: "admin_sending_domain_owner_status_idx")
}
model AdminBccAddress {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
archivedAt DateTime?
adminUserId String
mailboxId String
localPartHash String @unique
displayAddress String
rotatedAt DateTime?
mailbox AdminMailbox @relation(fields: [mailboxId], references: [id], onDelete: Cascade)
@@index([adminUserId, archivedAt], name: "admin_bcc_address_owner_archive_idx")
}