OsmoWeb BTS Demo is split into a small application shell and shared domain packages. This repository owns the demo composition: the NestJS host, the Vue user interface, configuration wiring, and the browser workflow. The lower-level BTS, SDR, WebUSB, WebSocket, authentication, and telemetry behavior is provided by npm packages in the @osmoweb/* and @websdr/* namespaces.
This application is part of a small set of related repositories:
- wavelet-lab/osmoweb-app - the demo application described here.
- wavelet-lab/osmoweb - shared OsmoWeb packages.
- wavelet-lab/websdr - shared WebSDR packages.
- wavelet-lab/osmoweb-tools - scripts and configuration for running the Osmo backend services.
flowchart LR
User[User in browser]
UI[Vue 3 frontend]
Trx[OsmoBtsTrx wrapper]
FrontendCore["@osmoweb/frontend-core<br/>@websdr/frontend-core"]
Usb[SDR device via WebUSB]
Backend[NestJS backend]
BackendModules["@osmoweb/nestjs-microservice<br/>@websdr/nestjs-microservice"]
Static[frontend/dist]
User --> UI
UI --> Trx
UI --> FrontendCore
Trx --> FrontendCore
FrontendCore --> Usb
FrontendCore <--> Backend
Backend --> BackendModules
Backend --> Static
The local backend owns:
- NestJS bootstrap and global application setup.
- CORS, logging, validation, cookie parsing, and WebSocket adapter registration.
- Static serving for the compiled frontend.
- Local app controller and service scaffolding.
- Backend module composition for dynamic BTS configuration through shared Osmo services.
The local frontend owns:
- Vue application composition.
- The main BTS control screen.
- Start/stop orchestration around shared frontend services.
- Local
OsmoBtsTrxwrapper behavior. - Statistics normalization for display.
- Demo UI styles.
The shared packages provide most domain-specific behavior.
| Package area | Used for |
|---|---|
@osmoweb/core |
GSM radio types and ARFCN configuration helpers. |
@osmoweb/frontend-core |
BTS service calls and frontend TRX manager integration. |
@osmoweb/vue3-components |
BTS UI components such as BtsInput. |
@osmoweb/nestjs-microservice |
Backend Osmo module integration. |
@websdr/core |
Shared utility types such as journal log items. |
@websdr/frontend-core |
WebUSB and telemetry runtime support. |
@websdr/vue3-components |
SDR input and log UI components. |
@websdr/nestjs-microservice |
Backend auth, logging, and related NestJS integrations. |
This repository should document how those packages are used, but it should avoid duplicating their internal implementation details.
The backend starts from backend/src/main.ts and creates AppModule.withLogging(...).
Runtime responsibilities:
- Apply logger levels from
LOG_LEVELSorLOG_LEVEL. - Create the NestJS application.
- Load environment values through
ConfigService. - Register cookie parsing and global validation.
- Register
WsAdapterfor WebSocket support. - Configure CORS according to
NODE_ENV,CORS_ALLOW_ALL, andCORS_ORIGIN. - Listen on
PORT, defaulting to4000.
The root module mounts:
AuthModuleLoggingModuleOsmoModuleServeStaticModule
The local GET /api/hello endpoint is a small guarded example route. BTS-specific API and WebSocket behavior is expected to come from the shared Osmo backend module.
The frontend starts from frontend/src/main.ts, mounts App.vue, and renders the main BTS workflow through OsmoMain.vue.
OsmoMain.vue coordinates:
SdrInputfor WebUSB device selection.BtsInputfor GSM BTS configuration.BtsControlPanelfor start/stop and traffic metrics.LogAreafor journal log output.StreamMeterfor traffic and cloud connection telemetry.OsmoBtsTrxfor TRX runtime actions.normalizeBtsStats(...)for statistics display.
sequenceDiagram
participant User
participant UI as OsmoMain.vue
participant SdrInput
participant Trx as OsmoBtsTrx
User->>SdrInput: Select SDR device
SdrInput-->>UI: vendorId, productId, device name
UI->>Trx: configure({ vendorId, productId })
sequenceDiagram
participant User
participant UI as OsmoMain.vue
participant Services as Osmoweb frontend services
participant Trx as OsmoBtsTrx
participant Manager as Shared TRX manager
User->>UI: Press Start
UI->>Services: updateBts({ instanceId, band, arfcn })
Services-->>UI: BTS config
UI->>Trx: configure({ vendorId, productId, btsConfig })
Trx->>Manager: open_bts(...)
UI->>Trx: start()
Trx->>Manager: open_ws(...)
Trx->>Manager: open_usb(...)
UI-->>User: State becomes connected
sequenceDiagram
participant User
participant UI as OsmoMain.vue
participant Services as Osmoweb frontend services
participant Trx as OsmoBtsTrx
User->>UI: Press Stop
UI->>Trx: stop()
UI->>Services: releaseBts(instanceId)
UI-->>User: State returns to configured
The same release path is also triggered when the page is hidden or the component is unmounted while a BTS session is running.
While the BTS state is connected, the frontend polls statistics every two seconds.
sequenceDiagram
participant UI as OsmoMain.vue
participant Trx as OsmoBtsTrx
participant Manager as Shared TRX manager
participant Normalizer as osmoBtsStats.ts
participant Modal as StatisticsModal.vue
UI->>Trx: getBtsStats(group)
Trx->>Manager: getBtsStats(group)
Manager-->>Trx: raw stats
Trx-->>UI: parsed stats
UI->>Normalizer: normalizeBtsStats(group, stats)
UI->>Modal: render normalized tree
Current groups:
['stats', 'rate-counters', 'bts', 'trx', 'transceiver', 'websdr']The shared TRX manager emits journal log items through callbacks. OsmoBtsTrx forwards those items through onLogItem, and OsmoMain.vue appends them to LogArea.
Subsystem names are collected as logs arrive and are exposed to the log component as filter options.
The frontend uses the BTS state from @osmoweb/vue3-components.
Important local states:
| State | Meaning in this app |
|---|---|
configured |
A valid radio configuration exists, but the BTS runtime is not running. |
connected |
The BTS runtime has been started successfully. |
disconnected |
A start/stop action failed or runtime connection was lost. |
not-configured |
A placeholder state supported by the UI contract; the current default flow starts with a valid config. |
Additional local flags:
osmoBusydisables controls while start/stop is in progress.osmoErrorstores the latest runtime error message.cloudConnectedmirrors stream telemetry state.
During development, Vite serves the frontend and can proxy /api to the backend.
For built output:
npm run build --prefix frontendemitsfrontend/dist.npm run build --prefix backendemits backend JavaScript tobackend/dist.- The backend serves
frontend/distthroughServeStaticModule. - API and auth paths remain excluded from static serving.
Common extension areas:
- Add new local backend controllers for app-specific API endpoints.
- Add new frontend panels around existing telemetry or BTS statistics.
- Expand
osmoBtsStats.tswhen new statistics shapes are introduced. - Add configuration documentation for new environment variables.
- Replace the demo
GET /api/helloroute with real application-specific endpoints.
When adding behavior that belongs to shared BTS, SDR, or authentication logic, prefer implementing it in the corresponding @osmoweb/* or @websdr/* package and documenting only the integration point here.