Skip to content

Architecture 05 Building Blocks

github-actions[bot] edited this page Oct 15, 2026 · 17 revisions

5. Building blocks

Container view (C4 level 2)

flowchart TB
    subgraph clients["Clients"]
        app["Web app (PWA)"]
        hacs["HACS integration"]
        bridge["ESP32 bridge"]
    end

    gw["Gateway (Traefik)"]

    subgraph services["Services"]
        identity["Identity"]
        fleet["Fleet"]
        dgw["Device-Gateway"]
        telemetry["Telemetry"]
        realtime["Realtime"]
        scheduler["Scheduler"]
        planner["Planner"]
        notif["Notifications"]
        entitle["Entitlements"]
        billing["Billing (optional)"]
        vision["Vision (AI assist)"]
    end

    nats[("NATS JetStream")]
    fga["OpenFGA"]
    pg[("PostgreSQL: one database per service")]

    app --> gw
    hacs --> gw
    bridge --> gw
    gw --> identity
    gw --> fleet
    gw --> realtime
    gw --> dgw
    gw --> telemetry
    gw --> notif
    gw --> entitle
    gw --> planner
    identity --> fga
    entitle --> fga
    planner --> fga
    fleet --> fga
    notif --> fga
    fga --> pg
    identity --> pg
    fleet --> pg
    telemetry --> pg
    scheduler --> pg
    notif --> pg
    entitle --> pg
    planner --> pg
    billing --> pg
    vision --> pg
    fleet <--> nats
    dgw <--> nats
    telemetry <--> nats
    realtime <--> nats
    scheduler <--> nats
    notif <--> nats
    billing <--> nats
    planner <--> nats
    vision <--> nats
    entitle <--> nats
    planner <--> nats
Loading

Only the Device-Gateway talks to mowers. App, Home Assistant and bridges are equal clients. A later Vision service adds camera and Ai Recover.

Services

Service Responsibility Own data Scales with Reusable
Gateway single entry: TLS, routing, rate limits, token check none requests standard software (Traefik)
Identity accounts, users, sub-users, roles and permissions, login plug-ins, API tokens, issuing short-lived tokens users, sessions, identities logins yes, for any project with login
Authz (OpenFGA) answers every permission question from model and relations relations (who, role, level) check requests standard software
Fleet (available, Phase 1) mowers, sites, groups, connection type, command records, bulk commands (shares are role assignments in Identity) sites, groups, mowers, commands requests no
Device-Gateway (available: simulated mowers, Mammotion cloud and BLE bridge adapters) holds connections to mowers and bridges, executes commands, reports state transient only connected mowers (sharding by mower ID) yes, core as library mowdeck-control
Telemetry (available, Phase 1) stores and queries latest state, de-duplicated history, positions with RTK fix, command result timeline latest state, history, position track, command timeline, mower directory data volume no
Scheduler schedules, rain pause, maintenance reminders plans number of plans no
Planner (available, Phase 5) mowing patterns as plug-ins (mowdeck-patterns), route calculation, validation chain, preview, coverage and gaps from the position track, execution mode per mower (ADR 0030) pattern templates and a snapshot directory of maps and capabilities; plans are never stored CPU load yes, as library mowdeck-patterns
Notifications (available, Phase 2) derives notifications (finished, stuck, battery low, offline) from the mower states, delivers by Web Push, ntfy and other channel plug-ins per user preferences preferences, push subscriptions, ntfy targets, inbox, delivery outbox, mower directory and watch messages yes
Realtime WebSocket fan-out of live data to app and Home Assistant none open connections yes
Entitlements (available, Phase 4) answers "may account X use feature Y, or have one more Z?" over entitlements.check; plans as data, assignments, the feature catalogue of the module descriptors, operator endpoints (ADR 0028) plans, account plans and their history, feature catalogue requests (snapshot cached per account in every client) no
Billing (available, optional, Phase 4) subscriptions through a payment provider (Stripe Checkout and customer portal), signed webhooks processed once that set plan statuses in Entitlements over entitlements.plan.set; not started when billing is disabled (ADR 0031) customers, subscriptions, invoice references, webhook ledger webhooks no
Vision (available, Phase 6) AI assist for stuck mowers and Find Dock: camera snapshot and map context to a vision model (any family through LiteLLM, per-user providers, an optional installation model), a proposed maneuver a user with can_drive approves, driven through fleet.drive.* with blades off and a safety watch (ADR 0033) proposals, step audit, short-lived images, cost accounting, encrypted user provider keys running executions yes
Web app (PWA, available, Phase 2) UI for users and operators: SvelteKit 2 SPA served by the web service at / (ADR 0020) none static, CDN capable no
ESP32 bridge firmware on the mower, Bluetooth to WLAN none none yes
HACS integration (available, Phase 3; own repository lukislp/mowdeck-hacs) Home Assistant as client: custom integration mowdeck with config flow (URL and API token), lawn mower, sensors, numbers, select, buttons, GPS tracker and actions, live states over the Realtime WebSocket (ADR 0025, guide) none none no

