mirror of
https://github.com/LucasKalil-Programador/world-2026-hub.git
synced 2026-07-04 17:41:28 -03:00
13 KiB
13 KiB
Project Map — World Cup 2026 Hub
Navigation map of the codebase. Use this to find which file owns a concern before reading code.
Status 2026-06-12 (all 12 steps + real-data migration done): everything works with real World Cup 2026 data — all views, bracket interactions, simulation, responsive/a11y pass, favorites, time toggle, challenge, share link,
.icsexport. Remaining: keepresults.jsoncurrent, fillthirdPlaceAssignmentafter the group stage (~Jun 27), Lighthouse run + GitHub Pages deploy. Spec source of truth:world-cup-2026-hub-spec-en.md+complement-spec-worldcup2026-en.md(complement wins on conflict).
File tree
worldcup2026/
├── .agents/ ← Internal documentation for AI agents
│ ├── project-map.md This file
│ ├── project-memory.md Context, decisions, gotchas
│ ├── stats-screen-plan.md Plan for the post-tournament "final stats" screen
│ │ (NOT implemented — planning only, 2026-06-14)
│ └── TODO.md 12-step build checklist
│
├── .github/workflows/
│ └── deploy.yml CI: FTP deploy to Hostinger on push to master
│ (needs FTP_SERVER/USERNAME/PASSWORD secrets)
│ .gitignore OS/editor junk
│
├── index.html ★ SPA shell — header, nav tabs (Home, Matches,
│ Groups, Knockout, Stadiums, Stats), hero, dashboard,
│ modal container; loads app.js as ES module.
│ <head> has the PWA block (manifest link, theme-color,
│ favicons, apple-mobile-web-app-* meta)
│
├── manifest.json PWA web app manifest (name/short_name, standalone,
│ theme/background #081421, icons[]) — relative paths
│ (start_url ".", scope "./") for the subpath deploy
│ favicon.ico Root favicon (16+32, from the trophy logo)
│
├── assets/
│ ├── css/
│ │ ├── style.css ★ Palette variables, glassmorphism base, layout,
│ │ │ components — mobile-first
│ │ ├── bracket.css Bracket columns, connectors, highlight states
│ │ ├── stats.css Stats tab: hero "pulse", overview cards, goals-by-stage chart
│ │ └── animations.css Entry (fade-in, slide-up/left) + interaction
│ │ (hover-scale/glow, pulse, line-draw)
│ ├── js/
│ │ ├── app.js ★ Entry point: loadData() (Promise.all over data/),
│ │ │ tab routing + lastTab (active-tab scroll-into-view +
│ │ │ edge fades on the scrollable nav), formatMatchTime(), dashboard,
│ │ │ clock-driven hero (matchState/findFeaturedMatches +
│ │ │ 1s heroTick: hybrid JSON+clock, 2h/3h window; stacks
│ │ │ simultaneous group-final matches, one shared timer),
│ │ │ live data refresh (startResultsPolling: 90s poll of
│ │ │ results.json, no-store + ?t, content signature, pauses
│ │ │ when tab hidden, stops at FINAL; on change also refetches
│ │ │ bracket-config.json; fires `datachange`)
│ │ ├── schedule.js Match list, filters (incl. occurrence toggle
│ │ │ Played/Upcoming via hybrid matchState), search,
│ │ │ sort, "My Matches"; 60s clock-tick re-render
│ │ ├── groups.js Standings computation (3/1/0, GD, GF) + group tables
│ │ ├── stadiums.js Stadium cards + "view matches" cross-link
│ │ ├── bracket.js ★ Bracket tree resolution, resolveBracketTeams(),
│ │ │ simulation, challenge score, share prediction
│ │ ├── modal.js Match detail modal (ARIA dialog)
│ │ ├── storage.js localStorage wrapper — wc2026_* keys, auto-JSON
│ │ ├── i18n.js EN/PT-BR dicts + t(key), lang toggle
│ │ ├── stats.js ★ Stats tab: tournament-to-date aggregates (finished
│ │ │ matches only), hero pulse + overview + goals-by-stage.
│ │ │ PARTIAL (during-cup) — grows into the post-cup plan.
│ │ └── calendar.js .ics export (RFC 5545, CRLF, Blob download)
│ ├── images/ Team flag SVGs, stadium placeholders
│ └── icons/ PWA app icons (from the header trophy logo): icon.svg
│ (master + manifest SVG), icon-192/512.png (purpose any),
│ icon-maskable-192/512.png (safe-zone padded),
│ apple-touch-icon.png (180), favicon-16/32.png, favicon.ico
│
├── data/ All content — REAL WC2026 data since 2026-06-12
│ ├── teams.json 48 real qualifiers: { id, name, flag } (FIFA codes)
│ ├── groups.json Official draw { "A": [4 team ids], ... } × 12 (A–L)
│ ├── matches.json 104 real fixtures; UTC times; ids 1–72 chronological
│ │ group games, 73–104 = FIFA match numbers (bracketRef)
│ ├── results.json { matchId, homeScore, awayScore, penalties?, status } —
│ │ update as the tournament progresses
│ ├── stadiums.json 16 real venues: { id, name, city, capacity, image, timezone }
│ └── bracket-config.json ★ official R32 structure + thirdPlaceAssignment (all null) —
│ the ONLY file to edit once real 3rd places are known
│ (slot → allowed-groups table in project-memory.md)
│
├── README.md Setup, GitHub Pages deploy, JSON maintenance guide
├── how-update.md Real-data migration runbook (mock → real — DONE 2026-06-12)
├── how-refresh-data.md ★ Daily refresh runbook during the tournament:
│ results.json scores/status + one-time
│ thirdPlaceAssignment; everything else frozen
├── world-cup-2026-hub-spec-en.md Main spec
└── complement-spec-worldcup2026-en.md Complement spec (precedence on conflict)
★ = critical files. Most changes touch one of them.
Key flows
1. Data load → render
index.html (type="module")
└─ app.js: loadData() ── Promise.all ──> data/*.json
├─ hero + dashboard (app.js)
├─ schedule.js ──┐
├─ groups.js ├── render into tab panels
├─ bracket.js ──┘
└─ modal.js (on match click, from any view)
2. Bracket resolution
groups.json + results.json
└─ groups.js: standings (pts 3/1/0 → GD → GF)
└─ bracket.js: R32 from bracket-config.json
├─ type:"group" → standings[ref][pos-1]
├─ type:"third" → standings[thirdPlaceAssignment[slot]][2] (null → placeholder)
└─ R16…FINAL: sequential pairing of winners (0-1→0, 2-3→1, …)
└─ wc2026_simulation overlays user picks (never mutates JSON)
3. Time display
matches.json time (UTC) ── formatMatchTime(match, stadium, mode)
├─ mode "local" → Intl.DateTimeFormat() (browser tz)
└─ mode "stadium" → Intl.DateTimeFormat({ timeZone: stadium.timezone })
Conventions
Imports
- ES Modules only (
type="module"), relative paths, no bundler/CDN.
Naming
- Team ids: 3-letter uppercase (
MEX,BRA). Knockout match ids:R32-1…R32-16,R16-1…,QF-1…,SF-1/SF-2,THIRD-PLACE,FINAL. - localStorage keys prefixed
wc2026_, accessed only throughstorage.js.
Content / i18n
- All user-facing strings go through
i18n.jst(key)— never hardcode UI text in HTML/JS. - Data values (team names, stadium names, cities) come from JSON and are not translated.
Where is each thing?
| Question | Answer |
|---|---|
| Where do I update scores / match status? | data/results.json |
| Where do I set the 8 best third-place teams? | data/bracket-config.json → thirdPlaceAssignment |
| Where do I add/translate a UI label? | assets/js/i18n.js (both EN and PT dicts) |
| Where is the standings math? | assets/js/groups.js |
| Where are knockout teams resolved (placeholders, TBD)? | assets/js/bracket.js → resolveBracketTeams() |
| Where is simulation state stored/cleared? | localStorage key wc2026_simulation, via assets/js/storage.js |
| Where do I change colors/theme? | CSS variables at the top of assets/css/style.css |
| Where do I add a stadium? | data/stadiums.json + image in assets/images/ |
| Where do I change the app name / install icon / theme color? | manifest.json (name/short_name/theme) + assets/icons/ (regenerate PNGs from icon.svg) + PWA <meta> in index.html <head> |
| How do I replace mock data with real WC2026 data? | how-update.md (root) — done 2026-06-12; kept as schema reference |
| How do I update scores during the tournament? | how-refresh-data.md (root) — daily results.json routine + thirdPlaceAssignment how-to |
Main functions
(Planned signatures from the complement spec — confirmed/updated as each step is implemented.)
| Function | File | Parameters | Returns | Description |
|---|---|---|---|---|
loadData |
assets/js/app.js |
() |
Promise<AppData> |
Fetches all data/*.json in parallel, caches in memory |
formatMatchTime |
assets/js/app.js |
(match, stadium, mode) |
string |
UTC → display time; mode is "local" or "stadium" |
matchState |
assets/js/app.js |
(match, result, now) |
'over' | 'live' | 'upcoming' |
Hybrid JSON+clock state (finished/live win; else clock advances at kickoff/kickoff+window). Used by the hero and the schedule occurrence filter / "Awaiting result" chip |
get / set |
assets/js/storage.js |
(key, fallback) / (key, value) |
any / void |
localStorage wrapper, auto JSON parse/stringify |
t |
assets/js/i18n.js |
(key) |
string |
Translated UI string for current lang |
resolveBracketTeams |
assets/js/bracket.js |
(matchOrRef) |
{ home, away } of { team, label } |
Display slots for any match (group or knockout); reused by schedule/modal/filters |
getBracketTree |
assets/js/bracket.js |
() |
{ rounds, third, nodesByRef, champion } |
Cached resolved bracket tree |
invalidateBracket |
assets/js/bracket.js |
() |
void |
Drop the cached tree (simulation overlay, step 9) |
calculateChallengeScore |
assets/js/bracket.js |
(simulation, results, bracketTree) |
{ correct, total, byPhase } |
Compares user picks vs finished results |
getShareableLink |
assets/js/bracket.js |
() |
string |
Current URL + ?prediction=base64(simulation) |
loadPredictionFromURL |
assets/js/bracket.js |
() |
void |
Decodes, validates, confirms before overwriting local simulation |
toggleFavorite |
assets/js/storage.js |
(teamId) |
void |
Add/remove team in wc2026_favorites |
computeStandings |
assets/js/groups.js |
() |
{ [letter]: Row[] } |
Sorted standings per group, finished matches only |
isGroupFinished |
assets/js/groups.js |
(letter) |
boolean |
All 6 group matches have status finished |
navigateTo |
assets/js/app.js |
(tab) |
void |
Programmatic tab switch (cross-view links) |
setStadiumFilter |
assets/js/schedule.js |
(stadiumName) |
void |
Reset filters + show one stadium's matches |
getFavoriteMatches |
assets/js/bracket.js |
(matches, favorites) |
Match[] |
Matches involving favorited teams (resolved slots); used by schedule |
calculateChallengeScore |
assets/js/bracket.js |
(simulation, results, bracketTree) |
{ correct, total, byPhase } |
Picks vs real finished knockout results |
getShareableLink / loadPredictionFromURL |
assets/js/bracket.js |
() |
string / void |
base64 ?prediction= export/import with validation + confirm |
exportMatchToICS |
assets/js/calendar.js |
(match, stadium) |
void |
RFC 5545 VEVENT (UTC, 2h, CRLF, escaped TEXT), Blob download |