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

138 lines
5.8 KiB
Plaintext

// R-LEADS / M040a - HiveGrid's operator-wide sales lead intake.
//
// Platform leads deliberately carry no tenantId. They are isolated by the
// platform-admin RLS contract and are visible only to authenticated operators.
// Anonymous S2S intake uses a reviewed SECURITY DEFINER capability; the API
// runtime role never receives direct table access outside those policies.
enum AdminLeadStatus {
new
contacted
qualified
disqualified
}
enum AdminLeadActivityType {
captured
imported
manually_created
status_changed
assigned
note_added
archived
restored
duplicate_hint_recorded
legacy_event
}
model AdminLeadSource {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
key String @unique
displayName String
enabled Boolean @default(true)
defaultAssigneeAdminUserId String?
notifyAdminUserIds String[] @default([])
rateLimitPerMinute Int @default(60)
metadata Json?
leads AdminLead[]
credentials AdminLeadSourceCredential[]
@@index([enabled, displayName], name: "admin_lead_source_enabled_display_name_idx")
@@index([defaultAssigneeAdminUserId], name: "admin_lead_source_default_assignee_idx")
}
/// Rotatable source credential. Only a one-way digest is persisted; the raw
/// bearer value is returned once by the source administration service.
model AdminLeadSourceCredential {
id String @id @default(cuid())
createdAt DateTime @default(now())
sourceId String
keyHash String @unique
keyPrefix String
expiresAt DateTime?
revokedAt DateTime?
lastUsedAt DateTime?
source AdminLeadSource @relation(fields: [sourceId], references: [id], onDelete: Cascade)
@@index([sourceId, revokedAt, expiresAt], name: "admin_lead_source_credential_active_idx")
@@index([sourceId, keyPrefix], name: "admin_lead_source_credential_prefix_idx")
}
model AdminLead {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
capturedAt DateTime @default(now())
archivedAt DateTime?
sourceId String
sourceDetail String?
externalId String?
idempotencyKey String?
firstName String?
lastName String?
email String?
normalizedEmail String?
phone String?
normalizedPhone String?
company String?
message String?
utmSource String?
utmMedium String?
utmCampaign String?
utmTerm String?
utmContent String?
referrer String?
landingPage String?
status AdminLeadStatus @default(new)
assignedToAdminUserId String?
duplicateHintOfLeadId String?
metadata Json?
source AdminLeadSource @relation(fields: [sourceId], references: [id], onDelete: Restrict)
activities AdminLeadActivity[]
duplicateHint AdminLead? @relation("AdminLeadDuplicateHint", fields: [duplicateHintOfLeadId], references: [id], onDelete: SetNull)
duplicates AdminLead[] @relation("AdminLeadDuplicateHint")
convertedCompany AdminCompany? @relation("AdminLeadConvertedCompany")
convertedContact AdminContact? @relation("AdminLeadConvertedContact")
convertedDeal AdminDeal? @relation("AdminLeadConvertedDeal")
salesActivities AdminActivity[]
qualification AdminLeadQualification?
duplicateCandidatesPrimary AdminDuplicateCandidate[] @relation("AdminDuplicatePrimaryLead")
duplicateCandidatesSecondary AdminDuplicateCandidate[] @relation("AdminDuplicateSecondaryLead")
mergeRecordsSurvived AdminMergeRecord[] @relation("AdminMergeSurvivorLead")
mergeRecordMerged AdminMergeRecord? @relation("AdminMergeMergedLead")
emailMessages AdminEmailMessage[]
callSessions AdminCallSession[]
callMatchCandidates AdminCallMatchCandidate[]
@@unique([sourceId, externalId], name: "admin_lead_source_external_id_key")
@@unique([sourceId, idempotencyKey], name: "admin_lead_source_idempotency_key")
@@index([status, archivedAt, capturedAt(sort: Desc)], name: "admin_lead_status_archive_captured_idx")
@@index([sourceId, capturedAt(sort: Desc)], name: "admin_lead_source_captured_idx")
@@index([assignedToAdminUserId, status, capturedAt(sort: Desc)], name: "admin_lead_assignee_status_captured_idx")
@@index([normalizedEmail], name: "admin_lead_normalized_email_idx")
@@index([normalizedPhone], name: "admin_lead_normalized_phone_idx")
@@index([duplicateHintOfLeadId], name: "admin_lead_duplicate_hint_idx")
}
/// Append-only business timeline. Notes are activities rather than a mutable
/// blob on AdminLead so every operator-visible change remains attributable.
model AdminLeadActivity {
id String @id @default(cuid())
createdAt DateTime @default(now())
leadId String
type AdminLeadActivityType
actorAdminUserId String?
payload Json
lead AdminLead @relation(fields: [leadId], references: [id], onDelete: Cascade)
@@index([leadId, createdAt(sort: Desc)], name: "admin_lead_activity_lead_created_idx")
@@index([type, createdAt(sort: Desc)], name: "admin_lead_activity_type_created_idx")
@@index([actorAdminUserId, createdAt(sort: Desc)], name: "admin_lead_activity_actor_created_idx")
}