Vai ai modelli SQL

Helpdesk · SQL simulato

Prime tabelle prima dei model Django.

Questa pagina traduce le logiche business in una bozza PostgreSQL leggibile, includendo il ponte tra ente, AOO, uffici, funzioni e ticket. Non applica migrazioni, non crea dati e resta una simulazione progressiva da S0 a S19, con tre SPEM ora coperti da comando backend di emergenza.

Base tecnica provvisoria

Schema da discutere, non da migrare

Il modello parte dalla fondazione shared `enti` e poi arriva al ticket madre, tenendo separate policy, conversazione, audit, privacy, allegati, SLA e snapshot di routing. Le parti dipendenti dal primo sprint restano marcate come bozza.

28 tabelle3 core/workflow48 assunzioni3 SPEM3 funzioni seed

Assunzioni

Cosa vale in questa simulazione

  • PostgreSQL come riferimento tecnico, coerente con la suite Django.
  • SQL solo simulato: non esistono migrazioni e non viene creato nessun dato reale; i valori IPA mostrati sono invece dati ufficiali verificati.
  • Le tabelle usano nomi espliciti helpdesk_* per preparare i model Django futuri.
  • I campi utente Django sono indicati come *_user_id BIGINT NULL finche non si decide il legame preciso con auth_user.
  • Stati, SLA, visibilita e permessi restano policy configurabili per evitare hardcode.
  • Gli allegati sono modellati, ma upload pubblico resta rinviato.
  • Il setup Helpdesk non duplica l ente: punta alla base shared enti.PublicEntity e resta mono-ente solo come configurazione MVP.
  • Fonte ente/AOO/UO per Sprint 1: CMDC_AV, A009176, KFYBVW, NBECRO e UF2UQQ da IndicePA/Opendata IPA.
  • Il seed iniziale resta mono-ente ma ogni configurazione punta all ente, cosi il passaggio multi-ente non richiede riscrittura delle regole.
  • AOO e UO restano visibili nel perimetro organigramma, ma la relazione documentale AOO/UO viene modellata in modo esplicito.
  • Funzioni iniziali: carriera amministrativa studenti, carriera didattica studenti, protocollo/AOO come raccordo documentale e non come coda pubblica ordinaria.
  • Certificati di iscrizione, frequenza e attestati sono funzione amministrativa studenti; presenze/frequenza al singolo corso sono funzione didattica.
  • Le code Helpdesk puntano sia a un ufficio responsabile sia a una funzione: la funzione spiega cosa viene chiesto, l ufficio chi presidia.
  • Le categorie hanno una regola di ingresso: informazione prima, ticket ordinario, orientamento o pre-triage controllato.
  • Mailbox di servizio e bozza risposta sono modellate ma l invio email reale resta rinviato.
  • Sprint 1 deve restare piccolo: model minimi piu setup essenziale, seed idempotente, admin essenziale, form pubblico base, lista operatore semplice e test bloccanti prima di dashboard/report avanzati.
  • Fuori Sprint 1: email reale, upload pubblico, area riservata, AI, protocollo reale, notifiche interne avanzate, report direzionali e consultazione pubblica email+codice.
  • Sprint 2 e preparato ma non avviato: puo partire stretto dalla consultazione pubblica read-only su /helpdesk/consultazione/, email+codice+cognome, parte pubblica del ticket, ricevuta HTML, log minimizzato e blocco tentativi.
  • Integrazione pubblica e richiesta di riapertura sono certe ma progressive: possono essere predisposte come modello/evento senza attivarle subito nella prima UI pubblica.
  • Ticket riservati o segreti sono esclusi dalla consultazione pubblica email+codice e restano accessibili solo da backend/admin autorizzato.
  • La dashboard S2 non diventa ancora board completa: resta lista semplice con tre ingressi filtrati Da prendere, In scadenza e Arretrati.
  • S7 chiude la preparazione UX: pagina separata di consultazione, box secondario nella pagina nuovo ticket, ricevuta HTML stampabile, badge tra messaggi interlocutori e risposta ufficiale.
  • Gli accessi pubblici riusciti e i tentativi errati restano separati: PublicAccessLog per accessi riusciti, PublicAccessAttempt per errori, rate-limit e blocchi.
  • Il gate S2 resta leggero: test Django, smoke route manuale, report e commit; Playwright entra solo quando la UI pubblica e stabile.
  • Ready S2: le domande Q321-Q330 chiudono il passaggio da progettazione a esecuzione, ma il codice parte solo con via esplicito.
  • Il dettaglio ticket dopo consultazione riuscita non deve esporre il codice ticket nell URL pubblico.
  • TicketPublicView e un service/read model: non richiede per forza una tabella dedicata se la vista pubblica puo essere composta in modo sicuro dal ticket e dai messaggi pubblici.
  • S18 backend/staff e implementato come read model Django StaffDashboardView, derivato da ticket, assegnazioni, membership e audit/eventi: nessuna tabella fisica nuova e nessuna migrazione.
  • S9 blinda TicketPublicView nel service layer: il template non decide cosa nascondere.
  • La consultazione pubblica puo essere disattivata per singolo ticket con policy/campo dedicato.
  • I test S2 devono cercare nel markup pubblico l assenza di note interne, audit, riassegnazioni, cambi coda e stati interni.
  • Il seed deve essere idempotente e non sovrascrivere modifiche manuali gia fatte da amministratori.
  • Ogni ticket deve salvare uno snapshot di coda, ufficio e funzione per non perdere contesto quando organigramma o funzionigramma cambiano.
  • S15 e operativo nel runtime: Segreteria studenti ha responsabile primario luigi.dalessandro, Segreteria didattica ha responsabile primario francesca.manganiello.
  • S16 non richiede nuova migrazione: il collaudo usa il modello gia creato da S15 e produce dati runtime marcati come collaudo.
  • S17 non richiede nuova migrazione: chiusura assegnazione, riapertura staff e archiviazione collaudi usano helpdesk_ticket, helpdesk_ticket_assignment e helpdesk_audit_event gia esistenti.
  • Il comando archive_helpdesk_test_tickets e manutenzione prudente: default dry-run, scrive solo con --commit e archivia solo subject [COLLAUDO...] con richiedente @example.invalid.
  • S18 puo partire senza nuova migrazione obbligatoria: la dashboard staff minima e una vista derivata da ticket, assegnazioni, membership, stati, scadenze e audit/eventi.
  • La dashboard S18 non mostra tutto insieme: default propria coda; vista tutte le code solo come scelta esplicita e autorizzata.
  • La madre S18 resta compatta: quattro ingressi/pagine figlie Da prendere, In scadenza, Arretrati e Miei ticket, con massimo 5 ticket per blocco e colonne che non eccedono la larghezza disponibile.
  • S19 non richiede nuova tabella: la storia assegnazioni usa helpdesk_ticket_assignment con previous_assignment, reason, started_at, ended_at e audit_event collegato.
  • La soglia S19 di autoassegnazione e presa in carico configurata piu un minuto; nel setup base Cimarosa resta 32 ore + 1 minuto.
  • Il limite di saturazione operatore resta configurabile su helpdesk_institution_setup.operator_active_ticket_limit, default 10.
  • I badge S19 della dashboard staff sono derivati da assignment_kind e scadenze calcolate, non da campi duplicati.
  • SPEM-01 non crea nuova tabella obbligatoria: usa check_helpdesk_setup, setup, membership, seed idempotente, report admin/responsabili, blocco del non urgente e fallback Direttore amministrativo.
  • SPEM-02 usa autoassegnazione, storico helpdesk_ticket_assignment e dashboard staff gia esistenti; il dry-run puo diventare programmato solo dopo conferma amministrativa e, se tutti superano soglia 10, il ticket va al responsabile primario.
  • SPEM-03 usa TicketPublicView, public_lookup_enabled, sensitivity_level, audit_event e test anti-leak; un ticket segreto disattiva sempre la consultazione pubblica e la depurazione richiede doppia conferma o lista preautorizzata.
  • Il comando tecnico dei tre runbook e ora operativo: check_helpdesk_emergency --spem=01/02/03. Non sostituisce i comandi esistenti finche S20 non decide se serve tabella dedicata per esiti emergenza.

Dato reale IPA · 2026-06-02

Seed Cimarosa da non simulare

Il DDL resta una bozza, ma ente, AOO e UO sotto sono dati ufficiali verificati. Il primo sprint dovra importarli o agganciarli al dominio `enti`.

