This repository has been archived on 2026-08-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
DynaLab-V0/docs/architecture.md
T
2026-08-08 22:43:01 +01:00

86 lines
3.6 KiB
Markdown

# DynaLab Architecture and Naming
## Goals
DynaLab accepts live data from multiple connector implementations and presents it in a
desktop UI. The architecture keeps transport code, application state, and Dear PyGui
code independent so that adding a connector or UI feature does not require edits across
unrelated modules.
## Data Flow
```text
connector session -> ConnectorEvent queue -> UI feature controller -> feature state -> view
```
The connector thread owns sockets, handshakes, and heartbeat bookkeeping. It communicates
with the main thread only through immutable events. The main thread owns application state
and all Dear PyGui calls.
## Package Layout
```text
src/dynalab/
app.py composition, lifecycle, frame loop, shutdown
state.py focused application, signal, and recording state
connectors/
events.py typed connector-to-application events
protocol_server.py asyncio server and connector sessions
ui/
shell.py top-level window, menus, and feature navigation
loading/ loading view and tags
errors/ error modal view and tags
live_data/ gauge view, event controller, and tags
recording/ recording view, controller, presenter, and tags
```
Feature folders own their widgets, tags, callbacks, and model-to-widget synchronization.
Avoid global tag collections and modules named after generic implementation techniques,
such as `windows`, `routines`, or `render`.
## Naming
- `build_*` creates widgets once.
- `refresh_*` synchronizes existing widgets from state.
- `on_*` is a thin Dear PyGui callback.
- `handle_*` processes an application event or user intent.
- `start_*` and `stop_*` control service lifecycle.
- `load_*` and `save_*` access persistent storage.
- `*_tag` functions generate dynamic Dear PyGui identifiers.
- `*State` holds mutable state owned by the main thread.
- `*Event` is immutable communication across a boundary.
Tags are feature-qualified strings, for example `recording.dialog` and
`live_data.gauge.<uuid>`. Display labels are never parsed to recover domain identifiers;
features maintain explicit label-to-ID mappings.
## Ownership Rules
- Only the connector thread accesses streams, sessions, and heartbeat timestamps.
- Only the main thread mutates `ApplicationState` and calls Dear PyGui.
- `app.py` composes services and dispatches events; it does not build feature widgets.
- Controllers translate intent or events into state changes and view operations.
- Views construct widgets and contain no connector logic.
- Presenters format state for existing widgets and contain no networking logic.
## Adding a Connector
A connector adapts its transport into the event types in `connectors/events.py`. It must
not mutate application state or invoke Dear PyGui. Connector-specific handshake and
framing stay within its own server/session implementation.
## Adding a UI Feature
Create a folder under `ui/` containing only the pieces the feature needs. A typical
feature has `view.py`, `controller.py`, `presenter.py`, and `tags.py`; small features may
use fewer files. Register its top-level view in `ui/shell.py` and dispatch relevant events
from the application loop.
## Testing Boundaries
- Test event and state behavior without importing Dear PyGui.
- Test controllers with a stubbed gauge or Dear PyGui adapter.
- Test connector sessions with local asyncio streams or protocol fakes.
- Keep manual connector simulators under `test/` or move them to `tools/` when the
automated integration suite is introduced.