Skip to content

Architecture

Implemented pipeline

flowchart LR
    Weather[Open-Meteo] --> Refresh[Shared refresh loop]
    SportsA[API-Sports Baseball] --> Refresh
    SportsB[BALLDONTLIE MLB] --> Refresh
    Previous[MLB Stats - earlier release] -. disabled .-> Refresh
    News[NYT / Guardian RSS] --> Refresh
    Refresh --> Compose[Profile feed composition]
    Compose --> Render[SkiaSharp 1280×720 cards]
    Render --> Snapshots[Immutable in-memory snapshots]
    Snapshots --> API[Authenticated ASP.NET Core API]
    API --> Manifest[Versioned dashboard manifest]
    API --> Media[Immutable PNG assets]
    Manifest --> Android[Native Java Android app]
    Media --> Android
    Android --> Clock[Implemented live clock]
    Android --> Cache[Atomic private disk cache]
    Cache --> Slides[Dashboard presentation]
    Android -. future .-> Player[Local music player]
    Player -. future .-> Speaker[Bluetooth speaker]

The dashboard path is deployed on OVH and verified over HTTPS on the XT1058. The current deployment receipt records its immutable identity and five-card public HTTPS acceptance. The API also retains a development synthetic-feed option. The deployed evaluation profile selects two independent baseball sources. The dashed path describes the disabled source from the earlier release, not a third card.

The server owns provider integrations, content selection, time-zone-aware card rendering, and feed snapshots. A single background refresh loop fetches due sources with at most two concurrent requests, then recomposes affected profiles. The phone owns schedule decisions, card rotation, disk caching, offline continuity, clock rendering, and device lifecycle. Provider failures do not erase a still-valid source result; expired content is omitted on recomposition.

Android application

The application uses one native Activity and platform Views. Its dashboard client conditionally fetches schema-versioned manifests and hash-addressed images, validates them, and atomically activates a private disk cache. Clock, dashboard modes, cache, refresh, and presentation behavior live in collaborators around the Activity. Local music playback, playlist indexing, and boot recovery remain future work.

Clock faces, theme scheduling, and clock burn-in behavior are described in the clock overview, rendering algorithms, sound design, clock themes design, and implementation plan.

The app must remain useful when the server or Internet is unavailable. A failed refresh keeps the last verified manifest and content set; authentication failure clears that origin's cached feed.

The same APK targets Android 5.1 and modern Android phones (minSdk 22). A bearer token maps server-side to a device identity and profile; profile names are not credentials. The checked-in API configuration currently defines one bedroom profile with Bogotá weather, Yankees, NYT, and Guardian sources. Profiles and source assignments are configuration-driven, but user enrollment and an administration interface are not implemented. Appliance-only behavior such as forced landscape belongs to the device presentation mode, not a separate APK.

Backend

The API solution contains:

  • MotoXDashboard.Api: endpoints, contracts, and application services;
  • MotoXDashboard.Api.Tests: in-process integration tests.

Implemented boundaries include provider adapters, source refresh policy, profile composition, Skia rendering, device authentication, and an in-memory snapshot store. Snapshots retain a current revision and up to two prior revisions per profile so a device holding an older manifest can still fetch its assets. This is process memory, not durable storage.

The API process and container remain stateless across restarts. Dashboard PNGs are currently held in process memory; they are not served from a filesystem asset directory or Nginx static path. Future photographs and streamed music will need separately backed-up durable storage outside release directories.

Contract direction

GET /api/v1/dashboard is the versioned device contract. Schema 1 bounds the manifest to 64 KiB and eight cards, with 1280×720 PNGs capped at 2 MiB each. Manifests and assets use ETags; asset URLs are content-hash-addressed and immutable. New fields should remain additive and optional until clients understand them.

Future administration

An administration website may later edit content sources, schedules, and presentation preferences. It is a separate client of backend application services, not part of the Moto rendering surface. Authentication and authorization requirements must be designed before that surface is exposed.

See ADR 0002 for the accepted feed, Android compatibility, HTTPS trust, and durable-media decisions.

For dashboard behavior, see Dashboard and Backend. The Shower Radio page describes a future product surface.