Companion side of docs/companion-pairing-qr.md (v1 contract): - Connect screen lands on Scan Node's QR / Enter Manually; NESMenu gains an add-server-by-QR icon button - QrScannerOverlay: CameraX + ZXing core (pinned, on-device, no ML Kit) - ServerQrParser: archipelago://pair?v=1&url=..[&pw=..]; unknown major v -> 'update the app'; upsert by origin so re-scans never duplicate - archipelago:// deep link registered (singleTask + onNewIntent) for the modal's 'Open in companion app' button - WebView auto-fills and submits Login.vue's password form when a stored password exists — demo QR is one step to a logged-in session - Web modal + handoff doc copy synced to the real label: Scan Node's QR - v0.4.13 (versionCode 17) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
82 lines
4.1 KiB
Markdown
82 lines
4.1 KiB
Markdown
# Companion app pairing QR — integration handoff
|
|
|
|
**Status:** web-UI side SHIPPED (CompanionIntroOverlay.vue, 2026-07-16). This doc is
|
|
the contract + requirements for the companion-app side (worked on separately, on
|
|
the Mac).
|
|
|
|
## What the web UI now does
|
|
|
|
The "Remote Companion" intro modal (shown once after first dashboard login, and in
|
|
the public demo) gained a second screen:
|
|
|
|
1. **Screen 1 (existing):** APK download QR (desktop) / download button, plus a new
|
|
**"I've installed it"** button to the right of the download button.
|
|
2. **Screen 2 (new, slide transition):** a **pairing QR** the companion app scans to
|
|
auto-fill the server entry, with a **Back** button returning to screen 1. On
|
|
small screens (where you can't scan your own display) an
|
|
**"Open in companion app"** deep-link button is shown above Back, using the same
|
|
URI as the QR.
|
|
|
|
## The QR payload / deep link (the contract)
|
|
|
|
A single URI, also usable as an OS deep link:
|
|
|
|
```
|
|
archipelago://pair?v=1&url=<percent-encoded server URL>[&pw=<percent-encoded password>]
|
|
```
|
|
|
|
Query parameters:
|
|
|
|
| param | required | meaning |
|
|
|-------|----------|---------|
|
|
| `v` | yes | Payload version, currently `1`. Reject/ignore unknown majors gracefully — show "please update the app". |
|
|
| `url` | yes | Full origin the app should connect to, scheme included: `https://demo.archipelago-foundation.org`, `http://archipelago.local`, `http://192.168.1.228`, etc. No trailing slash guaranteed either way — normalize. |
|
|
| `pw` | no | Login password. **Only present in the public demo** (shared demo password `entertoexit`). Real nodes never embed a password — the frontend doesn't have it. |
|
|
|
|
Examples the web UI actually emits:
|
|
|
|
- Demo: `archipelago://pair?v=1&url=https%3A%2F%2Fdemo.archipelago-foundation.org&pw=entertoexit`
|
|
- Real node, browsed via LAN IP: `archipelago://pair?v=1&url=http%3A%2F%2F192.168.1.228`
|
|
- Real node kiosk (UI runs on localhost, so it advertises the mDNS name from
|
|
`system.get-hostname`): `archipelago://pair?v=1&url=http%3A%2F%2Farchipelago.local`
|
|
|
|
## Companion app requirements
|
|
|
|
1. **Scan entry point:** the app's action is labeled **"Scan Node's QR"**
|
|
(implemented 2026-07-17; the modal copy in CompanionIntroOverlay.vue was
|
|
updated to match).
|
|
2. **Parse the URI** (from camera scan AND from an OS deep-link intent —
|
|
register the `archipelago://` scheme so the "Open in companion app" button on
|
|
phones works).
|
|
3. On success, **create/update a saved server entry**:
|
|
- Server address = `url` exactly as given (respect the scheme — the demo is
|
|
https, LAN nodes are typically http, `.local` mDNS names must work).
|
|
- If `pw` present, prefill the password and attempt auto-login; otherwise land
|
|
on the password prompt for that server.
|
|
- If an entry with the same origin already exists, update it rather than
|
|
duplicating.
|
|
4. **Demo flow (the showcase):** scanning the demo QR should take a fresh install
|
|
to a logged-in demo session in one step — url `https://demo.archipelago-foundation.org`,
|
|
password `entertoexit`, no manual typing.
|
|
5. **Robustness:**
|
|
- Tolerate unknown extra query params (forward compat — we may add `name`,
|
|
`cert` fingerprint, etc. under `v=1`).
|
|
- Self-signed HTTPS on `.local`/LAN addresses may appear later; don't hard-fail
|
|
the parse on scheme.
|
|
- Bad/foreign QR → clear error, stay on the scan screen.
|
|
|
|
## Notes / future extensions (not in v1)
|
|
|
|
- A real-node pairing **token** instead of a password (backend mints a one-time
|
|
token, QR carries it, app exchanges it for a session) — needs a backend RPC;
|
|
the `v` param exists so we can bump when this lands.
|
|
- Optional `name` param (node display name) so the app labels the entry nicely.
|
|
|
|
## Testing checklist (app side)
|
|
|
|
- [ ] Scan demo QR from https://demo.archipelago-foundation.org → auto-connected demo session.
|
|
- [ ] Scan a real node's QR (LAN IP origin) → entry created, password prompt shown.
|
|
- [ ] Scan a kiosk node's QR (`http://<name>.local`) → mDNS resolution works on the phone.
|
|
- [ ] Tap "Open in companion app" on a phone browser → deep link opens the app with the same behavior.
|
|
- [ ] Re-scan same node → no duplicate entry.
|