LivelloCodiceDato da salvare
EnteCMDC_AVConservatorio di Musica 'D. Cimarosa' di Avellino · CF 80005510641 · PEC consavellino@pec.it
AOOA009176Denominazione Presidente · cod_aoo Presidente · protocollo@conservatoriocimarosa.org
UOKFYBVWConservatorio di musica · UO istituzionale · AOO A009176
UONBECROUfficio per la transizione al Digitale · UO RTD · AOO A009176
UOUF2UQQUff_eFatturaPA · UO fatturazione elettronica · AOO non associata

Seed funzionale

Funzioni iniziali prima dei model Django

Il seed iniziale lega funzionigramma, code e categorie. Le funzioni spiegano il perche del routing; le code restano i contenitori operativi dei ticket.

student_admin_careerSegreteria studenti

Carriera amministrativa studenti

Gestisce la posizione amministrativa dello studente e le richieste conoscitive o operative collegate alla segreteria studenti.

Visibilita: Pubblica sintetica, setup esteso riservato
student_didactic_careerSegreteria didattica

Carriera didattica studenti

Gestisce la carriera didattica: percorso formativo, attivita didattiche, esami e richieste che richiedono istruttoria didattica.

Visibilita: Pubblica sintetica, setup esteso riservato
protocol_aoo_document_flowSetup/AOO, non coda pubblica ordinaria nel MVP

Protocollo, AOO e flussi documentali

Collega ente, AOO, UO e uffici al perimetro documentale. Serve a sapere dove passa la pratica, senza trasformare il protocollo in helpdesk pubblico iniziale.

Visibilita: Pubblica solo come organigramma/funzionigramma sintetico; setup tecnico riservato

Runbook emergenza

SPEM senza migrazione obbligatoria immediata

Le tre soluzioni emergenza riusano setup, membership, assegnazioni, audit e vista pubblica sicura. I comandi dedicati `check_helpdesk_emergency --spem=01/02/03` sono previsti come gate operativi; eventuali tabelle dedicate restano da valutare solo dopo S20.

SPEM-01Runbook

Setup e permessi in emergenza

Setup non coerente, coda attiva senza responsabile primario, operatori non autorizzati, seed o policy base mancanti.

Regole confermate: Se il gate fallisce si blocca tutto il lavoro non urgente, non solo le nuove aperture pubbliche. Il report emergenza setup e visibile ad amministratori helpdesk e responsabili di coda. Se una coda resta senza responsabile primario, il Direttore amministrativo e fallback temporaneo proposto. SPEM-01 ha un comando/check dedicato.Logiche: HD-BL-017, HD-BL-021, HD-BL-024, HD-BL-043, HD-BL-049
SPEM-02Runbook

Arretrati, sovraccarico e recupero coda

Ticket non presi dopo 32h+1m, picco arretrati, operatori saturi o rilascio massivo al responsabile.

Regole confermate: L autoassegnazione parte in dry-run, poi puo diventare automatica programmata dopo conferma amministrativa. Se tutti gli operatori sono sopra soglia 10, il ticket va al responsabile primario. Non nasce una nuova pagina: si potenzia /helpdesk/staff/arretrati/. SPEM-02 ha un comando/check dedicato.Logiche: HD-BL-009, HD-BL-010, HD-BL-015, HD-BL-048, HD-BL-050
SPEM-03Runbook

Privacy, consultazione pubblica e dati riservati

Ticket con dati sensibili, consultazione pubblica da disattivare, rischio leak, nota interna da rendere pubblica solo dopo depurazione.

Regole confermate: Tutti gli operatori autorizzati possono segnalare/classificare, poi il ticket diventa visibile solo ai gradi piu alti. Se il ticket diventa segreto, la consultazione pubblica email+codice si disattiva sempre in automatico. La depurazione di una nota interna richiede doppia conferma autore piu responsabile. Sono ammesse depurazioni generiche preautorizzate da lista. SPEM-03 ha un comando/check dedicato.Logiche: HD-BL-004, HD-BL-005, HD-BL-013, HD-BL-019, HD-BL-041, HD-BL-051

Mappa tabelle

Dal dominio al dato

Ogni tabella indica fonte, livello, vincoli e indici minimi da tenere presenti quando nasceranno i model Django.

SetupBozza integrata enti

Ente e setup istituzionale integrato

Configura il perimetro Helpdesk senza duplicare l ente: il record punta alla base shared enti.PublicEntity e abilita il mono-ente MVP con futuro multi-ente.

Fonte: Q001-Q003, Q009-Q010, Q181-Q190, ENTE-AOO-01
Tabella
helpdesk_institution
Vincoli
public_entity_id unico nel setup; slug unico; name obbligatorio; un solo ente primario nel MVP
Indici
public_entity_id; slug; is_active; is_primary
SetupSprint 15 operativo

Setup operativo istituzione

Conserva testi privacy, consenso, ricevuta standard, soglie temporali minime e limite carico operatore per l istituzione helpdesk, lasciandoli configurabili da admin senza cambiare codice.

Fonte: Q009-Q010, Q015, Q056-Q061, Q251-Q258, Q405-Q407
Tabella
helpdesk_institution_setup
Vincoli
institution_id unico; testi obbligatori; soglie temporali maggiori di zero; limite carico operatore maggiore di zero; un setup operativo per istituzione
Indici
institution_id; is_active
Enti sharedBozza Sprint 1

Profilo AOO dell ente

Estende una unita organizzativa di livello AOO con i dati specifici del perimetro documentale/protocollo, senza confonderla con un ufficio ordinario. Per Cimarosa il seed iniziale usa il dato reale IPA A009176, denominazione AOO Presidente, cod_aoo Presidente.

Fonte: ENTE-AOO-01, IPA/enti, Q161-Q170
Tabella
enti_aoo_profile
Vincoli
una profile per unita AOO; entity_id + ipa_unique_code unico; official_label obbligatorio; una AOO primaria attiva per ente da vincolo parziale
Indici
entity_id, is_primary; organizational_unit_id; valid_from, valid_to
Enti sharedBozza Sprint 1

Relazione UO o ufficio verso AOO

Collega uffici, UO, servizi o segreterie al perimetro AOO competente per protocollo e flussi documentali.

Fonte: ENTE-AOO-01, Q161-Q170
Tabella
enti_unit_aoo_membership
Vincoli
AOO + unita + relation_kind unica; relation_kind vincolato; finestra date coerente
Indici
entity_id, aoo_profile_id; organizational_unit_id, is_primary; valid_from, valid_to
FunzionigrammaBozza Sprint 1

Catalogo funzioni dell ente

Descrive cosa fa l ente in modo riusabile: funzionigramma sintetico pubblico e setup esteso riservato partono dallo stesso catalogo.

Fonte: FUNZ-01, Q012-Q013, Q161-Q170
Tabella
enti_public_entity_function
Vincoli
entity_id + code unico; scope e visibilita vincolati; finestra date coerente
Indici
entity_id, function_scope; public_visibility, is_active; valid_from, valid_to
FunzionigrammaBozza Sprint 1

Assegnazione funzione a ufficio

Stabilisce chi fa cosa: collega funzioni a uffici/UO con ruolo di responsabilita e validita storica.

Fonte: FUNZ-01, QUEUE-BRIDGE-01, Q161-Q170
Tabella
enti_unit_function_assignment
Vincoli
funzione + unita + ruolo unica; responsibility_role vincolato; finestra date coerente
Indici
function_id, responsibility_role; organizational_unit_id, is_active; valid_from, valid_to
RoutingBozza integrata enti

Coda operativa collegata a ufficio e funzione

Rappresenta Segreteria studenti, Segreteria didattica e future code configurabili, collegandole a ufficio responsabile e funzione prevalente.

Fonte: Q004, Q027-Q028, Q034-Q036, Q161-Q170, QUEUE-BRIDGE-01
Tabella
helpdesk_queue
Vincoli
institution_id + code unico; ufficio e funzione obbligatori; privacy_level vincolato a valori ammessi
Indici
institution_id, is_active; organizational_unit_id; primary_function_id; privacy_level
PermessiSprint 15 operativo

Operatori e ruoli di coda

Collega utenti Django a code e ruoli operatore, responsabile o amministratore, includendo il responsabile primario richiesto per la governance S15.

