diff --git a/docs/go-rewrite-prompt.md b/docs/go-rewrite-prompt.md index c5c5f5ea..212b77ab 100644 --- a/docs/go-rewrite-prompt.md +++ b/docs/go-rewrite-prompt.md @@ -21,15 +21,21 @@ You are starting a side project: **rewrite the MosswartOverlord backend (current The Python service runs a **single uvicorn worker / single asyncio event loop**, so it's capped at one CPU core and can't use the host's other cores (in-memory state — plugin connections, live snapshots — prevents multi-worker). Under load it saturated that core (telemetry processing lagged, the dashboard flickered). Go's value here is **true multicore concurrency** (goroutines + shared state via `sync`/channels) plus ~10–50× cheaper per-message work. The win is the concurrency model, not raw speed — this is an I/O-bound service, so design for correctness and parallelism, not micro-optimization. ## Scope -**In scope (rewrite in Go):** -- The main tracker (`main.py`): WebSocket ingest (`/ws/position`), browser WebSocket (`/ws/live`), the HTTP read API (`/live`, `/trails`, `/stats/*`, `/total-rares`, `/total-kills`, `/character-stats/*`, `/quest-status`, etc.), the 5s `/live` cache loop, persistence to TimescaleDB, and serving the React static bundle. -- Optionally later: `inventory-service` and `discord-rare-monitor` (both smaller, good follow-ups). +**In scope — rewrite in Go. Three separate services, each independently deployable and parallel-testable:** + +1. **discord-rare-monitor** (`discord-rare-monitor/`) — **do this FIRST as the Go warm-up; it's the smallest and most isolated.** A Discord bot that connects to the tracker's `/ws/live` (subscribes to `rare`/`chat`), classifies rares (the ~71-name common-rares list → common vs great channel), posts embeds to Discord, and relays allegiance chat. In Go: a `coder/websocket` client + `bwmarrin/discordgo`. Parallel test: run the Go copy against the same `/ws/live` but pointed at a **TEST Discord channel** (so it doesn't double-post to the real ones), and compare its output to the Python bot's. + +2. **inventory-service** (`inventory-service/`) — a separate FastAPI app with its **own Postgres** (`inventory_db`, container `inventory-db`, port 5433). Receives inventory payloads over HTTP from the tracker (`POST /inventory/{char}/item`, `/process-inventory`), does item **enum translation** (`comprehensive_enum_database_v2.json`) + DB writes, and serves item search + the **suitbuilder constraint solver** (`suitbuilder.py` — the heaviest piece; port carefully and validate against the Python solver's results). In Go: `net/http` + `pgx`. Parallel test: Go copy on a separate port with its own DB (or read-only against the same one); have the tracker tee inventory forwards to it; diff outputs. + +3. **Main tracker** (`main.py`) — the big one, do last: WS ingest `/ws/position`, browser WS `/ws/live`, the HTTP read API (`/live`, `/trails`, `/stats/*`, `/total-rares`, `/total-kills`, `/character-stats/*`, `/quest-status`, …), the 5s `/live` cache loop, persistence to TimescaleDB, and serving the React `static/` bundle. Follow the phased parallel-run plan below. + +**Suggested order:** (1) discord bot → (2) tracker read-side (Phase 1 below) → (3) inventory-service → (4) tracker ingest + cutover. The three services can also progress somewhat independently. **Out of scope (keep as-is):** -- The **React frontend** (`frontend/`) — it stays; Go just serves the same built `static/` bundle and implements the same API/WS contract. No frontend changes should be needed if the contract matches. +- The **React frontend** (`frontend/`) — it stays; the Go tracker serves the same built `static/` bundle and implements the same API/WS contract. No frontend changes should be needed if the contract matches. - The **overlord-agent** (host-side, shells to `claude`) — leave in Python. - The **DECAL plugin** — do NOT change it. Go must speak the existing wire protocol. -- The **databases** — Go uses the same PostgreSQL/TimescaleDB. +- The **databases themselves** — Go reuses the same PostgreSQL/TimescaleDB and inventory Postgres. ## The parallel-run plan (this is the core of the project) Run Go as a **new container in the same docker-compose stack**, on a new loopback port (e.g. `127.0.0.1:8770`), reachable via a **separate nginx path** (e.g. `https://overlord.snakedesert.se/go/`) so it's testable side-by-side with the live Python app. Phases: