Behind the Code
A technical deep dive into how GeoGuessr Thai League was built using Next.js 16, Supabase Realtime, and Tailwind CSS.
The Tech Stack
Next.js 16
App Router, Server Actions & SSR
Supabase
PostgreSQL & Realtime Subscriptions
React 19
Hooks, Suspense & Optimistic UI
Tailwind CSS
Utility-First Responsive Styling
Architecture & Decisions
Real-time Data Sync
ใช้ Supabase Realtime Channels เพื่อรับ PostgreSQL changes (`INSERT`, `UPDATE`) แบบ real-time โดยไม่ต้อง polling
.channel('realtime-matches')
.on('postgres_changes', { event: '*', table: 'matches' }, (payload) => updateState(payload))
.subscribe();URL-Driven State (Deep Linking)
Modals ถูกควบคุมผ่าน URL Search Params เช่น ?match=123 หรือ ?player=John ทำให้สามารถแชร์ลิงก์ตรงไปยัง Match/Player ได้ และปุ่ม Back ของ Browser ปิด Modal ได้
const openMatchDetails = (m) =>
router.push(`${pathname}?match=${m.id}`, { scroll: false });Client-side Optimization
การคำนวณ Stats ต่างๆ (Leaderboard, Player Radar, First Guess Rate) ใช้ useMemo Hooks เพื่อลด Re-render และเพิ่มความเร็ว UI
const stats = useMemo(() => calculatePlayerStats(playerName, matches), [matches, playerName]);
JSONB for Flexibility
ข้อมูล GeoGuessr API มีความซับซ้อน แทนที่จะสร้าง 10+ tables เราเก็บ Game Payload ทั้งหมดใน JSONB column (match_details) แล้วประมวลผลฝั่ง Client
matches table ├── id: uuid ├── status: 'finished' ├── score_p1, score_p2 └── match_details: [JSONB Array]
Features Implemented
Data Flow
Database Schema
📦 Supabase PostgreSQL
│
├── 👥 players
│ ├── id (uuid, PK)
│ ├── name (text)
│ ├── group_name ('A' | 'B')
│ ├── province (text)
│ ├── avatar_url (text)
│ ├── rating, global_rank
│ └── mode_preferences, best_country, worst_country, quote
│
├── ⚔️ matches
│ ├── id (uuid, PK)
│ ├── player1_name, player2_name
│ ├── score_p1, score_p2
│ ├── status ('scheduled' | 'finished')
│ ├── match_time (timestamp)
│ ├── round_label (text) // for playoffs
│ ├── youtube_link (text)
│ └── match_details (jsonb[]) // 3 games array
│
└── 📜 legacy_matches
├── id, player1, player2
└── result (สำหรับ Head-to-Head history)Developed with 💙 by PadPrikGaengGai
GeoGuessr Thai League • Season 2 • 2026