docs: document the self-hosted app stack

This commit is contained in:
itsrubberduck
2026-07-27 19:30:44 +02:00
parent 65718ce21a
commit cd2b2820d2
2 changed files with 133 additions and 53 deletions

115
CLAUDE.md
View File

@@ -1,63 +1,72 @@
# OpenSquawk - Project Guide
# OpenSquawk App — Project Guide
## Scope
This repository is the self-hostable OpenSquawk application. It contains the
browser UI and its H3 API. It does not own the authoritative Live ATC decision
state; that belongs to the separate `OpenSquawk-LiveATC-api` service.
## Architecture
- **Nuxt 4** (Vue 3 SFC) frontend in `/app`
- **H3 server** handlers in `/server`
- **Shared types/utils** in `/shared`
- MongoDB models in `/server/models`
- **Python backend** — a separate repo, `OpenSquawk-LiveATC-api`, owns the authoritative
Live ATC (`/live-atc`, formerly `/pm` — legacy path now redirects) session state and routing decisions. It runs as its own service
(default `http://127.0.0.1:8000`). This Nuxt app owns STT, TTS, client audio, auth,
the flow editor, and account/admin features.
> The LLM decision routing that used to live in this repo (`routeDecision()`,
> `/api/llm/decide`, a Nuxt `/api/decision-flows/runtime` route) has been removed.
> Decision routing now happens in the Python backend. Don't reintroduce it here.
- Nuxt 4 and Vue 3 frontend in `/app`
- H3 API handlers in `/server`
- Shared types, data, and state-machine utilities in `/shared`
- MongoDB models in `/server/models`
- Python decision backend at `NUXT_PUBLIC_RADIO_BACKEND_URL`
`AUTH_MODE=open` is the default. It creates one stable local `AppUser` identity
and requires no login. `AUTH_MODE=sso` is optional and exchanges a one-time code
with the configured `NUXT_PUBLIC_AUTH_ISSUER`; the app then owns its session.
## Key Files
- `/app/composables/useRadioBackend.ts` — Typed client for the Python backend REST API
(`createSession`, `transmit`, `deleteSession`, `fetchFlows`). This is how `/live-atc` talks
to the decision engine.
- `/shared/utils/communicationsEngine.ts` — Local state-machine composable used by `/live-atc`.
It mirrors the flow for cursor tracking and TTS scheduling; the **Python backend owns the
authoritative state**. `fetchRuntimeTree()` loads the flow definition from the backend's
`/api/decision-flows/runtime`.
- `/server/services/decisionFlowService.ts` — Builds/edits MongoDB-backed decision trees.
Used **only by the flow editor** (`/server/api/editor/flows*`), not by `/live-atc`.
- `/server/utils/openai.ts``getOpenAIClient()` only. Used for TTS (`/api/atc/say`) and
STT (`/api/atc/ptt`). It is **not** a decision router anymore.
- `/app/pages/live-atc.vue` — Live ATC page (speech-to-text, PTT, text input).
- `/app/pages/classroom.vue` — Classroom learning mode (separate system, does NOT use
communicationsEngine).
## Live ATC Flow (/live-atc)
1. `startMonitoring()``fetchRuntimeTree('icao_atc_decision_tree', radioBackendUrl)`
loads the flow definition from the Python backend into the local engine (cursor / TTS).
2. `startMonitoring()``radioBackend.createSession(...)` creates the authoritative
server-side session and stores `backendSessionId`.
3. User input (PTT or text) → `handlePilotTransmission()`.
PTT audio is transcribed first via Nuxt `POST /api/atc/ptt` (Whisper).
4. `radioBackend.transmit(backendSessionId, transcript)` → the Python backend runs regex
routing, readback evaluation, side effects, and flow chaining; it returns
`next_state_id`, `controller_say_template`, `auto_advanced_states`, `flags`,
and `session_complete`.
5. `moveToSilent(stateId)` is called for each auto-advanced state and the final state —
advances the local cursor without re-triggering auto-transitions.
6. `scheduleControllerSpeech(...)` speaks the ATC reply via TTS (`/api/atc/say`).
- `/app/pages/index.vue` — mode selector and application entry point
- `/app/pages/live-atc.vue` — Live ATC UI
- `/app/pages/classroom.vue` — classroom learning mode
- `/app/composables/useRadioBackend.ts` — typed Python-backend client
- `/shared/utils/communicationsEngine.ts` — local cursor, variables, logs, and
TTS scheduling for Live ATC
- `/server/utils/auth.ts` — app-user resolution and request authentication
- `/server/utils/authMode.ts` — open/SSO identity selection and local user
- `/server/utils/session.ts` — app-owned cookie and bearer tokens
- `/server/utils/telemetry.ts` — opt-in telemetry mirror; disabled when
`TELEMETRY_URL` is empty
- `/server/utils/openai.ts` — OpenAI-compatible client for speech services
## Decision Tree States
States have `role: 'pilot' | 'atc' | 'system'`. The local engine handles two template
schemas transparently (via `stateSayTpl()` / `stateUtteranceTpl()`):
- Legacy (MongoDB editor): `say_tpl`, `utterance_tpl`, vars as `{var}`
- Python backend YAML: `say_template`, `expected_pilot_template`, vars as `{{var}}`
## Live ATC Flow
Both `{{var}}` and `{var}` are rendered by `renderTpl()`. Transition fields seen across
schemas: `next`, `ok_next`, `bad_next`, `timer_next`, `auto_transitions`.
1. The frontend loads a runtime flow from `OpenSquawk-LiveATC-api`.
2. It creates an authoritative radio session in the Python backend.
3. PTT audio is transcribed through `POST /api/atc/ptt`; text input skips STT.
4. The transmission is sent to the Python session.
5. The returned state, auto-advanced states, variables, and flags update the
local communications engine.
6. The controller response is spoken through `POST /api/atc/say`.
## Environment Variables
- `NUXT_PUBLIC_RADIO_BACKEND_URL` — URL of the Python backend (default `http://127.0.0.1:8000`)
The Python backend owns routing and authoritative session state. Do not add a
second routing implementation to the Nuxt application.
## Commands
- `yarn dev` — dev server (Nuxt)
- `yarn test` — runs the `tsx --test` suite (`tests/`, `server/`, `shared/`)
- Python backend: see `OpenSquawk-LiveATC-api/README.md`
## Decision State Compatibility
The local engine accepts both supported template conventions:
- `say_tpl` and `utterance_tpl`
- `say_template` and `expected_pilot_template`
It renders both `{variable}` and `{{variable}}`. Supported transition fields
include `next`, `ok_next`, `bad_next`, `timer_next`, and `auto_transitions`.
## Local Commands
```bash
yarn install
yarn dev
yarn test
yarn typecheck
```
Start `OpenSquawk-LiveATC-api` separately with:
```bash
poetry run uvicorn main:app --reload
```

