// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
previewFeatures = ["postgresqlExtensions"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
extensions = [vector]
}
model Quote {
id String @id @db.VarChar(50)
quoteDate DateTime @map("quote_date") @db.Timestamptz(6)
customerName String @map("customer_name") @db.VarChar(255)
contactEmail String? @map("contact_email") @db.VarChar(255)
// Normalized fields for matching
material String? @db.VarChar(100)
processes String[] @db.Text
qtyMin Int? @map("qty_min")
qtyMax Int? @map("qty_max")
tolerances String? @db.VarChar(100)
finish String? @db.VarChar(100)
// Costs and timing
costPerUnit Decimal @map("cost_per_unit") @db.Decimal(10, 2)
totalCost Decimal @map("total_cost") @db.Decimal(10, 2)
leadDays Int @map("lead_days")
actualLeadDays Int? @map("actual_lead_days")
// Metadata
approved Boolean @default(false)
won Boolean?
notes String? @db.Text
rawRfp String? @map("raw_rfp") @db.Text
// Vector embedding for semantic search
embedding Unsupported("vector(1536)")?
// Audit fields
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6)
createdBy String? @map("created_by") @db.VarChar(100)
// Relations
pdfUploads PdfUpload[]
@@index([material])
@@index([quoteDate(sort: Desc)])
@@index([customerName])
@@map("quotes")
}
model Evaluation {
id String @id @db.VarChar(64)
idempotencyKey String @unique @map("idempotency_key") @db.VarChar(64)
// Input RFP
rawText String @map("raw_text") @db.Text
qty Int?
contactEmail String? @map("contact_email") @db.VarChar(255)
customerName String? @map("customer_name") @db.VarChar(255)
// Parsed data (stored as JSON)
parsedRfp Json? @map("parsed_rfp")
// Results (stored as JSON)
matches Json? // Array of similar quotes with scores
estimate Json? // Cost and lead time estimate
quoteDoc Json? @map("quote_doc") // Generated quote document
confidence String? @db.VarChar(10) // high/medium/low
// Status
status String @default("draft") @db.VarChar(20) // draft/approved/sent
approvedBy String? @map("approved_by") @db.VarChar(100)
approvedAt DateTime? @map("approved_at") @db.Timestamptz(6)
sentAt DateTime? @map("sent_at") @db.Timestamptz(6)
// Audit
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
createdBy String? @map("created_by") @db.VarChar(100)
// Relations
pdfUploads PdfUpload[]
@@index([createdAt(sort: Desc)])
@@index([status])
@@index([customerName])
@@map("evaluations")
}
model User {
id Int @id @default(autoincrement())
username String @unique @db.VarChar(100)
email String @unique @db.VarChar(255)
role String @db.VarChar(20) // engineer/manager/admin
active Boolean @default(true)
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
lastLogin DateTime? @map("last_login") @db.Timestamptz(6)
// Relations
auditLogs AuditLog[]
@@map("users")
}
model AuditLog {
id Int @id @default(autoincrement())
timestamp DateTime @default(now()) @db.Timestamptz(6)
userId Int? @map("user_id")
action String @db.VarChar(100) // ingest_rfp/generate_quote/approve/send
resourceType String? @map("resource_type") @db.VarChar(50) // evaluation/quote
resourceId String? @map("resource_id") @db.VarChar(100)
details Json?
ipAddress String? @map("ip_address") @db.Inet
userAgent String? @map("user_agent") @db.Text
// Relations
user User? @relation(fields: [userId], references: [id])
@@index([timestamp(sort: Desc)])
@@index([userId])
@@index([action])
@@map("audit_logs")
}
model PdfUpload {
id Int @id @default(autoincrement())
evaluationId String? @map("evaluation_id") @db.VarChar(64)
quoteId String? @map("quote_id") @db.VarChar(50)
filename String @db.VarChar(255)
filePath String @map("file_path") @db.VarChar(500)
fileSize Int? @map("file_size")
mimeType String? @map("mime_type") @db.VarChar(100)
extractedText String? @map("extracted_text") @db.Text
metadata Json?
uploadedAt DateTime @default(now()) @map("uploaded_at") @db.Timestamptz(6)
uploadedBy String? @map("uploaded_by") @db.VarChar(100)
// Relations
evaluation Evaluation? @relation(fields: [evaluationId], references: [id])
quote Quote? @relation(fields: [quoteId], references: [id])
@@index([evaluationId])
@@index([quoteId])
@@map("pdf_uploads")
}