Skip to content

proposal

KaaG persona dashboards — backend gap analysis

Section titled “KaaG persona dashboards — backend gap analysis”

Scope. The three Atlas · RADR KaaG persona flows (VP Product, Product Manager, Technical Specialist) against what rechaj-backend-api (core-api), hermes-java-api (radr-api), vcu-consumer, radar-gateway, and rechaj-vehicle-controller (firmware) provide today. Codebase inventory date: 12 Jul 2026.


1 · What the backends already provide (build on these)

Section titled “1 · What the backends already provide (build on these)”
Capability Where Notes
Fleet roster + per-unit detail GET /api/v1/radr/roster, /api/v1/kaag/vcu-pins, /api/v1/kaag/vcu/{serial}/detail, /api/v1/asset/{serial} (radr-api) Detail already carries SOC/SOH/V/I/temp/firmwareVersion/signal_4g/mileage/last-seen/rider/cluster/plate/hasTelpoVcu
Telemetry history SOC history ≤7 d (1-min cagg w/ raw fallback), route replay 1-min buckets 30 d windows not reachable (168 h clamp); 1-h cagg exists in Timescale but is never queried
Live fleet state vcu-consumer → Redis veh:{id} → radar-gateway WS (JWT, binary viewport frames) Fleet/viewport only — no per-device channel
Command API skeleton POST /api/v1/vcu/{serial}/command — enum, confirm token CONFIRM-<CMD>-<serial>, idempotency, canCommand Disabled (radr.commands.enabled=false), publisher is a logging stub, idempotency in-memory, nothing persisted
Battery unlock POST /api/v1/battery/unlock → real MQTT (Magnetic/lockType:1) The only working command path; core-api has VcuUnlockAuditLog
Identity & segmentation Rider, Tricycle (plate/chassis), VCU.serial_number, riders_with_kaag + riders_with_telpo_vcu mirrors, hasKaag/hasTelpo flags on VCU lookup KaaG opt-in + preferred time on RiderOnboarding
Inspection (coarse) PATCH/GET /api/v1/admin/onboarding/{id}/inspection, MEI module Status enum only AWAITING / IN_PROGRESS / COMPLETED
Revenue & wallets SRRR jobs, RevenueDistribution, wallet ledger, Paystack webhooks Swap-oriented; no energy coupling
Immutable audit pattern BatteryAuditEvent (append-only, compensating records, 7-yr retention, payload_json, actor, linked events) The template for a VCU event timeline
Notification senders Termii SMS, Loop email, Firebase push No rules engine or digest on top
RBAC scaffolding RADR gated ADMIN/SUPER_ADMIN in core-api; RadrAccessPolicy (FLEET_VIEW / BOARD / COMMAND) in radr-api; Authority.CAN_MANAGE_VCU_FIRMWARES exists (unbacked) No VP/PM/TS AppRoles, no RADR App in mocx-contracts
Threshold evaluation deriveStatus() in vcu-consumer: SOC≤20, batt≥55 °C, motor≥95 °C, faults, unauthorized-move flag Ephemeral flag bits only — 48 h Redis TTL, never persisted
Offline bands VcuActivityStatus GREEN<10m…BLACK≥24h Matches the dashboards’ age chips exactly

2 · The gap map — persona feature → backend status

Section titled “2 · The gap map — persona feature → backend status”

Status: ✅ exists · 🟡 partial · ❌ missing. Epic column keys into §3.

