8. Modalità headless (server)

Nota

Questa sezione descrive una modalità avanzata e facoltativa di blunderDB, destinata ai deployment su server, all’uso multiutente e all’automazione. L’uso normale e consigliato di blunderDB resta l’applicazione desktop descritta nei capitoli precedenti. Se usi blunderDB da solo, sul tuo computer, non hai bisogno di questa modalità: puoi ignorare questo capitolo senza perdere nulla delle funzionalità di analisi.

8.1. Panoramica

Lo stesso binario blunderdb può, oltre all’applicazione desktop e ai comandi a riga di comando (vedi Interfaccia a riga di comando (CLI)), funzionare in modalità headless: senza interfaccia grafica, pilotato interamente da riga di comando o tramite rete. Questa modalità raggruppa tre usi:

  • il demone serve — espone il motore di blunderDB come servizio HTTP + JSON, per far girare un database condiviso su un server e accedervi in più persone;

  • il dispatcher generico call — richiama qualsiasi operazione di archiviazione direttamente, in locale, per lo scripting e i test;

  • il comando migrate — trasferisce un database SQLite monoutente verso un backend PostgreSQL multiutente.

Questi tre usi si basano su un livello di archiviazione comune capace di dialogare con due backend: SQLite (il consueto formato di file .db dell’applicazione desktop) e PostgreSQL (per i deployment server multiutente).

8.2. Il demone serve

blunderdb serve avvia il motore come servizio HTTP che risponde in JSON. Permette di ospitare un database di posizioni su una macchina e di accedervi da più client.

# Servir une base SQLite locale sur le port 8080
blunderdb serve --db ma_base.db --addr :8080

# Servir un backend PostgreSQL
blunderdb serve --backend postgres \
    --dsn "postgres://user:pass@host:5432/blunderdb?sslmode=disable" \
    --addr :8080

Avvertimento

Il demone non effettua alcuna autenticazione. Si fida dell’header di richiesta X-Tenant-ID e deve girare dietro un reverse-proxy (nginx, Caddy…) incaricato dell’autenticazione. Non esporlo mai direttamente su Internet pubblico.

Opzioni:

Opzione

Predefinito

Significato

--db <percorso>

file SQLite (scorciatoia per --backend sqlite --dsn <percorso>)

--backend <tipo>

sqlite

backend di archiviazione: sqlite o postgres

--dsn <stringa>

$BLUNDERDB_DSN

stringa di connessione del backend

--addr <host:porta>

:8080

indirizzo di ascolto

--log-level <livello>

info

livello di logging: debug|info|warn|error

--metrics

true

espone /metrics (formato Prometheus)

--cors-allow-origin <origine>

abilita CORS per questa origine (disabilitato per impostazione predefinita)

--rate-limit-rps <n>

0

limite di richieste al secondo per tenant (0 = disabilitato)

--rate-limit-burst <n>

2×rps

dimensione del secchio di token per i picchi di richieste

--rls

false

PostgreSQL: abilita la Row-Level Security per tenant (difesa in profondità, opzionale)

La maggior parte delle opzioni può anche essere fornita tramite variabile d’ambiente (BLUNDERDB_BACKEND, BLUNDERDB_DSN, BLUNDERDB_ADDR, BLUNDERDB_LOG_LEVEL, BLUNDERDB_RLS).

8.2.1. Punti di accesso

Il servizio espone dei punti di accesso operativi, sempre presenti:

  • GET /healthz — liveness (il processo è in esecuzione);

  • GET /readyz — readiness (l’archiviazione risponde);

  • GET /metrics — metriche Prometheus (se --metrics è attivo).

La superficie applicativa segue lo schema POST /v1/<famiglia>.<metodo> (per esempio /v1/positions.save, /v1/matches.get). Le famiglie coprono posizioni, analisi, match, commenti, collezioni, tornei, carte Anki, filtri, sessioni, ricerca, metadati, statistiche e import. Gli endpoint di elenco restituiscono un flusso NDJSON (un oggetto JSON per riga). Il server si arresta in modo pulito su SIGINT / SIGTERM.

Due metodi della famiglia positions decodificano una posizione senza salvarla: positions.fromXGID ricostruisce una posizione da una stringa XGID e positions.fromXGP da un file di posizione singola .xgp.

