1139 lines
21 KiB
Markdown
1139 lines
21 KiB
Markdown
# 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
|