Start the design document with the high-level architecture

DESIGN.md: one process with several threads (D16), three layers (D17),
HA-centric object classes (D18), injected configuration (D19). Design
decisions move from REQUIREMENTS.md to DESIGN.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 20:46:23 +02:00
co-authored by Claude Opus 5.5
parent ed8b2237bd
commit f6c5de4fb9
5 changed files with 86 additions and 16 deletions
+63
View File
@@ -0,0 +1,63 @@
# Design
Status: **in progress**, iteration 1, phase 2 (planning and design). High-level architecture
first, then the details for the MVP. Requirements and their decisions (D1–D15):
[REQUIREMENTS.md](REQUIREMENTS.md). Design decisions start at D16.
## Process and threads
- **One process** started by SteamVR does everything: HA connection, sensors, services, all
overlays (D16).
- Several threads inside it for concurrent work. Which work runs in which thread is still open.
## Layers
Three layers; dependencies only go downward (D17).
```
Presentation QML (view and controller)
▼
Business logic entities, services, managers
▼
I/O HA connection (MQTT), SteamVR, system (network, audio)
```
- Qt Quick already enforces separating presentation from logic.
- The overlay platform (`vrdashboard_core`) spans two layers: overlays, rendering and input
are presentation infrastructure; SteamVR access for sensors and actions is I/O.
## Object classes
The app is HA-centric, so its building blocks follow HA's concepts (D18). Objects talk to each
other through Qt signals and slots (Qt's observer pattern). Senders don't know their receivers,
and signals across threads are delivered through the receiver's event loop.
| Class | Role | MVP |
|---|---|---|
| **HA entity** | One HA entity, both directions. Entity → HA: state and JSON attributes. HA → entity: basic commands. Observes value signals of other objects and publishes them; turns MQTT commands into signals other objects act on. Covers sensors, simple actions (`button`), settings (`switch`, `number`), feedback (`event`). | ✓ |
| **HA service** | An action HA calls with parameters: a JSON command on an MQTT command topic (HA side: the standard `mqtt.publish` action). May be more complex than an entity command. Results go back asynchronously, e.g. through an `event` entity. How the user wraps it in HA (scripts, automations, pyscript) is their choice; FrameAssistant only requires stock HA with MQTT (NFR-6). | ✓ (notification) |
| **HA device** | Owns the MQTT connection, discovery and availability, and owns all entity and service objects. One per headset (CON-5). | ✓ |
| **I/O wrappers** | Data sources and actuators; know nothing about HA. One wrapper object per OpenVR interface used (e.g. `IVRSystem`, `IVRApplications`, `IVRChaperone`, `IVRSettings`). System wrappers (network, audio) later. | OpenVR ✓, system ✗ |
| **Overlays** | View and controller of MVC (QML), as dashboard tabs or world overlays. Get their data (the model) from other objects. | ✓ |
| **Managers** | One object per stateful feature that manages and coordinates it, using entities, services and overlays. Notification manager (MVP); status card manager (SRV-6/7) later. | notifications ✓ |
| **HA web UI** | Encapsulates Qt WebEngine for the dashboard (Q2). | ✗ |
| **Configuration** | Settings from the JSON file, loaded once by the app as an immutable value. Each component gets the part it needs through its constructor (D19). | ✓ |
| **App** | The managing object: owns all of the above as components and wires them together. | ✓ |
Notes for later:
- OpenVR delivers all events through one queue; one dispatcher (today `VrRuntime`) hands them
to the wrappers.
- OpenVR is not documented as thread-safe (relevant for the thread decision).
## Open
1. High-level points 3–7 (see [PROGRESS.md](PROGRESS.md), "Next steps").
## Decisions
| # | Date | Decision | Reason |
|---|------|----------|--------|
| D16 | 2026-10-05 | **One process** started by SteamVR does everything; several threads inside it for concurrent work | Meets NFR-2 without extra work, no IPC; the platform already supports several surfaces per process |
| D17 | 2026-10-05 | **Three layers:** presentation (QML), business logic, I/O. The overlay platform spans presentation (overlays, rendering, input) and I/O (SteamVR access) | Simple and enough for the start; Qt Quick already enforces separating presentation from logic |
| D18 | 2026-10-05 | **HA-centric object classes:** HA entity, HA service, HA device, I/O wrappers, overlays, managers, HA web UI, configuration, app; communication through signals and slots | The app is HA-centric; signals/slots decouple objects and work across threads |
| D19 | 2026-10-05 | **Configuration is injected:** the app loads it once as an immutable value and passes each component the part it needs; no singleton | Explicit dependencies, trivial tests with own configs, thread-safe; the app creates all components anyway |
+17 -13
View File
@@ -10,21 +10,20 @@ CLAUDE.md ("Working rules").
## Next steps
Phase 2 for the MVP scope (D8: MQTT connection + discovery + availability, the MVP sensors, a
basic notification). Design topics, proposed order:
Phase 2: first the high-level architecture, then the details for the MVP (D8). High-level
questions, in this order:
1. ~~Q4: MQTT client library~~: done, libmosquitto (D14). Remaining for the design: Qt
event-loop integration, shipping the library in the package (build + `install.sh`).
2. Component structure: configuration, MQTT/discovery layer, sensor sources, notification
service; how they fit into `Dashboard` (the app class).
3. HA entity model: topics, discovery payloads, availability, device grouping (CON-2/3/5,
SEN-15).
4. Basic notification (NOT-1): needs an overlay outside the dashboard, i.e. the planned
`WorldOverlay` (CLAUDE.md, "Planned extension"); MVP placement to be decided.
5. Test strategy for the MVP and the measurement method for NFR-3.
1. ~~Process model~~: one process, several threads (D16).
2. ~~Layers~~: presentation, business logic, I/O (D17).
3. How features plug in: object classes (D18) and configuration injection (D19) settled;
open: how the classes are wired.
4. HA channels: MQTT only, or prepare for a second one for the dashboard (Q2/Q3)?
5. Overlay kinds: dashboard tabs and world overlays (platform extension).
6. Runtime model: which work runs in which thread (D16: several threads).
7. Test strategy at a high level.
Later, not needed for the MVP: Q1 (several notifications), Q2/Q3 (dashboard); check only
whether they constrain the MVP architecture.
Details afterwards (MQTT library done: D14, D15): topics and payloads, basic notification,
configuration, packaging of libmosquitto.
## Log
@@ -41,6 +40,11 @@ whether they constrain the MVP architecture.
present (relevant for Q2/Q3).
- libmosquitto ABI check: Debian's 2.0.21 needs at most `OPENSSL_3.0.0`/`GLIBC_2.34`; the
Frame has OpenSSL 3.2.1 and glibc 2.39. No libcjson dependency. D14 holds.
- Started docs/DESIGN.md: one process (D16), three layers (D17), HA-centric object classes
(D18). HA side: FrameAssistant needs only stock HA; how the user wraps commands (scripts,
pyscript) is up to them (NFR-6 unchanged).
- Agreed to settle the high-level architecture first (list under "Next steps"), before
component details.
- Stay with the Debian build container: an Arch container wouldn't match SteamOS's own package
versions (private repos, rolling Arch) and has no arm64 multiarch for cross builds.
+2
View File
@@ -155,6 +155,8 @@ FrameAssistant.
| D14 | 2026-10-05 | MQTT client: **libmosquitto** from Debian's package in the build container, shipped in the release package like `libopenvr_api.so` | Not on the Frame; Qt MQTT would need the exact Qt version (Appendix B) |
| D15 | 2026-10-05 | HA MQTT discovery: **own small layer on Qt's JSON classes**, using device-based discovery (one `<prefix>/device/<id>/config` topic with all entities under `cmps`) | No suitable library (Appendix B); HA recommends device-based discovery for multi-entity devices (NFR-7) |
Design decisions (D16 onward) are in [DESIGN.md](DESIGN.md).
## Appendix A: data sources
What the headset can report, by source. Checked against `openvr.h` (OpenVR 2.15.6). **None of