# Piano: Migrazione area /admin da gix-evoaz a gix-supernova

**Data**: 2026-07-08 (ultima verifica end-to-end: 2026-07-09)
**Stato**: **Implementato e verificato end-to-end** (Fasi 0-4, 6-8). Fase 5 (Firma elettronica) in attesa di credenziali DocuSeal dedicate.
**Obiettivo**: Portare in gix-supernova tutte le funzionalità backend (e le relative viste `/admin`) oggi presenti in gix-evoaz, adattando naming, branding e configurazione al nuovo progetto.

---

## 0. Stato di verifica (2026-07-09)

Verifica end-to-end reale contro DB (`gix_supernova_site`) e MinIO (bucket `supernova-admin`), non solo screenshot:

| Flusso testato | Esito |
|---|---|
| Login + JWT + `/auth/me` | ✅ |
| CRUD Contatti, Offerte (+ visibilità su endpoint pubblico) | ✅ |
| CRUD Campagne + KPI (budget_pct calcolato correttamente) | ✅ |
| Creazione candidatura admin **con upload CV reale su MinIO** | ✅ upload, download e cancellazione da MinIO tutti verificati |
| Pipeline candidatura (prequalifica → proposta accettata → assunto con scorecard) | ✅ |
| Onboarding: invio link email, form pubblico, upload documento identità su MinIO, `anagrafica_completata` | ✅ |
| Formazione: corso → modulo → iscrizione (da candidato assunto) → test → invio email → submit pubblico → risultato | ✅ |
| Data retention: tabelle e scheduler attivi, nessun anonimizzato prematuro | ✅ |
| Rate limiting login (10/15min) | ✅ verificato attivo (scattato durante i test intensivi, comportamento corretto) |
| MinIO: bucket, upload, download, delete diretti | ✅ |

**Bug pre-esistente in evoaz, replicato fedelmente (non introdotto da questa migrazione)**: `deleteApplication` in `adminController.js` elimina da MinIO solo il CV (`cv_path`), non i documenti di onboarding (`application_documents` → cartella `documents/{id}/`). Cancellare manualmente una candidatura che ha completato l'onboarding lascia file orfani su MinIO (il ciclo di GDPR retention invece li pulisce correttamente). Presente identico in gix-evoaz — da valutare fix in entrambi i progetti se si vuole correggerlo.

**Bug di porting trovato e corretto**: `AdminView.vue` era stato ricostruito a pezzi invece che copiato integralmente da evoaz, perdendo ~340 righe di CSS (dropdown kebab menu, alcuni stati hover). Corretto il 2026-07-09 ricopiando l'intero blocco `<style>` di evoaz con sola sostituzione colore brand.

---

## 1. Decisioni prese

| Punto | Decisione |
|---|---|
| Firma elettronica (DocuSeal) | **Portare** — account DocuSeal EU dedicato per Supernova |
| Formazione (corsi/test) | **Portare** — schema completo 7 tabelle |
| Governance (231, whistleblowing, ecc.) | **Portare 1:1 per ora** — struttura e contenuti copiati da evoaz; i testi normativi menzionano "Evoluzione Azienda" e le diciture vanno sostituite (Evoluzione Azienda S.r.l.s. -> Super Nova S.r.l., Evoluzione Azienda -> Super Nova, Fulvio Marini diventa Danilo Landolfi. Partita IVA di Super Nova la sai già) (task di contenuto, fuori scope di questo piano tecnico) |
| MinIO | Stesso account (`storage.gixflow.cloud`), **bucket dedicato** `supernova-admin` |
| Schema DB | Identico a evoaz (stessi nomi tabella/colonna) per riuso diretto del codice controller |

---

## 2. Situazione attuale (rilevata da esplorazione diretta + agenti Explore)

### gix-evoaz (sorgente — sistema completo e in produzione)

