// ============================================================ // INSIGHT MVP - Core Schema (platform_core Datenbank) // ============================================================ // Zentrale Plattform-Tabellen: Users, Tenants, Auth, Modules // Kein raw SQL - nur Prisma! // ============================================================ generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") directUrl = env("DATABASE_URL_DIRECT") } // -------------------------------------------------------- // User - Plattform-Benutzer // -------------------------------------------------------- model User { id String @id @default(uuid()) @db.Uuid email String @unique @db.VarChar(255) firstName String @map("first_name") @db.VarChar(100) lastName String @map("last_name") @db.VarChar(100) avatar String? @db.Text // Profilbild als Base64 Data-URL // Kontaktdaten phone String? @map("phone") @db.VarChar(30) mobile String? @map("mobile") @db.VarChar(30) // Adresse street String? @map("street") @db.VarChar(200) postalCode String? @map("postal_code") @db.VarChar(10) city String? @map("city") @db.VarChar(100) role String @default("USER") @db.VarChar(50) // PLATFORM_ADMIN, TENANT_ADMIN, USER isActive Boolean @default(true) @map("is_active") // 2FA twoFactorEnabled Boolean @default(false) @map("two_factor_enabled") // Login-Tracking lastLogin DateTime? @map("last_login") failedLoginAttempts Int @default(0) @map("failed_login_attempts") lastFailedLogin DateTime? @map("last_failed_login") // Timestamps createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relationen authProvider AuthProvider[] tenantMemberships TenantMembership[] auditLogs AuditLog[] expertProfile ExpertProfile? @@map("users") } // -------------------------------------------------------- // AuthProvider - Authentifizierungs-Provider pro User // -------------------------------------------------------- // Unterstuetzt mehrere Auth-Methoden pro User: // LOCAL (Passwort), MS_SSO (spaeter), M2M (Machine-to-Machine) model AuthProvider { id String @id @default(uuid()) @db.Uuid userId String @map("user_id") @db.Uuid provider String @db.VarChar(50) // LOCAL, MS_SSO, M2M providerId String? @map("provider_id") @db.VarChar(255) // Externe ID (z.B. MS Object ID) passwordHash String? @map("password_hash") @db.VarChar(255) totpSecret String? @map("totp_secret") @db.VarChar(255) // Verschluesselt createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relationen user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([userId, provider]) @@map("auth_providers") } // -------------------------------------------------------- // Tenant - Mandant // -------------------------------------------------------- model Tenant { id String @id @default(uuid()) @db.Uuid name String @db.VarChar(200) slug String @unique @db.VarChar(50) // URL-freundlich, fuer DB-Name isActive Boolean @default(true) @map("is_active") // Mandant-Einstellungen (JSON) settings Json @default("{}") // Timestamps createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relationen members TenantMembership[] modules TenantModule[] @@map("tenants") } // -------------------------------------------------------- // TenantMembership - User-Tenant-Zuordnung (M:N) // -------------------------------------------------------- model TenantMembership { id String @id @default(uuid()) @db.Uuid userId String @map("user_id") @db.Uuid tenantId String @map("tenant_id") @db.Uuid tenantRole String @default("MEMBER") @map("tenant_role") @db.VarChar(50) // ADMIN, MEMBER, VIEWER isActive Boolean @default(true) @map("is_active") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relationen user User @relation(fields: [userId], references: [id], onDelete: Cascade) tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade) @@unique([userId, tenantId]) @@map("tenant_memberships") } // -------------------------------------------------------- // Module - Verfuegbare Plattform-Module // -------------------------------------------------------- model Module { id String @id @default(uuid()) @db.Uuid key String @unique @db.VarChar(50) // z.B. "crm", "project", "docs" name String @db.VarChar(100) description String? @db.Text version String @default("1.0.0") @db.VarChar(20) isActive Boolean @default(true) @map("is_active") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relationen tenantModules TenantModule[] @@map("modules") } // -------------------------------------------------------- // TenantModule - Welcher Tenant welche Module nutzt // -------------------------------------------------------- model TenantModule { id String @id @default(uuid()) @db.Uuid tenantId String @map("tenant_id") @db.Uuid moduleId String @map("module_id") @db.Uuid isActive Boolean @default(true) @map("is_active") // Modul-spezifische Konfiguration pro Tenant config Json @default("{}") activatedAt DateTime @default(now()) @map("activated_at") // Relationen tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade) module Module @relation(fields: [moduleId], references: [id], onDelete: Cascade) @@unique([tenantId, moduleId]) @@map("tenant_modules") } // -------------------------------------------------------- // AuditLog - Plattform-weites Audit-Log // -------------------------------------------------------- model AuditLog { id String @id @default(uuid()) @db.Uuid userId String? @map("user_id") @db.Uuid action String @db.VarChar(100) // z.B. "user.login", "tenant.create" entity String @db.VarChar(100) // z.B. "User", "Tenant" entityId String? @map("entity_id") @db.VarChar(255) details Json? // Zusaetzliche Informationen ipAddress String? @map("ip_address") @db.VarChar(45) userAgent String? @map("user_agent") @db.Text createdAt DateTime @default(now()) @map("created_at") // Relationen user User? @relation(fields: [userId], references: [id], onDelete: SetNull) @@index([userId]) @@index([action]) @@index([entity, entityId]) @@index([createdAt]) @@map("audit_logs") } // -------------------------------------------------------- // ExpertProfile - Experten-Profil (1:1 mit User) // -------------------------------------------------------- model ExpertProfile { id String @id @default(uuid()) @db.Uuid userId String @unique @map("user_id") @db.Uuid // Skills als Tag-Array skills String[] @default([]) // Timestamps createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relationen user User @relation(fields: [userId], references: [id], onDelete: Cascade) experiences ExpertExperience[] languages ExpertLanguage[] projects ExpertProject[] certifications ExpertCertification[] attachments ExpertAttachment[] @@map("expert_profiles") } // -------------------------------------------------------- // ExpertExperience - Erfahrung / Expertise-Bereiche // -------------------------------------------------------- model ExpertExperience { id String @id @default(uuid()) @db.Uuid expertProfileId String @map("expert_profile_id") @db.Uuid area String @db.VarChar(200) // z.B. "IT Infrastruktur" years Int // Jahre Erfahrung level String? @db.VarChar(50) // Experte, Fortgeschritten, Grundkenntnisse createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relationen expertProfile ExpertProfile @relation(fields: [expertProfileId], references: [id], onDelete: Cascade) @@map("expert_experiences") } // -------------------------------------------------------- // ExpertLanguage - Sprachen // -------------------------------------------------------- model ExpertLanguage { id String @id @default(uuid()) @db.Uuid expertProfileId String @map("expert_profile_id") @db.Uuid language String @db.VarChar(100) // z.B. "Deutsch" level String @db.VarChar(20) // Muttersprache, C2, C1, B2, B1, A2, A1 createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relationen expertProfile ExpertProfile @relation(fields: [expertProfileId], references: [id], onDelete: Cascade) @@map("expert_languages") } // -------------------------------------------------------- // ExpertProject - Projekthistorie // -------------------------------------------------------- model ExpertProject { id String @id @default(uuid()) @db.Uuid expertProfileId String @map("expert_profile_id") @db.Uuid // Zeitraum fromMonth Int @map("from_month") // 1-12 fromYear Int @map("from_year") // z.B. 2023 toMonth Int? @map("to_month") // null wenn isCurrent toYear Int? @map("to_year") isCurrent Boolean @default(false) @map("is_current") // Details role String @db.VarChar(200) // Taetigkeit tasks String? @db.Text // Aufgaben (max 1500 Zeichen im DTO) company String? @db.VarChar(200) // Firma companySize String? @map("company_size") @db.VarChar(20) // "1-10", "11-50", etc. industry String? @db.VarChar(200) // Branche createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relationen expertProfile ExpertProfile @relation(fields: [expertProfileId], references: [id], onDelete: Cascade) @@index([expertProfileId, fromYear, fromMonth]) @@map("expert_projects") } // -------------------------------------------------------- // ExpertCertification - Zertifizierungen // -------------------------------------------------------- model ExpertCertification { id String @id @default(uuid()) @db.Uuid expertProfileId String @map("expert_profile_id") @db.Uuid title String @db.VarChar(300) // Titel issuingBody String @map("issuing_body") @db.VarChar(300) // Zertifizierungsstelle website String? @db.VarChar(500) // URL issueYear Int @map("issue_year") // Ausstellungsjahr createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relationen expertProfile ExpertProfile @relation(fields: [expertProfileId], references: [id], onDelete: Cascade) @@map("expert_certifications") } // -------------------------------------------------------- // ExpertAttachment - Profilanlagen (Dateien als Base64) // -------------------------------------------------------- model ExpertAttachment { id String @id @default(uuid()) @db.Uuid expertProfileId String @map("expert_profile_id") @db.Uuid filename String @db.VarChar(255) mimetype String @db.VarChar(100) size Int // Groesse in Bytes data String @db.Text // Base64-Daten createdAt DateTime @default(now()) @map("created_at") // Relationen expertProfile ExpertProfile @relation(fields: [expertProfileId], references: [id], onDelete: Cascade) @@map("expert_attachments") }