Files
tessera-ctl/.planning/quick/261002-fm5-finanzbuchhaltung-module-kantinenabrechn/261002-fm5-SUMMARY.md
T
schalli b94d267584
Tessera CI/CD / Lint & Type Check (push) Successful in 53s
Tessera CI/CD / Tests (push) Successful in 1m45s
Tessera CI/CD / Desktop-Pakete bauen (push) Successful in 18s
Tessera CI/CD / Build & Publish Images (push) Successful in 3m19s
docs(quick-261002-fm5): Finanzbuchhaltung-Module Kantinenabrechnung und Handelsware
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 11:52:33 +02:00

14 KiB
Raw Blame History

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, decisions, metrics, status, plan_head_before, plan_head_after, commits, actuals
phase plan subsystem tags requires provides affects tech-stack key-files decisions metrics status plan_head_before plan_head_after commits actuals
quick-261002-fm5 01 finanzbuchhaltung
kantine-datev
handelsware-datev
datev
prisma-rls
nestjs
next-intl
xlsx
Seitenleisten-Kategorie accounting (Finanzbuchhaltung / Financial accounting)
Modul kantine-datev (Kantinenabrechnung) mit DATEV-Lohn-ASCII-Export
Modul handelsware-datev (Handelsware) mit Kontenliste und DATEV-Buchungsdatei
module-registry
marketplace
sidebar
rls-access-inventory
added patterns
reine, getestete Verarbeitungsfunktionen getrennt von Dienst und Controller
Speicherung nur beim Export, in einer mandantengebundenen Transaktion mit erneuter Berechnung
Blob-Download im Browser (wie der Zertifikat-Manager), keine Tauri-Sonderlogik
created modified
apps/api/src/accounting/decode-csv-text.ts
apps/api/src/accounting/decode-upload-filename.ts
apps/api/src/kantine-datev/ (Parser, Validator, Transformer, Pipeline, Dienst, Controller, Seed, Modul, Tests)
apps/api/src/handelsware-datev/ (XLSX, Transformation, Konten-CSV, Dienst, Controller, Seed, Modul, Tests)
apps/api/prisma/migrations/20261002120000_kantine_datev_config/migration.sql
apps/api/prisma/migrations/20261002130000_handelsware_datev/migration.sql
apps/web/src/app/(portal)/modules/kantine-datev/ (Seite, Layout, Test)
apps/web/src/app/(portal)/modules/handelsware-datev/ (Seite, Layout, drei Reiter, Test)
apps/web/src/lib/kantine-datev-api.ts
apps/web/src/lib/handelsware-datev-api.ts
apps/web/src/lib/accounting-request.ts
apps/web/src/lib/download-base64.ts
apps/web/src/components/accounting/file-drop-area.tsx
apps/web/src/components/accounting/tab-bar.tsx
packages/shared/src/index.ts
apps/api/prisma/schema.prisma
apps/api/src/app.module.ts
docs/mandantentrennung-zugriffsklassifikation.md
apps/web/src/messages/de.json
apps/web/src/messages/en.json
apps/web/src/messages/umlaut-dictionary.ts
apps/web/src/lib/module-loader.ts
apps/web/src/lib/module-identity.ts
apps/web/src/components/modules/module-tile.tsx
apps/web/src/lib/stores/nav-store.ts
apps/web/src/app/(portal)/modules/module-layouts.test.tsx
CHANGELOG.md
docs/anleitung-anwender.md
Handelsware-Export schickt die Excel-Datei erneut mit (Multipart) plus buchungsdatum und newAccounts (JSON-Text), statt einer JSON-Liste aller Zeilen
Startwert Gegenkonto ist die erste vergebene Nummer bei leerer Kontenliste, sonst hoechstes vorhandenes Gegenkonto + 1
Einstellungen aendern nur Administratoren, die Kontenliste pflegen alle Benutzer mit Modulzugriff
Handelsware-TXT bleibt UTF-8 (wie die Vorlage), offene Frage zur Kodierung siehe unten
duration completed
ca. 1 h 20 min 2026-10-02
complete 0edd6e9b1a 14933753e7 4
tokens tasks commits
63000 3 4

Phase quick-261002-fm5 Plan 01: Finanzbuchhaltung, Kantinenabrechnung und Handelsware

Zwei neue Module in der neuen Seitenleisten-Gruppe „Finanzbuchhaltung“: Kantinenabrechnung (Kantinen-CSV prüfen, DATEV-Lohndatei im ASCII-Format erzeugen) und Handelsware (Excel-Umsätze Erlöskonten zuordnen, Kontenliste pflegen, DATEV-Buchungsdatei als TXT erzeugen). Beide laufen über Aktivierung im Marktplatz plus Freigabe. Beraternummer, Mandantennummer, Lohnart, Standard-Erlöskonto und Startwert Gegenkonto sind je Mandant leer, bis ein Administrator sie einträgt. Nichts wurde gepusht.

