Skip to content

Review follow-ups: lighter dashboard, Retry-After, faster telemetry writes and statistics, shared nginx config - #519

Merged
joszz merged 7 commits into
mainfrom
claude/gallant-rubin-ihbf2v
Oct 19, 2026
Merged

joszz merged 7 commits into
mainfrom
claude/gallant-rubin-ihbf2v

Conversation

@joszz

@joszz joszz commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner

Pull Request

Summary

The first two batches (P1 and P2) from a full review of the project.

P1

  • perf(dashboard): the tyre and level history dialogs, and Chart.js with them (about 190 KB, 67 KB gzipped), are fetched on their first tap instead of with every dashboard visit. Each dialog is mounted closed and opened on the next tick, so its fade-in and its fetch still start from the change.
  • fix(frontend): useSignalR reports a reconnect (automatic, or after its own restart), and App fetches the status again: telemetry pushed while the connection was down never reached the page.
  • fix(frontend): an address no view answers to redirects to the dashboard instead of rendering an empty page.
  • fix(upstream): Nominatim, Valhalla, Overpass, Open Charge Map and the RDW back off as long as Retry-After asks (seconds or a date, kept between 1 s and 1 h), falling back to each client's own default without one.
  • perf(telemetry): TelemetrySnapshot.RawTopic is dropped (DropRawTopic migration). Every row stored the full topic saic/<account email>/vehicles/<VIN>/..., so every row carried the MG account's email address. The undocumented diagnostic endpoint GET /api/vehicles/{vin}/topics, its only reader, goes with it.
  • build(frontend): workbox-window moves to devDependencies: nothing imports it, it is a peer of vite-plugin-pwa.
  • docs(readme): a contents list, a "What leaves your network" table (each outside service, what it receives, how to switch it off), the Retry-After behaviour, and a documentation index.

P2

  • perf(telemetry): merging an MQTT message into its poll's row no longer reads the row (about eighty columns) first: the patch goes onto a key-only stand-in, so EF sends one UPDATE of just the fields the message carried. Checked against a real PostgreSQL: one UPDATE plus the pg_notify per message, where there was a SELECT too; a row that has gone still takes the patch as a new row.
  • perf(statistics): finished days' statistics are kept in memory per vehicle and time zone, and only the span the cache lacks is read; a statistics page opened again reads today rather than the whole period (up to ten years). A day counts as finished an hour after its local midnight, past the merge window. Documented under Caching in ARCHITECTURE.md.
  • refactor(upstream): UpstreamRateGate.SendAsync waits out the interval, sends, and reads the answer for a slow-down; the five clients no longer repeat those steps by hand.
  • perf(nginx): the frontend and all-in-one configs share one server body (frontend/nginx-app.conf) and only set their own $api_upstream. The build writes a .gz beside every compressible file at the highest level (scripts/precompress.mjs) and gzip_static serves it.
  • refactor(data): the repositories demo mode shares with a real deployment are registered once.

Measured and left out: precompiling the vue-i18n messages saved under 1 KB gzipped on the entry bundle (the compiled English messages grow the main chunk about as much as the runtime-only build saves), not worth the new build dependency.

For the release notes (Upgrade Notes): GET /api/vehicles/{vin}/topics is removed. Dropping the column is instant in PostgreSQL; the space returns gradually, or at once with VACUUM FULL "TelemetrySnapshots";.

Type of Change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Documentation
  • Dependency update
  • Other

Related Issues

None.

Checklist

  • Tests added or updated (CarDiagram, reconnect, catch-all route, Retry-After and SendAsync, fresh-context merges, the daily statistics cache)
  • Linting passes (pnpm lint / dotnet build), plus dotnet format --verify-no-changes, has-pending-model-changes, 1432 backend and 1130 frontend tests
  • No secrets or personal data committed
  • Responsive on mobile (no layout changes)
  • i18n keys added for any new UI strings (none added)
  • If unraid/garagestack.xml changed: not changed

Also checked locally: every migration applies on PostgreSQL 16; both nginx configs pass nginx -t, and the frontend config, serving the real build, sends the prebuilt .gz byte for byte with Vary, the security headers and the cache headers. The Docker images and the Playwright smoke tests were not built or run locally (no Docker); CI covers them.

🤖 Generated with Claude Code

https://claude.ai/code/session_01L6DtW2eHhipteRopmy3cif

… first tap

CarDiagram imported the tyre and level history dialogs directly, which put
Chart.js (about 190 KB, 67 KB gzipped) on every dashboard visit. Each dialog
is now fetched when it is first opened, mounted closed and opened on the next
tick so its fade-in and its fetch still start from the change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6DtW2eHhipteRopmy3cif
Telemetry pushed while the SignalR connection was down never reached the page,
which kept showing the old state until the next poll. useSignalR now reports a
reconnect (automatic or after its own restart) and App refetches the status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6DtW2eHhipteRopmy3cif
An old bookmark or a typo rendered an empty page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6DtW2eHhipteRopmy3cif
Open Charge Map, Overpass, Nominatim, Valhalla and the RDW each backed off a
fixed time after a 429/503/504, whatever the server said. The gate now reads
Retry-After (seconds or a date), kept between a second and an hour, and falls
back to each client's own default without one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6DtW2eHhipteRopmy3cif
Each telemetry row kept the full topic that started it,
saic/<account email>/vehicles/<VIN>/..., so every row carried the MG account's
email address. Only the undocumented diagnostic endpoint
GET /api/vehicles/{vin}/topics read it; it goes too. Unmapped topics are still
logged once each. The DropRawTopic migration drops the column, which
PostgreSQL does without rewriting the table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6DtW2eHhipteRopmy3cif
Nothing in the app imports it; it is there as a peer of vite-plugin-pwa, which
only the build uses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6DtW2eHhipteRopmy3cif
…tion index

The prerequisites named only some of the services GarageStack asks; a table
under Security defaults now lists each one, what it receives and how to switch
it off. Overpass backing off follows its Retry-After, and the README links
every other document, CONTRIBUTING and SECURITY among them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6DtW2eHhipteRopmy3cif
@joszz
joszz enabled auto-merge October 19, 2026 19:08
@joszz
joszz merged commit 2e9d135 into main Oct 19, 2026
21 checks passed
@joszz
joszz deleted the claude/gallant-rubin-ihbf2v branch October 19, 2026 19:08
@joszz joszz changed the title Review follow-ups: lighter dashboard, Retry-After, no raw topic per row, README Review follow-ups: lighter dashboard, Retry-After, faster telemetry writes and statistics, shared nginx config Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants