home.html: in a Capacitor app shell, setupPush() now uses the native FCM/APNs path instead of Web Push — requests permission, registers, POSTs the OS device token to /api/v1/devices, deep-links on notification tap (selectChat), and unregisters the token on logout. Web Notification prompts are suppressed on native. Fully inert in a normal browser (Web Push unchanged). build batch15. CLIENTS.md Phase B push items checked off. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5.6 KiB
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 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),setDisplayMediaRequestHandlerso 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
- Push backend: device-token registration (
POST /api/v1/devices,/api/v1/devices/remove) + native senders folded into the singlepush.sendToUserpath — 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. (dbdevice_tokens, repodeviceTokens,push.js.) Mobile app still needs the Capacitor push plugin wired + FCM/APNs creds to deliver end-to-end. - Capacitor push plugin wired in the web UI (
setupNativePushin home.html): inside the app it requests permission, registers, andPOSTs the FCM/APNs token to/api/v1/devices; notification taps deep-link viaselectChat; 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.
Build & run
Desktop (technician client)
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)
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)
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.