Fonte: Q031-Q040, Q051-Q055, Q391-Q400, Q403-Q404
Tabella
helpdesk_queue_membership
Vincoli
queue_id + user_id unico; role vincolato; un solo responsabile primario attivo per coda; il responsabile primario deve avere ruolo responsible o administrator; la supervisione coda e derivata dal ruolo responsible/administrator
Indici
queue_id, role, is_active; user_id, is_active; queue_id, is_primary_responsible, is_active
IdentitaBozza

Richiedente

Salva la persona o organizzazione che chiede assistenza senza imporre subito account.

Fonte: Q005, Q021-Q026
Tabella
helpdesk_requester
Vincoli
email obbligatoria; requester_type vincolato
Indici
email; requester_type; student_number
RoutingBozza integrata enti

Categoria, funzione e routing

Traduce cosa vuole chiedere il pubblico in funzione, coda, tipologia, orientamento o ticket ordinario.

Fonte: Q012-Q013, Q041-Q047, Q151-Q160, Q231-Q234, Q236-Q250, QUEUE-BRIDGE-01
Tabella
helpdesk_category
Vincoli
institution_id + code unico; mode vincolato; function_id consigliato per categorie instradabili
Indici
default_queue_id; function_id; mode, is_active
RoutingBozza S4

Regola ingresso categoria

Decide se una categoria mostra informazione prima, apre ticket ordinario, resta orientamento o entra in pre-triage controllato senza dati riservati.

Fonte: Q233-Q234, Q236-Q247
Tabella
helpdesk_category_entry_rule
Vincoli
una regola per categoria; entry_mode vincolato; nessun ticket pubblico se solo orientamento
Indici
category_id; entry_mode; allow_public_ticket
WorkflowBozza

Policy categoria/tipologia

Decide cambio coda, chiusura, riapertura, mapping stati e catena libero/guidato.

Fonte: Q041, Q054-Q055, Q074-Q075, Q201-Q205, Q224-Q225
Tabella
helpdesk_category_workflow_policy
Vincoli
una policy attiva per categoria; modalita vincolate
Indici
category_id
SLABozza dipendente da Q206-Q213

SLA e soglie operative

Conserva tempi obiettivo per presa in carico, prima risposta, arretrato e sollecito.

Fonte: Q056-Q060, Q206-Q213
Tabella
helpdesk_sla_policy
Vincoli
almeno categoria o coda valorizzata; valori positivi
Indici
category_id; queue_id; calendar_mode
CoreCore operativo con estensioni S17

Ticket madre

Contiene richiesta, stati, coda corrente, categoria, riepilogo e tracciatori temporali principali; S17 usa closed_at e reopened_count per chiusura ordinaria e prima riapertura staff.

Fonte: Q006-Q008, Q014, Q021-Q027, Q050, Q061-Q065, Q421-Q426
Tabella
helpdesk_ticket
Vincoli
code unico; stati vincolati; sensitivity_level vincolato; public_lookup_enabled disattivabile per singolo ticket
Indici
code; queue_id, internal_status; requester_id; public_status; public_lookup_enabled, public_access_until; created_at
GDPRBozza S4

Marker contenuto sensibile

Registra scelta utente, rilevazione automatica o decisione amministratore quando il ticket contiene dati riservati, sensibili o segreti.

Fonte: Q077, Q217-Q219, Q234, Q247
Tabella
helpdesk_sensitive_content_marker
Vincoli
classificazione e fonte vincolate; reason minimizzato; piu marker ammessi per audit
Indici
ticket_id, status; classification; source
RoutingBozza Sprint 1

Snapshot routing del ticket

Congela per ogni ticket la fotografia di ente, AOO, ufficio, funzione e coda usati al momento del routing.

Fonte: QUEUE-BRIDGE-01, Q050, Q061-Q065, Q161-Q170
Tabella
helpdesk_ticket_routing_snapshot
Vincoli
uno snapshot iniziale per ticket; payload minimizzato; FK storiche nullable solo se dati dismessi
Indici
ticket_id; queue_id; organizational_unit_id; function_id
WorkflowSprint 15 operativo, chiusura S17 integrata

Assegnazione e presa in carico

Traccia coda, operatore incaricato, riassegnazioni, rilascio al responsabile, autoassegnazione e periodo di validita senza appesantire il ticket madre. S17 chiude l assegnazione attiva quando il ticket viene chiuso o archiviato come collaudo.

Fonte: Q027-Q028, Q031-Q036, Q051-Q055, Q401-Q410, Q421-Q423, Q427-Q430
Tabella
helpdesk_ticket_assignment
Vincoli
una assegnazione attiva per ticket da vincolo parziale; reason obbligatoria; assegnazione attiva senza ended_at, chiusa con ended_at; assegnatario deve appartenere alla coda salvo superuser
Indici
ticket_id, is_active; queue_id, is_active; assigned_to_user_id, is_active; assignment_kind, started_at
ConversazioneBozza

Messaggi pubblici

Conserva descrizione iniziale, messaggi del richiedente, richieste integrazione e risposte ufficiali.

Fonte: Q014, Q019, Q052-Q054, Q081-Q090
Tabella
helpdesk_public_message
Vincoli
body obbligatorio; kind vincolato
Indici
ticket_id, created_at; is_official_answer
ConversazioneBozza S4

Bozza risposta ufficiale

Permette di preparare, proporre e approvare una risposta prima di trasformarla in messaggio pubblico ufficiale.

Fonte: Q080, Q203, Q249
Tabella
helpdesk_reply_draft
Vincoli
body obbligatorio; status vincolato; official_message_id valorizzato solo dopo invio
Indici
ticket_id, status; reviewer_user_id
Lavoro internoBozza

Note interne

Tiene istruttoria, coordinamento e valutazioni non visibili al richiedente.

Fonte: Q019-Q020, Q031-Q040, Q081-Q090
Tabella
helpdesk_internal_note
Vincoli
nota non pubblica; visibility_scope vincolato
Indici
ticket_id, created_at; visibility_scope
DocumentiBozza backend only

Allegati

Predispone allegati pubblici e interni, limiti, neutralizzazione e classificazione.

Fonte: Q011, Q016-Q018, Q063-Q064, Q081-Q090
Tabella
helpdesk_attachment
Vincoli
dimensione positiva; scope e security_status vincolati
Indici
ticket_id; visibility_scope; security_status
GDPRBozza

Privacy e consenso

Salva doppio click, versione informativa e testo accettato per il singolo ticket.

Fonte: Q009-Q010, Q021, Q029-Q030
Tabella
helpdesk_privacy_consent_snapshot
Vincoli
un consenso per ticket; doppio timestamp obbligatorio
Indici
ticket_id; privacy_version
NotificheBozza

Ricevuta salvata

Registra ricevuta generata, anche senza invio email reale, con dati minimizzati.

Fonte: Q015, Q066-Q070, Q222-Q223
Tabella
helpdesk_receipt_snapshot
Vincoli
piu snapshot ammessi per eventi diversi; delivery_status vincolato
Indici
ticket_id, created_at; delivery_status
NotificheBozza S4

Mailbox di servizio

Configura mailbox generale, mailbox di coda o categoria e mailbox errori, senza attivare ancora il delivery email reale.

Fonte: Q079, Q248
Tabella
helpdesk_service_mailbox
Vincoli
indirizzo obbligatorio; mailbox_kind vincolato; almeno ente sempre presente
Indici
institution_id, mailbox_kind; queue_id; category_id; is_active
AuditAppend-only operativo con eventi S17

Cronologia eventi

Registra cambi stato, categoria, coda, assegnazioni, oscuramenti, accessi rilevanti ed escalation. S17 registra assignment_closed, reopen_first_staff e archive_test_ticket come payload auditati.

Fonte: Q019, Q024, Q050, Q065, Q121-Q130, Q421-Q430
Tabella
helpdesk_audit_event
Vincoli
append-only da rispettare lato servizio; event_type obbligatorio
Indici
ticket_id, created_at; event_type; payload GIN futuro
SicurezzaBozza S2

Log accesso pubblico riuscito

Tiene traccia minimizzata degli accessi pubblici riusciti alla vista ticket, senza salvare contenuto ticket e con retention iniziale di 30 giorni.

Fonte: Q025, Q061, Q065, Q221, Q266-Q305, Q331-Q340
Tabella
helpdesk_public_access_log
Vincoli
nessun contenuto ticket; ticket obbligatorio; public_view_mode vincolato
Indici
ticket_id, created_at; email_hash, created_at; expires_at
SicurezzaBozza S2

Tentativi consultazione pubblica

Registra tentativi falliti o bloccati della consultazione pubblica, separandoli dagli accessi riusciti e mantenendo messaggi utente sempre generici.

