feat(vehicle): config flags + per-vehicle overrides with HTTP polling#198
Merged
Conversation
…ling - config_flag (per vehicle type + default), vehicle_config_override (per vehicle), vehicle_config_status (applied version + last poll) - effective config = type defaults merged with vehicle overrides, resolved on read; version is a content hash used as ETag for conditional polls - GET /vehicles/:id/config is the car's poll endpoint (ETag/304, records poll, ?applied_version= ack); /config/status reports desired vs applied - flag CRUD scoped to vehicle type; deleting a flag cascades its overrides - vehicle type enum (gr24/gr25/gr26) with validation on flag + vehicle create, exposed via GET /vehicle-types - unit tests for merge/hash/validation; Postgres integration test for the full flow
- vehicle cards navigate to a new /vehicles/:id details page - details page shows vehicle info (edit/delete) and a config section: create flags for the vehicle type, set/clear per-vehicle overrides, and view effective values with their source (default vs override) - config status surfaces last-updated, last-pulled-by-vehicle, applied-at, and desired/applied version drift - create-vehicle type dropdown now driven by GET /vehicle-types Backend: GET /vehicles/:id/config/status also returns config_updated_at (max updated_at across the type's flags and the vehicle's overrides).
- bump all in-major deps to latest (radix-ui, axios 1.17, recharts 2.15.4, mapbox-gl, xyflow, postcss, prettier, typescript 5.9, etc.) - npm audit fix (non-breaking): 26 vulns (2 critical/15 high) down to 10 that require breaking major bumps (vite/rollup/esbuild chain) - cast dnd DraggableStyle to CSSProperties in WidgetSelectionDialog: newer radix tightens React's CSSProperties augmentation with a --radix-* index signature that DraggableStyle lacks Framework majors (React 19, Tailwind 4, Vite 8, ESLint 10 flat config, react-router 7, recharts 3) intentionally deferred — each needs its own migration + QA.
New config endpoints fell through to the dashboard catch-all. The per-vehicle config routes (/vehicles/:id/config*) are already covered by the vehicles-id wildcard; this adds the two top-level paths.
Conditional GET added complexity (gateway would need a passthrough route to preserve If-None-Match/ETag) for a small, infrequently-changing payload. Just return the snapshot every poll; the car converges the same way and can use the normal enveloped gateway route.
The car proves identity with ?upload_key= on the config fetch; a valid key records last_synced_at (the fetch is the ack). A vehicle is in sync when last_synced_at >= config_updated_at — pure timestamp compare, no content hash, no applied-version echo, no one-poll lag. Dashboard reads (no key) don't count as a sync. Removes ConfigSnapshot.version, SnapshotVersion, and the applied-version fields from status.
Config, flag, override, status, and vehicle-type GETs are now Cache-Control: no-store so browsers/proxies can't cache or revalidate them into 304s. Stale flag data must never be served — a cached kill switch is unacceptable.
The 304s were harmless browser revalidation; not worth the extra headers.
Adds a per-flag delete button with a confirm dialog that warns it removes the flag for the whole vehicle type and cascades to every override. Wires the existing DELETE /config/flags/:vehicleType/:key endpoint.
One "Config" card now carries the in-sync badge, last-updated/last-synced line, and the flag list. Also fix fmtTime to render Go's zero time (0001-01-01) as "—" instead of a bogus date for never-synced vehicles.
One divider under the header; spacing separates the status line from the flag list.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a config / feature-flag system to the vehicle service, with dashboard UI. Flags are defined per vehicle type with a default, overridable per individual vehicle; the car pulls its effective config over HTTP and reports back what it applied. Postgres is the single source of truth — no broker.
Backend (
vehicleservice)config_flag(per vehicle type + default),vehicle_config_override(per vehicle),vehicle_config_status(applied version + last poll)304GET /vehicles/:id/config— the car's poll endpoint (records poll,?applied_version=ack)GET /vehicles/:id/config/status— desired vs applied,in_sync,config_updated_at,last_polled_atGET /vehicle-typesFrontend (dashboard)
/vehicles/:iddetails pageGET /vehicle-typesNot included (intentional): auth on mutating endpoints, audit/history table.
Validation:
go vet+ Go unit/integration tests pass; dashboardtsc --noEmitandeslintclean.