---
name: GuruConnect — v2 direction and deploy procedure
description: GuruConnect v2 architecture direction (native-first full key fidelity, bidirectional file cut/paste/drag; WebRTC fallback only) plus the manual deploy procedure to 172.16.3.30 (build-on-server, login shell, sqlx runtime queries, NPM trusted-proxy gotcha). v2 live since 2026-05-30 at connect.azcomputerguru.com.
type: project
---

## Direction (v2 architecture)

Re-architecture set 2026-05-29 after an audit found 3 CRITICAL relay-plane auth holes. Spec: `projects/msp-tools/guru-connect/docs/specs/SPEC-002-v2-modernization-architecture.md`. Mike is the product owner; willing to scrap v1 entirely for a considerably better product.

- **Greenfield, salvage cores:** keep the proven Rust (DXGI/GDI capture, input injection, SAS helper, prost codec, proto, Gitea-Actions CI) — rebuild relay/auth, session, viewer, dashboard, deploy. Clean reset in-place (keep repo/history/issues), not a new repo.
- **Native-first, NOT WebRTC.** Mike's headline must-haves:
  1. **Keyboard hooks / full key fidelity** — Win+R, Ctrl+C/V, **Ctrl+Alt+Del** must work. Browsers structurally can't do these — WebRTC is fallback/secondary only.
  2. **Bidirectional file transfer via clipboard cut/paste AND drag-and-drop** from/to either guest or host. Core differentiator, not deferred. Needs delayed-render clipboard + chunked engine; drag-out (remote→local) is the hard case and ships after drag-in.
- Transport stays custom protobuf-over-WSS.
- **Standalone-first + versioned `/api/integration/v1/` contract** with GuruRMM (ADR-001).
- **Hardened single-tenant now, multi-tenancy-READY schema** (nullable `tenant_id` everywhere) so the partner/client model switches on later with no migration rewrite.
- Adopt GuruRMM principles: per-agent keys (kill shared AGENT_API_KEY), no-TOML-for-endpoints, living-roadmap = definition-of-done, full-stack features, true-integration / anti-Datto.
- Ship each capability **full-stack** (proto + agent + server + viewer + dashboard + docs). See [[project_versionable_products]].

**Open questions still pending Mike's answer:** repo reset, H.264-vs-HEVC default, web transport, support-code format, v1 cutover.

---

## Deploy procedure (manual, to 172.16.3.30)

Live in prod since 2026-05-30 at `connect.azcomputerguru.com` (NPM → localhost:3002). The `.gitea/workflows/deploy.yml` "deploy to server" step is a STUB (builds an artifact only) — deploy is manual.

**Repo on the box:** `/home/guru/guru-connect` (separate repo `azcomputerguru/guru-connect`, NOT a submodule).

**Build host = the server itself.** 172.16.3.30 has rust (rustup, cargo 1.94, `x86_64-unknown-linux-gnu` target), node 20 + npm 10, and protoc (`~/.local/bin`, libprotoc 28.3) — but **only on PATH in a login shell**: `ssh guru@172.16.3.30 'bash -lc "..."'`. A non-interactive shell doesn't source `~/.profile`, so cargo/protoc look "missing". GURU-5070 builds the Windows agent + a Windows-target server, NOT the Linux release — build Linux on the box. See [[reference_guru5070_rust_toolchain]].

### Sequence (build while v1 runs, quick cutover restart)

1. **Backup first:**
   ```bash
   pg_dump "$DATABASE_URL" | gzip > ~/backups/guruconnect/pre-deploy-$(date +%F-%H%M).sql.gz
   ```
   Save current commit + copy running binary to `~/guruconnect-server.vN.bak`.

2. **Get the code.** The server's local `main` may have **diverged** from origin (the v2 greenfield respec rewrote history — `git pull --ff-only` will refuse). Tree is clean, so:
   ```bash
   git fetch origin && git reset --hard origin/main
   ```
   `.env` is gitignored, untouched. Save the rollback SHA before resetting.

3. **SPA:** `cd dashboard && npm ci && npm run build` → emits to `../server/static/app/` (gitignored).

4. **Binary** (from repo root, login shell, `PROTOC` set):
   ```bash
   cargo build --release -p guruconnect-server --target x86_64-unknown-linux-gnu
   ```
   `-p` scopes to the server so the Windows-only agent crate isn't compiled. Explicit `--target` overrides `.cargo/config.toml`'s windows-msvc default. Output: `target/x86_64-unknown-linux-gnu/release/guruconnect-server` = the unit's ExecStart. ~3 min. sqlx uses RUNTIME queries (no `query!` macros, no `.sqlx` cache) — build needs no DB.

5. **Cutover:** `sudo systemctl restart guruconnect`. Migrations are sqlx-embedded and **auto-run on startup** (`db.migrate()`) — no manual `psql`. Watch `journalctl -u guruconnect` for "Migrations complete" + "Server listening".

### Gotchas (all hit on the 2026-05-30 deploy)

- **systemd unit:** the INSTALLED `/etc/systemd/system/guruconnect.service` has **no `WatchdogSec`** (correct for v2, which sends no `sd_notify`). The repo's `server/guruconnect.service` DOES set `WatchdogSec=30s` — so do NOT run `setup-systemd.sh` / copy the repo unit, or v2 restart-loops every 30s. Unit: `User=guru`, `EnvironmentFile=server/.env`, `WorkingDirectory=server/`, `ProtectSystem=strict`.

- **`CONNECT_TRUSTED_PROXIES`** is a v2 env var (comma-separated IPs; defaults to loopback fail-closed). Public `connect.azcomputerguru.com` ingresses through **NPM on Jupiter (172.16.3.20)** → relay on `172.16.3.30:3002`. Set `CONNECT_TRUSTED_PROXIES=127.0.0.1,::1,172.16.3.20` in `server/.env` (the Jupiter NPM hop, NOT the relay host `.30` — that was the wrong first guess). Without trusting `172.16.3.20`, the relay logs every public agent as `172.16.3.20` instead of reading `X-Forwarded-For`. With it, the real client IP shows (verified: a Pavon agent logged its true public IP `98.172.64.243`). Only `JWT_SECRET` is hard-required.

- **NULL tags bug:** `connect_machines.tags` is `text[]` nullable with no default; v2 decodes as non-`Option`, so NULL rows throw "unexpected null" at reconcile (and likely the Machines list). Mitigate: `UPDATE connect_machines SET tags='{}' WHERE tags IS NULL`. Real fix is a TODO (decode `Option<...>` + migration default).

- **DB:** Postgres 14 `guruconnect` on localhost. Existing users (admin, howard, both role admin) survive migration.

### Rollback

`git reset --hard <saved-sha>`, rebuild, restart, `psql < backup`.
