# TerManager2 — Specifiche funzionali + istruzioni per container (Laravel)

> Documento operativo per realizzare **TerManager2**, applicazione Laravel per la gestione dell’assegnazione/rientro di cartoline territorio, statistiche di percorrenza e campagne speciali.
>
> **Obiettivo del documento**: chiarire requisiti, proporre un’architettura “container-ready”, definire modello dati e regole di calcolo, e fornire una **scomposizione in sottotask** con checklist di controllo a fine attività.

---

## 1) Visione d’insieme

**TerManager2** gestisce:
- **Territori** (cartoline) con PDF, stato (in reparto / assegnato / da rientrare / prioritario / inattivo) e proprietà (Zona, Tipologia, ecc.).
- **Proclamatori** (assegnatari) con dati **illeggibili in DB** (cifratura applicativa a livello di colonna) e gestione **GDPR**.
- **Assegnazioni** con data assegnazione/rientro, teocratic year, opzionale “conteggio campagna”.
- **Campagne** (periodi speciali) con percentuali di percorrenza e dashboard.
- **Statistiche** (media mensile di percorrenza nell’anno teocratico, indicatori di giacenza e “smarriti”).

**Ruoli (RBAC)**:
- **Amministratore**: tutto (impostazioni, territori, proclamatori, campagne, registro, proprietà territorio, assegnazione/rientro).
- **Assistente**: proclamatori, campagne, assegnazione/rientro.
- **Operatore**: assegnazione/rientro.

---

## 2) Requisiti non funzionali (sicurezza, GDPR, UX)

### 2.1 Sicurezza e dati illeggibili in DB
Requisito: i dati dei proclamatori devono risultare **illeggibili** se si accede direttamente al database.

**Scelta consigliata (Laravel)**:
- Password utente: **hash** (bcrypt/argon2id) (standard Laravel).
- Dati sensibili (nome, cognome, eventuali note): **cifratura applicativa per colonna**.
  - Usare **Laravel Eloquent encrypted casts** (es. `protected $casts = ['nome' => 'encrypted', ...];`) oppure un **Custom Cast** che cifri/decifri con AES-256-GCM.
  - La chiave di cifratura è `APP_KEY` (gestita come secret in ambiente). **Mai** versionarla.

**Nota importante**: la cifratura applicativa protegge “a riposo” nel DB. Per un livello ulteriore:
- cifrare anche **backup**;
- considerare cifratura volume/disco a livello host.

### 2.2 GDPR — criteri base da rispettare
Implementare almeno:
- **Minimizzazione**: salvare solo ciò che serve (nome/cognome e stato attivo).
- **Ruoli e autorizzazioni**: accesso ai dati solo per chi ha permessi.
- **Audit trail**: log di operazioni critiche (creazione/modifica/eliminazione, assegnazione/rientro, cambio stato territorio).
- **Retention**: definire policy su conservazione storici (es. registro assegnazioni conservato per X anni — parametro impostazioni).
- **Diritto all’oblio**: possibilità di **disattivare/anonimizzare** un proclamatore (senza rompere lo storico).
- **Esportazione**: esportazione dati (CSV/PDF) su richiesta (opzionale ma consigliato).
- **Consenso e informativa**: pagina “Privacy / Informativa” e log di accettazione (se necessario al contesto).

### 2.3 UI/UX
- Responsive “mobile-first” (smartphone/tablet), grafica minimale e moderna.
- Layout con:
  - header con logo + congregazione;
  - menu laterale (collassabile su mobile);
  - contenuti centrali con card e tabelle filtrabili.

Tecnologie UI consigliate:
- **TailwindCSS** + **Livewire** (rapido, server-driven) **oppure** Inertia + Vue/React.
- Componenti: ricerca veloce, paginazione, badge di stato, drawer per dettagli.

---

## 3) Architettura applicativa (Laravel)

### 3.1 Componenti
- Laravel (>=10) con:
  - Auth (Breeze/Jetstream o Fortify) + **RBAC** (Spatie Laravel Permission consigliato).
  - DB: MySQL/MariaDB o PostgreSQL.
  - Storage: `storage/app` per PDF (in dev) + volume Docker; in produzione valutare S3/MinIO.
  - Queue: Redis (opzionale ma utile per report/esportazioni).
  - Scheduler: `artisan schedule:work` per job (es. calcoli, pulizie, report).

