User-facing - New post-login home (/home): chat rail + Share/Connect (embedded) + Meeting; login lives here when logged out - Landing: "Log in with BizGaze" + no-login screen share - Console replaced by a role-scoped Dashboard (/dashboard): admins see all team sessions, others see only their own; stats + CSV/PDF export - Recordings saved as MP4 (H.264/AAC) with WebM fallback; old .webm still downloadable - Fix: duplicate "Sign in" on the login card Auth / integration - BizGaze as identity provider: /api/login validates against BIZGAZE_LOGIN_URL (env-gated) and provisions a local user - Phase 2 start: /api/v1 alias for all /api routes; Authorization: Bearer accepted across HTTP + WS; login returns a token (for native desktop/mobile clients) Backend refactor (Phase 1, behavior-preserving) - Split server.js into config/lib/session/presence/routes/static/signaling + repos (data-access) + bizgaze (service) - All SQL behind repos.js, tenant-scoped (tenantId == team_id for now) - e2e updated to current flow (21/21 pass before and after) Docs: ARCHITECTURE.md (target architecture + phased plan), CLAUDE.md repo layout, .env.example BIZGAZE_LOGIN_URL Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
9.9 KiB
BizGaze Connect — Architecture & Roadmap
This document records the current architecture, the target architecture, and a phased migration plan so that the three strategic goals can be added additively rather than as rewrites.
Strategic goals (see also CLAUDE.md):
- Native Android/iOS apps
- Integration with any third-party application
- Org-based licensing model (Zoom-like: organizations buy seats/plans)
1. Current architecture (as of 2026-06)
Single Node process (server/server.js, ~640 lines)
├── HTTP JSON API (/api/*, cookie-session auth)
├── WebSocket signaling (/ws — SDP/ICE relay, consent, share codes)
├── Static file serving (public/*.html, single-file pages, no build)
└── In-process state liveSessions / onlineAgents / pendingShares (Maps)
Data: node:sqlite single file (server/data.db)
teams, users, sessions_auth, machines, audit_log, sessions_log
Media: WebRTC P2P (1:1). STUN + managed TURN. Media never traverses the server.
Auth: scrypt passwords, opaque session token in an HttpOnly `sid` cookie. TOTP code exists but
login currently marks sessions MFA-passed directly.
Integrations: outbound webhook (single env URL, `session.ended`, HMAC-signed);
inbound SSO (`/sso`, custom HMAC token).
Recordings/transcripts: written to local disk (server/recordings, server/transcripts).
What is already future-proof (keep)
- WebRTC +
/wssignaling — standards-based; reused as-is by native apps and an SFU. - P2P media — no server media path for 1:1; cheap and private.
- HMAC-signed webhooks and audit log — right primitives, just need to scale out.
- Team-scoped queries — the seed of multi-tenancy is present.
Structural constraints that block the roadmap
| # | Constraint | Blocks |
|---|---|---|
| C1 | Auth is cookie-only (parseCookies(req).sid); no Authorization: Bearer, no API keys |
Mobile, Integrations |
| C2 | No API versioning (/api/...) |
Mobile (shipped clients pin a contract) |
| C3 | team is a thin tenant (id,name,created_at); app assumes one team |
Licensing |
| C4 | Session state in process memory (Maps) | Horizontal scale, Meetings |
| C5 | SQLite single-writer, queries inline at ~100 call-sites | Scale, multi-tenant isolation |
| C6 | P2P mesh only — no SFU | Multi-party meetings (Zoom-like) |
| C7 | Recordings on local disk | Multi-instance, per-org storage quotas |
| C8 | Monolithic server.js mixes HTTP/WS/static/logic/DB |
All (maintainability) |
2. Target architecture (principles)
- Organization is the top-level tenant. Every row and every request resolves to an
org_id. Billing, seats, plan, and feature flags hang off the Organization. - Data access goes through a repository layer, never raw SQL in route handlers. This is what makes the SQLite→Postgres migration and strict tenant-scoping feasible.
- The API is versioned and token-addressable.
/api/v1; auth accepted via cookie (web) orAuthorization: Bearer(mobile) or scoped API key (integrations). - Shared runtime state lives outside the process (Redis) so the app can run N instances.
- Multi-party media uses an SFU (LiveKit/mediasoup); 1:1 may stay P2P.
- Entitlements are enforced centrally — one middleware checks plan limits before privileged actions (add seat, start meeting, record, call the API).
┌──────────── clients ────────────┐
│ web (HTML) mobile (native) 3rd-party (API key) │
└───────┬───────────┬───────────────┬──────────────┘
│ cookie │ Bearer │ API key
┌───────▼───────────▼───────────────▼──────────────┐
│ API v1 (routes → services → repository) │
│ authN (cookie/Bearer/key) · authZ (RBAC) │
│ entitlements middleware (plan/seat/feature) │
└───────┬───────────────────────┬──────────────────┘
│ │
┌─────────▼────────┐ ┌─────────▼─────────┐
│ Repository layer │ │ Signaling (ws) │──── Redis (shared state,
│ (SQLite→Postgres)│ │ + SFU for meetings│ pub/sub across instances)
└─────────┬────────┘ └───────────────────┘
│
Postgres · Object storage (recordings) · usage-metering
3. Goal-by-goal requirements
Goal 1 — Native Android/iOS
- Bearer-token auth (C1) + refresh tokens; device registration.
/api/v1(C2) — stable, documented contract.- Push notifications (APNs/FCM) for incoming sessions/calls (mobile can't hold a background WS).
- Reuse WebRTC/
/wsviareact-native-webrtc/native SDKs; native screen capture (ReplayKit / MediaProjection) for the phone-can't-share gap.
Goal 2 — Third-party integration
- Scoped API keys / OAuth2 client-credentials per org (C1).
- Webhook subscriptions per org: multiple endpoints, event types, signed payloads, retries.
- OIDC/JWT SSO to replace the custom HMAC
/sso. - Optional: embeddable JS widget / SDK.
Goal 3 — Org licensing (Zoom-like)
- Organization entity (C3):
plan,seats,status,trial_ends_at, feature flags. - Entitlements + metering: tables for plan limits and usage (minutes, sessions, storage); central enforcement middleware.
- SFU for multi-party meetings (C6); per-org concurrent-meeting / minute caps.
- Redis shared state (C4) for multi-instance; Postgres (C5); object storage (C7).
- Billing provider integration (e.g. Stripe) driving subscription state.
4. Phased plan
Priority (set by the user 2026-06-11): mobile + integration first; licensing last. Principle unchanged: do the shared groundwork first, so later work is additive. Because licensing is last, the full Organization entity moves to Phase 3 with it — Phase 1 keeps only a tenant-id abstraction (mapping to today's
team_id) so Phase-2 auth/keys don't need reworking when the tenant is later elevated to a full Organization.
Phase 1 — Foundations (structural, no behavior change) ✅ DONE (2026-06-11)
- Extracted a data-access layer (
repos.js) — all SQL moved out ofserver.js. - Modularized
server.js→config / lib / session / presence / routes / static / signaling(plusreposdata layer andbizgazeservice).server.jsis now a thin entry point. - Standardized a tenant id in the data layer (repo params named
tenantId, ==team_idtoday); every query is tenant-scoped. No Organization entity / plan-seats yet — that's Phase 3. - Verified behavior-preserving by
test/e2e.js(21/21) before and after.
Phase 2 — API + access ← PRIORITY (mobile + desktop + integrations)
Target clients: web (cookie), native Android/iOS, a native Windows desktop app where the
viewer CONTROLS the remote screen (reuses the WebRTC inputChannel + OS input injection like
agent/), and third-party systems (API keys). All authenticate through this one access layer.
/api/v1— every/api/*route aliased under/api/v1/*(routes.js); web keeps unversioned paths.Authorization: Bearer <token>accepted incurrentUser()across HTTP + WS, alongside the cookie (session.jstokenFromReq);/api/loginnow also returns thetokenfor native clients. WS upgrades carry the token in the Authorization header (native) or?access_token=(browser fallback).- Refresh tokens (short access token + long refresh) so native apps stay signed in safely.
- API keys table + middleware (scoped per tenant, hashed at rest).
- Push-notification hooks (APNs/FCM) for incoming sessions/calls on mobile.
- OIDC/JWT SSO; per-tenant webhook subscriptions with retries.
Phase 3 — Licensing + scale (last, per priority)
- Elevate tenant →
organization(additive migration: addorganizations, keepteam_idas alias/FK); addplan,seats,status,featurescolumns. - Entitlements module + central enforcement; usage metering (minutes/sessions/storage).
- SFU (LiveKit/mediasoup) for multi-party meetings; keep 1:1 P2P.
- Redis for
liveSessions/onlineAgents/pendingShares+ cross-instance pub/sub. - Postgres migration (enabled by the Phase-1 data-access layer); object storage (S3) for recordings.
- Billing provider + subscription lifecycle webhooks.
Explicitly NOT yet
- Don't add an SFU or Postgres before the data-access layer exists — you'd rework them.
- Don't build the full Organization/plan model before Phase 2 ships — but do keep the tenant-id abstraction consistent from Phase 1 so the elevation is additive.
- Don't shard or add microservices; a well-modularized monolith + Redis + Postgres scales far enough.
5. Key decisions to confirm (when we reach them)
- Auth tokens: opaque (DB-backed, easy revoke) vs JWT (stateless, harder revoke). Lean: opaque
access + refresh, since
sessions_authalready works that way. - SFU: LiveKit (batteries-included, good mobile SDKs) vs mediasoup (lower-level, more control).
- DB: Postgres (recommended) — keep the repository layer DB-agnostic until the cutover.
- Billing: Stripe vs BizGaze's own billing (depends on how Connect sits inside the BizGaze suite).