# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. --- ## ISTRUZIONI OBBLIGATORIE PER CLAUDE ### Auto-Aggiornamento CLAUDE.md **OBBLIGATORIO:** Claude DEVE aggiornare questo file CLAUDE.md ogni volta che: 1. **Viene completato un task significativo** (fix, nuova feature, refactoring importante) 2. **Viene risolto un problema tecnico** che potrebbe ripresentarsi in futuro 3. **Si scopre un pattern/workaround** importante da ricordare 4. **Termina una sessione di lavoro** - aggiornare "Quick Start - Session Recovery" **Cosa aggiornare:** - **Sezione "Quick Start - Session Recovery":** - Aggiornare "Ultima sessione" con data corrente - Spostare lavoro completato da "ultima sessione" a "sessioni precedenti" - Aggiungere nuovi task completati alla lista - Aggiornare "Prossimi task prioritari" (spuntare completati, aggiungere nuovi) - **Sezione "Problemi Risolti (da ricordare)":** - Aggiungere OGNI problema tecnico risolto con: - Descrizione del problema - Causa root - Soluzione implementata - File coinvolti - **Checklist:** - Aggiornare checkbox `[x]` per task completati - Aggiungere nuovi task se scoperti durante il lavoro **Formato per nuovi problemi risolti:** ```markdown XX. **Nome Problema (FIX/IMPLEMENTATO DATA):** - **Problema:** Descrizione breve - **Causa:** Perché succedeva - **Soluzione:** Come è stato risolto - **File:** File modificati ``` **NON dimenticare:** Questo file è la memoria persistente tra sessioni. Se non viene aggiornato, il lavoro fatto andrà perso e dovrà essere riscoperto. --- ## Quick Start - Session Recovery **Ultima sessione:** 29 Novembre 2025 **Stato progetto:** Migrazione Oracle APEX → .NET + React TypeScript in corso **Lavoro completato nell'ultima sessione:** - **NUOVA FEATURE: Scorciatoie da Tastiera Complete per Report Designer** - COMPLETATO - **Problema:** Le scorciatoie da tastiera (Ctrl+X, Ctrl+C, etc.) venivano intercettate dal browser invece che dalla pagina - **Soluzione:** Riscritto completamente l'handler delle scorciatoie con: - Controllo se il focus è su campi input/textarea/contenteditable - Nuovo metodo `isTextEditing()` esposto da EditorCanvasRef per verificare editing testo nel canvas - `e.preventDefault()` per bloccare comportamento browser - **Scorciatoie implementate:** - `Ctrl+Z` - Annulla - `Ctrl+Y` - Ripeti - `Ctrl+S` - Salva - `Ctrl+X` - Taglia - `Ctrl+C` - Copia - `Ctrl+V` - Incolla - `Ctrl+D` - Duplica - `Ctrl+A` - Seleziona tutto - `Ctrl+L` - Blocca/Sblocca elemento - `Ctrl+G` - Raggruppa - `Ctrl+Shift+G` - Separa - `Ctrl+]` - Porta avanti - `Ctrl+Shift+]` - Porta in primo piano - `Ctrl+[` - Porta indietro - `Ctrl+Shift+[` - Porta in fondo - `Delete/Backspace` - Elimina elemento - `Escape` - Deseleziona - **File modificati:** - `EditorCanvas.tsx` - Aggiunto `isTextEditing()` a `EditorCanvasRef` - `ReportEditorPage.tsx` - Importato `EditorCanvasRef`, aggiunto `canvasRef`, riscritto `useEffect` delle scorciatoie - **FIX: Rimossa Toolbar Contestuale che causava Layout Shift** - COMPLETATO - **Problema:** Quando si selezionava un oggetto nel canvas, appariva una toolbar aggiuntiva sotto quella principale che causava uno scroll della pagina - **Soluzione:** Rimossa completamente la toolbar contestuale - le proprietà degli oggetti vengono gestite solo dal `PropertiesPanel` sulla destra - **Rimosso da EditorToolbar.tsx:** - Sezione "Contextual Toolbar Row" (desktop) - Sezione "Contextual toolbar for text/shape" (tablet) - Funzioni: `handleTextFormat()`, `handleTextAlign()`, `renderContextualToolbar()` - Componente `ColorPickerButton` - Costante `COLOR_PRESETS` - Props: `selectedElement`, `onUpdateSelectedElement` - Import non più usati: `TextField`, `ToggleButton`, `ToggleButtonGroup`, icone formattazione - **File modificati:** - `EditorToolbar.tsx` - Rimossa toolbar contestuale e codice correlato - `ReportEditorPage.tsx` - Rimossi props `selectedElement` e `onUpdateSelectedElement` dalla chiamata a EditorToolbar - **NUOVA FEATURE: Selezione Multipla nel Report Editor** - COMPLETATO - Implementato sistema di selezione multipla personalizzato (senza usare ActiveSelection di Fabric.js che causava riposizionamento oggetti) - **Selezione con rettangolo di trascinamento**: trascinando sul canvas vuoto appare rettangolo blu tratteggiato, al rilascio seleziona tutti gli oggetti che intersecano - **Shift+click**: aggiunge/rimuove oggetti dalla selezione - **Spostamento multiplo**: quando più oggetti sono selezionati, trascinandone uno si spostano tutti insieme - **Feedback visivo**: oggetti selezionati mostrano bordo blu (#1976d2) e ombra - **Gestione corretta degli eventi**: i ref (`selectedElementIdsRef`, `onSelectElementRef`, etc.) evitano stale closures negli event handler - **File modificati:** - `EditorCanvas.tsx` - Nuovi handler `handleMouseDown`, `handleMouseUp`, logica selezione multipla, refs per valori correnti - `ReportEditorPage.tsx` - Cambiato `selectedElementId: string | null` → `selectedElementIds: string[]`, aggiornati tutti i riferimenti **Lavoro completato nelle sessioni precedenti (28 Novembre 2025 notte):** - **NUOVA FEATURE: Sincronizzazione Real-Time Efficiente** - COMPLETATO - **Prima:** Al salvataggio veniva inviata solo una notifica `DataSaved`, l'altra sessione ricaricava il template dal server (lento) - **Dopo:** Al salvataggio viene inviato l'intero template via SignalR (`BroadcastTemplateSync`), l'altra sessione lo applica direttamente (istantaneo) - **Compressione automatica** per template > 10KB usando gzip via browser's CompressionStream API - **Version tracking** per gestione conflitti (ignora template con versione più vecchia) - Nuovo metodo Hub: `BroadcastTemplateSync(roomKey, templateJson, version, compressed)` - Nuovo evento: `TemplateSync` con decompressione automatica lato client - **FIX: Limite messaggio SignalR** - Aumentato `MaximumReceiveMessageSize` a 1MB in `Program.cs` (default era 32KB) - **File modificati:** - `CollaborationHub.cs` - Aggiunto `BroadcastTemplateSync` e `TemplateSyncMessage` con campo `Compressed` - `collaboration.ts` - Aggiunto `broadcastTemplateSync()`, utilities compressione/decompressione (`compressString`, `decompressString`), handler `TemplateSync` - `CollaborationContext.tsx` - Esposto `broadcastTemplateSync` e `onTemplateSync` - `ReportEditorPage.tsx` - Sostituito `sendDataSaved()` con `broadcastTemplateSync()`, aggiunto handler per applicare template ricevuti - `Program.cs` - Configurato SignalR con `MaximumReceiveMessageSize = 1MB` - **FIX: Auto-Save Event-Based con Debounce** - COMPLETATO - Riscritto auto-save per triggerare ad ogni modifica (non a intervalli) - Debounce di 500ms per evitare salvataggi multipli durante editing rapido - Usa `useRef` per `saveMutation`, `template`, `templateInfo` per evitare re-creazione del timeout - Dipendenze effect: solo `autoSaveEnabled`, `isNew`, `hasUnsavedChanges`, `templateHistory.undoCount` - Il check `isPending` avviene al momento dell'esecuzione del timeout, non come dipendenza **Lavoro completato nelle sessioni precedenti (28 Novembre 2025 pomeriggio - sera):** - **NUOVA FEATURE: Sistema Collaborazione Real-Time Globale** - COMPLETATO - Migrato da sistema report-specific a sistema globale per tutta l'app - `CollaborationHub.cs` - Hub SignalR generico per qualsiasi entità/pagina - `collaboration.ts` - Service singleton per gestione connessione - `CollaborationContext.tsx` - React Context con hooks (`useCollaboration`, `useCollaborationRoom`) - `CollaborationIndicator.tsx` - Indicatore globale nella UI - Room-based collaboration con formato `{entityType}:{entityId}` - **FIX: Incompatibilità versione SignalR** - Rimosso package `Microsoft.AspNetCore.SignalR.Common` v10.0.0 incompatibile con .NET 9, downgrade client `@microsoft/signalr` a v8.0.7 - **FIX: Auto-save non funzionante** - Usati `useRef` per evitare re-run dell'effect causato da `saveMutation` nelle dependencies **Lavoro completato nelle sessioni precedenti (28 Novembre 2025 tarda notte):** - **NUOVA FEATURE: Toolbar Report Designer Migliorata Drasticamente** - COMPLETATO - Design moderno stile Canva/Figma con gradient buttons e animazioni fluide - **Sezioni etichettate** su desktop (INSERISCI, MODIFICA, CRONOLOGIA, VISTA, ZOOM, PAGINA) - **Toolbar contestuale** dinamica che appare quando un elemento è selezionato: - Per testo: formattazione (grassetto, corsivo, sottolineato), allineamento, color picker - Per forme/linee: color picker riempimento/bordo, spessore bordo - Per immagini: indicatore mantieni proporzioni - Mostra tipo elemento, nome e dimensioni in tempo reale - **Color Picker integrato** con palette di 20 colori predefiniti - **Indicatore stato salvataggio** visivo: Salvato (verde), Non salvato (arancione), Salvataggio... (spinner) - **Badge** sul pulsante Snap che mostra quante opzioni sono attive - **Zoom esteso** fino al 300% con pulsante "Adatta alla finestra" - Pannello scorciatoie tastiera ampliato - Aggiunto `textDecoration` a `AprtStyle` per supportare sottolineato - **FIX: Indicatore "Non Salvato" errato** - RISOLTO - Prima usava `canUndo` che indicava solo presenza di history - Ora usa `undoCount` confrontato con `lastSavedUndoCount` per tracking accurato - **NUOVA FEATURE: Auto-Save con Toggle** - COMPLETATO - Salvataggio automatico dopo 1 secondo di inattività (debounce) - **Abilitato di default** - Toggle nella toolbar (icona AutoMode) per attivare/disattivare - Quando auto-save è attivo, il pulsante "Salva" manuale è nascosto - Quando auto-save è disattivo, il pulsante "Salva" appare - Non si attiva per template nuovi (richiede primo salvataggio manuale) - Non si attiva durante salvataggio in corso **Lavoro completato nelle sessioni precedenti (28 Novembre 2025 notte):** - **NUOVA FEATURE: Responsive Design Completo** - COMPLETATO - Tutta l'applicazione è ora responsive per mobile, tablet e desktop - Breakpoints: mobile (<600px), tablet (600-900px), desktop (>900px) - **Layout.tsx**: Sidebar collassata con icone su tablet, drawer mobile - **ReportTemplatesPage**: Header stackato su mobile, FAB per nuovo template, dialog fullScreen - **ReportEditorPage**: BottomNavigation + SwipeableDrawer (70vh) per pannelli su mobile, auto-zoom - **EditorToolbar**: 3 varianti (mobile compatta con riga collassabile, tablet media, desktop completa) - **Pannelli laterali** (DataBindingPanel, PropertiesPanel, PageNavigator): larghezza piena su mobile - **DatasetSelector**: Header collassabile su mobile - **PreviewDialog**: fullScreen su mobile con navigazione step-by-step (dataset → entity) - **ImageUploadDialog**: fullScreen su mobile, area drag-drop ottimizzata, bottoni stacked **Lavoro completato nelle sessioni precedenti (28 Novembre 2025 sera):** - **FIX: Variabili Globali Report ({{$pageNumber}}, {{$totalPages}}, ecc.)** - RISOLTO - Le variabili speciali ora vengono correttamente risolte nel PDF finale - Aggiunta classe `PageContext` per passare numero pagina e totale pagine durante il rendering - Propagato `PageContext` attraverso tutta la catena di rendering (bitmap, text, binding resolution) - `ResolveBindingPath()` ora restituisce valori reali invece di placeholder **Lavoro completato nelle sessioni precedenti (28 Novembre 2025):** - **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 ``` **IMPORTANTE:** Dopo modifiche al codice, i servizi backend e frontend vanno **sempre riavviati** per vedere le modifiche: - Backend: fermare con `Ctrl+C` e rilanciare `dotnet run` - Frontend: in dev mode (`npm run dev`) il hot-reload è automatico per la maggior parte delle modifiche, ma per modifiche strutturali (nuovi file, cambi a tipi, etc.) potrebbe essere necessario riavviare --- ## 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% - 300%) - [x] Griglia e snap to grid - [x] Undo/Redo (max 100 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) - [x] **Responsive design completo** (mobile, tablet, desktop) - [x] **Toolbar professionale** stile Canva/Figma con sezioni etichettate - [x] **Toolbar contestuale** per formattazione rapida (testo, forme, immagini) - [x] **Color picker integrato** con palette preset - [x] **Auto-save** con toggle (abilitato di default, 1s debounce) - [x] **Indicatore stato salvataggio** accurato (Salvato/Non salvato/Salvataggio...) ### 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 - [x] **Responsive design** (mobile/tablet/desktop) - [ ] 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 `[, ]` 7. **HTML p/div nesting (FIX 27/11/2025):** - Error: `
cannot be a descendant of

