feat(reports-ui): Caddy static SPA over the reports API (RFC-0002) - #182
Conversation
A small, dependency-free browser UI for the reports service, served by Caddy as a separate `reports-ui` service (RFC-0002, ADR-0013). No new runtime -- an integration exhibit. - Vanilla HTML/CSS/JS SPA (no build step): submit a report, watch it reach SUCCEEDED, download the artifact, list recent jobs. All calls go same-origin under /api/*; rendering is textContent/createElement only (no innerHTML). - Caddy on :8084: `handle_path /api/*` strips the prefix so reports sees /reports/... (a bare reverse_proxy would 404); an explicit `metrics` handler serves Caddy's native Prometheus metrics on the service listener (they live on the admin API by default, which stays private/unpublished); /healthz + /readyz complete the D6 contract that the frontend's nginx does not meet. - Active upstream health check (health_uri /healthz) so caddy_reverse_proxy_upstreams_healthy tracks reality -- the dashboard shows a dead reports backend as down, not green (verified 1->0->1 across a stop/start). With reports absent the page still serves and the client shows an unavailable banner (D10); proxied calls return 503. - `reports-ui` compose profile at :8084 (admin :2019 never published), into up-full/up-workshop and the nightly smoke-full stack with an e2e-smoke health assertion; Prometheus scrape job + a provisioned Caddy dashboard; reports-ui.yml CI (caddy fmt/validate + image build) + Trivy matrix entry; non-root digest-pinned Dockerfile. Also refreshes the stale e2e.yml comment.
|
Warning Review limit reached
Next review available in: 40 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
WalkthroughAdds a Caddy-served Reports UI SPA with same-origin API proxying, compose integration, containerised validation, CI coverage, nightly checks, Prometheus scraping, and Grafana monitoring. ChangesReports UI
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Browser
participant Caddy
participant ReportsAPI
Browser->>Caddy: Submit report through /api/reports
Caddy->>ReportsAPI: Proxy request to reports:8083
ReportsAPI-->>Caddy: Return job status
Caddy-->>Browser: Return API response
Browser->>Caddy: Poll job status
Caddy->>ReportsAPI: Proxy status request
ReportsAPI-->>Browser: Return status or download link
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/reports-ui.yml:
- Around line 35-43: Update the caddy fmt step so the formatter command used to
generate Caddyfile.fmt cannot terminate the shell before diff runs; append the
failure suppression only to the docker run command that writes the comparison
output. Preserve the existing diff check and explicit failure message so
unformatted Caddyfiles still fail the job.
In `@services/reports-ui/site/app.js`:
- Around line 73-76: Update the polling flow around pollJob and submission
handling to track a submission generation or abort signal. Invalidate the
previous generation when a new job is submitted, and ensure stale poll
responses, errors, and timer scheduling are ignored so only the active job can
update status/download state or schedule another poll; retain clearing pollTimer
as cleanup.
- Around line 122-131: Update the polling error handling around pollJob so
recoverable transport and HTTP 5xx failures schedule another poll with
setTimeout until POLL_TIMEOUT_MS is reached, instead of returning permanently.
Preserve the existing showBanner behavior and active-job guard, while continuing
to stop polling immediately for non-recoverable errors and after the timeout.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 9c746e20-fba0-471b-9750-f809598b0aed
📒 Files selected for processing (19)
.github/workflows/e2e.yml.github/workflows/images.yml.github/workflows/reports-ui.ymlMakefileREADME.mddeploy/compose/docker-compose.ymldocs/architecture.mddocs/ci.mddocs/observability.mdobservability/grafana/dashboards/reports-ui.jsonobservability/prometheus.ymlscripts/e2e-smoke.shservices/reports-ui/Caddyfileservices/reports-ui/Dockerfileservices/reports-ui/Makefileservices/reports-ui/README.mdservices/reports-ui/site/app.jsservices/reports-ui/site/index.htmlservices/reports-ui/site/styles.css
…fmt diag Address PR #182 review findings: - app.js: a resubmission could leave an earlier in-flight poll running, which would overwrite the new job's status/download and schedule a second poller. A submission-generation token now tags each poll; a poll whose generation is no longer current bails after every await and schedules nothing. - app.js: a transient network error or 5xx during polling permanently stopped monitoring before the 60s deadline (Refresh only reloads the table). Such recoverable failures now reschedule until the deadline; a 4xx (job gone) or the deadline still stops with the existing banner. - reports-ui.yml: append `|| true` to the `caddy fmt` capture so a non-zero exit no longer aborts the step under `set -e` before the diff prints the "run make ... format" helper. The diff remains the gate -- an unformatted Caddyfile still fails.
The phase tags were never pushed. origin carries only v1.1.0-v1.5.0, so `git diff phase-2..phase-3` fails for everyone who clones this repo -- the course promised a history workflow no reader could run, in eleven places. Pushing them was the alternative, and it is worse. Every tag predates the loopback port binding and the dashboard uid fix: all eight publish ports on every interface (8 mappings at phase-0, rising to 18 at rfc-0002) and none pins a dashboard uid. Publishing eight trees that put Postgres on the wire, to an audience that will check them out and run them, is not worth a diff convenience. Better to not ship the footgun than to document it. The construction history is unaffected: every phase is a run of PRs on main, RFC-0001 Section 9 lists what each delivered, and the ADRs froze the decisions. The Tag column, the checkout instruction, the read-only-checkpoint paragraph, and the two "the rfc-000N tag will mark it" promises are gone. Tags deleted locally, recreatable from these commits if ever wanted: phase-0 8775267 Phase 0: repo restructure, CI, baseline hardening (#143) phase-1 99d458a Phase 1: three-layer monitoring, canary v1 (#159) phase-2 23170c3 Phase 2: contract-first gRPC + OpenTelemetry (#162) phase-3 a8ccbc0 Phase 3: Go analytics, pipeline-lag canary v2 (#167) phase-4 ec4810b Phase 4: load profile, Alertmanager, e2e gate (#172) phase-5 9cb1b1f Phase 5: historical seeder, workshop mode (#175) phase-6 393989a Phase 6: Kotlin reports, report load, canary v3 (#180) rfc-0002 e4bbafc RFC-0002: reports-ui Caddy static SPA (#182) All eight are ancestors of main, so the commits stay reachable regardless.
A small, dependency-free browser UI for the reports service, served by Caddy as a separate
reports-uiservice (RFC-0002, ADR-0013). No new runtime - an integration exhibit.handle_path /api/*strips the prefix so reports sees /reports/... (a bare reverse_proxy would 404); an explicitmetricshandler serves Caddy's native Prometheus metrics on the service listener (they live on the admin API by default, which stays private/unpublished); /healthz + /readyz complete the D6 contract that the frontend's nginx does not meet.reports-uicompose profile at :8084 (admin :2019 never published), into up-full/up-workshop and the nightly smoke-full stack with an e2e-smoke health assertion; Prometheus scrape job + a provisioned Caddy dashboard; reports-ui.yml CI (caddy fmt/validate + image build) + Trivy matrix entry; non-root digest-pinned Dockerfile. Also refreshes the stale e2e.yml comment.Summary by CodeRabbit
New Features
Documentation
Bug Fixes