AlgoChess is the chess platform for developers and CS students. It doesn't just tell you what mistake you made — it tells you what algorithmic failure caused it: greedy local optimization, minimax blindness, premature search pruning, or positional neglect. Think of it as LeetCode feedback, but applied to chess.
The system runs a real-time Stockfish evaluation engine in the browser, a 5-stage sequential AI pipeline for post-game debrief running server-side in a Supabase Edge Function, a retrieval-augmented generation (RAG) historian that maps your play to historical grandmaster games, and a full multiplayer suite built on Supabase Realtime.
| Production URL | https://nfac-chess.vercel.app |
| Repository | https://github.com/n6s8/nfac-chess |
| Hosting | Vercel (static, auto-deploy on push to main) |
| Database | Supabase PostgreSQL — live, connected, RLS enabled |
| Backend API | Supabase Edge Functions (Secure AI proxy, Stripe Webhooks) |
| Auth | Supabase Auth — email/password, session-based |
| Monetization | Stripe Checkout & Webhooks (Test Mode) |
| AI Inference | Groq API — llama-3.1-8b-instant, live |
| Chess Engine | Stockfish 16 WASM — runs in browser Web Worker, no server |
All external services (Vercel, Supabase, Groq, Stripe) are configured and connected in production. The architecture assumes live Supabase, Groq, and Vercel — see Setup to run with your own keys. The multiplayer rooms, ELO updates, game history, virtual economy, and AI debriefs all write to and read from the live Supabase database. Server-side secrets are securely managed in Supabase Edge Functions.
CS students and early-career developers (18–28) who play chess casually and are preparing for technical interviews or studying algorithms.
The only chess platform that explains moves in algorithmic terms — turning each game into a CS lesson.
| Metric | Target |
|---|---|
| D1 retention | > 35% |
| Games per session | > 2 |
| Master Council debrief open rate | > 60% |
| Free → Pro conversion | > 4% |
Pro tier ($4.99/mo): unlimited Master Council debriefs, custom board themes, priority Stockfish depth (depth 24 vs 16).
| Area | Description |
|---|---|
| Single-player vs Engine | Play against Stockfish at 4 difficulty levels (Beginner 800 ELO → Master 3200 ELO). Each move is classified in real time using a heuristic algorithm. |
| Post-game Analysis | Full Stockfish re-analysis of every move. Blunders and mistakes are explained through CS theory by a Groq LLM. |
| Master Council Debrief | A 5-stage sequential pipeline runs server-side: Engine Analyst → CS Professor → Historian (RAG) → Emotional Coach → Synthesizer. Produces a short, honest text debrief. |
| Multiplayer | Real-time rooms via Supabase Realtime. Clock with increment, draw negotiations, in-game chat, and ELO updates persist to PostgreSQL. |
| Friend Challenges | Share a room link with a friend — they join directly. Friend request system with username search. Accepted friends can be challenged from the Friends page. |
| Rating System | ELO-style rating adjustments after every game, shown as a delta chip on the board after the result. |
| Profile and History | Full game history with move-by-move replay support. Country/city-based leaderboard. |
| Economy & Store | Server-side coin economy (earn coins by playing). Purchase board themes via atomic DB transactions. 6 themes available. |
| Monetization (Pro) | Fully integrated Stripe Checkout to upgrade to Pro, unlocking the Master Council debrief and exclusive themes. |
| Daily CS Puzzle | A new chess puzzle every day framed as a CS problem (Greedy vs Minimax vs Pruning Error). Streak tracking persisted to the database. |
| Sound Effects | Procedural Web Audio API sounds for moves, captures, check, win, loss, and draw — no external assets. |
flowchart TD
subgraph Browser["Browser (React 18 + Vite)"]
UI["Game UI\n(React Components)"]
Hook_SP["useGame.ts\n(single-player state machine)"]
Hook_MP["useGameRoom.ts\n(multiplayer state machine)"]
ChessJS["chess.js\n(move validation, FEN/PGN)"]
Board["react-chessboard\n(SVG rendering)"]
subgraph Worker["Web Worker"]
SF["Stockfish 16 (WASM)\nUCI protocol"]
end
subgraph Analysis["Post-game Analysis"]
AP["analyzeGame()\nStockfish per-move scoring"]
LLM1["Groq LLM\nCS-framed explanations\n(via Edge Function proxy)"]
end
end
subgraph Supabase["Supabase (Backend)"]
Auth["Auth\n(email/password)"]
DB["PostgreSQL\n(profiles, games, game_rooms)"]
RT["Realtime\n(WebSocket per room)"]
RPC["Stored Procedures\n(economy, ELO, transactions)"]
subgraph EdgeFns["Edge Functions"]
Council["Master Council\n5-stage AI pipeline\n(Groq, server-side)"]
StripeCheckout["stripe-checkout\nCreates Checkout session"]
StripeWebhook["stripe-webhook\nHandles payment events"]
end
end
UI --> Hook_SP
UI --> Hook_MP
Hook_SP --> ChessJS
Hook_MP --> ChessJS
ChessJS --> Board
Hook_SP -- "evaluate(fen, depth)" --> SF
Hook_MP -- "evaluate(fen, depth)" --> SF
SF -- "bestmove + score" --> Hook_SP
SF -- "bestmove + score" --> Hook_MP
Hook_SP --> AP
Hook_MP --> AP
AP --> SF
AP --> LLM1
LLM1 --> Council
Hook_SP -- "read/write" --> DB
Hook_MP -- "read/write" --> DB
Hook_MP -- "subscribe" --> RT
RT -- "postgres_changes" --> Hook_MP
DB --> RPC
UI --> Auth
After a game ends, analyzeGame() iterates over every move and evaluates each resulting position with Stockfish. Then enrichAnalysisWithExplanations() sends the flagged mistakes to Groq (via the Edge Function proxy) for CS-framed explanations.
flowchart LR
Moves["moves[]"]
Loop["For each move:\nReconstruct board with chess.js"]
SF2["Stockfish.evaluate\nfen, depth=16"]
Delta["Compute evaluationDiff\n(centipawns)"]
Flag{"Flag move"}
Blunder["Blunder\ndiff <= -150cp"]
Mistake["Mistake\ndiff <= -50cp"]
Good["Inaccuracy / Good\nno flag"]
Enrich["enrichAnalysisWithExplanations\nbatch Groq calls (Edge Function)"]
LLM2["Groq LLM\nllama-3.1-8b-instant\nClassify as Greedy / Minimax /\nPruning / Positional"]
Profile["ThinkingStyle Profile\ngreedy% minimax% tradeoff% positional%"]
Moves --> Loop --> SF2 --> Delta --> Flag
Flag --> Blunder
Flag --> Mistake
Flag --> Good
Blunder --> Enrich
Mistake --> Enrich
Enrich --> LLM2 --> Profile
The debrief pipeline follows a 5-stage sequential design (Engine Analyst → CS Professor → Historian → Emotional Coach → Synthesizer), implemented as a manual async chain of groqChat() calls in the ai-debrief Supabase Edge Function. No LangGraph SDK is used — the pipeline is a hand-written sequential async function. Each stage reads the accumulated state, adds its own report, and passes the enriched context to the next stage.
flowchart TD
START(["START\nmoves[] + analysis[]"])
subgraph A["Node 1: engineAnalyst"]
A1["Count blunders, mistakes, inaccuracies\nfrom analysis[]"]
A2["Produce factual engine report\n(no LLM, deterministic)"]
A1 --> A2
end
subgraph B["Node 2: csProfessor"]
B1{"Are there\nblunders or mistakes?"}
B2["Call Groq LLM\nClassify root cause:\nGreedy / Minimax Failure / Pruning Error"]
B3["Return static:\n'Sound algorithmic execution'"]
B1 -->|yes| B2
B1 -->|no| B3
end
subgraph C["Node 3: historianRag (RAG)"]
C1["Retrieve from knowledge base\n4 canonical grandmaster games\ntied to CS failure types"]
C2["Call Groq LLM\nMap csReport to best matching game\nExplain the parallel in 2 sentences"]
C1 --> C2
end
subgraph D["Node 4: emotionalCoach"]
D1{"Errors\nexist?"}
D2["Call Groq LLM\nDiagnose cognitive pattern\n(tunnel vision, time pressure, etc.)"]
D3["Return static:\n'Consistent and composed'"]
D1 -->|yes| D2
D1 -->|no| D3
end
subgraph E["Node 5: synthesizer"]
E1["Call Groq LLM\nCombine all 4 reports\ninto 3 plain paragraphs"]
E2["Output finalDebrief\nNo emojis / No headers / Direct prose"]
E1 --> E2
end
END_(["END\nfinalDebrief string"])
START --> A --> B --> C --> D --> E --> END_
The RAG in this system is prompt-based retrieval, not vector search. The knowledge base is a fixed set of 4 annotated games injected directly into the Groq prompt. The LLM performs the semantic matching.
flowchart LR
subgraph KB["Knowledge Base (in-memory)"]
G1["Kasparov vs Deep Blue 1997\nPruning Error"]
G2["Spassky vs Fischer 1972\nMinimax Failure"]
G3["Tal vs Botvinnik 1960\nGreedy Algorithm"]
G4["Carlsen vs Caruana 2018\nOptimal Execution"]
end
csReport["csReport\n(CS failure classification)"]
Prompt["Construct prompt:\ncsReport + full knowledge base"]
Groq["Groq LLM\nSelect most relevant game\nExplain parallel in 2 sentences"]
Out["historicalGame\n(2 sentence comparison)"]
csReport --> Prompt
KB --> Prompt
Prompt --> Groq --> Out
The knowledge base is injected wholesale. The LLM acts as the retriever and ranker. For production scale (hundreds of games), replace with pgvector semantic search and an embedding model.
Stockfish runs in a Web Worker and speaks UCI. Evaluations are serialized — only one evaluation runs at a time.
sequenceDiagram
participant Hook as useGame / useGameRoom
participant Engine as StockfishEngine
participant Worker as Web Worker (Stockfish WASM)
Hook->>Engine: evaluate(fen, depth, skill?, elo?)
Engine->>Worker: postMessage("stop")
Worker-->>Engine: (search halts)
Engine->>Worker: postMessage("isready")
Worker-->>Engine: postMessage("readyok")
Engine->>Worker: postMessage("position fen <fen>")
Engine->>Worker: postMessage("setoption Skill Level <n>")
Engine->>Worker: postMessage("go depth <n>")
Worker-->>Engine: postMessage("info depth ... score cp ...")
Worker-->>Engine: postMessage("bestmove <uci>")
Engine-->>Hook: resolve({ score, bestMove })
stateDiagram-v2
[*] --> waiting: Room created\nlast_move_at = null\nclock frozen
waiting --> lobby: Second player joins\nboth profiles visible
lobby --> playing: White makes first move\nlast_move_at set\nclock starts
lobby --> abandoned: 5s grace period expires\nno move made
playing --> playing: Each move\ndeducts elapsed from active clock\nupdates last_move_at
playing --> finished: Checkmate / Resign / Draw / Time flag
finished --> [*]
abandoned --> [*]
erDiagram
PROFILES {
uuid id PK
text email
text username
text country
text city
int rating
int games_won
int games_lost
int games_drawn
int coins
text[] owned_themes
bool is_pro
text stripe_customer_id
text stripe_subscription_id
int daily_puzzle_streak
date last_puzzle_date
}
GAME_ROOMS {
uuid id PK
uuid created_by FK
uuid white_player_id FK
uuid black_player_id FK
text fen
text pgn
jsonb moves
text status
text turn
text result
text time_control
bigint white_time_ms
bigint black_time_ms
timestamptz last_move_at
jsonb chat_messages
}
GAMES {
uuid id PK
uuid user_id FK
uuid room_id FK
text mode
text pgn
jsonb moves
text result
jsonb analysis
uuid winner_id FK
uuid loser_id FK
}
FRIENDSHIPS {
uuid id PK
uuid requester_id FK
uuid addressee_id FK
text status
}
FRIEND_CHALLENGES {
uuid id PK
uuid from_user_id FK
uuid to_user_id FK
uuid room_id FK
text status
}
PROFILES ||--o{ GAME_ROOMS : "creates / plays"
PROFILES ||--o{ GAMES : "plays"
GAME_ROOMS ||--o| GAMES : "produces"
PROFILES ||--o{ FRIENDSHIPS : "has"
PROFILES ||--o{ FRIEND_CHALLENGES : "sends / receives"
FRIEND_CHALLENGES }o--|| GAME_ROOMS : "links to"
| Layer | Technology |
|---|---|
| Frontend | React 18, TypeScript, Vite |
| Styling | Tailwind CSS v3, custom CSS variables for theming |
| Chess Engine | Stockfish 16 (WASM) via Web Worker, UCI protocol |
| Chess Logic | chess.js (move validation, FEN, PGN) |
| Board UI | react-chessboard |
| Sound | Web Audio API (procedural tones, no external files) |
| Database | Supabase (PostgreSQL, Row Level Security, Realtime) |
| Auth | Supabase Auth (email/password) |
| AI Inference | Groq API, llama-3.1-8b-instant |
| AI Pipeline | 5-stage sequential async pipeline (Edge Function, Groq) |
| Payments | Stripe Checkout + Webhooks (Edge Functions) |
| Routing | React Router v6 |
- Node.js 18+
- A Supabase project (free tier is sufficient)
- A Groq API key (added as a Supabase Secret for the Edge Function)
1. Install dependencies
npm install2. Copy the engine binary into the public directory
npm run setup:stockfishThis copies Stockfish WASM files from node_modules/stockfish into public/ so the Web Worker can load them at runtime.
3. Configure environment variables
cp .env.example .env.localEdit .env.local:
VITE_SUPABASE_URL=https://<your-project>.supabase.co
VITE_SUPABASE_ANON_KEY=<your-anon-key>
# Stripe public keys
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_...
VITE_STRIPE_PRICE_ID=price_...
Note on Security: Sensitive keys (STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, and GROQ_API_KEY) are stored in Supabase Secrets and are only accessed by Edge Functions. They are never exposed to the browser bundle.
4. Apply the database schema
Open the Supabase SQL editor and run the contents of supabase/schema.sql in full. This creates all tables, indices, RLS policies, triggers, and stored procedures.
If you are updating an existing deployment, the schema uses create table if not exists and alter table ... add column if not exists throughout. It is safe to re-run.
5. Deploy Edge Functions
supabase functions deploy ai-debrief
supabase functions deploy stripe-checkout
supabase functions deploy stripe-webhook
supabase secrets set GROQ_API_KEY=gsk_...
supabase secrets set STRIPE_SECRET_KEY=sk_test_...
supabase secrets set STRIPE_WEBHOOK_SECRET=whsec_...6. Start the development server
npm run devThe app runs on http://localhost:5173 by default.
| Variable | Required | Description |
|---|---|---|
VITE_SUPABASE_URL |
Yes | Supabase project URL |
VITE_SUPABASE_ANON_KEY |
Yes | Supabase anon public key |
VITE_STRIPE_PUBLISHABLE_KEY |
Yes | Stripe Publishable Key |
VITE_STRIPE_PRICE_ID |
Yes | Stripe Price ID for Pro |
src/
├── components/
│ ├── AnalysisPanel.tsx Post-game analysis UI, worst moves, master council trigger
│ ├── AuthModal.tsx Login/signup flow with username uniqueness check
│ ├── ChessBoard.tsx Board rendering, move interaction, resign/draw controls, sounds
│ ├── CreateRoomModal.tsx Room creation with time control selection
│ ├── MasterCouncilPanel.tsx 5-stage AI debrief UI — calls the ai-debrief Edge Function
│ ├── MoveHistory.tsx Scrollable move list with analysis overlay
│ ├── PreferenceToolbar.tsx Board theme, engine level (with ELO descriptions), focus mode
│ ├── ProModal.tsx Stripe Checkout upgrade UI with feature list
│ └── ThinkingStylePanel.tsx Greedy/minimax/tradeoff/positional breakdown chart
├── hooks/
│ ├── useAuthSession.ts Auth state, profile refresh on session change
│ ├── useChessSound.ts Procedural Web Audio API sounds (move, capture, check, win/loss)
│ ├── useGame.ts Single-player state machine, Stockfish loop, rating updates
│ ├── useGameRoom.ts Multiplayer state, clock, draw negotiations, Realtime sync
│ └── useThemePreferences.ts Dark/light mode + board theme persistence via localStorage
├── lib/
│ ├── agents.ts Architectural reference for the 5-stage pipeline structure
│ ├── ai.ts Move analysis orchestration, Edge Function proxy calls
│ ├── chess.ts chess.js wrappers (makeMove, getFen, getGameResult, etc.)
│ ├── stockfish.ts StockfishEngine class, UCI protocol, Web Worker bridge
│ ├── stripe.ts Stripe Checkout session creation via Edge Function
│ ├── supabase.ts All database operations, auth, friends, shop, challenges
│ └── time-controls.ts Time control configs (bullet, blitz, rapid, classical)
├── pages/
│ ├── DailyPuzzle.tsx Daily CS puzzle with streak tracking (persisted to DB)
│ ├── Friends.tsx Friend search, requests, challenge flow
│ ├── Game.tsx Single-player layout, player cards, eval bar
│ ├── Leaderboard.tsx Country/city-filtered rating leaderboard
│ ├── MultiplayerRoom.tsx Multiplayer layout, lobby, countdown, clock bars, chat
│ ├── NotFound.tsx 404 page with chess-themed message
│ ├── Profile.tsx User profile, game history, friends tab, challenges
│ ├── Replay.tsx Move-by-move game replay from history
│ └── Shop.tsx Board theme store with server-side coin economy
└── types/
└── index.ts All shared TypeScript interfaces and type aliases
supabase/
├── schema.sql Full DDL: tables, RLS policies, triggers, stored procedures
└── functions/
├── ai-debrief/ 5-stage AI pipeline + single-move explanations (Groq)
├── stripe-checkout/ Creates Stripe Checkout session server-side
└── stripe-webhook/ Handles checkout.session.completed → sets is_pro in DB
RAG knowledge base: The historian agent uses a fixed 4-game knowledge base injected into the prompt. It is not a semantic vector search. Results are plausible but not verifiably accurate. Extending this to a real retrieval system would require a vector store and an embedding model.
Clock authority: Time enforcement runs on the room creator's browser. If the creator disconnects mid-game, the clock stops. A production implementation would move this to a server-side cron or Edge Function.
ELO simplification: The current rating system applies fixed deltas (+15 win, -15 loss, 0 draw for single-player; +16/-16/+4 for multiplayer via stored procedure). It does not account for opponent strength. Replace with a proper ELO formula if ranking fidelity is a requirement.
AI pipeline: The Master Council pipeline is implemented as a sequential async chain of Groq API calls, not a graph framework. The design mirrors a 5-node DAG but does not use LangGraph or LangChain at runtime.