README.md

March 24, 2026 · View on GitHub

Node.js Sails.js IOTA 2.0 Arweave React Vite TailwindCSS Encryption

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

PanoramicaArchitetturaCodifica On-ChainStackModello DatiSicurezzaFunzionalitaInstallazioneAPI


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)

  1. L'utente interagisce con il frontend React (SPA)
  2. Il frontend invia una richiesta REST al backend Sails.js
  3. Il backend valida i dati, genera le chiavi crittografiche, salva nella cache locale
  4. Il controller risponde immediatamente al client (HTTP 200)
  5. I dati sono gia persistiti su disco (SQLite)
  6. 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
  7. Il client riceve feedback in tempo reale via WebSocket durante le operazioni blockchain

Flusso di avvio (Bootstrap con SQLite)

  1. Step 1: Il server lifta immediatamente — i dati sono gia su disco in .tmp/exart26.db (istantaneo se non e il primo avvio)
  2. Step 2: Sync blockchain in background (non bloccante) — il frontend mostra un banner animato con barra di progresso
  3. 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)

  1. Il payload JSON viene convertito in Buffer
  2. Il buffer viene diviso in blocchi da 7 byte
  3. Ogni blocco viene prefissato con 1 byte di indice (posizione del chunk)
  4. Il risultato (8 byte) viene interpretato come BigInt u64
  5. Le coin risultanti vengono trasferite a se stessi (nessuna perdita di fondi)

Decodifica (_decodeChunksToPayload)

  1. Si leggono gli input u64 dalla transazione (queryTransactionBlocks)
  2. Si verifica il marker: il primo u64 deve essere 1
  3. Il secondo u64 indica la lunghezza del payload
  4. I restanti u64 vengono convertiti in buffer da 8 byte, ordinati per indice (byte 0), concatenati i byte 1-7
  5. Il buffer viene troncato a payloadLength e 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 entityId per 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

ComponenteTecnologiaVersioneRuolo
FrontendReact19SPA con design futuristico dark mode
Build ToolVite6Dev server con HMR e build ottimizzata
StylingTailwindCSS4Utility-first CSS (glassmorphism, neon gradients)
AnimazioniFramer Motion12Transizioni e animazioni fluide
Graforeact-force-graph-2d-Visualizzazione interattiva force-directed
IconeLucide React0.400+Set di icone moderne
RoutingReact Router DOM7Navigazione SPA
BackendSails.js1.5.0Framework MVC, REST API, WebSocket
RuntimeNode.js>= 17Ambiente di esecuzione (consigliato v20+)
Blockchain@iota/iota-sdk1.10+IOTA 2.0 Rebased (Ed25519, Programmable TX)
PermawebArweave1.15.5Backup permanente e immutabile
Cache localesails-disk3.0.1Cache ricostruibile (source of truth = blockchain)
SyncCacheFile JSON (.tmp/sync-cache.json)-Cache persistente per avvio istantaneo del server
Real-timeSocket.io (sails-hook-sockets)2.0.0Feedback live operazioni blockchain
API DocsSwagger UI5.17.2Documentazione interattiva OpenAPI
Rate Limitingexpress-rate-limit7.1.0Disponibile ma disabilitato per compatibilita SPA
CrittografiaNode.js crypto (built-in)-RSA-2048 OAEP SHA-256, AES-256-CBC, HMAC-SHA256
Task RunnerGrunt1.6.1Build 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

ModelloDescrizioneRelazioniCampi chiave
OrganizzazioneEnte sanitario (ASL, cooperativa)1:N con Strutturanome, publicKey, privateKey
StrutturaCentro di riabilitazione fisicoN:1 con Organizzazione, 1:N con Listanome, indirizzo, organizzazione
ListaLista d'attesa per un servizioN:1 con Struttura, M:N con Assistitonome, descrizione, struttura
AssistitoPaziente in attesa di servizioM:N con Lista (via AssistitiListe)nome, cognome, codiceFiscale, publicKey, privateKey
AssistitiListeTabella di giunzioneN:1 con Assistito, N:1 con Listastato, dataInserimento, dataRimozione
BlockchainDataCache locale transazioni blockchain-digest, tag, entityId, version, payload, timestamp