- **Stack backend**: Node.js ESM + Express 5 + MariaDB (`mysql2`, query raw, niente ORM) — porta 3004, proxato da Apache su `www.evoluzioneazienda.it`.
- **Stack frontend**: Vue 3 + Vue Router, pattern "singleton di modulo" (ref/reactive esportati da composable, niente Pinia).
- **Autenticazione**: JWT (bcrypt + jsonwebtoken) + 2FA TOTP (otplib), onboarding forzato al primo accesso (cambio password + attivazione 2FA obbligatori), invalidazione token via `last_logout_at`.
- **Storage file**: MinIO (bucket privato `evoluzioneazienda-admin`, backend fa da proxy autenticato, mai URL pubblici diretti) — CV, documenti anagrafici, PDF contratti, audit trail.
- **Firma elettronica**: DocuSeal Cloud EU (FEA/eIDAS) — webhook con verifica HMAC, OTP SMS 2FA, template builder embedded (`@docuseal/vue`).
- **Email**: nodemailer, SMTP configurabile da tabella `settings` (con fallback `.env`), più invio alternativo via Google OAuth2/Gmail alias.
- **Moduli completi**: Recruiting (candidature, pipeline, valutazioni, onboarding dipendente, GDPR retention), Campagne marketing (con KPI: CPH, OCT, ROI), Offerte di lavoro, Contatti, Firma elettronica/Contratti, Formazione (corsi/moduli/presenze/test), Governance (pagine normative statiche), Gestione utenti admin, Impostazioni (SMTP, Google OAuth2).
- **Pattern architetturali**: routing centralizzato in un unico `allRoutes.js`; controller come funzioni async esportate (no classi); validazione manuale inline (no Joi/Zod); error handling try/catch locale con log `[EvoAz ...]`; migrazioni DB idempotenti inline in `index.js` (`CREATE TABLE IF NOT EXISTS` + `ALTER TABLE` con cattura `ER_DUP_FIELDNAME`); nessun sistema di ruoli/permessi (tutti gli admin hanno pieno accesso).

### gix-supernova (target — stato attuale)

- **Backend**: scaffold minimale, **solo sito pubblico**. `index.js`, `db.js`, `emailService.js` (base), `routes/publicRoutes.js` con 3 controller pubblici (`contactController`, `applyController`, `offersController`). Cartella `middleware/` vuota. Nessuna tabella oltre a `contacts`, `applications` (versione ridotta), `offers`, `settings` (solo config SMTP base).
  - **Bug/gap noto**: `applyController.js` riceve il CV via multer `memoryStorage` ma il buffer **non viene mai persistito** — va risolto contestualmente all'integrazione MinIO (Fase 3).
- **Frontend**: sorprendentemente **quasi tutti i composable admin sono già presenti**, "trapiantati" da gix-evoaz e in parte già ribrandizzati (`supernova_admin_jwt` in `useAuth.js`), ma **altri contengono ancora riferimenti a EvoAz non ripuliti** (es. `useSettings.js` default `from_name: 'Evoluzione Azienda'`, log `[EvoAz]` in `useApplications.js`). Presenti: `useAuth.js`, `useApi.js`, `useApplications.js`, `useCampaigns.js`, `useContacts.js`, `useContracts.js`, `useOffers.js`, `useOverview.js`, `useRetention.js`, `useSettings.js`, `useTemplates.js`, `useTraining.js`, `useAdminNav.js`, `useToast.js`.
  - **Mancano completamente**: `AdminView.vue`, tutta la cartella `views/admin/**` (sidebar + pannelli), la voce `/admin` nel router (`router/index.js`).
  - `App.vue` ha già i computed `isAdmin`/`isOnboarding`/`isTest`/`isLanding` cablati a `false`, pronti per essere agganciati a `route.path.startsWith('/admin')` — segno che il porting era già previsto.
  - Le pagine Governance già esistenti (`Modello231View.vue`, `CodiceEticoView.vue`, `WhistleblowingView.vue`, ecc.) e i relativi `.md` in `documenti-interni/` sono **copie testuali di EvoAz** — contengono già il nome "Evoluzione Azienda" nei contenuti normativi pubblici, non solo nell'area admin. Da segnalare come task di contenuto separato.
