No description
Find a file
Kundencenter 12fec5c822 feat(rechnungen): Export für den Steuerberater (CSV, PDF-ZIP, DATEV-Buchungsstapel)
Neue Seite Rechnungen → Export mit Zeitraum-/Status-Filter und drei
Downloads, nie Entwürfe:

- Rechnungsjournal als CSV (Semikolon, Dezimalkomma, UTF-8-BOM):
  Nummer, Datum, Kunde, Netto/USt/Brutto, effektiver USt-Satz, Status,
  Zahlungsdatum, aufgelöste Storno-Referenzen.
- Alle zugehörigen Rechnungs-PDFs als ZIP (die eigentlichen Belege,
  wie von GoBD neben dem Journal verlangt), gebaut über das lokale
  zip-Binary wie in ops/backup.ts.
- Echter DATEV-Buchungsstapel (EXTF, Format 700/21) zum direkten
  Import beim Steuerberater. Pro Rechnung eine Buchungszeile je
  USt-Satz-Gruppe (Automatikkonten-Verfahren: Konto = aus der
  Kundennummer abgeleitetes Debitorenkonto, Gegenkonto = konfiguriertes
  Erlöskonto des jeweiligen Satzes – kein geratener BU-Schlüssel
  nötig). Kopf- und Buchungszeilen-Layout (31 bzw. 125 Felder) gegen
  die offizielle DATEV-Formatbeschreibung und ein reales Beispiel aus
  github.com/ledermann/datev verifiziert, nicht aus dem Gedächtnis
  geraten. Ausgabe in Windows-1252 (eigener Encoder: Node kennt nur
  striktes ISO-8859-1, das den Halbgeviertstrich in den DATEV-
  Spaltennamen stillschweigend verstümmelt hätte – beim Testlauf
  gefunden und behoben).

Dafür neue DATEV-Stammdaten unter Einstellungen → Firma (Berater-/
Mandantennummer, SKR, Sachkontenlänge, Wirtschaftsjahresbeginn,
Erlöskonten je Steuersatz; Migration 031). Ohne diese Angaben liefert
der DATEV-Export eine klare Fehlermeldung statt einer falschen Datei;
das CSV/ZIP funktioniert unabhängig davon immer.

Gegen echte Rechnungen (RE-1001/RE-1002, Original + Storno) über eine
temporäre Test-Session verifiziert: CSV/ZIP/DATEV liefern korrekte
Inhalte, Storno kehrt Soll/Haben korrekt um, Feldzahlen exakt 31/125,
Encoding rund-trip-fest.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 11:05:56 +02:00
apps feat(rechnungen): Export für den Steuerberater (CSV, PDF-ZIP, DATEV-Buchungsstapel) 2026-09-29 11:05:56 +02:00
bundles Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
data Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
docs Rechnungsmodul: Entwurf/Ausstellen/Bezahlt/Storno, PDF, Firmenstammdaten 2026-09-27 09:05:13 +02:00
migrations feat(rechnungen): Export für den Steuerberater (CSV, PDF-ZIP, DATEV-Buchungsstapel) 2026-09-29 11:05:56 +02:00
ops Nacht-Agent: automatische Bearbeitung von Plane-Tickets (Label agent) 2026-09-27 08:20:26 +02:00
packages fix(audit): GET_LOCK-Ergebnis prüfen, connector/ip in Hash-Kette 2026-09-29 09:56:46 +02:00
.env.example Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
.gitignore Build-Artefakt aus der Versionsverwaltung nehmen 2026-09-27 08:36:24 +02:00
package.json Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
pnpm-lock.yaml feat: IMAP-Posteingang fürs Ticketsystem (Mail-Antworten -> Tickets) 2026-09-28 17:35:58 +02:00
pnpm-workspace.yaml Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00
README.md Rechnungsmodul: Entwurf/Ausstellen/Bezahlt/Storno, PDF, Firmenstammdaten 2026-09-27 09:05:13 +02:00
tsconfig.base.json Stand vor Einführung des Nacht-Agenten 2026-09-27 00:51:32 +02:00

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).