# Biz Connect — Mobile & Desktop clients

Native clients for Biz Connect. **The web app is the single source of truth for the UI**;
each native client is a thin shell that loads that UI and adds the capabilities a browser
can't provide (background push, native screen capture, OS input injection, store presence).

Decisions (set by the user 2026-06-30):
- **Build mobile and desktop in parallel.**
- **Desktop = both pieces:** the remote-control **host** (existing `agent/`) *and* a
  **technician desktop client** (`desktop/` — Connect in a window).
- **Mobile = Capacitor wrap** of the existing web UI (one codebase), not a native rewrite.

Backend is already client-ready (see [ARCHITECTURE.md](ARCHITECTURE.md) Phase 2): `/api/v1`,
`Authorization: Bearer` + refresh tokens, API keys, per-tenant webhooks. The one remaining
backend gap is **APNs/FCM push** for native mobile (needs Apple/Google credentials).

---

## Components

| Dir | Client | Tech | What it adds over the browser |
|-----|--------|------|-------------------------------|
| `mobile/` | iOS + Android app | **Capacitor** loading the Connect UI | Native push (FCM/APNs), camera/mic perms, store distribution, screen capture (ReplayKit / MediaProjection) |
| `desktop/` | Technician client | **Electron** loading the Connect UI | Native full-screen capture for screen-share; windowed app; later: tray, auto-update |
| `agent/` | Remote-control **host** (customer) | **Electron + nut-js** *(exists, v0.2.0)* | Screen capture + **OS input injection** so a technician can control the machine |

All three authenticate through the same `/api/v1` access layer (Bearer token for mobile/desktop,
the existing consent/enroll flow for the agent).

---

## Why "wrap the web UI" (not rewrite)

The Connect UI is already an installable PWA built from server-rendered single-file HTML.
Pointing a native webview at the server origin means **every relative `/api` and `/ws` URL
keeps working unchanged** — zero web-code changes — while native plugins augment it through
the JS bridge. One codebase, three shells.

Trade-off: a server-URL shell needs network at launch (fine for a remote-support tool) and
some stores scrutinise "just a website". We mitigate by shipping real native capabilities
(push, screen capture, deep links), and can later switch to **bundled** web assets + an
absolute API base if offline-launch or store policy requires it.

---

## Phased plan

### Phase A — Shells that load the live app  ← start here
- [ ] `desktop/` Electron client: `loadURL(server)`, `setDisplayMediaRequestHandler` so
      screen-share works natively, external links → browser, persisted session.
- [ ] `mobile/` Capacitor project: `server.url` → Connect, app icons/splash, status bar.
- [ ] Inject `window.__NATIVE__ = 'desktop' | 'ios' | 'android'` so the web UI can adapt
      (e.g. hide the PWA "install" prompt, enable native push instead of Web Push).

### Phase B — Native capabilities
- [x] **Push backend:** device-token registration (`POST /api/v1/devices`,
      `/api/v1/devices/remove`) + native senders folded into the single `push.sendToUser`
      path — **FCM v1** (Android) and **APNs** token-based over HTTP/2 (iOS), each
      config-gated and a no-op until creds are set. Web Push (VAPID) unchanged. Dead
      tokens are pruned on 404/410/UNREGISTERED. (db `device_tokens`, repo `deviceTokens`,
      `push.js`.) *Mobile app still needs the Capacitor push plugin wired + FCM/APNs creds
      to deliver end-to-end.*
- [x] **Capacitor push plugin wired** in the web UI (`setupNativePush` in home.html):
      inside the app it requests permission, registers, and `POST`s the FCM/APNs token to
      `/api/v1/devices`; notification taps deep-link via `selectChat`; logout unregisters the
      token. Web Push is skipped when running natively. Inert in a normal browser. *Activates
      once the Capacitor Android/iOS app is built and FCM/APNs creds are set.*
- [ ] **Mobile screen capture** for "Share Screen" from a phone (ReplayKit / MediaProjection plugin).
- [ ] **Deep links / universal links** so a session/meeting link opens the app.

### Phase C — Packaging & distribution  *(needs external accounts)*
- [ ] Desktop installers via **electron-builder** (Win NSIS + Mac dmg); **code-signing**
      (Win EV cert, Apple Developer ID + notarization).
- [ ] Mobile store builds: **Apple Developer** ($99/yr) + **Google Play** ($25 once);
      signing keys; store listings & privacy disclosures.
- [ ] Agent host installer (signed) for customers.
- [ ] Auto-update channels.

### Phase D — Inline-reply notifications (Teams-style)  *(right AFTER packaging)*
Reply to a chat directly from the OS notification, without opening the app. Cross-platform:
- [x] **Desktop (Windows):** native Windows toast with a **reply box** via **node-notifier**
      (bundles SnoreToast). main.js `reply-notification` handler → preload `replyNotify` →
      home.html `notify()` routes chat toasts through it: a typed reply calls `sendReplyTo`
      (POST /api/messages) without opening the app; clicking opens the chat. Uses the installer's
      AppUserModelID, so it only works in the **installed** app. *Needs a live test in the
      installed app (can't drive a real Windows toast from CI).*
- **Android:** notification action with **`RemoteInput`** (direct reply) on the FCM message.
- **iOS:** **`UNTextInputNotificationAction`** on the APNs notification category.
All three hand the typed text to the same send path. Depends on Phase B push + Phase C packaging.

---

## Build & run

### Desktop (technician client)
```bash
cd desktop
npm install
SERVER_URL=https://remote.bizgaze.com npm start     # or http://localhost:8090 in dev
npm run dist                                         # build installers (needs electron-builder + certs)
```

### Mobile (Capacitor)
```bash
cd mobile
npm install
npx cap add android        # needs Android Studio + SDK
npx cap add ios            # needs macOS + Xcode
npx cap sync
npx cap open android       # build/run from Android Studio
npx cap open ios           # build/run from Xcode
```
Set the server origin in `capacitor.config.json` (`server.url`).

### Agent host (existing)
```bash
cd agent
npm install
SERVER_URL=https://remote.bizgaze.com AGENT_ENROLL_TOKEN=<token> npm start
```

---

## What's gated on you (external, can't be done from code alone)
- **Apple Developer** + **Google Play** accounts (mobile store builds & push).
- **Code-signing certificates** (Windows EV, Apple Developer ID) for trusted installers.
- **FCM/APNs credentials** for native push.
Everything else — the shells, the device/push backend, native plugin wiring — is built here.