Libraries (libs/, Apache-2.0 unless stated)

Library Purpose Status
mowdeck-control mower control without the platform (scripts, other projects): MowerConnection, safety controller, simulated mower available (0.1.0)
mowdeck-control-mammotion (GPL-3.0, ADR 0011) the real Mammotion adapter on PyMammotion: cloud and ble_bridge connections (ADR 0019) available (0.1.0), hardware run pending
mowdeck-contracts all API and event formats available (0.1.0)
mowdeck-auth verify access tokens against Identity's cached JWKS (EdDSA), the kit's principal resolver, token issuing and test helpers (ADR 0015) available (0.1.0)
mowdeck-authz thin OpenFGA client: one question, fail closed, decision cache, tuple writer, in-memory fake on the real model, FastAPI dependencies (ADR 0014) available (0.1.0)
mowdeck-service-kit service skeleton: config, logging, tracing, health, bus, tenant filter, error format, the Entitlements client (require_limit, require_feature, snapshot cache, problem types plan-limit and feature-not-in-plan) available (0.1.0)
mowdeck-ui design system of the web app (pnpm package @mowdeck/ui): design tokens with light and dark themes, Svelte 5 components (status, mower card, command bar with the emergency stop, permission gate, forms, layout), token lint rules and contrast check; the map component follows in Task 11 available (0.1.0)
mowdeck-patterns mowing patterns as plug-ins (entry point group mowdeck.patterns), the validation chain, chains, coverage and gaps, preview; pure computation on Shapely (ADR 0030) available (0.1.0)

Details and examples: shared libraries.

Service status

