Zwei vom Nacht-Agenten gefundene Lücken, gegen den echten Code verifiziert und behoben: 1. Das Ergebnis von GET_LOCK() wurde nie geprüft. Bei Timeout (10s) oder Fehler lief audit() trotzdem ungesperrt weiter – zwei gleichzeitige Aufrufe hätten dieselbe "letzte Zeile" lesen und beide anhängen können, was die Kettengarantie bricht. Wirft jetzt einen Fehler, wenn die Sperre nicht erlangt wurde. 2. connector und ip wurden zwar in audit_events gespeichert, aber nie mitgehasht – beide Felder ließen sich im Nachhinein unbemerkt ändern, ohne die Kette zu brechen. Neue Einträge (hash_version = 2, Migration 030) hashen sie jetzt mit. Bestehende Einträge (Version 1) bleiben mit ihrer ursprünglichen Formel gültig; verifyAuditChain() berücksichtigt die Version pro Zeile. Gegen die echte Datenbank verifiziert: Kette bleibt über alle 183 bestehenden (v1) Einträge sauber, ein neu eingefügter (v2) Eintrag mit connector/ip ebenfalls – 184/184 ohne Bruch. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|---|---|---|
| apps | ||
| bundles | ||
| data | ||
| docs | ||
| migrations | ||
| ops | ||
| packages | ||
| .env.example | ||
| .gitignore | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| tsconfig.base.json | ||
Kundencenter
Modulares Kundencenter für Hosting, Server und Lizenzen (Modularer Monolith, TypeScript).
| Prozess | Pfad | Port (nur 127.0.0.1) | Aufgabe |
|---|---|---|---|
kc-api |
apps/api |
4100 | Fastify-API (/v1/*), Module, Policy, Audit |
kc-worker |
apps/worker |
4102 (Health) | Persistente Aufträge, Discord-Bot |
kc-web |
apps/web |
4101 | Next.js-Oberfläche, Proxy /api/* → API |
Stand (Grundsystem)
Login mit Passwort + TOTP, Wiederherstellungscodes, Sitzungsverwaltung, Passwort-Reset, Einladungen, Benutzerverwaltung (Mitarbeiterrollen),
Kunden/Organisationen anlegen und verwalten, Rechnungsanschrift, Audit-Protokoll mit Hash-Kette, persistente Job-Queue, Discord-Bot (optional).
Produkte (versioniert), Bestellungen mit Freigabe und unveränderlichem Preis-Snapshot, Verträge mit Kündigung/Verlängerung, Provisionierung über Connectoren (docs/produkte-bestellungen-vertraege.md), Connector-Framework (docs/connector-vertrag.md).
Support-Tickets (je Kunde, mit internen Notizen für Personal, Dateianhänge als Bild/PDF, Discord-Benachrichtigung).
Rechnungen (docs/rechnungen.md): Entwurf → Ausstellen (unveränderlich) → Bezahlt/Storno, PDF-Erzeugung, Firmenstammdaten unter Einstellungen → Firma.
Noch nicht vorhanden: Zahlungsanbieter-Anbindung, automatische wiederkehrende Rechnungsstellung, E-Mail-Versand von Rechnungen, Selbstregistrierung, Plesk-Connector, Domain-Registrierung über eine Registrar-API (aktuell manuell über die Domain-Aufstellung).
Modularität
API-Module liegen in apps/api/src/modules/<name> und implementieren KcModule (core/module.ts).
Sie werden in modules/index.ts eingetragen, registrieren Routen und Rechte und sprechen nur über core/* und Jobs miteinander.
Neue Fähigkeiten (Connectoren, Rechnungen, Tickets) kommen als weitere Module hinzu.
Konfiguration
Geheimnisse liegen nicht im Repo, sondern in /etc/kundencenter/*.env (chmod 600): db.env, app.env, discord.env, optional SMTP in app.env.
Vorlage: .env.example. Wichtig: KC_BASE_URL muss exakt der Browser-URL entsprechen (Origin-Prüfung gegen CSRF).
Betrieb
systemctl status kc-api kc-worker kc-web # Dienste (Autostart, Restart=always)
journalctl -u kc-api -f # Logs
pnpm install && pnpm build # Update: danach chown -R kundencenter und systemctl restart kc-*
pnpm migrate # Migrationen (migrations/*.sql, einmalig je Datei)
pnpm cli create-superadmin --email=… --name=… --password=…
Health: GET :4100/v1/health, GET :4100/v1/ready, GET :4102/health.
Tests
cd apps/api && pnpm test – Integrationstests gegen eine separate Datenbank kundencenter_test (wird bei jedem Lauf neu erstellt).
Abgedeckt: Login, Sperre, CSRF, 2FA-Pflicht, Sitzungen, Kundenanlage, Mandantentrennung, Rechte, Audit-Kette/Maskierung.
Discord-Bot
In /etc/kundencenter/discord.env setzen: DISCORD_BOT_TOKEN, DISCORD_GUILD_ID, DISCORD_ADMIN_CHANNEL_ID, DISCORD_STAFF_USER_IDS (kommagetrennt), dann systemctl restart kc-worker.
Befehle: /kc-status, /kc-kunde suche:<Text> (nur für freigegebene Discord-User, Antworten nur für sie sichtbar). In Kanäle gehen nur Ereignisse ohne personenbezogene Daten (z. B. „Neuer Kunde angelegt: K-10001“).
Backup / Restore (Datenbank)
set -a; . /etc/kundencenter/db.env; set +a
MYSQL_PWD=$DB_PASSWORD mysqldump -h127.0.0.1 -u$DB_USER --single-transaction --routines $DB_NAME | gzip > kundencenter-$(date +%F).sql.gz
gunzip -c kundencenter-DATUM.sql.gz | MYSQL_PWD=$DB_PASSWORD mysql -h127.0.0.1 -u$DB_USER $DB_NAME # Restore in leere DB
Automatisiertes, verschlüsseltes Backup mit Restore-Test ist noch offen (siehe Plane).