Share-Erweiterung: ein PDF aus Mail landet ueber Teilen -> DataMetric360 als Tankbeleg. Alles Native liegt versioniert unter companion-app/native/, weil ios/ gitignored ist und npx cap add ios es sonst wieder frisst; scripts/ios-teilen-einrichten.mjs haengt es bei jedem Bau ins Xcode-Projekt und ist in ios-signieren.sh eingehaengt. Der pbxproj-Teil ist auf keinem Mac erprobt - er bricht vor dem Schreiben ab, und docs/SHARE_EXTENSION.md beschreibt dieselben Handgriffe fuer Xcode. "In den Kalender uebernehmen" ging in der App nie: WKWebView ignoriert das download-Attribut, der Klick lief ins Leere. Auf dem Geraet jetzt @capacitor/filesystem plus @capacitor/share. useTheme/useBoden legten je Aufrufer eigenen Zustand an - fuenf Kopien. Der Schalter aenderte nur seine eigene, data-theme in App.tsx blieb stehen, die Tag/Nacht-Umschaltung wirkte erst nach einem Neustart. Jetzt ein Speicher je Einstellung ueber useSyncExternalStore. Zwei Regressionstests, gegen den alten Stand als fehlschlagend nachgewiesen. Alle Popups nach Apple HIG: neue Bausteine Sheet und ActionSheet, blickdicht und mit abgedunkeltem Schleier, in beiden Codebasen. Popup portalierte nach document.body - ausserhalb von [data-theme] - und war deshalb im Tagmodus fast unsichtbar; Portal zielt jetzt auf .ads-root. ImagePlaceholder merkte sich "fehlgeschlagen" ohne die Adresse: nach einem leeren Galerieplatz zeigten auch die mit Foto nur noch den Platzhalter. Vier Regressionstests, ebenfalls gegen den alten Stand geprueft. Bildadressen tragen jetzt einen Cache-Brecher - HA liefert /local/ mit 31 Tagen Cache-Vorgabe aus, im Panel eingefuegte Radfotos erschienen in der App deshalb nicht. uebersichtsbild: Panel speichert den Namen, die App verglich gegen den Dateinamen - der Vergleich traf nie zu. Kanonisch ist der Name. Weiter: Navigationspfeil statt gleichschenkligem Dreieck auf der Streckenlinie (die Kerbe unterscheidet Kopf und Ende), CI-Symbol tour-s als Fahrten-Icon, Datumsfelder zeigen ihren Wert ohne erstes Antippen, feste Beispielnamen im Setup, Kopf-Gegengewicht fuer mittige Titel, Standort-Blatt mit festem Fussabstand, NSLocationWhenInUseUsageDescription, watchPosition fuer die Live-Ortung, Art-Pille wieder als Knopf, Zwischenablage fuer Tankbelege. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
companion-app — DataMetric360
Private Fahrzeug-App für einen Audi RS 4 Avant competition. Läuft als Web-App im Browser, als PWA auf dem Homescreen, später über Capacitor nativ auf iOS/Android und eingebettet als Iframe im Home-Assistant-Dashboard.
Kein eigenes Backend. Die App spricht direkt mit der REST- und
WebSocket-Schnittstelle von Home Assistant und ruft dieselben
pyscript.audi_dashboard_*-Dienste auf wie das bestehende Panel. Alle Daten
liegen auf dem eigenen Server; das Gerät hält nur den Zugangstoken und einen
Zwischenspeicher für die Offline-Anzeige.
Architektur: ../COMPANION_APP_ARCHITECTURE.md · Umsetzungsschritte:
../UMSETZUNGSPLAN.md · Projektstand: ../AGENTS.md
Loslegen
npm install # im Repo-Wurzelverzeichnis, nicht hier (npm-Workspace)
npm run build:ds # Design-System bauen, die App importiert aus dessen dist/
npm run dev --workspace datametric360
Beim ersten Start fragt die App nach Server-Adresse und Zugangstoken. Für die
Entwicklung setzt ../testumgebung/aufsetzen.sh eine vollständige
Home-Assistant-Instanz mit dem echten Backend auf.
Aufbau
| Ordner | Inhalt |
|---|---|
src/api/ |
Datenschicht: REST, WebSocket mit Wiederverbindung, Offline-Warteschlange, Zugangsdaten |
src/daten/ |
Fachlogik: Profil-Umrechnung, Statistik, Service-Prognose, Datenkontext |
src/screens/ |
Die 21 Seiten der App |
src/stile/ |
Layout, Bildschirmbausteine, Audi-Schrift |
src/assets/audi/ |
Schrift, Vier-Ringe, Typenschilder — lizenzpflichtig, siehe unten |
src/tests/ |
Testaufbau und Beispieldaten |
Gestaltung kommt vollständig aus @audi-dash/ui (../design-system/). Neue
Komponenten entstehen dort, nicht hier.
Prüfen
npm run typecheck # TypeScript, sehr streng (exactOptionalPropertyTypes u. a.)
npm run test # 90 Tests: Rechenlogik, Layoutwechsel, alle Seiten gerendert
npm run smoke # Adressbildung und Endpunkte, ohne Token
npm run smoke:auth # gegen die laufende Testinstanz, mit Token
npm run build # Produktionsbündel
smoke:auth liest Adresse und Token aus .env.local (schreibt
../testumgebung/aufsetzen.sh, gitignored). Ohne die Datei überspringt der
Test sich selbst, statt fehlzuschlagen.
Die Rendertests decken alle 21 Seiten in beiden Layouts ab — schmal mit Tab-Leiste, breit mit Seitenleiste.
Rechtlicher Hinweis
src/assets/audi/ enthält die Hausschrift Audi Type, das Vier-Ringe-Zeichen
und die Modell-Typenschilder. Diese sind lizenz- beziehungsweise
markenrechtlich geschützt und ausschließlich für diese eine private,
unveröffentlichte Installation freigegeben (../bauauftrag.md §8/§12).
Daraus folgt: Die App wird nur seitlich installiert, nie in einem App Store
veröffentlicht, und dieses Repository bleibt privat. ../design-system/
kommt bewusst ohne diese Dateien aus, weil es nach außen hochgeladen wird —
dort niemals Markendateien ablegen.
Die signierte App
auslieferung/App.ipa ist der fertige, Ad-hoc signierte Stand (Team
RMACS9VLS4, Profil gültig bis 29.08.2027, nur für das eingetragene iPhone).
Neu bauen: bash scripts/ios-signieren.sh - baut Webbündel, synchronisiert die
Hülle, signiert und legt die .ipa wieder hier ab.
Beim ersten Signieren fragt der Schlüsselbund um Erlaubnis. Dort „Immer
erlauben" wählen, sonst hängt xcodebuild wortlos und endet nach Minuten mit
errSecInternalComponent.
Noch offen
- Native Hülle selbst:
ios//android/(vonnpx cap adderzeugt, absichtlich gitignored) existieren in keinem Checkout dauerhaft und müssen auf einem Mac (für iOS zwingend, Xcode) neu erzeugt werden - die sichere Tokenablage (Keychain/Keystore) ist dagegen bereits vollständig angebunden (src/api/ablageNativ.ts, vonmain.tsxaktiviert) und wird automatisch aktiv, sobald die Hülle existiert - Übertragung über die Luft:
scripts/ios-luftweg.sh https://<host>erzeugt Manifest und Installationsseite; es fehlt nur noch ein Host, der den Ordner über HTTPS mit gültigem Zertifikat ausliefert (tailscale serveangedacht, dieser Mac ist dort noch abgemeldet) - QR-Einrichtung als Alternative zum Einfügen des Tokens
- Live-Ansicht der laufenden Fahrt: gebaut, aber über
src/funktionen.tsabgeschaltet, bis der FMM003 echte Werte liefert