Formato di esportazione
Che cosa contiene l'archivio dei dati dello spazio di lavoro che un titolare scarica da CantiereGo: ogni file, ogni campo e lo schema JSON che lo descrive. È il registro aggiornato delle strutture e dei formati dei dati esportabili previsto dall'articolo 26 del Regolamento (UE) 2023/2854 (Data Act), per chi passa a un altro fornitore o vuole una copia completa dei propri dati.
L'archivio è un file ZIP. Contiene manifest.json, che lo descrive; tredici file JSON, uno per famiglia di dati, completi e autorevoli; anagrafiche.xlsx, l'anagrafica attiva nel formato del modello di importazione; e cinque cartelle: schemas/, presence/, timesheets/, photos/ e documents/.
Nei file JSON, in UTF-8, le chiavi sono in inglese e i valori sono come l'app li registra: gli identificativi sono UUID; gli istanti sono date e ore ISO 8601 con lo scarto dal tempo universale, i giorni AAAA-MM-GG, le ore del giorno HH:MM:SS; le scelte sono codici, che ogni schema elenca; un importo o una durata con i decimali è scritto come testo; null vuol dire che il dato non c'è. I testi scritti dall'ufficio restano come sono stati scritti.
L'ultima sezione, «Giurisdizione e accesso ai dati», dà le informazioni dell'articolo 28 dello stesso Regolamento: dove si trova l'infrastruttura con cui CantiereGo tratta i dati e quali misure tecniche, organizzative e contrattuali A176lab adotta contro l'accesso ai dati, o il loro trasferimento, da parte di autorità di paesi terzi.
Il formato e la sua versione
Il campo format del manifest dice il nome e la versione del formato: cantierego-workspace-export per l'archivio dello spazio di lavoro e cantierego-medical-export per l'archivio sanitario, entrambi alla versione 1.0.0, quella che questa pagina descrive.
La versione è semantica. Un campo o un file nuovo e facoltativo fa salire la versione minore (1.1.0); un campo tolto, rinominato o di tipo diverso, o un significato cambiato, fa una nuova versione maggiore (2.0.0), i cui schemi sono pubblicati in una cartella nuova, /formato-esportazione/2/. Gli schemi di questa pagina, sotto /formato-esportazione/1/, descrivono l'ultima versione minore della versione maggiore 1.
Ogni archivio porta con sé, nella cartella schemas/, gli schemi della versione con cui è stato scritto: il contratto viaggia con i dati.
Come si scarica, e per quanto tempo
Un titolare chiede l'archivio dalle impostazioni dello spazio di lavoro (Impostazioni › Azienda). L'app lo prepara in background e lo elenca quando è pronto; se ne prepara uno al giorno per spazio di lavoro, uno alla volta. Il file di ciascun archivio si scarica per 14 giorni dalla preparazione, e comunque non oltre l'inizio della cancellazione dello spazio di lavoro. Le stesse operazioni si fanno dall'interfaccia di programmazione dell'app, con le credenziali dell'account: la descrive il documento OpenAPI pubblicato all'indirizzo https://app.cantierego.it/api/v1/openapi.json.
Lo spazio di lavoro si chiude dalle stesse impostazioni. Dopo la chiusura i titolari possono ancora leggerlo, esportarlo e riaprirlo per almeno 30 giorni: trascorsi 30 giorni dalla chiusura, la cancellazione comincia al primo passaggio notturno e si conclude entro 40 giorni dalla chiusura. Un blocco legale sulle presenze o un blocco su un documento ferma la cancellazione e conserva ciò che trattiene.
Uno spazio di lavoro chiuso prima che valesse questa regola conserva la data che i suoi titolari hanno ricevuto alla chiusura: la sua cancellazione può cominciare 21 giorni dopo la chiusura.
I file dell'archivio
manifest.json
Il file da leggere per primo, scritto per ultimo: il formato e la sua versione, lo spazio di lavoro, l'istante e il giorno in cui l'archivio è stato scritto, quante righe ha ogni file JSON e quanti file ha ogni cartella, quanto è stato trattenuto per riservatezza sanitaria e quali file mancavano.
Sugli originali dei documenti fanno fede missing.originals e missing.originals_reason: un originale perso, o la lettura dei documenti sospesa per un incidente, lascia una revisione il cui campo file nomina un file che l'archivio non contiene.
Schema JSON: manifest.schema.json
| Campo | Significato |
|---|---|
format | Il formato dell'archivio. |
format.name | Nome del formato. |
format.version | Versione del formato, semantica: una nuova voce facoltativa è una minore, una voce tolta, rinominata o di tipo diverso è una nuova maggiore. |
export_id | Identificativo dell'esportazione. |
workspace | Lo spazio esportato. |
workspace.id | Identificativo dello spazio. |
workspace.name | Nome. |
workspace.slug | Nome breve nell'indirizzo dell'app. |
workspace.legal_name | Ragione sociale. |
generated_at | Istante in cui l'archivio è stato scritto. |
day | Il giorno dello spazio in cui l'archivio è stato scritto. |
timezone | Il fuso orario dello spazio. |
app_version | La versione dell'app che ha scritto l'archivio. |
read_mode | Come sono state lette le famiglie di dati: una dopo l'altra, a pagine. |
read_mode_note | Che cosa comporta la lettura sequenziale. |
read_mode_note.it | Il testo in italiano. |
read_mode_note.en | Il testo in inglese. |
files | Per ogni file JSON le righe scritte, per ogni cartella i file. |
files.workspace.json | Righe in workspace.json: sempre 1. |
files.members.json | Membri più inviti in members.json. |
files.employers.json | Imprese in employers.json. |
files.sites.json | Cantieri in sites.json. |
files.workers.json | Lavoratori in workers.json. |
files.vehicles.json | Mezzi in vehicles.json. |
files.documents.json | Documenti in documents.json. |
files.attendance_events.json | Timbrature in attendance_events.json. |
files.presence.json | Intervalli in presence.json. |
files.timesheet_sends.json | Invii in timesheet_sends.json. |
files.imports.json | Importazioni in imports.json. |
files.consents.json | Prese visione in consents.json. |
files.audit.json | Righe in audit.json. |
files.anagrafiche.xlsx | Righe dei fogli di anagrafiche.xlsx, le intestazioni escluse: l'anagrafica attiva nelle colonne del modello di importazione. |
files.schemas/ | Schemi nella cartella schemas/. |
files.presence/ | Fogli mensili nella cartella presence/. |
files.timesheets/ | File nella cartella timesheets/. |
files.photos/ | Foto nella cartella photos/. |
files.documents/ | Originali nella cartella documents/. |
withheld | Quanto l'archivio non contiene per riservatezza sanitaria. |
withheld.medical | Totale dei documenti, esiti e giudizi trattenuti. |
withheld.decisions | Esiti sanitari trattenuti. |
withheld.documents | Documenti sanitari trattenuti. |
withheld.facts | Giudizi di idoneità trattenuti perché selezionano un esito. |
withheld.audit_rows | Righe del registro tolte o mascherate per riservatezza sanitaria. |
withheld.by_employer | Il totale trattenuto per impresa a cui risponde — un giudizio di idoneità e un esito, l'impresa per cui l'esito è stato registrato, anche se il lavoratore è poi passato a un'altra —: la chiave è l'identificativo dell'impresa, o none. |
withheld.note | Che cosa è trattenuto e dove si trova. |
withheld.note.it | Il testo in italiano. |
withheld.note.en | Il testo in inglese. |
missing | I file che l'archivio avrebbe dovuto contenere e non ha trovato. |
missing.photos | Lavoratori la cui foto mancava. |
missing.originals | Revisioni il cui originale mancava. |
missing.timesheets | Percorsi dei file di invio che mancavano. |
missing.originals_reason | Perché mancano gli originali: null se ne manca solo qualcuno che l'archivio dei file non aveva più; document_reads_disabled se la lettura dei documenti era sospesa per un incidente e nessun originale è stato letto, tutti elencati in originals. |
workspace.json
Un oggetto: l'anagrafica dello spazio di lavoro e la sua sede, le impostazioni delle presenze e della conformità, il suo stato (sospensione, chiusura, da quando la cancellazione può cominciare), le regole di conservazione dei documenti in ogni loro versione e le impostazioni dei canali di chat.
Schema JSON: workspace.schema.json
| Campo | Significato |
|---|---|
id | Identificativo dello spazio di lavoro. |
slug | Nome breve dello spazio nell'indirizzo dell'app (/w/<slug>). |
name | Nome dello spazio di lavoro. |
legal_name | Ragione sociale. |
vat_number | Partita IVA. |
tax_code | Codice fiscale dell'azienda. |
sdi_code | Codice destinatario SdI per la fatturazione elettronica. |
pec | Indirizzo di posta elettronica certificata. |
address | Sede dell'azienda. |
address.street | Via e numero civico. |
address.cap | Codice di avviamento postale, cinque cifre. |
address.city | Comune. |
address.province | Sigla della provincia, due lettere. |
address.country | Paese, codice ISO 3166-1 a due lettere (IT se non indicato). |
phone | Telefono. |
timezone | Fuso orario IANA in cui lo spazio legge i suoi giorni (per esempio Europe/Rome). |
settings | Impostazioni dello spazio per sezione: un oggetto vuoto finché l'ufficio non ne ha salvata una; ogni sezione presente è scritta intera. |
settings.attendance | Le impostazioni delle presenze, salvate dall'ufficio. |
settings.attendance.red_badge_policy | Una timbratura in autonomia con il badge rosso: registrata o rifiutata. |
settings.attendance.work_start | Inizio dell'orario di lavoro (ore locali). |
settings.attendance.work_end | Fine dell'orario di lavoro (ore locali). |
settings.attendance.break_minutes | Minuti di pausa. |
settings.attendance.retention_years | Anni di conservazione delle presenze dalla fine del rapporto. |
settings.attendance.legal_hold | Se la cancellazione delle presenze è sospesa per un obbligo di legge. |
settings.attendance.consultant | Il consulente del lavoro a cui si inviano i fogli delle ore, o null. |
settings.attendance.consultant.name | Nome. |
settings.attendance.consultant.email | Email. |
settings.attendance.consultant.note | Nota. |
settings.compliance | La politica della conformità, salvata da un titolare. |
settings.compliance.strict | Se i requisiti mancanti rendono rosso il badge invece di restare avvisi. |
created_by | L'account che ha creato lo spazio. |
created_at | Istante di creazione. |
updated_at | Istante dell'ultima modifica. |
suspended_at | Istante della sospensione decisa dalla piattaforma. |
suspended_reason | Il motivo della sospensione comunicato ai titolari. |
closed_at | Istante della chiusura. |
closed_by | L'account del titolare che ha chiuso lo spazio. |
closed_source | Chi ha chiuso lo spazio: un titolare o la piattaforma. |
purge_after | Istante dal quale la cancellazione dello spazio chiuso può cominciare. |
retention_policies | Le regole di conservazione dei documenti, ogni versione scritta dall'ufficio. |
retention_policies[].id | Identificativo della regola. |
retention_policies[].version | Versione della regola per la sua categoria. |
retention_policies[].employer_id | L'impresa, per una regola dei documenti sanitari; null altrimenti. |
retention_policies[].category | Categoria di documenti: ordinari, riservati, sanitari, dei mezzi. |
retention_policies[].purpose | Finalità della conservazione. |
retention_policies[].trigger | Evento da cui decorre il termine: fine del rapporto del lavoratore, chiusura del cantiere, archiviazione dell'impresa, fine del noleggio, archiviazione del documento. |
retention_policies[].superseded_trigger | Per una revisione sostituita: il termine decorre dalla sostituzione, o come per la revisione corrente. |
retention_policies[].fallback | Evento di riserva quando quello principale non arriva. |
retention_policies[].retention_months | Mesi di conservazione dopo l'evento. |
retention_policies[].justification_ref | Riferimento normativo o contrattuale. |
retention_policies[].review_on | Giorno in cui la regola va rivista. |
retention_policies[].created_by | L'account che l'ha scritta. |
retention_policies[].created_at | Istante di creazione. |
bot_settings | I canali di chat dello spazio e gli orari dei due avvisi programmati; null se non sono mai stati impostati. |
bot_settings.telegram_enabled | Se il canale Telegram è aperto per lo spazio. |
bot_settings.whatsapp_enabled | Se il canale WhatsApp è aperto per lo spazio. |
bot_settings.forgotten_exit_at | Ora dell'avviso di uscita dimenticata. |
bot_settings.office_summary_at | Ora del riepilogo per l'ufficio. |
bot_settings.updated_by | L'account che li ha impostati. |
bot_settings.updated_at | Istante dell'ultima modifica. |
members.json
Un oggetto con cinque elenchi: i membri, attuali e passati, con il loro ruolo; gli inviti, accettati, scaduti o in attesa, mai il loro link; le chat Telegram o WhatsApp che i membri hanno collegato allo spazio; gli avvisi che hanno chiesto; ogni concessione o ritiro di un avviso.
Schema JSON: members.schema.json
| Campo | Significato |
|---|---|
members | I membri, attivi e passati. |
members[].user_id | Identificativo dell'account. |
members[].full_name | Nome e cognome dell'account. |
members[].email | Email dell'account. |
members[].phone | Telefono dell'account, in formato E.164. |
members[].role | Ruolo nello spazio. |
members[].status | Stato dell'appartenenza. |
members[].created_at | Istante dell'ingresso nello spazio. |
members[].updated_at | Istante dell'ultima modifica. |
members[].ended_at | Istante della fine dell'appartenenza. |
invitations | Gli inviti, accettati, scaduti o in attesa. |
invitations[].id | Identificativo dell'invito. |
invitations[].role | Ruolo offerto. |
invitations[].email | Email a cui l'invito è stato spedito. |
invitations[].phone | Telefono a cui l'invito è stato spedito. |
invitations[].worker_id | Il lavoratore a cui l'invito collega l'account. |
invitations[].expires_at | Istante di scadenza dell'invito. |
invitations[].accepted_at | Istante dell'accettazione. |
invitations[].accepted_user_id | L'account che ha accettato. |
invitations[].invited_by | L'account che ha invitato. |
invitations[].created_at | Istante dell'invio. |
bot_links | Le chat Telegram o WhatsApp che i membri hanno collegato allo spazio. |
bot_links[].id | Identificativo del collegamento. |
bot_links[].user_id | L'account del membro. |
bot_links[].provider | Il canale. |
bot_links[].member_enabled | Se il membro usa il canale in questo spazio. |
bot_links[].office_enabled | Se l'ufficio lascia aperto il canale al membro. |
bot_links[].worker_id | Il lavoratore a cui la chat è legata, se c'è. |
bot_links[].notice_version | Versione dell'informativa del canale accettata. |
bot_links[].plan_held_at | Istante della sospensione per i limiti del piano. |
bot_links[].created_at | Istante del collegamento. |
bot_links[].updated_at | Istante dell'ultima modifica. |
bot_subscriptions | Gli avvisi che i membri hanno chiesto nello spazio, concessi o no. |
bot_subscriptions[].id | Identificativo dell'iscrizione. |
bot_subscriptions[].user_id | L'account del membro. |
bot_subscriptions[].provider | Il canale. |
bot_subscriptions[].purpose | L'avviso: badge da guardare, documenti in scadenza, uscita dimenticata, riepilogo per l'ufficio. |
bot_subscriptions[].scope_id | Il collegamento della chat allo spazio. |
bot_subscriptions[].granted | Se l'avviso è concesso. |
bot_subscriptions[].notice_version | Versione dell'informativa accettata. |
bot_subscriptions[].consent_event_id | La registrazione del consenso. |
bot_subscriptions[].created_at | Istante di creazione. |
bot_subscriptions[].updated_at | Istante dell'ultima modifica. |
bot_consents | Ogni concessione o ritiro di un avviso nello spazio. |
bot_consents[].id | Identificativo della registrazione. |
bot_consents[].scope_id | Il collegamento della chat allo spazio. |
bot_consents[].user_id | L'account del membro. |
bot_consents[].provider | Il canale. |
bot_consents[].action | Concessione o ritiro dell'avviso. |
bot_consents[].purpose | L'avviso. |
bot_consents[].notice_version | Versione dell'informativa. |
bot_consents[].granted | Se l'avviso è stato concesso. |
bot_consents[].source | Dove è stato espresso: nell'app, nella chat privata, nella migrazione. |
bot_consents[].actor_user_id | L'account che l'ha registrato, se c'è. |
bot_consents[].created_at | Istante. |
employers.json
Un elenco, un oggetto per impresa, archiviate comprese: l'impresa dello spazio, le imprese esecutrici e i lavoratori autonomi, con la patente a crediti, l'attestazione SOA e il DURC come l'ufficio li ha registrati, il blocco, l'istruzione sui documenti riservati e sanitari e chi l'impresa ha nominato con l'accesso nominativo ai suoi giudizi di idoneità: la nomina, mai un giudizio.
Schema JSON: employers.schema.json
| Campo | Significato |
|---|---|
id | Identificativo dell'impresa. |
kind | Impresa o lavoratore autonomo. |
is_own | true per l'impresa dello spazio stesso. |
legal_name | Ragione sociale, o nome e cognome del lavoratore autonomo. |
vat_number | Partita IVA. |
tax_code | Codice fiscale. |
address | Sede. |
address.street | Via e numero civico. |
address.cap | Codice di avviamento postale, cinque cifre. |
address.city | Comune. |
address.province | Sigla della provincia, due lettere. |
address.country | Paese, codice ISO 3166-1 a due lettere (IT se non indicato). |
email | Email. |
phone | Telefono. |
notes | Note dell'ufficio. |
patente_status | Stato della patente a crediti come registrato dall'ufficio. |
patente_exempt_reason | Motivo dell'esenzione: attestazione SOA di classifica III o superiore, titolo equivalente di un altro Stato dell'Unione, attività non soggetta. |
patente_credits | Crediti della patente. |
patente_number | Numero della patente. |
patente_checked_on | Giorno in cui l'ufficio ha verificato la patente. |
patente_exception_until | Fine della deroga sui crediti. |
patente_exception_reason | Motivo della deroga sui crediti. |
patente_suspended_until | Fine della sospensione della patente, quando l'ufficio l'ha registrata (solo con stato suspended). |
soa_class | Classifica dell'attestazione SOA che fonda l'esenzione (solo con motivo soa_iii). |
soa_valid_until | Scadenza dell'attestazione SOA (solo con motivo soa_iii). |
durc_status | Esito del DURC come registrato dall'ufficio. |
durc_valid_until | Scadenza del DURC. |
durc_document_id | Il documento DURC che sostiene i dati. |
durc_revision_id | La revisione del documento DURC citata. |
durc_review_id | La revisione dell'ufficio che ha applicato il DURC. |
blocked_at | Istante del blocco dell'impresa da parte dell'ufficio. |
blocked_reason | Motivo del blocco. |
blocked_by | L'account che ha bloccato l'impresa. |
deleted_at | Istante dell'archiviazione. |
plan_held_at | Istante della sospensione per i limiti del piano. |
created_by | L'account che l'ha creata. |
created_at | Istante di creazione. |
updated_at | Istante dell'ultima modifica. |
document_policy | L'istruzione dell'impresa sui suoi documenti riservati e sanitari: finalità, base e attivazione; null se non c'è. |
document_policy.purpose_ref | Riferimento della finalità. |
document_policy.basis_ref | Riferimento della base giuridica. |
document_policy.controller_ack | Se il titolare ha confermato l'istruzione. |
document_policy.outcome_aware_since | Da quando l'app registra gli esiti dei giudizi di idoneità. |
document_policy.terms_version | Versione delle condizioni accettate. |
document_policy.uploads_allowed | Se i documenti sanitari si possono caricare. |
document_policy.review_on | Giorno in cui l'istruzione va rivista. |
document_policy.updated_by | L'account che l'ha scritta. |
document_policy.created_at | Istante di creazione. |
document_policy.updated_at | Istante dell'ultima modifica. |
medical_access | Chi l'impresa ha nominato per i suoi giudizi di idoneità, nomine ritirate comprese: la nomina, mai un giudizio. |
medical_access[].id | Identificativo della nomina. |
medical_access[].user_id | L'account nominato. |
medical_access[].can_write | Se può anche registrare i giudizi. |
medical_access[].appointment_ref | Riferimento dell'atto di nomina. |
medical_access[].granted_by | L'account che ha nominato. |
medical_access[].granted_at | Istante della nomina. |
medical_access[].revoked_by | L'account che ha ritirato la nomina. |
medical_access[].revoked_at | Istante del ritiro. |
sites.json
Un elenco, un oggetto per cantiere, archiviati compresi: i dati del cantiere e il suo orario, le imprese che vi partecipano, le assegnazioni dei lavoratori, passate comprese, i collegamenti dei tablet delegati e i codici di accesso ispettivo con le sessioni aperte con ciascuno.
Il codice di timbratura del cantiere, il token di un tablet e il codice ispettivo sono credenziali e non ci sono. Una sessione ispettiva porta l'indirizzo, mascherato, e il browser, come l'ufficio li legge nel registro degli usi del codice.
Schema JSON: sites.schema.json
| Campo | Significato |
|---|---|
id | Identificativo del cantiere. |
code | Codice del cantiere, immutabile. |
name | Nome del cantiere. |
address | Indirizzo. |
city | Comune. |
province | Sigla della provincia. |
postal_code | Codice di avviamento postale. |
client_name | Committente. |
client_tax_code | Codice fiscale o partita IVA del committente. |
works_director | Direttore dei lavori. |
safety_coordinator | Coordinatore per la sicurezza. |
starts_on | Inizio dei lavori. |
planned_end_on | Fine prevista. |
actual_end_on | Fine effettiva. |
contract_value | Importo dei lavori, in euro, scritto come testo. |
status | Stato del cantiere. |
geo_lat | Latitudine del recinto geografico, come testo. |
geo_lng | Longitudine del recinto geografico, come testo. |
geo_radius_m | Raggio del recinto geografico, in metri. |
geofence_enabled | Se le timbrature in autonomia chiedono la posizione. |
work_starts_at | Inizio dell'orario di lavoro (ore locali); null: quello dello spazio. |
work_ends_at | Fine dell'orario di lavoro (ore locali); null: quello dello spazio. |
break_minutes | Minuti di pausa; null: quelli dello spazio. |
notes | Note dell'ufficio. |
deleted_at | Istante dell'archiviazione. |
plan_held_at | Istante della sospensione per i limiti del piano. |
created_by | L'account che l'ha creato. |
created_at | Istante di creazione. |
updated_at | Istante dell'ultima modifica. |
employers | Le imprese che partecipano al cantiere. |
employers[].id | Identificativo della partecipazione. |
employers[].employer_id | L'impresa. |
employers[].role | Ruolo: appaltatrice, subappaltatrice o lavoratore autonomo. |
employers[].subcontract_authorization | Estremi dell'autorizzazione al subappalto. |
employers[].subcontract_authorized_on | Giorno dell'autorizzazione al subappalto. |
employers[].created_by | L'account che l'ha registrata. |
employers[].created_at | Istante di creazione. |
employers[].updated_at | Istante dell'ultima modifica. |
assignments | Le assegnazioni dei lavoratori, passate comprese. |
assignments[].id | Identificativo dell'assegnazione. |
assignments[].worker_id | Il lavoratore. |
assignments[].role | Mansione nel cantiere. |
assignments[].starts_on | Inizio dell'assegnazione. |
assignments[].ends_on | Fine dell'assegnazione. |
assignments[].accredited | Se il lavoratore è accreditato nel cantiere. |
assignments[].accredited_at | Istante dell'accreditamento. |
assignments[].accredited_by | L'account che ha accreditato il lavoratore. |
assignments[].created_by | L'account che l'ha registrata. |
assignments[].created_at | Istante di creazione. |
assignments[].updated_at | Istante dell'ultima modifica. |
gate_links | I collegamenti dei tablet delegati del cantiere; il loro token non c'è. |
gate_links[].id | Identificativo del collegamento. |
gate_links[].label | Nome del tablet. |
gate_links[].expires_at | Istante di scadenza. |
gate_links[].revoked_at | Istante della revoca. |
gate_links[].revoked_by | L'account che l'ha revocato. |
gate_links[].created_by | L'account che l'ha creato. |
gate_links[].last_used_at | Istante dell'ultimo uso. |
gate_links[].use_count | Usi. |
gate_links[].created_at | Istante di creazione. |
gate_links[].updated_at | Istante dell'ultima modifica. |
access_grants | I codici di accesso ispettivo del cantiere, con il registro dei loro usi; il codice non c'è, né alcuna sua parte. |
access_grants[].id | Identificativo del codice. |
access_grants[].kind | Per chi: coordinatore per la sicurezza, ispettorato del lavoro, ASL, committente, altro. |
access_grants[].label | Il nome del titolare, obbligatorio per altro. |
access_grants[].legacy | Se viene dal sistema precedente. |
access_grants[].expires_at | Istante di scadenza. |
access_grants[].revoked_at | Istante della revoca. |
access_grants[].revoked_by | L'account che l'ha revocato. |
access_grants[].created_by | L'account che l'ha creato. |
access_grants[].use_count | Sessioni aperte con il codice. |
access_grants[].last_used_at | Istante dell'ultimo uso. |
access_grants[].created_at | Istante di creazione. |
access_grants[].updated_at | Istante dell'ultima modifica. |
access_grants[].uses | Le sessioni aperte con il codice. |
access_grants[].uses[].id | Identificativo della sessione. |
access_grants[].uses[].started_at | Istante di apertura. |
access_grants[].uses[].expires_at | Istante di scadenza. |
access_grants[].uses[].last_seen_at | Istante dell'ultima lettura. |
access_grants[].uses[].ended_at | Istante di chiusura. |
access_grants[].uses[].ended_reason | Perché si è chiusa: scaduta, codice scaduto, codice revocato, cantiere archiviato. |
access_grants[].uses[].ip | Indirizzo da cui è stata aperta, mascherato. |
access_grants[].uses[].user_agent | Il browser da cui è stata aperta. |
access_grants[].uses[].reads | Letture fatte. |
workers.json
Un elenco, un oggetto per lavoratore, disattivati compresi: l'anagrafica, il percorso della foto, i requisiti (la formazione e il giudizio di idoneità), le revisioni della formazione, le verifiche d'identità, il badge con il verdetto e i suoi motivi e la storia dei suoi stati. Il token che apre il badge è una credenziale e non c'è.
Un giudizio di idoneità compare, come l'ufficio lo legge senza l'accesso nominativo, solo finché non seleziona un esito; quando ne seleziona uno resta solo che esiste, il suo tipo e la sua versione, con withheld a true, e il suo contenuto esce con l'archivio sanitario. I motivi di un verdetto non nominano mai una causa sanitaria. Una verifica d'identità per i documenti sanitari compare senza il suo riferimento (verification_ref è null), che esce con l'archivio sanitario.
L'archivio riporta quello che l'ufficio vede: il campo version c'è sui requisiti, dove la pagina del lavoratore lo mostra, e non sulle altre righe, dove è solo il controllo interno delle modifiche concorrenti.
Schema JSON: workers.schema.json
| Campo | Significato |
|---|---|
id | Identificativo del lavoratore. |
employer_id | L'impresa da cui dipende. |
user_id | L'account collegato al lavoratore, se c'è. |
first_name | Nome. |
last_name | Cognome. |
tax_code | Codice fiscale, sedici caratteri. |
birth_date | Data di nascita. |
birth_place | Luogo di nascita. |
nationality | Cittadinanza. |
address | Indirizzo. |
phone | Telefono. |
email | Email. |
job_title | Mansione. |
hired_on | Data di assunzione. |
employment_ended_on | Fine del rapporto di lavoro. |
employer_changed_at | Istante dell'ultimo cambio di impresa. |
badge_exempt | Se il lavoratore è esente dal badge. |
badge_exempt_reason | Motivo dell'esenzione dal badge. |
photo_updated_at | Istante dell'ultima foto. |
notes | Note dell'ufficio. |
training_basis | Regola di formazione applicata: registrazione combinata precedente, formazione specifica, o aggiornamento. |
training_review_required | Se la formazione va rivista dall'ufficio prima di tornare valida. |
deleted_at | Istante della disattivazione. |
disposed_at | Istante della cancellazione dei dati del lavoratore. |
plan_held_at | Istante della sospensione per i limiti del piano. |
created_by | L'account che l'ha creato. |
created_at | Istante di creazione. |
updated_at | Istante dell'ultima modifica. |
photo | Percorso della foto nell'archivio (photos/<id>.jpg), o null se non c'è. |
facts | I requisiti del lavoratore. |
facts[].id | Identificativo del requisito. |
facts[].kind | Tipo: formazione generale, specifica, aggiornamento, preposto, altra formazione, formazione di base (registrazione combinata precedente) o giudizio di idoneità. |
facts[].title | Titolo di un'altra formazione (training_other). |
facts[].completed_on | Giorno di conseguimento. |
facts[].expires_on | Giorno di scadenza; il requisito vale fino a quel giorno compreso. |
facts[].reference | Riferimento dell'attestato o del documento. |
facts[].note | Nota dell'ufficio. |
facts[].document_id | Il documento che sostiene il requisito, se ce n'è uno. |
facts[].created_at | Istante di creazione. |
facts[].updated_at | Istante dell'ultima modifica. |
facts[].source | Origine: inserito a mano, applicato dalla revisione di un documento, o importato dal sistema precedente. Null su un giudizio trattenuto. |
facts[].document_revision_id | La revisione del documento citata come prova. |
facts[].document_review_id | La revisione dell'ufficio che ha applicato il requisito. |
facts[].claim_id | L'affermazione della revisione che ha scritto il requisito. |
facts[].decision_id | Sempre null in questo archivio: un giudizio che seleziona un esito è trattenuto, e gli esiti escono con l'archivio sanitario. |
facts[].version | Versione del requisito, che cresce a ogni modifica. |
facts[].provider | Ente formatore che ha erogato il corso (solo formazione). |
facts[].hours | Durata del corso in ore, maggiore di zero, al più un decimale (solo formazione), scritta come testo. |
facts[].delivery_mode | Modalità di erogazione del corso (solo formazione). |
facts[].place | Luogo di svolgimento del corso (solo formazione). |
facts[].created_by | L'account che ha registrato il requisito; resta anche su un giudizio trattenuto. |
facts[].withheld | true se il requisito è un giudizio di idoneità che seleziona un esito, trattenuto da questo archivio. |
training_reviews | Le revisioni della formazione fatte dall'ufficio. |
training_reviews[].id | Identificativo della revisione. |
training_reviews[].kind | Tipo: conversione, revisione, ritiro o correzione. |
training_reviews[].basis_before | Regola di formazione prima. |
training_reviews[].basis_after | Regola di formazione dopo. |
training_reviews[].general_fact_id | Il requisito di formazione generale considerato. |
training_reviews[].specific_fact_id | Il requisito di formazione specifica considerato. |
training_reviews[].refresher_fact_id | Il requisito di aggiornamento considerato. |
training_reviews[].snapshot | Istantanea dei requisiti di formazione al momento della revisione: un oggetto libero, nella forma che l'app usava in quel momento. |
training_reviews[].applicability_ref | Riferimento che fonda la regola applicata. |
training_reviews[].reviewer_id | L'account che ha fatto la revisione. |
training_reviews[].reviewed_at | Istante della revisione. |
identity_checks | Le verifiche d'identità fatte dall'ufficio prima che l'app del lavoratore mostri un suo documento riservato o sanitario. |
identity_checks[].id | Identificativo della verifica. |
identity_checks[].user_id | L'account del lavoratore verificato. |
identity_checks[].scope | Per quali documenti. |
identity_checks[].employer_id | L'impresa, per i documenti sanitari. |
identity_checks[].custodian_id | L'account che ha verificato. |
identity_checks[].verified_at | Istante della verifica. |
identity_checks[].verification_ref | Il documento esibito o il riferimento della verifica; null per una verifica dei documenti sanitari, il cui riferimento esce con l'archivio sanitario. |
identity_checks[].revoked_by | L'account che l'ha ritirata. |
identity_checks[].revoked_at | Istante del ritiro. |
badge | Il badge del lavoratore, o null se non è mai stato emesso. Il token che lo apre è una credenziale e non c'è. |
badge.id | Identificativo del badge. |
badge.issued_at | Istante di emissione. |
badge.expires_at | Istante di scadenza. |
badge.revoked_at | Istante della revoca. |
badge.revoked_reason | Motivo della revoca. |
badge.revoked_by | L'account che l'ha revocato. |
badge.suspended_at | Istante della sospensione. |
badge.suspended_reason | Motivo della sospensione. |
badge.suspended_by | L'account che l'ha sospeso. |
badge.blocked_at | Istante del blocco. |
badge.blocked_reason | Motivo del blocco. |
badge.blocked_by | L'account che l'ha bloccato. |
badge.override_until | Fine della deroga in corso. |
badge.override_reason | Motivo della deroga. |
badge.override_by | L'account che ha concesso la deroga. |
badge.state | Verdetto: verde, rosso o sospeso. |
badge.state_reasons | I motivi del verdetto. |
badge.state_reasons[].code | Codice della regola (per esempio missing_durc, training_specific_expired, override_active); overridden:<codice> per un motivo sollevato da una deroga. |
badge.state_reasons[].detail | Il testo che accompagna il motivo, dove la regola ne porta uno. |
badge.state_reasons[].until | Il giorno a cui il motivo si riferisce: una scadenza o la fine di una deroga. |
badge.warnings | Gli avvisi del verdetto. |
badge.warnings[].code | Codice della regola (per esempio missing_durc, training_specific_expired, override_active); overridden:<codice> per un motivo sollevato da una deroga. |
badge.warnings[].detail | Il testo che accompagna il motivo, dove la regola ne porta uno. |
badge.warnings[].until | Il giorno a cui il motivo si riferisce: una scadenza o la fine di una deroga. |
badge.state_computed_at | Istante del calcolo del verdetto. |
badge.created_at | Istante di creazione. |
badge.updated_at | Istante dell'ultima modifica. |
badge_history | I cambi di stato del badge. |
badge_history[].id | Identificativo del cambio. |
badge_history[].from_state | Stato prima. |
badge_history[].to_state | Stato dopo. |
badge_history[].reasons | I motivi del nuovo stato. |
badge_history[].reasons[].code | Codice della regola (per esempio missing_durc, training_specific_expired, override_active); overridden:<codice> per un motivo sollevato da una deroga. |
badge_history[].reasons[].detail | Il testo che accompagna il motivo, dove la regola ne porta uno. |
badge_history[].reasons[].until | Il giorno a cui il motivo si riferisce: una scadenza o la fine di una deroga. |
badge_history[].cause | Che cosa ha mosso il verdetto. |
badge_history[].actor_user_id | L'account che ha agito, se c'è. |
badge_history[].created_at | Istante del cambio. |
vehicles.json
Un elenco, un oggetto per mezzo, archiviati compresi: veicoli targati e non targati, a noleggio, macchine e attrezzature, con il cantiere in cui si trovano, la revisione, l'assicurazione e il noleggio.
Schema JSON: vehicles.schema.json
| Campo | Significato |
|---|---|
id | Identificativo del mezzo. |
kind | Tipo: veicolo targato, non targato, a noleggio, macchina, attrezzatura, altro. |
name | Nome. |
plate | Targa. |
make | Marca. |
model | Modello. |
year | Anno. |
serial | Numero di serie. |
site_id | Il cantiere in cui si trova. |
inspection_kind | Revisione: con scadenza, non registrata, non prevista. |
inspection_expires_on | Scadenza della revisione. |
inspection_revision_id | La revisione del documento che la prova. |
insurance_kind | Assicurazione: con scadenza, non registrata, non prevista. |
insurance_expires_on | Scadenza dell'assicurazione. |
insurance_revision_id | La revisione del documento che la prova. |
rental_company | Società di noleggio. |
rental_ref | Riferimento del contratto di noleggio. |
rental_starts_on | Inizio del noleggio. |
rental_ends_on | Fine del noleggio. |
rental_contract_document_id | Il documento del contratto di noleggio. |
notes | Note dell'ufficio. |
archived_at | Istante dell'archiviazione. |
plan_held_at | Istante della sospensione per i limiti del piano. |
created_by | L'account che l'ha creato. |
created_at | Istante di creazione. |
updated_at | Istante dell'ultima modifica. |
documents.json
Un elenco, un oggetto per documento ordinario o riservato non cancellato, con le sue revisioni, le decisioni e le incongruenze di conservazione, i blocchi della cancellazione e le revisioni dell'ufficio con quanto ciascuna ha affermato. L'originale di ogni revisione disponibile è nella cartella documents/, al percorso che il suo campo file indica.
I documenti sanitari, le loro revisioni e la loro storia non ci sono: escono con l'archivio sanitario.
Schema JSON: documents.schema.json
| Campo | Significato |
|---|---|
id | Identificativo del documento. |
site_id | Il cantiere a cui si riferisce, se è suo. |
worker_id | Il lavoratore a cui si riferisce, se è suo. |
employer_id | L'impresa a cui si riferisce, se è sua. |
vehicle_id | Il mezzo a cui si riferisce, se è suo. |
kind | Tipo di documento. |
custom_kind | Tipo scritto dall'ufficio per un documento other. |
sensitivity | Riservatezza: ordinario o riservato. |
current_revision_id | La revisione corrente. |
current_review_id | La revisione dell'ufficio in vigore. |
status | Stato del documento. |
archived_at | Istante dell'archiviazione. |
created_by | L'account che l'ha creato. |
created_at | Istante di creazione. |
updated_at | Istante dell'ultima modifica. |
revisions | Le revisioni del documento, in ordine. |
revisions[].id | Identificativo della revisione. |
revisions[].ordinal | Numero d'ordine della revisione nel documento. |
revisions[].original_filename | Nome del file caricato. |
revisions[].content_type | Tipo del file (per esempio application/pdf). |
revisions[].byte_length | Dimensione del file, in byte. |
revisions[].sha256 | Impronta SHA-256 del file, in esadecimale. |
revisions[].availability | Disponibilità dell'originale. |
revisions[].use_state | Uso: candidata, revisionata, sostituita, ritirata. |
revisions[].ready_at | Istante in cui l'originale è stato accettato. |
revisions[].retired_at | Istante in cui la revisione è uscita dall'uso. |
revisions[].document_date | Data del documento. |
revisions[].validity_kind | Validità: con scadenza, senza scadenza, non registrata. |
revisions[].expires_on | Scadenza del documento. |
revisions[].note | Nota dell'ufficio. |
revisions[].retention_policy_id | La regola di conservazione applicata. |
revisions[].retention_trigger | L'evento della regola da cui decorre il termine, come applicato. |
revisions[].retention_trigger_on | Il giorno di quell'evento. |
revisions[].retention_deadline | Giorno fino al quale va conservato. |
revisions[].created_at | Istante di creazione. |
revisions[].updated_at | Istante dell'ultima modifica. |
revisions[].file | Percorso dell'originale nell'archivio (documents/<documento>/<revisione>.<estensione>), o null se l'originale non è disponibile. |
revisions[].retention_decisions | Le decisioni dell'ufficio sulla conservazione della revisione. |
revisions[].retention_decisions[].id | Identificativo della decisione. |
revisions[].retention_decisions[].decision | Applicare la regola, conservare, eliminare. |
revisions[].retention_decisions[].policy_before | La regola prima. |
revisions[].retention_decisions[].policy_after | La regola dopo. |
revisions[].retention_decisions[].deadline_before | Il termine prima. |
revisions[].retention_decisions[].deadline_after | Il termine dopo. |
revisions[].retention_decisions[].reason | Il motivo. |
revisions[].retention_decisions[].decided_by | L'account che ha deciso. |
revisions[].retention_decisions[].decided_at | Istante della decisione. |
revisions[].retention_conflicts | Le incongruenze di conservazione trovate sulla revisione, risolte comprese. |
revisions[].retention_conflicts[].id | Identificativo dell'incongruenza. |
revisions[].retention_conflicts[].reason | Perché: la revisione prova un requisito, il soggetto è tornato attivo, l'evento non è plausibile. |
revisions[].retention_conflicts[].created_at | Istante in cui è stata trovata. |
revisions[].retention_conflicts[].resolved_at | Istante della risoluzione. |
revisions[].retention_conflicts[].decision_id | La decisione che l'ha risolta. |
holds | I blocchi della cancellazione posti sul documento, tolti compresi. |
holds[].id | Identificativo del blocco. |
holds[].authority_ref | Riferimento dell'autorità o dell'atto. |
holds[].placed_by | L'account che l'ha posto. |
holds[].placed_at | Istante in cui è stato posto. |
holds[].review_on | Giorno in cui va rivisto. |
holds[].released_by | L'account che l'ha tolto. |
holds[].released_at | Istante in cui è stato tolto. |
reviews | Le revisioni dell'ufficio sul documento, con quanto ciascuna ha affermato. |
reviews[].id | Identificativo della revisione. |
reviews[].revision_id | La revisione del documento esaminata. |
reviews[].previous_review_id | La revisione dell'ufficio precedente. |
reviews[].reviewer_id | L'account che l'ha fatta. |
reviews[].reviewed_at | Istante della revisione. |
reviews[].scope | Che cosa ha fatto: archiviazione, dati, classificazione, ritiro, ripristino. |
reviews[].snapshot | I dati del documento come la revisione li ha visti: un oggetto libero, nella forma che l'app usava in quel momento. |
reviews[].share_with_worker | Se il documento è mostrato al lavoratore nella sua app. |
reviews[].claims | Che cosa la revisione ha affermato del soggetto (un requisito, il DURC, una scadenza del mezzo). |
reviews[].claims[].id | Identificativo dell'affermazione. |
reviews[].claims[].worker_id | Il lavoratore, se il soggetto è un lavoratore. |
reviews[].claims[].employer_id | L'impresa, se il soggetto è un'impresa. |
reviews[].claims[].vehicle_id | Il mezzo, se il soggetto è un mezzo. |
reviews[].claims[].claim_kind | Che cosa afferma. |
reviews[].claims[].values | I valori affermati (date, riferimenti): un oggetto libero, nella forma del tipo di affermazione. |
attendance_events.json
Un elenco, una voce per timbratura, annullate comprese, da qualsiasi canale: il varco, l'app del lavoratore, il tablet delegato, l'inserimento manuale, le chat, l'importazione. Ogni timbratura porta il verdetto del badge di quell'istante, la distanza dal cantiere e la precisione della posizione: le coordinate non sono mai conservate.
Schema JSON: attendance_events.schema.json
| Campo | Significato |
|---|---|
id | Identificativo della timbratura. |
worker_id | Il lavoratore. |
site_id | Il cantiere. |
kind | Entrata o uscita. |
occurred_at | Istante della timbratura. |
device_at | Istante secondo il dispositivo, se diverso. |
clock_offset_s | Scarto dell'orologio del dispositivo, in secondi. |
offline | Se è stata registrata senza rete e inviata dopo. |
channel | Canale: varco, app del lavoratore, tablet delegato, inserimento manuale, WhatsApp, Telegram, importazione. |
identified_by | Come è stato identificato il lavoratore. |
gate_link_id | Il collegamento del tablet delegato, se usato. |
actor_user_id | L'account che ha registrato la timbratura, se c'è. |
badge_state | Verdetto del badge in quell'istante. |
badge_reasons | I motivi di quel verdetto. |
badge_reasons[].code | Codice della regola (per esempio missing_durc, training_specific_expired, override_active); overridden:<codice> per un motivo sollevato da una deroga. |
badge_reasons[].detail | Il testo che accompagna il motivo, dove la regola ne porta uno. |
badge_reasons[].until | Il giorno a cui il motivo si riferisce: una scadenza o la fine di una deroga. |
accuracy_m | Precisione della posizione, in metri. |
distance_m | Distanza dal cantiere, in metri. |
geofence_enforced | Se il recinto geografico è stato applicato. |
justification | Giustificazione di un inserimento manuale o per codice fiscale. |
justification_doc | Riferimento del documento a supporto. |
note | Nota. |
presumed | Se è un'entrata o un'uscita presunta dall'app. |
flags | Segnalazioni sulla timbratura (per esempio clock_skew, late_sync). |
voided_at | Istante dell'annullamento. |
voided_reason | Motivo dell'annullamento. |
voided_by | L'account che l'ha annullata. |
ip | Indirizzo da cui è arrivata la timbratura. |
user_agent | Il browser o l'app da cui è arrivata. |
created_at | Istante di registrazione. |
updated_at | Istante dell'ultima modifica (un annullamento, una nota). |
presence.json
Un elenco, una voce per intervallo di presenza ricavato dalle timbrature: una permanenza di un lavoratore in un cantiere, con i suoi estremi, quelli presunti e la durata. I fogli mensili sono nella cartella presence/.
Schema JSON: presence.schema.json
| Campo | Significato |
|---|---|
id | Identificativo dell'intervallo. |
worker_id | Il lavoratore. |
site_id | Il cantiere. |
starts_at | Inizio dell'intervallo. |
ends_at | Fine dell'intervallo; null se è ancora aperto. |
in_event_id | La timbratura di entrata. |
out_event_id | La timbratura di uscita. |
presumed_in | Se l'entrata è presunta. |
presumed_out | Se l'uscita è presunta. |
presumed_cause | Perché un estremo è presunto: cambio di cantiere, fine giornata, entrata mancante. |
minutes | Durata in minuti; null se è ancora aperto. |
flags | Segnalazioni sull'intervallo (per esempio double_in). |
timesheet_sends.json
Un elenco, una voce per ogni invio dei fogli delle ore di presenza al consulente del lavoro, con il mese, il destinatario, i conteggi e l'esito. I file spediti sono nella cartella timesheets/.
Schema JSON: timesheet_sends.schema.json
| Campo | Significato |
|---|---|
id | Identificativo dell'invio. |
period_month | Il mese, come il suo primo giorno. |
site_id | Il cantiere, se l'invio riguarda uno solo. |
recipient_email | Email del consulente. |
worker_count | Lavoratori nel foglio. |
hours_total | Ore di presenza in totale, come testo. |
presumed_count | Estremi presunti nel foglio. |
anomaly_count | Anomalie nel foglio. |
status | Stato dell'invio. |
error | Codice dell'errore di un invio fallito. |
is_resend | Se è un nuovo invio dello stesso mese. |
sent_by | L'account che ha inviato. |
sent_at | Istante dell'invio. |
created_at | Istante della richiesta. |
updated_at | Istante dell'ultima modifica. |
files | Percorsi dei file spediti nell'archivio (timesheets/<id>.xlsx e .csv). |
imports.json
Un elenco, una voce per importazione da foglio di calcolo, prove comprese, con il riepilogo per foglio e l'esito di ogni riga letta. Il file caricato non c'è: l'app lo cancella dopo sette giorni.
Schema JSON: imports.schema.json
| Campo | Significato |
|---|---|
id | Identificativo dell'importazione. |
created_by | L'account che ha caricato il file. |
file_name | Nome del file caricato. |
file_size | Dimensione del file, in byte. |
mode | Prova o applicazione. |
options | Le opzioni scelte. |
options.update_existing | Se le righe esistenti andavano aggiornate. |
status | Stato. |
started_at | Istante di inizio. |
finished_at | Istante di fine. |
summary | Il riepilogo, null finché l'importazione non è finita: per ogni foglio che il file conteneva (IMPRESE, CANTIERI, LAVORATORI, ASSEGNAZIONI, MEZZI) i conteggi per esito, e gli avvisi. |
summary.notices | Gli avvisi della lettura (per esempio un foglio saltato e perché). |
summary.* | I conteggi per esito delle righe del foglio. |
summary.*.created | Righe che hanno creato. |
summary.*.updated | Righe che hanno aggiornato. |
summary.*.skipped | Righe saltate. |
summary.*.failed | Righe in errore. |
summary.*.refused | Righe rifiutate per i limiti del piano (assente nei riepiloghi scritti prima del 19 ottobre 2026). |
error | Codice dell'errore di un'importazione fallita. |
created_at | Istante del caricamento. |
updated_at | Istante dell'ultima modifica. |
rows | L'esito di ogni riga letta. |
rows[].id | Identificativo della riga del rapporto. |
rows[].sheet | Il foglio. |
rows[].row_number | Il numero di riga nel foglio. |
rows[].key | La chiave della riga (per esempio un codice fiscale). |
rows[].outcome | Esito. |
rows[].code | Codice dell'esito. |
rows[].message | Messaggio in italiano. |
rows[].entity_type | Il tipo di riga scritta. |
rows[].entity_id | La riga scritta. |
rows[].created_at | Istante. |
consents.json
Un elenco, una voce per ogni presa visione dell'informativa sulla geolocalizzazione da parte di un lavoratore dello spazio, data o ritirata, con la versione dell'informativa. Mai l'indirizzo o il browser da cui è arrivata.
Schema JSON: consents.schema.json
| Campo | Significato |
|---|---|
id | Identificativo della presa visione. |
worker_id | Il lavoratore collegato all'account che l'ha data. |
version | Versione dell'informativa. |
granted | Se è stata data (true) o ritirata (false). |
created_at | Istante. |
audit.json
Un elenco, una riga per azione registrata nello spazio, come i titolari leggono il registro delle attività: chi ha agito, su che cosa, e lo stato prima e dopo. Come quel registro non porta l'indirizzo né il browser: quelli delle righe che riguardano un account, e che l'account stesso ha scritto, sono nell'esportazione di quell'account.
La storia di un documento sanitario non c'è, e l'istantanea di una riga che riguarda un giudizio di idoneità, con o senza esito, è sostituita da {"withheld": "medical"}. La riga di un vecchio aggiornamento di un requisito che non ne nomina il tipo (worker.fact_updated) perde le date, il riferimento e la nota, e la sua istantanea porta {"withheld": "unclassified"} accanto al resto, perché potrebbe essere quella di un giudizio di idoneità. Il manifest conta queste righe in withheld.audit_rows.
Schema JSON: audit.schema.json
| Campo | Significato |
|---|---|
id | Identificativo della riga. |
action | L'azione (per esempio worker.created, badge.issued). |
entity_type | Il tipo di cosa su cui si è agito. |
entity_id | La cosa su cui si è agito. |
actor_user_id | L'account che ha agito, se c'è. |
actor_kind | Chi ha agito: un account, il sistema, un servizio esterno, la piattaforma. |
before | Lo stato prima: un oggetto libero, nella forma dell'azione; null se non c'è. |
after | Lo stato dopo: un oggetto libero, nella forma dell'azione; null se non c'è. |
created_at | Istante. |
anagrafiche.xlsx
L'anagrafica attiva nei cinque fogli del modello di importazione — IMPRESE, CANTIERI, LAVORATORI, ASSEGNAZIONI, MEZZI — con le stesse intestazioni, nello stesso ordine: un formato parallelo e volutamente parziale, che si apre con qualsiasi programma per fogli di calcolo e si reimporta in CantiereGo. I file JSON restano completi e fanno fede.
I valori sono scritti come l'importazione li legge: le date come date (gg/mm/aaaa), i numeri come numeri, le scelte con le parole del modello, sì e no. Il file non ha un limite di righe suo; un foglio xlsx ne contiene al massimo 1.048.576, l'intestazione compresa, mentre i file JSON non hanno questo limite.
- Solo l'anagrafica attiva: le imprese, i cantieri e i mezzi non archiviati, i lavoratori né disattivati né cancellati, le assegnazioni in corso o future; le righe sospese per i limiti del piano ci sono. Le righe archiviate, disattivate o cancellate e le assegnazioni finite sono solo nei file JSON: il modello non ha una colonna di stato, e una reimportazione le riporterebbe attive.
- Restano vuote, e sono nei file JSON:
formazione_base_dataeformazione_base_scadenza(la registrazione combinata precedente, che l'importazione rifiuta su un lavoratore con la formazione specifica, come è ogni lavoratore che un'importazione crea),idoneita_scadenza(un dato sanitario) e la colonnaiddei mezzi, che identifica un mezzo solo in questo spazio di lavoro. La formazione generale, specifica e di aggiornamento e gli altri corsi non hanno una colonna nel modello e sono solo nei file JSON; il corso del preposto c'è. - Il foglio
IMPRESEriporta un'impresa solo se ha la partita IVA o il codice fiscale, la chiave con cui l'importazione la riconosce. Di un'altra impresa senza nessuno dei due mancano anche i lavoratori e le loro assegnazioni, che sono solo nei file JSON; i lavoratori dell'impresa dello spazio ci sono comunque. - I lavoratori dell'impresa dello spazio hanno vuote le colonne
datore_pivaedatore_cf, e l'importazione li assegna all'impresa dello spazio di destinazione. Prima di importare, inserisci la partita IVA o il codice fiscale dell'azienda nelle impostazioni dello spazio di destinazione: così la riga dell'impresa nel foglioIMPRESEaggiorna quella e non ne crea una seconda. - Un testo che comincia con
=,+,-o@, una tabulazione o un ritorno a capo è scritto con un apostrofo davanti, perché un foglio di calcolo non lo esegua come una formula; una reimportazione conserva l'apostrofo, tranne in un numero di telefono. - I fogli sono letti uno dopo l'altro, non in un'unica istantanea: una riga creata mentre l'archivio si scrive può nominare un codice che un foglio letto prima non riporta.
- Un'importazione legge un foglio di al più 5000 righe (uno più lungo è saltato) da un file di al più 10 MiB: un'anagrafica più grande si reimporta in più file, ciascuno entro questi limiti, le imprese e i cantieri prima dei lavoratori e delle assegnazioni che li nominano.
- Reimportato nello stesso spazio di lavoro con l'aggiornamento delle righe esistenti, il file vede rifiutata, con il suo errore nel rapporto, ogni riga il cui DURC o corso del preposto è sostenuto da un documento: quei dati si correggono dalla revisione del documento. Nello stesso spazio, un lavoratore di un'impresa sospesa per i limiti del piano è rifiutato, come lo sarebbe dall'app.
schemas/
Gli schemi JSON dei file JSON dell'archivio, gli stessi pubblicati su questa pagina: manifest.schema.json e uno per ogni file, con il nome del file seguito da .schema.json.
presence/
Un file CSV per ogni mese con almeno una presenza, presence/<AAAA-MM>.csv: il foglio mensile delle ore di presenza come l'ufficio lo scarica, una riga per lavoratore, giorno e cantiere. È in italiano, separato da punti e virgola, in UTF-8 con BOM, con le ore in decimali e la virgola.
timesheets/
I file spediti al consulente del lavoro, timesheets/<id>.xlsx e timesheets/<id>.csv, byte per byte come sono partiti: riletti, mai ricostruiti. L'id è quello dell'invio in timesheet_sends.json.
photos/
La foto di ogni lavoratore che ne ha una, photos/<id>.jpg, in JPEG come l'app la conserva. L'id è quello del lavoratore in workers.json.
documents/
L'originale di ogni revisione disponibile dei documenti di documents.json, documents/<documento>/<revisione>.<estensione>, letto dalla sua versione esatta: la sua impronta SHA-256 è nel campo sha256 della revisione. Mai un documento sanitario. Una revisione ferma per un'incongruenza di conservazione aperta non porta il suo originale finché non è risolta; un originale che manca è elencato nel manifest, in missing.originals.
L'archivio sanitario
I giudizi di idoneità con un esito, gli esiti e i documenti sanitari non sono nell'archivio dello spazio di lavoro: nell'ufficio li legge solo chi l'impresa ha nominato con l'accesso nominativo ai suoi giudizi, ed escono con un archivio a parte, l'archivio sanitario, nel formato cantierego-medical-export, con la stessa versione e la stessa regola.
Lo chiede, da Impostazioni › Documenti, un membro che ha l'accesso nominativo ai giudizi di almeno un'impresa, da un accesso con la verifica in due passaggi. Copre le imprese che il suo accesso copre quando lo chiede e ancora quando l'archivio si scrive: per i loro lavoratori contiene i giudizi di idoneità, con o senza esito, gli esiti con il riferimento della revisione delle prescrizioni, i documenti sanitari con la loro storia e i loro originali, e le verifiche d'identità per i documenti sanitari con il loro riferimento, queste solo per le imprese di cui chi lo chiede legge le verifiche nell'app: tutte per un titolare, quelle di cui è referente sanitario per chi non è titolare, nessuna per chi ha un accesso in sola lettura.
Se ne chiede uno al giorno. L'archivio è di chi l'ha chiesto: lo scarica solo lui, finché ha ancora l'accesso a ogni impresa che copre, per 14 giorni dalla preparazione.
Se nessuno ha un accesso nominativo, un titolare nomina sé stesso dalla pagina dell'impresa, con la verifica in due passaggi, e chiede l'archivio: è così che l'azienda raggiunge i propri dati sanitari. Un titolare può nominarsi su uno spazio di lavoro attivo o chiuso, non su uno sospeso. Su uno spazio di lavoro sospeso o chiuso l'archivio sanitario lo chiede e lo scarica solo un titolare che abbia l'accesso nominativo: chi lo ha e non è titolare lo chieda e lo scarichi mentre lo spazio di lavoro è attivo.
Un giudizio di idoneità compare nell'archivio dello spazio di lavoro, come l'ufficio lo legge, solo finché non seleziona un esito; quando ne seleziona uno, il suo contenuto è nell'archivio sanitario.
manifest.json — archivio sanitario
Il manifest dell'archivio sanitario: il formato e la sua versione, lo spazio di lavoro, chi l'ha chiesto e le imprese che il suo accesso nominativo copriva, l'istante e il giorno in cui è stato scritto, i conteggi e quali originali mancavano, con il motivo.
Schema JSON: medical/manifest.schema.json
| Campo | Significato |
|---|---|
format | Il formato dell'archivio. |
format.name | Nome del formato. |
format.version | Versione del formato, con la stessa regola dell'archivio dello spazio. |
export_id | Identificativo dell'esportazione. |
workspace | Lo spazio esportato. |
workspace.id | Identificativo dello spazio. |
workspace.name | Nome. |
workspace.slug | Nome breve nell'indirizzo dell'app. |
workspace.legal_name | Ragione sociale. |
requested_by | L'account che ha chiesto l'archivio. |
employers | Le imprese i cui giudizi l'accesso nominativo del richiedente copriva. |
employers[].id | Identificativo dell'impresa. |
employers[].legal_name | Ragione sociale. |
generated_at | Istante in cui l'archivio è stato scritto. |
day | Il giorno dello spazio in cui l'archivio è stato scritto. |
timezone | Il fuso orario dello spazio. |
app_version | La versione dell'app che ha scritto l'archivio. |
read_mode | Come sono stati letti i dati: uno dopo l'altro, a pagine. |
read_mode_note | Che cosa comporta la lettura sequenziale. |
read_mode_note.it | Il testo in italiano. |
read_mode_note.en | Il testo in inglese. |
files | Per ogni file JSON le righe scritte, per ogni cartella i file. |
files.workers.json | Lavoratori in workers.json. |
files.schemas/ | Schemi nella cartella schemas/. |
files.documents/ | Originali nella cartella documents/. |
missing | I file che l'archivio avrebbe dovuto contenere e non ha trovato. |
missing.originals | Revisioni il cui originale mancava. |
missing.originals_reason | Perché mancano gli originali: null se ne manca solo qualcuno che l'archivio dei file non aveva più; document_reads_disabled se la lettura dei documenti era sospesa per un incidente e nessun originale è stato letto, tutti elencati in originals. |
workers.json — archivio sanitario
Un elenco, un oggetto per lavoratore delle imprese coperte, o con un dato sanitario registrato sotto una di esse: i giudizi di idoneità, gli esiti con il loro riferimento, i documenti sanitari con le loro revisioni, le revisioni dell'ufficio, le decisioni e le incongruenze di conservazione e i blocchi, e le verifiche d'identità per i documenti sanitari con il loro riferimento delle sole imprese di cui chi l'ha chiesto legge le verifiche nell'app (tutte per un titolare, quelle di cui è referente sanitario per chi non è titolare, nessuna per chi ha un accesso in sola lettura). Ciascun dato sta sotto l'impresa per cui è stato registrato; un giudizio senza esito sotto l'impresa attuale del lavoratore.
Schema JSON: medical/workers.schema.json
| Campo | Significato |
|---|---|
worker | Il lavoratore. |
worker.id | Identificativo del lavoratore. |
worker.employer_id | L'impresa da cui dipende. |
worker.first_name | Nome. |
worker.last_name | Cognome. |
worker.tax_code | Codice fiscale, sedici caratteri. |
worker.deleted_at | Istante della disattivazione. |
worker.disposed_at | Istante della cancellazione dei dati del lavoratore. |
facts | I giudizi di idoneità del lavoratore. |
facts[].id | Identificativo del requisito. |
facts[].kind | Tipo: giudizio di idoneità. |
facts[].title | Titolo di un'altra formazione (training_other). |
facts[].completed_on | Giorno di conseguimento. |
facts[].expires_on | Giorno di scadenza; il requisito vale fino a quel giorno compreso. |
facts[].reference | Riferimento dell'attestato o del documento. |
facts[].note | Nota dell'ufficio. |
facts[].document_id | Il documento che sostiene il requisito, se ce n'è uno. |
facts[].created_at | Istante di creazione. |
facts[].updated_at | Istante dell'ultima modifica. |
facts[].source | Origine: inserito a mano, applicato dalla revisione di un documento, o importato dal sistema precedente. Null su un giudizio trattenuto. |
facts[].document_revision_id | La revisione del documento citata come prova. |
facts[].document_review_id | La revisione dell'ufficio che ha applicato il requisito. |
facts[].claim_id | L'affermazione della revisione che ha scritto il requisito. |
facts[].decision_id | L'esito che il giudizio seleziona. |
facts[].version | Versione del requisito, che cresce a ogni modifica. |
facts[].provider | Ente formatore che ha erogato il corso (solo formazione). |
facts[].hours | Durata del corso in ore, maggiore di zero, al più un decimale (solo formazione), scritta come testo. |
facts[].delivery_mode | Modalità di erogazione del corso (solo formazione). |
facts[].place | Luogo di svolgimento del corso (solo formazione). |
facts[].created_by | L'account che ha registrato il requisito; resta anche su un giudizio trattenuto. |
facts[].withheld | Sempre false: in questo archivio nessun giudizio è trattenuto. |
decisions | Gli esiti sanitari registrati. |
decisions[].id | Identificativo dell'esito. |
decisions[].employer_id | L'impresa a cui il giudizio risponde. |
decisions[].previous_decision_id | L'esito che questo sostituisce. |
decisions[].outcome | Esito: idoneo, idoneo con prescrizioni, non idoneo temporaneamente, non idoneo permanentemente, non classificato (precedente). |
decisions[].assessed_on | Giorno della visita. |
decisions[].valid_until | Validità del giudizio. |
decisions[].next_review_on | Prossima visita. |
decisions[].eligibility_until | Fino a quando il lavoratore è ammesso. |
decisions[].boundary_basis | Su che cosa si fonda il limite di ammissione. |
decisions[].boundary_ref | Riferimento del limite. |
decisions[].context_version | Versione del contesto in cui è stato registrato. |
decisions[].applicability | Se l'esito è confermato o da rivedere. |
decisions[].review_ref | Riferimento della revisione delle prescrizioni. |
decisions[].retention_policy_id | La regola di conservazione applicata. |
decisions[].document_id | Il documento sanitario che lo prova. |
decisions[].revision_id | La revisione del documento. |
decisions[].review_id | La revisione dell'ufficio. |
decisions[].correction_of | L'esito che questo corregge. |
decisions[].correction_ref | Riferimento della correzione. |
decisions[].actor_id | L'account che l'ha registrato. |
decisions[].created_at | Istante di registrazione. |
decisions[].policy_review_overdue | Se la regola di conservazione andava rivista. |
documents | I documenti sanitari non cancellati. |
documents[].id | Identificativo del documento. |
documents[].kind | Tipo di documento. |
documents[].custom_kind | Tipo scritto dall'ufficio per un documento other. |
documents[].sensitivity | Riservatezza: sempre sanitario. |
documents[].medical_employer_id | L'impresa a cui il documento risponde. |
documents[].current_revision_id | La revisione corrente. |
documents[].current_review_id | La revisione dell'ufficio in vigore. |
documents[].status | Stato del documento. |
documents[].archived_at | Istante dell'archiviazione. |
documents[].created_by | L'account che l'ha creato. |
documents[].created_at | Istante di creazione. |
documents[].updated_at | Istante dell'ultima modifica. |
documents[].revisions | Le revisioni del documento, in ordine. |
documents[].revisions[].id | Identificativo della revisione. |
documents[].revisions[].ordinal | Numero d'ordine della revisione nel documento. |
documents[].revisions[].original_filename | Nome del file caricato. |
documents[].revisions[].content_type | Tipo del file (per esempio application/pdf). |
documents[].revisions[].byte_length | Dimensione del file, in byte. |
documents[].revisions[].sha256 | Impronta SHA-256 del file, in esadecimale. |
documents[].revisions[].availability | Disponibilità dell'originale. |
documents[].revisions[].use_state | Uso: candidata, revisionata, sostituita, ritirata. |
documents[].revisions[].ready_at | Istante in cui l'originale è stato accettato. |
documents[].revisions[].retired_at | Istante in cui la revisione è uscita dall'uso. |
documents[].revisions[].document_date | Data del documento. |
documents[].revisions[].validity_kind | Validità: con scadenza, senza scadenza, non registrata. |
documents[].revisions[].expires_on | Scadenza del documento. |
documents[].revisions[].note | Nota dell'ufficio. |
documents[].revisions[].retention_policy_id | La regola di conservazione applicata. |
documents[].revisions[].retention_trigger | L'evento della regola da cui decorre il termine, come applicato. |
documents[].revisions[].retention_trigger_on | Il giorno di quell'evento. |
documents[].revisions[].retention_deadline | Giorno fino al quale va conservato. |
documents[].revisions[].created_at | Istante di creazione. |
documents[].revisions[].updated_at | Istante dell'ultima modifica. |
documents[].revisions[].file | Percorso dell'originale nell'archivio (documents/<documento>/<revisione>.<estensione>), o null se l'originale non è disponibile. |
documents[].revisions[].retention_decisions | Le decisioni dell'ufficio sulla conservazione della revisione. |
documents[].revisions[].retention_decisions[].id | Identificativo della decisione. |
documents[].revisions[].retention_decisions[].decision | Applicare la regola, conservare, eliminare. |
documents[].revisions[].retention_decisions[].policy_before | La regola prima. |
documents[].revisions[].retention_decisions[].policy_after | La regola dopo. |
documents[].revisions[].retention_decisions[].deadline_before | Il termine prima. |
documents[].revisions[].retention_decisions[].deadline_after | Il termine dopo. |
documents[].revisions[].retention_decisions[].reason | Il motivo. |
documents[].revisions[].retention_decisions[].decided_by | L'account che ha deciso. |
documents[].revisions[].retention_decisions[].decided_at | Istante della decisione. |
documents[].revisions[].retention_conflicts | Le incongruenze di conservazione trovate sulla revisione, risolte comprese. |
documents[].revisions[].retention_conflicts[].id | Identificativo dell'incongruenza. |
documents[].revisions[].retention_conflicts[].reason | Perché: la revisione prova un requisito, il soggetto è tornato attivo, l'evento non è plausibile. |
documents[].revisions[].retention_conflicts[].created_at | Istante in cui è stata trovata. |
documents[].revisions[].retention_conflicts[].resolved_at | Istante della risoluzione. |
documents[].revisions[].retention_conflicts[].decision_id | La decisione che l'ha risolta. |
documents[].holds | I blocchi della cancellazione posti sul documento, tolti compresi. |
documents[].holds[].id | Identificativo del blocco. |
documents[].holds[].authority_ref | Riferimento dell'autorità o dell'atto. |
documents[].holds[].placed_by | L'account che l'ha posto. |
documents[].holds[].placed_at | Istante in cui è stato posto. |
documents[].holds[].review_on | Giorno in cui va rivisto. |
documents[].holds[].released_by | L'account che l'ha tolto. |
documents[].holds[].released_at | Istante in cui è stato tolto. |
documents[].reviews | Le revisioni dell'ufficio sul documento, con quanto ciascuna ha affermato. |
documents[].reviews[].id | Identificativo della revisione. |
documents[].reviews[].revision_id | La revisione del documento esaminata. |
documents[].reviews[].previous_review_id | La revisione dell'ufficio precedente. |
documents[].reviews[].reviewer_id | L'account che l'ha fatta. |
documents[].reviews[].reviewed_at | Istante della revisione. |
documents[].reviews[].scope | Che cosa ha fatto: archiviazione, dati, classificazione, ritiro, ripristino. |
documents[].reviews[].snapshot | I dati del documento come la revisione li ha visti: un oggetto libero, nella forma che l'app usava in quel momento. |
documents[].reviews[].share_with_worker | Se il documento è mostrato al lavoratore nella sua app. |
documents[].reviews[].claims | Che cosa la revisione ha affermato del soggetto, il giudizio di idoneità compreso. |
documents[].reviews[].claims[].id | Identificativo dell'affermazione. |
documents[].reviews[].claims[].worker_id | Il lavoratore, se il soggetto è un lavoratore. |
documents[].reviews[].claims[].employer_id | L'impresa, se il soggetto è un'impresa. |
documents[].reviews[].claims[].vehicle_id | Il mezzo, se il soggetto è un mezzo. |
documents[].reviews[].claims[].claim_kind | Che cosa afferma. |
documents[].reviews[].claims[].values | I valori affermati (date, riferimenti): un oggetto libero, nella forma del tipo di affermazione. |
identity_checks | Le verifiche d'identità fatte dal referente sanitario dell'impresa prima che l'app del lavoratore mostri un suo documento sanitario, con il loro riferimento. Solo per le imprese di cui chi ha chiesto l'archivio legge le verifiche nell'app: tutte per un titolare, quelle di cui è referente sanitario per chi non è titolare; nessuna per chi ha un accesso in sola lettura. |
identity_checks[].id | Identificativo della verifica. |
identity_checks[].user_id | L'account del lavoratore verificato. |
identity_checks[].scope | Per quali documenti: sempre i sanitari. |
identity_checks[].employer_id | L'impresa i cui documenti sanitari la verifica apre. |
identity_checks[].custodian_id | L'account che ha verificato. |
identity_checks[].verified_at | Istante della verifica. |
identity_checks[].verification_ref | Il documento esibito o il riferimento della verifica. |
identity_checks[].revoked_by | L'account che l'ha ritirata. |
identity_checks[].revoked_at | Istante del ritiro. |
schemas/ — archivio sanitario
I due schemi dell'archivio sanitario, manifest.schema.json e workers.schema.json, gli stessi pubblicati qui sotto /formato-esportazione/1/medical/.
documents/ — archivio sanitario
L'originale di ogni revisione disponibile dei documenti sanitari, documents/<documento>/<revisione>.<estensione>, letto dalla sua versione esatta. Fanno fede missing.originals e missing.originals_reason del manifest.
Che cosa l'archivio non contiene
- I dati del tuo account. Il profilo, le sessioni, i consensi e le righe del registro che ti riguardano si scaricano dall'account (Account › Dati e privacy), in un file a parte che questo formato non descrive.
- La fatturazione. L'abbonamento e le fatture si leggono e si scaricano da Impostazioni › Piano e fatturazione; il registro fiscale resta ad A176lab, che lo conserva dieci anni.
- Le credenziali. Il codice di timbratura dei cantieri, i token dei badge e dei tablet delegati, le impronte dei codici ispettivi e degli inviti e le chiavi con cui l'app conserva i file non ci sono; le foto, i fogli inviati e gli originali, invece, ci sono, come file.
- I dati sanitari con un esito. I giudizi di idoneità con un esito, gli esiti e i documenti sanitari escono con l'archivio sanitario.
- Il funzionamento interno del servizio: le code, i tentativi, i contatori e la diagnostica dei messaggi (le consegne dei bot, tenute 30 giorni). La sezione seguente elenca ogni tabella che resta fuori, e perché.
- Un'istantanea. Le famiglie di dati sono lette una dopo l'altra, a pagine: un dato registrato mentre l'archivio si scrive può comparire in un file e non in un altro. Il manifest lo dice nel campo
read_mode.
Ogni tabella, dentro o fuori dall'archivio
Ogni tabella con una colonna workspace_id, e la riga dello spazio di lavoro stesso, è qui, con dove finisce nell'archivio o perché ne resta fuori. Il percorso indica il file e le chiavi sotto cui le sue righe sono annidate: sites.json/access_grants/uses sono le sessioni dentro ciascun codice ispettivo, dentro ciascun cantiere. L'elenco è quello con cui il servizio scrive l'archivio, e le sue prove falliscono se nel database compare una tabella che non vi è. members.json e consents.json leggono anche gli account collegati: il nome, l'email e il telefono dei membri, le prese visione dei lavoratori.
La colonna workspace_id delle tabelle non è ripetuta: l'archivio è di un solo spazio di lavoro. Le altre colonne ci sono tutte, tranne quelle elencate, ciascuna per uno di questi motivi: una credenziale o la sua impronta; il funzionamento interno del servizio (un contatore delle modifiche, una chiave di archiviazione, un riferimento che il servizio tiene per sé); un dato che l'archivio dice già in un altro modo (già detto: il genitore sotto cui una voce è annidata, il soggetto di un documento che le sue revisioni ripeterebbero); o una colonna che la vista dell'ufficio non mostra, perché l'archivio riporta quello che l'ufficio vede.
| Tabella | Nell'archivio | Colonne lasciate fuori, e perché |
|---|---|---|
workspaces | workspace.json | suspended_by, deleted_at, purged_at, purge_counts (funzionamento interno). suspended_by è l'amministratore della piattaforma che ha sospeso lo spazio; deleted_at, purged_at e purge_counts sono della cancellazione definitiva, mai valorizzati su uno spazio che esiste ancora. |
document_retention_policies | workspace.json/retention_policies | Nessuna. |
bot_workspace_settings | workspace.json/bot_settings | version (funzionamento interno). |
memberships | members.json/members | Nessuna. |
invitations | members.json/invitations | token_hash (una credenziale). |
bot_workspace_links | members.json/bot_links | connection_id, epoch, worker_link_epoch, notice_consent_id, version (funzionamento interno). connection_id, la connessione dell'account alla chat, è nell'esportazione dell'account. |
bot_notification_subscriptions | members.json/bot_subscriptions | connection_id, connection_proactive_epoch, version (funzionamento interno). |
bot_consent_events | members.json/bot_consents | connection_id, instance_id (funzionamento interno). |
employers | employers.json | version (funzionamento interno). |
employer_document_policies | employers.json/document_policy | employer_id (già detto); version (funzionamento interno). |
employer_medical_access | employers.json/medical_access | employer_id (già detto). |
sites | sites.json | punch_code (una credenziale). |
site_employers | sites.json/employers | site_id (già detto). |
site_workers | sites.json/assignments | site_id (già detto). |
gate_links | sites.json/gate_links | site_id (già detto); token_hash (una credenziale). |
access_grants | sites.json/access_grants | site_id (già detto); code_hash, code_prefix (una credenziale); legacy_id, legacy_revoked (funzionamento interno). code_hash e code_prefix sono l'impronta del codice e i quattro caratteri che la indicizzano; legacy_id e legacy_revoked, la corrispondenza con il sistema precedente. |
access_grant_uses | sites.json/access_grants/uses | grant_id (già detto); token_hash (una credenziale). L'indirizzo, mascherato, e il browser ci sono, come l'ufficio li legge nel registro degli usi. |
workers | workers.json | photo_key, link_epoch, compliance_context_version, version (funzionamento interno). La foto è photos/<id>.jpg. |
worker_compliance_facts | workers.json/facts | worker_id (già detto). Un giudizio di idoneità che seleziona un esito resta senza contenuto, con withheld a true; version c'è, perché la pagina del lavoratore la mostra. |
worker_training_reviews | workers.json/training_reviews | worker_id (già detto); context_version (funzionamento interno). |
worker_document_identity_checks | workers.json/identity_checks | worker_id (già detto); link_epoch (funzionamento interno). Per una verifica dei documenti sanitari verification_ref è null: esce con l'archivio sanitario. |
badges | workers.json/badge | worker_id (già detto); attention_transition_id (funzionamento interno). Il token del badge sta in un'altra tabella, badge_tokens, che resta fuori. |
badge_state_changes | workers.json/badge_history | badge_id (già detto); health_employer_id (funzionamento interno). health_employer_id dice quale regola sanitaria di quale impresa ha deciso uno stato: un riferimento che il servizio tiene per la propria lettura del verdetto, non un dato del cliente; la causa sanitaria a cui punta è tolta dai motivi. |
vehicles | vehicles.json | plate_normalized (già detto); version (funzionamento interno). La targa come è stata scritta c'è. |
documents | documents.json | deleted_at (già detto); medical_employer_id (nell'archivio sanitario); version (funzionamento interno). Un documento cancellato non è nell'archivio; un documento sanitario è nell'archivio sanitario. |
document_revisions | documents.json/revisions | document_id, worker_id, employer_id, vehicle_id (già detto); upload_id, vault_key, vault_version_id, inbox_version_id, object_missing_at, version (funzionamento interno). L'originale è nella cartella documents/; un originale mancante è elencato nel manifest, in missing. |
retention_decisions | documents.json/revisions/retention_decisions | revision_id (già detto). |
retention_conflicts | documents.json/revisions/retention_conflicts | revision_id (già detto). |
document_holds | documents.json/holds | document_id (già detto). |
document_reviews | documents.json/reviews | document_id, worker_id, employer_id, vehicle_id (già detto). |
document_review_claims | documents.json/reviews/claims | review_id, document_id (già detto). L'affermazione di un giudizio di idoneità è nell'archivio sanitario. |
attendance_events | attendance_events.json | client_id, health_employer_id (funzionamento interno). client_id è la chiave con cui un dispositivo evita di registrare due volte la stessa timbratura; health_employer_id, lo stesso riferimento interno della storia del badge. |
attendance_presence | presence.json | created_at, updated_at (già detto). period è scritta come starts_at, ends_at. |
timesheet_sends | timesheet_sends.json | xlsx_key, csv_key (funzionamento interno). I file spediti sono nella cartella timesheets/. |
imports | imports.json | file_key (funzionamento interno). Il file caricato non è nell'archivio. |
import_rows | imports.json/rows | import_id (già detto). |
audit_events | audit.json | ip, user_agent (non mostrata dall'ufficio); request_id (funzionamento interno). L'indirizzo e il browser delle righe che riguardano un account, e che l'account stesso ha scritto, sono nell'esportazione di quell'account. |
badge_tokens | Fuori: una credenziale | I token che dal QR aprono la pagina pubblica del badge. |
worker_medical_decisions | Nell'archivio sanitario | Gli esiti dei giudizi di idoneità: nell'archivio sanitario, in workers.json, sotto decisions. |
billing_accounts | Fuori: registri di fatturazione | Il collegamento dello spazio ai sistemi di pagamento e di fatturazione elettronica, e l'email di fatturazione. |
billing_invoices | Fuori: registri di fatturazione | Il registro delle fatture e delle note di credito: le fatture si scaricano da Impostazioni › Piano e fatturazione, e il registro resta ad A176lab per dieci anni. |
subscriptions | Fuori: registri di fatturazione | L'abbonamento al piano: si legge da Impostazioni › Piano e fatturazione. |
billing_checkouts | Fuori: funzionamento interno | Gli acquisti in corso sulla pagina di pagamento, che scadono. |
workspace_exports | Fuori: funzionamento interno | Le richieste di esportazione stesse, con il loro stato. |
deletion_requests | Fuori: funzionamento interno | Le richieste di cancellazione e il loro avanzamento. |
erasure_intents | Fuori: funzionamento interno | I lavori che eseguono una cancellazione, un passo alla volta. |
document_deletions | Fuori: funzionamento interno | I lavori che cancellano un documento o una revisione dall'archivio dei file. |
document_processing_attempts | Fuori: funzionamento interno | I tentativi di controllo e di copia di un file caricato. |
document_uploads | Fuori: funzionamento interno | Le prenotazioni di un caricamento, prima che il file diventi una revisione. |
document_usage | Fuori: funzionamento interno | Il contatore dello spazio occupato dai documenti. |
bot_command_admissions | Fuori: funzionamento interno | L'ammissione dei comandi ricevuti in chat, con le loro scadenze. |
bot_deliveries | Fuori: funzionamento interno | La diagnostica delle consegne dei messaggi dei bot, tenuta 30 giorni: code, tentativi e chiavi del fornitore, mai il testo di un messaggio. |
bot_delivery_sources | Fuori: funzionamento interno | Il legame tra una consegna e ciò che l'ha causata. |
bot_intents | Fuori: funzionamento interno | I passaggi da una chat al wallet per completare una timbratura. |
bot_interactions | Fuori: funzionamento interno | Le interazioni in corso con il bot, che scadono. |
bot_legacy_links | Fuori: funzionamento interno | La corrispondenza con i collegamenti del sistema precedente. |
bot_media_cleanup | Fuori: funzionamento interno | I file temporanei dei bot da cancellare. |
bot_notification_sources | Fuori: funzionamento interno | La coda degli eventi che possono generare un avviso. |
Gli schemi JSON
Ogni file JSON dei due archivi ha uno schema JSON, draft 2020-12, scritto a mano e pubblicato qui all'indirizzo che il suo $id dichiara: ogni campo è descritto, e un campo che lo schema non nomina è rifiutato (additionalProperties: false), salvo negli oggetti che lo schema dice liberi, come le istantanee del registro delle attività. Le prove del servizio costruiscono gli archivi di uno spazio di lavoro di prova e li validano contro questi schemi; ogni archivio ne porta una copia nella cartella schemas/.
L'archivio dello spazio di lavoro
manifest.schema.jsonworkspace.schema.jsonmembers.schema.jsonemployers.schema.jsonsites.schema.jsonworkers.schema.jsonvehicles.schema.jsondocuments.schema.jsonattendance_events.schema.jsonpresence.schema.jsontimesheet_sends.schema.jsonimports.schema.jsonconsents.schema.jsonaudit.schema.json
L'archivio sanitario
Giurisdizione e accesso ai dati
L'articolo 28 del Regolamento (UE) 2023/2854 chiede a chi fornisce servizi di trattamento dei dati di indicare sul proprio sito la giurisdizione a cui è soggetta l'infrastruttura con cui li tratta, e di descrivere le misure tecniche, organizzative e contrattuali che adotta per impedire l'accesso ai dati non personali conservati nell'Unione, o il loro trasferimento, da parte di autorità di paesi terzi, quando sarebbe in contrasto con il diritto dell'Unione o con quello dello Stato membro interessato.
CantiereGo è fornito da A176lab S.r.l., una società con sede in Italia, ad Alcamo (TP), e i Termini di servizio sono regolati dalla legge italiana. L'infrastruttura che conserva i dati dei clienti è nella regione AWS di Milano (eu-south-1), in Italia: il server dell'app e il suo database, gli archivi dei file e dei documenti, le copie di sicurezza e le istantanee del disco dei dati, i registri tecnici. Dalla stessa regione partono le email e gli SMS. Nessuno di questi dati è replicato in un'altra regione.
Le pagine del sito e dell'app arrivano ai browser attraverso CloudFront, la rete di distribuzione di AWS, dai punti di presenza della classe di prezzo scelta, in Europa, Israele, Turchia, Stati Uniti, Messico e Canada; AWS avverte che di tanto in tanto un contenuto può essere servito da un punto di presenza che non fa parte di quella classe. Un punto di presenza termina la connessione cifrata e non conserva le risposte dell'app che portano i dati dei clienti, che arrivano dal server di Milano (sezione 7 dell'Informativa sulla privacy).
Gli altri fornitori che trattano dati per il servizio comprendono quelli che le sezioni 6 e 7 dell'Informativa sulla privacy elencano con il luogo in cui li trattano — Sentry, per le segnalazioni di errore, e Zoho Mail, per la casella info@cantierego.it, li conservano nell'Unione europea; Stripe, per i pagamenti, li tratta in Irlanda e può trasferirli alle società del proprio gruppo negli Stati Uniti — e Fatture in Cloud (TeamSystem S.p.A., Italia), con cui A176lab emette e trasmette le fatture elettroniche ai propri clienti, che conserva i dati nell'Unione europea. Il cliente può inoltre abilitare per il proprio spazio di lavoro i canali Telegram e, dal piano Professional, WhatsApp: i messaggi scambiati con il bot sono trattati dai fornitori di quei canali, Telegram e, per WhatsApp, Meta, secondo i propri termini.
Misure tecniche
- Cifratura a riposo: i dischi del server, compreso quello del database, sono cifrati; gli archivi dei file dell'app e dei documenti sono cifrati con la chiave di S3 gestita da AWS in AWS KMS, gli altri archivi, compreso quello delle copie di sicurezza, con la cifratura lato server di S3.
- Cifratura in transito: i browser raggiungono app.cantierego.it e cantierego.it soltanto con TLS 1.3; il tratto tra CloudFront e il server è cifrato con almeno TLS 1.2 (in TLS 1.2 con i soli cifrari ECDHE e AES-GCM); gli archivi rifiutano ogni richiesta che non arrivi cifrata.
- Accesso all'infrastruttura: il server non conserva chiavi di accesso ad AWS, perché firma ogni sua chiamata con il ruolo dell'istanza, i cui permessi sono limitati agli archivi e ai servizi che il server usa; accetta connessioni web soltanto da CloudFront, che porta un segreto che il server verifica, e non ha una porta SSH aperta su internet.
Misure organizzative
- In A176lab accedono ai dati soltanto le persone autorizzate, vincolate alla riservatezza e solo per quanto serve al servizio (articolo 6.5 dei Termini di servizio).
- Le persone di A176lab accedono all'account AWS con AWS IAM Identity Center, con il secondo fattore a ogni accesso, e al server attraverso una rete privata cifrata, che chiede di nuovo l'identità a intervalli regolari, o, in emergenza, attraverso AWS stesso.
- Un amministratore della piattaforma agisce soltanto da una sessione verificata con il secondo fattore, che dura al più ventiquattro ore, e ogni sua modifica è tracciata nel registro delle attività.
- Le operazioni di gestione dell'account AWS sono registrate da AWS CloudTrail, in ogni regione, con la verifica dell'integrità dei registri.
Misure contrattuali
- Sui dati personali che il Cliente registra, A176lab è responsabile del trattamento e li tratta soltanto su istruzione documentata del Cliente, salvo che lo richieda il diritto dell'Unione o nazionale a cui A176lab è soggetta; in tal caso informa il Cliente di tale obbligo giuridico prima del trattamento, a meno che il diritto vieti tale informazione per rilevanti motivi di interesse pubblico (articolo 6.4 dei Termini di servizio).
- Presso A176lab e i fornitori elencati nella sezione 6 dell'Informativa sulla privacy, i dati non sono trasferiti fuori dall'Unione europea, salvo quanto descritto nella sezione 7 dell'Informativa sulla privacy (articolo 6.4 dei Termini), che ne indica le basi: per il passaggio da CloudFront, l'accordo sul trattamento dei dati di AWS e le clausole contrattuali standard approvate dalla Commissione europea; per Stripe, la decisione di adeguatezza per il Data Privacy Framework UE-USA, a cui Stripe, Inc. aderisce, e le clausole contrattuali standard. Questo impegno non riguarda i messaggi delle chat con i bot Telegram e WhatsApp: il server di A176lab li scambia con Telegram e, attraverso AWS, con Meta, che li trattano secondo i propri termini.
- Ogni fornitore elencato nella sezione 6 dell'Informativa è vincolato da un accordo sul trattamento dei dati; A176lab impone ai sub-responsabili obblighi di protezione dei dati equivalenti a quelli dell'articolo 6 dei Termini, ne risponde verso il Cliente e gli comunica in anticipo l'aggiunta o la sostituzione di un sub-responsabile, a cui il Cliente può opporsi (articolo 6.7).
Il dettaglio è nei testi legali: