17 Abnahmekriterien und 12 User Stories mit Status und Nachweis (Testskript, Route, Lane-Bericht); Soll-/Kann-Funktionen; getroffene MVP-Annahmen zu den offenen fachlichen Entscheidungen; bekannte Einschränkungen und nicht verifizierte Punkte. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
12 KiB
12 KiB
Craftvia MVP – Abnahme-Matrix
Stand: 2026-09-15 · Branch
feature/craftvia-mvp@ef2f3f1· Gate: tsc · lint · build · 65/65 Testskripte grün; komplette Suite zusätzlich mitRLS_ENFORCED=true65/65 grün Quelle der Anforderungen:docs/craftvia/SPEC-CRAFTVIA.md§40 (Gesamt-Abnahme), §37 (User Stories), §44 (offene fachliche Entscheidungen). Status: erfüllt = umgesetzt und durch automatisierten Test belegt · teilweise = umgesetzt mit dokumentierter Lücke · offen = nicht umgesetzt. Nachweise verweisen auf Testskripte unterscripts/(Lauf:npm run test) und Lane-Berichte unterdocs/craftvia/lanes/.
1. Gesamt-Abnahmekriterien (Spec §40)
| # | Kriterium | Status | Nachweis | Offene Punkte |
|---|---|---|---|---|
| 1 | Mehrere Mandanten mit sicher getrennter Datenhaltung | erfüllt | Tenant-Guard src/server/db.ts + RLS enable_tenant_rls für alle Fachtabellen; test-tenant-isolation, test-rls-enforcement (35+ Tabellen FORCE RLS), Mandantentrennungs-Fälle in allen Lane-Tests; test-tenant-transaction (Owner + RLS); komplette Testsuite zusätzlich mit RLS_ENFORCED=true grün (52/52) ; test-e2e-* Mandantentrennung über alle 35 Tenant-Modelle (direkt in Postgres + 67 Service-Aufrufe), test-security-http (Produktions-Build: fremde IDs in allen /api/v1- und Datei-Routen → 404) |
RLS in Prod aktivieren (RLS_ENFORCED=true, Rolle craftvia_app LOGIN) – Betriebsschritt |
| 2 | Benutzer, Rollen und Montageteams verwaltbar | erfüllt | Fundament Nutzer/Rollen/Einladung (test-invitation, test-tenant-users-authz); Rollen tenant-admin/backoffice/team-lead/technician in rbac.ts; Teams L1 (test-stammdaten-teams) |
|
| 3 | Auftragsbestätigungen als PDF importierbar | erfüllt | L3 /imports, POST /api/v1/work-orders/import; test-import-flow, test-import-rules |
Live-Extraktion gegen Claude nur mit ANTHROPIC_API_KEY (test-import-live) |
| 4 | Kunden-, Objekt- und Auftragsdaten automatisiert extrahiert | teilweise | L3 Claude-Provider (PDF-/Bild-Block, JSON-Schema, Konfidenz je Feld), Plausibilitätsprüfung, Dubletten-/Objektkandidaten; Fake-Provider-Tests | Umgesetzt und mit Fake-Provider getestet; Live-Extraktion mit Claude mangels ANTHROPIC_API_KEY nicht verifiziert – an echten Pilotdokumenten validieren |
| 5 | Backoffice prüft und korrigiert erkannte Daten | erfüllt | Prüfmaske /imports/[id] (unsichere Felder markiert, Korrektur-Diff, keine Auftragsanlage ohne Bestätigung); test-import-flow K-Fälle |
|
| 6 | Aufträge Teams zuweisbar | erfüllt | L2 assignWorkOrder + Event work_order.assigned → L6 Empfänger; test-auftraege-core, test-benachrichtigungen-events |
|
| 7 | Monteure bearbeiten Aufträge auf Tablet/Smartphone | erfüllt | L4 /m/** (eigene Shell, Bottom-Nav, Touch ≥ 48 px); test-einsatz-field; authentifizierter Smoke scripts/smoke-auth.ts |
smoke-auth.ts 94/94 Seiten-Prüfungen für alle Rollen + zweiten Mandanten; visuelle Prüfung 375/768/1024 px im Browser offen |
| 8 | Wesentliche Daten offline erfassbar | erfüllt | L7 Service Worker, IndexedDB-Outbox, /m/offline, /m/sync; test-offline-core, test-offline-sync-e2e (20 Ops → 1 Batch, Replay → duplicate) |
Manueller DevTools-Offline-Test; Abschließen offline bewusst gesperrt (Pflichtprüfung server-seitig) |
| 9 | Arbeitszeiten, Tätigkeiten, Material, Fotos dokumentierbar | erfüllt | L4 Sessions/TimeEntry, Notizen, Material (Abweichungsgrund Pflicht), Fotos (Kompression, Pflichtfotos); test-einsatz-field, test-einsatz-sync |
|
| 10 | Tagesberichte erzeugbar | erfüllt | L5 Tagesbericht (Content-Snapshot je Tag, Auftrag bleibt offen); test-berichte-flow |
|
| 11 | Abschlussberichte inkl. Kundenunterschrift | erfüllt | L5 Abschlussbericht, Unterschrift inkl. Abwesend/Verweigert/Später mit Begründung; test-berichte-flow |
|
| 12 | PDF-Arbeitsnachweis erstellt | erfüllt | L5 HTML→PDF (Playwright/Chromium im Worker), Checksumme, unveränderliche Version; test-berichte-pdf |
Worker-Image craftvia-worker mit Chromium lokal gebaut und PDF erzeugt (L10b); Registry-Push/Prod-Deploy offen |
| 13 | Backoffice gibt abgeschlossene Aufträge zur Abrechnung frei | erfüllt | L2 releaseForBilling nur mit freigegebenem Abschlussbericht; test-auftraege-status |
|
| 14 | Monteure legen selbstständig Notdiensteinsätze an | erfüllt | L8 /m/emergency (vorläufiger Kunde/Objekt in einer Transaktion, offline als Sync-Op); test-notdienst-flow |
|
| 15 | Backoffice wird über Notdiensteinsätze informiert | erfüllt | L6 Pflichtmail + In-App bei emergency.created/completed (Format §19.4); test-notdienst-flow, test-benachrichtigungen-events |
Echter SMTP-Versand in Prod konfigurieren |
| 16 | Frühere Einsätze und technische Dokumente pro Objekt abrufbar | erfüllt | L1 Objekt-Historie + Dokumente (Sichtbarkeit/Scope), L4 mobile Historie; test-stammdaten-sites, test-stammdaten-documents |
|
| 17 | Relevante Änderungen revisionsfähig protokolliert | erfüllt | writeAuditLog (before/after, IP, User-Agent) in allen Mutationen, Audit-Viewer /settings/audit; test-audit-mail-context, test-benachrichtigungen-inbox-audit |
Audit-Einträge in Transaktionen erst nach Commit (L10b); Tamper-Schutz/Log-Aggregation (Betrieb) offen |
2. User Stories (Spec §37)
| US | Titel | Status | Nachweis | Offene Punkte |
|---|---|---|---|---|
| US-001 | Mandant anlegen | erfüllt | Plattform-Konsole /admin (Fundament), provisionTenant; Isolationstests |
|
| US-002 | Auftragsbestätigung importieren | teilweise | L3 (s. §40 #3–5); test-import-flow, test-e2e-* (Import → Abrechnung) |
Live-Texterkennung/Extraktion mit Claude nicht verifiziert (kein API-Schlüssel) |
| US-003 | Bestehenden Kunden erkennen | erfüllt | L1 findDuplicateCustomers (keine Auto-Zusammenführung), L3 Kandidaten in Prüfmaske; test-stammdaten-duplicates |
|
| US-004 | Auftrag einem Team zuweisen | erfüllt | L2 + L6 | |
| US-005 | Technische Unterlagen ansehen | erfüllt | L1/L4 Dokumente mit Sichtbarkeit (backoffice_only verborgen), freigegebene Historie; L7 Vorab-Download offline | |
| US-006 | Einsatz dokumentieren | erfüllt | L4 | |
| US-007 | Tagesbericht erstellen | erfüllt | L5 | |
| US-008 | Abschlussbericht erstellen | erfüllt | L5 (Pflichtangaben/-fotos geprüft, Status „Zur Prüfung") | |
| US-009 | Auftrag zur Abrechnung freigeben | erfüllt | L2 + L5 + L6 | |
| US-010 | Notdiensteinsatz anlegen | erfüllt | L8 + L6 | |
| US-011 | Objekt-Historie aufrufen | erfüllt | L1 getSiteHistory (offene Folgearbeiten hervorgehoben) |
|
| US-012 | Offline arbeiten | erfüllt | L7 + L4 Sync-Server (Idempotenz, Konflikte nicht still überschrieben) |
3. Soll-/Kann-Funktionen (Spec §36.2/§36.3)
| Funktion | Status | Nachweis / Anmerkung |
|---|---|---|
| Sprachnotizen + Transkription | erfüllt | L4 Aufnahme, L9 Whisper-kompatibler Provider (test-lotse-transcription); ohne TRANSCRIPTION_API_KEY Status disabled |
| KI-Berichtsentwurf (Lotse) | erfüllt | L9 Vorschlag in content.lotse, Prüfbestätigung serverseitig Pflicht, Datenminimierung (test-lotse-draft) |
| Konfigurierbare Vorlagen | erfüllt | L2 /settings/order-types, /settings/checklists |
| E-Mail-Versand von Berichten | erfüllt | L6 interne Benachrichtigungen; L11 „An Kunden senden“ auf /reports/[id] und POST /api/v1/reports/{id}/send: freigegebenes PDF als Anhang (Queue enthält nur Document-Referenz; Zustellung lädt Bytes mandantengebunden mit Prüfsummenprüfung), Recht report:approve, Audit, Dedupe je Adresse+Version; test-report-customer-mail (41 Prüfungen), realer Versand an Mailhog geprüft. Offen: kein erneutes Senden an dieselbe Adresse, ein Empfänger ohne CC, Sprache = Mandant |
| Berichtsversionierung | erfüllt | L5 lineageId/version, alte Version erst bei Freigabe der neuen superseded |
| MFA | erfüllt | Fundament TOTP + Passkeys, Mandanten-MFA-Pflicht |
| Kartenlink zur Einsatzadresse | erfüllt | L1 OpenStreetMap-Link, L4 Routenlink |
| Push-Benachrichtigungen | offen | nach MVP (Spec §20.2 „später") |
| Kalenderansicht | offen | optional (§11.2) |
| Standorterfassung beim Einsatzstart | erfüllt | L4 optional beim Session-Start |
| Barcode/QR-Code | offen | Version 2 |
| Kundenspezifische Statusmodelle | offen | Statusmodell global, Labels gruppiert (Brandbook §12.3) |
| Digitale Einsatzfreigabe durch Teamleiter | erfüllt | L5 report:approve_team |
4. Offene fachliche Entscheidungen (Spec §44) – getroffene MVP-Annahmen
| Thema | MVP-Annahme | Zu klären mit Pilotkunde |
|---|---|---|
| Berichtsvorlage | generische Vorlage L5 mit Mandantenlogo/-namen | Layout/Pflichtinhalte des Pilotkunden |
| Pflichtfelder je Auftragsart | über Checklisten-Vorlagen je Auftragsart konfigurierbar | konkrete Pflichtfelder |
| Fotoarten | Standard-Pflichtfotos §14.2 als Vorschläge | verbindliche Liste |
| Arbeitszeitkorrektur | nur mit field:correct_time (Teamleiter/Admin), Grund Pflicht, Audit |
Genehmigungsprozess? |
| Aufbewahrungsfristen | Soft Delete, keine automatische Löschung; KI-Protokoll: AI_GENERATION_RETENTION_DAYS (Default 180): täglicher Worker-Job leert Ein-/Ausgaben und Personenbezug im KI-Protokoll; monatliches Token-Kontingent je Mandant (/settings/lotse) |
Fristen je Dokumentart |
| Empfänger Abrechnungsbenachrichtigung | /settings/email Abrechnungsempfänger je Mandant |
Adressen |
| OCR-/KI-Anbieter | Claude (Anthropic) für Extraktion + Lotse, Whisper-kompatibel für Transkription (Entscheidung 2026-09-14) | Vertrag/AVV, Region |
| E-Mail-Dienst | SMTP (Mail-Worker, Queue) | Anbieter, SPF/DKIM/DMARC |
| Hostingstandort | Coolify/Docker (aus Certvia übernommen) | Rechenzentrum/Region |
| MFA-Regelung | optional je Nutzer, Mandanten-Pflicht einschaltbar | Pflicht für Admins? |
| Standortdaten | optional beim Einsatzstart/Foto, kein Dauertracking | Einwilligung/Betriebsvereinbarung |
| Maximale Offline-Dauer | OFFLINE_MAX_DAYS=7 |
Wert |
| Maximale Dateigrößen | Bild 15 MB, PDF 25 MB, Audio 20 MB | Werte |
| Buchhaltungssoftware | keine Schnittstelle (MVP-Abgrenzung §35) | Zielsystem für V2 |
| Spätere Schnittstellen | versionierte API /api/v1 + OpenAPI |
Prioritäten |
| Branding der PWA | Craftvia (Brandbook), Mandantenlogo in Berichten | Mandanten-Branding in App? |
| Berichtssprache | Deutsch (EN-Kataloge vorbereitet) | |
| Lösch-/Archivierungskonzept | DSGVO-Export/-Löschung aus Fundament, PII-Liste um Fachfelder erweitert | Löschfristen |
5. Bekannte Einschränkungen vor Produktivbetrieb
- Login-Drosselung: Konto-Lockout nach 5 Fehlversuchen vorhanden; zusätzlich Drosselung je IP und je Konto (Scope
login, 20 Versuche / 15 min,LOGIN_RATE_LIMIT_PER_15_MIN;test-login-rate-limit). Zähler im Speicher je App-Instanz. - Polyglot-Uploads: gültiger Bildkopf mit angehängtem Inhalt passiert die Typprüfung (Auslieferung als Download mit erkanntem Typ +
nosniff, keine Ausführung); echte Inhaltsprüfung nur mit ClamAV (CLAMAV_HOST). - Rate-Limit
/api/v1je App-Instanz im Speicher (bei mehreren Instanzen Redis-Zähler nötig); API nur mit Session-Cookie (kein Token-Zugang für Integrationen). - Mobile Listen ohne Paginierung (max. 200 bzw. 100 heute) – für MVP-Größen ausreichend (Performance-Messung 5 020 Aufträge: Dashboard/Liste 30–53 ms, mobil ~110 ms im Produktions-Build).
emitEventin Transaktionen feuert sofort (bei späterem Rollback evtl. Benachrichtigung ohne Datenänderung).- Unterschrift offline: Sync-Op
signature.capturenicht registriert (Unterschrift erfordert Verbindung). - Live-KI (Claude-Extraktion, Lotse, Transkription) ohne API-Schlüssel nicht verifiziert.
- Deployment: Images lokal gebaut (App 400 MB, Worker 2,68 GB inkl. Chromium), kein Registry-Push, CI-Testjob nicht auf Server ausgeführt.
- Demo-Seed: Daten relativ zum Seed-Zeitpunkt.
6. Nicht verifiziert in dieser Umgebung
- Live-Aufrufe gegen Claude (Extraktion, Lotse) und Transkription – keine API-Schlüssel gesetzt.
- Visuelle Prüfung mit echter Passwort-Anmeldung im Browser (Agenten geben keine Passwörter ein; angemeldete Prüfungen per
scripts/smoke-auth.ts). - Manueller Offline-Test mit Browser-DevTools.
- Deployment auf Zielumgebung (nur lokaler Docker-Build).