~/projects/voiceapp
VoiceApp
A self-hosted Discord for one friend group — text, voice, screenshare, camera and files, on my own stack.Vlastiti self-hosted Discord za jednu ekipu — tekst, glas, dijeljenje ekrana, kamera i datoteke, na mojoj infrastrukturi.
VoiceApp is my own self-hosted Discord — a private, Discord-style comms app I built for one friend group so we own our text, voice and screenshare instead of renting it. It's an end-to-end TypeScript project: a shared types package, a Node/TypeScript modular-monolith backend (Fastify, transport → service → domain → adapters), and an Electron + React desktop client whose renderer is deliberately unprivileged.
The hard part is real-time media. Voice, video and screenshare run over a self-hosted LiveKit (WebRTC) server — you click a channel to join the call, and the share picker splits app windows, whole screens and cameras into a clean grid. State lives in PostgreSQL and Valkey, and file uploads go to a self-hosted S3-compatible object store (Garage). I planned the whole thing with the BMAD method (brief, PRD, UX, architecture) and locked it down with 14 architecture invariants — the strictest being that the optional `/claude` command is client-local and prompt-only, so an AI helper can never reach the server or other people's data.
It's not a demo — it's deployed and in use. The client ships as a Windows installer (electron-builder, NSIS), and the backend runs as a single Docker Compose stack — Postgres, Valkey, Garage, LiveKit and a Caddy reverse proxy that fetches Let's Encrypt certificates automatically — self-hosted on my TrueNAS server behind a real domain. I reskinned the UI 1:1 to a Discord look, and the codebase is covered by 268 automated tests (224 backend, 44 client).
VoiceApp je moj vlastiti self-hosted Discord — privatna aplikacija za komunikaciju u stilu Discorda koju sam izradio za jednu ekipu kako bismo sami posjedovali svoj tekst, glas i dijeljenje ekrana umjesto da ih iznajmljujemo. Riječ je o end-to-end TypeScript projektu: zajednički paket tipova, Node/TypeScript backend kao modularni monolit (Fastify, transport → service → domain → adapters) i Electron + React desktop klijent čiji je renderer namjerno nepovlašten.
Najteži dio je medijski prijenos u stvarnom vremenu. Glas, video i dijeljenje ekrana idu preko self-hosted LiveKit (WebRTC) servera — kanalu se pridružiš jednim klikom, a birač izvora dijeli prozore aplikacija, cijele ekrane i kamere u pregledni raspored. Stanje je u PostgreSQL-u i Valkeyu, a datoteke se spremaju u self-hostani S3-kompatibilni object store (Garage). Sve sam isplanirao BMAD metodom (brief, PRD, UX, arhitektura) i osigurao s 14 arhitektonskih invarijanti — najstroža je da je opcionalna `/claude` naredba isključivo klijentska i samo-prompt, pa AI pomoćnik nikad ne može doći do servera ni tuđih podataka.
Nije riječ o demou — deployano je i u upotrebi. Klijent se isporučuje kao Windows instaler (electron-builder, NSIS), a backend radi kao jedan Docker Compose stack — Postgres, Valkey, Garage, LiveKit i Caddy reverse proxy koji automatski dohvaća Let's Encrypt certifikate — self-hostan na mom TrueNAS serveru iza prave domene. Sučelje sam 1:1 preuredio u Discord izgled, a kod pokriva 268 automatiziranih testova (224 backend, 44 klijent).
HighlightsIstaknuto
A full Discord-style client — text channels, voice, screenshare, camera and file sharing — built in Electron + React with a deliberately unprivileged renderer.
Real-time voice & video over a self-hosted LiveKit (WebRTC) media server: click-to-join voice channels and a share picker for any app window, whole screen, or camera.
Servers, channels, roles, @-mentions and single-use invite codes, with an Owner role and full-stack join/leave — backed by Postgres, Valkey and an S3-compatible object store (Garage) for uploads.
An opt-in, sandboxed `/claude` assistant that is strictly client-local and prompt-only — it never touches the server (one of 14 architecture invariants that govern the codebase).
Shipped end-to-end: a Windows installer (electron-builder) plus a one-command Docker Compose backend (Postgres · Valkey · Garage · LiveKit · Caddy), self-hosted on a TrueNAS box with automatic Let's Encrypt TLS. 268 automated tests (224 backend, 44 client).
Potpun klijent u stilu Discorda — tekstualni kanali, glas, dijeljenje ekrana, kamera i slanje datoteka — izrađen u Electronu + Reactu s namjerno nepovlaštenim rendererom.
Glas i video u stvarnom vremenu preko self-hosted LiveKit (WebRTC) media servera: pridruživanje glasovnim kanalima jednim klikom i biranje izvora za dijeljenje bilo kojeg prozora, cijelog ekrana ili kamere.
Serveri, kanali, uloge, @-spominjanja i jednokratni pozivni kodovi, s Owner ulogom i full-stack pridruživanjem/napuštanjem — na Postgresu, Valkeyu i S3-kompatibilnom object storeu (Garage) za uploade.
Opcionalan, izoliran `/claude` asistent koji je strogo klijentski i samo-prompt — nikad ne dira server (jedna od 14 arhitektonskih invarijanti koje upravljaju kodom).
Isporučeno od početka do kraja: Windows instaler (electron-builder) i backend na jednu naredbu kroz Docker Compose (Postgres · Valkey · Garage · LiveKit · Caddy), self-hostan na TrueNAS uređaju uz automatski Let's Encrypt TLS. 268 automatiziranih testova (224 backend, 44 klijent).