Repository navigation
feat: Dutch registration lookup at the RDW (APK, recalls, insurance) - #518
Merged
Merged
Conversation
Off unless RDW_ENABLED is set. The plate, entered per vehicle, is the only
thing sent to opendata.rdw.nl: the registration (m9d7-ebf2), the recall
statuses on the plate (t49b-isb7) and, for codes not seen before, the recall
details (j9yg-7rg9). The API looks a plate up as soon as it is entered; the
Worker's RdwSyncService keeps it current every RDW_REFRESH_HOURS and sends
the notifications: once per open recall, the APK a month and a week ahead
and once expired, and a car with no WAM insurance on record.
- RdwOptions, EnvironmentAliases, .env.example, compose, Unraid template and
CONFIGURATION.md for RDW_ENABLED, RDW_REFRESH_HOURS and RDW_APP_TOKEN.
- Vehicle.LicensePlate and RdwVehicleInfo in one migration.
- PUT /api/vehicles/{vin}/license-plate and GET /api/vehicles/{vin}/rdw,
both 404 rdw.disabled while off.
- A stand-in client and seeded lookup for demo mode.
- Parser tests against responses recorded from the RDW.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QUS3qyf8owf2McmxrZB6zu
- An "APK & recalls" card: the days the APK has left and the open recalls on the card; the APK date, the WAM insurance, each open recall with its risk and repair, the repaired ones and when the RDW was asked in its dialog. It shows only where the deployment looks plates up and a plate is set. - A licence plate field under Settings, and an "rdw" notification type, both only where the API does not answer rdw.disabled. - Demo mode leaves the RDW lookup and its notifications out when RDW_ENABLED=false. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QUS3qyf8owf2McmxrZB6zu
The field is a yellow plate with the blue EU band and NL, in the plate's own colours in either theme. The dashes go where the Dutch side codes put them while typing: at every change between letters and digits, with a group of four split in two (AB-12-34, 12-ABC-3, HPK-98-B). Backspace or Delete next to a dash takes the character beyond it, the caret stays where it was, and anything but letters and digits, or past eight, is refused. The RDW card writes the plate the same way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QUS3qyf8owf2McmxrZB6zu
- README: a section on the Dutch registration (the plate field, the lookup, the card, the notifications), the card under its on-screen name, the RDW among the hosts the container may reach, and the RDW type among those the notification checklist leaves out when off. - ARCHITECTURE: the RDW lookup among the caches, the browser side (the rdw store and the side-code formatting of the plate field), and the RDW and Valhalla clients behind the shared rate gate. - DEMO: RDW_ENABLED in the demo's variables, which docker-compose.demo.yml now passes through so the note about switching it off holds there too. - HOME_ASSISTANT and the all-in-one README: the /rdw endpoint and the RDW settings among the ones listed. - GarageStack.Api.http: the RDW endpoints, and /stats/daily in place of the /history endpoint that no longer exists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QUS3qyf8owf2McmxrZB6zu
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.
Summary
For a car with a Dutch licence plate, GarageStack now shows what the RDW has on record: when the APK runs out, open recalls, and whether the car has WAM insurance. The data comes from the RDW's open data and drives a new dashboard card and new notifications.
It is off by default (
RDW_ENABLED=false). While off, nothing is sent and the plate field, the card and the notification type do not appear. While on, the plate is the only thing that leaves the network. No API key is needed.Backend
Lookup.
RdwApiClientqueries three Socrata datasets by plate: the registration (m9d7-ebf2), the recall statuses (t49b-isb7), and recall details (j9yg-7rg9) only for codes it has not seen yet. It goes through the sharedUpstreamRateGateand refuses to send anything while the feature is off. A plate the RDW does not know is saved as "not found", not as an error. A failed lookup keeps the last good answer and records the error inLastError.Storage. Migration
AddRdwLookupsaddsVehicle.LicensePlate(stored without dashes) and anRdwVehicleInfostable, one row per vehicle, with the recalls in a JSON column. No index drops or raw SQL.API.
PUT /api/vehicles/{vin}/license-platesaves the plate and looks it up immediately.GET /api/vehicles/{vin}/rdwreturns the lookup. Both return 404rdw.disabledwhile the feature is off.Worker.
RdwSyncServicerefreshes lookups older thanRDW_REFRESH_HOURS(default 24) and sends the notifications:Days are counted between calendar dates in Amsterdam. Nothing is sent from a lookup older than two refresh intervals, so an APK renewed while the RDW was unreachable is not reported as running out.
Config.
RDW_ENABLED,RDW_REFRESH_HOURSandRDW_APP_TOKEN(optional Socrata token for a higher rate limit) are inRdwOptions,EnvironmentAliases,.env.example, both compose files and the Unraid template.Demo mode.
DemoRdwClientplus a seeded lookup, so no plate leaves a demo deployment either.Frontend
AB-12-34,12-ABC-3,HPK-98-B). Backspace and Delete skip over dashes, and anything other than letters and digits, or more than 8 characters, is refused.rdwtype in the per-device checklist, hidden while the feature is off.Docs
README (feature list, card table, notification table, new "Dutch registration (RDW)" section), CONFIGURATION, ARCHITECTURE, DEMO, HOME_ASSISTANT, the all-in-one README, and
GarageStack.Api.http. The.httpfile also replaces the removed/historyendpoint with/stats/daily.Type of Change
Checklist
pnpm lint/dotnet build)unraid/garagestack.xmlchanged: synced tojoszz/unraid-community-appsafter merge, through a pull request there (see "Keeping the Community Apps copy in sync" indocumentation/RELEASING.md)Test plan
dotnet test --project src/GarageStack.Tests), build without warningsvitest run)vue-tsc --build, oxlint, eslint, stylelint andprettier --checkcleanRDW_ENABLED=true: enter a plate, check the card fills, wait for a Worker refreshAfter merge: the Unraid template gained the three
RDW_*variables, so it needs syncing tojoszz/unraid-community-apps.🤖 Generated with Claude Code