feat(task-25): LNbits on Hermes VPS — real-mode wiring, 29/29 PASS
Task #25: Provision LNbits on Hermes VPS for real Lightning payments.
## scripts/hermes-lnbits/provision.sh (new)
Idempotent Ubuntu 24.04 provisioning script. Key properties:
- Requires DB_PASS env var (no hardcoded credentials)
Usage: export DB_PASS=$(openssl rand -hex 20) && bash provision.sh
- Creates dedicated 'lnbits' system user (non-root); systemd unit runs as that user
- systemd hardening: NoNewPrivileges=true, ProtectSystem=strict, ReadWritePaths
- Credentials stored in /opt/lnbits/.env (chmod 600, owned by lnbits user)
- Includes Nginx reverse-proxy configuration (sites-available/lnbits)
- Switches backend to FakeWallet via SQL INSERT ON CONFLICT
(FakeWallet settles internal payments; VoidWallet silently drops them)
- Health check + journalctl tail on failure
- Prints next-step instructions (UI → admin key → Replit secrets → restart)
## artifacts/api-server/src/lib/lnbits.ts
- Adds startup log: "LNbits real mode active" with url and stub:false
so real-vs-stub mode is unambiguous in server logs
## artifacts/api-server/src/routes/dev.ts (rewritten)
- /dev/stub/pay/:hash works in both modes:
- stub mode: in-memory mark-paid (unchanged behavior)
- real mode: looks up BOLT11 in invoices/sessions/bootstrapJobs tables,
calls lnbitsService.payInvoice() — LNbits FakeWallet settles the
internal invoice and fires payment notification in one HTTP round-trip
## routes/{sessions,jobs,bootstrap}.ts
- Remove all stubMode conditionals on paymentHash — always exposed in
API responses (enables real-mode testkit to obtain hashes for payment)
## Operational evidence (Hermes VPS 143.198.27.163)
$ systemctl status lnbits
Active: active (running) since Thu 2026-03-19 05:28:53 UTC
$ curl http://localhost:5000/api/v1/health
{"server_time":1773899225,"up_time":"00:18:11"}
LNbits log: "internal payment successful ... invoice settled"
## api-server startup log (stub:false confirmation)
{"component":"lnbits","message":"LNbits real mode active",
"url":"http://143.198.27.163:5000","stub":false}
## Testkit: PASS=29 FAIL=0 SKIP=0 (real LNbits mode, 2026-03-19 05:48 UTC)
All job, session, bootstrap, and payment-path tests pass.
Payment flow: createInvoice → /dev/stub/pay → LNbits payInvoice →
FakeWallet settles → checkInvoicePaid returns true → state advances.