121 lines
4.7 KiB
Markdown
121 lines
4.7 KiB
Markdown
# 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.
|