mirror of
https://github.com/tiennm99/vngeoguessr.git
synced 2026-10-18 12:14:40 +00:00
feat(game): serve panorama index from Neon Postgres
- panoramas + pano_provinces tables replace 28MB bundled JSON; pano-index.js now draws via cached COUNT + ORDER BY id OFFSET with rejection sampling, composite (province,id)/(district,id) indexes support the skip - scripts/seed-pano-db.mjs validates pipeline artifacts (the old real-data vitest invariants, extracted to scripts/lib/pano-artifacts.mjs), stages into panoramas_next, verifies, renames into place in one transaction, keeps panoramas_old as backup; --province reseeds in place; --check validates only - pipeline writes gitignored data-build/panos/; pano barrel removed - tests run against PGlite mocked in at the @neondatabase/serverless boundary, mirroring the fake-upstash pattern; fixtures replace real data - infrastructure errors rethrow instead of reading as missing coverage; session ids via crypto.randomUUID (uuid package dropped)
This commit is contained in:
1 parent
da7a715478
commit
6569f095c9
45 files changed
+1510
-425270
No files matched your search
+21
-9
@@ -1,7 +1,7 @@
|
||||
# Tech Stack
|
||||
|
||||
## Frontend Framework
|
||||
- **Next.js 15.5**: React-based full-stack framework with App Router
|
||||
- **Next.js 16**: React-based full-stack framework with App Router
|
||||
- **React 19.2**: Component architecture
|
||||
- **Tailwind CSS 4**: Utility-first CSS framework for styling
|
||||
|
||||
@@ -23,16 +23,23 @@
|
||||
## Geographic Processing
|
||||
- **@turf/turf**: distance, point-in-polygon, union, simplify, and
|
||||
point-to-line distance -- used both at runtime and by the offline builds
|
||||
- **Generated region tree**: `src/data/regions/` holds the nodes,
|
||||
`src/data/boundaries/<province>/` the simplified outlines, and
|
||||
`src/data/panos/` the per-province panorama indexes
|
||||
- **Generated region tree**: `src/data/regions/` holds the nodes and
|
||||
`src/data/boundaries/<province>/` the simplified outlines. The per-province
|
||||
panorama indexes live in Postgres (see below), seeded from local pipeline
|
||||
artifacts in `data-build/panos/` (gitignored)
|
||||
- **Client/server split**: `src/lib/regions.js` is the client-safe view and
|
||||
imports nothing from `src/data/panos/` or `src/lib/pano-index.js`. That
|
||||
imports nothing from `src/lib/pano-index.js` or `src/lib/pano-db.js`. That
|
||||
boundary is enforced by an import-graph walk in `tests/regions.test.js` -- the
|
||||
indexes are ~29MB of exact answers
|
||||
panorama rows are exact answers
|
||||
- **Server-side Calculations**: All geographic processing on backend
|
||||
|
||||
## Data Storage & Session Management
|
||||
- **Neon Postgres (HTTP)**: The panorama index -- 424k rows of id, province,
|
||||
district, lat, lng -- read via `@neondatabase/serverless` (`DATABASE_URL` or
|
||||
`POSTGRES_URL`). One random-draw query per round, count queries cached
|
||||
per process. Seeded by `scripts/seed-pano-db.mjs`, which stages into
|
||||
`panoramas_next`, verifies, then renames into place, keeping the previous
|
||||
generation as `panoramas_old`
|
||||
- **Upstash Redis (REST)**: Session and leaderboard storage via `@upstash/redis` SDK (REST client, no sockets)
|
||||
- **Credential Flexibility**: Accepts `UPSTASH_REDIS_REST_URL`+`UPSTASH_REDIS_REST_TOKEN` (vanilla Upstash) or `KV_REST_API_URL`+`KV_REST_API_TOKEN` (Vercel Marketplace aliases)
|
||||
- **Multi-tenant Key Prefix**: All physical keys carry `KEY_PREFIX` (default `vngeoguessr:`) to safely share Upstash DB with other Vercel projects. Prefix applied centrally in `src/lib/upstash.js`; callers use logical keys only.
|
||||
@@ -41,7 +48,7 @@
|
||||
`city:{regionCode}` for every province and district -- the `city:` segment is
|
||||
kept so existing scores stay addressable
|
||||
- **Sorted Sets**: Leaderboard ranking with automatic trimming (top 200)
|
||||
- **UUID v4**: Session identifier generation
|
||||
- **UUID v4**: Session identifier generation via built-in `crypto.randomUUID()`
|
||||
- **30-minute Session Expiry**: Automatic TTL-based cleanup
|
||||
|
||||
## UI Components & Styling
|
||||
@@ -55,8 +62,14 @@
|
||||
## Testing
|
||||
- **Vitest**: Test runner for the logic in `src/lib/`, the API routes, the
|
||||
generated region data, and the leaderboard migration
|
||||
- **In-memory Upstash fake**: Default backing store, no service required
|
||||
- **In-memory Upstash fake**: Default Redis backing store, no service required
|
||||
- **PGlite**: In-process Postgres (WASM) mocked in at the
|
||||
`@neondatabase/serverless` boundary, so the panorama queries run against real
|
||||
Postgres semantics with no service
|
||||
- **SRH + Redis (Docker)**: Optional lane running the same tests against real Redis
|
||||
- **Playwright**: Chromium smoke tests for the UI (`tests/e2e/`), with every
|
||||
API call and the panorama image stubbed at the browser boundary -- no
|
||||
services, no env vars
|
||||
|
||||
## Development & Analytics
|
||||
- **ESLint**: Code linting with Next.js configuration
|
||||
@@ -65,7 +78,6 @@
|
||||
- **@vercel/speed-insights**: Performance monitoring
|
||||
|
||||
## Key Dependencies
|
||||
- **uuid**: unique session identifier generation
|
||||
- **@upstash/redis**: REST-based Upstash client; no socket pooling, works in edge compute and serverless
|
||||
- **JavaScript Only**: No TypeScript - pure JavaScript implementation
|
||||
- **Individual Parameters**: Functions use separate parameters instead of object destructuring
|
||||
|
||||
Reference in new issue
Block a user