# 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.`. 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.