# EnvelopeGenerator — Current Workspace Context ## Purpose Digital document signing system for senders and receivers. - Senders authenticate, view envelope lists, and manage envelope workflows. - Receivers authenticate per envelope, open PDFs, create signatures, and apply them in the viewer. - The active UI stack is `Blazor Auto` with server-side and WebAssembly render modes. - Primary UI/PDF libraries are `DevExpress` and `PDF.js`. --- ## Active Application Structure ### Main Host **Primary active application:** `EnvelopeGenerator.Server` `EnvelopeGenerator.Server` is the current runtime host and contains: - Blazor server host - WebAssembly host integration - API controllers - authentication/authorization setup - Swagger/Scalar setup - YARP reverse proxy configuration - DevExpress server-side services - SQL Server distributed cache setup ### Client Project **Client UI project:** `EnvelopeGenerator.Server.Client` This project contains: - WebAssembly-rendered pages - client-side services - client models and options - sender and receiver login flows ### Other Projects - `EnvelopeGenerator.Application` — MediatR/CQRS handlers and business logic - `EnvelopeGenerator.Domain` — domain models, constants, shared abstractions - `EnvelopeGenerator.Infrastructure` — EF Core and infrastructure services - `EnvelopeGenerator.PdfEditor` — PDF-related backend utilities - `EnvelopeGenerator.API` — still exists in the solution, but the current merged app host is `EnvelopeGenerator.Server` ### Legacy / Do Not Touch - `EnvelopeGenerator.Service` - `EnvelopeGenerator.Form` - `EnvelopeGenerator.BBTests` - `EnvelopeGenerator.CommonServices` --- ## Current Hosting Model `EnvelopeGenerator.Server/Program.cs` currently configures: - `AddRazorComponents()` with both interactive server and interactive WebAssembly components - `AddControllers()` and `MapControllers()` - JWT authentication for sender and receiver flows - cookie authentication - authorization policies using `AuthScheme.Sender`, `AuthScheme.Receiver`, `AuthPolicy.Sender`, `AuthPolicy.Receiver` - `AddReverseProxy()` with `yarp.json` - Swagger / OpenAPI / Scalar - distributed SQL Server cache - DevExpress Blazor and DevExpress PDF Viewer server-side services - request localization middleware This means the active app is a **merged UI + API host**. --- ## Reverse Proxy **Config file:** `EnvelopeGenerator.Server/EnvelopeGenerator.Server/yarp.json` Current YARP usage is focused on **AuthHub forwarding**, not a general `/api/* -> EnvelopeGenerator.API` proxy. Configured routes forward: - `POST /api/auth` -> AuthHub `/api/auth/sign-flow` - `POST /api/Auth/envelope-receiver/{key}` -> AuthHub `/api/auth/envelope-receiver/{key}?cookie=true` --- ## Active Routes and Files ### WebAssembly Pages (`EnvelopeGenerator.Server.Client`) | Route | File | Render Mode | Purpose | |---|---|---|---| | `/` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/IndexPage.razor` | WebAssembly | Landing page | | `/sender/login` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/LoginSenderPage.razor` | WebAssembly | Sender login | | `/sender` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor` | WebAssembly (`prerender: false`) | Sender dashboard | | `/envelope/login/{EnvelopeKey}` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/LoginReceiverPage.razor` | WebAssembly | Receiver login | ### Server Pages (`EnvelopeGenerator.Server`) | Route | File | Render Mode | Purpose | |---|---|---|---| | `/envelope/{EnvelopeKey}` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeReceiverPage.razor` | InteractiveServer | Main receiver PDF viewer and signing page | | `/envelope/DxPdfViewer` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeReceiverPage_DxPdfViewer.razor` | InteractiveServer | DevExpress PDF Viewer test page | | `/envelope/{EnvelopeKey}/DxReportViewer` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeReceiverPage_DxReportViewer.razor` | InteractiveServer | DevExpress report-based PDF rendering | | `/envelope/Embed` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeReceiverPage_embed.razor` | InteractiveServer | Embedded browser PDF view test page | --- ## Current API Location The active application exposes controllers from: `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers` Current controller set includes: - `AnnotationController` - `AuthController` - `CacheController` - `ConfigController` - `DocumentController` - `EmailTemplateController` - `EnvelopeController` - `EnvelopeReceiverController` - `EnvelopeTypeController` - `HistoryController` - `LocalizationController` - `ReadOnlyController` - `ReceiverController` - `SignatureController` - `TfaRegistrationController` Do not assume API behavior lives only in `EnvelopeGenerator.API`; the active merged host contains controller endpoints directly. --- ## Authentication Model ### Sender Client login page uses `EnvelopeGenerator.Server.Client/Services/AuthService.cs`. Key sender endpoints: - `POST /api/auth?cookie=true` — login - `GET /api/auth/check` — current sender access check - `POST /api/auth/logout` — logout ### Receiver Receiver authentication is **per envelope**. Key receiver endpoints used by client services: - `POST /api/Auth/envelope-receiver/{envelopeKey}` — submit access code - `GET /api/auth/check/envelope/{envelopeKey}` — check access - `POST /api/auth/logout/envelope/{envelopeKey}` — logout receiver for one envelope Receiver cookie resolution in server auth uses an envelope-specific cookie name derived from: - `AuthTokenSignFLOWReceiver.{envelopeKey}` pattern ### Receiver Server-Side Authorization `EnvelopeReceiverPage.razor` does **not** rely on its own API access-check call for page authorization. It uses: - `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Services/EnvelopeReceiverAuthorizationService.cs` Behavior: - tries the current `HttpContext.User` - if needed, reads the per-envelope receiver cookie directly - validates the JWT with the receiver auth scheme - verifies the token subject matches the route envelope key --- ## Receiver Page Data Loading Main server-side page data service: - `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Services/EnvelopeReceiverPageDataService.cs` This service loads directly via MediatR and distributed cache: - document bytes - receiver envelope data - signature placeholders - cached signature data For signature placeholders, the service: - reads document receiver elements - filters them for the authenticated receiver - converts coordinates to `UnitOfLength.Point` before UI use --- ## Receiver PDF Viewer **Main file:** `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeReceiverPage.razor` Current receiver viewer characteristics: - route: `/envelope/{EnvelopeKey}` - render mode: `InteractiveServer` - PDF rendering: `PDF.js` - toolbar: page navigation, zoom, thumbnail toggle, signature navigation, signature reset - signature popup: `DxPopup` - thumbnail sidebar: resizable and stored in `localStorage` ### JS Assets - `EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/js/pdf-viewer.js` - `EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/js/receiver-signature.js` ### CSS - `EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/envelope-viewer.css` ### PDF.js CDN - `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js` - `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf_viewer.min.css` --- ## Signature Workflow Receiver signatures are handled as a **viewer overlay workflow**. ### Current behavior 1. Server-side authorization validates receiver access. 2. The page loads document bytes, receiver data, signature placeholders, and cached signature state. 3. If no cached signature exists, the signature popup opens automatically. 4. Receiver creates signature using one of three tabs: - draw - text - image 5. Required metadata: - full name - place 6. Optional metadata: - position 7. Clicking a signature placeholder applies the signature as a client-side overlay in the PDF viewer. ### Important note Although `itext` is referenced by the server project, the current receiver page signing flow is **not PDF stamping-based**. The active receiver UI uses client-side overlay behavior in the viewer. ### Signature DTO `EnvelopeGenerator.Server.Client/Models/SignatureCaptureDto.cs` ```csharp public sealed record SignatureCaptureDto { public required string DataUrl { get; init; } public required string FullName { get; init; } public string Position { get; init; } = ""; public required string Place { get; init; } } ``` --- ## Signature Cache ### Active cache model The current receiver page cache flow is handled directly in the server project through: - `EnvelopeReceiverPageDataService` - `IDistributedCache` - SQL Server distributed cache configuration from `Program.cs` ### Cache key format Current server-side key prefix: - `envelope-generator.receiver-ui.signature:{receiverSignature}` This is different from an envelope-key-only cache convention. ### Config `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Options/CacheOptions.cs` - section name: `Cache` - option: `SignatureCacheExpiration` ### Related controller A cache API controller also exists in: - `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/CacheController.cs` --- ## Sender Dashboard **Main file:** `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor` Current behavior: - checks sender access through `AuthService.CheckSenderAccessAsync()` - redirects to `/sender/login` when unauthorized - loads envelope list through client `EnvelopeService` - separates envelopes into active/completed tabs - uses `DevExpress DxGrid` The sender page is active, but create/edit/delete actions are still marked with TODO behavior in the UI page. --- ## Localization Current server host localization setup in `Program.cs`: - supported cultures: `de-DE`, `en-US` - request localization middleware is enabled - `QueryStringRequestCultureProvider` is added - cookie-based localization services are registered via `AddCookieBasedLocalizer()` Do not assume the old ReceiverUI-only `localStorage` culture approach is the current source of truth for the active host. --- ## Coordinate System ### Source data Database signature coordinates are still based on: - **unit:** inches - **origin:** top-left - **axes:** X right, Y down ### Relevant conversions - inches -> PDF points: `x_pt = x_inches * 72` - inches -> DevExpress DX units: `x_dx = x_inches * 100` ### Current receiver page behavior The server page data service converts signature placeholders to **points** before sending them into the viewer workflow. ### Unit systems to keep in mind | System | Unit | Origin | Y-axis | |---|---|---|---| | Database | Inches | Top-left | Down | | PDF.js display | Pixels | Top-left | Down | | PDF points | Points | Depends on PDF model | Depends on consumer | | DevExpress DX | 1/100 inch style coordinates | Top-left-oriented usage in this app | Down-oriented usage | --- ## Key Services and Files ### Client services - `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/AuthService.cs` - `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/EnvelopeService.cs` - `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/DocumentService.cs` - `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/SignatureCacheService.cs` ### Server services - `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Services/EnvelopeAuthService.cs` - `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Services/IEnvelopeAuthService.cs` - `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Services/EnvelopeReceiverAuthorizationService.cs` - `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Services/EnvelopeReceiverPageDataService.cs` ### Server config and host files - `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Program.cs` - `EnvelopeGenerator.Server/EnvelopeGenerator.Server/yarp.json` --- ## Working Rules for This Workspace - Treat `EnvelopeGenerator.Server` as the active main application host. - Treat `EnvelopeGenerator.Server.Client` as the active client UI project. - Prefer current `Server` / `Server.Client` paths over old `WebUI` / `ReceiverUI` references. - Do not use `EnvelopeGenerator.Web` or `EnvelopeGenerator.ReceiverUI` as the primary implementation target unless explicitly asked. - Do not modify the legacy VB.NET projects unless explicitly requested. - For receiver PDF/signature work, prefer the current `PDF.js`-based flow in `EnvelopeReceiverPage.razor`. - For DevExpress PDF viewer issues, remember server-side services are registered in `EnvelopeGenerator.Server`. --- **Last Updated:** 2026-06-29