Schema und Konventionen
Status: Entwurf · Spec-Kandidat: ja
Schema-Trennung: System vs. Domain
Es gibt zwei Postgres-Schemata mit klarer Verantwortungsgrenze:
| Schema | Zweck | Tenant-Bindung | Beispiel-Tabellen |
|---|---|---|---|
mdm_sys | System — plattformweite Verwaltung, kein Tenant-Scope | keine tenant_id | AA_TENANT, AA_APP_USER, AA_SERVICE_ACCOUNT, System-Rollen, System-Permissions |
mdm | Domain — fachliche Stammdaten, immer mandantengebunden | tenant_id NOT NULL auf jeder Tabelle | DDM_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_LOGliegt inmdmmittenant_id NULLABLE— Datensätze ohne Tenant-Bezug (Plattform-Admin-Aktionen, Tenant-Anlage) sind erlaubt.AA_OUTBOX_EVENTliegt inmdmmittenant_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 inmdm. System-Rollen/Permissions (is_system=true) sind inmdm_sysgespiegelt 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
-
pgcryptoist Pflicht (fürgen_random_uuid()):CREATE EXTENSION IF NOT EXISTS pgcrypto;
Postgres-Enums (Typen)
| Typ | Werte |
|---|---|
mdm.attribute_data_type | string, text, integer, decimal, boolean, date, datetime, enum, multi_enum, reference, multi_reference, json |
mdm.entity_status | draft, active, inactive, archived |
mdm.delete_policy | restrict, detach, cascade, archive_only |
mdm.audit_action | insert, update, archive, restore, soft_delete, hard_delete, relate, unrelate, version_create, permission_grant, permission_revoke, role_assign, role_unassign, login, access_denied |
mdm.principal_type | user, service_account, role, group |
mdm.permission_effect | allow, deny |
mdm.permission_action | read, create, update, archive, restore, soft_delete, hard_delete, relate, unrelate, export, manage_metadata, manage_permissions, read_audit |
mdm.acl_scope | global, tenant, entity_type, entity, relation_type |
mdm.outbox_status | pending, 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, nichtddm_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_caseohne Präfix (z. B.mdm.entity_status,trg_entity_before_write,uq_entity_code_active). - Primärschlüssel:
id uuidmitgen_random_uuid(). - Fachlicher Schlüssel:
key textmit 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) tragentenant_idNOT NULL. RBAC/Audit/Outbox tragentenant_idNULLABLE 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 zustatus='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.