Scoring, the Upstash key adapter, sessions and the leaderboards had no coverage, and they carry the anti-cheat model: server-held coordinates, session TTLs, rank arithmetic. One suite runs against two backing stores. By default @upstash/redis is mocked with an in-memory fake, so `npm test` needs no service and finishes well under a second. With TEST_REDIS=real the mock steps aside and the same files run against a real Redis behind SRH, the proxy Upstash recommends for local work, since the SDK speaks HTTP REST rather than RESP and a plain Redis container cannot serve it alone. Running both is what keeps the fake honest: a semantic it gets wrong shows up as a green unit run and a red integration run. Two tests skip against real Redis, one asserting a response shape only an older SDK produces and one fast-forwarding half an hour to watch a session expire. The suite was checked by mutation rather than by passing alone. Breaking a score band, the key prefix and the session TTL each failed a test; reversing the global trim window did not, because only the city leaderboard was asserted, so that test now covers both scopes. The compose stack doubles as a local Redis for `npm run dev`, which had no credentials to reach one before. package.json also loses the eight unused runtime dependencies removed in the cleanup that follows; they cannot be split from the same file.
4.3 KiB
Development Guidelines
Development Commands
npm run dev- Start development server with Turbopacknpm run build- Build the application for productionnpm start- Start production servernpm run lint- Run ESLintnpm test- Run the test suite against the in-memory Redis fakenpm run test:watch- Re-run tests on changenpm run test:integration- Run the same suite against a local Redisnpm run redis:up/npm run redis:down- Start/stop that local Redis
Important Development Guidelines
JavaScript Only
- This project uses JavaScript exclusively
- Never create or suggest TypeScript files (.ts, .tsx)
- All components and utilities should be .js or .jsx files
Function Parameters
- All functions should use individual parameters instead of object destructuring
- Use
function(param1, param2)instead offunction({param1, param2}) - This applies to React components, utility functions, and API handlers
File Modification Policy
- Only modify source code files, documentation (/docs), and plans (/plans)
- Configuration changes (package.json, next.config.mjs, eslint.config.mjs, components.json, etc.) should be highlighted for manual processing
- Environment files and build settings require manual review
Security Best Practices
- Never expose or commit secret keys and sensitive information
- Server-side session management prevents client-side coordinate access (Redis TTL 30 min)
- All geographic calculations must be performed server-side
- Session cleanup after guess submission for security
Environment Variables
Redis (required):
- Either
UPSTASH_REDIS_REST_URL+UPSTASH_REDIS_REST_TOKEN(vanilla Upstash) - Or
KV_REST_API_URL+KV_REST_API_TOKEN(Vercel Marketplace) - Optional:
KEY_PREFIX(default:vngeoguessr:) for multi-tenant DB sharing
Mapillary (required):
MAPILLARY_ACCESS_TOKEN- Mapillary API token for image fetching
For local Redis without an Upstash account, see Running Upstash locally below.
Testing & Completion
Tests live in tests/ and cover the logic in src/lib/: scoring and distance,
the Upstash key adapter, game sessions, and the leaderboards. Run npm test
after changing anything under src/lib/.
The suite runs against two backing stores, from one set of test files:
npm testusestests/fake-upstash-redis.js, an in-memory stand-in mocked in at the@upstash/redisboundary. No service, no Docker, well under a second. This is the default.npm run test:integrationruns the same files against a real Redis. Two of them skip: one asserts a response shape only an older SDK produces, and one fast-forwards half an hour to watch a session expire.
Running both is what keeps the fake honest. A behaviour the fake gets wrong shows up as a green unit run and a red integration run.
Everything above src/lib/ (UI, panorama viewer, map interaction, Mapillary
calls) is still manual: inform the user when work is complete. Do NOT start
development servers - user handles testing manually.
Running Upstash locally
Upstash itself is cloud-only, but @upstash/redis speaks HTTP REST, so any
server exposing that REST surface is indistinguishable to the app.
docker-compose.yml runs the proxy Upstash's own docs recommend, SRH
(hiett/serverless-redis-http), in front of a real Redis:
npm run redis:up # redis + SRH on http://localhost:8079
npm run redis:down # stop and discard the data
npm run test:integration points at it automatically. To use it for npm run dev as well, set in .env:
UPSTASH_REDIS_REST_URL=http://localhost:8079
UPSTASH_REDIS_REST_TOKEN=vngeoguessr-local-token
SRH accepts commands only as a JSON array POSTed to /, which is what the SDK
sends; the path form Upstash also supports (GET /set/key/value) returns 404.
shadcn/ui Configuration
- Style: "new-york"
- Path aliases: Configured for
@/components,@/lib, etc. - Components: Use JavaScript (.js) not TypeScript
- CSS variables: Enabled for theming
- Components location:
src/components/ui/
Code Style Standards
- Follow existing code patterns in the codebase
- Use established libraries and utilities already present
- Maintain consistent naming conventions
- No comments unless explicitly requested
- Prefer editing existing files over creating new ones