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

4 KiB
Raw Permalink Blame History

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 (DOMContentLoadedDataSync.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
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.