Migrate WebUI to EnvelopeGenerator.Server

Updated documentation to reflect the migration from WebUI to EnvelopeGenerator.Server, including a new "Documentation Catalog" in `AGENTS.md`. Adjusted route mappings, render modes, and directory structure for Blazor components.

Revised coordinate system documentation and CSS for status colors to align with the new architecture. Updated YARP proxy and PDF.js configuration paths.

Migrated `MIGRATION_PLAN.md` to modernize `EnvelopeGenerator.Service` with C# Worker Service equivalents. Updated `FORM_APPLICATION_CONTEXT.md` and `RECEIVER_PDF_VIEWER_CONTEXT.md` to reflect the new architecture and planned viewer integration.

Fixed German translation issues in `fix-report-label-read-and-confirmed.md`. Standardized formatting and terminology across all files.
This commit is contained in:
2026-09-22 16:17:09 +02:00
parent 80733ab1f7
commit eb219291de
5 changed files with 182 additions and 81 deletions

147
AGENTS.md
View File

@@ -4,19 +4,118 @@
- **`COPILOT_CONTEXT.md`** - Architecture, coordinate systems, migration status - **`COPILOT_CONTEXT.md`** - Architecture, coordinate systems, migration status
- **`FORM_APPLICATION_CONTEXT.md`** - Legacy VB.NET features to migrate - **`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) ## Active Architecture (Post-Migration)
**Frontend:** Blazor Auto (Server+WASM hybrid) **Frontend:** Blazor Auto (Server+WASM hybrid)
- **WebUI** (Server): `@rendermode InteractiveServer` - PDF viewers requiring DevExpress backend - **EnvelopeGenerator.Server** (Server): `@rendermode InteractiveServer` - PDF viewers requiring DevExpress backend
- **WebUI.Client** (WASM): `@rendermode InteractiveWebAssembly` - Login, dashboards, business logic - **EnvelopeGenerator.Server.Client** (WASM): `@rendermode InteractiveWebAssembly` - Login, dashboards, business logic
**Backend:** EnvelopeGenerator.API (ASP.NET Core 8.0) **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 ### Deprecated Projects - DO NOT USE
- `EnvelopeGenerator.ReceiverUI` - Pure WASM (migrated to WebUI) - `EnvelopeGenerator.ReceiverUI` - Pure WASM (migrated to Server)
- `EnvelopeGenerator.Web` - Razor Pages (replaced by WebUI) - `EnvelopeGenerator.Web` - Razor Pages (replaced by Server)
- **VB.NET projects** (`Form`, `Service`, `BBTests`) - Legacy, read-only for reference - **VB.NET projects** (`Form`, `Service`, `BBTests`) - Legacy, read-only for reference
## Development Commands ## Development Commands
@@ -28,11 +127,11 @@ cd EnvelopeGenerator.API
dotnet run dotnet run
# Terminal 2 - Blazor Frontend # Terminal 2 - Blazor Frontend
cd EnvelopeGenerator.WebUI\EnvelopeGenerator.WebUI cd EnvelopeGenerator.Server\EnvelopeGenerator.Server
dotnet run 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 ### Build
```powershell ```powershell
@@ -46,23 +145,25 @@ EnvelopeGenerator.Domain/ # Entities (Envelope, Receiver, Document, etc
EnvelopeGenerator.Application/ # MediatR CQRS (Commands, Queries, Handlers) EnvelopeGenerator.Application/ # MediatR CQRS (Commands, Queries, Handlers)
EnvelopeGenerator.Infrastructure/ # EF Core, SQL executors, repositories EnvelopeGenerator.Infrastructure/ # EF Core, SQL executors, repositories
EnvelopeGenerator.API/ # Controllers, endpoints EnvelopeGenerator.API/ # Controllers, endpoints
EnvelopeGenerator.WebUI/ # Server-side Blazor components EnvelopeGenerator.Server/
├─ Components/Pages/ # @rendermode InteractiveServer EnvelopeGenerator.Server/ # Server-side Blazor components
EnvelopeGenerator.WebUI.Client/ # Client-side WASM components ├─ Components/Pages/ # @rendermode InteractiveServer
├─ Pages/ # @rendermode InteractiveWebAssembly EnvelopeGenerator.Server.Client/ # Client-side WASM components
├─ Services/ # HTTP API clients ├─ Pages/ # @rendermode InteractiveWebAssembly
├─ Models/ # DTOs ├─ Services/ # HTTP API clients
├─ Models/ # DTOs
``` ```
## Route Structure (Critical) ## Route Structure (Critical)
| Route | File Location | Render Mode | Purpose | | Route | File Location | Render Mode | Purpose |
|-------|--------------|-------------|---------| |-------|--------------|-------------|---------|
| `/` | `WebUI.Client/Pages/Index.razor` | WASM | Landing page | | `/` | `Server.Client/Pages/Index.razor` | WASM | Landing page |
| `/sender/login` | `WebUI.Client/Pages/LoginSenderPage.razor` | WASM | Sender auth | | `/sender/login` | `Server.Client/Pages/LoginSenderPage.razor` | WASM | Sender auth |
| `/sender` | `WebUI.Client/Pages/EnvelopeSenderPage.razor` | WASM | Sender dashboard | | `/sender` | `Server/Components/Pages/EnvelopeSenderPage.razor` | **Server** | Sender dashboard |
| `/envelope/login/{key}` | `WebUI.Client/Pages/LoginReceiverPage.razor` | WASM | Receiver auth | | `/sender/editor` | `Server/Components/Pages/EnvelopeSenderEditorPage.razor` | **Server** | Envelope editor + PDF viewer |
| `/envelope/{key}` | `WebUI/Components/Pages/EnvelopeReceiverPage.razor` | **Server** | PDF viewer + signing | | `/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. **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 ## Status Color Coding
Form app uses DevExpress `CustomDrawCell`. WebUI needs CSS: Form app uses DevExpress `CustomDrawCell`. EnvelopeGenerator.Server needs CSS:
```css ```css
.envelope-row.status-partly-signed { background-color: #81C784; } /* GREEN_300 */ .envelope-row.status-partly-signed { background-color: #81C784; } /* GREEN_300 */
@@ -123,10 +224,10 @@ Form app uses DevExpress `CustomDrawCell`. WebUI needs CSS:
## Configuration ## Configuration
### YARP Proxy (`WebUI/yarp.json`) ### YARP Proxy (`EnvelopeGenerator.Server/yarp.json`)
Routes `/api/*`, `/swagger/*`, `/openapi/*`, `/scalar/*` → `https://localhost:8088` Routes `/api/*`, `/swagger/*`, `/openapi/*`, `/scalar/*` → `https://localhost:8088`
### PDF.js Settings (`WebUI/wwwroot/appsettings.json`) ### PDF.js Settings (`EnvelopeGenerator.Server/wwwroot/appsettings.json`)
```json ```json
{ {
"PdfViewerOptions": { "PdfViewerOptions": {
@@ -177,7 +278,7 @@ Routes `/api/*`, `/swagger/*`, `/openapi/*`, `/scalar/*` → `https://localhost:
Manual testing workflow: Manual testing workflow:
1. Start API (`dotnet run` in `EnvelopeGenerator.API`) 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) 3. Navigate to `https://localhost:5131` (or check console output for port)
4. Test sender login at `/sender/login` 4. Test sender login at `/sender/login`
5. Test receiver flow at `/envelope/login/{envelopeKey}` 5. Test receiver flow at `/envelope/login/{envelopeKey}`
@@ -245,7 +346,7 @@ Each envelope maintains independent authentication state.
**CDN:** **CDN:**
- PDF.js 3.11.174: `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js` - 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 - `DevExpress.Blazor.*` 25.2.3
- `SkiaSharp.*` 3.119.1 (WASM rendering) - `SkiaSharp.*` 3.119.1 (WASM rendering)

View File

@@ -1,5 +1,5 @@
# Migration Plan: EnvelopeGenerator.Service_legacy ? EnvelopeGenerator.Service # Migration Plan: EnvelopeGenerator.Service_legacy ? EnvelopeGenerator.Service
**Revision v3** — Full deep analysis complete **Revision v3** — Full deep analysis complete
## Overview ## Overview
@@ -11,25 +11,25 @@ C# Worker Service (`EnvelopeGenerator.Service`) targeting **.NET Framework 4.6.2
## Deep Analysis Findings (vs. v1/v2) ## 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 `FinalizeDocumentJob` and `APIEnvelopeJob` call `MSSQLServer.DecryptConnectionString()` on the
`JobDataMap[Value.DATABASE]` value. However, `MSSQLServer.DecryptConnectionString()` is a pass-through `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 **Resolution**: The connection string is read from `IConfiguration` via the standard
`ConnectionStrings:Default` key (same key as `appsettings.Database.json` in `EnvelopeGenerator.Web`). `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 It is passed **as-is** to both the Worker-level `MSSQLServer` and the `JobDataMap`. No
`EncryptConnectionString()` call is made anywhere in the new service. `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: 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`. This is called on every job execution and manages the job's own temp lifecycle. It expects `LogConfig`.
**We do not touch this.** **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<TempFiles>`. shutdown cleanup). This is the one we rewrite in C# in the Service project using `ILogger<TempFiles>`.
### 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: `FinalizeDocumentJob.Execute()` and `APIEnvelopeJob.Execute()` both do:
```vb ```vb
LogConfig = pContext.MergedJobDataMap.Item(Value.LOGCONFIG) LogConfig = pContext.MergedJobDataMap.Item(Value.LOGCONFIG)
@@ -45,17 +45,17 @@ build a `LogConfig` from `ServiceConfig` values:
- `Debug` = `ServiceConfig.Debug` - `Debug` = `ServiceConfig.Debug`
- Application name = `"EnvelopeGenerator.Service"` - 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. `ProjectInstaller.vb` was the old `installutil.exe` mechanism for Windows Service registration.
With `AddWindowsService()` + `sc create` / PowerShell `New-Service`, this is **completely replaced**. With `AddWindowsService()` + `sc create` / PowerShell `New-Service`, this is **completely replaced**.
No equivalent is needed in the new project. 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` 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 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). 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`. `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, 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. 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**: - Add **NuGet packages**:
- `NLog` (5.x, matching CommonServices' `NLog.5.0.5`) - `NLog` (5.x, matching CommonServices' `NLog.5.0.5`)
- `NLog.Extensions.Logging` (latest net462-compatible) - `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()`) - `Microsoft.Extensions.Hosting.WindowsServices` (for `AddWindowsService()`)
- Add **project reference** to `EnvelopeGenerator.CommonServices` (vbproj) - Add **project reference** to `EnvelopeGenerator.CommonServices` (vbproj)
- Add **project reference** to `EnvelopeGenerator.Domain` (csproj) - 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.Database.json` used by `EnvelopeGenerator.Web`:
`appsettings.json`: `appsettings.json`:
@@ -136,7 +136,7 @@ builder.Logging.AddNLog("nlog.config");
## 4. LogConfigFactory (`LogConfigFactory.cs`) ## 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 ```csharp
internal static class LogConfigFactory 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`) ## 5. Quartz LogProvider (`QuartzLogProvider.cs`)
C# rewrite of `LogProvider.vb` — bridges Quartz `ILogProvider` ? `ILogger<T>`: C# rewrite of `LogProvider.vb` — bridges Quartz `ILogProvider` ? `ILogger<T>`:
```csharp ```csharp
internal class QuartzLogProvider : ILogProvider 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<TempFiles>`: Service-level rewrite of `Service_legacy/TempFiles.vb` using `ILogger<TempFiles>`:
- `Create()` ? create `%TEMP%\EnvelopeGenerator`, or clean existing files - `Create()` ? create `%TEMP%\EnvelopeGenerator`, or clean existing files
- `CleanUp()` ? delete the directory on service stop - `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`. > inside each job via `LogConfig`.
--- ---
@@ -231,7 +231,7 @@ ExecuteAsync:
1. Read ServiceConfig from IOptions<ServiceConfig> 1. Read ServiceConfig from IOptions<ServiceConfig>
2. Validate ConnectionString ? throw if empty 2. Validate ConnectionString ? throw if empty
3. Build LogConfig via LogConfigFactory 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 5. Query: SELECT LICENSE FROM TBDD_3RD_PARTY_MODULES WHERE NAME='GDPICTURE' AND ACTIVE=1
? throw if null/empty (matches legacy behavior) ? throw if null/empty (matches legacy behavior)
6. TempFiles.Create() 6. TempFiles.Create()

View File

@@ -1,7 +1,7 @@
# EnvelopeGenerator.Form – VB.NET Desktop Application Context # EnvelopeGenerator.Form — VB.NET Desktop Application Context
## Purpose ## 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) **Primary Libraries:** DevExpress XtraGrid/XtraEditors, GdPicture14, VB.NET (.NET Framework 4.6.2)
@@ -141,7 +141,7 @@
--- ---
#### 3. **frmEnvelopeMainData.vb** - Envelope Settings Popup #### 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. **Purpose:** Configure envelope metadata and behavior. **Shown as modal popup** before main editor.
@@ -196,7 +196,7 @@
| **Save** | Saves signature fields to database | | **Save** | Saves signature fields to database |
**Signature Field Details:** **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) - **Color:** Matches receiver color (from grid assignment)
- **Label:** "SIGNATUR" (or localized "Signature") - **Label:** "SIGNATUR" (or localized "Signature")
- **Position:** Draggable on PDF canvas - **Position:** Draggable on PDF canvas
@@ -226,7 +226,7 @@ End Sub
- **Save:** Saves current receiver's fields, switches receiver, reloads all annotations - **Save:** Saves current receiver's fields, switches receiver, reloads all annotations
**Annotation Behavior:** **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) - **Existing annotation:** Loaded from database, locked size (can move but not resize)
- **Styling:** Filled rectangle with centered text "SIGNATUR" - **Styling:** Filled rectangle with centered text "SIGNATUR"
- **Validation:** No resize, no text edit, no rotation - **Validation:** No resize, no text edit, no rotation
@@ -240,7 +240,7 @@ End Sub
--- ---
#### 5. **frmRueckruf.vb** - Delete Reason Dialog #### 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. **Purpose:** Capture reason for envelope deletion/withdrawal.
@@ -278,7 +278,7 @@ Public Shared Reject_reason As String = ""
--- ---
#### 7. **frmOrderFiles.vb** - PDF Merge Tool #### 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. **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 ### Mapping Table
| Form Feature | ReceiverUI Equivalent | Status | | Form Feature | EnvelopeGenerator.Server Equivalent | Status |
|---|---|---| |---|---|---|
| **frmMain** (Envelope list) | `/sender` (EnvelopeSenderPage.razor) | ? Exists | | **frmMain** (Envelope list) | `/sender` (EnvelopeSenderPage.razor) | ? Exists |
| Tab 0: Active Envelopes | `/sender` default view | ? Grid with filters | | Tab 0: Active Envelopes | `/sender` default view | ? Grid with filters |
@@ -409,7 +409,7 @@ End Sub
### 1. **Coordinate System Consistency** ### 1. **Coordinate System Consistency**
**Database (Form App):** INCHES (GdPicture native) **Database (Form App):** INCHES (GdPicture native)
**ReceiverUI (PDF.js):** Pixels on canvas **EnvelopeGenerator.Server (PDF.js):** Pixels on canvas
**Conversion Required:** **Conversion Required:**
```csharp ```csharp
// Sender side (placing fields): // Sender side (placing fields):
@@ -428,7 +428,7 @@ float canvasY = (yInches / pageHeightInches) * canvasHeight;
--- ---
### 2. **Status Color System** ### 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 ```css
/* Envelope status colors */ /* Envelope status colors */
@@ -447,7 +447,7 @@ Form app uses **DevExpress CustomDrawCell** event for row coloring. ReceiverUI s
--- ---
### 3. **Master-Detail Grid Pattern** ### 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 **Option A:** DevExpress Blazor Grid with master-detail template
```razor ```razor
@@ -481,11 +481,11 @@ Form app uses **nested GridViews** (ViewReceivers, ViewHistory). ReceiverUI opti
**Form App:** **Form App:**
- GdPicture14 native annotations - GdPicture14 native annotations
- Fixed size (1.77×1.96 inches) - Fixed size (1.77×1.96 inches)
- Color-coded per receiver - Color-coded per receiver
- Draggable, non-resizable - Draggable, non-resizable
**ReceiverUI Equivalent:** **EnvelopeGenerator.Server Equivalent:**
- PDF.js canvas + HTML overlay (like receiver signature buttons) - PDF.js canvas + HTML overlay (like receiver signature buttons)
- `<div class="signature-field-placeholder">` positioned absolutely - `<div class="signature-field-placeholder">` positioned absolutely
- Drag & drop with JS (`onmousedown`, `onmousemove`, `onmouseup`) - Drag & drop with JS (`onmousedown`, `onmousemove`, `onmouseup`)
@@ -526,7 +526,7 @@ function makeSignatureFieldDraggable(element) {
--- ---
### 5. **Auto-Complete Receiver Email** ### 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 **Option A:** DevExpress Blazor TagBox with remote data
```razor ```razor
@@ -550,7 +550,7 @@ Form app uses **DevExpress ComboBox** with `AllReceiverEmails` list. ReceiverUI
--- ---
### 6. **Drag & Drop File Upload** ### 6. **Drag & Drop File Upload**
Form app uses **WinForms DragDrop** events. ReceiverUI equivalent: Form app uses **WinForms DragDrop** events. EnvelopeGenerator.Server equivalent:
```razor ```razor
<div class="file-drop-zone" <div class="file-drop-zone"
@@ -577,7 +577,7 @@ Form app uses **WinForms DragDrop** events. ReceiverUI equivalent:
--- ---
### 7. **PDF Merge (frmOrderFiles)** ### 7. **PDF Merge (frmOrderFiles)**
Form app uses **GdPicture14 MergeDocuments**. ReceiverUI options: Form app uses **GdPicture14 MergeDocuments**. EnvelopeGenerator.Server options:
**Option A:** Server-side merge (iText7 or PDFSharp) **Option A:** Server-side merge (iText7 or PDFSharp)
```csharp ```csharp
@@ -634,7 +634,7 @@ async function mergePDFs(fileDataUrls) {
4. frmFieldEditor opens 4. frmFieldEditor opens
- Select receiver from dropdown (colored circles) - Select receiver from dropdown (colored circles)
- Click "Add Signature" ? draw box on PDF - Click "Add Signature" ? draw box on PDF
- Drag to position (1.77×1.96 inches, fixed size) - Drag to position (1.77×1.96 inches, fixed size)
- Repeat for each receiver - Repeat for each receiver
- Click "Save" - Click "Save"
? ?
@@ -680,7 +680,7 @@ async function mergePDFs(fileDataUrls) {
--- ---
## Missing Features in ReceiverUI (To Implement) ## Missing Features in EnvelopeGenerator.Server (To Implement)
### High Priority ### High Priority
1. ? **Envelope list grid** (`/sender`) with status colors 1. ? **Envelope list grid** (`/sender`) with status colors
@@ -735,7 +735,7 @@ async function mergePDFs(fileDataUrls) {
???????????????????????? ????????????????????????
? frmFieldEditor ? ? GdPicture PDF viewer ? frmFieldEditor ? ? GdPicture PDF viewer
? (Signature Placer) ? ? Receiver selector (colored circles) ? (Signature Placer) ? ? Receiver selector (colored circles)
???????????????????????? ? Draggable signature boxes (1.77×1.96") ???????????????????????? ? Draggable signature boxes (1.77×1.96")
? Click "Save" ? Click "Save"
? ?
???????????????????????? ????????????????????????

View File

@@ -1,4 +1,4 @@
# EnvelopeGenerator — Receiver PDF Viewer Context # EnvelopeGenerator — Receiver PDF Viewer Context
## Purpose ## Purpose
This document summarizes the active receiver-side PDF viewing and signing experience so that other agents can understand the current implementation quickly without re-reading all related files. This document summarizes the active receiver-side PDF viewing and signing experience so that other agents can understand the current implementation quickly without re-reading all related files.
@@ -765,7 +765,7 @@ The migration should preserve this capability contract at the page level even if
### 8. Planned migration strategy ### 8. Planned migration strategy
#### Phase 1 — Confirm the `DxPdfViewer` integration surface #### Phase 1 — Confirm the `DxPdfViewer` integration surface
Use `EnvelopeReceiverPage_DxPdfViewer.razor` as a reference and determine exactly what `DxPdfViewer` exposes for: Use `EnvelopeReceiverPage_DxPdfViewer.razor` as a reference and determine exactly what `DxPdfViewer` exposes for:
@@ -785,7 +785,7 @@ Key question:
If yes, overlays can be positioned relative to the rendered page. If yes, overlays can be positioned relative to the rendered page.
If no, a wrapper-based approximation or alternative integration is required. If no, a wrapper-based approximation or alternative integration is required.
#### Phase 2 — Replace the main render surface in `EnvelopeReceiverPage.razor` #### Phase 2 — Replace the main render surface in `EnvelopeReceiverPage.razor`
The current custom `canvas + text layer + signature layer` block should be replaced with a `DxPdfViewer` host region while keeping: The current custom `canvas + text layer + signature layer` block should be replaced with a `DxPdfViewer` host region while keeping:
@@ -798,7 +798,7 @@ The current custom `canvas + text layer + signature layer` block should be repla
At this stage, only the main document display needs to work. At this stage, only the main document display needs to work.
Signature overlays may temporarily be disabled while the host geometry is established. Signature overlays may temporarily be disabled while the host geometry is established.
#### Phase 3 — Introduce a dedicated overlay host above `DxPdfViewer` #### Phase 3 — Introduce a dedicated overlay host above `DxPdfViewer`
The new viewer surface should be wrapped with a custom page container. The new viewer surface should be wrapped with a custom page container.
@@ -813,7 +813,7 @@ Planned structure:
The overlay layer must be independently controlled by our code and not depend on internal `PDF.js` DOM ids. The overlay layer must be independently controlled by our code and not depend on internal `PDF.js` DOM ids.
#### Phase 4 — Rebuild page/zoom geometry acquisition #### Phase 4 — Rebuild page/zoom geometry acquisition
Because the current implementation derives position using only `sig.x * scale`, the target implementation must determine: Because the current implementation derives position using only `sig.x * scale`, the target implementation must determine:
@@ -829,7 +829,7 @@ At redraw time, the adapter must produce page-relative pixel coordinates for:
This should be centralized in one geometry function rather than scattered across multiple viewer actions. This should be centralized in one geometry function rather than scattered across multiple viewer actions.
#### Phase 5 — Move signature overlay state to a canonical model #### Phase 5 — Move signature overlay state to a canonical model
The current JavaScript keeps runtime state in: The current JavaScript keeps runtime state in:
@@ -849,7 +849,7 @@ Preferably:
If necessary, applied signature state should be re-sendable from .NET after viewer redraw. If necessary, applied signature state should be re-sendable from .NET after viewer redraw.
That prevents losing visual signatures when page layout changes. That prevents losing visual signatures when page layout changes.
#### Phase 6 — Re-implement signature placeholder rendering on top of `DxPdfViewer` #### Phase 6 — Re-implement signature placeholder rendering on top of `DxPdfViewer`
The current implementation filters placeholders by: The current implementation filters placeholders by:
@@ -868,7 +868,7 @@ Rendering rules to preserve:
The existing scaling behavior uses `baseScale = 1.5` as the visual reference. The existing scaling behavior uses `baseScale = 1.5` as the visual reference.
That visual convention should be preserved initially unless a new normalized sizing model is intentionally introduced. That visual convention should be preserved initially unless a new normalized sizing model is intentionally introduced.
#### Phase 7 — Re-implement applied signature rendering on top of `DxPdfViewer` #### Phase 7 — Re-implement applied signature rendering on top of `DxPdfViewer`
The current applied signature overlay includes: The current applied signature overlay includes:
@@ -888,7 +888,7 @@ Required behavior:
- applied signature repositions on page/zoom changes - applied signature repositions on page/zoom changes
- applied signature is hidden when the user navigates to a different page - applied signature is hidden when the user navigates to a different page
#### Phase 8 — Re-implement page navigation through a central page-change pipeline #### Phase 8 — Re-implement page navigation through a central page-change pipeline
The following actions must all converge into a single page navigation routine: The following actions must all converge into a single page navigation routine:
@@ -906,7 +906,7 @@ That routine must do all of the following in order:
4. redraw placeholder overlays 4. redraw placeholder overlays
5. refresh signature navigation counter state 5. refresh signature navigation counter state
#### Phase 9 — Re-implement zoom through a central zoom-change pipeline #### Phase 9 — Re-implement zoom through a central zoom-change pipeline
The following actions must converge into one zoom update path: The following actions must converge into one zoom update path:
@@ -926,7 +926,7 @@ That routine must:
The current implementation already treats redraw after zoom as mandatory. That must remain true. The current implementation already treats redraw after zoom as mandatory. That must remain true.
#### Phase 10 — Preserve signature navigation independently from the viewer engine #### Phase 10 — Preserve signature navigation independently from the viewer engine
Current navigation logic is driven by the global ordered signature list and not by PDF rendering internals alone. Current navigation logic is driven by the global ordered signature list and not by PDF rendering internals alone.
@@ -940,7 +940,7 @@ This behavior must remain engine-independent:
If `DxPdfViewer` changes scrolling mechanics, the `scrollToElement` / `scrollToButton` logic must be adapted, but the traversal rules must remain unchanged. If `DxPdfViewer` changes scrolling mechanics, the `scrollToElement` / `scrollToButton` logic must be adapted, but the traversal rules must remain unchanged.
#### Phase 11 — Thumbnail sidebar should remain custom unless `DxPdfViewer` can match all current behavior #### Phase 11 — Thumbnail sidebar should remain custom unless `DxPdfViewer` can match all current behavior
The current sidebar is not just decorative. It also provides: The current sidebar is not just decorative. It also provides:
@@ -963,7 +963,7 @@ If `DxPdfViewer` cannot provide matching thumbnails directly, a hybrid solution
This still satisfies the requirement that `DxPdfViewer` becomes the main viewer technology. This still satisfies the requirement that `DxPdfViewer` becomes the main viewer technology.
#### Phase 12 — Keep signature capture popup unchanged unless integration forces a minimal adjustment #### Phase 12 — Keep signature capture popup unchanged unless integration forces a minimal adjustment
`receiver-signature.js` and the popup flow should remain mostly untouched. `receiver-signature.js` and the popup flow should remain mostly untouched.

View File

@@ -1,4 +1,4 @@
# Fix: Report Label "Read and confirmed" for Read and Sign Envelopes # Fix: Report Label "Read and confirmed" for Read and Sign Envelopes
## Status ## Status
✅ **COMPLETED** ✅ **COMPLETED**
@@ -13,11 +13,11 @@ fix/report-label-read-and-confirmed
## Problem ## Problem
In the **Signature Certificate report** (`Signierungszertifikat`), the history event In the **Signature Certificate report** (`Signierungszertifikat`), the history event
list always showed **"Document signed"** for status `DocumentSigned` (code `2005`) <EFBFBD> list always showed **"Document signed"** for status `DocumentSigned` (code `2005`) —
even when the envelope type was **"Read and Sign"** (`EnvelopeTypeId = 2`). even when the envelope type was **"Read and Sign"** (`EnvelopeTypeId = 2`).
For "Read and Sign" envelopes the correct label must be **"Read and confirmed"** For "Read and Sign" envelopes the correct label must be **"Read and confirmed"**
(DE: **"Gelesen und best<EFBFBD>tigt"**). (DE: **"Gelesen und bestätigt"**).
### Screenshot reference ### Screenshot reference
The report shows a table with columns *Ereignis | Benutzer | Zeitstempel*. The report shows a table with columns *Ereignis | Benutzer | Zeitstempel*.
@@ -57,7 +57,7 @@ Read-and-Sign label variants across all resource files:
| Resource file | Value | | Resource file | Value |
|---|---| |---|---|
| `Model.resx` (DE, default) | `Gelesen und best<EFBFBD>tigt` | | `Model.resx` (DE, default) | `Gelesen und bestätigt` |
| `Model.en.resx` (EN) | `Read and confirmed` | | `Model.en.resx` (EN) | `Read and confirmed` |
### Logic change in `ReportItem.vb` ### Logic change in `ReportItem.vb`
@@ -104,7 +104,7 @@ Each file needs one new `<data>` block inserted **directly after** the existing
```xml ```xml
<data name="DocumentSignedRaC" xml:space="preserve"> <data name="DocumentSignedRaC" xml:space="preserve">
<value>Gelesen und best<EFBFBD>tigt</value> <!-- DE files --> <value>Gelesen und bestätigt</value> <!-- DE files -->
<!-- OR --> <!-- OR -->
<value>Read and confirmed</value> <!-- EN file --> <value>Read and confirmed</value> <!-- EN file -->
</data> </data>
@@ -115,7 +115,7 @@ Each file needs one new `<data>` block inserted **directly after** the existing
```csharp ```csharp
/// <summary> /// <summary>
/// Looks up a localized string similar to Gelesen und best<EFBFBD>tigt. /// Looks up a localized string similar to Gelesen und bestätigt.
/// </summary> /// </summary>
public static string DocumentSignedRaC { public static string DocumentSignedRaC {
get { get {
@@ -131,5 +131,5 @@ public static string DocumentSignedRaC {
After changes, generate a Signature Certificate report for a **Read and Sign** After changes, generate a Signature Certificate report for a **Read and Sign**
envelope and verify: envelope and verify:
- History row with status 2005 shows **"Read and confirmed"** (EN) - History row with status 2005 shows **"Read and confirmed"** (EN)
- History row with status 2005 shows **"Gelesen und best<EFBFBD>tigt"** (DE) - History row with status 2005 shows **"Gelesen und bestätigt"** (DE)
- Regular (non-RaC) envelopes still show **"Document signed"** / **"Dokument unterzeichnet"** - Regular (non-RaC) envelopes still show **"Document signed"** / **"Dokument unterzeichnet"**