The `EnvelopeGenerator.Server` project now serves as the unified runtime host for both the Blazor frontend and Web API backend, deprecating the `EnvelopeGenerator.API` project. All API endpoints have been merged into `EnvelopeGenerator.Server`. Key changes: - Updated `EnvelopeGenerator.Server` to include API controllers. - Deprecated `EnvelopeGenerator.API` and removed it from the active solution. - Simplified development workflow to run only `EnvelopeGenerator.Server`. - Updated `appsettings.json` to consolidate configuration settings. - Adjusted documentation to reflect the new unified architecture. - Updated manual testing steps and environment variable references. - Migrated legacy VB.NET app references to the new architecture. These changes simplify development, deployment, and testing workflows while consolidating the solution architecture.
319 lines
13 KiB
Markdown
319 lines
13 KiB
Markdown
# EnvelopeGenerator - Agent Guide
|
||
|
||
## Must Read First
|
||
- **`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.
|
||
|
||
---
|
||
|
||
### 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.
|
||
|
||
---
|
||
|
||
## Active Architecture (Post-Migration)
|
||
|
||
**Frontend:** Blazor Auto (Server+WASM hybrid)
|
||
- **EnvelopeGenerator.Server** (Server): `@rendermode InteractiveServer` - PDF viewers requiring DevExpress backend
|
||
- **EnvelopeGenerator.Server.Client** (WASM): `@rendermode InteractiveWebAssembly` - Login, dashboards, business logic
|
||
|
||
**Backend + API Host:** `EnvelopeGenerator.Server` (ASP.NET Core 8.0, merged Blazor + Web API host)
|
||
|
||
**Proxy:** YARP in `EnvelopeGenerator.Server` is used for external integrations (for example AuthHub forwarding), not for routing app APIs to `EnvelopeGenerator.API`.
|
||
|
||
### Deprecated Projects - DO NOT USE
|
||
- `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
|
||
|
||
### Run Active Host
|
||
```powershell
|
||
# Terminal - Blazor + Web API host
|
||
cd EnvelopeGenerator.Server\EnvelopeGenerator.Server
|
||
dotnet run
|
||
```
|
||
|
||
**Critical:** `EnvelopeGenerator.Server` is the active runtime host for both UI and API controllers.
|
||
|
||
### Build
|
||
```powershell
|
||
dotnet build EnvelopeGenerator.sln
|
||
```
|
||
|
||
## Project Boundaries
|
||
|
||
```
|
||
EnvelopeGenerator.Domain/ # Entities (Envelope, Receiver, Document, etc.)
|
||
EnvelopeGenerator.Application/ # MediatR CQRS (Commands, Queries, Handlers)
|
||
EnvelopeGenerator.Infrastructure/ # EF Core, SQL executors, repositories
|
||
EnvelopeGenerator.Server/
|
||
EnvelopeGenerator.Server/ # Server-side Blazor + API controllers
|
||
├─ Components/Pages/ # @rendermode InteractiveServer
|
||
├─ Controllers/ # Active Web API endpoints
|
||
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 |
|
||
|-------|--------------|-------------|---------|
|
||
| `/` | `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.
|
||
|
||
## Coordinate System (CRITICAL)
|
||
|
||
**Database stores INCHES** (GdPicture14 native). Origin: top-left, Y-axis down.
|
||
|
||
### Conversions
|
||
```csharp
|
||
// Database (INCHES) → PDF Points
|
||
float points = inches * 72;
|
||
|
||
// Database (INCHES) → DevExpress DX
|
||
float dx = inches * 100;
|
||
|
||
// PDF.js Pixels → Database (INCHES)
|
||
float inches = (pixelX / canvasWidth) * pageWidthInches;
|
||
```
|
||
|
||
**A4 Page:** 8.27" wide × 11.69" tall = 595pt × 842pt
|
||
|
||
**Signature Field Size:** 1.77" × 1.96" (FIXED, do not change)
|
||
|
||
**Evidence:** See `COPILOT_CONTEXT.md` lines 158-185, `EnvelopeGenerator.Form/frmFieldEditor.vb`
|
||
|
||
## API Architecture Quirks
|
||
|
||
### Monolithic Endpoint (Avoid for UI)
|
||
`POST /api/EnvelopeReceiver` - Creates envelope+document+receivers+fields atomically.
|
||
- **Use case:** External API consumers
|
||
- **Not suitable for:** Step-by-step UI workflow (no draft support, no partial updates)
|
||
|
||
### Missing Granular Endpoints (Need to Create)
|
||
```
|
||
POST /api/Envelope/draft # Create draft envelope
|
||
PUT /api/Envelope/{id} # Update metadata
|
||
DELETE /api/Envelope/{id} # Delete with reason
|
||
POST /api/Envelope/{id}/document # Upload PDF
|
||
POST /api/Envelope/{id}/receivers # Add receiver
|
||
POST /api/Envelope/{id}/signature-fields # Place signature field
|
||
POST /api/Envelope/{id}/send # Send to receivers
|
||
```
|
||
|
||
See `FORM_APPLICATION_CONTEXT.md` for detailed workflow requirements.
|
||
|
||
## Status Color Coding
|
||
|
||
Form app uses DevExpress `CustomDrawCell`. EnvelopeGenerator.Server needs CSS:
|
||
|
||
```css
|
||
.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; }
|
||
.envelope-row.status-deleted,
|
||
.envelope-row.status-rejected { background-color: #E57373; } /* RED_300 */
|
||
```
|
||
|
||
## Configuration
|
||
|
||
### YARP Proxy (`EnvelopeGenerator.Server/yarp.json`)
|
||
Routes `/api/*`, `/swagger/*`, `/openapi/*`, `/scalar/*` → `https://localhost:8088`
|
||
|
||
### PDF.js Settings (`EnvelopeGenerator.Server/wwwroot/appsettings.json`)
|
||
```json
|
||
{
|
||
"PdfViewerOptions": {
|
||
"ThumbnailBaseScale": 0.75,
|
||
"ThumbnailEnableHiDPI": true,
|
||
"MainCanvasEnableHiDPI": true,
|
||
"ZoomStepPercentage": 5
|
||
}
|
||
}
|
||
```
|
||
|
||
### Server Host Config (`EnvelopeGenerator.Server/EnvelopeGenerator.Server/appsettings.json`)
|
||
- `ConnectionStrings:Default` - SQL Server DB
|
||
- `AllowedOrigins` - CORS (includes `http://localhost:5131`, `http://localhost:7192`)
|
||
- `Cache:SignatureCacheExpiration` - Signature persistence timeout
|
||
- `PSPDFKitLicenseKey` - **DEPRECATED** (use PDF.js instead)
|
||
|
||
## Migration Status
|
||
|
||
### Complete ✅
|
||
- Receiver login/authentication
|
||
- PDF viewing with PDF.js (HiDPI, zoom, thumbnails)
|
||
- Signature capture (draw/type/image)
|
||
- Signature caching (Redis/SQL)
|
||
- Sender login
|
||
|
||
### Missing (High Priority) ❌
|
||
- Sender dashboard (`/sender`) - Empty stub
|
||
- Envelope editor (`/sender/envelope/{id}`)
|
||
- Signature field placement tool (PDF.js + draggable overlays)
|
||
- Granular API endpoints (draft, receivers, fields)
|
||
- Master-detail grids for receivers/history
|
||
|
||
## Common Mistakes (DO NOT REPEAT)
|
||
|
||
| Mistake | Why Wrong |
|
||
|---------|-----------|
|
||
| Using iText7 in receiver pages | GPL license issue. Use PDF.js overlays. |
|
||
| Using PSPDFKit | Removed from architecture. Use PDF.js + DevExpress. |
|
||
| `@rendermode InteractiveWebAssembly` on PDF viewers | DevExpress DxPdfViewer requires server-side rendering. |
|
||
| Hardcoded quality in PDF.js | Use `appsettings.json` `PdfViewerOptions`. |
|
||
| Coordinates in points/pixels for DB | Database uses INCHES. Convert before save. |
|
||
| `BottomMarginBand` for signatures | Repeats on every page. Use `DetailBand`. |
|
||
|
||
## Testing
|
||
|
||
**No automated tests exist yet.**
|
||
|
||
Manual testing workflow:
|
||
1. Start EnvelopeGenerator.Server (`dotnet run` in `EnvelopeGenerator.Server\EnvelopeGenerator.Server`)
|
||
2. Navigate to `https://localhost:5131` (or check console output for port)
|
||
3. Test sender login at `/sender/login`
|
||
4. Test receiver flow at `/envelope/login/{envelopeKey}`
|
||
|
||
## Database
|
||
|
||
**SQL Server** (DD_ECM)
|
||
- Connection string in `EnvelopeGenerator.Server/EnvelopeGenerator.Server/appsettings.json`
|
||
- EF Core migrations NOT used (manual SQL scripts)
|
||
- Stored procedures: `PRSIG_*` prefix
|
||
|
||
**Key Tables:**
|
||
- `TBSIG_ENVELOPE` - Envelope metadata
|
||
- `TBSIG_ENVELOPE_RECEIVER` - Receiver assignments
|
||
- `TBSIG_DOC_RECEIVER_ELEMENT` - Signature fields (X, Y in INCHES)
|
||
- `TBSIG_RECEIVER` - Receiver registry
|
||
- `TBSIG_DOCUMENT` - PDF binary data
|
||
- `TBSIG_ENVELOPE_HISTORY` - Audit trail
|
||
|
||
## DevExpress
|
||
|
||
**License:** Commercial (v25.2.3)
|
||
**Components Used:**
|
||
- `DxGrid` - Master-detail grids
|
||
- `DxPdfViewer` - Server-side PDF rendering
|
||
- `DxPopup` - Modal dialogs
|
||
- `DxToolbar` - Action bars
|
||
- `DxFormLayout` - Forms
|
||
|
||
**Theme:** Blazing Berry (default)
|
||
|
||
## JavaScript Interop
|
||
|
||
**PDF Viewer:** `wwwroot/js/pdf-viewer.js`
|
||
```javascript
|
||
window.pdfViewer = {
|
||
initialize(canvasId, pdfDataUrl, dotNetRef),
|
||
renderPage(num),
|
||
renderSignatureButtons(signatures, pageNum, dotNetRef),
|
||
applySignature(signatureId, dataUrl, fullName, position, place),
|
||
zoomIn(), zoomOut(), dispose()
|
||
}
|
||
```
|
||
|
||
**Signature Pad:** `wwwroot/js/receiver-signature.js`
|
||
```javascript
|
||
window.receiverSignature = {
|
||
initializeDrawPad(canvasId, dotNetRef),
|
||
getSignatureDataUrl(canvasId),
|
||
clearPad(canvasId)
|
||
}
|
||
```
|
||
|
||
## Multi-Envelope Support
|
||
|
||
Receivers can login to **multiple envelopes simultaneously** via per-envelope cookies:
|
||
```
|
||
AuthTokenSignFLOWReceiver.{envelopeKey}
|
||
```
|
||
|
||
Each envelope maintains independent authentication state.
|
||
|
||
## External Dependencies
|
||
|
||
**CDN:**
|
||
- PDF.js 3.11.174: `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js`
|
||
|
||
**NuGet (Server.Client):**
|
||
- `DevExpress.Blazor.*` 25.2.3
|
||
- `SkiaSharp.*` 3.119.1 (WASM rendering)
|
||
|
||
**External Services:**
|
||
- LDAP/AD authentication (optional)
|
||
- GTX Messaging (SMS 2FA)
|
||
- Email dispatcher (signFlow)
|
||
|
||
## Environment Variables
|
||
|
||
None required. All config in `appsettings.json`.
|
||
|
||
**Local dev ports:**
|
||
- App host (UI + API): `https://localhost:5131` or `http://localhost:7192`
|