Appearance
Finalisierungsablauf
Der Pfad für Kundensignatur und Finalisierung umfasst customer-view/signatures, den route-basierten Finalize-Start und die Composables der Finalisierungsseite.
Die vorgeschalteten Signatur-/Finalize-Guards sind zentral in app/utils/protocolWorkflow.ts gebündelt. Signaturseite, Middleware und Editor verwenden dadurch denselben Pfad für Setup-Load, Kündigungsgrund-Blockade und Step-Zielpfade.
Signaturseite
app/pages/customer-view/signatures.vue ist der letzte bearbeitbare Schritt vor der Finalisierung.
Aufgaben:
- rendert Signaturen von Mieter, Vermieter und dynamischen Vertragspartnern
- speichert den Signaturzustand über
signatureStore.$saveToServer() - wechselt zwischen handschriftlichem Signaturmodus und manuellem Signaturmodus
- validiert den Kündigungsgrund vor der Freigabe für Finalize über den gemeinsamen Workflow-Guard
- übergibt den gewählten Finalize-Modus als
finalizeMode-Query, bevor nach/finalizeumgeleitet wird
Der persistente Signaturzustand ist dafür in app/composables/media/pdf/useCustomerSignatureSession.ts gekapselt und nicht mehr mit der PDF-Erzeugung vermischt.
Ablaufdiagramm
Finalize-Routen- und Acceptance-Zustand
Der fachliche Finalize-Zustand wird aus den Acceptance-Metadaten abgeleitet:
lockedAt: finalisiert und für Bearbeitung gesperrtuploadPendingAt: gesperrt, aber der Upload steht noch aus- ohne beide Werte: weiter editierbar
app/utils/acceptanceStatus.ts bündelt diese Ableitung über getAcceptanceFinalizeState(...). Browser Storage enthält keinen fachlichen Finalisierungsstatus.
app/utils/finalizeRoute.ts hält nur den expliziten Startmodus aus der Route:
finalizeMode=auto: automatische Finalisierung startenfinalizeMode=manual: Protokoll sperren und Upload später manuell starten
Ohne gesperrte Acceptance und ohne gültigen finalizeMode leitet die Middleware /finalize zurück nach /customer-view/signatures.
Aufbau der Finalize-Seite
app/pages/finalize.vue bleibt eine schlanke Page-Shell: Sie delegiert das Verhalten an useFinalizePage() und setzt die großen Präsentationsblöcke zusammen.
Die wichtigsten Orchestrierungsbausteine sind:
useFinalizePage.tsuseFinalizePageFlow.tsuseAcceptanceFinalize.tsuseFinalizePagePreview.tsuseFinalizePageArchive.tsuseFinalizePageUnlock.ts
Die Präsentation ist in fokussierte Komponenten ausgelagert:
app/components/Finalize/FinalizeStatusHero.vue: Status, Fortschritt, Retry-Hinweis und Hauptaktionenapp/components/Finalize/FinalizeDispatchSummary.vue: deklarative Versandzusammenfassung nach erfolgreicher Finalisierungapp/components/Finalize/FinalizePdfPreviewSection.vue: Preview-Tabs und Versandart-Auswahlapp/components/Finalize/FinalizePdfPreviewPane.vue: gemeinsamer Wrapper überPdfPreviewFrameundPdfPageCanvasfür externes PDF und Zählerstands-PDF
Finalisierungs-, Upload-, Archivierungs- und Unlock-Logik gehört weiter in die Composables, nicht in die Präsentationskomponenten.
Preflight-Verhalten
useFinalizePageFlow.ts führt einen Preflight aus, bevor die eigentliche Finalisierung startet.
Geprüft werden:
- gültige Acceptance-ID
- aktuelle Acceptance-Metadaten
- ob die Acceptance bereits finalisiert ist
- ob die Acceptance bereits auf manuellen Upload wartet
- ob der Client offline ist
Wenn sich die Acceptance bereits im Pending-Upload-Zustand befindet, wechselt die Finalize-Seite in einen manuellen Vorschauzustand, statt die komplette Pipeline erneut auszuführen.
Automatische Finalisierung
useAcceptanceFinalize.ts führt die komplette Finalisierungspipeline in dieser Reihenfolge aus:
Für die PDF-Erzeugung verwendet der Composable app/composables/media/pdf/useCustomerPdfPreview.ts, also denselben Generierungspfad wie die Kundenansicht, aber ohne den Signatur-Session-Code mitzuschleppen.
- lokale Änderungen auf den Server speichern
- internes PDF erzeugen
- externes PDF erzeugen
- beide PDFs mit Retry-Unterstützung hochladen
- Acceptance erneut synchronisieren
- die Finalize-Stufe auf
donesetzen
Im Code verfolgte Finalize-Stufen:
idlesyncinggeneratingInterngeneratingExternuploadingfinalSyncdoneerror
Manuelle Finalisierung
Manuelle Finalisierung ist nicht nur ein UI-Label. Dafür existiert ein eigener Implementierungspfad.
useFinalizePageFlow.ts:
- speichert lokale Änderungen auf den Server
- ruft
acceptanceApi.markPendingUpload(acceptanceId)auf - synchronisiert den Acceptance-Zustand erneut
- bereitet eine externe Vorschau vor, ohne PDFs hochzuladen
Dadurch entsteht eine Acceptance, die für Bearbeitung gesperrt und als wartend auf Upload markiert ist.
Retry-Verhalten beim Upload
app/composables/protocol/finalizeUpload.ts lädt das Finalize-Payload per XHR hoch.
Retry-Verhalten:
- wiederholt Fehler ohne numerischen Status
- wiederholt
408,429und5xx - stoppt nach
maxRetries - markiert das Ausschöpfen der Retries mit
uploadRetryAbort
maxRetries wird aus runtimeConfig.public.finalizeUploadRetryLimit abgeleitet.
Verhalten bei gesperrten Acceptances
Sobald die Acceptance gesperrt ist, wird die Finalize-Seite zum kanonischen Ziel dieser Acceptance.
- finalisierte Acceptances zeigen den gespeicherten Abschlusszustand
- Acceptances im Pending-Upload-Zustand zeigen manuellen Bereitschaftszustand und Vorschau
/customer-view*und/werden von der Middleware weg umgeleitet