Replace flowchart.mmd with per-topic diagrams and a print pipeline
Split the single flowchart.mmd into flowchart/platform-overview.mmd (all 5 phases) and flowchart/round-lifecycle.mmd (round/draw detail), plus render-pdf.sh to generate print-ready A4/A3 PDFs with a consistent theme, header/footer, and legible contrast against the page background. Also flip the operational policy in CLAUDE.md: the app now always runs via Docker (dev and prod alike), with the venv reserved for tests, migration authoring, and one-time secret/key-generation scripts.
This commit is contained in:
@@ -12,25 +12,24 @@ All 10 build-order stages from `/home/davide/.claude/plans/scalable-mixing-sloth
|
||||
|
||||
Real-money verification on mainnet, done so far: registration + address derivation, deposit crediting (1-conf), a real 10 PLM bet (broadcast, confirmed, change credited back), and a full round cycle — close → draw (real block hash) → payout (70/30 split, exact sat math verified against the broadcast tx) → confirmation → round closed → next round auto-opened. Withdrawal and the RBF bump path are unit-tested but have never been exercised against a live broadcast. See "Known gaps" below before treating this as production-ready.
|
||||
|
||||
Before writing code, always read [flowchart.mmd](flowchart.mmd) in full: every node in the diagram corresponds to a behavior that must be implemented exactly as described, including the labels on the edges (conditions, retries, loops).
|
||||
Before writing code, always read the "Architecture" section below in full, plus the diagrams in [flowchart/](flowchart/): [platform-overview.mmd](flowchart/platform-overview.mmd) for the whole 5-phase flow, and [round-lifecycle.mmd](flowchart/round-lifecycle.mmd) for the round/draw lifecycle in detail. Every node in these diagrams corresponds to a behavior that must be implemented exactly as described, including the labels on the edges (conditions, retries, loops). Regenerate their companion PDFs with `flowchart/render-pdf.sh <file>.mmd` after editing either one.
|
||||
|
||||
Human-facing guides live in [docs/](docs/) (Italian, per explicit request — an exception to this file's English-only rule below): [setup.md](docs/setup.md), [running-the-server.md](docs/running-the-server.md), [guida-utente.md](docs/guida-utente.md), [guida-admin.md](docs/guida-admin.md).
|
||||
|
||||
## Commands
|
||||
|
||||
The server itself — in development and in production alike — always runs via Docker (see "Deployment" below); there is no supported way to run `uvicorn` directly against this codebase. The venv (`.venv/`) is only for local tooling: running tests, authoring Alembic migrations, and running the one-time scripts that generate the secrets/key material that end up referenced from `.env`.
|
||||
|
||||
```bash
|
||||
source .venv/bin/activate # venv already created at .venv/
|
||||
pip install -e ".[dev]" # install/update deps
|
||||
|
||||
alembic upgrade head # apply DB migrations
|
||||
alembic revision --autogenerate -m "message" # generate a new migration after editing app/db/models.py
|
||||
alembic revision --autogenerate -m "message" # generate a new migration after editing app/db/models.py (applied automatically by the container's startup command — see Deployment — never run `alembic upgrade head` manually)
|
||||
|
||||
PYTHONPATH=. python scripts/generate_master_key.py # one-time: create+encrypt the server's master xprv (requires XPRV_ENCRYPTION_KEY in .env)
|
||||
PYTHONPATH=. python scripts/generate_master_key.py # one-time: create+encrypt the server's master xprv (requires XPRV_ENCRYPTION_KEY in .env; see Deployment for where MASTER_KEY_PATH should point)
|
||||
PYTHONPATH=. python scripts/decrypt_master_key.py # ops recovery: decrypt+print the existing master xprv (asks for confirmation first)
|
||||
PYTHONPATH=. python scripts/encrypt_master_key.py # ops bootstrap: bring your own externally-generated xprv instead of generating one (getpass prompt, --overwrite to replace)
|
||||
|
||||
uvicorn app.main:app --reload --port 8123 # run the dev server
|
||||
|
||||
python -m pytest # run all tests
|
||||
python -m pytest tests/unit/test_hd.py # run one test file
|
||||
python -m pytest tests/unit/test_hd.py::test_derivation_is_deterministic # run a single test
|
||||
@@ -40,14 +39,15 @@ python -m pytest tests/unit/test_hd.py::test_derivation_is_deterministic # run
|
||||
|
||||
## Deployment (Docker + Caddy)
|
||||
|
||||
`docker-compose.yml` runs two containers: `app` (this codebase, built by `Dockerfile`, runs `alembic upgrade head` then `uvicorn`) and `caddy` (reverse proxy + automatic TLS). `.env` still holds the app secrets; `docker-compose.yml` overrides `DATABASE_URL`/`MASTER_KEY_PATH` to point at the bind-mounted `./data/` (db, encrypted master key, logs — all gitignored, persist across container restarts).
|
||||
The app is always run via Docker — dev and prod alike use the same `docker-compose.yml`, just with a different `SITE_ADDRESS` (see below); there's no separate dev-mode compose file or bare-`uvicorn` workflow. `docker-compose.yml` runs two containers: `app` (this codebase, built by `Dockerfile`, runs `alembic upgrade head` then `uvicorn`) and `caddy` (reverse proxy + automatic TLS). `.env` holds the app secrets; `docker-compose.yml` overrides `DATABASE_URL`/`MASTER_KEY_PATH` inside the container to point at the bind-mounted `./data/` (db, encrypted master key, logs — all gitignored, persist across container restarts). Set `MASTER_KEY_PATH` in `.env` itself to the host-side equivalent, `./data/keys/master.xprv.enc`, so the venv-run key-generation scripts above (see "Commands") write to the exact same file the container reads — one source of truth for the key, whichever way it was generated.
|
||||
|
||||
```bash
|
||||
mkdir -p data/db data/keys data/logs # one-time: host dirs bind-mounted into the app container
|
||||
mkdir -p data/db data/keys data/logs # one-time: host dirs bind-mounted into the app container
|
||||
|
||||
docker compose run --rm app python scripts/generate_master_key.py # one-time: create+encrypt the master xprv into ./data/keys/
|
||||
# one-time: generate the master key via the venv script above (scripts/generate_master_key.py),
|
||||
# not via `docker compose run` — MASTER_KEY_PATH in .env already points at ./data/keys/
|
||||
|
||||
docker compose up -d --build # build + start app and caddy
|
||||
docker compose up -d --build # build + start app and caddy — same command for dev and prod
|
||||
docker compose logs -f app # tail app logs (also written to ./data/logs/app.log)
|
||||
docker compose down # stop
|
||||
```
|
||||
@@ -113,7 +113,7 @@ A periodic-round lottery system built on a Bitcoin-like coin (PLM, mainnet). Eac
|
||||
|
||||
## Architecture (from the flowchart subgraphs)
|
||||
|
||||
The flow is organized into 5 phases, each a subgraph in [flowchart.mmd](flowchart.mmd):
|
||||
The flow is organized into 5 phases (see [flowchart/platform-overview.mmd](flowchart/platform-overview.mmd) for the full-platform diagram, and [flowchart/round-lifecycle.mmd](flowchart/round-lifecycle.mmd) for the round/draw phase in detail):
|
||||
|
||||
- **REG (Registration)**: on signup the server derives a new P2WPKH address via BIP84 (`m/84'/coin'/0'/0/index`, one index per user) from a master xprv **encrypted at rest**. This address is permanent and serves as both the deposit address and the address that receives winnings and withdrawals.
|
||||
- **DEP (Balance top-up)**: an ElectrumClient/SPV subscribes to the user's address scripthash. Internal balance (DB) is credited after **1 confirmation only** — the reorg risk at 1-conf is knowingly accepted in v1, with no rollback logic.
|
||||
|
||||
Reference in New Issue
Block a user