Skip to content

Development

DomeNinchen edited this page Oct 13, 2026 · 4 revisions

Development

Architecture

┌──────────────┐     ┌──────────────┐     ┌─────────────────┐
│   Frontend   │────▶│   Backend    │────▶│  TS Server      │
│  React SPA   │     │  Express API │     │  WebQuery HTTP  │
│  nginx :8080 │     │  Node :3001  │     │  SSH (events)   │
└──────────────┘     └──────┬───────┘     └─────────────────┘
                            │
                     ┌──────┴───────┐
                     │   SQLite     │
                     │   (Prisma)   │
                     └──────────────┘
                            │
                     ┌──────┴───────┐
                     │   Sidecar    │
                     │  Go/Pion     │
                     │  WebRTC :9800│
                     └──────────────┘

Public:  /widget/:token  ──▶  SVG / PNG / JSON (no auth)

Four packages in a pnpm monorepo:

Package Description
@ts6/common Shared types, constants, utilities — built to dist/ and imported by the backend and the frontend as a real package
@ts6/backend Express API, WebQuery client, bot engine, voice bots, widgets
@ts6/frontend React SPA with Vite, TailwindCSS, Radix UI primitives (shadcn-style)
sidecar Go WebRTC media relay (Pion) for video streaming; not part of the pnpm workspace

The backend proxies every TeamSpeak API call. The frontend never has direct access to API keys or server credentials — they are stored encrypted and never sent to the browser, which is also why credential fields in the UI appear blank when editing.

A server connection can use up to three independent links to a TeamSpeak server, and they are not all required: WebQuery (HTTP, for essentially every management operation), SSH ServerQuery (only for live events and the file transfer commands — see Getting Started) and the native TeamSpeak client protocol (only for the music bots, which join a channel as ordinary clients).

Tech stack

Frontend — React 19, Vite, TailwindCSS 4, Radix UI (shadcn-style components), TanStack Query + Table, Recharts, Zustand, i18next. The bot flow editor is built into the app and does not use a diagramming library.

Backend — Node.js, Express 5, Prisma 7 (SQLite through the better-sqlite3 adapter), JWT authentication, WebQuery HTTP client, SSH event listener

Voice/audio — a custom TS3 voice protocol client over UDP, Opus encoding, FFmpeg, yt-dlp

Video streaming — Go sidecar using Pion WebRTC v4, with RTCP Sender Reports for A/V sync

Running it locally

Requires Node.js 22.22 or newer (the Docker images use Node 24) and pnpm 9 or newer.

pnpm install
pnpm dev

That starts backend and frontend in parallel — backend on :3001, frontend on :5173 via the Vite dev server, which forwards /api and /ws to the backend. It also runs @ts6/common in watch mode, which matters: the backend and the frontend read its compiled dist/, not its source, so a change to common only shows up once it has been built.

Copy .env.example to .env first; JWT_SECRET is the one that has to be set in production (see Configuration).

The checks that exist:

pnpm typecheck                     # tsc --noEmit across the TypeScript packages
cd packages/sidecar && go test ./...   # the Go sidecar's tests

There is no JavaScript/TypeScript test suite; pnpm typecheck is the automated check for the backend, the frontend and common. Everything else is tried against a real TeamSpeak server.

Database

Prisma with SQLite. The schema in packages/backend/prisma/schema.prisma is the single source of truth; there are no migration files, schema changes are pushed. On first run:

cd packages/backend
npx prisma db push

The Docker images do this automatically on startup, so it is only needed when running directly from source.

How changes are documented

Every user-visible change is recorded in the Changelog, in the order it shipped, usually including the reasoning behind it and anything that was ruled out along the way. It is the best starting point for understanding why something is built the way it is — several entries document TeamSpeak server behaviour that is either undocumented or documented incorrectly elsewhere.

Backend, frontend and sidecar each carry their own independent version number, bumped whenever that component changes.


v0.5, last edited 13.10.2026

Getting started

Home
Getting Started
Install on Debian 13
Setup: same machine
Setup: elsewhere / rented
Users and Roles

Using the app

Dashboard
Virtual Servers and Instance
Channels
Clients
Client Database
Permissions
Server and Channel Groups
Moderation
Tokens and Passwords
Files
Icons
Bot Flows
Music Bots
Server Widgets
Server Maintenance
Server Logs
Query Console
Connection Journal
Themes and Appearance

Running it

Administration
Configuration
Deployment
Privacy and Hosting

When something is odd

Tips and Pitfalls
Troubleshooting

Contributing

Development

Repository · Changelog

Clone this wiki locally