L4 Einsatz mobil: Field-Services, Sync-API, Uploads und Tests

- services/field: Einsatz-Sessions (Anfahrt/Arbeit/Pause als TimeEntry-Segmente,
  eine aktive Session je User+Auftrag), Zeitkorrektur mit Recht + Grund + Audit,
  Checkliste, Material (Abweichung nur mit Begründung, Zusatzmaterial), Notizen,
  Fotos, Sprachnotizen (ohne Transkriptions-Processor Status disabled), Uploads
  (idempotent je Mandant), autorisierte Dokument-Auslieferung, Lesemodelle + Bundle
- services/sync: applyOperations mit Idempotenz, baseVersion-Konfliktprüfung,
  Registry für Ops anderer Lanes, lane-lokaler requireApiContext
- /api/v1/sync, /api/v1/uploads, /api/v1/field/bundle, /api/v1/field/documents/[id]
- lib/sync/ops.ts (Zod-Payloads je opType), lib/field/material-rules.ts
- Stubs mit Vertragssignatur: transitionWorkOrder (L2), storeFile (§4.3),
  getSiteHistory (L1)
- Processor image-derivatives + Registrierung, Audit-Entity-Labels
- Tests: test-einsatz-field (48 Prüfungen), test-einsatz-sync (38 Prüfungen)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-14 12:29:48 +02:00
co-authored by Claude Opus 5
parent bf4456718e
commit 952e74cddd
31 changed files with 2312 additions and 1 deletions
+2
View File
@@ -66,6 +66,8 @@ const ENTITY_LABEL: Record<string, string> = {
report: "Bericht",
emergency: "Notdienst",
document: "Dokument",
// Einsatz mobil (L4)
work_session: "Einsatz-Zeiterfassung", time_entry: "Zeitabschnitt", checklist_item: "Checklistenpunkt", material_usage: "Materialverbrauch", photo: "Foto", voice_note: "Sprachnotiz", activity_note: "Tätigkeitsnotiz", sync_operation: "Sync-Vorgang",
};
const fmt = new Intl.DateTimeFormat("de-DE", { dateStyle: "medium", timeStyle: "short" });