# 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](#maintaining-this-file) and the > [Changelog](#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 — `engines` requires **>= 22.5**; the Docker image is **`node:24-alpine`**. - **HTTP/HTTPS:** Node built-in `http`/`https` modules. **No Express/Koa/Fastify** — a small custom router (`routes.js`) maps `"METHOD /path"` to handlers; static files + authenticated downloads via `static.js`. - **WebSockets:** [`ws`](https://github.com/websockets/ws) `^8.18` (`WebSocketServer` on `/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 at `server/db/schema.pg.sql`. Selected via `DB_BACKEND=pg` / `DATABASE_URL`. - **DB access:** hand-written SQL through an async adapter (`server/dbx.js`, `server/db/`), centralized in `repos.js`. No ORM. - **Cache / pub-sub:** **Redis 7** (`redis` `^4.7`) for cross-instance real-time fan-out (chat/presence) — **optional**, only when `PUBSUB_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, `sfu` compose profile, dormant unless `LIVEKIT_*` 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`, product `LiveKit`). - Android: **LiveKit Android SDK** (`io.livekit:livekit-android`) — planned for native-calling Increment 2. ## Web client (`server/public/`) - **Vanilla JavaScript SPA** — `home.html` is the app (large single file with inline JS). **No framework, no bundler, no build step.** Supporting files: `icons.js` (shared Lucide icon set via `ic()`), `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 from `https://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 + a `FirebaseMessagingService` woken 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`) since `mobile/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-js`** for 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 over `ws`. ## Push notifications - **Web Push** via VAPID (`web-push` `^3.6`) for browsers/PWA. - **Android:** Firebase Cloud Messaging (FCM) — Firebase project `bizgaze-connect`; client `google-services.json` ships 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, `scale` profile), `livekit` (SFU, `sfu` profile). - **Reverse proxy / TLS:** **Nginx Proxy Manager** (external, shared `nginx_proxy_manager_default` network) — terminates HTTPS and proxies `remote.bizgaze.com` → `app:8090` and `wss://livekit.bizgaze.com` → LiveKit. - **Persistence:** named Docker volumes — app data (`/data`: uploads, recordings, transcripts, downloads) and Postgres data. - **Deploy flow:** push to `master` (Gitea remote `code.bizgaze.com`) → `redeploy.sh` (plink/SSH to the host) → server-side `deploy.sh` (git pull + docker rebuild + recreate). Secrets live in a gitignored `.env` on 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-core` driving 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.yml` or a build workflow in `codemagic.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.