Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
ca115c6
feat(v2): bootstrap modern Fastify rewrite with game resource API
Feb 22, 2026
1477fae
refactor(v2): migrate rewrite bootstrap to TypeScript
Feb 22, 2026
4778b67
refactor(v1): remove highscore routes and clean legacy route wiring
Feb 22, 2026
1d8d8ad
feat(v2): redesign clean game API and add timed chess clocks
Feb 22, 2026
9a535ea
refactor: replace legacy API with clean TypeScript chess API and time…
Feb 22, 2026
4303e85
feat(api): remove /v2 prefix and use chess-ai-kong for engine moves
Feb 22, 2026
c7fea2f
feat(engine): use Stockfish for ai-move with kong fallback
Feb 22, 2026
c0d1b78
feat(prod): add Postgres+Drizzle, Google auth, API keys, and persiste…
Feb 22, 2026
17d5ea8
refactor(architecture): rewrite API to NestJS modular structure
Feb 22, 2026
20fce80
feat(api): add DTO validation classes and chess engine tests
Feb 22, 2026
6a12f03
test(modules): add auth/users/chess/health module tests and keep DTO …
Feb 22, 2026
3481540
feat(web): add Next.js landing page with shadcn-style UI components
Feb 22, 2026
ab70d5e
chore(web): remove build artifacts and ignore .next outputs
Feb 22, 2026
cc57819
feat(web): add docs, login, and dashboard pages to landing app
Feb 22, 2026
5b501a6
feat(web): redesign landing page with modern SaaS hero and premium st…
Feb 22, 2026
d1a5485
feat(web-docs): redesign docs page for API-key routes only
Feb 22, 2026
e86d9c2
feat(web): wire login/docs/dashboard to live API flow for SaaS frontend
Feb 22, 2026
a410f57
feat(web-copy): rewrite landing copy with chess-first SaaS positioning
Feb 22, 2026
c0d63a8
feat(saas): add plan model, /me/plan endpoint, and free-tier API key …
Feb 22, 2026
a25cf76
docs(plan): add execution plan for production SaaS chess API
Feb 22, 2026
f9a3ab5
chore(prod): add env validation, CI workflow, and local postgres compose
Feb 22, 2026
61d3257
feat(billing): add Stripe customer bootstrap service
Feb 22, 2026
1d1f83d
feat(billing): add authenticated Stripe checkout session endpoint
Feb 22, 2026
c99665c
feat(billing): add Stripe billing portal session endpoint
Feb 22, 2026
6427b87
chore(git): stop tracking dist artifacts and ignore build outputs
Feb 22, 2026
678f763
feat(billing): handle Stripe subscription webhooks
Feb 22, 2026
a7a35f8
feat(entitlements): enforce per-plan RPM and monthly quotas for API keys
Feb 22, 2026
db19e2d
feat(api): add centralized exception filter and error shape
Feb 22, 2026
a2d8a1f
feat(api): add request logging middleware with request id
Feb 22, 2026
b66b25a
feat(chess): add paginated GET /games with mode/status filters
Feb 22, 2026
5fa742c
test(api): verify API key rate limiting is isolated per key
Feb 22, 2026
43eb66b
feat(api): add profile-scoped GET /games/players endpoint
Feb 22, 2026
99ded42
feat(chess-data): add players and game_players models with player ass…
Feb 22, 2026
b6fed5c
fix(chess): enforce ownership on all game state mutations
Feb 22, 2026
8e7de8c
docs: add 60-second API key quickstart flow
Feb 22, 2026
b0e7332
feat(chess): add owned player update/delete APIs and SDK snippets in …
Feb 22, 2026
6900d5f
docs: add plan limits and billing upgrade path
Feb 22, 2026
6c4fd7f
docs: add API error code catalog
Feb 22, 2026
ae7c388
chore(env): expand runtime env validation and add config tests
Feb 22, 2026
32e4b56
ci: split API and web build workflows with dependency caching
Feb 22, 2026
63f7728
chore(deploy): add Vercel config for web app
Feb 22, 2026
8332968
ops(staging): add end-to-end staging verification script
Feb 22, 2026
910c66a
chore(qa): document staging credentials and extend verify script
Feb 22, 2026
492dc46
chore(qa): add optional billing checks to staging verification
Feb 23, 2026
e634804
chore(qa): add checklist runner for staging signoff
Feb 23, 2026
50ff4ac
test(api): cover request-id propagation in logging middleware
Feb 23, 2026
1bbe058
ops(qa): add staging QA checklist runner script
Feb 23, 2026
b2f3fa7
test(api): cover validation-array error formatting
Feb 23, 2026
66cfe11
test(config): expand env validation coverage
Feb 23, 2026
87bac95
ops(qa): expand checklist script with docs-smoke and free-tier limit …
Feb 23, 2026
bb1d45c
test(billing): ignore unrelated Stripe webhook events
Feb 23, 2026
6c1184d
test(billing): cover signed webhook parsing path
Feb 23, 2026
d5b0b9d
ops(staging): allow verify script auth via ACCESS_TOKEN fallback
Feb 23, 2026
29411bd
test(api): verify request-id generation fallback
Feb 23, 2026
2852ef6
docs: dedupe staging QA helper examples
Feb 23, 2026
2d51fd3
ops(qa): add clock-timeout and optional checkout checks to staging QA…
Feb 23, 2026
2fac1eb
test(billing): cover missing-signature webhook fallback
Feb 23, 2026
6e5e93f
test(chess): cover missing-player assignment rejection
Feb 23, 2026
5668fb9
ops(staging): add webhook transition verification helper script
Feb 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
DATABASE_URL=postgres://user:pass@host:5432/chess
GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PRICE_PRO=price_...
APP_URL=http://localhost:3000
PORT=3000
46 changes: 46 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: ci