Commits

Aufgabe Commit Inhalt
1 (Tracer) 1f85277 Kategorie accounting, Kantinenabrechnung durchgängig (API, Migration, Web, Zugriffsinventar)
2 44c1d43 Handelsware API: Prisma-Modelle mit Zeilenschutz, XLSX/TXT/CSV-Funktionen, Dienst, Controller
3 42b89f1 Handelsware Modulseite (Import / Konten / Einstellungen), Registries, Umlaut-Allowlist
3 (Doku) 1493375 CHANGELOG und Anwenderanleitung

SUMMARY, STATE und PLAN sind wie verlangt nicht committet (Orchestrator).

Prüfergebnisse (ehrlich)

  • API-Tests: 109 Testdateien, 1857 Tests grün (pnpm --filter @tessera/api test). Davon neu: accounting 8, kantine-datev 53, handelsware-datev 110 (Spec-Läufe zusammen 206 inkl. RLS-Gates).
  • Web-Tests: 115 Testdateien, 1214 Tests grün (pnpm --filter @tessera/web test). Davon neu: kantine-datev 7 + 1 Layout, handelsware-datev 15 + 1 Layout.
  • Type-Check: tsc --noEmit für api und web sauber.
  • Biome: biome lint auf allen neuen/geänderten Dateien ohne Befund. biome check --write (Format + Importsortierung) wurde auf die neuen Dateien angewandt. Bestehende, nicht von mir angefasste Dateien (z. B. apps/api/src/proxmox) sind schon vorher nicht formatrein; das habe ich nicht angefasst.
  • RLS-Gates: rls-coverage und rls-access-inventory grün, Fundstellentabelle, Bereichszeilen, Summenzeile und Paarzählung (92 Paare) im Dokument nachgeführt.
  • Migrationen: beide lokal über die Container-IP angewandt, prisma migrate status „Database schema is up to date“ (54 Migrationen), prisma migrate diff Schema gegen DB: „No difference detected“.
  • Grep-Gates: keine Zahlen 1387819 / 10001 / 9005 in Kantine-Code, -Tests, -Web oder -Migration; keine 8000 in Handelsware-Code, -Tests, -Web, -Migration, auch nicht in den Testdateien.
  • Lokaler Stack: docker compose up -d --build api web gebaut, API healthy. Logs: Kantine-DATEV module seeded in registry, Handelsware-DATEV module seeded in registry, alle Routen gemappt, kein Migrationsfehler. Zeilen in Module: kantine-datev und handelsware-datev, beide Kategorie accounting.
  • Browser-Prüfung: nicht gemacht, liegt beim Orchestrator. Ich habe mich nicht angemeldet und keine Zugangsdaten gelesen. Das heißt: die Seiten laufen bisher nur gegen die Komponententests und gegen den gebauten Stack (Start, Routen, Seed), nicht gegen echte Klicks.

Testdateien für die Browser-Prüfung

Alle in /home/vicolab/projects/tessera-ctl/.planning/quick/261002-fm5-finanzbuchhaltung-module-kantinenabrechn/testdata/, alles erfundene Daten, mit den Pipeline-Funktionen gegengeprüft:

Datei Zweck Erwartung in der Vorschau
kantine-cp1252-fehler.csv Windows-1252, CRLF, Umlaute, ein ungültiger Betrag, zwei Abrechnungsmonate 4 Zeilen, Monat 03/2026, Gesamtbetrag 71,74 EUR, Fehler in Zeile 4 (Betrag), Warnung „03/2026, 04/2026“, Download gesperrt
kantine-gueltig-utf8.csv gültig, UTF-8, LF 4 Zeilen, 03/2026, 82,54 EUR, kein Fehler. Datei bei Einstellungen z. B. 1234567 / 12345 / 1111: LuG_1234567_12345_03_2026.sic
HWA 0326 Test.xlsx B1 = 2026, gemischt Zahl und deutscher Text, ein negativer Wert, ein unbekanntes Produkt Datumsvorschlag 3103, Dateiname HWA_0326.txt
Konten.csv Windows-1252, Name;Gegenkonto;Konto enthält 4 Konten, „Neues Produkt Saft“ fehlt absichtlich. Nach dem Import dieser Liste (Standard-Erlöskonto z. B. 4711, Startwert 2000) bekommt das Produkt Gegenkonto 2014 und die Markierung „neu“

