This guide explains how to run WaveStream locally without tripping over loopback host, CORS, cookie, storage, or Playwright differences.
| Surface | Preferred URL |
|---|---|
| Web | http://localhost:3000 |
| API | http://localhost:4000 |
| API health | http://localhost:4000/api/health |
| Swagger | http://localhost:4000/api/docs |
| Mailpit | http://localhost:8025 |
| MinIO Console | http://localhost:9001 |
Use one hostname family consistently during manual browser testing.
Good pairs:
http://localhost:3000withhttp://localhost:4000http://127.0.0.1:3000withhttp://127.0.0.1:4000
Avoid mixing localhost on one side and 127.0.0.1 on the other when diagnosing browser behavior. Matching hosts keeps cookies, CORS, refresh auth, and localStorage easier to reason about.
WaveStream has defensive loopback handling for local smoke tests. The API can allow loopback CORS automatically when configured origins are local, but matching hosts is still the cleanest path.
Use Docker when you want the app to behave closest to the production stack.
pnpm install
cp .env.example .env
docker compose up --buildAfter startup:
- Open web at
http://localhost:3000. - Check API health at
http://localhost:4000/api/health. - Open Swagger at
http://localhost:4000/api/docs. - Open Mailpit at
http://localhost:8025. - Open MinIO Console at
http://localhost:9001.
| Role | Password | |
|---|---|---|
| Admin | admin@wavestream.local |
Admin123! |
| Creator | solis@wavestream.demo |
DemoPass123! |
| Listener | ivy@wavestream.demo |
DemoPass123! |
These credentials are for local development only. Production must use strong secrets and must not print demo passwords from seed scripts.
Use this flow when actively editing code:
pnpm install
pnpm devDefault local ports:
- Web:
3000 - API:
4000
Useful targeted commands:
pnpm dev:web
pnpm dev:api
pnpm --filter web test
pnpm --filter api test
pnpm --filter web typecheck
pnpm --filter api typecheckIf you override ports, align these variables:
FRONTEND_URL=http://localhost:3000
NEXT_PUBLIC_API_URL=http://localhost:4000
INTERNAL_API_URL=http://localhost:4000
Use this when a bug appears only after next build.
pnpm --filter web build
pnpm --filter web exec node ./scripts/prepare-playwright-server.mjsThen start the standalone server with matching API values if you need to inspect the production artifact manually.
The normal e2e command already does this automatically:
pnpm test:e2eBefore saying a local change is done, prefer this order:
pnpm docs:check
pnpm lint
pnpm typecheck
pnpm test
pnpm build
pnpm test:e2e
pnpm smoke:dockerFor a narrower frontend-only pass:
pnpm --filter web test
pnpm --filter web typecheck
pnpm --filter web build
pnpm --filter web test:e2eAfter Docker or production-style startup, verify:
//discover/search?genre=ambient/track/aurora-current/playlist/global-beats/about
Expected public behavior:
- Dark/orange theme by default in a fresh browser session.
- Real seeded tracks appear on discovery, search, playlist, and track pages.
- The player can start from landing, search, playlist, and track surfaces.
- Public pages show friendly error or empty states instead of blank skeletons.
- Vietnamese locale text renders with correct accents.
Check the API request in devtools or server logs. /api/search should receive a q parameter. It should not reject extra unsupported query parameters.
Check NEXT_PUBLIC_API_URL, INTERNAL_API_URL, and API health. Also verify the browser and API are using the same loopback host family.
Check that MinIO is running, seeded objects exist, and the API media proxy can read the private object. Then run:
pnpm smoke:dockerClear cookies and localStorage for both localhost and 127.0.0.1, then retest with a single hostname family.
Run:
pnpm docs:checkThe check scans README, docs, UI copy, i18n files, and e2e text for common mojibake patterns.