Full stack: plain Node (http/https + ws, custom router, no framework), PostgreSQL 16 (SQLite retired), vanilla-JS web SPA, Capacitor 8 mobile with custom native-call/audio/media/share plugins, two Electron clients, LiveKit SFU + WebRTC mesh, Web Push/FCM/APNs, Docker + Nginx Proxy Manager, Codemagic CI. Includes a maintenance rule + changelog so it's kept current. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
9.1 KiB
Tech Stack — BizGaze Connect
Living document. Last updated: 2026-10-27. Update this file whenever a dependency, platform, service, or tool is added/removed/version-bumped. See Maintaining this file and the Changelog at the bottom.
What this project is
BizGaze Connect is a self-hosted team chat + meetings + calling product (evolved from a remote screen-sharing/"remote-access" tool, whose agent console still lives in the repo). One backend serves a web app and is wrapped by native mobile (Capacitor) and desktop (Electron) shells. The UI loads live from the server, so web changes deploy without rebuilding the native apps.
Architecture style: thin, dependency-light Node backend (custom modules, no web framework) + a single-page vanilla-JS web UI + native shells that wrap the web and add native capabilities (push, calling, screen capture, file access). Real-time via WebSockets; meeting media via WebRTC (P2P mesh, or LiveKit SFU when enabled).
Backend (server)
- Runtime: Node.js —
enginesrequires >= 22.5; the Docker image isnode:24-alpine. - HTTP/HTTPS: Node built-in
http/httpsmodules. No Express/Koa/Fastify — a small custom router (routes.js) maps"METHOD /path"to handlers; static files + authenticated downloads viastatic.js. - WebSockets:
ws^8.18(WebSocketServeron/ws) — chat, presence, meeting signaling (SDP/ICE relay + consent). - Structure (server/):
server.js(wiring),routes.js(HTTP JSON API),repos.js(all SQL / data access),signaling.js(WS),calls.js,chat.js,presence.js,session.js/auth.js,push.js,livekit.js,media.js,mailer.js,webhooks.js,bizgaze.js(BizGaze identity provider),directory.js,config.js. - Media tooling: ffmpeg (in the image) for server-side video poster thumbnails.
Data layer
- Database: PostgreSQL 16 (
pg^8.13). This is the only backend — SQLite was retired 2026-08-12; one schema source of truth atserver/db/schema.pg.sql. Selected viaDB_BACKEND=pg/DATABASE_URL. - DB access: hand-written SQL through an async adapter (
server/dbx.js,server/db/), centralized inrepos.js. No ORM. - Cache / pub-sub: Redis 7 (
redis^4.7) for cross-instance real-time fan-out (chat/presence) — optional, only whenPUBSUB_BACKEND=redis; default is in-memory single-instance (pubsub.js).
Real-time & media
- WebRTC for calls/meetings: built-in P2P mesh by default; LiveKit SFU when configured.
- LiveKit SFU server:
livekit/livekit-server:**v1.9**(Docker,sfucompose profile, dormant unlessLIVEKIT_*env is set). Server mints per-user JWT join tokens (server/livekit.js). - LiveKit clients:
- Web: self-hosted
livekit-client~2.20 UMD (server/public/vendor/livekit-client.umd.min.js). - iOS: LiveKit Swift SDK
2.15.3(SPM,client-sdk-swift, productLiveKit). - Android: LiveKit Android SDK (
io.livekit:livekit-android) — planned for native-calling Increment 2.
- Web: self-hosted
Web client (server/public/)
- Vanilla JavaScript SPA —
home.htmlis the app (large single file with inline JS). No framework, no bundler, no build step. Supporting files:icons.js(shared Lucide icon set viaic()),connect.html(embed),sw.js(service worker),bizconnect-toast.js. - PWA: installable; service worker for Web Push + offline shell.
- Icons: Lucide (shared set, rendered through
ic()); no emoji as control icons.
Mobile app (mobile/) — Capacitor
- Framework: Capacitor 8 (
@capacitor/core^8) — a native shell (iOS WKWebView / Android WebView) loading the remote web UI fromhttps://remote.bizgaze.com. Not Flutter/React Native. - Official plugins (
^8): App, Camera, Filesystem, Keyboard, Share, Push Notifications, Splash Screen, Status Bar; community@capacitor-community/safe-area^8;@capacitor/assets^3(icons/splash). - Local/custom plugins (
mobile/plugins/):native-call— native calling. iOS: Swift, CallKit + PushKit (VoIP) + LiveKit Swift SDK (native media, video tiles, screen-share via a ReplayKit broadcast extension), on-device live transcription (SFSpeechRecognizer). Android: Java, full-screen incoming-call UI over the lock screen + aFirebaseMessagingServicewoken by high-priority FCM data messages (native LiveKit media = Increment 2, WIP).audio-route(iOS audio output routing),media-library(save to Photos/gallery),share-inbox(inbound share sheet),file-opener(native Quick Look / open-with).
- iOS build: Capacitor 8 + SPM (CocoaPods retired); Xcode 26; a share extension + a broadcast extension.
- Android build: JDK 21, AGP 8.7 / Gradle 8.11, target SDK 36, edge-to-edge; manifest patched in CI
(
mobile/scripts/android-patch.js) sincemobile/android/is generated fresh per build.
Desktop app (desktop/) — Electron
- Electron 31 + electron-builder 24 (NSIS/Windows, DMG/mac, AppImage/Linux) + electron-updater 6
(auto-update from
https://remote.bizgaze.com/downloads/). Wraps the web UI and adds native screen capture. Optional@nut-tree-fork/nut-jsfor input automation.
Native host agent (agent/) — Electron
- Legacy remote-access agent (
remote-access-agent): Electron 31 host for screen capture, WebRTC, consent, and OS input injection (@nut-tree-fork/nut-js), signaling overws.
Push notifications
- Web Push via VAPID (
web-push^3.6) for browsers/PWA. - Android: Firebase Cloud Messaging (FCM) — Firebase project
bizgaze-connect; clientgoogle-services.jsonships in the APK; server uses a service-account key (base64 in.env). High-priority data messages wake the native-call plugin for incoming calls. - iOS: Apple Push Notification service (APNs) over HTTP/2 with a token (
.p8) auth key, including VoIP pushes (PushKit → CallKit) for incoming calls.
Infrastructure & deployment
- Containers: Docker + Docker Compose (
Dockerfile,docker-compose.yml). Services:app(Node),bizgazepg(Postgres 16),bizgazeredis(Redis 7,scaleprofile),livekit(SFU,sfuprofile). - Reverse proxy / TLS: Nginx Proxy Manager (external, shared
nginx_proxy_manager_defaultnetwork) — terminates HTTPS and proxiesremote.bizgaze.com→app:8090andwss://livekit.bizgaze.com→ LiveKit. - Persistence: named Docker volumes — app data (
/data: uploads, recordings, transcripts, downloads) and Postgres data. - Deploy flow: push to
master(Gitea remotecode.bizgaze.com) →redeploy.sh(plink/SSH to the host) → server-sidedeploy.sh(git pull + docker rebuild + recreate). Secrets live in a gitignored.envon the server (/opt/bizgaze-support/.env); see.env.example. - CI (mobile builds): Codemagic (
codemagic.yaml) — iOS (mac_mini_m2, SPM, publishes to TestFlight) and Android (mac_mini_m2, Node 22, JDK 21, produces an installable debug APK).
External integrations
- BizGaze SSO / identity provider + outbound webhook (
bizgaze.js,webhooks.js). - SMTP email via Nodemailer
^6.9(optional) — meeting invites to external participants. - GIPHY GIF search (server-proxied, optional, key-gated).
- TURN/STUN for WebRTC NAT traversal (credentials via
.env).
Dev & test tooling
- Local DB for tests: PostgreSQL 16 (local).
- Browser automation:
puppeteer-coredriving local Chrome (scratch testing). - Android debugging:
adb(platform-tools). - Shell/OS: developed on Windows; Git Bash + PowerShell; deploy via plink (PuTTY).
Repo layout (key directories)
| Path | What |
|---|---|
server/ |
Node backend (API, WS, data access, push, media) |
server/public/ |
Vanilla-JS web UI (home.html, icons.js, sw.js, vendor/) |
server/db/ |
PostgreSQL schema + DB adapter |
mobile/ |
Capacitor app (iOS/Android) |
mobile/plugins/ |
Custom Capacitor plugins (native-call, audio-route, media-library, share-inbox, file-opener) |
desktop/ |
Electron technician desktop client |
agent/ |
Legacy Electron remote-access host agent |
Dockerfile, docker-compose.yml, livekit.yaml |
Deploy stack |
codemagic.yaml |
Mobile CI (iOS + Android) |
redeploy.sh, deploy.sh |
Deployment |
ARCHITECTURE.md, DEPLOY.md, CLIENTS.md, README.md |
Docs |
Maintaining this file
Update this document in the same commit as any change that alters the stack, specifically when you:
- add/remove a dependency, or bump a major version (server
package.json,mobile/package.json,desktop/package.json,agent/package.json, plugin manifests); - change a platform/toolchain version (Node, Postgres, Redis, LiveKit, Capacitor, Electron, JDK, Xcode);
- add/remove a service in
docker-compose.ymlor a build workflow incodemagic.yaml; - add a new custom Capacitor plugin or a new external integration.
Bump the Last updated date at the top and add a line to the Changelog below.
Changelog
- 2026-10-27 — Initial tech-stack document created.