Ablauf-Vorschlag: Kantine-Einstellungen leer lassen und Hinweis prüfen, dann Werte eintragen. Handelsware: erst Einstellungen setzen, dann Konten.csv im Reiter Konten importieren, danach die XLSX hochladen, „neu“ prüfen, Konten-Reiter vor und nach dem Download vergleichen.

Abweichungen vom Plan

  1. [Regel 1 – Fehler] Zeilennummern aus der echten Datei. Die Vorlage nutzt Index + 2; bei Leerzeilen oder übersprungenen Zeilen zeigt das eine falsche Zeile. Der Parser gibt jetzt die echte 1-basierte Dateizeile mit (line), der Validator nutzt sie und fällt ohne sie auf Index + 2 zurück (Test deckt beides ab). Commit 1f85277.
  2. [Regel 3 – blockierend] sheetRows = 10 002 statt MAX_ROWS + 1. Mit MAX_ROWS + 1 wäre die 10 001. Datenzeile nie sichtbar, „zu viele Zeilen“ also nicht erkennbar. Test prüft genau 10 000 (ok) und 10 001 (Fehler). Commit 44c1d43.
  3. [Regel 2 – fehlende Absicherung] XLSX-Signaturprüfung. SheetJS wirft bei Müll-Bytes nicht, es liest sie als Text. Ohne Prüfung des ZIP-/OLE-Kopfes wäre „garbage bytes → invalidFile“ nicht erfüllbar. Commit 44c1d43.
  4. [Regel 2] Tabulator und Zeilenumbruch in Buchungstext und Kopftext werden durch ein Leerzeichen ersetzt, sonst würden sie die Spalten der TXT-Datei zerreißen. Gleiches gilt für Kontennamen über das DTO (Tabulator abgelehnt). Commit 44c1d43.
  5. [Regel 2] Dateinamen-Dekodierung (apps/api/src/accounting/decode-upload-filename.ts): multer liefert UTF-8-Namen als latin1-gelesen; der Helfer kehrt das um, ohne einen schon richtigen Namen zu beschädigen. Der Plan nannte nur die Umwandlung; ein blindes Buffer.from(name, 'latin1') hätte Namen mit Zeichen über 255 zerstört. Commit 44c1d43.
  6. Zusätzliche gemeinsame Web-Bausteine (nicht in files_modified): accounting-request.ts (Anfrage, Fehlerklasse), file-drop-area.tsx, tab-bar.tsx. Sie ersetzen eine zweifach kopierte Ablagefläche, Reiterleiste und Fehlerbehandlung. Die Ablage importiert keine Texte aus dem Zertifikat-Manager, wie verlangt.
  7. Umlaut-Wächter: das Wort „neues“ (korrektes Deutsch) stand nicht auf der Allowlist und ließ die volle Web-Suite rot werden; ergänzt in umlaut-dictionary.ts (nur die Teilmenge der Aufgabe 1 hatte das nicht gezeigt, die volle Suite schon).
  8. Doku: Im Inhaltsverzeichnis der Anwenderanleitung fehlte Proxmox, ich habe es mit ergänzt; „fünf Module“ wurde zu „sieben“. Die alte Klassen-Tabelle im Zugriffsdokument (Zahl 83) war schon vorher veraltet (gezählt waren 89); ich habe sie nicht umgeschrieben, sondern wie bisher einen Nachtragsabsatz mit nachgezählten Werten (90, dann 92 Paare) ergänzt.
  9. TDD: Aufgabe 2 und die Kantine-Funktionen sind mit den Tests zusammen entstanden und in je einem atomaren Commit gelandet; es gibt keine getrennten RED-Commits. Die Tests laufen gegen die finale Implementierung.

Auth-Gates

Keine. Es wurde kein Login benötigt; ich habe keine Zugangsdaten gelesen oder verwendet (die Lesesperre für .env hat zudem gegriffen, als ich die Admin-Angaben nachsehen wollte, und ich habe es dabei belassen).