Dashboard feature Backend status Epic
Fleet table (filters, pagination, 9 columns) 🟡 roster exists, returns full unpaged lists; no carrier/SIM field; no uptime or fault columns E11
Last-seen age chips / honesty buckets 🟡 bands exist per unit; no bucket-counts endpoint E2
Uptime 7d sparkbars / 30d % ❌ no uptime computation anywhere E2
Fault chips MCU·VCU·BMS·DU ❌ fault register parsed on-device but publish commented out (RUNBOOK §4.4); DU/display-link health not on the wire E13
24 h connectivity timeline + disconnect stats ❌ no LWT ingestion, no gap detection, offline = ping staleness only E2
Display & indicators (0x18F86590, SOC-push freshness, odometer) 🟡 odometer on wire; vehicle-lights + SOC-push-freshness publish commented out E13
Per-unit event timeline (commands/policy/connectivity/firmware/lifecycle) ❌ nothing queryable; [radar-command-audit] is a log line; station events exist but internal-only E6
Live decoded signals (2 s tick) + view-only raw stream ❌ gateway is viewport-fleet only; findLast10ByDeviceId unexposed; no per-device WS/SSE channel E10
Feature Status Epic
KAAG_ON/OFF/AUTO with reason, instant vs queued 🟡 API skeleton exists; publisher stub, disabled, no ack/queue/expiry, nothing persisted E1
Command history / shared audit table ❌ E1+E6
Safety exceptions (inverter-on-while-moving, low-SOC w/ inverter, SOH drop) 🟡 flags computed in consumer, ephemeral; inverter-on-while-moving not derived (needs inv+speed rule) E8
Sessions & energy (session list, kWh, SOC delta, end reason, data quality) ❌ no session detection, no kWh integration, V/I stored but never integrated E3
Adoption 7-day ❌ needs “actively using” definition from sessions E3+E5
Inspection pipeline (read-only 4-state) 🟡 coarse 3-state onboarding inspection; no PASSED / PENDING_ASSIGNMENT E9
Rider SMS on inverter cut 🟡 SMS sender exists; no trigger wiring E8
Feature Status Epic
Live raw MQTT console (per-unit tail, gap/backfill markers) ❌ E10
Commissioning: bench gates, enforcement, ready pool, install queue ❌ no provisioning workflow; InverterAuthController is a hardcoded stub; SIM ICCID/IMEI never captured E9
Diagnostics case queue (incl. unauthorized-move, thresholds) 🟡 flags ephemeral; no case persistence E8
Firmware releases, waves, adoption, per-version coverage drill ❌ no OTA server exists at all — the device’s hourly OTA check hits nothing; fvr per ping is the only building block; CAN_MANAGE_VCU_FIRMWARES authority is unbacked E7
Full command set incl. IMMOBILIZE (confirm token), SENT/QUEUED/expired/suppressed 🟡 enum + token + (in-memory) idempotency exist; everything downstream missing E1
Command audit page ([radar-command-audit] as queryable data) ❌ log line only E1+E6
First-heartbeat validation (LWT cleared) ❌ no LWT anywhere: firmware sets it, consumer never subscribes will/# E2+E13
Feature Status Epic
Adoption vs threshold, programme trajectory ❌ E3+E5
kWh + ₦ @ tariff, nightly curve, ARPU, collections, idle-kit revenue at risk ❌ no tariff, no energy billing, no ARPU anywhere in core-api E3+E4
Fleet health: 90 d uptime trend w/ incidents, carrier comparison, FW spread ❌ uptime engine; carrier not captured; FW spread derivable from fvr (needs endpoint) E2, E11, E7
Rollout vs 140 target, deployment readiness 🟡 deployment counts derivable from mirrors + telemetry; no target/campaign config E5+E9
Management report (period narratives, WoW, DFI impact, thresholds, risks) ❌ no report compiler, no PDF/CSV infra at all, no digest job E5+E14
Executive notifications (digest, adoption-below, offline>10%) ❌ senders exist; no rules/digest engine E5+E8

Ordered by phase. Owner repos in brackets. Details assume the repos’ package-by-feature conventions and the two-datasource boundary (primary vs Timescale) in hermes-java-api.

Phase 0 — enablers (unblock everything else)

Section titled “Phase 0 — enablers (unblock everything else)”
  • E12 · RADR personas RBAC [mocx-contracts + core-api + radr-api]: add a RADR App and three AppRoles (VP read-only → BOARD; PM → FLEET_VIEW + a limited COMMAND scope of KAAG_ON/KAAG_OFF/AUTO; TS → full COMMAND + FIRMWARE backed by CAN_MANAGE_VCU_FIRMWARES). Extend RadrAccessPolicy with per-command-type scoping. Lift the admins-only RADR gate.
  • E13 · Firmware-side prerequisites [rechaj-vehicle-controller]: (a) uncomment the fault register + MOSFET/motor temp publish (RUNBOOK §4.4 — columns and parser already exist); (b) publish vehicle-lights frame states + last_soc_send_time for display-link health; (c) resolve the pub/ vs vcu/pub/ topic-namespace mismatch; (d) emit a command-ack frame. All four are small device changes that unblock fault chips, DU health, ack tracking, and clean ingestion.
  • E1 · Real command execution + durable audit [radr-api]: replace LoggingVcuCommandPublisher with a real MQTT publisher on sub/<device_id>; persist a vcu_command table (status SENT/QUEUED/ACKED/EXPIRED/SUPPRESSED, actor, reason, confirm token, idempotency key — durable, not in-memory); ack consumption (from E13’s ack frame or next-frame state confirmation); queued-replay on reconnect + 72 h expiry job; command history endpoints (GET /api/v1/vcu/{serial}/commands, global list w/ filters); flip radr.commands.enabled after the Stage-6 bench review.
  • E11 · Fleet-table API hardening [radr-api]: pagination/filter/sort on the roster; add uptime + fault-chip + carrier fields to the row DTO (carrier requires E9’s SIM capture or a new payload field); a bucket-counts endpoint for the honesty strip.

Phase 1 — visibility (make the telemetry surfaces real)