8.3. Backend PostgreSQL e multiutente

Per un deployment condiviso, blunderDB può memorizzare i dati in PostgreSQL invece che in un file SQLite. Il backend è selezionato tramite --backend postgres e la stringa di connessione --dsn. Lo schema viene creato e migrato automaticamente all’avvio.

I dati sono compartimentati per tenant (locatario): ogni richiesta porta un identificatore di scope (header X-Tenant-ID, per impostazione predefinita default), il che permette a più utenti di condividere la stessa istanza senza vedere i dati altrui. L’opzione --rls abilita in aggiunta la Row-Level Security di PostgreSQL: vengono installate politiche di isolamento per tenant e app.tenant_id viene impostato per connessione. È una difesa in profondità facoltativa, disabilitata per impostazione predefinita.

8.4. Migrare un database SQLite verso PostgreSQL

blunderdb migrate copia un database SQLite monoutente verso un backend PostgreSQL, sotto uno scope di tenant scelto — è il percorso per « caricare » una libreria desktop verso un deployment server.

blunderdb migrate \
    --from sqlite:///chemin/vers/base.db \
    --to   "postgres://user:pass@host:5432/db?sslmode=disable" \
    --tenant-id mon-tenant

# Prévisualiser sans rien écrire
blunderdb migrate --from sqlite:///chemin/vers/base.db \
    --tenant-id mon-tenant --dry-run

La migrazione copia le posizioni, le loro analisi e commenti, i match (partite + mosse), i tornei (con i loro collegamenti ai match) e le collezioni (con la loro composizione), riassegnando le chiavi primarie ed esterne, il tutto in una sola transazione lato destinazione: l’operazione è atomica (un errore lascia la destinazione intatta, basta riavviarla). L’avanzamento e il bilancio finale vengono emessi in NDJSON sullo standard output.

Opzione

Predefinito

Significato

--from <uri>

database SQLite di origine (sqlite:///percorso o un semplice percorso)

--to <dsn>

DSN PostgreSQL di destinazione (postgres://…)

--tenant-id <scope>

scope di tenant di destinazione (obbligatorio tranne in --dry-run)

--dry-run

conta ciò che verrebbe copiato senza scrivere nulla

--on-conflict <politica>

""

"" interrompe se il tenant ha già dei dati; skip unisce (deduplicazione delle posizioni tramite hash Zobrist)

Nota

Non vengono (ancora) migrati gli stati applicativi: deck/carte Anki, libreria di filtri, cronologia di ricerca e di comandi, e metadati di sessione. La priorità è la migrazione della libreria di posizioni e della cronologia dei match.

8.5. Il dispatcher generico call

In aggiunta ai sottocomandi storici (Interfaccia a riga di comando (CLI)), blunderdb call espone tutte le operazioni di archiviazione direttamente, in locale. Passa per gli stessi gestori del demone serve: il comportamento è quindi identico a POST /v1/<famiglia>.<metodo>. È utile per lo scripting e i test di integrazione.

# Lister toutes les méthodes disponibles
blunderdb call --list

# Lectures
blunderdb call metadata.counts --db ma_base.db
blunderdb call positions.list  --db ma_base.db --json '{"limit":10}'
blunderdb call matches.get     --db ma_base.db --json '{"id":1}'

# Écritures
blunderdb call positions.save  --db ma_base.db --json '{"position":{...}}'
blunderdb call matches.delete  --db ma_base.db --json '{"id":42}'

Opzioni:

Opzione

Predefinito

Significato

--db <percorso>

file SQLite (scorciatoia per --backend sqlite --dsn <percorso>)

--backend <tipo>

sqlite

sqlite o postgres

--dsn <stringa>

$BLUNDERDB_DSN

stringa di connessione del backend

--scope <stringa>

default

scope di tenant (inviato come X-Tenant-ID)

--json <stringa>

{}

corpo della richiesta in formato JSON

--json-file <percorso>

legge il corpo della richiesta da un file

--list

mostra tutti i metodi <famiglia>.<metodo> ed esce

La risposta JSON (o il flusso NDJSON per gli endpoint *.list) viene scritta sullo standard output. In caso di errore, il processo termina con un codice diverso da zero e l’envelope {"error":{…}} viene stampato sullo standard output per restare analizzabile (per esempio con jq).