MosswartOverlord/go-services/docker-compose.go.yml
Erik 253250a01d feat(go-services): inventory-go Phase A — read-side scaffold + simple endpoints
First slice of the inventory-service port, running in parallel READ-ONLY against
the production inventory_db (never written):
- main.go/store.go: pgx pool (forced read-only), enum-DB loader extracting
  AttributeSetInfo for set-name resolution, /health, /sets/list, /characters/list.
- Dockerfile + compose service inventory-go (127.0.0.1:8772, enum JSON mounted).

Validated vs the Python service on the same DB: /characters/list 167 chars exact
counts; /sets/list 76 sets EXACT match (ids, names, counts).

Remaining (large): /search/items (40+ filters + enrich_db_item), inventory
fetch, item-processing ingestion (extract_item_properties), and the suitbuilder
solver.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 11:33:55 +02:00

156 lines
5.7 KiB
YAML

# Compose OVERRIDE that adds the Go services alongside the live Python stack.
# It only ADDS containers; it never modifies the tracked docker-compose.yml or
# any running Python service.
#
# Invoke from the repo root so the Compose project name resolves to
# "mosswartoverlord" (same as the live stack) and the new container joins the
# existing default network — letting it reach the `db` service by name:
#
# cd /home/erik/MosswartOverlord
# export BUILD_VERSION="$(date -u +%Y.%-m.%-d.%H%M)-$(git rev-parse --short HEAD)"
# docker compose -f docker-compose.yml -f go-services/docker-compose.go.yml \
# build dereth-tracker-go
# docker compose -f docker-compose.yml -f go-services/docker-compose.go.yml \
# up -d --no-deps dereth-tracker-go
#
# --no-deps keeps Compose from touching the already-running `db` (and anything
# else). The service is loopback-bound (127.0.0.1:8770); external reach is only
# ever via the host nginx `location /go/` block (added separately).
services:
dereth-tracker-go:
build:
context: ./go-services/tracker-go
args:
BUILD_VERSION: ${BUILD_VERSION:-dev}
image: dereth-tracker-go:local
container_name: dereth-tracker-go
ports:
- "127.0.0.1:8770:8770"
environment:
PORT: "8770"
# Read-only use of the same dereth TimescaleDB the Python tracker writes.
DATABASE_URL: "postgresql://postgres:${POSTGRES_PASSWORD}@db:5432/dereth"
INVENTORY_SERVICE_URL: "http://inventory-service:8000"
# Same signing key as the Python tracker so the same login cookie verifies
# on both during the parallel run.
SECRET_KEY: "${SECRET_KEY}"
LOG_LEVEL: "INFO"
depends_on:
- db
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Go port of discord-rare-monitor. Consumes the SAME Python /ws/live firehose
# as the live Python bot. DRY-RUN by default (logs classifications, posts
# nothing) so it can't double-post. To parallel-test for real, set a TEST
# DISCORD_RARE_BOT_TOKEN + TEST channel IDs + DRY_RUN=0 here.
discord-rare-monitor-go:
build:
context: ./go-services/discord-go
args:
BUILD_VERSION: ${BUILD_VERSION:-dev}
container_name: discord-rare-monitor-go
environment:
DERETH_TRACKER_WS_URL: "ws://dereth-tracker:8765/ws/live"
MONITOR_CHARACTER: "Dunking Rares"
ICONS_DIR: "/icons"
LOG_LEVEL: "INFO"
# DISCORD_RARE_BOT_TOKEN: "" # set a TEST token to go live
# DRY_RUN: "0" # required (with a token) to actually post
# COMMON_RARE_CHANNEL_ID / GREAT_RARE_CHANNEL_ID / SAWATOLIFE_CHANNEL_ID /
# ACLOG_CHANNEL_ID: set TEST channels before going live
volumes:
- ./discord-rare-monitor/icons:/icons:ro
depends_on:
- dereth-tracker
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# ---- Phase 2: shadow ingest (fully isolated; production never touched) ----
# A SEPARATE TimescaleDB the Go tracker owns for shadow ingest. Isolated
# volume + loopback port; the production dereth DB is never written.
dereth-go-db:
image: timescale/timescaledb:2.19.3-pg14
container_name: dereth-go-db
ports:
- "127.0.0.1:5434:5432"
environment:
POSTGRES_DB: "dereth_go"
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
volumes:
- dereth-go-data:/var/lib/postgresql/data
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Shadow tracker instance: same image, but OWNS dereth-go-db (read-write) and
# (once ingest lands) consumes the Python /ws/live firehose into it, so its
# ingest output can be compared against production without writing to it.
dereth-tracker-go-shadow:
image: dereth-tracker-go:local
container_name: dereth-tracker-go-shadow
ports:
- "127.0.0.1:8771:8771"
environment:
PORT: "8771"
DATABASE_URL: "postgresql://postgres:${POSTGRES_PASSWORD}@dereth-go-db:5432/dereth_go"
READ_ONLY: "false" # owns its DB; creates schema on boot
INVENTORY_SERVICE_URL: "http://inventory-service:8000"
SECRET_KEY: "${SECRET_KEY}"
SHARED_SECRET: "${SHARED_SECRET}" # /ws/position plugin auth (cutover-ready)
SHARED_SECRET_LEGACY: "${SHARED_SECRET_LEGACY:-}"
# Replay the Python /ws/live firehose into the ingest handlers (shadow).
SHADOW_INGEST_WS: "ws://dereth-tracker:8765/ws/live"
LOG_LEVEL: "INFO"
depends_on:
- dereth-go-db
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Go port of inventory-service. Phase A: read side, READ-ONLY against the
# production inventory_db, validated vs the Python service. Loopback :8772.
inventory-go:
build:
context: ./go-services/inventory-go
args:
BUILD_VERSION: ${BUILD_VERSION:-dev}
image: inventory-go:local
container_name: inventory-go
ports:
- "127.0.0.1:8772:8772"
environment:
PORT: "8772"
DATABASE_URL: "postgresql://inventory_user:${INVENTORY_DB_PASSWORD}@inventory-db:5432/inventory_db"
READ_ONLY: "true"
ENUM_DB_PATH: "/enums/comprehensive_enum_database_v2.json"
LOG_LEVEL: "INFO"
volumes:
- ./inventory-service/comprehensive_enum_database_v2.json:/enums/comprehensive_enum_database_v2.json:ro
depends_on:
- inventory-db
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
volumes:
dereth-go-data: