netwatch-server is an MIT-licensed Go HTTP backend by [@sneak](https://sneak.berlin) that receives telemetry reports from the NetWatch SPA and persists them as zstd-compressed JSONL files on disk. ## Getting Started From this directory (`backend/`): ```bash # Build and run locally make run # Run the backend's tests, lint, and format check make check ``` From the repo root, one directory up — `Dockerfile.backend` lives there and its build context is the repo root, so there is no `docker` target here: ```bash # Build both images, including netwatch-server make docker # Run the backend image docker run -p 8080:8080 netwatch-server ``` ## Entrypoints This project follows the same [Scripts to Rule Them All](https://github.com/github/scripts-to-rule-them-all) pattern as the repo root: the implementations live in `backend/script/` and the targets in `backend/Makefile` are thin shims that call them. The repo root's `script/test`, `script/lint`, `script/fmt` and `script/fmt-check` call these too, so the root `make check` covers the backend. - `script/build` — compile `netwatch-server` with the version and architecture stamped in via ldflags (statically linked on Linux) - `script/test` — run the Go tests under a 30-second timeout - `script/lint` — assert `.golangci.yml` still matches its pinned sha256, then run golangci-lint - `script/fmt` — format the Go sources (writes) - `script/fmt-check` — check Go formatting (read-only) - `script/check` — run test, lint, and fmt-check - `script/run` — build and run the server locally - `script/clean` — remove build artifacts There is deliberately no `hooks` target here: the repo has exactly one pre-commit hook installer, the root `script/install-precommit`, and the hook it installs runs the root `script/check`, which gates both halves of the repo. There is no `docker` target either: `Dockerfile.backend` lives at the repo root and builds with the repo root as its context, so the backend image is built by the root `make docker` and by `script/cibuild`. ## Rationale The NetWatch frontend collects latency measurements from the browser but has no way to persist or aggregate them. This backend provides a minimal `POST /api/v1/reports` endpoint that buffers incoming reports in memory and flushes them to compressed files on disk for later analysis. ## Design The server is structured as an `fx`-wired Go application under `cmd/netwatch-server/`. Internal packages in `internal/` follow standard Go project layout: - **`config`**: Loads configuration from environment variables and config files via Viper. - **`handlers`**: HTTP request handlers for the API (health check, report ingestion). - **`reportbuf`**: In-memory buffer that accumulates JSONL report lines and flushes to zstd-compressed files when the buffer reaches 10 MiB or every 60 seconds. - **`server`**: Chi-based HTTP server with middleware wiring and route registration. - **`healthcheck`**, **`middleware`**, **`logger`**, **`globals`**: Supporting infrastructure. ### Configuration | Variable | Default | Description | | ---------- | ------------------ | --------------------------------- | | `PORT` | `8080` | HTTP listen port | | `DATA_DIR` | `./data/reports` | Directory for compressed reports | | `DEBUG` | `false` | Enable debug logging | ### Report storage Reports are written as `reports-.jsonl.zst` files in `DATA_DIR`. Each file contains one JSON object per line, compressed with zstd. Files are created with `O_EXCL` to prevent overwrites. ## TODO - Add integration test that POSTs a report and verifies the compressed output - Add report decompression/query endpoint - Add metrics (Prometheus) for buffer size, flush count, report count - Add retention policy to prune old report files ## License MIT. See [LICENSE](LICENSE). ## Author [@sneak](https://sneak.berlin)