Plan the car server (InfluxDB 2, ABRP forwarder, k8s manifests) in SPECS.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 13:51:07 +02:00
co-authored by Claude Opus 5.5
parent de2428786a
commit d4fb4ba3af
+62
View File
@@ -7,6 +7,68 @@ what has been changed, and what is still to do.
- Upstream: https://github.com/fatihdonmezdev/FatihsMG4 (itself a fork of malys / EVABRPUploader
and Leon Kernan / ABRP_Uploader). Credited in the app's About dialog.
## Plan: car server at car.stinnesbeck.com
The car sends everything to our own server. The server stores it and forwards live telemetry to
ABRP, so the ABRP token lives only on the server, never in the APK.
```
car ──live telemetry───▶ car.stinnesbeck.com ──▶ ABRP api.iternio.com/1/tlm/send
──daily totals─────▶ │
──charging sessions▶ ▼
InfluxDB 2
```
### Server — extend `web/` (Next.js)
- **Storage: MongoDB → InfluxDB 2.** Rewrite `web/src/lib/mongo.ts` / `data.ts` against one bucket
(tag `installationId` on every point):
| Measurement | Timestamp | Tags | Fields |
|---|---|---|---|
| `telemetry` | sample time | — | soc, power, speed, lat, lon, heading, elevation, is_charging, is_dcfc, is_parked, capacity, soe, odometer, est_battery_range, batt_temp, cabin_temp, ext_temp, hvac_setpoint, voltage, current, tire_pressure_fl/fr/rl/rr |
| `consumption_daily` | the day, 00:00 UTC | — | km, kwh, hours, socDrop, sohPercent |
| `charging_session` | startedAt | sessionId | endedAt, durationSeconds, energyKwh, gridEnergyKwh, pricePerKwh, totalCost, start/endSocPercent |
| `charging_curve` | point time | sessionId | powerKw, socPercent |
Same measurement + tags + timestamp overwrites, so the car's retries stay idempotent
(MongoDB used unique indexes for that).
- **New endpoint `POST /v1/telemetry`:** a batch of live samples, ingest-token auth, validated
and bounded like the existing endpoints.
- **ABRP forwarder:** after storing, forward the newest sample to `tlm/send` with `ABRP_API_KEY` and
`ABRP_USER_TOKEN` from the environment. Rate-limited; a failed forward is logged but not
retried, since stale live data is useless to ABRP. Off when the token is unset.
- **Existing endpoints stay:** `PUT /v1/consumption/daily`, `PUT /v1/charging-sessions/:id`,
`GET /v1/consumption/history/:id`, the dashboard and `/v1/health`.
- **Self-hosting:** drop the Vercel assumptions, `output: "standalone"`, a `Dockerfile`, and
`ensureIndexes()` replaced by bucket checks at startup.
### Car app
- Restore the live telemetry payload and upload cadence from before `ea8032a` (`TelemetryPayload`,
`UploadCadence`, location access), sending to the server instead of ABRP.
- Server URL and ingest token: open question, see below.
- Generate our own `CONSUMPTION_INSTALLATION_ID`.
### Image and deployment
- Image: `git.stinnesbeck.com/nils/mg4-server:<version>`, pushed to the forge's registry
(needs a registry login on the build machine).
- `k8s/` with plain manifests: Namespace, InfluxDB StatefulSet + PVC + Service (cluster-internal),
server Deployment + Service + Ingress for `car.stinnesbeck.com` (TLS), and Secret *templates*
with placeholder values only.
- **Nothing is ever applied to the cluster by us.** Nils applies the manifests.
### Open questions
- [ ] Run InfluxDB inside the cluster from our manifests (assumed), or use an existing instance?
- [ ] Ingress class and TLS setup (e.g. cert-manager `ClusterIssuer` name), or an existing wildcard
certificate Secret?
- [ ] Car config: bake the server URL and ingest token into the APK at build time (as upstream
does), or enter them in the app, which restores the settings tab with the config-file import?
In the app keeps the token out of the APK.
- [ ] ABRP API key: the open-source default key from upstream, or our own?
## To do
- [ ] **About dialog link and QR code → https://git.stinnesbeck.com/nils/mg4.**