- **Deploy**: stessa architettura di evoaz — Apache reverse proxy su `127.0.0.1:3005`, dist statico da `/var/www/html/gix-supernova/dist`. VirtualHost già pronto (`supernova-group.it-le-ssl.conf`), manca solo avviare il backend esteso con PM2.
- **`.env` attuale**: solo `PORT`, `DB_*`, `SMTP_HOST/PORT/USER/PASS`. Mancano `JWT_SECRET`, `ADMIN_DEFAULT_EMAIL/PASS`, `DOCUSEAL_*`, `MINIO_*`.
- **Dipendenze backend mancanti**: `bcrypt`, `jsonwebtoken`, `otplib`, `minio`, `jszip`, `pdf-lib`. (Express 5, `mysql2`, `nodemailer`, `multer`, `cors`, `express-rate-limit` già presenti, versioni allineate a evoaz.)

**Conclusione**: il frontend "contratto API" è già scritto nei composable (path, verbi, payload attesi) — è una specifica di fatto per il porting. Il lavoro reale è quasi interamente **backend** (schema DB + controller + route + middleware + servizi) più le **viste Vue mancanti** (shell admin + pannelli).

---

## 3. Inventario funzionalità da portare

### 3.1 Infrastruttura di base (blocca tutto il resto)

- Middleware `authMiddleware` + `onboardingMiddleware` (JWT, `middleware/auth.js`)
- Middleware upload (`middleware/upload.js`) — memoryStorage, filtri MIME, limiti differenziati (CV 5MB, documenti 10MB, PDF contratti 20MB)
- Servizio MinIO (`services/minioClient.js`) — bucket `supernova-admin`
- Servizio email esteso (`emailService.js` con SMTP da DB + template separati in `emails/`)
- Tabella `users` (email, password_hash, totp_secret/enabled, must_change_password, force_2fa_required, first_name, last_name, last_login, last_logout_at)
- Tabella `settings` (key/value — già esiste in forma ridotta, da estendere)
- Login JWT + 2FA TOTP (`authController.js`)
- Onboarding utente forzato (cambio password + 2FA obbligatoria al primo accesso, welcome email con password temporanea)
- Gestione utenti admin (`usersController.js` — CRUD, reset 2FA, reinvio welcome)

### 3.2 Moduli funzionali (ordine di priorità/dipendenza)

1. **Contatti** — form pubblico + lista/elimina in admin
2. **Offerte di lavoro** — pubbliche + CRUD admin (estendere `offersController.js` esistente)
3. **Candidature / Recruiting** — modulo più corposo: pipeline stati, valutazioni scorecard, anagrafica estesa, onboarding dipendente (token pubblico + upload documenti), data retention GDPR
4. **Campagne marketing** — CRUD + KPI (CPH, OCT, ROI) collegati a offerte/candidature/contatti
5. **Impostazioni** — SMTP via DB, test email, Google OAuth2/Gmail alias, gestione utenti
6. **Firma elettronica (DocuSeal)** — contratti, firmatari, template builder, webhook
7. **Formazione** — corsi, moduli didattici, iscrizioni, presenze, test valutazione con token pubblico
8. **Governance** — pagine statiche normative (231, whistleblowing, privacy, cookie, sicurezza, GDPR, RAEE), portate 1:1 per struttura e contenuto

### 3.3 Schema dati completo da replicare

```
users, settings
contacts
offers
applications, application_evaluations, application_documents, onboarding_tokens
campaigns
contracts, contract_signers, docuseal_webhook_logs, document_templates
training_courses, training_modules, training_enrollments,
training_attendance, training_tests, training_test_tokens,
training_test_results
```

Tutte le migration inline in `index.js` con pattern `CREATE TABLE IF NOT EXISTS` + `ALTER TABLE` con catch su `ER_DUP_FIELDNAME`/`ER_DUP_KEYNAME` — pattern da riusare identico. La tabella `applications` esistente in Supernova è una versione ridotta: servirà l'intera batteria di `ALTER TABLE` per portarla allo schema esteso di evoaz (pipeline, anagrafica, GDPR, campaign_id, ecc.).