### 3.2 Concetti chiave di dominio
- **Anno teocratico**: da **Settembre** (anno precedente) ad **Agosto** (anno corrente).
- **Percorrenza**: giorni tra assegnazione e rientro (nell’anno teocratico corrente) aggregati e convertiti in media mensile.
- **Campagna**: periodo con start/end; a ogni rientro si chiede se quel rientro conta per la campagna (anche retroattivo se assegnato durante il periodo ma rientrato dopo).

---

## 4) Modello dati (proposta)

> I nomi campi sono indicativi; adeguare naming (snake_case) e indici.

### 4.1 Tabelle

#### `users`
- auth utenti app (admin/assistente/operatore)
- campi standard Laravel (`email`, `password`, `name`, ecc.).

#### `roles`, `permissions`, `model_has_roles`, ...
- se si usa Spatie Permission.

#### `settings`
- configurazioni globali:
  - `congregazione_nome`
  - soglia `giorni_giacenza_da_assegnare`
  - soglia `giorni_giacenza_prioritari`
  - soglia `giorni_per_smarrito`
  - `home_limit_list` (default 10)
  - altre.

#### `proclamatori`
- `id`
- `nome` **encrypted**
- `cognome` **encrypted**
- `attivo` boolean
- timestamps

> (Opzionale) `display_name_hash` per ricerche rapide senza decifrare tutto (hash normalizzato di nome+cognome). Attenzione: l’hash può comunque essere dato personale; trattarlo come tale.

#### `territori`
- `id`
- `numero` (string/int) **univoco**
- `zona_id`
- `tipologia_id`
- `note` (text)
- `confini` (text)
- `pdf_path` (string)
- `attivo` boolean
- `prioritario` boolean
- timestamps

#### `zone` e `tipologie`
- `id`, `nome`, `attivo`.

#### `anni_teocratici`
- `id`
- `label` (es. `2025-2026`)
- `start_date` (1 settembre)
- `end_date` (31 agosto)
- univoco per `label`.

#### `campagne`
- `id`
- `start_date`
- `end_date`
- `descrizione`
- `attiva` (derivabile da date, ma può essere utile una view/flag)
- timestamps

#### `assegnazioni`
- `id`
- `territorio_id`
- `proclamatore_id`
- `anno_teocratico_id`
- `assigned_at`
- `returned_at` (nullable)
- `counted_in_campaign` boolean nullable (null = non chiesto/non applicabile)
- `campaign_id` nullable (se conteggiata)
- `note` nullable
- `created_by` (user_id)
- `returned_by` (user_id) nullable
- timestamps

#### `audit_logs` (o `activity_log`) — per pagina Log attività
- tabella dedicata a tracciare azioni utenti (vedi §6.7)
- se si usa un pacchetto, mantenere naming/colonne del pacchetto; altrimenti creare tabella custom.

### 4.2 Vincoli e indici (essenziali)
- `territori.numero` unique
- `assegnazioni`:
  - indice su (`territorio_id`, `returned_at`)
  - indice su (`proclamatore_id`, `returned_at`)
  - indice su (`anno_teocratico_id`)
- integrità referenziale con `ON DELETE CASCADE` dove sensato.
  - **Attenzione**: requisito: eliminazione territorio => eliminazione su tutto il registro assegnazioni. Quindi `assegnazioni.territorio_id` con cascade.

---

## 5) Regole di business e calcoli

### 5.1 Anno teocratico (creazione automatica)
- All’avvio Home o in fase di assegnazione/rientro:
  1. determinare data odierna;
  2. se mese >= 9 (settembre) -> anno teocratico = `anno_corrente-anno_corrente+1`;
  3. se mese <= 8 -> anno teocratico = `anno_corrente-1-anno_corrente`;
  4. se non esiste in DB, crearlo con start_date=1/09 e end_date=31/08.

### 5.2 Stato territorio
- **In reparto**: nessuna assegnazione aperta (ultima assegnazione `returned_at` non null) e attivo.
- **Assegnato a X**: esiste assegnazione aperta (`returned_at` null).
- **Smarrito / da rientrare**: assegnazione aperta da più giorni rispetto a `settings.giorni_per_smarrito`.
- **Prioritario**: flag `prioritario=true` oppure giacenza in reparto > soglia `giorni_giacenza_prioritari`.
- **Inattivo**: `attivo=false` (non assegnabile).

