Architettura
Cosa fa
TrainingHub è una piattaforma .NET 10 / Blazor Server per la gestione della formazione sulla sicurezza sul lavoro. È single-tenant per istanza: si deploya un'istanza per cliente (un database/app pair per cliente), nessuna tabella applicativa ha colonna tenant e view/service non filtrano per tenant.
Componenti principali
TrainingHub.BackOffice— Blazor Server web app (UI principale)TrainingHub.Database— progetto SQL Server (DACPAC deployment)TrainingHub.Import— console app per import massivi da ExcelTrainingHub.Shared— shared project (models/costanti)
Framework 3SD
L'app usa l'ecosistema interno 3SD: Scarnas, Brighela, Oss, Servel, Ploc, Oster, Mulet, DeFa, KSet, Mola, Tabiot.
Pattern ricorrenti
View SQL → CRUD auto-generato (read-only)
Per esporre dati aggregati o derivati senza scrivere componenti UI custom si usa il pattern vista SQL + CRUD generato:
- Creare una vista in
TrainingHub.Database/<schema>/Views/vw_<nome>.sql, esponendo le colonne con i loro identificatori*Id(no*Label: il generator costruisce le FK). - Allineare il database (deploy DACPAC).
- MCP
3sd-generator(generator_runcondefaultsCompiler) produce ilmodel.conf.jsone ildxgrid.conf.jsonpartendo dalla view. - Configurare a mano nel
dxgrid.conf.json:- FK manuali sulle colonne
*Id(la view non ha vincoli FK):FkSchema,FkTableName,FkClassName, eventualeCellLink+CellPolicy. AllowInsert,AllowUpdate,AllowDelete,AllowClone=false.IgnoreFormPopup = true+IgnoreForm = true(evita di generare popup/form per un'entità non scrivibile).
- FK manuali sulle colonne
- Rigenerare: si ottiene un
<Entity>.razorstandard usabile come grid stand-alone o come step nei wizard.
Esempi attuali:
edu.vw_workerTrainingStatus— stato per-formazione di ogni lavoratore.job.vw_workerComplianceSummary— rollup per-lavoratore (stato peggiore + conteggi). Usata come step "Conformità formativa" nel wizard azienda.
Persistenza markup custom in conf.json
Il generator rigenera .razor e .razor.tt.cs ad ogni run: ciò che
viene scritto a mano nel .razor viene perso. I dxgrid.conf.json
offrono diversi hook per persistere markup custom:
| Hook | Posizione resa | Quando usarlo |
|---|---|---|
FormPopup.MarkupBeforeForm / MarkupAfterForm | Prima/dopo <EditForm> nel popup | Wizard, banner contestuali |
FormPopup.MarkupEnd | Dopo </DxPopup> | Popup secondari (anteprima, conferme) |
Columns.{name}.RenderFragmentParameters.CellDisplayTemplate | Cella della grid | Badge stato, link condizionali |
Form.TabPages.Tabs.{tab}.Groups.{group}.Columns.{col}.Template | Sostituisce l'editor del campo nel form | Wrap con badge, override editor |
Regola pratica: prima di scrivere markup custom direttamente nel
.razor, verificare se esiste un hook in conf.json; se manca, va
aggiunto al generator piuttosto che accettare la perdita su regen.
⚠️ Domande aperte / debito tecnico
Nessuna voce aperta al momento.