Utility da copiare: `utils/comuni_con_cap.json` (dataset comuni italiani + CAP, usato per autocompletamento indirizzi in anagrafica candidato).

---

## 4. Struttura file backend da creare in gix-supernova

```
backend/src/
├── index.js                          MODIFICA — CORS con tutti i metodi (PUT/PATCH/DELETE),
│                                      header Authorization, rate limit login, bootstrap migrazioni,
│                                      header X-Robots-Tag su /admin e /api/admin
├── middleware/
│   ├── auth.js                        NUOVO — authMiddleware + onboardingMiddleware
│   └── upload.js                      NUOVO — multer memoryStorage (CV, documenti, PDF contratti)
├── services/
│   ├── minioClient.js                 NUOVO — bucket supernova-admin
│   ├── emailService.js                MODIFICA — estendere con SMTP-da-DB + funzioni invio
│   ├── dataRetentionService.js        NUOVO
│   └── docuseal.service.js            NUOVO
├── emails/
│   └── welcomeTemplate.js             NUOVO
├── utils/
│   └── comuni_con_cap.json             NUOVO — copiato da evoaz
├── controllers/
│   ├── adminController.js             NUOVO — settings, contatti admin, candidature admin,
│   │                                   CV serving, comuni, OAuth2 Google/Gmail
│   ├── authController.js              NUOVO — login/2FA/onboarding
│   ├── usersController.js             NUOVO — gestione utenti admin
│   ├── campaignController.js          NUOVO
│   ├── onboardingController.js        NUOVO — onboarding dipendente pubblico
│   ├── offersController.js            MODIFICA — aggiungere CRUD admin (oggi solo getActiveOffers)
│   ├── contactController.js           INVARIATO probabile
│   ├── applyController.js             MODIFICA — integrare MinIO per CV (fix bug: buffer scartato)
│   ├── contractsController.js         NUOVO
│   ├── templateController.js          NUOVO
│   └── trainingController.js          NUOVO
└── routes/
    └── allRoutes.js                   NUOVO — sostituisce publicRoutes.js, tutte le rotte
                                        auth/admin/webhook + quelle pubbliche esistenti
```

---

## 5. API routes da esporre (mutuate 1:1 da gix-evoaz/allRoutes.js)

```
# Pubbliche
GET    /api/health
POST   /api/contact
POST   /api/apply
GET    /api/offers
GET    /api/comuni
GET    /api/onboarding/:token
POST   /api/onboarding/:token/submit
GET    /api/training/test/:token
POST   /api/training/test/:token/submit
POST   /api/webhooks/docuseal                 (rawBody per HMAC — deve precedere express.json())
GET    /api/o2callback

# Auth
POST   /api/auth/login                         (rate-limited)
POST   /api/auth/verify-2fa                    (rate-limited)
GET    /api/auth/me                            [auth]
POST   /api/auth/logout                        [auth]
POST   /api/auth/setup-2fa                     [auth]
POST   /api/auth/confirm-2fa                   [auth]
POST   /api/auth/disable-2fa                   [auth]
POST   /api/auth/change-password               [auth]
POST   /api/auth/complete-onboarding-pwd       [onboarding]
POST   /api/auth/onboarding/setup-2fa          [onboarding]
POST   /api/auth/onboarding/confirm-2fa        [onboarding]

# Admin — core
GET/PUT    /api/admin/settings(/:key)                                    [auth]
GET/DELETE /api/admin/contacts(/:id)                                     [auth]
GET/POST/PATCH/PUT/DELETE /api/admin/applications...                     [auth]
GET        /api/admin/applications/:id/cv                                [auth]
GET/POST   /api/admin/applications/:id/send-onboarding, onboarding-status,
           documents(/:docId)                                            [auth]
GET/POST/PUT/PATCH/DELETE /api/admin/offers...                           [auth]
GET/POST/PUT/DELETE /api/admin/campaigns...                              [auth]
POST       /api/admin/email/test                                         [auth]
GET/DELETE /api/admin/google-oauth2/...                                  [auth]

# Admin — utenti
GET/POST/PUT/DELETE /api/admin/users...        [auth]
POST /api/admin/users/:id/reset-2fa            [auth]
POST /api/admin/users/:id/send-welcome         [auth]

# Data retention (GDPR)
GET/PUT /api/admin/retention/status            [auth]
GET     /api/admin/retention/expiring          [auth]
POST    /api/admin/retention/run               [auth]

# Firma elettronica
GET/POST/DELETE /api/admin/contracts...        [auth]
POST    /api/admin/contracts/:id/send          [auth]
POST    /api/admin/contracts/:id/cancel        [auth]
GET     /api/admin/contracts/:id/download      [auth]
GET/POST/PUT/DELETE /api/admin/templates...    [auth]
GET     /api/admin/templates/:id/fields        [auth]
GET     /api/admin/templates/:id/builder-token [auth]

# Formazione
GET/POST/PUT/DELETE /api/admin/training/courses...                       [auth]
GET/POST/PUT/DELETE /api/admin/training/courses/:courseId/modules...     [auth]
GET/POST/DELETE /api/admin/training/eligible, enrollments...              [auth]
GET/PUT /api/admin/training/modules/:moduleId/attendance, attendance-grid [auth]
GET/POST/PUT/DELETE /api/admin/training/tests...                          [auth]
POST    /api/admin/training/tests/:id/send                               [auth]
GET     /api/admin/training/tests/:id/results                            [auth]
DELETE  /api/admin/training/results/:id                                  [auth]
```

---

## 6. Struttura frontend da creare in gix-supernova

```
frontend/src/
├── router/index.js                   MODIFICA — aggiungere:
│                                       { path: '/admin', component: AdminView }
│                                       { path: '/test/:token', component: TestView }  (formazione)
├── views/
│   ├── AdminView.vue                  NUOVO — shell login + layout admin (porta App.vue isAdmin=true)
│   ├── TestView.vue                   NUOVO — test formazione pubblico via token
│   └── admin/
│       └── components/
│           ├── AdminSidebar.vue        NUOVO — consuma useAdminNav.js già presente
│           ├── AdminLoginPanel.vue     NUOVO — step credentials/2fa/onboarding
│           ├── AdminOverviewPanel.vue  NUOVO — dashboard/riepilogo
│           ├── AdminContactsPanel.vue  NUOVO
│           ├── AdminApplicationsPanel.vue  NUOVO — pipeline, anagrafica, onboarding, CV/documenti
│           ├── AdminOffersPanel.vue    NUOVO
│           ├── AdminCampaignsPanel.vue NUOVO
│           ├── AdminSettingsPanel.vue  NUOVO — SMTP, utenti, Google OAuth, 2FA personale
│           ├── AdminRetentionPanel.vue NUOVO
│           ├── AdminContractsPanel.vue NUOVO — "Firma elettronica" / Firme
│           ├── AdminTemplatesPanel.vue NUOVO — "Modelli" + DocusealBuilder embedded
│           ├── AdminTrainingPanel.vue  NUOVO — Corsi/Classe/Slide/Test/Risultati
│           └── AdminGovernancePanel.vue NUOVO — render markdown documenti-interni (già presenti)
└── composables/
    └── useAdminNav.js                  MODIFICA — già presente, ripulire riferimenti EvoAz residui
```

I composable dati (`useAuth`, `useApplications`, `useCampaigns`, `useContracts`, `useTemplates`, `useTraining`, `useRetention`, `useSettings`, `useOffers`, `useContacts`, `useOverview`) **sono già presenti** — vanno rivisti endpoint per endpoint contro il backend nuovo, ripulendo i residui di branding EvoAz (es. `from_name` default in `useSettings.js`, prefissi di log `[EvoAz]`), non riscritti da zero.

**Dipendenza frontend da aggiungere**: `npm install @docuseal/vue` (per `AdminTemplatesPanel.vue`).

---

## 7. Fasi di implementazione

