docs: update CLAUDE.md with branding param, page 1 redesign, new PdfTheme palette
This commit is contained in:
109
CLAUDE.md
Normal file
109
CLAUDE.md
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project
|
||||||
|
|
||||||
|
**SmartReports / CertReports.Syncfusion** — ASP.NET Core 8 REST API che genera PDF di certificati finanziari strutturati, sostituendo il vecchio progetto WebForms DevExpress. Usa Syncfusion PDF (Community License) e SkiaSharp per i grafici.
|
||||||
|
|
||||||
|
Progetto unico nella solution: `CertReports.Syncfusion/`.
|
||||||
|
|
||||||
|
## Build & Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Restore + build
|
||||||
|
dotnet restore
|
||||||
|
dotnet build
|
||||||
|
|
||||||
|
# Run locale → https://localhost:{porta}/api/report/by-isin/{ISIN}
|
||||||
|
dotnet run --project CertReports.Syncfusion
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
docker-compose up --build
|
||||||
|
# → http://localhost:5080/api/report/by-isin/{ISIN}
|
||||||
|
```
|
||||||
|
|
||||||
|
Non esistono test automatici al momento.
|
||||||
|
|
||||||
|
## Architettura
|
||||||
|
|
||||||
|
Il flusso di generazione è orchestrato da `ReportOrchestrator`:
|
||||||
|
|
||||||
|
```
|
||||||
|
HTTP (ISIN) → ReportController → ReportOrchestrator
|
||||||
|
├── CertificateDataService (4 SP → anagrafica, sottostanti, eventi, scenario)
|
||||||
|
├── AnagraficaSectionRenderer → PdfDocument (Sezione 1)
|
||||||
|
├── EventiSectionRenderer → PdfDocument (Sezione 2)
|
||||||
|
├── ScenarioSectionRenderer → PdfDocument (Sezione 3, opzionale)
|
||||||
|
├── ChartDataService (3 SP → dati grafico)
|
||||||
|
├── SkiaChartRenderer → PNG in memoria
|
||||||
|
├── ChartSectionRenderer → PdfDocument (Sezione 4)
|
||||||
|
└── PdfMergerService → byte[] → Response
|
||||||
|
```
|
||||||
|
|
||||||
|
**Aggiungere una nuova sezione PDF**: implementare `IPdfSectionRenderer`, impostare `SectionName` e `Order`, registrare in `Program.cs` come `AddScoped<IPdfSectionRenderer, NuovaSezione>()`. L'orchestratore la include automaticamente ordinandola per `Order`.
|
||||||
|
|
||||||
|
**Tema**: tutto in `PdfTheme.cs` — colori, font, layout, brush/pen. Modificare lì per aggiornare tutti i renderer.
|
||||||
|
|
||||||
|
**Palette colori principale** (stile "Ibrido elegante"):
|
||||||
|
- `AccentBlue` `#1565C0` — titoli, header tabelle, valori chiave
|
||||||
|
- `NegativeRed` `#CC0000` — valori negativi (performance, rendimento)
|
||||||
|
- `PositiveGreen` `#2E7D32` — valori positivi (performance)
|
||||||
|
- Brush corrispondenti: `AccentBlueBrush`, `NegativeRedBrush`, `PositiveGreenBrush`, `TableHeaderBrush` (alias di `AccentBlueBrush`)
|
||||||
|
|
||||||
|
## Configurazione chiave
|
||||||
|
|
||||||
|
- `appsettings.json`: connection string (`CertDb`), Syncfusion license key, CryptoSettings passphrase, cache TTL
|
||||||
|
- `appsettings.Development.json`: **non deve contenere `ConnectionStrings`**, altrimenti sovrascrive `appsettings.json`
|
||||||
|
- Connection string: usare `Data Source` + `Initial Catalog` + `Encrypt=False;` per `Microsoft.Data.SqlClient` v5
|
||||||
|
- Se la connessione fallisce via Named Pipes, aggiungere prefisso `tcp:` all'indirizzo IP
|
||||||
|
|
||||||
|
## Gotcha Syncfusion v33 & SkiaSharp
|
||||||
|
|
||||||
|
| Problema | Soluzione |
|
||||||
|
|----------|-----------|
|
||||||
|
| `Color(r,g,b)` rimosso | `Color.FromArgb(255, r, g, b)` |
|
||||||
|
| `Syncfusion.Drawing.Net.Core` non esiste | Inglobato in `Syncfusion.Pdf.Net.Core`, rimuovere dal `.csproj` |
|
||||||
|
| `PdfStandardFont` non è IDisposable | Non usare `using` sulla dichiarazione |
|
||||||
|
| `grid.Headers` non iterabile con `foreach` | `for (int r = 0; r < grid.Headers.Count; r++)` |
|
||||||
|
| `PdfTextWebLink` non trovato | Aggiungere `using Syncfusion.Pdf.Interactive;` |
|
||||||
|
| `RectangleF` non supporta named arguments | `new RectangleF(x, y, w, h)` — no `startY:` o simili |
|
||||||
|
| `grid.Draw()` restituisce `void` | Stimare altezza con `(rows + 1) * RowHeight` |
|
||||||
|
| `PdfMergerService`: stream chiuso prima del `Save()` | Tenere tutti gli stream aperti fino al salvataggio finale, poi cleanup in `finally` |
|
||||||
|
| SkiaSharp `DrawText` obsoleto | `SKFont` + `canvas.DrawText(text, x, y, SKTextAlign, font, paint)` |
|
||||||
|
| Namespace conflict `CertReports.Syncfusion.Pdf` | Aggiungere `using Syncfusion.Pdf;` esplicito nel file |
|
||||||
|
|
||||||
|
## Database
|
||||||
|
|
||||||
|
Tutte le stored procedure sono su `FirstSolutionDB`. I dati tornano **già formattati come stringhe** dalle SP (es. `FORMAT(value,'P2','it-IT')`): i modelli C# usano `string` per questi campi. Solo `NominalValue`, `PrezzoEmissione`, `CpnPagati`, `CpnDaPagare`, `CpnInMemoria` sono `decimal?` perché servono come valori numerici nel rendering.
|
||||||
|
|
||||||
|
## API Endpoints
|
||||||
|
|
||||||
|
- `GET /api/report?p={isin_cifrato}` / `?alias={id}` / `/by-isin/{isin}` — PDF inline
|
||||||
|
- `GET /api/report/download?p={...}` / `?alias={...}` — PDF come allegato
|
||||||
|
- Tutti gli endpoint report accettano `?branding=true` (default `false`) per abilitare il footer "Powered by Smart Roots"
|
||||||
|
- `GET /api/chart/{isin}[?format=png|pdf&width=&height=]` — grafico standalone
|
||||||
|
- `GET /health` — health check DB + chart service
|
||||||
|
|
||||||
|
## Footer branding
|
||||||
|
|
||||||
|
Il parametro `?branding=true` aggiunge al footer di ogni pagina del report:
|
||||||
|
- Sinistra: `"Powered by "` + hyperlink PDF cliccabile `"Smart Roots"` → `https://www.smart-roots.net`
|
||||||
|
- Destra: numero pagina
|
||||||
|
|
||||||
|
Con `branding=false` (default): solo numero pagina centrato.
|
||||||
|
|
||||||
|
La cache usa chiavi separate: `{isin}:branded` vs `{isin}`. Il flag è propagato come `CertificateReportData.ShowBranding` e passato a `PdfTheme.DrawFooter(g, pageWidth, pageHeight, pageNumber, showBranding)`. L'hyperlink usa `PdfTextWebLink` (richiede `using Syncfusion.Pdf.Interactive;`).
|
||||||
|
|
||||||
|
## Sezione 1 — AnagraficaSectionRenderer
|
||||||
|
|
||||||
|
Struttura a 3 sezioni verticali in una singola pagina A4:
|
||||||
|
|
||||||
|
| Sezione | Contenuto |
|
||||||
|
|---------|-----------|
|
||||||
|
| **Titolo** | "Scheda Prodotto {ISIN}" blu + Bid/Ask a destra + linea separatrice blu |
|
||||||
|
| **A — Caratteristiche Prodotto** | Tabella emittente a sinistra (ISIN, Mercato, Valuta, Date, Autocall) + tabella cedole a destra (CpnPagati/DaPagare/InMemoria, RendimentoAttuale) |
|
||||||
|
| **B — Analisi** | 8 KV a sinistra + 9 KV a destra. Leva/FattoreAirbag/TriggerOneStar mostrati come `"—"` anche se vuoti |
|
||||||
|
| **C — Sottostanti** | PdfGrid 9 colonne: Nome, Strike, Last, % Perf., Barr.K, Buffer K, Trig.CPN, Buf.CPN, Trig.AC (Dist.AC rimossa) |
|
||||||
|
|
||||||
|
Se la tabella Sottostanti non entra (y > PageH-80pt), si crea una nuova pagina. Il footer viene disegnato su ogni pagina con `PdfTheme.DrawFooter`.
|
||||||
Reference in New Issue
Block a user