Frontend reporting client: POST collected samples to /api/v1/reports #53

Open
opened 2026-09-21 09:47:41 +02:00 by clawbot · 0 comments
Collaborator

Why

Owner ruling on #25: the backend ships wired up. POST /api/v1/reports (backend/internal/handlers/report.go) has no caller; src/main.js collects every sample the endpoint is shaped for and never sends any of it.

Definition of done

  • The page periodically POSTs a JSON report to the same-origin path /api/v1/reports in the shape the backend decodes today: {clientId, geo, hosts: [{name, url, status, history: [{t, latency, error}]}], timestamp}. clientId is a random id generated once per browser and kept in localStorage. geo is sent as JSON null (no geolocation lookup). timestamp is ISO 8601 UTC. t is the sample's Unix time in milliseconds; latency is the integer ms or null; error is the existing "timeout" / "unreachable" string or null. Paused (blank) samples are not reported.
  • Each report carries only samples not yet reported (a per-host high-water mark), so it is a delta. The interval is a CONFIG value, default 60 s. While paused nothing is sent. Unsent samples are bounded by the existing history window; if a report cannot be delivered, what falls out of the window is dropped oldest-first.
  • Failure is quiet and bounded: a failed POST (network error, non-2xx, including the 404 you get under yarn dev with no backend) is logged once to the in-page debug log at debug level, retried at the next interval, never blocks probing, never shows an alert, never retries in a tight loop. A later success is logged at debug level once.
  • fetch POST with Content-Type: application/json, credentials: "omit", no other headers. No new dependency.
  • The measured byte size of a full report at the maximum history (maxHistoryPoints x all hosts) is stated in the PR and is well under the backend's 1 MiB body limit.
  • vite.config.js gains a dev-server proxy for /api to http://127.0.0.1:8080 so make dev with a locally running netwatch-server exercises the real path; one line in README Getting Started says so.
  • Verified and summarised in the PR: with the backend running locally, it logs report received with the expected host_count; without a backend the page works and the debug log shows one debug-level failure line per outage, not one per interval.
  • Code follows the file's existing class-based structure (a reporter class beside AppState), with the report-building step a pure function of host state so #21 can test it. README Design section gets a short paragraph: what is sent, how often, to where.
  • make check green; docker build . green. TODO.md updated in the same commit. Commit title ends (closes #N).

Implementation requirements

  • Do not change the backend or its schema. If the schema needs a change to be usable, stop, say so on the PR with the reading taken, and leave the backend alone.
  • Do not touch nginx.conf or any Dockerfile; the proxy route is #52.
  • No scripted edits (sed -i, perl -pi, awk, python rewrites); edit by hand, format only via make fmt. make targets and script/ entrypoints only. No attribution trailers.

model: claude-fable-5

## Why Owner ruling on https://git.eeqj.de/sneak/netwatch/issues/25: the backend ships wired up. `POST /api/v1/reports` (`backend/internal/handlers/report.go`) has no caller; `src/main.js` collects every sample the endpoint is shaped for and never sends any of it. ## Definition of done - [ ] The page periodically POSTs a JSON report to the same-origin path `/api/v1/reports` in the shape the backend decodes today: `{clientId, geo, hosts: [{name, url, status, history: [{t, latency, error}]}], timestamp}`. `clientId` is a random id generated once per browser and kept in `localStorage`. `geo` is sent as JSON `null` (no geolocation lookup). `timestamp` is ISO 8601 UTC. `t` is the sample's Unix time in milliseconds; `latency` is the integer ms or `null`; `error` is the existing `"timeout"` / `"unreachable"` string or `null`. Paused (blank) samples are not reported. - [ ] Each report carries only samples not yet reported (a per-host high-water mark), so it is a delta. The interval is a `CONFIG` value, default 60 s. While paused nothing is sent. Unsent samples are bounded by the existing history window; if a report cannot be delivered, what falls out of the window is dropped oldest-first. - [ ] Failure is quiet and bounded: a failed POST (network error, non-2xx, including the 404 you get under `yarn dev` with no backend) is logged once to the in-page debug log at debug level, retried at the next interval, never blocks probing, never shows an alert, never retries in a tight loop. A later success is logged at debug level once. - [ ] `fetch` POST with `Content-Type: application/json`, `credentials: "omit"`, no other headers. No new dependency. - [ ] The measured byte size of a full report at the maximum history (`maxHistoryPoints` x all hosts) is stated in the PR and is well under the backend's 1 MiB body limit. - [ ] `vite.config.js` gains a dev-server proxy for `/api` to `http://127.0.0.1:8080` so `make dev` with a locally running `netwatch-server` exercises the real path; one line in README Getting Started says so. - [ ] Verified and summarised in the PR: with the backend running locally, it logs `report received` with the expected `host_count`; without a backend the page works and the debug log shows one debug-level failure line per outage, not one per interval. - [ ] Code follows the file's existing class-based structure (a reporter class beside `AppState`), with the report-building step a pure function of host state so https://git.eeqj.de/sneak/netwatch/issues/21 can test it. README Design section gets a short paragraph: what is sent, how often, to where. - [ ] `make check` green; `docker build .` green. `TODO.md` updated in the same commit. Commit title ends ` (closes #N)`. ## Implementation requirements - Do not change the backend or its schema. If the schema needs a change to be usable, stop, say so on the PR with the reading taken, and leave the backend alone. - Do not touch `nginx.conf` or any Dockerfile; the proxy route is https://git.eeqj.de/sneak/netwatch/issues/52. - No scripted edits (`sed -i`, `perl -pi`, awk, python rewrites); edit by hand, format only via `make fmt`. `make` targets and `script/` entrypoints only. No attribution trailers. model: claude-fable-5
clawbot added this to the 1.0.0 milestone 2026-09-21 09:47:41 +02:00
clawbot self-assigned this 2026-09-21 09:47:41 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/netwatch#53