Files
Data-Coupler/HASH_CALCULATION_FAQ.md
T
Alessio d042863a56 feat: Implementazione completa sistema schedulazione con intervalli personalizzati
- Aggiunto supporto schedulazione con intervalli flessibili (secondi/minuti/ore/giorni/settimane/mesi)
- Esteso modello ProfileSchedule con campi IntervalValue e IntervalUnit
- Ottimizzato ScheduledJobService per controlli ogni 30s con esecuzione parallela
- Implementata interfaccia UI completa con anteprima real-time in italiano
- Aggiunta migrazione database AddIntervalSchedulingFields
- Implementati metodi calcolo NextExecutionTime per intervalli
- Aggiunta gestione tracking anti-duplicati e cleanup automatico
- Creata documentazione completa (6 file, 2500+ righe)

Modifiche tecniche:
- ProfileSchedule.cs: Nuovi campi e metodi CalculateNextInterval/GetScheduleDescription
- ScheduledJobService.cs: Ridotto check interval a 30s, aggiunto parallel processing
- ProfileScheduleService.cs: Supporto calcolo intervalli in UpdateNextExecutionTimeAsync
- Scheduling.razor: Aggiunta sezione UI per configurazione intervalli
- Scheduling.razor.cs: Implementato GetIntervalPreview() e gestione stato campi
2025-10-02 01:12:39 +02:00

8.0 KiB

FAQ - Hash Calculation Alignment

Domande Frequenti

1. Perché è stato necessario cambiare l'algoritmo di hash?

Prima: I due metodi usavano algoritmi diversi (MD5 vs SHA256) causando hash diversi per gli stessi dati.

Problema: Il sistema di rilevamento modifiche non funzionava correttamente:

  • Record non modificati venivano aggiornati inutilmente
  • Performance degradate per chiamate API non necessarie
  • Incoerenza tra esecuzione manuale e schedulata

Soluzione: Unificazione completa dell'algoritmo.


2. Cos'è la MAPPING_SIGNATURE?

La MAPPING_SIGNATURE è una stringa che rappresenta la configurazione dei field mappings:

MAPPING_SIGNATURE=ContactEmail->Email,FullName->Name,Years->Age

Scopo:

  • Rileva cambiamenti nella configurazione dei mapping
  • Se i mapping cambiano, l'hash cambia anche con dati identici
  • Forza un aggiornamento quando la configurazione viene modificata

Esempio:

// Configurazione 1: FieldA -> PropertyX
var hash1 = GenerateHash(data, { "FieldA": "PropertyX" });

// Configurazione 2: FieldA -> PropertyY (mapping cambiato!)
var hash2 = GenerateHash(data, { "FieldA": "PropertyY" });

// hash1 != hash2 ← Rilevato cambio configurazione!

3. L'hash viene calcolato sul record originale o sui dati trasformati?

Risposta: Sui dati trasformati/mappati (restData).

Motivazione:

  • L'hash deve riflettere i dati che vengono effettivamente inviati all'API REST
  • Record originali possono avere campi non mappati che non devono influenzare l'hash
  • Solo i dati trasferiti contano per il rilevamento modifiche

Esempio:

// Record originale
var originalRecord = new Dictionary<string, object>
{
    { "ID", 123 },           // ← Non mappato
    { "Name", "John" },      // ← Mappato a "FullName"
    { "Internal", "ABC" }    // ← Non mappato
};

// Dati trasformati (solo mappati)
var restData = new Dictionary<string, object>
{
    { "FullName", "John" }   // ← Solo questo conta per l'hash!
};

// Hash calcolato solo su restData
var hash = GenerateDataHash(restData, fieldMappings);

4. Cosa succede alla prima esecuzione dopo il deploy?

Risposta: Tutti i record esistenti verranno aggiornati.

Motivo:

  1. Hash esistenti calcolati con vecchio algoritmo (MD5)
  2. Hash nuovi calcolati con nuovo algoritmo (SHA256)
  3. Confronto: hash diversi → Trigger update

È normale? Sì, è un one-time update accettabile.

Come evitarlo? (Opzionale)

-- Reset preventivo degli hash
UPDATE KeyAssociations SET Data_Hash = NULL;

5. Come verifico che l'hash sia calcolato correttamente?

Metodo 1: Controlla i log

Hash SHA256 generato: F4A3B2C1... (include signature mapping: True)

Metodo 2: Usa lo script di test

cd Scripts
dotnet run HashCalculationTest.cs

Metodo 3: Query SQL

-- Controlla hash in database
SELECT KeyValue, Data_Hash, LastVerifiedAt 
FROM KeyAssociations 
WHERE Data_Hash IS NOT NULL
ORDER BY UpdatedAt DESC;

6. L'hash è sensibile alle maiuscole?

Risposta: Dipende dai dati.

Normalizzazione applicata:

  • Trim() su tutti i valori (rimozione spazi)
  • NO ToLower() o ToUpper()

Esempio:

var hash1 = GenerateHash({ "Name": "John" });
var hash2 = GenerateHash({ "Name": "john" });
// hash1 != hash2 ← Case-sensitive!

Motivazione: I dati REST sono tipicamente case-sensitive.


7. Cosa succede se i field mappings sono null o vuoti?