Section titled “Phase 1 — visibility (make the telemetry surfaces real)”
  • E2 · Connectivity & uptime engine [vcu-consumer + radr-api]: subscribe will/# and persist connect/disconnect events; gap-detection job sessionizing pings into online/idle/offline segments; per-unit uptime 7 d/30 d + fleet daily uptime rollup (new cagg or table); endpoints for connectivity timeline, disconnect stats, uptime league, fleet trend (with incident annotation records). Also unlocks TS first-heartbeat validation.
  • E10 · Per-unit streams [radar-gateway + radr-api]: per-device WS/SSE channel — decoded frames for PM/VP (view-only), raw JSON tail for TS (RBAC-scoped); expose a last-N-frames REST tail (extend findLast10ByDeviceId); backfill/gap markers derived from E2 events.
  • E8 · Alerts persistence & safety exceptions [vcu-consumer + radr-api + core-api]: persist flag transitions into an alert table (low-SOC-with-inverter, inverter-on-while-moving = inv==ON && speed>threshold, batt-temp, unauthorized-move, SOH-drop); ack/resolve endpoints; wire rider SMS on inverter safety cut via Termii.
  • E6 · Unified VCU event timeline [radr-api, pattern from core-api’s BatteryAuditEvent]: append-only vcu_event store fed by E1 (commands), E2 (connectivity), E7 (OTA), E8 (alerts), lifecycle (assignment/commissioning), device policy events (SoC-floor cut, night schedule — inferable from inv transitions until the device emits explicit events). GET /api/v1/vcu/{serial}/events?category=&page=.
  • E3 · Sessions & energy [vcu-consumer ingest + radr-api reads] — REVISED 2026-07-13: Telpo firmware (VCU v1.6.x) now EMITS sessions; no derivation needed. The device publishes {"cmd":"inverter_session"} frames on the telemetry topic: START (inv_sid per-device counter, inv_t0 ISO-Z, inv_ah_start), periodic DURING (inv_dur s, inv_kw, inv_ah, inv_kwh, inv_ah_bms, inv_v_avg, inv_kwh_bms), END (+ inv_tN, inv_end_reason — seen: manual, vehicle_moving — inv_ah_end, inv_dq). Work: consumer upserts frames into a kaag_sessions table keyed (device_id, inv_sid, started_at) with missed-start tolerance (derive started_at = arrival − inv_dur); the BMS-sourced duplicates power the dual-method energy-divergence check; radr-api read endpoints (per-unit session list, daily unit/fleet kWh aggregates, nightly curve once Telpo adds bms_ah+v_avg to DURING frames — requested). Note env-broker split (DEV/UAT/PROD) and per-env firmware.
  • E4 · Energy commercial layer [core-api]: tariff config entity (₦/kWh, effective-dated); billable computation from E3 sessions; collections linkage to the wallet ledger; ARPU + idle-kit-revenue-at-risk aggregates; revenue endpoints for the VP commercial table.
  • E5 · Adoption & programme metrics [radr-api + core-api]: “actively using” = sessions within N days; adoption % vs configurable threshold; deployment-vs-target (140) campaign config; weekly digest compiler + threshold notifications (adoption-below, offline-share

    10%) using the existing email/push senders.

  • E7 · Firmware & OTA management [new service or radr-api + a device-facing endpoint]: release registry (version, signed artifact, delta size, notes, status); the device-check endpoint the firmware’s hourly OTA poll can finally hit; staged wave campaigns w/ server-evaluated guardrail preconditions (parked, SOC≥40, RSSI floor, not-in-session); chunked resumable delivery; A/B outcome tracking (boot-check pass/rollback from fvr confirmation); coverage endpoints (on-version / not-on-version lists with per-unit reasons) — the dashboards’ drill-down maps 1:1 onto this.
  • E9 · Commissioning & provisioning [core-api]: device registry (VCU serial ↔ NVS/MAC id, SIM ICCID/IMEI capture — new fields, kit/inverter serial registry replacing the hardcoded InverterAuthController stub); bench-gate state machine with ordered-gate enforcement + refusal reasons; ready-to-install pool with the pull-only constraint; 4-state inspection pipeline (awaiting / in-progress / passed / pending-assignment); install assignment writing the rider↔device custody history that’s currently missing.
  • E14 · Exports & reports [core-api or radr-api]: CSV/PDF generation infra (none exists); the VP management-report compiler (period narratives, WoW deltas, DFI impact constants 0.66 L/kWh + 1.53 kgCO₂e/kWh as auditable config); scheduled digest email job.

Phase 0 is small and unblocks demos of the highest-value loops (a PM sending a real KAAG_OFF that lands, acks, and appears in an audit trail). Phase 1 makes every table and timeline in the dashboards truthful instead of mocked. Phase 2 is where KaaG becomes a measurable business (sessions → kWh → ₦ → adoption → the VP report). Phase 3 rounds out the operational lifecycle the TS persona models. The single highest-leverage item in the whole map is E13(a) — one uncommented firmware publish block that the RUNBOOK has been pointing at since Stage 4.4: it turns the fault-chip and diagnostics surfaces from derived guesses into wire truth.