The post below is in Portuguese. We will translate critical announcements as the project gains an English-speaking audience.

Keychain, Kuma, and an interactive tour — seven hardware-free fronts in a day

Tuner now keeps tokens in the OS keychain, smoke:prod publishes a heartbeat to Uptime Kuma, the mobile app got a Connect screen, the dashboard sim hit 5 screens, /sobre became a visual tour. Another day without hardware with real leverage.

Phase 0 hardware still in transit. Full day of hardware-free leverage — seven commits, seven fronts, all tying together pieces that were loose.

Tuner desktop — token in the OS keychain

Until now, Tuner’s cloudState kept apiBase + deviceId + token in localStorage. Works, but in production (Tauri shell) localStorage is the local WebView — unencrypted, easy to extract with any profile inspection tool. Pro apps use Keychain (macOS) / Credential Manager (Windows) / Secret Service (Linux).

I added the keyring = "3" crate to the Rust backend and exposed three Tauri commands: secret_get, secret_set, secret_delete. The frontend has a single wrapper (secretGet/Set/Delete) that detects the runtime via __TAURI_INTERNALS__ and routes automatically:

  • In production (Tauri shell) — goes to the OS native keychain.
  • In vite dev (browser) — transparent fallback to localStorage.
  • In vitest (node) — same fallback, no mocking needed.

The Svelte store still initializes synchronously from LS (Svelte runes require sync), and right after boot App.svelte fires hydrateSecretsFromKeychain() in a $effect that replaces the in-memory values with the keychain ones whenever it has something fresher.

I packaged the trade-off in ADR-013. The keyring crate beat tauri-plugin-stronghold (which requires a user password on boot — bad UX for a tool) and keytar (deprecated in 2024).

Garage — heartbeat on Uptime Kuma

pnpm smoke:prod running daily on GitHub Actions had a subtle problem: if it broke at dawn, the signal was a GitHub email. GitHub emails go to spam. Result: you find out the API is down when someone opens the Actions panel.

But vps-pomatti already runs Uptime Kuma serving 5+ owner-managed apps (Frigoo, Lumê, etc.). It’s the channel I already check on my phone for ecosystem state. So smoke became a push monitor: after running the 5 checks, it does GET ${UPTIME_KUMA_PUSH_URL}?status=up|down&msg=…&ping=… with the overall set status, a one-liner with the names of the failing checks, and the average ping in ms.

Important detail: failing to reach Kuma is non-fatal. If Kuma is down or the cron runs without internet, smoke still exits 0 with 5/5 green. Product truth doesn’t depend on monitor health.

Documented in ADR-014 with the alternatives I rejected (Datadog Synthetic, Better Stack — US$ 30-100/month when I already have Kuma free; Prometheus — over-engineering for current scale).

Pistonix Ride — Connect screen

ConnectionRepository (ADR-012) had 4 green tests but no screen used it yet. Now it does: a new Connect screen with a big state circle (160×160), color shifting per state-machine state (idle gray / connecting+connected Pistonix orange / streaming green / lost+error red), spinner during connecting, Connect/Disconnect/Cancel button contextual to state.

main.dart now mounts a MockConnectionRepository(telemetry: MockTelemetryRepository()) and auto-connects on boot — the app opens straight into “streaming” after ~500ms of mock handshake. When BLE is real, swap one line at boot (MockConnectionRepository → BleConnectionRepository) and nothing else changes.

Three new widget tests cover render-idle, on-tap transition, and the error path of the BLE stub (which throws UnimplementedError in connect() until Phase 5+).

Dashboard sim — Settings + Datalog

The SDL2 dashboard simulator had 3 screens (home, race, diagnostic). Added 2: Settings (10-100% brightness slider, mock km/h↔mph and day↔night switches, ”● paired” Garage status) and Datalog (mock list of 5 sessions with bike / duration / size / sync indicator).

S key toggles settings, D toggles datalog. Each toggle hides all other screens — explicit overlay mutex, no modal stack. TAB and R still toggle diagnostic and race respectively.

MOCK_ENTRIES[] is a static array in datalog.c; when the real cloud client lands (Phase 5+), it gets replaced by the GET /telemetry payload.

Web /sobre — interactive tour

/sobre got a “How it works — Five pieces talking to each other” section: 5 numbered cards (01-05) describing Forge (ECU) → Dash (display) → Ride (app) → Garage (cloud) → Tuner (desktop), connected by horizontal arrows that show each link’s protocol (CAN bus 500kbps, BLE GATT, HTTPS, USB · HTTPS).

Hover animates translateX(4px) + red border, gradient on the horizontal lines between cards, arrow pointing down at the end. Full build in 75s, no Lighthouse regression.

ADR-012 — ConnectionRepository pattern

Documented the ConnectionRepository pattern (which extends TelemetryRepository instead of living parallel to it) in ADR-012. Justifies the trade-off against two alternatives I rejected: transport states inside TelemetryRepository (couples things that don’t belong together) and a global event bus (implicit singleton that re-introduces the coupling ADR-010 had rejected).

STATE.md

Synced with the batch — 2026-05-06 batch (hardware-free, continuação) entry lists the 4 commits in the window and updates coverage totals (200 ECU + 67 cloud integration + 22 Rust + 8 vitest Tuner + 11 Ride).

What was NOT part of this session

  • Real mobile BLE — depends on the Dash hardware existing.
  • Telemetry binary upload in Garage — schema decided, handler still a stub.
  • DTC details modal in the dashboard sim — went into the next queue.

But the loose ends from the previous day (token in LS, smoke without broadcast, ConnectionRepository with no UI consuming it, dashboard with 3 screens but no settings/datalog) all got tied up. A hardware-free day with real leverage — work that doesn’t show up in Lighthouse, but it’s the difference between “the app opens and works” and “the app opens and works and is easy to operate.”

Waitlist

Be the first to know.

Pistonix is under active development. Sign up for product updates, early basemaps, invites to ride at Milwaukee Garage Drag Racing events, and priority on the first batch of Pistonix Forge.

  • Monthly roadmap and firmware updates
  • Invite to pre-sale tuning sessions
  • Priority on the initial Pistonix Forge batch
  • Early access to per-engine basemaps

By signing up you agree to receive emails from Pistonix. We do not share your email. You can unsubscribe at any time.