Files
geograsim/App/sims/_inbox/logistik/_status.md
T
Adminator 79ac9dad84 Atlas: Deploy-Buendel vor Staustufen-Sprint
- Logistik: Musik-Player Playlist-Modus (5 Gruppen, 20 Tracks)
- Heli: End-Screen auf .ggs-endscreen, Mission-Bilder, Voice-Lines, Briefing-Audio
- Logistik: Layout-Tausch Auftraege+Fahrzeuge links, Karte rechts
- Logistik: Tier-1-Staedte ausgebaut, Auto-Timescale-Badge
- Logistik: Roadnet/Railnet Dijkstra-Routing, Balance-Updates
- Atlas: 5 Atlas-Inbox-Nachrichten (Cards-Pattern, DALL-E-Key, Musik-Playlists)
- Status-Updates Heli + Logistik

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 01:05:13 +02:00

78 KiB
Raw Blame History

instanz, rolle, stand_seit, phase
instanz rolle stand_seit phase
logistik Simulation „Logistik Europa" (Modul 11) 2026-04-19 Phase 8d — Integrations-Vertrag §6 umgesetzt (mode-check + assessment-calls) + L1-UI-Polish + Manueller Fahrzeugkauf ab L2. Wartet auf Atlas-Reviews (3 offene Mails)

Status — Logistik-Instanz

Rolle und Scope

  • Eigner: App/sims/logistik/ (Gerüst kommt von Atlas)
  • Eigner: App/pages/logistik.php, App/pages/modul-logistik.php
  • Eigner: App/php/api/logistik-*.php
  • Optional: neue MySQL-Tabellen lg_… (nur nach Atlas-Abstimmung)
  • Plattform-Zentrale ist Atlas — Anfragen über _inbox/zentrale/

Aktueller Stand

  • 2026-04-19 23:15 — Kickoff-Briefing von Atlas erhalten
  • 2026-04-19 23:25 — Briefing + Pflichtenheft (alle Schlüsselkapitel) gelesen
  • 2026-04-19 23:30 — Empfangsbestätigung an Zentrale geschickt
  • 2026-04-20 00:10 — Atlas-Antworten auf alle 4 Rückfragen erhalten
  • 2026-04-20 00:20 — Quittung an Atlas (Routing bestätigt, alle Punkte übernommen)
  • Warte auf: Atlas baut Gerüst (module_info, Landing-Card, Detailseite, Wrapper, Skelette unter App/sims/logistik/)

Geklärte Entscheidungen (Atlas-Antwort 00:10)

  • Lehrplan: kompetenzen.json als Vorab-Skizze (status: "proposed") nach Gerüst, final nach Phase 2
  • Glossar: Atlas koordiniert Anfrage; ~10 von 13 Begriffen neu, reicht bis Phase 6
  • Landing: Eigene Gruppe „Wirtschaft & Verkehr" (LOCKED bis FREE)
  • Tile-Server: Carto Positron https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png, Leaflet 1.9.4, minZoom: 4, maxZoom: 10
  • Routing: bestätigt — L1 Luftlinie×1.3, L2/L3 hand-gepflegte Polylines in lg-routes-osm.json, OSRM erst auf Thomas-Wunsch
  • State-Machine: Atlas legt Enum exakt nach Pflichtenheft Kap 44.2 ins engine.js-Skelett

Phasenplan (aus Briefing)

  • Phase 0 — Balance-Matrix + Test-Harness + Headless-Runner-Skelett → Atlas-Review
  • Phase 1 — Fundament (engine.js + Karte + Seed-Daten)
  • Phase 2 — Kern-Loop (Level 1 spielbar)
  • Phase 3 — Kostenmodell + Mehrfahrzeuge + mehrere Aufträge (Level 2)
  • Phase 4 — Bahn + Häfen + Intermodal (Level 3)
  • Phase 5 — Hilfestufen + Events
  • Phase 6 — Minigames + Sprachregel-Check + Leichte Sprache
  • Phase 7 — Lehrkraftmodus + Analytics + Polish

Offene Aufgaben (kurzfristig)

  1. App/docs/module-interface.md Abschnitte 4a/4b/4c/7b lesen
  2. Sobald Gerüst von Atlas steht: balance-matrix.md schreiben (Werte aus Kap 65 + Schätzwerte)
  3. test.html mit 7 Pflichttests anlegen
  4. Headless-Runner-Skelett runLevel(levelId, seed, strategy) definieren
  5. Atlas-Review von Phase 0 anfordern, bevor Phase 1 startet

Blocker

  • Keine. Wartepunkt: Atlas-Gerüst (≈ 2 Sessions geschätzt)

Konventions-Anker (Erinnerung)

  • Sprachregel 4a: keine „spielen / Spiel / Spieler"
  • Leichte Sprache 4b: pickText()-Pattern für alle UI-Texte
  • iPad 4c: 1180×820 Landscape, 36 px Touch-Ziele, kein Hover-Kleber
  • Autosave 7b: Pflicht bei state-relevanten Übergängen
  • Keine KI im Produkt: Auftragstexte/Events/Hilfe vorab generieren, statisch ausliefern
  • Inbox-Check vor jeder „Fertig"-Meldung
  • Commits: Logistik: <Kurzbeschreibung>

Komplexitätshinweis

Atlas schätzt 3050 Sessions für das Gesamtmodul. Phasenschnitte sauber halten, nicht den ganzen Brocken auf einmal angehen.


Tagesabschluss 2026-04-20 (00:20)

  • Kickoff + Pflichtenheft gelesen
  • Empfangsbestätigung + 4 Rückfragen an Atlas verschickt
  • Atlas-Antworten gelesen, alle Entscheidungen quittiert
  • Routing-Strategie (L1 Luftlinie×1.3 / L2-L3 Hand-Polylines / kein OSRM) bestätigt
  • Nächstes (sobald Gerüst steht): balance-matrix.md → 7 Pflichttests in test.html → Headless-Runner-Skelett runLevel(levelId, seed, strategy)
  • Blocker: keiner — wartet auf Atlas-Gerüst (~2 Sessions)
  • Offen für Thomas: keine akute Frage, alles geklärt

Tagesabschluss 2026-04-20 (00:55)

  • Atlas-Gerüst empfangen (DB, Landing-Card, PHP-Wrapper, Sim-Skelette, Seeds)
  • 7 Pflichttests in test.html statisch geprüft + via Python-Mathematik verifiziert → 22 von 22 Test-Cases bestehen rechnerisch, Browser-Bestätigung steht aus
  • Phase 0 v0.1 geliefert:
    • App/sims/logistik/balance-matrix.md v0.1
    • App/sims/logistik/headless-runner.html (Skelett, alles SKIP)
  • Atlas-Review angefordert

Tagesabschluss 2026-04-20 (01:30) — Phase 0 v0.2 nach Atlas-Klarstellung

Atlas hat klargestellt: Phase 0 ist meine Arbeit, das Gerüst war nur Vorarbeit. Konkrete Atlas-Forderungen alle abgehakt:

  • balance-matrix.md v0.2 — Rationale-Spalte je Parameter, INSERT-SQLs für game_levels, Konsistenz-Checks an Atlas, Event-Wahrsch. als Multiplikator umstrukturiert, noop zur Strategieliste
  • headless-runner.js (NEU, vorher .html) — Vanilla-JS-Modul, Browser+Node-kompatibel via UMD, Mulberry32-RNG, runLevel-Vertrag, 4 Strategien (noop lauffähig + naive/greedy/optimal als Stubs)
  • headless-runner.html umgebaut zu dünner UI-Hülle (Logik in .js)
  • test.html erweitert um:
    • Test 8 — Edge-Cases (8 Cases: leere Polyline, getrennter Dijkstra-Graph, Pfad zum Selbst, negative Hours, null-Werte, unbekannter Modus)
    • Test 9 — Seeded-Random (4 Cases: Determinismus, verschiedene Seeds, Range, Seed 0)
    • Test 10 — Runner-Vertrag (10 Cases: noop läuft, reproduzierbar, Stubs werfen kontrolliert)
    • group() und Render auf async umgebaut, damit Test 10 (await runLevel) sauber läuft
  • Python-Verifikation der Mathematik: alle neuen Cases grün (10 von 10)
  • Atlas-Review erneut angefordert mit aktualisierten Artefakten

Nächstes (nach Review-OK): Phase 1 — engine.js tick() Loop + Leaflet-Karte mit 13 Seed-Locations Blocker: Atlas-Review + Thomas-Browser-Test (test.html + headless-runner.html) Offen für Thomas: einmal beide HTML-Seiten öffnen, Status melden

Tagesabschluss 2026-04-20 (02:30) — Phase 1 ausgeliefert

Phase 0 von Atlas mit BESTANDEN reviewt (01:45). Doku-Korrekturen aus Review umgesetzt (Bahnnetz-Distanzen Paris↔Rotterdam=520, Paris↔München=820; INSERT-Schema mit scenario+levelNameEasy in params); 3 Logistik-Level sind in DB. Phase 1 komplett implementiert:

  • engine.js erweitert:

    • loadContent(game, seeds) — INIT → LOADING_CONTENT → READY
    • startPlanning(game) — READY → PLANNING
    • startSimulation(game) — PLANNING → RUNNING (paused=false)
    • pause(game) / resume(game) — User-Pause via paused-Flag
    • setTimeScale(game, scale) — 1×/2×/4×/8×
    • onStateChange(game, callback) → unregister-Funktion (für Autosave 7b)
    • tick(game, deltaMs) — Phase 1: Sim-Zeit + Zeitlimit-Check, alle anderen Pipeline-Schritte (Vehicles, Contracts, Economy, Events) sind Phase 2/3/5 Stubs
    • convertRealTimeToGameMinutes(deltaMs, timeScale) — utility
    • getSimHoursElapsed(game) — utility
    • serialize(game) / deserialize(json) — ohne Listener (Autosave 7b)
    • createGame(levelNum, {deterministic, seed}) — neue Option für Tests
    • Internes _setState() löst onStateChange-Callbacks aus
  • game.html komplett umgebaut:

    • Leaflet-Karte mit Carto Positron (Atlas-Vorgabe), tap:true für iPad
    • 13 Locations gerendert als CircleMarker pro Typ (CAPITAL grün/CITY grau/PORT blau/TERMINAL braun)
    • Layer-Gruppen: Hauptstädte, Städte, Häfen, Terminals, Bahnnetz
    • Layer-Control oben rechts (collapsed:false), Marker-Filter nach visibleFromLevel <= visibleLocationLevel aus Level-Config
    • Bahnnetz als gestrichelte Polylines (5 Kanten Wien-München-Hamburg- Rotterdam-Paris-München)
    • RAF-Loop ruft tick(deltaMs) und updateStatusUI()
    • Speed-Buttons (1×/2×/4×/8×) mit aria-pressed-Toggle, ≥36px
    • Pause-Button mit kontextsensitiven Übergängen (READY→PLANNING→RUNNING ↔ pause/resume)
    • Status-Leiste live: Sim-Zeit, Konto, Bilanz, Aufträge x/y, State
    • Save/Load via localStorage (Phase 1 Skelett, Server-API in Phase 7)
    • Autosave-Hook via onStateChange (localStorage)
    • Sprachregel 4a durchgehend („Bearbeiter:in", „Simulation", „Durchgang", „Sim-Zeit") — nirgends „Spieler"/„Spiel"
  • test.html erweitert um Test 11 (10 Cases) Phase 1:

    • 11.1 deterministic createGame → reproduzierbare sessionId+startTime
    • 11.2 State-Übergänge INIT→LOADING_CONTENT→READY
    • 11.3 startPlanning + startSimulation
    • 11.4 tick(1000ms, 1×) → +1 Sim-Min
    • 11.5 tick(1000ms, 4×) → +4 Sim-Min
    • 11.6 paused tick → keine Zeit-Änderung
    • 11.7 50× tick auf zwei Instanzen mit Seed 99 → identische simulationTime
    • 11.8 onStateChange protokolliert alle 4 Übergänge
    • 11.9 Zeitlimit überschritten → state=LEVEL_FAILED
    • 11.10 serialize/deserialize Roundtrip + Listener-Reaktivierung
    • Test 7 (Bahn-Dijkstra) erweitert um Wien→Paris (1220 km) und Wien→Rotterdam (1700 km via Hamburg, nicht via Paris)
  • noop-Strategie weiterhin lauffähig: noop nutzt eigenen Mini-Loop (simHours += 1), keine engine.tick-Abhängigkeit → läuft ohne Phase-2-Implementierung weiter. Test 10 grün-erwartet.

  • Mathematische Verifikation (Python 1:1): Tick-Konversion, Dijkstra-Pfade, Mulberry32 — alle neuen Cases verifiziert.

