📋 Commit iniziale con: - ✅ Documentazione unificata in docs/ - ✅ Codice Laravel in netgescon-laravel/ - ✅ Script automazione in scripts/ - ✅ Configurazione sync rsync - ✅ Struttura organizzata e pulita 🔄 Versione: 2025.07.19-1644 🎯 Sistema pronto per Git distribuito
590 lines
19 KiB
Markdown
590 lines
19 KiB
Markdown
# NETGESCON - DATABASE COMUNI ITALIANI
|
|
|
|
## 📋 OVERVIEW
|
|
Integrazione del database completo dei comuni italiani con licenza MIT per gestire indirizzi, calcolo codice fiscale, CAP e dati geografici. Sistema auto-aggiornante collegato alle fonti ISTAT ufficiali.
|
|
|
|
## 🗂️ STRUTTURA DATI FORNITA
|
|
|
|
### Tabelle Principali (6 normalizzate + 2 aggregate)
|
|
|
|
#### 1. gi_nazioni
|
|
**Scopo**: Calcolo codice fiscale per persone nate all'estero
|
|
```sql
|
|
CREATE TABLE gi_nazioni (
|
|
sigla_nazione VARCHAR(10) PRIMARY KEY, -- IT, F, D, USA
|
|
codice_belfiore VARCHAR(4), -- Codice per CF
|
|
denominazione_nazione VARCHAR(255), -- ITALIA, FRANCIA
|
|
denominazione_cittadinanza VARCHAR(255) -- Italiana, Francese
|
|
);
|
|
```
|
|
|
|
#### 2. gi_regioni
|
|
**Scopo**: Classificazione geografica e menù a tendina
|
|
```sql
|
|
CREATE TABLE gi_regioni (
|
|
codice_regione VARCHAR(3) PRIMARY KEY, -- Codice ISTAT
|
|
ripartizione_geografica VARCHAR(50), -- Nord-ovest, Centro, Sud, Isole
|
|
denominazione_regione VARCHAR(100),
|
|
tipologia_regione VARCHAR(50), -- statuto ordinario/speciale
|
|
numero_province INT,
|
|
numero_comuni INT,
|
|
superficie_kmq DECIMAL(10,2)
|
|
);
|
|
```
|
|
|
|
#### 3. gi_province
|
|
**Scopo**: Unità territoriali sovracomunali
|
|
```sql
|
|
CREATE TABLE gi_province (
|
|
codice_sovracomunale VARCHAR(6) PRIMARY KEY, -- Codice ISTAT
|
|
codice_regione VARCHAR(3), -- FK
|
|
sigla_provincia VARCHAR(2), -- MI, RM, BO
|
|
denominazione_provincia VARCHAR(255),
|
|
tipologia_provincia VARCHAR(100), -- Provincia, Città metropolitana, etc
|
|
numero_comuni INT,
|
|
superficie_kmq DECIMAL(10,2)
|
|
);
|
|
```
|
|
|
|
#### 4. gi_comuni ⭐ (PRINCIPALE)
|
|
**Scopo**: Tutti i comuni italiani attivi
|
|
```sql
|
|
CREATE TABLE gi_comuni (
|
|
codice_istat VARCHAR(6) PRIMARY KEY, -- Codice ISTAT alfanumerico
|
|
sigla_provincia VARCHAR(2), -- FK
|
|
denominazione_ita_altra VARCHAR(255), -- Bolzano/Bozen
|
|
denominazione_ita VARCHAR(255), -- Bolzano
|
|
denominazione_altra VARCHAR(255), -- Bozen
|
|
flag_capoluogo ENUM('SI','NO'),
|
|
codice_belfiore VARCHAR(4), -- PER CALCOLO CODICE FISCALE ⭐
|
|
lat DECIMAL(10,8), -- Coordinate GPS
|
|
lon DECIMAL(11,8),
|
|
superficie_kmq DECIMAL(10,2),
|
|
codice_sovracomunale VARCHAR(6) -- FK
|
|
);
|
|
```
|
|
|
|
#### 5. gi_comuni_validita ⭐ (STORICO)
|
|
**Scopo**: Comuni cessati - FONDAMENTALE per CF persone anziane
|
|
```sql
|
|
CREATE TABLE gi_comuni_validita (
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|
codice_istat VARCHAR(6),
|
|
sigla_provincia VARCHAR(2),
|
|
denominazione_ita VARCHAR(255),
|
|
codice_belfiore VARCHAR(4), -- CHIAVE per CF
|
|
data_inizio_validita DATE,
|
|
data_fine_validita DATE, -- NULL = attivo
|
|
stato_validita ENUM('Attivo','Inattivo')
|
|
);
|
|
```
|
|
|
|
#### 6. gi_cap
|
|
**Scopo**: Relazione Comuni-CAP (molti a molti)
|
|
```sql
|
|
CREATE TABLE gi_cap (
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|
codice_istat VARCHAR(6), -- FK
|
|
cap VARCHAR(5)
|
|
);
|
|
```
|
|
|
|
### Tabelle Aggregate (Per performance)
|
|
|
|
#### 7. gi_comuni_nazioni_cf ⭐ (PER CALCOLO CF)
|
|
**Scopo**: Unisce comuni + nazioni per calcolo CF completo
|
|
```sql
|
|
CREATE TABLE gi_comuni_nazioni_cf (
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|
sigla_provincia VARCHAR(2), -- EE per estero
|
|
denominazione_ita VARCHAR(255), -- Comune o Nazione
|
|
codice_belfiore VARCHAR(4), -- CODICE PER CF ⭐
|
|
data_inizio_validita DATE,
|
|
data_fine_validita DATE
|
|
);
|
|
```
|
|
|
|
#### 8. gi_comuni_cap ⭐ (PER AUTOCOMPLETAMENTO)
|
|
**Scopo**: Tutti i dati aggregati per ricerca rapida
|
|
```sql
|
|
CREATE TABLE gi_comuni_cap (
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|
codice_istat VARCHAR(6),
|
|
denominazione_ita_altra VARCHAR(255),
|
|
denominazione_ita VARCHAR(255),
|
|
cap VARCHAR(5),
|
|
sigla_provincia VARCHAR(2),
|
|
denominazione_provincia VARCHAR(255),
|
|
codice_regione VARCHAR(3),
|
|
denominazione_regione VARCHAR(100),
|
|
lat DECIMAL(10,8),
|
|
lon DECIMAL(11,8),
|
|
codice_belfiore VARCHAR(4), -- ⭐ SEMPRE PRESENTE
|
|
flag_capoluogo ENUM('SI','NO')
|
|
);
|
|
```
|
|
|
|
## 🧮 ALGORITMO CALCOLO CODICE FISCALE
|
|
|
|
### Struttura Codice Fiscale (16 caratteri)
|
|
```
|
|
RSSMRA80E15H501T
|
|
└─┬─┘└┬┘└┬┘└┬──┘└┬
|
|
│ │ │ │ │
|
|
│ │ │ │ └─ Carattere controllo (T)
|
|
│ │ │ └───── Codice Belfiore comune (H501)
|
|
│ │ └──────── Giorno nascita + 40 se donna (15)
|
|
│ └─────────── Mese nascita (E = Maggio)
|
|
└─────────────── Anno nascita (80 = 1980)
|
|
```
|
|
|
|
### Implementazione Algoritmo PHP
|
|
|
|
```php
|
|
class CodiceFiscaleCalculator
|
|
{
|
|
// Tabelle conversione per algoritmo
|
|
private static $mesi = [
|
|
1 => 'A', 2 => 'B', 3 => 'C', 4 => 'D', 5 => 'E', 6 => 'H',
|
|
7 => 'L', 8 => 'M', 9 => 'P', 10 => 'R', 11 => 'S', 12 => 'T'
|
|
];
|
|
|
|
private static $caratteriDispari = [
|
|
'0' => 1, '1' => 0, '2' => 5, '3' => 7, '4' => 9, '5' => 13,
|
|
'6' => 15, '7' => 17, '8' => 19, '9' => 21, 'A' => 1, 'B' => 0,
|
|
'C' => 5, 'D' => 7, 'E' => 9, 'F' => 13, 'G' => 15, 'H' => 17,
|
|
'I' => 19, 'J' => 21, 'K' => 2, 'L' => 4, 'M' => 18, 'N' => 20,
|
|
'O' => 11, 'P' => 3, 'Q' => 6, 'R' => 8, 'S' => 12, 'T' => 14,
|
|
'U' => 16, 'V' => 10, 'W' => 22, 'X' => 25, 'Y' => 24, 'Z' => 23
|
|
];
|
|
|
|
private static $caratteriPari = [
|
|
'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5,
|
|
'6' => 6, '7' => 7, '8' => 8, '9' => 9, 'A' => 0, 'B' => 1,
|
|
'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6, 'H' => 7,
|
|
'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13,
|
|
'O' => 14, 'P' => 15, 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19,
|
|
'U' => 20, 'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, 'Z' => 25
|
|
];
|
|
|
|
private static $caratteriControllo = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
|
|
/**
|
|
* Calcola il codice fiscale completo
|
|
*/
|
|
public static function calcola($nome, $cognome, $dataNascita, $sesso, $codiceBelfiore)
|
|
{
|
|
$cf = '';
|
|
|
|
// 1. Cognome (3 caratteri)
|
|
$cf .= self::calcolaCognome($cognome);
|
|
|
|
// 2. Nome (3 caratteri)
|
|
$cf .= self::calcolaNome($nome);
|
|
|
|
// 3. Anno nascita (2 caratteri)
|
|
$cf .= substr($dataNascita->format('Y'), -2);
|
|
|
|
// 4. Mese nascita (1 carattere)
|
|
$cf .= self::$mesi[(int)$dataNascita->format('n')];
|
|
|
|
// 5. Giorno nascita (2 caratteri) + 40 se donna
|
|
$giorno = (int)$dataNascita->format('d');
|
|
if (strtoupper($sesso) === 'F') {
|
|
$giorno += 40;
|
|
}
|
|
$cf .= str_pad($giorno, 2, '0', STR_PAD_LEFT);
|
|
|
|
// 6. Codice Belfiore (4 caratteri)
|
|
$cf .= strtoupper($codiceBelfiore);
|
|
|
|
// 7. Carattere di controllo
|
|
$cf .= self::calcolaCarattereControllo($cf);
|
|
|
|
return $cf;
|
|
}
|
|
|
|
/**
|
|
* Calcola le prime 3 consonanti del cognome
|
|
*/
|
|
private static function calcolaCognome($cognome)
|
|
{
|
|
return self::estraiCaratteri($cognome, 3);
|
|
}
|
|
|
|
/**
|
|
* Calcola caratteri nome (regole particolari)
|
|
*/
|
|
private static function calcolaNome($nome)
|
|
{
|
|
$consonanti = self::estraiConsonanti($nome);
|
|
$vocali = self::estraiVocali($nome);
|
|
|
|
// Se consonanti >= 4, prendi 1°, 3°, 4°
|
|
if (strlen($consonanti) >= 4) {
|
|
return substr($consonanti, 0, 1) . substr($consonanti, 2, 2);
|
|
}
|
|
|
|
// Altrimenti segui regola standard
|
|
return self::estraiCaratteri($nome, 3);
|
|
}
|
|
|
|
/**
|
|
* Estrae caratteri secondo regole CF
|
|
*/
|
|
private static function estraiCaratteri($stringa, $lunghezza)
|
|
{
|
|
$stringa = strtoupper(preg_replace('/[^A-Za-z]/', '', $stringa));
|
|
|
|
$consonanti = self::estraiConsonanti($stringa);
|
|
$vocali = self::estraiVocali($stringa);
|
|
|
|
$risultato = $consonanti . $vocali;
|
|
|
|
// Pad con X se necessario
|
|
return str_pad(substr($risultato, 0, $lunghezza), $lunghezza, 'X');
|
|
}
|
|
|
|
/**
|
|
* Estrae consonanti
|
|
*/
|
|
private static function estraiConsonanti($stringa)
|
|
{
|
|
return preg_replace('/[AEIOU]/', '', strtoupper($stringa));
|
|
}
|
|
|
|
/**
|
|
* Estrae vocali
|
|
*/
|
|
private static function estraiVocali($stringa)
|
|
{
|
|
return preg_replace('/[^AEIOU]/', '', strtoupper($stringa));
|
|
}
|
|
|
|
/**
|
|
* Calcola carattere di controllo
|
|
*/
|
|
private static function calcolaCarattereControllo($codice15Caratteri)
|
|
{
|
|
$somma = 0;
|
|
|
|
for ($i = 0; $i < 15; $i++) {
|
|
$carattere = $codice15Caratteri[$i];
|
|
|
|
if ($i % 2 === 0) { // Posizione dispari (0, 2, 4, ...)
|
|
$somma += self::$caratteriDispari[$carattere];
|
|
} else { // Posizione pari (1, 3, 5, ...)
|
|
$somma += self::$caratteriPari[$carattere];
|
|
}
|
|
}
|
|
|
|
$resto = $somma % 26;
|
|
return self::$caratteriControllo[$resto];
|
|
}
|
|
|
|
/**
|
|
* Valida un codice fiscale esistente
|
|
*/
|
|
public static function valida($codiceFiscale, $nome = null, $cognome = null, $dataNascita = null, $sesso = null, $codiceBelfiore = null)
|
|
{
|
|
// Verifica lunghezza
|
|
if (strlen($codiceFiscale) !== 16) {
|
|
return false;
|
|
}
|
|
|
|
// Verifica carattere controllo
|
|
$primi15 = substr($codiceFiscale, 0, 15);
|
|
$carattereControllo = substr($codiceFiscale, 15, 1);
|
|
|
|
if (self::calcolaCarattereControllo($primi15) !== $carattereControllo) {
|
|
return false;
|
|
}
|
|
|
|
// Se sono forniti i dati anagrafici, verifica coerenza
|
|
if ($nome && $cognome && $dataNascita && $sesso && $codiceBelfiore) {
|
|
$cfCalcolato = self::calcola($nome, $cognome, $dataNascita, $sesso, $codiceBelfiore);
|
|
return $codiceFiscale === $cfCalcolato;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Trova codice Belfiore per comune e data nascita
|
|
*/
|
|
public static function trovaCodiceBelfiore($comuneId, $dataNascita)
|
|
{
|
|
// Cerca in gi_comuni_validita per gestire comuni cessati
|
|
$comune = DB::table('gi_comuni_validita')
|
|
->where('codice_istat', $comuneId)
|
|
->where(function($query) use ($dataNascita) {
|
|
$query->where('data_inizio_validita', '<=', $dataNascita)
|
|
->where(function($q) use ($dataNascita) {
|
|
$q->whereNull('data_fine_validita')
|
|
->orWhere('data_fine_validita', '>=', $dataNascita);
|
|
});
|
|
})
|
|
->first();
|
|
|
|
return $comune ? $comune->codice_belfiore : null;
|
|
}
|
|
}
|
|
```
|
|
|
|
## 🔄 SISTEMA AUTO-AGGIORNAMENTO
|
|
|
|
### Fonti Ufficiali
|
|
- **ISTAT**: Dataset comuni italiani
|
|
- **Agenzia Entrate**: Codici Belfiore
|
|
- **Poste Italiane**: Database CAP
|
|
|
|
### Procedura Aggiornamento Automatico
|
|
```php
|
|
class AggiornamentoComuni
|
|
{
|
|
/**
|
|
* Download e import automatico da ISTAT
|
|
*/
|
|
public function aggiornaDatasetCompleto()
|
|
{
|
|
Log::info('Inizio aggiornamento dataset comuni');
|
|
|
|
// 1. Download file ufficiali
|
|
$dataset = $this->downloadDatasetISTAT();
|
|
|
|
// 2. Parsing e validazione
|
|
$datiValidati = $this->validaEparsaDati($dataset);
|
|
|
|
// 3. Confronto con dati esistenti
|
|
$differenze = $this->confrontaConEsistente($datiValidati);
|
|
|
|
// 4. Applicazione modifiche
|
|
if ($differenze['nuovi'] || $differenze['modificati'] || $differenze['cessati']) {
|
|
$this->applicaModifiche($differenze);
|
|
$this->inviaReportAggiornamento($differenze);
|
|
}
|
|
|
|
Log::info('Aggiornamento completato', ['differenze' => $differenze]);
|
|
}
|
|
|
|
/**
|
|
* Aggiornamento incrementale (solo nuovi/modificati)
|
|
*/
|
|
public function aggiornamentoIncrementale()
|
|
{
|
|
// Check solo comuni modificati nell'ultimo mese
|
|
$ultimoAggiornamento = Setting::get('ultimo_aggiornamento_comuni');
|
|
|
|
// Logica di confronto e import selettivo
|
|
}
|
|
}
|
|
```
|
|
|
|
### Scheduling Automatico
|
|
```php
|
|
// In app/Console/Kernel.php
|
|
protected function schedule(Schedule $schedule)
|
|
{
|
|
// Aggiornamento completo mensile
|
|
$schedule->command('comuni:aggiorna-completo')
|
|
->monthlyOn(1, '02:00')
|
|
->emailOutputOnFailure('admin@netgescon.it');
|
|
|
|
// Check incrementale settimanale
|
|
$schedule->command('comuni:aggiorna-incrementale')
|
|
->weeklyOn(1, '03:00');
|
|
}
|
|
```
|
|
|
|
## 🏗️ INTEGRAZIONE IN NETGESCON
|
|
|
|
### Tabelle NetGesCon da Modificare
|
|
|
|
```sql
|
|
-- Modifica tabella persone per FK a comuni
|
|
ALTER TABLE persone
|
|
ADD COLUMN luogo_nascita_comune_id VARCHAR(6),
|
|
ADD COLUMN residenza_comune_id VARCHAR(6),
|
|
ADD COLUMN domicilio_comune_id VARCHAR(6),
|
|
ADD COLUMN corrispondenza_comune_id VARCHAR(6),
|
|
ADD FOREIGN KEY fk_nascita_comune (luogo_nascita_comune_id) REFERENCES gi_comuni(codice_istat),
|
|
ADD FOREIGN KEY fk_residenza_comune (residenza_comune_id) REFERENCES gi_comuni(codice_istat);
|
|
|
|
-- Modifica tabella stabili
|
|
ALTER TABLE stabili
|
|
ADD COLUMN comune_id VARCHAR(6),
|
|
ADD FOREIGN KEY fk_stabile_comune (comune_id) REFERENCES gi_comuni(codice_istat);
|
|
```
|
|
|
|
### Helper Class per Comune
|
|
```php
|
|
class ComuneHelper
|
|
{
|
|
/**
|
|
* Ricerca comuni con autocompletamento
|
|
*/
|
|
public static function ricercaComuni($query, $limit = 10)
|
|
{
|
|
return DB::table('gi_comuni_cap')
|
|
->where('denominazione_ita', 'LIKE', "%$query%")
|
|
->orWhere('cap', 'LIKE', "$query%")
|
|
->orWhere('sigla_provincia', '=', strtoupper($query))
|
|
->limit($limit)
|
|
->get();
|
|
}
|
|
|
|
/**
|
|
* Dati completi comune per codice ISTAT
|
|
*/
|
|
public static function datiComune($codiceIstat)
|
|
{
|
|
return DB::table('gi_comuni_cap')
|
|
->where('codice_istat', $codiceIstat)
|
|
->first();
|
|
}
|
|
|
|
/**
|
|
* Calcola distanza tra due comuni
|
|
*/
|
|
public static function distanzaComuni($comune1Id, $comune2Id)
|
|
{
|
|
$c1 = self::datiComune($comune1Id);
|
|
$c2 = self::datiComune($comune2Id);
|
|
|
|
return self::calcolaDistanzaGPS($c1->lat, $c1->lon, $c2->lat, $c2->lon);
|
|
}
|
|
|
|
/**
|
|
* Trova comuni limitrofi
|
|
*/
|
|
public static function comuniLimitrofi($comuneId, $raggioKm = 25)
|
|
{
|
|
$comune = self::datiComune($comuneId);
|
|
|
|
// Query con calcolo distanza GPS
|
|
return DB::table('gi_comuni_cap')
|
|
->select('*')
|
|
->selectRaw("
|
|
( 6371 * acos( cos( radians(?) )
|
|
* cos( radians( lat ) )
|
|
* cos( radians( lon ) - radians(?) )
|
|
+ sin( radians(?) )
|
|
* sin( radians( lat ) ) ) ) AS distanza_km
|
|
", [$comune->lat, $comune->lon, $comune->lat])
|
|
->having('distanza_km', '<', $raggioKm)
|
|
->orderBy('distanza_km')
|
|
->get();
|
|
}
|
|
}
|
|
```
|
|
|
|
## 📱 COMPONENTI UI
|
|
|
|
### Autocompletamento Indirizzo
|
|
```html
|
|
<!-- Component: address-autocomplete.blade.php -->
|
|
<div class="form-group">
|
|
<label for="comune">Comune</label>
|
|
<input type="text" id="comune-search" class="form-control"
|
|
placeholder="Digita nome comune o CAP..." autocomplete="off">
|
|
<input type="hidden" id="comune-id" name="comune_id">
|
|
|
|
<div id="comuni-dropdown" class="dropdown-menu" style="display:none;">
|
|
<!-- Risultati via AJAX -->
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
$('#comune-search').on('input', function() {
|
|
const query = $(this).val();
|
|
|
|
if (query.length >= 2) {
|
|
$.ajax({
|
|
url: '/api/comuni/search',
|
|
data: { q: query },
|
|
success: function(comuni) {
|
|
let html = '';
|
|
comuni.forEach(comune => {
|
|
html += `
|
|
<a href="#" class="dropdown-item comune-option"
|
|
data-id="${comune.codice_istat}"
|
|
data-denominazione="${comune.denominazione_ita}"
|
|
data-cap="${comune.cap}"
|
|
data-provincia="${comune.sigla_provincia}">
|
|
${comune.denominazione_ita} (${comune.cap}) - ${comune.sigla_provincia}
|
|
</a>
|
|
`;
|
|
});
|
|
$('#comuni-dropdown').html(html).show();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
$(document).on('click', '.comune-option', function(e) {
|
|
e.preventDefault();
|
|
const $this = $(this);
|
|
|
|
$('#comune-search').val($this.data('denominazione'));
|
|
$('#comune-id').val($this.data('id'));
|
|
$('#cap').val($this.data('cap')); // Auto-compila CAP
|
|
$('#provincia').val($this.data('provincia')); // Auto-compila Provincia
|
|
$('#comuni-dropdown').hide();
|
|
});
|
|
</script>
|
|
```
|
|
|
|
## 📊 UTILIZZI IN NETGESCON
|
|
|
|
### 1. Calcolo Codice Fiscale
|
|
- **Input persona** → Verifica CF automatico
|
|
- **Persone anziane** → Cerca comune validità storica
|
|
- **Stranieri** → Gestione nazioni estere
|
|
|
|
### 2. Gestione Indirizzi
|
|
- **Autocompletamento** indirizzi completi
|
|
- **Validazione** CAP-Comune
|
|
- **Geolocalizzazione** stabili
|
|
|
|
### 3. Reportistica Geografica
|
|
- **Distribuzione** condomini per area
|
|
- **Analisi** bacino utenza amministratori
|
|
- **Ricerca** fornitori zona
|
|
|
|
### 4. Comunicazioni Legali
|
|
- **Indirizzi** conformi normative
|
|
- **CAP** sempre corretti
|
|
- **Certificazioni** conformità dati
|
|
|
|
## 🚀 ROADMAP INTEGRAZIONE
|
|
|
|
### Fase 1 - Import Database (Sprint 1)
|
|
- [ ] Download dataset MIT completo
|
|
- [ ] Import tabelle in NetGesCon
|
|
- [ ] Setup auto-aggiornamento mensile
|
|
- [ ] Test algoritmo codice fiscale
|
|
|
|
### Fase 2 - Integrazione Base (Sprint 2)
|
|
- [ ] Modifica tabelle esistenti con FK
|
|
- [ ] Helper class ComuneHelper
|
|
- [ ] API endpoint ricerca comuni
|
|
- [ ] Component autocompletamento
|
|
|
|
### Fase 3 - Validazioni (Sprint 3)
|
|
- [ ] Validazione CF all'inserimento persona
|
|
- [ ] Controllo coerenza CAP-Comune
|
|
- [ ] Import massivo con validazione
|
|
- [ ] Dashboard errori dati
|
|
|
|
### Fase 4 - Funzionalità Avanzate (Sprint 4)
|
|
- [ ] Geolocalizzazione e mappe
|
|
- [ ] Ricerca per prossimità
|
|
- [ ] Analytics geografiche
|
|
- [ ] Export dati conformi
|
|
|
|
---
|
|
|
|
**Data Analisi:** 14/07/2025
|
|
**Stato:** PRONTO PER IMPLEMENTAZIONE
|
|
**Priorità:** ALTA - Richiesto per anagrafica e CF
|