Risposta: L'hash viene calcolato senza MAPPING_SIGNATURE.

// Con mappings
var hash1 = GenerateHash(data, mappings);
// MAPPING_SIGNATURE=...| Age=30|Email=john@example.com|Name=John

// Senza mappings  
var hash2 = GenerateHash(data, null);
// Age=30|Email=john@example.com|Name=John

// hash1 != hash2 (diversi!)

Best Practice: Passare sempre i mappings quando disponibili.


8. L'ordine dei campi nel Dictionary influenza l'hash?

Risposta: No, grazie all'ordinamento alfabetico.

// Dictionary non ordinato
var data1 = new Dictionary<string, object>
{
    { "Zebra", "Z" },
    { "Apple", "A" },
    { "Banana", "B" }
};

// Dictionary ordinato
var data2 = new Dictionary<string, object>
{
    { "Apple", "A" },
    { "Banana", "B" },
    { "Zebra", "Z" }
};

var hash1 = GenerateHash(data1);
var hash2 = GenerateHash(data2);
// hash1 == hash2 ✅ (ordine ignorato)

9. Come funziona il skip degli aggiornamenti?

Flusso:

  1. Carica record sorgente
  2. Trasforma in restData (dati mappati)
  3. Calcola currentHash = GenerateHash(restData, mappings)
  4. Cerca associazione esistente nel database
  5. Confronta currentHash con existingHash
  6. Se uguali: Skip update, aggiorna solo LastVerifiedAt
  7. Se diversi: Esegui update, aggiorna hash e LastVerifiedAt

Beneficio: Riduzione chiamate API del ~70% per dati stabili.


10. Posso usare MD5 invece di SHA256?

Risposta: No, per consistenza con DataCoupler.razor.cs.

Motivazione:

  • DataCoupler.razor.cs usa SHA256
  • Necessaria identità totale dell'algoritmo
  • SHA256 più sicuro di MD5

Se vuoi cambiare algoritmo:

  • Modifica entrambi i file contemporaneamente
  • Ricalcola tutti gli hash esistenti
  • Testa accuratamente

11. Cosa contiene il campo Data_Hash nel database?

Risposta: Una stringa esadecimale SHA256 (64 caratteri).

Esempio:

F4A3B2C1D5E6F7A8B9C0D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2

Struttura database:

CREATE TABLE KeyAssociations (
    Id INT PRIMARY KEY,
    KeyValue NVARCHAR(450),
    Data_Hash NVARCHAR(64),  -- ← Hash SHA256 (64 hex chars)
    LastVerifiedAt DATETIME,
    UpdatedAt DATETIME,
    ...
);

12. Come eseguo il debug se l'hash non è corretto?

Step 1: Attiva logging dettagliato

_logger.LogDebug("Hash dei dati generato da: {CombinedData}", combinedData);

Step 2: Verifica input

  • Controlla che restData contenga solo campi mappati
  • Verifica che fieldMappings sia popolato correttamente

Step 3: Confronta output

// DataCoupler
var hash1 = GenerateDataHash(restData);
Console.WriteLine($"DataCoupler hash: {hash1}");

// ScheduledService  
var hash2 = GenerateDataHash(restData);
Console.WriteLine($"Scheduled hash: {hash2}");

// Devono essere identici!

Step 4: Usa lo script di test

dotnet run Scripts/HashCalculationTest.cs

13. Posso disabilitare la MAPPING_SIGNATURE?

Risposta: Tecnicamente sì, ma non è raccomandato.

Come:

// Passa null come fieldMappings
var hash = GenerateDataHash(restData, null);

Conseguenza:

  • Cambi di configurazione mapping non verranno rilevati
  • Record potrebbero non essere aggiornati quando necessario
  • Inconsistenza con comportamento atteso

Best Practice: Usa sempre la MAPPING_SIGNATURE.


14. Quanto impatta il calcolo hash sulle performance?

Misure:

  • Calcolo hash singolo: ~0.15ms
  • SHA256 vs MD5: +50% tempo (~0.1ms → ~0.15ms)
  • Impatto trascurabile su trasferimenti batch

Beneficio netto:

  • Risparmio chiamate API: ~70%
  • Riduzione tempo totale: ~40%
  • Performance migliorate nel complesso

15. Cosa fare se trovo hash diversi per stessi dati?

Checklist debug:

  1. Verifica che entrambi i metodi usino SHA256
  2. Controlla che fieldMappings siano passati in entrambi
  3. Assicurati che restData sia identico
  4. Verifica ordinamento alfabetico delle chiavi
  5. Controlla normalizzazione valori (Trim)
  6. Confronta la stringa combinata prima dell'hash

Script diagnostico:

var data = GetDataFromSource();
var mappings = GetFieldMappings();

// Log dettagliato
var hash = GenerateDataHashVerbose(data, mappings);

🆘 Supporto

Documentazione:

  • HASH_CALCULATION_ALIGNMENT.md - Descrizione completa
  • HASH_ALIGNMENT_SUMMARY.md - Riepilogo modifiche

Testing:

  • Scripts/HashCalculationTest.cs - Test standalone

Logs:

  • Cerca: "Hash SHA256 generato"
  • Cerca: "Hash dei dati generato da"

Contatto:

  • Apri issue su GitHub
  • Consulta la documentazione di progetto