Offene Fragen und Hinweise für Sie

  • Kodierung der Handelsware-TXT: Ich habe UTF-8 beibehalten, wie in der Vorlage. DATEV-Importe erwarten oft Windows-1252 (ANSI). Enthalten Produktnamen Umlaute, kann DATEV sie falsch anzeigen. Das sollte die Kollegin am echten Import prüfen; die Umstellung wäre eine Zeile in handelsware-datev.service.ts (Ausgabe) plus mimeType.
  • Export schickt die Datei erneut: Statt einer JSON-Liste aller Zeilen sendet der Export die Original-XLSX als Multipart plus buchungsdatum und newAccounts (JSON-Text). Der Server liest alle Zeilen selbst neu und berechnet die Zuordnung in derselben Transaktion; die TXT kann so nicht von der Arbeitsmappe abweichen, und die JSON-Grenze von Express (100 kB) kappt große Listen nicht.
  • „Startwert“-Bedeutung: Er ist die erste Nummer, die vergeben wird, wenn die Kontenliste leer ist. Ist die Liste nicht leer, gilt höchstes vorhandenes Gegenkonto + 1 (wie die Vorlage mit festem 8000). Das ist eine Entscheidung von mir, bitte bestätigen.
  • Wer was ändert: Nur Administratoren ändern die Einstellungen (beide Module). Die Kontenliste der Handelsware dürfen alle Benutzer mit Modulzugriff pflegen.
  • xlsx 0.18.5: Das Lesen der hochgeladenen Excel-Dateien nutzt die bereits vorhandene xlsx-Abhängigkeit der API (0.18.5). Bekannte Hinweise (Prototype Pollution, ReDoS), die nur in Versionen behoben sind, die nicht in der npm-Registry stehen, sind laut Bedrohungsmodell T-FM5-05 bewusst akzeptiert: nur angemeldete, freigegebene interne Benutzer, Formeln/HTML/Formate abgeschaltet, nur erstes Blatt, Spalten A/B, 5 MB und 10 000 Zeilen Grenze. Ein Austausch der Bibliothek ist eine eigene Entscheidung.
  • Kantine: Betragsformat wie in der Vorlage: „1.234,56“ und „-5,00“ werden als Fehler gemeldet (die Vorlage akzeptiert nur Ziffern mit optionalem Komma). Das ist so gewollt, könnte aber bei Kantinenexporten mit Tausenderpunkt hinderlich sein.
  • Desktop-Download: Der Download läuft über denselben Blob-Mechanismus wie der Zertifikat-Manager (vom Desktop-Client seit 1.9.2 gespeichert). Im Desktop-Client selbst nicht getestet.
  • Icons: utensils und shopping-bag habe ich den Lucide-Pfaden nach gezeichnet; optisch noch nicht gesehen.

Known Stubs

Keine. Es gibt keine Platzhalter oder fest eingebauten leeren Werte, die in die Oberfläche fließen. Die Einstellungsfelder sind absichtlich leer (kein Standardwert), das ist Teil der Anforderung und kein Stub.

Threat Flags

Keine neue Angriffsfläche außerhalb des Bedrohungsmodells. Umgesetzt: T-FM5-01 (keine Speicherung/Protokollierung der Kantinenzeilen; Test, dass die Vorschau keine Namen enthält), T-FM5-02 (Rollen-Metadaten per Test), T-FM5-03 (RLS plus Inventar), T-FM5-04 (5 MB, 1 MB für Konten-CSV, 10 000 Zeilen, newAccounts begrenzt), T-FM5-05 (akzeptiert, siehe oben), T-FM5-06 (Neuberechnung in der Transaktion, 409, P2002 → 409), T-FM5-07 (Apostroph vor =+-@, Rundlauf-Test).

Self-Check: PASSED

  • Dateien vorhanden: Migrationen, Dienste, Controller, Seiten, Testdaten (4 Dateien) — geprüft per ls und Lauf der Funktionen gegen die Testdaten.
  • Commits vorhanden: 1f85277, 44c1d43, 42b89f1, 1493375 (git log), commits: 4 gemessen mit git rev-list --count 0edd6e9..HEAD.
  • Keine Löschungen in den Commits (git diff --diff-filter=D leer).

Browser-Prüfung (Orchestrator, 02.10., lokal, dunkel)

  • Marktplatz: beide Module unter „Finanzbuchhaltung“, aktiviert; Seitenleiste zeigt neue Kategorie.
  • Kantine: Hinweis bei leeren Einstellungen; kantine-cp1252-fehler.csv → 4 Zeilen, 03/2026, 71,74 €, Warnung zwei Monate, Fehler Zeile 4, Download gesperrt. Einstellungen 1234567/12345/1111 gespeichert; kantine-gueltig-utf8.csv → LuG_1234567_12345_03_2026.sic, 11 Spalten, CRLF, Inhalt identisch zur Vorlage (Betrag 0 → -0.00 wie in der Vorlage).
  • Handelsware: Einstellungen 4711/2000; Konten.csv (cp1252) importiert, Umlaute korrekt; HWA 0326 Test.xlsx → Datum 3103, Kopftext 2026, „Neues Produkt Saft“ neu mit 2014/4711; Download HWA_0326.txt (UTF-8, CRLF); neues Konto erst danach in der Kontenliste.
  • Korrektur: Einstellungstexte nannten „Ihres Mandanten“ → entfernt (de/en), Web-Suite 1214 grün.
  • Desktop-Client-Download nicht geprüft.