Files
trumpsignal-backend/deploy
k b941223c88 fix: complete v5 routing — API exposure, rescore persistence, leverage cap, key backup doc
Three plumbing fixes + one ops doc that close the gaps from the audit.

scripts/rescore_v5.py
  Was overwriting only signal/conf/reasoning/sentiment/relevant/
  prefilter_reason/analysis_version. Now also persists target_asset,
  category, expected_move_pct — without these the bot can't route
  rescored posts correctly (would silently fall back to BTC).

app/schemas.py + app/api/posts.py
  TrumpPost response model didn't expose target_asset/category/
  expected_move_pct, so the frontend had no way to display "this
  signal will trade SOL". Added the three fields + mapping in
  _post_to_schema(). Pre-v5 posts return null. No frontend changes
  yet — display work is a follow-up.

app/services/hyperliquid.py
  HL caps max leverage per asset (BTC/ETH 50×, SOL 20×, memes 3-5×).
  set_leverage() always tried to push self._leverage — if user set
  30× and bot routed to TRUMP, HL rejected the order and the trade
  silently dropped. Added _get_max_leverage() (queries meta()'s
  maxLeverage field) and _clip_leverage() that caps to HL's max.
  set_leverage now returns the effective leverage so callers can
  use it for notional sizing if needed.

deploy/ENCRYPTION_KEY_BACKUP.md
  Documented mandatory backup procedure for the symmetric key that
  encrypts every user's HL API key. Lost key = all users' bots dead
  with no recovery. Includes rotation procedure + quarterly test
  step + things-not-to-do list.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 19:59:30 +08:00
..

Backend deployment + uptime monitoring

This folder collects the moving pieces that turn the backend from "runs on my laptop" into "runs 24/7 with auto-restart and external alerting".

What the bot needs to be reliable

  1. Auto-restart on crash — handled by systemd (Restart=always) or Docker Compose (restart: unless-stopped). Pick one.
  2. Health endpoints — exposed by app/main.py:
    • GET /api/health (shallow): 200 as long as the FastAPI process is alive. Used by Docker's internal HEALTHCHECK.
    • GET /api/health/deep: 200 only if DB ping works AND at least one Truth Social scraper has polled in the last 90s. Used by external uptime monitors.
  3. Dual-source scrapertruth_social.py (CNN archive) + trumpstruth.py (RSS). Both insert into posts with the same external_id hash, so duplicates are dropped. Whoever sees the post first wins.
  4. External uptime monitor — pings the deep health endpoint from outside the box. If we lose internet or the box is on fire, we get alerted. Recommended: UptimeRobot (free tier covers this).

docker-compose.yml is already configured with:

restart: unless-stopped
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:8000/api/health"]
  interval: 15s
  timeout: 5s
  retries: 5
  start_period: 30s

Deploy steps on a fresh server:

git clone <repo>
cd backend
cp .env.example .env
# Fill in: SERVICE_USER_POSTGRES, SERVICE_PASSWORD_POSTGRES, FRONTEND_URL,
#          ENCRYPTION_KEY, AI_API_KEY, HL_MAINNET=true
docker compose up -d
docker compose logs -f api    # tail logs

To verify auto-restart works:

docker compose kill api       # simulate crash
sleep 12                      # wait for compose to relaunch
curl http://localhost:8000/api/health   # should return {"status":"ok"}

Option B — systemd (bare-metal, no Docker)

Use trumpsignal-api.service from this folder.

# 1. Code lives at /opt/trumpsignal/backend
sudo useradd -m -d /opt/trumpsignal trumpsignal
sudo -u trumpsignal git clone <repo> /opt/trumpsignal/backend
cd /opt/trumpsignal/backend
sudo -u trumpsignal python3.11 -m venv venv
sudo -u trumpsignal venv/bin/pip install -r requirements.txt

# 2. Configure
sudo -u trumpsignal cp .env.example .env
sudo -u trumpsignal nano .env       # fill in secrets

# 3. Install + start the service
sudo cp deploy/trumpsignal-api.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now trumpsignal-api

# 4. Tail logs
sudo journalctl -u trumpsignal-api -f

Test auto-restart:

sudo systemctl kill --signal=SIGKILL trumpsignal-api
sleep 12
curl http://localhost:8000/api/health   # should return {"status":"ok"}

UptimeRobot setup

  1. Sign up at https://uptimerobot.com (free tier = 50 monitors, 5-min interval).
  2. Add new monitor:
    • Type: HTTP(s)
    • URL: https://api.trump-signal.bitnews.day/api/health/deep (replace with your real domain)
    • Monitoring interval: 5 min
    • Alert contacts: add your email and/or Telegram
  3. UptimeRobot will alert you when the deep healthcheck returns 503 — i.e. when both scrapers have been silent for >90s, OR when the DB is unreachable.

Why deep, not shallow

The shallow /api/health returns 200 even if the scraper has died but the FastAPI process is still serving HTTP. A monitor pointed at the shallow endpoint would happily report "all green" while the bot silently misses posts. Always point external monitors at /api/health/deep.


Reading the deep healthcheck

{
  "status": "ok",
  "now": "2026-04-25T07:35:01.123456+00:00",
  "db_ok": true,
  "db_error": null,
  "scrapers": [
    { "name": "cnn",         "last_poll": "2026-04-25T07:34:58Z", "age_sec": 3,  "last_error": null },
    { "name": "trumpstruth", "last_poll": "2026-04-25T07:34:52Z", "age_sec": 9,  "last_error": null }
  ],
  "freshest_age_sec": 3,
  "problems": []
}

status: "degraded" + HTTP 503 means at least one item in problems is non-empty. The most common failure modes:

  • db: <error> — Postgres/SQLite can't be reached. Check DATABASE_URL.
  • scrapers: all stale (freshest=Ns) — both upstream feeds silent. Check network egress, then check if both ix.cnn.io and trumpstruth.org are responding from the box: curl -sI https://ix.cnn.io/data/truth-social/truth_archive.json

Burst-protection note (systemd)

The unit file caps restarts at 5 within 60s, so a hard misconfiguration (missing env var, etc.) stops the boot loop instead of thrashing forever. After fixing the underlying issue:

sudo systemctl reset-failed trumpsignal-api
sudo systemctl start trumpsignal-api