Files
investor-flow/docs/DEPLOY_UNRAID.md
T
Investor Flow Build 90e1829d39
CI / Test (push) Canceled after 0s
CI / Build and push (push) Canceled after 0s
feat: Unraid deploy, dealer-flow heatmap, confluence zones, 13F capture
Ship Node production images, Unraid compose, and Gitea CI/CD (test then
push registry images; cron script if no runner). Rebuild dealer flow as a
heatmap-first map with integrity gates and chart helpers. Add confluence
zone rules, session clock, capture evidence, and tighter 13F/queue/options
paths, plus the matching UI and tests.
2026-08-18 14:10:02 -04:00

5.2 KiB

Deploy Investor Flow on Unraid

Two containers: backend (:3001, SQLite + queue) and frontend (:3000, Next.js, proxies /api to the backend). Git and Actions already live on this Unraid box at http://unraid.local:3003/transnet/investor-flow.

The current Gitea repo has Actions enabled but no runner registered, so every CI run is cancelled. Follow "One-time: Gitea runner" below if you want push-to-main to test and publish images.

What you get

Path Role
docker-compose.yml Build-from-git stack (works on Unraid or a laptop)
deploy/unraid/compose.pull.yml Pull prebuilt images from the Gitea registry
deploy/unraid/.env.example Secrets + ports + data dir
deploy/unraid/act-runner-compose.yml Gitea act_runner so CI/CD actually runs
deploy/unraid/user-scripts/sync-and-up.sh Cron CD: git pull + compose up --build
.github/workflows/ci.yml Tests on every push / PR
.github/workflows/cd.yml Build + push images on main

Use a cache (or single-disk) path for SQLite. /mnt/user/... is FUSE and can corrupt WAL files.

/mnt/cache/appdata/investor-flow/
  repo/          git checkout (this repo)
  data/          investor-flow.db + harvest files
  .env           secrets (not in git)

First-time stack

SSH to Unraid (or Unraid terminal):

mkdir -p /mnt/cache/appdata/investor-flow/data
git clone http://unraid.local:3003/transnet/investor-flow.git \
  /mnt/cache/appdata/investor-flow/repo

cp /mnt/cache/appdata/investor-flow/repo/deploy/unraid/.env.example \
  /mnt/cache/appdata/investor-flow/.env
nano /mnt/cache/appdata/investor-flow/.env

Required in .env:

  • IFLOW_SESSION_SECRET — openssl rand -hex 32
  • SEC_OPERATOR_EMAIL — real address (SEC + Yahoo user-agent)
  • LLM_PROVIDER_URL — Ornith LAN URL, e.g. http://10.37.0.165:30081/v1 (not localhost)
  • IFLOW_DATA_DIR=/mnt/cache/appdata/investor-flow/data

If you copy today's Mac DB into data/, also set IFLOW_CRYPTO_KEY to the same value the Mac used. If the Mac never set one, encrypted X/FRED rows used the built-in dev key; re-enter those keys in Admin after a fresh Unraid DB instead of guessing.

Optional: copy the existing database (stop the Mac backend first so WAL is clean):

# from the Mac, after stopping :3001
scp app/server/data/investor-flow.db* \
  root@unraid.local:/mnt/cache/appdata/investor-flow/data/

Build and start:

cd /mnt/cache/appdata/investor-flow/repo
docker compose --env-file /mnt/cache/appdata/investor-flow/.env up -d --build

Open http://unraid.local:3000. Backend health: http://unraid.local:3001/health.

Compose Manager plugin: create a stack whose project directory is the repo checkout and whose env file is /mnt/cache/appdata/investor-flow/.env.

Reverse proxy (SWAG / NPM): point the host at frontend :3000 only. The browser talks same-origin /api; the Next container reaches the backend on the compose network.

One-time: Gitea runner (unlocks CI + image CD)

  1. Gitea → Site Administration → Actions → Runners → Create new runner. Copy the token.
  2. Unraid Docker: add insecure registry 10.37.0.86:3003 (Gitea HTTP) so pulls/pushes work. Restart Docker.
  3. Start the runner:
cd /mnt/cache/appdata/investor-flow/repo
export GITEA_RUNNER_REGISTRATION_TOKEN=...   # from step 1
export GITEA_INSTANCE_URL=http://10.37.0.86:3003
docker compose -f deploy/unraid/act-runner-compose.yml up -d
  1. Confirm the runner is Idle on the Gitea runners page.
  2. Repo → Settings → Actions → Secrets: REGISTRY_TOKEN = a Gitea token with write:package and write:repository.
  3. Push to main. CI should run tests; CD should push:
  • 10.37.0.86:3003/transnet/investor-flow-backend:latest
  • 10.37.0.86:3003/transnet/investor-flow-frontend:latest

Then switch .env image names to those registry tags and use deploy/unraid/compose.pull.yml so Unraid no longer builds on the array.

CD that works before a runner exists

Unraid → User Scripts → new script, paste deploy/unraid/user-scripts/sync-and-up.sh, schedule every 10 minutes (or after you push). It fast-forwards main and rebuilds only when HEAD moved.

A push to Gitea is then: write code → git push origin main → cron on Unraid rebuilds containers.

Day-2 operations

Task How
Logs docker compose logs -f --tail=200 backend frontend
Restart docker compose up -d
Update (pull mode) docker compose -f deploy/unraid/compose.pull.yml pull && docker compose -f deploy/unraid/compose.pull.yml up -d
Backup DB copy /mnt/cache/appdata/investor-flow/data/investor-flow.db* (stop backend first, or use SQLite backup)
Ornith keep LLM_PROVIDER_URL on the LAN IP; user LLM endpoint in Settings can stay http://10.37.0.165:30081/v1

The backend process must stay up for dealer-map snapshots and the queue. restart: unless-stopped plus Unraid array autostart covers that.

What this is not

  • Not Vercel. Next standalone + the Node backend both run on Unraid.
  • /reports is still the thin HTML stub. A daily GEX briefing job is separate.
  • Do not publish IFLOW_SESSION_SECRET, IFLOW_CRYPTO_KEY, or Gitea tokens.