patrick
345002944e
feat: Freizeitausgleich-Lücken geschlossen (Gap 1-3) + konfigurierbare Schwellwerte
...
Gap-1: Überziehschutz für Überstundenkonto
- Company.overtime_overdraft_allowed (default: true) – blockiert FZA wenn deaktiviert
- Company.overtime_warning_threshold_hours (default: 0) – Warnung wenn Konto unter Schwelle fällt
- warnings[] jetzt in approve_absence Response (AbsenceApproveOut)
- Migration 0028_overtime_fza_config.py
Gap-2: total_hours wird bei Zeiteintrag-Genehmigung neu berechnet
- time_service.approve_entry() ruft _recalculate_overtime_balance() auf
- last_calculated Timestamp wird gesetzt
Gap-3: Stornierung genehmigter FZA-Anträge bucht taken_hours zurück
- _refund_overtime() Helfer hinzugefügt
- cancel_absence() erlaubt jetzt HR/Admin auch genehmigte Abwesenheiten zu stornieren
- DELETE /absences/{id} gibt jetzt AbsenceOut zurück (statt 204)
- Mitarbeiter können genehmigte FZA-Anträge nicht selbst stornieren (409)
Frontend:
- CompanySettingsPage: neuer Abschnitt 'Freizeitausgleich' mit Toggle + Schwellwert-Eingabe
Tests: backend/tests/test_fza.py mit 6 Tests (alle 3 Gaps)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-25 00:08:03 +02:00
patrick
0ba16bb6af
fix: ternäre Button-Kette in MobileStampScreen korrigiert
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-24 23:53:43 +02:00
patrick
c8804efbd0
feat: Admin-Toggle für mobile Zeiterfassung
...
Backend:
- Company.mobile_stamping_enabled (BOOLEAN DEFAULT TRUE)
- CompanyOut + CompanyUpdate: neues Feld
- Migration 0027: companies.mobile_stamping_enabled
Frontend Desktop (CompanySettingsPage):
- Abschnitt 'Mobile-Ansicht' mit Toggle-Switch
- Speichert via PATCH /companies/me
Frontend Mobile (MobileStampScreen):
- Lädt mobile_stamping_enabled aus GET /companies/me
- Deaktiviert: Hinweis-Banner statt Buttons
('Einstempeln nicht verfügbar – bitte Kiosk/Desktop nutzen')
- Aktiviert: normales Verhalten
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-24 23:52:46 +02:00
patrick
22be68ee27
feat: Abwesenheiten-Screen in Mobile-App
...
- MobileAbsencesScreen.tsx:
- Urlaubskonto-Karte (verbleibende Tage + Fortschrittsbalken)
- Liste eigener Abwesenheiten (aktuell/geplant + vergangen)
- Farbpunkt pro Abwesenheitstyp, Status-Badge
- Bottom-Sheet Modal: Antrag stellen oder Krank melden
- Start-/Enddatum-Picker, Typ-Auswahl, optionale Notiz
- SICK-Typ → quick-sick Endpoint, sonst POST /absences/
- MobileBottomNav: 4. Tab 'Urlaub' (war 3 Tabs)
- MobilePage: Screen 'absences' eingebunden
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-24 23:31:00 +02:00
patrick
4a1dec7ae7
fix: mobile/tablet Geräteerkennung in LoginPage → Redirect zu /mobile/login
...
- useEffect prüft Bildschirmbreite (<1024px) + User-Agent (Mobi/Android/iPad/iPhone)
- Tablet/Handy wird automatisch zu /mobile/login weitergeleitet
- Desktop bleibt auf /login
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-24 23:22:11 +02:00
patrick
edb1568801
feat: mobile Login-Seite /mobile/login
...
- MobileLoginPage.tsx: touch-optimiertes Login-Formular
- E-Mail + Passwort mit großen Touch-Targets (min-h-[52px])
- TOTP-Flow: nach erstem Login automatisch 6-stelliges Code-Feld
- Numerische Tastatur (inputMode=numeric) für TOTP-Eingabe
- Fehlerbehandlung + Ladezustand
- Link zur Desktop-Version
- MobilePage: Redirect zu /mobile/login statt /login
- App.tsx: Route /mobile/login registriert (kein Layout-Wrapper)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-24 21:17:32 +02:00
patrick
8a04525dfc
fix: auto-refresh access token on 401 in API client
...
- Neuer refreshAccessToken()-Helper: POST /auth/refresh → neuer access_token
- Bei 401-Response: Token refreshen, Request automatisch wiederholen
- Parallele Requests: nur ein Refresh gleichzeitig (_refreshing-Promise)
- Refresh fehlgeschlagen → localStorage löschen + Redirect zu /login
- Gilt für alle API-Aufrufe (Desktop + Mobile)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-24 21:12:50 +02:00
patrick
094863f94b
feat: agent-02-kiosk Phase 1 - NFC UID migration + session service
...
- Migration 0025: kiosk_nfc_uid column on users table with partial unique index per company
- User model: kiosk_nfc_uid field after personnel_number
- New service: kiosk_session_service.py (Redis-based 15min sessions)
- New core module: app/core/redis.py (sync Redis client with ping-test)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-24 12:45:47 +02:00
patrick
35fcea90f4
feat(kiosk): Stufe 3 – ServiceWorker, WebCrypto Setup-Flow, Kiosk-UI, 15 Security-Tests
...
3A – Frontend Kiosk-Modus:
- public/kiosk-sw.js (NEU, 187 Zeilen): ServiceWorker signiert alle /api/v1/kiosk/
Requests automatisch mit Ed25519. Keypair-Generierung intern (non-extractable),
Speicherung in IndexedDB. BroadcastChannel-Leader-Election für Heartbeat.
- KioskSetupPage.tsx (NEU, 307 Zeilen): Enrollment-Flow unter /kiosk/setup.
Keypair-Generierung via WebCrypto im ServiceWorker, Public Key als PEM anzeigen.
Browser-Kompatibilitäts-Check (Ed25519 ab Chrome 113+).
- KioskStampPage.tsx (NEU, 348 Zeilen): Kiosk-UI unter /kiosk.
Live-Uhr mit Server-Zeit-Offset, Heartbeat-Loop 30s, Online/Offline-Indikator.
- App.tsx: /kiosk und /kiosk/setup Routen außerhalb ProtectedRoute
3B – Tests:
- tests/test_kiosk_security.py (NEU, 387 Zeilen): 15/15 Tests grün
Abgedeckt: gültige Signatur, falscher Key, Replay-Schutz, Timestamp-Drift,
Future-Timestamp, pending/revoked Device, unbekanntes Gerät, fehlende Header,
Lifecycle-Tests, heartbeat_status nach Heartbeat
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-24 12:23:03 +02:00
patrick
0f83d13c0c
feat(kiosk): Stufe 2 – Ed25519-Auth, CLI-Tool, neue KioskDevicesPage
...
2A – Backend Ed25519-Verifizierung:
- app/core/kiosk_security.py (NEU): verify_kiosk_request() Dependency
- Timestamp-Check (30s Drift), Nonce-Cache (Redis/In-Memory), IP-Whitelist
- Ed25519-Signatur über METHOD+PATH+TIMESTAMP+NONCE+sha256(BODY)
- PEM + OpenSSH Key-Format unterstützt
- app/routers/kiosk.py: approve/revoke Endpunkte, POST /heartbeat (Ed25519-signiert)
- app/services/kiosk_service.py: token-basierte Methoden entfernt, approve/revoke/heartbeat
- app/schemas/kiosk.py: KioskDeviceOut mit heartbeat_status, HeartbeatRequest/Response
2B – CLI-Tool:
- cli.py (NEU, 529 Zeilen): Typer-CLI mit kiosk add/list/approve/revoke/info
- Public-Key-Fingerprint (SHA256), Rich-Tabellen, CIDR-Validierung
- Direkter DB-Zugriff mit RLS-Bypass
2C – Frontend:
- KioskDevicesPage.tsx: Zwei-Tab-Layout (Wartet/Aktiv), Status-Ampel,
Auto-Refresh 30s, Ed25519-Workflow (kein Token mehr)
- Layout.tsx: KioskHealthBadge (online/total, 30s Refresh, nur COMPANY_ADMIN)
requirements.txt: typer>=0.12.0, rich>=13.7.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-24 12:13:46 +02:00
patrick
62ef6c2a11
feat: Live-Stempel-Uhr, Break-UI, Balance-Widget, Approval-Queue + PDF-Export (WeasyPrint)
...
Frontend (TimeTrackingPage):
- Live-Arbeitsuhr (HH:MM:SS) während eingestempelt
- Break-Start/End-Buttons mit laufender Pausenuhr
- Wochen-Balance-Widget (gearbeitet / erwartet / überstunden)
- Approval-Queue Tab für Manager/HR/Admin (pending entries genehmigen/ablehnen)
Backend (Reports):
- weasyprint>=61.0 in requirements.txt
- 3 neue PDF-Export-Tests (Zeit, Abwesenheit, Überstunden)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-24 11:59:32 +02:00
patrick
ada1b51f33
docs: vollständige Projektdokumentation hinzugefügt
...
- docs/api.md: komplette API-Referenz (1375 Zeilen, alle Endpunkte)
- docs/architecture.md: Tech-Stack, DB-Schema, RLS-Architektur, Auth-Flow
- docs/deployment.md: Setup, nginx, systemd, update.sh, Backup/Rollback
- docs/development.md: Dev-Setup, Test-Workflow, Code-Konventionen, Fallstricke
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-24 11:29:44 +02:00
patrick
fbc04bc2c0
agent-07 phase 2: fix test isolation + CSV import UI
...
- Fix conftest.py: commit after each request in override_get_db so
preview_csv's rollback no longer wipes the shared registered_user
(root cause of 401 cascade across test_user_import + test_personnel_number)
- Fix limiter.enabled=False in client fixture (blocks rate-limit 429)
- Fix user_import_service: allow reactivation when personnel number
belongs to the same user being reactivated
- Fix test_personnel_number: use PATCH /companies/me (not /companies/{id})
and add try/finally cleanup for personnel_number_required flag
- Frontend UsersPage: add CSV import modal with template download,
preview/validation table, and guarded apply button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-23 21:07:32 +02:00
sysops
1fedd683e0
Initial commit – TimeMaster Zeiterfassung & HR-Tool
...
Stand: agent-06 (Audit-Log), agent-05 (Krankmeldung), agent-07 Phase 1 (Personalnummer),
Busylight-Pull-Integration, TOTP/2FA, Abwesenheiten, Zeiterfassung, Kiosk-Grundgerüst.
Migrations 0001–0023 deployed auf 192.168.1.137 + .164.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-23 20:03:27 +02:00