Architecture#
Self Hosted
BrewGraph is a multi-service application. A core set of three services handles all data storage and serves the API and web UI. Optional sidecar services extend the platform with BLE ingestion, mDNS discovery, and device log collection.
Service topology#
Physical Devices (BLE / mDNS / HTTP)
│
┌────────┴──────────────────┐
│ brewgraph_ble (optional) │
│ brewgraph_mdns (optional) │──→ brewgraph_api ←── brewgraph_web :80
│ brewgraph_log (optional) │ │
└───────────────────────────┘ brewgraph_db (PostgreSQL 17)
brewgraph_redis (Redis 7)
Core services#
brewgraph_api
The FastAPI backend. All business logic, database access, and external integrations live here. Clients — the web UI, the mDNS/BLE sidecars, and devices — reach it through the web server’s reverse proxy.
Internally structured as:
Layer |
Role |
|---|---|
|
SQLAlchemy ORM abstract base classes and model registry. |
|
Concrete SQLAlchemy ORM table definitions. No business logic. |
|
Pydantic v2 camelCase and pagination base classes. |
|
Concrete request and response shapes for each domain entity. |
|
All business logic. Extend |
|
Thin FastAPI endpoint functions. Delegate to services. |
|
APScheduler background jobs: fermentation predictions, gravity forwarding. |
|
Machine learning model for fermentation completion prediction. |
|
API key authentication dependency. |
brewgraph_db
PostgreSQL 17 for production deployments. SQLite is used in development (set
DATABASE_URL=sqlite:///./brewgraph.sqlite). Schema is managed via Alembic migrations.
brewgraph_redis
Redis 7 used for response caching and ephemeral state shared between the API and sidecars.
The API stores the latest per-device readings under ble_<id>_* keys with a 6-hour TTL.
Sidecar services#
brewgraph_ble (Linux only)
Scans for Bluetooth Low Energy advertisements from brewing sensors. Parses manufacturer
data using binary specs (Construct library) and POSTs readings to the API ingest endpoint.
Requires network_mode: host, NET_ADMIN and NET_RAW capabilities, and the
BlueZ D-Bus socket mounted at /var/run/dbus.
Supported BLE devices: Tilt, GravityMon, and PressureMon. A RAPT Pill is supported through an iSpindel-compatible bridge such as SPINDELMATE.
brewgraph_mdns
Listens for Bonjour/mDNS service announcements on the local network using Zeroconf and
exposes discovered devices through GET /api/devices/mdns for the operator
to review and register in the Devices view.
Scanned service types:
_pressuremon._tcp.local.
_gravitymon._tcp.local.
_gravitymon-gateway._tcp.local.
_kegmon._tcp.local.
Requires network_mode: host for LAN multicast access.
brewgraph_log
Fetches the device list from the API, then opens a WebSocket connection to each device’s
serial endpoint (ws://<device_url>/serialws) and writes incoming lines to rotating log
files in the brewgraph_logs shared volume.
Authentication#
All service-to-service calls and all client requests to the API use Bearer token authentication:
Authorization: Bearer <API_KEY>
Authentication can be disabled for local development by setting API_KEY_ENABLED=false.
Technology stack#
Layer |
Technology |
|---|---|
Frontend |
Vue 3.5, Vite 7, Pinia 3, Vue Router 4, Bootstrap 5, Chart.js 4 |
API |
FastAPI, SQLAlchemy, Pydantic v2, APScheduler |
Database |
PostgreSQL 17 (production), SQLite (development) |
Cache |
Redis 7 |
BLE ingestion |
Python / Bleak 0.21 / Construct |
Device discovery |
Python / Zeroconf 0.148 |
Log collection |
Python / Websockets 16 |
Web server |
Nginx Alpine |
Containers |
Docker Compose |
Testing |
Pytest (Python), Vitest (JavaScript) |