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") }