kundencenter/migrations
Kundencenter 5ec8a526b3 fix(audit): audit_events auf DB-Ebene unveränderlich machen (append-only)
Nightbot-Befund #34 (Teil 1 von 2 – "eigene DB-Rolle für Audit ohne
UPDATE/DELETE"): eine echte separate DB-Rolle nur für Audit-Schreibzugriffe
ist mit dem bestehenden Muster (audit() schreibt oft in derselben
Transaktion wie die Fachaktion, die sie protokolliert, über dieselbe
Connection) nicht sauber vereinbar, ohne diese Atomarität zu verlieren
oder alle ~50 Tabellen einzeln neu zu berechtigen (MySQL/MariaDB kann
eine datenbankweite Berechtigung nicht durch eine engere Tabellen-
Berechtigung "überschreiben" – Rechte sind additiv, nicht spezifischer
gewinnt).

Stattdessen: BEFORE UPDATE/DELETE-Trigger auf audit_events, die beides
unabhängig vom verbindenden DB-Nutzer grundsätzlich verweigern (Migration
033). INSERT/SELECT bleiben uneingeschränkt möglich – genau das, was
audit()/verifyAuditChain() je brauchen. TRUNCATE bleibt technisch möglich
(feuert keine Trigger, betrifft nur die Testdatenbank-Zurücksetzung
zwischen Testdateien), DROP TABLE weiterhin auch – echte Kompromittierung
der DB-Zugangsdaten bleibt außerhalb dieser Verteidigungslinie, aber
versehentliche oder fehlerhafte Anwendungscode-Änderungen sind jetzt
ausgeschlossen.

test/core.test.ts angepasst: die bisherige Manipulationssimulation per
UPDATE ist jetzt selbst Teil des Tests (muss fehlschlagen); die Prüfung
"Hash-Kette erkennt Fälschung" simuliert stattdessen eine eingeschleuste
Fälschung per INSERT (weiterhin erlaubt).

Verifiziert: Testsuite (59/59, neuer Testfall für die Trigger-Ablehnung),
echte UPDATE/DELETE-Versuche gegen die Produktionsdatenbank beide
abgelehnt, Hash-Kette danach weiterhin intakt (192 Einträge), volles
Backup+Wiederherstellungstest gegen die echte Produktionsdatenbank
gefahren (Trigger werden korrekt mitgesichert/wiederhergestellt).

Aufbewahrungsfristen (DSGVO) und Export sind Teil desselben Tickets,
brauchen aber eine fachliche/rechtliche Entscheidung des Nutzers und
bleiben offen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 11:49:26 +02:00
..
001_core.sql Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
002_connectors_resources.sql Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
003_customer_type.sql Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
004_catalog_orders_contracts.sql Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
005_product_external_ref.sql Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
006_price_basis.sql Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
007_backup_settings_targets.sql Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
008_org_legacy_ref.sql Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
009_connector_error_time.sql Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
010_domains.sql Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
011_domain_rounding.sql Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
012_domain_records.sql Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
013_domain_cost_basis.sql Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
014_tickets.sql Support-Tickets: Modul, Oberfläche, Discord-Benachrichtigung 2026-09-27 08:36:18 +02:00
015_ticket_attachments.sql Ticket-Anhänge: Bilder/PDF hochladen und anzeigen (geprüft anhand der Dateikennung) 2026-09-27 08:53:27 +02:00
016_invoices.sql Rechnungsmodul: Entwurf/Ausstellen/Bezahlt/Storno, PDF, Firmenstammdaten 2026-09-27 09:05:13 +02:00
017_ticket_domain_link.sql Tickets: Bezug zu Ressource oder Domain wählen, Verknüpfung direkt aus der Domain-Aufstellung 2026-09-27 16:40:14 +02:00
018_product_term_prices.sql Hosting-Produkte: Staffelpreise nach Laufzeit (1/3/6/12/24 Monate) 2026-09-27 18:35:34 +02:00
019_panel_credentials.sql KeyHelp: Panel-Passwort neu vergeben und verschlüsselt hinterlegen (verblurrt wie Lizenzschlüssel) 2026-09-27 21:35:15 +02:00
020_invoice_party_snapshots.sql Rechnungen: Absender-/Empfängerdaten beim Ausstellen einfrieren, Statuswechsel atomar (behebt Codex-Fund #95) 2026-09-28 10:29:00 +02:00
021_invoice_item_discount.sql Rechnungen: Rabatt je Position 2026-09-28 11:01:19 +02:00
022_mail_templates.sql feat: SMTP-Stack mit konfigurierbaren Mailvorlagen 2026-09-28 12:53:29 +02:00
023_mail_sender_profiles.sql feat: separate Absenderprofile für Kundencenter/Störungsticket/Rechnungen 2026-09-28 13:16:42 +02:00
024_imap_inbox.sql feat: IMAP-Posteingang fürs Ticketsystem (Mail-Antworten -> Tickets) 2026-09-28 17:35:58 +02:00
025_mail_link_buttons.sql feat(mail): HTML-Mails mit Link zum Ticket/zur Rechnung als Schaltfläche 2026-09-28 23:00:31 +02:00
026_discord_settings.sql feat: Discord-Bot über die Oberfläche konfigurierbar 2026-09-28 23:28:24 +02:00
027_discord_linking.sql feat(discord): Kunden-Kontoverknüpfung per Discord-OAuth 2026-09-28 23:41:04 +02:00
028_welcome_mail.sql feat(mail): Begrüßungsmail mit Zugang, Produkten, Preisen und Discord 2026-09-28 23:50:53 +02:00
029_discord_drop_staff_ids.sql refactor(discord): einheitliche Berechtigung über verknüpfte Konten 2026-09-29 00:12:10 +02:00
030_audit_hash_v2.sql fix(audit): GET_LOCK-Ergebnis prüfen, connector/ip in Hash-Kette 2026-09-29 09:56:46 +02:00
031_datev_export.sql feat(rechnungen): Export für den Steuerberater (CSV, PDF-ZIP, DATEV-Buchungsstapel) 2026-09-29 11:05:56 +02:00
032_jobs_lease.sql fix(worker): Lease/Heartbeat statt starrer 5-Minuten-Grenze bei Jobwiederaufnahme 2026-09-29 11:41:43 +02:00
033_audit_immutable.sql fix(audit): audit_events auf DB-Ebene unveränderlich machen (append-only) 2026-09-29 11:49:26 +02:00