feat: BizGaze Connect home, BizGaze login, modular backend, /api/v1
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>
This commit is contained in:
+163
@@ -0,0 +1,163 @@
|
||||
# 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`):
|
||||
1. **Native Android/iOS apps**
|
||||
2. **Integration with any third-party application**
|
||||
3. **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 + `/ws` signaling** — 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)
|
||||
|
||||
1. **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.
|
||||
2. **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.
|
||||
3. **The API is versioned and token-addressable.** `/api/v1`; auth accepted via cookie
|
||||
(web) *or* `Authorization: Bearer` (mobile) *or* scoped API key (integrations).
|
||||
4. **Shared runtime state lives outside the process** (Redis) so the app can run N instances.
|
||||
5. **Multi-party media uses an SFU** (LiveKit/mediasoup); 1:1 may stay P2P.
|
||||
6. **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/`/ws` via `react-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)
|
||||
- [x] Extracted a **data-access layer** (`repos.js`) — all SQL moved out of `server.js`.
|
||||
- [x] **Modularized** `server.js` → `config / lib / session / presence / routes / static / signaling`
|
||||
(plus `repos` data layer and `bizgaze` service). `server.js` is now a thin entry point.
|
||||
- [x] Standardized a **tenant id** in the data layer (repo params named `tenantId`, == `team_id` today);
|
||||
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.
|
||||
- [x] **`/api/v1`** — every `/api/*` route aliased under `/api/v1/*` (routes.js); web keeps unversioned paths.
|
||||
- [x] **`Authorization: Bearer <token>`** accepted in `currentUser()` across HTTP + WS, alongside the
|
||||
cookie (session.js `tokenFromReq`); `/api/login` now also returns the `token` for 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: add `organizations`, keep `team_id`
|
||||
as alias/FK); add `plan`, `seats`, `status`, `features` columns.
|
||||
- [ ] **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_auth` already 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).
|
||||
Reference in New Issue
Block a user