on:
push:
pull_request:

jobs:
api-build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json

- name: Install API deps
run: npm ci

- name: Build API
run: npm run build

- name: Test API
run: npm test

web-build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: web
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: web/package-lock.json

- name: Install web deps
run: npm ci

- name: Build web
run: npm run build
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules
.env
dist
*.log
75 changes: 75 additions & 0 deletions PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# CHESS API SAAS PLAN (Execution Checklist)

## Goal
Ship a production-ready SaaS chess API where users can sign in, create API keys, and build apps without their own backend.

## Current State (done)
- [x] NestJS modular rewrite (auth/users/chess/database/health)
- [x] Postgres + Drizzle schemas
- [x] Google auth endpoint
- [x] API key create/list/revoke
- [x] Core chess routes (create/get/delete/moves/ai/resign)
- [x] Timed games support
- [x] DTO coverage + module tests + engine tests
- [x] SaaS landing/docs/login/dashboard scaffolding + wiring
- [x] Basic plan model + free-tier API key limits

## Remaining (must finish)

### 1) Billing + Entitlements (Stripe)
- [x] Stripe customer creation on first paid action
- [x] Checkout session endpoint
- [x] Billing portal endpoint
- [x] Webhook handler (subscription created/updated/canceled)
- [x] Persist plan tier/status in `plans`
- [x] Enforce plan limits:
- [x] free: low RPM + low monthly requests + key cap
- [x] pro: higher quotas

### 2) Production API hardening
- [x] Centralized exception filter + error shape
- [x] Request logging middleware with requestId
- [x] API key rate limit per key (not only global)
- [x] Pagination DTOs + list endpoints:
- [x] `GET /games` with filters/status/mode
- [x] `GET /players` (or profile-scoped player listing)
- [x] Ownership checks on all mutable resources

### 3) Data model completion
- [x] `players` table (profile for app users)
- [x] `game_players` table (white/black participants)
- [x] Optional metadata fields for external app IDs

### 4) Docs + Developer onboarding
- [x] “Get key in 60 seconds” flow docs
- [x] Copy-paste SDK-style snippets (JS/TS + curl)
- [x] Plan limits docs + upgrade path
- [x] Error code catalog

### 5) Ops + deployment
- [x] docker-compose for local Postgres + app
- [x] env validation at boot
- [x] CI workflow (build + test)
- [x] Vercel deployment files/config
- [x] staging verification script

### 6) QA checklist (before STG signoff)
Blocked pending staging credentials/env:
- `API_BASE_URL`
- one of: `GOOGLE_ID_TOKEN` or `ACCESS_TOKEN`
- `STRIPE_TEST_PRICE_ID` (optional for billing endpoint verification; or configured `STRIPE_PRICE_PRO` on staging)
- `STRIPE_WEBHOOK_SECRET` + `STRIPE_CUSTOMER_ID` + `USER_ID` (for webhook transition script)

- [ ] Google login works
- [ ] API key lifecycle works
- [ ] Game flow works (create->move->ai->resign)
- [ ] Clock timeout works
- [ ] Free-tier limits enforced
- [ ] Upgrade to pro updates limits
- [ ] Stripe webhook updates entitlements (ready to verify via `scripts/staging-webhook-verify.sh`)
- [ ] Docs examples execute successfully

## Work Rules
- Keep scope strictly to SaaS chess API.
- No extra features unless directly required for reliability, billing, or developer onboarding.
- Commit in small, verifiable increments.
1 change: 0 additions & 1 deletion Procfile

This file was deleted.

193 changes: 183 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,188 @@
# ♟️ Chess API ♟️
API for playing chess and highscores storing. Api could be easily used to implement a multiplayer room based chess game, because every instance of a game initilizes new unique game_id.
* ### [API Documentation](https://documenter.getpostman.com/view/1741165/chess-api/7Lof2bk#intro)
# chess-api (NestJS rewrite)

## Feautures:
Proper modular architecture with NestJS:

* Player vs. Player game mode
* Player vs. Computer game mode
* Highscores data storing
- `AuthModule` (Google login + sessions)
- `UsersModule` (API key management)
- `ChessModule` (game lifecycle, clocks, PvP/PvE)
- `DatabaseModule` (Postgres + Drizzle)
- `HealthModule` (root/docs)

## Tech
- NestJS
- PostgreSQL
- Drizzle ORM
- Google OAuth ID token verification
- chess.js + chess-ai-kong

