Files
wm-projekt/README.md
2026-06-22 15:32:32 -05:00

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.