404 lines
17 KiB
Markdown
404 lines
17 KiB
Markdown
# Projektplan: WM 2026 Tippspiel — Staffbase Custom Plugin
|
||
|
||
**Projekt:** WM 2026 Tippspiel
|
||
**Auftraggeber:** GEALAN Fenster-Systeme GmbH
|
||
**Erstellt:** April 2026
|
||
**Version:** 1.0
|
||
**Status:** Initialisierung
|
||
|
||
---
|
||
|
||
## 1. Projektziel & Vision
|
||
|
||
### 1.1 Zielsetzung
|
||
|
||
Entwicklung eines interaktiven Tippspiel-Plugins für die FIFA Weltmeisterschaft 2026 (USA/Kanada/Mexiko, 11. Juni – 19. Juli 2026), das nahtlos in die bestehende Staffbase-Mitarbeiter-App von GEALAN integriert wird. Alle Mitarbeitenden können über die gewohnte Staffbase-Oberfläche — auf Mobile und Desktop — ihre Tipps abgeben, Ergebnisse verfolgen und die Rangliste einsehen.
|
||
|
||
### 1.2 Kernziele
|
||
|
||
- Mitarbeiterbindung und -engagement rund um die WM 2026 stärken
|
||
- Niedrigschwellige Teilnahme: kein separates Login, keine externe App nötig
|
||
- Vollständige Integration in die bestehende Staffbase-Instanz von GEALAN
|
||
- Mehrsprachige Unterstützung (Deutsch, Englisch — erweiterbar)
|
||
- Skalierbar für zukünftige Turniere (EM, CL etc.)
|
||
|
||
### 1.3 Nicht-Ziele (Out of Scope v1.0)
|
||
|
||
- Echte Geldwetten oder externe Zahlungsabwicklung
|
||
- Integration mit externen sozialen Netzwerken
|
||
- Eigene mobile App (kein separates iOS/Android-App-Release)
|
||
|
||
---
|
||
|
||
## 2. Technische Architektur
|
||
|
||
### 2.1 Integrationsmodell: Staffbase Custom Plugin
|
||
|
||
Das Tippspiel wird als **Staffbase Custom Plugin** realisiert. Custom Plugins sind externe Web-Applikationen, die per **iFrame** in die Staffbase-Plattform eingebettet werden. Staffbase übernimmt die Authentifizierung der Mitarbeitenden automatisch über **JWT-Tokens (RS256)**, sodass kein separates Benutzerkonto für das Tippspiel benötigt wird.
|
||
|
||
**Vorteile dieses Ansatzes:**
|
||
- Vollständige technische Freiheit bei Backend, Frontend und Datenbank
|
||
- Automatisches Single Sign-On via Staffbase JWT
|
||
- Funktioniert auf iOS-App, Android-App und Web-Browser
|
||
- Keine Änderungen an der Staffbase-Instanz selbst notwendig
|
||
|
||
### 2.2 Architektur-Übersicht
|
||
|
||
```
|
||
┌─────────────────────────────────────────────┐
|
||
│ Staffbase-Plattform (GEALAN) │
|
||
│ │
|
||
│ ┌──────────────────────────────────────┐ │
|
||
│ │ Custom Plugin (iFrame) │ │
|
||
│ │ → Tippspiel-Frontend (React) │ │
|
||
│ └──────────────┬───────────────────────┘ │
|
||
│ │ JWT Token (automatisch) │
|
||
└─────────────────│───────────────────────────┘
|
||
│ HTTPS
|
||
┌────────▼─────────┐
|
||
│ Backend API │
|
||
│ (Node.js/Express)│
|
||
│ + JWT-Validierung│
|
||
└────────┬──────────┘
|
||
│
|
||
┌────────▼──────────┐
|
||
│ Datenbank │
|
||
│ (PostgreSQL) │
|
||
│ Supabase Managed │
|
||
└───────────────────┘
|
||
│
|
||
┌────────▼──────────┐
|
||
│ WM-Spielplan API │
|
||
│ football-data.org│
|
||
└───────────────────┘
|
||
```
|
||
|
||
### 2.3 Technologie-Stack
|
||
|
||
| Schicht | Technologie | Begründung |
|
||
|---|---|---|
|
||
| **Frontend** | React + TypeScript | Moderner Standard, große Community, passt zu Staffbase Client SDK |
|
||
| **Staffbase Integration** | @staffbase/plugins-client-sdk | Offizielle Brücke zwischen iFrame und Staffbase-App |
|
||
| **Backend** | Node.js + Express | Passt nahtlos zum Staffbase Node.js SDK |
|
||
| **Auth / SSO** | @staffbase/staffbase-plugin-sdk | JWT-Validierung (RS256/PKCS8) |
|
||
| **Datenbank** | PostgreSQL via Supabase | Managed, DSGVO-konform (EU-Region wählbar), einfaches Setup |
|
||
| **Hosting** | Railway oder Render | HTTPS out-of-the-box, einfaches Deployment, kostengünstig |
|
||
| **WM-Spielplan** | football-data.org API | Kostenfreie WM-Daten inkl. Ergebnisse, Teams, Gruppen |
|
||
| **Caching** | Redis (optional) | Spielplandaten cachen, Rate-Limit-Entlastung |
|
||
| **CI/CD** | GitHub Actions | Automatisiertes Deployment |
|
||
|
||
### 2.4 Staffbase SDK — Verfügbare Nutzerdaten via JWT
|
||
|
||
Bei jedem Aufruf des Plugins stellt Staffbase automatisch folgende Nutzerdaten bereit:
|
||
|
||
| Feld | Beschreibung | Verwendung im Tippspiel |
|
||
|---|---|---|
|
||
| `userId` | Eindeutige Staffbase-User-ID | Primärschlüssel für Tipps & Rangliste |
|
||
| `fullName` | Vollständiger Name | Anzeigename in der Rangliste |
|
||
| `locale` | Spracheinstellung (z.B. `de_DE`) | Automatische Sprachumschaltung |
|
||
| `role` | Staffbase-Rolle (admin, reader…) | Admin-Bereich nur für Admins sichtbar |
|
||
| `branchId` | Instanz-/Bereichs-ID | Für standortbezogene Auswertungen |
|
||
|
||
---
|
||
|
||
## 3. Funktionsumfang (Features)
|
||
|
||
### 3.1 Kernfunktionen (MVP — Pflicht für v1.0)
|
||
|
||
#### F1 — Benutzer & Authentifizierung
|
||
- Automatischer Login via Staffbase SSO (JWT) — kein separates Konto
|
||
- Benutzerprofil mit Name und Gesamtpunkten
|
||
- Rollenbasierter Zugriff: Normaler Nutzer vs. Admin
|
||
|
||
#### F2 — WM-Spielplan
|
||
- Anzeige aller 104 WM-Spiele (Gruppenphase + KO-Runde)
|
||
- Automatische Synchronisation mit football-data.org API
|
||
- Anzeige von Datum, Uhrzeit (lokalisiert), Stadion, Teams, aktueller Ergebnisstatus
|
||
|
||
#### F3 — Tipp-Eingabe
|
||
- Tipp abgeben: Ergebnis (Heimtore : Auswärtstore) pro Spiel
|
||
- Tipp nur möglich bis Anpfiff (Deadline-Schutz)
|
||
- Tipp-Änderung bis zur Deadline erlaubt
|
||
- Visuelle Bestätigung bei gespeichertem Tipp
|
||
|
||
#### F4 — Punkte-System
|
||
- **Ergebnis exakt richtig:** 3 Punkte
|
||
- **Tendenz richtig (Sieg/Remis/Niederlage):** 1 Punkt
|
||
- **Falsch:** 0 Punkte
|
||
- Bonus-Punkte für KO-Runde konfigurierbar (z.B. ×2 ab Halbfinale)
|
||
- Automatische Berechnung nach Ergebnis-Eintrag durch Admin
|
||
|
||
#### F5 — Rangliste
|
||
- Live-Gesamtrangliste aller Teilnehmenden
|
||
- Anzeige: Platz, Name, Punkte, Tipp-Quote
|
||
- Filterbar nach Abteilung oder Standort (via Staffbase-Gruppen)
|
||
- Eigene Position stets sichtbar (auch wenn außerhalb der Top 10)
|
||
|
||
#### F6 — Admin-Bereich
|
||
- Spielergebnisse manuell eintragen / korrigieren
|
||
- Punkte automatisch neu berechnen nach Eintrag
|
||
- Übersicht aller Tipps pro Spiel
|
||
- Teilnahme-Statistiken (Anzahl Tipps, aktive Nutzer)
|
||
|
||
### 3.2 Erweiterungen (Nice-to-have — v1.1 oder später)
|
||
|
||
| Feature | Beschreibung | Aufwand |
|
||
|---|---|---|
|
||
| **Push-Benachrichtigungen** | Ergebnisse-Update via Staffbase News API | Mittel |
|
||
| **Gruppenphase-Tipper** | Tipp auf Gruppensieger/-zweiten | Mittel |
|
||
| **Turniersieger-Tipp** | Einmaliger Tipp auf WM-Sieger (×5 Punkte) | Klein |
|
||
| **Mini-Ligen** | Interne Teams (z.B. nach Abteilung) | Groß |
|
||
| **Kommentar-Funktion** | Tipps kommentieren | Klein |
|
||
| **Tipp-Analyse** | Auswertung: beliebteste Tipps, Überraschungen | Mittel |
|
||
| **Automatische Ergebnis-Synchronisation** | Polling football-data.org, kein manuelles Eintragen | Mittel |
|
||
|
||
---
|
||
|
||
## 4. Datenbankschema
|
||
|
||
### 4.1 Kerntabellen
|
||
|
||
```sql
|
||
-- Nutzer (befüllt automatisch via JWT bei erstem Login)
|
||
CREATE TABLE users (
|
||
id VARCHAR(64) PRIMARY KEY, -- Staffbase userId
|
||
full_name VARCHAR(255) NOT NULL,
|
||
locale VARCHAR(10) DEFAULT 'de_DE',
|
||
role VARCHAR(20) DEFAULT 'reader',
|
||
branch_id VARCHAR(64),
|
||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
last_seen_at TIMESTAMPTZ DEFAULT NOW()
|
||
);
|
||
|
||
-- WM-Spiele (synchronisiert via football-data.org)
|
||
CREATE TABLE matches (
|
||
id SERIAL PRIMARY KEY,
|
||
external_id VARCHAR(32) UNIQUE NOT NULL, -- ID aus football-data.org
|
||
stage VARCHAR(50) NOT NULL, -- 'GROUP_STAGE', 'ROUND_OF_16', ...
|
||
group_name VARCHAR(10), -- 'A', 'B', ... (NULL in KO-Runde)
|
||
home_team VARCHAR(100) NOT NULL,
|
||
away_team VARCHAR(100) NOT NULL,
|
||
kickoff_at TIMESTAMPTZ NOT NULL,
|
||
home_score SMALLINT, -- NULL bis Abpfiff
|
||
away_score SMALLINT,
|
||
status VARCHAR(20) DEFAULT 'SCHEDULED' -- SCHEDULED, IN_PLAY, FINISHED
|
||
);
|
||
|
||
-- Tipps
|
||
CREATE TABLE predictions (
|
||
id SERIAL PRIMARY KEY,
|
||
user_id VARCHAR(64) REFERENCES users(id),
|
||
match_id INTEGER REFERENCES matches(id),
|
||
predicted_home SMALLINT NOT NULL,
|
||
predicted_away SMALLINT NOT NULL,
|
||
points_earned SMALLINT, -- NULL bis Spiel ausgewertet
|
||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||
UNIQUE (user_id, match_id)
|
||
);
|
||
|
||
-- Rangliste (materialized view oder separate Tabelle für Performance)
|
||
CREATE MATERIALIZED VIEW leaderboard AS
|
||
SELECT
|
||
u.id AS user_id,
|
||
u.full_name,
|
||
u.branch_id,
|
||
COALESCE(SUM(p.points_earned), 0) AS total_points,
|
||
COUNT(p.id) AS total_predictions,
|
||
COUNT(CASE WHEN p.points_earned = 3 THEN 1 END) AS exact_hits,
|
||
RANK() OVER (ORDER BY COALESCE(SUM(p.points_earned), 0) DESC) AS rank
|
||
FROM users u
|
||
LEFT JOIN predictions p ON p.user_id = u.id
|
||
GROUP BY u.id, u.full_name, u.branch_id;
|
||
```
|
||
|
||
---
|
||
|
||
## 5. API-Design (Backend)
|
||
|
||
### 5.1 Endpunkte
|
||
|
||
| Method | Endpunkt | Beschreibung | Auth |
|
||
|---|---|---|---|
|
||
| `GET` | `/api/matches` | Alle Spiele mit Status | JWT |
|
||
| `GET` | `/api/matches/:id` | Einzelnes Spiel | JWT |
|
||
| `GET` | `/api/predictions/me` | Eigene Tipps | JWT |
|
||
| `POST` | `/api/predictions` | Tipp abgeben | JWT |
|
||
| `PUT` | `/api/predictions/:id` | Tipp ändern (vor Deadline) | JWT |
|
||
| `GET` | `/api/leaderboard` | Gesamtrangliste | JWT |
|
||
| `GET` | `/api/leaderboard/me` | Eigene Position | JWT |
|
||
| `PUT` | `/api/admin/matches/:id/result` | Ergebnis eintragen | JWT + Admin |
|
||
| `POST` | `/api/admin/recalculate` | Punkte neu berechnen | JWT + Admin |
|
||
| `GET` | `/api/admin/stats` | Teilnahmestatistiken | JWT + Admin |
|
||
|
||
### 5.2 Authentifizierung
|
||
|
||
Jeder Request vom Frontend sendet den Staffbase JWT im Header:
|
||
|
||
```
|
||
Authorization: Bearer <staffbase-jwt-token>
|
||
```
|
||
|
||
Das Backend validiert den Token mit dem `@staffbase/staffbase-plugin-sdk` (RS256, Public Key aus Staffbase Studio). Bei gültigem Token werden Nutzer-ID, Name, Rolle und Locale aus dem Token extrahiert und der Nutzer automatisch in der `users`-Tabelle angelegt (upsert).
|
||
|
||
---
|
||
|
||
## 6. Projektphasen & Zeitplan
|
||
|
||
### Gesamtlaufzeit: 10 Wochen (April — Mitte Juni 2026)
|
||
|
||
### Phase 1 — Setup & Fundament (Woche 1–2)
|
||
|
||
| Aufgabe | Verantwortlich | Aufwand |
|
||
|---|---|---|
|
||
| Staffbase Plugin registrieren (Plugin-ID + Public Key) | Admin | 0,5 Tage |
|
||
| Node.js Projekt-Skeleton generieren (`create-staffbase-plugin-nodejs`) | Entwicklung | 0,5 Tage |
|
||
| Git-Repository anlegen, CI/CD konfigurieren (GitHub Actions) | Entwicklung | 1 Tag |
|
||
| Hosting-Umgebung aufsetzen (Railway/Render) | Entwicklung | 0,5 Tage |
|
||
| Supabase-Projekt anlegen, Datenbankschema deployen | Entwicklung | 1 Tag |
|
||
| JWT-Authentifizierung implementieren und testen | Entwicklung | 1 Tag |
|
||
| football-data.org API-Key beantragen und testen | Entwicklung | 0,5 Tage |
|
||
|
||
**Meilenstein:** Authentifizierter API-Call von Staffbase-Plugin zu Backend funktioniert.
|
||
|
||
### Phase 2 — Kern-Backend (Woche 3–4)
|
||
|
||
| Aufgabe | Verantwortlich | Aufwand |
|
||
|---|---|---|
|
||
| Spielplan-Synchronisation (football-data.org → DB) | Entwicklung | 2 Tage |
|
||
| REST API vollständig implementieren | Entwicklung | 3 Tage |
|
||
| Tipp-Logik mit Deadline-Prüfung | Entwicklung | 1 Tag |
|
||
| Punkte-Berechnungslogik | Entwicklung | 1 Tag |
|
||
| Ranglisten-Abfrage (inkl. Materialized View) | Entwicklung | 1 Tag |
|
||
| Unit-Tests für Kernlogik | Entwicklung | 1 Tag |
|
||
|
||
**Meilenstein:** Vollständige Backend-API testbar via Postman/API-Client.
|
||
|
||
### Phase 3 — Frontend (Woche 5–7)
|
||
|
||
| Aufgabe | Verantwortlich | Aufwand |
|
||
|---|---|---|
|
||
| React-Projekt aufsetzen, Staffbase Client SDK integrieren | Entwicklung | 1 Tag |
|
||
| Spielplan-Übersicht (nach Datum / Gruppe filtern) | Entwicklung | 2 Tage |
|
||
| Tipp-Eingabeformular mit Validierung | Entwicklung | 2 Tage |
|
||
| Rangliste mit Pagination | Entwicklung | 1,5 Tage |
|
||
| Admin-Bereich (Ergebnis eintragen, Statistiken) | Entwicklung | 2 Tage |
|
||
| Responsive Design (Mobile-first für Staffbase App) | Entwicklung | 1,5 Tage |
|
||
| Mehrsprachigkeit DE/EN | Entwicklung | 1 Tag |
|
||
|
||
**Meilenstein:** Vollständige App funktionsfähig im Browser (ohne Staffbase-Integration).
|
||
|
||
### Phase 4 — Staffbase-Integration & Test (Woche 8–9)
|
||
|
||
| Aufgabe | Verantwortlich | Aufwand |
|
||
|---|---|---|
|
||
| Plugin-URL in Staffbase Studio hinterlegen | Admin | 0,5 Tage |
|
||
| iFrame-Test in Staffbase Web und Mobile App | Entwicklung | 1 Tag |
|
||
| End-to-End-Tests mit echten Staffbase-Nutzern | Entwicklung + QA | 2 Tage |
|
||
| Bugfixing aus Testphase | Entwicklung | 2 Tage |
|
||
| Performance-Test (Last: viele gleichzeitige Tipps) | Entwicklung | 1 Tag |
|
||
| DSGVO-Check: keine unautorisierten Daten gespeichert | PM/Legal | 1 Tag |
|
||
|
||
**Meilenstein:** Plugin läuft stabil in der Staffbase-Staging-Umgebung.
|
||
|
||
### Phase 5 — Launch & Betrieb (Woche 10 + laufend)
|
||
|
||
| Aufgabe | Verantwortlich | Aufwand |
|
||
|---|---|---|
|
||
| Go-Live in Staffbase Produktivumgebung | Admin + Entwicklung | 1 Tag |
|
||
| Kommunikation an Mitarbeitende (via Staffbase News Channel) | Kommunikation | 0,5 Tage |
|
||
| Monitoring & Alerting einrichten (Uptime, Fehler-Logs) | Entwicklung | 1 Tag |
|
||
| WM-Start-Phase begleiten (Hotfixes, Support) | Entwicklung | laufend |
|
||
| Tägliche Ergebnispflege (manuell oder automatisch) | Admin | laufend |
|
||
|
||
---
|
||
|
||
## 7. Ressourcen & Rollen
|
||
|
||
| Rolle | Verantwortlichkeiten | Zeitaufwand |
|
||
|---|---|---|
|
||
| **Projektleiter/PM** | Steuerung, Stakeholder-Kommunikation, Abnahme | ~20% (verteilt) |
|
||
| **Fullstack-Entwickler (1–2)** | Backend, Frontend, Deployment, Tests | 100% über 8 Wochen |
|
||
| **Staffbase-Admin** | Plugin-Registrierung, Studio-Konfiguration, Rollout | ~5% |
|
||
| **Kommunikation** | Launch-Kommunikation, Mitarbeitende informieren | ~5% |
|
||
| **QA (optional)** | Testen, Bugmeldungen | ~20% in Phase 4 |
|
||
|
||
---
|
||
|
||
## 8. Infrastruktur & Kosten
|
||
|
||
### 8.1 Hosting (monatlich, geschätzt)
|
||
|
||
| Dienst | Zweck | Kosten/Monat |
|
||
|---|---|---|
|
||
| **Railway / Render** | Backend-Hosting (Node.js) | ~5–15 € |
|
||
| **Supabase** | PostgreSQL (Free Tier reicht für ~500 User) | 0 € (Free) / 25 € (Pro) |
|
||
| **football-data.org** | WM-Spielplan API | 0 € (Free Tier) |
|
||
| **GitHub** | Code-Repository + CI/CD | 0 € (Free) |
|
||
| **Gesamt** | | ~5–40 € / Monat |
|
||
|
||
### 8.2 Einmalige Kosten (Entwicklung)
|
||
|
||
Gemäß separater Aufwandsschätzung (siehe Projektphasen). Bei internem Entwicklerteam: reine Zeitkosten. Bei externer Vergabe: ca. 15.000–25.000 € (je nach Erfahrungsniveau und Scope).
|
||
|
||
---
|
||
|
||
## 9. Risiken & Maßnahmen
|
||
|
||
| Risiko | Wahrscheinlichkeit | Auswirkung | Maßnahme |
|
||
|---|---|---|---|
|
||
| Staffbase JWT-Integration schlägt fehl | Niedrig | Hoch | Frühzeitig in Phase 1 testen, Staffbase Support einbinden |
|
||
| football-data.org API unzuverlässig | Mittel | Mittel | Spielplandaten lokal cachen, manuelle Eingabe als Fallback |
|
||
| Zu viele gleichzeitige Nutzer (WM-Start) | Mittel | Mittel | Load-Test vor Go-Live, Auto-Scaling auf Hosting-Plattform |
|
||
| DSGVO: unbeabsichtigte Datenspeicherung | Niedrig | Hoch | Nur JWT-Daten speichern, kein Tracking, Datenschutzprüfung |
|
||
| Entwicklungsrückstand (Urlaube, Krankheit) | Mittel | Mittel | Puffer von 1 Woche eingeplant, MVP-Scope reduzierbar |
|
||
| WM-Spielplan ändert sich (Absagen, Verlegungen) | Niedrig | Niedrig | Automatische API-Synchronisation |
|
||
|
||
---
|
||
|
||
## 10. Definition of Done (DoD)
|
||
|
||
Ein Feature gilt als fertig, wenn:
|
||
|
||
1. Funktionalität implementiert und manuell getestet
|
||
2. Unit-Tests vorhanden (Backend-Logik)
|
||
3. Responsive auf Mobile und Desktop
|
||
4. In Staffbase-iFrame getestet (Web + App)
|
||
5. Kein Fehler in den Browser-Konsolen-Logs
|
||
6. Code reviewed und in `main`-Branch gemergt
|
||
|
||
Das Gesamtprojekt gilt als abgenommen, wenn:
|
||
|
||
1. Alle MVP-Features (F1–F6) funktionsfähig sind
|
||
2. Mind. 20 Test-Nutzer einen Tipp abgegeben haben (Pilottest)
|
||
3. Performance-Test bestanden (< 2 Sekunden Ladezeit)
|
||
4. DSGVO-Prüfung abgeschlossen und dokumentiert
|
||
5. Go-Live in Produktivumgebung erfolgt
|
||
|
||
---
|
||
|
||
## 11. Nächste Schritte (Sofortmaßnahmen)
|
||
|
||
1. **Plugin bei Staffbase registrieren** → Staffbase Studio → Einstellungen → Plugins → neues Plugin anlegen → Plugin-ID und Public Key notieren
|
||
2. **Entwicklungsumgebung aufsetzen** → `npx create-staffbase-plugin-nodejs@latest wm2026-tippspiel`
|
||
3. **football-data.org API-Key beantragen** → https://www.football-data.org/client/register
|
||
4. **Supabase-Projekt anlegen** → https://supabase.com (EU-Region Frankfurt)
|
||
5. **Kickoff-Meeting** mit allen Beteiligten (PM, Entwicklung, Staffbase-Admin, Kommunikation)
|
||
|
||
---
|
||
|
||
## Anhang A: Nützliche Links & Ressourcen
|
||
|
||
| Ressource | URL |
|
||
|---|---|
|
||
| Staffbase Developer Portal | https://developers.staffbase.com |
|
||
| Staffbase Custom Plugin Übersicht | https://developers.staffbase.com/concepts/customplugin-overview/ |
|
||
| Staffbase Plugins Client SDK | https://github.com/Staffbase/plugins-client-sdk |
|
||
| Staffbase Node.js SDK | https://github.com/Staffbase/plugins-sdk-nodejs |
|
||
| Staffbase Plugin Skeleton Generator | https://github.com/Staffbase/create-staffbase-plugin-nodejs |
|
||
| football-data.org API | https://www.football-data.org |
|
||
| Supabase | https://supabase.com |
|
||
| Railway Hosting | https://railway.app |
|
||
| Render Hosting | https://render.com |
|
||
| WM 2026 Spielplan (FIFA) | https://www.fifa.com/worldcup |
|