## Built With
## Env
```env
DATABASE_URL=postgres://...
GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PRICE_PRO=price_...
APP_URL=http://localhost:3000
PORT=3000
```

* [Chess.js](https://github.com/jhlywa/chess.js)
* [ChessCorp Artificial Intelligence: Kong](https://www.npmjs.com/package/chess-ai-kong)
## Run API
```bash
npm install
npm run dev
```

## Staging verification script
```bash
API_BASE_URL=https://stg-api.example.com \
GOOGLE_ID_TOKEN=<google_id_token> \
bash scripts/staging-verify.sh
```

## QA checklist runner (staging)
```bash
API_BASE_URL=https://stg-api.example.com \
GOOGLE_ID_TOKEN=<google_id_token> \
bash scripts/qa-checklist.sh
```
(Or provide `ACCESS_TOKEN` directly to skip login bootstrap.)

## Stripe webhook transition verifier (staging)
Use this after you have a real staged user + Stripe customer id.

```bash
API_BASE_URL=https://stg-api.example.com \
STRIPE_WEBHOOK_SECRET=whsec_xxx \
STRIPE_CUSTOMER_ID=cus_xxx \
USER_ID=<app_user_id> \
bash scripts/staging-webhook-verify.sh
```

Optional billing checks:
```bash
API_BASE_URL=https://stg-api.example.com \
GOOGLE_ID_TOKEN=<google_id_token> \
STRIPE_TEST_PRICE_ID=price_xxx \
bash scripts/qa-checklist.sh
```

## Landing page + docs + login + dashboard (shadcn-style UI)
A separate Next.js app lives in `web/` and is wired to the API.

```bash
cd web
cp .env.example .env.local
npm install
npm run dev
```

### Vercel deploy (web)
`web/vercel.json` is included for Vercel deployment.

Required Vercel project env vars:
- `NEXT_PUBLIC_API_BASE_URL`
- `NEXT_PUBLIC_GOOGLE_CLIENT_ID`

Suggested project root in Vercel: `web/`

## Auth routes
- `POST /auth/google` with `{ idToken }`
- `GET /me` (Bearer session token)
- `GET /me/api-keys`
- `POST /me/api-keys`
- `DELETE /me/api-keys/:id`

## Chess routes (require `x-api-key`)
- `GET /games`
- `GET /games/players`
- `POST /games/players`
- `POST /games/:id/players`
- `POST /games`
- `GET /games/:id`
- `DELETE /games/:id`
- `GET /games/:id/moves`
- `POST /games/:id/moves`
- `POST /games/:id/ai-move`
- `POST /games/:id/resign`

## Get key in 60 seconds
1. **Sign in** via `POST /auth/google` with your Google ID token.
2. **Save bearer token** from `accessToken` in response.
3. **Create API key** via `POST /me/api-keys` using bearer auth.
4. **Call chess API** with `x-api-key: <returned apiKey>`.

Quick example:
```bash
# 1) Google login
curl -s -X POST http://localhost:3000/auth/google \
-H "content-type: application/json" \
-d '{"idToken":"<google-id-token>"}'

# 2) Create API key (replace $ACCESS_TOKEN)
curl -s -X POST http://localhost:3000/me/api-keys \
-H "authorization: Bearer $ACCESS_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"quickstart"}'

# 3) Create a game (replace $API_KEY)
curl -s -X POST http://localhost:3000/games \
-H "x-api-key: $API_KEY" \
-H "content-type: application/json" \
-d '{"mode":"pve","aiColor":"b"}'
```

## Plan limits + upgrade path

### Free
- API keys: **2 active keys**
- Rate limit: **30 requests/minute** per API key
- Monthly quota: **10,000 requests** per account

### Pro
- API keys: **20 active keys**
- Rate limit: **300 requests/minute** per API key
- Monthly quota: **1,000,000 requests** per account

### Upgrade
1. Create checkout session: `POST /billing/checkout-session`
2. Redirect user to returned Stripe URL
3. Stripe webhook updates plan to `pro` when subscription is active
4. User can manage billing via `POST /billing/portal-session`

Minimal checkout call:
```bash
curl -s -X POST http://localhost:3000/billing/checkout-session \
-H "authorization: Bearer $ACCESS_TOKEN" \
-H "content-type: application/json" \
-d '{}'
```

## Error code catalog
All API errors use a consistent shape:

```json
{
"error": {
"statusCode": 400,
"code": "Bad Request",
"message": "Human-readable message"
},
"path": "/games",
"timestamp": "2026-02-22T22:00:00.000Z"
}
```

Common errors:
- `401 Unauthorized`
- Missing/invalid bearer session (`/me`, `/billing/*`)
- Missing/invalid `x-api-key` (`/games*`)
- `404 Not Found`
- Game or player not found / not owned by caller
- `429 Too Many Requests`
- API key RPM exceeded for current plan
- Monthly request quota exceeded for current plan
- `400 Bad Request`
- Validation failures (DTO constraints)
- Missing billing config (e.g. Stripe price)
- `500 Internal Server Error`
- Unhandled server-side failure
Loading