From 75c60b65b5739d5c87ea86ee8a1e322927fef0eb Mon Sep 17 00:00:00 2001 From: wyattb Date: Sat, 16 May 2026 12:56:40 -0400 Subject: [PATCH 1/7] #632 - parameterize dev compose ports and drop container_name Drop fixed container_name from db, scylla, siren, grafana, client, calypso so docker compose's project-name suffix handles uniqueness. Parameterize host ports via ${VAR:-default} for db (5432), scylla (8000), siren (1883 and 9002), grafana (3002), client (80). Defaults match today's values so single-stack and production behavior are byte-identical. Pass SCYLLA_PORT into the scylla container so its listener tracks the host binding. Update compose.scylla-dev.yml BACKEND_URL to follow SCYLLA_HOST_PORT so its dockerized client points at its own scylla. --- angular-client/compose.client.yml | 3 +-- compose/compose.calypso.yml | 1 - compose/compose.scylla-dev.yml | 2 +- compose/compose.yml | 7 +++---- siren-base/compose.grafana.yml | 3 +-- siren-base/compose.siren.yml | 5 ++--- 6 files changed, 8 insertions(+), 13 deletions(-) diff --git a/angular-client/compose.client.yml b/angular-client/compose.client.yml index 0605d38b..bc351073 100644 --- a/angular-client/compose.client.yml +++ b/angular-client/compose.client.yml @@ -1,6 +1,5 @@ services: client: - container_name: client restart: unless-stopped image: ghcr.io/northeastern-electric-racing/argos-client:develop build: @@ -8,7 +7,7 @@ services: target: production dockerfile: Dockerfile ports: - - 80:80 + - ${CLIENT_HOST_PORT:-80}:80 cpu_shares: 512 environment: diff --git a/compose/compose.calypso.yml b/compose/compose.calypso.yml index 6042fde0..8c2a3d97 100644 --- a/compose/compose.calypso.yml +++ b/compose/compose.calypso.yml @@ -1,6 +1,5 @@ services: calypso: - container_name: calypso image: ghcr.io/northeastern-electric-racing/calypso:Develop restart: unless-stopped environment: diff --git a/compose/compose.scylla-dev.yml b/compose/compose.scylla-dev.yml index 9028156f..612fa4ca 100644 --- a/compose/compose.scylla-dev.yml +++ b/compose/compose.scylla-dev.yml @@ -10,7 +10,7 @@ services: build: context: ../angular-client environment: - BACKEND_URL: http://127.0.0.1:8000 + BACKEND_URL: http://127.0.0.1:${SCYLLA_HOST_PORT:-8000} siren: extends: diff --git a/compose/compose.yml b/compose/compose.yml index 2dd75534..5dabe803 100644 --- a/compose/compose.yml +++ b/compose/compose.yml @@ -2,7 +2,6 @@ version: "3.8" services: odyssey-db: - container_name: odyssey-db image: postgres:17.2 restart: unless-stopped environment: @@ -12,7 +11,7 @@ services: - "-c" - "shared_buffers=256MB" ports: - - 5432:5432 # Exposed for external access if needed + - ${ODYSSEY_DB_PORT:-5432}:5432 # Exposed for external access if needed expose: - 5432 # Allow inter-container communication volumes: @@ -21,18 +20,18 @@ services: stop_grace_period: 2m scylla-server: - container_name: scylla-server image: ghcr.io/northeastern-electric-racing/argos-scylla:develop build: context: ../scylla-server restart: unless-stopped ports: - - 8000:8000 + - ${SCYLLA_HOST_PORT:-8000}:${SCYLLA_HOST_PORT:-8000} depends_on: - odyssey-db environment: - DATABASE_URL=postgresql://postgres:password@odyssey-db:5432/postgres - RUST_LOG=warn,scylla_server=debug + - SCYLLA_PORT=${SCYLLA_HOST_PORT:-8000} cpu_shares: 1024 stop_grace_period: 2m stop_signal: SIGINT diff --git a/siren-base/compose.grafana.yml b/siren-base/compose.grafana.yml index 5f445c35..22b2fadb 100644 --- a/siren-base/compose.grafana.yml +++ b/siren-base/compose.grafana.yml @@ -1,7 +1,6 @@ services: grafana: image: grafana/grafana-oss - container_name: grafana restart: unless-stopped environment: # increases the log level from info to debug @@ -9,6 +8,6 @@ services: - GF_PLUGINS_PREINSTALL=grafana-mqtt-datasource@@https://github.com/Northeastern-Electric-Racing/mqtt-datasource/releases/download/v1.2.0/grafana-mqtt-datasource-1.2.0.zip - GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=grafana-mqtt-datasource ports: - - "3002:3000" + - "${GRAFANA_HOST_PORT:-3002}:3000" volumes: - "grafana_storage:/var/lib/grafana" diff --git a/siren-base/compose.siren.yml b/siren-base/compose.siren.yml index 3e4e4c68..c3554ec6 100644 --- a/siren-base/compose.siren.yml +++ b/siren-base/compose.siren.yml @@ -1,11 +1,10 @@ services: siren: - container_name: siren restart: unless-stopped image: eclipse-mosquitto:latest ports: - - 1883:1883 - - 9002:9001 # win conflict on 9001 + - ${SIREN_MQTT_PORT:-1883}:1883 + - ${SIREN_WS_PORT:-9002}:9001 # win conflict on 9001 expose: - 1883 volumes: From d7e0dc97dcb3207a5445c80904cd8f4097514f9e Mon Sep 17 00:00:00 2001 From: wyattb Date: Sat, 16 May 2026 12:57:35 -0400 Subject: [PATCH 2/7] #632 - argos.sh honors STACK_OFFSET for parallel dev stacks When STACK_OFFSET=N is set, export per-service host-port env vars shifted by N and suffix the compose project name with _oN so 'down', 'logs', and 'exec' target the right stack. Unset or 0 = byte-identical to today's single-stack behavior. --- argos.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/argos.sh b/argos.sh index f00f9a85..d75fd965 100755 --- a/argos.sh +++ b/argos.sh @@ -2,5 +2,20 @@ profile=$1 shift 1 + +# STACK_OFFSET=N shifts every published host port by N and suffixes the +# compose project name with _oN so a second dev stack runs alongside the +# first with zero collisions. Unset or 0 = byte-identical to today. +project="odyssey_$profile" +if [ -n "$STACK_OFFSET" ] && [ "$STACK_OFFSET" != "0" ]; then + export ODYSSEY_DB_PORT=$((5432 + STACK_OFFSET)) + export SCYLLA_HOST_PORT=$((8000 + STACK_OFFSET)) + export CLIENT_HOST_PORT=$((80 + STACK_OFFSET)) + export SIREN_MQTT_PORT=$((1883 + STACK_OFFSET)) + export SIREN_WS_PORT=$((9002 + STACK_OFFSET)) + export GRAFANA_HOST_PORT=$((3002 + STACK_OFFSET)) + project="${project}_o${STACK_OFFSET}" +fi + cd ./compose -docker compose -f compose.yml -f "compose.$profile.yml" -p "odyssey_$profile" "$@" +docker compose -f compose.yml -f "compose.$profile.yml" -p "$project" "$@" From 156e6c611621bed9c578a1875e0d0ee738901bef Mon Sep 17 00:00:00 2001 From: wyattb Date: Sat, 16 May 2026 13:02:51 -0400 Subject: [PATCH 3/7] #632 - integration_test.sh uses project-aware compose down Replace 'docker rm -f odyssey-db' with 'docker compose -p odyssey_integration_test down', and run up/down under the same project so the script no longer depends on a fixed container_name. --- scylla-server/integration_test.sh | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/scylla-server/integration_test.sh b/scylla-server/integration_test.sh index b9e53d09..1e562800 100755 --- a/scylla-server/integration_test.sh +++ b/scylla-server/integration_test.sh @@ -1,16 +1,18 @@ #!/bin/sh +PROJECT=odyssey_integration_test + # Navigate to the compose directory echo "Navigating to compose directory..." cd ../compose || { echo "Compose directory not found"; exit 1; } -# Remove any existing odyssey-timescale container -echo "Stopping and removing any existing odyssey-timescale container..." -docker rm -f odyssey-db 2>/dev/null || echo "No existing container to remove." +# Tear down any leftover integration-test stack from a previous run +echo "Stopping any existing integration-test stack..." +docker compose -p "$PROJECT" down 2>/dev/null || true -# Start a new odyssey-timescale container -echo "Starting a new odyssey-timescale container..." -docker compose up -d odyssey-db || { echo "Failed to start odyssey-timescale"; exit 1; } +# Start a new odyssey-db container under our project +echo "Starting odyssey-db..." +docker compose -p "$PROJECT" up -d odyssey-db || { echo "Failed to start odyssey-db"; exit 1; } # Wait for the database to initialize echo "Waiting for the database to initialize..." @@ -32,6 +34,6 @@ cd ../compose || { echo "Compose directory not found"; exit 1; } # Stop and clean up containers echo "Stopping and cleaning up containers..." -docker compose down || { echo "Failed to clean up containers"; exit 1; } +docker compose -p "$PROJECT" down || { echo "Failed to clean up containers"; exit 1; } echo "Script completed successfully!" From 907d95e34e5a2846217b4aaedb3222c171c49ded Mon Sep 17 00:00:00 2001 From: wyattb Date: Sat, 16 May 2026 13:07:14 -0400 Subject: [PATCH 4/7] #632 - document STACK_OFFSET recipe for concurrent dev stacks Add a 'Running multiple dev stacks side-by-side' section to compose/README.md showing how STACK_OFFSET=N shifts ports and project names, with a concurrent client-dev + fake-data example. Note that production profiles and existing ng-serve / cargo-run workflows are unaffected. Also updates .claude/skills/run-local/SKILL.md (not tracked in this repo, lives in the shared worktrees-root .claude/) to scan ports 8000/8010/.../8090 for backend liveness and identify which stack owns the listening port via the docker project's _oN suffix. --- compose/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/compose/README.md b/compose/README.md index 56884871..1a73e225 100644 --- a/compose/README.md +++ b/compose/README.md @@ -30,6 +30,24 @@ The base docker compose (`compose.yml`) contains some important features to note *These profiles are non-exhuastive, there are plently of use cases these profiles do not cover. In that case, you can write your own profile to cover it.* +#### Running multiple dev stacks side-by-side + +Set `STACK_OFFSET=N` in front of `argos.sh` to shift every published host port by `N` and suffix the compose project name with `_oN`, so a second dev stack runs alongside the first with no name or port collisions. Unset (or `0`) means today's exact behavior, byte-identical to before. + +``` +# stack 1: today's ports (db 5432, scylla 8000, client 80, siren 1883/9002, grafana 3002) +./argos.sh client-dev up -d + +# stack 2: every port shifted by 10 (db 5442, scylla 8010, client 90, siren 1893/9012, grafana 3012) +STACK_OFFSET=10 ./argos.sh fake-data up -d + +# tear each down with the same offset that started it +./argos.sh client-dev down +STACK_OFFSET=10 ./argos.sh fake-data down +``` + +`STACK_OFFSET` is honored for the dev profiles (`client-dev`, `scylla-dev`, `fake-data`). Production profiles (`router`, `brick`, `tpu`) are unaffected when run with no env vars. Multiple `ng serve` clients and multiple `cargo run` scyllas are already supported via the existing port flags and are independent of this. + #### Examples with and without profiles - To send some simulated data to a client you are running with `npm`: `./argos.sh client-dev up` From 822892bbb906c841b23263cf2581efa6193763e9 Mon Sep 17 00:00:00 2001 From: wyattb Date: Sat, 16 May 2026 13:19:47 -0400 Subject: [PATCH 5/7] #632 - keep argos.sh thin, push port math to caller argos.sh now only appends '_oN' to the compose project name when STACK_OFFSET=N is set, leaving port env vars to the caller (shell, .envrc, or an alias). The base compose files still default every port to today's value via \${VAR:-default}, so unset = byte-identical. README's two-stack recipe shows the inline 'env STACK_OFFSET=N ODYSSEY_DB_PORT=... ./argos.sh ...' pattern, and notes that 'compose down' only needs STACK_OFFSET since it targets by project name not port. --- argos.sh | 18 ++---------------- compose/README.md | 23 ++++++++++++++++------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/argos.sh b/argos.sh index d75fd965..6c3b7662 100755 --- a/argos.sh +++ b/argos.sh @@ -2,20 +2,6 @@ profile=$1 shift 1 - -# STACK_OFFSET=N shifts every published host port by N and suffixes the -# compose project name with _oN so a second dev stack runs alongside the -# first with zero collisions. Unset or 0 = byte-identical to today. -project="odyssey_$profile" -if [ -n "$STACK_OFFSET" ] && [ "$STACK_OFFSET" != "0" ]; then - export ODYSSEY_DB_PORT=$((5432 + STACK_OFFSET)) - export SCYLLA_HOST_PORT=$((8000 + STACK_OFFSET)) - export CLIENT_HOST_PORT=$((80 + STACK_OFFSET)) - export SIREN_MQTT_PORT=$((1883 + STACK_OFFSET)) - export SIREN_WS_PORT=$((9002 + STACK_OFFSET)) - export GRAFANA_HOST_PORT=$((3002 + STACK_OFFSET)) - project="${project}_o${STACK_OFFSET}" -fi - cd ./compose -docker compose -f compose.yml -f "compose.$profile.yml" -p "$project" "$@" +docker compose -f compose.yml -f "compose.$profile.yml" \ + -p "odyssey_$profile${STACK_OFFSET:+_o$STACK_OFFSET}" "$@" diff --git a/compose/README.md b/compose/README.md index 1a73e225..8ac7063c 100644 --- a/compose/README.md +++ b/compose/README.md @@ -32,21 +32,30 @@ The base docker compose (`compose.yml`) contains some important features to note #### Running multiple dev stacks side-by-side -Set `STACK_OFFSET=N` in front of `argos.sh` to shift every published host port by `N` and suffix the compose project name with `_oN`, so a second dev stack runs alongside the first with no name or port collisions. Unset (or `0`) means today's exact behavior, byte-identical to before. +Every published host port in the dev compose files reads from an env var with today's value as the default: `ODYSSEY_DB_PORT` (5432), `SCYLLA_HOST_PORT` (8000), `CLIENT_HOST_PORT` (80), `SIREN_MQTT_PORT` (1883), `SIREN_WS_PORT` (9002), `GRAFANA_HOST_PORT` (3002). With no env vars set, behavior is byte-identical to before. + +To run a second dev stack alongside the first, set those vars (shifted to free values) plus `STACK_OFFSET=N`, which `argos.sh` appends to the project name as `_oN` so `down`, `logs`, and `exec` target the right stack: ``` -# stack 1: today's ports (db 5432, scylla 8000, client 80, siren 1883/9002, grafana 3002) +# stack 1 at defaults ./argos.sh client-dev up -d -# stack 2: every port shifted by 10 (db 5442, scylla 8010, client 90, siren 1893/9012, grafana 3012) -STACK_OFFSET=10 ./argos.sh fake-data up -d - -# tear each down with the same offset that started it +# stack 2, shifted by 10 — each profile only consumes the vars its services need. +# Use 'env' so the vars don't leak into stack 1's teardown. +N=10 +env STACK_OFFSET=$N \ + ODYSSEY_DB_PORT=$((5432+N)) SCYLLA_HOST_PORT=$((8000+N)) \ + CLIENT_HOST_PORT=$((80+N)) SIREN_MQTT_PORT=$((1883+N)) \ + SIREN_WS_PORT=$((9002+N)) GRAFANA_HOST_PORT=$((3002+N)) \ + ./argos.sh fake-data up -d + +# Teardown: stack 1 needs nothing; stack 2 only needs STACK_OFFSET since +# 'compose down' targets containers by project name, not by port. ./argos.sh client-dev down STACK_OFFSET=10 ./argos.sh fake-data down ``` -`STACK_OFFSET` is honored for the dev profiles (`client-dev`, `scylla-dev`, `fake-data`). Production profiles (`router`, `brick`, `tpu`) are unaffected when run with no env vars. Multiple `ng serve` clients and multiple `cargo run` scyllas are already supported via the existing port flags and are independent of this. +Production profiles (`router`, `brick`, `tpu`) are unaffected when run with no env vars. Multiple `ng serve` clients and multiple `cargo run` scyllas are already supported via the existing port flags and are independent of this. #### Examples with and without profiles From c87ecc19fe0fff9d323c41956f2396c871a310d7 Mon Sep 17 00:00:00 2001 From: wyattb Date: Sun, 17 May 2026 16:29:57 -0400 Subject: [PATCH 6/7] #632 - drop 'o' prefix from STACK_OFFSET project name suffix --- argos.sh | 2 +- compose/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/argos.sh b/argos.sh index 6c3b7662..213b8999 100755 --- a/argos.sh +++ b/argos.sh @@ -4,4 +4,4 @@ profile=$1 shift 1 cd ./compose docker compose -f compose.yml -f "compose.$profile.yml" \ - -p "odyssey_$profile${STACK_OFFSET:+_o$STACK_OFFSET}" "$@" + -p "odyssey_$profile${STACK_OFFSET:+_$STACK_OFFSET}" "$@" diff --git a/compose/README.md b/compose/README.md index 8ac7063c..b80ade07 100644 --- a/compose/README.md +++ b/compose/README.md @@ -34,7 +34,7 @@ The base docker compose (`compose.yml`) contains some important features to note Every published host port in the dev compose files reads from an env var with today's value as the default: `ODYSSEY_DB_PORT` (5432), `SCYLLA_HOST_PORT` (8000), `CLIENT_HOST_PORT` (80), `SIREN_MQTT_PORT` (1883), `SIREN_WS_PORT` (9002), `GRAFANA_HOST_PORT` (3002). With no env vars set, behavior is byte-identical to before. -To run a second dev stack alongside the first, set those vars (shifted to free values) plus `STACK_OFFSET=N`, which `argos.sh` appends to the project name as `_oN` so `down`, `logs`, and `exec` target the right stack: +To run a second dev stack alongside the first, set those vars (shifted to free values) plus `STACK_OFFSET=N`, which `argos.sh` appends to the project name as `_N` so `down`, `logs`, and `exec` target the right stack: ``` # stack 1 at defaults From c29ebc63dac3cf9180fd2a8a2bf7eac3cbcd667c Mon Sep 17 00:00:00 2001 From: wyattb Date: Tue, 19 May 2026 13:06:25 -0400 Subject: [PATCH 7/7] #632 - readme cleanups + integration_test honors ODYSSEY_DB_PORT README: - Correct the volume name (it is per-project, e.g. odyssey_client-dev_db-data, not the stale 'argos_db-data'). - Make the teardown line in the two-stack recipe use the same $N as the up command for copy-paste consistency. - Add a one-line caveat that STACK_OFFSET is purely a project-name suffix (any non-empty value, including 0, creates a separate project), so it should not be set when running production profiles. integration_test.sh: - Read DATABASE_URL's port from ${ODYSSEY_DB_PORT:-5432} in both the diesel migration and cargo test invocations. Default behavior is unchanged; if the user has ODYSSEY_DB_PORT set (e.g. from running a parallel stack), the DB binds and the tests connect on the same port instead of fighting. --- compose/README.md | 6 +++--- scylla-server/integration_test.sh | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compose/README.md b/compose/README.md index b80ade07..b9a4a14b 100644 --- a/compose/README.md +++ b/compose/README.md @@ -24,7 +24,7 @@ Profiles: The base docker compose (`compose.yml`) contains some important features to note. However, it is useless standalone. Please read the profile customization selection below before using the base compose. -- It persists the database between `down` commands via a volume called `argos_db-data`. Delete it with `docker volume rm argos_db-data` to start with a new database next `up`. +- It persists the database between `down` commands via a volume named `_db-data` (e.g. `odyssey_client-dev_db-data` for the default `client-dev` stack). Wipe it with `./argos.sh down -v` or `docker volume rm _db-data` to start with a new database next `up`. - It weighs the CPU usage of siren higher, so it is prioritized in CPU starvation scenarios. @@ -52,10 +52,10 @@ env STACK_OFFSET=$N \ # Teardown: stack 1 needs nothing; stack 2 only needs STACK_OFFSET since # 'compose down' targets containers by project name, not by port. ./argos.sh client-dev down -STACK_OFFSET=10 ./argos.sh fake-data down +STACK_OFFSET=$N ./argos.sh fake-data down ``` -Production profiles (`router`, `brick`, `tpu`) are unaffected when run with no env vars. Multiple `ng serve` clients and multiple `cargo run` scyllas are already supported via the existing port flags and are independent of this. +`STACK_OFFSET` is purely a project-name suffix: any non-empty value (including `0`) creates a separate compose project, so don't set it when running production profiles. Production profiles (`router`, `brick`, `tpu`) are unaffected when run with no env vars. Multiple `ng serve` clients and multiple `cargo run` scyllas are already supported via the existing port flags and are independent of this. #### Examples with and without profiles diff --git a/scylla-server/integration_test.sh b/scylla-server/integration_test.sh index 1e562800..205ad7f5 100755 --- a/scylla-server/integration_test.sh +++ b/scylla-server/integration_test.sh @@ -23,11 +23,11 @@ cd ../scylla-server || { echo "scylla-server directory not found"; exit 1; } # Run database migrations echo "Running database migrations..." -DATABASE_URL=postgresql://postgres:password@127.0.0.1:5432/postgres diesel migration run || { echo "Migration failed"; exit 1; } +DATABASE_URL=postgresql://postgres:password@127.0.0.1:${ODYSSEY_DB_PORT:-5432}/postgres diesel migration run || { echo "Migration failed"; exit 1; } # Run tests echo "Running tests..." -DATABASE_URL=postgresql://postgres:password@127.0.0.1:5432/postgres cargo test -- --test-threads=1 || { echo "Tests failed"; exit 1; } +DATABASE_URL=postgresql://postgres:password@127.0.0.1:${ODYSSEY_DB_PORT:-5432}/postgres cargo test -- --test-threads=1 || { echo "Tests failed"; exit 1; } # Navigate back to the compose directory cd ../compose || { echo "Compose directory not found"; exit 1; }