Dominio fin — Panoramica sviluppatore
🎯 Cosa fa
Il dominio fin (funded projects) gestisce i progetti formativi
finanziati da FondItalia: ciclo di vita del progetto, fasi,
moduli, edizioni, aziende partecipanti, rendicontazione.
Dominio grande: 48 tabelle. Questa pagina copre il core F2 (7 tabelle): progetti, fasi, moduli, edizioni, aziende, adesioni. Le aree restanti (spese, staff, documenti, integrazioni, anagrafiche di supporto) saranno documentate in spec successive.
Le iscrizioni dei lavoratori alle edizioni FondItalia vivono in
edu.workerTrainingDetails (con trainingSessionId = fin.editions.id
via shared PK). Le presenze sono tracciate dalle colonne
attendanceHours, attendanceRate e passed della stessa tabella.
La tabella fin.enrollments è stata rimossa.
🗺️ Mappa moduli
Database — TrainingHub.Database/fin/
Core in questa documentazione (7):
| Area | Tabella | Ruolo |
|---|---|---|
| Progetti | fin.projects | Progetto formativo finanziato |
| Progetti | fin.phases | Anagrafica fasi (ordinate, con managedType) |
| Progetti | fin.projectPhases | Istanza fase per progetto (stato + completionRate) |
| Struttura | fin.modules | Moduli formativi del progetto |
| Struttura | fin.editions | Edizioni del modulo (replicazioni) |
| Partecipazione | fin.projectCompanies | N:N progetto ↔ azienda + regime aiuto |
| Partecipazione | fin.companyMemberships | Adesione azienda al fondo |
Estensioni coperte lato utente (dettaglio dev pianificato come lavoro futuro):
| Area | Tabelle | Pagina utente |
|---|---|---|
| Documenti & compliance | companyDocuments, projectDocuments, workerDocuments, staffDocuments, documentTypes | Documenti di progetto |
| Fondi & bandi | accounts, budgets, cofinancing, contributions, calls, callWindows, callDocuments, callAmendments, callAmendmentWindows, callAmendmentDocuments | Fondi, bandi e budget |
| Spese | expenses, expenseCategories, expenseChapters, expenseDocuments | Spese e rendicontazione, Foglio di rendicontazione |
| Staff & sessioni | staff (FK nullable userId → kset.users per riuso identità / email / ruoli), staffRoles (lookup ruolo con colore), projectStaff, sessions, attendanceRegisters, phaseRequirements, projectHistory | Staff e sessioni |
| Calendario ore | calendarEntries, calendarBlocks | Calendario ore staff |
| Variazioni | projectVariations, variationDocuments, variationEnrollments, variationTypeDocuments | Variazioni |
| Anagrafiche & integrazioni | teachingMethods, thematicAreas, integrationRequests, implementingBodies (Ente Attuatore, FK NOT NULL sul progetto) | Anagrafiche e integrazioni |
| Adesioni | companyMemberships, companyMembershipStatusHistory, membershipDocuments, accountDocuments, femidataSummaries | Adesioni FondItalia |
| Requisiti di fase | phaseRequirements, projectPhaseRequirementChecks | Fasi e requisiti |
Schema DB dettagliato di queste estensioni non incluso in Schema DB (focus sulle 7 core).
Documentazione pregressa
Ricco materiale disponibile in:
docs/fonditalia-client-overview.md— panoramica cliente-friendly delle fasi (call 03/04/2026).docs/fonditalia-technical-overview.md— overview tecnica.docs/fonditalia_context_for_claude_code.md— contesto storico.docs/superpowers/specs/_archive/2026-04-02-fonditalia-integration-design.mde2026-04-03-fonditalia-v2-design.md— spec iniziali.
UI CRUD — TrainingHub.BackOffice/Components/CRUD/fin/
45 pagine CRUD auto-generate (e 58 file di conf, perché alcune entità
hanno più viste). Pattern identico a inv/reg/edu/job
(vedi componenti UI inv).
Le 7 entità core:
Project,Phase,ProjectPhaseModule,EditionProjectCompany,CompanyMembership
🔧 Enum e stati
Dal file TrainingHub.Shared/Enums.cs:
public enum AccountType { rete, monoaziendale }
public enum PhaseManagedType { active, tracking, tracking_readonly }
public enum PhaseRequirementType { document, data_field, action }
// 21 stati, gli stessi vincolati da CK_projects_status
public enum ProjectStatus { BOZZA, IN_COMPOSIZIONE, PRESENTATO,
IN_CONDIVISIONE, CONDIVISIONE_OK, CONDIVISIONE_NEGATA,
INVIO_ALLEGATI_AZIENDE, IN_APPROVAZIONE, APPROVATO,
APPROVATO_CON_MODIFICHE, RIGETTATO, IN_PREPARAZIONE,
IN_EROGAZIONE, EROGAZIONE_COMPLETATA, IN_RENDICONTAZIONE,
RENDICONTAZIONE_INVIATA, CHIUSO, IN_INTEGRAZIONI, SALDO,
REVOCATO, RINUNCIATO }
public enum AidRegime { de_minimis, aiuti_formazione }
public enum ProjectPhaseStatus { not_started, in_progress, completed, skipped }
public enum MembershipStatus { active, suspended, ceased, ceased_provisional,
revoked, not_adhering, failed, not_processable }
public enum DocumentSubject { azienda, progetto, docente, modulo, sessione,
corsista, spesa, variazione }
public enum VariationType { rimodulazione, sostituzione_iscritto,
ritiro_iscritto, calendario, altro }
public enum VariationStatus { IN_ATTESA, APPROVATA }
public enum ExpenseDocumentRole { costo, pagamento }
DocumentStatus è stato rimosso (sotto-progetto D, 2026-07): companyDocuments/projectDocuments/workerDocuments
sono bridge Pattern-A puri (documentId NOT NULL, niente status/documentTypeId/notes) — il tipo del file si
legge dal categorySlug di oss.documents, non da una colonna sul bridge.
🧩 Pattern chiave
Ciclo a fasi
Il progetto segue una sequenza di fasi regolamentate. Ogni fase ha:
- Un managedType:
active(gestita nel sistema),tracking(solo stato),tracking_readonly(esterna, no dati). - Requisiti (
phaseRequirementsfuori scope): documenti, campi dati, azioni richieste per chiudere la fase. - Un flag hideable che permette di saltarla.
Lo stato del progetto (projects.status) è sincronizzato con la
fase attiva, ma con più granularità: 21 stati su 8 fasi.
Il motore è fatto di quattro pezzi, ciascuno con una sola responsabilità:
| Pezzo | Responsabilità |
|---|---|
Services/FundedTraining/ProjectStatusPhaseMap.cs | mappa stato → fase: dato uno stato, quale fase risulta attiva |
Services/FundedTraining/ProjectStatusTransitions.cs | quali transizioni di stato sono ammesse da ciascuno stato. Porta due FIXME validate-fonditalia (righe 13 e 19), ipotesi da confermare col process owner |
Services/FundedTraining/ProjectLifecycleService.cs | orchestrazione: applica la transizione, riallinea le fasi, scrive lo storico. La prima fase si sceglie per sortOrder minimo, quindi è dinamica: togliere una fase dal seed basta |
Services/FundedTraining/PhaseRequirementEvaluators.cs | i valutatori automatici dei requisiti di fase |
I valutatori registrati sono cinque, indirizzati per evaluatorKey:
project.allAppointmentsHaveDates, project.hasWorkersEnrolled, project.hasCompanies,
project.chaptersWithinLimits, project.noPendingVariations. Un requisito senza evaluatorKey non è
valutabile automaticamente: si spunta a mano, e la spunta vive in fin.projectPhaseRequirementChecks.
Le fasi non si avanzano direttamente: si cambia lo stato del progetto e le fasi seguono. Non esiste un comando «completa fase».
Avvisi, sportelli, rettifiche
Il modello dei bandi ha tre livelli, non uno (non esiste più alcun fin.notices):
fin.calls— l'avviso pubblicato dal fondo: il contenitore.fin.callWindows— lo sportello, cioè la finestra di presentazione con i propri termini. Il progetto sta su uno sportello, non su un avviso: è lo sportello a fissare le scadenze.fin.callAmendments— la rettifica che il fondo pubblica su un avviso già uscito, confin.callAmendmentWindowsper gli sportelli che tocca.
Il punto delicato è il congelamento dei termini: callAmendmentWindows conserva sia i nuovi termini sia
quelli precedenti, così una rettifica resta ricostruibile a posteriori invece di sovrascrivere la storia.
La logica sta in Services/FundedTraining/CallAmendmentService.cs:30-55, con
Services/QueryModifiers/fin/CallAmendmentWindowsQueryModifier.cs a presidiare le scritture.
Avvisi, sportelli e rettifiche hanno ciascuno il proprio bridge documenti (callDocuments,
callAmendmentDocuments).
Variazioni in itinere
Una variazione (fin.projectVariations) è la richiesta che l'Ente Attuatore inoltra al fondo durante il
progetto: rimodulazione ore, cambio calendario, sostituzione o ritiro di iscritti. È un fascicolo, non un
campo: tipo, descrizione, documenti a supporto ed esito del fondo.
fin.variationEnrollmentsregistra i nominativi coperti: l'iscrizione uscente e, se è una sostituzione, quella entrante.fin.variationTypeDocumentsmappa quali tipi documento ciascun tipo di variazione si aspetta — è seedato, non si compila caso per caso.- La logica sta in
Services/FundedTraining/ProjectVariationService.cs:128-210.
Il legame col ciclo di vita passa dall'evaluator project.noPendingVariations: una variazione ancora aperta
tiene indietro la fase.
Multi-progetto per azienda
Un'azienda può partecipare a più progetti contemporaneamente via
projectCompanies. La disponibilità sul conto
(companyMemberships.availableBalance) è condivisa: il sistema
dovrebbe scalarla con l'avvio di nuovi progetti, ma la logica non è
chiara.
Integrazione esterna FemiWeb
Presentazione, rendicontazione e comunicazioni con FondItalia passano
da FemiWeb (piattaforma esterna). Il sistema esporta/importa
dati con FemiWeb — la tabella integrationRequests (fuori scope)
traccia queste comunicazioni.
📦 Dipendenze
Brighela.SimpleCRUD— CRUD base- UI stack standard (DevExpress, Tabiot)
- Cross-dominio:
fin.projectCompanies.companyId→reg.companies(id)fin.companyMemberships.companyId→reg.companies(id)edu.workerTrainingDetails.trainingSessionId→fin.editions(id)(iscrizioni lavoratori)
📁 File chiave
Database/fin/Tables/*.sql(~29)BackOffice/Components/CRUD/fin/*.razor(~29)Shared/Enums.cs— enum progetto, fase, regime, statodocs/fonditalia-*.md— documentazione storica
⚠️ Domande aperte / debito tecnico
-
SincronizzazioneAggiorna lo stato:projects.status↔projectPhases.status.ProjectStatusPhaseMapdice quale fase corrisponde a ogni stato, eProjectLifecycleServicefa avanzare le fasi di conseguenza. Non esiste il percorso inverso — non si completa una fase per far cambiare stato al progetto. -
Transizioni stato progetto: macchina a stati formale o ad hoc?Formale e centralizzata:Services/FundedTraining/ProjectStatusTransitions.csdichiaraAllowedcome dizionario stato → stati raggiungibili, conIsAllowed(from, to). Restano dueFIXME validate-fonditaliada confermare col process owner. - Validazione saldo disponibile. Un progetto che supera la disponibilità dell'azienda non è bloccato automaticamente.
-
fin.editionsvsedu.trainingSessions. Risolto: le edizioni FondItalia condividono la PK conedu.trainingSessionsvia pattern di ereditarietà; le iscrizioni lavoratori vivono inedu.workerTrainingDetails. - Integrazione FemiWeb. Gestita via
integrationRequestsma non esiste documentazione di protocollo/payload. -
InphaseRequirements: dov'è la validazione "fase completabile solo se requisiti OK"?Services/FundedTraining/PhaseRequirementsService.cs, che risolve i requisitidata_fieldtramite il registryPhaseRequirementEvaluators.cs(chiaviproject.*). I requisiti conhardBlock = 1sono gli unici che fermano l'avanzamento; gli altri compaiono come cose da confermare. Un test di drift (PhaseRequirementEvaluatorsTests) verifica che ognievaluatorKeyseedato sia registrato.
🔁 Workflow di promozione edu → fin
Un corso/sessione/appuntamento di edu può essere "promosso" alla controparte FondItalia in fin (shared PK):
Origine edu | Target fin | Tab UI | Servizio |
|---|---|---|---|
courses | modules | "Progetto FondItalia" sulla pagina Course | IFundedTrainingService.PromoteCourseToModuleAsync |
trainingSessions | editions | "Edizione FondItalia" sulla pagina TrainingSession | PromoteSessionToEditionAsync |
appointments | sessions | "Sessione FondItalia" sulla pagina Appointment | PromoteAppointmentToFinSessionAsync |
| (n/a — workflow inverso) | aggancio bulk | "Aggancia corso esistente" sulla pagina Project | usa PromoteCourseToModuleAsync per ogni course selezionato |
Stati progetto ammessi alla promozione (hard-coded in FundedTrainingService.PromotableStatuses): BOZZA, IN_COMPOSIZIONE, IN_PREPARAZIONE. Gli stati post-presentazione (PRESENTATO in avanti, elencati in NonPromotableStatuses) richiederebbero una richiesta formale di modifica al fondo, quindi sono esclusi.
Vincoli a catena: per promuovere un appointment a fin.sessions la session parent deve essere già promossa a fin.editions. Analogamente, per promuovere una session a fin.editions almeno uno dei suoi corsi deve essere già promosso a fin.modules. I tab UI mostrano un messaggio informativo se il prerequisito manca, invece di abilitare il bottone.
Iscrizione worker in regime finanziato: il vincolo non è più su
IFundedTrainingService, che non espone più EnrollWorkerInEditionAsync.
Vive lato dati, in
Services/QueryModifiers/edu/WorkerTrainingDetailsQueryModifier.cs:96-97:
l'azienda del lavoratore deve comparire fra quelle restituite da
IFundedEligibilityService.GetEligibleCompanyIdsForSessionAsync, cioè
essere nel progetto e con adesione attiva sul conto FondItalia.
Altrimenti il modifier lancia
BusinessRuleException("fin_worker_company_not_eligible"). La
fundedness si deriva via shared PK, niente flag denormalizzato.
Authorization: i tab riusano policy esistenti — page-fin-modules_R per visualizzare il tab Course→Module, page-fin-modules_C per la promozione effettiva (e analoghi per editions/sessions). Niente policy custom.
🔗 Vedi anche
- Schema DB
- Aggiungere un campo
- Guida utente: Panoramica formazione finanziata (docs-site-user)
- Dominio
reg: panoramica (aziende partecipanti) - Dominio
job: panoramica (lavoratori iscritti) - Dominio
edu: panoramica (formazione ordinaria — relazione da chiarire)