Zum Inhalt springen

Schema und Konventionen

Status: Entwurf · Spec-Kandidat: ja

Schema-Trennung: System vs. Domain

Es gibt zwei Postgres-Schemata mit klarer Verantwortungsgrenze:

SchemaZweckTenant-BindungBeispiel-Tabellen
mdm_sysSystem — plattformweite Verwaltung, kein Tenant-Scopekeine tenant_idAA_TENANT, AA_APP_USER, AA_SERVICE_ACCOUNT, System-Rollen, System-Permissions
mdmDomain — fachliche Stammdaten, immer mandantengebundentenant_id NOT NULL auf jeder TabelleDDM_ENTITY, DDM_ENTITY_RELATION, DDM_ENTITY_VERSION, DDM_ENUM_SET, DDM_ENUM_VALUE, DDM_ENTITY_TYPE, DDM_ENTITY_TYPE_ATTRIBUTE, DDM_RELATION_TYPE, DDM_RELATION_TYPE_ATTRIBUTE, AA_OUTBOX_EVENT, AA_AUDIT_LOG (für fachliche Aktionen)

Querschnittstabellen mit gemischter Nutzung:

  • AA_AUDIT_LOG liegt in mdm mit tenant_id NULLABLE — Datensätze ohne Tenant-Bezug (Plattform-Admin-Aktionen, Tenant-Anlage) sind erlaubt.
  • AA_OUTBOX_EVENT liegt in mdm mit tenant_id NULLABLE — analog.
  • RBAC/ACL-Tabellen (AA_ROLE, AA_PERMISSION, AA_ROLE_PERMISSION, AA_PRINCIPAL_ROLE, AA_PRINCIPAL_GROUP, AA_PRINCIPAL_GROUP_MEMBER, AA_ACL_ENTRY) liegen in mdm. System-Rollen/Permissions (is_system=true) sind in mdm_sys gespiegelt nicht dupliziert, sondern in derselben Tabelle markiert.

Die Anwendung greift ausschließlich über voll qualifizierte Namen (mdm.DDM_ENTITY, mdm_sys.AA_TENANT, …) zu, nicht über search_path-Manipulation.

Entscheidung (OP-28a): DDM_ENTITY_TYPE, DDM_ENTITY_TYPE_ATTRIBUTE, DDM_RELATION_TYPE, DDM_RELATION_TYPE_ATTRIBUTE, DDM_ENUM_SET, DDM_ENUM_VALUE sind per-tenant (mdm.<tabelle> mit tenant_id NOT NULL). Damit darf jede Konzern-Tochter eigene Typen pflegen. Eine spätere “Globalisierung” einzelner Typen ist durch Replikation (oder optionalen “shared”-Tenant) möglich; das Umgekehrte (von global zu tenant-spezifisch) wäre teurer.

Erweiterungen

  • pgcrypto ist Pflicht (für gen_random_uuid()):

    CREATE EXTENSION IF NOT EXISTS pgcrypto;

Postgres-Enums (Typen)

TypWerte
mdm.attribute_data_typestring, text, integer, decimal, boolean, date, datetime, enum, multi_enum, reference, multi_reference, json
mdm.entity_statusdraft, active, inactive, archived
mdm.delete_policyrestrict, detach, cascade, archive_only
mdm.audit_actioninsert, update, archive, restore, soft_delete, hard_delete, relate, unrelate, version_create, permission_grant, permission_revoke, role_assign, role_unassign, login, access_denied
mdm.principal_typeuser, service_account, role, group
mdm.permission_effectallow, deny
mdm.permission_actionread, create, update, archive, restore, soft_delete, hard_delete, relate, unrelate, export, manage_metadata, manage_permissions, read_audit
mdm.acl_scopeglobal, tenant, entity_type, entity, relation_type
mdm.outbox_statuspending, dispatched, failed, skipped

Naming-Konventionen

  • Tabellen-Präfixe trennen die zwei großen Verantwortungsbereiche:
    • DDM_ (Dynamic Domain Model) — Tabellen, die das dynamische, fachliche Domänenmodell abbilden, das zur Laufzeit über Metadaten definiert wird (DDM_ENTITY_TYPE, DDM_ENTITY_TYPE_ATTRIBUTE, DDM_ENTITY, DDM_RELATION_TYPE, DDM_RELATION_TYPE_ATTRIBUTE, DDM_ENTITY_RELATION, DDM_ENTITY_VERSION, DDM_ENUM_SET, DDM_ENUM_VALUE).
    • AA_ (AdhocAi) — Plattform-/System-Tabellen für Identität, RBAC/ACL, Audit, Outbox, Mandant (AA_TENANT, AA_APP_USER, AA_SERVICE_ACCOUNT, AA_PRINCIPAL_GROUP, AA_PRINCIPAL_GROUP_MEMBER, AA_ROLE, AA_PERMISSION, AA_ROLE_PERMISSION, AA_PRINCIPAL_ROLE, AA_ACL_ENTRY, AA_AUDIT_LOG, AA_OUTBOX_EVENT).
  • Tabellen-Identifier werden in der Spec UPPERCASE geschrieben (DDM_ENTITY, nicht ddm_entity). PostgreSQL faltet unquoted Identifier intern auf Lowercase — Queries sind case-insensitive, daher in DDL und Code beide Schreibweisen äquivalent. Die UPPERCASE-Schreibweise dient ausschließlich der Lesbarkeit und der schnellen Unterscheidung beider Tabellenklassen.
  • Spalten: snake_case (tenant_id, entity_type_id, created_at).
  • Enum-Typen, Trigger-Funktionen, Indizes, Constraints: snake_case ohne Präfix (z. B. mdm.entity_status, trg_entity_before_write, uq_entity_code_active).
  • Primärschlüssel: id uuid mit gen_random_uuid().
  • Fachlicher Schlüssel: key text mit Format ^[a-z][a-z0-9_]*$ (Check Constraint).
  • Fachlicher Code je Datensatz: code text, eindeutig je Tenant + Typ unter aktiven Datensätzen (Partial Unique Index).
  • Mandant: alle fachlichen Tabellen (DDM_ENTITY_TYPE, DDM_ENTITY, DDM_ENTITY_RELATION) tragen tenant_id NOT NULL. RBAC/Audit/Outbox tragen tenant_id NULLABLE für tenant-übergreifende Aktionen.
  • Zeitstempel: timestamptz.
  • Soft Delete: deleted_at timestamptz NULLABLE, deleted_by text NULLABLE.
  • Archivierung: archived_at timestamptz, archived_by text (zusätzlich zu status='archived').
  • Audit-Felder je Tabelle: created_at, created_by, updated_at, updated_by.
  • JSONB-Strukturen, die Objekte sein müssen, werden per Check Constraint geprüft (jsonb_typeof(...) = 'object').

Migrationsstrategie

  • Migrationswerkzeug ist Pflicht (siehe CI/CD und Migrationen).
  • Konkretes Tool ist nicht festgelegt (offen).
  • Änderungen am mdm-Schema sind versioniert; rein metadatengetriebene Änderungen (neuer Entitätstyp, neues Attribut) erfolgen nicht über Migrationen, sondern über die API.

Verwandte Dokumente