# Sender Save/Edit Migration Plan (Legacy Form -> Blazor Server) ## Objective Migrate the legacy `frmEnvelopeEditor` save/edit workflow into current architecture so that: 1. Sender can **save incomplete envelope as draft** (`EnvelopeSaved = 1002`) from `EnvelopeSenderEditorPage.razor`. 2. Sender can **resume editing** saved/created envelopes from `EnvelopeSenderPage.razor` via **Bearbeiten** and continue where they left off. This plan introduces a distinct draft flow and a same-ID send-from-draft flow, aligned with legacy Form app semantics. --- ## Scope ### In scope - Add separate **Save** and **Send** actions in sender editor. - Persist draft data server-side with partial/incomplete payload support. - Re-open existing draft from dashboard and restore editor state. - Preserve existing delete/withdraw logic and status model. - Add endpoints and application commands required for progressive sender workflow. ### Out of scope (this ticket) - Full redesign of editor UX. - Multi-document support parity with `frmOrderFiles`. - New DB schema changes (unless separately approved). --- ## Current Gap Analysis ## Current behavior (problem) - `EnvelopeSenderEditorPage.razor` has only one save path (`SaveAsync`) that behaves like "send": - requires title + PDF + receivers + fields. - calls `EnvelopeReceiverService.CreateAsync(...)` -> `/api/EnvelopeReceiver` monolithic create/send pipeline. - `EnvelopeSenderPage.razor` `EditEnvelope()` is TODO and does not navigate to editable persisted draft data. ## Legacy behavior (target) - `frmEnvelopeEditor` has both: - **Save**: persists envelope without full validation/sending. - **Send**: validates required business data then sends invitations. - Dashboard "Bearbeiten" opens selected unsent envelope and restores work state. --- ## Architectural Decisions 1. **Split command model by intent** - Draft persistence must not reuse monolithic `/api/EnvelopeReceiver` create+send endpoint. - Introduce dedicated sender workflow commands/endpoints for draft lifecycle. 2. **Progressive persistence** - Persist envelope metadata, document, receivers, and fields incrementally. - Draft save accepts partial data and updates only provided segments. 3. **Status ownership** - Draft operations set status to `EnvelopeSaved` (1002). - Send operation transitions to queued/sent path (existing 1003+ behavior). 4. **Editor route strategy** - Keep `/sender/editor` for new envelope. - Support edit mode via query: `/sender/editor?envelopeId={id}` (or route variant in follow-up if preferred). 5. **No DB schema migration by default** - Use existing tables (`TBSIG_ENVELOPE`, `TBSIG_DOCUMENT`, `TBSIG_ENVELOPE_RECEIVER`, `TBSIG_DOC_RECEIVER_ELEMENT`). - If a field is missing for a requirement, handle in application logic first and escalate only if unavoidable. --- ## Target Workflow ## A) New envelope (draft first) 1. User opens `/sender/editor`. 2. User enters any subset of data. 3. User clicks **Save**. 4. System creates or updates draft envelope and sets status `EnvelopeSaved`. 5. User gets confirmation and remains in editor (or optional return to dashboard). ## B) New envelope (direct send) 1. User fills required data. 2. User clicks **Send**. 3. System validates complete data and sends invitations. 4. Status transitions to queued/sent flow. ## C) Edit existing draft/created 1. User selects row in `/sender` with `EnvelopeCreated` or `EnvelopeSaved`. 2. User clicks **Bearbeiten**. 3. App navigates to `/sender/editor?envelopeId={id}`. 4. Editor loads persisted data (metadata, PDF, receivers, fields). 5. User can save again (draft) or send. --- ## Detailed Implementation Plan ## Phase 1 - Contracts and Application Use Cases ### 1.1 Add sender draft commands (Application) - `CreateEnvelopeCommand` (create/update draft with partial data) - `ReadEnvelopeDraftQuery` (load full editable projection by envelope id) - `CreateEnvelopeCommand` (same request, `Send=true` for final send) Each command should enforce sender ownership (`UserId`) and return structured result DTOs. ### 1.2 Validation policy split - **Draft Save validation (minimal):** - title optional at first save? choose one policy and keep consistent. - no requirement for receivers/fields/document. - **Send validation (strict):** - title required - document required - at least one receiver - required signature field mapping per receiver (business rule) ### 1.3 History policy - On draft save/update: optional lightweight history entry (`EnvelopeSaved`) if legacy parity requires it. - On send: keep current history/send pipeline behavior. --- ## Phase 2 - Server Endpoints Implement in `EnvelopeGenerator.Server` only. ### 2.1 Draft endpoints - `POST /api/Envelope` - Create/update draft envelope (partial payload allowed), and send when `Send=true`. - `GET /api/Envelope/{id}/draft` - Read full editable aggregate for editor hydration. ### 2.2 Authorization + errors - 400 validation issues - 403 sender mismatch - 404 envelope not found - 409 invalid state transition (optional, if needed) --- ## Phase 3 - Sender Editor UI (`EnvelopeSenderEditorPage.razor`) ### 3.1 Action buttons - Keep current action as **Send** (rename from "Speichern" to "Senden"). - Add separate **Save** button next to Send. ### 3.2 Editor mode state - Add `_editingEnvelopeId` from query param `envelopeId`. - `null` => create mode, value => edit mode. ### 3.3 Load existing draft - On parameter set / first render in edit mode: - call draft read endpoint. - hydrate title, message, PDF bytes, receiver list, field list. - map DB inches <-> PDF points correctly: - DB inches -> UI points: `pt = inches * 72` - UI points -> DB inches: `inches = pt / 72` ### 3.4 Save behavior (new) - Save button calls `SaveDraftAsync()`: - no strict send validations. - create draft if no id yet, otherwise update. - force status `EnvelopeSaved`. - keep user in editor and show non-blocking success feedback. ### 3.5 Send behavior (existing path replacement) - Send button calls `SendAsync()`: - strict validation. - if no draft id: create draft first then send, or direct send command. - if edit mode: send current draft id. ### 3.6 Session cache coexistence - Keep `esid` memory cache for transient UX resilience. - In edit mode, server data is source of truth; cache is fallback only. --- ## Phase 4 - Dashboard Edit Resume (`EnvelopeSenderPage.razor`) ### 4.1 Edit button enablement - Enable **Bearbeiten** for statuses: - `EnvelopeCreated` - `EnvelopeSaved` - Keep disabled for sent/queued/completed/deleted/withdrawn/rejected. ### 4.2 Navigation - Implement `EditEnvelope()`: - `Navigation.NavigateTo($"/sender/editor?envelopeId={_selectedEnvelope.Id}")`. ### 4.3 Optional UX - Double-click on editable rows can open editor instead of preview (or keep current preview behavior per product decision). --- ## Phase 5 - Data Mapping Rules 1. **Document** - Persist original PDF bytes (no visual placeholder burn-in). 2. **Receivers** - Draft can contain receivers with/without fields. 3. **Fields** - Store in DB inches with fixed signature size semantics. 4. **Ownership** - Sender can read/update/send only own envelopes. --- ## Suggested DTO Shape (Draft) Use one aggregate DTO for editor hydration/save/update: - `EnvelopeDraftDto` - `EnvelopeId` - `Status` - `Title` - `Message` - `DocumentBase64` (or document id + fetch endpoint) - `Receivers[]` - `ReceiverId?` - `Name` - `Email` - `Phone` - `Fields[] { XInches, YInches, Page }` --- ## Migration Strategy ## Step A (safe vertical slice) - Add read/edit route query handling and dashboard navigation first. - Hydrate editor from existing envelope data where possible. ## Step B (draft save) - Implement draft create/update endpoints + app commands. - Wire Save button. ## Step C (send from draft) - Move Send to explicit command/endpoint. - Ensure existing email/history behavior remains intact. ## Step D (hardening) - Add tests + manual QA checklist. --- ## Testing Plan ## Automated (Application) - Save draft with partial data -> status `EnvelopeSaved`. - Edit draft updates existing records, no duplicate orphan data. - Send draft with missing required data -> validation error. - Send draft complete -> queued/sent flow success. - Ownership checks -> 403 behavior. ## Manual (UI) 1. New editor -> save with only title. 2. Reopen from dashboard -> state restored. 3. Add PDF only -> save -> reopen -> PDF still present. 4. Add receivers/fields incrementally -> save repeatedly. 5. Final send -> status transitions and receiver notifications. --- ## Risks and Mitigations 1. **Monolithic endpoint coupling risk** - Mitigation: draft/send dedicated endpoints. 2. **Data duplication on repeated save** - Mitigation: idempotent upsert logic for receivers/fields. 3. **Coordinate regression** - Mitigation: centralize inches/points conversion helpers. 4. **Trigger side effects/history duplication** - Mitigation: verify DB-trigger interactions per status events. --- ## Definition of Done - Editor has two distinct actions: **Save** and **Send**. - Save allows incomplete payload and persists with `EnvelopeSaved` status. - Dashboard **Bearbeiten** opens editor for `EnvelopeCreated`/`EnvelopeSaved` and restores state. - Sender can continue from last saved point and eventually send. - Server endpoints support save/edit/send draft workflow with same envelope id. - No DB schema changes introduced without explicit approval.