472 lines
9.3 KiB
Markdown
472 lines
9.3 KiB
Markdown
## 1. Zusammenfassung
|
|
|
|
Claude benennt valide Architektur-Risiken. Für das Projekt werden daraus keine neuen Produktziele abgeleitet, sondern konkrete Korrekturen an Datenmodell, Security-Dokumentation, ADRs und Betriebsregeln.
|
|
|
|
Kernentscheidungen:
|
|
|
|
- `tenant_id` wird der einzige technische Mandanten-Isolationsschlüssel.
|
|
- `organisation_id` wird nicht mehr für Tenant-Isolation verwendet.
|
|
- Multi-Tenancy wird nicht „halb vorbereitet“, sondern technisch sauber in V1 angelegt.
|
|
- Secrets werden nicht im Domainmodell gespeichert, sondern nur referenziert.
|
|
- Audit-Hash-Chain wird nicht als manipulationssichere Security-Maßnahme verkauft.
|
|
- DLQ, Dokumente, Rollen und Reconciliation erhalten konkrete Regeln.
|
|
- Bounded Contexts werden als Modul-/Schema-Grenzen dokumentiert, keine Microservice-Aufspaltung.
|
|
|
|
---
|
|
|
|
## 2. Übernommene Punkte
|
|
|
|
### Tenant-Isolation
|
|
|
|
Übernehmen.
|
|
|
|
Änderung:
|
|
|
|
- `tenant_id` ist Pflichtfeld auf allen mandantenbezogenen Tabellen.
|
|
- `organisation_id` wird aus der technischen Isolation entfernt.
|
|
- Falls Organisation benötigt wird, dann nur fachlich, z. B. als `customer_organisation_id`.
|
|
- PostgreSQL Row-Level-Security wird vorgesehen.
|
|
- Tenant-Kontext wird pro Request/Job explizit gesetzt.
|
|
- Queries ohne Tenant-Kontext müssen fehlschlagen.
|
|
|
|
Konkrete Modellregel:
|
|
|
|
```text
|
|
tenant_id UUID NOT NULL REFERENCES tenants(id)
|
|
```
|
|
|
|
Für mandantenbezogene Relationen:
|
|
|
|
```text
|
|
FOREIGN KEY (tenant_id, customer_id)
|
|
REFERENCES customers(tenant_id, id)
|
|
```
|
|
|
|
---
|
|
|
|
### Secrets-Management
|
|
|
|
Übernehmen.
|
|
|
|
Änderung:
|
|
|
|
- Keine API-Keys, Passwörter oder Tokens in Fachentitäten.
|
|
- Domainmodelle speichern nur `secret_ref`.
|
|
- Secret-Service wird als technischer Baustein dokumentiert.
|
|
- Encryption-at-rest wird verpflichtend für Secret-Storage.
|
|
- Zugriff auf Secrets nur über Service-Layer, nicht über direkte DB-Reads.
|
|
|
|
Beispiel:
|
|
|
|
```text
|
|
registrar_accounts.secret_ref
|
|
```
|
|
|
|
statt:
|
|
|
|
```text
|
|
registrar_accounts.api_key
|
|
registrar_accounts.password
|
|
```
|
|
|
|
---
|
|
|
|
### Audit-Log
|
|
|
|
Teilweise übernehmen.
|
|
|
|
Änderung:
|
|
|
|
- Hash-Chain wird nicht als Schutz gegen DB-Admin-Manipulation beschrieben.
|
|
- Audit-Log bleibt append-only auf Anwendungsebene.
|
|
- Integritätsprüfung wird klar abgegrenzt.
|
|
- Optional: periodischer Export/Checkpoint in externes System.
|
|
|
|
ADR 0014 muss entsprechend korrigiert werden.
|
|
|
|
---
|
|
|
|
### Dead Letter Queue
|
|
|
|
Übernehmen.
|
|
|
|
Änderung:
|
|
|
|
- DLQ erhält Retention-Regeln.
|
|
- PII in Fehlerpayloads wird vermieden oder redaktiert.
|
|
- Maximale Aufbewahrung wird festgelegt.
|
|
- Reprocessing und Löschung werden beschrieben.
|
|
|
|
Vorschlag:
|
|
|
|
```text
|
|
DLQ default retention: 30 Tage
|
|
DLQ max retention: 90 Tage
|
|
PII payloads: nicht speichern oder redaktieren
|
|
```
|
|
|
|
---
|
|
|
|
### Bounded Contexts
|
|
|
|
Übernehmen, aber pragmatisch.
|
|
|
|
Änderung:
|
|
|
|
- Keine sofortige Service-Aufteilung.
|
|
- Einführung klarer Modulgrenzen im Monolithen.
|
|
- Datenmodell wird nach fachlichen Bereichen gegliedert.
|
|
|
|
Kontexte:
|
|
|
|
- Identity & Access
|
|
- CRM
|
|
- Billing
|
|
- Provisioning
|
|
- Registry
|
|
- Support
|
|
- Documents
|
|
- Audit
|
|
|
|
---
|
|
|
|
### Reconciliation
|
|
|
|
Teilweise übernehmen.
|
|
|
|
Änderung:
|
|
|
|
- Kein vollständiges Event-Sourcing für V1.
|
|
- Stattdessen Operation-/Job-Historie und Status-Snapshots.
|
|
- Reconciliation basiert auf:
|
|
- gewünschtem Zustand
|
|
- aktuellem externem Zustand
|
|
- letzter Operation
|
|
- Fehlerhistorie
|
|
|
|
Benötigte Tabellen/Modelle:
|
|
|
|
```text
|
|
provisioning_operations
|
|
external_resource_snapshots
|
|
job_runs
|
|
job_attempts
|
|
```
|
|
|
|
---
|
|
|
|
### Rollen und Scopes
|
|
|
|
Übernehmen.
|
|
|
|
Änderung:
|
|
|
|
- Rollen werden nicht nur benannt, sondern mit konkreten Berechtigungen dokumentiert.
|
|
- Zugriff auf Secrets, Rechnungen, Serverdaten und Kundendaten wird explizit geregelt.
|
|
|
|
Beispielrollen:
|
|
|
|
- Owner
|
|
- Admin
|
|
- Billing
|
|
- Support
|
|
- Provisioning Operator
|
|
- Read-only Auditor
|
|
|
|
---
|
|
|
|
### Dokument-Storage
|
|
|
|
Übernehmen.
|
|
|
|
Änderung:
|
|
|
|
- Dokumente speichern keine Datei direkt im Datenmodell.
|
|
- Dokumente referenzieren Object Storage.
|
|
- Tenant-Isolation über Bucket/Prefix plus DB-Zugriffskontrolle.
|
|
- Löschung, Archivierung und Legal Hold werden dokumentiert.
|
|
|
|
Beispiel:
|
|
|
|
```text
|
|
documents.object_key
|
|
documents.storage_provider
|
|
documents.checksum_sha256
|
|
documents.retention_until
|
|
documents.legal_hold
|
|
documents.deleted_at
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Abgelehnte oder verschobene Punkte
|
|
|
|
### Vollständiges Event-Sourcing
|
|
|
|
Verschoben.
|
|
|
|
Begründung:
|
|
|
|
- Für V1 nicht erforderlich.
|
|
- Reconciliation kann über Operation-Historie, Job-Historie und Snapshots umgesetzt werden.
|
|
|
|
---
|
|
|
|
### Microservice-Aufteilung nach Bounded Contexts
|
|
|
|
Abgelehnt für V1.
|
|
|
|
Begründung:
|
|
|
|
- Zu hoher Betriebs- und Integrationsaufwand.
|
|
- Modulgrenzen im Monolithen reichen aktuell aus.
|
|
|
|
---
|
|
|
|
### Audit-Hash-Chain als Manipulationsschutz
|
|
|
|
Abgelehnt.
|
|
|
|
Änderung:
|
|
|
|
- Hash-Chain darf maximal als Integritätsindikator beschrieben werden.
|
|
- Kein Sicherheitsversprechen gegen privilegierte DB-Manipulation.
|
|
|
|
---
|
|
|
|
### Parallele Nutzung von `organisation_id` und `tenant_id`
|
|
|
|
Abgelehnt.
|
|
|
|
Änderung:
|
|
|
|
- Nur `tenant_id` ist technischer Scope.
|
|
- Organisation ist, falls benötigt, ein CRM-/Kundenkonzept.
|
|
|
|
---
|
|
|
|
### Single-Tenant V1 ohne Tenant-Schutz
|
|
|
|
Abgelehnt.
|
|
|
|
Änderung:
|
|
|
|
- V1 darf fachlich nur einen aktiven Tenant haben.
|
|
- Technisch wird Tenant-Isolation trotzdem sauber eingebaut.
|
|
|
|
---
|
|
|
|
## 4. Neue/geänderte Dateien
|
|
|
|
### Geändert
|
|
|
|
#### `docs/data-model-v0.2.md`
|
|
|
|
Änderungen:
|
|
|
|
- `organisation_id` aus technischer Mandanten-Isolation entfernen.
|
|
- `tenant_id` als verbindlichen Scope definieren.
|
|
- Tenant-FK-Regeln ergänzen.
|
|
- Tabellen nach Bounded Contexts gruppieren.
|
|
- Secret-Felder durch `secret_ref` ersetzen.
|
|
- Dokumentmodell um Storage-Metadaten erweitern.
|
|
- Operation-/Job-Historie ergänzen.
|
|
|
|
---
|
|
|
|
#### `docs/security.md`
|
|
|
|
Änderungen:
|
|
|
|
- Tenant-Isolation konkretisieren.
|
|
- Secrets-Management konkretisieren.
|
|
- RBAC/Scopes verlinken.
|
|
- RLS und Tenant-Kontext als Pflichtmechanismus aufnehmen.
|
|
|
|
---
|
|
|
|
#### `docs/adr/0014-audit-log.md`
|
|
|
|
Änderungen:
|
|
|
|
- Hash-Chain nicht mehr als manipulationssicher beschreiben.
|
|
- Algorithmus konkretisieren, falls beibehalten.
|
|
- Optionalen externen Checkpoint/Export dokumentieren.
|
|
- Grenzen des Mechanismus explizit nennen.
|
|
|
|
---
|
|
|
|
#### `docs/adr/0017-jobs-reconciliation-dlq.md`
|
|
|
|
Änderungen:
|
|
|
|
- DLQ-Retention ergänzen.
|
|
- PII-Regeln ergänzen.
|
|
- Reprocessing-Regeln ergänzen.
|
|
- Reconciliation-Datenbasis ergänzen.
|
|
|
|
---
|
|
|
|
### Neu
|
|
|
|
#### `docs/architecture/tenant-isolation.md`
|
|
|
|
Inhalt:
|
|
|
|
- `tenant_id` als einziger technischer Mandantenschlüssel
|
|
- Request-/Job-Tenant-Kontext
|
|
- Fail-closed-Verhalten
|
|
- RLS-Grundregeln
|
|
- Cross-Tenant-Zugriffe verboten
|
|
- Composite FK-Regeln
|
|
|
|
---
|
|
|
|
#### `docs/architecture/bounded-contexts.md`
|
|
|
|
Inhalt:
|
|
|
|
- Modulgrenzen
|
|
- erlaubte Abhängigkeiten
|
|
- Besitz von Tabellen/Entitäten
|
|
- keine direkten Fremdzugriffe zwischen Kontexten ohne definierte Schnittstelle
|
|
|
|
---
|
|
|
|
#### `docs/security/secrets-management.md`
|
|
|
|
Inhalt:
|
|
|
|
- Secret-Service-Konzept
|
|
- `secret_ref`
|
|
- keine Klartext-Secrets in DB
|
|
- Rotation
|
|
- Zugriffskontrolle
|
|
- Auditierung von Secret-Zugriffen
|
|
|
|
---
|
|
|
|
#### `docs/security/rbac-matrix.md`
|
|
|
|
Inhalt:
|
|
|
|
| Bereich | Owner | Admin | Billing | Support | Provisioning | Auditor |
|
|
|---|---:|---:|---:|---:|---:|---:|
|
|
| Kunden lesen | ja | ja | ja | ja | ja | ja |
|
|
| Kunden ändern | ja | ja | nein | eingeschränkt | nein | nein |
|
|
| Rechnungen lesen | ja | ja | ja | nein | nein | ja |
|
|
| Rechnungen ändern | ja | ja | ja | nein | nein | nein |
|
|
| Serverdaten lesen | ja | ja | nein | eingeschränkt | ja | ja |
|
|
| Server ändern | ja | ja | nein | nein | ja | nein |
|
|
| Secrets lesen | nein | nein | nein | nein | nein | nein |
|
|
| Secret nutzen | ja | ja | nein | nein | system | nein |
|
|
|
|
---
|
|
|
|
#### `docs/storage/document-storage.md`
|
|
|
|
Inhalt:
|
|
|
|
- Object-Storage-Strategie
|
|
- Tenant-Isolation per Prefix/Bucket
|
|
- Checksums
|
|
- Archivierung
|
|
- Löschanfragen
|
|
- Legal Hold
|
|
- Zugriffskontrolle
|
|
|
|
---
|
|
|
|
#### `docs/operations/dlq-retention.md`
|
|
|
|
Inhalt:
|
|
|
|
- DLQ-Retention
|
|
- PII-Regeln
|
|
- Reprocessing
|
|
- manuelle Freigabe
|
|
- endgültige Löschung
|
|
- Monitoring
|
|
|
|
---
|
|
|
|
#### `docs/operations/reconciliation.md`
|
|
|
|
Inhalt:
|
|
|
|
- gewünschter Zustand
|
|
- externer Ist-Zustand
|
|
- Operation-Historie
|
|
- Snapshot-Modell
|
|
- Konfliktbehandlung
|
|
- Retry-Strategie
|
|
|
|
---
|
|
|
|
#### `db/policies/tenant_rls.sql`
|
|
|
|
Inhalt:
|
|
|
|
- PostgreSQL RLS-Grundstruktur
|
|
- Policy pro mandantenbezogener Tabelle
|
|
- Nutzung von `current_setting('app.tenant_id')`
|
|
- Fail-closed bei fehlendem Tenant-Kontext
|
|
|
|
Beispiel:
|
|
|
|
```sql
|
|
ALTER TABLE customers ENABLE ROW LEVEL SECURITY;
|
|
|
|
CREATE POLICY tenant_isolation_customers
|
|
ON customers
|
|
USING (
|
|
tenant_id = current_setting('app.tenant_id')::uuid
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
#### `db/migrations/xxxx_add_tenant_scope.sql`
|
|
|
|
Inhalt:
|
|
|
|
- `tenants`-Tabelle
|
|
- `tenant_id` auf mandantenbezogenen Tabellen
|
|
- NOT NULL Constraints
|
|
- Composite Foreign Keys
|
|
- Indizes auf `(tenant_id, id)`
|
|
|
|
---
|
|
|
|
## 5. Konkrete nächste Schritte
|
|
|
|
1. `docs/data-model-v0.2.md` anpassen:
|
|
- `tenant_id` festlegen
|
|
- `organisation_id` aus Isolation entfernen
|
|
- Secret-Felder durch `secret_ref` ersetzen
|
|
|
|
2. `docs/architecture/tenant-isolation.md` neu erstellen.
|
|
|
|
3. `db/migrations/xxxx_add_tenant_scope.sql` vorbereiten:
|
|
- `tenants`
|
|
- `tenant_id`
|
|
- Constraints
|
|
- Indizes
|
|
|
|
4. `db/policies/tenant_rls.sql` erstellen.
|
|
|
|
5. `docs/security/secrets-management.md` erstellen.
|
|
|
|
6. `docs/security/rbac-matrix.md` erstellen.
|
|
|
|
7. ADR 0014 überarbeiten:
|
|
- keine falsche Sicherheitsbehauptung zur Hash-Chain
|
|
|
|
8. ADR 0017 überarbeiten:
|
|
- DLQ-Retention
|
|
- PII-Regeln
|
|
- Reconciliation-Datenbasis
|
|
|
|
9. `docs/storage/document-storage.md` erstellen.
|
|
|
|
10. `docs/architecture/bounded-contexts.md` erstellen und Datenmodell danach gruppieren. |