### 5.3 “Territori da assegnare” (Home)
- Territori **in reparto** con giacenza > `giorni_giacenza_da_assegnare`.
- Mostrare primi N (`home_limit_list`).
- Azione: assegnazione rapida a proclamatore.

### 5.4 “Territori prioritari” (Home)
- Territori in reparto con giacenza > `giorni_giacenza_prioritari` **oppure** `prioritario=true`.
- Azione: assegnazione rapida.

### 5.5 “Territori da rientrare” (Home)
- Territori con assegnazione aperta da più giorni di `giorni_per_smarrito`.
- Azione: rientro rapido (sull’attuale assegnatario).

### 5.6 Media mensile di percorrenza (Home)
Definizione richiesta: media mensile di percorrenza di tutti i territori nell’anno teocratico corrente.

Interpretazione operativa (coerente con testo):
- Per ogni **assegnazione chiusa** (returned_at valorizzato) nell’anno teocratico corrente:
  - `giorni = returned_at - assigned_at` (in giorni, >=0)
- Sommare tutti i `giorni` e normalizzare su base mensile.

Proposta formula (trasparente e verificabile):
- `giorni_totali = Σ giorni` per tutte le assegnazioni chiuse dell’anno teocratico corrente
- `mesi_trascorsi = numero mesi dall’inizio anno teocratico a oggi (min 1)`
- `media_mensile = giorni_totali / mesi_trascorsi`

> Alternativa: media per territorio o per assegnazione; scegliere una e documentarla in impostazioni. L’importante è che sia consistente e testata.

### 5.7 Campagne (Home + Tab Campagne)
- Campagna attiva se `today` tra `start_date` e `end_date`.
- Percentuale percorrenza campagna:
  - `territori_percorsi_in_campagna / territori_totali_pertinenti`.

Chiarimento necessario per “totali pertinenti”: suggerito:
- denominatore = numero di territori rientrati **conteggiati campagna** durante il periodo **+** territori assegnati nel periodo ma non ancora rientrati? (da definire).

Per evitare ambiguità e mantenere semplice:
- **Proposta**: percentuale = (numero assegnazioni chiuse conteggiate campagna) / (numero assegnazioni chiuse totali che hanno `assigned_at` nel range campagna) * 100.

#### Avviso rientro “con o senza campagna” (retroattivo)
Alla chiusura di un’assegnazione:
- se esiste campagna tale che `assigned_at` è compreso nel range campagna **(anche se oggi è dopo end_date)**, mostrare prompt:
  - “Questo rientro conta per la campagna X?”
  - se sì: `counted_in_campaign=true` e `campaign_id`.
  - se no: `counted_in_campaign=false`.
- se non applicabile: lasciare null.

#### Vista “territori percorsi e in quanto tempo”
Per campagna selezionata:
- lista assegnazioni conteggiate in campagna con:
  - territorio, proclamatore (mostrato in chiaro solo in UI), assigned_at, returned_at, giorni.

---

## 6) Pagine e funzionalità (corrette/riordinate)

### 6.1 Wizard iniziale (primo avvio)
Se mancano impostazioni base (`settings` vuoto):
- Step 1: Nome congregazione + logo (upload).
- Step 2: soglie (giacenza, prioritari, smarrito) + limite liste Home.
- Step 3: conferma e creazione admin (se necessario).

### 6.2 Home
Header:
- sinistra: logo + nome congregazione
- destra: nome utente + ruolo + logout

Sidebar:
- voci variabili in base ai permessi.

Contenuto centrale:
1) **Anno teocratico in corso** (auto-creazione se non esiste)
2) **Media mensile di percorrenza** (anno teocratico corrente)
3) **Campagna in corso** (se attiva): descrizione + percentuale + pulsante “Dettagli in tempo reale”
4) **Assegnazione rapida** (3 colonne/zone):
   - Territori da assegnare
   - Territori prioritari
   - Territori da rientrare
   Ogni lista:
   - mostra top N
   - ricerca veloce
   - pulsante “Vedi tutti” (pagina completa con filtri)

### 6.3 Gestione Territori
Lista filtrabile con colonne:
- Numero
- Zona / Tipologia
- Stato (badge)
- Ultimo rientro
- Azioni: Visualizza / Modifica / Elimina / Attiva-Disattiva

Dettaglio territorio (“Visualizza”):
- dati completi + PDF viewer
- storico assegnazioni raggruppato per anno teocratico

Regole:
- Eliminazione territorio => rimuove anche tutte le assegnazioni (cascade).
- Territorio inattivo non è assegnabile e non appare nelle liste “da assegnare/prioritari” (a meno di filtro admin).

### 6.4 Gestione Proclamatori
Lista filtrabile:
- Proclamatore (nome/cognome decifrati in UI)
- Attivo
- Territori attualmente in assegnazione (conteggio + link)
- Azioni: Visualizza / Modifica / Elimina / Disattiva

Regole consigliate:
- Eliminazione fisica solo se nessuno storico (oppure prevedere “anonimizza”).

### 6.5 Gestione Campagne
- Form creazione campagna (start, end, descrizione)
- Evidenza campagna attiva
- Elenco campagne completate (indipendente dall’anno teocratico)
- Dettaglio: elenco assegnazioni conteggiate, tempi, export.

### 6.6 Registro assegnazioni
Lista filtrabile per:
- anno teocratico
- territorio
- zona
- tipologia
- proclamatore

Output:
- tabella con assegnazioni (assegnato, rientrato, giorni, campagna sì/no)
- export CSV/PDF (opzionale)

### 6.7 Log attività (Audit trail) — **REQUISITO OBBLIGATORIO**

> Deve essere disponibile una **pagina di log** che riporti **tutte le azioni degli utenti** (Amministratore, Assistente, Operatore) e in particolare le operazioni di:
> - **Assegnazione** territorio
> - **Rientro** territorio (con/senza campagna)
> - **Creazione / modifica / cancellazione** di: Territori, Proclamatori, Campagne, Zone, Tipologie, Impostazioni
> - **Attiva/Disattiva** territorio o proclamatore
> - **Upload / sostituzione / eliminazione** PDF territorio
> - (Consigliato) **Login/Logout**, tentativi falliti, export dati

#### 6.7.1 Scopo
- Tracciabilità e accountability (chi ha fatto cosa e quando).
- Supporto a sicurezza e requisiti GDPR (audit delle operazioni sui dati).

#### 6.7.2 Permessi di accesso alla pagina log
- **Visualizzazione log**: `audit.view` (almeno Amministratore).
  - Opzionale: consentire anche ad Assistente una vista “limitata” (solo eventi di assegnazione/rientro e senza IP/user-agent).
- **Esportazione log**: `audit.export` (solo Amministratore).

#### 6.7.3 Dati minimi da registrare per ogni evento
Registrare per ogni azione:
- `id`
- `created_at` (data/ora evento)
- `causer_user_id` (utente che ha eseguito)
- `causer_role_snapshot` (ruolo al momento dell’azione)
- `event` (es. `created`, `updated`, `deleted`, `assigned`, `returned`, `activated`, `deactivated`, `uploaded_pdf`)
- `subject_type` + `subject_id` (entità coinvolta: Territorio/Proclamatore/Campagna/Assegnazione/Setting...)
- `description` (testo leggibile)
- `properties` (JSON) con dettagli evento:
  - **prima/dopo** per update (diff campi)
  - motivazioni/flag (es. `counted_in_campaign=true`)
  - valori di soglia usati in calcoli/decisioni (se rilevanti)
- (Consigliato) `ip_address` e `user_agent` (dato personale → retention e minimizzazione)

> Nota GDPR: retention configurabile (es. 365/730 giorni). Evitare di salvare nei log dati sensibili in chiaro non necessari: per Proclamatori salvare `proclamatore_id` e non nome/cognome.

#### 6.7.4 Implementazione consigliata (senza vincoli)
- È possibile implementare il log con tabella custom (`audit_logs`) oppure usare un pacchetto dedicato.
- Scelta spesso adottata in Laravel: **spatie/laravel-activitylog** per logging automatico su modelli + logging manuale per eventi “di flusso” (assegnazione/rientro).

#### 6.7.5 UI pagina Log
Funzioni minime:
- Tabella: Data/Ora, Utente, Ruolo, Azione, Oggetto, Esito, Dettagli.
- Filtri: date, utente, ruolo, tipo evento, entità.
- Dettaglio evento (drawer/modal): diff before/after + metadati.
- Paginazione + ricerca veloce.

---

## 7) Containerizzazione (Docker) — sviluppo e produzione

### 7.1 Struttura consigliata repository
```
termanager2/
  docker/
    nginx/
      default.conf
    php/
      Dockerfile
      php.ini
  .env.example
  docker-compose.yml
  composer.json
  package.json
  ...
```

> In dev si può usare `npm run dev` in un container separato o sul host.

### 7.6 Produzione (note rapide)
- Impostare `APP_ENV=production`, `APP_DEBUG=false`.
- Usare immagini “buildate” senza montare volume codice.
- Gestire segreti con Docker secrets o secret manager.
- Abilitare HTTPS con reverse proxy (Traefik/Nginx) e HSTS.
- Backup cifrati e rotazione.

---

## 8) RBAC: permessi e gating UI

Definire permessi granulari (anche se i ruoli sono solo 3):
- `settings.manage`
- `proclamatori.manage`
- `territori.manage`
- `campagne.manage`
- `registro.view`
- `territori.assign`
- `territori.return`
- `audit.view`
- `audit.export` (opzionale)

Mappatura ruoli:
- Admin: tutti (incluso `audit.view` e opzionale `audit.export`)
- Assistente: proclamatori.manage, campagne.manage, territori.assign, territori.return
- Operatore: territori.assign, territori.return

Applicare:
- Middleware route (`can:` / `role:` / `permission:`)
- Condizionali menu sidebar

## 8-bis) API routes / schermate (URL, metodi, middleware)

> Nota: di seguito sono indicate **route Web** (UI) e (opzionalmente) **route API**. Anche se l’app nasce “web”, formalizzare le route aiuta a:
> - applicare correttamente `auth` + permessi,
> - mantenere coerenza tra schermate e controller,
> - facilitare test e manutenzione.

### 8-bis.1 Convenzioni middleware
- `auth` su tutte le rotte applicative.
- `permission:<permesso>` (o `can:<permesso>`) per schermate/azioni.
- `throttle` (consigliato) su login e su endpoint di export.

### 8-bis.2 Mappa schermate principali
- **Home/Dashboard**: `/` (GET)
- **Wizard iniziale**: `/setup/*` (GET/POST)
- **Territori**: `/territori` (lista), `/territori/create`, `/territori/{id}` (dettaglio), `/territori/{id}/edit`
- **Proclamatori**: `/proclamatori` + CRUD
- **Campagne**: `/campagne` + CRUD + dettaglio
- **Registro**: `/registro` (filtri)
- **Audit log**: `/audit` (lista) + `/audit/{id}` (dettaglio)

### 8-bis.3 Route Web (UI) — dettaglio

#### Autenticazione
- `GET  /login` → form login | middleware: `guest`
- `POST /login` → login | middleware: `guest`, `throttle:login`
- `POST /logout` → logout | middleware: `auth`

#### Wizard iniziale (primo avvio)
- `GET  /setup` → step 1 | middleware: `setup.required`
- `POST /setup/step-1` → salva congregazione | middleware: `setup.required`
- `POST /setup/step-2` → salva soglie | middleware: `setup.required`
- `POST /setup/finish` → completa setup | middleware: `setup.required`

> `setup.required` è un middleware custom che intercetta l’assenza di settings e forza il wizard.

#### Home
- `GET /` → dashboard | middleware: `auth`

#### Territori
- `GET  /territori` → lista | middleware: `auth`, `permission:territori.manage`
- `GET  /territori/create` → form create | middleware: `auth`, `permission:territori.manage`
- `POST /territori` → store | middleware: `auth`, `permission:territori.manage`
- `GET  /territori/{territorio}` → dettaglio | middleware: `auth`, `permission:territori.manage`
- `GET  /territori/{territorio}/edit` → form edit | middleware: `auth`, `permission:territori.manage`
- `PUT  /territori/{territorio}` → update | middleware: `auth`, `permission:territori.manage`
- `DELETE /territori/{territorio}` → delete (cascade assegnazioni) | middleware: `auth`, `permission:territori.manage`
- `PATCH /territori/{territorio}/toggle-active` → attiva/disattiva | middleware: `auth`, `permission:territori.manage`
- `PATCH /territori/{territorio}/toggle-priority` → prioritario sì/no | middleware: `auth`, `permission:territori.manage`
- `POST  /territori/{territorio}/pdf` → upload/sostituzione PDF | middleware: `auth`, `permission:territori.manage`
- `DELETE /territori/{territorio}/pdf` → rimuovi PDF | middleware: `auth`, `permission:territori.manage`

