Previous attempts hardcoded 3011, but something on tyler's host is
holding 3011 too. Instead of guessing ports, make the deploy probe
for the first free port starting from 3011 and thread that choice
through the rest of the workflow.
How it works:
1. Start Docker stack frees 3001 + the previous deploy's chosen port
(read from .postgrest-port) so the lowest free port can be picked
back up
2. Loops from 3011 upward, checking ss -tln until it finds a free
port in the 3011-30200 range
3. Writes the chosen port to .postgrest-port in the workspace
4. Sets NEXT_PUBLIC_API_URL based on that port
5. Writes POSTGREST_HOST_PORT and NEXT_PUBLIC_API_URL to the .env
that docker compose reads
6. Build and Deploy steps read .postgrest-port to set their
NEXT_PUBLIC_API_URL dynamically — no more hardcoded 3011
The dev PostgREST (started outside docker compose for local development)
and the production PostgREST (started by docker compose up) were both
trying to bind 127.0.0.1:3001. Even with fuser -k in the deploy cleanup,
something on tyler's host (likely a process supervisor restarting the
dev PostgREST) keeps reclaiming 3001 between our check and the
docker bind.
Move the production PostgREST to host port 3011, keeping the container's
internal port at 3001 (PostgREST's default). This lets dev and prod
coexist on the same host without fighting over a port.
Update NEXT_PUBLIC_API_URL to http://localhost:3011 in:
- Build step env (so the build bakes in the right URL)
- Start Docker stack .env append (so docker compose + app see the URL)
- Deploy step .env.production writing (so runtime app uses 3011)
- docker-compose.yml: Postgres 16 Alpine with named volume, healthcheck
- .env.example: POSTGRES_* and DATABASE_URL template
- .gitignore: exclude db_data/ volume
Starting fresh, no data migration. App still wired to Supabase;
DB is ready for migrations to be applied.