πŸ”¨
DatasetForge Β· Docs
Documentazione, guida utente & architettura
← App πŸ“˜ API Reference

DatasetForge

Micro-gestionale FastAPI per la curazione e validazione del dataset di fine-tuning LLM Nutriverso. Editor collaborativo, flag system avanzato, grafo di navigazione interattivo e pipeline di validazione incrociata.

Cosa fa DatasetForge?

  • Dataset editing β€” CRUD entry JSONL, validazione mojibake/code-leak, export
  • Flag System V3 β€” 11 tipi di flag, workflow biforcato (umano + auto), anti-flooding
  • Graph Layer β€” endpoint per navigare il grafo del sito (path finder, neighbors, search)
  • Cross-validation β€” pipeline 5-stadi che verifica coerenza dataset ↔ grafo
  • Graph Mapper β€” crawler per espandere/verificare il grafo (bundle statico + crawl dinamico)
  • Backup & health β€” backup atomici crash-safe, health score dataset + grafo

Stack tecnologico

LivelloTecnologia
BackendFastAPI + uvicorn + pydantic v2
FrontendHTML + CSS + JavaScript vanilla (no framework, no build step)
Grafocytoscape.js per la visualizzazione interattiva
Validazione testopyahocorasick (gazetteer) + rapidfuzz (fuzzy)
Semantica (opt.)sentence-transformers (LaBSE/MiniLM multilingue) + faiss-cpu
DeployContainer Docker 100% replicabile

Avvio rapido

cd tools/datasetforge
pip install -r requirements.txt
python3 server.py    # β†’ http://localhost:8420

Come iniziare

1. Avvia il server

DatasetForge gira su http://127.0.0.1:8420 di default.

python3 server.py
# βœ… Server running at http://127.0.0.1:8420

2. Verifica che sia attivo

curl http://127.0.0.1:8420/api/health
# β†’ {"status":"ok","entries":4926,"version":"2.1"}

3. Apri l'interfaccia web

Naviga su http://127.0.0.1:8420/ β€” vedrai la tabella delle entry del dataset con filtri, ricerca e strumenti.

Autenticazione & API Key

Ogni chiamata API (eccetto /api/health, le pagine web e /docs) richiede l'header X-API-Key. Le chiavi sono mappate in keys.json con un agent_id e un role.

RuoloCosa puΓ² fare
readerSolo GET: leggere dataset, flag, grafo, changelog
writer+ write non distruttive: creare/modificare entry e flag, rispondere, crossval
admin+ operazioni distruttive: delete, restore backup, apply-fix, revert, resolve

Usare una API Key

# Health (pubblico, no key)
curl http://127.0.0.1:8420/api/health

# Autenticato (reader)
curl -H "X-API-Key: YOUR-KEY" http://127.0.0.1:8420/api/stats

# Creare una entry (writer)
curl -X POST -H "X-API-Key: YOUR-KEY" \
  -H "Content-Type: application/json" \
  http://127.0.0.1:8420/api/entries \
  -d '{"messages":[...],"lang":"it"}'

Nella web UI: l'API key viene richiesta al primo accesso se l'autenticazione Γ¨ attiva. Viene salvata in localStorage e inviata automaticamente ad ogni richiesta. Se la modalitΓ  Γ¨ "open" (auth disabilitata), l'accesso Γ¨ diretto in read-only.

FunzionalitΓ  implementate

Le funzionalitΓ  dell'interfaccia sono definite da user stories con criteri di accettazione espliciti.