#### Proclamatori
- `GET  /proclamatori` → lista | middleware: `auth`, `permission:proclamatori.manage`
- `GET  /proclamatori/create` → form create | middleware: `auth`, `permission:proclamatori.manage`
- `POST /proclamatori` → store | middleware: `auth`, `permission:proclamatori.manage`
- `GET  /proclamatori/{proclamatore}` → dettaglio | middleware: `auth`, `permission:proclamatori.manage`
- `GET  /proclamatori/{proclamatore}/edit` → form edit | middleware: `auth`, `permission:proclamatori.manage`
- `PUT  /proclamatori/{proclamatore}` → update | middleware: `auth`, `permission:proclamatori.manage`
- `DELETE /proclamatori/{proclamatore}` → delete/anonimizza (policy) | middleware: `auth`, `permission:proclamatori.manage`
- `PATCH /proclamatori/{proclamatore}/toggle-active` → attiva/disattiva | middleware: `auth`, `permission:proclamatori.manage`

#### Campagne
- `GET  /campagne` → lista + campagna attiva | middleware: `auth`, `permission:campagne.manage`
- `GET  /campagne/create` → form create | middleware: `auth`, `permission:campagne.manage`
- `POST /campagne` → store | middleware: `auth`, `permission:campagne.manage`
- `GET  /campagne/{campagna}` → dettaglio + tempi real-time | middleware: `auth`, `permission:campagne.manage`
- `GET  /campagne/{campagna}/edit` → form edit | middleware: `auth`, `permission:campagne.manage`
- `PUT  /campagne/{campagna}` → update | middleware: `auth`, `permission:campagne.manage`
- `DELETE /campagne/{campagna}` → delete | middleware: `auth`, `permission:campagne.manage`

#### Assegnazioni (azioni core)
- `POST /assegnazioni/assign` → assegna territorio a proclamatore | middleware: `auth`, `permission:territori.assign`
- `POST /assegnazioni/{assegnazione}/return` → rientro territorio | middleware: `auth`, `permission:territori.return`

> Nota: `assign` e `return` devono sempre scrivere su **audit log**.

#### Registro
- `GET /registro` → lista filtrabile | middleware: `auth`, `permission:registro.view`
- (Opzionale) `GET /registro/export` → export | middleware: `auth`, `permission:registro.export`

#### Audit log
- `GET /audit` → lista log | middleware: `auth`, `permission:audit.view`
- `GET /audit/{log}` → dettaglio log | middleware: `auth`, `permission:audit.view`
- (Opzionale) `GET /audit/export` → export | middleware: `auth`, `permission:audit.export`

### 8-bis.4 Route API (opzionali, se si usa UI “dinamica”)
> Se si adotta Livewire spesso bastano le Web route. Se si usa SPA (Inertia/Vue/React) o si vuole un frontend più interattivo, prevedere API JSON:
- `GET /api/territori?filters=...` | `auth:sanctum`, `permission:territori.manage`
- `GET /api/home/quicklists` | `auth:sanctum`
- `POST /api/assegnazioni/assign` | `auth:sanctum`, `permission:territori.assign`
- `POST /api/assegnazioni/{id}/return` | `auth:sanctum`, `permission:territori.return`
- `GET /api/campagne/{id}/realtime` | `auth:sanctum`, `permission:campagne.manage`

---

## 9) Checklist di funzionalità (con sottotask e ricontrollo)

> Regola di lavoro: **ogni funzionalità va spezzata in sottotask**, ognuno con test + verifica UI. A completamento, ricontrollare l’intera funzionalità end-to-end.

### EPIC A — Setup progetto e base security
**Sottotask**
1. Creazione progetto Laravel + repo + CI base (lint/test).
2. Setup Auth (login/logout) + password policy.
3. Setup RBAC (ruoli/permessi) + seed iniziale admin.
4. Setup cifratura colonne proclamatori + test round-trip.
5. Logging audit (azioni critiche) + retention log.

**Ricontrollo (DoD)**
- Login funziona, utenti e ruoli corretti.
- Dati proclamatori illeggibili in DB (verifica diretta tabella).
- Rotte protette da permessi.

### EPIC B — Wizard iniziale + Settings
**Sottotask**
1. Model/settings + migrazione.
2. Wizard UI 3 step + validazione.
3. Blocco app finché wizard non completato (redirect).

