636 lines
18 KiB
Plaintext
636 lines
18 KiB
Plaintext
// =============================================================================
|
|
// HiveGrid 2.0 — ENTITÄTENMODELL (Projekt-zentrisch, AD-20) — ✅ APPROVED & LOCKED 2026-06-15
|
|
// · Update 2026-06-16: pipeline_field_visibility NEU (Field-Level-Rechte); projekt_externes_feld → [v2] (KWP komplett v2)
|
|
// =============================================================================
|
|
// ⚠ entity-model.svg ist NICHT automatisch aktualisiert (dbdiagram.io-Export) — nach diesem Update neu generieren:
|
|
// Import → https://dbdiagram.io ("Import → DBML") → Export SVG → entity-model.svg ersetzen.
|
|
// Approved-Quelle: HiveGrid_CRM_Datenlogik_UX_Entscheidungen.md · Voll/Prosa: ENTITY-MODEL.md · Laienfassung: ENTITY-MODELL-ERKLAERUNG.pdf
|
|
//
|
|
// Deckt die KERN-Domäne ab:
|
|
// Lead → Projekt (ein Kern) + Pipeline (konfigurierbare Views) + Kontakt + Sub-Areas.
|
|
// "Deal" und "Auftrag" sind NUR Pipeline-Typen — KEINE eigenen Entitäten.
|
|
//
|
|
// STUBS: unveränderte Cross-Cutting-/Modul-Tabellen (Auth, Files, Tasks, Audit, Automation,
|
|
// KI, Email, Chat, Kalender, Booking, Forms, HR, Billing, Admin) sind nur als Stub (Schlüssel-
|
|
// spalten) referenziert — ihr volles Modell steht in ENTITY-MODEL.md.
|
|
//
|
|
// Konventionen:
|
|
// AD-1 RLS auf allem mit tenant_id.
|
|
// AD-2 typisierte Tabellen + CustomFields/FieldConfig (KEIN generischer Entity-Builder).
|
|
// Polymorphe Refs (entity_type + entity_id) haben bewusst KEINEN DB-FK.
|
|
// [v1] = Launch-Scope · [v2] = nach Launch.
|
|
// =============================================================================
|
|
|
|
|
|
// ============================ ENUMS ============================
|
|
|
|
Enum kontakt_typ {
|
|
privatperson
|
|
organisation
|
|
}
|
|
|
|
Enum kontakt_status {
|
|
kontakt
|
|
kunde
|
|
bestandskunde
|
|
}
|
|
|
|
// optionales Rechtsform-/Kategorie-Merkmal, NICHT Grundtyp
|
|
Enum org_merkmal {
|
|
gmbh
|
|
kg
|
|
oeffentliche_einrichtung
|
|
sonstige
|
|
}
|
|
|
|
Enum kontakt_art {
|
|
hauptkontakt
|
|
sekundaerkontakt
|
|
mitarbeiter
|
|
sonstige
|
|
}
|
|
|
|
Enum projekt_kontakt_rolle {
|
|
auftraggeber
|
|
bauherr
|
|
rechnungsempfaenger
|
|
ansprechpartner
|
|
sonstige
|
|
}
|
|
|
|
Enum lead_quelle {
|
|
formular
|
|
website
|
|
social_media
|
|
leadliste
|
|
csv
|
|
manuell
|
|
email
|
|
anruf
|
|
}
|
|
|
|
Enum lead_status {
|
|
new
|
|
qualified
|
|
converted
|
|
lost
|
|
spam
|
|
}
|
|
|
|
// "Weiterverarbeitungsfreigabe"
|
|
Enum weiterverarbeitung_freigabe {
|
|
ja
|
|
nein
|
|
unklar
|
|
}
|
|
|
|
// typ_hint: nur Label/Default-Verhalten, kein Hard-Type
|
|
Enum pipeline_typ_hint {
|
|
sales
|
|
auftrag
|
|
custom
|
|
}
|
|
|
|
// Reporting (Won/Lost); KEIN globaler Projektstatus
|
|
Enum stage_kind {
|
|
offen
|
|
gewonnen
|
|
verloren
|
|
}
|
|
|
|
Enum principal_type {
|
|
rolle
|
|
user
|
|
gruppe
|
|
}
|
|
|
|
Enum projekt_prioritaet {
|
|
niedrig
|
|
normal
|
|
hoch
|
|
kritisch
|
|
}
|
|
|
|
Enum projekt_mitglied_rolle {
|
|
projektleiter
|
|
monteur
|
|
zustaendig
|
|
beobachter
|
|
}
|
|
|
|
Enum field_entity_type {
|
|
projekt
|
|
kontakt
|
|
lead
|
|
rechnung
|
|
}
|
|
|
|
Enum custom_field_datentyp {
|
|
text
|
|
textarea
|
|
zahl
|
|
waehrung
|
|
datum
|
|
datum_range
|
|
select
|
|
multiselect
|
|
boolean
|
|
email
|
|
telefon
|
|
datei
|
|
}
|
|
|
|
Enum rechnung_status {
|
|
entwurf
|
|
gestellt
|
|
bezahlt
|
|
storniert
|
|
}
|
|
|
|
Enum checkliste_typ {
|
|
generisch
|
|
maengel
|
|
abnahme_doku
|
|
}
|
|
|
|
Enum checklist_item_status {
|
|
offen
|
|
erledigt
|
|
nicht_relevant
|
|
}
|
|
|
|
Enum maengel_klasse {
|
|
kritisch
|
|
klein
|
|
kosmetisch
|
|
}
|
|
|
|
Enum abnahme_signer_rolle {
|
|
kunde
|
|
monteur
|
|
}
|
|
|
|
Enum externes_system {
|
|
kwp
|
|
sonstige
|
|
}
|
|
|
|
|
|
// ============================ STUBS (anderswo voll modelliert) ============================
|
|
|
|
Table tenant {
|
|
id uuid [pk]
|
|
Note: '[v1] Mandant. RLS-Anker für alles unten.'
|
|
}
|
|
|
|
Table app_user {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
Note: '[v1] Mandanten-Nutzer (Mitarbeiter/Vertriebler/Monteur). = User in ENTITY-MODEL.md.'
|
|
}
|
|
|
|
Table file {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
Note: '[v1] Datei (Storage). Volles Modell: M23/Files.'
|
|
}
|
|
|
|
Table tag {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
name varchar
|
|
farbe varchar
|
|
}
|
|
|
|
Table hive_number_seq {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
sequence_key varchar [note: 'z.B. projekt:auftrag, rechnung — fortlaufende Nummern pro Tenant']
|
|
current bigint
|
|
}
|
|
|
|
|
|
// ============================ ADRESSE (wiederverwendbar) ============================
|
|
|
|
Table adresse {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
strasse varchar
|
|
hausnummer varchar
|
|
plz varchar
|
|
ort varchar
|
|
land varchar [note: 'v1 DE-Default']
|
|
Note: '[v1] Eigene Tabelle, damit Projekt-/Rechnungs-/Bauher-Adresse getrennt referenzierbar sind.'
|
|
}
|
|
|
|
|
|
// ============================ KONTAKT (Oberbegriff Person/Organisation) ============================
|
|
|
|
Table kontakt {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
kontakt_typ kontakt_typ [note: 'privatperson | organisation — EIN Tabellen-Modell mit Diskriminator']
|
|
kontakt_status kontakt_status [note: 'kontakt | kunde | bestandskunde']
|
|
// --- Person (wenn typ=privatperson) ---
|
|
vorname varchar
|
|
nachname varchar
|
|
// --- Organisation (wenn typ=organisation) ---
|
|
org_name varchar
|
|
org_merkmal org_merkmal [note: 'optionales Rechtsform-/Kategorie-Merkmal, kein Grundtyp']
|
|
// --- gemeinsam ---
|
|
primaer_email varchar
|
|
primaer_telefon varchar
|
|
adresse_id uuid [ref: > adresse.id]
|
|
zustaendiger_user_id uuid [ref: > app_user.id]
|
|
archiviert_at timestamp
|
|
Note: '''[v1] Kontakt = Oberbegriff (David-Modell). Person- und Org-Felder im selben Table,
|
|
App erzwingt Pflichtfelder je kontakt_typ. Mehrfach-Emails/-Telefone via kontakt_email/_telefon.'''
|
|
}
|
|
|
|
Table kontakt_email {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
kontakt_id uuid [ref: > kontakt.id]
|
|
email varchar
|
|
primaer boolean
|
|
}
|
|
|
|
Table kontakt_telefon {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
kontakt_id uuid [ref: > kontakt.id]
|
|
telefon varchar
|
|
primaer boolean
|
|
}
|
|
|
|
Table kontakt_relation {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
von_kontakt_id uuid [ref: > kontakt.id, note: 'z.B. Organisation oder Privatperson']
|
|
zu_kontakt_id uuid [ref: > kontakt.id, note: 'der verknüpfte Kontakt']
|
|
rolle kontakt_art [note: 'hauptkontakt | sekundaerkontakt — "Kontaktart" als ROLLE der Relation']
|
|
kontext varchar
|
|
Note: '''[v1] Haupt-/Sekundärkontakt-Verknüpfung (self-ref M:N).
|
|
Organisation hat >=1 Hauptkontakt (mehrere erlaubt) + Sekundärkontakte;
|
|
Privatperson kann selbst Hauptkontakt sein + Sekundärkontakte.'''
|
|
}
|
|
|
|
|
|
// ============================ LEAD / LEADINPUT (Vorstufe) ============================
|
|
|
|
Table lead {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
quelle lead_quelle
|
|
quelle_detail varchar [note: 'Formular-Name/IP bzw. Inbound-Mail/Anrufnummer']
|
|
status lead_status
|
|
weiterverarbeitung_freigabe weiterverarbeitung_freigabe [note: 'ja | nein | unklar — Grenze Lead↔Projekt']
|
|
// Roh-/Vorab-Daten (Felder dürfen leer sein, früh Projektfeldern zuordenbar):
|
|
vorname varchar
|
|
nachname varchar
|
|
email varchar
|
|
telefon varchar
|
|
rohdaten jsonb [note: 'Quell-Payload + vorab gemappte Projekt-Feldwerte']
|
|
spam_score numeric
|
|
zugewiesen_user_id uuid [ref: > app_user.id]
|
|
konvertiert_projekt_id uuid [ref: > projekt.id, note: 'gesetzt bei Weiterverarbeitung → Projekt (E4)']
|
|
verknuepfter_kontakt_id uuid [ref: > kontakt.id, note: 'Kontakt separat verknüpft (nicht promotet)']
|
|
eingegangen_at timestamp
|
|
archiviert_at timestamp
|
|
Note: '''[v1] LeadInput = eigenes Tool/Vorstufe. Bei Freigabe → Projekt anlegen, gemappte Daten
|
|
vererben, konvertiert_projekt_id setzen. KEIN Lead→Contact-Promotion-Modal mehr (E4).'''
|
|
}
|
|
|
|
|
|
// ============================ PIPELINE (konfigurierbare Views) ============================
|
|
|
|
Table pipeline {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
name varchar [note: '"Deal", "Auftrag", … frei benennbar']
|
|
beschreibung text
|
|
typ_hint pipeline_typ_hint [note: 'sales | auftrag | custom — steuert Default-Features (Forecast vs. Plantafel)']
|
|
reihenfolge int
|
|
archiviert boolean
|
|
Note: '[v1] Pipeline = View auf Projekte. Admin legt an/benennt/konfiguriert.'
|
|
}
|
|
|
|
Table pipeline_stage {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
pipeline_id uuid [ref: > pipeline.id]
|
|
name varchar
|
|
reihenfolge int
|
|
stage_kind stage_kind [note: 'offen | gewonnen | verloren — nur Reporting, kein globaler Status']
|
|
win_wahrscheinlichkeit int
|
|
farbe varchar
|
|
Note: '[v1] Spalten/Schritte der Pipeline = die Statuswerte des Projekts in dieser Pipeline.'
|
|
}
|
|
|
|
Table pipeline_access {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
pipeline_id uuid [ref: > pipeline.id]
|
|
principal_type principal_type [note: 'rolle | user | gruppe']
|
|
principal_id uuid [note: 'polymorph: Rolle/User/Gruppe-ID']
|
|
kann_sehen boolean
|
|
kann_bearbeiten boolean
|
|
Note: '[v1] "Wer darf die Pipeline sehen/bearbeiten" (Admin entscheidet).'
|
|
}
|
|
|
|
Table pipeline_field_config {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
pipeline_id uuid [ref: > pipeline.id]
|
|
stage_id uuid [ref: > pipeline_stage.id, note: 'NULL = pipeline-weit; gesetzt = Pflicht ab diesem Status']
|
|
field_key varchar [note: 'System-Feldschlüssel (z.B. "auftragsvolumen") ODER "custom:<definition_id>"']
|
|
sichtbar boolean
|
|
pflicht boolean
|
|
reihenfolge int
|
|
Note: '''[v1] DER Konfig-Layer: pro Pipeline (+Status) welche Felder sichtbar/pflichtig.
|
|
field_key überbrückt typisierte Kern-Felder UND Custom-Fields. Nicht sichtbare Felder
|
|
bleiben am Projekt erhalten (nur ausgeblendet).'''
|
|
}
|
|
|
|
Table pipeline_field_visibility {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
field_config_id uuid [ref: > pipeline_field_config.id]
|
|
principal_type varchar [note: 'rolle | gruppe | user']
|
|
principal_id uuid
|
|
kann_sehen boolean
|
|
kann_bearbeiten boolean
|
|
Note: '''[v1] Field-Level-Rechte (Entscheidung 16.06.): pro Feld-Config je Rolle/Gruppe/User
|
|
sehen/bearbeiten — z.B. Auftragsvolumen nur fuer Vertrieb. Ohne Eintrag = fuer alle sichtbar.'''
|
|
}
|
|
|
|
|
|
// ============================ PROJEKT (zentraler Kern) ============================
|
|
|
|
Table projekt {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
projekt_nummer varchar [note: 'aus hive_number_seq']
|
|
projektname varchar
|
|
pipeline_id uuid [ref: > pipeline.id, note: 'genau EINE Pipeline (AD-20)']
|
|
stage_id uuid [ref: > pipeline_stage.id, note: '= Status (pipeline-intern)']
|
|
projekttyp varchar
|
|
quelle varchar
|
|
promotion varchar
|
|
prioritaet projekt_prioritaet
|
|
start_datum date
|
|
deadline date
|
|
auftragsvolumen numeric [note: '"Auftrag"-Welt']
|
|
potenzieller_auftragswert numeric [note: '"Deal"-Welt']
|
|
zustaendige_person_id uuid [ref: > app_user.id, note: 'Vertriebler/zuständig']
|
|
projektleiter_id uuid [ref: > app_user.id]
|
|
projekt_adresse_id uuid [ref: > adresse.id]
|
|
rechnungsadresse_id uuid [ref: > adresse.id, note: 'separat, optional']
|
|
bauheradresse_id uuid [ref: > adresse.id, note: 'separat, optional']
|
|
kommunikation_email varchar [note: 'projektbezogene Kommunikationsdaten']
|
|
kommunikation_telefon varchar
|
|
kommunikation_fax varchar
|
|
konvertiert_aus_lead_id uuid [ref: > lead.id]
|
|
archiviert_at timestamp
|
|
Note: '''[v1] EIN Projekt-Kern (Deal+Auftrag verschmolzen). Typisierte Superset-Spalten;
|
|
branchen-/pipelinespezifische Zusatzfelder via custom_field_value. Monteure (mehrere)
|
|
via projekt_mitglied. KWP-Felder via projekt_externes_feld.'''
|
|
}
|
|
|
|
Table projekt_mitglied {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
projekt_id uuid [ref: > projekt.id]
|
|
user_id uuid [ref: > app_user.id]
|
|
rolle projekt_mitglied_rolle [note: 'monteur (mehrere) | beobachter | …']
|
|
Note: '[v1] Mehrfach-Zuordnung (v.a. Monteure). projektleiter/zustaendig sind zusätzlich Direkt-FKs am Projekt.'
|
|
}
|
|
|
|
Table projekt_kontakt {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
projekt_id uuid [ref: > projekt.id]
|
|
kontakt_id uuid [ref: > kontakt.id]
|
|
rolle projekt_kontakt_rolle [note: 'auftraggeber | bauherr | rechnungsempfaenger | ansprechpartner']
|
|
primaer boolean
|
|
Note: '[v1] Verknüpfung Projekt↔Kontakt(e) mit Rolle. Inline-Edit am Kontakt schreibt zurück.'
|
|
}
|
|
|
|
|
|
// ============================ CUSTOM FIELDS (typisiert-erweiterbar, AD-2) ============================
|
|
|
|
Table custom_field_definition {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
entity_type field_entity_type
|
|
key varchar
|
|
label varchar
|
|
datentyp custom_field_datentyp
|
|
optionen jsonb [note: 'Werte für select/multiselect']
|
|
archiviert boolean
|
|
Note: '[v1] Eigen-Felder pro Entity-Typ. SHK-Branchen-Felder als Seed-Template (AD-12).'
|
|
}
|
|
|
|
Table custom_field_value {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
definition_id uuid [ref: > custom_field_definition.id]
|
|
entity_type field_entity_type
|
|
entity_id uuid [note: 'polymorph (projekt/kontakt/…), KEIN FK']
|
|
wert jsonb
|
|
Note: '[v1] Wert je (Definition, Entität). Von pipeline_field_config via "custom:<id>" referenzierbar.'
|
|
}
|
|
|
|
|
|
// ============================ SUB-AREAS am Projekt ============================
|
|
|
|
Table termin {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
projekt_id uuid [ref: > projekt.id]
|
|
kontakt_id uuid [ref: > kontakt.id]
|
|
titel varchar
|
|
start_at timestamp
|
|
ende_at timestamp
|
|
ort varchar
|
|
Note: '[v1] Projektbezogene Termine (Kalender-Sync M25 dockt an).'
|
|
}
|
|
|
|
Table rechnung {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
projekt_id uuid [ref: > projekt.id]
|
|
rechnungsnummer varchar [note: 'aus hive_number_seq']
|
|
betrag numeric
|
|
status rechnung_status
|
|
datum date
|
|
faellig_am date
|
|
datei_id uuid [ref: > file.id, note: 'Rechnungs-PDF']
|
|
quelle externes_system [note: 'manuell | kwp (v2-Sync)']
|
|
notiz text
|
|
Note: '[v1 NEU — E3] Einfaches Rechnungs-Sub-Entity am Projekt (Liste/Anlegen/Verknüpfen).'
|
|
}
|
|
|
|
Table checkliste {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
projekt_id uuid [ref: > projekt.id]
|
|
name varchar [note: 'z.B. "Mängel", "Abnahme-Doku"']
|
|
typ checkliste_typ [note: 'generisch | maengel | abnahme_doku']
|
|
Note: '[v1] Generisches Checklisten-Konstrukt. "Mängel" = Checkliste mit typ=maengel (E2).'
|
|
}
|
|
|
|
Table checklist_item {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
checkliste_id uuid [ref: > checkliste.id]
|
|
text varchar
|
|
status checklist_item_status
|
|
maengel_klasse maengel_klasse [note: 'nur bei Mängel-Checkliste: kritisch | klein | kosmetisch']
|
|
foto_file_id uuid [ref: > file.id, note: 'Foto je Mangel']
|
|
reihenfolge int
|
|
}
|
|
|
|
Table abnahme_protokoll {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
projekt_id uuid [ref: > projekt.id]
|
|
maengel_checkliste_id uuid [ref: > checkliste.id, note: 'verknüpfte Mängel-Checkliste']
|
|
datum date
|
|
anwesende text
|
|
druckprobe_bestanden boolean
|
|
druckprobe_wert varchar
|
|
funktionspruefung text
|
|
zaehlerstaende jsonb
|
|
pdf_file_id uuid [ref: > file.id]
|
|
gesperrt_at timestamp [note: 'nach Signatur immutable']
|
|
Note: '''[v1 — E2] Abnahme als eigene immutable Entität (rechtlich bindend, 6 J., offline-fähig).
|
|
Bindet Mängel-Checkliste ein; "Mängel = Checkliste" bleibt erfüllt.'''
|
|
}
|
|
|
|
Table abnahme_signatur {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
abnahme_id uuid [ref: > abnahme_protokoll.id]
|
|
signer_name varchar
|
|
signer_rolle abnahme_signer_rolle [note: 'kunde | monteur']
|
|
signatur_file_id uuid [ref: > file.id, note: 'Touch-Unterschrift als Bild']
|
|
signiert_at timestamp
|
|
}
|
|
|
|
Table projekt_externes_feld {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
projekt_id uuid [ref: > projekt.id]
|
|
system externes_system [note: 'kwp']
|
|
feld_key varchar [note: 'KW-Projektnummer | Abteilungsnummer | Sachbearbeiter | Auftragsstatus | …']
|
|
wert varchar
|
|
Note: '''[v2] KWP/API-Felder — Entscheidung 16.06.: komplett v2, in v1 NICHT vorhanden
|
|
(kein Feld-Halter). KWP-Sync ab v2 (API-Zugang ~19.07.); Konflikt-Regel "KWP gewinnt".'''
|
|
}
|
|
|
|
|
|
// ============================ CROSS-CUTTING (polymorph, Stub) ============================
|
|
|
|
Table aufgabe {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
titel varchar
|
|
status varchar
|
|
faellig_am date
|
|
assignee_user_id uuid [ref: > app_user.id]
|
|
linked_entity_type varchar [note: 'projekt | kontakt | lead | … (polymorph, KEIN FK)']
|
|
linked_entity_id uuid
|
|
quelle varchar [note: 'manuell | chat | form | automation']
|
|
Note: '[v1] Task (M26) — wiederverwendbar, polymorph an jede Entität.'
|
|
}
|
|
|
|
Table aktivitaet {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
typ varchar
|
|
actor_user_id uuid [ref: > app_user.id]
|
|
entity_type varchar [note: 'projekt | kontakt | lead | … (polymorph)']
|
|
entity_id uuid
|
|
daten jsonb
|
|
created_at timestamp
|
|
Note: '[v1] Activity-Stream (append-only, Event-Sourcing). Speist Inline-Edit-Verlauf.'
|
|
}
|
|
|
|
Table file_entity_link {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
file_id uuid [ref: > file.id]
|
|
entity_type varchar [note: 'projekt | kontakt | rechnung | abnahme | … (polymorph)']
|
|
entity_id uuid
|
|
rolle varchar
|
|
Note: '[v1] Dokumente an jede Entität hängen (M23).'
|
|
}
|
|
|
|
Table entity_tag {
|
|
id uuid [pk]
|
|
tenant_id uuid [ref: > tenant.id]
|
|
tag_id uuid [ref: > tag.id]
|
|
entity_type varchar [note: 'projekt | kontakt | lead | … (polymorph)']
|
|
entity_id uuid
|
|
}
|
|
|
|
|
|
// ============================ GRUPPIERUNG (geordnete Darstellung) ============================
|
|
// Cluster nach Achse — rendert als Boxen (dbml-renderer + dbdiagram.io).
|
|
|
|
TableGroup Kern_Kette {
|
|
lead
|
|
projekt
|
|
kontakt
|
|
}
|
|
|
|
TableGroup Pipeline_Views_und_Konfig {
|
|
pipeline
|
|
pipeline_stage
|
|
pipeline_access
|
|
pipeline_field_config
|
|
}
|
|
|
|
TableGroup Kontakt_Detail {
|
|
kontakt_email
|
|
kontakt_telefon
|
|
kontakt_relation
|
|
projekt_kontakt
|
|
}
|
|
|
|
TableGroup Projekt_Beteiligte_und_Adresse {
|
|
projekt_mitglied
|
|
adresse
|
|
}
|
|
|
|
TableGroup Sub_Areas_am_Projekt {
|
|
termin
|
|
rechnung
|
|
checkliste
|
|
checklist_item
|
|
abnahme_protokoll
|
|
abnahme_signatur
|
|
projekt_externes_feld
|
|
}
|
|
|
|
TableGroup Custom_Fields {
|
|
custom_field_definition
|
|
custom_field_value
|
|
}
|
|
|
|
TableGroup Cross_Cutting {
|
|
aufgabe
|
|
aktivitaet
|
|
file_entity_link
|
|
entity_tag
|
|
}
|
|
|
|
TableGroup Stubs {
|
|
tenant
|
|
app_user
|
|
file
|
|
tag
|
|
hive_number_seq
|
|
}
|