Skip to content

tasks

Phase 0 tickets — enablers for the KaaG persona dashboards

Section titled “Phase 0 tickets — enablers for the KaaG persona dashboards”

Tracker-ready. Each ticket: repo · title · description · acceptance criteria. Epics reference proposal.md §3. Branch/PR conventions per each repo’s .claude/skills/backend-pr-conventions.


T1 · [mocx-contracts] Add RADR App + three KaaG persona AppRoles

Section titled “T1 · [mocx-contracts] Add RADR App + three KaaG persona AppRoles”

Add RADR to the App enum and three AppRoles: RADR_VP_PRODUCT (read-only), RADR_PRODUCT_MANAGER, RADR_TECHNICAL_SPECIALIST. Version-bump the contract and publish to the local maven repo consumers (core-api, hermes-java-api). Accept: contracts artifact consumed by both services; AppRoleCatalogController lists the three roles under the RADR app; no existing role IDs shifted.

T2 · [hermes-java-api] Per-persona scoping in RadrAccessPolicy

Section titled “T2 · [hermes-java-api] Per-persona scoping in RadrAccessPolicy”

Extend core/configs/security/RadrAccessPolicy: map RADR_VP_PRODUCT → BOARD (read-only, no COMMAND), RADR_PRODUCT_MANAGER → FLEET_VIEW + a limited command set (KAAG_ON, KAAG_OFF, AUTO only), RADR_TECHNICAL_SPECIALIST → full COMMAND + firmware scope backed by Authority.CAN_MANAGE_VCU_FIRMWARES. Add per-VcuCommandType authorization to VcuCommandServiceImpl (PM attempting IMMOBILIZE ⇒ 403). Accept: integration tests per persona × command type; VP receives 403 on any POST command.

T3 · [rechaj-backend-api] Lift the admins-only RADR gate

Section titled “T3 · [rechaj-backend-api] Lift the admins-only RADR gate”

RequestSource.RADR_APP currently allows ADMIN/SUPER_ADMIN only. Allow the three new AppRoles through login/token issuance for the RADR surfaces while keeping fine-grained policy in radr-api. Accept: a user holding only RADR_VP_PRODUCT can authenticate into RADR surfaces; non-RADR roles still rejected.


E13 · Firmware-side prerequisites (→ Telpo change requests)

Section titled “E13 · Firmware-side prerequisites (→ Telpo change requests)”

Ownership note (2026-07-13): Telpo writes the VCU firmware. The local rechaj-vehicle-controller repo is stale — a wire-contract reference, not a ship vehicle (its main doesn’t compile; changes there never reach devices). T4–T7 are therefore change requests to Telpo. The reference implementation in rechaj-vehicle-controller#3 doubles as the vendor spec: exact payload keys (fault register hpd…bcf/icf, packed ind indicator bitmask with documented bit layout, spa SOC-push age, the {"ack","result","ts"} command-ack frame) and the fvr JSON-quoting fix. Acceptance criteria below still apply — verified on a bench unit running Telpo’s build.

T4 · Publish the MCU fault register + MOSFET/motor temps (RUNBOOK §4.4)

Section titled “T4 · Publish the MCU fault register + MOSFET/motor temps (RUNBOOK §4.4)”

Uncomment the publish lines in updateData() (main.cpp ~670-681). vcu-consumer columns and parser already exist. Accept: fault flags + tp1/tp2 visible in vcu_telemetry_data for a bench unit; a forced bms_comm_failure appears end-to-end within one cadence.

Section titled “T5 · Publish display-link health (vehicle-lights frame + SOC-push freshness)”

Add the parsed MCU_VEHICLE_LIGHTS_DATA_T states (frame 0x18F86590) and last_soc_send_time age to the payload; extend vcu-consumer normalization. Accept: indicator states + soc_push_age_s land in Timescale; DU display-link health is derivable server-side.

T6 · Resolve the pub/ vs vcu/pub/ topic-namespace mismatch

