Files
vngeoguessr/docs/development.md
T
tiennm99 c2c1ced387 test: cover the lib layer against a fake and a real Redis
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.
2026-08-30 09:26:02 +07:00

4.3 KiB

Development Guidelines

Development Commands

  • npm run dev - Start development server with Turbopack
  • npm run build - Build the application for production
  • npm start - Start production server
  • npm run lint - Run ESLint
  • npm test - Run the test suite against the in-memory Redis fake
  • npm run test:watch - Re-run tests on change
  • npm run test:integration - Run the same suite against a local Redis
  • npm 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 of function({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 test uses tests/fake-upstash-redis.js, an in-memory stand-in mocked in at the @upstash/redis boundary. No service, no Docker, well under a second. This is the default.
  • npm run test:integration runs 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