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

155 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: quick-261002-fm5
plan: 01
subsystem: finanzbuchhaltung
tags: [kantine-datev, handelsware-datev, datev, prisma-rls, nestjs, next-intl, xlsx]
requires: []
provides:
- Seitenleisten-Kategorie accounting (Finanzbuchhaltung / Financial accounting)
- Modul kantine-datev (Kantinenabrechnung) mit DATEV-Lohn-ASCII-Export
- Modul handelsware-datev (Handelsware) mit Kontenliste und DATEV-Buchungsdatei
affects: [module-registry, marketplace, sidebar, rls-access-inventory]
tech-stack:
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
key-files:
created:
- 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
modified:
- 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
decisions:
- 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
metrics:
duration: ca. 1 h 20 min
completed: 2026-10-02
status: complete
plan_head_before: 0edd6e9b1a1e0e594663129fdc185187ef81636e
plan_head_after: 14933753e70e85bb7c318ac347dd02a702e11841
commits: 4
actuals:
tokens: 63000
tasks: 3
commits: 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.