docs(dev): explain the combined Vite and FastAPI launcher

This commit is contained in:
2026-10-06 16:53:40 -03:00
parent c8f8aff8c7
commit 99413fc06d
6 changed files with 170 additions and 78 deletions
+80 -41
View File
@@ -6,48 +6,84 @@ rendering and state, including the realtime WebSocket and audio integration.
## Run during development
Use Node.js 22.18 or later on the 22.x line, or Node.js 24+. Install dependencies
with npm; the lockfile is committed.
From the repository root, run `./start_ui.sh`. Open `http://localhost:8420`.
Add `?debug=true` to access settings, tools, and custom RAG context. Existing
`phoneNumber` and `episode_id` query parameters are supported.
1. Start the existing backend using `./start_ui.sh` from your configured S2S
checkout, or reuse an already-running instance. It normally listens on port
`8420` and continues serving the original static UI there. Its Python
environment, `.env`, speech service, and upstream services must be configured
as before.
2. In a second terminal, start this frontend:
The launcher requires Python 3 with venv support, Node.js 22.18 or later on the
22.x line or Node.js 24+, npm, Bash 4.4+, `setsid` (util-linux), and `curl`.
It creates `.venv` and installs missing Python dependencies. It runs
`npm ci --include=dev` on first start and when either frontend package manifest
changes. Subsequent restarts reuse the installed dependencies.
```sh
cd frontend-s2s
npm ci
npm run dev
```
| Server | Default address | Purpose |
| ------- | ---------------- | ---------------------------------------------- |
| Vite | `0.0.0.0:8420` | Public React UI, backend proxy, and hot reload |
| FastAPI | `127.0.0.1:8421` | Internal HTTP APIs and speech WebSocket relay |
3. Open `http://127.0.0.1:5173`. Add `?debug=true` to access settings, tools,
and custom RAG context. Existing `phoneNumber` and `episode_id` query
parameters are supported.
`UI_PORT` preserves the existing public port override. `UI_HOST` defaults to
`0.0.0.0`; `S2S_BACKEND_PORT` changes the loopback backend port. The two ports
must differ. Occupied ports fail startup rather than silently selecting a new
endpoint. The launcher waits for FastAPI before starting Vite, stops both
process groups on Ctrl+C/SIGTERM, and exits with a failure if either server exits.
Uvicorn watches only `s2s-client`, avoiding frontend and dependency directories.
The Vite child explicitly uses `NODE_ENV=development`, including when a process
manager sets `NODE_ENV=production`, so React Fast Refresh remains enabled.
Vite serves React and Tailwind with hot updates. It proxies `/api`,
`/v1/realtime` (including WebSockets), OAuth, and backend documentation routes
to FastAPI. The browser uses one origin on port `5173`, so there is no separate
to FastAPI. The browser uses one origin on port `8420`, so there is no separate
API origin or development CORS setup. The proxy preserves the incoming Host
header because FastAPI uses it to construct the speech WebSocket URL.
For a different backend, copy `.env.example` to `.env.local` and set
`S2S_BACKEND_URL`. This is a **Vite server** setting. Runtime UI flags, voices,
reasoning mode, prompts, and the speech URL still come from FastAPI's
Runtime UI flags, voices, reasoning mode, prompts, and the speech URL still come from FastAPI's
`/api/config`. A backend explicitly configured with `SPEECH_TO_SPEECH_URL`
continues to return that direct speech endpoint.
The Vite configuration reads only this project's environment files. Do not
copy the repository's backend secrets into this directory or into `VITE_*`
The launcher sources the root `.env`, retaining its precedence over shell
variables. The Vite configuration reads this project's environment files and
the inherited `S2S_*` settings. Do not copy the repository's backend secrets
into this directory or into `VITE_*`
variables, which are exposed to browser code.
For access through a development reverse proxy, set the exact hostname in
`S2S_DEV_ALLOWED_HOSTS`. Use `npm run dev -- --host 0.0.0.0` only when Vite must
listen beyond localhost. The browser needs HTTPS for microphone access outside
localhost, and that proxy must forward WebSocket upgrades for both speech and
Vite HMR. Wiring the staging entrypoint and launcher is a separate step:
**this port does not change `start_ui.sh`.**
## Staging with hot reload
PM2 can continue running the root `start_ui.sh` as its existing `s2s_ui` process.
Ensure the Node/npm versions above are on PM2's PATH and deploy `frontend-s2s`
alongside `s2s-client` and `docs`. The reverse proxy still targets port `8420`.
Set the exact public hostname in the root `.env`, without scheme or port:
```dotenv
S2S_DEV_ALLOWED_HOSTS=voice-staging.example.com
```
Replace the example with the existing staging hostname; use commas for multiple
hosts. IP addresses and localhost are accepted without this setting.
The HTTPS reverse proxy must preserve `Host`, `X-Forwarded-Host` and
`X-Forwarded-Proto`, and forward WebSocket upgrades for `/v1/realtime` and
`/__vite_hmr`. HMR uses the browser's public origin, including HTTPS/WSS, so no
second public port is needed. The browser needs HTTPS for microphone access
outside localhost. Restart `s2s_ui` after changing launcher or environment
settings; source edits use the reloaders. The speech service remains separately
managed.
## Run the servers separately
Start FastAPI on `127.0.0.1:8421` as described in the
[client usage guide](../docs/client/usage.md), then run:
```sh
cd frontend-s2s
npm ci
npm run dev
```
Standalone Vite binds `127.0.0.1:8420`; add `-- --host 0.0.0.0` for remote
access. For a different backend, copy `.env.example` to `.env.local` and set
`S2S_BACKEND_URL`. The combined launcher overrides that setting to point at the
backend it starts. Do not start standalone Vite while the combined launcher
already owns the public port.
Component and CSS changes use Fast Refresh. Editing the session controller or
audio modules can require restarting a conversation or a page reload. Teardown
@@ -60,26 +96,29 @@ The scripts and code style follow `frontend-admin` conventions, with Vite and
React plugins replacing Next.js-specific tooling. Executable configuration
files use TypeScript; TypeScript's own project settings use JSON.
| Command | Purpose |
| -------------------- | ----------------------------------------------------------- |
| `npm run dev` | Vite development server on port 5173, with a fixed port |
| `npm run check` | Formatting, strict typed ESLint, type checking, and tests |
| `npm run lint:fix` | Apply ESLint fixes |
| `npm run format` | Format source and sort Tailwind classes |
| `npm run typecheck` | Check application, tests, audio worklets, and configuration |
| `npm test` | Run Vitest and React Testing Library regression tests |
| `npm run test:watch` | Watch tests while editing |
| `npm run build` | Typecheck and compile the app and worklets into `dist/` |
| `npm run preview` | Inspect the compiled output locally |
| Command | Purpose |
| ----------------------- | ----------------------------------------------------------- |
| `npm run dev` | Vite development server on port 8420, with a fixed port |
| `npm run check` | Formatting, strict typed ESLint, type checking, and tests |
| `npm run lint:fix` | Apply ESLint fixes |
| `npm run format` | Format source and sort Tailwind classes |
| `npm run typecheck` | Check application, tests, audio worklets, and configuration |
| `npm test` | Run Vitest and React Testing Library regression tests |
| `npm run test:watch` | Watch tests while editing |
| `npm run test:launcher` | Test launcher supervision and signal handling on Linux |
| `npm run build` | Typecheck and compile the app and worklets into `dist/` |
| `npm run preview` | Inspect the compiled output locally |
No build step is needed before `npm run dev`. `dist/` is generated and ignored
by Git. Build output is available for later serving integration; this change
does not mount it in FastAPI or change the staging launch process.
by Git. The launcher serves source through Vite; it does not use `dist/` or
`vite preview`.
Tests cover session initialization, response sequencing, cumulative transcripts,
interruptions, queue cancellation, microphone-permission cancellation, tool
results, external reasoning and `LOG_ONLY`, late-response cleanup, the idle
timeout, settings, RAG, profiles, and sanitized Markdown/export behavior.
Launcher tests start temporary local children to check readiness, environment
forwarding, failures, and shutdown of complete process groups.
Vitest handles Node 26's experimental web storage behavior internally.
## Source layout