mirror of
http://172.20.10.11:3000/gitadmin/INSIGHT-MVP.git
synced 2026-06-25 00:16:41 +02:00
- Phase 2.3 Forecast: probability-Feld in PipelineStage, GET /crm/deals/forecast Endpoint - Phase 2.2 Import: ImportModule mit preview/execute/history Endpoints (CSV, XLSX, vCard) - Phase 2.4 Enrichment: EnrichmentModule mit /enrich + /settings/integrations/north-data - Contracts: ContractsModule mit CRUD + File-Upload Endpoints (Multer, max 25MB) - Migrations: 20260312_contract_files, 20260312_phase23_forecast - docker-compose.crm.yml: uploads Volume für Vertragsdokumente Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
844 lines
27 KiB
Text
844 lines
27 KiB
Text
// ============================================================
|
|
// INSIGHT CRM Service - Prisma Schema
|
|
// ============================================================
|
|
// Eigenes Schema im PostgreSQL-Schema 'app_crm'
|
|
// Eigener Prisma-Client-Output (kein Konflikt mit Core)
|
|
// ============================================================
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
output = "../node_modules/.prisma/crm-client"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
directUrl = env("DATABASE_URL_DIRECT")
|
|
schemas = ["app_crm"]
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Industry - Branche (admin-konfigurierbar pro Tenant)
|
|
// --------------------------------------------------------
|
|
model Industry {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
name String @db.VarChar(100)
|
|
color String @default("#6B7280") @db.VarChar(7)
|
|
sortOrder Int @default(0) @map("sort_order")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
companies Company[]
|
|
|
|
@@unique([tenantId, name])
|
|
@@index([tenantId])
|
|
@@map("industries")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// AccountType - Kontotyp (admin-konfigurierbar pro Tenant)
|
|
// --------------------------------------------------------
|
|
model AccountType {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
name String @db.VarChar(100)
|
|
sortOrder Int @default(0) @map("sort_order")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
companies Company[]
|
|
|
|
@@unique([tenantId, name])
|
|
@@index([tenantId])
|
|
@@map("account_types")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// RelationshipType - Beziehungstyp (admin-konfigurierbar)
|
|
// --------------------------------------------------------
|
|
model RelationshipType {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
name String @db.VarChar(100)
|
|
sortOrder Int @default(0) @map("sort_order")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
relationships CompanyRelationship[]
|
|
|
|
@@unique([tenantId, name])
|
|
@@index([tenantId])
|
|
@@map("relationship_types")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Company - Unternehmen (uebergeordnete Entity)
|
|
// --------------------------------------------------------
|
|
model Company {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
|
|
name String @db.VarChar(200)
|
|
industry String? @db.VarChar(100)
|
|
|
|
// Admin-konfigurierbare Felder
|
|
industryId String? @map("industry_id") @db.Uuid
|
|
accountTypeId String? @map("account_type_id") @db.Uuid
|
|
ownerId String? @map("owner_id") @db.Uuid
|
|
ownerName String? @map("owner_name") @db.VarChar(200)
|
|
|
|
// Phase 1: Registerdaten
|
|
vatId String? @map("vat_id") @db.VarChar(50)
|
|
taxId String? @map("tax_id") @db.VarChar(50)
|
|
tradeRegisterNumber String? @map("trade_register_number") @db.VarChar(100)
|
|
registerCourt String? @map("register_court") @db.VarChar(200)
|
|
companySize CompanySize? @map("company_size")
|
|
|
|
// Kontaktdaten (Legacy-Einzelfelder, deprecated — siehe emails[]/phones[])
|
|
email String? @db.VarChar(255)
|
|
phone String? @db.VarChar(50)
|
|
website String? @db.VarChar(500)
|
|
|
|
// Adresse (Hauptsitz)
|
|
street String? @db.VarChar(200)
|
|
zip String? @db.VarChar(20)
|
|
city String? @db.VarChar(100)
|
|
state String? @db.VarChar(100)
|
|
country String? @default("DE") @db.VarChar(2)
|
|
|
|
// Adresse (Lieferung)
|
|
deliveryStreet String? @map("delivery_street") @db.VarChar(200)
|
|
deliveryZip String? @map("delivery_zip") @db.VarChar(20)
|
|
deliveryCity String? @map("delivery_city") @db.VarChar(100)
|
|
deliveryCountry String? @map("delivery_country") @db.VarChar(2)
|
|
|
|
// Zusaetzlich
|
|
notes String? @db.Text
|
|
tags String[] @default([])
|
|
|
|
// Status (Phase 1: EntityStatus Enum ersetzt isActive)
|
|
status EntityStatus @default(ACTIVE)
|
|
isActive Boolean @default(true) @map("is_active") // DEPRECATED: Synchron gehalten
|
|
|
|
// Datenanreicherung
|
|
dataEnrichedAt DateTime? @map("data_enriched_at")
|
|
dataEnrichedSource String? @map("data_enriched_source") @db.VarChar(200)
|
|
|
|
// Lexware Office Integration
|
|
lexwareContactId String? @map("lexware_contact_id") @db.VarChar(36)
|
|
lexwareContactVersion Int? @map("lexware_contact_version")
|
|
lexwareSyncedAt DateTime? @map("lexware_synced_at")
|
|
|
|
// Audit-Trail
|
|
createdBy String @map("created_by") @db.Uuid
|
|
updatedBy String? @map("updated_by") @db.Uuid
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relationen
|
|
industryRef Industry? @relation(fields: [industryId], references: [id], onDelete: SetNull)
|
|
accountType AccountType? @relation(fields: [accountTypeId], references: [id], onDelete: SetNull)
|
|
contacts Contact[]
|
|
deals Deal[]
|
|
activities Activity[]
|
|
lexwareVouchers LexwareVoucher[]
|
|
relationships CompanyRelationship[] @relation("companyRelationships")
|
|
relatedRelationships CompanyRelationship[] @relation("relatedCompanyRelationships")
|
|
contracts Contract[]
|
|
emails ContactEmail[]
|
|
phones ContactPhone[]
|
|
owners CompanyOwner[]
|
|
|
|
@@unique([tenantId, lexwareContactId])
|
|
@@index([tenantId])
|
|
@@index([tenantId, name])
|
|
@@index([tenantId, industry])
|
|
@@index([tenantId, industryId])
|
|
@@index([tenantId, accountTypeId])
|
|
@@index([tenantId, isActive])
|
|
@@index([tenantId, status])
|
|
@@map("companies")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Contact - CRM-Kontakte (Personen)
|
|
// --------------------------------------------------------
|
|
model Contact {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
type ContactType @default(PERSON)
|
|
|
|
// Person
|
|
firstName String? @map("first_name") @db.VarChar(100)
|
|
lastName String? @map("last_name") @db.VarChar(100)
|
|
|
|
// Unternehmenszuordnung
|
|
companyId String? @map("company_id") @db.Uuid
|
|
companyName String? @map("company_name") @db.VarChar(200)
|
|
position String? @db.VarChar(200)
|
|
|
|
// Kontaktdaten (Legacy-Einzelfelder, deprecated — siehe emails[]/phones[])
|
|
email String? @db.VarChar(255)
|
|
phone String? @db.VarChar(50)
|
|
mobile String? @db.VarChar(50)
|
|
website String? @db.VarChar(500)
|
|
|
|
// Phase 1: Neue Felder
|
|
linkedinUrl String? @map("linkedin_url") @db.VarChar(500)
|
|
birthday DateTime?
|
|
source ContactSource?
|
|
department String? @db.VarChar(200)
|
|
|
|
// Adresse
|
|
street String? @db.VarChar(200)
|
|
zip String? @db.VarChar(20)
|
|
city String? @db.VarChar(100)
|
|
state String? @db.VarChar(100)
|
|
country String? @default("DE") @db.VarChar(2)
|
|
|
|
// Zusaetzlich
|
|
notes String? @db.Text
|
|
tags String[] @default([])
|
|
|
|
// Status (Phase 1: EntityStatus Enum ersetzt isActive)
|
|
status EntityStatus @default(ACTIVE)
|
|
isActive Boolean @default(true) @map("is_active") // DEPRECATED: Synchron gehalten
|
|
|
|
// Lexware Office Integration
|
|
lexwareContactId String? @map("lexware_contact_id") @db.VarChar(36)
|
|
lexwareContactVersion Int? @map("lexware_contact_version")
|
|
lexwareSyncedAt DateTime? @map("lexware_synced_at")
|
|
|
|
// Audit-Trail (User-IDs aus platform_core)
|
|
createdBy String @map("created_by") @db.Uuid
|
|
updatedBy String? @map("updated_by") @db.Uuid
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relationen
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
|
activities Activity[]
|
|
deals Deal[]
|
|
lexwareVouchers LexwareVoucher[]
|
|
emails ContactEmail[]
|
|
phones ContactPhone[]
|
|
owners ContactOwner[]
|
|
|
|
@@unique([tenantId, lexwareContactId])
|
|
@@index([tenantId])
|
|
@@index([tenantId, email])
|
|
@@index([tenantId, companyId])
|
|
@@index([tenantId, companyName])
|
|
@@index([tenantId, lastName, firstName])
|
|
@@index([tenantId, isActive])
|
|
@@index([tenantId, status])
|
|
@@map("contacts")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
enum ContactType {
|
|
PERSON
|
|
ORGANIZATION
|
|
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Activity - CRM-Aktivitaeten (Notizen, Anrufe, E-Mails)
|
|
// --------------------------------------------------------
|
|
model Activity {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
contactId String? @map("contact_id") @db.Uuid
|
|
companyId String? @map("company_id") @db.Uuid
|
|
type ActivityType
|
|
subject String @db.VarChar(500)
|
|
description String? @db.Text
|
|
|
|
// Terminierung
|
|
scheduledAt DateTime? @map("scheduled_at")
|
|
completedAt DateTime? @map("completed_at")
|
|
|
|
// Audit-Trail
|
|
createdBy String @map("created_by") @db.Uuid
|
|
updatedBy String? @map("updated_by") @db.Uuid
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relationen
|
|
contact Contact? @relation(fields: [contactId], references: [id], onDelete: Cascade)
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([tenantId])
|
|
@@index([tenantId, contactId])
|
|
@@index([tenantId, companyId])
|
|
@@index([tenantId, type])
|
|
@@index([tenantId, scheduledAt])
|
|
@@map("activities")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
enum ActivityType {
|
|
NOTE
|
|
CALL
|
|
EMAIL
|
|
MEETING
|
|
TASK
|
|
FOLLOWUP
|
|
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Phase 1 Enums — Kontakt-Herkunft, Status, Owner, etc.
|
|
// --------------------------------------------------------
|
|
enum ContactSource {
|
|
TRADE_FAIR
|
|
REFERRAL
|
|
WEBSITE
|
|
COLD_CALL
|
|
IMPORT
|
|
BUSINESS_CARD
|
|
OTHER
|
|
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
enum EntityStatus {
|
|
ACTIVE
|
|
INACTIVE
|
|
BLOCKED
|
|
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
enum CompanySize {
|
|
SIZE_1_10
|
|
SIZE_11_50
|
|
SIZE_51_200
|
|
SIZE_201_500
|
|
SIZE_500_PLUS
|
|
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
enum OwnerRole {
|
|
OWNER
|
|
MEMBER
|
|
WATCHER
|
|
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
enum LostReason {
|
|
PRICE
|
|
TIMING
|
|
COMPETITOR
|
|
NO_NEED
|
|
OTHER
|
|
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
enum EmailType {
|
|
WORK
|
|
PERSONAL
|
|
OTHER
|
|
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
enum PhoneType {
|
|
OFFICE
|
|
MOBILE
|
|
FAX
|
|
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// CompanyRelationship - Beziehungen zwischen Unternehmen (N:M)
|
|
// --------------------------------------------------------
|
|
model CompanyRelationship {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
companyId String @map("company_id") @db.Uuid
|
|
relatedCompanyId String @map("related_company_id") @db.Uuid
|
|
relationshipTypeId String @map("relationship_type_id") @db.Uuid
|
|
notes String? @db.Text
|
|
createdBy String @map("created_by") @db.Uuid
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
// Relationen
|
|
company Company @relation("companyRelationships", fields: [companyId], references: [id], onDelete: Cascade)
|
|
relatedCompany Company @relation("relatedCompanyRelationships", fields: [relatedCompanyId], references: [id], onDelete: Cascade)
|
|
relationshipType RelationshipType @relation(fields: [relationshipTypeId], references: [id], onDelete: Restrict)
|
|
|
|
@@unique([companyId, relatedCompanyId, relationshipTypeId])
|
|
@@index([tenantId])
|
|
@@index([tenantId, companyId])
|
|
@@index([tenantId, relatedCompanyId])
|
|
@@map("company_relationships")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Contract - Vertraege (Platzhalter fuer zukuenftiges Modul)
|
|
// --------------------------------------------------------
|
|
model Contract {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
companyId String @map("company_id") @db.Uuid
|
|
title String @db.VarChar(255)
|
|
status ContractStatus @default(DRAFT)
|
|
startDate DateTime? @map("start_date")
|
|
endDate DateTime? @map("end_date")
|
|
value Decimal? @db.Decimal(15, 2)
|
|
currency String @default("EUR") @db.VarChar(3)
|
|
notes String? @db.Text
|
|
createdBy String @map("created_by") @db.Uuid
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relationen
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
files ContractFile[]
|
|
|
|
@@index([tenantId, companyId])
|
|
@@map("contracts")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
model ContractFile {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
contractId String @map("contract_id") @db.Uuid
|
|
originalName String @map("original_name") @db.VarChar(500)
|
|
storagePath String @map("storage_path") @db.VarChar(1000)
|
|
mimeType String @map("mime_type") @db.VarChar(200)
|
|
size Int
|
|
uploadedBy String @map("uploaded_by") @db.Uuid
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
contract Contract @relation(fields: [contractId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([contractId])
|
|
@@map("contract_files")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
enum ContractStatus {
|
|
DRAFT
|
|
ACTIVE
|
|
EXPIRED
|
|
CANCELLED
|
|
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Pipeline - Sales-Pipelines (konfigurierbar pro Tenant)
|
|
// --------------------------------------------------------
|
|
model Pipeline {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
name String @db.VarChar(200)
|
|
|
|
isDefault Boolean @default(false) @map("is_default")
|
|
isActive Boolean @default(true) @map("is_active")
|
|
|
|
// Audit-Trail
|
|
createdBy String @map("created_by") @db.Uuid
|
|
updatedBy String? @map("updated_by") @db.Uuid
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relationen
|
|
stages PipelineStage[]
|
|
deals Deal[]
|
|
|
|
@@index([tenantId])
|
|
@@index([tenantId, isActive])
|
|
@@map("pipelines")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// PipelineStage - Stufen einer Pipeline (z.B. Lead, Angebot)
|
|
// --------------------------------------------------------
|
|
model PipelineStage {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
pipelineId String @map("pipeline_id") @db.Uuid
|
|
name String @db.VarChar(200)
|
|
sortOrder Int @default(0) @map("sort_order")
|
|
color String @default("#6B7280") @db.VarChar(7)
|
|
probability Decimal @default(0) @map("probability") @db.Decimal(3, 2)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relationen
|
|
pipeline Pipeline @relation(fields: [pipelineId], references: [id], onDelete: Cascade)
|
|
deals Deal[]
|
|
|
|
@@index([pipelineId])
|
|
@@index([pipelineId, sortOrder])
|
|
@@map("pipeline_stages")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Deal - Verkaufschancen / Deals
|
|
// --------------------------------------------------------
|
|
model Deal {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
pipelineId String @map("pipeline_id") @db.Uuid
|
|
stageId String @map("stage_id") @db.Uuid
|
|
contactId String? @map("contact_id") @db.Uuid
|
|
companyId String? @map("company_id") @db.Uuid
|
|
title String @db.VarChar(500)
|
|
value Decimal? @db.Decimal(15, 2)
|
|
currency String @default("EUR") @db.VarChar(3)
|
|
status DealStatus @default(OPEN)
|
|
|
|
expectedCloseDate DateTime? @map("expected_close_date")
|
|
closedAt DateTime? @map("closed_at")
|
|
notes String? @db.Text
|
|
|
|
// Phase 1: Lost-Reason
|
|
lostReason LostReason? @map("lost_reason")
|
|
lostReasonText String? @map("lost_reason_text") @db.Text
|
|
|
|
// Audit-Trail
|
|
createdBy String @map("created_by") @db.Uuid
|
|
updatedBy String? @map("updated_by") @db.Uuid
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relationen
|
|
pipeline Pipeline @relation(fields: [pipelineId], references: [id], onDelete: Cascade)
|
|
stage PipelineStage @relation(fields: [stageId], references: [id])
|
|
contact Contact? @relation(fields: [contactId], references: [id], onDelete: SetNull)
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
|
dealVouchers DealVoucher[]
|
|
owners DealOwner[]
|
|
|
|
@@index([tenantId])
|
|
@@index([tenantId, pipelineId])
|
|
@@index([tenantId, stageId])
|
|
@@index([tenantId, contactId])
|
|
@@index([tenantId, companyId])
|
|
@@index([tenantId, status])
|
|
@@map("deals")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
enum DealStatus {
|
|
OPEN
|
|
WON
|
|
LOST
|
|
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Lexware Office Integration - Voucher Types
|
|
// --------------------------------------------------------
|
|
enum VoucherType {
|
|
QUOTATION
|
|
ORDER_CONFIRMATION
|
|
INVOICE
|
|
CREDIT_NOTE
|
|
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// LexwareVoucher - Gecachte Belege aus Lexware Office
|
|
// --------------------------------------------------------
|
|
model LexwareVoucher {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
lexwareVoucherId String @map("lexware_voucher_id") @db.VarChar(36)
|
|
voucherType VoucherType @map("voucher_type")
|
|
|
|
voucherNumber String? @map("voucher_number") @db.VarChar(100)
|
|
voucherDate DateTime? @map("voucher_date")
|
|
voucherStatus String? @map("voucher_status") @db.VarChar(50)
|
|
|
|
totalGrossAmount Decimal? @map("total_gross_amount") @db.Decimal(15, 2)
|
|
totalNetAmount Decimal? @map("total_net_amount") @db.Decimal(15, 2)
|
|
totalTaxAmount Decimal? @map("total_tax_amount") @db.Decimal(15, 2)
|
|
currency String @default("EUR") @db.VarChar(3)
|
|
|
|
title String? @db.VarChar(500)
|
|
lineItemsCount Int? @map("line_items_count")
|
|
lineItemsJson String? @map("line_items_json") @db.Text
|
|
|
|
// Verknuepfung zu Lexware-Kontakt und CRM-Entitaeten
|
|
lexwareContactId String @map("lexware_contact_id") @db.VarChar(36)
|
|
companyId String? @map("company_id") @db.Uuid
|
|
contactId String? @map("contact_id") @db.Uuid
|
|
|
|
lexwareDeepLink String? @map("lexware_deep_link") @db.VarChar(500)
|
|
|
|
fetchedAt DateTime @default(now()) @map("fetched_at")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relationen
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
|
contact Contact? @relation(fields: [contactId], references: [id], onDelete: SetNull)
|
|
deals DealVoucher[]
|
|
|
|
@@unique([tenantId, lexwareVoucherId])
|
|
@@index([tenantId])
|
|
@@index([tenantId, companyId])
|
|
@@index([tenantId, contactId])
|
|
@@index([tenantId, lexwareContactId])
|
|
@@index([tenantId, voucherType])
|
|
@@map("lexware_vouchers")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// DealVoucher - Verknuepfung Deal <-> Lexware-Beleg (m:n)
|
|
// --------------------------------------------------------
|
|
model DealVoucher {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
dealId String @map("deal_id") @db.Uuid
|
|
voucherId String @map("voucher_id") @db.Uuid
|
|
linkedBy String @map("linked_by") @db.Uuid
|
|
linkedAt DateTime @default(now()) @map("linked_at")
|
|
|
|
// Relationen
|
|
deal Deal @relation(fields: [dealId], references: [id], onDelete: Cascade)
|
|
voucher LexwareVoucher @relation(fields: [voucherId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([dealId, voucherId])
|
|
@@index([tenantId])
|
|
@@index([tenantId, dealId])
|
|
@@index([tenantId, voucherId])
|
|
@@map("deal_vouchers")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// ContactEmail - Multi-Value E-Mail-Adressen (Phase 1)
|
|
// --------------------------------------------------------
|
|
model ContactEmail {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
contactId String? @map("contact_id") @db.Uuid
|
|
companyId String? @map("company_id") @db.Uuid
|
|
email String @db.VarChar(255)
|
|
type EmailType @default(WORK)
|
|
isPrimary Boolean @default(false) @map("is_primary")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
contact Contact? @relation(fields: [contactId], references: [id], onDelete: Cascade)
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([contactId])
|
|
@@index([companyId])
|
|
@@map("contact_emails")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// ContactPhone - Multi-Value Telefonnummern (Phase 1)
|
|
// --------------------------------------------------------
|
|
model ContactPhone {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
contactId String? @map("contact_id") @db.Uuid
|
|
companyId String? @map("company_id") @db.Uuid
|
|
phone String @db.VarChar(50)
|
|
type PhoneType @default(OFFICE)
|
|
isPrimary Boolean @default(false) @map("is_primary")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
contact Contact? @relation(fields: [contactId], references: [id], onDelete: Cascade)
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([contactId])
|
|
@@index([companyId])
|
|
@@map("contact_phones")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// ContactOwner - Zustaendige pro Kontakt (m:n, Phase 1)
|
|
// --------------------------------------------------------
|
|
model ContactOwner {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
contactId String @map("contact_id") @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
role OwnerRole @default(OWNER)
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([contactId, userId])
|
|
@@index([tenantId])
|
|
@@index([tenantId, contactId])
|
|
@@map("contact_owners")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// CompanyOwner - Zustaendige pro Unternehmen (m:n, Phase 1)
|
|
// --------------------------------------------------------
|
|
model CompanyOwner {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
companyId String @map("company_id") @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
role OwnerRole @default(OWNER)
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([companyId, userId])
|
|
@@index([tenantId])
|
|
@@index([tenantId, companyId])
|
|
@@map("company_owners")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// DealOwner - Zustaendige pro Deal (m:n, Phase 1)
|
|
// --------------------------------------------------------
|
|
model DealOwner {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
dealId String @map("deal_id") @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
role OwnerRole @default(OWNER)
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
deal Deal @relation(fields: [dealId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([dealId, userId])
|
|
@@index([tenantId])
|
|
@@index([tenantId, dealId])
|
|
@@map("deal_owners")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Phase 2.1 Enums — Custom Fields
|
|
// --------------------------------------------------------
|
|
enum CustomFieldEntityType {
|
|
PERSON
|
|
COMPANY
|
|
DEAL
|
|
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
enum CustomFieldType {
|
|
TEXT
|
|
TEXTAREA
|
|
NUMBER
|
|
DATE
|
|
DROPDOWN
|
|
MULTI_SELECT
|
|
CHECKBOX
|
|
URL
|
|
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// CustomFieldDef - Benutzerdefinierte Feld-Definitionen (Phase 2.1)
|
|
// --------------------------------------------------------
|
|
model CustomFieldDef {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
entityType CustomFieldEntityType @map("entity_type")
|
|
name String @db.VarChar(200)
|
|
label String @db.VarChar(200)
|
|
fieldType CustomFieldType @map("field_type")
|
|
options Json? @db.JsonB
|
|
isRequired Boolean @default(false) @map("is_required")
|
|
position Int @default(0)
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
values CustomFieldValue[]
|
|
|
|
@@unique([tenantId, entityType, name])
|
|
@@index([tenantId])
|
|
@@index([tenantId, entityType])
|
|
@@map("crm_custom_field_defs")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// CustomFieldValue - Benutzerdefinierte Feld-Werte (Phase 2.1)
|
|
// --------------------------------------------------------
|
|
model CustomFieldValue {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
fieldDefId String @map("field_def_id") @db.Uuid
|
|
entityId String @map("entity_id") @db.Uuid
|
|
valueText String? @map("value_text") @db.Text
|
|
valueNumber Decimal? @map("value_number") @db.Decimal(15, 4)
|
|
valueDate DateTime? @map("value_date")
|
|
valueBoolean Boolean? @map("value_boolean")
|
|
valueJson Json? @map("value_json") @db.JsonB
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
fieldDef CustomFieldDef @relation(fields: [fieldDefId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([fieldDefId, entityId])
|
|
@@index([tenantId])
|
|
@@index([tenantId, entityId])
|
|
@@index([fieldDefId])
|
|
@@map("crm_custom_field_values")
|
|
@@schema("app_crm")
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// TradeEvent - Messe-/Event-Timer (admin-konfigurierbar)
|
|
// --------------------------------------------------------
|
|
model TradeEvent {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
tenantId String @map("tenant_id") @db.Uuid
|
|
name String @db.VarChar(200)
|
|
description String? @db.Text
|
|
startDate DateTime @map("start_date")
|
|
endDate DateTime @map("end_date")
|
|
location String? @db.VarChar(300)
|
|
boothInfo String? @map("booth_info") @db.VarChar(200)
|
|
websiteUrl String? @map("website_url") @db.VarChar(500)
|
|
isActive Boolean @default(true) @map("is_active")
|
|
sortOrder Int @default(0) @map("sort_order")
|
|
|
|
// Audit-Trail
|
|
createdBy String @map("created_by") @db.Uuid
|
|
updatedBy String? @map("updated_by") @db.Uuid
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@unique([tenantId, name])
|
|
@@index([tenantId])
|
|
@@index([tenantId, isActive])
|
|
@@index([tenantId, startDate])
|
|
@@map("trade_events")
|
|
@@schema("app_crm")
|
|
}
|