|
|
||
|---|---|---|
| .. | ||
| src/m2_ledger | ||
| tests | ||
| Dockerfile | ||
| pyproject.toml | ||
| README.md | ||
m2-ledger
Append-only credits ledger — transactions {ts, from, to, amount, reason, ref},
balances always derived by folding the tx log (never stored authoritatively). See
specs/001-market-first-wedge/contracts/ledger-api.md (frozen v1 contract) and
docs/config.md (env var / key reference) for the full spec.
Run locally
cd ledger
uv sync
LEDGER_DB_PATH=./ledger.db \
LEDGER_SERVICE_KEYS=svc_devkey \
LEDGER_ADMIN_KEYS=admin_devkey \
uv run uvicorn m2_ledger.api:app --reload --port 8000
GET http://localhost:8000/health should return {"status":"healthy"}. All other
endpoints require an X-API-Key header (service or admin class — see
docs/config.md §4).
Deploy as a Coolify app
m2-ledger is the one sanctioned new service in the first wedge (constitution I);
it deploys as a plain Coolify app on the coolify Docker network, not baked into
any image.
- Build: point the Coolify app at this repo/subpath (
ledger/) withledger/Dockerfile— no build args, no secrets at build time (constitution VI: no secrets in repos or images). - Network + alias: attach the app to the
coolifynetwork with aliasm2-ledger, so callers usehttp://m2-ledger:8000per the frozen contract's base URL. - Env vars (inject at runtime via Coolify's environment panel — never commit
real values, see
docs/config.md§5):LEDGER_DB_PATH=/data/ledger.db(already set as the image default; override only if the persistent volume is mounted elsewhere)LEDGER_SERVICE_KEYS— comma-separatedservice-class keys (CLI/Store/indexer)LEDGER_ADMIN_KEYS— comma-separatedadmin-class keys (grants, snapshots); keep this set smallLEDGER_PLATFORM_PCT(default0.10, UNCONFIRMED) andLEDGER_STARTER_GRANT(default100, UNCONFIRMED) — optional, override the code defaultsREGISTRY_REPO_URL+FORGEJO_TOKEN— required once/snapshotactually commits tom2/market-registry(see TODO below)
- Persistent volume: mount a Coolify persistent volume at
/data(the image declaresVOLUME /data) soledger.dbsurvives redeploys. This is the single source of truth for the tx log — never point it at ephemeral container storage. - Health check: the image's
HEALTHCHECKhitsGET /health(no auth). Coolify should also be configured to poll the same endpoint for its own readiness gate. - Canary-first (constitution VI): roll out to one environment before any
fleet-wide dependency on
m2-ledger— there is no fleet-wide blast for this service since it's a single shared instance, but verify/healthand one/balance/{operator_id}call with a real service key before pointing the CLI'sledger_urlat it in~/.m2-market/config.toml.
Snapshot cron (TODO T034)
POST /snapshot (admin) currently computes audit/YYYY-MM-DD.json balances and
returns the JSON body but does not commit it anywhere — see the
TODO(T034) in src/m2_ledger/api.py. Once T034 lands (Forgejo commit via
REGISTRY_REPO_URL + FORGEJO_TOKEN), add a daily Coolify scheduled task (or
cron container) that calls POST /snapshot with an admin key once every 24h,
per constitution V ("Daily balance snapshots MUST be committed to Forgejo for
audit") and the contract's "admin, also daily cron" note. Not wired up yet.