Initial commit

This commit is contained in:
2025-11-28 10:59:10 +01:00
commit 14b3e965d0
540 changed files with 784121 additions and 0 deletions

912
CLAUDE.md Normal file
View File

@@ -0,0 +1,912 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
---
## Quick Start - Session Recovery
**Ultima sessione:** 28 Novembre 2025
**Stato progetto:** Migrazione Oracle APEX → .NET + React TypeScript in corso
**Lavoro completato nell'ultima sessione:**
- **NUOVA FEATURE: Gestione Multi-Pagina nel Report Designer** - Completata
- Nuovo tipo `AprtPage` per definire pagine con impostazioni individuali (size, orientation, margins, backgroundColor)
- Ogni elemento ha `pageId` per assegnazione a pagina specifica
- Nuovo componente `PageNavigator.tsx` - sidebar con lista pagine, context menu, rinomina, duplica, elimina, riordina
- Navigazione rapida pagine in `EditorToolbar.tsx` (pulsanti prev/next, indicatore "X / Y")
- `PropertiesPanel.tsx` aggiornato per mostrare/modificare impostazioni pagina corrente
- Backend `ReportGeneratorService.cs` genera PDF multi-pagina correttamente
- Migrazione automatica template legacy (elementi senza pageId assegnati a prima pagina)
- **FIX CRITICO: Rotazione oggetti nel PDF** - Gli oggetti ruotati nel canvas ora vengono posizionati correttamente nel PDF generato
- Implementata la formula Fabric.js per calcolare il centro di rotazione
- Coordinate corrette per `originX='left'`, `originY='top'`
**Lavoro completato nelle sessioni precedenti:**
- Sistema Report PDF con editor visuale (98% completato)
- Fabric.js v6 canvas editor funzionante
- Multi-dataset support con preview
- **FIX: Data binding PDF ora funzionante** - I campi dati vengono risolti correttamente
- **FIX: Formattazione campi** - Date, valute, numeri formattati correttamente nel PDF
- Sistema Virtual Dataset implementato (CRUD completo)
- SignalR real-time updates funzionante
- **Context Menu ricco** - Tasto destro con opzioni complete stile Canva (copia, taglia, incolla, layer, allineamento, trasformazioni)
- **FIX: Posizionamento assoluto PDF FUNZIONANTE** - SVG con viewBox in mm, coordinate corrette
- **FIX: Immagini nel PDF** - Data URI, API URL e risorse embedded ora renderizzate correttamente
- **FIX: Font size nel PDF** - Conversione corretta da px screen a mm per SVG
**Per riprendere il lavoro sui Report:**
1. Vai alla sezione "Report PDF System - Implementation Details" più sotto
2. Consulta la "Checklist Completamento Report System" per vedere cosa manca
3. I file principali sono:
- Backend: `/src/Apollinare.API/Controllers/ReportsController.cs`
- Frontend: `/frontend/src/pages/ReportEditorPage.tsx`
- Canvas: `/frontend/src/components/reportEditor/EditorCanvas.tsx`
- **Context Menu:** `/frontend/src/components/reportEditor/ContextMenu.tsx`
- **PDF Generator:** `/src/Apollinare.API/Services/Reports/ReportGeneratorService.cs`
- **Page Navigator:** `/frontend/src/components/reportEditor/PageNavigator.tsx`
**Prossimi task prioritari (Report System):**
1. [x] ~~**CRITICO: Posizionamento assoluto PDF**~~ - COMPLETATO
2. [x] ~~Implementare caricamento immagini reali~~ - COMPLETATO
3. [x] ~~**FIX: Rotazione oggetti nel PDF**~~ - COMPLETATO
4. [x] ~~**Gestione Multi-Pagina**~~ - COMPLETATO
5. [ ] Aggiungere rendering tabelle dinamiche per collection
6. [ ] Gestire sezioni header/footer ripetute su ogni pagina
7. [ ] UI per relazioni tra dataset multipli
**Comandi utili:**
```bash
# Build backend
cd src && dotnet build
# Build frontend
cd frontend && npm run build
# Run backend (porta 5000)
cd src/Apollinare.API && dotnet run
# Run frontend dev (porta 5173)
cd frontend && npm run dev
```
---
## Project Overview
This repository contains documentation for migrating the **Apollinare Catering & Banqueting Management Software** from Oracle APEX to .NET + React TypeScript.
**Original Application:**
- Oracle APEX 21.1.0 (Application ID: 112)
- 56 pages, 302 items, 98 processes
- Database: Oracle 18 XE (schema: APOLLINARECATERINGPROD)
- Language: Italian
**Target Stack:**
- Backend: .NET (C#)
- Frontend: React TypeScript (not Vue - note the user request mentions Vue but the actual target is React TypeScript)
- Database: Oracle 18 XE (read-only access for analysis)
## Database Connection (Read-Only)
**Connection Details:**
- Database: Oracle 18 XE
- Username: `apollinarecateringprod`
- Password: `bmwmRaSBRT53Z2J8CCvYK45EPDyAJ4`
- Database: `xepdb1`
- Hostname: `apollinare`
- Port: `1521`
**Important:** This connection is READ-ONLY. Use it only to analyze schema, extract business logic from procedures/packages/functions, and understand data relationships.
## Application Architecture
### Core Business Domain: Event Catering Management
The application manages the complete lifecycle of catering events from quote to execution, including:
- Event creation and management
- Client and location management
- Inventory (articles) with image storage
- Quote generation with complex calculations
- Resource (staff) scheduling
- Kitchen and setup reports
- Multi-level authorization system
### Main Business Entities
**Events (EVENTI)** - Central entity
- Event details (date, location, client, event type)
- Guest counts by type (adults, children, seated, buffet)
- Status workflow: 0 (Scheda) → 10 (Preventivo/Quote) → 20 (Confermato/Confirmed)
- Quote expiration tracking
- Distance calculations for location
**Event Details (1:N relationships):**
- `EVENTI_DET_OSPITI` - Guest type breakdown
- `EVENTI_DET_PREL` - Pick lists (articles needed for the event)
- `EVENTI_DET_RIS` - Resource assignments (staff)
- `EVENTI_DET_DEGUST` - Tasting event details
- `EVENTI_ACCONTI` - Deposits/advances
- `EVENTI_ALLEG` - Attachments
- `EVENTI_ALTRICOSTI` - Other costs
**Master Data:**
- `ARTICOLI` - Articles/items with images (BLOB), quantities, coefficients
- `TB_CODICI_CATEG` - Categories with calculation coefficients (COEFF_A/B/S)
- `TB_TIPI_MAT` - Material types
- `TB_TIPI_EVENTO` - Event types with meal classifications
- `TB_TIPI_OSPITI` - Guest types
- `CLIENTI` - Clients
- `LOCATION` - Event locations
- `RISORSE` - Resources (staff) with type classification
### Critical Business Logic in Database
**Key Stored Procedures:**
- `EVENTI_AGGIORNA_QTA_LISTA(p_event_id)` - Updates pick list quantities based on guest counts and coefficients
- `EVENTI_AGGIORNA_TOT_OSPITI(p_event_id)` - Recalculates total guest count
- `EVENTI_RICALCOLA_ACCONTI(p_event_id)` - Recalculates deposit amounts
- `EVENTI_COPIA` - Event duplication functionality
- `EVENTI_PREPARE` - Event preparation process
**Key Functions:**
- `F_GET_QTA_IMPEGNATA(cod_articolo, data)` - Returns committed quantity for an article on a specific date (inventory reservation)
- `F_EVENTO_SCADUTO(data_scad, stato, ...)` - Checks if event quote has expired
- `F_MAX_NUMERO_EVENTI_RAGGIUNTO(data)` - Enforces daily event limit
- `F_USER_IN_ROLE(app_user, role)` - Role-based authorization
- `STRING_TO_TABLE_ENUM(string, position, delimiter)` - Utility for string parsing
**Important Views:**
- `V_IMPEGNI_ARTICOLI` - Calculates article commitments across events (inventory availability)
- `V_IMPEGNI_ARTICOLI_LOC` - Article commitments by location
- `VW_CALENDARIO_EVENTI` - Calendar view of events
### Quantity Calculation Algorithm
The application uses a sophisticated coefficient-based system:
1. **Coefficients** are defined at category level (`TB_CODICI_CATEG.COEFF_A/B/S`)
2. **Standard quantities** are stored per article (`ARTICOLI.QTA_STD_A/S/B`)
3. **Guest counts** by type determine multipliers (`EVENTI_DET_OSPITI`)
4. **Final quantities** calculated as: `Guest_Count × Coefficient × Standard_Qty`
Types: A (Adulti/Adults), S (Seduti/Seated), B (Buffet)
### Authorization Model
**5 Authorization Levels:**
1. **Admin_auth_schema** - Full admin access
- Users: admin, monia, andrea, maria, sabrina, nicole, cucina, developer, elia.ballarani
2. **User Read/Write** - Controlled by `USERS_READONLY` table
- `FLGWRITE` flag determines write access
3. **Consuntivi** - Access to financial summaries
- Users from `GET_CONSUNTIVI_USERS` view
4. **Gestori** (Managers) - Manager-level permissions
- Users from `GET_GESTORI_USERS` view
5. **Solo Admins** - Highest level
- Only: admin, monia
**Session Management:**
- `SET_USER_READONLY` process runs before header on every page
- Sets `APP_READ_ONLY` application item based on user permissions
### Page Structure (56 Pages)
**Master Data Pages:**
- Pages 2-3: Articles (list + form)
- Pages 4-5: Categories
- Pages 6-7: Types
- Pages 17-18: Clients
- Pages 15, 20: Locations
- Page 31: Resources (staff)
**Event Management:**
- Page 1: Dashboard
- Page 8: Event creation wizard
- Page 9: Event list
- Page 12: Calendar view
- Pages 13-14: Event types
- **Page 22: Main event form** (most complex - multiple interactive grids)
- Page 27, 32: Tastings
- Page 35: Event cards/confirmed cards
- Page 48: Event templates
**Reports:**
- Page 16: Grid view
- Page 25: Kitchen summary
- Page 28: Cakes and extra costs
- Page 30: Setup summary
- Page 38: Resources summary
- Page 39: Article commitments
**Admin:**
- Page 45: Data management
- Page 46: Max events configuration
- Page 47: Permissions
- Page 49: Scheduled jobs
- Page 50: Sent emails
- Page 51: Pending emails
### External Integrations
**JasperReports:**
- Quote reports (preventivi)
- Event cards (schede evento)
- Kitchen summaries
- Custom iframeObj.js wrapper for embedding reports
**Email System:**
- Mail queue (pages 50-51)
- Background job processing (page 49)
- Template-based notifications
**Custom JavaScript:**
- `ajaxUtils.js` - AJAX utilities for dynamic updates
- `notifica(pText, pType)` - Dynamic notifications
- `setSessionState(elemList, pCallback)` - Session state management
- `ajaxExec(...)` - Generic AJAX execution
- `execProcessAsync(...)` - Async process execution
- `execQueryAsync(...)` - Async query execution
### Migration Considerations
**Complex Features Requiring Special Attention:**
1. **Page 22 (Nuovo Evento)** - Most complex page
- Multiple editable interactive grids on single page
- Master-detail relationships with real-time calculations
- Guest type grid → triggers quantity recalculations in pick list grids
- Resource assignment grid
- Requires careful state management in React
2. **BLOB Storage for Images**
- Article images stored as BLOBs in Oracle
- Migration strategy needed (Azure Blob Storage, AWS S3, or filesystem)
- MIMETYPE tracking for proper rendering
3. **PL/SQL Business Logic**
- Decision needed: Port to C# or keep as Oracle functions?
- Quantity calculations are complex - ensure parity
- Inventory commitment logic (V_IMPEGNI_ARTICOLI) is critical
4. **State Management**
- Heavy use of APEX session state
- Consider Redux Toolkit or Zustand for React
- Real-time grid updates and calculations
5. **Reporting**
- JasperReports replacement needed
- Options: SSRS, Crystal Reports, DevExpress, or PDF libraries (iTextSharp, QuestPDF)
6. **Email Queue System**
- Asynchronous processing required
- Consider: Hangfire, Azure Functions, or background services
7. **Calendar Component**
- Page 12 uses APEX calendar
- React options: FullCalendar, React Big Calendar, @event-calendar/core
8. **Multi-Grid Interactions**
- Interactive grids with master-detail relationships
- Consider: AG Grid, DevExtreme DataGrid, or Material-UI DataGrid
## Business Rules to Preserve
1. **Event Status Workflow:** Must follow 0 → 10 → 20 progression
2. **Quote Expiration:** Automatic status change when `DATA_SCAD_PREVENTIVO` passed
3. **Max Events Per Day:** Enforced limit (configurable)
4. **Article Commitment Tracking:** Prevent overbooking of inventory
5. **Coefficient-Based Calculations:** Ensure quantity formulas match exactly
6. **Deposit Calculations:** Auto-recalculation on cost changes
7. **Role-Based Access:** 5-level authorization system
8. **Read-Only Mode:** User-specific write restrictions
## Data Extraction Queries
When analyzing the database, useful queries:
```sql
-- Get all tables in schema
SELECT table_name FROM user_tables ORDER BY table_name;
-- Get table structure
SELECT column_name, data_type, nullable, data_default
FROM user_tab_columns
WHERE table_name = 'EVENTI'
ORDER BY column_id;
-- Get all procedures and functions
SELECT object_name, object_type
FROM user_objects
WHERE object_type IN ('PROCEDURE', 'FUNCTION', 'PACKAGE')
ORDER BY object_type, object_name;
-- Get procedure source
SELECT text FROM user_source
WHERE name = 'EVENTI_AGGIORNA_QTA_LISTA'
ORDER BY line;
-- Get view definitions
SELECT view_name, text FROM user_views
WHERE view_name LIKE 'V_%' OR view_name LIKE 'VW_%';
-- Get foreign key relationships
SELECT a.constraint_name, a.table_name, a.column_name,
c_pk.table_name r_table_name, c_pk.constraint_name r_constraint_name
FROM user_cons_columns a
JOIN user_constraints c ON a.constraint_name = c.constraint_name
JOIN user_constraints c_pk ON c.r_constraint_name = c_pk.constraint_name
WHERE c.constraint_type = 'R'
ORDER BY a.table_name, a.constraint_name;
```
## File References
- `apollinare-db-connection.md` - Database connection details (credentials)
- `f112.sql` - Complete APEX export (53,282 lines)
- Application structure
- Page definitions
- Processes and validations
- LOVs and static data
- JavaScript libraries
## Development Approach
When working on migration tasks:
1. **Always query the database** to understand current data structure and relationships
2. **Extract PL/SQL source code** for procedures/functions before implementing equivalent C# logic
3. **Document business rules** discovered in stored procedures
4. **Preserve Italian field names** in database but consider English in application layer
5. **Test quantity calculations** thoroughly - they are core to the business
6. **Map APEX page flows** to React routes and components
7. **Identify reusable components** (grids, forms, lookups)
8. **Plan data migration** for BLOBs and complex relationships
## Key Terminology (Italian → English)
- **Scheda** → Card/Draft (Event status 0)
- **Preventivo** → Quote (Event status 10)
- **Confermato** → Confirmed (Event status 20)
- **Lista Prelievo** → Pick List (articles for event)
- **Articoli** → Articles/Items
- **Ospiti** → Guests
- **Risorse** → Resources (staff)
- **Degustazioni** → Tastings
- **Allestimenti** → Setups
- **Acconti** → Deposits/Advances
- **Impegni** → Commitments (inventory reservations)
## Notes
- The application is mature and in production use
- Italian language throughout (UI, database, code comments)
- Complex business logic embedded in database layer
- Heavy use of APEX-specific features (Interactive Grids, Dynamic Actions)
- Real-time calculations and validations are critical to user experience
---
## Report PDF System - Implementation Details
### Overview
Sistema completo di generazione report PDF con editor visuale drag-and-drop (stile Canva) e metalinguaggio APRT (Apollinare Report Template) per template portabili.
### Stack Tecnologico
**Backend:**
- QuestPDF (Community License) - Generazione PDF programmatica
- .NET 9 Web API con Entity Framework Core
- SQLite per storage template, font e immagini
**Frontend:**
- React 19 + TypeScript + Vite
- Fabric.js v6 - Canvas editor per design visuale
- Material-UI per componenti UI
### Stato Corrente dell'Implementazione
#### Backend (COMPLETATO)
**Entities** (`/src/Apollinare.Domain/Entities/`):
- `ReportTemplate.cs` - Template con JSON, thumbnail, metadata
- `ReportFont.cs` - Font custom uploadabili (TTF/OTF)
- `ReportImage.cs` - Immagini riutilizzabili nei report
**Services** (`/src/Apollinare.API/Services/Reports/`):
- `ReportGeneratorService.cs` - Parsing APRT e generazione PDF con QuestPDF
- `AprtModels.cs` - Modelli C# per il metalinguaggio APRT
**Controllers** (`/src/Apollinare.API/Controllers/`):
- `ReportTemplatesController.cs` - CRUD template, clone, import/export
- `ReportResourcesController.cs` - Gestione font e immagini
- `ReportsController.cs` - Generazione PDF, schema dati, dataset management
**API Endpoints disponibili:**
```
# Templates
GET /api/report-templates
GET /api/report-templates/{id}
POST /api/report-templates
PUT /api/report-templates/{id}
DELETE /api/report-templates/{id}
POST /api/report-templates/{id}/clone
GET /api/report-templates/{id}/export
POST /api/report-templates/import
GET /api/report-templates/categories
# Resources
GET /api/report-resources/fonts
POST /api/report-resources/fonts
DELETE /api/report-resources/fonts/{id}
GET /api/report-resources/fonts/families
GET /api/report-resources/images
POST /api/report-resources/images
DELETE /api/report-resources/images/{id}
# Report Generation
POST /api/reports/generate
GET /api/reports/evento/{eventoId}
POST /api/reports/preview
GET /api/reports/datasets
GET /api/reports/schema/{datasetId}
GET /api/reports/datasets/{datasetId}/entities
```
#### Frontend (COMPLETATO ~90%)
**Pagine** (`/frontend/src/pages/`):
- `ReportTemplatesPage.tsx` - Lista template con cards, filtri, import/export
- `ReportEditorPage.tsx` - Editor principale con undo/redo, shortcuts
**Componenti Editor** (`/frontend/src/components/reportEditor/`):
- `EditorCanvas.tsx` - Canvas Fabric.js per design visuale
- `EditorToolbar.tsx` - Toolbar con strumenti, zoom, grid, azioni
- `PropertiesPanel.tsx` - Pannello proprietà elemento/pagina
- `DataBindingPanel.tsx` - Browser campi dati con supporto multi-dataset
- `DatasetSelector.tsx` - Selezione dataset per template
- `PreviewDialog.tsx` - Dialog selezione entità per anteprima
**Types** (`/frontend/src/types/report.ts`):
- Definizioni complete APRT (AprtTemplate, AprtElement, AprtStyle, etc.)
- DTOs per API (ReportTemplateDto, DataSchemaDto, DatasetTypeDto, etc.)
- Utility functions (mmToPx, pxToMm, getPageDimensions)
**Services** (`/frontend/src/services/reportService.ts`):
- reportTemplateService - CRUD template
- reportFontService - Gestione font
- reportImageService - Gestione immagini
- reportGeneratorService - Generazione PDF e schema
### Metalinguaggio APRT (Apollinare Report Template)
Formato JSON esportabile/importabile per portabilità template:
```json
{
"version": "1.0",
"meta": {
"name": "Template Evento",
"pageSize": "A4",
"orientation": "portrait",
"margins": { "top": 20, "right": 15, "bottom": 20, "left": 15 }
},
"resources": {
"fonts": [],
"images": []
},
"dataSources": {
"evento": { "type": "object", "schema": "evento" }
},
"sections": [],
"elements": [
{
"id": "uuid",
"type": "text",
"position": { "x": 20, "y": 20, "width": 100, "height": 20 },
"style": {
"fontFamily": "Helvetica",
"fontSize": 14,
"color": "#000000"
},
"content": { "type": "binding", "expression": "{{evento.codice}}" },
"section": "body"
}
]
}
```
**Tipi elemento supportati:** text, image, shape, table, line, barcode
**Data binding:** `{{campo}}`, `{{dataset.campo}}`, `{{collection.campo}}`
**Variabili speciali:** `{{$pageNumber}}`, `{{$totalPages}}`, `{{$date}}`, `{{$datetime}}`
### Dataset Disponibili
| Dataset ID | Nome | Descrizione |
| ---------- | -------- | ------------------------------------------------------------------ |
| evento | Evento | Dati evento con cliente, location, dettagli ospiti, costi, risorse |
| cliente | Cliente | Anagrafica clienti completa |
| location | Location | Sedi e location eventi |
| articolo | Articolo | Catalogo articoli e materiali |
| risorsa | Risorsa | Staff e personale |
### Funzionalità Implementate
- [x] Editor visuale drag-and-drop con Fabric.js
- [x] Supporto elementi: testo, forme, linee, tabelle, immagini (placeholder)
- [x] Gestione zoom (25% - 200%)
- [x] Griglia e snap to grid
- [x] Undo/Redo (max 20 stati)
- [x] Shortcuts tastiera (Ctrl+Z, Ctrl+Y, Ctrl+S, Delete)
- [x] Pannello proprietà con posizione, stile, contenuto
- [x] Data binding con browser campi disponibili
- [x] Selezione multipla dataset per template
- [x] Preview con selezione entità reali
- [x] Salvataggio/caricamento template
- [x] Import/export template come file .aprt
- [x] Clone template
- [x] Generazione PDF default per eventi
- [x] Formattazione campi (valuta, data, numero, percentuale)
### Cosa Manca per Completare
#### Alta Priorità
- [ ] **Caricamento immagini reali** - Attualmente placeholder, implementare upload e rendering
- [ ] **Tabelle dinamiche** - Rendering collection dati (es. lista ospiti, articoli)
- [ ] **Sezioni header/footer** - Ripetizione su ogni pagina
- [ ] **Font custom** - Upload e utilizzo font TTF/OTF nei PDF
#### Media Priorità
- [ ] **Relazioni tra dataset** - UI per collegare campi tra dataset diversi
- [ ] **Barcode/QRCode** - Supporto codici a barre
- [ ] **Formule calcolate** - Espressioni matematiche nei campi
- [ ] **Stili condizionali** - Formattazione basata su valore dati
- [ ] **Raggruppamento elementi** - Group/ungroup nel canvas
#### Bassa Priorità
- [ ] **Template predefiniti** - Library di template pronti all'uso
- [ ] **Anteprima live** - Preview in tempo reale durante editing
- [x] ~~**Multi-pagina** - Editor pagine multiple~~ - COMPLETATO
- [ ] **Righelli e guide** - Ausili allineamento avanzati
- [ ] **Esportazione altri formati** - Excel, Word oltre PDF
---
## Checklist Completamento Report System
### Backend
- [x] Entity ReportTemplate
- [x] Entity ReportFont
- [x] Entity ReportImage
- [x] ReportTemplatesController (CRUD + clone + import/export)
- [x] ReportResourcesController (fonts + images)
- [x] ReportsController (generate + preview + schema + datasets)
- [x] ReportGeneratorService con QuestPDF
- [x] Schema dati per tutti i dataset (evento, cliente, location, articolo, risorsa)
- [x] Generazione PDF default evento
- [x] Generazione PDF multi-pagina
- [ ] Rendering tabelle dinamiche da collection
- [ ] Supporto font custom nel PDF
- [ ] Rendering immagini da storage
### Frontend
- [x] ReportTemplatesPage (lista + filtri + azioni)
- [x] ReportEditorPage (editor principale)
- [x] EditorCanvas con Fabric.js v6
- [x] EditorToolbar completa
- [x] PropertiesPanel (posizione + stile + contenuto)
- [x] DataBindingPanel multi-dataset
- [x] DatasetSelector
- [x] PreviewDialog con selezione entità
- [x] Types APRT completi
- [x] Services API completi
- [x] Undo/Redo
- [x] Keyboard shortcuts
- [x] PageNavigator (gestione multi-pagina)
- [x] Navigazione pagine in toolbar
- [ ] Upload e gestione immagini nell'editor
- [ ] Editor tabelle avanzato (colonne, binding dati)
- [ ] UI relazioni tra dataset
- [ ] Gestione sezioni header/footer
### Testing
- [x] Build frontend senza errori
- [x] Build backend senza errori
- [ ] Test funzionale editor canvas
- [x] Test generazione PDF con dati reali (binding e formattazione funzionanti)
- [ ] Test import/export template
- [ ] Test con font e immagini custom
### Documentazione
- [x] Documentazione APRT metalanguage
- [x] Lista API endpoints
- [x] Checklist implementazione
- [ ] Guida utente editor
- [ ] Esempi template comuni
---
## Note Tecniche per Future Sessioni
### Struttura File Report System
```
src/
├── Apollinare.Domain/Entities/
│ ├── ReportTemplate.cs # Entity template con TemplateJson
│ ├── ReportFont.cs # Font custom uploadati
│ └── ReportImage.cs # Immagini riutilizzabili
├── Apollinare.API/
│ ├── Controllers/
│ │ ├── ReportTemplatesController.cs # CRUD template
│ │ ├── ReportResourcesController.cs # Font e immagini
│ │ └── ReportsController.cs # Generazione PDF + schema
│ │
│ └── Services/Reports/
│ ├── ReportGeneratorService.cs # QuestPDF generator
│ └── AprtModels.cs # Modelli C# per APRT JSON
frontend/src/
├── pages/
│ ├── ReportTemplatesPage.tsx # Lista template
│ └── ReportEditorPage.tsx # Editor principale
├── components/reportEditor/
│ ├── EditorCanvas.tsx # Fabric.js canvas
│ ├── EditorToolbar.tsx # Toolbar strumenti
│ ├── PropertiesPanel.tsx # Proprietà elemento
│ ├── DataBindingPanel.tsx # Browser campi dati
│ ├── DatasetSelector.tsx # Selezione dataset
│ ├── PreviewDialog.tsx # Dialog anteprima
│ └── ContextMenu.tsx # Menu tasto destro (NEW)
├── types/
│ └── report.ts # Types APRT + DTOs
└── services/
└── reportService.ts # API calls
```
### Problemi Risolti (da ricordare)
1. **Fabric.js v6 breaking changes:**
- `sendToBack()``canvas.sendObjectToBack(obj)`
- Event handlers hanno signature diversa
- Proprietà `data` non è nel tipo base, serve cast a `FabricObjectWithData`
2. **TypeScript strict mode:**
- Usare `as any` per event handlers Fabric.js
- Interface `FabricObjectWithData` per oggetti con metadata custom
3. **QuestPDF TimeSpan:**
- `evento.OraInizio` è `TimeSpan?` non `string`
- Formattare con `{evento.OraInizio:hh\\:mm}`
4. **Data Binding PDF (FIX 27/11/2025):**
- **Problema:** I binding `{{dataEvento}}` non venivano risolti - PDF mostrava campi vuoti
- **Causa:** Il frontend creava binding senza prefisso dataset quando c'era un solo dataset
- **Soluzione Frontend** (`DataBindingPanel.tsx`): Sempre includere il prefisso dataset
```typescript
// Prima: {{dataEvento}} - non funzionava
// Dopo: {{evento.dataEvento}} - corretto
const createBinding = (datasetId: string, fieldName: string) => {
return `{{${datasetId}.${fieldName}}}`;
};
```
- **Soluzione Backend** (`ReportGeneratorService.cs`): Aggiunto fallback per compatibilità con template esistenti
```csharp
// Se binding senza prefisso, cerca in tutti i dataset
if (current == null && parts.Length == 1)
{
foreach (var kvp in dataContext)
{
var foundValue = GetPropertyValue(kvp.Value, path);
if (foundValue != null) { current = foundValue; break; }
}
}
```
- **Formattazione:** Aggiunto `ResolveBindingWithFormat()` per applicare format (date, currency, etc.)
5. **SignalR Connection (FIX 27/11/2025):**
- Aggiunto `app.UseWebSockets()` in Program.cs prima di `app.UseRouting()`
- Configurato signalr.ts con `withAutomaticReconnect()`
6. **MUI Fragment in Menu (FIX 27/11/2025):**
- Menu component non accetta Fragment come child
- Sostituire `<>...</>` con array `[<Divider key="..." />, <MenuItem key="..." />]`
7. **HTML p/div nesting (FIX 27/11/2025):**
- Error: `<div> cannot be a descendant of <p>`
- Fix: `<ListItemText secondaryTypographyProps={{ component: "div" }} />`
8. **Context Menu Browser Default (FIX 27/11/2025 notte):**
- **Problema:** Il menu contestuale del browser appariva invece di quello custom
- **Soluzione:** Usare `onContextMenu` su Box container React invece di eventi Fabric.js
- **File:** `EditorCanvas.tsx` - Aggiunto handler sul Box wrapper
9. **Fabric.js v6 Layer Ordering (FIX 27/11/2025 notte):**
- **Problema:** `canvas.moveTo()` non esiste in Fabric.js v6
- **Soluzione:** Usare `canvas.remove(obj)` + `canvas.insertAt(targetIndex, obj)`
- **File:** `EditorCanvas.tsx` - Aggiunto z-index sync in useEffect
10. **QuestPDF Posizionamento Assoluto (RISOLTO 27/11/2025):**
- **Problema:** QuestPDF non ha API `.Position()` per posizionamento assoluto
- **Soluzione:** Usare SVG con `viewBox` in mm per avere coordinate 1:1 con il designer
- **File:** `ReportGeneratorService.cs` - Metodi `GenerateSvgContent()`, `RenderElementToSvg()`
- **Chiave della soluzione:**
```csharp
// SVG viewBox in mm - 1 unità SVG = 1mm
svgBuilder.AppendLine($"<svg xmlns=\"...\" " +
$"width=\"{contentWidthMm}mm\" height=\"{contentHeightMm}mm\" " +
$"viewBox=\"0 0 {contentWidthMm} {contentHeightMm}\">");
```
- Le coordinate dal template sono già in mm relative all'area contenuto (dentro i margini)
- Non serve più conversione mm→px: usiamo mm direttamente nel viewBox
11. **Immagini nel PDF (RISOLTO 27/11/2025):**
- **Problema:** Le immagini embedded come data URI in `imageSettings.src` non venivano renderizzate
- **Soluzione:** `RenderImageToSvg()` ora gestisce 3 fonti:
1. Data URI (`data:image/...;base64,...`) - usato direttamente
2. API URL (`/api/report-resources/images/{id}`) - caricato da DB e convertito in data URI
3. URL esterni (`http://...`) - passato direttamente
- **File:** `ReportGeneratorService.cs` - Metodo `RenderImageToSvg()`, `GuessMimeType()`
12. **Font Size nel PDF (RISOLTO 27/11/2025):**
- **Problema:** Il font size appariva troppo grande/piccolo nel PDF
- **Causa:** La formula `fontSize * mmToPx / 3` era un'approssimazione incorretta
- **Soluzione:** Conversione corretta da px screen (96 DPI) a mm:
```csharp
// 1px @ 96 DPI = 0.2646mm
var fontSizeMm = (style?.FontSize ?? 12) * 0.2646f;
```
- **File:** `ReportGeneratorService.cs` - Metodo `RenderElementToSvg()` case "text"
13. **Rotazione Oggetti nel PDF (RISOLTO 28/11/2025):**
- **Problema:** Gli oggetti ruotati nel canvas Fabric.js venivano posizionati in modo completamente errato nel PDF
- **Causa:** In Fabric.js con `originX='left'` e `originY='top'`, quando un oggetto viene ruotato:
- L'oggetto ruota attorno al suo centro geometrico
- Le coordinate `left`/`top` salvate rappresentano la posizione dell'origin point **dopo** la rotazione
- Il backend calcolava il centro di rotazione in modo errato usando `(x + width/2, y + height/2)`
- **Soluzione:** Implementata la formula corretta di Fabric.js per calcolare il centro:
```csharp
// Calcolo del centro usando la formula Fabric.js (originX='left', originY='top')
var angleRad = rotation * Math.PI / 180f;
var halfWidth = width / 2;
var halfHeight = height / 2;
var cos = (float)Math.Cos(angleRad);
var sin = (float)Math.Sin(angleRad);
// Centro dell'oggetto in coordinate canvas
var centerX = left + halfWidth * cos - halfHeight * sin;
var centerY = top + halfWidth * sin + halfHeight * cos;
// Posizione di disegno (angolo sup-sinistro del rettangolo non ruotato centrato sul centro)
var drawX = centerX - halfWidth;
var drawY = centerY - halfHeight;
// Ruota attorno al centro calcolato
canvas.RotateDegrees(rotation, centerX, centerY);
// Disegna a (drawX, drawY)
```
- **File:** `ReportGeneratorService.cs` - Metodi `RenderElementToCanvas()` e `GenerateSvgContent()` + `RenderElementToSvg()`
- **Nota:** La stessa logica è applicata sia al rendering bitmap (SkiaSharp) che SVG
14. **Gestione Multi-Pagina (IMPLEMENTATO 28/11/2025):**
- **Struttura dati:**
- `AprtPage`: `{ id, name, pageSize?, orientation?, margins?, backgroundColor? }`
- `AprtElement.pageId`: ID della pagina a cui appartiene l'elemento
- `AprtTemplate.pages`: Array di pagine del template
- **Frontend:**
- `PageNavigator.tsx`: Sidebar con lista pagine, context menu (rinomina, duplica, elimina, sposta)
- `EditorToolbar.tsx`: Pulsanti prev/next pagina, indicatore "Pagina X di Y"
- `ReportEditorPage.tsx`: State `currentPageId`, filtro elementi per pagina, handlers CRUD pagine
- `PropertiesPanel.tsx`: Modifica nome pagina e impostazioni (format, orientation, margins, background)
- **Backend (`ReportGeneratorService.cs`):**
```csharp
// Pre-render di ogni pagina separatamente
foreach (var pageDefinition in aprt.Pages)
{
var pageElements = aprt.Elements
.Where(e => e.Visible && (e.PageId == pageDefinition.Id ||
(string.IsNullOrEmpty(e.PageId) && pageDefinition.Id == aprt.Pages[0].Id)))
.ToList();
var pageImageBytes = RenderContentToBitmap(pageElements, pageWidth, pageHeight, ...);
pageRenderData.Add((pageWidth, pageHeight, bgColor, pageImageBytes));
}
// Genera PDF con pagine separate
Document.Create(container => {
foreach (var (pageWidth, pageHeight, bgColor, imageBytes) in pageRenderData)
container.Page(page => { page.Size(...); page.Content().Image(imageBytes); });
});
```
- **Migrazione template legacy:** `MigrateTemplatePages()` crea pagina default e assegna elementi orfani
### Schema Database Report System
Le tabelle sono già nel DbContext (`AppollinareDbContext.cs`):
- `ReportTemplates` - Template salvati
- `ReportFonts` - Font custom
- `ReportImages` - Immagini riutilizzabili
Migration già applicata per SQLite.
### Dipendenze Chiave
**Backend (NuGet):**
- `QuestPDF` - Generazione PDF (Community License, gratis per revenue < $1M)
**Frontend (npm):**
- `fabric` v6.x - Canvas editor
- `uuid` - Generazione ID elementi
- `@tanstack/react-query` - Data fetching
### Routes Frontend
```typescript
// App.tsx
<Route path="/report-templates" element={<ReportTemplatesPage />} />
<Route path="/report-editor" element={<ReportEditorPage />} />
<Route path="/report-editor/:id" element={<ReportEditorPage />} />
```
Menu aggiunto in `Layout.tsx` sotto "Report" con icona PrintIcon.