# CODEX.md — Forza Telemetry Tuning Analyzer ## Projektziel Baue eine webbasierte Anwendung zur Analyse von Forza-Telemetriedaten über UDP Data Out. Die Anwendung soll lokal testbar sein, später aber so strukturiert werden, dass sie auf einem Server betrieben und mehreren Nutzern zur Verfügung gestellt werden kann. Primäres Ziel ist nicht nur ein Live-Dashboard, sondern ein Tool, das Fahrverhalten und Fahrzeugsetup analysiert und daraus konkrete Setup-Hinweise ableitet. ## Kurzbeschreibung Forza sendet Telemetriedaten per UDP an eine Ziel-IP und einen Ziel-Port. Die Anwendung soll diese Daten empfangen, parsen, speichern, visualisieren und analysieren. Die Weboberfläche soll Nutzern erlauben: - Live-Telemetrie anzuzeigen - Sessions aufzuzeichnen - Runden und Stints auszuwerten - Fahrzeug-Setup manuell zu erfassen - wiederkehrende Fahrverhaltensprobleme zu erkennen - Setup-Tipps auf Basis von Telemetrie + Setup zu erhalten - Sessions zu vergleichen ## Zielplattform ### MVP Lokaler Betrieb auf einem Gaming-PC oder im lokalen Netzwerk. Beispiel: ```text Forza → UDP → Local Backend → Web UI im Browser ``` ### Spätere Server-Variante Serverbetrieb für mehrere Nutzer. Da Forza UDP-Daten normalerweise aus dem lokalen Netzwerk sendet, soll die Architektur später einen lokalen Agenten unterstützen: ```text Forza → UDP → Local Agent → WebSocket/HTTPS → Server → Web UI ``` Der Server soll Sessions speichern, Nutzer verwalten und Analysen bereitstellen. ## Technologievorschlag ### Backend Nutze bevorzugt: - Python 3.12+ - FastAPI - WebSockets - asyncio UDP Receiver - SQLAlchemy oder SQLModel - SQLite für MVP - PostgreSQL für Serverbetrieb - Pydantic für Datenmodelle - Alembic für Migrationen ### Frontend Nutze bevorzugt: - React - TypeScript - Vite - Tailwind CSS - Recharts oder uPlot für Charts - WebSocket Client für Live-Daten ### Deployment Für den MVP: - Docker Compose - Backend Container - Frontend Container oder statische Auslieferung über Backend - SQLite Volume Für spätere Server-Version: - PostgreSQL - Reverse Proxy - TLS via nginx / Caddy / Traefik - optional Redis für Live-State und Queues ## Projektstruktur Empfohlene Struktur: ```text forza-telemetry-analyzer/ ├─ CODEX.md ├─ README.md ├─ docker-compose.yml ├─ .env.example ├─ backend/ │ ├─ pyproject.toml │ ├─ app/ │ │ ├─ main.py │ │ ├─ config.py │ │ ├─ telemetry/ │ │ │ ├─ udp_receiver.py │ │ │ ├─ parser.py │ │ │ ├─ models.py │ │ │ ├─ formats.py │ │ │ └─ normalizer.py │ │ ├─ analysis/ │ │ │ ├─ rules.py │ │ │ ├─ handling.py │ │ │ ├─ tires.py │ │ │ ├─ suspension.py │ │ │ ├─ gearing.py │ │ │ ├─ braking.py │ │ │ └─ advisor.py │ │ ├─ sessions/ │ │ │ ├─ router.py │ │ │ ├─ service.py │ │ │ └─ repository.py │ │ ├─ setups/ │ │ │ ├─ router.py │ │ │ ├─ service.py │ │ │ └─ schemas.py │ │ ├─ db/ │ │ │ ├─ database.py │ │ │ └─ models.py │ │ └─ websocket/ │ │ └─ manager.py │ └─ tests/ ├─ frontend/ │ ├─ package.json │ ├─ index.html │ └─ src/ │ ├─ main.tsx │ ├─ App.tsx │ ├─ api/ │ ├─ components/ │ ├─ pages/ │ ├─ telemetry/ │ ├─ sessions/ │ ├─ setup/ │ └─ analysis/ └─ docs/ ├─ telemetry-format.md ├─ analysis-rules.md └─ server-architecture.md ``` ## Funktionsumfang MVP Baue zuerst einen funktionalen MVP. Keine unnötige Komplexität. ### Muss-Funktionen 1. UDP-Telemetrie empfangen 2. Telemetriepakete parsen 3. Live-Daten per WebSocket an das Frontend senden 4. Live-Dashboard anzeigen 5. Recording starten/stoppen 6. Session speichern 7. Session-Liste anzeigen 8. Session öffnen und Charts anzeigen 9. Manuelle Fahrzeug-/Setup-Eingabe 10. Erste Analyse-Regeln ausführen 11. Setup-Hinweise anzeigen ### Kein Muss im MVP - Nutzerverwaltung - Cloud-Sync - Public Sharing - KI-Chat - automatische Streckenerkennung - perfekte Runden-Segmentierung - mobile App - Multiplayer/Team-Funktionen ## Backend-Anforderungen ### FastAPI App Die Backend-App soll folgende Bereiche haben: - Health Check - UDP Receiver Lifecycle - WebSocket Live Feed - Session API - Setup API - Analysis API Beispiel-Endpunkte: ```text GET /api/health POST /api/telemetry/start POST /api/telemetry/stop GET /api/telemetry/status WS /ws/live POST /api/sessions GET /api/sessions GET /api/sessions/{session_id} DELETE /api/sessions/{session_id} POST /api/sessions/{session_id}/setup GET /api/sessions/{session_id}/setup POST /api/sessions/{session_id}/analyze GET /api/sessions/{session_id}/analysis ``` ### UDP Receiver Implementiere einen asynchronen UDP Receiver. Konfigurierbare Werte: ```env FORZA_UDP_HOST=0.0.0.0 FORZA_UDP_PORT=5685 FORZA_PACKET_FORMAT=dash ``` Der Receiver soll: - UDP-Pakete empfangen - Paketlänge prüfen - Paketformat erkennen oder anhand Config parsen - ungültige Pakete ignorieren, aber zählen - aktuelle Telemetrie normalisieren - Live-Daten an WebSocket Clients senden - bei aktivem Recording Daten speichern ### Parser Implementiere den Parser modular. Wichtig: - keine Parser-Logik direkt im UDP Receiver - Paketformat in separaten Dateien definieren - Binary Parsing sauber kapseln - Little Endian beachten - Tests mit Beispielpaketen ermöglichen Parser-Dateien: ```text backend/app/telemetry/parser.py backend/app/telemetry/formats.py backend/app/telemetry/models.py ``` Der Parser soll zunächst mindestens die bekannten Forza-Dash-Felder abbilden, soweit verfügbar. ### Normalisiertes Telemetrie-Modell Erzeuge aus den Rohdaten ein normalisiertes Modell, das das Frontend und die Analyse nutzen. Beispiel: ```python class TelemetryFrame(BaseModel): timestamp_ms: int is_race_on: bool engine_max_rpm: float | None engine_idle_rpm: float | None current_engine_rpm: float | None speed_mps: float | None speed_kmh: float | None acceleration_x: float | None acceleration_y: float | None acceleration_z: float | None velocity_x: float | None velocity_y: float | None velocity_z: float | None angular_velocity_x: float | None angular_velocity_y: float | None angular_velocity_z: float | None yaw: float | None pitch: float | None roll: float | None normalized_suspension_travel_front_left: float | None normalized_suspension_travel_front_right: float | None normalized_suspension_travel_rear_left: float | None normalized_suspension_travel_rear_right: float | None tire_slip_ratio_front_left: float | None tire_slip_ratio_front_right: float | None tire_slip_ratio_rear_left: float | None tire_slip_ratio_rear_right: float | None tire_slip_angle_front_left: float | None tire_slip_angle_front_right: float | None tire_slip_angle_rear_left: float | None tire_slip_angle_rear_right: float | None tire_combined_slip_front_left: float | None tire_combined_slip_front_right: float | None tire_combined_slip_rear_left: float | None tire_combined_slip_rear_right: float | None tire_temp_front_left: float | None tire_temp_front_right: float | None tire_temp_rear_left: float | None tire_temp_rear_right: float | None wheel_rotation_speed_front_left: float | None wheel_rotation_speed_front_right: float | None wheel_rotation_speed_rear_left: float | None wheel_rotation_speed_rear_right: float | None throttle: float | None brake: float | None clutch: float | None handbrake: float | None gear: int | None steer: float | None power: float | None torque: float | None boost: float | None lap_number: int | None current_lap_time_ms: int | None last_lap_time_ms: int | None best_lap_time_ms: int | None race_position: int | None car_id: int | None car_class: int | None car_performance_index: int | None drivetrain_type: str | None num_cylinders: int | None ``` ## Datenbankmodell Für den MVP reicht SQLite. Tabellen: ### sessions ```text id name game track_name nullable car_name nullable car_id nullable car_class nullable performance_index nullable drivetrain_type nullable created_at started_at ended_at notes nullable ``` ### telemetry_frames ```text id session_id timestamp_ms frame_index raw_json normalized_json speed_kmh rpm gear throttle brake steer lap_number current_lap_time_ms created_at ``` Wichtig: Speichere nicht nur einzelne extrahierte Felder, sondern auch das normalisierte Frame als JSON. Das erleichtert spätere Analyseänderungen ohne Datenverlust. ### vehicle_setups ```text id session_id car_name drivetrain_type tire_pressure_front tire_pressure_rear gear_final_drive gear_1 gear_2 gear_3 gear_4 gear_5 gear_6 gear_7 gear_8 gear_9 gear_10 camber_front camber_rear toe_front toe_rear caster antiroll_front antiroll_rear springs_front springs_rear ride_height_front ride_height_rear rebound_front rebound_rear bump_front bump_rear aero_front aero_rear brake_balance brake_pressure front_diff_accel front_diff_decel rear_diff_accel rear_diff_decel center_diff_balance created_at updated_at ``` ### analysis_results ```text id session_id created_at summary_json findings_json recommendations_json ``` ## Frontend-Anforderungen ### Seiten Baue diese Seiten: ```text / Dashboard /sessions Session-Liste /sessions/:id Session-Detail mit Charts und Analyse /sessions/:id/setup Setup-Eingabe /sessions/:id/analysis Analysebericht /settings UDP-Port, Paketformat, Anzeigeoptionen ``` ### Dashboard Das Dashboard soll anzeigen: - Verbindungsstatus - Recording-Status - aktuelle Geschwindigkeit - RPM - Gang - Gas - Bremse - Lenkung - G-Kräfte - Reifentemperaturen - Reifen-Slip - Federweg - aktuelle Runde - letzte Runde - beste Runde ### Session-Ansicht Charts für: - Geschwindigkeit über Zeit - RPM über Zeit - Gang über Zeit - Gas/Bremse/Lenkung über Zeit - Reifen-Combined-Slip je Rad - Reifen-Temperatur je Rad - Federweg je Rad - Querbeschleunigung - Längsbeschleunigung Keine überladenen Monster-Charts. Lieber mehrere klare Diagramme. ### Analysebericht Der Analysebericht soll gegliedert sein: 1. Executive Summary 2. Handling 3. Reifen 4. Fahrwerk 5. Getriebe 6. Bremsen 7. Priorisierte Setup-Vorschläge 8. Hinweise zur Aussagekraft Jeder Befund soll enthalten: ```text Titel Kategorie Schweregrad: info | low | medium | high Confidence: 0–100 % Beobachtung Telemetrie-Begründung Empfohlene Änderung Alternative Ursache ``` ## Analyse-Engine Die Analyse soll regelbasiert starten. Keine Blackbox. ### Grundprinzip Jede Regel bekommt: - Liste von TelemetryFrames - optional VehicleSetup - abgeleitete Metriken - Kontext wie Drivetrain Type Jede Regel gibt Findings zurück. Beispiel: ```python class Finding(BaseModel): category: str title: str severity: str confidence: float observation: str evidence: list[str] recommendation: str alternative_causes: list[str] ``` ## Abgeleitete Metriken Berechne vor den Regeln zusätzliche Werte: ```text front_combined_slip_avg rear_combined_slip_avg front_slip_angle_avg rear_slip_angle_avg front_tire_temp_avg rear_tire_temp_avg left_tire_temp_avg right_tire_temp_avg suspension_front_avg suspension_rear_avg steer_abs throttle_normalized brake_normalized rpm_ratio speed_delta yaw_rate lateral_g longitudinal_g ``` ### Kurvenphasen Die Analyse soll versuchen, Fahrsituationen zu klassifizieren: ```text straight braking turn_in mid_corner corner_exit acceleration unknown ``` Heuristik: ```text braking: brake > 0.25 and speed_kmh > 40 turn_in: steer_abs > 0.25 and brake <= 0.40 and throttle < 0.30 mid_corner: steer_abs > 0.35 and throttle between 0.05 and 0.55 and brake < 0.25 corner_exit: steer_abs > 0.20 and throttle > 0.45 straight: steer_abs < 0.10 and brake < 0.10 ``` ## Beispiel-Regeln ### Entry Understeer Bedingung: ```text phase in [turn_in] steer_abs > 0.55 front_combined_slip_avg > rear_combined_slip_avg + 0.10 yaw_response_low == true speed_kmh > 50 ``` Empfehlungen: - Front-Stabi 1–2 Klicks weicher testen - alternativ Heck-Stabi 1 Klick härter - bei starkem Bremsanteil: Bremsbalance 1–2 % nach hinten testen - bei FWD vorsichtig mit zu viel Gas am Kurveneingang ### Mid-Corner Understeer Bedingung: ```text phase == mid_corner steer_abs > 0.50 front_combined_slip_avg > rear_combined_slip_avg + 0.12 throttle between 0.10 and 0.50 ``` Empfehlungen: - Front-Reifendruck leicht senken, falls Fronttemperatur niedrig/uneinheitlich - Front-Stabi weicher oder Heck-Stabi härter - Front-Camber prüfen - Aero vorn erhöhen, falls verfügbar und bei schnellen Kurven relevant ### Power Oversteer Bedingung: ```text phase == corner_exit throttle > 0.65 rear_combined_slip_avg > front_combined_slip_avg + 0.18 rear_slip_angle_avg deutlich erhöht ``` Empfehlungen: - Rear Diff Accel reduzieren - längere Übersetzung für kritischen Gang testen - Rear-Reifendruck prüfen - Heck-Stabi weicher oder Front-Stabi härter - Gasprogression weicher fahren ### Exit Understeer AWD/FWD Bedingung: ```text phase == corner_exit throttle > 0.60 front_combined_slip_avg > rear_combined_slip_avg + 0.15 steer_abs > 0.45 ``` Empfehlungen: - bei AWD: Center Diff mehr nach hinten - Front Diff Accel reduzieren - Front-Stabi weicher oder Heck-Stabi härter - später/vorsichtiger Vollgas geben ### Bottoming Out Bedingung: ```text normalized_suspension_travel_* repeatedly near 0.0 or 1.0 speed_kmh > 80 ``` Empfehlungen: - Ride Height erhöhen - Federrate erhöhen - Bump-Dämpfung prüfen - bei Aero-Fahrzeugen: Aero-Balance prüfen ### Zu kurze Übersetzung Bedingung: ```text rpm_ratio > 0.97 throttle > 0.75 speed_delta low same_gear_duration > 0.5s ``` Empfehlungen: - betroffenen Gang verlängern - Final Drive länger stellen, falls mehrere Gänge betroffen sind - Ziel: am Ende langer Geraden knapp unter Max RPM liegen ### Zu lange Übersetzung Bedingung: ```text throttle > 0.80 rpm_ratio < 0.55 acceleration low gear high ``` Empfehlungen: - Gang kürzer - Final Drive kürzer - Ganganschluss prüfen ### Bremsinstabilität Bedingung: ```text phase == braking brake > 0.60 rear_combined_slip_avg > front_combined_slip_avg + 0.12 yaw_rate rising ``` Empfehlungen: - Bremsbalance nach vorne - Bremsdruck reduzieren - Rear Decel Diff prüfen - Heck-Stabi weicher testen ### Trailbrake Understeer Bedingung: ```text brake between 0.15 and 0.50 steer_abs > 0.45 front_combined_slip_avg high yaw_response_low == true ``` Empfehlungen: - Bremsbalance leicht nach hinten testen - Bremse früher lösen - Front-Stabi weicher - Front-Reifendruck prüfen ## Setup Advisor Logik Der Advisor darf keine absoluten Garantien formulieren. Gute Formulierungen: ```text Teste Front-Stabi 1–2 Klicks weicher. Wenn das Auto dadurch am Kurvenausgang instabil wird, Änderung zurücknehmen und stattdessen Heck-Stabi 1 Klick härter testen. ``` Schlechte Formulierungen: ```text Stelle Front-Stabi auf exakt 23.4. ``` Jede Empfehlung braucht: - Symptom - Begründung - Setup-Hebel - mögliche Nebenwirkung - Testvorschlag ## Nutzerführung Die Anwendung soll Nutzer nicht mit Daten erschlagen. Priorisiere: 1. Was ist das größte Problem? 2. Wo tritt es auf? 3. Woran erkennt das Tool das? 4. Was soll ich zuerst ändern? 5. Wie teste ich, ob die Änderung geholfen hat? ## Sprache UI und Texte zunächst auf Deutsch. Code, Variablen und interne Namen auf Englisch. ## Design-Richtung Modernes, technisches Webinterface. Stil: - dunkles Dashboard bevorzugt - klare Karten - kompakte Zahlenanzeigen - gute Chart-Lesbarkeit - nicht verspielt - kein Gaming-Kitsch - keine überladenen Neon-Effekte - responsive, aber Desktop-first ## Wichtige UX-Details ### Recording Flow Der Nutzer soll klar sehen: ```text UDP verbunden / nicht verbunden Pakete pro Sekunde letztes Paket vor X ms Recording aktiv / inaktiv aktuelle Session ``` Buttons: ```text Start Recording Stop Recording Discard Save Session Analyze Session ``` ### Setup-Eingabe Setup-Eingabe als strukturierte Tabs: ```text Reifen Übersetzung Ausrichtung Stabis Federn Dämpfer Aero Bremsen Differenzial ``` Erlaube leere Werte. Nicht jedes Fahrzeug hat alle Tuningoptionen. ### Analysebericht Der Bericht soll priorisiert sein. Beispiel: ```text Höchste Priorität: 1. Power-Oversteer am Kurvenausgang 2. 4. Gang zu kurz 3. Frontreifen überlastet in langen Kurven Geringere Priorität: 4. leichter Temperaturunterschied links/rechts ``` ## Serverfähigkeit Schon im MVP so bauen, dass spätere Serverfähigkeit nicht blockiert wird. ### Für später vorbereiten - klare Trennung zwischen UDP Receiver und Web-App - Session gehört perspektivisch zu User - Local Agent als eigenes Modul denkbar - API nicht hart an localhost koppeln - Auth später ergänzbar - Datenbankzugriff abstrahieren ### Spätere Architektur ```text Local Agent: - empfängt UDP von Forza - normalisiert Telemetrie - sendet Frames per WebSocket/HTTPS an Server - optional lokaler Cache Server: - Nutzerverwaltung - Session Storage - Analyse - Web UI - Team-/Sharing-Funktion ``` Für den MVP darf der Backend-Server UDP direkt empfangen. ## Sicherheit Für lokalen MVP simpel halten. Für Serverbetrieb später beachten: - Authentifizierung - Nutzertrennung - Rate Limits - keine offenen UDP-Ports ins Internet als Pflicht - Local Agent bevorzugen - HTTPS - CORS sauber konfigurieren - keine beliebigen File Uploads im MVP ## Performance Telemetrie kann viele Frames pro Sekunde erzeugen. Daher: - nicht jedes Frame einzeln synchron in die Datenbank schreiben - Buffer verwenden - Batch Inserts - Live-Frontend throttlen, z. B. 10–20 FPS - Rohdaten optional speichern, aber nicht UI mit 60 FPS erzwingen - Session-Charts downsamplen ## Testing Erstelle Tests für: - Parser mit Beispiel-Binary-Payloads - Normalizer - Analyse-Regeln - API-Endpunkte - WebSocket-Verbindung - Session-Speicherung Erstelle zusätzlich einen Fake-Telemetry-Generator: ```text backend/app/dev/fake_telemetry_sender.py ``` Dieser soll UDP-Pakete oder normalisierte Frames simulieren, damit Frontend und Backend ohne laufendes Forza getestet werden können. ## Akzeptanzkriterien MVP Der MVP gilt als fertig, wenn: 1. Backend startet per Docker Compose 2. Frontend ist im Browser erreichbar 3. UDP Receiver kann gestartet werden 4. Live-Dashboard zeigt eingehende Frames 5. Recording kann gestartet und beendet werden 6. Session wird gespeichert 7. Session kann erneut geöffnet werden 8. Charts zeigen Telemetriedaten 9. Setup kann zur Session gespeichert werden 10. Analyse erzeugt mindestens 5 Typen von Findings: - Understeer - Oversteer - Gearing Issue - Braking Instability - Suspension Bottoming 11. Empfehlungen werden verständlich auf Deutsch angezeigt ## Entwicklungsreihenfolge Arbeite in dieser Reihenfolge: ### Schritt 1 Projektstruktur erstellen. ### Schritt 2 FastAPI Backend mit Health Check und Config. ### Schritt 3 UDP Receiver mit Logging. ### Schritt 4 Parser-Schnittstelle und Fake-Parser, falls echtes Format noch nicht vollständig implementiert ist. ### Schritt 5 WebSocket Live Feed. ### Schritt 6 React Frontend mit Dashboard. ### Schritt 7 Recording und Session Storage. ### Schritt 8 Session-Liste und Session-Detailseite. ### Schritt 9 Setup-Formular. ### Schritt 10 Analyse-Engine mit ersten Regeln. ### Schritt 11 Analysebericht UI. ### Schritt 12 Docker Compose und README. ## Wichtige Implementierungsregeln - Schreibe klaren, wartbaren Code. - Keine riesigen Dateien. - Business-Logik nicht in UI-Komponenten verstecken. - Analyse-Regeln modular halten. - Datenmodelle typisieren. - Frontend-Komponenten wiederverwendbar bauen. - Fehler im UI sichtbar machen. - Backend-Logs verständlich halten. - Konfiguration über `.env`. - Keine Secrets committen. - Schreibe README mit Setup-Anleitung. ## Beispiel README-Anleitung Die README soll mindestens erklären: ```text 1. Voraussetzungen 2. Start mit Docker Compose 3. UDP-Port konfigurieren 4. Forza Data Out konfigurieren 5. Live-Dashboard öffnen 6. Session aufnehmen 7. Analyse ausführen 8. Bekannte Limitierungen ``` ## Bekannte Limitierungen Diese Punkte in README und UI transparent machen: - Das Tool kennt das Fahrzeugsetup nur, wenn der Nutzer es eingibt. - Setup-Tipps sind heuristisch, keine perfekte Simulation. - Reifentemperaturen je Rad reichen nicht für perfekte Camber-Diagnose. - Manche Probleme können durch Fahrstil statt Setup entstehen. - Game-Version und Paketformat können sich ändern. - FH6-Unterstützung muss anhand realer Pakete validiert werden. ## Codex-Arbeitsweise Wenn Informationen fehlen: 1. eine sinnvolle Annahme treffen 2. diese Annahme im Code oder README dokumentieren 3. den MVP nicht blockieren 4. Parser und Formate so bauen, dass Anpassungen leicht möglich sind Wenn echte Telemetriedaten noch nicht vorliegen: - mit Fake-Telemetrie weiterarbeiten - Parser-Schnittstelle vorbereiten - Sample-Payloads später ergänzbar machen ## Ergebnis Erzeuge am Ende ein lauffähiges Projekt mit: - Backend - Frontend - Docker Compose - README - Beispiel `.env` - Fake Telemetry Sender - ersten Analyse-Regeln - deutscher UI - klarer Struktur für spätere Server-/Multi-User-Version