9.1 KiB
Design Spec — Report ETF/Fondi
Data: 2026-06-08
Scope: Nuovo report PDF a 2 pagine per ETF/fondi, con endpoint dedicati /api/report/fund/ e /api/chart/fund/. Indipendente dal flusso certificati.
1. Endpoints
Report PDF
| Metodo | Route | Comportamento |
|---|---|---|
| GET | /api/report/fund/by-isin/{isin} |
PDF inline |
| GET | /api/report/fund?p={isin_cifrato} |
PDF inline (ISIN cifrato, stesso CryptoHelper) |
| GET | /api/report/fund?alias={id} |
PDF inline (alias → ISIN via FindIsinByAliasIdAsync) |
| GET | /api/report/fund/download?p={...} |
PDF come allegato (Content-Disposition: attachment) |
Grafico standalone
| Metodo | Route | Comportamento |
|---|---|---|
| GET | /api/chart/fund/{isin} |
PNG/PDF inline (vedi §4) |
Parametri opzionali (tutti gli endpoint report)
| Parametro | Default | Effetto |
|---|---|---|
?branding=true |
false |
Footer "Powered by Smart Roots" — riusa PdfTheme.DrawFooter già esistente |
Parametri opzionali (endpoint chart)
| Parametro | Default | Effetto |
|---|---|---|
?format=png|pdf|jpg|jpeg |
png |
Formato output |
?save=true |
false |
Salva JPEG su disco (ChartSettings:SavePath) |
2. Architettura
HTTP → FundReportController
├── FundDataService sfih_GetOptDettagli @ISIN → FundInfo
├── FundReportOrchestrator
│ ├── FundAnagraficaRenderer → PdfDocument (Pagina 1)
│ ├── FundChartRenderer → PdfDocument (Pagina 2, placeholder)
│ └── PdfMergerService → byte[] (riusato)
└── PdfCacheService → cache chiave "fund:{isin}[:branded]"
HTTP → FundChartController
├── FundChartDataService SP da definire → FundChartData
└── FundSkiaChartRenderer → PNG/JPEG/PDF
Riuso componenti esistenti: PdfMergerService, PdfCacheService, PdfTheme (incluso DrawFooter), CryptoHelper.
Nessuna modifica ai controller/renderer/service certificati esistenti.
3. Pagina 1 — Anagrafica (Layout C)
Struttura visiva
┌─────────────────────────────────────────────────────────┐
│ [BLUE BAR] {typ} — {str} — {isn} │
├──────────────────────────────────────────────────────────┤
│ [RANK strip] rnk │ [PREZZO strip] prz val │ dpz │
├──────────────────────────────────────────────────────────┤
│ Dati Anagrafici │ ESG Score │ Perf·Vol·R/R grid │
│ (flex 1.3) │ (flex 0.9) │ (flex 1.4) │
└──────────────────────────────────────────────────────────┘
│ footer: [Powered by Smart Roots]? pagina N │
Mapping campi SP → sezioni
Titolo:
{typ} — {str} — {isn}(es.ETF — WisdomTree … — IE00BDVPNG13)
Strip Rank/Prezzo:
- Rank:
rnk - Prezzo:
prz+val - Data aggiornamento:
dpz(formatodd/MM/yyyy)
Dati Anagrafici (tabella label/valore):
| Label | Campo SP |
|---|---|
| Società | soc |
| Categoria MS | msc |
| Tipo | typ |
| Valuta | val |
| Hedged | hed (→ "sì" / "no") |
| Benchmark | bmk |
| Spese correnti | spc (→ formato 0.##%) |
| Catalogo | itr |
| Proventi | prv |
| Data lancio | daf (formato dd/MM/yyyy) |
| Patrimonio | pat (formato #,##0 EUR) |
ESG Score (4 card verdi verticali):
- Sustainability:
sus - Environmental:
env - Social:
ssc - Governance:
gov - Se un singolo valore è
0(AMC/fallback), viene mostrato come"—". La sezione ESG è sempre visibile.
Griglia Performance/Volatilità/RendRisk (3×2):
| Periodo | Perf | Vol | R/R |
|---|---|---|---|
| 3 Mesi | p3M |
v3M |
r3M |
| 6 Mesi | p6M |
v6M |
r6M |
| Da inizio anno | pYD |
vYD |
rYD |
| 1 Anno | p1Y |
v1Y |
r1Y |
| 3 Anni | p3Y |
v3Y |
r3Y |
| 5 Anni | p5Y |
v5Y |
r5Y |
Colori: Perf positiva → PositiveGreenBrush, negativa → NegativeRedBrush, Vol e R/R → testo normale.
4. Pagina 2 — Grafico (placeholder)
Il rendering della pagina 2 è un placeholder in questa fase. La SP del grafico verrà fornita in seguito.
FundChartRenderer restituisce per ora una pagina con il testo "Grafico non disponibile" oppure viene omessa se la SP non è configurata. La struttura è pronta per accogliere la SP senza modifiche all'orchestratore.
FundSkiaChartRenderer (endpoint /api/chart/fund/{isin}):
- Singola linea: close price storico (
Px_Closeda SP da definire) - Supporta
?format=png|jpg|jpeg|pdfe?save=true - Nessuna logica WorstOf/barriere/label complesse
5. Modelli
File: Models/FundModels.cs
// Mapping 1:1 con result set di sfih_GetOptDettagli
public class FundInfo
{
public string Isin { get; set; } // isn
public string Strumento { get; set; } // str
public string Tipo { get; set; } // typ
public string Societa { get; set; } // soc
public string CategoriaMorningstar { get; set; } // msc
public string Valuta { get; set; } // val
public string Hedged { get; set; } // hed
public string Benchmark { get; set; } // bmk
public string Catalogo { get; set; } // itr
public string Proventi { get; set; } // prv
public DateTime? DataLancio { get; set; } // daf
public decimal? Patrimonio { get; set; } // pat
public decimal? SpeseCorrenti { get; set; } // spc
public decimal? Prezzo { get; set; } // prz
public DateTime? DataPrezzo { get; set; } // dpz
public decimal? Rank { get; set; } // rnk
// Performance
public decimal? P3M { get; set; } public decimal? P6M { get; set; }
public decimal? PYD { get; set; } public decimal? P1Y { get; set; }
public decimal? P3Y { get; set; } public decimal? P5Y { get; set; }
// Volatilità
public decimal? V3M { get; set; } public decimal? V6M { get; set; }
public decimal? VYD { get; set; } public decimal? V1Y { get; set; }
public decimal? V3Y { get; set; } public decimal? V5Y { get; set; }
// RendRisk
public decimal? R3M { get; set; } public decimal? R6M { get; set; }
public decimal? RYD { get; set; } public decimal? R1Y { get; set; }
public decimal? R3Y { get; set; } public decimal? R5Y { get; set; }
// ESG
public decimal? Sustainability { get; set; } // sus
public decimal? Environmental { get; set; } // env
public decimal? Social { get; set; } // ssc
public decimal? Governance { get; set; } // gov
}
public class FundReportData
{
public FundInfo Info { get; set; }
public bool ShowBranding { get; set; }
}
6. Interfacce
// IFundDataService
Task<FundInfo?> GetFundInfoAsync(string isin);
Task<string?> FindIsinByAliasIdAsync(string aliasId); // riusa stessa logica
// IFundReportOrchestrator
Task<byte[]> GenerateReportAsync(string isin, bool showBranding = false);
7. Registrazioni Program.cs
builder.Services.AddScoped<IFundDataService, FundDataService>();
builder.Services.AddScoped<IFundReportOrchestrator, FundReportOrchestrator>();
builder.Services.AddScoped<FundAnagraficaRenderer>();
builder.Services.AddScoped<FundChartRenderer>(); // placeholder
builder.Services.AddScoped<FundSkiaChartRenderer>(); // per /api/chart/fund/
8. Cache
Chiave pattern: fund:{isin} + suffisso :branded se showBranding=true.
Riusa il PdfCacheService esistente (stesso TTL da appsettings.json).
9. File da creare
| File | Descrizione |
|---|---|
Models/FundModels.cs |
FundInfo, FundReportData, FundChartData (placeholder) |
Services/Interfaces/IFundServices.cs |
IFundDataService, IFundReportOrchestrator |
Services/Implementations/FundDataService.cs |
Chiama sfih_GetOptDettagli |
Services/Implementations/FundAnagraficaRenderer.cs |
Pagina 1 layout C |
Services/Implementations/FundChartRenderer.cs |
Pagina 2 placeholder |
Services/Implementations/FundReportOrchestrator.cs |
Coordina anagrafica + chart + merge + cache |
Services/Implementations/FundSkiaChartRenderer.cs |
Rendering grafico (placeholder, SP da aggiungere) |
Controllers/FundReportController.cs |
4 endpoint /api/report/fund/ |
Controllers/FundChartController.cs |
1 endpoint /api/chart/fund/ |
10. Fuori scope (questa iterazione)
- SP grafico:
FundChartDataServiceeFundSkiaChartRendererrimangono placeholder fino alla fornitura della SP - Parametri
?natixis,?dividend— non applicabili ai fondi - Test automatici (nessun test nel progetto al momento)