From e5c0c8a448576ec54bc53fd409705f90fd276c5c Mon Sep 17 00:00:00 2001 From: Matthew Meszaros Date: Fri, 22 May 2026 14:51:16 +0000 Subject: [PATCH] chore(dev): standardize ports where they don't conflict MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most container ports go back to their natural defaults — the offsets that existed weren't justified, they just made URLs harder to remember. Now standard: backend 8080 (was always 8080) tracking 3000 (was 13000) realtime 4000 (was 14000) web 5173 (was 15173 — already changed) kafka 9092 (was 19092) schema-registry 8081 (was 18081) localstack 4566 (was 14566) cloud-tasks 8123 (was 18123) stripe-mock 12111 (always was) Kept offset (the defaults conflict too often on real dev machines): postgres 15432 (system postgres / sibling project) redis 16379 (sibling docker projects with redis) mailpit ui 18025 (sibling docker projects with mailpit) mailpit smtp 11025 (same) kafka-ui 18090 (8080 already used by backend) Touched: docker-compose.yml, Makefile (test-seed SEED_TEST_DB), READMEs (root + deploy), local-development.md + deployment-guide.md. Internal docker-network refs (kafka:29092, mailpit:1025, etc.) unchanged — only host-port mappings moved. Compose validated, all default-profile services come up healthy on the new ports. --- README.md | 14 ++++----- deploy/README.md | 4 +-- docker-compose.yml | 54 ++++++++++++++++++++++------------ resources/local-development.md | 26 ++++++++-------- 4 files changed, 57 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 8fe40a49..c9d33e92 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,8 @@ The frontend (React) talks to three control-plane services: the **Backend API** | Service | Port (local) | Plane | Description | |---------|------|-------|-------------| | Backend | 8080 | control | REST API, auth, business logic, worker orchestration | -| Tracking | 13000 | control | Open/click pixel + redirect service | -| Realtime | 14000 | control | WebSocket gateway | +| Tracking | 3000 | control | Open/click pixel + redirect service | +| Realtime | 4000 | control | WebSocket gateway | | Consumer | – | control | Kafka event processor | | Worker | – | execution | SSH-managed sender process, one per VPS | | Web | 5173 | – | Vite dev server (frontend) | @@ -60,15 +60,15 @@ make tools Service URLs (all ports offset to avoid clashes with locally-installed daemons): - Backend API: http://localhost:8080 -- Tracking: http://localhost:13000 -- Realtime: http://localhost:14000 +- Tracking: http://localhost:3000 +- Realtime: http://localhost:4000 - Web: http://localhost:5173 - Mailpit: http://localhost:18025 -- Kafka: localhost:19092 -- Schema Registry: http://localhost:18081 +- Kafka: localhost:9092 +- Schema Registry: http://localhost:8081 - Postgres: localhost:15432 - Redis: localhost:16379 -- LocalStack: http://localhost:14566 +- LocalStack: http://localhost:4566 - stripe-mock: http://localhost:12111 See [resources/local-development.md](resources/local-development.md) for the full setup. diff --git a/deploy/README.md b/deploy/README.md index 4ca2c228..022b5519 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -108,8 +108,8 @@ Each worker profile picks a release channel (`pinned` / `stable` / `dev`) and an ```bash curl http://localhost:8080/health # backend -curl http://localhost:13000/health # tracking -curl http://localhost:14000/health # realtime +curl http://localhost:3000/health # tracking +curl http://localhost:4000/health # realtime ``` ## Documentation diff --git a/docker-compose.yml b/docker-compose.yml index e0de5aea..c910c99f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,11 +15,17 @@ # docker compose --profile seed run --rm seed # docker compose --profile tools up -d kafka-ui # -# All ports are offset so they don't clash with locally-run services: -# postgres 15432, redis 16379, kafka 19092, schema-registry 18081, -# backend 8080, tracking 13000, realtime 14000, web 5173, -# mailpit ui 18025 / smtp 11025, kafka-ui 18090, -# localstack 14566, stripe-mock 12111, cloud-tasks 18123. +# Standard ports throughout, with a few exceptions kept offset: +# - postgres 15432 (5432 commonly bound by system Postgres) +# - redis 16379 (6379 commonly bound by sibling projects) +# - mailpit ui 18025 / smtp 11025 (8025/1025 commonly bound by +# sibling projects) +# - kafka-ui 18090 (8080 is taken by backend) +# +# Standard ports for everything else: +# backend 8080, tracking 3000, realtime 4000, web 5173, +# kafka 9092, schema-registry 8081, localstack 4566, +# stripe-mock 12111, cloud-tasks 8123. x-aws-localstack: &aws-localstack AWS_ENDPOINT_URL: http://localstack:4566 @@ -59,6 +65,9 @@ services: POSTGRES_USER: warmbly POSTGRES_PASSWORD: warmbly POSTGRES_DB: warmbly_dev + # 5432 is more often already taken on dev machines (system Postgres, + # another docker-compose project, etc.) than any other port in this + # stack — keep the offset for it specifically. ports: ["15432:5432"] volumes: - postgres_data:/var/lib/postgresql/data @@ -70,6 +79,7 @@ services: redis: image: redis:7-alpine + # 6379 commonly conflicts with another docker-compose project's redis. ports: ["16379:6379"] volumes: - redis_data:/data @@ -88,12 +98,12 @@ services: kafka: image: confluentinc/cp-kafka:7.5.0 depends_on: [zookeeper] - ports: ["19092:19092"] + ports: ["9092:9092"] environment: KAFKA_BROKER_ID: 1 KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 - KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:29092,PLAINTEXT_HOST://0.0.0.0:19092 - KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:19092 + KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:29092,PLAINTEXT_HOST://0.0.0.0:9092 + KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 @@ -110,7 +120,7 @@ services: depends_on: kafka: condition: service_healthy - ports: ["18081:8081"] + ports: ["8081:8081"] environment: SCHEMA_REGISTRY_HOST_NAME: schema-registry SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS: kafka:29092 @@ -124,10 +134,12 @@ services: - "8123" - "-queue" - "projects/local/locations/local/queues/default" - ports: ["18123:8123"] + ports: ["8123:8123"] mailpit: image: axllent/mailpit:latest + # 8025 / 1025 are common defaults in other docker-compose stacks + # (any project with mailpit). Offsetting to avoid conflict. ports: - "18025:8025" # web UI - "11025:1025" # SMTP @@ -140,7 +152,7 @@ services: localstack: image: localstack/localstack:3.7 ports: - - "14566:4566" + - "4566:4566" environment: SERVICES: kms,dynamodb,s3 DEBUG: "0" @@ -149,7 +161,11 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock healthcheck: - test: ["CMD-SHELL", "curl -fsS http://localhost:4566/_localstack/health | grep -q '\"kms\": \"available\"'"] + # LocalStack reports each service as 'available' (initialised, never + # called) or 'running' (initialised + handled at least one request). + # Either state means KMS is up; the previous check only matched + # 'available' and flipped to unhealthy the moment anything used KMS. + test: ["CMD-SHELL", "curl -fsS http://localhost:4566/_localstack/health | grep -qE '\"kms\": \"(available|running)\"'"] interval: 5s timeout: 5s retries: 30 @@ -189,10 +205,10 @@ services: # Web origin for CORS. Backend's allow-list resolution checks # CORS_ALLOW_ORIGINS, then APP_URL, then a fallback derived from # WEBSOCKET_URL. Without this the origin would default to the - # realtime port (14000), not the Vite dev server (5173), and + # realtime port (4000), not the Vite dev server (5173), and # browser preflights from the dashboard get 403'd. APP_URL: "http://localhost:5173" - WEBSOCKET_URL: ws://localhost:14000/socket/websocket + WEBSOCKET_URL: ws://localhost:4000/socket/websocket PRIMARY_DB: postgres://warmbly:warmbly@postgres:5432/warmbly_dev?sslmode=disable REDIS: redis://redis:6379 @@ -206,7 +222,7 @@ services: AUTH_SECRET: local-dev-auth-secret-minimum-32-characters-long GOOGLE_CLIENT_ID: local-google-client-id GOOGLE_CLIENT_SECRET: local-google-client-secret - GOOGLE_REDIRECT_URI: http://localhost:13000/auth/google/callback + GOOGLE_REDIRECT_URI: http://localhost:3000/auth/google/callback APPLE_APP_ID: local-apple-app-id APPLE_TEAM_ID: local-apple-team-id APPLE_KEY_ID: local-apple-key-id @@ -221,7 +237,7 @@ services: EMAIL_NAME: Warmbly Dev EMAIL_ADDRESS: dev@warmbly.local - TRACKING_DOMAIN: localhost:13000 + TRACKING_DOMAIN: localhost:3000 SMTP_HOST: mailpit SMTP_PORT: "1025" @@ -320,7 +336,7 @@ services: build: context: ./tracking dockerfile: Dockerfile - ports: ["13000:3000"] + ports: ["3000:3000"] environment: APP_ENV: dev AWS_CONFIG_ENABLED: "false" @@ -339,7 +355,7 @@ services: build: context: . dockerfile: deploy/docker/realtime.Dockerfile - ports: ["14000:4000"] + ports: ["4000:4000"] environment: PHX_HOST: localhost PORT: 4000 @@ -384,7 +400,7 @@ services: environment: VITE_APP_URL: "http://localhost:5173" VITE_API_URL: "http://localhost:8080" - VITE_TRACKING_DOMAIN: "localhost:13000" + VITE_TRACKING_DOMAIN: "localhost:3000" VITE_TURNSTILE_KEY: "1x00000000000000000000AA" VITE_TURNSTILE_BYPASS_TOKEN: "warmbly-local-turnstile-bypass" depends_on: diff --git a/resources/local-development.md b/resources/local-development.md index 2f70de71..b5b6bb1d 100644 --- a/resources/local-development.md +++ b/resources/local-development.md @@ -75,22 +75,22 @@ The `sim` profile adds two more workers (`worker-premium-1`, `worker-dedicated-1 ## Service URLs -All ports are offset to avoid colliding with locally-installed daemons: +Mostly standard ports. A few are offset because their defaults conflict too often: Postgres `15432`, Redis `16379`, Mailpit UI `18025` and SMTP `11025`, kafka-ui `18090` (because 8080 is backend). Everything else uses its natural port. Override locally in a `docker-compose.override.yml` if you still hit a conflict. | Service | URL | |---------|-----| | Backend API | http://localhost:8080 | -| Tracking | http://localhost:13000 | -| Realtime | http://localhost:14000 | +| Tracking | http://localhost:3000 | +| Realtime | http://localhost:4000 | | Web (Vite dev) | http://localhost:5173 | | Mailpit | http://localhost:18025 | -| Kafka | localhost:19092 | -| Schema Registry | http://localhost:18081 | +| Kafka | localhost:9092 | +| Schema Registry | http://localhost:8081 | | Postgres | localhost:15432 | | Redis | localhost:16379 | -| LocalStack | http://localhost:14566 | +| LocalStack | http://localhost:4566 | | stripe-mock | http://localhost:12111 | -| Cloud Tasks emulator | http://localhost:18123 | +| Cloud Tasks emulator | http://localhost:8123 | | kafka-ui (with `make tools`) | http://localhost:18090 | ## Database setup @@ -153,9 +153,9 @@ go install github.com/cosmtrek/air@latest # Point at containerized infra export PRIMARY_DB="postgres://warmbly:warmbly@localhost:15432/warmbly_dev?sslmode=disable" export REDIS="redis://localhost:16379" -export KAFKA_BOOTSTRAP_SERVERS="localhost:19092" -export SCHEMA_REGISTRY_URL="http://localhost:18081" -export AWS_ENDPOINT_URL="http://localhost:14566" +export KAFKA_BOOTSTRAP_SERVERS="localhost:9092" +export SCHEMA_REGISTRY_URL="http://localhost:8081" +export AWS_ENDPOINT_URL="http://localhost:4566" export AWS_REGION="us-east-1" export AWS_ACCESS_KEY_ID="test" export AWS_SECRET_ACCESS_KEY="test" @@ -253,13 +253,13 @@ Or use kafka-ui at http://localhost:18090 (`make tools`). ### Inspect schema registry ```bash -curl http://localhost:18081/subjects | jq -curl http://localhost:18081/subjects/tracking-events-value/versions/latest | jq +curl http://localhost:8081/subjects | jq +curl http://localhost:8081/subjects/tracking-events-value/versions/latest | jq ``` ## Troubleshooting -**Port already in use** — `lsof -i :15432` (or whichever) to find what's holding it. The compose ports are offset on purpose; if you have a local Postgres on 5432 it shouldn't clash. +**Port already in use** — `lsof -i :5432` (or whichever) to find what's holding it. The compose ports are offset on purpose; if you have a local Postgres on 5432 it shouldn't clash. **Backend can't reach Kafka** — Kafka needs ~30s to fully start. Healthchecks gate the dependent services, so `docker compose up` should handle this. If you brought services up in a weird order, `docker compose restart backend consumer`.