Another one from the ground up. FreeVox is a self-hosted voice/video/screenshare platform — think Zoom to FreeChat's Slack. Same LiveKit backend, shared JWT auth, completely separate frontend and Go API. 64 files committed, both sides compile clean, git repo initialized and local-only until we shake it down.
Why a Separate App
FreeChat already has LiveKit voice/video, so the natural question was: why not just add channels there? The answer is product positioning. FreeChat is the encrypted chat platform; FreeVox is the meeting-first video platform. Persistent voice channels and shareable meeting codes don't fit cleanly into FreeChat's room model. The plan is to use FreeVox as a testing ground — prove features here, then fold the good ones back into FreeChat.
Architecture Decisions
| Backend | Go with Chi router — first Go project in the ecosystem. Chose it over Node/Express for the lighter runtime and because we wanted the contrast with FreeChat's TypeScript stack |
| Database | modernc.org/sqlite — pure Go, no CGO/GCC needed on Windows. Four tables: channels, meetings, participants, user_settings |
| Auth | No login flow. FreeVox validates FreeChat JWTs directly — shared auth means one login for both platforms. Refresh requests proxy back to FreeChat |
| LiveKit | Shared instance with FreeChat. Room names namespaced to prevent collisions. Token generation via LiveKit's Go SDK |
| Frontend | React 19 + Zustand + Vite. LiveKit service wrapper copied verbatim from FreeChat — it's a clean SDK abstraction with no app-specific logic |
What Shipped
Full REST API (14 endpoints), WebSocket hub with authenticated broadcast, persistent voice channels with join/leave, ephemeral meeting rooms with shareable 8-character codes, device settings, and a complete React UI with video grid, media controls, and participant tiles. Docker deployment configured to join FreeChat's network. Go 1.26 installed via winget as a prerequisite — first Go toolchain on this machine.
Gotcha: Gitignore vs Directory Name
The gitignore entry freevox (meant to ignore the compiled binary) also matched cmd/freevox/, silently excluding our entry point from the repo. Fixed by anchoring to root: /freevox. A good reminder that unanchored gitignore patterns match anywhere in the tree.
What's Next
- Test against the running FreeChat Docker stack end-to-end
- Decide on domain strategy —
freevox.icu,freevox.org, orfreechat.icu/voxinitially - Push to GitHub once the first live test passes