Concetti
Cosa sono davvero una Session, una riga Evidence e una Audit Chain, nel minor numero di parole possibile. Leggi questo una volta e il riferimento API avrà senso.
Organizzazione
Il tenant di primo livello. Un'org corrisponde a un account cliente. Ogni altra risorsa (sessioni, prove, eventi di audit, utenti) è vincolata a un'Org tramite row-level security sulle tabelle Postgres sottostanti. Un bug nel codice applicativo non può superare i confini tra tenant — il database rifiuterà la query.
Un'Org ha: membri (utenti con accesso basato sui ruoli), branding (logo / colori / piè di pagina del PDF), un abbonamento di fatturazione, dati opzionali sull'entità legale KYB, configurazione SSO opzionale e una policy di retention.
Membro, Ruolo, Permesso
Un L'appartenenza è il collegamento tra un User e un'Org. Un utente può avere appartenenze in più org e passare dall'una all'altra (l'org attiva viaggia come claim JWT).
Ogni Org inizializza quattro ruoli di sistema alla creazione:
org_admin— controllo completo. Fatturazione, membri, branding, retention.inspector— può eseguire ispezioni, catturare prove, firmare report.observer— accesso in sola lettura a sessioni + dati di audit.auditor— accesso in sola lettura più permesso di verifica della catena.
Gli admin dell'org possono creare ruoli personalizzati componendo il catalogo dei permessi. I permessi vengono verificati per slug al livello della view + controllati in modo incrociato da RLS al livello del DB.
Session
Una ispezione. L'unità di fatturazione (paghi per sessione chiusa) e l'unità di prova (una catena di audit è per sessione, non per org).
Una sessione ha: un operatore (il membro del tuo team che l'ha avviata), uno o più partecipanti (l'utente sul campo, più osservatori opzionali), lo stato del consenso, posizione GPS opzionale, note opzionali, una catena di audit e — una volta chiusa — marche temporali ancorate presso una TSA.
Participant
Una persona in una sessione. C'è un operatore per sessione e almeno un utente sul campo; sono supportati osservatori aggiuntivi opzionali. Gli utenti sul campo si uniscono tramite un URL firmato monouso (nessun account richiesto); operatori + osservatori sono membri dell'Org.
Evidence
Una prova catturata durante una sessione. Tipi:
snapshot— foto statica dalla fotocamera dell'utente sul campo.annotation— disegno sovrapposto a uno snapshot o a una lavagna.whiteboard— canvas Excalidraw della sessione esportato come PNG + stato.clip— breve segmento video.document— file caricato (usato dal livello chat per il PDF-per-firma).
Ogni riga Evidence ha uno SHA-256 del proprio contenuto binario, memorizzato nella catena di audit. La manomissione del file dopo il fatto fa fallire la verifica.
Audit Chain
La spina dorsale crittografica. Ogni evento in una sessione — creazione della sessione, concessione del consenso, registrazione GPS, cattura di prove, annotazione, salvataggio della lavagna, firma, fine della sessione — emette una AuditEvent riga con:
{
"session": "<uuid>",
"sequence": N,
"occurred_at": "<iso8601>",
"kind": "evidence.snapshot_added",
"actor": { "user": <id|null>, "participant": <id|null> },
"payload": { /* event-specific */ },
"prev_hash": "<sha256 of previous event>",
"hash": "<sha256 of canonical_json of this event>"
} Il primo evento usa prev_hash = "0" * 64 (genesis). Ogni evento successivo usa l'hash dell'evento precedente come prev_hash e incrementa sequence di 1. Un advisory lock di Postgres serializza le scritture per sessione; un trigger append-only blocca UPDATE + DELETE sulla tabella.
TimestampToken (ancoraggio TSA)
A fine sessione (e su "stamp now" attivato dall'operatore), la testa della catena corrente viene inviata a tre timestamp authority indipendenti:
- YodaLedger — Ancoraggio sulla blockchain Tezos. Finalità di ~15-20 minuti. Asincrono; riceviamo una callback quando il blocco è confermato.
- FreeTSA — Marca temporale RFC 3161. Sincrona; token restituito immediatamente. Sostituibile con un QTSP a pagamento (DataSure) per la conformità eIDAS Art. 42.
- OpenTimestamps — Ancoraggio su Bitcoin tramite il protocollo di calendario OpenTimestamps. Asincrono; il percorso di upgrade gira su uno sweep Celery.
Tre è una scelta progettuale — se una qualsiasi TSA scompare, le altre due ancorano comunque la catena. Un revisore può verificare rispetto a ciascuna di esse in modo indipendente usando block explorer pubblici / endpoint di verifica.
Signature (SES / AES / QES)
Tre livelli eIDAS, tutti sullo stesso PDF del report di audit:
- SES (Simple Electronic Signature) — supportata dalla catena di audit, nessun certificato di firma. Adatta a documenti interni.
- AES (Advanced Electronic Signature) — certificato di firma vincolato all'identità, ancorato PAdES B-T. Adatta alla maggior parte dei contratti B2B.
- QES (Qualified Electronic Signature) — il livello eIDAS più alto, equivalente legale di una firma autografa in tutta l'UE. Abilitata dietro verifica KYB dell'organizzazione emittente.
Campaign (opzionale)
Un raggruppamento logico di sessioni per la reportistica in batch — "Sinistri auto Q2 2026" o "Difetti di consegna Cantiere A". Le sessioni non richiedono una campagna; è una comodità di reportistica.
Webhook
Un URL registrato dal cliente che riceve POST di eventi firmati HMAC. Tipi di evento: session.created, session.completed,
participant.joined, participant.left,
evidence.added, recording.ready,
audit.anchored, signature.completed, più un webhook.test per la verifica del recapito.
Firma: header in stile Stripe t=...,v1=... con HMAC-SHA256 su <timestamp>.<body>. L'helper constructEvent() dell'SDK verifica in tempo costante con una tolleranza di scarto dell'orologio di 5 minuti.