339 lines
12 KiB
Plaintext
339 lines
12 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// ── Organization ──────────────────────────────────────────────────────────────
|
|
|
|
model Organization {
|
|
id String @id @default(cuid())
|
|
name String
|
|
slug String @unique
|
|
logoUrl String?
|
|
primaryColor String?
|
|
stripeAccountId String?
|
|
publicUrl String?
|
|
localHostname String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
events AuctionEvent[]
|
|
bidders Bidder[]
|
|
staffUsers StaffUser[]
|
|
}
|
|
|
|
// ── Staff Users ───────────────────────────────────────────────────────────────
|
|
|
|
model StaffUser {
|
|
id String @id @default(cuid())
|
|
organizationId String
|
|
email String @unique
|
|
name String
|
|
role String // admin | event_manager | auctioneer | spotter | checkin_staff
|
|
passwordHash String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id])
|
|
auditLogs AuditLog[]
|
|
}
|
|
|
|
// ── Events ────────────────────────────────────────────────────────────────────
|
|
|
|
model AuctionEvent {
|
|
id String @id @default(cuid())
|
|
organizationId String
|
|
name String
|
|
slug String
|
|
description String?
|
|
venueAddress String?
|
|
startAt DateTime
|
|
endAt DateTime
|
|
status String @default("draft") // draft | published | active | closed | archived
|
|
timezone String @default("America/New_York")
|
|
bannerImageUrl String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id])
|
|
auctions Auction[]
|
|
bidders BidderEventEnrollment[]
|
|
invoices Invoice[]
|
|
donations Donation[]
|
|
paddleRaiseCampaigns PaddleRaiseCampaign[]
|
|
auditLogs AuditLog[]
|
|
|
|
@@unique([organizationId, slug])
|
|
}
|
|
|
|
// ── Auctions ──────────────────────────────────────────────────────────────────
|
|
|
|
model Auction {
|
|
id String @id @default(cuid())
|
|
eventId String
|
|
type String // live | silent
|
|
name String
|
|
status String @default("draft") // draft | active | paused | closed
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
event AuctionEvent @relation(fields: [eventId], references: [id])
|
|
items AuctionItem[]
|
|
silentWindows SilentAuctionWindow[]
|
|
}
|
|
|
|
// ── Auction Items ─────────────────────────────────────────────────────────────
|
|
|
|
model AuctionItem {
|
|
id String @id @default(cuid())
|
|
auctionId String
|
|
lotNumber String
|
|
title String
|
|
description String?
|
|
donorName String?
|
|
category String?
|
|
fairMarketValue Decimal?
|
|
openingBid Decimal @default(0)
|
|
reservePrice Decimal?
|
|
currentHighBid Decimal?
|
|
currentHighBidderId String?
|
|
bidIncrement Decimal @default(10)
|
|
state String @default("preview") // preview | active | going_once | going_twice | sold | passed | closed
|
|
pickupNotes String?
|
|
sortOrder Int @default(0)
|
|
silentWindowId String?
|
|
softCloseEnabled Boolean @default(false)
|
|
softCloseExtendMinutes Int @default(2)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
auction Auction @relation(fields: [auctionId], references: [id])
|
|
silentWindow SilentAuctionWindow? @relation(fields: [silentWindowId], references: [id])
|
|
currentHighBidder Bidder? @relation("CurrentHighBids", fields: [currentHighBidderId], references: [id])
|
|
media ItemMedia[]
|
|
bids Bid[]
|
|
|
|
@@unique([auctionId, lotNumber])
|
|
}
|
|
|
|
model ItemMedia {
|
|
id String @id @default(cuid())
|
|
itemId String
|
|
mediaType String // image | video | document | embed
|
|
url String
|
|
thumbnailUrl String?
|
|
caption String?
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
|
|
item AuctionItem @relation(fields: [itemId], references: [id], onDelete: Cascade)
|
|
}
|
|
|
|
model SilentAuctionWindow {
|
|
id String @id @default(cuid())
|
|
auctionId String
|
|
name String
|
|
opensAt DateTime
|
|
closesAt DateTime
|
|
softCloseEnabled Boolean @default(false)
|
|
softCloseExtendMinutes Int @default(2)
|
|
status String @default("pending") // pending | open | closed
|
|
|
|
auction Auction @relation(fields: [auctionId], references: [id])
|
|
items AuctionItem[]
|
|
}
|
|
|
|
// ── Bidders ───────────────────────────────────────────────────────────────────
|
|
|
|
model Bidder {
|
|
id String @id @default(cuid())
|
|
organizationId String
|
|
email String?
|
|
phone String?
|
|
firstName String
|
|
lastName String
|
|
paymentMethodOnFile Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id])
|
|
authMethods BidderAuthMethod[]
|
|
eventEnrollments BidderEventEnrollment[]
|
|
bids Bid[]
|
|
currentHighBids AuctionItem[] @relation("CurrentHighBids")
|
|
invoices Invoice[]
|
|
donations Donation[]
|
|
deviceSessions DeviceSession[]
|
|
notifications Notification[]
|
|
}
|
|
|
|
model BidderAuthMethod {
|
|
id String @id @default(cuid())
|
|
bidderId String
|
|
type String // email_magic_link | sms_otp
|
|
identifier String
|
|
verifiedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
|
|
bidder Bidder @relation(fields: [bidderId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([type, identifier])
|
|
}
|
|
|
|
model BidderEventEnrollment {
|
|
id String @id @default(cuid())
|
|
bidderId String
|
|
eventId String
|
|
paddleNumber String?
|
|
tableAssignment String?
|
|
notes String?
|
|
checkInStatus String @default("pending") // pending | checked_in
|
|
checkInAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
|
|
bidder Bidder @relation(fields: [bidderId], references: [id])
|
|
event AuctionEvent @relation(fields: [eventId], references: [id])
|
|
|
|
@@unique([bidderId, eventId])
|
|
@@unique([eventId, paddleNumber])
|
|
}
|
|
|
|
// ── Bids ──────────────────────────────────────────────────────────────────────
|
|
|
|
model Bid {
|
|
id String @id @default(cuid())
|
|
itemId String
|
|
bidderId String
|
|
amount Decimal
|
|
clientCreatedAt DateTime
|
|
serverReceivedAt DateTime @default(now())
|
|
originMode String // public | local_dns | local_ip | offline_queue
|
|
syncStatus String @default("synced") // synced | pending | conflict | rejected
|
|
deviceId String
|
|
clientSeq Int
|
|
isWinning Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
|
|
item AuctionItem @relation(fields: [itemId], references: [id])
|
|
bidder Bidder @relation(fields: [bidderId], references: [id])
|
|
|
|
@@index([itemId, createdAt])
|
|
@@index([bidderId])
|
|
}
|
|
|
|
// ── Paddle Raise & Donations ──────────────────────────────────────────────────
|
|
|
|
model PaddleRaiseCampaign {
|
|
id String @id @default(cuid())
|
|
eventId String
|
|
name String
|
|
goal Decimal?
|
|
totalRaised Decimal @default(0)
|
|
tiers Json @default("[]") // number[]
|
|
isActive Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
event AuctionEvent @relation(fields: [eventId], references: [id])
|
|
donations Donation[]
|
|
}
|
|
|
|
model Donation {
|
|
id String @id @default(cuid())
|
|
eventId String
|
|
bidderId String?
|
|
campaignId String?
|
|
amount Decimal
|
|
anonymous Boolean @default(false)
|
|
stripePaymentIntentId String?
|
|
createdAt DateTime @default(now())
|
|
|
|
event AuctionEvent @relation(fields: [eventId], references: [id])
|
|
bidder Bidder? @relation(fields: [bidderId], references: [id])
|
|
campaign PaddleRaiseCampaign? @relation(fields: [campaignId], references: [id])
|
|
}
|
|
|
|
// ── Invoices & Payments ───────────────────────────────────────────────────────
|
|
|
|
model Invoice {
|
|
id String @id @default(cuid())
|
|
bidderId String
|
|
eventId String
|
|
stripeInvoiceId String?
|
|
totalAmount Decimal @default(0)
|
|
paidAmount Decimal @default(0)
|
|
status String @default("draft") // draft | open | paid | partially_paid | void
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
bidder Bidder @relation(fields: [bidderId], references: [id])
|
|
event AuctionEvent @relation(fields: [eventId], references: [id])
|
|
payments Payment[]
|
|
}
|
|
|
|
model Payment {
|
|
id String @id @default(cuid())
|
|
invoiceId String
|
|
stripePaymentIntentId String?
|
|
amount Decimal
|
|
currency String @default("usd")
|
|
status String // pending | succeeded | failed | refunded
|
|
createdAt DateTime @default(now())
|
|
|
|
invoice Invoice @relation(fields: [invoiceId], references: [id])
|
|
}
|
|
|
|
// ── Device Sessions ───────────────────────────────────────────────────────────
|
|
|
|
model DeviceSession {
|
|
id String @id @default(cuid())
|
|
bidderId String
|
|
deviceId String @unique
|
|
userAgent String?
|
|
lastSeenAt DateTime @default(now())
|
|
createdAt DateTime @default(now())
|
|
|
|
bidder Bidder @relation(fields: [bidderId], references: [id])
|
|
}
|
|
|
|
// ── Audit Log ─────────────────────────────────────────────────────────────────
|
|
|
|
model AuditLog {
|
|
id String @id @default(cuid())
|
|
eventId String?
|
|
staffUserId String?
|
|
action String
|
|
entityType String
|
|
entityId String
|
|
payload Json?
|
|
originMode String? // mirrors bid origin when relevant
|
|
ipAddress String?
|
|
createdAt DateTime @default(now())
|
|
|
|
event AuctionEvent? @relation(fields: [eventId], references: [id])
|
|
staffUser StaffUser? @relation(fields: [staffUserId], references: [id])
|
|
|
|
@@index([eventId, createdAt])
|
|
@@index([entityType, entityId])
|
|
}
|
|
|
|
// ── Notifications ─────────────────────────────────────────────────────────────
|
|
|
|
model Notification {
|
|
id String @id @default(cuid())
|
|
bidderId String
|
|
type String // outbid | item_closed | checkout_ready | otp | receipt
|
|
channel String // in_app | push | email | sms
|
|
payload Json
|
|
sentAt DateTime?
|
|
readAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
|
|
bidder Bidder @relation(fields: [bidderId], references: [id])
|
|
}
|