diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 0000000..3141065
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,451 @@
+# Data-Coupler - GitHub Copilot Instructions
+
+## 📋 Panoramica del Progetto
+
+**Data-Coupler** è una soluzione enterprise di integrazione dati sviluppata in .NET 9.0 con architettura Blazor Server. Il sistema facilita il trasferimento e la sincronizzazione di dati tra diverse tipologie di sorgenti: database relazionali, REST API, file Excel/CSV con funzionalità avanzate di mapping, scheduling e gestione associazioni.
+
+## 🏗️ Architettura del Sistema
+
+### Progetti Principali
+
+1. **CredentialManager** - Libreria per gestione sicura delle credenziali
+ - Crittografia dei dati sensibili con Data Protection API
+ - Persistenza su database SQLite
+ - Supporto per credenziali database e REST API
+ - Gestione profili Data Coupler e schedulazioni
+
+2. **DataConnection** - Libreria per connessioni dati
+ - **Database supportati**: SQL Server, MySQL, PostgreSQL, Oracle, SQLite, IBM DB2, SAP HANA
+ - **REST API**: Generic REST, Salesforce, SAP Business One Service Layer
+ - Factory pattern per gestione provider
+ - Operazioni batch e parallel processing
+
+3. **Data_Coupler** - Applicazione Blazor Server
+ - Interfaccia web per gestione credenziali e profili
+ - Sistema di trasferimento dati con mapping intelligente
+ - Schedulazione avanzata con background services
+ - Sistema di backup e ripristino completo
+
+4. **Components** - Libreria componenti UI riutilizzabili
+ - Componenti Blazor per gestione profili
+ - Selettori e editor configurazioni
+ - UI responsive con Bootstrap 5
+
+## 🎯 Feature Implementate
+
+### 1. Gestione Credenziali Sicura
+
+#### Caratteristiche:
+- **Crittografia**: Password e chiavi API crittografate con `IDataProtectionProvider`
+- **Multi-piattaforma**: Supporto per database eterogenei e REST API
+- **Test Connessioni**: Validazione credenziali prima del salvataggio
+- **CRUD Completo**: Interfaccia web per gestione completa
+
+#### File Chiave:
+- `CredentialManager/Services/ICredentialService.cs`
+- `CredentialManager/Services/EncryptionService.cs`
+- `Data_Coupler/Pages/CredentialManagement.razor`
+
+### 2. Sistema di Profili Data Coupler
+
+#### Caratteristiche:
+- **Profili Riutilizzabili**: Configurazioni salvate per trasferimenti ricorrenti
+- **Mapping Campi**: Sistema avanzato di mappatura tra sorgente e destinazione
+- **Sorgenti Multiple**: Database, REST API, File (Excel/CSV)
+- **Gestione Completa**: CRUD con validazione e test
+
+#### Componenti:
+- **Sorgente**: Tipo (Database/REST/File), credenziale, tabella/endpoint/percorso file
+- **Destinazione**: Tipo, credenziale, tabella/endpoint
+- **Mapping**: Corrispondenza campi sorgente → destinazione
+- **Chiave Sorgente**: Campo identificativo univoco per tracking
+
+#### File Chiave:
+- `CredentialManager/Models/DataCouplerProfile.cs`
+- `CredentialManager/Services/DataCouplerProfileService.cs`
+- `Data_Coupler/Pages/ProfilesManagement.razor`
+
+### 3. Sistema di Associazioni Record (Key Associations)
+
+#### Caratteristiche:
+- **Tracciamento ID**: Memorizza relazione tra chiavi sorgente e ID destinazione
+- **Prevenzione Duplicati**: Verifica esistenza prima di creare nuovi record
+- **Pre-Discovery**: Cerca record esistenti nella destinazione prima della creazione
+- **Hash Comparison**: Rileva modifiche dati tramite hash SHA256
+- **Validazione Intelligente**: Verifica esistenza ID destinazione, cleanup automatico
+
+#### Flusso Operativo:
+1. Estrazione record da sorgente
+2. Verifica associazione esistente in locale
+3. **PRE-DISCOVERY**: Se non esiste, cerca nella destinazione tramite chiave
+4. Se trovato → Crea associazione + Aggiorna record
+5. Se non trovato → Crea nuovo record + Associazione
+6. Calcola hash dati per tracking modifiche future
+
+#### File Chiave:
+- `CredentialManager/Models/KeyAssociation.cs`
+- `CredentialManager/Services/KeyAssociationService.cs`
+- `Data_Coupler/Pages/KeyAssociations.razor`
+- `Data_Coupler/Services/AssociationService.cs`
+
+#### Gestione Avanzata:
+- **Pulizia Selettiva**: Elimina associazioni per sorgente/destinazione specifica
+- **Pulizia Totale**: Reset completo sistema associazioni
+- **Validazione**: Trova e pulisce associazioni con ID non più validi
+- **Export/Import**: CSV per backup e migrazione dati
+
+### 4. Trasferimento Dati Avanzato
+
+#### Caratteristiche Standard:
+- **Mapping Automatico**: Trasformazione campi sorgente → destinazione
+- **Batch Processing**: Elaborazione ottimizzata per grandi volumi
+- **Error Handling**: Gestione errori robusta con retry logic
+- **Logging Dettagliato**: Tracciamento completo operazioni
+
+#### Salesforce Composite API:
+- **Batch Operations**: Fino a 25 operazioni per request (limite Salesforce)
+- **Parallel Processing**: Elaborazione parallela batch multipli
+- **Performance**: 10-25x più veloce per grandi dataset
+- **Riduzione API Calls**: 60-90% in meno chiamate
+
+#### Metodi Batch Implementati:
+- `BatchExecuteQueriesAsync`: Esecuzione parallela multiple query SOQL
+- `BatchFindEntitiesByKeysAsync`: Ricerca batch entità con diverse chiavi
+- `BatchGetEntitiesByIdsAsync`: Recupero batch tramite ID (max 200 per query)
+- `ExtractAllEntitiesAsync`: Estrazione completa con paginazione automatica
+- `ExtractEntitiesParallelAsync`: Estrazione parallela con deduplicazione
+- `ExtractLargeDatasetAsync`: Estrattore intelligente con auto-detect strategia
+- `ExtractRecentlyModifiedAsync`: Sincronizzazione incrementale
+
+#### File Chiave:
+- `Data_Coupler/Pages/DataCoupler.razor.cs`
+- `DataConnection/REST/Implementations/SalesforceServiceClient.cs`
+- `Data_Coupler/Services/ScheduledProfileExecutionService.cs`
+
+### 5. Sistema di Schedulazione Avanzata
+
+#### Tipi di Schedulazione:
+1. **Una Volta (Once)**: Esecuzione singola a data/ora specifica
+2. **Giornaliera (Daily)**: Ogni giorno a orario specifico
+3. **Settimanale (Weekly)**: Ogni settimana in giorno specifico
+4. **Mensile (Monthly)**: Ogni mese in giorno specifico
+5. **A Intervalli (Interval)**: Ricorrente ogni N unità di tempo
+ - Secondi, Minuti, Ore, Giorni, Settimane, Mesi
+ - Esempio: Ogni 5 minuti, ogni 2 ore, ogni 30 secondi
+
+#### Componenti Sistema:
+- **ProfileSchedule**: Modello dati schedulazione
+- **ScheduledExecutionBackgroundService**: Background service per esecuzione automatica
+- **ScheduledProfileExecutionService**: Logica completa trasferimento schedulato
+- **ProfileScheduleService**: CRUD e gestione schedule
+
+#### Funzionalità:
+- **Esecuzione Automatica**: Background service sempre attivo
+- **Gestione Stato**: Tracciamento esecuzioni (success, failed, running)
+- **Storico Esecuzioni**: Log completo con timestamp, record processati, errori
+- **Pausa/Riprendi**: Controllo dinamico schedulazioni
+- **Override Database**: Possibilità di sovrascrivere sorgente/destinazione
+- **Deletion Sync Configurabile**: Opzione per abilitare sincronizzazione eliminazioni (disabilitata di default)
+
+#### File Chiave:
+- `CredentialManager/Models/ProfileSchedule.cs`
+- `CredentialManager/Services/ProfileScheduleService.cs`
+- `Data_Coupler/BackgroundServices/ScheduledExecutionBackgroundService.cs`
+- `Data_Coupler/Pages/Scheduling.razor`
+- `Data_Coupler/Pages/SchedulingHistory.razor`
+
+### 6. Sistema di Backup e Ripristino
+
+#### Funzionalità Export:
+- **Configurazione Flessibile**: Export selettivo per componente
+- **Componenti Supportati**:
+ - Profili Data Coupler
+ - Credenziali (senza dati sensibili)
+ - Associazioni Chiavi
+ - Schedulazioni
+- **Formato JSON**: Leggibile e versionato
+- **Metadati**: Timestamp, utente, descrizione, componenti inclusi
+
+#### Funzionalità Import:
+- **Validazione Rigorosa**: Controllo formato, versione, integrità dati
+- **Modalità Ripristino**:
+ - **Overwrite**: Sostituisce dati esistenti
+ - **Merge**: Integra con dati esistenti
+ - **Preview**: Mostra anteprima senza eseguire
+- **Transazioni Sicure**: Rollback automatico in caso di errori
+
+#### Sicurezza:
+- **Esclusione Dati Sensibili**: Password e API keys non inclusi in backup
+- **Crittografia Opzionale**: Backup crittografati per sicurezza extra
+- **Audit Logging**: Tracciamento completo operazioni backup/restore
+
+#### File Chiave:
+- `Data_Coupler/Services/BackupService.cs`
+- `Data_Coupler/Models/BackupModels.cs`
+- `Data_Coupler/Pages/SettingsPage.razor`
+
+### 7. Sincronizzazione Eliminazioni (Deletion Sync)
+
+#### Caratteristiche:
+- **Rilevamento Eliminazioni**: Identifica record eliminati da sorgente
+- **Sincronizzazione Automatica**: Elimina corrispondenti in destinazione
+- **Gestione Associazioni**: Aggiorna/elimina associazioni correlate
+- **Modalità Sicura**: Preview eliminazioni prima dell'esecuzione
+- **Logging Completo**: Traccia tutte le operazioni di eliminazione
+- **Configurazione Granulare**:
+ - **Disabilitata** completamente nei trasferimenti manuali (DataCoupler.razor)
+ - **Configurabile** nelle schedulazioni tramite flag `EnableDeletionSync`
+ - **Default: false** per massima sicurezza
+ - Warning esplicito nell'UI per operazioni critiche
+
+#### Sicurezza:
+- La funzionalità è **disabilitata di default** per evitare eliminazioni accidentali
+- Disponibile **solo per le schedulazioni** con configurazione esplicita
+- L'utente deve attivamente abilitare la funzione con piena consapevolezza
+- Logging completo di tutte le operazioni di eliminazione per audit trail
+
+#### File Chiave:
+- `Data_Coupler/Services/DeletionSyncService.cs`
+- `Data_Coupler/Services/ScheduledProfileExecutionService.cs`
+- `CredentialManager/Models/ProfileSchedule.cs` (campo `EnableDeletionSync`)
+- `Data_Coupler/Pages/Scheduling.razor` (UI configurazione)
+
+### 8. Sistema di Autenticazione
+
+#### Caratteristiche:
+- **Login Protetto**: Autenticazione via credenziali o token
+- **Session Management**: Gestione sessioni utente
+- **Password Sicure**: Hashing con algoritmi moderni
+- **Remember Me**: Persistenza login opzionale
+
+#### File Chiave:
+- `Data_Coupler/Services/AuthenticationService.cs`
+- `Data_Coupler/Pages/Login.razor`
+- `Data_Coupler/Middleware/AuthenticationMiddleware.cs`
+
+### 9. Interfaccia Utente Avanzata
+
+#### Pagine Principali:
+- **Dashboard** (`Index.razor`): Panoramica sistema e quick actions
+- **Data Coupler** (`DataCoupler.razor`): Interfaccia principale trasferimento dati
+- **Gestione Profili** (`ProfilesManagement.razor`): CRUD profili completo
+- **Schedulazione** (`Scheduling.razor`): Gestione schedule con UI intuitiva
+- **Storico Schedulazioni** (`SchedulingHistory.razor`): Visualizzazione esecuzioni
+- **Associazioni** (`KeyAssociations.razor`): Gestione completa associazioni
+- **Credenziali** (`CredentialManagement.razor`): CRUD credenziali
+- **Impostazioni** (`SettingsPage.razor`): Backup, sistema, sicurezza, manutenzione
+
+#### Componenti UI:
+- **ProfileSelector**: Selezione e caricamento profili
+- **ProfileSaver**: Salvataggio profili con validazione
+- **ProfileManagement**: CRUD profili completo
+- **Toast Notifications**: Feedback utente in tempo reale
+- **Modal Dialogs**: Conferme operazioni critiche
+- **Progress Indicators**: Feedback operazioni lunghe
+
+#### Design:
+- **Bootstrap 5**: Framework CSS responsive
+- **Font Awesome**: Iconografia consistente
+- **Dark/Light Mode**: Temi personalizzabili
+- **Mobile Responsive**: Ottimizzato per dispositivi mobili
+
+### 10. Health Checks e Monitoraggio
+
+#### Caratteristiche:
+- **Health Checks**: Endpoint per monitoraggio stato applicazione
+- **Database Health**: Verifica connessione database
+- **Background Services**: Stato background services
+- **Memory Monitoring**: Tracciamento utilizzo memoria
+- **Performance Metrics**: Statistiche performance sistema
+
+#### File Chiave:
+- `Data_Coupler/HealthChecks/DatabaseHealthCheck.cs`
+- `Data_Coupler/HealthChecks/BackgroundServiceHealthCheck.cs`
+
+## 🔐 Sicurezza
+
+### Gestione Credenziali:
+- **Data Protection API**: Crittografia con chiavi managed da .NET
+- **Key Rotation**: Supporto rotazione chiavi automatica
+- **Secure Storage**: Persistenza sicura su SQLite
+
+### Input Validation:
+- **SQL Injection Prevention**: Query parametrizzate ovunque
+- **XSS Protection**: Sanitizzazione input utente
+- **Whitelist Validation**: Validazione nomi tabelle/campi
+
+### Comunicazioni Sicure:
+- **HTTPS**: Forzato in produzione
+- **Certificate Validation**: Validazione certificati SSL/TLS
+- **Secure Headers**: Security headers HTTP
+
+### Audit Logging:
+- **Tracciamento Accessi**: Log accessi credenziali
+- **Operazioni Sensibili**: Log modifiche configurazioni
+- **Security Events**: Alert eventi sicurezza
+
+## 🛠️ Convenzioni di Codice
+
+### Naming:
+- **Classes/Interfaces**: PascalCase (es. `DataConnectionFactory`)
+- **Methods**: PascalCase (es. `GetDataAsync`)
+- **Properties**: PascalCase (es. `ConnectionString`)
+- **Private Fields**: camelCase con underscore (es. `_logger`)
+- **Local Variables**: camelCase (es. `connectionName`)
+
+### Async/Await:
+- Tutti i metodi I/O sono asincroni
+- Naming convention: `*Async` suffix
+- Uso di `CancellationToken` per operazioni cancellabili
+- **MAI** usare `.Result` o `.Wait()` - rischio deadlock
+
+### Dependency Injection:
+- **Singleton**: Servizi stateless (es. `IEncryptionService`)
+- **Scoped**: Servizi con stato per request (es. `IDataConnectionFactory`)
+- **Transient**: Servizi leggeri (es. validators)
+
+### Error Handling:
+- Try-catch con logging specifico
+- Messaggi utente user-friendly
+- Dettagli tecnici nei log, non in UI
+- Rollback transazioni in caso di errore
+
+## 📝 Pattern Architetturali Utilizzati
+
+### 1. Repository Pattern:
+- Astrazione accesso dati
+- `*Service` interfacce per business logic
+- `*Repository` per accesso database
+
+### 2. Factory Pattern:
+- `DataConnectionFactory`: Creazione connessioni database/REST
+- `RestServiceClientFactory`: Creazione client REST specifici
+
+### 3. Strategy Pattern:
+- Diversi provider database (SQL Server, MySQL, PostgreSQL, etc.)
+- Diversi client REST (Generic, Salesforce, SAP B1)
+
+### 4. Observer Pattern:
+- Background services per schedulazioni
+- Event-driven processing
+
+## 🧪 Testing
+
+### Unit Tests:
+- Copertura servizi core
+- Mock di dipendenze esterne
+- Test naming: `MethodName_Scenario_ExpectedBehavior`
+
+### Integration Tests:
+- Test connessioni database reali
+- Test API REST con server di test
+- Test end-to-end UI con Playwright
+
+## 📦 Deployment
+
+### Docker Support:
+- `Dockerfile`: Immagine Linux
+- `Dockerfile.windows`: Immagine Windows
+- `docker-compose.yml`: Orchestrazione multi-container
+- Health checks integrati
+
+### Windows Service:
+- Deploy come Windows Service
+- Auto-start configurabile
+- Logging Windows Event Log
+
+### Azure Deployment:
+- App Service support
+- Container Apps support
+- Key Vault integration per secrets
+
+## 🔄 Workflow di Sviluppo
+
+### Branching Strategy:
+- `main`: Produzione stabile
+- `development`: Sviluppo attivo (pubblica su `latest` tag)
+- `feature/*`: Nuove feature
+- `hotfix/*`: Fix urgenti
+
+### CI/CD Pipeline:
+- **Branch `main`**: Pubblica immagini Docker con tag `latest`
+- **Branch `development`**: Pubblica immagini Docker con tag `latest` (per testing continuo)
+- **Branch `staging`**: Pubblica immagini Docker con tag `staging-latest`
+- **Ogni commit**: Crea tag con SHA e timestamp per tracciabilità
+
+### Commit Messages:
+- Formato: `[Tipo] Descrizione breve`
+- Tipi: `[Feature]`, `[Fix]`, `[Refactor]`, `[Docs]`, `[Test]`
+- Esempio: `[Feature] Implementato sistema schedulazione avanzata`
+
+### Code Review:
+- Ogni PR richiede review
+- Checklist: code style, tests, documentation
+- CI/CD automatico
+
+## 📚 Documentazione Correlata
+
+### File di Documentazione nel Progetto:
+- **AGENTS.md**: Guida completa per AI agents e Copilot
+- **ADVANCED_SCHEDULING_SYSTEM.md**: Sistema schedulazione dettagliato
+- **GESTIONE_ASSOCIAZIONI_AVANZATA.md**: Sistema associazioni completo
+- **SALESFORCE_BATCH_EXTRACTION_IMPROVEMENTS.md**: Batch extraction Salesforce
+- **PRE_DISCOVERY_SYSTEM.md**: Sistema pre-discovery associazioni
+- **DELETION_SYNC_IMPLEMENTATION.md**: Sincronizzazione eliminazioni
+- **DOCKER_DEPLOYMENT.md**: Guida deployment Docker
+- **WINDOWS_SERVICE_DEPLOYMENT.md**: Deploy come Windows Service
+
+## 🎓 Best Practices per AI Assistants
+
+### Quando Modificare Codice:
+1. **Leggere Documentazione**: Consultare file MD correlati
+2. **Analizzare Pattern**: Seguire pattern esistenti nel codebase
+3. **Validare Input**: Sempre validare parametri
+4. **Error Handling**: Gestire tutti i possibili errori
+5. **Logging**: Aggiungere log appropriati
+6. **Testing**: Creare/aggiornare test correlati
+7. **Documentazione**: Aggiornare XML comments e MD files
+
+### Quando Creare Nuove Feature:
+1. **Progettare Prima**: Pianificare architettura
+2. **Seguire Convenzioni**: Rispettare code style
+3. **Dependency Injection**: Registrare nuovi servizi in `Program.cs`
+4. **Database Changes**: Creare migration Entity Framework
+5. **UI Consistency**: Seguire design pattern esistente
+6. **Documentare**: Creare/aggiornare documentazione
+
+### Red Flags da Evitare:
+- ❌ Hardcoded credentials o secrets
+- ❌ SQL injection vulnerabilities
+- ❌ Blocking calls in async methods
+- ❌ Catch generico senza logging
+- ❌ Modifiche database senza migration
+- ❌ Breaking changes senza versioning
+- ❌ Codice duplicato invece di refactoring
+
+## 🚀 Roadmap Futura
+
+### Feature in Pianificazione:
+- [ ] Supporto file Excel/CSV avanzato
+- [ ] Sistema di notifiche (email, webhook)
+- [ ] Dashboard analytics avanzato
+- [ ] Multi-tenant support
+- [ ] API REST pubblica
+- [ ] Plugin system per connectors custom
+- [ ] Machine learning per mapping suggeriti
+- [ ] Real-time data sync
+
+### Miglioramenti Tecnici:
+- [ ] Migrazione a .NET 10 (quando disponibile)
+- [ ] Caching distribuito (Redis)
+- [ ] Message queue (RabbitMQ/Azure Service Bus)
+- [ ] Elasticsearch per log search
+- [ ] Prometheus/Grafana per monitoring
+
+---
+
+**Versione**: 2.0
+**Ultimo Aggiornamento**: 22 Gennaio 2026
+**Framework**: .NET 9.0
+**Sviluppatore**: Alessio Dalsanto
+**Repository**: https://github.com/AlessioDalsi/Data-Coupler
diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
index 3f48edc..55b4c5a 100644
--- a/.github/workflows/docker-build.yml
+++ b/.github/workflows/docker-build.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- main
- - dev
+ - development
- staging
workflow_dispatch:
inputs:
@@ -50,6 +50,7 @@ jobs:
tags: |
# Tag based on branch
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
+ type=raw,value=latest,enable=${{ github.ref == 'refs/heads/development' }}
type=raw,value=dev-latest,enable=${{ github.ref == 'refs/heads/dev' }}
type=raw,value=staging-latest,enable=${{ github.ref == 'refs/heads/staging' }}
# Tag with commit sha
@@ -107,6 +108,7 @@ jobs:
tags: |
# Tag based on branch with windows suffix
type=raw,value=latest-windows,enable=${{ github.ref == 'refs/heads/main' }}
+ type=raw,value=latest-windows,enable=${{ github.ref == 'refs/heads/development' }}
type=raw,value=dev-latest-windows,enable=${{ github.ref == 'refs/heads/dev' }}
type=raw,value=staging-latest-windows,enable=${{ github.ref == 'refs/heads/staging' }}
# Tag with commit sha
@@ -165,6 +167,14 @@ jobs:
${IMAGE_LOWER}:latest \
${IMAGE_LOWER}:latest-windows
+ - name: Create and push manifest for development branch
+ if: github.ref == 'refs/heads/development'
+ run: |
+ IMAGE_LOWER=$(echo "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" | tr '[:upper:]' '[:lower:]')
+ docker buildx imagetools create -t ${IMAGE_LOWER}:latest \
+ ${IMAGE_LOWER}:latest \
+ ${IMAGE_LOWER}:latest-windows
+
- name: Create and push manifest for dev branch
if: github.ref == 'refs/heads/dev'
run: |
diff --git a/CredentialManager/Migrations/20260123104841_AddEnableDeletionSyncToProfileSchedule.Designer.cs b/CredentialManager/Migrations/20260123104841_AddEnableDeletionSyncToProfileSchedule.Designer.cs
new file mode 100644
index 0000000..897a8d6
--- /dev/null
+++ b/CredentialManager/Migrations/20260123104841_AddEnableDeletionSyncToProfileSchedule.Designer.cs
@@ -0,0 +1,585 @@
+//
+using System;
+using CredentialManager.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace CredentialManager.Migrations
+{
+ [DbContext(typeof(CredentialDbContext))]
+ [Migration("20260123104841_AddEnableDeletionSyncToProfileSchedule")]
+ partial class AddEnableDeletionSyncToProfileSchedule
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "9.0.0");
+
+ modelBuilder.Entity("CredentialManager.Models.CredentialEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AdditionalParameters")
+ .HasMaxLength(2000)
+ .HasColumnType("TEXT");
+
+ b.Property("CommandTimeout")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(30);
+
+ b.Property("ConnectionString")
+ .HasMaxLength(500)
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedBy")
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.Property("DatabaseName")
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.Property("DatabaseType")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("EncryptedApiKey")
+ .HasMaxLength(500)
+ .HasColumnType("TEXT");
+
+ b.Property("EncryptedAuthToken")
+ .HasMaxLength(500)
+ .HasColumnType("TEXT");
+
+ b.Property("EncryptedPassword")
+ .HasColumnType("TEXT");
+
+ b.Property("Headers")
+ .HasMaxLength(2000)
+ .HasColumnType("TEXT");
+
+ b.Property("Host")
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("IgnoreSslErrors")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(false);
+
+ b.Property("IsActive")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(true);
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.Property("Port")
+ .HasColumnType("INTEGER");
+
+ b.Property("RestServiceType")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("TimeoutSeconds")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(100);
+
+ b.Property("Type")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("Username")
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DatabaseType");
+
+ b.HasIndex("IsActive");
+
+ b.HasIndex("Name")
+ .IsUnique();
+
+ b.HasIndex("Type");
+
+ b.ToTable("Credentials", (string)null);
+ });
+
+ modelBuilder.Entity("CredentialManager.Models.DataCouplerProfile", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasDefaultValueSql("CURRENT_TIMESTAMP");
+
+ b.Property("CreatedBy")
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.Property("DeletionAction")
+ .HasMaxLength(20)
+ .HasColumnType("TEXT");
+
+ b.Property("DeletionMarkField")
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("DeletionMarkValue")
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.Property("Description")
+ .HasMaxLength(500)
+ .HasColumnType("TEXT");
+
+ b.Property("DestinationCredentialId")
+ .HasColumnType("INTEGER");
+
+ b.Property("DestinationEndpoint")
+ .HasMaxLength(500)
+ .HasColumnType("TEXT");
+
+ b.Property("DestinationSchema")
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("DestinationTable")
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("DestinationType")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("TEXT");
+
+ b.Property("FieldMappingJson")
+ .HasMaxLength(4000)
+ .HasColumnType("TEXT");
+
+ b.Property("IsActive")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(true);
+
+ b.Property("LastUsedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.Property("SourceCredentialId")
+ .HasColumnType("INTEGER");
+
+ b.Property("SourceCustomQuery")
+ .HasMaxLength(2000)
+ .HasColumnType("TEXT");
+
+ b.Property("SourceDatabaseName")
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("SourceFilePath")
+ .HasMaxLength(500)
+ .HasColumnType("TEXT");
+
+ b.Property("SourceKeyField")
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("SourceSchema")
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("SourceTable")
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("SourceType")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("TEXT");
+
+ b.Property("SyncDeletions")
+ .HasColumnType("INTEGER");
+
+ b.Property("UseRecordAssociations")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CreatedAt");
+
+ b.HasIndex("DestinationCredentialId");
+
+ b.HasIndex("DestinationType");
+
+ b.HasIndex("IsActive");
+
+ b.HasIndex("LastUsedAt");
+
+ b.HasIndex("Name")
+ .IsUnique();
+
+ b.HasIndex("SourceCredentialId");
+
+ b.HasIndex("SourceType");
+
+ b.ToTable("DataCouplerProfiles", (string)null);
+ });
+
+ modelBuilder.Entity("CredentialManager.Models.KeyAssociation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AdditionalInfo")
+ .HasMaxLength(2000)
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("Data_Hash")
+ .HasMaxLength(64)
+ .HasColumnType("TEXT");
+
+ b.Property("DeletedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("DeletionSynced")
+ .HasColumnType("INTEGER");
+
+ b.Property("DeletionSyncedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("DestinationEntity")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("DestinationId")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("DestinationKeyField")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("IsActive")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(true);
+
+ b.Property("IsSourceDeleted")
+ .HasColumnType("INTEGER");
+
+ b.Property("KeyValue")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("TEXT");
+
+ b.Property("LastVerifiedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("MappedDestinationField")
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("RestCredentialName")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.Property("SourceKeyField")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("SourcesInfo")
+ .HasMaxLength(2000)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CreatedAt");
+
+ b.HasIndex("DestinationEntity");
+
+ b.HasIndex("IsActive");
+
+ b.HasIndex("KeyValue")
+ .HasDatabaseName("IX_KeyAssociations_KeyValue");
+
+ b.HasIndex("LastVerifiedAt");
+
+ b.HasIndex("RestCredentialName");
+
+ b.HasIndex("KeyValue", "DestinationEntity", "RestCredentialName")
+ .IsUnique()
+ .HasDatabaseName("IX_KeyAssociations_Unique");
+
+ b.ToTable("KeyAssociations", (string)null);
+ });
+
+ modelBuilder.Entity("CredentialManager.Models.ProfileSchedule", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("CreatedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedBy")
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.Property("DailyTime")
+ .HasMaxLength(10)
+ .HasColumnType("TEXT");
+
+ b.Property("DayOfMonth")
+ .HasColumnType("INTEGER");
+
+ b.Property("DayOfWeek")
+ .HasColumnType("INTEGER");
+
+ b.Property("Description")
+ .HasMaxLength(500)
+ .HasColumnType("TEXT");
+
+ b.Property("DestinationDatabaseOverride")
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.Property("EnableDeletionSync")
+ .HasColumnType("INTEGER");
+
+ b.Property("ExecutionCount")
+ .HasColumnType("INTEGER");
+
+ b.Property("IntervalUnit")
+ .HasMaxLength(20)
+ .HasColumnType("TEXT");
+
+ b.Property("IntervalValue")
+ .HasColumnType("INTEGER");
+
+ b.Property("IsActive")
+ .HasColumnType("INTEGER");
+
+ b.Property("IsEnabled")
+ .HasColumnType("INTEGER");
+
+ b.Property("LastExecutionMessage")
+ .HasMaxLength(1000)
+ .HasColumnType("TEXT");
+
+ b.Property("LastExecutionRecordCount")
+ .HasColumnType("INTEGER");
+
+ b.Property("LastExecutionStatus")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("TEXT");
+
+ b.Property("LastExecutionTime")
+ .HasColumnType("TEXT");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.Property("NextExecutionTime")
+ .HasColumnType("TEXT");
+
+ b.Property("ProfileId")
+ .HasColumnType("INTEGER");
+
+ b.Property("ScheduleType")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("TEXT");
+
+ b.Property("ScheduledDateTime")
+ .HasColumnType("TEXT");
+
+ b.Property("SourceDatabaseOverride")
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ProfileId");
+
+ b.ToTable("ProfileSchedules");
+ });
+
+ modelBuilder.Entity("CredentialManager.Models.ScheduleExecutionHistory", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AdditionalInfo")
+ .HasMaxLength(2000)
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("DestinationInfo")
+ .HasMaxLength(500)
+ .HasColumnType("TEXT");
+
+ b.Property("DestinationType")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("EndTime")
+ .HasColumnType("TEXT");
+
+ b.Property("ErrorDetails")
+ .HasMaxLength(5000)
+ .HasColumnType("TEXT");
+
+ b.Property("Message")
+ .HasMaxLength(2000)
+ .HasColumnType("TEXT");
+
+ b.Property("ProfileId")
+ .HasColumnType("INTEGER");
+
+ b.Property("ProfileName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("TEXT");
+
+ b.Property("RecordsProcessed")
+ .HasColumnType("INTEGER");
+
+ b.Property("RecordsWithErrors")
+ .HasColumnType("INTEGER");
+
+ b.Property("ScheduleId")
+ .HasColumnType("INTEGER");
+
+ b.Property("SourceInfo")
+ .HasMaxLength(500)
+ .HasColumnType("TEXT");
+
+ b.Property("SourceType")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT");
+
+ b.Property("StartTime")
+ .HasColumnType("TEXT");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("TEXT");
+
+ b.Property("TriggerType")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("TEXT");
+
+ b.Property("TriggeredBy")
+ .HasMaxLength(100)
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ProfileId");
+
+ b.HasIndex("ScheduleId");
+
+ b.HasIndex("StartTime");
+
+ b.HasIndex("Status");
+
+ b.HasIndex("TriggerType");
+
+ b.ToTable("ScheduleExecutionHistories", (string)null);
+ });
+
+ modelBuilder.Entity("CredentialManager.Models.DataCouplerProfile", b =>
+ {
+ b.HasOne("CredentialManager.Models.CredentialEntity", "DestinationCredential")
+ .WithMany()
+ .HasForeignKey("DestinationCredentialId")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ b.HasOne("CredentialManager.Models.CredentialEntity", "SourceCredential")
+ .WithMany()
+ .HasForeignKey("SourceCredentialId")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ b.Navigation("DestinationCredential");
+
+ b.Navigation("SourceCredential");
+ });
+
+ modelBuilder.Entity("CredentialManager.Models.ProfileSchedule", b =>
+ {
+ b.HasOne("CredentialManager.Models.DataCouplerProfile", "Profile")
+ .WithMany()
+ .HasForeignKey("ProfileId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Profile");
+ });
+
+ modelBuilder.Entity("CredentialManager.Models.ScheduleExecutionHistory", b =>
+ {
+ b.HasOne("CredentialManager.Models.ProfileSchedule", "Schedule")
+ .WithMany()
+ .HasForeignKey("ScheduleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Schedule");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/CredentialManager/Migrations/20260123104841_AddEnableDeletionSyncToProfileSchedule.cs b/CredentialManager/Migrations/20260123104841_AddEnableDeletionSyncToProfileSchedule.cs
new file mode 100644
index 0000000..d202b37
--- /dev/null
+++ b/CredentialManager/Migrations/20260123104841_AddEnableDeletionSyncToProfileSchedule.cs
@@ -0,0 +1,29 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace CredentialManager.Migrations
+{
+ ///
+ public partial class AddEnableDeletionSyncToProfileSchedule : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "EnableDeletionSync",
+ table: "ProfileSchedules",
+ type: "INTEGER",
+ nullable: false,
+ defaultValue: false);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "EnableDeletionSync",
+ table: "ProfileSchedules");
+ }
+ }
+}
diff --git a/CredentialManager/Migrations/CredentialDbContextModelSnapshot.cs b/CredentialManager/Migrations/CredentialDbContextModelSnapshot.cs
index 885c024..64a742e 100644
--- a/CredentialManager/Migrations/CredentialDbContextModelSnapshot.cs
+++ b/CredentialManager/Migrations/CredentialDbContextModelSnapshot.cs
@@ -382,6 +382,9 @@ namespace CredentialManager.Migrations
.HasMaxLength(100)
.HasColumnType("TEXT");
+ b.Property("EnableDeletionSync")
+ .HasColumnType("INTEGER");
+
b.Property("ExecutionCount")
.HasColumnType("INTEGER");
diff --git a/CredentialManager/Models/ProfileSchedule.cs b/CredentialManager/Models/ProfileSchedule.cs
index 9de9e3c..593931f 100644
--- a/CredentialManager/Models/ProfileSchedule.cs
+++ b/CredentialManager/Models/ProfileSchedule.cs
@@ -70,6 +70,9 @@ public class ProfileSchedule
[MaxLength(100)]
public string? DestinationDatabaseOverride { get; set; }
+ // Configurazione sincronizzazione eliminazioni (default: disabilitata)
+ public bool EnableDeletionSync { get; set; } = false;
+
// Metadati
[MaxLength(100)]
public string? CreatedBy { get; set; }
diff --git a/CredentialManager/design_time_temp.db b/CredentialManager/design_time_temp.db
index 589aa35..0482876 100644
Binary files a/CredentialManager/design_time_temp.db and b/CredentialManager/design_time_temp.db differ
diff --git a/Data_Coupler/Models/BackupModels.cs b/Data_Coupler/Models/BackupModels.cs
index 4eeb651..423ef01 100644
--- a/Data_Coupler/Models/BackupModels.cs
+++ b/Data_Coupler/Models/BackupModels.cs
@@ -289,6 +289,9 @@ public class ProfileScheduleBackup
[JsonPropertyName("createdBy")]
public string? CreatedBy { get; set; }
+
+ [JsonPropertyName("enableDeletionSync")]
+ public bool EnableDeletionSync { get; set; } = false;
}
///
diff --git a/Data_Coupler/Pages/DataCoupler.razor.cs b/Data_Coupler/Pages/DataCoupler.razor.cs
index 6cf9b76..ff532e7 100644
--- a/Data_Coupler/Pages/DataCoupler.razor.cs
+++ b/Data_Coupler/Pages/DataCoupler.razor.cs
@@ -1496,8 +1496,10 @@ public partial class DataCoupler : ComponentBase
recordNumber++;
}
- // 3.5 Sincronizza le cancellazioni (se abilitato)
+ // 3.5 Sincronizzazione cancellazioni (DISABILITATA per trasferimenti manuali)
+ // Questa funzionalità è disponibile solo per le schedulazioni con configurazione esplicita
int deletedCount = 0;
+ /* DELETION SYNC DISABILITATA PER TRASFERIMENTI MANUALI
if (useRecordAssociations && !string.IsNullOrEmpty(sourceKeyField))
{
try
@@ -1570,6 +1572,7 @@ public partial class DataCoupler : ComponentBase
});
}
}
+ */
// 4. Mostra risultati
if (errorCount == 0)
diff --git a/Data_Coupler/Pages/Scheduling.razor b/Data_Coupler/Pages/Scheduling.razor
index d780b72..d6bd0b3 100644
--- a/Data_Coupler/Pages/Scheduling.razor
+++ b/Data_Coupler/Pages/Scheduling.razor
@@ -336,6 +336,30 @@
+
+
+
+ Opzioni Avanzate
+
+
+
+
+
+
+
+
+
+
+ Attenzione: Se abilitata, i record eliminati dalla sorgente saranno automaticamente eliminati anche dalla destinazione durante l'esecuzione schedulata.
+ Questa opzione è disabilitata di default per motivi di sicurezza.
+ Usare con cautela!
+
+