71
README.md Normal file
View File

@@ -0,0 +1,71 @@
# Self-host OpenSquawk
OpenSquawk is a browser-based aviation radio training application. It provides
Live ATC scenarios with spoken controller responses, a classroom learning mode,
and optional simulator/cockpit bridge integration.
This repository contains the Nuxt application and its H3 API. Live ATC routing
and authoritative session state are provided by the separate
[`OpenSquawk-LiveATC-api`](https://github.com/OpenSquawk/OpenSquawk-LiveATC-api)
service.
## Requirements
- Node.js 22 and Yarn 4
- MongoDB
- Python 3.12 and Poetry for `OpenSquawk-LiveATC-api`
- An OpenAI-compatible service for cloud STT/TTS, or a configured local speech
provider
The simulator/cockpit bridge is optional.
## Start locally
Start MongoDB, then prepare the Nuxt application:
```bash
corepack enable
cp .env.example .env
yarn install
```
Generate strong values for `JWT_SECRET`, `APP_JWT_SECRET`, and
`SERVICE_SECRET`. Keep `AUTH_MODE=open` for a self-hosted instance without a
login. Configure the speech provider variables required by your setup.
In a separate checkout of `OpenSquawk-LiveATC-api`, start the decision backend:
```bash
poetry install
poetry run uvicorn main:app --reload
```
It listens on `http://127.0.0.1:8000` by default. If it runs elsewhere, set
`NUXT_PUBLIC_RADIO_BACKEND_URL` accordingly.
Start the Nuxt application:
```bash
AUTH_MODE=open yarn dev
```
The application is then available at `http://localhost:3000`.
## Configuration
All documented variables and self-hosting defaults are in
[`.env.example`](./.env.example). MongoDB stores user state, learning progress,
bug reports, and transmission logs locally. Telemetry forwarding is disabled
when `TELEMETRY_URL` is empty.
## Services
- `OpenSquawk-LiveATC-api`: decision flows, routing, and Live ATC session state
- MongoDB: application identities, progress, reports, and logs
- OpenAI-compatible or local speech service: transcription and controller audio
- Optional bridge: simulator and cockpit integration
## License
OpenSquawk is licensed under the
[GNU Affero General Public License v3.0 only](./LICENSE).