SkyTalk Docs
Runbook

Local Development

How to run the full SkyTalk stack locally — pnpm workspace setup, Docker Compose, database seeding, and mobile mock mode.

This covers running the full stack on your local machine for development. Everything runs in Docker except the mobile app (Expo runs natively).

Prerequisites

ToolVersionNotes
Node.js20+LTS recommended
pnpm9+npm install -g pnpm
Docker24+Docker Compose v2 (docker compose, not docker-compose)
Expo GoLatestOn your iPhone/Android for testing the mobile app

Monorepo Setup

The project is a pnpm workspace. Install all dependencies from the root once:

pnpm install

This installs deps for all packages: packages/server, packages/mobile, packages/comms, packages/portal, packages/docs.


Server Setup

Create the .env file

cp packages/server/.env.example packages/server/.env

Edit it with these values:

POSTGRES_USER=skytalk
POSTGRES_PASSWORD=skytalkpass
POSTGRES_DB=skytalk
JWT_SECRET=dev-jwt-secret-change-in-prod
DATABASE_URL=postgresql://skytalk:skytalkpass@db:5432/skytalk

The DATABASE_URL host must be db (the Docker Compose service name) when running inside Docker — not localhost.

Start with Docker Compose

cd packages/server
docker compose up -d

Starts two containers:

  • db — Postgres 16 on port 5432 (internal only)
  • server — Fastify on port 3000

The server container runs prisma db push on startup via entrypoint.sh to sync the schema.

Verify the server is running

curl http://localhost:3000/ping
# expected: {"pong":true}

Seed the database

npx tsx prisma/seed.ts

Creates:

  • Admin user: admin / admin
  • Pilot user: pilot1 / test
  • Talkgroup: Ground Ops (both users as members)

Get a JWT for API testing

JWT=$(curl -s -X POST http://localhost:3000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin"}' | \
  grep -o '"jwt":"[^"]*"' | cut -d'"' -f4)
echo $JWT

$JWT is per-terminal-session. If you open a new pane (e.g. in zellij), re-run the login command.

Test the WebSocket

Install wscat if needed:

npm install -g wscat

Connect and join a talkgroup:

wscat -c "ws://localhost:3000/ws?token=$JWT"

Send a JOIN_TALKGROUP message:

{"type":"JOIN_TALKGROUP","talkgroup":"<talkgroup-uuid>"}

You should receive a PRESENCE message back immediately.


Stopping and Resetting

# Stop containers
docker compose down
 
# Destroy the database volume (wipe all data)
docker compose down -v

After wiping, re-seed with npx tsx prisma/seed.ts.


Viewing Logs

docker compose logs server -f     # follow server logs
docker compose logs -f            # follow all services

Mobile App

No server needed. MockRelaySocket echoes messages back locally.

Set in packages/mobile/.env.local:

EXPO_PUBLIC_MOCK_MODE=true

Then:

cd packages/mobile
pnpm start

Scan the QR code with Expo Go.


Docs Site

cd packages/docs
pnpm dev

Opens at http://localhost:3000 (or next available port if 3000 is taken by the server).


pnpm Workspace Commands

# Run a command in a specific package
pnpm --filter @skytalk/server <command>
pnpm --filter @skytalk/mobile <command>
 
# Build all packages
pnpm run build --recursive

Prisma Commands

cd packages/server
 
npx prisma db push          # sync schema to database (run after any schema change)
npx prisma generate         # regenerate TypeScript client (run after any schema change)
npx prisma studio           # open browser GUI to inspect the database
npx prisma db push --force-reset   # wipe and re-push schema

On this page