Skip to content

Datenbank-Architektur

TCM365 verwendet PostgreSQL 15 als primäre Datenbank mit TypeORM 0.3 als ORM-Schicht. Das Datenbankdesign umfasst 35 Entities, Single Table Inheritance für Multi-Vendor-Support, Row-Level Security für Tenant-Isolation und Per-Tenant-Schemas für Data-Plane-Trennung.


Technology Stack

Technologie Version Zweck
PostgreSQL 15 Relationale Datenbank-Engine
TypeORM 0.3 Object-Relational Mapping
uuid-ossp Built-in UUID-Generierung für Primärschlüssel
Row-Level Security Built-in Tenant-Level-Datenisolation

Entity-Ueberblick

TCM365 definiert 35 TypeORM Entities in sechs funktionalen Kategorien. Alle Entities erweitern eine gemeinsame BaseEntity, die UUID-Primärschlüssel und Zeitstempel bereitstellt.

BaseEntity-Pattern

Jede Entity erbt von der gemeinsamen BaseEntity:

// backend-js/src/common/entities/base.entity.ts
import { PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';

export abstract class BaseEntity {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @CreateDateColumn({ name: 'created_at' })
  createdAt: Date;

  @UpdateDateColumn({ name: 'updated_at' })
  updatedAt: Date;
}

UUID-Primärschlüssel

TCM365 verwendet UUID v4 Primärschlüssel statt Auto-Increment-Integers. Dies verhindert ID-Enumerationsangriffe, unterstützt verteilte ID-Generierung und vermeidet Konflikte in Multi-Tenant-Schemas.


Entity-Katalog

Kern-Entities

Entity Tabelle Beschreibung
User users Anwendungsbenutzer mit lokaler/Azure AD Auth, RBAC-Rollen und Berechtigungen
Group groups Benutzergruppen-Management mit rollenbasierten Mitgliedschaften
InternalTenant internal_tenants Organisatorische Gruppierungen (Org-Level-Isolationsgrenze)

Legacy Cleanup (v2.4.0)

Die m365_tenants-Tabelle wurde in v2.4.0 vollständig entfernt. Alle Foreign Keys wurden auf vendor_tenants migriert. Das frühere "Dual FK"-Pattern (sowohl m365_tenant_id als auch vendor_tenant_id) existiert nicht mehr.

Vendor Tenant-Hierarchie (Single Table Inheritance)

Entity Tabelle Diskriminator Beschreibung
VendorTenant vendor_tenants Basis (abstrakt) STI-Eltern-Entity mit gemeinsamen Spalten
M365VendorTenant vendor_tenants microsoft Microsoft 365 Tenant mit M365-spezifischen Spalten
ZscalerVendorTenant vendor_tenants zscaler Zscaler Tenant mit ZIA/ZPA-spezifischen Spalten
AtlassianVendorTenant vendor_tenants atlassian Atlassian Cloud Tenant mit OAuth Tokens, Site-Info, Guard Tier (v2.5.0)

Siehe den Abschnitt Single Table Inheritance (STI) weiter unten für Details.

Configuration Management Entities

Entity Tabelle Beschreibung
Snapshot snapshots Point-in-Time Konfigurationserfassungen
Blueprint blueprints Konfigurationsvorlagen und Baselines
BlueprintAnalysis blueprint_analyses KI-gestützte Analyseergebnisse für Blueprint-Einstellungen
ConfigurationDrift configuration_drifts Erkannte Drift-Einträge zwischen Snapshots
ConfigurationMonitor configuration_monitors Aktive Drift-Monitoring-Konfigurationen
SeveritySuggestion severity_suggestions KI-basierte Severity-Anreicherung für Compliance-Regeln (v2.4.0)

Operations Entities

Entity Tabelle Beschreibung
Workflow workflows Geplante Aufgabendefinitionen
WorkflowExecution workflow_executions Aufgabenausfuehrungsprotokolle mit Status und Output
RollbackHistory rollback_histories Rollback-Operationsprotokolle mit Pre/Post-State

Anomaly Detection Entities

Entity Tabelle Beschreibung
AnomalyBaseline anomaly_baselines ML-basierte Anomalie-Detection-Baseline-Profile
AnomalyEvent anomaly_events Erkannte Anomalie-Events mit Schweregrad und Kontext
AnomalyMetric anomaly_metrics Zeitreihen-Anomalie-Detection-Metriken
CustomProbe custom_probes Benutzerdefinierte Custom Monitoring Probe-Definitionen
CustomProbeExecution custom_probe_executions Custom Probe-Ausfuehrungsergebnisse

KRITIS/NIS2 Compliance Entities

Entity Tabelle Beschreibung
Incident incidents Sicherheitsvorfälle mit NIS2-Meldefristen
RiskAssessment risk_assessments Risikobewertungen mit Wahrscheinlichkeits-/Auswirkungs-Scoring
ChangeRequest change_requests Change Management Requests
ChangeApproval change_approvals Approval Chain-Einträge für Change Requests
ComplianceCheck compliance_checks Compliance-Bewertungsergebnisse über Frameworks
BcdrTest bcdr_tests BC/DR-Testprotokolle mit RTO/RPO-Tracking
AuditEvidence audit_evidences Audit-Nachweisartefakte für Compliance-Audits
ReadinessAssessment readiness_assessments Copilot Readiness Assessment-Ergebnisse (44 Checks)

Infrastruktur-Entities

Entity Tabelle Beschreibung
AuditLog audit_logs Unveränderliche Aktionsprotokolle (wer hat was wann getan)
NotificationConfig notification_configs Benachrichtigungskanal-Konfigurationen
NotificationLog notification_logs Benachrichtigungs-Zustellstatus-Einträge
Report reports Generierte Report-Metadaten und Speicherreferenzen
SystemSetting system_settings Systemweite Key-Value-Konfigurationseinstellungen
UTCMQuotaUsage utcm_quota_usages UTCM API Quota-Nutzungsverfolgung pro Tenant

Single Table Inheritance (STI)

Die vendor_tenants-Tabelle verwendet TypeORMs Single Table Inheritance-Pattern mit einer vendor-Diskriminatorspalte, um mehrere Vendor-Typen in einer Tabelle zu unterstützen.

STI-Struktur

vendor_tenants Tabelle
├── id (uuid, PK)
├── vendor (varchar) ─── Diskriminator: 'microsoft' | 'zscaler' | 'atlassian'
├── name (varchar)
├── org_id (uuid, FK → internal_tenants)
├── created_at (timestamp)
├── updated_at (timestamp)
├── [Microsoft-spezifische Spalten]
│   ├── tenant_id (varchar, nullable)
│   ├── domain (varchar, nullable)
│   ├── connection_type (varchar, nullable)
│   ├── enabled_workloads (jsonb, nullable)
│   ├── write_credentials (jsonb, nullable)
│   └── granted_permissions (jsonb, nullable)
├── [Zscaler-spezifische Spalten]
│   ├── zia_cloud (varchar, nullable)
│   ├── zia_api_key (varchar, nullable)
│   ├── zia_admin_username (varchar, nullable)
│   ├── zia_admin_password (varchar, nullable)
│   ├── zpa_customer_id (varchar, nullable)
│   ├── zpa_client_id (varchar, nullable)
│   ├── zpa_client_secret (varchar, nullable)
│   └── zpa_cloud (varchar, nullable)
└── [Atlassian-spezifische Spalten] (v2.5.0)
    ├── oauth_access_token (text, nullable)
    ├── oauth_refresh_token (text, nullable)
    ├── oauth_token_expires_at (timestamp, nullable)
    ├── site_id (varchar, nullable)
    ├── site_url (varchar, nullable)
    ├── site_name (varchar, nullable)
    └── guard_tier (varchar, nullable)

TypeORM-Implementierung

// Basis-Entity
@Entity('vendor_tenants')
@TableInheritance({ column: { type: 'varchar', name: 'vendor' } })
export class VendorTenant extends BaseEntity {
  @Column()
  name: string;

  @ManyToOne(() => InternalTenant)
  @JoinColumn({ name: 'org_id' })
  organization: InternalTenant;
}

// Microsoft Child-Entity
@ChildEntity('microsoft')
export class M365VendorTenant extends VendorTenant {
  @Column({ name: 'tenant_id', nullable: true })
  tenantId: string;

  @Column({ nullable: true })
  domain: string;

  @Column({ name: 'enabled_workloads', type: 'jsonb', nullable: true })
  enabledWorkloads: string[];
}

// Zscaler Child-Entity
@ChildEntity('zscaler')
export class ZscalerVendorTenant extends VendorTenant {
  @Column({ name: 'zia_cloud', nullable: true })
  ziaCloud: string;

  @Column({ name: 'zia_api_key', nullable: true })
  ziaApiKey: string;
  // ... weitere ZIA/ZPA-Spalten
}

// Atlassian Child-Entity (v2.5.0)
@ChildEntity('atlassian')
export class AtlassianVendorTenant extends VendorTenant {
  @Column({ name: 'site_id', nullable: true })
  siteId: string;

  @Column({ name: 'site_url', nullable: true })
  siteUrl: string;

  @Column({ name: 'guard_tier', nullable: true })
  guardTier: string;
  // ... weitere OAuth- und Site-Spalten
}

Neue Vendor hinzufügen

Neue Vendor werden durch Erstellen einer @ChildEntity hinzugefügt, die VendorTenant erweitert. Vendor-spezifische Spalten werden in derselben Tabelle mit nullable: true hinzugefügt. Keine neuen Tabellen erforderlich.


Row-Level Security (RLS)

PostgreSQL Row-Level Security stellt sicher, dass Anwendungsabfragen nur Daten zurueckgeben, die zur Organisation des authentifizierten Benutzers gehören -- selbst wenn Anwendungsebenen-Checks umgangen werden.

Zwei-Rollen-Architektur

Rolle RLS-Verhalten Zweck
tcm_admin BYPASSRLS Migrationen, Admin-Operationen, Schema-Verwaltung
tcm_app Respektiert RLS Anwendungsabfragen, benutzerseitige Operationen

RLS-Policy-Pattern

-- RLS auf tenant-scoped Tabellen aktivieren
ALTER TABLE snapshots ENABLE ROW LEVEL SECURITY;

-- Policy: Benutzer sehen nur Daten ihrer Organisation
CREATE POLICY tenant_isolation ON snapshots
  USING (org_id = current_setting('app.current_org_id')::uuid);

-- Die Anwendung setzt die Session-Variable vor jeder Abfrage
SET app.current_org_id = '<user-org-uuid>';

RLS-geschuetzte Tabellen

RLS-Policies werden auf 18 tenant-scoped Tabellen angewendet:

Kategorie Tabellen
Tenants vendor_tenants
Config Management snapshots, configuration_drifts, configuration_monitors, blueprints, blueprint_analyses
Operations workflows, workflow_executions, rollback_histories
Compliance incidents, risk_assessments, change_requests, compliance_checks, bcdr_tests, audit_evidences
Anomaly anomaly_baselines, anomaly_events, custom_probes

Schema-per-Tenant-Isolation

Über RLS hinaus bietet TCM365 physische Datentrennung für Data-Plane-Tabellen durch Per-Tenant PostgreSQL-Schemas.

Schema-Namenskonvention

public                  -- Gemeinsame Control-Plane-Tabellen (users, groups, system_settings)
tenant_{uuid}           -- Per-Tenant Data-Plane-Tabellen (snapshots, drifts, monitors)

Beispiel: Eine Organisation mit ID a1b2c3d4-... erhält Schema tenant_a1b2c3d4.

Data-Plane-Tabellen (23 Tabellen pro Tenant-Schema)

Diese Tabellen werden in jedem Tenant-Schema dupliziert:

  • snapshots, configuration_drifts, configuration_monitors
  • workflows, workflow_executions, rollback_histories
  • anomaly_baselines, anomaly_events, anomaly_metrics
  • custom_probes, custom_probe_executions
  • blueprints, blueprint_analyses
  • incidents, risk_assessments, change_requests, change_approvals
  • compliance_checks, bcdr_tests, audit_evidences
  • notification_configs, reports, utcm_quota_usages

TenantSchemaManager

Der TenantSchemaManager-Service verwaltet den Schema-Lebenszyklus:

@Injectable()
export class TenantSchemaManager {
  // Schema erstellen, wenn eine neue Organisation hinzugefügt wird
  async createTenantSchema(orgId: string): Promise<void>;

  // Migrationen auf einem bestimmten Tenant-Schema ausführen
  async migrateTenantSchema(orgId: string): Promise<void>;

  // Schema löschen, wenn eine Organisation entfernt wird
  async dropTenantSchema(orgId: string): Promise<void>;
}

Migrations-Hinweise

Bei der Erstellung von Migrationen, die Data-Plane-Tabellen betreffen, muss die Migration sowohl das public-Schema (Vorlage) als auch alle bestehenden tenant_*-Schemas aktualisieren. Siehe Migration Troubleshooting für Anleitungen.


Entity-Beziehungen

Wichtige Beziehungen

erDiagram
    InternalTenant ||--o{ VendorTenant : "hat viele"
    InternalTenant ||--o{ User : "hat viele"
    InternalTenant ||--o{ Group : "hat viele"
    VendorTenant ||--o{ Snapshot : "hat viele"
    VendorTenant ||--o{ ConfigurationDrift : "hat viele"
    VendorTenant ||--o{ ConfigurationMonitor : "hat viele"
    VendorTenant ||--o{ Workflow : "hat viele"
    Snapshot ||--o{ ConfigurationDrift : "Quelle/Ziel"
    ChangeRequest ||--o{ ChangeApproval : "hat viele"
    User }o--|| InternalTenant : "gehört zu"
    User }o--o{ Group : "Mitglied von"

Legacy Cleanup abgeschlossen (v2.4.0)

Ab v2.4.0 verwenden alle Entities ausschliesslich vendor_tenant_id als Fremdschluessel zur vendor_tenants-Tabelle. Die frühere m365_tenants-Tabelle und die zugehörigen m365_tenant_id-Spalten wurden vollständig entfernt.


Migrationen

TCM365 hat 32 TypeORM-Migrationen, die das vollständige Datenbankschema aufbauen.

Migrations-Befehle

cd backend-js

# Alle ausstehenden Migrationen ausführen
npm run migration:run

# Neue Migration aus Entity-Änderungen generieren
npm run migration:generate src/database/migrations/BeschreibenderName

# Letzte angewendete Migration zurücksetzen
npm run migration:revert

Migrations-Best-Practices

  1. Immer generieren, nie von Hand schreiben. Verwenden Sie migration:generate, um Entity-Änderungen automatisch zu erkennen.
  2. Beide Richtungen testen. Stellen Sie sicher, dass up() und down() beide funktional sind.
  3. Tenant-Schemas aktualisieren. Data-Plane-Tabellenaenderungen müssen auf alle tenant_*-Schemas angewendet werden.
  4. snake_case für Spalten. TypeORM transformiert camelCase-Properties in snake_case-Spalten.
  5. Standard nullable für neue Spalten. Vermeiden Sie das Brechen bestehender Daten mit NOT NULL-Constraints auf neuen Spalten.

DataSource-Konfiguration

// backend-js/src/database/data-source.ts
export const AppDataSource = new DataSource({
  type: 'postgres',
  host: process.env.DATABASE_HOST,
  port: parseInt(process.env.DATABASE_PORT, 10),
  username: process.env.DATABASE_USERNAME,
  password: process.env.DATABASE_PASSWORD,
  database: process.env.DATABASE_NAME,
  entities: [__dirname + '/../entities/*.entity{.ts,.js}'],
  migrations: [__dirname + '/migrations/*{.ts,.js}'],
  synchronize: false,  // Niemals true in der Produktion
  logging: process.env.DATABASE_LOGGING === 'true',
});

Niemals Synchronize aktivieren

synchronize: true ändert das Datenbankschema bei jedem Start automatisch, um es an die Entities anzupassen. Dies kann zu Datenverlust in der Produktion führen. Verwenden Sie immer Migrationen.


JSONB-Spalten

TCM365 verwendet PostgreSQL JSONB-Spalten für flexible Metadatenspeicherung, wo Schema-Flexibilitaet benötigt wird:

Entity Spalte Inhalt
Snapshot data Vollständiger Konfigurationssnapshot (vendor-spezifisches JSON)
M365VendorTenant enabled_workloads Array der aktivierten M365 Workloads
M365VendorTenant write_credentials Verschluesselte Schreiboperations-Credentials
M365VendorTenant granted_permissions Array der erteilten Graph API-Berechtigungen
ConfigurationDrift changes Drift-Aenderungsdetails (Vorher/Nachher-Werte)
ConfigurationMonitor resource_filters Ressourcentyp-Filter für Monitoring
Blueprint configuration Blueprint-Konfigurationsvorlagendaten
ComplianceCheck results Compliance-Bewertungsergebnisse pro Regel
AnomalyBaseline baseline_data ML-berechnetes Baseline-Statistikmodell
CustomProbe probe_config Custom Probe-Definition und Parameter

Performance-Aspekte

Indexierungsstrategie

TCM365 erstellt Indizes auf häufig abgefragten Spalten:

  • Fremdschluessel: Alle org_id, vendor_tenant_id, m365_tenant_id-Spalten
  • Status-Spalten: status auf Snapshots, Workflows, Incidents
  • Zeitstempel: created_at für Zeitbereichsabfragen
  • Zusammengesetzt: (org_id, vendor_tenant_id, created_at) für tenant-scoped Zeitabfragen

Abfrage-Patterns

  • TypeORM Repository-Methoden (find, findOne, save) statt roher Abfragen verwenden
  • QueryBuilder für komplexe Joins und Aggregationen nutzen
  • take und skip für Paginierung verwenden (niemals unbegrenzte Ergebnismengen laden)
  • order nach Zeitstempel absteigend für Neueste-Zuerst-Abfragen anwenden

Datenbank-Diagnostik

TCM365 bietet integrierte Datenbankdiagnostik:

Endpoint Zweck
GET /health Datenbank-Konnektivitaetspruefung mit Latenzmessung
GET /api/v1/diagnostics Vollständige Datenbankgesundheit inkl. Migrationsstatus
POST /api/v1/diagnostics/repair?action=run_migrations Ausstehende Migrationen über API ausführen