Repository navigation
Architecture 04 Solution Strategy
github-actions[bot] edited this page Oct 16, 2026
·
21 revisions
| Goal | Approach |
|---|---|
| Tenant isolation | Account ID only from the verified token; filter in every query; per-service tests that request foreign data; OpenFGA for permission checks. |
| Independent scaling and failure | Small services; synchronous queries via the gateway, everything time-critical and all commands asynchronous over NATS JetStream. No service reads another service's database; only contracts are shared. |
| Same everywhere | Identical container images for Compose and Kubernetes; differences only in configuration and instance count. |
| Safe commands | Commands carry a unique ID (deduplication) and an expiry (stale "start" is dropped); emergency stop has priority; dead-man switch for driving. |
| Extensibility | Fixed extension points (interfaces) and self-describing modules; shared libraries; a service template. Every feature sits behind a feature key. |
| Authentication | Identity issues short-lived signed JWTs (EdDSA); services verify them locally using a JWKS public key, with no per-request call to Identity. |
| Authorization | OpenFGA with a model stored in the repository (ADR 0001). |
| Contracts | OpenAPI for REST, AsyncAPI/JSON Schema for events, in the package mowdeck-contracts. |
| Internal structure | Every service has the same layers: domain, application (use cases), adapters. |
| Observability | OpenTelemetry traces and logs, Prometheus metrics, a correlation ID through all services. |
| Layer | Choice |
|---|---|
| Services | Python 3.13, FastAPI |
| Mower control |
mowdeck-control library (interface, safety controller, simulator, ADR 0012); PyMammotion adapters for BLE bridge and cloud in the GPL-3.0 package mowdeck-control-mammotion
|
| Bridge | ESP32 (for example XIAO ESP32-S3) |
| Gateway | Traefik (ADR 0008) |
| Event bus | NATS JetStream (ADR 0007) |
| Database | PostgreSQL, one database per service, Alembic migrations; optional TimescaleDB (ADR 0006) |
| Authentication | Plug-ins: password (Argon2id), API tokens, OAuth 2/OIDC, later passkeys |
| Service tokens | JWT with EdDSA, public keys via JWKS |
| Authorization | OpenFGA (ADR 0001) |
| Payment | Stripe adapter in Billing, switchable |
| Frontend | SvelteKit PWA, Leaflet with Geoman (ADR 0003) |
| Store app (later) | Capacitor |
| Route planning | Shapely |
| Tooling | uv workspace, Ruff, mypy strict, pytest, MkDocs Material (ADR 0004) |
| Operations | Docker Compose, Helm chart (cloud), images built in CI |
Mirrored from docs/architecture/04-solution-strategy.md at commit a117684672263ba4f0b7e2e3538233456122d24e. Edit the file in the repository, not this wiki page.
Mirrored from the docs/ directory at commit a117684672263ba4f0b7e2e3538233456122d24e. Edit the files in the repository, not this wiki.
MowDeck documentation
- Home
- Phases
- Architecture
-
Decisions (ADR)
- Architecture decisions
- ADR 0001: OpenFGA instead of self-built authorization
- ADR 0002: Self-built Identity service in FastAPI instead of Keycloak or Zitadel
- ADR 0003: SvelteKit for the web app
- ADR 0004: Monorepo with a uv workspace
- ADR 0005: AGPL-3.0 for services and apps, Apache-2.0 for libraries
- ADR 0006: PostgreSQL for all persistence, no SQLite
- ADR 0007: NATS JetStream as event bus
- ADR 0008: Traefik as gateway
- ADR 0009: Command and event envelopes, subject naming and de-duplication
- ADR 0010: Python 3.13 for all services and libraries
- ADR 0011: Separate GPL-3.0 package for the PyMammotion adapter
- ADR 0012: Mower control interface and safety rules
- ADR 0013: Device-Gateway registry, sharding and per-mower concurrency
- ADR 0014: Authorization model, tuple ownership and the mowdeck-authz client
- ADR 0015: Tokens, sessions and key rotation
- ADR 0016: Fleet commands and authorization per command kind
- ADR 0017: Telemetry storage and retention
- ADR 0018: Realtime WebSocket protocol
- ADR 0019: Mammotion adapter transports, manual drive and secrets
- ADR 0020: Web app architecture
- ADR 0021: Browser authentication flow
- ADR 0022: Notifications: rules, recipients and delivery
- ADR 0023: Map rendering and projection
- ADR 0024: Scheduler: recurrence, rain pause and command issuing
- ADR 0025: Home Assistant integration as a pure API client
- ADR 0026: Manual drive channel over the Realtime WebSocket
- ADR 0027: Health history and theft alarm
- ADR 0028: Entitlements: plans as data and enforcement
- ADR 0029: Helm chart and release pipeline
- ADR 0030: Mowing patterns as plug-ins and the Planner
- ADR 0031: Billing with a Stripe adapter
- ADR 0032: Live camera over Agora, joined directly by the browser
- ADR 0033: Vision-assisted recovery with human approval
- ADR 0034: Linked cloud accounts and device discovery
- ADR 0035: Server-side camera frames and automatic AI analysis on errors
- ADR 0036: Native app shells with Capacitor, loading the web app from the server
- ADR 0037: Camera panorama calibration in the browser, with the AI supplying points only
- ADR 0038: Dual link per mower and firmware updates
- ADR 0039: Spot mowing by MowDeck-driven paths
- ADR 0040: Link heartbeat for online status
- ADR 0041: Spot runs from the dock: undock, transit and return
- ADR 0042: Drive calibration
- ADR 0043: Turn styles
- ADR 0044: Drive view with camera
- Development
- Operations
- Spikes
- Guides
- Original plan (German)