Fonte: Q269-Q270, Q284-Q285, Q297-Q300, Q302-Q303, Q331-Q340
Tabella
helpdesk_public_access_attempt
Vincoli
nessun contenuto ticket; attempt_result vincolato; lock_level tra 0 e 3
Indici
email_hash, code_hash, created_at; attempt_result, created_at; locked_until; expires_at
SLABozza

Escalation e arretrati

Registra alert, solleciti, contatto umano proposto e passaggi a responsabile/admin.

Fonte: Q048-Q049, Q056-Q060, Q191-Q198
Tabella
helpdesk_escalation_event
Vincoli
level e status vincolati
Indici
ticket_id, created_at; level, status

DDL PostgreSQL

Primi CREATE TABLE simulati

Sono blocchi tecnici di lavoro: servono a ragionare su relazioni, campi mancanti, indici e vincoli prima di generare migrazioni Django.

Setup

helpdesk_institution

Q001-Q003, Q009-Q010, Q181-Q190, ENTE-AOO-01
ColonnaTipoLogica
idBIGSERIALchiave primaria
public_entity_idBIGINTFK verso enti.PublicEntity
nameVARCHAR(180)nome pubblico ente
slugVARCHAR(80)chiave tecnica unica
official_emailVARCHAR(160)recapito istituzionale
privacy_contactVARCHAR(180)contatto diritti GDPR
is_primaryBOOLEANente principale nel MVP
public_organization_visibleBOOLEANorganigramma sintetico pubblico
public_function_visibleBOOLEANfunzionigramma sintetico pubblico
is_activeBOOLEANsetup attivo
CREATE TABLE helpdesk_institution (
  id BIGSERIAL PRIMARY KEY,
  public_entity_id BIGINT NOT NULL REFERENCES enti_publicentity(id),
  name VARCHAR(180) NOT NULL,
  slug VARCHAR(80) NOT NULL UNIQUE,
  official_email VARCHAR(160) NOT NULL,
  privacy_contact VARCHAR(180) NOT NULL,
  is_primary BOOLEAN NOT NULL DEFAULT FALSE,
  public_organization_visible BOOLEAN NOT NULL DEFAULT TRUE,
  public_function_visible BOOLEAN NOT NULL DEFAULT TRUE,
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (public_entity_id)
);

CREATE UNIQUE INDEX helpdesk_institution_primary_uniq
ON helpdesk_institution(is_primary)
WHERE is_primary;
Setup

helpdesk_institution_setup

Q009-Q010, Q015, Q056-Q061, Q251-Q258, Q405-Q407
ColonnaTipoLogica
idBIGSERIALchiave primaria
institution_idBIGINTFK verso helpdesk_institution
privacy_text_versionVARCHAR(80)versione informativa privacy breve
privacy_textTEXTtesto informativa privacy configurabile
consent_textTEXTtesto consenso assistenza
receipt_templateTEXTtemplate ricevuta standard personalizzabile
public_access_daysSMALLINTgiorni futuri di accesso pubblico email + codice
take_charge_hoursSMALLINTore obiettivo prima presa in carico
first_response_hoursSMALLINTore obiettivo prima risposta o integrazione
urgent_review_hoursSMALLINTore valutazione urgenza dichiarata
new_ticket_backlog_daysSMALLINTgiorni per arretrato nuova
user_integration_reminder_daysSMALLINTgiorni prima del sollecito integrazione
operator_active_ticket_limitSMALLINTmassimo ticket attivi per operatore
is_activeBOOLEANsetup attivo
CREATE TABLE helpdesk_institution_setup (
  id BIGSERIAL PRIMARY KEY,
  institution_id BIGINT NOT NULL UNIQUE REFERENCES helpdesk_institution(id) ON DELETE CASCADE,
  privacy_text_version VARCHAR(80) NOT NULL,
  privacy_text TEXT NOT NULL,
  consent_text TEXT NOT NULL,
  receipt_template TEXT NOT NULL,
  public_access_days SMALLINT NOT NULL DEFAULT 30,
  take_charge_hours SMALLINT NOT NULL DEFAULT 32,
  first_response_hours SMALLINT NOT NULL DEFAULT 48,
  urgent_review_hours SMALLINT NOT NULL DEFAULT 24,
  new_ticket_backlog_days SMALLINT NOT NULL DEFAULT 4,
  user_integration_reminder_days SMALLINT NOT NULL DEFAULT 3,
  operator_active_ticket_limit SMALLINT NOT NULL DEFAULT 10,
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CHECK (public_access_days > 0),
  CHECK (take_charge_hours > 0),
  CHECK (first_response_hours > 0),
  CHECK (urgent_review_hours > 0),
  CHECK (new_ticket_backlog_days > 0),
  CHECK (user_integration_reminder_days > 0),
  CHECK (operator_active_ticket_limit > 0)
);
Enti shared

enti_aoo_profile

ENTE-AOO-01, IPA/enti, Q161-Q170
ColonnaTipoLogica
idBIGSERIALchiave primaria
entity_idBIGINTente proprietario
organizational_unit_idBIGINTunita organigramma di livello AOO
ipa_unique_codeVARCHAR(20)Codice_uni_aoo IPA, es. A009176
cod_aooVARCHAR(100)codice AOO assegnato dall ente, es. Presidente
official_labelVARCHAR(220)denominazione AOO da enti/IPA
protocol_labelVARCHAR(180)denominazione protocollo
pec_primaryVARCHAR(180)domicilio digitale principale AOO
protocol_uriVARCHAR(220)URI protocollo informatico
source_updated_onDATEdata aggiornamento fonte IPA
is_primaryBOOLEANAOO principale nel MVP
ipa_snapshot_payloadJSONBpayload IPA normalizzato se disponibile
valid_fromDATEinizio validita
valid_toDATEfine validita
CREATE TABLE enti_aoo_profile (
  id BIGSERIAL PRIMARY KEY,
  entity_id BIGINT NOT NULL REFERENCES enti_publicentity(id),
  organizational_unit_id BIGINT NOT NULL UNIQUE REFERENCES enti_publicentityorganizationalunit(id),
  ipa_unique_code VARCHAR(20) NOT NULL,
  cod_aoo VARCHAR(100) NOT NULL DEFAULT '',
  official_label VARCHAR(220) NOT NULL,
  protocol_label VARCHAR(180) NOT NULL DEFAULT '',
  pec_primary VARCHAR(180) NOT NULL DEFAULT '',
  protocol_uri VARCHAR(220) NOT NULL DEFAULT '',
  source_updated_on DATE,
  ipa_snapshot_payload JSONB NOT NULL DEFAULT '{}'::jsonb,
  is_primary BOOLEAN NOT NULL DEFAULT FALSE,
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  valid_from DATE NOT NULL DEFAULT CURRENT_DATE,
  valid_to DATE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (entity_id, ipa_unique_code),
  CHECK (valid_to IS NULL OR valid_to >= valid_from)
);

CREATE UNIQUE INDEX enti_aoo_profile_primary_uniq
ON enti_aoo_profile(entity_id)
WHERE is_primary AND is_active;
Enti shared

enti_unit_aoo_membership

ENTE-AOO-01, Q161-Q170
ColonnaTipoLogica
idBIGSERIALchiave primaria
entity_idBIGINTente
aoo_profile_idBIGINTAOO
organizational_unit_idBIGINTufficio/UO/servizio
ipa_unit_codeVARCHAR(20)Codice_uni_uo IPA, es. KFYBVW
relation_kindVARCHAR(40)protocol_scope/document_flow/reference
is_primaryBOOLEANrelazione prevalente
valid_fromDATEinizio validita
valid_toDATEfine validita
CREATE TABLE enti_unit_aoo_membership (
  id BIGSERIAL PRIMARY KEY,
  entity_id BIGINT NOT NULL REFERENCES enti_publicentity(id),
  aoo_profile_id BIGINT NOT NULL REFERENCES enti_aoo_profile(id),
  organizational_unit_id BIGINT NOT NULL REFERENCES enti_publicentityorganizationalunit(id),
  ipa_unit_code VARCHAR(20) NOT NULL DEFAULT '',
  relation_kind VARCHAR(40) NOT NULL DEFAULT 'protocol_scope',
  is_primary BOOLEAN NOT NULL DEFAULT TRUE,
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  valid_from DATE NOT NULL DEFAULT CURRENT_DATE,
  valid_to DATE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (aoo_profile_id, organizational_unit_id, relation_kind),
  CHECK (relation_kind IN ('protocol_scope', 'document_flow', 'reference')),
  CHECK (valid_to IS NULL OR valid_to >= valid_from)
);
Funzionigramma

