# CurrenciCombo — Phoenix / systemd deployment This directory holds everything needed to deploy CurrenciCombo onto a systemd host — starting with Phoenix CT 8604 on `r630-01`, but any Debian/Ubuntu (or Alpine) host with Postgres + Redis available works. The files here are **target-agnostic**. They hardcode no IPs, hostnames, or VLANs. Environment-specific values — `curucombo.曼李.com`, the `10.160.0.14` VIP, the NPMplus reverse proxy — are applied at the edge (NPMplus) and at `/etc/currencicombo/orchestrator.env`, never in the repo. ## Architecture on CT 8604 ``` ┌────────────────────┐ curucombo.曼李.com ──▶ NPMplus │192.168.11.167 │ (Cloudflare-proxied) │ TLS terminates here│ └─────────┬──────────┘ │ ┌──────────────────────┴──────────────────────┐ │ │ ▼ ▼ curucombo.曼李.com/* (default) curucombo.曼李.com/api/* curucombo.曼李.com/events/* (SSE) ← swap ─ correctly routed to :8080 │ │ CT 8604 │10.160.0.14:3000 CT 8604 │10.160.0.14:8080 ▼ ▼ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │ currencicombo-webapp.service │ │ currencicombo-orchestrator │ │ nginx → /opt/currencicombo/ │ │ .service (systemd) │ │ webapp/dist/ │ │ node dist/index.js │ └─────────────────────────────┘ │ env /etc/currencicombo/ │ │ orchestrator.env │ └──────────────┬──────────────┘ │ ▼ postgresql + redis (same CT, local) ``` ## Files | path | purpose | |---|---| | `systemd/currencicombo-orchestrator.service` | Node orchestrator, reads `/etc/currencicombo/orchestrator.env` | | `systemd/currencicombo-webapp.service` | nginx serving the Vite SPA on `:3000` | | `webapp-nginx.conf` | full nginx.conf for the webapp unit | | `.env.prod.example` | env template installed to `/etc/currencicombo/orchestrator.env` | | `install.sh` | one-shot host setup: user / dirs / DB role / systemd units | | `deploy-currencicombo-8604.sh` | build-and-swap deploy driver (the script Phoenix/proxmox deploy-api calls) | | `README.md` | you're reading it | ## First-time setup on CT 8604 All commands run as **root** inside the CT. 1. Ensure Postgres + Redis are installed and running: ``` apt-get install -y postgresql redis-server systemctl enable --now postgresql redis-server ``` 2. Clone the repo into its staging location (once): ``` install -d -o root -g root /var/lib/currencicombo git clone https://gitea.d-bis.org/d-bis/CurrenciCombo.git /var/lib/currencicombo/repo ``` 3. Run `install.sh` (creates user, DB, systemd units, env file): ``` bash /var/lib/currencicombo/repo/scripts/deployment/install.sh ``` On success you'll see: ``` [install] generated EVENT_SIGNING_SECRET (64 hex) [install] generated 3 API keys (initiator/settler/auditor) — grep /etc/currencicombo/orchestrator.env [install] install complete. ``` **Grab the three API keys from `/etc/currencicombo/orchestrator.env`** and put them in your password manager — they authenticate initiator / settler / auditor calls. 4. If you need to resolve any `EXT-*` blocker (e.g. point at a real dbis_core), edit `/etc/currencicombo/orchestrator.env` before the first deploy. 5. First build-and-start: ``` bash /var/lib/currencicombo/repo/scripts/deployment/deploy-currencicombo-8604.sh ``` Expected tail: ``` [deploy] orchestrator ready: {"ready":true} [deploy] portal OK (HTTP 200) [deploy] EXT-* blocker summary from orchestrator boot log: [ExternalBlockers] 6 active, 1 resolved id: EXT-DBIS-CORE id: EXT-CC-PAYMENT-ADAPTERS ... id: EXT-CHAIN138-CI-RPC (resolved) [deploy] deploy complete. ref=main sha= ts= ``` ## NPMplus ingress changes required at cutover `curucombo.曼李.com` today proxies 100% to `10.160.0.14:3000`. After cutover it must become a **single-origin path-routed proxy**: | location | upstream | notes | |---|---|---| | `/api/*` | `http://10.160.0.14:8080` | orchestrator API. Forward `Host`, `X-Real-IP`, `X-Forwarded-*`. `proxy_read_timeout 60s`. | | `/events/*` | `http://10.160.0.14:8080` | **SSE** — must set `proxy_buffering off;` and `proxy_read_timeout 24h;`. | | `/` | `http://10.160.0.14:3000` | Vite SPA. Default upstream. | If you skip the `/api` + `/events` rules, the nginx in `webapp-nginx.conf` intentionally returns `HTTP 421` for those paths — a clean "upstream is misconfigured" signal instead of silently returning `index.html` and breaking the browser with a JSON parse error. ## Subsequent deploys Every deploy after the first is just: ``` sudo /var/lib/currencicombo/repo/scripts/deployment/deploy-currencicombo-8604.sh ``` Flags: - `--ref=` — deploy something other than `main`. - `--dry-run` — print what would happen, don't touch anything. - `--skip-migrate` — hotfix deploys that don't change the schema. - `--skip-build` — reuse the build from the previous run (debugging only). - `--rollback` — restore the most recent `/var/lib/currencicombo/backups//` and restart units. Does **not** git-pull or rebuild. Every deploy writes a timestamped backup to `/var/lib/currencicombo/backups//` before swapping. Old backups are not auto-pruned — `find /var/lib/currencicombo/backups -maxdepth 1 -mtime +30 -exec rm -rf {} +` on a cron. ## Rollback (if a deploy goes sideways) ``` sudo /var/lib/currencicombo/repo/scripts/deployment/deploy-currencicombo-8604.sh --rollback ``` Restores the most recent backup and restarts both units. Does not touch the DB. If the deploy that failed applied a new migration, a DB rollback is a manual `psql` task — we don't attempt generic `down` migrations because the orchestrator's migration runner only emits `up()` paths. ## Troubleshooting | symptom | cause / check | |---|---| | `/api/*` returns `421 NPMplus is misconfigured` | NPMplus `/api/*` rule missing or wrong upstream. | | `/events/*` connects then disconnects after ~60s | NPMplus forgot `proxy_buffering off` + high `proxy_read_timeout`. | | orchestrator unit enters `activating (auto-restart)` loop | `journalctl -u currencicombo-orchestrator -n 80` — usually a zod env-validation error. The boot-time assertion message names the missing/invalid var. | | orchestrator boot log says `[ExternalBlockers] N active` where N > 6 | you added an `EXT-*` env var without also updating the central registry in `orchestrator/src/config/externalBlockers.ts`. | | `/health` returns 503 but `/ready` is 200 | memory `critical` is a separate signal from readiness. Inspect CT memory; this happens on constrained builders and is not a deploy bug. | | portal page loads but MetaMask login does nothing | the portal couldn't reach `/api/auth/*`. Walk back up the NPMplus rule chain. | ## Cutting over from the pre-existing Next.js build Phoenix previously had an older Next.js "ISO-20022 Combo Flow" app in `/opt/currencicombo/webapp`. The cutover sequence on CT 8604 is: 1. **Backup the old install** out-of-band: ``` tar czf /root/currencicombo-preRepo-$(date +%s).tgz /opt/currencicombo /etc/currencicombo 2>/dev/null || true ``` 2. **Disable the pre-existing systemd units** (they're the same names but point at the old tree): ``` systemctl stop currencicombo-webapp currencicombo-orchestrator systemctl disable currencicombo-webapp currencicombo-orchestrator ``` 3. Run `install.sh` (writes the new units, new nginx, new env). On an already-set-up host this is idempotent: it preserves `/etc/currencicombo/orchestrator.env` if it already exists. 4. Run `deploy-currencicombo-8604.sh`. 5. Apply the NPMplus `/api` + `/events` path rules. 6. Smoke from outside the CT: `curl -skI https://curucombo.xn--vov0g.com/ && curl -sk https://curucombo.xn--vov0g.com/api/ready`. ## Proxmox-side follow-up (not in this PR) After this PR merges and the above cutover runs cleanly, the `/home/intlc/projects/proxmox` repo needs a separate commit to: - Update `phoenix-deploy-api/deploy-targets.json` to point at: - repo: `d-bis/CurrenciCombo` - branch: `main` - target: `default` - deploy entrypoint: `scripts/deployment/deploy-currencicombo-8604.sh` - Remove any stale `/opt/currencicombo/webapp` Next.js references. - Drop any description of `ignoreBuildErrors: true` in `webapp/next.config.ts` — the new webapp is Vite+tsc-strict, no build-error suppression.