Nereus/docs/roadmap.md

243 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Nereus delivery roadmap
Updated: 2026-08-28
`[x]` means locally verified. `[~]` means implemented but awaiting a real
integration environment. `[ ]` means not implemented. `[H]` is human-owned and
must not be edited by agents.
Update this file in the same change that completes or materially changes a
task. Mark a task `[x]` only after its stated verification passes.
## API service
- [x] Create the Go 1.26 module and dependency lock file.
- [x] Create the idempotent `buoys` table migration.
- [x] Create the idempotent `readings` table migration.
- [x] Create `idx_readings_buoy_time` idempotently.
- [x] Parse `PORT`, `CHAOS_ERROR_RATE`, and `LOG_LEVEL`.
- [x] Preserve the build-injected `APP_VERSION` value.
- [x] Require `DATABASE_URL` without logging it.
- [x] Start HTTP without waiting for PostgreSQL.
- [x] Retry migrations while PostgreSQL is unavailable.
- [x] Keep `/healthz` independent of PostgreSQL.
- [x] Require a reachable, migrated database for `/readyz`.
- [x] Implement `GET /api/v1/buoys`.
- [x] Implement `POST /api/v1/buoys`.
- [x] Implement `GET /api/v1/buoys/{id}`.
- [x] Implement `DELETE /api/v1/buoys/{id}`.
- [x] Implement filtered, paginated `GET /api/v1/readings`.
- [x] Implement `POST /api/v1/readings`.
- [x] Implement the real grouped aggregate query.
- [x] Bound JSON request bodies and return JSON errors.
- [x] Restrict chaos injection to `/api/v1/*`.
- [x] Expose all five required Prometheus metrics.
- [x] Use chi route templates for the HTTP `path` label.
- [x] Enable OTLP/gRPC tracing only when configured.
- [x] Create HTTP spans and child database spans.
- [x] Emit structured request logs containing `trace_id`.
- [x] Add table-driven handler tests without a live database.
- [x] Test chaos and unaffected health behavior.
- [x] Add a `testing.Short()`-guarded PostgreSQL integration test.
- [x] Pass `go test -short ./...`.
- [x] Pass `go vet ./...`.
- [x] Build with `CGO_ENABLED=0`.
- [x] Run the integration test against PostgreSQL 17.
- [x] Test database failure behavior on every data endpoint.
- [x] Assert exact metric names and route-template labels in tests.
- [x] Test malformed and oversized JSON request bodies.
- [x] Run `golangci-lint run` with the CI-selected version.
## Load generator
- [x] Create the standalone Go 1.26 module.
- [x] Require `TARGET_URL` and default `RPS` to 5.
- [x] Reuse existing buoys or seed 42 validated offshore buoys.
- [x] Generate the 60/25/15 request mix.
- [x] Generate plausible synthetic reading values.
- [x] Count HTTP statuses and network errors.
- [x] Log a JSON status summary every ten seconds.
- [x] Continue traffic while requests and seeding fail.
- [x] Retry seeding without blocking read traffic.
- [x] Handle SIGTERM and SIGINT.
- [x] Keep the implementation below 200 lines.
- [x] Pass `go vet` and a static build.
- [x] Test request weighting deterministically.
- [x] Test seeding against an empty `httptest` API.
- [x] Test continued traffic through repeated HTTP 500 responses.
- [x] Run against the real API for at least five minutes.
- [x] Confirm Prometheus receives continuous request samples.
## Container build and local Compose
- [x] Create the API builder stage from `golang:1.26-alpine`.
- [x] Cache dependencies before copying API source.
- [x] Build with `CGO_ENABLED=0` and `-ldflags "-s -w"`.
- [x] Inject `APP_VERSION` with `-X`.
- [x] Copy only the API binary into `gcr.io/distroless/static:nonroot`.
- [x] Create the load-generator multi-stage image.
- [x] Use `gcr.io/distroless/static:nonroot` for the load generator.
- [x] Add the required `.dockerignore` exclusions.
- [x] Confirm both images run non-root and read-only.
- [x] Confirm the API image is below 25 MB (7,815,877 bytes locally).
- [x] Add API, PostgreSQL 17, and OTEL Collector to local Compose.
- [x] Add the PostgreSQL healthcheck.
- [x] Make the API wait on healthy PostgreSQL in Compose.
- [x] Verify `docker compose up` reaches API readiness.
- [x] Keep Mini PC and local-development Compose files separate.
## Static web dashboard
- [x] Create the no-build static HTML entry point.
- [x] Create the dark teal/navy glass visual system.
- [x] Replace decorative background waves with an operational chart grid.
- [x] Keep version, health, and error panels visible together.
- [x] Show the build-injected API version from the existing health response header.
- [x] Poll `/healthz` every two seconds.
- [x] Poll `/readyz` every two seconds.
- [x] Show each health indicator's last transition timestamp.
- [x] Count non-2xx `/api/v1/*` browser responses.
- [x] Calculate the rolling 60-second HTTP error rate.
- [x] Distinguish network-offline events from HTTP errors.
- [x] Preserve and grey the last known telemetry values offline.
- [x] Recover automatically when the API returns.
- [x] Add a fully local Natural Earth buoy map and pulsing markers.
- [x] Add animated reading charts.
- [x] Keep all API calls same-origin and relative.
- [x] Remove all frontend runtime dependencies on external hosts.
- [x] Verify all panels fit at 1280×720 without page scrolling.
- [x] Create the unprivileged nginx image.
- [x] Create the separate Mini PC Traefik Compose file.
- [x] Test the finished offline/degraded rendering without API connectivity.
- [x] Test the rendered dashboard while the API returns HTTP 500 responses.
## Observability
- [x] Receive OTLP/gRPC traces in the Collector.
- [x] Export traces from the Collector to Tempo.
- [x] Ship structured Kubernetes pod logs to Loki with the cluster Collector.
- [x] Start Loki locally and verify its Grafana data source readiness.
- [x] Configure Prometheus to scrape `/metrics`.
- [x] Add request-rate, error-rate, and latency panels.
- [x] Add database-operation latency panels.
- [x] Add readings-ingested and active-buoy panels.
- [x] Add a deployed-version dashboard variable.
- [x] Correlate logs and traces using `trace_id` after cluster log ingestion exists.
- [x] Add API error-rate, latency, readiness, and scrape alerts.
- [~] Route warning and critical alerts to Discord; configuration validates and awaits the owner-provided sealed webhook.
- [x] Load the dashboard and evaluate all six PromQL queries.
- [x] Trigger chaos and distinguish the failing version in Grafana.
## Fedora 44 host provisioning
- [x] Separate node 1 and node 2 inventory groups.
- [x] Pin the project k3s version.
- [x] Reject managed hosts that are not Fedora 44.
- [x] Install common host dependencies.
- [x] Enable firewalld.
- [x] Trust the configured pod and service CIDRs.
- [x] Open VXLAN port 8472/UDP between nodes.
- [x] Open kubelet port 10250/TCP between nodes.
- [x] Open API server port 6443/TCP on node 1.
- [x] Install node 1 as the k3s server.
- [x] Install node 2 as a k3s agent.
- [x] Keep the cluster token out of repository files and output.
- [x] Enable both k3s systemd services.
- [x] Wait for every Kubernetes node to become Ready.
- [x] Add the equivalent manual configuration checklist.
- [x] Document Terraform-to-Ansible inventory handoff.
- [x] Keep libvirt addresses, bridge rules, and VM network profiles out of the reusable Ansible roles.
- [x] Run the playbook twice on two clean Fedora 44 QEMU machines.
- [x] Confirm the second run reports no unintended changes (`changed=0`).
- [x] Restrict firewall sources to actual node/operator networks.
- [x] Confirm SELinux remains enforcing on both QEMU machines.
- [x] Reboot both QEMU machines and confirm automatic recovery.
- [x] Disconnect and reconnect node 2, then confirm it rejoins.
- [x] Record tested minimum CPU, memory, and disk requirements.
## One-command QEMU lab
- [x] Check QEMU, libvirt, cloud-utils, Ansible, SSH, ping, and KVM.
- [x] Install missing dependencies on a Fedora workstation.
- [x] Enable libvirt and its default network.
- [x] Discover and cache the Fedora 44 x86_64 cloud image.
- [x] Keep SSH and VM state outside the repository.
- [x] Generate cloud-init media for both nodes.
- [x] Create reusable copy-on-write disks.
- [x] Create each VM with two vCPUs and 3 GiB RAM.
- [x] Assign deterministic addresses to both local VMs.
- [x] Wait for ICMP ping and SSH on both nodes.
- [x] Generate the Ansible inventory automatically.
- [x] Configure both nodes automatically.
- [x] Check Ansible reachability, k3s files, and binaries.
- [x] Check firewalld, k3s services, ports 6443 and 10250.
- [x] Check Kubernetes node readiness.
- [x] Add `check`, `stop`, and explicit `destroy` actions.
- [x] Execute `lab.sh up` with working `/dev/kvm` and pass the full verification.
- [x] Reboot both local VMs and pass the bounded post-reboot service and node checks.
- [x] Execute `lab.sh check` after a workstation reboot.
- [x] Test recovery from an interrupted image download and validate the resumed QCOW2.
- [x] Test recovery after node 2 is deleted manually and rejoin it with a fresh identity.
- [~] Test on a workstation with no dependencies installed; the reproducible fresh-VM path is implemented and awaits a second host.
- [x] Decide whether an aarch64 image path is required; keep the lab x86_64-only.
- [ ] After final sign-off, destroy the QEMU lab and remove packages installed only for it with Pacman's dependency-aware cleanup.
## Local k3d rollback mechanism
- [x] Define one local server and two local agent nodes.
- [x] Map Traefik to host ports 8080 and 8443.
- [x] Add lean kube-prometheus-stack values.
- [x] Add the synthetic Argo Rollouts analysis harness.
- [x] Add an idempotent `up/check/destroy` command and verify fresh creation and reconciliation.
- [x] Install Argo Rollouts.
- [x] Install kube-prometheus-stack with the local values.
- [x] Apply the synthetic harness.
- [x] Prove `vector(0.0)` permits promotion.
- [x] Change the test value to `vector(1.0)`.
- [x] Prove failed analysis aborts promotion with `vector(0.9)`.
- [x] Tear down and recreate the test from scratch.
## Human-owned deployment and infrastructure
- [x] Define libvirt infrastructure and Helm platform stacks under `terraform/`.
- [x] Export stable node addresses to an Ansible inventory without provisioner hooks.
- [H] Create Kubernetes base resources and overlays. Agent-authored 2026-08-21 at the owner's request; builds and server dry-runs pass, not applied.
- [H] Create API and load-generator workloads. Agent-authored 2026-08-21; not applied.
- [H] Create active and preview Services. Agent-authored 2026-08-21; not applied.
- [H] Create the Prometheus ServiceMonitor. Agent-authored 2026-08-21; not applied, scrape not confirmed.
- [H] Create the real error-rate AnalysisTemplate. Agent-authored 2026-08-21; PromQL never evaluated against real series.
- [H] Configure blue-green promotion and automated rollback. Agent-authored 2026-08-21; promotion and abort paths untested with the real API.
- [H] Maintain Forgejo Actions and GitHub mirror workflows.
- [x] Install Sealed Secrets, commit the encrypted database resource, and verify the fresh-volume cutover.
## Forgejo CI/CD
- [x] Run API and load-generator race tests, vet, and pinned lint in containers.
- [x] Scan committed history and the working tree for secrets.
- [x] Scan release configuration and images for high or critical findings.
- [x] Build immutable commit-SHA API, load-generator, and web image tags.
- [x] Keep active and preview traffic flowing during rollout analysis.
- [x] Run the Forgejo workflow after a private `docker` runner and encrypted secrets are configured.
- [x] Publish images and execute the first automated production rollout.
## End-to-end acceptance
- [ ] Provision two clean Fedora hosts.
- [ ] Reboot both hosts before platform installation.
- [x] Install the cluster platform components.
- [x] Deploy PostgreSQL and wait for health.
- [x] Verify API liveness before database readiness.
- [x] Verify readiness after migrations complete.
- [x] Deploy the load generator and observe continuous samples.
- [x] Send one request to every API endpoint in the local Compose stack.
- [x] Verify every required metric and exact label name locally.
- [x] Verify an HTTP trace contains a child database span.
- [x] Correlate one stdout request log and Tempo trace by `trace_id`.
- [x] Promote a healthy preview through analysis.
- [x] Deploy a preview with a nonzero chaos rate.
- [x] Observe preview errors in Prometheus.
- [x] Confirm analysis aborts the unhealthy promotion.
- [x] Confirm the active Service remains on the healthy version.
- [x] Confirm load generation continues throughout failure.
- [x] Confirm the Mini PC page remains usable with the cluster off.
- [x] Capture reproducible, non-secret evidence needed for the final project report.