Initial commit
This commit is contained in:
912
CLAUDE.md
Normal file
912
CLAUDE.md
Normal 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.
|
||||
Reference in New Issue
Block a user