generator client { provider = "prisma-client-js" } datasource db { provider = "sqlite" url = env("DATABASE_URL") } enum TeamRole { OWNER MEMBER } enum MessageDirection { IN OUT } enum MessageChannel { TELEGRAM WHATSAPP INSTAGRAM PHONE EMAIL INTERNAL } enum ContactMessageKind { MESSAGE CALL } enum ChatRole { USER ASSISTANT SYSTEM } enum OmniMessageStatus { PENDING SENT FAILED DELIVERED READ } enum FeedCardDecision { PENDING ACCEPTED REJECTED } enum WorkspaceDocumentType { Regulation Playbook Policy Template } model Team { id String @id @default(cuid()) name String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt members TeamMember[] contacts Contact[] calendarEvents CalendarEvent[] deals Deal[] conversations ChatConversation[] chatMessages ChatMessage[] omniThreads OmniThread[] omniMessages OmniMessage[] omniIdentities OmniContactIdentity[] telegramBusinessConnections TelegramBusinessConnection[] feedCards FeedCard[] contactPins ContactPin[] documents WorkspaceDocument[] } model User { id String @id @default(cuid()) phone String @unique passwordHash String email String? @unique name String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt memberships TeamMember[] conversations ChatConversation[] @relation("ConversationCreator") chatMessages ChatMessage[] @relation("ChatAuthor") } model TeamMember { id String @id @default(cuid()) teamId String userId String role TeamRole @default(MEMBER) createdAt DateTime @default(now()) team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([teamId, userId]) @@index([userId]) } model Contact { id String @id @default(cuid()) teamId String name String company String? country String? location String? avatarUrl String? email String? phone String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) note ContactNote? messages ContactMessage[] events CalendarEvent[] deals Deal[] feedCards FeedCard[] pins ContactPin[] omniThreads OmniThread[] omniMessages OmniMessage[] omniIdentities OmniContactIdentity[] @@index([teamId, updatedAt]) } model ContactNote { id String @id @default(cuid()) contactId String @unique content String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade) } model ContactMessage { id String @id @default(cuid()) contactId String kind ContactMessageKind @default(MESSAGE) direction MessageDirection channel MessageChannel content String durationSec Int? transcriptJson Json? occurredAt DateTime @default(now()) createdAt DateTime @default(now()) contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade) @@index([contactId, occurredAt]) } model OmniContactIdentity { id String @id @default(cuid()) teamId String contactId String channel MessageChannel externalId String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade) @@unique([teamId, channel, externalId]) @@index([contactId]) @@index([teamId, updatedAt]) } model OmniThread { id String @id @default(cuid()) teamId String contactId String channel MessageChannel externalChatId String businessConnectionId String? title String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade) messages OmniMessage[] @@unique([teamId, channel, externalChatId, businessConnectionId]) @@index([teamId, updatedAt]) @@index([contactId, updatedAt]) } model OmniMessage { id String @id @default(cuid()) teamId String contactId String threadId String direction MessageDirection channel MessageChannel status OmniMessageStatus @default(PENDING) text String providerMessageId String? providerUpdateId String? rawJson Json? occurredAt DateTime @default(now()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade) thread OmniThread @relation(fields: [threadId], references: [id], onDelete: Cascade) @@unique([threadId, providerMessageId]) @@index([teamId, occurredAt]) @@index([threadId, occurredAt]) } model TelegramBusinessConnection { id String @id @default(cuid()) teamId String businessConnectionId String isEnabled Boolean? canReply Boolean? rawJson Json? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) @@unique([teamId, businessConnectionId]) @@index([teamId, updatedAt]) } model CalendarEvent { id String @id @default(cuid()) teamId String contactId String? title String startsAt DateTime endsAt DateTime? note String? status String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) contact Contact? @relation(fields: [contactId], references: [id], onDelete: SetNull) @@index([startsAt]) @@index([contactId, startsAt]) @@index([teamId, startsAt]) } model Deal { id String @id @default(cuid()) teamId String contactId String title String stage String amount Int? nextStep String? summary String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade) @@index([teamId, updatedAt]) @@index([contactId, updatedAt]) } model ChatConversation { id String @id @default(cuid()) teamId String createdByUserId String title String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) createdByUser User @relation("ConversationCreator", fields: [createdByUserId], references: [id], onDelete: Cascade) messages ChatMessage[] @@index([teamId, updatedAt]) @@index([createdByUserId]) } model ChatMessage { id String @id @default(cuid()) teamId String conversationId String authorUserId String? role ChatRole text String planJson Json? createdAt DateTime @default(now()) team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) conversation ChatConversation @relation(fields: [conversationId], references: [id], onDelete: Cascade) authorUser User? @relation("ChatAuthor", fields: [authorUserId], references: [id], onDelete: SetNull) @@index([createdAt]) @@index([teamId, createdAt]) @@index([conversationId, createdAt]) } model FeedCard { id String @id @default(cuid()) teamId String contactId String? happenedAt DateTime text String proposalJson Json decision FeedCardDecision @default(PENDING) decisionNote String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) contact Contact? @relation(fields: [contactId], references: [id], onDelete: SetNull) @@index([teamId, happenedAt]) @@index([contactId, happenedAt]) } model ContactPin { id String @id @default(cuid()) teamId String contactId String text String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade) @@index([teamId, updatedAt]) @@index([contactId, updatedAt]) } model WorkspaceDocument { id String @id @default(cuid()) teamId String title String type WorkspaceDocumentType owner String scope String summary String body String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) @@index([teamId, updatedAt]) }