Datenbank
Support-Engine verwendet PostgreSQL 16 mit Drizzle ORM. Das Schema ist vollständig in shared/schema.ts definiert — diese Datei ist die einzige Quelle für alle Tabellenstrukturen und Zod-Validierungsschemas.
Schema-Workflow
# 1. Spalte/Tabelle in shared/schema.ts hinzufügen
# 2. Schema anwenden
npm run db:push
# 3. Zod-Schema wird automatisch abgeleitet
# (drizzle-zod generiert Insert/Select-Typen)
Warnung
npm run db:push wendet Änderungen direkt an. Für Produktionsmigrationen sollten die generierten Migrationsdateien in migrations/ verwendet werden.
Tabellen-Übersicht
Mandanten & Benutzer
Tabelle |
Beschreibung |
|---|---|
|
Mandanten: Slug, Name, Branding (Logo, Farben, Custom CSS) |
|
Benutzer mit Rolle ( |
Tickets & Kommentare
Tabelle |
Beschreibung |
|---|---|
|
Kern-Tickettabelle: Titel, Beschreibung (HTML), Status, Priorität, SLA-Felder, Soft-Delete |
|
Anpassbare Tickettypen pro Mandant |
|
Benutzerdefinierte Felder für Tickets |
|
n:m-Relation Ticket ↔ Agent |
|
n:m-Relation Ticket ↔ Beobachter |
|
Kommentare (intern/öffentlich), HTML-Inhalt, Soft-Delete |
|
Dateianhänge mit MIME-Typ, Dateipfad, Ticketreferenz |
|
@-Erwähnungen in Kommentaren |
SLA
Tabelle |
Beschreibung |
|---|---|
|
SLA-Regeln: Reaktionszeit, Lösungszeit, Priorität, Arbeitszeiten |
|
Eskalationsstufen mit Schwellenwerten und Aktionen |
Wissensdatenbank
Tabelle |
Beschreibung |
|---|---|
|
Kategorien (hierarchisch, optional) |
|
Artikel mit HTML-Inhalt, Tags, Veröffentlichungsstatus, Soft-Delete |
|
Versionsverlauf für Artikel |
|
Verknüpfung Ticket ↔ KB-Artikel |
Zeiterfassung
Tabelle |
Beschreibung |
|---|---|
|
Gebuchte Zeiteinträge (Ticket, Agent, Dauer, Beschreibung) |
|
Laufende Timer pro Ticket und Benutzer |
|
Detaillierte Arbeitsprotokoll-Einträge |
CRM
Tabelle |
Beschreibung |
|---|---|
|
Organisationen/Firmen |
|
Kunden mit Kontaktdaten, verknüpft mit Organisation |
|
Standorte pro Kunde |
|
Ansprechpartner für Kunden/Organisationen |
|
n:m-Relation Ticket ↔ Kontakt |
|
Aktivitätsprotokoll pro Kunde |
Assets
Tabelle |
Beschreibung |
|---|---|
|
Kategorien für Assets |
|
Geräte/Assets: Typ, Seriennummer, Status, Standort, Besitzer |
|
Softwarelizenzen, die Assets zugeordnet sind |
|
Wartungsverträge pro Asset |
|
n:m-Relation Ticket ↔ Asset |
|
Änderungsverlauf pro Asset |
Projekte & Kanban
Tabelle |
Beschreibung |
|---|---|
|
Projekte mit Farbe, Kürzel, Status |
|
Projektmitglieder |
|
Kanban-Spalten pro Projekt |
|
n:m-Relation Ticket ↔ Projekt (mit Board-Position) |
Bereiche
Tabelle |
Beschreibung |
|---|---|
|
Organisationseinheiten/Abteilungen pro Mandant |
|
n:m-Relation Ticket ↔ Bereich |
Benachrichtigungen & Umfragen
Tabelle |
Beschreibung |
|---|---|
|
In-App-Benachrichtigungen pro Benutzer |
|
Kundenzufriedenheitsumfragen |
|
Fragen pro Umfrage |
|
Einladungen an Kunden |
|
Antworten der Kunden |
TLS-Zertifikate
Tabelle |
Beschreibung |
|---|---|
|
ACME-Konfiguration (E-Mail, Staging-Flag) |
|
Ausgestellte Zertifikate mit Ablaufdatum |
|
Aktionsprotokoll pro Zertifikat |
|
ACME HTTP-01 Challenge-Token |
Exchange Online
Tabelle |
Beschreibung |
|---|---|
|
OAuth2-Konfiguration (TenantId, ClientId, verschlüsseltes Secret) |
|
Konfigurierte Postfächer mit Sync-Status |
|
Regeln: Bedingung → Aktion (Priorität, Agent, Ticket) |
|
Abgerufene E-Mails mit Verarbeitungsstatus |
|
Erweiterte Verarbeitungsregeln (Absender, Betreff, Inhalt) |
|
Sync-Protokoll pro Postfach |
Multi-Tenancy
Jede Tabelle hat ein tenantId-Feld (Ausnahmen: reine Join-Tabellen). Alle Abfragen in server/storage.ts filtern immer nach tenantId:
// Richtig — tenantId immer filtern
const result = await db
.select()
.from(tickets)
.where(and(eq(tickets.tenantId, tenantId), eq(tickets.id, ticketId)));
Soft-Delete
Tickets, Kommentare und KB-Artikel unterstützen Soft-Delete (DSGVO):
// Felder in der Tabelle
deletedAt: timestamp("deleted_at") // null = aktiv
deletedBy: text("deleted_by") // userId
Alle Abfragen für aktive Einträge schließen deletedAt IS NULL ein.
Verbindungskonfiguration
DATABASE_URL=postgresql://user:password@host:5432/dbname
Für Neon-Serverless wird @neondatabase/serverless als Drizzle-Adapter verwendet, was WebSocket-basierte Verbindungen ermöglicht.