Files
Atlas/prisma/schema.prisma
2025-11-12 20:21:32 +01:00

425 lines
10 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum UserRole {
ADMIN
DRIVER
}
enum BookingStatus {
RESERVED // Initial (nach E-Mail-Eingang)
CONFIRMED // Admin hat bestätigt & gesendet
READY_FOR_ASSIGNMENT // Vertrag unterschrieben → Admin-Freigabe
OPEN_FOR_DRIVERS // Admin hat freigegeben → Fahrer können sich melden
ASSIGNED // Admin hat Fahrer zugewiesen & Tour erstellt
COMPLETED // Event abgeschlossen
CANCELLED // Storniert
}
enum PhotoboxStatus {
AVAILABLE
IN_USE
MAINTENANCE
DAMAGED
}
enum PhotoboxModel {
VINTAGE_SMILE
VINTAGE_PHOTOS
NOSTALGIE
MAGIC_MIRROR
}
enum InvoiceType {
PRIVATE
BUSINESS
}
enum EquipmentType {
PRINTER
CARPET
VIP_BARRIER
ACCESSORIES_KIT
PRINTER_PAPER
TRIPOD
OTHER
}
enum EquipmentStatus {
AVAILABLE
IN_USE
MAINTENANCE
DAMAGED
RESERVED
}
model User {
id String @id @default(cuid())
email String @unique
name String
password String
role UserRole @default(DRIVER)
phoneNumber String?
vehiclePlate String?
vehicleModel String?
active Boolean @default(true)
available Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
driverTours Tour[]
notifications Notification[]
driverAvailability DriverAvailability[]
}
model Location {
id String @id @default(cuid())
name String
city String
slug String @unique
websiteUrl String
contactEmail String
active Boolean @default(true)
imapHost String?
imapPort Int?
imapUser String?
imapPassword String?
imapSecure Boolean @default(true)
smtpHost String?
smtpPort Int?
smtpUser String?
smtpPassword String?
smtpSecure Boolean @default(true)
emailSyncEnabled Boolean @default(false)
lastEmailSync DateTime?
priceConfig PriceConfig[]
photoboxes Photobox[]
bookings Booking[]
equipment Equipment[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([slug])
}
model PriceConfig {
id String @id @default(cuid())
locationId String
location Location @relation(fields: [locationId], references: [id], onDelete: Cascade)
model PhotoboxModel
basePrice Float
pricePerKm Float
includedKm Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([locationId, model])
}
model Photobox {
id String @id @default(cuid())
locationId String
location Location @relation(fields: [locationId], references: [id], onDelete: Cascade)
model PhotoboxModel
serialNumber String @unique
status PhotoboxStatus @default(AVAILABLE)
active Boolean @default(true)
description String?
purchaseDate DateTime?
lastMaintenance DateTime?
bookings Booking[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([locationId, model])
@@index([status])
}
model Booking {
id String @id @default(cuid())
bookingNumber String @unique
locationId String
location Location @relation(fields: [locationId], references: [id])
photoboxId String?
photobox Photobox? @relation(fields: [photoboxId], references: [id])
status BookingStatus @default(RESERVED)
customerName String
customerEmail String
customerPhone String
customerAddress String?
customerCity String?
customerZip String?
invoiceType InvoiceType @default(PRIVATE)
companyName String?
eventDate DateTime
eventAddress String
eventCity String
eventZip String
eventLocation String?
setupTimeStart DateTime
setupTimeLatest DateTime
dismantleTimeEarliest DateTime?
dismantleTimeLatest DateTime?
distance Float?
calculatedPrice Float?
// Contract Management
contractSigned Boolean @default(false)
contractSignedAt DateTime?
contractGenerated Boolean @default(false)
contractGeneratedAt DateTime?
contractSentAt DateTime?
contractSignedOnline Boolean @default(false)
contractPdfUrl String?
contractSignatureData String? @db.Text
contractSignedBy String?
contractSignedIp String?
contractUploadedBy String?
lexofficeOfferId String?
lexofficeInvoiceId String?
lexofficeContactId String?
lexofficeConfirmationId String?
confirmationSentAt DateTime?
// KI-Analyse
aiParsed Boolean @default(false)
aiResponseDraft String? @db.Text
aiProcessedAt DateTime?
// Freigabe-Status
readyForAssignment Boolean @default(false)
openForDrivers Boolean @default(false)
// Kalender-Sync (Nextcloud)
calendarEventId String?
calendarSynced Boolean @default(false)
calendarSyncedAt DateTime?
tourId String?
tour Tour? @relation(fields: [tourId], references: [id])
notes String?
internalNotes String?
emails Email[]
bookingEquipment BookingEquipment[]
driverAvailability DriverAvailability[]
setupWindows SetupWindow[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([eventDate])
@@index([status])
@@index([locationId])
}
model SetupWindow {
id String @id @default(cuid())
bookingId String
booking Booking @relation(fields: [bookingId], references: [id], onDelete: Cascade)
setupDate DateTime
setupTimeStart DateTime
setupTimeEnd DateTime
preferred Boolean @default(false)
selected Boolean @default(false)
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([bookingId])
@@index([setupDate])
}
enum TourStatus {
PLANNED
IN_PROGRESS
COMPLETED
CANCELLED
}
model Tour {
id String @id @default(cuid())
tourDate DateTime
tourNumber String @unique
driverId String?
driver User? @relation(fields: [driverId], references: [id])
bookings Booking[]
routeOptimized Json?
totalDistance Float?
estimatedDuration Int?
status TourStatus @default(PLANNED)
startedAt DateTime?
completedAt DateTime?
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([tourDate])
@@index([driverId])
@@index([status])
}
model Notification {
id String @id @default(cuid())
userId String?
user User? @relation(fields: [userId], references: [id])
type String
title String
message String
read Boolean @default(false)
metadata Json?
createdAt DateTime @default(now())
@@index([userId, read])
}
model Email {
id String @id @default(cuid())
locationSlug String?
from String
to String
subject String
textBody String?
htmlBody String?
messageId String? @unique
inReplyTo String?
bookingId String?
booking Booking? @relation(fields: [bookingId], references: [id])
parsed Boolean @default(false)
parsedData Json?
direction String @default("INBOUND")
receivedAt DateTime @default(now())
createdAt DateTime @default(now())
@@index([locationSlug])
@@index([bookingId])
@@index([receivedAt])
}
model Project {
id String @id @default(cuid())
name String
description String?
active Boolean @default(true)
equipment Equipment[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Equipment {
id String @id @default(cuid())
name String
type EquipmentType
brand String?
model String?
serialNumber String? @unique
quantity Int @default(1)
status EquipmentStatus @default(AVAILABLE)
locationId String?
location Location? @relation(fields: [locationId], references: [id])
projectId String?
project Project? @relation(fields: [projectId], references: [id])
notes String?
purchaseDate DateTime?
purchasePrice Decimal?
minStockLevel Int?
currentStock Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
bookingEquipment BookingEquipment[]
@@index([type])
@@index([status])
@@index([locationId])
}
model BookingEquipment {
id String @id @default(cuid())
bookingId String
booking Booking @relation(fields: [bookingId], references: [id], onDelete: Cascade)
equipmentId String
equipment Equipment @relation(fields: [equipmentId], references: [id])
quantity Int @default(1)
createdAt DateTime @default(now())
@@unique([bookingId, equipmentId])
@@index([bookingId])
@@index([equipmentId])
}
model DriverAvailability {
id String @id @default(cuid())
bookingId String
booking Booking @relation(fields: [bookingId], references: [id], onDelete: Cascade)
driverId String
driver User @relation(fields: [driverId], references: [id], onDelete: Cascade)
available Boolean @default(true)
message String? @db.Text
createdAt DateTime @default(now())
@@unique([bookingId, driverId])
@@index([bookingId])
@@index([driverId])
}