6 Commits
Author SHA1 Message Date
nilsandClaude Opus 5.5 9226616261 Grafana's read-only InfluxDB token is made automatically
The read-only token for Grafana needed a manual influx command and a
Secret. InfluxDB generates every token but the admin one and ignores a
chosen value (tested on 2.7.12), so it cannot be preset in a Secret.

Instead an init container in the Grafana pod creates it at every start
with the admin token, deletes the one from the previous start, and
writes only the read-only token to a memory-backed volume; the
provisioned datasource reads it with $__file{/run/influx/token}. The
Grafana process never sees the admin token. The grafana-influx Secret
is gone from the template and the README.

Tested in podman: InfluxDB 2.7.12, the script run twice as the Grafana
user (the old token is replaced, not piled up), and Grafana 13.2.3
reporting the datasource healthy with the file-based token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 19:05:58 +02:00
nilsandClaude Opus 5.5 a5db5604d3 Code review fixes: app 2.9.0, server 2.2.0
Telemetry no longer loses queued batches. The server drops a bad value,
or a sample without a plausible time, instead of rejecting the batch,
and answers 200 with what it dropped. The app sends only values inside
the server's ranges (speed as a magnitude, so reversing is fine) and no
samples before the head unit's clock is set.

Server:
- Pairing hands out and accepts a token only after the device is saved;
  a failed save leaves the request pending.
- A paired token serves only the installation id it was paired with
  (403 otherwise); the shared INGEST_TOKEN still serves any.
- Wrong-password lockouts and open pairing requests are limited per
  client address (last X-Forwarded-For entry), so a stranger cannot
  lock the owner out; a car starting again replaces its own request.
- ABRP forwarding skips samples stamped ahead of the server's clock,
  which used to stop it until a restart.

App:
- Settings written to plaintext during a keystore failure move back
  into encrypted storage; the stored installation id wins.
- The installation id is derived from ANDROID_ID on first start, so a
  reinstall finds its history; a stored or imported id still wins.
- The scanned config file is deleted after import (it holds the token).
- GPS stops while live telemetry is off or the server unconfigured, and
  pauses while parked and idle, keeping the fix the car parked with.
- Range estimates use the monotonic clock.
- One HTTP helper (ServerHttp) for telemetry, sync and pairing.
- Last Turkish strings translated; mise logs shows the NilsMG4 tags.

Grafana reads InfluxDB with its own read-only token (new grafana-influx
Secret, created by hand as described in k8s/README.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 00:36:19 +02:00
nilsandClaude Opus 5.5 cee0eaeab3 Grafana: memory request 512Mi, limit 1Gi
It runs at about 406 MiB in the cluster, too close to the 512Mi limit:
long-range dashboard queries could get it OOM-killed. The request now
matches what it uses, so the scheduler reserves it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 21:45:56 +02:00
nilsandClaude Opus 5.5 756ae65d0b Grafana: startup probe so a slow first start is not killed
Grafana's first start creates and migrates its database: 44 s at
0.5 CPU and 3 minutes at 0.1 CPU (measured with 13.2.3 on an empty
volume). With only 50m requested, the liveness probe (30 s delay,
3 x 30 s) restarted it mid-migration, in a loop, and readiness never
passed.

- startupProbe on /api/health allows up to 10 minutes; liveness and
  readiness start only after it succeeds.
- 5 s timeouts on all probes instead of the 1 s default.
- Requests raised to 250m CPU / 256Mi (measured about 240 MB in use);
  still no CPU limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 21:43:49 +02:00
nilsandClaude Opus 5.5 315586f94c Move the server to car.k8s.stinnesbeck.com
The server's host is car.k8s.stinnesbeck.com, not car.stinnesbeck.com:
IngressRoute, PUBLIC_URL (so the pairing QR code points there), the
app's pre-filled server URL and hint, and the docs. Grafana's
placeholder host follows to car-grafana.k8s.stinnesbeck.com, so one
*.k8s.stinnesbeck.com default certificate covers both. App 2.4.1 for the
new default; the server image is unchanged (its URL comes from the
manifest).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 18:08:35 +02:00
nilsandClaude Opus 5.5 5473ab1c2b Dashboards in Grafana; clean up after the Next.js app
- k8s/grafana.yaml: Grafana 13.2.3 with a 1Gi PVC, sign-up and
  anonymous access off. The InfluxDB datasource (URL and token from the
  environment) and three dashboards — Live, Consumption, Charging — are
  provisioned from k8s/grafana/ via kustomize-generated ConfigMaps.
- server.yaml for the Go server (port 8080, UID 65532, smaller limits),
  image tag 2.0.0. The NetworkPolicy now admits Grafana to InfluxDB.
- ingress.yaml: IngressRoutes for car.stinnesbeck.com and Grafana
  (placeholder host car-grafana.stinnesbeck.com) with tls: {}, using
  Traefik's default certificate; the cert-manager Certificate is gone.
- secrets.example.yaml: drops the dashboard secrets, adds grafana-admin.
- AGENTS.md loses its Next.js block; SPECS.md describes the new setup.

The removal of web/ (the Next.js app) and of the stale .next/ cache
upstream had committed already landed in 51e6f6f, which was staged
together with the Go server by mistake.

Checked end to end in podman (Go server + InfluxDB 2.7.12 + Grafana
13.2.3): all 25 dashboard queries return the expected data, and the
dashboards were rendered with headless Chromium. Manifests validated
offline with kustomize and kubeconform. Nothing applied to a cluster.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 15:18:09 +02:00