Dienstplan-Pro/_bmad-output/project-context.md

54 lines
4 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.

# Project Context — Dienstplan-Pro
*Lean, LLM-optimized brownfield context. Loaded as a persistent fact by BMAD workflows.*
## What it is
Deutschsprachige Progressive Web App (PWA) zur Berechnung von **Bonuszahlungen für Wochenend- und Feiertagsdienste** nach NRW-Regelung (Psychiatrie 2011). Live unter `https://bonus.pixel-by-design.de`. Sprache durchgehend Deutsch (UI, Doku, Kommentare); Variablen-/Funktionsnamen Englisch.
## Tech-Stack
- **Frontend:** Vanilla JS (ES6-Klassen an `window`), HTML5, CSS3, LocalStorage. Kein Build-Step, kein Framework.
- **Backend (seit „Stufe 1"):** Node 20 (CommonJS) + Express 4 + `better-sqlite3` 11 (synchron, WAL). Ein Prozess serviert statisches Frontend **und** `/api/*`.
- **Tests:** `node --test` (kein Framework). Alt-Artefakte `test.html`/`test-suite.js` (Browser) noch vorhanden, teils veraltet.
- **Deployment:** Docker (`node:20-slim`) hinter Caddy (Let's Encrypt TLS) auf Hetzner; SQLite-DB + Backups auf Docker-Volume `dienstplan-data` (`/data`). Server zieht Code von **GitHub** (`Kenearos/Dienstplan-Pro`), nicht vom lokalen Forgejo-Origin. Deploy-Key: `~/.ssh/id_ed25519_hetzner`. Service-Worker mit `skipWaiting`+`clients.claim` (self-updating).
## Kernmodule (Frontend)
| Datei | Klasse/Rolle |
|---|---|
| `app.js` | `DienstplanApp` — UI-Orchestrierung, Event-Handling, Bootstrap (`DOMContentLoaded``DataSync.boot()``new DienstplanApp()``imageImporter`) |
| `calculator.js` | `BonusCalculator` — orchestriert Tag-Klassifizierung + 3 Varianten, wählt Gewinner |
| `variants.js` | reine Funktionen: `classify` (Slot fr/sa/so/weekday inkl. Feiertags-Verschiebung), `variant1/2/3` |
| `holidays.js` | `HolidayProvider` — NRW-Feiertage 20252030 (handgepflegt) |
| `storage.js` | `DataStorage` — synchron, LocalStorage; Keys `dienstplan_employees|_duties|_vacation`, plus gerätelokaler OpenRouter-Key/Modell |
| `sync.js` | `DataSync` — hält LocalStorage (Working-Copy) und Server-DB synchron; `pending`-Flag schützt Offline-Änderungen; last-write-wins auf ganzen Dokumenten |
| `image-import.js` | `ImageImporter` — Foto→Dienste via OpenRouter Vision-LLM; Namens-Matching, Monat aus Live-Dropdown |
## Backend (`server/`)
- `db.js` — better-sqlite3, WAL + `synchronous=NORMAL`; Tabellen `documents(key PK, value, updated_at)` + `history`; `getDoc(key)`/`putDoc(key,value,now)` (putDoc snapshottet Alt-Wert in history).
- `index.js` — Express; `GET /api/health`, `GET/PUT /api/state` (liest/schreibt die 3 Dokumente employees/duties/vacation), statisches Frontend.
- `backup.js` — tägliches SQLite-Online-Backup (`db.backup()`), letzte 14.
## Geschäftslogik (verifiziert korrekt)
- **Sätze:** Wochenend-Slot (fr/sa/so) = 450 €, Werktag = 250 €. Dienst-Anteil 1,0 oder 0,5.
- **Tag-Klassifizierung:** echte Fr/Sa/So gewinnen immer; MoDo: Feiertag→so, Tag-vor-Feiertag→fr, Sandwich→sa.
- **3 Varianten** (V1 fr+so-Pool+Werktage, V2 sa+Werktage, V3 Wochenend-Pool) mit eigenen Schwellen/Abzügen (Freitag-Priorität); Rechner nimmt die mit dem höchsten Bonus. Urlaubsmodus halbiert Schwellen+Abzüge.
## Datenmodell (aktuell, Single-User)
LocalStorage-Working-Copy ↔ Server-Dokumente. `documents` global (kein Nutzerbezug). Datum als ISO-String, intern `T12:00:00` gegen Zeitzonen-Kanten.
## Constraints / Gotchas
- `better-sqlite3` ist **synchron** — kein `db.run()` (das ist node-sqlite3), immer `db.prepare().run()`/`db.exec()`.
- SQLite `foreign_keys` ist **standardmäßig AUS** — für CASCADE explizit `PRAGMA foreign_keys=ON`.
- SQLite kann **PK nicht per ALTER ändern** → Table-Rebuild.
- Deploy ohne Volume `dienstplan-data` = Datenverlust.
- CI-Pipeline (`.github/workflows/ci.yml`) mit OPA/Rego-Policy-Gates (`secrets_in_env`, `deploy_rules`, `image_provenance` …) aus einem Org-Standard.
## Reifegrad
„Stufe 1" (Server-Persistenz + Backup + Sync) ist gebaut, getestet, live. Bild-Import funktioniert (Juni-Erkennung + Berechnung gegen Handrechnung verifiziert). Aktuell **öffentlich ohne Login** — das ist der zentrale Punkt des v1.0-Team-Release.