VOL. I  ·  NO. 
SUB/WAVE
ON AIR

SETUP · 04

Hacking on SUB/WAVE.

Two compose files, two deployment shapes. Dev mode runs the radio backend in Docker and the Next.js UI on the host with hot reload, so you can iterate on the web without a rebuild.

THE TWO STACKS

Compose files.

Compose fileWhat runsState dir
docker/docker-compose.ymlicecast · liquidsoap · controller (web runs separately on host)./state
docker/docker-compose.prod.yml+ web (built image) + caddy edge${STATE_DIR:-<repo>/state}

DAY-TO-DAY COMMANDS

Everything's an npm script.

The compose flags are all wired into package.json so you don't have to remember them:

npm run setup        # interactive wizard (writes envs, brings the stack up)
npm run dev          # alias for setup — same wizard
npm run dev:docker   # docker compose up -d        (radio backend only)
npm run dev:web      # next dev on :7700           (hot-reloaded UI)
npm run rebuild      # docker compose up -d --build  (after controller/liquidsoap src changes)
npm run logs         # tail docker logs
npm run jingles      # render station idents via Piper
npm run down         # stop the stack

A TYPICAL SESSION

Backend in Docker, UI on the host.

# one-time, in two terminals:
npm run dev:docker   # terminal 1: backend (Icecast, Liquidsoap, Controller)
npm run dev:web      # terminal 2: Next.js on http://localhost:7700

# editing web/** — saves are hot-reloaded, no docker action needed.
# editing controller/src/** or liquidsoap/radio.liq:
npm run rebuild      # rebuilds + recreates the affected containers
THE ONE GOTCHA

Code changes need a rebuild, not a restart. Both the controller and Liquidsoap Dockerfiles COPY their source at build time — they don't bind-mount it. So docker compose restart controller will cheerfully rerun the same baked-in code as before. npm run rebuild (or docker compose up -d --build <service>) is what you want.

The web dev server (npm run dev:web) is exempt — Next.js hot-reloads, so edits to web/** show up instantly without touching Docker.