diff --git a/AGENTS.md b/AGENTS.md index 8f57e84a..396e2211 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,19 +4,118 @@ - **`COPILOT_CONTEXT.md`** - Architecture, coordinate systems, migration status - **`FORM_APPLICATION_CONTEXT.md`** - Legacy VB.NET features to migrate +--- + +## Documentation Catalog + +This section explains every markdown file in the repo: what it contains, why it exists, and when you need it. Read this before deciding which file to open. + +### Core Architecture Docs (Active — Always Relevant) + +#### `AGENTS.md` â†� you are here +**What:** Authoritative agent/copilot onboarding guide. Covers project structure, route table, render mode rules, coordinate system, API gaps, and common mistakes. +**Why it exists:** Single source of truth for agents so they don't re-derive architecture from code on every session. +**When you need it:** Always. Read first on every session. +**Maintenance:** Update whenever project structure, routes, render modes, or naming conventions change. + +#### `COPILOT_CONTEXT.md` +**What:** Deep-dive architecture reference. Covers the full Blazor Auto hybrid setup, authentication flows (JWT + cookies, per-envelope receiver tokens), service registration patterns, coordinate system proof, and an explicit "prefer Server/Server.Client over old WebUI/ReceiverUI" rule. +**Why it exists:** Prevents agents from re-deriving or misinterpreting the hybrid SSR+WASM architecture. Also documents coordinate system evidence to prevent regressions (inches vs. points vs. pixels). +**When you need it:** +- Implementing any new page or service +- Debugging auth/cookie issues +- Any coordinate conversion question +- Unsure which project a new file should go in +**Maintenance:** Update when render mode assignments change, new auth schemes are added, or the coordinate system is touched. + +#### `FORM_APPLICATION_CONTEXT.md` +**What:** Comprehensive reverse-engineering of the legacy VB.NET WinForms app (`EnvelopeGenerator.Form`). Documents every form (frmMain, frmEnvelopeEditor, frmFieldEditor, etc.), their UI layout, toolbar actions, data models, coordinate system, and a feature-by-feature migration mapping table to `EnvelopeGenerator.Server`. +**Why it exists:** The WinForms app is the functional specification for the sender-side web UI. It documents the full intended workflow that is being migrated to Blazor — especially the envelope creation, signature field placement, and dashboard features that are not yet implemented. +**When you need it:** +- Implementing any sender-side feature (`/sender`, `/sender/editor`, `/sender/envelope/{id}`) +- Understanding what a specific toolbar button or form should do +- Designing API endpoints for sender workflow +- Checking coordinate system behavior (INCHES proof is here) +**Maintenance:** Update the mapping table as features are implemented (change `â�Œ Not implemented` → `✅ Exists`). Do not rename `ReceiverUI` back — it was the old project name; current target is `EnvelopeGenerator.Server`. + +#### `RECEIVER_PDF_VIEWER_CONTEXT.md` +**What:** Detailed technical reference for the receiver-side PDF viewer (`EnvelopeReceiverPage.razor`). Documents the PDF.js integration, signature button rendering, JS interop API (`window.pdfViewer`), signature capture flow, HiDPI/zoom/thumbnail config, and the full component lifecycle. +**Why it exists:** The receiver PDF viewer is the most complex component in the codebase. This doc prevents agents from misunderstanding the JS↔Blazor boundary, re-implementing already-solved problems (HiDPI, zoom, signature caching), or breaking the signing flow. +**When you need it:** +- Working on `EnvelopeReceiverPage.razor` or `pdf-viewer.js` +- Adding new signature field rendering logic +- Debugging signature rendering, zoom, or thumbnail issues +- Implementing sender-side PDF.js overlay (signature field placement) — the receiver side is the reference implementation +**Maintenance:** Update when `pdf-viewer.js` API changes, new JS interop functions are added, or the signing flow is modified. + +--- + +### Ticket / Feature Plans (Active Work Items) + +#### `EnvelopeGenerator.Server/SF-74-PLAN.md` +**What:** Implementation plan for SF-74 ticket — Theme selection, Dark Mode, Grid Layout Persistence, signFLOW logo, and customer logo area on the sender dashboard. Includes the original ticket requirements, component breakdown, and implementation steps. +**Why it exists:** Captures the agreed scope and implementation decisions for SF-74 so work can be resumed or reviewed without re-reading the ticket system. +**When you need it:** +- Resuming work on theme, dark mode, or grid persistence features +- Checking what was agreed for logo positioning and size +- Verifying which features of SF-74 are complete vs. pending +**Maintenance:** Mark items as complete as they are implemented. Archive when the ticket is closed. + +--- + +### Deployment Docs + +#### `EnvelopeGenerator.Server/EnvelopeGenerator.Server/README.md` +**What:** IIS publish and deployment guide for `EnvelopeGenerator.Server`. Covers why self-contained publish is required (WASM assembly version strictness), the exact `dotnet publish` command, IIS Application Pool settings (`No Managed Code`), directory structure after publish, and common deployment errors. +**Why it exists:** Blazor Auto (Server + WASM hybrid) has non-obvious deployment requirements that differ from a standard ASP.NET Core app. Forgetting self-contained publish or using the wrong app pool will break WASM loading in production. +**When you need it:** +- Deploying to IIS for the first time +- Troubleshooting 500 errors on production after deploy +- Setting up a new deployment environment +**Maintenance:** Update if the publish target, IIS config, or runtime version changes. + +--- + +### Fix Reports (Historical — Read-Only) + +These files document completed bug fixes. They exist as audit trails and as references if a similar issue resurfaces. Do not modify them. + +#### `fix-report-label-read-and-confirmed.md` +**What:** Documents the fix for an incorrect label in the Signature Certificate report (`Signierungszertifikat`). For "Read and Sign" envelope type (`EnvelopeTypeId = 2`), the history event showed "Document signed" instead of "Read and confirmed" / "Gelesen und bestätigt". +**Branch:** `fix/report-label-read-and-confirmed` — **COMPLETED** +**When you need it:** If a similar report label regression appears, or when adding new envelope type-specific label logic to the certificate report. + +#### `fix-signature-field-formatting.md` +**What:** Documents a signature stamp layout fix triggered by WISAG customer feedback (email 3/7/2026). The finalized PDF's signature stamp had incorrect spacing: certificate hash too close to name, position text wrapping, no spacing before date. Fix was applied in the GdPicture14 PDF burning pipeline — not in the Blazor UI. +**When you need it:** If signature stamp formatting regresses, or when modifying the PDF stamping/burning pipeline in the API or infrastructure layer. + +--- + +### Service Migration Docs + +#### `EnvelopeGenerator.Service/MIGRATION_PLAN.md` +**What:** Migration plan (v3) for porting `EnvelopeGenerator.Service_legacy` (VB.NET Windows Service) to `EnvelopeGenerator.Service` (C# Worker Service, .NET Framework 4.6.2). Documents connection string handling, job scheduling (Quartz → IHostedService), and deep analysis of legacy code. +**Why it exists:** The Windows Service handles background jobs (email dispatch, envelope finalization). This plan ensures the port is complete and no job logic is silently dropped. +**When you need it:** +- Modifying background jobs (email sending, PDF finalization, access code dispatch) +- Debugging service startup or job execution issues +- Checking if a specific legacy VB.NET job has been ported + +--- + ## Active Architecture (Post-Migration) **Frontend:** Blazor Auto (Server+WASM hybrid) -- **WebUI** (Server): `@rendermode InteractiveServer` - PDF viewers requiring DevExpress backend -- **WebUI.Client** (WASM): `@rendermode InteractiveWebAssembly` - Login, dashboards, business logic +- **EnvelopeGenerator.Server** (Server): `@rendermode InteractiveServer` - PDF viewers requiring DevExpress backend +- **EnvelopeGenerator.Server.Client** (WASM): `@rendermode InteractiveWebAssembly` - Login, dashboards, business logic **Backend:** EnvelopeGenerator.API (ASP.NET Core 8.0) -**Proxy:** YARP in WebUI routes `/api/*` → `localhost:8088` (API) +**Proxy:** YARP in EnvelopeGenerator.Server routes `/api/*` → `localhost:8088` (API) ### Deprecated Projects - DO NOT USE -- `EnvelopeGenerator.ReceiverUI` - Pure WASM (migrated to WebUI) -- `EnvelopeGenerator.Web` - Razor Pages (replaced by WebUI) +- `EnvelopeGenerator.ReceiverUI` - Pure WASM (migrated to Server) +- `EnvelopeGenerator.Web` - Razor Pages (replaced by Server) - **VB.NET projects** (`Form`, `Service`, `BBTests`) - Legacy, read-only for reference ## Development Commands @@ -28,11 +127,11 @@ cd EnvelopeGenerator.API dotnet run # Terminal 2 - Blazor Frontend -cd EnvelopeGenerator.WebUI\EnvelopeGenerator.WebUI +cd EnvelopeGenerator.Server\EnvelopeGenerator.Server dotnet run ``` -**Critical:** Both must run simultaneously. WebUI proxy forwards `/api/*` to API. +**Critical:** Both must run simultaneously. EnvelopeGenerator.Server proxy forwards `/api/*` to API. ### Build ```powershell @@ -46,23 +145,25 @@ EnvelopeGenerator.Domain/ # Entities (Envelope, Receiver, Document, etc EnvelopeGenerator.Application/ # MediatR CQRS (Commands, Queries, Handlers) EnvelopeGenerator.Infrastructure/ # EF Core, SQL executors, repositories EnvelopeGenerator.API/ # Controllers, endpoints -EnvelopeGenerator.WebUI/ # Server-side Blazor components - ├─ Components/Pages/ # @rendermode InteractiveServer -EnvelopeGenerator.WebUI.Client/ # Client-side WASM components - ├─ Pages/ # @rendermode InteractiveWebAssembly - ├─ Services/ # HTTP API clients - ├─ Models/ # DTOs +EnvelopeGenerator.Server/ + EnvelopeGenerator.Server/ # Server-side Blazor components + ├─ Components/Pages/ # @rendermode InteractiveServer + EnvelopeGenerator.Server.Client/ # Client-side WASM components + ├─ Pages/ # @rendermode InteractiveWebAssembly + ├─ Services/ # HTTP API clients + ├─ Models/ # DTOs ``` ## Route Structure (Critical) | Route | File Location | Render Mode | Purpose | |-------|--------------|-------------|---------| -| `/` | `WebUI.Client/Pages/Index.razor` | WASM | Landing page | -| `/sender/login` | `WebUI.Client/Pages/LoginSenderPage.razor` | WASM | Sender auth | -| `/sender` | `WebUI.Client/Pages/EnvelopeSenderPage.razor` | WASM | Sender dashboard | -| `/envelope/login/{key}` | `WebUI.Client/Pages/LoginReceiverPage.razor` | WASM | Receiver auth | -| `/envelope/{key}` | `WebUI/Components/Pages/EnvelopeReceiverPage.razor` | **Server** | PDF viewer + signing | +| `/` | `Server.Client/Pages/Index.razor` | WASM | Landing page | +| `/sender/login` | `Server.Client/Pages/LoginSenderPage.razor` | WASM | Sender auth | +| `/sender` | `Server/Components/Pages/EnvelopeSenderPage.razor` | **Server** | Sender dashboard | +| `/sender/editor` | `Server/Components/Pages/EnvelopeSenderEditorPage.razor` | **Server** | Envelope editor + PDF viewer | +| `/envelope/login/{key}` | `Server.Client/Pages/LoginReceiverPage.razor` | WASM | Receiver auth | +| `/envelope/{key}` | `Server/Components/Pages/EnvelopeReceiverPage.razor` | **Server** | PDF viewer + signing | **Rule:** PDF viewers MUST use `@rendermode InteractiveServer` (DevExpress backend requirement). Everything else uses WASM. @@ -110,7 +211,7 @@ See `FORM_APPLICATION_CONTEXT.md` for detailed workflow requirements. ## Status Color Coding -Form app uses DevExpress `CustomDrawCell`. WebUI needs CSS: +Form app uses DevExpress `CustomDrawCell`. EnvelopeGenerator.Server needs CSS: ```css .envelope-row.status-partly-signed { background-color: #81C784; } /* GREEN_300 */ @@ -123,10 +224,10 @@ Form app uses DevExpress `CustomDrawCell`. WebUI needs CSS: ## Configuration -### YARP Proxy (`WebUI/yarp.json`) +### YARP Proxy (`EnvelopeGenerator.Server/yarp.json`) Routes `/api/*`, `/swagger/*`, `/openapi/*`, `/scalar/*` → `https://localhost:8088` -### PDF.js Settings (`WebUI/wwwroot/appsettings.json`) +### PDF.js Settings (`EnvelopeGenerator.Server/wwwroot/appsettings.json`) ```json { "PdfViewerOptions": { @@ -177,7 +278,7 @@ Routes `/api/*`, `/swagger/*`, `/openapi/*`, `/scalar/*` → `https://localhost: Manual testing workflow: 1. Start API (`dotnet run` in `EnvelopeGenerator.API`) -2. Start WebUI (`dotnet run` in `EnvelopeGenerator.WebUI\EnvelopeGenerator.WebUI`) +2. Start EnvelopeGenerator.Server (`dotnet run` in `EnvelopeGenerator.Server\EnvelopeGenerator.Server`) 3. Navigate to `https://localhost:5131` (or check console output for port) 4. Test sender login at `/sender/login` 5. Test receiver flow at `/envelope/login/{envelopeKey}` @@ -245,7 +346,7 @@ Each envelope maintains independent authentication state. **CDN:** - PDF.js 3.11.174: `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js` -**NuGet (WebUI.Client):** +**NuGet (Server.Client):** - `DevExpress.Blazor.*` 25.2.3 - `SkiaSharp.*` 3.119.1 (WASM rendering) diff --git a/EnvelopeGenerator.Service/MIGRATION_PLAN.md b/EnvelopeGenerator.Service/MIGRATION_PLAN.md index 2cd4c380..cc78fca9 100644 --- a/EnvelopeGenerator.Service/MIGRATION_PLAN.md +++ b/EnvelopeGenerator.Service/MIGRATION_PLAN.md @@ -1,5 +1,5 @@ -# Migration Plan: EnvelopeGenerator.Service_legacy ? EnvelopeGenerator.Service -**Revision v3** — Full deep analysis complete +# Migration Plan: EnvelopeGenerator.Service_legacy ? EnvelopeGenerator.Service +**Revision v3** — Full deep analysis complete ## Overview @@ -11,25 +11,25 @@ C# Worker Service (`EnvelopeGenerator.Service`) targeting **.NET Framework 4.6.2 ## Deep Analysis Findings (vs. v1/v2) -### Finding 1 — Connection String: Plain Text, No Encryption Required +### Finding 1 — Connection String: Plain Text, No Encryption Required `FinalizeDocumentJob` and `APIEnvelopeJob` call `MSSQLServer.DecryptConnectionString()` on the `JobDataMap[Value.DATABASE]` value. However, `MSSQLServer.DecryptConnectionString()` is a pass-through -for plain-text strings — no wrapping/encryption step is needed. +for plain-text strings — no wrapping/encryption step is needed. **Resolution**: The connection string is read from `IConfiguration` via the standard `ConnectionStrings:Default` key (same key as `appsettings.Database.json` in `EnvelopeGenerator.Web`). It is passed **as-is** to both the Worker-level `MSSQLServer` and the `JobDataMap`. No `EncryptConnectionString()` call is made anywhere in the new service. -### Finding 2 — Dual TempFiles Architecture +### Finding 2 — Dual TempFiles Architecture There are **two independent** `TempFiles` classes: -- `EnvelopeGenerator.CommonServices.TempFiles` — used **inside each job** via `New TempFiles(LogConfig)`. +- `EnvelopeGenerator.CommonServices.TempFiles` — used **inside each job** via `New TempFiles(LogConfig)`. This is called on every job execution and manages the job's own temp lifecycle. It expects `LogConfig`. **We do not touch this.** -- `EnvelopeGenerator.Service_legacy.TempFiles` — used at the **service/host level** (startup cleanup, +- `EnvelopeGenerator.Service_legacy.TempFiles` — used at the **service/host level** (startup cleanup, shutdown cleanup). This is the one we rewrite in C# in the Service project using `ILogger`. -### Finding 3 — LogConfig is a Hard Dependency of All Jobs +### Finding 3 — LogConfig is a Hard Dependency of All Jobs `FinalizeDocumentJob.Execute()` and `APIEnvelopeJob.Execute()` both do: ```vb LogConfig = pContext.MergedJobDataMap.Item(Value.LOGCONFIG) @@ -45,17 +45,17 @@ build a `LogConfig` from `ServiceConfig` values: - `Debug` = `ServiceConfig.Debug` - Application name = `"EnvelopeGenerator.Service"` -### Finding 4 — ProjectInstaller is Obsolete +### Finding 4 — ProjectInstaller is Obsolete `ProjectInstaller.vb` was the old `installutil.exe` mechanism for Windows Service registration. With `AddWindowsService()` + `sc create` / PowerShell `New-Service`, this is **completely replaced**. No equivalent is needed in the new project. -### Finding 5 — GDPicture License SQL +### Finding 5 — GDPicture License SQL The legacy service queries: `SELECT LICENSE FROM TBDD_3RD_PARTY_MODULES WHERE NAME = 'GDPICTURE' and ACTIVE = 1` This must be replicated exactly in the Worker startup sequence. If the result is null/empty, startup fails with a descriptive exception (matching legacy behavior). -### Finding 6 — Quartz Version Mismatch +### Finding 6 — Quartz Version Mismatch `CommonServices` uses `Quartz 3.8.0`. `Service_legacy` uses `Quartz 3.15.0`. The new `EnvelopeGenerator.Service` must use **Quartz 3.8.0** to match `CommonServices` (same AppDomain, same version must be loaded). The legacy version bump in `Service_legacy` was inconsistent. @@ -67,7 +67,7 @@ same version must be loaded). The legacy version bump in `Service_legacy` was in - Add **NuGet packages**: - `NLog` (5.x, matching CommonServices' `NLog.5.0.5`) - `NLog.Extensions.Logging` (latest net462-compatible) - - `Quartz` (**3.8.0** — must match CommonServices) + - `Quartz` (**3.8.0** — must match CommonServices) - `Microsoft.Extensions.Hosting.WindowsServices` (for `AddWindowsService()`) - Add **project reference** to `EnvelopeGenerator.CommonServices` (vbproj) - Add **project reference** to `EnvelopeGenerator.Domain` (csproj) @@ -86,7 +86,7 @@ public class ServiceConfig } ``` -Connection string is read via the standard `ConnectionStrings:Default` key — consistent with +Connection string is read via the standard `ConnectionStrings:Default` key — consistent with `appsettings.Database.json` used by `EnvelopeGenerator.Web`: `appsettings.json`: @@ -136,7 +136,7 @@ builder.Logging.AddNLog("nlog.config"); ## 4. LogConfigFactory (`LogConfigFactory.cs`) -New static helper — bridges `ServiceConfig` ? `LogConfig` (required by CommonServices jobs): +New static helper — bridges `ServiceConfig` ? `LogConfig` (required by CommonServices jobs): ```csharp internal static class LogConfigFactory @@ -159,7 +159,7 @@ This `LogConfig` instance is what gets placed into every `JobDataMap[Value.LOGCO ## 5. Quartz LogProvider (`QuartzLogProvider.cs`) -C# rewrite of `LogProvider.vb` — bridges Quartz `ILogProvider` ? `ILogger`: +C# rewrite of `LogProvider.vb` — bridges Quartz `ILogProvider` ? `ILogger`: ```csharp internal class QuartzLogProvider : ILogProvider @@ -173,13 +173,13 @@ internal class QuartzLogProvider : ILogProvider --- -## 6. TempFiles (`TempFiles.cs`) — Service-level only +## 6. TempFiles (`TempFiles.cs`) — Service-level only Service-level rewrite of `Service_legacy/TempFiles.vb` using `ILogger`: - `Create()` ? create `%TEMP%\EnvelopeGenerator`, or clean existing files - `CleanUp()` ? delete the directory on service stop -> **Does NOT replace** `CommonServices.TempFiles` — that one continues to be used +> **Does NOT replace** `CommonServices.TempFiles` — that one continues to be used > inside each job via `LogConfig`. --- @@ -231,7 +231,7 @@ ExecuteAsync: 1. Read ServiceConfig from IOptions 2. Validate ConnectionString ? throw if empty 3. Build LogConfig via LogConfigFactory - 4. Connect to DB (plain connection string — Worker-level only) + 4. Connect to DB (plain connection string — Worker-level only) 5. Query: SELECT LICENSE FROM TBDD_3RD_PARTY_MODULES WHERE NAME='GDPICTURE' AND ACTIVE=1 ? throw if null/empty (matches legacy behavior) 6. TempFiles.Create() diff --git a/FORM_APPLICATION_CONTEXT.md b/FORM_APPLICATION_CONTEXT.md index 948290e6..d3aebcbb 100644 --- a/FORM_APPLICATION_CONTEXT.md +++ b/FORM_APPLICATION_CONTEXT.md @@ -1,7 +1,7 @@ -# EnvelopeGenerator.Form – VB.NET Desktop Application Context +# 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. +**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 EnvelopeGenerator.Server + API** architecture. **Primary Libraries:** DevExpress XtraGrid/XtraEditors, GdPicture14, VB.NET (.NET Framework 4.6.2) @@ -141,7 +141,7 @@ --- #### 3. **frmEnvelopeMainData.vb** - Envelope Settings Popup -**Route Equivalent:** Part of `/sender/envelope/{id}` (inline in ReceiverUI) +**Route Equivalent:** Part of `/sender/envelope/{id}` (inline in EnvelopeGenerator.Server) **Purpose:** Configure envelope metadata and behavior. **Shown as modal popup** before main editor. @@ -196,7 +196,7 @@ | **Save** | Saves signature fields to database | **Signature Field Details:** -- **Size:** 1.77" × 1.96" (4.5cm × 5cm) - **FIXED SIZE** +- **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 @@ -226,7 +226,7 @@ End Sub - **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 +- **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 @@ -240,7 +240,7 @@ End Sub --- #### 5. **frmRueckruf.vb** - Delete Reason Dialog -**Route Equivalent:** Inline confirmation in ReceiverUI +**Route Equivalent:** Inline confirmation in EnvelopeGenerator.Server **Purpose:** Capture reason for envelope deletion/withdrawal. @@ -278,7 +278,7 @@ Public Shared Reject_reason As String = "" --- #### 7. **frmOrderFiles.vb** - PDF Merge Tool -**Route Equivalent:** Inline in ReceiverUI (future) +**Route Equivalent:** Inline in EnvelopeGenerator.Server (future) **Purpose:** Select multiple PDFs and merge them into a single document. @@ -368,11 +368,11 @@ End Sub --- -## Migration to ReceiverUI + API +## Migration to EnvelopeGenerator.Server + API ### Mapping Table -| Form Feature | ReceiverUI Equivalent | Status | +| Form Feature | EnvelopeGenerator.Server Equivalent | Status | |---|---|---| | **frmMain** (Envelope list) | `/sender` (EnvelopeSenderPage.razor) | ? Exists | | Tab 0: Active Envelopes | `/sender` default view | ? Grid with filters | @@ -409,7 +409,7 @@ End Sub ### 1. **Coordinate System Consistency** **Database (Form App):** INCHES (GdPicture native) -**ReceiverUI (PDF.js):** Pixels on canvas +**EnvelopeGenerator.Server (PDF.js):** Pixels on canvas **Conversion Required:** ```csharp // Sender side (placing fields): @@ -428,7 +428,7 @@ float canvasY = (yInches / pageHeightInches) * canvasHeight; --- ### 2. **Status Color System** -Form app uses **DevExpress CustomDrawCell** event for row coloring. ReceiverUI should use: +Form app uses **DevExpress CustomDrawCell** event for row coloring. EnvelopeGenerator.Server should use: ```css /* Envelope status colors */ @@ -447,7 +447,7 @@ Form app uses **DevExpress CustomDrawCell** event for row coloring. ReceiverUI s --- ### 3. **Master-Detail Grid Pattern** -Form app uses **nested GridViews** (ViewReceivers, ViewHistory). ReceiverUI options: +Form app uses **nested GridViews** (ViewReceivers, ViewHistory). EnvelopeGenerator.Server options: **Option A:** DevExpress Blazor Grid with master-detail template ```razor @@ -481,11 +481,11 @@ Form app uses **nested GridViews** (ViewReceivers, ViewHistory). ReceiverUI opti **Form App:** - GdPicture14 native annotations -- Fixed size (1.77×1.96 inches) +- Fixed size (1.77×1.96 inches) - Color-coded per receiver - Draggable, non-resizable -**ReceiverUI Equivalent:** +**EnvelopeGenerator.Server Equivalent:** - PDF.js canvas + HTML overlay (like receiver signature buttons) - `
` positioned absolutely - Drag & drop with JS (`onmousedown`, `onmousemove`, `onmouseup`) @@ -526,7 +526,7 @@ function makeSignatureFieldDraggable(element) { --- ### 5. **Auto-Complete Receiver Email** -Form app uses **DevExpress ComboBox** with `AllReceiverEmails` list. ReceiverUI options: +Form app uses **DevExpress ComboBox** with `AllReceiverEmails` list. EnvelopeGenerator.Server options: **Option A:** DevExpress Blazor TagBox with remote data ```razor @@ -550,7 +550,7 @@ Form app uses **DevExpress ComboBox** with `AllReceiverEmails` list. ReceiverUI --- ### 6. **Drag & Drop File Upload** -Form app uses **WinForms DragDrop** events. ReceiverUI equivalent: +Form app uses **WinForms DragDrop** events. EnvelopeGenerator.Server equivalent: ```razor