Skip to content

Architecture

Chris Nighswonger edited this page Apr 2, 2026 · 4 revisions

Architecture

Kanfei uses a two-process backend architecture with a shared SQLite database.

Process Model

  1. Logger daemon (backend/logger_main.py)
  • Owns the hardware connection to the weather station
  • Polls sensor data via the configured StationDriver
  • Writes sensor rows to SQLite
  • Exposes hardware/status commands over TCP IPC
  1. Web app (backend/app/main.py)
  • FastAPI app serving REST API + built frontend
  • Relays live updates to browser clients via WebSocket
  • Uses IPC client to request hardware actions from logger daemon
  • Runs background services (nowcast, APRS-IS map collector, bot supervisors)

Data Flow

  1. The configured StationDriver communicates with the weather station over serial, TCP, HTTP, or UDP depending on hardware type.
  2. Poller receives a SensorSnapshot from the driver, computes derived values (heat index, dew point, wind chill, feels-like, theta-e, pressure trend), and stores them in sensor_readings.
  3. Poller broadcasts sensor_update messages through IPC subscriptions.
  4. Web app WebSocket handler relays IPC messages to /ws/live browser clients.
  5. REST API reads from SQLite for current conditions, history, forecasts, config, and admin features.

Driver Architecture

All hardware drivers implement the StationDriver abstract base class (backend/app/protocol/base.py). Each driver's poll() method returns a SensorSnapshot — a canonical data class with all values in SI units (°C, m/s, hPa, etc.). The driver is responsible for converting from native hardware formats to SI before returning.

Driver Factory

The logger daemon instantiates drivers via a factory function (_create_driver) based on the station_driver_type config key. This allows the rest of the system (poller, IPC, web API, dashboard) to work identically regardless of hardware.

Capabilities

Drivers declare their supported features via a capabilities set. The UI and services check capabilities before offering hardware-specific operations (archive sync, calibration, clock sync, rain reset, etc.). This prevents unsupported actions from being shown or attempted.

IPC Boundary

  • Logger daemon runs an IPC server on configurable port (default 6514).
  • Web app creates an IPC client during lifespan startup.
  • If logger is unavailable, web app remains up in degraded mode.

Database

Primary database: SQLite (WAL mode enabled during initialization).

Key tables include:

  • sensor_readings
  • station_config
  • users, sessions, api_keys (authentication)
  • nowcast history/knowledge/verification tables
  • spray product/schedule/outcome tables
  • archive records

Frontend Architecture

  • React + TypeScript + Vite SPA
  • Route-based pages (Dashboard, History, Forecast, Astronomy, Map, Settings, About, Login)
  • Nowcast, Spray, and Map pages are feature-flag controlled
  • Setup wizard is shown until setup_complete is true (includes admin account creation)
  • AuthContext manages session state; 401 responses redirect to Login
  • Weather data pages are public; Settings and admin actions require login
  • Weather data context consumes REST + WebSocket updates

Security

  • Admin API endpoints require session cookie or API key authentication; public weather data endpoints are unauthenticated. See Security and Networking for details.
  • CORS is restricted to a configurable allowlist (KANFEI_CORS_ORIGINS env var; empty = same-origin only).
  • OpenAPI/Swagger docs are disabled in production (no schema exposure).

Reliability Characteristics

  • Hardware I/O is isolated to one process (logger daemon)
  • Web app can continue serving UI/API even without station connectivity
  • Many services reload config from DB dynamically so settings changes apply without full restart

Clone this wiki locally