Files
vngeoguessr/scripts
tiennm99 4770de51d4 feat(leaderboard): roll a guess up through the region tree
A guess is credited to the district its panorama sits in, then to that
district's province, then to Vietnam. Each level keeps its own board, so a
player can top District 7 without touching the national table.

Every existing point survives untouched. The country maps to the
leaderboard:vietnam and distance:vietnam keys that already exist rather than
to a new leaderboard:city:vn, so the national board keeps accumulating instead
of restarting. The ':city:' segment in the key namespace is now a misnomer --
it holds district and province codes alike -- but renaming it to ':region:'
would strand every key holding a player's history, so it stays, with a comment
recording why. Da Lat and Duc Hoa keep their bare codes for the same reason.
Ha Noi, Da Nang and Ho Chi Minh keep their totals on the province: those
points predate districts and cannot be attributed to one, so their boards stay
continuous while district boards start at zero.

Levels are written in parallel. They are independent keys and none reads
another's state, so serialising them would add two round trips of latency to
every guess for nothing.

Region codes and the leaderboard limit are validated inside the library rather
than only in the routes. The key builder lowercases whatever it is handed
straight into a Redis key, and the routes are not its only callers -- the
migration script and anything added later bypass them entirely.

The adapter gains scanKeys, which the migration needs to enumerate what it is
about to touch. It applies the key prefix to the pattern and strips it from
the results, because a caller that scanned 'leaderboard:*' directly would
match nothing at all: every physical key carries the prefix, and an empty
result is indistinguishable from an empty database. An empty KEY_PREFIX is no
longer accepted, since enumeration with no prefix would reach every other
project sharing the database.

The migration seeds Lam Dong and Long An from Da Lat and Duc Hoa, whose
history they inherit. It runs after the deploy, not before: migrating first
leaves a window where a Da Lat guess credits the town and the country but not
the province. It copies absolute scores so a second run converges rather than
doubling, and empties the destination first so a player trimmed out of the
source cannot survive in the copy with a stale score. An empty source is
refused before that delete -- otherwise the destination is wiped and nothing
written back, which reads as a clean no-op. Afterwards it confirms each
destination matches its source and that nothing else went backwards, accepting
that boards grow while the app serves traffic. Its backup can be restored
through the same script.

The migration logic lives in scripts/lib/ so its guards are reachable from a
test rather than only by running it against a live database.
2026-08-30 17:45:37 +07:00
..