cb168fbd18
- Reisezeit wird aus Reise-Beginn/-Ende zur Laufzeit berechnet (Spalte reisezeit entfernt), Anzeige in Vorschau und Liste wie Mehrarbeit - Pause pro Eintrag in Minuten (Feld zwischen Beginn und Ende), Default aus globaler Einstellung - Eingabefelder werden nach dem Speichern eines neuen Eintrags geleert - DB-Migrationen für reise_beginn/reise_ende/pause-Spalten - Version 0.1.2 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
64 lines
3.5 KiB
Markdown
64 lines
3.5 KiB
Markdown
# 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.
|