Merge branch 'umsetzung-datametric360': Companion-App-Phasen 1-10 uebernehmen
Bringt die vollstaendig gebaute DataMetric360-App zusammen (React/Vite, 21 Screens, Audi-Assets, PWA + native Capacitor-Huelle, 90+9 Tests) sowie die profil_lesen()-Haertung gegen fehlende/kaputte Profildatei zusammen. Konfliktaufloesung: - AGENTS.md, INSTALL.md, README.md: main-Fassung war jeweils die chronologisch neuere, uebernommen und um die durch den Merge tatsaechlich erledigten Punkte ergaenzt (profil_lesen()-Haertung, Audit-Reste-Entscheidung). - fahrterkennung.py: toten WLAN-Zweig vom Branch verworfen, Zuendungs- basierte Erkennung von main behalten. - homeassistant/FMM003_MAPPING.md (MQTT/Mosquitto-Ansatz vom 2026-08-11, vor der Umstellung auf flespi) bewusst nicht uebernommen - main nutzt seit 2026-08-12 flespi als alleinigen FMM003-Datenweg. UMSETZUNGSPLAN.md Phase 13 entsprechend als ueberholt markiert, verweist auf AGENTS.md als massgeblich. - REVIEW_main_2026-08-13.md, ha_install.md (add/add): main-Fassung war die spaetere Revision derselben Dokumente, uebernommen. Die von REVIEW_main_2026-08-13.md befuerchtete Merge-Falle (profil_lesen() gibt jetzt None zurueck, main-seitige Aufrufer pruefen das nicht) wurde verifiziert als bereits entschaerft: alle 5 Aufrufstellen im gemergten Stand (backup.py x2, fahrterkennung.py, frontend_veroeffentlichung.py, reifenzaehler.py, tankerkennung.py) sind None-sicher. installationspaket/ nicht Teil dieses Commits (gitignored, wird bei Bedarf neu zusammengestellt).
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
# AGENTS.md — Project state, review findings, open items, and working rules
|
||||
|
||||
**Last updated: 2026-08-13** (design/CI review added, see `DESIGN_REVIEW_2026-08-13.md`). This file is the entry point for every new agent
|
||||
**Last updated: 2026-08-13** (merged the `umsetzung-datametric360` branch — companion app phases
|
||||
1–10 done, see `UMSETZUNGSPLAN.md`). 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.
|
||||
|
||||
@@ -73,19 +74,22 @@ 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)
|
||||
2. `UMSETZUNGSPLAN.md` — the step-by-step execution plan for all open items (13 phases with
|
||||
commands and acceptance criteria); when working on an open item, follow the plan's phase
|
||||
3. `SPECIFICATION.md` — authoritative for the HA panel, incl. §7 "Known Gaps"
|
||||
4. `COMPANION_APP_ARCHITECTURE.md` — authoritative for DataMetric360 (decided, phases 1–10 built)
|
||||
5. `AUDIT_2026-08-10.md` — accessibility/platform audit of the panel (partly done, rest below)
|
||||
6. `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** |
|
||||
| `homeassistant/` | HA panel (`panel_custom`): pyscript backend + vanilla-JS frontend | ✅ **finished, in use** — to be replaced by the app |
|
||||
| `testumgebung/` | Script that rebuilds a throwaway Home Assistant with the real backend | ✅ new, reproducible |
|
||||
| `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) |
|
||||
| `companion-app/` | **DataMetric360** — successor app (web, PWA, native iOS/Android via Capacitor, HA iframe); will **replace** the panel | ✅ **all 21 screens built and tested**; runs natively on iOS with real data |
|
||||
| `design/` | Export of the Claude Design draft for DataMetric360 | 🚧 interim and now behind the code — screens were derived from the old panel instead (owner's decision) |
|
||||
|
||||
Root files: `dashboard-muster*.html` = original static prototype (superseded, reference only),
|
||||
`bauauftrag.md`/`.html` = original build brief (historical), `DESIGN_BRIEF_DATAMETRIC360.md` = the
|
||||
@@ -103,12 +107,12 @@ Fahrzeug einrichten → Setup), stored as overrides in `data/entitaeten.json`;
|
||||
`pyscript/modules/einstellungen.py` holds only the built-in defaults. 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.
|
||||
**`companion-app/` — what exists:** the full app. Data layer (`src/api/`: REST, WebSocket with
|
||||
reconnect backoff, persistent offline write queue, credential storage), domain logic
|
||||
(`src/daten/`: profile adapter, statistics, service forecast, data context), all 21 screens
|
||||
(`src/screens/`), Audi assets (`src/assets/audi/`), PWA manifest and icons. Verified by 90 unit
|
||||
and render tests plus 9 checks against a live Home Assistant. `npm run dev` in the repo root
|
||||
starts it; `testumgebung/aufsetzen.sh` provides the server side.
|
||||
|
||||
**DataMetric360 architecture (short — details in `COMPANION_APP_ARCHITECTURE.md`):**
|
||||
- Future data source: **Teltonika FMM003** on the CAN bus, fully replacing the iPhone WLAN sensor
|
||||
@@ -170,7 +174,7 @@ formatting hold everywhere; `design-system/` is verifiably brand-free.
|
||||
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)
|
||||
### Documentation drift ✅ FIXED 2026-08-11 (kept as a record of what was wrong)
|
||||
|
||||
- `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**;
|
||||
@@ -179,19 +183,21 @@ formatting hold everywhere; `design-system/` is verifiably brand-free.
|
||||
`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)
|
||||
### Audit leftovers — two of three now fixed in the new app
|
||||
|
||||
- 🟠 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).
|
||||
- ✅ Swipe-to-delete without a gesture-free fallback — **fixed in the app**: every list row also
|
||||
carries an always-visible "…" menu (`companion-app/src/screens/Zeilenmenue.tsx`). Still open in
|
||||
the old panel, which is being replaced anyway.
|
||||
- ✅ Leaflet from a CDN — **fixed in the app**: bundled from node_modules as a lazy chunk.
|
||||
- 🟡 Popup close-by-tap-outside in the old panel: still unchecked (the app uses the library's
|
||||
Popup, which is keyboard-reachable).
|
||||
- Audit's own note: these three may be better done in DataMetric360 than retrofitted — the panel
|
||||
gets replaced anyway.
|
||||
|
||||
### companion-app / design-system
|
||||
### companion-app / design-system ✅ RESOLVED 2026-08-11
|
||||
|
||||
- **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.
|
||||
- **Not wired together** — fixed: an npm workspace in the repo root links `@audi-dash/ui` into the
|
||||
app as a real dependency.
|
||||
- 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).
|
||||
@@ -201,24 +207,100 @@ formatting hold everywhere; `design-system/` is verifiably brand-free.
|
||||
|
||||
---
|
||||
|
||||
### Found while building (2026-08-11) — all fixed
|
||||
|
||||
Three defects that only surfaced by running against a real Home Assistant, not by reading code:
|
||||
|
||||
1. **The data layer declared field names the backend never sends.** `Fahrzeugstatus` had
|
||||
`tank_prozent`/`sicher_abgestellt`/`sicherheit`; the backend writes
|
||||
`tankprozent`/`gesichert`/`sicherheitscheck`. Every screen would have read `undefined` without
|
||||
anything failing. `technik`/`ausstattung` were typed as objects but are arrays.
|
||||
2. **The profile adapter handed out live references into the raw profile.** Editing a form would
|
||||
have silently mutated the baseline and broken the promise never to overwrite the
|
||||
backend-maintained tire odometer. Sections are copied now.
|
||||
3. **`design-system` still carried the pre-audit `--fg3: #657081`** (3.0:1 on `--tile`, fails WCAG
|
||||
AA) that the panel had already fixed to `#8a94a3`. The new app would have inherited a
|
||||
already-solved contrast defect.
|
||||
|
||||
Also: two TypeScript parameter properties in the data layer broke Node's strip-only mode, which is
|
||||
what the smoke scripts run on — rewritten as plain fields.
|
||||
|
||||
Three more that only screenshots revealed — nothing failed, the pixels were simply wrong:
|
||||
|
||||
4. **The vehicle block on the home screen was invisible.** `overflow: hidden` sets a flex item's
|
||||
automatic minimum size to 0, so once the page was taller than the screen, flex-shrink squashed
|
||||
the block to zero height and took model name, badge and plate with it. Fixed with
|
||||
`.dm-inhalt > * { flex: none }`.
|
||||
5. **The model name appeared twice** — once as the badge image, once as text beside it.
|
||||
6. **Filenames overflowed the gallery thumbnails.**
|
||||
|
||||
And one in the backend, found by watching the log against a current Home Assistant: the odometer
|
||||
screening called `urlopen` directly, which HA aborts as a blocking call since 2026.8. Every trip
|
||||
stayed without a distance, visible only as a warning. Now runs through `task.executor`.
|
||||
|
||||
**CORS is a real constraint for this app.** `cors_allowed_origins` did not take effect on HA
|
||||
2026.8 (preflight 403 even same-origin). Two consequences, both handled: the web build is served
|
||||
from Home Assistant itself (`/local/dm360/`, same origin — the planned deployment anyway), and the
|
||||
native hull enables `CapacitorHttp`, which routes fetch through native HTTP where CORS does not
|
||||
apply. Verify this again at commissioning if the app ever moves to a separate hostname.
|
||||
|
||||
**A self-written QR encoder was discarded.** It disagreed with a reference implementation on 1239
|
||||
of 3249 modules — the code would have been unreadable. `homeassistant/www/dm360-qr.html` now uses a
|
||||
vendored MIT library served from Home Assistant itself, which satisfies the actual requirement
|
||||
(no network call, token never leaves the local network) and round-trips correctly.
|
||||
|
||||
## Pending: this branch has diverged from `main` (noted 2026-08-13)
|
||||
|
||||
`ha_install.md` (root) plans the move from pyscript to a **native HA integration** with a config
|
||||
flow — UI-only setup, no YAML, and updates via a self-reporting `UpdateEntity` against the Gitea
|
||||
repo (HACS is GitHub-only, so it is not an option). All APIs in it were verified against the
|
||||
running 2026.8.1 instance. It also records which review findings that move eliminates by design.
|
||||
|
||||
A full review of `main`'s 18 new commits is in `REVIEW_main_2026-08-13.md` — 15 findings, the
|
||||
three most serious in the new setup menu (saving with an unloaded catalogue wipes the whole
|
||||
mapping; "reset" has no effect on 15 of 17 fields; all four list positions get the same sensor,
|
||||
which makes "securely parked" report safe while three doors were never checked).
|
||||
|
||||
`main` has moved 18 commits ahead of `umsetzung-datametric360` (FMM003 switch, sensor-mapping setup
|
||||
menu, iOS/large-screen overlay from Claude Design). **Deliberate decision: do not merge yet** — the
|
||||
owner keeps working on `main` first.
|
||||
|
||||
Three files conflict (`AGENTS.md`, `homeassistant/INSTALL.md`,
|
||||
`homeassistant/pyscript/fahrterkennung.py`); four more are touched by both sides but merge cleanly.
|
||||
|
||||
**One hazard that a clean merge will not catch.** This branch changed `profil_lesen()` in
|
||||
`homeassistant/pyscript/modules/profil.py` to return `None` when the profile file is missing or
|
||||
corrupt, and guarded all seven call sites that existed here. `profil.py` is untouched on `main`, so
|
||||
it merges silently — but `main`'s call sites (`fahrterkennung.py`, `tankerkennung.py`,
|
||||
`reifenzaehler.py`, `modules/frontend_veroeffentlichung.py`) do **not** guard against `None` and
|
||||
would raise `AttributeError` on a missing profile instead of logging a clear error.
|
||||
|
||||
When merging: take `main`'s FMM003 version of `fahrterkennung.py`, then re-apply the `None` guard to
|
||||
every remaining `profil.profil_lesen()` call site.
|
||||
|
||||
## Open items
|
||||
|
||||
Execution order, exact steps, and acceptance criteria for every item below live in
|
||||
`UMSETZUNGSPLAN.md` (phases 1–13). Additional decisions of 2026-08-11: **no Electron** (Capacitor
|
||||
wraps the web app for iPhone; a PWA home-screen install is the accepted intermediate step) and
|
||||
**no separate backend** (the app talks to the HA REST/WebSocket API directly).
|
||||
|
||||
### 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;
|
||||
- [x] 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
|
||||
- [x] `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/` —
|
||||
- [x] Implement the screens from the design draft on top of the existing `DataMetricApi` layer
|
||||
- [x] 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
|
||||
- [x] 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
|
||||
- [x] 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)
|
||||
- [x] 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)
|
||||
- [x] Offline UX per design brief (offline marker, visible pending queue)
|
||||
|
||||
### B) Infrastructure / commissioning (partly waits for FMM003 hardware)
|
||||
|
||||
@@ -227,7 +309,7 @@ formatting hold everywhere; `design-system/` is verifiably brand-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)
|
||||
- [x] Define the reverse-proxy path allowlist (depends on final entity/service names)
|
||||
- [ ] Install/wire the FMM003; record firmware version (Codec JSON is firmware-dependent)
|
||||
- [x] Generate TLS certificates for Mosquitto + device (small private CA) — done 2026-08-11, 10-year
|
||||
validity; Mosquitto configured (`certfile`/`keyfile`/`cafile`/`require_certificate: true`).
|
||||
@@ -420,9 +502,20 @@ formatting hold everywhere; `design-system/` is verifiably brand-free.
|
||||
was left unexercised beyond confirming it registers without error at pyscript load time.
|
||||
- [ ] Fix remaining documentation drift (statistics claim, README gaps, obsolete TODO comment) —
|
||||
text-only changes; INSTALL.md's WLAN/TommiG1 drift and stale variable names were fixed
|
||||
2026-08-12 (see section B)
|
||||
- [ ] Harden `profil_lesen()` against missing/corrupt `fahrzeugprofil.json`
|
||||
- [ ] Decide whether the 3 audit leftovers get fixed here or only in DataMetric360
|
||||
2026-08-12 (see section B); `DESIGN_REVIEW_2026-08-13.md` and `REVIEW_main_2026-08-13.md`
|
||||
list further drift not yet fixed (WLAN references still in `SPECIFICATION.md`,
|
||||
`homeassistant/README.md`, the profile template)
|
||||
- [x] Harden `profil_lesen()` against missing/corrupt `fahrzeugprofil.json` — done on the
|
||||
`umsetzung-datametric360` branch (2026-08-11), brought over by the 2026-08-13 merge. Returns
|
||||
`None` on a missing or malformed file instead of raising; all 5 call sites
|
||||
(`backup.py` ×2, `fahrterkennung.py`, `frontend_veroeffentlichung.py`, `reifenzaehler.py`,
|
||||
`tankerkennung.py`) already guard for `None` — verified by grep across the merged tree, no
|
||||
caller left unguarded (this was flagged as the merge's main risk in `REVIEW_main_2026-08-13.md`
|
||||
§"Was den Branch betrifft").
|
||||
- [x] Decide whether the 3 audit leftovers get fixed here or only in DataMetric360 — decided
|
||||
2026-08-11 (`UMSETZUNGSPLAN.md` Phase 2): swipe-delete keyboard fallback, popup keyboard
|
||||
access, and self-hosting Leaflet stay unfixed in this panel and are addressed 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)
|
||||
|
||||
Reference in New Issue
Block a user