` - Fix: `` 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($""); ``` - 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 15. **Variabili Globali Report (FIX 28/11/2025 sera):** - **Problema:** Le variabili speciali `{{$pageNumber}}`, `{{$totalPages}}`, `{{$date}}`, `{{$datetime}}`, `{{$time}}` non venivano stampate nel PDF - restavano come placeholder - **Causa:** `ResolveBindingPath()` restituiva placeholder statici (`"{{PAGE}}"`) invece dei valori reali perché il contesto pagina non veniva passato durante il rendering - **Soluzione:** 1. Aggiunta classe `PageContext` con `PageNumber` e `TotalPages` 2. Il ciclo di rendering ora traccia l'indice pagina corrente 3. `PageContext` propagato attraverso tutta la catena: `GeneratePdfAsync` → `RenderContentToBitmap` → `RenderElementToCanvas` → `RenderTextToCanvas` → `ResolveContent` → `ResolveBindingWithFormat` → `ResolveBindingPath` 4. `ResolveBindingPath()` ora usa i valori reali dal contesto: ```csharp "$pageNumber" => pageContext?.PageNumber.ToString() ?? "1", "$totalPages" => pageContext?.TotalPages.ToString() ?? "1", "$date" => DateTime.Now.ToString("dd/MM/yyyy"), "$time" => DateTime.Now.ToString("HH:mm"), "$datetime" => DateTime.Now.ToString("dd/MM/yyyy HH:mm"), ``` - **File:** `ReportGeneratorService.cs` - Metodi `GeneratePdfAsync()`, `RenderContentToBitmap()`, `RenderElementToCanvas()`, `RenderTextToCanvas()`, `ResolveContent()`, `ResolveBindingWithFormat()`, `ResolveBinding()`, `ResolveExpression()`, `ResolveBindingPath()` 16. **Responsive Design Completo (IMPLEMENTATO 28/11/2025 notte):** - **Obiettivo:** Rendere tutta l'applicazione responsive per mobile, tablet e desktop - **Breakpoints MUI utilizzati:** - Mobile: `theme.breakpoints.down("sm")` → < 600px - Tablet: `theme.breakpoints.between("sm", "md")` → 600-900px - Desktop: `theme.breakpoints.up("md")` → > 900px - **Pattern principale per Report Editor su mobile:** - `BottomNavigation` per switch tra pannelli (Pagine, Dati, Proprietà) - `SwipeableDrawer` con `anchor="bottom"` e altezza 70vh per contenuto pannelli - Auto-zoom canvas: 0.5 mobile, 0.75 tablet, 1 desktop - **Pattern per toolbar mobile:** - Riga primaria con azioni essenziali sempre visibili - Riga secondaria collassabile con `` per azioni secondarie - **Pattern per dialog mobile:** - `fullScreen` prop su Dialog - AppBar con pulsante back invece di DialogTitle - Navigazione step-by-step invece di layout side-by-side - **File modificati:** - `Layout.tsx` - Sidebar collassata su tablet - `ReportTemplatesPage.tsx` - FAB, fullScreen dialogs - `ReportEditorPage.tsx` - BottomNavigation + SwipeableDrawer - `EditorToolbar.tsx` - 3 varianti layout (mobile/tablet/desktop) - `DataBindingPanel.tsx`, `PropertiesPanel.tsx`, `PageNavigator.tsx` - Width responsive - `DatasetSelector.tsx` - Header collapsible - `PreviewDialog.tsx`, `ImageUploadDialog.tsx` - fullScreen + step navigation 17. **Indicatore "Non Salvato" Errato (FIX 28/11/2025 tarda notte):** - **Problema:** Dopo il salvataggio, l'indicatore continuava a mostrare "Non salvato" - **Causa:** `hasUnsavedChanges` era basato su `templateHistory.canUndo` che indica solo se c'è history disponibile, non se ci sono modifiche non salvate - **Soluzione:** Introdotto `lastSavedUndoCount` che viene aggiornato dopo ogni salvataggio riuscito. `hasUnsavedChanges` ora confronta `templateHistory.undoCount !== lastSavedUndoCount` - **File:** `ReportEditorPage.tsx` 18. **Auto-Save Feature (IMPLEMENTATO 28/11/2025 tarda notte):** - **Funzionalità:** Salvataggio automatico dopo 1 secondo di inattività - **Implementazione:** - Stato `autoSaveEnabled` (default: true) in `ReportEditorPage.tsx` - `useEffect` con debounce di 1000ms che triggera `saveMutation.mutate()` - Non si attiva se: `isNew`, `!hasUnsavedChanges`, `saveMutation.isPending` - Toggle nella toolbar con icona `AutoSaveIcon` (da @mui/icons-material) - Pulsante "Salva" nascosto quando auto-save è attivo - **Props toolbar:** `autoSaveEnabled`, `onAutoSaveToggle` - **File:** `ReportEditorPage.tsx`, `EditorToolbar.tsx` 19. **Toolbar Migliorata Stile Canva/Figma (IMPLEMENTATO 28/11/2025 tarda notte):** - **Miglioramenti:** - Design moderno con gradient buttons e animazioni fluide - Sezioni etichettate su desktop (INSERISCI, MODIFICA, CRONOLOGIA, VISTA, ZOOM, PAGINA) - Toolbar contestuale dinamica basata su tipo elemento selezionato - Color picker integrato con 20 colori preset - Indicatore stato salvataggio visivo - Badge su pulsante Snap - Zoom esteso fino a 300% - **Componenti aggiunti:** `ToolbarSection`, `StyledIconButton`, `ColorPickerButton` - **Type aggiunto:** `textDecoration` in `AprtStyle` - **File:** `EditorToolbar.tsx`, `types/report.ts` 20. **Incompatibilità Versione SignalR (FIX 28/11/2025 pomeriggio):** - **Problema:** Errore "Method not found: 'System.String Microsoft.AspNetCore.SignalR.IInvocationBinder.GetTarget(System.ReadOnlySpan`1)'." - connessioni SignalR fallivano immediatamente - **Causa:** Package `Microsoft.AspNetCore.SignalR.Common` v10.0.0 nel backend incompatibile con .NET 9 (è per .NET 10 preview) - **Soluzione:** - Rimosso `Microsoft.AspNetCore.SignalR.Common` dal .csproj (SignalR è già incluso in ASP.NET Core) - Downgrade frontend `@microsoft/signalr` da v10.0.0 a v8.0.7 - **File:** `Apollinare.API.csproj`, `frontend/package.json` 21. **Auto-Save Non Funzionante (FIX 28/11/2025 pomeriggio):** - **Problema:** Con auto-save attivo, le modifiche non venivano salvate (l'indicatore mostrava "Non salvato" sempre) - **Causa:** `saveMutation` nell'array di dipendenze dell'`useEffect` causava il reset del timeout ad ogni render (React Query crea un nuovo oggetto ad ogni render) - **Soluzione:** Usati `useRef` per `saveMutation`, `template`, e `templateInfo` per evitare che l'effect si ri-esegua inutilmente - **File:** `ReportEditorPage.tsx` 22. **Sistema Collaborazione Real-Time (COMPLETATO 28/11/2025):** - **Obiettivo:** Collaborazione stile Google Docs su tutto l'applicativo - **Architettura implementata:** - `CollaborationHub.cs` - Hub SignalR generico con room-based collaboration - `collaboration.ts` - Service singleton frontend - `CollaborationContext.tsx` - React Context con `useCollaborationRoom` hook - Room key format: `{entityType}:{entityId}` (es. `report-template:2`) - **File principali:** - Backend: `CollaborationHub.cs` - Frontend: `collaboration.ts`, `CollaborationContext.tsx`, `ReportEditorPage.tsx` 23. **Sincronizzazione Real-Time Lenta (FIX 28/11/2025 sera):** - **Problema:** Al salvataggio (manuale o auto-save), l'altra sessione impiegava diversi secondi per vedere le modifiche - **Causa:** Il sistema usava `DataSaved` notification che causava un reload del template dal server (`queryClient.invalidateQueries`) - **Soluzione:** Implementato `BroadcastTemplateSync` che invia l'intero template via SignalR direttamente alle altre sessioni: - Nuovo metodo Hub `BroadcastTemplateSync(roomKey, templateJson, version, compressed)` - L'altra sessione riceve il template e lo applica istantaneamente con `historyActions.setWithoutHistory()` - Aggiunto version tracking per evitare di applicare versioni più vecchie - Compressione automatica gzip per template > 10KB (usa browser's CompressionStream API) - **File:** `CollaborationHub.cs`, `collaboration.ts`, `CollaborationContext.tsx`, `ReportEditorPage.tsx` 24. **Limite Messaggio SignalR (FIX 28/11/2025 notte):** - **Problema:** La connessione SignalR si disconnetteva con errore "The maximum message size of 32768B was exceeded" - **Causa:** Il template compresso (~110KB) superava il limite di default di SignalR (32KB) - **Soluzione:** Configurato `MaximumReceiveMessageSize = 1MB` in `Program.cs`: ```csharp builder.Services.AddSignalR(options => { options.MaximumReceiveMessageSize = 1024 * 1024; // 1MB }) ``` - **File:** `Program.cs` 25. **Auto-Save Non Funzionante (FIX 28/11/2025 notte):** - **Problema:** L'auto-save non si attivava anche con modifiche non salvate - **Causa:** Le dipendenze dell'effect includevano `saveMutation`, `template`, `templateInfo` che cambiano ad ogni render, causando reset continui del timeout - **Soluzione:** Approccio event-based con debounce usando refs: - `saveMutationRef`, `templateForSaveRef`, `templateInfoForSaveRef` per accedere ai valori correnti senza re-triggerare l'effect - Dipendenze effect ridotte a: `autoSaveEnabled`, `isNew`, `hasUnsavedChanges`, `templateHistory.undoCount` - Check `isPending` spostato dentro il callback del setTimeout - **File:** `ReportEditorPage.tsx` 26. **Selezione Multipla Fabric.js - Riposizionamento Oggetti (FIX 29/11/2025):** - **Problema:** Usando `ActiveSelection` di Fabric.js per la selezione multipla, gli oggetti venivano riposizionati/spostati quando selezionati - **Causa:** `ActiveSelection` raggruppa gli oggetti e le loro coordinate diventano relative al centro del gruppo. Inoltre, ricreando l'`ActiveSelection` nell'effect quando cambiava `selectedElementIds`, gli oggetti venivano spostati - **Soluzione:** Sistema di selezione multipla completamente personalizzato: - Disabilitata selezione nativa di Fabric.js (`selection: false` nel canvas) - Implementato `handleMouseDown` per: - Click su oggetto → selezione singola - Shift+click → aggiunge/rimuove dalla selezione - Click su canvas vuoto → inizio rettangolo di selezione - Click su oggetto già selezionato (multi) → inizio drag multiplo - Implementato `handleMouseMove` per: - Disegno rettangolo di selezione (Rect blu tratteggiato) - Spostamento multiplo oggetti (aggiorna `left`/`top` di ogni oggetto) - Implementato `handleMouseUp` per: - Fine rettangolo → calcola intersezione e seleziona oggetti - Fine drag multiplo → aggiorna template con nuove posizioni - Feedback visivo: bordo blu e ombra sugli oggetti selezionati (invece di ActiveSelection) - Usati refs (`selectedElementIdsRef`, `onSelectElementRef`, etc.) per evitare stale closures negli event handler registrati una sola volta - **File:** `EditorCanvas.tsx`, `ReportEditorPage.tsx` 27. **Toolbar Contestuale Layout Shift (FIX 29/11/2025):** - **Problema:** Quando si selezionava un oggetto nel canvas del report designer, appariva una toolbar contestuale aggiuntiva sotto quella principale, causando uno scroll/layout shift della pagina - **Causa:** La toolbar contestuale (`renderContextualToolbar()`) veniva renderizzata condizionalmente quando `selectedElement` era presente, aggiungendo una riga extra all'altezza della toolbar - **Soluzione:** Rimossa completamente la toolbar contestuale - le proprietà degli oggetti selezionati vengono gestite esclusivamente dal `PropertiesPanel` sulla destra (che è sempre visibile) - **Rimosso:** - `renderContextualToolbar()` - funzione che rendeva la toolbar - `handleTextFormat()`, `handleTextAlign()` - handler per formattazione - `ColorPickerButton` component - color picker inline - `COLOR_PRESETS` - palette colori - Props `selectedElement`, `onUpdateSelectedElement` dall'interfaccia - Import inutilizzati: `TextField`, `ToggleButton`, `ToggleButtonGroup`, icone formattazione - **File:** `EditorToolbar.tsx`, `ReportEditorPage.tsx` 28. **Scorciatoie da Tastiera Intercettate dal Browser (FIX 29/11/2025):** - **Problema:** Le scorciatoie da tastiera (Ctrl+S, Ctrl+C, Ctrl+V, etc.) nel report designer venivano catturate dal browser invece che dalla pagina - ad esempio Ctrl+S apriva il dialog di salvataggio del browser invece di salvare il template - **Causa:** L'handler delle scorciatoie non chiamava `e.preventDefault()` in modo consistente e non verificava se l'utente stava modificando testo in un input field o nel canvas - **Soluzione:** Riscritto completamente l'handler delle scorciatoie: - Verifica se il target è un campo input (`INPUT`, `TEXTAREA`, `contentEditable`) - Nuovo metodo `isTextEditing()` esposto da `EditorCanvasRef` per verificare se un elemento testo è in editing nel canvas Fabric.js - `e.preventDefault()` chiamato subito dopo il riconoscimento della scorciatoia - Implementate tutte le scorciatoie dichiarate nel context menu (Ctrl+X/C/V/D/A/L/G, Ctrl+[/], Delete, Escape) - **File:** `EditorCanvas.tsx` (aggiunto `isTextEditing()` a `EditorCanvasRef`), `ReportEditorPage.tsx` (riscritto `useEffect` delle scorciatoie, aggiunto `canvasRef`) ### 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 } /> } /> } /> ``` Menu aggiunto in `Layout.tsx` sotto "Report" con icona PrintIcon.