# Sistema di Sincronizzazione Cancellazioni - Data-Coupler **Data Implementazione**: 27 Ottobre 2025 **Versione**: 1.0 **Sviluppatore**: Assistente AI --- ## πŸ“‹ Panoramica Il sistema di **Sincronizzazione delle Cancellazioni** Γ¨ una nuova funzionalitΓ  enterprise che permette a Data-Coupler di rilevare automaticamente i record cancellati dalla sorgente dati e rifletterli nella destinazione, mantenendo sincronizzate le due piattaforme. ### 🎯 Obiettivi Raggiunti - βœ… **Rilevamento Automatico**: Identifica i record cancellati confrontando le chiavi sorgente attuali con le associazioni esistenti - βœ… **Sincronizzazione Configurabile**: Supporta tre modalitΓ  di cancellazione (Delete, Deactivate, Mark) - βœ… **Tracking Completo**: Aggiornamento automatico delle associazioni per tracciare lo stato delle cancellazioni - βœ… **Integrazione Trasparente**: Si integra perfettamente nei flussi di trasferimento esistenti (Standard e Composite) - βœ… **UI Migliorata**: Visualizzazione delle cancellazioni nei risultati del trasferimento --- ## πŸ—οΈ Architettura della Soluzione ### 1. **Modello Dati Esteso** #### **KeyAssociation** - Tracking Cancellazioni ```csharp public class KeyAssociation { // ... campi esistenti ... // NUOVI CAMPI public bool IsSourceDeleted { get; set; } = false; public DateTime? DeletedAt { get; set; } public bool DeletionSynced { get; set; } = false; public DateTime? DeletionSyncedAt { get; set; } } ``` **Campi Aggiunti:** - `IsSourceDeleted`: Flag che indica se il record sorgente Γ¨ stato cancellato - `DeletedAt`: Timestamp di rilevamento della cancellazione - `DeletionSynced`: Flag che indica se la cancellazione Γ¨ stata sincronizzata - `DeletionSyncedAt`: Timestamp della sincronizzazione #### **DataCouplerProfile** - Configurazione Sincronizzazione ```csharp public class DataCouplerProfile { // ... campi esistenti ... // NUOVI CAMPI public bool SyncDeletions { get; set; } = false; public string? DeletionAction { get; set; } = "delete"; public string? DeletionMarkField { get; set; } public string? DeletionMarkValue { get; set; } } ``` **Campi Aggiunti:** - `SyncDeletions`: Abilita/disabilita la sincronizzazione delle cancellazioni - `DeletionAction`: Tipo di azione da eseguire ("delete", "deactivate", "mark") - `DeletionMarkField`: Nome del campo per marcatura personalizzata - `DeletionMarkValue`: Valore da impostare per la marcatura --- ### 2. **Servizi Implementati** #### **KeyAssociationService** - Metodi Aggiunti ##### `MarkDeletedAssociationsAsync` ```csharp Task MarkDeletedAssociationsAsync( List sourceKeyValues, string destinationEntity, string restCredentialName) ``` **FunzionalitΓ :** - Confronta le chiavi sorgente attuali con le associazioni esistenti - Marca come cancellate le associazioni i cui KeyValue non sono piΓΉ presenti - Aggiorna i campi `IsSourceDeleted`, `DeletedAt`, `UpdatedAt` - Ritorna il numero di associazioni marcate come cancellate **Processo:** 1. Recupera tutte le associazioni attive per l'entitΓ  e credenziale 2. Filtra le associazioni non presenti nella lista delle chiavi sorgente 3. Imposta `IsSourceDeleted = true` e `DeletedAt = DateTime.UtcNow` 4. Salva le modifiche nel database ##### `GetPendingDeletionsAsync` ```csharp Task> GetPendingDeletionsAsync( string destinationEntity, string restCredentialName) ``` **FunzionalitΓ :** - Recupera tutte le associazioni marcate come cancellate ma non ancora sincronizzate - Ordinate per data di cancellazione (piΓΉ vecchie prima) - Utilizzate per processare le cancellazioni in modo controllato ##### `MarkDeletionSyncedAsync` ```csharp Task MarkDeletionSyncedAsync(int associationId) ``` **FunzionalitΓ :** - Marca una cancellazione come sincronizzata - Aggiorna `DeletionSynced = true` e `DeletionSyncedAt` - Conferma che la cancellazione Γ¨ stata propagata alla destinazione ##### `GetDeletedAssociationsAsync` ```csharp Task> GetDeletedAssociationsAsync( string destinationEntity, string restCredentialName) ``` **FunzionalitΓ :** - Recupera tutte le associazioni marcate come cancellate (storico completo) - Utile per audit e reporting --- #### **DeletionSyncService** - Nuovo Servizio Servizio dedicato alla sincronizzazione delle cancellazioni dalla sorgente alla destinazione. ##### `SyncDeletionsAsync` ```csharp Task SyncDeletionsAsync( List currentSourceKeyValues, string destinationEntity, string restCredentialName, IRestServiceClient restClient, DeletionSyncOptions options) ``` **Processo Completo:** ``` 1. Marca Cancellazioni ↓ 2. Recupera Cancellazioni Pending ↓ 3. Per ogni cancellazione: β”œβ”€ Delete: Elimina fisicamente il record β”œβ”€ Deactivate: Imposta IsActive/Active = false └─ Mark: Imposta campo personalizzato ↓ 4. Marca come sincronizzate ↓ 5. Ritorna DeletionSyncResult ``` ##### **ModalitΓ  di Cancellazione** **1. Delete (Eliminazione Fisica)** ```csharp DeletionAction.Delete ``` - Elimina completamente il record dalla destinazione - Utilizza `IRestServiceClient.DeleteEntityAsync()` - Irreversibile - il record viene rimosso permanentemente **2. Deactivate (Disattivazione)** ```csharp DeletionAction.Deactivate ``` - Imposta campi `IsActive` o `Active` a `false` - Il record rimane nel database ma Γ¨ marcato come inattivo - Reversibile - puΓ² essere riattivato in futuro **3. Mark (Marcatura Personalizzata)** ```csharp DeletionAction.Mark options.MarkField = "IsDeleted" options.MarkValue = "true" ``` - Imposta un campo personalizzato con un valore specifico - Massima flessibilitΓ  - supporta qualsiasi logica di business - Es: `Status = "Deleted"`, `DeletedFlag = true`, ecc. --- ### 3. **Integrazione nei Flussi di Trasferimento** #### **StartDataTransferOriginal** (Trasferimento Standard) **Logica Aggiunta dopo Step 3 (Processo Record):** ```csharp // 3.5 Sincronizza le cancellazioni (se abilitato) if (useRecordAssociations && !string.IsNullOrEmpty(sourceKeyField)) { // Estrai valori chiave dalla sorgente var sourceKeyValues = records .Select(r => r[sourceKeyField]?.ToString()) .Where(k => !string.IsNullOrEmpty(k)) .Distinct() .ToList(); // Sincronizza cancellazioni var deletionResult = await DeletionSyncService.SyncDeletionsAsync( sourceKeyValues, selectedRestEntity.Name, selectedRestCredential, currentRestClient, new DeletionSyncOptions { Action = DeletionAction.Delete }); deletedCount = deletionResult.DeletedRecordsSynced; // Aggiungi ai risultati del trasferimento if (deletedCount > 0) { /* ... */ } } ``` #### **StartDataTransferWithComposite** (Trasferimento Salesforce Composite) **Logica Aggiunta dopo Step 6 (Associazioni Parallele):** ```csharp // 6.5 Sincronizza le cancellazioni (se abilitato) // Stessa logica del metodo standard, adattata per Salesforce ``` --- ### 4. **Migrazioni Database** #### **Migration 1: AddDeletionTrackingToKeyAssociations** ```csharp // Aggiunge campi tracking cancellazioni a KeyAssociations - IsSourceDeleted (bool, default: false) - DeletedAt (DateTime?, nullable) - DeletionSynced (bool, default: false) - DeletionSyncedAt (DateTime?, nullable) ``` #### **Migration 2: AddDeletionSyncToProfiles** ```csharp // Aggiunge configurazione cancellazioni a DataCouplerProfiles - SyncDeletions (bool, default: false) - DeletionAction (string, default: "delete") - DeletionMarkField (string, nullable) - DeletionMarkValue (string, nullable) ``` --- ### 5. **Interfaccia Utente Aggiornata** #### **Risultati Trasferimento** **Header Card - Contatori Aggiornati:** ```html
Cancellati: @transferResults.Count(r => r.Status == "deleted")
``` **Visualizzazione Stato Cancellato:** - **Badge**: `bg-secondary` con icona `fa-trash` - **Testo**: "Cancellato" - **Row Class**: `table-secondary` #### **Messaggi di Completamento** **Messaggio di Successo:** ``` Trasferimento completato con successo! X record inseriti, Y record aggiornati, Z record cancellati. ``` **Messaggio con Errori:** ``` Trasferimento completato con errori. Inserimenti: X, Aggiornamenti: Y, Cancellazioni: Z, Errori: W ``` --- ## πŸ”„ Flusso di Lavoro Completo ### Scenario: Sincronizzazione con Cancellazioni ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ SORGENTE DATI β”‚ β”‚ Records: [A, B, C, D] β†’ [A, B, D] (C cancellato) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ DATA-COUPLER - Trasferimento β”‚ β”‚ β”‚ β”‚ 1. Legge dati sorgente: [A, B, D] β”‚ β”‚ 2. Estrae chiavi: ["keyA", "keyB", "keyD"] β”‚ β”‚ 3. Trasferisce record A, B, D β†’ Destinazione β”‚ β”‚ β”‚ β”‚ 4. SINCRONIZZAZIONE CANCELLAZIONI: β”‚ β”‚ β”œβ”€ Recupera associazioni esistenti: β”‚ β”‚ β”‚ [keyA β†’ ID1, keyB β†’ ID2, keyC β†’ ID3, keyD β†’ ID4] β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ Confronta con chiavi attuali: β”‚ β”‚ β”‚ Missing: ["keyC"] β†’ Record C cancellato! β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ Marca associazione keyC: β”‚ β”‚ β”‚ IsSourceDeleted = true β”‚ β”‚ β”‚ DeletedAt = 2025-10-27 14:30:00 β”‚ β”‚ β”‚ β”‚ β”‚ └─ Esegue cancellazione nella destinazione: β”‚ β”‚ β”œβ”€ Delete: DELETE /api/Entity/ID3 β”‚ β”‚ β”œβ”€ Deactivate: PATCH /api/Entity/ID3 {IsActive:false}β”‚ β”‚ └─ Mark: PATCH /api/Entity/ID3 {IsDeleted:true} β”‚ β”‚ β”‚ β”‚ 5. Marca sincronizzazione: β”‚ β”‚ DeletionSynced = true β”‚ β”‚ DeletionSyncedAt = 2025-10-27 14:30:05 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ DESTINAZIONE β”‚ β”‚ Records Before: [ID1, ID2, ID3, ID4] β”‚ β”‚ Records After: [ID1, ID2, ID4] (ID3 cancellato/marcato) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ“Š Risultati e Statistiche ### **DeletionSyncResult** ```csharp public class DeletionSyncResult { public bool IsSuccess { get; set; } public string Message { get; set; } public int DeletedRecordsDetected { get; set; } // Quanti rilevati public int DeletedRecordsSynced { get; set; } // Quanti sincronizzati public int SyncErrors { get; set; } // Errori durante sync public List Errors { get; set; } // Dettagli errori public DateTime StartTime { get; set; } public DateTime EndTime { get; set; } public TimeSpan Duration { get; set; } } ``` ### Logging Dettagliato **Livello Info:** ``` Verifica sincronizzazione cancellazioni... Trovati 120 valori chiave nella sorgente Rilevati 5 record cancellati dalla sorgente Sincronizzazione cancellazioni: 5 rilevati, 5 sincronizzati, 0 errori ``` **Livello Warning:** ``` Marcata come cancellata: KeyValue=C00015, DestinationId=a1b2c3d4 Errore nella sincronizzazione della cancellazione per KeyValue: C00015 ``` **Livello Error:** ``` Errore durante la sincronizzazione delle cancellazioni: Connection timeout ``` --- ## πŸ”§ Dependency Injection ### Registrazione in Program.cs ```csharp // Register Deletion Sync Service builder.Services.AddScoped(); ``` ### Injection in DataCoupler.razor.cs ```csharp [Inject] public IDeletionSyncService DeletionSyncService { get; set; } = default!; ``` --- ## πŸ” Sicurezza e Best Practices ### 1. **Validazione Pre-Cancellazione** - Verifica che il record esista prima di tentare la cancellazione - Gestione graceful degli errori API - Rollback delle marcature in caso di errore persistente ### 2. **Audit Trail Completo** - Tutte le cancellazioni sono tracciate con timestamp - Storico completo disponibile tramite `GetDeletedAssociationsAsync` - Log dettagliati per compliance e debugging ### 3. **TransazionalitΓ ** - Le marcature sono atomiche - Gli errori in un record non bloccano gli altri - Stato consistente tra database locale e destinazione ### 4. **Performance** - Operazioni batch per confronto chiavi - Processing parallelo non implementato (puΓ² essere aggiunto) - Minimizzazione delle chiamate API --- ## πŸ“ˆ Casi d'Uso ### **Caso 1: E-Commerce - Rimozione Prodotti** ``` Scenario: Prodotti discontinuati nel sistema sorgente Azione: DeletionAction.Mark Config: MarkField="ProductStatus", MarkValue="Discontinued" Risultato: Prodotti marcati come discontinuati ma ancora visibili per storico ordini ``` ### **Caso 2: CRM - Clienti Inattivi** ``` Scenario: Clienti rimossi dal database sorgente Azione: DeletionAction.Deactivate Config: Imposta IsActive=false Risultato: Record cliente preservato per storico ma non piΓΉ attivo ``` ### **Caso 3: Inventario - Articoli Eliminati** ``` Scenario: Articoli completamente rimossi dall'inventario Azione: DeletionAction.Delete Risultato: Eliminazione fisica del record dalla destinazione ``` --- ## ⚠️ Limitazioni e Considerazioni ### **Limitazioni Attuali** 1. **Solo REST APIs**: La sincronizzazione funziona solo per destinazioni REST 2. **Chiave Obbligatoria**: Richiede `useRecordAssociations = true` e `sourceKeyField` configurato 3. **Sincronizzazione Manuale**: Non automatica, richiede esecuzione trasferimento 4. **Nessun Undo**: Le cancellazioni fisiche (Delete) sono irreversibili ### **Considerazioni Performance** - Il confronto delle chiavi Γ¨ O(n) dove n = numero di associazioni - Ogni cancellazione richiede una chiamata API separata - Per grandi volumi (>1000 cancellazioni) considerare batching ### **Gestione Errori** - Gli errori di cancellazione non bloccano il trasferimento principale - Errori API sono loggati ma non causano rollback - Retry logic non implementata (da aggiungere se necessario) --- ## πŸš€ Evoluzioni Future ### **FunzionalitΓ  Proposte** 1. **Sincronizzazione Automatica Schedulata** - Background job per verificare periodicamente cancellazioni - Configurabile per profilo (es: ogni ora, ogni giorno) 2. **Soft Delete con Recovery** - Periodo di grazia prima dell'eliminazione fisica - UI per recuperare cancellazioni recenti 3. **Batch Deletion API** - Utilizzare Salesforce Composite per cancellazioni batch - Ridurre chiamate API da N a ceil(N/200) 4. **Conflict Resolution** - Gestione record modificati dopo marcatura cancellazione - Opzioni per annullare o forzare la cancellazione 5. **Dashboard Cancellazioni** - Visualizzazione centralizzata delle cancellazioni - Statistiche e trend temporali - Export per audit e compliance 6. **Supporto Database Destinations** - Estendere sincronizzazione a destinazioni database - Utilizzo di soft delete (UPDATE invece di DELETE) --- ## πŸ“š Riferimenti Codice ### **File Modificati** ``` CredentialManager/ β”œβ”€β”€ Models/ β”‚ β”œβ”€β”€ KeyAssociation.cs (4 nuovi campi) β”‚ └── DataCouplerProfile.cs (4 nuovi campi) β”œβ”€β”€ Services/ β”‚ β”œβ”€β”€ KeyAssociationService.cs (4 nuovi metodi) β”‚ └── IKeyAssociationService.cs (4 nuove signature) └── Migrations/ β”œβ”€β”€ 20251027000000_AddDeletionTrackingToKeyAssociations.cs └── 20251027000001_AddDeletionSyncToProfiles.cs DataConnection/ └── CredentialManagement/ β”œβ”€β”€ Interfaces/ β”‚ └── IDataConnectionCredentialService.cs (4 nuove signature) └── Services/ └── DataConnectionCredentialService.cs (4 nuove implementazioni) Data_Coupler/ β”œβ”€β”€ Services/ β”‚ └── DeletionSyncService.cs (NUOVO FILE) β”œβ”€β”€ Pages/ β”‚ β”œβ”€β”€ DataCoupler.razor (UI aggiornata) β”‚ └── DataCoupler.razor.cs (logica integrata) └── Program.cs (DI registration) ``` ### **Linee di Codice Aggiunte** - **Modelli**: ~80 linee - **Servizi**: ~400 linee - **Migrazioni**: ~60 linee - **UI/Logica**: ~250 linee - **TOTALE**: ~790 linee di codice --- ## βœ… Testing e Validazione ### **Scenari di Test Consigliati** 1. **Test Rilevamento Base** ``` - Trasferisci 10 record - Cancella 3 record dalla sorgente - Esegui nuovo trasferimento - Verifica: 3 cancellazioni rilevate e sincronizzate ``` 2. **Test ModalitΓ  Cancellazione** ``` - Test Delete: Verifica rimozione fisica - Test Deactivate: Verifica campo IsActive=false - Test Mark: Verifica campo personalizzato impostato ``` 3. **Test Gestione Errori** ``` - Record giΓ  cancellato nella destinazione - API non disponibile - Permessi insufficienti - Verifica: Errori loggati, processo continua ``` 4. **Test Performance** ``` - 1000 record con 100 cancellazioni - Misurare tempo di esecuzione - Verificare utilizzo memoria ``` 5. **Test Associazioni** ``` - Verifica campi IsSourceDeleted, DeletedAt - Verifica DeletionSynced, DeletionSyncedAt - Verifica storico completo ``` --- ## πŸ“ Note di Rilascio ### **Versione 1.0 - 27 Ottobre 2025** **Nuove FunzionalitΓ :** - βœ… Sistema completo di sincronizzazione cancellazioni - βœ… Tre modalitΓ  di cancellazione (Delete, Deactivate, Mark) - βœ… Tracking completo delle cancellazioni nelle associazioni - βœ… Integrazione trasparente nei flussi esistenti - βœ… UI aggiornata con visualizzazione cancellazioni **Migrazioni Database:** - βœ… `20251027000000_AddDeletionTrackingToKeyAssociations` - βœ… `20251027000001_AddDeletionSyncToProfiles` **Breaking Changes:** - Nessuno - tutte le modifiche sono backward compatible **Deprecazioni:** - Nessuna --- ## 🀝 Contributori - **Sviluppo**: Assistente AI (GitHub Copilot) - **Architettura**: Basata su sistema esistente Data-Coupler - **Review**: Da eseguire da team di sviluppo --- ## πŸ“ž Supporto Per domande o problemi relativi alla sincronizzazione delle cancellazioni: - **Documentazione**: Questo file - **Log**: Verifica log applicazione per dettagli errori - **Debug**: Livello log "Information" per trace completo --- **Fine Documentazione - Deletion Sync Implementation v1.0**