# CLAUDE.md Hinweise für Claude Code (claude.ai/code) zur Arbeit in diesem Repository. ## Commands ```bash npm run dev # Entwicklungsserver npm run build # Produktions-Build (nach jeder Änderung zur Prüfung ausführen) npm run lint # ESLint ``` Kein Test-Setup. Deploy via `./deploy.sh [tag]` — baut ein Multiplatform-Docker-Image (amd64 + arm64) und pusht es nach `docker.citysensor.de`. ## Architektur Next.js 16 App-Router-Anwendung. Seiten sind Server-Komponenten; interaktive Teile sind Client-Komponenten in `app/MainClient.tsx` und `components/`. Layout und Design sind dem Schwesterprojekt `~/Projekte/logbuch` nachempfunden, jedoch mit **grüner** Grundfarbe. **Auth**: Single-User. Benutzername und Passwort sind fest in `.env` hinterlegt (`APP_USERNAME` default `Birgit`, `APP_PASSWORD`). Login über `app/login/actions.ts` → `lib/auth.ts` (Plaintext-Vergleich, kein bcrypt). Sessions sind JWT-Cookies via `jose` (`lib/session.ts`, 8 h Gültigkeit, Cookie `arbeitszeit_session`). Middleware liegt in `proxy.ts` (Next.js-16-Konvention) und exportiert `middleware`. **Passkeys (WebAuthn)**: Zusätzlich zum Passwort (das als Fallback bleibt). `lib/webauthn.ts` kapselt `@simplewebauthn/server` (RP-Config aus `RP_ID`/`RP_ORIGIN`/`RP_NAME`, Default `localhost`); Credentials liegen in Tabelle `passkeys` (`lib/passkeys.ts`). Die Challenge wird kurzlebig in einem httpOnly-Cookie zwischengespeichert. API unter `app/api/passkey/`: `register` (GET Options / POST Verify, Session nötig), `authenticate` (GET/POST, **öffentlich** — in `proxy.ts` von der Session-Pflicht ausgenommen, setzt bei Erfolg die Session), sowie `GET`/`DELETE` auf `app/api/passkey/route.ts` zum Verwalten. Registrierung im Einstellungen-Tab (`components/Passkeys.tsx`), Anmeldung per Button auf `app/login/page.tsx`. **WebAuthn braucht HTTPS** (Prod via Traefik) bzw. `localhost` in der Entwicklung. **Datenbank**: SQLite3 via `better-sqlite3`. `lib/db.ts` ist ein Singleton, legt Schema und die `settings`-Tabelle beim ersten Zugriff an. Datei unter `DB_PATH` (default `./data/arbeitszeit.db`, in Produktion `/app/data/arbeitszeit.db` auf einem Volume). `better-sqlite3` ist nativ → `serverExternalPackages` in `next.config.ts` und im Dockerfile `python3 make g++` in der `deps`-Stage. **Datenzugriff**: `lib/repo.ts` (CRUD + Pause-Setting), `lib/calc.ts` (Zeit-/Wochentag-Helfer), `lib/validate.ts` (Body-Validierung). API-Routen unter `app/api/` prüfen alle `getSession()` und liefern 401 ohne Session. ## Datenmodell & Berechnungen Tabelle `arbeitszeit`: `datum`, `ort` (Kunde FFM | Homeoffice | Andrena), `beginn`, `ende` (je HH:MM), `reise_beginn`, `reise_ende` (je HH:MM, optional), `pause` (dezimale Stunden), `vertriebsunterstuetzung` (default 2), `kommentar` (max. 500). - `Arbeitszeit = Ende − Beginn` (dezimale Stunden) - `Reisezeit = Reise-Ende − Reise-Beginn`: im Formular werden Start/Ende eingegeben, die Reisezeit wird wie Mehrarbeit zur Laufzeit berechnet (nicht gespeichert) und in Vorschau und Liste angezeigt. Beim Speichern koppelt sie nur die Vertriebsunterstützung. - `Mehrarbeit = Arbeitszeit − 8 − Pause` - Die Spalte „Arbeitszeit Kunde" ist fix 8 h (`ARBEITSZEIT_KUNDE_FIX`). - Die **Pause** wird pro Eintrag gespeichert (Spalte `pause`, dezimale Stunden; Eingabe im Formular in Minuten zwischen Beginn und Ende). Standard ist die globale Pause-Einstellung in der `settings`-Tabelle (Tab „Einstellungen"). Mehrarbeit wird je Eintrag aus dieser Pause zur Laufzeit berechnet, nicht gespeichert.