Verbliebene Stubs (Phase 2+): assignContract, calculateRoute, useHint, applyMinigameResult, sowie die Strategien naive/greedy/optimal.

Nächstes (Phase 2): Auftrags-Generierung + Fahrzeug-Bewegung + Routen-Visualisierung → Level 1 spielbar Blocker: keiner — Atlas hat „keine weiteren Reviews bis Phase 1 fertig" gesagt, ich starte Phase 2 nach Thomas-Test Offen für Thomas:

  • Browser-Test http://localhost/geograsim/App/sims/logistik/test.html (Test 111, ~36 Cases)
  • Browser-Test http://localhost/geograsim/App/logistik?level=1 (Karte sichtbar, Pause-Button startet Sim-Zeit, Speed-Buttons schalten)

Tagesabschluss 2026-04-20 (03:30) — Phase 2 ausgeliefert + Header-Fix

Atlas-Phase-1-OK + grünes Licht für Phase 2 (03:00). Atlas hat mein Phase-1-Plan-§6 1:1 übernommen und „keine weiteren Reviews bis Phase 2 fertig" gesagt. Header-Klassen-Anfrage von 02:45 wurde nicht direkt beantwortet (Überschneidung), aber das Template ist die Wahrheitsquelle — Header habe ich selbst aufs Template-Pattern umgestellt (kein Klassen- Erfinden, nur 1:1-Übernahme).