### Fase 0 — Setup ambiente
- [ ] `.env`: aggiungere `JWT_SECRET`, `ADMIN_DEFAULT_EMAIL`/`ADMIN_DEFAULT_PASS`, `MINIO_*` (bucket `supernova-admin`), `DOCUSEAL_*` (nuovo account EU dedicato Supernova)
- [ ] Creare bucket MinIO `supernova-admin` sullo stesso account/endpoint `storage.gixflow.cloud`
- [ ] Attivare account/progetto DocuSeal EU dedicato a Supernova (o workspace separato nello stesso account, da verificare in base al piano DocuSeal)
- [ ] `npm install bcrypt jsonwebtoken otplib minio jszip pdf-lib` nel backend
- [ ] `npm install @docuseal/vue` nel frontend
- [ ] Copiare `utils/comuni_con_cap.json` da evoaz

### Fase 1 — Infrastruttura auth + utenti (blocca tutto il resto)
- [ ] Tabelle `users`, estensione `settings` + seed admin default
- [ ] `middleware/auth.js`, `authController.js`, `usersController.js`
- [ ] `emailService.js` esteso + `emails/welcomeTemplate.js`
- [ ] Route auth + admin/users in `allRoutes.js` (sostituisce `publicRoutes.js`)
- [ ] Frontend: `AdminView.vue` con step login/2FA/onboarding, `AdminLoginPanel.vue`, route `/admin`, collegare `isAdmin` in `App.vue`
- [ ] Test end-to-end: login, 2FA, onboarding primo accesso, gestione utenti

### Fase 2 — Contatti, Offerte, Impostazioni
- [ ] `adminController` (settings, contacts), CRUD offerte admin (estendere `offersController.js`)
- [ ] `AdminOverviewPanel.vue`, `AdminContactsPanel.vue`, `AdminOffersPanel.vue`, `AdminSettingsPanel.vue`, `AdminSidebar.vue`
- [ ] Google OAuth2/Gmail alias (credenziali OAuth2 dedicate a Supernova, non riusare quelle di evoaz)

### Fase 3 — Recruiting
- [ ] Schema DB: estendere `applications` esistente con tutte le `ALTER TABLE` (pipeline, anagrafica, GDPR, campaign_id) + nuova `application_evaluations`
- [ ] MinIO per CV (`minioClient.js`, `middleware/upload.js` memoryStorage) — **fix contestuale del bug attuale** (buffer CV scartato in `applyController.js`)
- [ ] `adminController` sezione applications, `onboardingController.js` (onboarding_tokens, application_documents)
- [ ] Data retention GDPR: `dataRetentionService.js` + scheduler + routes
- [ ] `AdminApplicationsPanel.vue` (pipeline, anagrafica, valutazioni, onboarding, CV/documenti)

### Fase 4 — Campagne
- [ ] `campaigns` table + `campaignController.js` (con KPI CPH/OCT/ROI)
- [ ] `AdminCampaignsPanel.vue`

### Fase 5 — Firma elettronica (DocuSeal)
- [ ] Variabili `.env` DocuSeal dedicate, webhook endpoint configurato lato DocuSeal per dominio Supernova
- [ ] Schema `contracts`, `contract_signers`, `docuseal_webhook_logs`, `document_templates`
- [ ] `docuseal.service.js`, `contractsController.js`, `templateController.js`
- [ ] Webhook pubblico con verifica HMAC (`express.raw` prima di `express.json`)
- [ ] `AdminContractsPanel.vue`, `AdminTemplatesPanel.vue`, componente `<DocusealBuilder>`

### Fase 6 — Formazione
- [ ] Schema 7 tabelle `training_*`
- [ ] `trainingController.js` completo (corsi, moduli, iscrizioni, presenze, test, risultati)
- [ ] Endpoint pubblico test con token + `TestView.vue`
- [ ] `AdminTrainingPanel.vue` con tutte le sotto-tab (Corsi, Classe/Presenze, Slide, Test, Risultati)

### Fase 7 — Governance
- [ ] Copiare struttura tab Governance nella sidebar admin (`AdminGovernancePanel.vue`)
- [ ] Copiare i file markdown esistenti (già presenti in `documenti-interni/` e `frontend/src/assets/documenti-interni/`) così come sono
- [ ] **Nota**: contenuti menzionano "Evoluzione Azienda" — annotare come follow-up separato la revisione testi per Supernova (non blocca il porting tecnico)

