5.6 KiB
5.6 KiB
HANDOFF.md — Session Handoff (OVERWRITE at the end of every phase or when context is getting long)
Read order for a new session:
NOTES.md→STATUS.md→ this file → then work. If this file disagrees with the code, trust the code and fix this file.
1. Where we are
- Last completed step: 7.3 (Expedition UI: start panel, progress bar, claim button) — TICKED in STATUS.md
- Next step: 8.1 — Leaderboard:
GET /api/leaderboard?type=level|gold|killstop 50, with pagination param. - Updated: 2026-10-21
- Was the last session cut off mid-task? No
2. Verified state (run these first)
| Command | Expected |
|---|---|
npm install |
succeeds |
npm run migrate |
applies 001–006 / "nothing to do" |
npm test |
153 passing, 0 failing (85 unit + 68 integration) |
3. What exists now (files that matter)
src/db/migrations/005_expeditions.sql—expedition_defs+expeditionstables, unique active-expedition index, 3 seed definitions.src/services/expeditionService.js—startExpedition,getActive,claimExpedition,listDefinitions. Uses WeakMap stmt cache.src/routes/expeditions.js—POST /api/expeditions/start,GET /api/expeditions/active,POST /api/expeditions/claim,GET /api/expeditions/defs.src/game/energy.js—computeEnergynow usesnow()from utils/time.src/services/characterService.js—createCharacter,getCharacterProfile,getCharacterIdForUser.src/services/huntService.js—hunt(characterId, zoneId, {rng, now}); ONE transaction; test-injectable.src/services/inventoryService.js—listInventory,equipItem,unequipItem,useConsumable. Uses WeakMap stmt cache.src/services/shopService.js—getStock,buyItem,sellItem. Uses WeakMap stmt cache.src/game/combat.js—resolveCombat(hero, monster, rng); both sides attack each round, faster first.src/game/stats.js—calcDerived()is the ONLY derived-stat formula. Also re-exports xpToNext/checkLevelUp.src/utils/time.js—now()/setNow()/resetNow(); never callDate.now()in services.src/routes/zones.js—GET /api/zones.src/routes/combatLog.js—GET /api/combat-log.public/game.html— dashboard with stats panel, tabbed action panel (Hunt/Inventory/Expedition).public/js/game.js— full hunt UI + inventory UI + expedition UI (start panel, progress bar, claim button, auto-refresh).public/css/main.css— expedition UI styles (cards, progress bar, buttons).public/shop.html— dedicated shop page with buy/sell tabs.tests/integration/expeditions.test.js— 13 integration tests.tests/integration/shop.test.js— 16 integration tests.tests/integration/shop-page.test.js— 5 integration tests.tests/integration/inventory.test.js— 20 integration tests.
4. Half-finished / fragile things
- No leaderboard UI yet (Phase 8).
- HP never regenerates naturally; only level-up restores it.
- No restart-persistence test for sessions.
npm run seedscript in package.json points to nonexistentscripts/seed.js.- Equipment bonuses not yet passed into combat (Issue #5 in STATUS.md).
- No shop link in game.html top-bar navigation.
5. Decisions & deviations from the docs
- D-004..D-007 in
docs/DECISIONS.md(combat rounds, equipment counted once, session store, clock). - Zod query param parsing uses
zod.coerce.number()because Express query params are strings. - Inventory response uses
itemId(item.id) andinventoryId(inventory row id) to avoid confusion. - Consumable effect parsing: regex
^(heal|energy):(\d+)$on items.effect field. - Qty decrement avoids CHECK constraint violation: delete directly when qty==1, decrement when qty>1.
- D-008: Shop materials with buy_price=0 sell at
floor(default_rate * character_level / item_min_level). - D-009:
sellItemchecks equipped_slot before material type. - D-010:
startExpeditionchecks active-expedition before energy (so 409 ACTIVE_EXPEDITION takes priority over 422 INSUFFICIENT_ENERGY). - D-011:
computeEnergyusesnow()from utils/time instead ofDate.now()directly, so test time overrides work.
6. Gotchas learned
npm testmust benode --testwith NO path/glob; files must be named*.test.js.- better-sqlite3-session-store ignores
clear:false; that's why the timer is unref'd. - Statement caches are per-DB-handle (WeakMap) in huntService; copy that pattern for new services.
- Verify test COUNT, not just "all passing".
- Node.js
fetchdoesn't persist cookies across calls — extractSet-Cookieheader and pass manually in integration tests. - SQL
SELECT idfrom inventory returns the auto-increment row id; rename withAS inventory_idwhen you also needitem_id. - Transaction callback args must match the call order exactly.
- Error responses from route-level
AppErrors do NOT includedatafield. setNowaffects ALLnow()calls including those in service logic — for tests that need to verify time-based behavior, manipulate the DB directly instead.
7. Next-step briefing (8.1)
- Goal: Leaderboard endpoint —
GET /api/leaderboard?type=level|gold|killstop 50, with?page=Npagination. - Docs: GAME_DESIGN.md §Leaderboards, DATABASE.
- Files to create:
src/services/leaderboardService.js,src/routes/leaderboard.js. - Files to modify:
src/app.js(register route). - API:
GET /api/leaderboard?type=level|gold|kills&page=1— returns ranked list of heroes (name, level/gold/kills) with pagination metadata.
8. Open Known Issues
STATUS.md issues 1–6 (balance, dangling seed script, restart test, equipment-in-combat, HP regen, zone min_level balance).