Add FORM_APPLICATION_CONTEXT.md for migration documentation
Added a new file, `FORM_APPLICATION_CONTEXT.md`, to the solution file `EnvelopeGenerator.sln`. This file provides detailed documentation of the legacy VB.NET Windows Forms application, including its architecture, workflows, and migration plan to the ReceiverUI + API architecture. The documentation outlines the application's purpose, primary libraries, project structure, and key forms with their respective features and behaviors. It also describes data models, controllers, and their methods, along with technical details such as coordinate systems, status colors, and master-detail grid patterns. Additionally, the file includes implementation notes for key features like drag-and-drop file uploads, auto-complete for receiver emails, and PDF merging. Workflow summaries and a data flow diagram are provided to clarify the application's processes. The document concludes with key takeaways to ensure consistency during the migration.
This commit is contained in:
@@ -22,6 +22,7 @@ EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{134D4164-B291-4E19-99B9-E4FA3AFAB62C}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
COPILOT_CONTEXT.md = COPILOT_CONTEXT.md
|
||||
FORM_APPLICATION_CONTEXT.md = FORM_APPLICATION_CONTEXT.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0CBC2432-A561-4440-89BC-671B66A24146}"
|
||||
|
||||
788
FORM_APPLICATION_CONTEXT.md
Normal file
788
FORM_APPLICATION_CONTEXT.md
Normal file
@@ -0,0 +1,788 @@
|
||||
# EnvelopeGenerator.Form – VB.NET Desktop Application Context
|
||||
|
||||
## Purpose
|
||||
**Legacy Windows Forms application** for envelope creation, management, and signature field placement. Built with **DevExpress components** and **GdPicture14** for PDF manipulation. This application is being **migrated to ReceiverUI + API** architecture.
|
||||
|
||||
**Primary Libraries:** DevExpress XtraGrid/XtraEditors, GdPicture14, VB.NET (.NET Framework 4.6.2)
|
||||
|
||||
---
|
||||
|
||||
## Application Architecture
|
||||
|
||||
### Projects Structure
|
||||
| Project | Purpose |
|
||||
|---|---|
|
||||
| **EnvelopeGenerator.Form** | Main WinForms UI (VB.NET) |
|
||||
| **EnvelopeGenerator.CommonServices** | Shared services/helpers |
|
||||
| **EnvelopeGenerator.Service** | Windows Service (legacy) |
|
||||
| **EnvelopeGenerator.BBTests** | Tests |
|
||||
|
||||
### Key Forms (Pages)
|
||||
|
||||
#### 1. **frmMain.vb** - Envelope Overview (Dashboard)
|
||||
**Route Equivalent:** `/sender` (EnvelopeSenderPage.razor)
|
||||
|
||||
**Purpose:** Main dashboard showing all envelopes with status filtering.
|
||||
|
||||
**Key Features:**
|
||||
- **Tab-based layout** with 2+2 tabs:
|
||||
- **Tab 0:** Active Envelopes (not sent/partially signed)
|
||||
- **Tab 1:** Completed Envelopes (signed/rejected/deleted)
|
||||
- **Tab 2:** Reports (Admin only)
|
||||
- **Tab 3:** Additional Reports (Admin only)
|
||||
|
||||
**Envelope Status Colors:**
|
||||
| Status | Color | Hex Code | Description |
|
||||
|---|---|---|---|
|
||||
| `EnvelopePartlySigned` | Green | `#81C784` (GREEN_300) | At least one receiver signed |
|
||||
| `EnvelopeQueued` / `EnvelopeSent` | Orange | `#FFB74D` (ORANGE_300) | Sent to receivers, awaiting signatures |
|
||||
| `EnvelopeCompletelySigned` | Green | `#81C784` (GREEN_300) | All receivers signed |
|
||||
| `EnvelopeDeleted` / `EnvelopeWithdrawn` / `EnvelopeRejected` | Red | `#E57373` (RED_300) | Envelope cancelled/rejected |
|
||||
|
||||
**Receiver Status Colors (in detail grids):**
|
||||
| Status | Color | Hex Code |
|
||||
|---|---|---|
|
||||
| `Signed` | Green | `#81C784` (GREEN_300) |
|
||||
| `Not Signed` | Red | `#E57373` (RED_300) |
|
||||
|
||||
**Grid Layouts:**
|
||||
|
||||
1. **GridEnvelopes** (Active):
|
||||
- Columns: ID, Title, Status, Created Date, Creator
|
||||
- **Master-Detail:** Expands to show:
|
||||
- **ViewReceivers:** Receiver list with status colors
|
||||
- **ViewHistory:** Envelope history (status changes, emails sent)
|
||||
|
||||
2. **GridCompleted** (Completed):
|
||||
- Same structure as GridEnvelopes
|
||||
- **ViewReceiversCompleted** and **ViewHistoryCompleted** detail grids
|
||||
|
||||
**Toolbar Actions:**
|
||||
| Button | Action | Enabled When |
|
||||
|---|---|---|
|
||||
| **Create Envelope** | Opens `frmEnvelopeEditor` | Always |
|
||||
| **Edit Envelope** | Opens `frmEnvelopeEditor` with selected envelope | Envelope selected & not sent |
|
||||
| **Delete Envelope** | Shows `frmRueckruf` (reason dialog) ? deletes | Envelope selected |
|
||||
| **Show Document** | Opens PDF in temp folder | Envelope & document selected |
|
||||
| **Contact Receiver** | Opens mailto link | Receiver selected |
|
||||
| **Resend Invitation** | Resends email to receiver | Receiver selected |
|
||||
| **Send Access Code** | Manually sends access code email | Receiver selected & UseAccessCode=true |
|
||||
| **Info Mail** | Opens mailto to support team | Receiver selected (for issues) |
|
||||
| **2FA Properties** | Shows `frm2Factor_Properties` dialog | Receiver selected & TFA enabled |
|
||||
| **Export Report (EB)** | Exports completed envelope result PDF | Completed envelope selected |
|
||||
| **Refresh** | Reloads data | Always |
|
||||
| **Export to Excel** | Exports current grid to XLSX | Always |
|
||||
|
||||
**Auto-Refresh:** Timer refreshes every N seconds (configurable), but **only when `frmEnvelopeEditor` is not open**.
|
||||
|
||||
**Persistence:** Grid layouts saved to `{GridViewName}_UserLayout.xml` in user AppData folder.
|
||||
|
||||
---
|
||||
|
||||
#### 2. **frmEnvelopeEditor.vb** - Envelope Creation/Edit
|
||||
**Route Equivalent:** `/sender/envelope/{id}` (future)
|
||||
|
||||
**Purpose:** Create or edit envelope details, add documents, manage receivers.
|
||||
|
||||
**Workflow:**
|
||||
1. **On New Envelope:** Opens `frmEnvelopeMainData` popup **first** (title, type, settings)
|
||||
2. **After popup OK:** Main editor loads
|
||||
3. **Add Document:** Single PDF file (via Open Dialog or Drag & Drop)
|
||||
4. **Add Receivers:** Grid with auto-complete from previous emails
|
||||
5. **Edit Fields:** Opens `frmFieldEditor` for signature field placement
|
||||
6. **Send Envelope:** Validates and sends invitations
|
||||
|
||||
**UI Layout:**
|
||||
- **Top Ribbon:** DevExpress ribbon with actions
|
||||
- **Left Panel:** Document list (thumbnail + details)
|
||||
- **Right Panel:** Receiver list (name, email, access code, phone)
|
||||
- **Bottom Bar:** Envelope ID, Creator Email, Info messages
|
||||
|
||||
**Ribbon Actions:**
|
||||
| Button | Action | Enabled When |
|
||||
|---|---|---|
|
||||
| **Add File** | Opens file dialog | No document added |
|
||||
| **Merge Files** | Opens `frmOrderFiles` to concatenate PDFs | No document added |
|
||||
| **Delete File** | Removes document | Document selected |
|
||||
| **Show File** | Opens PDF in default viewer | Document selected |
|
||||
| **Edit Fields** | Opens `frmFieldEditor` | Document + receivers exist |
|
||||
| **Edit Data** | Opens `frmEnvelopeMainData` | Always |
|
||||
| **Save** | Saves envelope without validation | Always |
|
||||
| **Send Envelope** | Validates & sends invitations | Document + receivers exist |
|
||||
| **Cancel** | Closes with save prompt | Always |
|
||||
| **Delete Receiver** | Removes receiver from list | Receiver selected |
|
||||
|
||||
**Receiver Grid:**
|
||||
- **Columns:** Name, Email, Access Code, Phone (if TFA enabled)
|
||||
- **Auto-complete:** Email field suggests previous receivers
|
||||
- **Validation:** Email format, Phone format (+49... for TFA)
|
||||
- **Access Code:** Auto-generated on email entry (if UseAccessCode=true)
|
||||
- **Color Assignment:** Each receiver gets a unique color (for signature fields)
|
||||
|
||||
**Document Grid:**
|
||||
- **Single file only** (currently limited to 1 PDF)
|
||||
- **Thumbnail:** Generated via GdPicture14
|
||||
- **Page Count:** Displayed
|
||||
|
||||
**Drag & Drop:**
|
||||
- Drop PDF files directly onto form
|
||||
- Only 1 file allowed
|
||||
- Visual feedback (red bar if >1 file)
|
||||
|
||||
**Validation:**
|
||||
- Title required
|
||||
- Message required
|
||||
- At least 1 document
|
||||
- At least 1 receiver
|
||||
- Valid email addresses
|
||||
- Valid phone numbers (if TFA enabled)
|
||||
- Signature fields exist for each receiver (before sending)
|
||||
|
||||
---
|
||||
|
||||
#### 3. **frmEnvelopeMainData.vb** - Envelope Settings Popup
|
||||
**Route Equivalent:** Part of `/sender/envelope/{id}` (inline in ReceiverUI)
|
||||
|
||||
**Purpose:** Configure envelope metadata and behavior. **Shown as modal popup** before main editor.
|
||||
|
||||
**Fields:**
|
||||
|
||||
| Field | Type | Description |
|
||||
|---|---|---|
|
||||
| **Title** | Text | Envelope title (required) |
|
||||
| **Envelope Type** | Dropdown | Template (ContractType, Language, defaults) |
|
||||
| **Language** | Dropdown | de/en |
|
||||
| **Use Access Code** | Checkbox | Require 6-digit code for signing |
|
||||
| **2FA Enabled** | Checkbox | Require SMS verification (forces Access Code ON) |
|
||||
| **Certification Type** | Dropdown | Basic / Advanced / Qualified |
|
||||
| **Final Email to Creator** | Dropdown | No / OnComplete / OnCompleteOrReject |
|
||||
| **Final Email to Receivers** | Dropdown | No / OnComplete / OnCompleteOrReject |
|
||||
| **Send Reminder Emails** | Checkbox | Auto-send reminders |
|
||||
| **First Reminder Days** | Number | Days before first reminder |
|
||||
| **Reminder Interval Days** | Number | Days between reminders |
|
||||
| **Expires When Days** | Number | Days until envelope expires |
|
||||
| **Expires Warning Days** | Number | Days before expiry to warn |
|
||||
|
||||
**Layout:**
|
||||
- **Compact mode:** Only Title, Type, Language visible
|
||||
- **Expanded mode:** Click "All Options" to show reminder/expiry settings
|
||||
|
||||
**Behavior:**
|
||||
- **On Type Selection:** Auto-fills all settings from template
|
||||
- **On 2FA Enable:** Forces "Use Access Code" ON and disables checkbox
|
||||
- **On New Envelope:** Shows before main editor
|
||||
- **On Edit Envelope:** Opens as separate dialog, Type field read-only
|
||||
|
||||
**Validation:** Title is required (red border via Adorner).
|
||||
|
||||
---
|
||||
|
||||
#### 4. **frmFieldEditor.vb** - Signature Field Placement
|
||||
**Route Equivalent:** `/sender/envelope/{id}/fields` (future, or inline in editor)
|
||||
|
||||
**Purpose:** Place signature fields on PDF pages using **GdPicture14** viewer with annotations.
|
||||
|
||||
**UI Layout:**
|
||||
- **Left:** PDF Viewer (GdViewer) with annotation tools
|
||||
- **Right:** Thumbnail navigator (ThumbnailEx2)
|
||||
- **Top:** Toolbar with receiver selector and actions
|
||||
|
||||
**Toolbar:**
|
||||
| Button | Action |
|
||||
|---|---|
|
||||
| **Receiver Selector** | Popup menu with receiver names (colored circles) |
|
||||
| **Add Signature** | Draws new signature annotation |
|
||||
| **Delete** | Removes selected annotation |
|
||||
| **Save** | Saves signature fields to database |
|
||||
|
||||
**Signature Field Details:**
|
||||
- **Size:** 1.77" × 1.96" (4.5cm × 5cm) - **FIXED SIZE**
|
||||
- **Color:** Matches receiver color (from grid assignment)
|
||||
- **Label:** "SIGNATUR" (or localized "Signature")
|
||||
- **Position:** Draggable on PDF canvas
|
||||
- **Database Format:** Coordinates stored in **INCHES** (GdPicture native)
|
||||
|
||||
**Coordinate System:**
|
||||
- **Origin:** Top-left corner
|
||||
- **Units:** Inches (not points or pixels)
|
||||
- **Axes:** X right, Y down
|
||||
- **Storage:** Direct INCHES values (no conversion)
|
||||
|
||||
**Evidence from Code:**
|
||||
```vb
|
||||
Private Const SIGNATURE_WIDTH As Single = 1.77 ' inches
|
||||
Private Const SIGNATURE_HEIGHT As Single = 1.96 ' inches
|
||||
|
||||
Sub LoadAnnotation(pElement As DocReceiverElement, ...)
|
||||
oAnnotation.Left = CSng(pElement.X) ' Direct INCHES assignment
|
||||
oAnnotation.Top = CSng(pElement.Y)
|
||||
End Sub
|
||||
```
|
||||
|
||||
**Multi-Receiver Support:**
|
||||
- **Receiver switcher:** Click receiver name in popup menu
|
||||
- **Current receiver:** Highlighted in toolbar (name + colored circle)
|
||||
- **Other receivers' fields:** Shown semi-transparent (30% opacity), not selectable
|
||||
- **Save:** Saves current receiver's fields, switches receiver, reloads all annotations
|
||||
|
||||
**Annotation Behavior:**
|
||||
- **New annotation:** User clicks "Add Signature" ? draws interactive annotation ? auto-sized to 1.77×1.96
|
||||
- **Existing annotation:** Loaded from database, locked size (can move but not resize)
|
||||
- **Styling:** Filled rectangle with centered text "SIGNATUR"
|
||||
- **Validation:** No resize, no text edit, no rotation
|
||||
|
||||
**Unsaved Changes Prompt:**
|
||||
- On form close: "There are unsaved changes. Save? Yes/No/Cancel"
|
||||
- Yes ? Saves ? Closes
|
||||
- No ? Discards ? Closes
|
||||
- Cancel ? Stays open
|
||||
|
||||
---
|
||||
|
||||
#### 5. **frmRueckruf.vb** - Delete Reason Dialog
|
||||
**Route Equivalent:** Inline confirmation in ReceiverUI
|
||||
|
||||
**Purpose:** Capture reason for envelope deletion/withdrawal.
|
||||
|
||||
**Fields:**
|
||||
- **Envelope ID** (display only)
|
||||
- **Envelope Title** (display only)
|
||||
- **Reason** (required text box)
|
||||
|
||||
**Buttons:**
|
||||
- **OK:** Confirms deletion with reason
|
||||
- **Cancel:** Cancels operation
|
||||
|
||||
**Global Variables:**
|
||||
```vb
|
||||
Public CurrentEnvelopID As Long
|
||||
Public CurrentEnvelopetitle As String
|
||||
Public Shared Continue_Reject As Boolean = False
|
||||
Public Shared Reject_reason As String = ""
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 6. **frm2Factor_Properties.vb** - 2FA Management
|
||||
**Route Equivalent:** `/admin/2fa/{email}` (future admin panel)
|
||||
|
||||
**Purpose:** View/manage 2FA settings for a receiver.
|
||||
|
||||
**Fields:**
|
||||
- **Email Address** (display only)
|
||||
- **TOTP Secret Key** (display only)
|
||||
- **Registration Deadline** (display only)
|
||||
|
||||
**Usage:** Admin tool to debug 2FA issues or reset TOTP secrets.
|
||||
|
||||
---
|
||||
|
||||
#### 7. **frmOrderFiles.vb** - PDF Merge Tool
|
||||
**Route Equivalent:** Inline in ReceiverUI (future)
|
||||
|
||||
**Purpose:** Select multiple PDFs and merge them into a single document.
|
||||
|
||||
**UI:**
|
||||
- **File list:** Selected PDFs
|
||||
- **Up/Down buttons:** Reorder files
|
||||
- **Add/Remove buttons:** Manage list
|
||||
|
||||
**Merge Logic:**
|
||||
- Uses GdPicture14 `MergeDocuments()`
|
||||
- Output: Single PDF in temp folder
|
||||
- Auto-loaded as envelope document
|
||||
|
||||
---
|
||||
|
||||
## Data Models (Controllers)
|
||||
|
||||
### EnvelopeListController
|
||||
**Purpose:** Load envelope lists for dashboard grids.
|
||||
|
||||
**Methods:**
|
||||
- `ListEnvelopes()` ? Active envelopes (not completed)
|
||||
- `ListCompleted()` ? Completed envelopes (signed/rejected/deleted)
|
||||
- `DeleteEnvelope(envelope, reason)` ? Soft delete with reason
|
||||
- `GetPieChart()` ? DevExpress ChartControl (not used)
|
||||
- `GetEnvelopeReceiverAddresses(userId)` ? List of previous receiver emails (for auto-complete)
|
||||
|
||||
---
|
||||
|
||||
### EnvelopeEditorController
|
||||
**Purpose:** Manage envelope CRUD and document/receiver operations.
|
||||
|
||||
**Key Methods:**
|
||||
|
||||
| Method | Purpose |
|
||||
|---|---|
|
||||
| `CreateDocument(filePath)` | Imports PDF, extracts pages/thumbnail, saves to DB |
|
||||
| `DeleteDocument(document)` | Removes document from envelope |
|
||||
| `SaveReceivers(envelope, receivers)` | Saves/updates receivers with access codes |
|
||||
| `DeleteReceiver(receiver)` | Removes receiver (checks if fields exist) |
|
||||
| `ElementsExist(receiverId)` | Checks if signature fields exist for receiver |
|
||||
| `SaveEnvelope()` | Persists envelope to database |
|
||||
| `SendEnvelope()` | Validates, queues emails, sends invitations |
|
||||
| `ValidateEnvelopeForSending(errors)` | Checks all receivers have signature fields |
|
||||
| `GetLastNameByEmailAdress(email)` | Returns previous name for email (auto-fill) |
|
||||
| `GetLastPhoneByEmailAdress(email)` | Returns previous phone for email (auto-fill) |
|
||||
| `DeleteEnvelopeFromDisk(envelope)` | Cleans up temp files |
|
||||
|
||||
**ActionService Methods:**
|
||||
- `ResendReceiver(envelope, receiver)` ? Resends invitation email
|
||||
- `ManuallySendAccessCode(envelope, receiver)` ? Sends access code email
|
||||
|
||||
---
|
||||
|
||||
### FieldEditorController
|
||||
**Purpose:** Manage signature field annotations (DocReceiverElement).
|
||||
|
||||
**Key Methods:**
|
||||
|
||||
| Method | Purpose |
|
||||
|---|---|
|
||||
| `LoadElements()` | Loads all signature fields from database |
|
||||
| `AddOrUpdateElement(annotation, orientation)` | Converts GdPicture annotation ? DocReceiverElement |
|
||||
| `SaveElements(receiverId)` | Persists signature fields for receiver |
|
||||
| `DeleteElement(element)` | Removes signature field |
|
||||
| `GetElement(annotation)` | Finds element by annotation tag |
|
||||
| `GetElementInfo(tag)` | Parses annotation tag (receiverId\|page\|guid) |
|
||||
|
||||
**Annotation Tag Format:**
|
||||
```
|
||||
"{receiverId}|{page}|{elementId}"
|
||||
Example: "42|1|-1" (receiver 42, page 1, unsaved)
|
||||
Example: "42|1|137" (receiver 42, page 1, element ID 137)
|
||||
```
|
||||
|
||||
**Element Coordinate Conversion:**
|
||||
```vb
|
||||
' Database stores INCHES directly (GdPicture native)
|
||||
Sub AddOrUpdateElement(annotation, orientation)
|
||||
element.X = annotation.Left ' INCHES
|
||||
element.Y = annotation.Top ' INCHES
|
||||
element.Width = annotation.Width ' INCHES
|
||||
element.Height = annotation.Height ' INCHES
|
||||
element.Page = currentPage
|
||||
End Sub
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration to ReceiverUI + API
|
||||
|
||||
### Mapping Table
|
||||
|
||||
| Form Feature | ReceiverUI Equivalent | Status |
|
||||
|---|---|---|
|
||||
| **frmMain** (Envelope list) | `/sender` (EnvelopeSenderPage.razor) | ? Exists |
|
||||
| Tab 0: Active Envelopes | `/sender` default view | ? Grid with filters |
|
||||
| Tab 1: Completed Envelopes | `/sender` with status filter | ? Same grid |
|
||||
| Status colors (Green/Orange/Red) | CSS classes `.status-signed`, `.status-pending`, etc. | ?? **Needs implementation** |
|
||||
| Master-detail grids (Receivers/History) | Expandable rows or modal dialogs | ?? **Needs implementation** |
|
||||
| Toolbar: Create Envelope | Button ? `/sender/envelope/new` | ?? **Needs implementation** |
|
||||
| Toolbar: Edit Envelope | Button ? `/sender/envelope/{id}` | ?? **Needs implementation** |
|
||||
| Toolbar: Delete Envelope | Button ? Shows delete reason modal | ?? **Needs implementation** |
|
||||
| Toolbar: Show Document | Downloads PDF | ?? **Needs implementation** |
|
||||
| Toolbar: Contact Receiver | `mailto:` link | ?? **Needs implementation** |
|
||||
| Toolbar: Resend Invitation | API call ? refresh grid | ?? **Needs implementation** |
|
||||
| Toolbar: Export Excel | Download XLSX | ?? **Needs implementation** |
|
||||
| Auto-refresh timer | SignalR or polling | ?? **Needs implementation** |
|
||||
| Grid layout persistence | LocalStorage | ?? **Needs implementation** |
|
||||
| **frmEnvelopeEditor** | `/sender/envelope/{id}` | ? **Not implemented** |
|
||||
| ? **frmEnvelopeMainData** popup | Inline form section or stepper | ? **Not implemented** |
|
||||
| Document upload (Drag & Drop) | Blazor InputFile with drag zone | ?? **Needs implementation** |
|
||||
| Receiver grid (auto-complete) | DevExpress Blazor Grid with lookup | ?? **Needs implementation** |
|
||||
| Merge PDFs (frmOrderFiles) | Client-side PDF.js or server-side | ?? **Needs implementation** |
|
||||
| **frmFieldEditor** | `/sender/envelope/{id}/fields` or inline | ? **Not implemented** |
|
||||
| GdPicture PDF viewer | PDF.js + canvas overlay (like EnvelopeReceiverPage) | ?? **Partial (receiver side only)** |
|
||||
| Signature field placement | Drag & drop signature boxes on canvas | ? **Not implemented** |
|
||||
| Receiver color coding | CSS variables + signature field borders | ? **Not implemented** |
|
||||
| Multi-receiver switcher | Dropdown or tabs | ? **Not implemented** |
|
||||
| Thumbnail navigator | PDF.js thumbnail sidebar (like receiver) | ?? **Exists for receiver** |
|
||||
| Save signature fields | API POST `/api/Envelope/{id}/Elements` | ? **Not implemented** |
|
||||
| **frm2Factor_Properties** | Admin panel `/admin/2fa/{email}` | ? **Not implemented** |
|
||||
| **frmRueckruf** (Delete reason) | Modal dialog in EnvelopeSenderPage | ?? **Needs implementation** |
|
||||
|
||||
---
|
||||
|
||||
## Critical Implementation Notes
|
||||
|
||||
### 1. **Coordinate System Consistency**
|
||||
**Database (Form App):** INCHES (GdPicture native)
|
||||
**ReceiverUI (PDF.js):** Pixels on canvas
|
||||
**Conversion Required:**
|
||||
```csharp
|
||||
// Sender side (placing fields):
|
||||
float xInches = canvasPixelX / (canvasWidth / pageWidthInches);
|
||||
float yInches = canvasPixelY / (canvasHeight / pageHeightInches);
|
||||
|
||||
// Receiver side (displaying fields):
|
||||
float canvasX = (xInches / pageWidthInches) * canvasWidth;
|
||||
float canvasY = (yInches / pageHeightInches) * canvasHeight;
|
||||
```
|
||||
|
||||
**A4 Page Dimensions:**
|
||||
- Width: 8.27" = 595pt
|
||||
- Height: 11.69" = 842pt
|
||||
|
||||
---
|
||||
|
||||
### 2. **Status Color System**
|
||||
Form app uses **DevExpress CustomDrawCell** event for row coloring. ReceiverUI should use:
|
||||
|
||||
```css
|
||||
/* Envelope status colors */
|
||||
.envelope-row.status-partly-signed { background-color: #81C784; } /* GREEN_300 */
|
||||
.envelope-row.status-queued,
|
||||
.envelope-row.status-sent { background-color: #FFB74D; } /* ORANGE_300 */
|
||||
.envelope-row.status-completed { background-color: #81C784; } /* GREEN_300 */
|
||||
.envelope-row.status-deleted,
|
||||
.envelope-row.status-rejected { background-color: #E57373; } /* RED_300 */
|
||||
|
||||
/* Receiver status colors */
|
||||
.receiver-row.signed { background-color: #81C784; }
|
||||
.receiver-row.unsigned { background-color: #E57373; }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. **Master-Detail Grid Pattern**
|
||||
Form app uses **nested GridViews** (ViewReceivers, ViewHistory). ReceiverUI options:
|
||||
|
||||
**Option A:** DevExpress Blazor Grid with master-detail template
|
||||
```razor
|
||||
<DxGrid Data="@Envelopes">
|
||||
<DxGridDataColumn FieldName="Title" />
|
||||
<DxGridDetailRowTemplate>
|
||||
<DxGrid Data="@context.EnvelopeReceivers">
|
||||
<DxGridDataColumn FieldName="Name" />
|
||||
<DxGridDataColumn FieldName="Status" />
|
||||
</DxGrid>
|
||||
</DxGridDetailRowTemplate>
|
||||
</DxGrid>
|
||||
```
|
||||
|
||||
**Option B:** Click row ? show modal with receivers/history
|
||||
```razor
|
||||
<DxGrid @ref="grid" Data="@Envelopes" RowClick="OnRowClick">
|
||||
...
|
||||
</DxGrid>
|
||||
|
||||
<DxPopup @bind-Visible="showDetailPopup">
|
||||
<DxGrid Data="@selectedEnvelope.EnvelopeReceivers">
|
||||
...
|
||||
</DxGrid>
|
||||
</DxPopup>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. **Signature Field Editor Architecture**
|
||||
|
||||
**Form App:**
|
||||
- GdPicture14 native annotations
|
||||
- Fixed size (1.77×1.96 inches)
|
||||
- Color-coded per receiver
|
||||
- Draggable, non-resizable
|
||||
|
||||
**ReceiverUI Equivalent:**
|
||||
- PDF.js canvas + HTML overlay (like receiver signature buttons)
|
||||
- `<div class="signature-field-placeholder">` positioned absolutely
|
||||
- Drag & drop with JS (`onmousedown`, `onmousemove`, `onmouseup`)
|
||||
- Snap to grid (optional)
|
||||
- Store coordinates in INCHES (convert from pixels)
|
||||
|
||||
**Example HTML Overlay:**
|
||||
```html
|
||||
<div class="pdf-signature-layer">
|
||||
<div class="signature-field"
|
||||
data-receiver-id="42"
|
||||
data-page="1"
|
||||
style="position: absolute; left: 200px; top: 300px; width: 177px; height: 196px; background: rgba(255,0,0,0.3); border: 2px dashed red;">
|
||||
Receiver: John Doe
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**JS Dragging Logic:**
|
||||
```javascript
|
||||
function makeSignatureFieldDraggable(element) {
|
||||
let offsetX, offsetY;
|
||||
element.onmousedown = (e) => {
|
||||
offsetX = e.clientX - element.offsetLeft;
|
||||
offsetY = e.clientY - element.offsetTop;
|
||||
document.onmousemove = (e) => {
|
||||
element.style.left = (e.clientX - offsetX) + 'px';
|
||||
element.style.top = (e.clientY - offsetY) + 'px';
|
||||
};
|
||||
document.onmouseup = () => {
|
||||
document.onmousemove = null;
|
||||
saveFieldPosition(element); // Convert px ? inches ? API
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. **Auto-Complete Receiver Email**
|
||||
Form app uses **DevExpress ComboBox** with `AllReceiverEmails` list. ReceiverUI options:
|
||||
|
||||
**Option A:** DevExpress Blazor TagBox with remote data
|
||||
```razor
|
||||
<DxTagBox Data="@previousEmails"
|
||||
@bind-Values="@selectedEmails"
|
||||
AllowCustomTags="true"
|
||||
ClearButtonDisplayMode="Auto">
|
||||
</DxTagBox>
|
||||
```
|
||||
|
||||
**Option B:** HTML5 datalist
|
||||
```razor
|
||||
<input list="receiver-emails" @bind="newReceiverEmail" />
|
||||
<datalist id="receiver-emails">
|
||||
@foreach (var email in previousEmails) {
|
||||
<option value="@email" />
|
||||
}
|
||||
</datalist>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. **Drag & Drop File Upload**
|
||||
Form app uses **WinForms DragDrop** events. ReceiverUI equivalent:
|
||||
|
||||
```razor
|
||||
<div class="file-drop-zone"
|
||||
@ondragover="HandleDragOver"
|
||||
@ondragover:preventDefault
|
||||
@ondrop="HandleDrop"
|
||||
@ondrop:preventDefault>
|
||||
<p>Drop PDF here or click to browse</p>
|
||||
<InputFile OnChange="HandleFileSelected" accept=".pdf" />
|
||||
</div>
|
||||
|
||||
@code {
|
||||
async Task HandleDrop(DragEventArgs e) {
|
||||
var files = e.DataTransfer.Files;
|
||||
if (files.Length > 1) {
|
||||
errorMessage = "Only one file allowed";
|
||||
return;
|
||||
}
|
||||
await UploadDocument(files[0]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7. **PDF Merge (frmOrderFiles)**
|
||||
Form app uses **GdPicture14 MergeDocuments**. ReceiverUI options:
|
||||
|
||||
**Option A:** Server-side merge (iText7 or PDFSharp)
|
||||
```csharp
|
||||
[HttpPost("api/Document/Merge")]
|
||||
public async Task<IActionResult> MergePDFs([FromForm] List<IFormFile> files) {
|
||||
using var outputStream = new MemoryStream();
|
||||
using var pdfDocument = new PdfDocument(new PdfWriter(outputStream));
|
||||
|
||||
foreach (var file in files) {
|
||||
using var inputStream = file.OpenReadStream();
|
||||
using var sourcePdf = new PdfDocument(new PdfReader(inputStream));
|
||||
sourcePdf.CopyPagesTo(1, sourcePdf.GetNumberOfPages(), pdfDocument);
|
||||
}
|
||||
|
||||
pdfDocument.Close();
|
||||
return File(outputStream.ToArray(), "application/pdf", "merged.pdf");
|
||||
}
|
||||
```
|
||||
|
||||
**Option B:** Client-side merge (PDF-lib.js in Blazor JS interop)
|
||||
```javascript
|
||||
async function mergePDFs(fileDataUrls) {
|
||||
const pdfDoc = await PDFDocument.create();
|
||||
for (const dataUrl of fileDataUrls) {
|
||||
const existingPdfBytes = await fetch(dataUrl).then(res => res.arrayBuffer());
|
||||
const pdf = await PDFDocument.load(existingPdfBytes);
|
||||
const copiedPages = await pdfDoc.copyPages(pdf, pdf.getPageIndices());
|
||||
copiedPages.forEach(page => pdfDoc.addPage(page));
|
||||
}
|
||||
const pdfBytes = await pdfDoc.save();
|
||||
return pdfBytes;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Form App Workflow Summary
|
||||
|
||||
### New Envelope Workflow (Sender)
|
||||
```
|
||||
1. Click "Create Envelope" in frmMain
|
||||
?
|
||||
2. frmEnvelopeMainData popup opens
|
||||
- Enter Title (required)
|
||||
- Select Envelope Type (loads defaults)
|
||||
- Configure settings (Access Code, 2FA, Language, etc.)
|
||||
- Click OK
|
||||
?
|
||||
3. frmEnvelopeEditor opens
|
||||
- Add PDF document (drag & drop or browse)
|
||||
- Add receivers (email auto-complete, access code auto-gen)
|
||||
- Click "Edit Fields"
|
||||
?
|
||||
4. frmFieldEditor opens
|
||||
- Select receiver from dropdown (colored circles)
|
||||
- Click "Add Signature" ? draw box on PDF
|
||||
- Drag to position (1.77×1.96 inches, fixed size)
|
||||
- Repeat for each receiver
|
||||
- Click "Save"
|
||||
?
|
||||
5. Back to frmEnvelopeEditor
|
||||
- Click "Send Envelope"
|
||||
- Validation:
|
||||
* Title exists
|
||||
* Message exists
|
||||
* Document exists
|
||||
* Receivers exist
|
||||
* All receivers have signature fields
|
||||
- Confirmation: "Do you want to start the signature process now?"
|
||||
- Click Yes ? Envelope status = EnvelopeSent
|
||||
?
|
||||
6. Emails sent to receivers with invitation links
|
||||
?
|
||||
7. frmMain refreshes, envelope moves to "Sent" (orange color)
|
||||
```
|
||||
|
||||
### Receiver Signing Workflow (External)
|
||||
```
|
||||
1. Receiver clicks link in email
|
||||
?
|
||||
2. Web browser opens (EnvelopeGenerator.Web or ReceiverUI)
|
||||
- If UseAccessCode=true: Enter 6-digit code
|
||||
- If TFA=true: Enter SMS code
|
||||
?
|
||||
3. PDF viewer loads with signature fields highlighted
|
||||
- Click "Sign" button on each field
|
||||
- Draw/type/upload signature
|
||||
- Enter name, position, place
|
||||
?
|
||||
4. Submit ? Backend stamps signature on PDF
|
||||
?
|
||||
5. Envelope status updates:
|
||||
- First signature ? EnvelopePartlySigned (green)
|
||||
- Last signature ? EnvelopeCompletelySigned (green)
|
||||
?
|
||||
6. Final emails sent (if configured):
|
||||
- To creator: "All receivers signed"
|
||||
- To receivers: "Envelope completed, download PDF"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Missing Features in ReceiverUI (To Implement)
|
||||
|
||||
### High Priority
|
||||
1. ? **Envelope list grid** (`/sender`) with status colors
|
||||
2. ? **Master-detail grids** (receivers/history)
|
||||
3. ? **Create/Edit envelope form** (`/sender/envelope/{id}`)
|
||||
4. ? **Envelope settings popup/stepper** (title, type, options)
|
||||
5. ? **Document upload** (drag & drop, single PDF)
|
||||
6. ? **Receiver management** (add/edit/delete with auto-complete)
|
||||
7. ? **Signature field editor** (PDF.js + draggable overlays)
|
||||
8. ? **Send envelope** (validation + API call)
|
||||
|
||||
### Medium Priority
|
||||
9. ? **Delete envelope** (with reason modal)
|
||||
10. ? **Resend invitation** (per receiver)
|
||||
11. ? **Show document** (PDF preview)
|
||||
12. ? **Contact receiver** (mailto link)
|
||||
13. ? **Export to Excel** (grid data)
|
||||
14. ? **PDF merge tool** (multi-file select + merge)
|
||||
15. ? **Grid layout persistence** (LocalStorage)
|
||||
|
||||
### Low Priority
|
||||
16. ? **2FA management** (admin panel)
|
||||
17. ? **Reports tab** (statistics, admin only)
|
||||
18. ? **Auto-refresh** (SignalR or polling)
|
||||
19. ? **Ghost mode** (impersonate user, admin only)
|
||||
20. ? **Log file export** (debug tool)
|
||||
|
||||
---
|
||||
|
||||
## Data Flow Diagram
|
||||
|
||||
```
|
||||
????????????????????????
|
||||
? frmMain ? ? Envelope list (Active/Completed tabs)
|
||||
? (Dashboard) ? ? Status colors (Green/Orange/Red)
|
||||
???????????????????????? ? Master-detail grids (Receivers/History)
|
||||
? ? Toolbar actions (Create/Edit/Delete/Send)
|
||||
? Click "Create"
|
||||
?
|
||||
????????????????????????
|
||||
? frmEnvelopeMainData ? ? Popup: Title, Type, Settings
|
||||
? (Settings Popup) ? ? Dropdowns: Language, Certification, Final Emails
|
||||
???????????????????????? ? Checkboxes: Access Code, 2FA, Reminders
|
||||
? Click OK
|
||||
?
|
||||
????????????????????????
|
||||
? frmEnvelopeEditor ? ? Document upload (drag & drop)
|
||||
? (Main Editor) ? ? Receiver grid (email auto-complete)
|
||||
???????????????????????? ? Merge PDFs button
|
||||
? Click "Edit Fields"
|
||||
?
|
||||
????????????????????????
|
||||
? frmFieldEditor ? ? GdPicture PDF viewer
|
||||
? (Signature Placer) ? ? Receiver selector (colored circles)
|
||||
???????????????????????? ? Draggable signature boxes (1.77×1.96")
|
||||
? Click "Save"
|
||||
?
|
||||
????????????????????????
|
||||
? Database ? ? DocReceiverElement (X, Y, Width, Height in INCHES)
|
||||
? (TBSIG_ELEMENT) ? ? EnvelopeReceiver (Name, Email, Access Code, Phone)
|
||||
???????????????????????? ? Envelope (Title, Status, Settings)
|
||||
? Click "Send Envelope"
|
||||
?
|
||||
????????????????????????
|
||||
? Email Service ? ? Send invitation emails to receivers
|
||||
? ? ? Template: Link + Access Code (if enabled)
|
||||
????????????????????????
|
||||
?
|
||||
?
|
||||
????????????????????????
|
||||
? Receiver Web Page ? ? PDF.js viewer with signature buttons
|
||||
? (EnvelopeReceiverPage)? ? Click button ? Signature popup (draw/type/image)
|
||||
???????????????????????? ? Submit ? API stamps signature on PDF
|
||||
?
|
||||
?
|
||||
????????????????????????
|
||||
? Database Update ? ? EnvelopeHistory (Signed, Timestamp)
|
||||
? ? ? Envelope Status ? PartlySigned / CompletelySigned
|
||||
????????????????????????
|
||||
? All signed?
|
||||
?
|
||||
????????????????????????
|
||||
? Final Email Service ? ? Send "Completed" email to creator/receivers
|
||||
? ? ? Attach signed PDF
|
||||
????????????????????????
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaways for Migration
|
||||
|
||||
1. **Tab-based layout** ? Single grid with status filter dropdown
|
||||
2. **Status colors** ? CSS classes or inline styles
|
||||
3. **Master-detail grids** ? Expandable rows or modal dialogs
|
||||
4. **Popup settings form** ? Inline form or stepper UI
|
||||
5. **GdPicture PDF viewer** ? PDF.js with canvas overlay
|
||||
6. **Signature field dragging** ? HTML5 drag & drop + absolute positioning
|
||||
7. **Coordinate system** ? **ALWAYS INCHES** in database, convert to/from pixels for UI
|
||||
8. **Receiver colors** ? CSS variables or inline styles
|
||||
9. **Auto-complete emails** ? DevExpress TagBox or HTML5 datalist
|
||||
10. **PDF merge** ? Server-side (iText7) or client-side (PDF-lib.js)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** Session 20 (Form Application Analysis)
|
||||
Reference in New Issue
Block a user