Schema DB edu
π― Cosa faβ
Definisce il persistence layer della formazione: ~38 tabelle
nel dominio edu. Questa pagina documenta in dettaglio le core
del catalogo + erogazione + docenti, allineate al redesign
edu-sessions-redesign del 2026-05-08 (co-erogazione multi-corso,
drop lessons/lessonsCourses, rename courseSessions β
trainingSessions).
πΊοΈ Tabelle coreβ
Catalogoβ
| Tabella | Ruolo |
|---|---|
edu.categories | Tassonomia piatta dei corsi |
edu.courses | Definizione corso (FK trainingVariants, organizers) |
Le tabelle
edu.lessonseedu.lessonsCoursessono state droppate dal redesign 2026-05-08. La struttura didattica vive ora sutrainingVariants/trainingArguments(fuori scope di questa pagina) +trainingSessionsCoursesArgumentsper gli argomenti effettivamente trattati nella sessione.
Erogazioneβ
| Tabella | Ruolo |
|---|---|
edu.trainingSessions | Sessione formativa: blocco fisico (giornata/giornate). FK opzionali locations (aula default), trainingTopics (vincola i corsi), core.recipientGroups (notifiche). Stati: planned/open/inProgress/completed/cancelled |
edu.trainingSessionsCourses | M:N session β corso (co-erogazione). Ogni riga Γ¨ una "vista contrattuale" del corso erogato nella session, con finestra oraria opzionale per-corso (NULL = eredita dalla session) |
edu.trainingSessionsCoursesArguments | Argomenti didattici trattati per ogni corso erogato (FK a trainingSessionsCourses). Rinomina di appointmentArguments. Etichetta libera + FK opzionale a trainingArguments di catalogo |
edu.trainingSessionsTeachers | Docenti agganciati alla session (default ereditato dagli appointment se questi non hanno override) |
edu.appointments | Occorrenza fisica (finestra oraria) all'interno di una session. FK trainingSessions NOT NULL, locations override opzionale |
edu.locations | Aule (indirizzo inline; FK opzionale reg.companies come gestore) |
edu.locationsTrainingVariants | M:N aula β variant per filtrare aule abilitate alle prove pratiche (variant con requiresEquippedRoom = 1) |
Docentiβ
| Tabella | Ruolo |
|---|---|
edu.teachers | Anagrafica docenti (label = computed firstName + ' ' + lastName) |
edu.appointmentsTeachers | M:N appuntamento β docente (override su default trainingSessionsTeachers, con hourlyAmount opzionale) |
edu.teacherCosts | Costo orario per docente per organizzatore |
edu.teacherSkills | Skill matrix docente β variante normativa (trainingVariantId, score). GranularitΓ a variant (non piΓΉ a lesson, ridenominata dal redesign 2026-05-08) |
πͺ Visteβ
| Vista | Ruolo |
|---|---|
edu.vw_appointmentsCalendar | Backing della vista calendario /appointments-calendar: appuntamenti arricchiti con info session, sede, docenti aggregati, primo trainingTopic (per il colore) |
edu.vw_appointmentsData | Dati appuntamenti aggregati (totale ore, partecipanti, ecc.) |
edu.vw_appointmentAttendees | Partecipanti per appuntamento |
edu.vw_workerTrainingStatus | Stato formativo per coppia (lavoratore Γ formazione richiesta): status (ok/expiring/expired/missing), daysRemaining, ultima formazione erogata, fonte del requisito (ruolo/mansione/qualifica/attrezzatura/rischio/esenzione). Esposta come CRUD read-only WorkerTrainingStatus. Aggregata da job.vw_workerComplianceSummary |
edu.vw_trainingSessionAppointmentsTeachers | Vista filtrata di appointmentsTeachers per trainingSessionId (usata negli step del session planner) |
edu.vw_workerEffectiveRisks | Rischi effettivi del lavoratore (JOIN diretto su workersRisks) |
edu.vw_workersData | Lavoratori arricchiti con dati di compliance |
edu.vw_companyComplianceStatus | Stato compliance per azienda |
edu.vw_trainingExpirations | Formazioni in scadenza |
edu.vw_availableTrainingSessions | Sessioni disponibili (per iscrizione) |
π Relazioniβ
Referenze esterne:
edu.courses.organizerSlugβreg.organizers(slug)edu.courses.trainingVariantIdβedu.trainingVariants(id)(subsystem normative)edu.trainingSessions.responsibleGroupIdβcore.recipientGroups(id)(notifiche operatore)edu.trainingSessions.trainingTopicIdβedu.trainingTopics(id)edu.locations.companyIdβreg.companies(id)(opzionale, gestore aula)edu.teacherCosts.organizerSlugβreg.organizers(slug)
ποΈ Dettaglio tabelleβ
edu.coursesβ
- PK:
id - FK:
trainingVariantId β edu.trainingVariants(id),organizerSlug β reg.organizers(slug) - Campi:
code,label,description,active(default 1),elearning(default 0),inCatalog(default 1),maxPeople,extraInstructorThreshold - Check:
maxPeople > 0,extraInstructorThreshold > 0
edu.trainingSessionsβ
Giornata (o giornate consecutive) di erogazione formativa, puΓ² ospitare uno o piΓΉ corsi in co-erogazione.
- PK:
id - FK:
locationId β edu.locations(id)(opzionale, aula default)responsibleGroupId β core.recipientGroups(id)(opzionale, gruppo destinatari notifiche operatore)trainingTopicId β edu.trainingTopics(id)(opzionale; se valorizzato, vincola i corsi della sessione a quel topic)
- Campi:
startDateTime(required, DATETIME),endDateTime(nullable: NULL = single-block),maxPeople(capienza pratica della giornata),status,notes(1024 char) - Check:
endDateTime IS NULL OR endDateTime >= startDateTimemaxPeople > 0status IN ('planned','open','inProgress','completed','cancelled')
- Indici:
IX_trainingSessions_startDateTime,IX_trainingSessions_locationId(filtered),IX_trainingSessions_trainingTopicId(filtered),IX_trainingSessions_responsibleGroupId(filtered)
edu.trainingSessionsCoursesβ
M:N session β corso: ogni riga rappresenta un corso erogato dentro la session, con finestra oraria opzionale per-corso (per co-erogazione di livelli diversi nello stesso giorno).
- PK:
id - FK:
trainingSessionId β edu.trainingSessions(id),courseId β edu.courses(id) - Unique:
(trainingSessionId, courseId)(un corso compare al piΓΉ una volta per session) - Campi:
startDateTime,endDateTime(entrambi nullable: NULL = eredita dalla session). VincoloCK_trainingSessionsCourses_windowforza la coppia consistente. - Indice:
IX_trainingSessionsCourses_courseId
edu.trainingSessionsCoursesArgumentsβ
Argomenti didattici trattati per ciascun corso erogato (rinomina di
appointmentArguments dal redesign 2026-05-08).
- PK:
id - FK:
trainingSessionsCoursesId β edu.trainingSessionsCourses(id),trainingArgumentId β edu.trainingArguments(id)(opzionale, riferimento a catalogo) - Campi:
label(string libero),description
edu.trainingSessionsTeachersβ
Default docenti agganciati alla session: ereditato dagli
appointment che non hanno override su appointmentsTeachers.
- PK composita:
(trainingSessionId, teacherId) - FK: a
trainingSessionseteachers - Indice:
IX_trainingSessionsTeachers_teacherId
edu.appointmentsβ
Occorrenza fisica (finestra oraria) all'interno di una session.
- PK:
id - FK:
trainingSessionId β edu.trainingSessions(id)(NOT NULL dal redesign 2026-05-08)locationId β edu.locations(id)(nullable, override dell'aula default della session)
- Campi:
startDateTime,endDateTime(entrambi required),link(NVARCHAR MAX),notes(NVARCHAR MAX) - Check:
endDateTime > startDateTime - Indici:
IX_appointments_trainingSessionId,IX_appointments_locationId(filtered),IX_appointments_startDateTime
lessonIdè stato droppato. L'appuntamento non riferisce più una lezione specifica: il "contenuto" è derivato daitrainingSessionsCoursesdella session e dai relativitrainingSessionsCoursesArguments.
edu.locationsβ
Aule / spazi di erogazione. EntitΓ autosufficiente: l'indirizzo Γ¨ inline sull'aula stessa, non rimandato a una sede.
- PK:
id - FK:
companyId β reg.companies(id)(opzionale: gestore aula esterno; NULL = aula 3SD) - Campi anagrafici:
shortName,label(required),description,instructions,active,digital,capacity - Tariffa:
unitCost,costMode('hourly' | 'daily'), coppia consistente (entrambi NULL = aula gratuita) garantita daCK_locations_costPair - Contatti / fatturazione:
email,vatCode(P.IVA gestore),invoicingLabel - Indirizzo geocoded:
formattedAddress,country,province,city,zipCode,address,streetNumber,latitude,longitude
edu.locationsTrainingVariantsβ
M:N aula β variante normativa: utilizzata per filtrare le aule
abilitate alle prove pratiche di una variante (requiresEquippedRoom = 1).
edu.teachersβ
- PK:
id - Campi:
firstName,lastName,label(computed column:firstName || ' ' || lastName),active,notes
edu.appointmentsTeachersβ
- PK composita:
(appointmentId, teacherId) - FK: a
appointmentseteachers - Campi:
hourlyAmount(nullable: override sul costo standard dateacherCosts) - Indice:
IX_appointmentsTeachers_teacherId
edu.teacherCostsβ
- PK composita:
(teacherId, organizerSlug) - FK:
teacherId β edu.teachers(id),organizerSlug β reg.organizers(slug) - Campi:
hourlyAmount(required)
edu.teacherSkillsβ
Skill matrix docente β variante normativa: abilitazione del formatore per quella variante (granularitΓ a variant dal redesign 2026-05-08, non piΓΉ a lesson).
- PK composita:
(teacherId, trainingVariantId) - FK:
teacherId β edu.teachers(id),trainingVariantId β edu.trainingVariants(id) - Campi:
score(nullable),active(default 1) - Indice:
IX_teacherSkills_trainingVariantId(filtered suactive = 1)
edu.trainingTopicsβ
Argomento didattico di alto livello (es. "Antincendio", "Primo
soccorso"). Usato come vincolo opzionale su trainingSessions e
come fonte del colore mostrato nel calendario.
- PK:
id - FK:
categoryId β edu.categories(id),riskId β job.risks(id)(opzionale) - Campi:
code,label,description,requireUpdates,regulated(default 1),fullRetrainingYears,ats(default 0),color(NVARCHAR(16), nullable; hex es.#e53935, usato dal calendario per il colore degli appuntamenti) - Check:
fullRetrainingYears > 0 - Indice:
IX_trainingTopics_riskId(filtered)
edu.categoriesβ
- PK:
id - Campi:
label
π Tabelle fuori scopeβ
Worker training journey (5)β
workersTrainings, workerTrainingDetails, trainingDetailAttempts,
attendances, workerCompletionsCache β registrazione iscrizioni,
presenze, esiti, materializzazione compliance.
Argomenti formativi (8)β
trainingArguments, trainingTopics, trainingVariants,
variantTopicMap, trainingTopicDependencies,
trainingArgumentChecks, trainingVariantsOverlaps,
appointmentChecks β macchina normativa degli argomenti formativi,
varianti, sovrapposizioni.
Nomine (3)β
nominations, workersNominations, nominationsTrainingTopics β
incarichi di ruolo (es. RSPP, ASPP, preposto) con vincoli formativi.
Certificati & qualifiche (5)β
certificates, enrollmentCosts, priorTrainings,
qualificationsExemptions, qualificationsRequiredTrainings β
attestati, costi iscrizione, formazione pregressa, esenzioni e
requisiti.
Ruoli vs corsi (2)β
rolesRequiredTrainings, rolesForbiddenTrainings β matrice ruoli
e corsi richiesti/vietati.
Attrezzature (3)β
equipments, workerEquipments, workerCredentials β attrezzature
e credenziali necessarie.
π File chiaveβ
TrainingHub.Database/edu/Tables/*.sqlβ ~38 tabelle- Indici espliciti: vedi sezione "Dettaglio tabelle"
β οΈ Debito tecnicoβ
-
. Risolto in edu-sessions-redesign 2026-05-08: ora Γ¨appointments.courseSessionIdnullabletrainingSessionIdNOT NULL. -
Drop. Risolto dallo stesso redesign: il contenuto deriva daappointments.lessonIdtrainingSessionsCourses+trainingSessionsCoursesArguments. -
. Sostituito dateacherSkills.lessonIdtrainingVariantIdper allinearsi alla granularitΓ varianti. -
Nessun check su sovrapposizione appuntamenti. A livello DB i constraint restano informativi, ma a livello applicativoISessionPlannerService.DetectConflictsAsyncrileva: docente sovrapposto, sede occupata, iscritti oltre capienza, soglia docente, lavoratore in piΓΉ sessioni, lezione mancante. Esposto come toast warning dal calendario e dal wizard. -
edu.categoriessenza FK visibili dacourses. La correlazione categoria β corso passa pertrainingVariants: da documentare chiaramente nel subsystem varianti. -
courses.maxPeoplevstrainingSessions.maxPeople. Due limiti distinti β validazione di coerenza non applicata a DB, solo in serviceSessionPlanner(conflictenrollment_overflow). -
teachers.labelcomputed. Colonna calcolata dafirstName + lastName: efficiente ma non indicizzabile. Se serve ricerca, aggiungere indice full-text o persisted computed column. - Cache
workerCompletionsCachenon atomica. Aggiornata da trigger/hook vari: coerenza in caso di failure non chiara.
π Vedi ancheβ
- Panoramica dominio
- Componenti UI
- Logica applicativa
- Dominio
reg: schema DB βheadquarters,organizers,companiesreferenziate da edu - Spec di riferimento:
docs/superpowers/specs/_archive/2026-05-08-edu-sessions-redesign-design.md