# aquapoly/aquadash architecture

> Architecture diagram of the GitHub repository aquapoly/aquadash, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-11-10). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/aquapoly/aquadash
- Repository: https://github.com/aquapoly/aquadash

## Overview

AquaDash is a hydroponics monitoring and control application with a web dashboard, API-backed sensor and actuator management, and a camera/timelapse feature. The primary workflow is dashboard user → frontend page → backend API → domain/data operations, with camera requests routed to a separate camera client. The README also describes real-time monitoring, actuator scheduling, charts, and controls; some frontend and sensor-device wiring is unsampled, so those links are omitted or marked unverified.

Main entry points: [`backend/app/main.py`](https://github.com/aquapoly/aquadash/blob/main/backend/app/main.py) (HTTP API), [`backend/app/crud.py`](https://github.com/aquapoly/aquadash/blob/main/backend/app/crud.py) (Domain operations), [`frontend/src/app`](https://github.com/aquapoly/aquadash/tree/main/frontend/src/app) (Angular app), [`backend/app/services/cam_client.py`](https://github.com/aquapoly/aquadash/blob/main/backend/app/services/cam_client.py) (Camera API client)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_web["Web dashboard"]
  node_frontend["Angular app"]
  node_status["Status dashboard"]
  node_configuration["Configuration page"]
  node_timelapse_ui["Timelapse pages"]
end

subgraph group_api["Backend API"]
  node_api_service["HTTP API<br/>[main.py]"]
  node_crud["Domain operations<br/>[crud.py]"]
  node_models["Domain models<br/>[models.py]"]
  node_schemas["API schemas<br/>[schemas.py]"]
  node_database[("SQL database<br/>[database.py]")]
  node_actuator_service["Actuator control<br/>[actuator.py]"]
  node_authentication["Authentication"]
  node_permissions["Permissions<br/>[permissions.py]"]
  node_export["Measurement export<br/>[export_data.py]"]
  node_ws_manager["WebSocket manager<br/>[ws_manager.py]"]
end

subgraph group_camera["Camera and timelapse"]
  node_cam_service["Camera API client<br/>[cam_client.py]"]
  node_cam_events["Camera event listener"]
  node_camera_http["Camera client service<br/>[main.py]"]
  node_timelapse["Timelapse manager"]
  node_camera_client["Camera socket client<br/>[camera_client.py]"]
  node_timelapse_store["Timelapse files"]
  node_camera_daemon["Camera host daemon<br/>[camera_daemon.py]"]
  node_physical_camera["Physical camera<br/>[physical_camera.py]"]
  node_logical_camera["Logical camera<br/>[logical_camera.py]"]
  node_timelapse_models["Timelapse contracts"]
end

subgraph group_sensors["Sensor devices"]
  node_sensor_hardware["Sensor interfaces<br/>[AtlasI2C.py]"]
  node_sensor_actuation["Sensor actuator service<br/>[actuator.py]"]
  node_sensor_constants["Sensor constants<br/>[constants.py]"]
end

node_user(("Dashboard user"))
node_external_camera["Camera service"]
node_hardware["Hydroponic sensors"]

node_user -->|"uses"| node_frontend
node_frontend -->|"routes to"| node_status
node_frontend -->|"routes to"| node_configuration
node_frontend -->|"routes to"| node_timelapse_ui
node_api_service -->|"calls"| node_crud
node_api_service -->|"uses"| node_database
node_crud -->|"queries"| node_models
node_crud -->|"uses"| node_schemas
node_api_service -->|"uses"| node_actuator_service
node_crud -->|"uses"| node_authentication
node_crud -->|"uses"| node_permissions
node_api_service -->|"calls"| node_export
node_api_service -->|"calls"| node_cam_service
node_api_service -->|"uses"| node_ws_manager
node_cam_service -->|"HTTP requests"| node_external_camera
node_camera_http -->|"uses"| node_camera_client
node_camera_http -->|"uses"| node_timelapse
node_timelapse -->|"captures frames"| node_camera_client
node_timelapse -->|"reads and writes"| node_timelapse_store
node_camera_daemon -->|"dispatches to"| node_physical_camera
node_camera_daemon -->|"dispatches to"| node_logical_camera
node_cam_events -->|"uses"| node_cam_service
node_cam_events -->|"broadcasts through"| node_ws_manager
node_sensor_actuation -->|"uses"| node_sensor_constants
node_sensor_hardware -.->|"interfaces with"| node_hardware
node_status -.->|"requests data"| node_api_service
node_configuration -.->|"submits settings"| node_api_service
node_api_service -->|"uses contracts"| node_timelapse_models
node_cam_service -->|"uses contracts"| node_timelapse_models

click node_frontend "https://github.com/aquapoly/aquadash/tree/main/frontend/src/app"
click node_status "https://github.com/aquapoly/aquadash/blob/main/frontend/src/app/pages/status-page/status-page.component.ts"
click node_configuration "https://github.com/aquapoly/aquadash/blob/main/frontend/src/app/pages/configuration-page/configuration-page.component.ts"
click node_timelapse_ui "https://github.com/aquapoly/aquadash/blob/main/frontend/src/app/pages/timelapse-page/timelapse-page.component.ts"
click node_api_service "https://github.com/aquapoly/aquadash/blob/main/backend/app/main.py"
click node_crud "https://github.com/aquapoly/aquadash/blob/main/backend/app/crud.py"
click node_models "https://github.com/aquapoly/aquadash/blob/main/backend/app/models.py"
click node_schemas "https://github.com/aquapoly/aquadash/blob/main/backend/app/schemas.py"
click node_database "https://github.com/aquapoly/aquadash/blob/main/backend/app/database.py"
click node_actuator_service "https://github.com/aquapoly/aquadash/blob/main/backend/app/services/actuator.py"
click node_authentication "https://github.com/aquapoly/aquadash/blob/main/backend/app/security/authentification.py"
click node_permissions "https://github.com/aquapoly/aquadash/blob/main/backend/app/security/permissions.py"
click node_export "https://github.com/aquapoly/aquadash/blob/main/backend/app/services/export_data.py"
click node_ws_manager "https://github.com/aquapoly/aquadash/blob/main/backend/app/ws_manager.py"
click node_cam_service "https://github.com/aquapoly/aquadash/blob/main/backend/app/services/cam_client.py"
click node_cam_events "https://github.com/aquapoly/aquadash/blob/main/backend/app/services/cam_event_listener.py"
click node_camera_http "https://github.com/aquapoly/aquadash/blob/main/backend/devices/camera/client/main.py"
click node_timelapse "https://github.com/aquapoly/aquadash/blob/main/backend/devices/camera/client/timelapse_client.py"
click node_camera_client "https://github.com/aquapoly/aquadash/blob/main/backend/devices/camera/client/camera_client.py"
click node_timelapse_store "https://github.com/aquapoly/aquadash/blob/main/backend/devices/camera/client/timelapse_client.py"
click node_camera_daemon "https://github.com/aquapoly/aquadash/blob/main/backend/devices/camera/host/camera_daemon.py"
click node_physical_camera "https://github.com/aquapoly/aquadash/blob/main/backend/devices/camera/host/physical_camera.py"
click node_logical_camera "https://github.com/aquapoly/aquadash/blob/main/backend/devices/camera/host/logical_camera.py"
click node_timelapse_models "https://github.com/aquapoly/aquadash/blob/main/backend/shared/timelapse_models.py"
click node_sensor_hardware "https://github.com/aquapoly/aquadash/blob/main/Sensors/services/AtlasI2C.py"
click node_sensor_actuation "https://github.com/aquapoly/aquadash/blob/main/Sensors/services/actuator.py"
click node_sensor_constants "https://github.com/aquapoly/aquadash/blob/main/Sensors/services/constants.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_frontend,node_status,node_configuration,node_timelapse_ui,node_user toneBlue
class node_api_service,node_crud,node_models,node_schemas,node_database,node_actuator_service,node_authentication,node_permissions,node_export,node_ws_manager toneAmber
class node_cam_service,node_cam_events,node_camera_http,node_timelapse,node_camera_client,node_timelapse_store,node_camera_daemon,node_physical_camera,node_logical_camera,node_timelapse_models toneMint
class node_sensor_hardware,node_sensor_actuation,node_sensor_constants toneRose
class node_external_camera,node_hardware toneIndigo
```

## Components

### Web dashboard

- [Angular app](https://github.com/aquapoly/aquadash/tree/main/frontend/src/app): `frontend/src/app`
- [Status dashboard](https://github.com/aquapoly/aquadash/blob/main/frontend/src/app/pages/status-page/status-page.component.ts): `frontend/src/app/pages/status-page/status-page.component.ts`
- [Configuration page](https://github.com/aquapoly/aquadash/blob/main/frontend/src/app/pages/configuration-page/configuration-page.component.ts): `frontend/src/app/pages/configuration-page/configuration-page.component.ts`
- [Timelapse pages](https://github.com/aquapoly/aquadash/blob/main/frontend/src/app/pages/timelapse-page/timelapse-page.component.ts): `frontend/src/app/pages/timelapse-page/timelapse-page.component.ts`

### Backend API

- [HTTP API](https://github.com/aquapoly/aquadash/blob/main/backend/app/main.py): `backend/app/main.py`
- [Domain operations](https://github.com/aquapoly/aquadash/blob/main/backend/app/crud.py): `backend/app/crud.py`
- [Domain models](https://github.com/aquapoly/aquadash/blob/main/backend/app/models.py): `backend/app/models.py`
- [API schemas](https://github.com/aquapoly/aquadash/blob/main/backend/app/schemas.py): `backend/app/schemas.py`
- [SQL database](https://github.com/aquapoly/aquadash/blob/main/backend/app/database.py): `backend/app/database.py`
- [Actuator control](https://github.com/aquapoly/aquadash/blob/main/backend/app/services/actuator.py): `backend/app/services/actuator.py`
- [Authentication](https://github.com/aquapoly/aquadash/blob/main/backend/app/security/authentification.py): `backend/app/security/authentification.py`
- [Permissions](https://github.com/aquapoly/aquadash/blob/main/backend/app/security/permissions.py): `backend/app/security/permissions.py`
- [Measurement export](https://github.com/aquapoly/aquadash/blob/main/backend/app/services/export_data.py): `backend/app/services/export_data.py`
- [WebSocket manager](https://github.com/aquapoly/aquadash/blob/main/backend/app/ws_manager.py): `backend/app/ws_manager.py`

### Camera and timelapse

- [Camera API client](https://github.com/aquapoly/aquadash/blob/main/backend/app/services/cam_client.py): `backend/app/services/cam_client.py`
- [Camera event listener](https://github.com/aquapoly/aquadash/blob/main/backend/app/services/cam_event_listener.py): `backend/app/services/cam_event_listener.py`
- [Camera client service](https://github.com/aquapoly/aquadash/blob/main/backend/devices/camera/client/main.py): `backend/devices/camera/client/main.py`
- [Timelapse manager](https://github.com/aquapoly/aquadash/blob/main/backend/devices/camera/client/timelapse_client.py): `backend/devices/camera/client/timelapse_client.py`
- [Camera socket client](https://github.com/aquapoly/aquadash/blob/main/backend/devices/camera/client/camera_client.py): `backend/devices/camera/client/camera_client.py`
- [Timelapse files](https://github.com/aquapoly/aquadash/blob/main/backend/devices/camera/client/timelapse_client.py): `backend/devices/camera/client/timelapse_client.py`
- [Camera host daemon](https://github.com/aquapoly/aquadash/blob/main/backend/devices/camera/host/camera_daemon.py): `backend/devices/camera/host/camera_daemon.py`
- [Physical camera](https://github.com/aquapoly/aquadash/blob/main/backend/devices/camera/host/physical_camera.py): `backend/devices/camera/host/physical_camera.py`
- [Logical camera](https://github.com/aquapoly/aquadash/blob/main/backend/devices/camera/host/logical_camera.py): `backend/devices/camera/host/logical_camera.py`
- [Timelapse contracts](https://github.com/aquapoly/aquadash/blob/main/backend/shared/timelapse_models.py): `backend/shared/timelapse_models.py`

### Sensor devices

- [Sensor interfaces](https://github.com/aquapoly/aquadash/blob/main/Sensors/services/AtlasI2C.py): `Sensors/services/AtlasI2C.py`
- [Sensor actuator service](https://github.com/aquapoly/aquadash/blob/main/Sensors/services/actuator.py): `Sensors/services/actuator.py`
- [Sensor constants](https://github.com/aquapoly/aquadash/blob/main/Sensors/services/constants.py): `Sensors/services/constants.py`

### Other components

- **Dashboard user**
- **Camera service**
- **Hydroponic sensors**

## Connections

- Dashboard user → Angular app: uses
- Angular app → Status dashboard: routes to (evidence: `frontend/src/app/app.routes.ts`)
- Angular app → Configuration page: routes to (evidence: `frontend/src/app/app.routes.ts`)
- Angular app → Timelapse pages: routes to (evidence: `frontend/src/app/app.routes.ts`)
- HTTP API → Domain operations: calls (evidence: `backend/app/main.py`)
- HTTP API → SQL database: uses (evidence: `backend/app/main.py`)
- Domain operations → Domain models: queries (evidence: `backend/app/crud.py`)
- Domain operations → API schemas: uses (evidence: `backend/app/crud.py`)
- HTTP API → Actuator control: uses (evidence: `backend/app/main.py`)
- Domain operations → Authentication: uses (evidence: `backend/app/crud.py`)
- Domain operations → Permissions: uses (evidence: `backend/app/crud.py`)
- HTTP API → Measurement export: calls (evidence: `backend/app/main.py`)
- HTTP API → Camera API client: calls (evidence: `backend/app/main.py`)
- HTTP API → WebSocket manager: uses (evidence: `backend/app/main.py`)
- Camera API client → Camera service: HTTP requests (evidence: `backend/app/services/cam_client.py`)
- Camera client service → Camera socket client: uses (evidence: `backend/devices/camera/client/main.py`)
- Camera client service → Timelapse manager: uses (evidence: `backend/devices/camera/client/main.py`)
- Timelapse manager → Camera socket client: captures frames (evidence: `backend/devices/camera/client/timelapse_client.py`)
- Timelapse manager → Timelapse files: reads and writes (evidence: `backend/devices/camera/client/timelapse_client.py`)
- Camera host daemon → Physical camera: dispatches to (evidence: `backend/devices/camera/host/camera_daemon.py`)
- Camera host daemon → Logical camera: dispatches to (evidence: `backend/devices/camera/host/camera_daemon.py`)
- Camera event listener → Camera API client: uses (evidence: `backend/app/services/cam_event_listener.py`)
- Camera event listener → WebSocket manager: broadcasts through (evidence: `backend/app/services/cam_event_listener.py`)
- Sensor actuator service → Sensor constants: uses (evidence: `Sensors/services/actuator.py`)
- Sensor interfaces → Hydroponic sensors: interfaces with
- Status dashboard → HTTP API: requests data
- Configuration page → HTTP API: submits settings
- HTTP API → Timelapse contracts: uses contracts (evidence: `backend/app/main.py`)
- Camera API client → Timelapse contracts: uses contracts (evidence: `backend/app/services/cam_client.py`)