Service Status Where
Device-Gateway available (0.1.0): simulated mowers, Mammotion cloud and ble_bridge adapters (ADR 0019), commands, telemetry, connection events, map and capabilities snapshots, sharding (ADR 0013) services/device-gateway
Identity available (0.1.0): registration, password login, sessions with rotation (cookie-only refresh and reuse grace for browsers), sub-users, roles and assignments with anti-escalation, API tokens, audit log, JWKS and key rotation, OpenFGA tuples, the ui_areas of the deployed modules (ADR 0015) services/identity
Fleet available (0.1.0): sites with a hidden default site, groups, mowers, hierarchy tuples in OpenFGA, the Device-Gateway's registry (fleet.mowers.list, mower.* events), commands checked per command kind with command records, bulk commands per site and group (ADR 0016), plan limits on mowers, sites and groups and the control feature on every command but the emergency stop (ADR 0028) services/fleet
Telemetry available (0.1.0): latest state, history with de-duplicated heartbeats and date_bin downsampling, position track, command timeline, map and capabilities snapshots, mower directory from Fleet, retention under an advisory lock (ADR 0017) services/telemetry
Realtime available (0.1.0): WebSocket /api/v1/realtime/ws with the token in the first message, can_view per subscription re-checked on identity.grants.changed, every 60 s and on token refresh, per-instance fan-out without queue groups, coalesced states and slow consumer close (4430), connection limits (ADR 0018) services/realtime
Notifications available (0.1.0): rules over MowerState and connection events (mowing finished, stuck, battery low with hysteresis, offline and online, job started), cooldown and de-duplication, subscribers re-checked with can_view, quiet hours per time zone, DE and EN templates, outbox worker with SKIP LOCKED and backoff, Web Push (VAPID) and ntfy channels, inbox (ADR 0022) services/notifications
Web app available (0.1.0): login with cookie-only refresh (ADR 0021), mower list and detail with live status, commands with the emergency stop, blade height and speed, area picker on a schematic map, mower settings, sub-users, API tokens, account (theme, language, install), German and English, service worker (ADR 0020) apps/web, served by the Compose service web
Scheduler available (0.1.0): weekly and every-N-days schedules for a mower or a group in the site's time zone (DST safe), windows, manual skip, pattern rotation, rain pause with Open-Meteo behind a weather port, ticker with SKIP LOCKED, starts and returns to the dock through Fleet's fleet.commands.issue on behalf of the owner with a re-check of can_control, run records and events (ADR 0024) services/scheduler
Entitlements available (0.1.0): plans seeded from infra/entitlements/plans.yaml, MOWDECK_ENTITLEMENTS_BILLING_ENABLED (off: every account unlimited), trial and grace computed from the clock, entitlements.check with snapshot, entitlements.plan.changed, feature catalogue from the module descriptors, operator endpoints on platform:main#can_manage_plans; enforced by Fleet, Scheduler, Identity, Realtime and Notifications (ADR 0028) services/entitlements
Planner available (0.1.0): patterns from the registry with their settings schemas, previews and plans for a mower or a raw map (map area, spot in local metres or WGS84), the validation chain on every plan, SpotMowPlan with hash for StartMow.spot_plan, execution mode (custom_paths, native, unsupported), coverage and gaps from Telemetry's track (tracks.positions.query), templates per account, plan feature spot_mowing (ADR 0030) services/planner
Billing available (0.1.0), optional (Compose profile billing, Helm services.billing.enabled): PaymentProvider with StripeProvider (SDK 16, api_base for stripe-mock) and FakeProvider, one customer per account, Checkout in subscription mode with trial, tax id and automatic_tax, the customer portal, prices from infra/billing/prices.yaml, webhooks with signature check and the webhook_events ledger, Stripe status to plan status (grace from the end of the last paid period), billing.subscription.changed, owner only (can_manage_billing) (ADR 0031) services/billing
Vision available (0.1.0): VisionProvider port with a LiteLLM adapter (model string, JSON schema or prompt mode, validation retry, cost accounting) and a rule based fake, per-user providers with AES-GCM keys and an installation default (ai_recover, ai_recover_hosted), proposals with approval, execution through the drive channel at 5 Hz (ttl_ms 1000, blades off) with abort on emergency stop, sensor stop, geofence, missing state and cancellation, verification, rounds, find_dock ending in return_to_dock, vision.proposal.created (ADR 0033) services/vision

Extension points

Extension point Interface Examples
Mower models and links MowerConnection in mowdeck-control, registered through the entry point group mowdeck.connections LUBA and YUKA via Mammotion cloud and ESPHome BLE bridge (mowdeck-control-mammotion), WLAN later
Login methods CredentialAuthenticator, RedirectAuthenticator password, GitHub, Google, passkey, OIDC
Authorization Authorizer in mowdeck-authz extend the OpenFGA model with new object types
Payment providers PaymentProvider Stripe, Paddle, invoice
Notification channels NotificationChannel in services/notifications, registered through the entry point group mowdeck.notification_channels Web Push, ntfy, log (shipped); e-mail, Telegram (interfaces)
Weather, maps, AI one adapter port each Open-Meteo, vision models
Mowing patterns MowPattern in mowdeck-patterns, registered through the entry point group mowdeck.patterns stripes, diagonal, checkerboard, spiral, border first + fill, contour-parallel, auto-aligned, cells, alternating, edge only, re-mow (shipped); waves, lawn art (later)
New feature new service listening to existing events reports, maintenance planner
New UI area built-in module in the app shell (apps/web/src/lib/modules/<name>/module.ts: route, menu label, required permission), enabled when a deployed service announces the route in its ui_areas fleet map, operator console

Each service describes itself (rights it defines, plan features, events, UI areas). Identity, Entitlements and the app read these descriptions at startup, so a new service appears in role and plan management automatically.


Mirrored from docs/architecture/05-building-blocks.md at commit 6a87264c6123f07c8474e153053525dc1816feb7. Edit the file in the repository, not this wiki page.

MowDeck documentation

Clone this wiki locally