Files
plm-lottery/docs/setup.md
T
davideandClaude Opus 5.5 61efbb0e37 Replace flowchart/ with a traceable specification in docs/
The two Mermaid diagrams under flowchart/ described the intended flow but
had drifted from the code and carried no link back to it. docs/ now holds
the specification instead: 15 Italian documents (flows, architecture, data
model, API, security, audit log, operations, decisions and limits, bug
history) with 472 numbered requirements, each pointing at the function
that implements it and the test that covers it. docs/processo-di-modifica.md
defines the ID convention and the spec -> code -> test change workflow, and
CLAUDE.md now names docs/ as authoritative.

Writing the spec from the code also corrected stale claims in CLAUDE.md
(B-41's get_history check, BUGS.md still tracking B-71/B-72, Cache-Control
scope, the error contract's bare-string exceptions) and in the operator
guides (payouts do retry, only `drawing` fails to resume, rounds do not
open without fee_address). The B-70 doc test now pins the prose in
docs/scommesse-e-prelievi.md instead of the deleted diagram.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 12:16:01 +02:00

132 lines
6.3 KiB
Markdown

# Setup
Passaggi da eseguire una tantum per preparare un'istanza di PLM Lottery, prima di
poterla avviare (in locale o via Docker). Per come avviarla poi ogni volta, vedi
[running-the-server.md](running-the-server.md).
## 1. Prerequisiti
- Python 3.12+ (serve solo per il workflow locale/venv — puoi saltarlo se usi solo Docker)
- Docker + Docker Compose (serve solo per il workflow a container)
- Un server Electrum raggiungibile per la rete PLM. Il server di bootstrap per lo
sviluppo è `santantonio.sytes.net:50002` (SSL) — va bene per i test, ma in
produzione conviene usarne uno di cui ci si fida o gestirne uno proprio.
- **Consigliato in produzione: più di un server.** Tutto passa da questa singola
connessione (accredito depositi, invio transazioni, conferme, altezza della
catena su cui si basa l'estrazione), quindi un solo server è il principale
punto di rottura della piattaforma. Elencane altri in
`ELECTRUM_FALLBACK_SERVERS` (vedi sotto): l'app li prova a rotazione, così un
server irraggiungibile costa un solo tentativo di riconnessione invece di un
disservizio.
## 2. Creare il file `.env`
Copia `.env.example` in `.env` e compila i segreti. Ogni valore sotto viene
generato una volta e non cambia più (ruotarlo invalida sessioni/dati cifrati
esistenti):
```bash
cp .env.example .env
```
| Variabile | Scopo | Come generarla |
|---|---|---|
| `XPRV_ENCRYPTION_KEY` | Chiave simmetrica che cifra a riposo la master xprv del server. **Perdere questa chiave significa perdere per sempre l'accesso ai fondi di tutti gli utenti.** | `python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"` |
| `JWT_SECRET` | Firma i token di sessione degli utenti. | `python -c "import secrets; print(secrets.token_urlsafe(32))"` |
| `ADMIN_TOKEN` | Token bearer richiesto sugli endpoint admin (header `X-Admin-Token`). | `python -c "import secrets; print(secrets.token_urlsafe(32))"` |
Le chiavi Electrum (`ELECTRUM_HOST`/`PORT`/`USE_SSL`) hanno default sensati in
`.env.example`. `DATABASE_URL` e `MASTER_KEY_PATH` non sono elencate lì:
hanno un default in `app/config.py`, e dentro il container vengono comunque
sovrascritte da `docker-compose.yml` per puntare a `./data/` (elenco completo
delle variabili in [architettura.md](architettura.md)).
`ENABLE_API_DOCS` (default `false`) controlla Swagger/ReDoc/l'OpenAPI JSON grezzo
su `/docs`, `/redoc` e `/openapi.json`: espongono l'intera superficie dell'API,
endpoint admin inclusi, quindi restano disattivati a meno di non impostarlo
esplicitamente a `true` — utile in locale, da evitare in produzione.
`ELECTRUM_FALLBACK_SERVERS` elenca i server di riserva, separati da virgola, nel
formato `host:porta` (TLS, il caso normale) oppure `host:porta:notls`. Esempio:
```
ELECTRUM_FALLBACK_SERVERS=nodo2.example.net:50002,nodo3.example.net:50001:notls
```
Vengono provati a rotazione dopo il primario. Attenzione: un valore scritto male
**blocca l'avvio** dell'app — è voluto, meglio accorgersene subito che durante il
disservizio in cui il fallback serve davvero.
`JWT_SECRET` e `XPRV_ENCRYPTION_KEY` vengono verificati all'avvio: se sono vuoti
(o `JWT_SECRET` è più corto di 32 caratteri) il container si rifiuta di partire con
un errore esplicito, invece di avviarsi e rompersi al primo login. Nota: `.env`
contiene solo segreti e configurazione di infrastruttura — i parametri di
business (bet amount, durata round, fee, ecc.) si configurano dal pannello
admin dopo l'avvio, non qui — vedi [guida-admin.md](guida-admin.md).
**Non committare mai `.env`.** È già escluso da `.gitignore`.
## 3. Generare la master key
Il server deriva l'indirizzo di deposito di ogni utente (e l'indirizzo pool) da
un'unica master xprv, generata una volta e cifrata a riposo con
`XPRV_ENCRYPTION_KEY`. Questo passaggio va eseguito esattamente una volta per
ogni deployment, dopo aver impostato `XPRV_ENCRYPTION_KEY` in `.env`:
- **Locale/venv**: `PYTHONPATH=. python scripts/generate_master_key.py`
- **Docker**: `docker compose run --rm app python scripts/generate_master_key.py`
Questo scrive un file cifrato (`MASTER_KEY_PATH`, default `./master.xprv.enc` in
locale o `./data/keys/master.xprv.enc` con Docker). **Fai il backup di questo
file insieme a `XPRV_ENCRYPTION_KEY`** — uno dei due da solo è inutile, ma
perderli entrambi insieme significa perdere i fondi di tutti gli utenti senza
possibilità di recupero.
### Recuperare o portare una xprv esistente
Due script, entrambi manuali/una tantum, per lo scenario di disaster recovery
o per usare una xprv generata altrove (es. offline/air-gapped) invece di
farla generare al server:
- **`scripts/decrypt_master_key.py`**: decifra e stampa a schermo la xprv
già presente in `MASTER_KEY_PATH` (con fallback automatico su
`./data/keys/master.xprv.enc` se il path di `.env` non esiste in locale).
Chiede conferma esplicita prima di stampare.
- **`scripts/encrypt_master_key.py`**: cifra una xprv esterna e la scrive in
`MASTER_KEY_PATH` con lo stesso identico schema (Fernet +
`XPRV_ENCRYPTION_KEY`) usato da `generate_master_key.py`. La xprv va
incollata con input nascosto (non appare a schermo). Si rifiuta di
sovrascrivere un file esistente a meno di passare `--overwrite`.
Entrambi vanno eseguiti localmente (o dentro il container via
`docker compose run --rm app ...`), mai esposti da un endpoint API o dal
pannello admin: chi ottiene questa xprv ottiene il controllo dei fondi di
tutti gli utenti e del pool.
## 4. Installare le dipendenze (solo workflow locale/venv)
Salta questo passaggio se usi solo Docker — l'immagine installa le proprie
dipendenze durante la build.
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
```
## 5. Applicare le migrazioni del database
- **Locale/venv**: `alembic upgrade head`
- **Docker**: le migrazioni vengono eseguite automaticamente all'avvio del
container (vedi il `CMD` del `Dockerfile`) — nessun passaggio manuale.
## 6. Impostare l'indirizzo delle fee
Prima che si possa aprire il primo round, un admin deve impostare
`fee_address` tramite il pannello admin o l'API — vedi
[guida-admin.md](guida-admin.md). Finché non è impostato **nessun round si
apre**, perché il pagamento non si potrebbe costruire.
A questo punto l'istanza è pronta per essere avviata — continua con
[running-the-server.md](running-the-server.md).