**Ricontrollo**
- Primo avvio porta al wizard.
- Home mostra logo/nome congregazione.

### EPIC C — Gestione Territori
**Sottotask**
1. Tabelle territori/zone/tipologie + seed.
2. CRUD territori + upload PDF.
3. Lista filtrabile + badge di stato.
4. Dettaglio con PDF viewer + storico per anno teocratico.
5. Attiva/disattiva + prioritario.
6. Delete con cascade su assegnazioni.

**Ricontrollo**
- Stati corretti e coerenti.
- PDF visibile e scaricabile.
- Eliminazione rimuove storico come richiesto.

### EPIC D — Gestione Proclamatori
**Sottotask**
1. CRUD proclamatori (encrypted fields).
2. Lista con filtro + indicazione territori assegnati.
3. Disattivazione / (opzionale) anonimizzazione.

**Ricontrollo**
- Dati illeggibili in DB.
- Non assegnabile se attivo=false.

### EPIC E — Assegnazione e rientro (core)
**Sottotask**
1. Flusso assegnazione: selezione territorio + proclamatore + conferma.
2. Prevenire doppia assegnazione (vincolo logico).
3. Flusso rientro: chiusura assegnazione + calcolo giorni.
4. Prompt campagna (retroattivo) al rientro.
5. Audit: created_by/returned_by.

**Ricontrollo**
- Un territorio non può avere due assegnazioni aperte.
- Prompt campagna compare quando dovuto.

### EPIC F — Home Dashboard
**Sottotask**
1. Calcolo anno teocratico corrente + autocreazione.
2. Calcolo media mensile percorrenza.
3. Liste rapide (da assegnare/prioritari/da rientrare) con filtri e “vedi tutti”.
4. UI responsive.

**Ricontrollo**
- Numeri coerenti con registro.
- Liste mostrano gli stessi risultati delle pagine complete.

### EPIC G — Campagne
**Sottotask**
1. CRUD campagne.
2. Indicazione campagna attiva.
3. Percentuale e dettaglio “in tempo reale”.
4. Lista campagne completate.

**Ricontrollo**
- Retroattività corretta.
- Dettaglio mostra tempi e territori.

### EPIC H — Registro e statistiche
**Sottotask**
1. Vista registro per territorio con filtri richiesti.
2. Export (opzionale).
3. Test prestazioni su query con indici.

**Ricontrollo**
- Filtri corretti.
- Dati coerenti con assegnazioni.

### EPIC I — Audit Log (pagina log e tracciamento eventi)
**Sottotask**
1. Definizione eventi da loggare (CRUD + flussi assegnazione/rientro + login/logout opzionale).
2. Implementazione persistenza log (tabella custom o activity log) + migrazioni.
3. Hook automatici su modelli (created/updated/deleted) e log manuali per `assign/return`.
4. Pagina `/audit` con filtri, paginazione, dettaglio evento (before/after).
5. RBAC: `audit.view` e (opzionale) `audit.export`.
6. Retention configurabile + job scheduler (opzionale) per pulizia log.

**Ricontrollo**
- Ogni operazione critica genera un record log.
- Il log non espone dati sensibili non necessari (es. nomi proclamatori in chiaro nei properties).
- Filtri e dettaglio mostrano correttamente chi/cosa/quando e diff.

---

## 10) Test consigliati
- **Unit test**: calcolo anno teocratico, stati territorio, logica campagne.
- **Feature test**: RBAC per pagina, assegnazione/rientro, wizard.
- **Security test**: accesso non autorizzato, CSRF, rate limit login.
- **UX test**: mobile viewport, tabelle filtrabili, azioni rapide.
- **Audit test**: ogni create/update/delete e assign/return produce log con subject/causer corretti.

---

## 11) “Done” globale (criteri di completamento)
- Tutte le funzionalità richieste presenti e testate.
- Responsività verificata su smartphone/tablet.
- Dati proclamatori cifrati e illeggibili in DB.
- Log operazioni critiche + policy di retention.
- Backup e gestione segreti definiti (per produzione).

---

### Allegato — Note di chiarezza (minime)
- La formula di “media mensile” e la definizione di denominatore percentuale campagna vanno **documentate** e rese consistenti con i test.
- La cancellazione territorio con cascade è conforme al requisito, ma valutare impatto GDPR/contabile: in alternativa soft-delete + “nascondi dallo storico”.