US-01 Visualizzare il dataset
Tabella paginata con colonne #, Lingua, Sorgente, Domanda, Risposta, Diff, Lunghezza. 50 entry per pagina, ordinamento per colonna, badge colorati per lingua (🟒IT πŸ”΅EN 🟑ES 🟠FR), evidenziazione duplicati, caricamento < 1s.
US-02 Cercare e filtrare
Ricerca istantanea (debounce 300ms) su domanda + risposta. Filtri per lingua, sorgente, difficoltΓ , tag, solo duplicati, lunghezza risposta. Combinazione AND, URL bookmarkable, reset con un click.
US-03 Modificare una entry
Click su riga β†’ editor modale con domanda, risposta, lang, source, difficulty, tags. System prompt in readonly. Contatore caratteri, anteprima chat, validazione pre-salvataggio (mojibake, code-leak). Ctrl+Enter per salvare, Esc per annullare. Auto-backup.
US-04 Aggiungere una entry
Bottone "+ Nuova entry". Form con domanda, risposta, lang (default IT), source (default manual), difficulty, tags. System prompt precompilato. Opzione "Aggiungi un'altra".
US-05 Eliminare una entry
Solo admin. Conferma modale irreversibile (backup resta). Auto-backup + audit log automatico.
US-06 Duplicare una entry
Bottone "Duplica" nell'editor: crea copia identica con nuovo ID, apre l'editor sulla nuova entry, aggiunge tag automatico variant-of-{id}.
US-07 Statistiche dashboard
Conteggio totale, distribuzione per lingua/sorgente/difficulty (bar chart), top 10 risposte duplicate, lunghezza media/mediana, stima categorie. Aggiornamento in tempo reale.
US-08 Validare il dataset
Bottone "Valida tutto": JSON valido, system prompt identico, encoding corretto, coerenza lingua, nessun campo vuoto, nessun leak codice. Progress bar + report con click sull'errore β†’ apre la entry.
US-09 Export dataset
Export JSONL: tutto o filtrato. File dataset_export_YYYYMMDD_HHMMSS.jsonl pronto per il training.
US-10 Bulk edit via API
POST /api/bulk e /api/bulk/create per Claude agent. Rate limit 200 modifiche/richiesta, validazione atomica (tutto o niente), auto-backup.
US-11 Audit log
Ogni modifica genera record in changelog.jsonl. UI con tabella, filtri (user, data, azione), revert (solo admin).
US-12 Login e autenticazione
Login con API key + nome utente. Sessione cookie HttpOnly 24h. ModalitΓ  "open" per accesso read-only diretto.
US-13 Multi-turn editor
L'editor riconosce entry con >3 messaggi, mostra tutti i turni user/assistant, ogni turno Γ¨ editabile. PossibilitΓ  di aggiungere/eliminare turni.

API Reference

La documentazione interattiva completa di tutti gli endpoint Γ¨ disponibile sulla pagina dedicata, che fetcha lo schema OpenAPI a runtime e lo renderizza dinamicamente con filtri per tag, metodo e ricerca testuale.

Gruppi di endpoint principali

