feat(service-health-ping): tile health badge + archive#15
Merged
Conversation
…ealth badge
Adds an optional health ping to a tile: HealthPingService performs an
allow-listed, server-side HTTP check via IClientService, classifies the
result online/degraded/offline, and caches it in ICache (TTL = interval,
default 60s, min 15s). HealthPingController exposes the cached badge at
GET /api/health-ping/{placementId} with a placement view-ACL guard, never
leaking the health URL or response body. HealthPingRefreshJob (TimedJob,
15s tick) refreshes due, ping-enabled placements in the background so
viewers don't pay upstream latency.
The host allow-list (healthping_allowed_hosts) is enforced fail-closed at
both save time (POST /api/health-ping/validate) and ping time. Config
lives in the placement's existing content JSON blob - no schema change.
Frontend: HealthPingBadge.vue renders the state as an icon AND a text
label (never colour alone, WCAG AA), with an accessible checked-at/latency
tooltip, wired into both live tile-render paths (Views.vue's main grid and
WidgetRenderer.vue). TileEditor.vue gains the enable/URL/expected-status/
interval fields with a best-effort save-time allow-list check.
28 new PHPUnit tests (Service/Controller/BackgroundJob) and 22 new Vitest
tests (badge render states, config validation) - all green, no real
network calls in any test.
Replaces the hand-written canonical spec with the one openspec archive generates, so the spec stays tool-owned. Full suites after rebase: 1472 phpunit tests / 3574 assertions OK, 615 vitest tests across 56 files pass.
rubenvdlinde
requested review from
Rem-Dam,
SudoThijn,
WilcoLouwerse,
bbrands02,
remko48 and
rjzondervan
as code owners
July 23, 2026 23:26
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.
Implements and archives
service-health-ping— the last of the nine market-gap changes. Answers the question a municipal IT landing page actually gets asked: is de zaakapplicatie bereikbaar?What
HealthPingService— server-side HTTP check (avoids CORS/mixed-content), fail-closed host allow-list,ICachewith a short TTL, online / offline / degraded classification.HealthPingRefreshJob— TimedJob keeps the cache warm so page loads stay fast.GET /api/health-ping/{placementId}(#[NoAdminRequired], placement view-ACL guarded) plusPOST /api/health-ping/validatefor save-time checks. The literalvalidateroute is registered before the{placementId}route so it is never parsed as an id.HealthPingBadge.vueoverlay + tile config fields. Badge state is icon and text, never colour alone.Verification (local, no CI wait)
Run after rebasing onto the full stack of the other eight changes:
phpunitfull suite → 1472 tests, 3574 assertions, OK (3 pre-existing skips).npx vitest runfull suite → 615 tests across 56 files, all pass.Merge-conflict resolution worth reviewing
This branch conflicted with
tile-usage-analyticsonTileWidget.vueand withiframe-embed-widgetonroutes.php. The first automatic resolution silently droppedrecordTileClick, which would have removed tile-click analytics from the merged product. I caught it by diffing againstorigin/developmentand restored the import, the@click="handleActivate"binding and themethodsblock, so both features now coexist. Worth a second pair of eyes on that file.Also: the build agent had hand-written
openspec/specs/service-health-ping/spec.md; removed soopenspec archiveowns it.Not done
Playwright e2e, left explicitly unchecked in the archived
tasks.md.