Under the hood
Helm is a multi-app desktop + cloud system: a player-facing launcher kiosk, an operator console, an agent on every station, and a shared cloud receiver. Below is the actual shape of what ships, the gates that protect it, and the gaps we have not closed yet. We would rather show this page than have you find the gaps on your own.
Component map
Four runtime components, one event spine, one brand pipeline.
┌─ Launcher (kiosk per station) │ WPF · .NET 8 self-contained · 167 MB │ Tile grid, preflight overlay, recovery UI │ Emits: GameLaunchAttempt / GameLaunched / GameLaunchFailed / │ AbandonedLaunch / MemberIdle / PerformanceSample / ... │ ├─ FrontDesk operator console (one per venue) │ WPF · .NET 8 · 5 pillars (Time / Members / Licenses │ / Software / Payment) + Overview │ Drill-down drawers, smart segments, settlement view, │ inline confirm strip for destructive ops │ ├─ Agent (per station, runs as SYSTEM) │ PowerShell + scheduled tasks │ Cleanup, reconcile, telemetry sync, autologin guard │ └─ Cloud receiver (one per venue, scales to HQ) ASP.NET Minimal API · SQLite (Postgres path planned) /events ingest · /api/stats · /api/recent Game licensing pool, members, billing, software catalog, venue pricing
Event spine
Every meaningful action emits a typed event. The launcher writes
to a local SQLite event store; a background uploader batches to
the cloud's POST /events. The cloud serves the
operator console (live activity feed) and downstream dashboards
off the same store.
Event types in flight today:
- Launch lifecycle:
GameLaunchAttempt→GameLaunched|GameLaunchFailed→GameSessionEnded. All four share anAttemptIdjoin key so the cloud can compute per-attempt success rate without inferring from timing. - Silent-crash detector:
AbandonedLaunchfires when an attempt produced no process within 90 s - catches the gap a typed failure can't see. - Member presence:
MemberCheckedIn,MemberCheckedOut,MemberIdle,MemberReturned. - UI interaction:
TileClicked,AppLaunched,ForegroundAppChanged. - Platform health:
PerformanceSample(CPU, memory, every 60 s),ControllerConnected/Disconnected/BatteryLow(XInput-driven, 5-min cadence, edge-debounced),NetworkSample,LauncherStarted/ShuttingDown. - Day-rollups (cloud-side): a background runner
scans the event stream into
event_projections_dailyunder three projection kinds today -event_counts_daily(per-station per-type counters),station_utilization(sessions + minutes played + members seated), andgame_popularity(per-game launches + minutes + abandoned). The Insights tab in the operator console renders all three. - Coach signal:
CoachAttentionRequested- raised when a kid clicks "Tell a coach" on the launcher's recovery overlay, with GameId + Source. The operator console surfaces these in the Needs-Attention rail.
Brand pipeline (the white-label seam)
Every WPF app reads VALHALLAN_BRAND at startup and
merges a brand-specific ResourceDictionary before the window
constructs. Palette, wordmark, logo, even motion accents come
from there. The same binary runs Valhallan or Helm; nothing in
the apps hardcodes a venue color or copy string. One source
file (Shared.Design/DesignLanguage.cs) is
link-compiled into every WPF project so motion durations, easing
curves, and depth shadows stay identical across the suite.
Verify gates
Four hard gates run before every release. All four are
currently green on main:
Verify-Demo.ps1- 36 invariants on a cold-start demo cloud (members seeded, licenses queued, refund flow, tenant isolation). Pass: 36 / 36.Verify-Operator-Console.ps1- 222 static checks on the operator console's depth-pass surface area (every drawer wired, every handler present, no MessageBox, cmd-K palette + dispatch, stats card, all five pillar tabs, build clean). Pass: 222 / 222.Verify-Launcher-Catalog.ps1- 21 catalog gates on the seeded pack (every tile resolves to a runnable adapter, every platform launcher configured, override modes valid). Pass: 21 / 21.Verify-Telemetry.ps1- hard + soft gates on the live event pipeline (every expected event type fired today, per-PC freshness, cloud ingestion latency). Hard pass.
Unit tests
753 tests green across five .NET projects:
Valhallan.Cloud.Tests- 268. Game licensing state machine, billing, refunds, tenant isolation, software rollout, pricing rules, challenge progress, fleet power, tenant settings, projection runner.Valhallan.Launcher.Tests- 290. Launch service (typed outcomes, dedupe, process probe), game-session tracker, idle presence watcher, abandoned-launch watcher, running-game probe, game-detail career stats, settings VM.Valhallan.Shared.Tests- 170. Event wire-shape round-trips (GameLaunchAttempt with AttemptId join key, CoachAttentionRequested with GameId/Source, etc.).Valhallan.FrontDesk.Tests- 12. Command palette VM filter + nav + lifecycle.Valhallan.Agent.Tests- 12. Heartbeat, status reporting.
What we have not built yet
We would rather you know now than discover later:
- Auth is off by default. The cloud APIs
run open today; the auth middleware exists behind a
RequireAuthflag. Flipping to true is a release-gating task, not architectural work. - Stripe is simulated. Billing flow, franchise revenue share, refund clawback are all real and persisted to an immutable audit trail. The processor itself is a simulated gateway; live Stripe Connect onboarding ships once the franchise's connected-account credentials are in place.
- Cloud is single-tenant per venue. Tenant scoping is enforced inside the data layer (see the Verify-Demo test), but the HQ rollup that aggregates across venues is not built. Today each venue runs its own cloud process bound to admin LAN.
- Database is SQLite. Schema migrations run on cloud startup. A Postgres provider path is wired but not switched on - switching is one DI rebind.
- No CI pipeline yet. Verify gates exist as scripts; they have not been wired into a hosted CI yet. That is the next-up infrastructure task.
- Phone view of Floor. Marketing site mentions "wall display or your phone" - phone view is on the roadmap, wall display is shipped.
If you want to run it
The portable demo bundles the full suite into a single
self-extracting helm-demo.exe (~469 MB). It runs
a self-contained cloud + console + launcher with seeded data on
a clean Windows path. Email
[email protected]
for a build and the walkthrough script.