enti_public_entity_function

FUNZ-01, Q012-Q013, Q161-Q170
ColonnaTipoLogica
idBIGSERIALchiave primaria
entity_idBIGINTente
codeVARCHAR(80)codice funzione
public_labelVARCHAR(180)label sintetica pubblica
setup_labelVARCHAR(220)label estesa backend
function_scopeVARCHAR(60)student_admin/student_didactic/protocol/etc
public_visibilityVARCHAR(32)public_synthetic/setup_only/hidden
valid_fromDATEinizio validita
valid_toDATEfine validita
CREATE TABLE enti_public_entity_function (
  id BIGSERIAL PRIMARY KEY,
  entity_id BIGINT NOT NULL REFERENCES enti_publicentity(id),
  code VARCHAR(80) NOT NULL,
  public_label VARCHAR(180) NOT NULL,
  setup_label VARCHAR(220) NOT NULL DEFAULT '',
  function_scope VARCHAR(60) NOT NULL,
  public_visibility VARCHAR(32) NOT NULL DEFAULT 'public_synthetic',
  description TEXT NOT NULL DEFAULT '',
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  valid_from DATE NOT NULL DEFAULT CURRENT_DATE,
  valid_to DATE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (entity_id, code),
  CHECK (function_scope IN ('student_admin', 'student_didactic', 'protocol', 'international', 'events', 'internal_admin', 'other')),
  CHECK (public_visibility IN ('public_synthetic', 'setup_only', 'hidden')),
  CHECK (valid_to IS NULL OR valid_to >= valid_from)
);
Funzionigramma

enti_unit_function_assignment

FUNZ-01, QUEUE-BRIDGE-01, Q161-Q170
ColonnaTipoLogica
idBIGSERIALchiave primaria
function_idBIGINTfunzione
organizational_unit_idBIGINTufficio/UO/servizio
responsibility_roleVARCHAR(40)responsible/instructor/support/approver/informed
public_summaryTEXTtesto sintetico pubblico
setup_notesTEXTnote setup esteso
valid_fromDATEinizio validita
valid_toDATEfine validita
CREATE TABLE enti_unit_function_assignment (
  id BIGSERIAL PRIMARY KEY,
  function_id BIGINT NOT NULL REFERENCES enti_public_entity_function(id),
  organizational_unit_id BIGINT NOT NULL REFERENCES enti_publicentityorganizationalunit(id),
  responsibility_role VARCHAR(40) NOT NULL DEFAULT 'responsible',
  public_summary TEXT NOT NULL DEFAULT '',
  setup_notes TEXT NOT NULL DEFAULT '',
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  valid_from DATE NOT NULL DEFAULT CURRENT_DATE,
  valid_to DATE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (function_id, organizational_unit_id, responsibility_role),
  CHECK (responsibility_role IN ('responsible', 'instructor', 'support', 'approver', 'informed')),
  CHECK (valid_to IS NULL OR valid_to >= valid_from)
);
Routing

helpdesk_queue

Q004, Q027-Q028, Q034-Q036, Q161-Q170, QUEUE-BRIDGE-01
ColonnaTipoLogica
idBIGSERIALchiave primaria
institution_idBIGINTsetup helpdesk ente
organizational_unit_idBIGINTufficio responsabile in enti
primary_function_idBIGINTfunzione prevalente in enti
aoo_profile_idBIGINTAOO di riferimento facoltativa
codeVARCHAR(60)codice interno
public_labelVARCHAR(140)area/servizio leggibile
unit_snapshot_labelVARCHAR(180)label ufficio storicizzabile
function_snapshot_labelVARCHAR(180)label funzione storicizzabile
privacy_levelVARCHAR(32)ordinary/reserved/restricted
is_activeBOOLEANcoda attiva o storica
CREATE TABLE helpdesk_queue (
  id BIGSERIAL PRIMARY KEY,
  institution_id BIGINT NOT NULL REFERENCES helpdesk_institution(id),
  organizational_unit_id BIGINT NOT NULL REFERENCES enti_publicentityorganizationalunit(id),
  primary_function_id BIGINT NOT NULL REFERENCES enti_public_entity_function(id),
  aoo_profile_id BIGINT REFERENCES enti_aoo_profile(id),
  code VARCHAR(60) NOT NULL,
  public_label VARCHAR(140) NOT NULL,
  unit_snapshot_label VARCHAR(180) NOT NULL DEFAULT '',
  function_snapshot_label VARCHAR(180) NOT NULL DEFAULT '',
  privacy_level VARCHAR(32) NOT NULL DEFAULT 'ordinary',
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (institution_id, code),
  CHECK (privacy_level IN ('ordinary', 'reserved', 'restricted'))
);
Permessi

helpdesk_queue_membership

Q031-Q040, Q051-Q055, Q391-Q400, Q403-Q404
ColonnaTipoLogica
idBIGSERIALchiave primaria
queue_idBIGINTcoda
user_idBIGINTutente Django
roleVARCHAR(32)operator/responsible/administrator
can_take_chargeBOOLEANabilitazione presa in carico
can_answer_publicBOOLEANabilitazione messaggi pubblici
can_add_internal_noteBOOLEANabilitazione note interne
can_reassign_within_queueBOOLEANabilitazione riassegnazione interna
can_close_ordinaryBOOLEANabilitazione chiusura ordinaria
can_reopen_firstBOOLEANabilitazione prima riapertura
is_primary_responsibleBOOLEANresponsabile primario della coda
is_activeBOOLEANabilitazione corrente
CREATE TABLE helpdesk_queue_membership (
  id BIGSERIAL PRIMARY KEY,
  queue_id BIGINT NOT NULL REFERENCES helpdesk_queue(id),
  user_id BIGINT NOT NULL,
  role VARCHAR(32) NOT NULL,
  can_take_charge BOOLEAN NOT NULL DEFAULT TRUE,
  can_answer_public BOOLEAN NOT NULL DEFAULT TRUE,
  can_add_internal_note BOOLEAN NOT NULL DEFAULT TRUE,
  can_reassign_within_queue BOOLEAN NOT NULL DEFAULT FALSE,
  can_close_ordinary BOOLEAN NOT NULL DEFAULT TRUE,
  can_reopen_first BOOLEAN NOT NULL DEFAULT FALSE,
  is_primary_responsible BOOLEAN NOT NULL DEFAULT FALSE,
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (queue_id, user_id),
  CHECK (role IN ('operator', 'responsible', 'administrator')),
  CHECK (is_primary_responsible = FALSE OR role IN ('responsible', 'administrator'))
);

CREATE UNIQUE INDEX helpdesk_queue_one_primary_responsible
ON helpdesk_queue_membership(queue_id)
WHERE is_primary_responsible AND is_active;
Identita

helpdesk_requester

Q005, Q021-Q026
ColonnaTipoLogica
idBIGSERIALchiave primaria
requester_typeVARCHAR(40)studente/pubblico/fornitore/personale/etc
first_nameVARCHAR(100)nome
last_nameVARCHAR(100)cognome
emailVARCHAR(180)email dichiarata
phoneVARCHAR(80)telefono facoltativo
student_numberVARCHAR(80)matricola facoltativa
organization_nameVARCHAR(180)ente/fornitore/stakeholder
CREATE TABLE helpdesk_requester (
  id BIGSERIAL PRIMARY KEY,
  requester_type VARCHAR(40) NOT NULL,
  first_name VARCHAR(100) NOT NULL,
  last_name VARCHAR(100) NOT NULL,
  email VARCHAR(180) NOT NULL,
  phone VARCHAR(80) NOT NULL DEFAULT '',
  student_number VARCHAR(80) NOT NULL DEFAULT '',
  organization_name VARCHAR(180) NOT NULL DEFAULT '',
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CHECK (requester_type IN ('student', 'public', 'partner', 'supplier', 'staff', 'operator_on_behalf'))
);
Routing

helpdesk_category

Q012-Q013, Q041-Q047, Q151-Q160, Q231-Q234, Q236-Q250, QUEUE-BRIDGE-01
ColonnaTipoLogica
idBIGSERIALchiave primaria
institution_idBIGINTente
default_queue_idBIGINTcoda ordinaria
function_idBIGINTfunzione richiesta
codeVARCHAR(80)codice categoria
public_labelVARCHAR(160)label pubblica
modeVARCHAR(32)ticket/orientation/guided
is_activeBOOLEANpubblicabile
CREATE TABLE helpdesk_category (
  id BIGSERIAL PRIMARY KEY,
  institution_id BIGINT NOT NULL REFERENCES helpdesk_institution(id),
  default_queue_id BIGINT REFERENCES helpdesk_queue(id),
  function_id BIGINT REFERENCES enti_public_entity_function(id),
  code VARCHAR(80) NOT NULL,
  public_label VARCHAR(160) NOT NULL,
  mode VARCHAR(32) NOT NULL DEFAULT 'ticket',
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (institution_id, code),
  CHECK (mode IN ('ticket', 'orientation', 'guided'))
);
Routing

helpdesk_category_entry_rule

Q233-Q234, Q236-Q247
ColonnaTipoLogica
idBIGSERIALchiave primaria
category_idBIGINTcategoria
entry_modeVARCHAR(32)informative_first/ticket/orientation/pre_triage
allow_public_ticketBOOLEANabilita apertura pubblica ordinaria
require_sensitive_warningBOOLEANmostra warning dati sensibili
required_context_fieldsJSONBcampi progressivi per categoria
public_guidanceTEXTtesto informativo iniziale
CREATE TABLE helpdesk_category_entry_rule (
  id BIGSERIAL PRIMARY KEY,
  category_id BIGINT NOT NULL UNIQUE REFERENCES helpdesk_category(id),
  entry_mode VARCHAR(32) NOT NULL DEFAULT 'informative_first',
  allow_public_ticket BOOLEAN NOT NULL DEFAULT TRUE,
  require_sensitive_warning BOOLEAN NOT NULL DEFAULT FALSE,
  required_context_fields JSONB NOT NULL DEFAULT '[]'::jsonb,
  public_guidance TEXT NOT NULL DEFAULT '',
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CHECK (entry_mode IN ('informative_first', 'ticket', 'orientation', 'pre_triage')),
  CHECK (entry_mode <> 'orientation' OR allow_public_ticket = FALSE)
);
Workflow

helpdesk_category_workflow_policy

Q041, Q054-Q055, Q074-Q075, Q201-Q205, Q224-Q225
ColonnaTipoLogica
idBIGSERIALchiave primaria
category_idBIGINTcategoria
queue_change_modeVARCHAR(32)free/supervisor/admin
close_modeVARCHAR(32)operator/supervisor/admin
reopen_modeVARCHAR(32)operator/supervisor/admin
public_status_strategyVARCHAR(32)auto/manual/hidden
requires_official_answerBOOLEANchiusura legata a risposta ufficiale
CREATE TABLE helpdesk_category_workflow_policy (
  id BIGSERIAL PRIMARY KEY,
  category_id BIGINT NOT NULL REFERENCES helpdesk_category(id),
  queue_change_mode VARCHAR(32) NOT NULL DEFAULT 'supervisor',
  close_mode VARCHAR(32) NOT NULL DEFAULT 'operator',
  reopen_mode VARCHAR(32) NOT NULL DEFAULT 'supervisor',
  public_status_strategy VARCHAR(32) NOT NULL DEFAULT 'manual',
  requires_official_answer BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (category_id),
  CHECK (queue_change_mode IN ('free', 'supervisor', 'admin')),
  CHECK (close_mode IN ('operator', 'supervisor', 'admin')),
  CHECK (reopen_mode IN ('operator', 'supervisor', 'admin')),
  CHECK (public_status_strategy IN ('auto', 'manual', 'hidden'))
);
SLA

helpdesk_sla_policy

Q056-Q060, Q206-Q213
ColonnaTipoLogica
idBIGSERIALchiave primaria
category_idBIGINTcategoria facoltativa
queue_idBIGINTcoda facoltativa
take_charge_hoursINTEGERprima presa in carico
first_response_hoursINTEGERprima risposta utile
new_backlog_daysINTEGERnuova arretrata
user_reminder_daysINTEGERsollecito utente
calendar_modeVARCHAR(32)calendar/business/institutional
CREATE TABLE helpdesk_sla_policy (
  id BIGSERIAL PRIMARY KEY,
  category_id BIGINT REFERENCES helpdesk_category(id),
  queue_id BIGINT REFERENCES helpdesk_queue(id),
  take_charge_hours INTEGER NOT NULL DEFAULT 32,
  first_response_hours INTEGER NOT NULL DEFAULT 48,
  new_backlog_days INTEGER NOT NULL DEFAULT 4,
  user_reminder_days INTEGER NOT NULL DEFAULT 3,
  urgent_validation_hours INTEGER NOT NULL DEFAULT 24,
  calendar_mode VARCHAR(32) NOT NULL DEFAULT 'institutional',
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CHECK (category_id IS NOT NULL OR queue_id IS NOT NULL),
  CHECK (take_charge_hours > 0 AND first_response_hours > 0),
  CHECK (calendar_mode IN ('calendar', 'business', 'institutional'))
);
Core

helpdesk_ticket

Q006-Q008, Q014, Q021-Q027, Q050, Q061-Q065, Q421-Q426
ColonnaTipoLogica
idBIGSERIALchiave primaria
codeVARCHAR(24)HD-YYYY-NNNNNN
requester_idBIGINTrichiedente
category_idBIGINTcategoria
queue_idBIGINTcoda corrente
public_statusVARCHAR(40)stato visibile
internal_statusVARCHAR(40)stato interno
subjectVARCHAR(180)oggetto breve
descriptionTEXTdomanda iniziale
sensitivity_levelVARCHAR(32)ordinario/riservato/dati sensibili/segreto/etc
public_access_untilTIMESTAMPTZscadenza email+codice
public_lookup_enabledBOOLEANabilita consultazione pubblica sul singolo ticket
public_lookup_disabled_reasonTEXTmotivo minimizzato di disattivazione pubblica
CREATE TABLE helpdesk_ticket (
  id BIGSERIAL PRIMARY KEY,
  code VARCHAR(24) NOT NULL UNIQUE,
  institution_id BIGINT NOT NULL REFERENCES helpdesk_institution(id),
  requester_id BIGINT NOT NULL REFERENCES helpdesk_requester(id),
  category_id BIGINT NOT NULL REFERENCES helpdesk_category(id),
  queue_id BIGINT REFERENCES helpdesk_queue(id),
  public_status VARCHAR(40) NOT NULL DEFAULT 'received',
  internal_status VARCHAR(40) NOT NULL DEFAULT 'new',
  subject VARCHAR(180) NOT NULL,
  description TEXT NOT NULL,
  sensitivity_level VARCHAR(32) NOT NULL DEFAULT 'ordinary',
  opened_by_user_id BIGINT,
  opened_for_requester BOOLEAN NOT NULL DEFAULT FALSE,
  first_taken_at TIMESTAMPTZ,
  first_public_response_at TIMESTAMPTZ,
  closed_at TIMESTAMPTZ,
  reopened_count INTEGER NOT NULL DEFAULT 0,
  public_access_until TIMESTAMPTZ,
  public_lookup_enabled BOOLEAN NOT NULL DEFAULT TRUE,
  public_lookup_disabled_reason TEXT NOT NULL DEFAULT '',
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CHECK (public_status IN ('received', 'in_progress', 'waiting_user', 'answered', 'closed', 'reopened')),
  CHECK (internal_status IN ('new', 'to_assign', 'assigned', 'in_review', 'suspended', 'waiting_user', 'ready_to_answer', 'closed', 'archived')),
  CHECK (sensitivity_level IN ('ordinary', 'reserved', 'sensitive', 'protected_attachments', 'admin_only', 'secret'))
);
GDPR

helpdesk_sensitive_content_marker

Q077, Q217-Q219, Q234, Q247
ColonnaTipoLogica
idBIGSERIALchiave primaria
ticket_idBIGINTticket
sourceVARCHAR(32)user/automatic/operator/admin
classificationVARCHAR(32)reserved/sensitive/secret/etc
actionVARCHAR(32)warning/review/minimize/lock
statusVARCHAR(32)open/resolved/dismissed
reasonTEXTmotivazione minimizzata
CREATE TABLE helpdesk_sensitive_content_marker (
  id BIGSERIAL PRIMARY KEY,
  ticket_id BIGINT NOT NULL REFERENCES helpdesk_ticket(id),
  source VARCHAR(32) NOT NULL,
  classification VARCHAR(32) NOT NULL,
  action VARCHAR(32) NOT NULL DEFAULT 'review',
  status VARCHAR(32) NOT NULL DEFAULT 'open',
  reason TEXT NOT NULL DEFAULT '',
  created_by_user_id BIGINT,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  resolved_at TIMESTAMPTZ,
  CHECK (source IN ('user', 'automatic', 'operator', 'admin')),
  CHECK (classification IN ('reserved', 'sensitive', 'protected_attachments', 'admin_only', 'secret')),
  CHECK (action IN ('warning', 'review', 'minimize', 'lock')),
  CHECK (status IN ('open', 'resolved', 'dismissed'))
);
Routing