Header-Fix (vor Phase 2)

  • Klassen auf Template-Muster: ggs-header-logo + ggs-header-logo-icon
    • ggs-header-logo-text + ggs-header-separator + ggs-header-module
    • ggs-header-badge + ggs-header-spacer + ggs-header-actions + ggs-speed/ggs-speed-btn + ggs-btn-ghost
  • Pause-Button als data-speed="0" integriert (Template-Vorschlag)
  • Lehrplan-Link 📚 ergänzt (verweist auf modul-logistik.php#lehrplan-bezug)
  • Eigene CSS-Override-Regeln entfernt (DS macht das jetzt sauber)
  • Speed-Button-Wahl steuert auch start (von PLANNING → RUNNING bei >0)

Phase 2 — Engine

  • calculateRoute(game, originId, targetId, mode) — Phase-2-Strategie Luftlinie × 1.3, liefert Route mit Geometrie + Distanz + Dauer + Segments. Provider markiert als airline_x1.3 (Phase 3 ersetzt mit Hand-Polylines).
  • assignContract(game, contractId, vehicleId) — Validierung, Routenberechnung, Vehicle springt zur Origin (kein Pickup-Drive in Phase 2), States werden gesetzt.
  • _updateVehicles(game, simMinutes) im tick — Routen-Interpolation, bei Ankunft Vehicle→IDLE, Contract→DELIVERED
  • _completeContract — Verspätung berechnen, Erlös + BonusFahrkostenStrafe buchen, Contract in completedContracts, Notification, Auto-Folgeauftrag generieren (Phase-3-Vorgriff für L1-Spielbarkeit)
  • seedInitialVehicles(game) — Level-Config-driven Vehicle-Erstellung (L1: 1× TRUCK_SMALL in Wien)
  • seedInitialContracts(game) — Level-1: 1× Wien→Salzburg fest
  • tick erweitert um Erfolgsprüfung (Time-Limit-Erreichung mit minTarget → LEVEL_SUCCESS, sonst LEVEL_FAILED)

Phase 2 — Headless-Runner

  • naive-Strategie aktiviert: nimmt erstes OPEN ↔ erstes IDLE, tickt 5 Sim-Min/Iter bis state≠RUNNING. Nutzt opts.seeds wenn übergeben (für Tests ohne window.LOGISTIK_SEEDS).
  • runLevel ruft createGame mit deterministic+seed
  • noop bleibt unverändert lauffähig (eigener Loop, keine engine.tick-Abhängigkeit)

Phase 2 — UI (game.html)

  • Contracts-Panel zeigt Cards pro Auftrag mit Code, Strecke, km, Erlös, Frist, State-Badge. Klick selektiert (toggleable).
  • Vehicles-Panel zeigt Cards pro Fahrzeug mit Name, Speed, Kapazität, Standort. Klick bei selected contract → assignContract.
  • Routen-Polylines (durchgezogen, dunkelgrün) für jede activeRoute
  • Fahrzeug-Marker als 🚚/🚆 (DivIcon), Position aus RAF-Loop
  • Hilfestufe BLINK_EXACT (Phase 5 vorgegriffen): blinkende Ringe um Origin (gelb) und Target (rot) bei selected contract
  • Toast-Notifications bei Delivery (mit Net-Betrag)
  • Sprachregel 4a durchgehend (Aufträge, Bearbeiter:in, etc.)

Phase 2 — Tests (test.html)

  • Test 12 (5 Cases) — calculateRoute Wien→Salzburg ≈ 326 km × 1.3
  • Test 13 (8 Cases) — assignContract State-Übergänge + doppelte Zuweisung wirft
  • Test 14 (3 Cases) — tick bewegt Vehicle (segmentProgress strikt zwischen 0/1)
  • Test 15 (6 Cases) — Delivery + Erlös + Folge-Auftrag automatisch
  • Test 16 (3 Cases) — latePenaltyOverride wird respektiert + analytics++
  • Test 17 (5 Cases) — naive auf L1 schafft Akzeptanzkorridor (≥4 Aufträge, Profit ≥ +1000€, success=true)
  • Test 10.3 angepasst: greedy wirft jetzt „Phase 2", naive ist aktiv

Mathematische Verifikation (Python 1:1)

  • Wien-Salzburg airline = 250.82 km, × 1.3 = 326.06 km, 4.66 h @ 70 km/h
  • Pro Auftrag: Net 792.27€ (1300€ Erlös 507.73€ Fahrkosten)
  • 24h / 4.66h = 5 Aufträge schaffbar
  • Gesamtprofit: 3961€ > 3000€ Min-Ziel → success ✓

L1 ist spielbar. Im Browser: Klick auf Auftrag (blinkende Ringe) → Klick auf LKW → Fahrt beginnt → 1× oder 4×/8× Speed → LKW fährt nach Salzburg → Toast „Auftrag abgeschlossen +792€" → Folge-Auftrag erscheint.

Nächstes (Phase 3): Mehrfahrzeuge, Mehraufträge mit Variation, Kostenmodell für Miete/Standkosten, Hand-Polylines für 12 Hauptstrecken, Level 2 spielbar. Ziel: ~50% schaffen L2 mit greedy, ~70% mit optimal.

Blocker: keiner — Atlas hat „direkt Level 1 spielbar → Thomas- Browsertest → Phase 3" gesagt. Header-Klassen-Frage 02:45 ist faktisch durch Selbstkorrektur auf Template gelöst, aber Atlas könnte noch beanstanden falls anders gemeint.

Offen für Thomas:

  • Browser-Test App/logistik?level=1: 1 Auftrag links, 1 LKW rechts, klicken → blinkende Ringe → LKW klicken → Fahrt → Toast bei Ankunft → Folge-Auftrag → Bilanz wächst
  • Test-Harness App/sims/logistik/test.html: 17 Gruppen, ~60 Cases, alle grün erwartet

Tagesabschluss 2026-04-20 (05:00) — Phase 3 ausgeliefert

Atlas-Wrapper-Patch war 04:00 fertig, Thomas hat Phase 2 live gesehen und sofort gefragt, ob die LKW Hauptstraßen statt Luftlinie fahren können — exakt Phase 3 nach Plan. Grünes Licht erteilt, gestartet.

Phase 3 — Hand-Polylines + Engine

  • App/assets/data/lg-routes-osm.json — 17 Hauptstrecken zwischen den 13 Locations mit handgepflegten Polyline-Stützpunkten an bekannten Knoten (St. Pölten, Linz, Brennerpass, Lille, Reims, etc.). Bidirektional. Polyline-Längen via Python verifiziert.
  • engine.calculateRoute Phase 3 — Polyline-Lookup (Forward + Reversed), Fallback auf Luftlinie × 1.3. Provider-Markierung (osm_polyline / osm_polyline_reversed / airline_x1.3).
  • Pickup-Drive in assignContract: wenn Vehicle nicht am Origin, zweistufige Route (Pickup + Delivery)
  • 4-Phasen-Trip in _updateVehicles: pickup_drive → loading → delivery_drive → unloading. Mit Phase-Übertrag-Loop (kein Drift bei großen Ticks)
  • _completeContract mit vehicle-Param: noEmpty-Bonus korrekt, Pickup-Fahrkosten zusätzlich, contract.pickupKm für Tracking
  • Kostenmodell im tick (_applyRunningCosts): Standkosten/h für IDLE-Vehicles, Miete/Tag für alle Vehicles
  • Auftrags-Variation deterministisch (Mulberry32 + Counter): 12 CONTRACT_TEMPLATES, L2/L3 ziehen daraus, L1 hardcoded auf Wien↔Salzburg-Pendel (vermeidet Leerfahrten, hält naive im Akzeptanzkorridor)
  • seedInitialVehicles verteilt auf Hubs (L1: Wien; L2: Wien/ München/Hamburg; L3: 5 Hubs)

Phase 3 — Headless-Runner

  • greedy-Strategie aktiviert: höchster rewardBase ↔ größtes Vehicle das passt

Phase 3 — Tests

5 neue Gruppen, 19 neue Cases (Test 18-22). Total 22 Gruppen / ~80 Cases.

Mathematische Sanity-Checks (Python)

  • L1 Pendel mit airline-Fallback: 4 Trips × 792€ = 3169€ > 3000€ Min ✓
  • L1 mit Polyline (kürzer): noch profitabler
  • L2/L3 Akzeptanzkorridor: nicht erfüllt (siehe Balance-Hinweis unten)

Atlas-Wartepunkt

Wrapper-Erweiterung in logistik.php für lg-routes-osm.json (siehe Atlas-Mail 2026-04-20-0500). Bis dahin fahren LKWs im Browser noch auf Luftlinie × 1.3. Test-Harness unbetroffen (Inline-Seeds).

Balance-Hinweis (für künftige Tuning-Iteration)

L2/L3-Akzeptanzkorridor mathematisch noch nicht erfüllt. Pflichtenheft gibt rewardBase=1000 fix (unabhängig von Container/Distanz). Mit Pickup-Drive werden lange Strecken (>500km) verlustig. Tuning für Phase 4+ (z.B. Reward proportional zur Distanz). Test 22 prüft nur strukturelle Lauffähigkeit.

Offen für Thomas

  • Atlas-Wrapper-Update abwarten, dann Browser-Test L1 (Pendel-Modus, Polyline-Routen sichtbar — LKW fährt entlang St. Pölten-Linz-Wels statt diagonal durch die Donau)
  • Test-Harness test.html: 22 Gruppen / ~80 Cases sollten alle grün

Tagesabschluss 2026-04-20 (06:00) — Phase 4a + Music

Music-Player aktiv

  • 4 Tracks aus .humanInput/Background Music/_claimed/ kopiert nach App/sims/logistik/sounds/music/:
    • saddlewood-metronome.mp3 (3 MB, mechanisch-rhythmisch)
    • gears-and-marbles.mp3 (3.2 MB, Steve-Reich-Stil)
    • barbed-lullaby.mp3 (3.2 MB)
    • untitled-instrumental.mp3 (2.9 MB)
  • .ggs-music-Markup im Header eingebaut (Pattern aus template.html)
  • ggsMusicSetup-Funktion inline (gleicher Code-Pfad wie Klima/Fluss)
  • Default-Volume 22 %, localStorage ggs-music-logistik

Phase 4a — Engine

  • TRAIN-Routing: calculateRoute nutzt für mode=TRAIN den railShortestPath-Dijkstra über worldState.railnet. Wenn beide Locations Bahnknoten sind, kommt eine echte Mehr-Segment-Route raus (provider: rail_dijkstra), sonst Fallback auf Polyline/airline. Geometrie führt durch alle Bahnknoten.
  • Hafen-Schiffsankünfte: _maybeGenerateShipArrival(game) läuft im tick, alle 6 Sim-Stunden ein Schiff (deterministisch via Counter). Generiert OPEN-Auftrag mit Origin=Hafen, Target=Hauptstadt-Pool rotierend. Code-Präfix SHIP-, narrativeText erwähnt Hafen, Notification SHIP_ARRIVED. Nur aktiv bei cfg.portsEnabled=true.
  • Container-Standkosten: _applyRunningCosts rechnet zusätzlich zu Vehicle-Standkosten/Miete auch containerStandCostPerHour × quantityContainers × simHours für jeden OPEN-Auftrag mit Origin am Hafen.

Phase 4a — Tests (3 neue Gruppen, ~10 Cases)

  • Test 23 (5): TRAIN-Routing über railnet-Dijkstra (Wien→Hamburg via München = 1200 km, 2 RAIL-Segmente), Fallback wenn kein Bahnknoten
  • Test 24 (4): Schiffsankunft-Generator (nach 7h Sim mit portsEnabled → SHIP-Auftrag + Notification)
  • Test 25 (1): Container-Standkosten an Häfen (3 Container × 10€/h × 1h = 30€ pro Sim-Stunde abgezogen)

Total jetzt: 25 Test-Gruppen, ~90 Cases.

Phase 4b verschoben (Intermodal)

Vollständige intermodale Aufträge mit legs[]-Struktur und Multi- Vehicle-Übergabe (LKW→Zug→LKW) sind komplexer als die anderen 3 Phase-4-Punkte zusammen. Phase 4a deckt die Basis-Strukturen ab (Bahn-Routing + Hafen-Aufträge), 4b kommt als nächste Iteration:

  • Contract-Schema um legs: [{mode, originId, targetId}] erweitern
  • Engine-Logik für Übergabe zwischen Vehicles am Terminal/Hafen
  • Container am Hafen warten auf Folge-Vehicle (Inland-Strecke)
  • LOADING-Phase am Übergabepunkt mit echten Cargo-Transfer-Zeiten
  • Lehrziel #13 (kombinierte Verkehre) wirklich erlebbar

Offen für Thomas

  • Browser-Test App/logistik?level=1: Music-Player rechts oben sollte sichtbar sein (Tracks wählbar, ▶ startet)
  • Browser-Test test.html: 25 Gruppen / ~90 Cases sollten alle grün
  • Phase-4b-Entscheidung: jetzt oder erst nach L3-Tuning?

Atlas-Wartepunkte

  • Wrapper-Erweiterung lg-routes-osm.json (von Mail 0500, noch offen)
  • Music-Tracks-Bestätigung (von Mail 0540, „letzten paar" akzeptiert?)

Tagesabschluss 2026-04-20 (06:30) — Phase 4b + 5a ausgeliefert

Thomas: „Arbeite weiter, soweit du kannst." → Phase 4b (Intermodal-Engine) und Phase 5a (Event-Engine) komplett implementiert. Phase 5b (Hilfestufen-UI) auf Phase 6 verschoben — passt natürlich zu Sprachregel-Check + Leichte Sprache (alles UI-Polish).

Phase 4b — Intermodale Aufträge

  • Schema: Contract bekommt optional intermodal: true und legs: [{legNum, mode, originLocationId, targetLocationId, state, assignedVehicleId, routeId, departTime, arrivalTime}]. Plus currentLegNum und currentLocationId (wo der Container gerade ist).
  • _makeIntermodalContract(game, code, legs, containers, isExpress): Factory mit Aggregations-Daten (Gesamt-Distanz approx, Gesamt-Frist, rewardBase × 1.5 als Intermodal-Bonus).
  • assignContract(game, contractId, vehicleId, legNum?):
    • bei intermodal: legNum Pflicht (sonst nimmt currentLegNum)
    • prüft Vehicle-Mode-Match zum Leg-Mode (TRAIN-Leg → TRAIN-Vehicle)
    • setzt leg.state statt c.state
  • _completeLeg(game, contract, legNum, route, vehicle):
    • markiert Leg als DELIVERED
    • bucht Fahrkosten dieses Legs sofort (Reward kommt am Schluss)
    • setzt currentLegNum/currentLocationId vor
    • aktiviert nächsten Leg auf OPEN (Notification LEG_TRANSFERRED)
    • bei letztem Leg: Reward + Bonus + Strafe in einem buchen, Contract als DELIVERED/LATE in completedContracts
  • _stepVehiclePhase UNLOADING: erkennt intermodal und ruft _completeLeg statt _completeContract

Wichtig: Strategien (naive/greedy) sind Phase 4b NICHT angepasst — sie würden auf intermodal-Aufträgen mit Mode-Mismatch crashen. Phase 4c oder Phase 5 für Strategy-Anpassung. UI ebenfalls noch nicht intermodal-tauglich; Tests testen explizit via _makeIntermodalContract.

Phase 5a — Event-Engine

  • _maybeGenerateEvents(game, simMinutes): würfelt deterministisch via Mulberry32 (game.seed ^ 0xE7E7 + Counter _eventsRngCalls). Pro Sim-Stunde-Block + EVENT_TYPE: prob = baseProb × eventProbabilityMultiplier
  • EVENT_RULES (aus PH 65.5): TRAFFIC_ACCIDENT 5 % Speed×0.5, SNOW 10 % Speed×0.7 (Alpen), PORT_DELAY 8 % Loadtime×1.5
  • Event-Dauer: 30-120 min (deterministisch via 2. Würfel)
  • _expireEvents(game): filtert abgelaufene Events
  • _vehicleSpeedMultiplier(game): kombiniert alle aktiven Events multiplikativ → wirkt im _stepVehiclePhase auf route.totalDurationMinutes
  • Notifications: EVENT_STARTED mit Emoji-Message (🚧 Unfall, ❄ Schnee, Hafenüberlastung)

Phase 5b — Hilfestufen-UI verschoben auf Phase 6

contract.hintMode ist schon im Schema (Phase 0/2), BLINK_EXACT ist visuell umgesetzt (Phase 2). Die anderen 4 Stufen (SHOW_COUNTRY, SHOW_REGION, DISTANCE_FEEDBACK, NONE) brauchen UI-Erweiterung und passen natürlich zu Phase 6 (UI-Polish + Sprachregel + Leichte Sprache) — alle drei drehen an der Darstellungs-Schicht.

Phase 4b + 5 — Tests

5 neue Cases:

  • Test 26 (4 Cases): Intermodal-Schema (legs[], States)
  • Test 27 (8 Cases): Multi-Leg-Trip (Rotterdam_Hafen→Hamburg→München)
  • Test 28 (3 Cases): Event-Generierung deterministisch + reproduzierbar
  • Test 29 (1 Case): Manuelles Event reduziert Vehicle-Speed
  • Test 30 (2 Cases): Events laufen nach Dauer ab

Total jetzt: 30 Test-Gruppen, ~110 Cases.

Was noch offen ist (Phase 6, 7, weitere)

  • Phase 6: Hilfestufen-UI, 1× Minigame (An-die-Rampe-Einparken), Sprachregel-4a-Check aller UI-Texte, Leichte-Sprache via pickText(), Glossar-Begriffs-Anbindung
  • Phase 7: Lehrkraft-Konfiguration (über Admin-Tool), Analytics-Dashboard (Kennzahlen aus PH 23.2)
  • Strategie-Anpassung: greedy für intermodal, optimal-Strategie
  • Balance-Tuning für L2/L3 (rewardBase distanzproportional?)

Browser-Tests offen

  • Test-Harness: 30 Gruppen / ~110 Cases sollten alle grün
  • Live-UI: Music-Player + LKW-Polylines (nach Atlas-Wrapper-Update)

Tagesabschluss 2026-04-20 (07:00) — Phase 6 ausgeliefert

Thomas: „Mach weiter. Direkt Phase 6 machen." → UI-Polish komplett in 3 Subphasen.

Phase 6a — Sprachregel + pickText + Hilfestufen + Glossar + Events

  • Sprachregel-4a-Audit: alle UI-Texte sauber (nur interne Doc-Comments enthalten „Spielzustand"/„spielbar" — laut Atlas-Briefing erlaubt)
  • pickText-Helper mit Easy-Detection: ?easy=1 URL-Param oder localStorage 'logistik:easy'='1' schaltet auf Leichte-Sprache-Variante
  • GLOSSAR-Fallback (Pattern aus Fluss): 16 Begriffe inline definiert (Container, Intermodal, Umschlag, Luftlinie, Disposition, Frist, Leerfahrt, Standkosten, Bahnterminal, Hafen, Routing, Spedition, Logistikkette, Auftrag, Fahrzeug, Logistik). Wenn Atlas/Glossar später DB-API liefert → Fallback bleibt als Backup.
  • Glossar-Click-Handler: .ggs-glossar-popup Pattern aus Design-System
  • Glossar-Markups in Auftrags-Karten + Hint-Texten + Didaktik-Text
  • 5 Hilfestufen visuell (PH 10.3):
    • BLINK_EXACT: ✓ Origin (gelb) + Target (rot) blinken (war Phase 2)
    • SHOW_COUNTRY: alle Locations im selben Land wie Target leuchten
    • SHOW_REGION: alle Locations in selber Region leuchten (sanftes Blau)
    • DISTANCE_FEEDBACK: Skelett (UX-Mechanik kommt mit Phase 7+)
    • NONE: nichts angezeigt
  • Event-Panel im Didaktik-Bereich: aktive Events als Pills („🚧 Unfall · noch 25 min", „❄ Schnee · noch 60 min")
  • pickText in Toasts: standard + easy für Auftrag-Zuweisung, Delivery-Result, Fehlermeldungen
  • CSS für [data-glossar]: dotted-Underline + cursor:help

Phase 6b — Intermodal-UI

  • Auftrags-Karte erkennt c.intermodal und zeigt Leg-Liste als Pills (durchgestrichen=DELIVERED, fett-grün=OPEN, grau=WAITING)
  • 🔗-Symbol im Auftrag-Titel bei Intermodal
  • Mode-Filter im Vehicles-Panel: bei selected intermodal-Auftrag werden Vehicles, deren Mode nicht zum aktuellen Leg passt, als „busy" angezeigt mit Hint „benötigt: 🚆 Zug" / „benötigt: 🚚 LKW"
  • Click-Handler übergibt currentLegNum an assignContract
  • Bei Intermodal: Auftrag bleibt selected nach Vehicle-Wahl (für Folge-Legs)
  • Demo-Hook: ?demo-intermodal=1 triggert Beispiel-Auftrag Rotterdam_Hafen → Hamburg → München bei L3
  • Strategien angepasst: naive/greedy filtern intermodal-Aufträge raus (Phase 6c oder Tuning-Iteration für intermodal-fähige Strategien)

Phase 6c — Minigame „An-die-Rampe-Einparken"

  • Engine: applyMinigameResult(game, result) implementiert (war Stub):
    • Speichert loadingTimeFactor aus result.metadata in game._loadingTimeModifier
    • Wirkt auf nächste LOADING-Phase (in assignContract), danach Reset auf 1
    • Trackt analytics.minigamesPlayed + minigamesSuccessful
    • Generiert MINIGAME_DONE-Notification
  • UI: Modal mit Canvas (420×200), Top-Down-View
  • Steuerung: Touch-Buttons ⬅ ➡ + 📦 Andocken (iPad-tauglich, ≥44px)
  • Bewertung:
    • LKW-Vorderkante in 12 px um Rampen-Mitte → perfect → factor 0.8 (20 %)
    • 12-30 px → ok → factor 1.0
    • 30 px → miss → factor 1.3 (+30 %)

  • PH 65.9 Werte exakt umgesetzt
  • Trigger-Button 🎮 im Header sichtbar wenn cfg.minigamesEnabled=true (L2/L3)
  • pickText für alle Minigame-Texte (standard + easy)

Phase 6 — Tests

  • Test 31 (4 Cases): applyMinigameResult setzt Modifier, wird in nächster LOADING-Phase angewendet (5 × 0.8 = 4 min), dann Reset
  • Test 32 (1 Case): Minigame-Fail erhöht Loading auf 6.5 min (5 × 1.3)

Total jetzt: 32 Test-Gruppen, ~115 Cases.

Was Phase 6 NICHT enthält

  • Strategien-Anpassung für intermodal (Phase 6d / Tuning)
  • DB-Glossar-API (Atlas + Glossar-Instanz)
  • DISTANCE_FEEDBACK voll umgesetzt (braucht Klick-zum-Wählen-UX)
  • Keine API-Endpunkte
  • Kein Lehrkraft-Konfig-UI (Phase 7)

Browser-Tests offen

Atlas-Wartepunkte

  • Wrapper-Erweiterung lg-routes-osm.json (Mail 0500)
  • Glossar-Begriffe (Anfrage 0010, Atlas koordiniert)
  • Music-Tracks-Bestätigung (Mail 0540)

Tagesabschluss 2026-04-21 (Phase 8) — Multi-Contract-Tour

Thomas's Konzept übernommen: Vehicle-first-Lademodus.

  1. Klick auf IDLE-Vehicle → Lademodus aktiv (Banner + Laderaum-Slots)
  2. Klick auf OPEN-Auftrag → wandert in den LKW (Cargo-Emoji im Slot)
  3. 🚀 Fahrt starten" → Multi-Stop-Tour beginnt

Engine-API neu:

  • loadContract(game, vehicleId, contractId) — Kapazität-Check, Mode-Check, Contract → RESERVED
  • unloadContract / cancelLoading — vor Fahrt-Start
  • startTour(game, vehicleId) — baut Stops (alle Pickups erst, dann alle Dropoffs in Klick-Reihenfolge), konsolidiert aufeinanderfolgende Stops am gleichen Ort, berechnet Routen pro Segment, startet erste Phase

Trip-Phase neu:

  • tour_driving (zwischen Stops) und tour_handling (an einem Stop laden/entladen)
  • _stepVehiclePhase durchläuft Stops sequentiell, bucht Fahrkosten pro Segment sofort, Reward bei Dropoff
  • _endTour setzt Vehicle zurück auf IDLE

Cargo-Typen mit Emojis:

  • lg-cargo-types.json um emoji-Feld erweitert (📱 Elektronik, 👕 Kleidung, ⚙️ Maschinen, 🥫 Lebensmittel, 🧪 Chemie, 🔩 Fahrzeugteile, 🪵 Holz/Papier, 🪨 Rohstoffe)
  • CONTRACT_TEMPLATES haben jetzt cargoTypeIds-Liste pro Strecke
  • _nextContractTemplate zieht deterministisch einen Cargo-Typ
  • Laderaum-Slots zeigen das Cargo-Emoji des belegenden Auftrags

UI-Lademodus:

  • Vehicle-Card zeigt Banner + Laderaum-Grid (cap-viele Slots, gefüllt mit Cargo-Icons)
  • 🚀 Fahrt starten"-Button (disabled bei leer) und „↺ Abbrechen"
  • Klick auf RESERVED-Auftrag macht nichts (Card ist busy-styled)
  • Wechsel zu anderem Vehicle: altes Vehicle wird automatisch entladen (cancelLoading)

Bestehende Pfade unangetastet:

  • assignContract bleibt für intermodale Aufträge (selectedContractId-Pfad)
  • Engine-Tests 1317 nutzen weiter assignContract → laufen unverändert
  • Intermodal hat eigenen 4-Phasen-Trip (pickup_drive/loading/delivery_drive/unloading), nicht den neuen Tour-Pfad

Was Phase 8 NICHT enthält (Phase 9 / nice-to-have):

  • Tour-Route-Vorschau auf der Karte vor „Fahrt starten" (geplante Stops als gestrichelte Linie)
  • Klick-Animation „Container wandert in den LKW"
  • Naive/greedy-Strategien wurden noch nicht angepasst (filtern intermodal+RESERVED)
  • Optimierungs-Button („Reihenfolge optimieren ")
  • Während-der-Fahrt-Nachladen (an Stops zusätzliche Aufträge dazunehmen)

Browser-Test:

  • http://localhost/geograsim/App/logistik?level=3
  • Zug-Card klicken → Banner „Lademodus aktiv" + 20 Slots
  • Aufträge nacheinander reinklicken — Container füllen sich mit Emoji
  • 🚀 Fahrt starten" — Zug fährt erst alle Pickup-Orte, dann alle Dropoff-Orte ab
  • Bei selber Origin: Stops werden konsolidiert (1 Pickup für mehrere Aufträge)

Tagesabschluss 2026-04-20 (08:00) — Phase 7a: Analytics + Balance-Tuning

Thomas: „mach weiter" → Phase 7 angepackt. Teile, die Plattform-Domain sind (Lehrkraft-Admin + API-Endpunkte + DB-Migration), an Atlas übergeben (Mail 0800). Modul-Seite von Phase 7 ist fertig:

Balance-Tuning: rewardBase distanzabhängig

  • _computeReward(distanceKm, isExpress) in Engine
  • PH-Base + max(0, (km - 300) × 1.5) Zuschlag
  • Kurze Strecken bleiben PH-kompatibel (Wien-Salzburg: 1000→1039€)
  • Lange Strecken profitabel (Wien-Hamburg: 1000→2350€)
  • Intermodal-Bonus × 1.5 bleibt erhalten
  • Python-verifiziert: L1-Pendel-naive bleibt schaffbar (845€ × 4 = 3380€)

Analytics-Tracking in Engine

  • totalRewardEarned, totalPenaltyPaid, totalFareCostPaid
  • runningCostsTotal (war schon da)
  • contract.durationHours pro abgeschlossenem Auftrag

UI — Analytics-Panel

  • Toggle-Button 📊 oben rechts auf der Karte
  • 12 Kennzahlen live (Aufträge, Leerfahrtenquote, Verspätungsquote, Ø-Net/Auftrag, Erlöse, Fahrkosten, Strafen, Standkosten+Miete, Minigame-Erfolg, Bilanz/Profit)
  • Live-Update im RAF-Loop bei offenem Panel

UI — End-Screen

  • Overlay bei State-Wechsel zu LEVEL_SUCCESS / LEVEL_FAILED
  • Success in grün, Fail in rot
  • Gekürzte Stats-Liste (5 wichtigste Werte)
  • pickText für standard/easy
  • „Neuer Durchgang"-Button reloaded Seite
  • Via onStateChange-Hook automatisch getriggert

Was bei Atlas liegt (Phase 7b)

  • Lehrkraft-Admin-Tool (admin-levels.html erweitern vs. separat)
  • API-Endpunkte App/php/api/logistik-*.php — ich kann selbst, erwarte Go
  • DB-Migration lg_contracts_log — Freigabe vom Schema
  • Glossar-API-Anbindung falls die 13+ Begriffe angelegt sind

Offen für Thomas

  • Browser-Test L1/L2/L3: Analytics-Button 📊 rechts oben, End-Screen nach Zeitlimit oder Min-Ziel-Erreichen
  • Die Balance-Tuning-Änderung macht L1 leichter, L2/L3 besser spielbar

Tagesabschluss 2026-04-20 (07:30) — UX-Iteration „Fahrzeug-Auftrags-Verbindung"

Thomas: „wenn der Auftrag angenommen wurde und das Fahrzeug unterwegs ist, wäre es schön, wenn irgendwo erkennbar wäre, dass diese Verbindung wirklich vorliegt." → drei Mechanismen ineinandergreifen lassen.

Was neu ist

  • Vehicle-Card zeigt Trip-Info bei MOVING/LOADING/UNLOADING:
    • Phase-Label („🟡 Leerfahrt zum Abholen", „📦 Lädt", „🟢 Unterwegs", „📥 Lädt ab")
    • Auftrag-Code + Strecke („C-001 · Wien → Salzburg")
    • Progress-Bar bei Fahrten (live aus v.segmentProgress)
    • ETA („ETA 14:32") oder Restdauer („noch 3 min") je nach Phase
  • Vehicle-Marker mit Hover-Tooltip (Leaflet bindTooltip, sticky): Name, Phase, Auftrag, Prozent-Fortschritt
  • Klickbares Pairing:
    • Klick auf Vehicle-Card oder -Marker → selectedVehicleId
    • Zugehörige Contract-Card bekommt linked-pair-Highlight (blauer Ring)
    • Vehicle-Card bekommt linked-Highlight (grüner Ring)
    • Zugehörige Route wird auf der Karte dicker+kräftigrot, andere Routen werden gedimmt
    • Klick zentriert die Karte auf's Fahrzeug
    • Erneuter Klick deselect
  • Auto-Deselect: wenn Vehicle IDLE wird (Delivery fertig) → Selection automatisch gelöscht

CSS-Klassen neu

  • .lg-trip-info (+ .pickup, .loading) — Trip-Box unter Vehicle-Titel
  • .lg-progress-bar + .lg-progress-fill (+ .pickup für gelb)
  • .lg-card.linked (grün) + .lg-card.linked-pair (blau)

Keine neuen Tests

UX-Erweiterung (visuell), kein Engine-Change. Test-Gruppen bleiben bei 32.

Offen für Thomas

  • Browser-Test App/logistik?level=1:
    • Auftrag klicken → LKW klicken → Fahrt startet
    • Jetzt: Vehicle-Card zeigt „🟢 Unterwegs · C-001 · Wien → Salzburg · ETA ..." mit Progress-Bar die mit 1×/4×/8× Speed füllt sich live
    • Marker-Hover auf der Karte zeigt Tooltip
    • Marker-Klick zentriert Karte + beide Cards sind farblich verbunden
  • Bei L2/L3 analog — mit mehreren aktiven Trips siehst du die Fokus- Route hervorgehoben, andere gedimmt

Tagesabschluss 2026-04-22 — UX-Polish-Sprint + Atlas-Phase-7b-Entscheidungen

Neue Atlas-Nachricht (1200, gelesen + quittiert)

2026-04-22-1200-phase7-entscheidungen-und-db.md — Atlas hat nach 2 Tagen Pause alle drei offenen Punkte entschieden:

  1. Lehrkraft-Admin: Atlas erweitert App/admin-levels.html (zentrales Tool). Mein Beitrag: App/sims/logistik/admin-fields.json mit Feld-Beschreibungen aus balance-matrix.md §5.
  2. API-Endpunkte: Ich baue selbst, Pattern aus App/php/api/glossar.php. Drei Endpunkte: logistik-sessions.php, logistik-saves.php, logistik-analytics.php. Security: Session-ID gegen student_sessions validieren. Kein formales Review, ich committe wenn zufrieden.
  3. DB-Migration lg_contracts_log erledigt. Schema erweitert um intermodal, route_distance_km, route_mode. Meister pingt Atlas für Produktions-Replikation.
  4. Glossar-API: Fallback bleibt, Switch wenn Glossar liefert. Pattern kommt in App/docs/module-interface.md.

Thomas-Frage „nächstes Modul" → Atlas sagt: erst nach Phase 7b.

Phase 8 + UX-Iterationen (heute + gestern)

  • Multi-Contract-Tour: Vehicle-first-Lademodus, Cargo-Icons (📱👕⚙️🥫🧪🔩🪵🪨), Klick-Reihenfolge-Tour (Pickups zuerst, dann Dropoffs; konsolidiert aufeinanderfolgende Stops am gleichen Ort), Laderaum-Slot-Visualisierung, „🚀 Fahrt starten" / „↺ Abbrechen"
  • Container-Visualisierung: bis 6 Container als einzelne 📦-Symbole, ab 7 als „N× 📦". Mit Glossar-Popup (TEU + metrische Maße)
  • Scale-Bar auf Leaflet-Karte (unten-links, metrisch, bis 100 km)
  • Pro-Vehicle-Farben (8 Palette-Farben): Vehicle-Card-Dot, Marker-Ring, Route-Farbe (durchgezogen Lieferfahrt, dünn gestrichelt Pickup-Leerfahrt)
  • Event-Symbole auf der Karte: 🚧 Unfall (Mittelpunkt einer aktiven Route), ❄ Schnee (Alpen-Region ±0.8°), Hafenüberlastung (am Hafen)
  • Rote Routen bei Verspätung (dashArray, überschreibt Vehicle-Farbe)
  • Analytics-Panel gedämpft (1 Hz statt 60 Hz), Status-Leiste 4 Hz
  • Farbleitsystem: OPEN grün · PICKUP/LOADING/IN_TRANSIT orange · DELIVERED blau · LATE rot · WAITING beige. Deutsche Labels mit pickText
  • State-Labels deutsch: „offen"/„Abholung läuft"/„unterwegs"/„geliefert"/...
  • Vehicle-Auftrag-Verbindung: Klick auf Vehicle (trip-aktiv) oder Marker → Fokus-Route rot-dick, andere gedimmt, passende Contract-Card mit blauem Ring (linked-pair). Vehicle-Card mit Progress-Bar + ETA
  • Analytics-Panel + End-Screen (Phase 7a)
  • Balance-Tuning (Phase 7a + 8): _computeReward distanz-proportional
    • Container-Komponente (+250 €/zusätzl. Container), CONTRACT_TEMPLATES auf mehr 1-Container-Ranges (damit kleiner LKW nützlich wird)
  • Drei-Kommastellen-Fix: fmtEuro() + fmtEuroSigned() runden überall auf ganze Euro (Status, Toast, Analytics, End-Screen)

Minigame-Komplettumbau (mehrere Iterationen heute)

  • Grüne Zielzone (LKW-Größe + 3 px Toleranz), sichtbar schraffiert mit „🎯 Hier parken"-Beschriftung
  • Referenz-Miniaturen (3× 130×70 Canvas): Rückwärts · Vorwärts · Schief
  • Countdown 3:00 rückwärts, MM:SS-Format, warnt bei <60 s orange, <30 s rot
  • Auto-Andocken sobald 0,3 s stabil in grüner Zone + rückseitig + langsam
  • Rückseitig-Pflicht: Nur angle ≈ 180° (Heck zur Rampen-Rückwand) zählt als „richtig"
  • Live-Dock-Status: „✓ Zone · ✗ Heck zur Rampe (45°) · ✓ still"
  • Crash-Szenarien → Game Over, factor 1.5:
    • Anderes Fahrzeug rammen
    • Bucht-Wand mit v>55 UND tiefem Overlap
    • Zeitablauf (3 min)
  • Active Mover ab L2 sichtbar im Feld: fahrendes Fahrzeug mit Waypoints
    • sanfter Lenkung (Math.atan2 + max-turn-rate), wraps am Rand
  • Zeit → Ladezeit-Faktor: <15 s → 0.7× / 15-30 s → 1.0 / 30-60 s → 1.2 / 60-180 s → 1.3 / Crash/Timeout → 1.5
  • LKW-Optik verbessert: Kabine + Auflieger, Frontscheibe, Scheinwerfer, 6 Räder mit gelenkten Vorderrädern, Schatten
  • Web-Audio-Sounds (synthesized, kein externer File nötig):
    • Engine-Brummen: Sägezahn 55-200 Hz, Volume skaliert mit v
    • Brems-Quietschen: Bandpass-Rauschen 0.25 s Burst bei abruptem v-Abfall
    • Crash: tieffrequenter Sinus-Sweep + Lowpass-Impuls
  • Musik-Auto-Start: Hauptmusik wird getriggert wenn Modal öffnet (click auf #ggs-music-toggle falls nicht playing)
  • Buttons: „↺ Neu starten" (gelb-warm, 46 px hoch) + „Fertig · Schließen" (dunkelgrün), beide groß und touch-tauglich
  • Andocken-Button entfernt (Auto-Detection ersetzt Manual-Check)

Offene Arbeitsliste (Phase 7b — Atlas-Reihenfolge)

  1. App/sims/logistik/admin-fields.json — Feld-Beschreibungen aus balance-matrix.md §5 (15 Min Arbeit)
  2. App/php/api/logistik-sessions.php — POST start/end, GET status
  3. App/php/api/logistik-saves.php — POST save, GET load (gegen game_saves.save_data JSON, Engine serialize() schon bereit)
  4. App/php/api/logistik-analytics.php — POST in lg_contracts_log (Schema Atlas bereits angelegt)
  5. Analytics-Logging in _completeContract-Hook — pro Delivery POST an Analytics-API

Nicht-Blocker-Wartepunkte

  • Wrapper-Erweiterung lg-routes-osm.json (Mail 0500) — Atlas hatte bestätigt 0400 als Tile-Proxy-Patch, Routes-Seed aber weiterhin offen. Browser-LKW fahren weiterhin Luftlinie × 1.3 (Fallback). Tatsächlich: engine.loadContent liest window.LOGISTIK_SEEDS.routesOsm falls gesetzt → wenn Atlas den Wrapper erweitert, greift Polyline-Routing automatisch.
  • Glossar-API-Pattern (Atlas koordiniert mit Glossar-Instanz)

Browser-Test jetzt


2026-04-22 ~14:00 — Phase 7b ausgeliefert (nach Atlas-12:00-Mail)

Gebaut

  • App/sims/logistik/admin-fields.json — alle 19 params-Keys aus balance-matrix.md §5 mit label, labelEasy, type, unit, min/max/step, options, default, help. Gruppiert in 7 Abschnitten (Wirtschaft, Auftragslage, Fahrzeugpool, Didaktik & Hilfen, Ereignisse, Verkehrstraeger, Sonstiges). Bonus: availableVehicleTypes als multienum, levelNameEasy als text für Leichte Sprache.

  • App/php/api/logistik-sessions.php — POST start/end, GET status. Persistiert ohne neue Tabelle via game_saves mit Namespace-Keys logistik:active-attempt / logistik:history (Ring-Puffer letzte 20 Durchgänge). Security: Cookie-Session gegen student_sessions validiert.

  • App/php/api/logistik-saves.php — GET/POST/DELETE. 5 Slots (15) via Keys logistik:save:<slot>. 500 KB-Limit. Baut auf generischer game_saves-Tabelle auf — keine Duplikat-Tabelle zu saves.php.

  • App/php/api/logistik-analytics.php — POST in lg_contracts_log (Atlas-Schema mit intermodal + route_distance_km + route_mode). GET liefert 3 Scopes: me (eigene letzten 50), class (Lehrer-only, pro Session), level (Lehrer-only, pro Level-Aggregation).

  • Engine-Hook: game.pendingAnalytics als neue Queue. _pushAnalyticsEntry() wird in _completeContract (Single) und _completeContractMulti (Tour) aufgerufen. Engine selbst macht keinen Netz-Call — bleibt in Node/Browser gleich testbar. UI drainiert die Queue alle 2s und POSTet (best-effort).

  • game.html-IntegrationLG_API-Helper: fire-and-forget mit credentials: same-origin, 401 → bis Session-Ende offline. Auf Game-Init: startAttempt(levelNum). Auf LEVEL_SUCCESS/FAIL: endAttempt(success, stats) + Last-Drain der Analytics. Save/Load-Buttons jetzt Server-first mit localStorage-Fallback + Leichte-Sprache-Toasts.

Security-Minimum (wie Atlas vorgegeben)

  • Jeder POST validiert Session-ID aus ggs_session-Cookie gegen student_sessions-Tabelle (nicht nur Cookie-Präsenz)
  • Keine Fremd-Session-IDs schreibbar — session_id kommt IMMER aus Server-Cookie, nie aus Request-Body
  • DELETE/GET auf Saves nur für eigene Session
  • class/level-Analytics-Scopes nur mit requireTeacher()

Offene Punkte (an Atlas-Review)

  • logistik-saves.php legt nicht in einer eigenen Tabelle ab, sondern namespaced im vorhandenen game_saves. Falls du stattdessen eine lg_saves-Tabelle willst, Migration + Refactor-Patch.
  • logistik-sessions.php speichert Aktiv-Attempt ebenfalls in game_saves. Einfach, kein Schema. Falls du reportingfähige lg_attempts-Tabelle willst, sag Bescheid.
  • Ich habe keinen Browser-Test gemacht — es hängt daran, ob die bestehende ggs_session-Cookie auch unter /App/logistik?level=1 mitkommt (sollte dank BASE_PATH-Konfiguration, aber ungeprüft).

PHP lint

/c/xampp/php/php.exe -l App/php/api/logistik-sessions.php → OK
/c/xampp/php/php.exe -l App/php/api/logistik-saves.php    → OK
/c/xampp/php/php.exe -l App/php/api/logistik-analytics.php → OK

Was Atlas jetzt tun kann

  1. Admin-UI gegen admin-fields.json bauen — alle Feld-Metadaten stehen
  2. Review der 3 PHP-Endpunkte, besonders: ist die game_saves-Kooptierung für Sessions/Saves ok oder dedizierte Tabelle?
  3. Meister anpingen, damit das lg_contracts_log-Schema auf Produktion ist
  4. Glossar-API — sobald die 13 Begriffe da sind, einbauen (Inline-Fallback in game.html funktioniert bis dahin)

2026-04-23 — Heute gebaut (lange Session)

Neu-Mails von Atlas (beide gelesen)

  • 2026-04-22 12:30 ElevenLabs-Sound-Pipeline: zentrales Script App/scripts/generate-sounds.py, API-Key liegt, Pattern App/sims/logistik/scripts/sounds-list.json. Vorgeschlagene Liste mit 22 Sounds (~3-5 €). Noch nicht ausgeloest — wartet auf Thomas-Kommando, dann einmaliger Aufruf.
  • 2026-04-23 11:00 Integrations-Auftrag: Logistik ist Referenz. Drei Punkte: (a) mode-check im Wrapper (logistik.php), (b) Assessment-Calls bei level-start/running/completed, (c) Phase-7b — Atlas listete das noch als „offen", das ist aber seit 2026-04-22 14:00 geliefert (siehe zentrale/2026-04-22-1400-logistik-phase7b-fertig.md). Atlas hat noch nicht reviewt.

Rangier-Minispiel — Phase 3 komplett neu gebaut (Thomas-Wunsch)

  • Top-Down-Ansicht (Lok + Waggons rotieren mit Schiene)
  • Canvas 1120×400, aspect 14/5
  • 17 Segmente: 4 Hauptgleis + 3 Sidings + 3 Top-Branches + 3 Bottom-Branches + 4 Sammelgleis (inkl. 20px Stub samm_R fuer W6)
  • 6 Weichen W1-W6, Tasten 1-6 oder Klick
  • Endpunkt-basierte Verbindungen (SG_LINKS + SG_SWITCHES), sgConnected(segId, endpoint)
  • Direction-Tracking {segId, s, dir} mit korrektem sgTransitionOut-Helper: Lok-Heading via Dot-Produkt projiziert. Buggy alter Code flippte dir bei geraden Uebergaengen → Zug faltete sich. Fix verifiziert.
  • Consist-Modell mit Items-Array, auto-Kupplung am Wagen-Ende (nicht an Lok-Nase → Lok-Front blockiert mit Warnung)
  • Entkupplung per ✂-Klick in Luecken (nur im Stillstand, senkrecht vom Gleis gezeichnet)
  • Waggon-Labels #1 #2 #3 #4 statt Stadt-Emojis (Thomas-Wunsch — klarer)
  • Switch-Warning: roter pulsierender Ring + Web-Audio-Warnton (2× 880Hz Square) wenn: Lok faehrt gegen Sackgasse / Lok-Front rammt geparkte Wagen / Weiche umschalten wenn Zug drauf
  • Zeit-Bonus: < 4 Minuten → timeBonus: true im applyMinigameResult-Result

L1-Innen-Progression (Thomas-Wunsch: steigernd)

  • game.progression = { round, trucksBought } in createGame
  • _effectiveMaxContracts(game): L1 waechst dynamisch 1 → 2 (Runde 2-3) → 3 (Runde 4+)
  • Pool mit 5 Staedten statt Wien↔Salzburg-Pendel: Wien/Salzburg/Muenchen/Berlin/Hamburg mit Reward-Multiplikatoren 0.81.7
  • Staffel-Freischaltung: Runde 1-2 nur mult ≤ 1.0, Runde 3-4 ≤ 1.4, ab Runde 5 voll
  • awayBonus: true-Flag auf Auftraegen mit Leerfahrt zum Pickup — UI-Badge noch zu bauen
  • Auto-Buy TRUCK_SMALL: ab Balance ≥ 15.000 € spawnt automatisch neuer Kleiner LKW (Kosten 5.000 €), max 3 Fahrzeuge
  • Runden-Increment in BEIDEN _completeContract*-Pfaden

Balance-Regel R-1 (Startbudget-Runway)

  • Formal: startBudget ≥ 1.5 × (rental×vc + idle×vc×12)
  • L3 verletzt R-1 (2.500 € startBudget vs. 4.650 € benoetigt)
  • L1/L2 passieren
  • Python-verifiziert: L3-Runway 0.810.89 Tage — Tag 1 endet sicher im Minus
  • Doku: App/sims/logistik/level-progression.md (L1-Design §1 + L3-Analyse + R-1 §2)

3 neue zentrale-Mails an Atlas (alle offen)

  1. 2026-04-22 14:30 ElevenLabs-Frage — von Atlas beantwortet (Pipeline-Doku, s.o.)
  2. 2026-04-23 17:00 Warnton-Asset (Heli-Ton wiederverwenden?) + Konzept „Minispiel-an-Fahrt-Koppeln" (bonus auf Lade-/Entlade-Zeit)
  3. 2026-04-23 17:30 L3-Balance kaputt + Regel R-1 zur Pruefung + 3 Fix-Optionen (Empfehlung: startBudget 2.500 → 5.000)

Was auf Atlas wartet

  1. Admin-UI gegen admin-fields.json (von Phase 7b)
  2. Review der 3 PHP-Endpunkte (game_saves-Kooptierung ok?)
  3. Meister-Ping fuers lg_contracts_log-Schema auf Produktion
  4. Entscheidung L3-Balance (A/B/C aus 17:30-Mail)
  5. Daumen hoch fuer R-1 als Invariante
  6. Heli-Warnton-Pfad freigeben
  7. Buy-in fuer Minispiel-an-Fahrt-Koppeln-Architektur

Was auf Thomas wartet (optional, kein Blocker)

  • Sounds generieren: python App/scripts/generate-sounds.py logistik nachdem sounds-list.json unter App/sims/logistik/scripts/ angelegt ist (kostet 3-5 € ElevenLabs-Kontingent)
  • Entscheidung ob L1-UI-Badges fuer Runde + awayBonus dazu sollen

Offene Arbeit bei mir (wenn Atlas freigibt)

  • Integrations-Auftrag (mail 23.04 11:00): mode-check im logistik.php + Assessment-Calls
  • sounds-list.json anlegen + Pipeline-Run (auf Thomas-Kommando)
  • End-Screen auf .ggs-endscreen-Komponente umstellen (sobald Atlas die Inbox-Meldung schickt)

2026-04-23 — Nachtrag (Integrations-Auftrag + Polish)

Integrations-Vertrag Kap. 6 umgesetzt

  • logistik.php: Session-Cookie → student_sessionsclass_modules + student_modules + students.easy_language. Setzt LOGISTIK_SESSION_MODE (free | teacher_started | locked), LOGISTIK_FORCED_LEVEL, LOGISTIK_EASY, STUDENT_EASY. Locked-Fall: HTTP 403 + minimale Sperrseite mit Cockpit-Link. PHP-Lint: ok.
  • game.html respektiert LOGISTIK_FORCED_LEVEL bei mode === 'teacher_started' (URL ?level wird ignoriert).
  • Assessment-Calls via LG_API.postAssessment(phase, payload):
    • started direkt nach Engine-Init
    • running alle 30 s Heartbeat aus RAF-Loop (mit balance, completed, active, ratios, round)
    • completed bei LEVEL_SUCCESS/LEVEL_FAILED (mit finalBalance, minTarget, success, kennzahlen)
    • Alle fire-and-forget via bestehende LG_API-Infrastruktur (401 -> session-disabled)

L1-Progression-UI-Polish

  • Away-Bonus-Badge auf Auftragskarten: ↗ woanders in Beige, wenn c.awayBonus === true (= Origin nicht an Vehicle-Location)
  • Runden-Anzeige im Header: Level-Badge zeigt jetzt Level 1 · Runde 3 auf L1 (andere Level unveraendert)

Regel R-1 engine-seitig als Soft-Check

  • In loadContent: _validateRuleR1(cfg) loggt console.warn mit Formel + benoetigtem Betrag, wenn Level die Regel verletzt. L3 triggert den Warn aktuell (2.500 € < 4.650 €). Nicht blockierend — Lehrkraft kann bewusst ueberschreiben.

Manueller Fahrzeugkauf ab L2

  • Engine: LogistikEngine.buyVehicle(game, mode) + LogistikEngine.VEHICLE_PRICES (TRUCK_SMALL 5k, TRUCK_LARGE 15k, TRAIN 40k). Prueft availableVehicleTypes, Balance, spawnt Fahrzeug, sendet VEHICLE_PURCHASED-Notification, incrementiert progression.trucksBought.
  • UI: Button „🛒 Neues Fahrzeug kaufen" oben in der Fahrzeugliste, sichtbar nur wenn maxActiveContracts > 1 (= L2+). Klick oeffnet Dialog-Overlay mit 3 Typen: Icon, Name, Kurz-Hint, €/km+€/h, Preis. Nicht-leistbare Fahrzeuge grau + Preis rot. Erfolg → Toast + Re-Render.

Testbar jetzt

Was jetzt auf Atlas/Thomas wartet

  • Atlas-Review aller 3 offenen Mails in zentrale (Phase-7b-Fertig, 17:00 Warnton+Trip-Koppeln, 17:30 L3-Balance+R-1)
  • Atlas-Meldung wegen .ggs-endscreen-Komponente (bis dahin bleibt unser Endscreen-Overlay)
  • Thomas: ElevenLabs (morgen) und Sounds

Deploy-bereit (auf Thomas-Kommando)

Alle Aenderungen lokal fertig. Kein DB-Migration noetig (alles via bestehende assessments-Tabelle + bestehende game_saves-Keys + Engine-interne Progression).


2026-04-24 ~11:00 — Deploy von Atlas durch (Option B)

Atlas hat den Deploy selbst koordiniert — antwortete auf meine Anfrage vom Morgen (zentrale/2026-04-24-0900-logistik-deploy-anfrage.md).

Auf Prod live (https://geograsim.at/):

  • pages/logistik.php — mode-check + forcedLevel + easy + Sperrseite
  • php/api/logistik-sessions.php, logistik-saves.php, logistik-analytics.php
  • sims/logistik/game.html (~149 KB, aktueller Stand)
  • DB: lg_contracts_log existiert und leer, bereit
  • DB: students.easy_language additiv ergänzt (Default 0)
  • Module-IDs-Migration sim-XX → klima/heli/fluss/logistik
  • HTTP-200 auf /logistik und /modul-logistik

Reviews geschlossen:

  • Phase 7b Fertig — gelesen, kein Review noetig
  • Warnton + Trip-Integration — kommt als Phase 8e separat
  • L3-Balance + R-1 — Atlas delegiert an mich: game_levels.params- Update mache ich selbst in einem Sweep, kein Atlas-Eingriff noetig

Noch bei mir offen (nicht blockierend):

  • L3 startBudget 2.500 → 5.000 in game_levels.params via UPDATE-SQL (Empfehlung A aus meiner 23.04 17:30 Mail) — wartet auf Thomas-OK
  • Sounds — Thomas kuemmert sich um ElevenLabs
  • End-Screen-Umstellung auf .ggs-endscreen — wartet auf Atlas-Komponenten-Meldung

2026-04-24 ~13:00 — Alle delegierten Schritte umgesetzt

L3-Balance-Fix

  • SQL-Migration: App/Don_t_Deploy/2026-04-24-logistik-l3-balance-fix.sql setzt L3 params.startBudget auf 5.000 (war 2.500).
  • Lokal ausgerollt auf XAMPP-MariaDB. Verifikation OK.
  • Wartet auf naechsten Deploy → Atlas (siehe Mail zentrale/2026-04-24-1300-logistik-l3-migration-und-balance-korridor.md).

Balance-Korridor-Doku + Mechanik

  • Neue Doku: App/sims/logistik/balance-corridor.md
  • Drei Regeln formal:
    • R-1 Runway: startBudget ≥ 1.5 × Tagesfixkosten — Engine-Warn.
    • R-2 Winnable: per Level min. 1 Strategie schafft Median-success ueber 5 Seeds.
    • R-3 Loseable: noop schlaegt 100% fehl, zusaetzlich strategie- spezifische Anforderungen pro Level.
  • Neuer Button Balance-Korridor-Check (R-1/R-2/R-3) in headless-runner.html: faehrt 45 Durchlaeufe (3 Lvl × 3 Strategien × 5 Seeds) und liefert PASS/FAIL pro Regel + Level. Auch greedy als Proxy fuer optimal verwendet (Stub fehlt noch).
  • Aktuelle Verifikation R-1 mathematisch: L1/L2/L3 alle PASS nach Fix.

Bekannte Luecke (nicht-blockierend)

  • optimal-Strategie in headless-runner.js ist noch Stub (wirft). Damit ist L3-Winnability nicht hart-verifiziert. Folgearbeit, sobald nichts dringender ist.

Atlas-Mail raus

zentrale/2026-04-24-1300-logistik-l3-migration-und-balance-korridor.md mit SQL-Migration zum naechsten Deploy + Korridor-Doku zur Kenntnis.


2026-04-24 ~14:00 — optimal-Strategie implementiert

Die letzte offene Luecke im Balance-Korridor geschlossen.

Was gebaut

headless-runner.jsoptimal ist nicht mehr ein Stub, sondern eine Best-Net-Heuristik:

  • Pro Tick alle (contract, vehicle)-Paarungen bewerten: net = reward × 1.15 fare erwartete Verspaetungsstrafe mit fare = pickup-km × €/km + pickup-h × €/h + delivery-km × €/km + delivery-h × €/h und expectedPenalty = rewardBase × latePenaltyRate × max(0, totalH slackH)
  • Kapazitaets-Constraint hart (Skip wenn veh.capacity < c.containers)
  • Paarungen nach Netto sortiert, oben-nach-unten feuern, pro Iteration jedes Vehicle/Contract max. 1×
  • Unprofitable Paarungen (net ≤ 0) werden ausgelassen

~120 Zeilen, UMD-konform (laeuft in Browser + Node). Intermodal noch ausgeklammert (wie greedy).

Korridor-Check jetzt vollstaendig

  • headless-runner.html → „Balance-Korridor-Check" faehrt jetzt 60 Durchlaeufe (3 Lvl × 4 Strategien × 5 Seeds)
  • R-2 ueber optimal hart verifizierbar (nicht mehr nur greedy-Proxy)
  • R-3 strenger: zusaetzlich zur noop-Regel wird fuer L2 naive und L3 greedy auf Median-Fail geprueft (Level muss schwerer werden, nicht nur durch Untaetigkeit verlierbar)

Docs aktualisiert

  • balance-corridor.md §5 + §7: Status auf vollstaendig, Luecke geschlossen
  • headless-runner.js Header-Kommentar: Strategie-Beschreibungen korrekt

Test-URL

http://localhost/geograsim/App/sims/logistik/headless-runner.html → 3. Button „Balance-Korridor-Check (R-1/R-2/R-3)" druecken → 60 Runs, Ergebnis-Tabelle mit PASS/FAIL pro Regel + Level + Detail-Zahlen.

Was jetzt noch offen bleibt

  • L3-SQL-Migration wartet auf naechsten Deploy (an Atlas via Mail 13:00)
  • ElevenLabs-Sounds (Thomas morgen)
  • End-Screen-Umstellung auf .ggs-endscreen (wartet auf Atlas)
  • Phase 8e Warnton + Trip-Integration (wartet auf Atlas-Meldung)

2026-04-24 ~16:00 — Phase 8e: L1-Stufen-Progression mit Accept/Decline

Auf Thomas-Wunsch: L1 in 6 Stufen geteilt mit jeweils einer neuen Entscheidungsdimension pro Stufe. Konzept in diesem Status-Update knapp, ausfuehrlich in level-progression.md nachtragbar.

Die 6 Stufen (L1-intern, reine Engine+UI-Mechanik, kein DB-Change)

Stufe ab Runde Neu Mechanik
1 Fahren lernen 1 START druecken 1 Auftrag direkt OPEN, kein Accept noetig
2 Rueckweg waehlen 2 Annehmen/Ablehnen offers-buffer=1, Standard-Varianten im Pool
3 Zeitdruck 4 Express-Varianten 30 % Chance auf Eilauftrag (halbe Frist, +50 % Reward)
4 Container-Grenze 6 Multi-Container + TRUCK_LARGE-Unlock 25 % Chance auf 2-Container, Kauf-Dialog zeigt TRUCK_LARGE
5 Parallel disponieren 8 2 OPEN gleichzeitig + offers-buffer=2 volle Pool-Breite, Distanzen bis 1.5× Mult
6 Soft-Ramp L2 11 Events 0 → 0.3, Fernstrecken eventProbabilityMultiplier=0.3, poolMaxMult=1.7

Neue Engine-Funktionen

  • CONTRACT_STATE.OFFERED + EXPIRED
  • LogistikEngine.acceptOffer(game, contractId) — setzt OFFERED→OPEN, prueft max-OPEN-Slots
  • LogistikEngine.declineOffer(game, contractId) — entfernt OFFERED
  • _l1Stufe(game) / _l1StufeCfg(game) — Stufen-Aufloesung via round
  • _totalContractSlots(game) — max-OPEN + offers-buffer
  • _maybeRefillOffers(game) — fuellt total-slots mit OFFERED-Angeboten
  • _expireOffers(game) — entfernt abgelaufene OFFERED nach Sim-Zeit
  • _maybeGenerateEvents + buyVehicle beachten L1-Stufen-Overrides
  • Offers expirieren nach 30 Sim-Minuten stumm
  • Tick ruft _expireOffers + _maybeRefillOffers jeden Tick

UI-Neu

  • OFFERED-Karten: eigenes Beige-Farbthema, Countdown ⏳ Verfällt in MM:SS
  • Buttons ✓ Annehmen / ✕ Ablehnen pro Angebot
  • Express-Badge ⚡ Eilauftrag + Multi-Container-Badge ×2
  • Header-Badge: Level 1 · Stufe 3 Zeitdruck · R 5
  • Kauf-Button erscheint auf L1 ab Stufe 4 (Container-Grenze)
  • Kauf-Dialog zeigt TRUCK_LARGE auf L1 Stufe 4+
  • RAF-Loop: Sekunden-Trigger fuer Countdown-Update wenn Offers aktiv

Headless-Runner angepasst

  • naive/greedy/optimal akzeptieren OFFERED automatisch (Stufe 1 hatte keine, jetzt ab Stufe 2)
  • noop laesst Offers verfallen → L1 fail wie erwartet

Testbar

Deploy-Relevant

  • Keine DB-Aenderung → keine Migration noetig
  • Reiner Code-Deploy (engine.js + game.html)

2026-04-24 ~17:00 — Phase 8e Rückbau (L1 zu komplex, zurück zu simpel)

Thomas-Feedback: „das mit dem Stress, Eilauftrag, geht viel zu schnell, keine Reaktionszeit. In Level 1 gibt es keinen Eilauftrag. Aufträge kommen und gehen, sind vielleicht irgendwann auch weg ... aber sonst zu kompliziert." → simpler machen.

Was rausgenommen

  • CONTRACT_STATE.OFFERED aus dem L1-Flow (Enum bleibt im Code, aber Generator setzt es nicht mehr). Aufträge erscheinen direkt als OPEN.
  • Accept/Decline-Buttons auf den Auftragskarten
  • Countdown Verfällt in MM:SS"
  • Express-Badge ⚡ Eilauftrag und Multi-Container-Badge ×2
  • RAF-Sekunden-Trigger (war nur für Countdown)
  • TRUCK_LARGE-Unlock ab L1 Stufe 4 in buyVehicle + UI-Kauf-Dialog
  • Kauf-Button auf L1 generell (Auto-Buy reicht)

Was bleibt (einfaches Modell)

  • 5 Stufen (statt 6), jeweils maxOpen + poolMaxMult + eventMult:
    • Stufe 1 Erster Auftrag (R1): 1 OPEN
    • Stufe 2 Mehrere zur Wahl (R2): 2 OPEN, gleicher Pool
    • Stufe 3 Weitere Strecken (R4): 2 OPEN, Pool bis Mult 1.3 (München)
    • Stufe 4 Mehr Fahrzeuge (R7): 3 OPEN, Pool bis Mult 1.5
    • Stufe 5 Soft-Ramp → L2 (R11): 3 OPEN, Pool 1.7 + Events 0→0.3
  • „Kommen und gehen": _expireOffers (nur auf L1 aktiv) entfernt OPEN-Auftraege die ihre eigene dueTime ueberschritten haben ohne Fahrzeug-Zuweisung. Silent-Remove + kurze Notification. Keine eigene Ablaufzeit, keine gelben Ringe, kein UI-Alarm — die Frist ist die natuerliche Grenze.
  • Auto-Buy TRUCK_SMALL bei Balance ≥ 15.000 €: unverändert
  • Pool-Staffelung nach Distanz (Stufen-poolMaxMult): unverändert
  • Away-Bonus-Badge auf Auftragskarten: bleibt (ist subtil, nicht stressig)
  • Runden-/Stufen-Anzeige im Header: aktualisiert auf neue Stufen-Namen

Engine-Seite

  • L1_STUFEN[] hat jetzt nur {n, name, minRound, maxOpen, poolMaxMult, eventMult}
  • _effectiveMaxContracts(game) nimmt stufe.maxOpen direkt
  • _totalContractSlots = _effectiveMaxContracts (kein Buffer-Konzept mehr)
  • _generateL1ContractFromPool: immer OPEN, 1 Container, nicht Express
  • _expireOffers → silent-removes OPEN mit abgelaufener dueTime (nur L1)

Headless-Runner

  • acceptOffer-Aufrufe in naive/greedy/optimal bleiben stehen (try/catch — no-op wenn keine OFFERED-Angebote da sind)
  • L1 sollte jetzt wieder mit noop=fail, naive=success laufen

Testbar

http://localhost/geograsim/App/logistik?level=1 — Runde 1: ein Auftrag (wie altbewährt). Nach Lieferung: zwei Aufträge parallel, ohne Accept-Klick, jeder mit eigener dueTime. Wer ignoriert wird, verschwindet irgendwann still. Kein Stress, keine Eilaufträge, keine Countdown-Alarme.

Nicht-Deploy-blockierend

Keine DB-Änderung, reiner Code-Deploy.


2026-04-24 ~18:00 — Phase 8e Ausbau: Variety, History, Verfahren-Event

Thomas-Feedback: „Ab der zweiten Fahrt sollte es 3-4 Optionen geben. Manchmal attraktiver mit längerer Anfahrt, manchmal finanziell gut aber zeitlich knapp — muss an den Zahlen erkennbar sein. Fahrt-Protokoll als Pill." Plus Zusatzaufgabe: „Fahrer:in hat sich verfahren"-Event.

Mehr Optionen ab Runde 2

L1_STUFEN.maxOpen erhoeht:

  • Stufe 1 (R1): 1 Auftrag
  • Stufe 2 (R2+): 3 Auftraege parallel (war 2)
  • Stufe 3+ (R4+): 4 Auftraege parallel
  • poolMaxMult auch schneller erweitert: Stufe 2 schon auf 1.3 (München)

Profile-Variance im Generator

Jedes Angebot bekommt ein Profil gewuerfelt (Stufe 1 immer standard):

Profil Gewicht Reward-Mult Frist-Mult Pool-Filter
standard 50 % 1.0 1.0
tight (Frist knapp) 20 % 1.3 0.6
far (Weite Fahrt) 15 % 1.0 1.0 mult ≥ 1.5
easy (Kurz) 15 % 0.85 1.3 mult ≤ 1.0

Profil-Name wird auf contract.profile gespeichert, UI-Badge rendert:

  • knappe Frist (orange)
  • 🌍 weite Fahrt (blau)
  • 🌿 kurz (grün)

Zeit-Reserve-Berechnung sichtbar

Beim Klick auf Fahrzeug (Lademodus) rechnet jede Auftragskarte jetzt:

  • Fahrkosten ≈ X € + Marge ± Y € (wie bisher)
  • NEU: ⏰ Z.Z h Reserve in Grün/Orange/Rot:
    • ≥ 3 h grün (entspannt)
    • 13 h orange (knapp)
    • 01 h rot (kritisch)
    • < 0 h rot „Frist NICHT zu schaffen"

Dadurch erkennt der Spieler an den Zahlen: ⚡ knappe Frist-Auftraege mit hohem Reward sind nur machbar wenn die Zeit-Reserve es zulaesst.

Fahrt-Historie als Pills

Neuer UI-Strip zwischen Status-Leiste und Didaktikfenster:

  • 📜 Historie: Fahrt 1 +523 € | Fahrt 2 120 € | Fahrt 3 +890 €
  • Grüne/rote Pills je nach Netto-Vorzeichen
  • Klick auf Pill → Detail-Modal mit Strecke, Container, Dauer, Verspätung, Netto

Strip erscheint nur wenn ≥ 1 Lieferung abgeschlossen. Horizontal scrollbar bei vielen Pills.

Zusatzaufgabe: Verfahren-Ereignis

  • Engine-Trigger: Mit 6 % / Sim-Stunde pro Fahrzeug im *_drive ab L1 Stufe 2 wuerfelt ein Verfahren-Event. Bei Treffer:
    • vehicle.verfahrenPending = true
    • vehicle.verfahrenTargetLocationId = aktueller Trip-Zielort
    • vehicle.verfahrenDriverLabel = „Fahrerin Anna" oder „Fahrer Tom" (alternierend ueber game.progression.verfahrenCount)
    • Fahrzeug pausiert in _updateVehicles (keine Bewegung, keine Zeit-Verbrauch)
    • Notification DRIVER_LOST wird gefeuert
  • UI-Banner am oberen Map-Rand: 🤷 Fahrerin Anna hat sich verfahren! Bring sie nach Salzburg — klick den Ort auf der Karte.
  • Map-Klick-Handler pro Stadt-Marker:
    • Wenn ein Fahrzeug verfahrenPending hat und der geklickte Ort das Ziel ist → LogistikEngine.resolveDriverLost(game, vehicleId, locationId) → Fahrt geht weiter
    • Falscher Ort → Toast-Hinweis, Event bleibt aktiv
  • Didaktik: uebt Kartenorientierung; Zielstadt muss identifiziert werden

Minigame-Buttons korrigiert

  • 🎮 Einparken: jetzt auf allen Levels sichtbar (war fälschlich an minigamesEnabled gebunden, dadurch L1 leer)
  • 🚆 Rangieren: nur sichtbar wenn TRAIN im Fuhrpark (L1 hat keinen → Button aus)

Testbar

http://localhost/geograsim/App/logistik?level=1:

  • Runde 1: 1 Auftrag (Tutorial)
  • Runde 2+: 3-4 Optionen mit unterschiedlichen Profilen, durchgemischt
  • Zeit-Reserve erscheint beim Klick auf Fahrzeug
  • Trip-Pills unten nach jeder Lieferung
  • Gelegentlich Verfahren-Event → Stadt auf Karte zeigen
  • 🎮 LKW-Einparken-Button sichtbar

Reiner Code-Deploy, keine DB-Aenderung


2026-04-24 ~19:00 — End-Screen transparent + L1 längere Spielzeit + Favicon

End-Screen-Zahlen klarer

Alter End-Screen zeigte nur „Ø Netto/Auftrag" und „Endbilanz". Das war irreführend, weil in Multi-Contract-Touren Fahrkosten im Tick abgezogen werden, aber NICHT in contract.finalBalance — Summe der avgNet × Anzahl stimmte nicht mit Endbilanz überein. Thomas sah: 3 × 1247 = 3741 vs. Endbilanz +2547, konnte es nicht nachvollziehen.

Neu im End-Screen — komplette Konto-Rechnung sichtbar:

  • Startbudget
  • Erlöse (Basis + Bonus) +X €
  • Strafen X €
  • Fahrkosten X €
  • Laufende Kosten X €
  • Zuwachs (Konto) ±X €
  • Min-Ziel

Jetzt kann der Spieler selbst ausrechnen, wo das Geld hin ist. Die Zahlen-Quellen sind dieselben wie vorher (game.analytics), nur die Zeilen transparenter gruppiert.

L1 timeLimitHours 24 → 72

Thomas-Feedback: „das Spiel sollte deutlich länger gehen". L1-Tutorial war bei 4×/8× nur 3-6 Echt-Minuten lang, fühlte sich gehetzt an.

SQL-Migration: App/Don_t_Deploy/2026-04-24-logistik-l1-timelimit-72h.sql setzt game_levels.params.timeLimitHours von 24 auf 72 (= 9 Echt-Min bei 8×, 18 Echt-Min bei 4×). Andere Parameter unverändert: Min-Ziel 3.000 €, Events aus, BLINK_EXACT-Hilfe.

Lokal ausgerollt auf XAMPP. Aktueller DB-Stand:

L1: timeLimitHours=72 (war 24)
L2: timeLimitHours=48 (unverändert)
L3: timeLimitHours=72 (unverändert, startBudget=5000 seit letztem Fix)

Favicon verdrahtet

game.html hatte keine <link rel="icon">-Tags → Browser-Tab zeigte Generic-Icon. Jetzt analog zu heli/lehrplan/glossar:

  • game.html referenziert ../../favicon.svg + ../../favicon-96x96.png
  • logistik.php-Wrapper biegt beide Pfade auf absolute BASE_PATH-URLs um (im bestehenden strtr-Block)

Offene Deploy-Items für Atlas

Sammel-Liste der lokalen DB-Änderungen, die noch auf Prod müssen:

  1. 2026-04-24-logistik-l3-balance-fix.sql — startBudget 2500 → 5000
  2. 2026-04-24-logistik-l1-timelimit-72h.sql — L1 timeLimit 24 → 72
  3. Seed-Einträge class_modules für logistik='free' pro Klasse (lokal nur)

Diese drei Migrations sind reine game_levels.params / class_modules Updates, keine Schema-Änderungen.


2026-04-24 ~19:30 — Auto-Boost Fahrtzeit

Thomas-Wunsch: „In Phasen, in denen nur Fahrtzeit erwartet wird, die Timescale automatisch auf 8× springen und dann automatisch zurück."

Mechanik

  • Gespeicherte Player-Wahl (playerSpeed) vs. aktuelle sim-Geschwindigkeit
  • Jeden Frame updateAutoBoost():
    • Condition: allBusy = alle Fahrzeuge haben tripPhase && keinen verfahrenPending
    • shouldBoost = allBusy && kein Verfahren-Event offen
    • Wenn true + !autoBoostActive → setTimeScale(8), Flag setzen
    • Wenn false + autoBoostActive → setTimeScale(playerSpeed), Flag loeschen
  • Klick auf einen Speed-Button: playerSpeed updaten, AutoBoost deaktivieren (manueller Override hat Vorrang)
  • Pause (0×): Auto-Boost greift nicht

UI

  • Spieler-Button bleibt aktiv (visueller Anker)
  • Neuer Badge ⚡ Auto 8× rechts neben den Speed-Buttons pulsiert sanft gelb, wenn Auto-Boost aktiv
  • Tooltip: „Alle Fahrzeuge unterwegs — Sim läuft automatisch auf 8×. Pressen einer Taste übernimmt wieder die Kontrolle."

Auto-Release in diesen Fällen

  • Ein Fahrzeug wird IDLE (Lieferung fertig) → Spieler könnte neuen Trip starten
  • Verfahren-Event triggert → Spieler muss Karte klicken
  • Spieler klickt selbst eine Speed-Taste

Testbar

http://localhost/geograsim/App/logistik?level=1:

  • Assign Auftrag zu Lok → Fahrt startet → sobald sie rollt: Auto 8× Badge pulsiert gelb, Sim-Zeit rennt
  • Lieferung fertig → Fahrzeug IDLE → Badge verschwindet, Zurück auf Spieler-Speed (normalerweise 1×)

2026-04-24 ~20:00 — Road-Dijkstra + Verfahren-Penalty + Auto-Boost-Override

Straßennetz-Routing für LKWs

Thomas: „LKW fährt Luftlinie Salzburg→Berlin, unrealistisch."

  • Neuer Seed App/assets/data/lg-roadnet.json: 11 Knoten (Stadt-Hubs) + 13 Edges mit echten Autobahn-Distanzen (A1/A7/A8/A9 etc)
  • logistik.php injiziert Roadnet in LOGISTIK_SEEDS.roadnet
  • engine.js loadContent: nimmt Roadnet in worldState.roadnet auf
  • calculateRoute für TRUCK_SMALL/TRUCK_LARGE: erst Dijkstra auf Roadnet, Geometry = Polyline durch die Dijkstra-Knoten, Segments pro Kante mit routeCode (A8, A9 etc). Fallback routesOsm/Luftlinie für Locations ausserhalb des Roadnet-Graphs.
  • Salzburg→Berlin fährt jetzt salzburg→muenchen→berlin (150+580=730km) statt Luftlinie (590km).

Vertagte Follow-Up: Höhere „Auflösung" der Polylines

Thomas: aktuell sind Polyline-Segmente zwischen Stadt-Knoten gerade Linien. Echte Autobahnen haben Kurven. Option C aus meinem Feedback: hand-gepflegte Polylines pro Road-Kante in lg-routes-osm.json (13 Paare × 5-10 Stützpunkte ≈ 1.5 h Arbeit). In die To-Do-Liste aufgenommen, niedrige Prio.

Verfahren-Ereignis: Zeit-Strafe + Capital-Only

Thomas-Wunsch: Stufe A (Zeit-Strafe statt sichtbarem Detour), nur Hauptstädte zaehlen (sonst iPad-Fat-Finger-Problem).

  • Engine resolveDriverLost(game, vehicleId, clickedLocationId, locationType) unterscheidet jetzt 3 Fälle:
    • locationType !== 'CAPITAL'ignored:true, kein Strafe, UI zeigt „Nur Hauptstädte zählen"
    • Falsche Hauptstadt → wrong:true, wastedHours:1.5, akkumuliert in vehicle.verfahrenPenaltyHours, Event bleibt offen
    • Richtige Hauptstadt → löst Event auf, rechnet akkumulierte Strafe in Reduktion von segmentProgress um (max 90 % zurück) → Restfahrt dauert entsprechend laenger, late-fee-Risiko steigt
  • UI-Marker-Klick reicht loc.type mit, Toasts differenziert nach Fall
  • Konstante VERFAHREN_PENALTY_H = 1.5 in engine.js

TimeScale-Override bei Verfahren

Thomas: „Beim Verfahren TimeScale 1."

  • effectiveTimeScale() mit Prioritaet: Pause → Verfahren 1× → AutoBoost 8× → playerSpeed
  • Wenn Verfahren-Event triggert: egal ob vorher Player auf 4× oder AutoBoost 8× war, Sim springt sofort auf 1×
  • Nach Resolution: zurueck zur richtigen Stufe
  • AutoBoost-Badge wird waehrend Verfahren ausgeblendet

2026-04-24 ~20:30 — QoL: Auto-Select + Auto-Swap + Layer-Control raus

Auto-Select beim Lademodus

Thomas: „Das oberste freie Fahrzeug ist automatisch schon markiert und offen. Sobald es steht."

  • In renderVehicles(): wenn kein loadingVehicleId → setze auf erstes IDLE-Fahrzeug ohne tripPhase. Auch beim Game-Start.
  • Wenn das aktuell gewählte IDLE-Fahrzeug losfährt (tripPhase wird gesetzt) → automatisch auf nächstes IDLE umschalten
  • Resultat: Spieler klickt nur noch Aufträge, das Fahrzeug ist vorausgewählt

Auto-Swap im Laderaum

Thomas: „Wenn ein Auftrag bereits zugewiesen ist und ein anderer angeklickt wird, der nicht mehr Platz hat, fliegt der Auftrag, der bereits im LKW drin ist, wieder raus."

  • In Auftragskarten-Klick-Handler:
    • Wenn Auftrag bereits im Fahrzeug geladen: Toggle → entladen
    • Wenn loadContract wegen vollem Laderaum failt: ältesten geladenen Auftrag unloadContract, dann neu versuchen
    • Toast-Message: „🔄 X geladen (Y ausgetauscht)" statt Fehler
  • Spieler kann durch Aufträge schnell durchblättern

Layer-Control-Widget entfernt

Thomas: „Die Auswahl zur Ansicht rechts oben (Hauptstädte, Städte, Häfen, Terminals und Bahnnetz) kannst du entfernen. Wir zeigen einfach immer alles an."

  • L.control.layers(...) entfernt aus der Karten-Initialisierung
  • Alle Layer werden unbedingt dem Map hinzugefügt (capitals, cities, ports, terminals); Bahnnetz nur wenn railEnabled im Level-Config
  • Die Karte hat jetzt keine Widget rechts oben mehr

2026-04-24 21:30 — Bonus-Pills + Gratulations-Modal + Städte Tier 1 + Atlas-Mail

Atlas-Mail raus: Info-Cards mit Bildern (Heli-Pattern)

  • _inbox/zentrale/2026-04-24-2100-logistik-infocards-heli-pattern.md
  • 5 konkrete Fragen: Heli-Card-Komponente, Bild-Pfad/Lizenz, Granularität (pro Auftrag vs. pro Zielort), AI-Pipeline, Design-System-Wiederverwendbarkeit
  • Thomas-Wunsch: pro Start eine Info-Card mit Bild der Zielstadt
  • Warte auf Atlas-Antwort; baue derweil andere Tasks

Gratulations-Meldungsfenster

Thomas: „einen zweiten LKW bekommen. Dies wurde aber nicht angekündigt. In einem solchen Fall bitte kurzes Meldungsfenster. Gratulation..."

  • Neue Komponente .lg-announce-overlay + .lg-announce-modal in game.html (CSS + DOM)
  • announce(icon, title, text, sub) — Scale-in-Animation, 4 Sek auto-close, Click schließt sofort
  • VEHICLE_PURCHASED-Notification wird via drainNotifications() auf das Modal umgeleitet (statt Toast)
  • checkStufeChange() vergleicht _l1Stufe mit lastAnnouncedStufe, feuert Modal bei Stufen-Wechsel mit Stufen-Parametern (maxOpen/poolMaxMult/eventMult)

Bonus-Pills UI komplett

Thomas: „rechts oben Pills setzen, klickbar für Info, automatisch benutzt. Stack-Limit gute Idee. Bonusskala passt."

  • Container #bonusPills oben rechts über der Karte (absolute positioniert, pointer-events: auto)
  • renderBonusPills() zeichnet die FIFO-Queue aus game.pendingBonuses (cap 5); jede Pill mit ⏱ Icon + Minutenwert + Quellen-Tooltip
  • showBonusPopover(idx) — Click zeigt kurzes Erklär-Popover („Bonus aus Rangier-Minispiel — wird beim nächsten Laden angewendet")
  • flyBonusToVehicle(vehicle) — Consumption-Animation: Pill fliegt zum Fahrzeug-Marker, skaliert auf 0, dann pendingBonuses.shift()
  • Minispiel-Hook in mgApplyResult: bei Success LogistikEngine.pushLoadBonus mit 45/20/5 min je nach Zeit (<15s/<30s/<60s)
  • Engine hat _consumeNextLoadBonus(game, vehicle) an 4 Phase-Transitions (pickup/loading/unloading/dropoff)

Layer-Fix: Ports + Terminals wirklich sichtbar

Fehler nach Layer-Control-Removal: visibleLevel-Filter im marker forEach blockte Ports/Terminals (nur ab L3 sichtbar).

  • Filter entfernt — alle Locations immer gerendert
  • bindPopup zeigt jetzt Name + Typ-Label (Hauptstadt/Stadt/Hafen/ Terminal) + didacticInfo als kleinen Absatz
  • Popup-CSS .lg-loc-popup mit typeLabel-Subtitle

Städte-Erweiterung Tier 1 (Hauptstädte)

Thomas: „Mache einen Entwurf und gib vor, wie viele Städte in Europa relevant wären."

  • App/assets/data/lg-locations.json von 13 auf 27 Einträge erweitert (alle bestehenden Einträge behalten IDs/Koordinaten)
  • +14 Hauptstädte: Rom, London, Brüssel, Amsterdam, Prag, Budapest, Athen, Stockholm, Oslo, Helsinki, Dublin, Lissabon, Bern
  • Jeder Eintrag hat didacticInfo — 1 Satz mit logistik-relevantem Geo-Fakt (Verkehrsknoten, Hafen-Kapazität, EU-Status etc.)
  • regionId konsistent gesetzt (benelux, scandinavia, iberia, western_europe, southern_europe, central_europe)
  • Offen: Tier 2 (~50 Großstädte) + Tier 3 (~25 Häfen/Terminals) — Konzept steht, Umsetzung vertagt

Auto-Timescale-Badge dynamisch

Thomas: „bei der Auto Timescale steht immer Auto 8× .. die Zahl sollte sich aber ändern, wenn nicht reine Fahrt aktiv ist."

  • Badge-Text wird jetzt pro Frame aus effectiveTimeScale() gesetzt
  • ⚡ Auto 8× bei reiner Fahrt, ⚡ Auto 1× bei Verfahren-Event (wenn playerSpeed != 1)
  • Badge hidden wenn Auto-Logik nicht override-t (playerSpeed==target)
  • updateAutoBoost() resettet Badge auch bei non-RUNNING States (MINIGAME/PAUSED/LEVEL_SUCCESS), bisher blieb es stale sichtbar

Offene Punkte

  • Atlas-Antwort zu Info-Cards (5 Fragen vom 21:00)
  • Städte Tier 2/3 (Konzept steht, ausbauen)
  • Uhr mit Stunden/Minutenzeiger + Tag/Nacht in Karten-Ecke
  • Pausepflicht LKW bei Langstrecken in höheren Levels
  • Sounds via ElevenLabs (Thomas macht morgen)
  • Polyline-Auflösung Option C (hand-gepflegt pro road-edge)