diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..45448a4 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,236 @@ +# AGENTS.md — Project state, review findings, open items, and working rules + +**Last updated: 2026-08-11** (full-repo review). This file is the entry point for every new agent +session: what this repo is, what is finished, what is missing, and how to work here. Detail lives in +the linked documents — this file points, it does not duplicate. + +> **Maintenance rule (binding):** whenever you change this repo in a way that affects anything +> recorded here — completing an open item, making or reversing a decision, adding/removing a +> component, discovering a new gap — **update this file in the same session** (tick the checkbox, +> adjust the status table, bump the "Last updated" date). This file must always be written in +> **English**, even though the rest of the project is German. + +**How this file is loaded:** Claude Code does not read `AGENTS.md` natively; the root `CLAUDE.md` +imports it via `@AGENTS.md` (official recommended pattern). Other agents (Codex, Cursor, Copilot) +read `AGENTS.md` directly. Edit content here, not in `CLAUDE.md`. + +--- + +## Working rules + +### Karpathy guidelines (adopted as project standard) + +From [`multica-ai/andrej-karpathy-skills`](https://github.com/multica-ai/andrej-karpathy-skills), +behavioral rules derived from Andrej Karpathy's observations on LLM coding failures. They bias +toward caution over speed — for trivial tasks, use judgment. + +1. **Think before coding.** Don't assume. Don't hide confusion. Surface tradeoffs. State + assumptions explicitly; if multiple interpretations exist, present them — don't pick silently. + If a simpler approach exists, say so. Push back when warranted. If something is unclear, stop + and ask. +2. **Simplicity first.** Minimum code that solves the problem. Nothing speculative: no features + beyond what was asked, no abstractions for single-use code, no unrequested configurability, no + error handling for impossible scenarios. If 200 lines could be 50, rewrite. +3. **Surgical changes.** Touch only what you must. Don't "improve" adjacent code, comments, or + formatting; don't refactor what isn't broken; match existing style. Remove only orphans **your** + change created; mention (don't delete) pre-existing dead code. Every changed line should trace + directly to the request. +4. **Goal-driven execution.** Define success criteria, loop until verified. "Fix the bug" → write a + test that reproduces it, then make it pass. For multi-step tasks, state a brief plan with a + verify step per item. + +### Claude Code practices (current guidance, 2026) + +- Keep this file **concise and specific** — instructions concrete enough to verify ("run X before + Y"), markdown headers/bullets, no dense prose. Context files reduce adherence as they grow; + target roughly ≤200 lines of actual instruction. +- Don't record here what the code or git history already shows (directory dumps, dependency + lists) — record pitfalls, rationale, decisions, and conventions that differ from defaults. +- Conflicting instructions get picked arbitrarily — when updating, **remove** superseded rules + rather than stacking corrections. +- Verify loading with `/context` (file must appear under **Memory files**); edit via `/memory`. + +--- + +## What this project is + +Private replacement for the Audi *connect plug & play* app (discontinued end of 2026), for exactly +one vehicle (**Audi RS 4 Avant competition**), single user, self-hosted on Home Assistant, access +via Tailscale only. Read-only toward the vehicle — no remote control. Covers: vehicle status, trip +log, fuel log with Shell receipt parsing, service forecasting, insurance/tax, tire management. + +**License rule (hard):** Audi Type fonts, four-rings SVG, and model-badge SVGs are cleared **only +for this one private, unpublished installation**. Therefore `design-system/` is brand-free (it gets +uploaded to Claude Design), while the HA panel and the future sideload-only app may use the real +assets. Never mix these the other way around. + +**Reading order for a new session:** +1. This file (overview + open items) +2. `SPECIFICATION.md` — authoritative for the HA panel, incl. §7 "Known Gaps" +3. `COMPANION_APP_ARCHITECTURE.md` — authoritative for DataMetric360 (decided, barely built) +4. `AUDIT_2026-08-10.md` — accessibility/platform audit of the panel (partly done, rest below) +5. `bauauftrag.md` — **historical only**; code has diverged (see SPECIFICATION.md §7) + +## The three projects in this repo + +| Area | What | Status | +|---|---|---| +| `homeassistant/` | HA panel (`panel_custom`): pyscript backend + vanilla-JS frontend | ✅ **finished, in use** | +| `design-system/` | React component library `@audi-dash/ui`, brand-free, feeds Claude Design | ✅ done as a kit (20 components, 1,690 lines) | +| `companion-app/` | **DataMetric360** — successor app (Capacitor iOS/Android + HA iframe); will **replace** the panel | 🚧 data layer only (~930 lines TS), **no UI** | +| `design/` | Export of the Claude Design draft for DataMetric360 | 🚧 interim (wrong model, main screens only) | + +Root files: `dashboard-muster*.html` = original static prototype (superseded, reference only), +`bauauftrag.md`/`.html` = original build brief (historical), `DESIGN_BRIEF_DATAMETRIC360.md` = the +prompt for the Claude Design project. + +**`homeassistant/` in one paragraph:** 10 pyscript scripts + 4 modules (`pyscript/modules/`); trip +detection via the iPhone WLAN sensor with pause tolerance, two-stage trip completion via HA history +screening (odometer often updates only on the next trip), fill-up detection on fuel-level rise, +Shell PDF parser (`data/shell_beleg_parser.py`, subprocess, the only tested part of the repo), tire +km counter, backup, self-update, image management. Frontend: one file `www/audi-dashboard-app.js` +(3,130 lines, custom element, no framework/bundler), 5 tabs + ~19 detail routes, cache-busting via +`audi-dashboard-version.json` + loader stub. Entity IDs configured centrally in +`pyscript/modules/einstellungen.py` (the one file edited before install). Deploy: `update.ps1` +(robocopy to Samba share) or — still inactive — self-update from git. + +**`companion-app/` — what exists:** dependency-free, strictly typed TS data layer (`src/api/`): +REST client (`rest.ts`), WebSocket client with auth flow + reconnect backoff (`live.ts`), +persistent offline write queue (`warteschlange.ts`, strict FIFO), environment detection +capacitor/iframe/browser (`umgebung.ts`), types + entity table (`types.ts`), facade +`DataMetricApi` (`index.ts`). Smoke test ran 7/7 green against Docker HA `audi_ha_test` +(localhost:18123) — unauthenticated only; token-authenticated reads/writes untested. + +**DataMetric360 architecture (short — details in `COMPANION_APP_ARCHITECTURE.md`):** +- Future data source: **Teltonika FMM003** on the CAN bus, fully replacing the iPhone WLAN sensor + and the VAG integration. +- **Current data path (since 2026-08-11): Codec JSON → MQTT/TLS → Mosquitto add-on → HA.** Traccar + is **dropped** (the decision log deliberately remains in the architecture doc, marked ÜBERHOLT). +- Frontend access: HA REST + WebSocket with a long-lived access token (no `hass` object). +- External access: Cloudflare Tunnel + reverse proxy with a path allowlist; HA itself stays + unreachable. Domain **`datametric360.app`** registered (all-inkl, 2026-08-11). +- Distribution: **sideload only** (license reason) — hence real Audi assets are allowed there. +- Trip detection moves to FMM003 ignition; the pause-tolerance feature + (`fahrten_pausenzeit_min`) is a deliberate product decision and must be preserved. + +--- + +## Review findings (2026-08-11) + +### HA panel — known gaps (most also in SPECIFICATION.md §7) + +- **GPS is dead schema:** `start_lat/lon`, addresses, `route`, `avg_speed_kmh` never populated. + The trip-detail map draws a **fabricated** line via `fakeTrack()` + (`audi-dashboard-app.js:414`) — not a real track. +- **No GPS fallback in trip completion:** trips without an odometer match stay `status="offen"` + forever (`modules/fahrtabschluss_logik.py:16-20`). +- **RAM-only state:** running trip (`_fahrt_start_ts`) and fuel low-water-mark + (`_tiefststand_pct`) do not survive an HA restart. Deliberately deferred hardening. +- **Inactive features:** `BATTERIE_SENSOR = ""` (entire battery-history feature is a no-op) and + `UPDATE_REPO_URL = ""` (self-update inactive), both in `pyscript/modules/einstellungen.py`. + `www/bilder/` has no vehicle photos (all slots show placeholders); `steuer.faellig` unset. +- **Robustness:** `profil_lesen()` in `modules/profil.py` does not handle a missing/corrupt + `fahrzeugprofil.json` — all callers throw. +- **Tests:** only the receipt parser is tested (`data/tests/test_shell_beleg_parser.py`, 10 real + receipts) — and its test PDFs are gitignored, so a fresh clone can't run it. Backend and + frontend: no tests, no CI. +- **Leaflet via CDN:** trip map needs public internet in addition to the Tailscale tunnel. + +### Documentation drift (small fixes; align docs to code) + +- `homeassistant/README.md:99`, `INSTALL.md:204`, and the header comment + `audi-dashboard-app.js:13-15` claim the statistics view shows sample numbers — **false**; + `vStat()` computes real values from `TRIPS`/`FILLS`. +- `INSTALL.md` step 4 names variables that no longer exist (`DOORS_SENSOR`, `WINDOWS_SENSOR`, + `LOCK_ENTITY`, `BATTERY_VOLTAGE_SENSOR`) — actual names: `TUER_SENSOREN`/`FENSTER_SENSOREN`/ + `TUERSCHLOSS_SENSOREN`/`BATTERIE_SENSOR`. +- `homeassistant/README.md:110` mentions the removed 97% full-tank rule (removal documented in + `belegverarbeitung.py:18-20`); the README file list omits 5 pyscript files. +- Obsolete comment `belegverarbeitung.py:41` ("TODO: Datei ablegen" — file has long existed). + +### Audit leftovers (`AUDIT_2026-08-10.md` §4, deliberately left open) + +- 🟠 Swipe-to-delete has no gesture-free fallback — screen-reader/switch-control users cannot + delete trips/fill-ups. Needs a design decision (long-press vs. "…" button vs. action sheet). +- 🟡 Popup close-by-tap-outside is not keyboard-reachable (needs a quick manual check). +- 🟡 Self-host Leaflet JS/CSS (tiles necessarily stay remote). +- Audit's own note: these three may be better done in DataMetric360 than retrofitted — the panel + gets replaced anyway. + +### companion-app / design-system + +- **Not wired together:** `companion-app` does not reference `@audi-dash/ui` anywhere (no + dependency, no import, no workspace root). The link exists only in prose. +- Both packages: no `node_modules`, no `dist` — smoke tests need `npm install` first + (design-system additionally `npm run build`; `scripts/smoke.mjs` imports from `../dist/`). +- No unit tests, no Storybook (substitute: SSR smoke over 21 cases in design-system). +- `design/` export (2026-08-11) has two known, already-commissioned fixes not yet in the export: + shows **RS 6 instead of RS 4**, and **16 sub-pages** the HA panel already has are missing + (list in `design/README.md`). + +--- + +## Open items + +### A) Build DataMetric360 (the big block) + +- [ ] Fix the Claude Design draft (RS 4, not RS 6) and extend it by the 16 missing sub-pages; + then re-export to `design/` +- [ ] `companion-app`: set up Vite + React + Capacitor scaffold; wire `@audi-dash/ui` as a real + dependency (possibly add a workspace/monorepo root) +- [ ] Implement the screens from the design draft on top of the existing `DataMetricApi` layer +- [ ] Add Audi assets (fonts/rings/badges) at implementation time from `homeassistant/www/` — + **never** into `design-system/` +- [ ] Secure storage for the LLAT (iOS Keychain / Android Keystore via Capacitor plugin; the + `ablageSetzen()` hook already exists) +- [ ] Onboarding: manual token paste (required); QR scan only if it stays simple (QR generated + locally under HA `/local/`, architecture §3) +- [ ] Authenticated smoke tests of the data layer (reads, service calls, queue round-trip) + against `audi_ha_test` with a real token +- [ ] Offline UX per design brief (offline marker, visible pending queue) + +### B) Infrastructure / commissioning (partly waits for FMM003 hardware) + +- [ ] Switch `datametric360.app` nameservers at all-inkl to Cloudflare ("full setup") — + prerequisite for the tunnel; domain carries nothing else, so this is consequence-free +- [ ] Decide hostname split (app on apex + API on `api.` subdomain, or vice versa) +- [ ] Choose reverse proxy (Nginx Proxy Manager vs. Traefik) — **can be done before hardware** + against the existing HA API +- [ ] Define the reverse-proxy path allowlist (depends on final entity/service names) +- [ ] Install/wire the FMM003; record firmware version (Codec JSON is firmware-dependent) +- [ ] Generate TLS certificates for Mosquitto + device (small private CA); FMM003 refuses MQTT + without them +- [ ] Decide broker reachability for the vehicle: port-forward 8883 vs. VPS broker with + Mosquitto bridge over Tailscale +- [ ] Capture the first real Codec JSON message (`mosquitto_sub`/MQTT Explorer) and build the + field mapping from it — **do not guess beforehand** (explicit decision) +- [ ] Move trip detection to FMM003 ignition (reuse the `fahrterkennung.py` pattern, keep pause + tolerance); then remove `sensor.iphone_wifi_connection` from `einstellungen.py` + +### C) Maintain the existing HA panel (low priority — being replaced) + +- [ ] Fix documentation drift (statistics claim, INSTALL variable names, README gaps, obsolete + TODO comment) — text-only changes +- [ ] Harden `profil_lesen()` against missing/corrupt `fahrzeugprofil.json` +- [ ] Decide whether the 3 audit leftovers get fixed here or only in DataMetric360 +- [ ] Optional: persist the RAM-only states (trip start, fuel low-water-mark) — deliberately + deferred; may become moot with the FMM003 switch +- [ ] Upload vehicle photos to `www/bilder/`, set `steuer.faellig` (operational data, not code) + +### D) Once the panel is superseded + +- [ ] **Archive** `audi-dashboard-app.js`, don't delete (settled decision, architecture §1) + +--- + +## Working conventions (observed — keep them) + +- German is the project language: identifiers, comments, commits, UI texts. Exceptions: + `design-system/` uses English props/JSDoc (Claude Design audience) — and **this file**, which is + English by rule. +- Decisions are logged, including rejected ones (see the Traccar section of the architecture + doc); superseded sections stay in place marked "ÜBERHOLT" rather than being deleted. +- Numbers in `de-DE` format; font weights 300/400 only, never ≥600 (only those cuts exist). +- Real vehicle/movement data stays local (`data/` contents and receipt PDFs are gitignored). +- Security principle: HA is never publicly exposed; only narrowly scoped surfaces (MQTT broker, + proxy allowlist) may be exposed, each by explicit decision. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..b96bdd3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,11 @@ +@AGENTS.md + +## Claude Code + +- `AGENTS.md` above is the single source of truth for project state, rules, and open items — + edit it there, keep this file as a thin shim. +- Remember the AGENTS.md maintenance rule: update it (in English) in the same session whenever + your changes affect anything it records. + +