VISP Relay

Local development

Set up the monorepo, database, API, portal, admin console, Expo clients, and test suite.

Prerequisites

  • Bun 1.3.14 or newer
  • Node.js 24 or newer
  • Docker with Compose
  • A Twitch application for Twitch login
  • A Kick application when testing Kick login, chat, or metadata
  • A Google OAuth web client with YouTube Data API v3 enabled when testing YouTube Direct
  • Xcode or Android Studio when working on either native Expo app

Install every workspace dependency from the repository root:

bun install

Configure the environment

The local launcher creates and validates the server, web, and OBS Remote env files. Copy the broadcaster example manually because its address depends on your device:

cp apps/native/.env.example apps/native/.env.local

The launcher generates missing local secrets and reports blank Twitch, Kick, or Google credentials. Those provider flows require real credentials; unrelated local features still start.

AI_GATEWAY_API_KEY enables Seppo through Vercel AI Gateway. Optional ELEVENLABS_API_KEY enables account-gated hosted captions and audio isolation; add ELEVENLABS_VOICE_ID for hosted chat text-to-speech. Without those optional values, the native app uses on-device fallbacks or hides the hosted option.

Register the callbacks for the providers you exercise locally:

Twitch: https://api.visp.localhost/api/auth/callback/twitch
Kick:   https://api.visp.localhost/api/auth/oauth2/callback/kick
Google: http://localhost:3000/api/auth/google-local-callback

For Google, create a Web application OAuth client. Add http://localhost:3000 as the authorized origin, add the Google callback above as the authorized redirect URI, and store its client ID and secret as GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in the server environment. Enable YouTube Data API v3 and add the youtube.force-ssl scope to the consent screen. See the repository DEVELOPMENT.md for the complete console and verification walkthrough.

Relay and S3 values point to the local Compose services. Never commit .env files.

Start the local stack

One command starts PostgreSQL 18, MinIO, two MediaMTX relays, the relay gateway, API, portal, admin console, OBS Remote web app, and docs, then applies migrations:

bun run dev:local

Run bun run dev:local:down to stop the containers without deleting data.

To exercise multi-relay assignment, register the second Compose relay in Admin with host 127.0.0.2, Control API http://127.0.0.2:9997, and ping URL http://relay2.visp.localhost:8082/ping.

When changing packages/db/src/schema, generate and inspect a migration before applying it:

bun run db:generate
bun run db:migrate

Use bun run db:push only with a disposable development database. Open Drizzle Studio with bun run db:studio.

Run the project

For normal API and portal work:

ProcessCommandAddress
Complete local stackbun run dev:localhttps://visp.localhost
APIManaged by the launcherhttps://api.visp.localhost
Admin consoleManaged by the launcherhttps://admin.visp.localhost
OBS Remote webManaged by the launcherhttp://localhost:8083
RelayManaged by the launcherhttps://relay.visp.localhost
MinIO consoleManaged by the launcherhttps://minio.visp.localhost
PostgreSQLManaged by the launcher127.0.0.1:54320
Documentationbun run --cwd apps/fumadocs devhttps://docs.visp.localhost
Expo dev serverbun run --cwd apps/native devShown by Expo

bun run dev starts every workspace through Turborepo. Use the focused commands unless you need the API, portal, admin console, Expo, and documentation site simultaneously.

OBS Remote

Run only the dedicated control surface with bun run dev:obs-remote. Web uses port 8083. For a physical phone, set EXPO_PUBLIC_SERVER_URL in apps/obs-remote/.env.local to http://LAN_IP:3000, then run its ios or android script. Browser authentication requires OBS_REMOTE_WEB_ORIGIN to exactly match the served origin.

Native app

Expo Go cannot load the local SRT module. Build a development client instead:

bun run --cwd apps/native ios
bun run --cwd apps/native android

Use a physical device for real camera, microphone, and network testing. A phone cannot reach the API through 127.0.0.1; set EXPO_PUBLIC_SERVER_URL to an address reachable from the phone.

Documentation

Pages live in apps/fumadocs/content/docs. Add an MDX file and include its slug in meta.json to place it in the sidebar.

Tests and checks

Run the smallest relevant check while working, then the full checks before submitting a change:

bun test
bun run test:integration
bun run check-types
bun run build
bun run check

The integration suite manages compose.test.yml, binds PostgreSQL to 127.0.0.1:55432, and removes its volumes on exit.

Code map

ChangePrimary location
HTTP routes, hooks, server lifecycleapps/server/src
tRPC procedures and relay rulespackages/api/src
Authentication and providerspackages/auth/src
Database schema and migrationspackages/db/src
Browser portalapps/web/src
Admin support consoleapps/admin/src
Shared UI primitivespackages/ui/src
Native client and SRT bridgeapps/native
OBS Remote control surfaceapps/obs-remote
OBS-side control transportapps/obs-plugin
Operator and broadcaster docsapps/fumadocs/content/docs

Add environment variables to packages/env and the relevant .env.example in the same change. Extend server log redaction when introducing a new credential-shaped field.

Troubleshooting

  • The server exits during import: a value in apps/server/.env is blank or invalid; the error names it.
  • The portal cannot authenticate: verify the API URL and make CORS_ORIGIN exactly match the portal origin.
  • The admin console denies access: sign in through the portal and confirm the account has role admin or is listed in ADMIN_USER_IDS.
  • A phone cannot connect: use a LAN or tunnel address instead of localhost and allow API port 3000 through the host firewall.
  • OBS Remote cannot authenticate: check OBS_REMOTE_WEB_ORIGIN, port 8083, and WebSocket upgrade support for /api/obs/live.
  • Relay or snapshot actions fail: check docker compose ps and the MediaMTX and gateway logs.
  • Integration tests cannot bind port 55432: stop the process using that port and rerun the suite.

The repository's DEVELOPMENT.md and component READMEs remain the canonical reference for implementation-specific details.

On this page