Dove vivono i dati

ModelloCache locale (sails-disk)Blockchain IOTA 2.0Arweave (backup)
OrganizzazioneCacheORGANIZZAZIONE_DATABackup
Struttura + ListeCacheSTRUTTURE_LISTE_DATABackup
AssistitoCacheASSISTITI_DATABackup
Chiavi privateCachePRIVATE_KEY (cifrate RSA)Backup
Indice entita-MAIN_DATABackup

Stati dell'assistito in lista (StatoLista)

CodiceStatoDescrizione
1INSERITO_IN_CODAPaziente in attesa nella lista
2RIMOSSO_IN_ASSISTENZAPreso in carico, riabilitazione avviata
3RIMOSSO_COMPLETATOPercorso riabilitativo concluso
4RIMOSSO_CAMBIO_LISTATrasferito a un'altra lista
5RIMOSSO_RINUNCIARinuncia volontaria del paziente
6RIMOSSO_ANNULLATORimozione 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

AspettoImplementazione
GenerazioneOgni entita (Organizzazione, Struttura, Assistito) riceve una coppia di chiavi RSA-2048 al momento della creazione
Chiave MAINEsiste una coppia di chiavi master (MAIN_PUBLIC_KEY / MAIN_PRIVATE_KEY) usata per cifrare le chiavi private delle entita
Archiviazione privataLe chiavi private delle entita vengono cifrate con la chiave pubblica MAIN e salvate on-chain come transazioni PRIVATE_KEY
Protezione APILe chiavi private non vengono mai esposte nelle risposte JSON grazie a customToJSON() nei modelli
Padding RSAOAEP con SHA-256 (aggiornato da PKCS1 per compatibilita Node.js 22)
Wallet IOTA 2.0Singolo keypair Ed25519 derivato da mnemonic BIP39 (nessun vault Stronghold)

Misure di sicurezza aggiuntive

  • Rate Limiting: disponibile via express-rate-limit ma attualmente disabilitato per compatibilita SPA
  • CSRF Protection: token CSRF disponibile via /csrfToken per 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 blockchain
  • GET /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/grafo con 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/debug per 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/reset per 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

RequisitoVersioneNote
Node.js>= 17Consigliato v20 LTS o v22
npm>= 8Incluso con Node.js
MySQL>= 5.7Solo 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:

  1. L'utente clicca "Inizializza Wallet" nel modale
  2. Il sistema chiama POST /api/v1/wallet/init
  3. Viene generato un nuovo mnemonic BIP39 e derivato un keypair Ed25519
  4. Il mnemonic viene salvato automaticamente nel file di configurazione
  5. Il modale mostra il mnemonic con possibilita di copiarlo
  6. Se la rete e testnet/devnet, i fondi vengono richiesti automaticamente dal faucet
  7. L'utente clicca "Continua" per procedere

Nota: e possibile impostare un mnemonic esistente in config/private_iota_conf.js prima del primo avvio per utilizzare un wallet gia esistente.

Reti disponibili

ReteIOTA_NETWORKNote
IOTA 2.0 TestnettestnetFaucet disponibile, consigliato per sviluppo
IOTA 2.0 DevnetdevnetFaucet disponibile
IOTA 2.0 MainnetmainnetProduzione

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

  1. Andare su arweave.app
  2. Creare un nuovo wallet
  3. Scaricare il file JSON (JWK) - questo e il wallet
  4. Copiare l'intero contenuto del file JSON nel campo ARWEAVE_WALLET_JWK
  5. 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:

  1. Carica la SyncCache da .tmp/sync-cache.json (istantaneo, se presente)
  2. Il server lifta immediatamente con i dati dalla cache
  3. Verifica la connessione al nodo IOTA 2.0
  4. Se il wallet non e inizializzato, il WalletInitModal apparira nel frontend
  5. La sincronizzazione blockchain avviene in background (non bloccante) - il frontend mostra un banner animato con progresso
  6. Se Arweave e configurato, verifica la connessione al gateway
  7. Genera la documentazione Swagger su /docs

