66 lines
2.9 KiB
Markdown
66 lines
2.9 KiB
Markdown
# Backend Contract Proposal — Device Connections feed (W-devices)
|
|
|
|
Status: **Partially implemented.** The website now shows the device/connection data it can
|
|
truthfully obtain today. A richer "connected devices" view (platform, app version, last-seen,
|
|
accessory pairing) needs a backend feed that does not exist yet.
|
|
|
|
## What shipped on the website (no backend change)
|
|
|
|
The account page "App Connections & Sync" block previously hardcoded a connected iOS app
|
|
("iPhone 16 Pro", "v4.1.0", "14m ago") and a paired "Cardo Packtalk Edge". These were
|
|
fabricated. They are now replaced with truthful, real-data states:
|
|
|
|
- **Google account** — reflects the signed-in Firebase user (real).
|
|
- **Authenticated devices** — count comes from the real `/api/account/sessions` feed
|
|
(proxied to `${MOTORSIGNAL_API_BASE_URL}/api/v1/auth/sessions`), already rendered in
|
|
detail in the Active Device Sessions panel.
|
|
- **Helmet comms & accessories** — "Unavailable on web": a browser cannot observe Bluetooth
|
|
pairing. Managed in the mobile app.
|
|
- **Apple Watch** — "Unavailable on web" (unchanged, already truthful).
|
|
|
|
## Why the full feature needs a backend
|
|
|
|
A browser cannot see a rider's paired Bluetooth hardware, installed mobile app build, or
|
|
device platform. Those facts live on the device and in MotorSignal's backend. The auth
|
|
sessions feed is close but does not classify platform / app version / accessory pairing.
|
|
|
|
Delivering a true "connected devices" panel therefore requires a backend endpoint (FastAPI;
|
|
out of scope for the website task and must be authorized separately).
|
|
|
|
## Proposed contract
|
|
|
|
Endpoint: `GET ${MOTORSIGNAL_API_BASE_URL}/api/v1/account/connections`
|
|
Auth: Bearer access token (same as the sessions endpoint).
|
|
|
|
```jsonc
|
|
{
|
|
"devices": [
|
|
{
|
|
"id": "string",
|
|
"kind": "mobile_app | web_session | accessory",
|
|
"platform": "ios | android | web | null",
|
|
"label": "iPhone 16 Pro", // human-friendly, backend-provided
|
|
"appVersion": "4.1.0 | null",
|
|
"lastSeenAt": "ISO-8601 | null",
|
|
"pairingStatus": "paired | disconnected | null", // accessories only
|
|
"current": false
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Rules:
|
|
- The backend is the only source of platform / app version / accessory pairing. The web
|
|
client must render exactly what it returns and must never infer or fabricate these.
|
|
- Absent/empty feed → truthful empty state ("No linked devices"), never sample data.
|
|
- Accessory (Cardo/Sena/GoPro/Apple Watch) rows appear only if the backend reports them;
|
|
otherwise the web continues to show "Unavailable on web".
|
|
|
|
## Website wiring once the endpoint exists
|
|
|
|
1. Add `fetchConnections()` to a lib module, proxied like `/api/account/sessions`.
|
|
2. Replace the current heuristic "Authenticated devices" row with the real feed, grouping by
|
|
`kind`, showing `label`, `appVersion`, and relative `lastSeenAt`.
|
|
3. Add tests for: real feed rendering, empty feed → empty state, and no fabrication when the
|
|
endpoint is unavailable.
|