| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- // EKS Support Relay — persistence layer.
- // SQLite for now; the schema deliberately avoids SQLite-only features so a
- // later move to PostgreSQL only needs a datasource/provider change.
- generator client {
- provider = "prisma-client-js"
- output = "../node_modules/.prisma/client"
- }
- datasource db {
- provider = "sqlite"
- url = env("DATABASE_URL")
- }
- /// One row per inbound source message. Primary idempotency guard for the
- /// Chatwoot webhook: (source, messageId) is unique.
- model ProcessedMessage {
- id String @id @default(cuid())
- source String
- messageId String
- conversationId Int
- /// queued | processing | replied | skipped | ticket | failed | spam
- status String
- reason String?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- @@unique([source, messageId])
- @@index([conversationId])
- @@index([status])
- }
- /// Async work item. The webhook persists a job and returns 202; the in-process
- /// worker picks it up, with retries and exponential backoff.
- model Job {
- id String @id @default(cuid())
- /// chatwoot_message
- type String
- /// queued | processing | done | failed | dead
- status String @default("queued")
- attempts Int @default(0)
- maxAttempts Int @default(3)
- /// Redacted, minimal payload — never full secrets.
- payloadJson String
- /// Redacted error text.
- lastError String?
- runAfter DateTime @default(now())
- startedAt DateTime?
- finishedAt DateTime?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- @@index([status, runAfter])
- }
- /// Handoff record. conversationId is unique so repeated new_ticket calls for
- /// the same conversation always resolve to the same ticket number.
- model Ticket {
- id String @id @default(cuid())
- conversationId Int @unique
- ticketNumber String
- reason String?
- createdAt DateTime @default(now())
- }
- /// Non-secret audit trail of decisions taken per message/conversation.
- model AuditEvent {
- id String @id @default(cuid())
- conversationId Int?
- messageId String?
- /// Set when the event belongs to a queued job, so the ops panel can join the
- /// audit trail to the queue without parsing summary text.
- jobId String?
- eventType String
- summary String
- /// Redacted JSON metadata.
- metaJson String?
- createdAt DateTime @default(now())
- @@index([conversationId])
- @@index([eventType])
- @@index([createdAt])
- @@index([jobId])
- }
- /// Cached AI translations for agent UI. Keyed by text hash rather than raw text
- /// to avoid duplicating customer content unnecessarily in lookup keys.
- model TranslationCache {
- id String @id @default(cuid())
- conversationId Int?
- messageId String?
- sourceHash String
- sourceLanguage String?
- targetLanguage String
- translatedText String
- provider String
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- @@unique([sourceHash, targetLanguage])
- @@index([conversationId])
- @@index([messageId])
- }
- /// Runtime operator controls used by /ops panic button and webhook cutoffs.
- model RuntimeSetting {
- key String @id
- value String
- updatedBy String?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- }
- /// Conversation-local durable state that must survive relay restarts.
- model ConversationState {
- id String @id @default(cuid())
- conversationId Int @unique
- flowiseSessionId String
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- @@index([flowiseSessionId])
- }
|