### Fase 8 — Hardening e deploy
- [ ] `ecosystem.config.cjs` PM2 per gix-supernova-backend (già esiste, verificare porta/nome)
- [ ] Rate limiting login, `X-Robots-Tag` su `/admin`, CORS con tutti i metodi necessari (oggi CORS limitato a GET/POST)
- [ ] Verifica end-to-end di ogni modulo in ambiente reale (non solo typecheck) — login, upload CV/documenti, invio contratto firma, iscrizione corso e invio test
- [ ] Verifica reverse proxy Apache (già pronto, solo da confermare dopo deploy backend)
- [ ] **Revisione CSS complessiva dell'area admin** — ripasso finale di stili/branding/coerenza visiva su tutti i pannelli portati (colori, spaziature, responsive) prima di considerare il porting concluso

---

## 8. Rischi e note

| Rischio | Mitigazione |
|---|---|
| Copia diretta del codice porta con sé assunzioni hardcoded su "Evoluzione Azienda" (branding email, nomi mittente, testi) | Ricerca sistematica di stringhe brand-specific durante il porting di ogni controller/template email/composable (es. `useSettings.js` default SMTP, log `[EvoAz]`) |
| Frontend ha endpoint già assunti identici a evoaz — se si cambiano i path nel backend si rompe tutto silenziosamente | Mantenere path API identici a evoaz salvo necessità esplicita |
| MinIO/DocuSeal con credenziali condivise potrebbero mescolare dati tra i due progetti | Bucket dedicato `supernova-admin` (deciso) + account/workspace DocuSeal dedicato (deciso) |
| Migration inline in `index.js` diventano lunghe e fragili (in evoaz sono già 500+ righe) | Valutare modularizzazione per dominio in file separati mantenendo lo stesso pattern idempotente `IF NOT EXISTS` |
| Bug esistente: CV pubblico non salvato in `applyController.js` | Risolvere contestualmente all'integrazione MinIO in Fase 3, non prima (altrimenti si scrive codice da buttare) |
| Contenuti Governance/231 errati (menzionano Evoluzione Azienda) già presenti anche nelle pagine pubbliche attuali di Supernova (`Modello231View.vue` ecc.) | Segnalato esplicitamente: è un problema di contenuto pre-esistente, indipendente da questo piano, ma da correggere quanto prima essendo già in produzione su un sito pubblico |
| CORS attuale di Supernova limita i metodi a GET/POST | Va esteso a PUT/PATCH/DELETE per tutte le rotte admin (Fase 1) |

---

## 9. Stima ordine di grandezza

| Fase | Complessità | Note |
|---|---|---|
| 0 — Setup | Bassa | Config e dipendenze |
| 1 — Auth/utenti | Media | Pattern esistente da replicare, ma blocca tutto |
| 2 — Contatti/Offerte/Settings | Bassa | CRUD semplici |
| 3 — Recruiting | Alta | Modulo più esteso: MinIO, onboarding, GDPR, anagrafica complessa |
| 4 — Campagne | Bassa-Media | CRUD + calcolo KPI |
| 5 — Firma elettronica | Alta | Dipendenza esterna DocuSeal, webhook, sicurezza HMAC, nuovo account da attivare |
| 6 — Formazione | Alta | 7 tabelle, builder domande, flusso pubblico test |
| 7 — Governance | Bassa (tecnica) | Solo porting struttura/file; revisione contenuti è task separato |
| 8 — Hardening/deploy | Media | Verifica end-to-end reale |

**Sequenza consigliata**: 0 → 1 → 2 → 3 → 4 → 5/6 (possono procedere in parallelo, sono indipendenti tra loro) → 7 → 8.

Il valore critico è concentrato nelle Fasi 1 e 3: senza autenticazione nulla è raggiungibile, e Recruiting è il cuore del sistema (candidature, CV, onboarding, da cui dipendono anche Formazione e Firma elettronica per il flusso "candidato assunto → discente/firmatario").

