19 KiB
19 KiB
Kritische Risiken und Refactoring-Gefahren
Stand: 15. Mai 2026 Reviewer: Claude Bezug: Hosting-Backoffice v0.1 (vollständiger Basisbestand)
Jedes Risiko ist mit Schweregrad, Zeitpunkt und konkreter Empfehlung markiert.
Legende:
- Schweregrad:
LOW/MEDIUM/HIGH/CRITICAL - Zeitpunkt:
NOW(vor Codebeginn) /V1/V2/V3/LATER
R-01 — Mandantenfähigkeit ist Absichtserklärung, kein Design
- Schweregrad:
CRITICAL - Zeitpunkt:
NOW - Problem: Die Multi-Tenancy-Strategie listet Ziele, keinen Mechanismus. V1 läuft als Single-Tenant mit zwei ungeklärten ID-Spalten (
tenant_id,organisation_id). Wenn V1 ohne Tenant-Scope-Enforcement deployt wird, ist V2/V3-Reseller-Fähigkeit ein Komplett-Refactor jeder Query, Policy, Job-Payload, Cache-Key und Webhook-Definition. - Empfehlung: Tenancy-Modell jetzt entscheiden und in ADR festschreiben. Vorschlag: Shared Database,
tenant_id-Scope, Postgres Row-Level Security als zweite Verteidigungsschicht. Eloquent Global Scope von Tag 1 auf allen mandantenscoped Modellen. Statische Analyse oder Runtime-Assertion in CI gegen ungescopte Queries.organisation_idvs.tenant_idmit ER-Modell klären oder eine der beiden Spalten streichen.
R-02 — Anbieterlogik im Core-Datenmodell bricht das eigene Adapter-Pattern
- Schweregrad:
CRITICAL - Zeitpunkt:
NOW - Problem:
Server.KeyHelp-ReferenzundRechnung.externes Systemstehen im Core-Datenmodell. Das widerspricht direkt dem Integration-Adapter-Pattern, das „Core kennt keine direkte Anbieterlogik" als Grundprinzip formuliert. Sobald V1 mit dieser Schema-Form deployt wird, ist das Adapter-Pattern in der Praxis tot, und jedes neue Hostingpanel braucht Core-Schema-Änderungen. - Empfehlung: Vor dem ersten Migration-File ein generisches External-Reference-Pattern einführen, z. B. Tabelle
external_references(id, owner_type, owner_id, adapter_id, external_id, metadata, last_synced_at). Im Core nur diese Tabelle, keine anbieter-spezifischen Felder.
R-03 — Daten im Core, Logik in Modulen (Billing-Anti-Pattern)
- Schweregrad:
CRITICAL - Zeitpunkt:
NOW - Problem:
RechnungundZahlungsind im Core-Datenmodell. Billing-Logik ist als Integrationsmodul gedacht (Lexware, Invoice Ninja). Konsequenz: Module schreiben in Core-Tabellen, kennen das Core-Schema, jede Schema-Änderung im Core bricht potenziell mehrere Module. Genau die Konstruktion, in der „modularer Aufbau" zum erweiterten Monolithen wird. - Empfehlung: Billing als eigene Bounded-Context-Domäne (Service-Modul) etablieren. Core kennt höchstens
InvoiceReferencemit Adapter-ID und externer ID, nicht aberRechnung.Betrag. Eigenes Datenmodell pro Modul, Kommunikation per definierten Service-Contract.
R-04 — Modulstruktur und Modul-Dokumente widersprechen sich
- Schweregrad:
HIGH - Zeitpunkt:
NOW - Problem:
module-structure-v0.1.mdlistet weder Billing noch Customer Portal, obwohl beide eigene Modul-Beschreibungen haben. KeyHelp und Registrar sind als Modul-Doks vorhanden – einer ist Integrationsmodul, der andere möglicherweise eine Mischform. Solange diese drei verschiedenen „Wahrheiten" parallel existieren, gibt es kein gemeinsames Architekturverständnis. - Empfehlung: Modulstruktur als alleinige Wahrheit etablieren. Jedes Modul-Dokument muss in der Modul-Struktur gelistet sein, oder es existiert nicht. Inkonsistenzen vor Codebeginn beheben.
R-05 — Secrets-Management vollständig undefiniert
- Schweregrad:
CRITICAL - Zeitpunkt:
NOW - Problem:
Registrar-Account.Zugangsdaten/API-Referenzenimpliziert Credentials im Datenmodell. Im gesamten Bestand findet sich kein Wort zu Vault, Verschlüsselung, Key Rotation, KMS, HSM oder Mandanten-Isolation der Schlüssel. Bei kompromittierter DB hätte ein Angreifer Zugriff auf Registrar-Accounts aller Mandanten – das wäre ein Vorfall mit Branchenrelevanz. - Empfehlung: Externes Secret-Management (HashiCorp Vault, AWS Secrets Manager, Bitwarden Secrets Manager) oder mindestens Envelope-Encryption mit pro-Mandant abgeleiteten Schlüsseln und externem KMS. Datenmodell darf keine Credentials enthalten, nur Referenzen in den Vault. Vor V1-Codebeginn entscheiden.
R-06 — Core ist zu groß, Monolith-Pfad voraussehbar
- Schweregrad:
HIGH - Zeitpunkt:
NOW - Problem: Core enthält 13 Bereiche, davon mindestens 6 mit eigener Geschäftslogik (Domains, Hostingpakete, Server, Dokumente, Notifications, Produkte). Diese Konstellation produziert einen Bounded Context für die gesamte Anwendung und macht den Modul-Ansatz architektonisch wirkungslos.
- Empfehlung: Core auf Identity, RBAC, Audit, Settings, Module-Registry, Event-Routing, Tenant-Scope reduzieren. Domains, Hostingpakete, Server, Dokumente, Notifications-Channels in eigene Service-Module auslagern. Adapter-Pattern und Modul-Contract als verbindliche Grenze.
R-07 — GoBD-Verantwortlichkeit nicht entschieden
- Schweregrad:
HIGH - Zeitpunkt:
V1 - Problem:
Rechnung.externes Systemimpliziert, dass Lexware/Invoice Ninja der Beleg-Originalspeicher ist. Die GoBD-Archive-Strategie sagt aber gleichzeitig „PDFs archivieren, Hashes speichern, Audit-Logs schreiben" – das klingt nach lokalem Originalspeicher. Wenn Hosting-Backoffice der Originalspeicher ist, gelten harte GoBD-Anforderungen (unveränderbare Belege, lückenlose Nummernkreise pro Mandant, 10-Jahres-Retention, Z3-Export). Aktuell ist das nicht entschieden. - Empfehlung: Klärungs-ADR. Empfehlung: Lexware/Invoice Ninja als Original, Hosting-Backoffice als Referenz-/Spiegel-System mit Archivkopie und Hash. Audit-Logs intern, aber keine GoBD-Originalrolle.
R-08 — DSGVO-Löschung vs. GoBD-Retention nicht modelliert
- Schweregrad:
HIGH - Zeitpunkt:
V1 - Problem: Endkunde verlangt Löschung nach DSGVO Art. 17, gleichzeitig müssen Rechnungsbelege 10 Jahre aufbewahrt werden. Diese Spannung muss technisch abgebildet sein. Im aktuellen Datenmodell gibt es weder Soft-Delete-Modell noch Pseudonymisierungs-Strategie noch Tombstone-Mechanismus.
- Empfehlung: Tombstone- und Pseudonymisierungs-Modell entwerfen. Pflicht: Trennung von Personen-Stammdaten (löschbar/pseudonymisierbar) und Beleg-Inhalt (retentionspflichtig). Konkrete Felder definieren, was bei „Löschung" mit der Person passiert (z. B.
Anonymized<UUID>als Name).
R-09 — API-Auth-Strategie unentschieden
- Schweregrad:
HIGH - Zeitpunkt:
NOW - Problem: „Tokenbasiert, später OAuth/Sanctum möglich" mischt Konzeptebenen. Das WordPress-Plugin und das Customer Portal können nicht entwickelt werden, bevor entschieden ist, welcher Auth-Mechanismus für welchen Client-Typ gilt.
- Empfehlung: ADR. Vorschlag für V1: Sanctum Personal Access Tokens (M2M, einfache Clients) plus Sanctum SPA-Mode (eigenes Frontend, falls vorhanden). V2: Passport/OAuth2 für WordPress-Plugin und Drittanbieter-Apps.
R-10 — Datenbankwahl offen
- Schweregrad:
HIGH - Zeitpunkt:
NOW - Problem: „MariaDB oder PostgreSQL" als Nicht-Entscheidung. Postgres bietet Row-Level Security (relevant für Tenancy als Defense-in-Depth), JSONB mit Indizes, transaktionales DDL, partielle Indizes. MariaDB nicht in gleichem Umfang. „Später entscheiden" ist faktisch eine Festlegung auf den kleinsten gemeinsamen Nenner.
- Empfehlung: ADR. Vorschlag: PostgreSQL 15+, mit expliziter Begründung an Tenancy-, Audit-, JSON- und Performance-Anforderungen.
R-11 — KI-Modul in V1 birgt DSGVO-Sprengstoff
- Schweregrad:
HIGH - Zeitpunkt:
NOW(Scope-Entscheidung) /V2(technisch) - Problem: KI-Funktionen verarbeiten potenziell personenbezogene Support-Ticket-Inhalte über US-Provider, was Auftragsverarbeitungsvertrag, SCC, Drittlandtransfer-Risikobewertung, Subprozessor-Transparenz und Endkunden-Information erfordert. Für V1 (3–5 Pilotkunden, „Ordnung schaffen") ist das Aufwand ohne Geschäftswert.
- Empfehlung: KI-Modul aus V1 entfernen, in V2 wieder aufnehmen. Bis dahin: Subprozessor-Strategie, DPA-Vorlage, Datenklassifikation und Mensch-im-Loop-Konzept ausarbeiten.
R-12 — SEPA-Lastschrift ohne SEPA-Modell
- Schweregrad:
MEDIUM - Zeitpunkt:
V1 - Problem: Payment Policy listet Lastschrift als V1-Zahlungsart. SEPA-Lastschrift erfordert Mandate (UMR, Mandatsdatum, Mandatstext), Pre-Notification (mind. 1 Tag), IBAN-Speicherung (personenbezogen + sicherheitsrelevant), Mandatsänderungs-Historie. Davon ist nichts modelliert.
- Empfehlung: Entweder Lastschrift aus V1 entfernen, oder SEPA-Mandat-Modell vollständig spezifizieren (eigene Tabellen, Statusmaschine, Verschlüsselung der IBAN, Audit-Log).
R-13 — V1-Scope intern widersprüchlich
- Schweregrad:
HIGH - Zeitpunkt:
NOW - Problem: Mehrere Dokumente erzählen unterschiedliche V1-Geschichten: KI in V1 vs. V2, Customer Portal in V1 vs. nicht in MVP, Kundenzahl 1–500 vs. 1–50. Das macht den V1-Scope unentscheidbar und damit das Erfolgsversprechen unprüfbar.
- Empfehlung: V1-Scope-Liste als einzelne Quelle der Wahrheit etablieren. Empfehlung: KI raus, Customer Portal raus oder mit reduziertem Umfang, Kundenzahl auf 1–50 festgelegt. Alle Dokumente daran ausrichten.
R-14 — Audit-Log-Unveränderbarkeit als Wunsch, kein Mechanismus
- Schweregrad:
MEDIUM - Zeitpunkt:
V1 - Problem: „Logs dürfen nicht manipulierbar sein" steht als Anforderung, aber kein Mechanismus ist beschrieben. Eine normale DB-Tabelle ist manipulierbar.
- Empfehlung: Mindestens Append-only-Tabelle ohne UPDATE/DELETE-Berechtigung des App-Users, Hash-Chain der Einträge, regelmäßiger Export in WORM-Storage oder externes Audit-Sink. ADR.
R-15 — Tenant-Offboarding und Datenexport nicht definiert
- Schweregrad:
HIGH - Zeitpunkt:
V2 - Problem: Wenn ein Mandant das System verlässt, muss er DSGVO-konform seine Daten erhalten (Datenportabilität) und der Plattformbetreiber muss löschen. Kein Konzept im Bestand.
- Empfehlung: Tenant-Lifecycle-Domäne entwerfen. Export-Format: maschinenlesbar (JSON Lines, oder pro-Tenant DB-Dump bei DB-per-Tenant-Modell). Aufbewahrungspflichten der GoBD beachten.
R-16 — Steuer-/MwSt-Logik komplett fehlend
- Schweregrad:
HIGH - Zeitpunkt:
V1 - Problem: Im gesamten Bestand kein Wort zu MwSt-Sätzen, OSS (One-Stop-Shop für EU-B2C), Reverse Charge B2B EU, oder MwSt-Befreiungen. Eine Rechnungs-Software ohne Steuermodell ist nicht produktiv einsetzbar.
- Empfehlung: Minimal-Modell für V1: deutscher Standardfall (19%/7%/0%), B2B/B2C-Flag pro Kunde, Erweiterbarkeit für OSS in V2. ADR + Daten-Modell-Update.
R-17 — Reseller-Hierarchie V3 ohne V1-Vorbereitung
- Schweregrad:
HIGH - Zeitpunkt:
NOW - Problem: V3 verspricht „Resellerstrukturen" und „tiefere Mandantenfähigkeit". Das setzt mindestens dreistufige Hierarchie (Plattform → Reseller → Endkunde) voraus. V1 plant zweistufig oder einstufig (siehe R-01). Ohne saubere Hierarchie-Definition heute wird V3 ein Modellbruch.
- Empfehlung: Hierarchie als Datenmodell-Entscheidung heute festlegen (selbst wenn V1 nur eine Ebene aktiv nutzt). ADR. Tabelle
tenantsmitparent_tenant_idals Vorbereitung.
R-18 — Fehlerresilienz für Integrationen nicht entworfen
- Schweregrad:
MEDIUM - Zeitpunkt:
V1 - Problem: Adapter-Anforderungen sagen „Fehlerbehandlung" – aber Retry-Strategie, Backoff, Circuit Breaker, Dead-Letter-Queue, Reconciliation bei inkonsistentem Zustand sind nicht beschrieben. Bei Domain-Renewal kann ein nicht behandelter Adapter-Fehler einen geschäftskritischen Datenverlust bedeuten.
- Empfehlung: Standardpattern für alle Adapter: Retry mit exponentiellem Backoff, Circuit Breaker, Dead Letter, Reconciliation-Job nightly. Job-Status sichtbar im UI.
R-19 — API-Versionierungsstrategie unvollständig
- Schweregrad:
MEDIUM - Zeitpunkt:
V1 - Problem: Nur Pfad-Versionierung (
/api/v1/) ohne Deprecation/Sunset/Compatibility-Strategie. Bei API-first-Anspruch zu wenig. - Empfehlung: ADR mit klaren Regeln: Breaking Changes nur über neue Major-Version, Minor-Changes additiv, Deprecation-Header (
Deprecation,Sunset), Mindest-Support-Zeitraum für ältere Versionen.
R-20 — Nummernkreise pro Mandant ohne Mechanismus
- Schweregrad:
HIGH - Zeitpunkt:
V1 - Problem: Rechnungsnummern müssen lückenlos sein und pro Mandant separat. Kunden-, Vertrags-, Rechnungsnummern: pro Mandant? Global? Konfigurierbar? Aktuell nicht modelliert.
- Empfehlung: Dedicate Sequence-Tabelle pro Mandant und pro Nummernkreis. Atomic-Increment mit DB-Lock. Konfigurierbares Format (Präfix, Padding, Reset-Verhalten). Pflicht für GoBD-Konformität.
R-21 — Personen-/Adressmodell als undifferenziertes Bündel
- Schweregrad:
MEDIUM - Zeitpunkt:
NOW - Problem:
Kundeenthält „Stammdaten + Ansprechpartner + Kontaktdaten" als monolithisches Objekt. Klassisches Anti-Pattern. Erschwert DSGVO-Auskunft/Löschung, B2B-Modell, Mehrfach-Ansprechpartner, getrennte Rechnungs-/Postanschriften. - Empfehlung: Trennung in
Party(Person oder Organisation) +Address(mit Verwendungszweck: Rechnung/Post/Rechtssitz) +ContactPoint(Mail/Tel/etc. mit Verwendungszweck). N:M zwischen Customer und Party für Ansprechpartner.
R-22 — WordPress-Plugin als zweite Sicherheitsdomäne
- Schweregrad:
MEDIUM - Zeitpunkt:
V2 - Problem: Plugin ist API-Client mit eigener Session-Domäne, eigenem Update-Lifecycle, eigener Plugin-Ökosystem-Risikofläche. Wenn die WP-Site kompromittiert ist, sind die API-Tokens des Plugins gefährdet. Aktuell ist nicht definiert, welche Scopes das Plugin erhält und wie kompromittierte Tokens rotiert werden.
- Empfehlung: Plugin nur mit minimal-Scope-Token. Token-Revocation aus Admin-UI. Lifetime begrenzen. Audit-Log bei jeder Plugin-API-Nutzung. Strategie für Sandbox-Tests bei kompromittiertem WP-Setup.
R-23 — Frontend-Strategie offen widerspricht API-first-Anspruch
- Schweregrad:
MEDIUM - Zeitpunkt:
NOW - Problem: „Blade oder später Vue/Nuxt" lässt eine fundamentale Architekturentscheidung offen. Klassischer Laravel-Monolith mit angeflanschter API ist eine andere Architekturklasse als ein API-first-System mit echtem SPA-Client.
- Empfehlung: ADR. Entweder Blade-als-API-Konsument (Blade-Views rufen interne API auf, kein direkter DB-Zugriff aus Views) oder Vue-/Nuxt-SPA. Nicht „später".
R-24 — BFSG / Barrierefreiheit für Customer Portal
- Schweregrad:
MEDIUM - Zeitpunkt:
V1(falls Portal in V1) /V2 - Problem: Seit 28. Juni 2025 sind in der EU kommerzielle digitale Dienste an Verbraucher barrierefrei zu gestalten (BFSG, Umsetzung der EU-Richtlinie 2019/882). Customer Portal fällt darunter.
- Empfehlung: UI-Komponenten und Frontend-Stack barrierefrei gestalten (WCAG 2.1 AA als Ziel). Wenn Portal aus V1 raus ist (R-13), entschärft sich das auf V2.
R-25 — Modul-Lifecycle (Deinstallation, Datenreferenzen) ungeklärt
- Schweregrad:
MEDIUM - Zeitpunkt:
V1 - Problem: Module sollen aktivierbar/deaktivierbar sein. Was passiert mit referenzierten Daten in anderen Modulen, wenn ein Modul deinstalliert wird? Was passiert bei Re-Installation? Diese Semantik ist nirgendwo beschrieben.
- Empfehlung: Modul-Lifecycle definieren: aktivieren / deaktivieren (Daten bleiben) / deinstallieren (Daten archivieren, optional löschen). Dependencies zwischen Modulen explizit deklarieren. Migrations-Strategie bei Re-Installation.
R-26 — Logging-/Audit-Sink-Architektur unspezifiziert
- Schweregrad:
MEDIUM - Zeitpunkt:
V1 - Problem: Logging-Strategie sagt was geloggt werden soll, aber nicht wohin oder wie. App-Logs vs. Audit-Logs sind getrennt, aber Speicherort, Retention, Mandantenscope, Integritätsschutz fehlen.
- Empfehlung: Drei getrennte Senken: App-Logs (lokal, kurzfristig, optional externer Aggregator wie Loki/Sentry), Audit-Logs (DB-Append-only, langfristig, pro Mandant), Security-Logs (Login, Auth-Fehler, Admin-Aktionen, separat).
R-27 — „Vorbereitende" Felder ohne Verwendung in V1
- Schweregrad:
LOW - Zeitpunkt:
NOW - Problem: Mehrfach „… später möglich" als Feld-Anmerkung (Server.Rollen später, Hostingpaket.Ressourcen später, Gebührenregeln später). Erfahrung: solche Felder werden entweder nie genutzt oder mit Bedeutung versehen, die nicht zur ursprünglichen Form passt.
- Empfehlung: „Später"-Felder aus dem v0.1-Datenmodell entfernen. Wenn ein Feld V1 nicht braucht, wird es V1 nicht migriert. Bei Bedarf später eigene Migration.
R-28 — Mehrere parallele Single Sources of Truth
- Schweregrad:
LOW(organisatorisch) /HIGH(in Konsequenz) - Zeitpunkt:
NOW - Problem: Strategie-Dokumente, Modul-Dokumente, Roadmap und MVP-Liste enthalten sich widersprechende Aussagen (siehe R-04, R-13). Ohne klare Hierarchie zwischen den Dokumenten wird im Code-Schritt jede Person eine andere Variante implementieren.
- Empfehlung: Dokumenthierarchie festlegen: ADRs > Strategie-Dokumente > Modul-Beschreibungen > Roadmap. Konflikte werden in dieser Reihenfolge aufgelöst. Bei Konflikt: ADR ergänzen oder Strategie-Doc aktualisieren, untere Ebenen nachziehen.
Zusammenfassende Priorisierung
CRITICAL / NOW (vor Codebeginn unverzichtbar):
- R-01 Mandantenfähigkeits-Mechanismus
- R-02 Anbieterlogik aus Core entfernen
- R-03 Billing aus Core entfernen
- R-05 Secrets-Management
HIGH / NOW (vor Codebeginn entscheiden):
- R-04 Modulstruktur als einzige Wahrheit
- R-06 Core verkleinern
- R-09 API-Auth-Strategie
- R-10 Datenbank-Engine
- R-11 KI-Scope-Entscheidung
- R-13 V1-Scope vereinheitlichen
- R-17 Reseller-Hierarchie-Vorbereitung
- R-21 Personen-/Adressmodell
- R-23 Frontend-Strategie
- R-28 Dokumenten-Hierarchie
HIGH / V1 (muss in V1 enthalten sein):
- R-07 GoBD-Verantwortlichkeit
- R-08 DSGVO-Löschung-Modell
- R-16 Steuer-/MwSt-Logik
- R-20 Nummernkreise
MEDIUM / V1:
- R-12 SEPA-Modell oder raus
- R-14 Audit-Unveränderbarkeit
- R-18 Adapter-Fehlerresilienz
- R-19 API-Versionierung
- R-24 Barrierefreiheit (falls Portal in V1)
- R-25 Modul-Lifecycle
- R-26 Logging-Architektur
MEDIUM/HIGH / V2-V3:
- R-15 Tenant-Offboarding
- R-22 WP-Plugin-Sicherheitsmodell
- R-24 Barrierefreiheit (Portal in V2)
LOW / NOW:
- R-27 Spekulative Felder entfernen
Die Gesamtbotschaft: Die Anzahl der CRITICAL/NOW-Punkte (4) ist überschaubar und alle in 2–4 Wochen entscheidungsreif. Die HIGH/NOW-Punkte (10) sind ADR-Material. Wenn diese 14 Punkte vor Codebeginn entschieden sind, hat das Projekt eine sehr gute Ausgangslage. Werden sie nicht entschieden, ist V1 voraussichtlich produktiv nutzbar, aber V2/V3 wird teurer als V1 selbst.