RouterPrefixDescrizione
entries.py/api/entries/*CRUD entry, bulk, export, validate
flags.py/api/flags/*Flag CRUD, resolve, dedup, import/export, auto-flag
graph.py/api/graph/*Grafo: screens, neighbors, paths, search, scan, diff
crossval.py/api/crossval/*Cross-validation pipeline run + results
maintenance.py/api/*Backups, health-score, changelog, stats

Architettura

DatasetForge segue un'architettura a 3 strati: Managers (logica di dominio + stato) β†’ Routers (endpoint HTTP thin) β†’ LockHub (concorrenza e write-safety).

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ WEB UI (vanilla JS) β”‚ β”‚ index.html Β· entries.js Β· flags.js Β· graph.js β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ HTTP (X-API-Key) β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ ROUTERS (FastAPI thin) β”‚ β”‚ entries.py Β· flags.py Β· graph.py β”‚ β”‚ crossval.py Β· maintenance.py β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β” β”‚ ENTRIES β”‚ β”‚ FLAGS β”‚ β”‚ GRAPH β”‚ β”‚ MANAGER β”‚ β”‚ MANAGER β”‚ β”‚ MANAGER β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ CRUD β”‚ β”‚ CRUD β”‚ β”‚ KB load β”‚ β”‚ backup β”‚ β”‚ resolve β”‚ β”‚ paths BFS β”‚ β”‚ validate β”‚ β”‚ dedup β”‚ β”‚ scanner β”‚ β”‚ health β”‚ β”‚ import/exp β”‚ β”‚ diff/apply β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ LOCKHUB β”‚ β”‚ (threading.RLock) β”‚ β”‚ β”‚ β”‚ dataset_lock β”‚ β”‚ flags_lock β”‚ β”‚ graph_lock β”‚ β”‚ _global_lock β”‚ β”‚ β”‚ β”‚ + atomic_write_* β”‚ β”‚ + file_lock (flock) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Principio chiave: i router sono thin β€” validano input e delegano ai manager. Nessuna logica di dominio nei router. I manager sono l'unico punto di accesso a stato e file.

Managers & Routers

Managers (logica di dominio)

I manager contengono tutta la logica di business e gestiscono lo stato persistente:

ManagerFileResponsabilitΓ 
DatasetManagerdataset_manager.pyCRUD entries JSONL, backup atomici, validazione, health-score
FlagManagerflag_manager.pyFlag CRUD, resolve/reject/wontfix, dedup_key anti-flooding, import/export
GraphManagergraph_manager.pyCaricamento kb.json, path finder (BFS), scanner integration, diff/apply
CrossValManagercrossval_manager.pyPipeline 5-stadi (ingest β†’ extract β†’ disambig β†’ path-check β†’ report)

Routers (endpoint HTTP)

Ogni router Γ¨ creato via factory create_router() e riceve i manager come dipendenze. I router sono stateless: non mantengono dati, solo validano e delegano.

# routers/entries.py β€” pattern
def create_router(dataset_manager, flag_manager, hub):
    router = APIRouter(prefix="/api/entries", tags=["entries"])

    @router.get("")
    async def list_entries(...):
        return dataset_manager.list(...)

    @router.put("/{entry_id}")
    async def update_entry(entry_id, body, actor):
        return dataset_manager.update(entry_id, body, actor)

    return router

LockHub & write-safety

LockHub Γ¨ il single source of truth per tutti i lock del sistema. Centralizza la concorrenza per evitare deadlock e garantire write-safety cross-file.

class LockHub:
    """Single source of truth per i lock."""
    dataset_lock = threading.RLock()   # dataset.jsonl
    flags_lock   = threading.RLock()   # flags.json
    graph_lock   = threading.RLock()   # kb.json
    _global_lock = threading.RLock()   # cross-file transactions

Regola deadlock-free: acquisisci sempre i lock nell'ordine _global_lock β†’ file-specific. Mai lock annidati cross-manager.

Write-safety (crash-safe)

Tutte le scritture passano per atomic_write_* con:

  • fsync su file + directory
  • os.replace (atomic rename, crash-safe)
  • Single-writer cross-process garantito da file_lock (RLock intra-processo + flock a livello OS)

Cross-val snapshot + MVCC

La cross-validation usa un pattern snapshot per non bloccare il sistema durante il compute lungo:

def run_crossval():
    # Snapshot breve (millisecondi)
    with hub.dataset_lock, hub.graph_lock:
        ds_snapshot = deepcopy(dataset_manager._load_all())
        kb_snapshot = deepcopy(graph_manager._load_kb())

    # Compute lungo (secondi/minuti) β€” lock rilasciati
    results = pipeline(ds_snapshot, kb_snapshot)

    # Write flag breve (atomico)
    with hub.flags_lock:
        for flag in results:
            flag_manager._create_or_update(flag)

Flag System V3

Il Flag System Γ¨ il cuore della curazione collaborativa. Permette di segnalare problemi sul dataset e sul grafo, tracciarli in un workflow strutturato e risolverli β€” con anti-flooding per i flag generati automaticamente.

11 tipi di flag

TipoScopeSource tipico
correctiondatasethuman/system β€” mojibake, empty_field, wrong_value
questiondatasethuman
gapdatasethuman β€” missing_faq, missing_topic
duplicatedatasethuman/system β€” exact_hash, near_dup
contradictioncrosshuman/validator
qualitydatasethuman/system β€” too_short, unclear
languagedatasethuman β€” lang_mismatch
safetydatasethuman/system β€” code_leak, pii
notefreehuman
graph_gapgraphcrawler/human β€” orphan_screen, missing_edge
graph_conflictcrossvalidator/human β€” unreachable_path
crawl_anomalycrawlcrawler β€” blank_page, demo_blocked

Workflow biforcato

I flag umani e quelli automatici seguono percorsi separati:

UMANI (source=human): open β†’ answered β†’ in_review β†’ resolved | rejected | wontfix AUTO (source ∈ {crawler, validator, system}): auto_pending β†’ triaged β†’ resolved | wontfix | suppressed ↓ (richiede lavoro umano) ↓ promoted a open (entra nel flow umano)

Stati chiave:

  • auto_pending β€” generato automaticamente, non in coda operatore attiva
  • triaged β€” un umano ha valutato e deciso il da farsi
  • suppressed β€” deduplicato/sovrascritto da run successivo
  • wontfix β€” il flag Γ¨ valido ma la condizione Γ¨ accettabile (chiusura permanente anti-reapertura)

Anti-flooding (3 meccanismi)

  1. dedup_key β€” hash di type + targets + sub_type. Prima di creare: se open β†’ aggiorna; se resolved/wontfix β†’ skip
  2. Rate limit β€” max N flag aperti per (source, type). Oltre β†’ coalesce in batch
  3. Coalescing β€” 28 schermate orfane identiche β†’ 1 flag con 28 graph_targets

Auto-priority deterministica

La prioritΓ  dipende dal contenuto (evidence/verdict), non dalla fonte:

CondizioneAuto-priority
graph_conflict con verdict UNREACHABLEP0
safety con leak confermatoP0
graph_gap schermata orfanaP1
graph_conflict con verdict ABBREVIATED_VALIDP2
crawl_anomaly transiente (403/timeout)P3
confidence < 0.7abbassa di 1 livello

Graph Mapper

Il Graph Mapper Γ¨ il crawler che mappa automaticamente il grafo di navigazione del sito, espande e verifica kb.json. Risolve il problema delle schermate orfane, edge mancanti e dati stale.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ DatasetForge :8420 β”‚ β”‚ β”‚ β”‚ POST /api/graph/scan β†’ lancia scanner β”‚ β”‚ GET /api/graph/status β†’ progress scan β”‚ β”‚ GET /api/graph/diff β†’ kb.json vs realtΓ  β”‚ β”‚ POST /api/graph/apply β†’ applica fix a kb.jsonβ”‚ β”‚ GET /api/graph/export β†’ export grafo (JSON) β”‚ β”‚ β”‚ β”‚ graph_mapper/ β”‚ β”‚ β”œβ”€β”€ phase1_static.py β†’ analizza bundle JS β”‚ β”‚ β”œβ”€β”€ phase2_crawl.py β†’ naviga sito dev β”‚ β”‚ β”œβ”€β”€ phase3_diff.py β†’ confronta vs kb.json β”‚ β”‚ └── runner.py β†’ orchestrazione β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Fase 1 β€” Analisi statica del bundle

Input: main.bundle.js (giΓ  scaricato). Deterministica, no auth.

  • Route table β€” tutti i <Route path>
  • Navigation calls β€” history.push(), <Link to>
  • Action labels β€” i18n keys IT/EN/FR/ES
  • Dialog triggers β€” setDialogVisible(true)

< 10s Veloce, deterministico, non serve il sito online.

Fase 2 β€” Crawling dinamico

Input: credenziali demo + route dalla Fase 1. Usa Playwright.

  • Login automatico β†’ JWT + cookie salvati
  • Per ogni route: estrai elementi cliccabili, click, registra edge
  • Rate limiting: 0.5s tra click, max 2 concurrent
  • Stop su 5xx o 429

5-10 min Cattura la realtΓ : cosa Γ¨ visibile, cosa fa ogni bottone.

Fase 3 β€” Diff & auto-fix

Confronta kb.json con i risultati delle fasi 1-2:

CheckCosa rileva
Schermate mancantiRoute nel bundle non in kb.json
Schermate orfaneScreen senza edge in/out
Edge mancantiNavigazione osservata non in kb.json
Edge erratiEdge in kb.json non confermati
Trigger mancantiEdge senza testo del bottone

Apply mode con dry_run=true|false: preview o applica fix con backup automatico.

Path Finder

L'endpoint /api/graph/paths risolve il caso d'uso tipico: "Dal login come arrivo a inserire patologie?" β€” calcola tutti i cammini possibili da A a B con step descritti in linguaggio naturale.

Cross-Validation

La validazione incrociata rileva automaticamente le risposte nel dataset che descrivono path di navigazione non validi rispetto al grafo reale del software, collegando le discrepanze al Flag System.

Il problema in una frase: l'assistant dice "vai in Elenco pazienti β†’ seleziona β†’ Visita β†’ tab Patologie", ma nel grafo reale il tab "Patologie" non esiste, oppure l'edge Γ¨ mancante. Il dataset insegna all'LLM percorsi sbagliati.

Pipeline a 5 stadi

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 1.INGEST β”‚β†’ β”‚2.EXTRACT β”‚β†’ β”‚3.DISAMBIGβ”‚β†’ β”‚4.PATH-CHKβ”‚β†’ β”‚5.REPORT β”‚ β”‚dataset + β”‚ β”‚entitΓ  dalβ”‚ β”‚risolvi β”‚ β”‚verifica β”‚ β”‚& FLAG β”‚ β”‚grafo β”‚ β”‚testo(4lg)β”‚ β”‚ambiguitΓ  β”‚ β”‚cammini β”‚ β”‚(FlagSys) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Stadio 1 β€” Ingest

Costruisce il gazetteer multilingue (surface forms normalizzate per ogni entità in 4 lingue) e la matrice di reachability (tutte le coppie src→dst raggiungibili — lookup O(1) con 64 nodi = 4096 entry).

Stadio 2 β€” Extract (3 vie combinate)

  • Aho-Corasick β€” match esatti e quasi-esatti in O(|testo|), 4 lingue gratis
  • Fuzzy (RapidFuzz) β€” parafrasi e typo, soglie differenziate (L1: 88, L2: 85, L3: 82)
  • Semantic (opz.) β€” LaBSE/MiniLM multilingue per parafrasi cross-lingua

Stadio 3 β€” Disambiguazione

Context anchoring: una menzione L2/L3 (es. bottone "Nuovo") si risolve solo fra le entitΓ  figlie della schermata corrente nel path ricostruito. Risolve la polisemia senza modelli pesanti.

Stadio 4 β€” Path-check

Verifica che il path dichiarato sia percorribile nel grafo:

StepCondizione di validitΓ Se fallisce
NAVIGATE (A→B)edge A→B nella reachabilityunreachable_edge
ACT (azione X)X ∈ actions(S)missing_action
SELECTselect ha target validoinvalid_selection

Tolleranza salto implicito: distingue path validi ma abbreviati (direct edge mancante ma reachability OK β†’ info) da path completamente rotti (nessun cammino β†’ error). Questo previene il falso positivo piΓΉ frequente.

Stadio 5 β€” Report & Flag

Ogni break con severity error/warning genera un flag automatico (source: "validator", stato auto_pending, con dedup_key anti-flooding). Output: metriche di copertura, qualitΓ  (valid/broken ratio), top path, breakdown per lingua.

Verdict possibili

VerdictSignificato
VALIDPath completamente percorribile
ABBREVIATED_VALIDPath valido ma con salti impliciti (non Γ¨ un errore)
BROKENPath impossibile, nessun cammino
NO_PATH_FOUNDRiferimenti estratti ma path non ricostruibile
NO_REFERENCESNessun riferimento nav (entry non-nav, esclusa)

Feedback bidirezionale

Il sistema Γ¨ un ciclo in entrambe le direzioni:

  • Grafo β†’ Dataset: valida il dataset (caso principale)
  • Dataset β†’ Grafo: menzioni ad alta frequenza senza match β†’ alias/entitΓ  mancanti in kb.json β†’ flag new_alias_candidate

Deployment

DatasetForge Γ¨ deployato come container Docker 100% replicabile: stessa immagine su qualsiasi host Linux AMD64, dati su volumi, API key come secret.

Stack di dipendenze

# requirements.txt (core)
fastapi
uvicorn
pydantic>=2
pyahocorasick
rapidfuzz

# requirements-optional.txt
sentence-transformers   # ~500MB, lazy import
faiss-cpu               # ~100MB, optional NN search

La cross-validation funziona con sole dipendenze core (gazetteer + fuzzy). Il semantic matcher Γ¨ opzionale con fallback automatico.

Deploy con Docker

cd tools/datasetforge/deploy

# 1. API keys (secret)
mkdir -p secrets
cp ../keys.json.example secrets/keys.json
$EDITOR secrets/keys.json    # genera chiavi ad alta entropia

# 2. Dati (volume)
docker volume create datasetforge-data
docker run --rm -v datasetforge-data:/data -v "$PWD":/src busybox \
  sh -c "cp /src/dataset.jsonl /src/kb.json /data/ && \
         mkdir -p /data/backups && chown -R 1000:1000 /data"

# 3. Avvio
cp .env.example .env        # opzionale: personalizza porta/auth
docker compose up -d --build

# 4. Verifica
curl http://127.0.0.1:8420/api/health
# β†’ {"status":"ok","entries":4926,"version":"2.1"}

Nota: il container gira non-root (uid 1000). Il chown -R 1000:1000 sul volume Γ¨ necessario perchΓ© possa scrivere i backup. keys.json non va mai committato (.gitignore lo esclude).

Configurazione

VariabileDefaultDescrizione
DF_HOST127.0.0.1Bind address
DF_AUTH_ENABLEDtrueAbilita/disabilita autenticazione
DF_API_KEYS_PATHkeys.jsonPercorso file chiavi

Struttura del progetto

tools/datasetforge/
β”œβ”€β”€ server.py              # Entrypoint: app, CORS, router includes
β”œβ”€β”€ config.py              # Path, constants, VALID_* sets
β”œβ”€β”€ models.py              # Pydantic BaseModel (entry + flag + graph)
β”œβ”€β”€ validators.py          # validate_entry_text, _validate_flag_*
β”œβ”€β”€ managers/              # Logica di dominio + LockHub
β”œβ”€β”€ routers/               # Endpoint HTTP thin
β”œβ”€β”€ graph_mapper/          # Crawler (phase1/2/3 + runner)
β”œβ”€β”€ web/                   # UI vanilla JS + CSS
β”‚   β”œβ”€β”€ index.html
β”‚   β”œβ”€β”€ docs.html          # ← questa pagina
β”‚   β”œβ”€β”€ api_docs.html      # API reference interattivo
β”‚   β”œβ”€β”€ style.css
β”‚   └── js/                # entries, flags, graph, groups, coverage, app
β”œβ”€β”€ tests/                 # pytest (entries, flags, graph, crossval, maintenance)
β”œβ”€β”€ docs/                  # Documentazione architetturale
└── deploy/                # Docker setup