415 lines
10 KiB
Plaintext
415 lines
10 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
enum Role {
|
|
SERVER_ADMIN
|
|
TENANT_ADMIN
|
|
OPERATOR
|
|
VIEWER
|
|
}
|
|
|
|
enum IconType {
|
|
STANDARD
|
|
RETTUNG
|
|
GEFAHRSTOFF
|
|
FEUER
|
|
WASSER
|
|
FAHRZEUG
|
|
}
|
|
|
|
enum ItemKind {
|
|
SYMBOL
|
|
LINE
|
|
POLYGON
|
|
RECTANGLE
|
|
CIRCLE
|
|
ARROW
|
|
TEXT
|
|
}
|
|
|
|
enum SubscriptionPlan {
|
|
FREE
|
|
PRO
|
|
}
|
|
|
|
enum DictionaryScope {
|
|
GLOBAL
|
|
TENANT
|
|
}
|
|
|
|
enum SubscriptionStatus {
|
|
ACTIVE
|
|
TRIAL
|
|
SUSPENDED
|
|
EXPIRED
|
|
CANCELLED
|
|
}
|
|
|
|
model Tenant {
|
|
id String @id @default(uuid())
|
|
name String
|
|
slug String @unique
|
|
description String?
|
|
isActive Boolean @default(true)
|
|
contactEmail String?
|
|
contactPhone String?
|
|
address String?
|
|
|
|
logoUrl String?
|
|
logoFileKey String?
|
|
|
|
// Subscription
|
|
plan SubscriptionPlan @default(FREE)
|
|
subscriptionStatus SubscriptionStatus @default(ACTIVE)
|
|
trialEndsAt DateTime?
|
|
subscriptionEndsAt DateTime?
|
|
maxUsers Int @default(5)
|
|
maxProjects Int @default(10)
|
|
notes String?
|
|
hiddenIconIds String[] @default([])
|
|
journalSuggestions String[] @default([])
|
|
|
|
// Privacy consent
|
|
privacyAccepted Boolean @default(false)
|
|
privacyAcceptedAt DateTime?
|
|
adminAccessAccepted Boolean @default(false)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
memberships TenantMembership[]
|
|
projects Project[]
|
|
hoseTypes HoseType[]
|
|
checkTemplates JournalCheckTemplate[]
|
|
iconCategories IconCategory[]
|
|
iconAssets IconAsset[]
|
|
upgradeRequests UpgradeRequest[]
|
|
dictionaryEntries DictionaryEntry[]
|
|
rapports Rapport[]
|
|
|
|
@@map("tenants")
|
|
}
|
|
|
|
// ─── System Settings (Key-Value, encrypted for secrets) ──────
|
|
|
|
model SystemSetting {
|
|
id String @id @default(uuid())
|
|
key String @unique
|
|
value String
|
|
isSecret Boolean @default(false)
|
|
category String @default("general")
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("system_settings")
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(uuid())
|
|
email String @unique
|
|
password String
|
|
name String
|
|
role Role @default(OPERATOR)
|
|
emailVerified Boolean @default(true)
|
|
emailVerificationToken String? @unique
|
|
resetToken String? @unique
|
|
resetTokenExpiry DateTime?
|
|
lastLoginAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
memberships TenantMembership[]
|
|
projects Project[]
|
|
iconAssets IconAsset[]
|
|
upgradeRequests UpgradeRequest[]
|
|
rapports Rapport[]
|
|
|
|
@@map("users")
|
|
}
|
|
|
|
model TenantMembership {
|
|
id String @id @default(uuid())
|
|
role Role @default(OPERATOR)
|
|
createdAt DateTime @default(now())
|
|
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
tenantId String
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([userId, tenantId])
|
|
@@map("tenant_memberships")
|
|
}
|
|
|
|
model Project {
|
|
id String @id @default(uuid())
|
|
einsatzNr String?
|
|
title String
|
|
location String?
|
|
description String?
|
|
einsatzleiter String?
|
|
journalfuehrer String?
|
|
mapCenter Json @default("{\"lng\": 8.5417, \"lat\": 47.3769}")
|
|
mapZoom Float @default(15)
|
|
isLocked Boolean @default(false)
|
|
|
|
// Live editing lock (session-based for same-account multi-device)
|
|
editingById String?
|
|
editingUserName String?
|
|
editingSessionId String?
|
|
editingStartedAt DateTime?
|
|
editingHeartbeat DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
ownerId String?
|
|
owner User? @relation(fields: [ownerId], references: [id], onDelete: SetNull)
|
|
tenantId String?
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)
|
|
|
|
features Feature[]
|
|
items Item[]
|
|
journalEntries JournalEntry[]
|
|
journalCheckItems JournalCheckItem[]
|
|
journalPendenzen JournalPendenz[]
|
|
rapports Rapport[]
|
|
|
|
@@map("projects")
|
|
}
|
|
|
|
model Feature {
|
|
id String @id @default(uuid())
|
|
type String
|
|
geometry Json
|
|
properties Json @default("{}")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
projectId String
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("features")
|
|
}
|
|
|
|
model IconCategory {
|
|
id String @id @default(uuid())
|
|
name String
|
|
description String?
|
|
sortOrder Int @default(0)
|
|
isGlobal Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
|
|
tenantId String?
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)
|
|
|
|
icons IconAsset[]
|
|
|
|
@@map("icon_categories")
|
|
}
|
|
|
|
model IconAsset {
|
|
id String @id @default(uuid())
|
|
name String
|
|
fileKey String
|
|
mimeType String
|
|
width Int?
|
|
height Int?
|
|
isSystem Boolean @default(false)
|
|
isActive Boolean @default(true)
|
|
iconType IconType @default(STANDARD)
|
|
tags String[] @default([])
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
categoryId String?
|
|
category IconCategory? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
|
|
|
|
ownerId String?
|
|
owner User? @relation(fields: [ownerId], references: [id], onDelete: SetNull)
|
|
|
|
tenantId String?
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)
|
|
|
|
@@map("icon_assets")
|
|
}
|
|
|
|
model HoseType {
|
|
id String @id @default(uuid())
|
|
name String @unique
|
|
diameterMm Int
|
|
lengthPerPieceM Int @default(10)
|
|
flowRateLpm Float
|
|
frictionCoeff Float
|
|
description String?
|
|
isDefault Boolean @default(false)
|
|
isActive Boolean @default(true)
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenantId String?
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)
|
|
|
|
@@map("hose_types")
|
|
}
|
|
|
|
// ─── Journal ───────────────────────────────────────────────
|
|
|
|
model JournalEntry {
|
|
id String @id @default(uuid())
|
|
time DateTime @default(now())
|
|
what String
|
|
who String?
|
|
done Boolean @default(false)
|
|
doneAt DateTime?
|
|
sortOrder Int @default(0)
|
|
isCorrected Boolean @default(false)
|
|
correctionOfId String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
projectId String
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("journal_entries")
|
|
}
|
|
|
|
model JournalCheckItem {
|
|
id String @id @default(uuid())
|
|
label String
|
|
confirmed Boolean @default(false)
|
|
confirmedAt DateTime?
|
|
ok Boolean @default(false)
|
|
okAt DateTime?
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
projectId String
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("journal_check_items")
|
|
}
|
|
|
|
model JournalPendenz {
|
|
id String @id @default(uuid())
|
|
what String
|
|
who String?
|
|
whenHow String?
|
|
done Boolean @default(false)
|
|
doneAt DateTime?
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
projectId String
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("journal_pendenzen")
|
|
}
|
|
|
|
model JournalCheckTemplate {
|
|
id String @id @default(uuid())
|
|
label String
|
|
sortOrder Int @default(0)
|
|
isActive Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
|
|
tenantId String?
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)
|
|
|
|
@@map("journal_check_templates")
|
|
}
|
|
|
|
model Item {
|
|
id String @id @default(uuid())
|
|
kind ItemKind
|
|
geometry Json
|
|
style Json @default("{}")
|
|
properties Json @default("{}")
|
|
isVisible Boolean @default(true)
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
projectId String
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
|
|
iconId String?
|
|
|
|
@@map("items")
|
|
}
|
|
|
|
// ─── Upgrade Requests ─────────────────────────────────────
|
|
|
|
enum UpgradeRequestStatus {
|
|
PENDING
|
|
APPROVED
|
|
REJECTED
|
|
}
|
|
|
|
model UpgradeRequest {
|
|
id String @id @default(uuid())
|
|
requestedPlan SubscriptionPlan
|
|
currentPlan SubscriptionPlan
|
|
message String?
|
|
status UpgradeRequestStatus @default(PENDING)
|
|
adminNote String?
|
|
processedAt DateTime?
|
|
processedById String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenantId String
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
|
|
requestedById String
|
|
requestedBy User @relation(fields: [requestedById], references: [id], onDelete: Cascade)
|
|
|
|
@@map("upgrade_requests")
|
|
}
|
|
|
|
// ─── Dictionary (Global + Tenant word library) ────────────
|
|
|
|
model DictionaryEntry {
|
|
id String @id @default(uuid())
|
|
word String
|
|
scope DictionaryScope @default(GLOBAL)
|
|
createdAt DateTime @default(now())
|
|
|
|
tenantId String?
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([word, tenantId])
|
|
@@map("dictionary_entries")
|
|
}
|
|
|
|
// ─── Rapport (PDF reports with public token access) ───────
|
|
|
|
model Rapport {
|
|
id String @id @default(uuid())
|
|
reportNumber String
|
|
token String @unique @default(uuid())
|
|
data Json
|
|
generatedAt DateTime @default(now())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
projectId String
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
|
|
tenantId String?
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
|
|
createdById String?
|
|
createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
|
|
|
|
@@map("rapports")
|
|
}
|