Risoluzione problemi

ProblemaSoluzione
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-sdkNormale: 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 stringWarning non bloccante con Node.js >= 20, task Grunt personalizzati risolvono il problema
WalletInitModal non appareVerificare che config/private_iota_conf.js esista. Il modale appare solo se il wallet non e inizializzato
Dati non sincronizzatiUsare 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 funzionaVerificare che il wallet JWK sia completo e che abbia fondi sufficienti
Frontend non si connette al backendVerificare che Sails.js sia in esecuzione sulla porta 1337 e che il proxy Vite sia configurato
Transazione blockchain fallisceVerificare 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)

MetodoRottaDescrizione
GET/api/v1/dashboardStatistiche per la dashboard
GET/api/v1/organizzazioni/:id?Lista organizzazioni (dettaglio se :id)
GET/api/v1/strutture?organizzazione=XLista 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=XDettaglio lista: coda con posizione + storico movimenti
GET/api/v1/graph-dataDati per il grafo interattivo (tutte le entita con relazioni)
GET/api/v1/debugDati debug: wallet, transazioni blockchain con decrypt, DB locale, cross-references

API Pubblica (zero autenticazione, dati anonimizzati)

MetodoRottaDescrizione
GET/api/v1/public/listeListe con assistiti anonimizzati (ID = primi 8 char SHA-256 del CF). Zero dati personali esposti

API Operative (blockchain)

MetodoRottaDescrizione
POST/api/v1/add-organizzazioneCrea organizzazione (risposta immediata, blockchain in background)
POST/api/v1/add-strutturaCrea struttura (risposta immediata, blockchain in background)
POST/api/v1/add-listaCrea lista d'attesa (risposta immediata, blockchain in background)
POST/api/v1/add-assistitoRegistra assistito (risposta immediata, blockchain in background)
POST/api/v1/add-assistito-in-listaInserisce un assistito in una lista d'attesa (risposta immediata, blockchain in background)
POST/api/v1/rimuovi-assistito-da-listaRimuove assistito da lista. Body: { idAssistitoListe, stato }. Stati: 2=in assistenza, 3=completato, 5=rinuncia, 6=annullato
POST/api/v1/fetch-db-from-blockchainRicostruisce la cache locale dalla blockchain (richiede wallet)
POST/api/v1/recover-from-arweaveRecupera tutti i dati dal backup Arweave (richiede wallet)
POST/api/v1/sync-resetCancella la SyncCache e riforza la sincronizzazione da blockchain
GET/api/v1/sync-statusStato sync in tempo reale: syncing, progress percentuale, contatori entita

API Wallet

MetodoRottaDescrizione
POST/api/v1/wallet/initInizializza wallet: genera mnemonic, ritorna { success, mnemonic, address }
POST/api/v1/wallet/resetReset wallet: distrugge e ricrea il wallet (doppia conferma UI)
GET/api/v1/wallet/get-infoRestituisce stato, balance, indirizzo e rete del wallet
GET/api/v1/get-transactionRecupera una transazione specifica

Viste (legacy EJS)

RottaDescrizione
GET /Homepage / redirect automatico
GET /dashboardDashboard (EJS)
GET /organizzazioni/:id?Organizzazioni (EJS)
GET /strutture/:idOrganizzazione?/:id?Strutture (EJS)
GET /assistiti/:id?Assistiti (EJS)
GET /wallet/verificaPagina verifica stato wallet

Utilita

RottaDescrizione
GET /swagger.jsonSchema OpenAPI in formato JSON
GET /docsDocumentazione Swagger UI interattiva
GET /csrfTokenOttieni token CSRF per le richieste
POST /api/v1/observe-my-sessionSottoscrizione 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