helpdesk_ticket_routing_snapshot

QUEUE-BRIDGE-01, Q050, Q061-Q065, Q161-Q170
ColonnaTipoLogica
idBIGSERIALchiave primaria
ticket_idBIGINTticket
queue_idBIGINTcoda corrente o iniziale
organizational_unit_idBIGINTufficio responsabile
function_idBIGINTfunzione richiesta
aoo_profile_idBIGINTAOO riferimento
public_area_labelVARCHAR(180)label pubblica ricevuta
snapshot_payloadJSONBetichette e contesto storico
CREATE TABLE helpdesk_ticket_routing_snapshot (
  id BIGSERIAL PRIMARY KEY,
  ticket_id BIGINT NOT NULL UNIQUE REFERENCES helpdesk_ticket(id),
  queue_id BIGINT REFERENCES helpdesk_queue(id),
  organizational_unit_id BIGINT REFERENCES enti_publicentityorganizationalunit(id),
  function_id BIGINT REFERENCES enti_public_entity_function(id),
  aoo_profile_id BIGINT REFERENCES enti_aoo_profile(id),
  public_area_label VARCHAR(180) NOT NULL,
  unit_label VARCHAR(180) NOT NULL DEFAULT '',
  function_label VARCHAR(180) NOT NULL DEFAULT '',
  aoo_label VARCHAR(180) NOT NULL DEFAULT '',
  snapshot_payload JSONB NOT NULL DEFAULT '{}'::jsonb,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX helpdesk_ticket_routing_snapshot_payload_gin
ON helpdesk_ticket_routing_snapshot USING GIN (snapshot_payload);
Workflow

helpdesk_ticket_assignment

Q027-Q028, Q031-Q036, Q051-Q055, Q401-Q410, Q421-Q423, Q427-Q430
ColonnaTipoLogica
idBIGSERIALchiave primaria
ticket_idBIGINTticket
queue_idBIGINTcoda
assigned_to_user_idBIGINToperatore o responsabile assegnato
assigned_by_user_idBIGINTchi assegna
previous_assignment_idBIGINTassegnazione precedente
assignment_kindVARCHAR(40)presa, riassegnazione, autoassegnazione, rilascio
reasonTEXTmotivo riassegnazione
started_atTIMESTAMPTZinizio assegnazione
ended_atTIMESTAMPTZfine assegnazione
ended_by_user_idBIGINTchi chiude assegnazione
end_reasonTEXTmotivazione chiusura assegnazione
is_activeBOOLEANassegnazione attiva
CREATE TABLE helpdesk_ticket_assignment (
  id BIGSERIAL PRIMARY KEY,
  ticket_id BIGINT NOT NULL REFERENCES helpdesk_ticket(id),
  queue_id BIGINT NOT NULL REFERENCES helpdesk_queue(id),
  assigned_to_user_id BIGINT NOT NULL,
  assigned_by_user_id BIGINT,
  previous_assignment_id BIGINT REFERENCES helpdesk_ticket_assignment(id) ON DELETE SET NULL,
  assignment_kind VARCHAR(40) NOT NULL DEFAULT 'self_take_charge',
  reason TEXT NOT NULL,
  started_at TIMESTAMPTZ NOT NULL,
  ended_at TIMESTAMPTZ,
  ended_by_user_id BIGINT,
  end_reason TEXT NOT NULL DEFAULT '',
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CHECK (assignment_kind IN (
    'self_take_charge',
    'responsible_assign',
    'auto_least_loaded',
    'auto_single_operator',
    'auto_responsible_overload',
    'release_to_responsible',
    'reassign_within_queue'
  )),
  CHECK (
    (is_active = TRUE AND ended_at IS NULL)
    OR (is_active = FALSE AND ended_at IS NOT NULL)
  )
);

CREATE UNIQUE INDEX helpdesk_ticket_one_active_assignment
ON helpdesk_ticket_assignment(ticket_id)
WHERE is_active;
Conversazione

helpdesk_public_message

Q014, Q019, Q052-Q054, Q081-Q090
ColonnaTipoLogica
idBIGSERIALchiave primaria
ticket_idBIGINTticket
author_kindVARCHAR(32)requester/operator/system
author_user_idBIGINTutente interno se presente
bodyTEXTtesto visibile
message_kindVARCHAR(32)question/reply/integration/official_answer
is_official_answerBOOLEANrisposta conclusiva
CREATE TABLE helpdesk_public_message (
  id BIGSERIAL PRIMARY KEY,
  ticket_id BIGINT NOT NULL REFERENCES helpdesk_ticket(id),
  author_kind VARCHAR(32) NOT NULL,
  author_user_id BIGINT,
  body TEXT NOT NULL,
  message_kind VARCHAR(32) NOT NULL DEFAULT 'reply',
  is_official_answer BOOLEAN NOT NULL DEFAULT FALSE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CHECK (author_kind IN ('requester', 'operator', 'system')),
  CHECK (message_kind IN ('question', 'reply', 'integration_request', 'official_answer', 'correction'))
);
Conversazione

helpdesk_reply_draft

Q080, Q203, Q249
ColonnaTipoLogica
idBIGSERIALchiave primaria
ticket_idBIGINTticket
author_user_idBIGINToperatore autore
reviewer_user_idBIGINTresponsabile facoltativo
bodyTEXTtesto bozza
statusVARCHAR(32)draft/proposed/approved/rejected/sent
official_message_idBIGINTmessaggio pubblico generato
CREATE TABLE helpdesk_reply_draft (
  id BIGSERIAL PRIMARY KEY,
  ticket_id BIGINT NOT NULL REFERENCES helpdesk_ticket(id),
  author_user_id BIGINT NOT NULL,
  reviewer_user_id BIGINT,
  body TEXT NOT NULL,
  status VARCHAR(32) NOT NULL DEFAULT 'draft',
  official_message_id BIGINT REFERENCES helpdesk_public_message(id),
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CHECK (status IN ('draft', 'proposed', 'approved', 'rejected', 'sent'))
);
Lavoro interno

helpdesk_internal_note

Q019-Q020, Q031-Q040, Q081-Q090
ColonnaTipoLogica
idBIGSERIALchiave primaria
ticket_idBIGINTticket
author_user_idBIGINToperatore
bodyTEXTnota
visibility_scopeVARCHAR(32)queue/supervisor/admin
CREATE TABLE helpdesk_internal_note (
  id BIGSERIAL PRIMARY KEY,
  ticket_id BIGINT NOT NULL REFERENCES helpdesk_ticket(id),
  author_user_id BIGINT NOT NULL,
  body TEXT NOT NULL,
  visibility_scope VARCHAR(32) NOT NULL DEFAULT 'queue',
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CHECK (visibility_scope IN ('queue', 'supervisor', 'admin'))
);
Documenti

helpdesk_attachment

Q011, Q016-Q018, Q063-Q064, Q081-Q090
ColonnaTipoLogica
idBIGSERIALchiave primaria
ticket_idBIGINTticket
uploaded_by_user_idBIGINToperatore o null futuro pubblico
file_nameVARCHAR(220)nome originale normalizzato
mime_typeVARCHAR(120)tipo dichiarato/rilevato
size_bytesBIGINTlimite 10 MB
visibility_scopeVARCHAR(32)public/internal/protected
security_statusVARCHAR(32)pending/safe/blocked
CREATE TABLE helpdesk_attachment (
  id BIGSERIAL PRIMARY KEY,
  ticket_id BIGINT NOT NULL REFERENCES helpdesk_ticket(id),
  uploaded_by_user_id BIGINT,
  file_name VARCHAR(220) NOT NULL,
  mime_type VARCHAR(120) NOT NULL,
  size_bytes BIGINT NOT NULL,
  storage_key VARCHAR(260) NOT NULL,
  visibility_scope VARCHAR(32) NOT NULL DEFAULT 'internal',
  security_status VARCHAR(32) NOT NULL DEFAULT 'pending',
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CHECK (size_bytes > 0 AND size_bytes <= 10485760),
  CHECK (visibility_scope IN ('public', 'internal', 'protected')),
  CHECK (security_status IN ('pending', 'safe', 'blocked'))
);
GDPR

helpdesk_privacy_consent_snapshot

Q009-Q010, Q021, Q029-Q030
ColonnaTipoLogica
idBIGSERIALchiave primaria
ticket_idBIGINTticket
privacy_versionVARCHAR(80)versione testo
privacy_textTEXTtesto snapshot
accepted_privacy_atTIMESTAMPTZpresa visione
accepted_processing_atTIMESTAMPTZconsenso/invio richiesta
ip_truncatedVARCHAR(64)dato tecnico minimizzato
CREATE TABLE helpdesk_privacy_consent_snapshot (
  id BIGSERIAL PRIMARY KEY,
  ticket_id BIGINT NOT NULL UNIQUE REFERENCES helpdesk_ticket(id),
  privacy_version VARCHAR(80) NOT NULL,
  privacy_text TEXT NOT NULL,
  accepted_privacy_at TIMESTAMPTZ NOT NULL,
  accepted_processing_at TIMESTAMPTZ NOT NULL,
  ip_truncated VARCHAR(64) NOT NULL DEFAULT '',
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
Notifiche

helpdesk_receipt_snapshot

Q015, Q066-Q070, Q222-Q223
ColonnaTipoLogica
idBIGSERIALchiave primaria
ticket_idBIGINTticket
template_versionVARCHAR(80)versione template
recipient_emailVARCHAR(180)destinatario
subjectVARCHAR(180)oggetto ricevuta
body_textTEXTtesto generato
delivery_statusVARCHAR(32)generated/sent/deferred/failed
CREATE TABLE helpdesk_receipt_snapshot (
  id BIGSERIAL PRIMARY KEY,
  ticket_id BIGINT NOT NULL REFERENCES helpdesk_ticket(id),
  template_version VARCHAR(80) NOT NULL,
  recipient_email VARCHAR(180) NOT NULL,
  subject VARCHAR(180) NOT NULL,
  body_text TEXT NOT NULL,
  delivery_status VARCHAR(32) NOT NULL DEFAULT 'generated',
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CHECK (delivery_status IN ('generated', 'sent', 'deferred', 'failed'))
);
Notifiche

helpdesk_service_mailbox

Q079, Q248
ColonnaTipoLogica
idBIGSERIALchiave primaria
institution_idBIGINTente/setup
queue_idBIGINTcoda facoltativa
category_idBIGINTcategoria facoltativa
addressVARCHAR(180)indirizzo mailbox
mailbox_kindVARCHAR(32)general/service/error
is_publicly_shownBOOLEANvisibile in ricevuta o UI pubblica
is_activeBOOLEANabilitata
CREATE TABLE helpdesk_service_mailbox (
  id BIGSERIAL PRIMARY KEY,
  institution_id BIGINT NOT NULL REFERENCES helpdesk_institution(id),
  queue_id BIGINT REFERENCES helpdesk_queue(id),
  category_id BIGINT REFERENCES helpdesk_category(id),
  address VARCHAR(180) NOT NULL,
  display_label VARCHAR(160) NOT NULL DEFAULT '',
  mailbox_kind VARCHAR(32) NOT NULL DEFAULT 'service',
  is_publicly_shown BOOLEAN NOT NULL DEFAULT FALSE,
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CHECK (mailbox_kind IN ('general', 'service', 'error'))
);
Audit

helpdesk_audit_event

Q019, Q024, Q050, Q065, Q121-Q130, Q421-Q430
ColonnaTipoLogica
idBIGSERIALchiave primaria
ticket_idBIGINTticket
actor_user_idBIGINToperatore o sistema
event_typeVARCHAR(80)tipo evento
payloadJSONBdettaglio minimizzato
created_atTIMESTAMPTZtimestamp evento
CREATE TABLE helpdesk_audit_event (
  id BIGSERIAL PRIMARY KEY,
  ticket_id BIGINT NOT NULL REFERENCES helpdesk_ticket(id),
  actor_user_id BIGINT,
  event_type VARCHAR(80) NOT NULL,
  payload JSONB NOT NULL DEFAULT '{}'::jsonb,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX helpdesk_audit_event_payload_gin
ON helpdesk_audit_event USING GIN (payload);
Sicurezza

helpdesk_public_access_log

Q025, Q061, Q065, Q221, Q266-Q305, Q331-Q340
ColonnaTipoLogica
idBIGSERIALchiave primaria
ticket_idBIGINTticket consultato
email_hashCHAR(64)hash email
code_hashCHAR(64)hash codice
surname_hashCHAR(64)hash cognome
ip_truncatedVARCHAR(64)IP minimizzato
user_agent_reducedVARCHAR(180)UA ridotto
public_view_modeVARCHAR(32)active/expired_minimal
expires_atTIMESTAMPTZscadenza retention/log
CREATE TABLE helpdesk_public_access_log (
  id BIGSERIAL PRIMARY KEY,
  ticket_id BIGINT NOT NULL REFERENCES helpdesk_ticket(id),
  email_hash CHAR(64) NOT NULL,
  code_hash CHAR(64) NOT NULL,
  surname_hash CHAR(64) NOT NULL,
  ip_truncated VARCHAR(64) NOT NULL DEFAULT '',
  user_agent_reduced VARCHAR(180) NOT NULL DEFAULT '',
  public_view_mode VARCHAR(32) NOT NULL DEFAULT 'active',
  expires_at TIMESTAMPTZ NOT NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CHECK (public_view_mode IN ('active', 'expired_minimal'))
);
Sicurezza

helpdesk_public_access_attempt

Q269-Q270, Q284-Q285, Q297-Q300, Q302-Q303, Q331-Q340
ColonnaTipoLogica
idBIGSERIALchiave primaria
ticket_idBIGINTticket se risolto senza esporre risposta al pubblico
email_hashCHAR(64)hash email normalizzata
code_hashCHAR(64)hash codice normalizzato
surname_hashCHAR(64)hash cognome normalizzato
ip_truncatedVARCHAR(64)IP minimizzato
user_agent_reducedVARCHAR(180)UA ridotto
attempt_resultVARCHAR(32)failed/expired/rate_limited/locked
lock_levelSMALLINT0/1/2/3
locked_untilTIMESTAMPTZfine blocco se automatico
expires_atTIMESTAMPTZscadenza retention/log
CREATE TABLE helpdesk_public_access_attempt (
  id BIGSERIAL PRIMARY KEY,
  ticket_id BIGINT REFERENCES helpdesk_ticket(id),
  email_hash CHAR(64) NOT NULL,
  code_hash CHAR(64) NOT NULL,
  surname_hash CHAR(64) NOT NULL,
  ip_truncated VARCHAR(64) NOT NULL DEFAULT '',
  user_agent_reduced VARCHAR(180) NOT NULL DEFAULT '',
  attempt_result VARCHAR(32) NOT NULL,
  lock_level SMALLINT NOT NULL DEFAULT 0,
  locked_until TIMESTAMPTZ,
  expires_at TIMESTAMPTZ NOT NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CHECK (attempt_result IN ('failed', 'expired', 'rate_limited', 'locked')),
  CHECK (lock_level >= 0 AND lock_level <= 3)
);
SLA

helpdesk_escalation_event

Q048-Q049, Q056-Q060, Q191-Q198
ColonnaTipoLogica
idBIGSERIALchiave primaria
ticket_idBIGINTticket
levelVARCHAR(32)supervisor/admin/super_admin
reasonVARCHAR(80)new_backlog/waiting_user/urgent/etc
statusVARCHAR(32)open/ack/done
assigned_to_user_idBIGINTdestinatario interno
CREATE TABLE helpdesk_escalation_event (
  id BIGSERIAL PRIMARY KEY,
  ticket_id BIGINT NOT NULL REFERENCES helpdesk_ticket(id),
  level VARCHAR(32) NOT NULL,
  reason VARCHAR(80) NOT NULL,
  status VARCHAR(32) NOT NULL DEFAULT 'open',
  assigned_to_user_id BIGINT,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  closed_at TIMESTAMPTZ,
  CHECK (level IN ('supervisor', 'helpdesk_admin', 'super_admin')),
  CHECK (status IN ('open', 'acknowledged', 'done'))
);