README.md
March 24, 2026 · View on GitHub
ExArt26-IOTA
Gestione decentralizzata delle liste d'attesa per la riabilitazione sanitaria (Ex Art. 26)
Dati business interamente on-chain su IOTA 2.0 Rebased, con backup permanente su Arweave
Panoramica • Architettura • Codifica On-Chain • Stack • Modello Dati • Sicurezza • Funzionalita • Installazione • API
Panoramica
ExArt26-IOTA affronta un problema concreto della sanita italiana: la gestione delle liste d'attesa per i percorsi di riabilitazione previsti dall'Art. 26 della Legge 833/1978.
Attualmente, queste liste vengono spesso gestite con fogli di calcolo, documenti cartacei o software centralizzati, esponendole a rischi di:
- Manipolazione dei dati e dell'ordine di inserimento
- Mancanza di trasparenza verso i cittadini in attesa
- Perdita di dati in caso di guasti o errori umani
- Assenza di auditabilita sulle modifiche effettuate
Questa applicazione risolve questi problemi registrando tutti i dati business interamente sulla blockchain IOTA 2.0 Rebased. Non esiste un database locale per i dati operativi: il DB locale (SQLite via better-sqlite3) funge esclusivamente da cache su disco ricostruibile in qualsiasi momento dalla chain. Un backup permanente su Arweave (permaweb) garantisce un ulteriore livello di resilienza. I dati sensibili degli assistiti sono protetti da un sistema di crittografia ibrida a triplo livello (RSA-2048 + AES-256-CBC + HMAC-SHA256).
Il frontend e una Single Page Application moderna costruita con React, Vite e TailwindCSS, con design futuristico dark mode, glassmorphism e neon gradients, ottimizzata come PWA per l'uso su dispositivi mobili.
Architettura
Il sistema e progettato su un'architettura dove la blockchain IOTA 2.0 e la fonte di verita unica (source of truth). Il database locale (SQLite via better-sqlite3) e una cache su disco riscrivibile. I controller CRUD rispondono immediatamente al client dopo il salvataggio in SQLite; la pubblicazione sulla blockchain avviene in background (setImmediate), senza bloccare l'utente. Il file .tmp/exart26.db persiste su disco e garantisce avvio istantaneo del server, con sincronizzazione blockchain in background.
+---------------------------+
| React SPA (Vite) |
| TailwindCSS + Framer |
| Motion + PWA Ready |
| (porta 5173 in dev) |
+------------+--------------+
|
| REST API / WebSocket
v
+---------------------------+
| Sails.js v1.5.0 |
| (porta 1337) |
| +---------+-----------+ |
| | REST API | Actions | |
| +---------+-----------+ |
| | ListManager.js | |
| | CryptHelper.js | |
| | ArweaveHelper.js | |
| | db.js (SQLite) | |
| +-----+-------+-------+ |
+--------+-------+----------+
| |
+------------+ +-------------+
| |
v v
+-----------------------+ +----------------------------+
| SQLite (cache disco) | | IOTA 2.0 Rebased |
| .tmp/exart26.db | | SOURCE OF TRUTH |
| Ricostruibile dalla | | Ed25519 + Programmable |
| blockchain | | TX Blocks (u64 encoding) |
+-----------------------+ +------------+---------------+
|
backup automatico
|
v
+-----------------------+
| Arweave Permaweb |
| (backup permanente) |
+-----------------------+
Flusso di una operazione tipica (non-bloccante)
- L'utente interagisce con il frontend React (SPA)
- Il frontend invia una richiesta REST al backend Sails.js
- Il backend valida i dati, genera le chiavi crittografiche, salva nella cache locale
- Il controller risponde immediatamente al client (HTTP 200)
- I dati sono gia persistiti su disco (SQLite)
- In background (
setImmediate):- I dati vengono cifrati con il sistema ibrido RSA+AES+HMAC
- Il payload cifrato viene codificato come u64 split-coin amounts e pubblicato su IOTA 2.0
- L'indice MAIN_DATA viene aggiornato sulla blockchain
- Una copia viene caricata su Arweave come backup permanente
- Il client riceve feedback in tempo reale via WebSocket durante le operazioni blockchain
Flusso di avvio (Bootstrap con SQLite)
- Step 1: Il server lifta immediatamente — i dati sono gia su disco in
.tmp/exart26.db(istantaneo se non e il primo avvio) - Step 2: Sync blockchain in background (non bloccante) — il frontend mostra un banner animato con barra di progresso
- Step 3: I dati decrittati vengono scritti direttamente su SQLite (zero accumulo RAM)
Codifica Dati On-Chain
Il sistema archivia i dati interamente sulla blockchain IOTA 2.0, senza bisogno di storage esterno. La tecnica sfrutta i Programmable Transaction Blocks: il payload JSON viene suddiviso in chunk da 7 byte, ciascuno codificato come amount u64 di una operazione splitCoins.
Schema della transazione
Programmable Transaction Block:
splitCoins(gas, [amount0, amount1, amount2, ..., amountN])
transferObjects([coin0, coin1, ..., coinN], selfAddress)
amount[0] = 1 <- Marker "exart26"
amount[1] = payloadLength (in bytes) <- Lunghezza totale del JSON
amount[2] = chunk0 (1 byte index + 7 bytes dati)
amount[3] = chunk1 (1 byte index + 7 bytes dati)
...
amount[N] = chunkN-2
Codifica (_encodePayloadToChunks)
- Il payload JSON viene convertito in
Buffer - Il buffer viene diviso in blocchi da 7 byte
- Ogni blocco viene prefissato con 1 byte di indice (posizione del chunk)
- Il risultato (8 byte) viene interpretato come
BigIntu64 - Le coin risultanti vengono trasferite a se stessi (nessuna perdita di fondi)
Decodifica (_decodeChunksToPayload)
- Si leggono gli input
u64dalla transazione (queryTransactionBlocks) - Si verifica il marker: il primo u64 deve essere
1 - Il secondo u64 indica la lunghezza del payload
- I restanti u64 vengono convertiti in buffer da 8 byte, ordinati per indice (byte 0), concatenati i byte 1-7
- Il buffer viene troncato a
payloadLengthe parsato come JSON
MAIN_DATA come indice leggero
Per evitare problemi di scalabilita, il sistema usa una strategia a indice:
- MAIN_DATA contiene solo un indice leggero: la lista di
entityIdper tipo (~50 byte per entita) con il digest dell'ultima transazione - Ogni entita ha la propria transazione dedicata (
ORGANIZZAZIONE_DATA,STRUTTURE_LISTE_DATA,ASSISTITI_DATA,PRIVATE_KEY) - MAIN_DATA serve come start-point certificato per il recovery: al bootstrap si legge l'indice, poi si recupera ogni entita dalla sua transazione
Lettura dalla blockchain
La funzione _queryTransactionsFromChain interroga il nodo IOTA con queryTransactionBlocks filtrando per FromAddress (l'indirizzo del wallet), decodifica ogni transazione e filtra per tag/entityId. Non serve alcun database locale per la lettura.
Stack Tecnologico
| Componente | Tecnologia | Versione | Ruolo |
|---|---|---|---|
| Frontend | React | 19 | SPA con design futuristico dark mode |
| Build Tool | Vite | 6 | Dev server con HMR e build ottimizzata |
| Styling | TailwindCSS | 4 | Utility-first CSS (glassmorphism, neon gradients) |
| Animazioni | Framer Motion | 12 | Transizioni e animazioni fluide |
| Grafo | react-force-graph-2d | - | Visualizzazione interattiva force-directed |
| Icone | Lucide React | 0.400+ | Set di icone moderne |
| Routing | React Router DOM | 7 | Navigazione SPA |
| Backend | Sails.js | 1.5.0 | Framework MVC, REST API, WebSocket |
| Runtime | Node.js | >= 17 | Ambiente di esecuzione (consigliato v20+) |
| Blockchain | @iota/iota-sdk | 1.10+ | IOTA 2.0 Rebased (Ed25519, Programmable TX) |
| Permaweb | Arweave | 1.15.5 | Backup permanente e immutabile |
| Cache locale | sails-disk | 3.0.1 | Cache ricostruibile (source of truth = blockchain) |
| SyncCache | File JSON (.tmp/sync-cache.json) | - | Cache persistente per avvio istantaneo del server |
| Real-time | Socket.io (sails-hook-sockets) | 2.0.0 | Feedback live operazioni blockchain |
| API Docs | Swagger UI | 5.17.2 | Documentazione interattiva OpenAPI |
| Rate Limiting | express-rate-limit | 7.1.0 | Disponibile ma disabilitato per compatibilita SPA |
| Crittografia | Node.js crypto (built-in) | - | RSA-2048 OAEP SHA-256, AES-256-CBC, HMAC-SHA256 |
| Task Runner | Grunt | 1.6.1 | Build e pipeline asset (con fix Node.js >= 20) |
Modello Dati
La gerarchia dei dati riflette l'organizzazione reale del sistema sanitario riabilitativo:
Organizzazione (ASL, Ente)
|
+-- ha molte --> Struttura (Centro di riabilitazione)
|
+-- ha molte --> Lista (Lista d'attesa specifica)
|
+-- M:N --> Assistito (Paziente)
(via AssistitiListe)
Dettaglio dei modelli
| Modello | Descrizione | Relazioni | Campi chiave |
|---|---|---|---|
| Organizzazione | Ente sanitario (ASL, cooperativa) | 1:N con Struttura | nome, publicKey, privateKey |
| Struttura | Centro di riabilitazione fisico | N:1 con Organizzazione, 1:N con Lista | nome, indirizzo, organizzazione |
| Lista | Lista d'attesa per un servizio | N:1 con Struttura, M:N con Assistito | nome, descrizione, struttura |
| Assistito | Paziente in attesa di servizio | M:N con Lista (via AssistitiListe) | nome, cognome, codiceFiscale, publicKey, privateKey |
| AssistitiListe | Tabella di giunzione | N:1 con Assistito, N:1 con Lista | stato, dataInserimento, dataRimozione |
| BlockchainData | Cache locale transazioni blockchain | - | digest, tag, entityId, version, payload, timestamp |
Dove vivono i dati
| Modello | Cache locale (sails-disk) | Blockchain IOTA 2.0 | Arweave (backup) |
|---|---|---|---|
| Organizzazione | Cache | ORGANIZZAZIONE_DATA | Backup |
| Struttura + Liste | Cache | STRUTTURE_LISTE_DATA | Backup |
| Assistito | Cache | ASSISTITI_DATA | Backup |
| Chiavi private | Cache | PRIVATE_KEY (cifrate RSA) | Backup |
| Indice entita | - | MAIN_DATA | Backup |
Stati dell'assistito in lista (StatoLista)
| Codice | Stato | Descrizione |
|---|---|---|
| 1 | INSERITO_IN_CODA | Paziente in attesa nella lista |
| 2 | RIMOSSO_IN_ASSISTENZA | Preso in carico, riabilitazione avviata |
| 3 | RIMOSSO_COMPLETATO | Percorso riabilitativo concluso |
| 4 | RIMOSSO_CAMBIO_LISTA | Trasferito a un'altra lista |
| 5 | RIMOSSO_RINUNCIA | Rinuncia volontaria del paziente |
| 6 | RIMOSSO_ANNULLATO | Rimozione per annullamento amministrativo |
Sicurezza e Crittografia
Il sistema implementa un meccanismo di crittografia ibrida a triplo livello per garantire riservatezza, autenticita e integrita dei dati sanitari.
Schema crittografico
Dati in chiaro (JSON)
|
v
+---------------------+
| AES-256-CBC | <-- Chiave simmetrica generata casualmente per ogni transazione
| (cifratura dati) |
+-----+---------------+
|
v
Dati cifrati (ciphertext)
+
+---------------------+
| RSA-2048 OAEP | <-- La chiave AES viene cifrata con la chiave pubblica
| (cifratura chiave) | del destinatario
+-----+---------------+
|
v
Chiave AES cifrata (encryptedKey)
+
+---------------------+
| HMAC-SHA256 | <-- Firma di integrita calcolata sul ciphertext
| (integrita) |
+-----+---------------+
|
v
Payload completo --> u64 encoding --> Blockchain IOTA 2.0 + Arweave
Gestione delle chiavi
| Aspetto | Implementazione |
|---|---|
| Generazione | Ogni entita (Organizzazione, Struttura, Assistito) riceve una coppia di chiavi RSA-2048 al momento della creazione |
| Chiave MAIN | Esiste una coppia di chiavi master (MAIN_PUBLIC_KEY / MAIN_PRIVATE_KEY) usata per cifrare le chiavi private delle entita |
| Archiviazione privata | Le chiavi private delle entita vengono cifrate con la chiave pubblica MAIN e salvate on-chain come transazioni PRIVATE_KEY |
| Protezione API | Le chiavi private non vengono mai esposte nelle risposte JSON grazie a customToJSON() nei modelli |
| Padding RSA | OAEP con SHA-256 (aggiornato da PKCS1 per compatibilita Node.js 22) |
| Wallet IOTA 2.0 | Singolo keypair Ed25519 derivato da mnemonic BIP39 (nessun vault Stronghold) |
Misure di sicurezza aggiuntive
- Rate Limiting: disponibile via
express-rate-limitma attualmente disabilitato per compatibilita SPA - CSRF Protection: token CSRF disponibile via
/csrfTokenper le richieste mutative - Nessuna autenticazione: l'applicazione e attualmente in modalita aperta (tutte le rotte pubbliche)
- Policy: le rotte admin (
fetch-db-from-blockchain,recover-from-arweave) richiedono wallet inizializzato
Funzionalita
Gestione liste d'attesa
- Creazione e gestione di organizzazioni, strutture, liste e assistiti
- Inserimento e rimozione assistiti dalle liste con tracciamento dello stato e dei timestamp
- Pagina Liste dedicata (
/app/liste): layout a 2 colonne con filtro testuale, cards per lista con statistiche (in coda, usciti, media attesa giorni), vista coda con posizioni, bottone "Chiama" per il primo in coda, toggle Coda/Storico - Rimozione assistiti: selezione dello stato di uscita (in assistenza, completato, rinuncia, annullato)
- Statistiche liste: API strutture arricchita con stats per lista (inCoda, usciti, totale, tempoMedioGiorni)
- Assistiti con liste: la tabella assistiti mostra le liste assegnate con posizione in coda (#1, #2...)
- Relazioni many-to-many: un assistito puo essere in piu liste contemporaneamente
Dati interamente on-chain
- Zero database locale per i dati business: tutto e archiviato sulla blockchain IOTA 2.0 Rebased
- I dati vengono codificati come u64 split-coin amounts nei Programmable Transaction Blocks
- MAIN_DATA come indice leggero: contiene solo la lista di entityId per tipo, non l'intero dataset
- Ogni entita ha la propria transazione dedicata sulla chain
- Il DB locale (sails-disk) e una cache ricostruibile dalla blockchain in qualsiasi momento
- Controller non-bloccanti: tutti i CRUD (inclusi add-assistito-in-lista e rimuovi-assistito-da-lista) rispondono immediatamente al client, pubblicazione blockchain in background via
setImmediate
SyncCache - Avvio istantaneo
- Cache locale persistente su file
.tmp/sync-cache.json - Al bootstrap il server lifta immediatamente con i dati dalla cache, senza aspettare la blockchain
- La sincronizzazione blockchain avviene in background (non bloccante)
- Ogni operazione CRUD aggiorna la cache automaticamente (debounced 5 secondi)
POST /api/v1/sync-reset: cancella la cache e riforza la sync da blockchainGET /api/v1/sync-status: stato sync in tempo reale (syncing, progress, contatori)- Banner sync nell'UI: barra di progresso animata visibile su ogni pagina durante la sincronizzazione, con status, percentuale e contatori (org/str/ass). Polling ogni 2 secondi, scompare automaticamente al completamento
Backup permanente su Arweave
- Backup automatico di ogni transazione sul permaweb Arweave
- I dati su Arweave sono permanenti e immutabili per design del protocollo
- Recovery da Arweave: in caso di perdita dei dati IOTA, e possibile recuperare tutto dal backup Arweave (
recover-from-arweave) - Il backup e non-bloccante: se Arweave fallisce, l'operazione IOTA non viene interrotta
Consultazione Pubblica Anonimizzata
- Pagina Pubblico (
/app/pubblico): frontend accessibile senza autenticazione per la verifica della posizione in lista - Ogni assistito viene mostrato come ID anonimo (primi 8 caratteri dello SHA-256 del codice fiscale)
- L'utente inserisce il proprio codice fiscale, che viene hashato lato client (mai inviato al server)
- La posizione corrispondente viene evidenziata nella lista
- Toggle Coda/Storico per ogni lista
- Zero dati personali esposti: nessun nome, cognome o codice fiscale visibile
- API dedicata:
GET /api/v1/public/liste
Visualizzazione Grafo
- Pagina
/app/grafocon grafo interattivo force-directed (react-force-graph-2d) - Tutte le entita rappresentate come nodi con codifica colore per tipo (organizzazioni, strutture, liste, assistiti, trattati)
- Nodi Trattati: pazienti usciti dalla lista, aggregati per lista, visualizzati come nodi dedicati nel grafo
- Pannello dettagli al hover con chiavi, indirizzi e timestamp
- Controlli zoom e layout
Load Test e Simulazione
- Pagina Load Test (
/app/load-test): generazione dati di prova direttamente dall'UI con log in tempo reale delle operazioni eseguite npm run simulate: script CLI per simulazione continua infinita con crescita proporzionale, utile per stress test e demo
Pagina Debug
- Pagina
/app/debugper diagnostica e verifica del sistema - Mostra stato wallet (indirizzo, balance, rete)
- Visualizza transazioni blockchain con decrypt del payload cifrato
- Mostra contenuto DB locale (cache)
- Cross-references con verifica di consistency tra DB e blockchain
- API dedicata:
GET /api/v1/debug
Gestione Wallet
- WalletInitModal: modale globale presente in ogni pagina, si attiva automaticamente se il wallet non e inizializzato
- Inizializzazione wallet via API
POST /api/v1/wallet/init(genera mnemonic, mostra con copia, richiede fondi faucet) - Reset Wallet:
POST /api/v1/wallet/resetper distruggere e ricreare il wallet con doppia conferma UI - Pagina dedicata per stato e informazioni wallet
- Keypair Ed25519 singolo derivato da mnemonic BIP39
Frontend moderno
- Single Page Application con React 19 e React Router 7
- Design futuristico dark mode con glassmorphism e neon gradients
- Animazioni fluide con Framer Motion
- Pagine: Dashboard, Organizzazioni, Strutture, Assistiti, Liste, Wallet, Grafo, Pubblico, Debug, Load Test
- PWA ready per supporto mobile
- Feedback WebSocket durante le operazioni blockchain (progresso, conferme, errori)
Documentazione API
- Swagger UI integrata e accessibile a
/docs - Schema OpenAPI auto-generato disponibile a
/swagger.json
Guida all'Installazione e Avvio
Prerequisiti
| Requisito | Versione | Note |
|---|---|---|
| Node.js | >= 17 | Consigliato v20 LTS o v22 |
| npm | >= 8 | Incluso con Node.js |
| MySQL | >= 5.7 | Solo per produzione (in sviluppo usa sails-disk come cache) |
1. Clonare il repository
git clone https://github.com/deduzzo/exart-26-iota.git
cd exart-26-iota
2. Installare le dipendenze backend
npm install
3. Installare le dipendenze frontend
cd frontend
npm install
cd ..
4. Configurare IOTA 2.0 Rebased (obbligatorio)
Questa configurazione e necessaria per avviare l'applicazione.
cp config/sample_private_iota_conf.js config/private_iota_conf.js
Editare config/private_iota_conf.js con i propri parametri:
module.exports = {
// Rete: 'testnet' | 'mainnet' | 'devnet'
IOTA_NETWORK: 'testnet',
// URL nodo custom (null = usa il default della rete selezionata)
IOTA_NODE_URL: null,
// Mnemonic BIP39 per il keypair Ed25519
// Viene generato automaticamente via WalletInitModal se null
IOTA_MNEMONIC: null,
// Chiavi RSA-2048 per crittografia dei dati
MAIN_PRIVATE_KEY: 'YOUR_RSA_PRIVATE_KEY',
MAIN_PUBLIC_KEY: 'YOUR_RSA_PUBLIC_KEY',
// Explorer URL
IOTA_EXPLORER_URL: 'https://explorer.rebased.iota.org',
};
Generare le chiavi RSA
Le chiavi RSA master sono fondamentali: vengono usate per cifrare/decifrare tutte le chiavi private delle entita. Per generarle:
node -e "require('./api/utility/CryptHelper').RSAGenerateKeyPair().then(k => console.log(JSON.stringify(k, null, 2)))"
Copiare i valori privateKey e publicKey nei campi MAIN_PRIVATE_KEY e MAIN_PUBLIC_KEY.
Importante: conservare la chiave privata master in un luogo sicuro. Senza di essa non sara possibile decifrare i dati sulla blockchain.
Inizializzazione Wallet
Il wallet viene inizializzato tramite il WalletInitModal, un modale che appare automaticamente nel frontend su ogni pagina se il wallet non e ancora configurato:
- L'utente clicca "Inizializza Wallet" nel modale
- Il sistema chiama
POST /api/v1/wallet/init - Viene generato un nuovo mnemonic BIP39 e derivato un keypair Ed25519
- Il mnemonic viene salvato automaticamente nel file di configurazione
- Il modale mostra il mnemonic con possibilita di copiarlo
- Se la rete e testnet/devnet, i fondi vengono richiesti automaticamente dal faucet
- L'utente clicca "Continua" per procedere
Nota: e possibile impostare un mnemonic esistente in
config/private_iota_conf.jsprima del primo avvio per utilizzare un wallet gia esistente.
Reti disponibili
| Rete | IOTA_NETWORK | Note |
|---|---|---|
| IOTA 2.0 Testnet | testnet | Faucet disponibile, consigliato per sviluppo |
| IOTA 2.0 Devnet | devnet | Faucet disponibile |
| IOTA 2.0 Mainnet | mainnet | Produzione |
Richiedere fondi dal faucet (testnet/devnet)
I fondi vengono richiesti automaticamente all'inizializzazione del wallet. Per richiedere fondi aggiuntivi, utilizzare la pagina Wallet nel frontend oppure l'API:
curl http://localhost:1337/api/v1/wallet/get-info
5. Configurare Arweave - Backup Permanente (opzionale)
Arweave fornisce un layer di backup permanente e immutabile. Se configurato, ogni transazione IOTA viene automaticamente duplicata su Arweave. Se non configurato, il sistema funziona normalmente solo con IOTA.
cp config/sample_private_arweave_conf.js config/private_arweave_conf.js
Editare config/private_arweave_conf.js:
module.exports = {
// Host del gateway Arweave
ARWEAVE_HOST: 'arweave.net',
ARWEAVE_PORT: 443,
ARWEAVE_PROTOCOL: 'https',
// Wallet JWK - copiare qui il contenuto del file JSON scaricato
ARWEAVE_WALLET_JWK: {
"kty": "RSA",
"n": "...",
"e": "...",
// ... contenuto completo del file JWK
},
};
Come ottenere un wallet Arweave
- Andare su arweave.app
- Creare un nuovo wallet
- Scaricare il file JSON (JWK) - questo e il wallet
- Copiare l'intero contenuto del file JSON nel campo
ARWEAVE_WALLET_JWK - Finanziare il wallet con AR token (per testnet: faucet.arweave.net)
6. Avviare l'applicazione
Sviluppo (due terminali)
Terminale 1 - Backend Sails.js:
node app.js
Il backend sara disponibile su http://localhost:1337.
Terminale 2 - Frontend React:
cd frontend
npm run dev
Il frontend sara disponibile su http://localhost:5173 con proxy automatico verso il backend.
Simulazione dati (opzionale):
npm run simulate
Avvia una simulazione continua infinita con crescita proporzionale (utile per test e demo).
Produzione
# Build del frontend
cd frontend
npm run build
cd ..
# Avvio del backend (serve anche il frontend compilato)
NODE_ENV=production node app.js
In produzione il frontend compilato viene servito da Sails.js tramite la rotta catch-all GET /app/*.
Primo avvio
Al primo avvio, il sistema:
- Carica la SyncCache da
.tmp/sync-cache.json(istantaneo, se presente) - Il server lifta immediatamente con i dati dalla cache
- Verifica la connessione al nodo IOTA 2.0
- Se il wallet non e inizializzato, il WalletInitModal apparira nel frontend
- La sincronizzazione blockchain avviene in background (non bloccante) - il frontend mostra un banner animato con progresso
- Se Arweave e configurato, verifica la connessione al gateway
- Genera la documentazione Swagger su
/docs
Risoluzione problemi
| Problema | Soluzione |
|---|---|
Cannot find module '../../config/private_iota_conf' | Copiare il sample: cp config/sample_private_iota_conf.js config/private_iota_conf.js |
ERR_REQUIRE_ESM con @iota/iota-sdk | Normale: l'SDK usa ESM, il sistema lo gestisce con dynamic import(). Verificare che iota.js usi loadSdk() |
Errore Grunt Cannot convert a Symbol value to a string | Warning non bloccante con Node.js >= 20, task Grunt personalizzati risolvono il problema |
| WalletInitModal non appare | Verificare che config/private_iota_conf.js esista. Il modale appare solo se il wallet non e inizializzato |
| Dati non sincronizzati | Usare POST /api/v1/sync-reset per cancellare la cache e riforzare la sync, oppure POST /api/v1/fetch-db-from-blockchain per ricostruire la cache dalla blockchain |
| Arweave non funziona | Verificare che il wallet JWK sia completo e che abbia fondi sufficienti |
| Frontend non si connette al backend | Verificare che Sails.js sia in esecuzione sulla porta 1337 e che il proxy Vite sia configurato |
| Transazione blockchain fallisce | Verificare il balance del wallet. Per testnet/devnet usare il faucet dalla pagina Wallet |
Struttura Progetto
exart26-iota/
|
+-- frontend/ # Frontend React SPA
| +-- src/
| | +-- pages/ # Dashboard, Organizzazioni, Strutture, Assistiti, Liste, Wallet, Grafo, Pubblico, Debug, LoadTest
| | +-- components/ # Layout, WalletInitModal, LoadingSpinner, ...
| | +-- hooks/ # Custom React hooks (useApi, ...)
| | +-- api/ # Client API per comunicazione con backend
| | +-- utils/ # Utility frontend (formatters, ...)
| | +-- App.jsx # Router e layout principale
| | +-- main.jsx # Entry point React
| | +-- index.css # Stili globali TailwindCSS
| +-- public/ # Asset statici
| +-- vite.config.js # Configurazione Vite (proxy, build)
| +-- package.json # Dipendenze frontend
|
+-- api/
| +-- controllers/ # Action-based controllers (Sails.js actions2)
| | +-- dashboard/ # Dashboard
| | +-- wallet/ # get-info, init-wallet, reset-wallet, view-verifica
| | +-- add-organizzazione.js # Non-bloccante (setImmediate per blockchain)
| | +-- add-struttura.js # Non-bloccante
| | +-- add-lista.js # Non-bloccante
| | +-- add-assistito.js # Non-bloccante
| | +-- add-assistito-in-lista.js # Non-bloccante
| | +-- rimuovi-assistito-da-lista.js # Non-bloccante, con selezione stato
| | +-- fetch-db-from-blockchain.js
| | +-- recover-from-arweave.js
| | +-- api-dashboard.js # GET /api/v1/dashboard (JSON)
| | +-- api-organizzazioni.js # GET /api/v1/organizzazioni (JSON)
| | +-- api-strutture.js # GET /api/v1/strutture con stats liste (JSON)
| | +-- api-assistiti.js # GET /api/v1/assistiti con liste e posizione (JSON)
| | +-- api-liste-dettaglio.js # GET /api/v1/liste-dettaglio: coda + storico (JSON)
| | +-- api-graph-data.js # GET /api/v1/graph-data (JSON)
| | +-- api-public.js # GET /api/v1/public/liste (dati anonimizzati)
| | +-- api-debug.js # GET /api/v1/debug (diagnostica)
| | +-- view-*.js # Controller delle viste (legacy)
| |
| +-- enums/ # Enumerazioni
| | +-- StatoLista.js # Stati dell'assistito in lista (6 stati)
| | +-- TransactionDataType.js # Tipi di payload blockchain (8 tipi)
| |
| +-- models/ # Modelli Waterline ORM
| | +-- Organizzazione.js
| | +-- Struttura.js
| | +-- Lista.js
| | +-- Assistito.js
| | +-- AssistitiListe.js # Tabella di giunzione M:N
| | +-- BlockchainData.js # Cache locale transazioni blockchain
| | +-- View.js
| |
| +-- utility/ # Componenti core del sistema
| | +-- iota.js # IOTA 2.0: u64 encoding, publishData, query on-chain
| | +-- ListManager.js # Logica business, MAIN_DATA index, sync blockchain->cache
| | +-- CryptHelper.js # Crittografia ibrida RSA+AES+HMAC
| | +-- ArweaveHelper.js # Backup e recovery da Arweave permaweb
| | +-- SyncCache.js # Cache locale persistente su file per avvio istantaneo
| |
| +-- helpers/ # Sails.js helpers riutilizzabili
| +-- hooks/ # Hook personalizzati
| +-- policies/ # Middleware (is-wallet-initialized)
| +-- responses/ # Risposte HTTP personalizzate
|
+-- config/
| +-- routes.js # Definizione di tutte le rotte (REST + SPA catch-all)
| +-- security.js # CSRF, CORS
| +-- datastores.js # Connessione database (sails-disk come cache)
| +-- custom.js # Parametri personalizzati (URL, email, token)
| +-- bootstrap.js # Carica SyncCache, lifta server, sync blockchain in background
| +-- policies.js # Mapping policy -> rotte (tutte pubbliche)
| +-- sample_private_iota_conf.js # Template configurazione IOTA 2.0
| +-- sample_private_arweave_conf.js # Template configurazione Arweave
|
+-- views/ # Template EJS (legacy)
+-- assets/ # File statici backend
+-- swagger/ # Schema OpenAPI generato
+-- tasks/ # Task Grunt personalizzati (fix Node.js >= 20)
+-- scripts/ # Script di utilita
API Endpoints
API JSON (per frontend React)
| Metodo | Rotta | Descrizione |
|---|---|---|
GET | /api/v1/dashboard | Statistiche per la dashboard |
GET | /api/v1/organizzazioni/:id? | Lista organizzazioni (dettaglio se :id) |
GET | /api/v1/strutture?organizzazione=X | Lista strutture filtrate per organizzazione, con stats per lista (inCoda, usciti, totale, tempoMedioGiorni) |
GET | /api/v1/assistiti/:id? | Lista assistiti con liste assegnate e posizione in coda (dettaglio se :id) |
GET | /api/v1/liste-dettaglio?idLista=X | Dettaglio lista: coda con posizione + storico movimenti |
GET | /api/v1/graph-data | Dati per il grafo interattivo (tutte le entita con relazioni) |
GET | /api/v1/debug | Dati debug: wallet, transazioni blockchain con decrypt, DB locale, cross-references |
API Pubblica (zero autenticazione, dati anonimizzati)
| Metodo | Rotta | Descrizione |
|---|---|---|
GET | /api/v1/public/liste | Liste con assistiti anonimizzati (ID = primi 8 char SHA-256 del CF). Zero dati personali esposti |
API Operative (blockchain)
| Metodo | Rotta | Descrizione |
|---|---|---|
POST | /api/v1/add-organizzazione | Crea organizzazione (risposta immediata, blockchain in background) |
POST | /api/v1/add-struttura | Crea struttura (risposta immediata, blockchain in background) |
POST | /api/v1/add-lista | Crea lista d'attesa (risposta immediata, blockchain in background) |
POST | /api/v1/add-assistito | Registra assistito (risposta immediata, blockchain in background) |
POST | /api/v1/add-assistito-in-lista | Inserisce un assistito in una lista d'attesa (risposta immediata, blockchain in background) |
POST | /api/v1/rimuovi-assistito-da-lista | Rimuove assistito da lista. Body: { idAssistitoListe, stato }. Stati: 2=in assistenza, 3=completato, 5=rinuncia, 6=annullato |
POST | /api/v1/fetch-db-from-blockchain | Ricostruisce la cache locale dalla blockchain (richiede wallet) |
POST | /api/v1/recover-from-arweave | Recupera tutti i dati dal backup Arweave (richiede wallet) |
POST | /api/v1/sync-reset | Cancella la SyncCache e riforza la sincronizzazione da blockchain |
GET | /api/v1/sync-status | Stato sync in tempo reale: syncing, progress percentuale, contatori entita |
API Wallet
| Metodo | Rotta | Descrizione |
|---|---|---|
POST | /api/v1/wallet/init | Inizializza wallet: genera mnemonic, ritorna { success, mnemonic, address } |
POST | /api/v1/wallet/reset | Reset wallet: distrugge e ricrea il wallet (doppia conferma UI) |
GET | /api/v1/wallet/get-info | Restituisce stato, balance, indirizzo e rete del wallet |
GET | /api/v1/get-transaction | Recupera una transazione specifica |
Viste (legacy EJS)
| Rotta | Descrizione |
|---|---|
GET / | Homepage / redirect automatico |
GET /dashboard | Dashboard (EJS) |
GET /organizzazioni/:id? | Organizzazioni (EJS) |
GET /strutture/:idOrganizzazione?/:id? | Strutture (EJS) |
GET /assistiti/:id? | Assistiti (EJS) |
GET /wallet/verifica | Pagina verifica stato wallet |
Utilita
| Rotta | Descrizione |
|---|---|
GET /swagger.json | Schema OpenAPI in formato JSON |
GET /docs | Documentazione Swagger UI interattiva |
GET /csrfToken | Ottieni token CSRF per le richieste |
POST /api/v1/observe-my-session | Sottoscrizione WebSocket per sessione corrente |
GET /app/* | SPA catch-all: serve il frontend React compilato |
Roadmap
- Implementazione completa della gestione movimenti tra liste (pagina Liste con coda, storico, rimozione con stato)
- Interfaccia pubblica per consultazione posizione in lista (anonimizzata con hash SHA-256 del CF)
- SyncCache per avvio istantaneo del server con sync blockchain in background
- Banner sync animato nell'UI con barra di progresso e contatori
- Pagina Load Test per generazione dati di prova dall'UI
- Script CLI di simulazione continua (
npm run simulate) - Pagina Liste a 2 colonne con filtro testuale
- Nodi Trattati nel grafo (pazienti usciti aggregati per lista)
- Dashboard analitica avanzata con grafici temporali
- Esportazione dati in formato PDF e CSV
- Notifiche push per aggiornamenti di stato
- Supporto multi-lingua (i18n)
- Test automatizzati end-to-end
- Containerizzazione con Docker
- Supporto IOTA 2.0 mainnet in produzione
- Integrazione con sistemi informativi sanitari regionali
- Autenticazione e autorizzazione utenti
Licenza
Questo progetto e distribuito con finalita di ricerca e sviluppo. Per informazioni sulla licenza, contattare l'autore.
Autore
Sviluppato da deduzzo
ExArt26-IOTA — Dati sanitari interamente on-chain, trasparenti e immutabili