Section titled “T6 · Resolve the pub/ vs vcu/pub/ topic-namespace mismatch”

Decide the canonical namespace; during transition the consumer subscribes both (pub/# and vcu/pub/#) with dedup by (device_id, ts). Update LoggingVcuCommandPublisher successor + docs. Accept: zero frame loss during cutover (compare ingest counts); RUNBOOK updated; diagnostics “namespace mismatch” case closable.

On executing any sub/<device_id> command (MECHON/MECHOFF/INVON/INVOFF/AUTO), publish an ack frame {ack:<token>, cmd, result, ts} on the telemetry topic. Accept: ack arrives within one cadence on bench; malformed/unknown commands ack with result:"rejected".


E1 · Real command execution + durable audit (hermes-java-api)

Section titled “E1 · Real command execution + durable audit (hermes-java-api)”

Replace LoggingVcuCommandPublisher with an MQTT publisher on sub/<device_id> (reuse the Spring-Integration mqttOutputChannel proven by battery unlock). Return SENT when the broker confirms publish to a connected client, QUEUED otherwise (retained or broker queue — match firmware semantics). Accept: bench KAAG_OFF opens the relay; SENT/QUEUED distinction verified against a disconnected unit.

T9 · Durable vcu_command table + idempotency

Section titled “T9 · Durable vcu_command table + idempotency”

Flyway migration: vcu_command (uid, vcu_serial, type, firmware_token, actor, reason, confirm_token_used, idempotency_key UNIQUE, status SENT/QUEUED/ACKED/EXPIRED/SUPPRESSED/ REJECTED, requested_at, resolved_at, ack_payload). Replace the in-memory idempotency Set. Accept: duplicate idempotency key returns SUPPRESSED across service restarts/replicas; every POST writes exactly one row.

T10 · Ack consumption, queued replay, 72 h expiry

Section titled “T10 · Ack consumption, queued replay, 72 h expiry”

Consume T7 ack frames → transition QUEUED/SENT → ACKED. On device reconnect (first frame after gap), replay unexpired QUEUED commands. Scheduled job expires QUEUED > 72 h → EXPIRED (never fire stale — the audit-trail invariant the dashboards promise). Accept: command sent to an offline unit lands after reconnect within one cadence; a 72 h-old queued command never fires and shows EXPIRED.

GET /api/v1/vcu/{serial}/commands and GET /api/v1/vcu/commands (filters: type, status, actor, date range; paged). Feeds the PM/TS audit tables and the per-unit event timeline (E6). Accept: OpenAPI documented; RBAC — VP read allowed, command POST still scoped per T2.

T12 · Stage-6 bench review → enable the kill-switch

Section titled “T12 · Stage-6 bench review → enable the kill-switch”

Run the bench checklist (T4–T10 verified on hardware), then flip radr.commands.enabled=true in qa → uat → prod with the rollout note. Accept: sign-off recorded; prod config change audit-logged.


E11 · Fleet-table API hardening (hermes-java-api)

Section titled “E11 · Fleet-table API hardening (hermes-java-api)”

T13 · Paginated, filterable fleet endpoint + honesty buckets

Section titled “T13 · Paginated, filterable fleet endpoint + honesty buckets”

New GET /api/v1/radr/fleet?page&size&sort&q&band&kaag&fw returning the dashboard row DTO (identity, last-seen band + minutes, SOC/SOH, fw, hasKaag/hasTelpo, latest flags). Companion GET /api/v1/radr/fleet/buckets returning the five last-seen band counts (GREEN<10m … BLACK≥24h) summing to deployed. Accept: p95 < 300 ms at fleet scale (uses findLatestForAllDevices / Redis cache); band math identical to VcuActivityStatus.


T1→T2→T3 (RBAC chain) can run parallel to T4–T7 (firmware). T8 depends on T6 (namespace decision); T9–T11 depend on T8; T10 depends on T7. T12 last. T13 independent — start anytime.