# WM 2026 Board Live-Gruppentabellen, Drittplatzierten-Wertung und vollständiger K.o.-Baum der FIFA WM 2026 — mit korrekter **Annex-C-Zuordnung** der acht besten Gruppendritten und optionalen **Polymarket-Wahrscheinlichkeiten** pro Spiel. Gebaut als Next.js 15 (App Router) mit serverseitigem Feed-Proxy und Caching, Docker-Standalone-Image, ausgelegt für Caddy als Reverse Proxy. ## Warum ein Backend-Proxy? Das Frontend kann die Feeds **nicht direkt** aufrufen: - **football-data.org** erlaubt im Free-Tier nur 10 Anfragen/Minute und verlangt einen `X-Auth-Token` (im Browser nicht sicher unterzubringen). - **Polymarket Gamma** liefert `outcomePrices` als JSON-String und hat Rate Limits. - Beide setzen kein CORS für beliebige Browser-Origins. Deshalb holt die Route `app/api/matches` beide Feeds **serverseitig**, cached sie in-memory (Spiele 60 s, Odds 120 s) und liefert ein fertiges JSON. Das Frontend pollt nur diese eine eigene Route (alle 30 s). ## Architektur ``` Browser ──poll 30s──> /api/matches (Next.js, gecacht) ├── football-data.org/v4/competitions/WC/matches └── gamma-api.polymarket.com/events?slug=... │ ├── computeGroupTables() (FIFA-Tiebreaker) ├── computeThirdPlaceTable() (beste 8 Dritte) └── resolveAnnexC() (495 Szenarien, lib/annexc-data.ts) ``` Die Annex-C-Tabelle (`lib/annexc-data.ts`) enthält alle 495 möglichen Kombinationen aus den FIFA-Wettbewerbsregeln. Sobald genau 8 Gruppendritte feststehen, ordnet `resolveAnnexC()` jedem der acht betroffenen Gruppensieger (A, B, D, E, G, I, K, L) seinen Drittplatzierten zu, und der Bracket „verbindet" sich automatisch. ## Schnellstart (lokal) ```bash cp .env.example .env # FOOTBALL_DATA_TOKEN eintragen npm install npm run dev # http://localhost:3000 ``` Token kostenlos registrieren: https://www.football-data.org/client/register ## Deployment auf dem VPS (Docker + Caddy) Das Projekt geht davon aus, dass Caddy bereits als Reverse Proxy in einem externen Docker-Netz läuft. Heißt dein Netz anders, in `docker-compose.yml` und im Caddy-Snippet anpassen. ```bash # 1. Netz prüfen/anlegen (falls noch nicht vorhanden) docker network ls | grep caddy_net || docker network create caddy_net # 2. .env anlegen cp .env.example .env && nano .env # 3. Bauen und starten docker compose up -d --build # 4. Caddy-Route einbinden # Inhalt von Caddyfile.snippet in deinen Caddyfile übernehmen, # Domain anpassen, dann Caddy neu laden: docker exec -w /etc/caddy caddy caddy reload ``` Danach ist die Seite unter `https://wm.deine-domain.de` erreichbar. Caddy besorgt TLS automatisch. ## Konfiguration (.env) | Variable | Pflicht | Beschreibung | |-----------------------|---------|--------------| | `FOOTBALL_DATA_TOKEN` | ja | Token von football-data.org. Ohne ihn liefert die API nur die Wettbewerbsliste. | | `POLYMARKET_WC_SLUG` | nein | Slug des WM-Events auf Polymarket (Standard `world-cup-2026`). Den exakten Slug aus der URL nach `/event/` ablesen. | ## Feeds verifizieren Beide Upstream-Strukturen vor dem Turnierstart kurz gegenchecken (Felder können sich ändern): ```bash # football-data: Gruppenfeld "GROUP_X", score.fullTime, stage curl -H "X-Auth-Token: $FOOTBALL_DATA_TOKEN" \ "https://api.football-data.org/v4/competitions/WC/matches" | jq '.matches[0]' # Polymarket: markets[].outcomes / outcomePrices (JSON-Strings!) curl "https://gamma-api.polymarket.com/events?slug=world-cup-2026" | jq '.[0].markets[0]' ``` Stimmen Feldnamen nicht, nur die Adapter in `lib/feeds.ts` anpassen — der Rest (Tabellen, Annex C, Bracket) ist davon entkoppelt. ## Was anpassbar ist - **Anderer Ergebnis-Feed** (API-Football, TheStatsAPI): nur `fetchMatchesAndTeams` in `lib/feeds.ts` neu schreiben, sodass es `Match[]` + `Team[]` liefert. - **Odds-Matching**: `attachOdds` verknüpft per Teamname im Markttitel. Bei abweichenden Namen (z. B. „USA" vs. „United States") dort eine Alias-Tabelle ergänzen. - **Poll-Intervall**: in `app/page.tsx` (`setInterval`, Standard 30 s) und den Cache-TTLs in `lib/feeds.ts`. ## Korrektheit der Annex-C-Logik `lib/annexc-data.ts` wurde gegen die veröffentlichte FIFA-/Wikipedia-Tabelle geprüft. Beispiel Szenario 415 (Dritte aus A,B,C,E,F,H,I,J) ergibt die Zuordnung `H J B C A F E I` für die Gruppensieger A,B,D,E,G,I,K,L — exakt wie in den offiziellen Regeln. ## Lizenz / Hinweise Kein offizielles FIFA-Produkt. football-data.org ist für nicht-kommerzielle Nutzung kostenlos; bei kommerzieller Nutzung dort anfragen. Polymarket-Zugang und -Daten unterliegen den jeweiligen lokalen Bestimmungen.