Files
Emberfall/HANDOFF.md
T
2026-10-21 06:32:47 +11:00

81 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.1 (Migration `005_expeditions.sql` with seed data) — TICKED in STATUS.md
- **Next step:** 7.2 — `POST /api/expeditions/start`, `GET /api/expeditions/active`, `POST /api/expeditions/claim`. Only one active expedition per hero. Claim rejected before `ends_at`.
- **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` | **139 passing, 0 failing** (85 unit + 54 integration) |
## 3. What exists now (files that matter)
- `src/db/migrations/005_expeditions.sql` — NEW: `expedition_defs` + `expeditions` tables, unique active-expedition index, 3 seed definitions (Scout 10min, Raid 1h, Delve 4h).
- `src/game/stats.js` — `calcDerived()` is the ONLY derived-stat formula. Also re-exports xpToNext/checkLevelUp.
- `src/game/combat.js` — `resolveCombat(hero, monster, rng)`; both sides attack each round, faster first.
- `src/services/huntService.js` — `hunt(characterId, zoneId, {rng, now})`; ONE transaction; test-injectable.
- `src/services/zoneService.js` — `listZones(characterLevel)` → zones with `unlocked` flag.
- `src/services/combatLogService.js` — `getCombatLog(characterId, limit)` → recent fights.
- `src/services/characterService.js` — `createCharacter`, `getCharacterProfile`, `getCharacterIdForUser`.
- `src/services/inventoryService.js` — `listInventory`, `equipItem`, `unequipItem`, `useConsumable`. Uses WeakMap stmt cache.
- `src/services/shopService.js` — `getStock`, `buyItem`, `sellItem`. Uses WeakMap stmt cache. Sell value = 40% of buy_price.
- `src/routes/shop.js` — `GET /api/shop`, `POST /api/shop/buy`, `POST /api/shop/sell`.
- `src/routes/inventory.js` — `GET /api/inventory`, `POST /api/inventory/equip`, `POST /api/inventory/unequip`, `POST /api/inventory/use`.
- `src/utils/time.js` — `now()/setNow()/resetNow()`; never call `Date.now()` in services.
- `src/routes/zones.js` — `GET /api/zones`.
- `src/routes/combatLog.js` — `GET /api/combat-log`.
- `src/db/migrations/003_content.sql` — also SEEDS zones/monsters/items/loot (INSERT OR IGNORE).
- `src/db/migrations/004_inventory.sql` — inventory table, FK constraints, partial unique index for equipped slots.
- `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.
- `public/shop.html` — dedicated shop page with buy/sell tabs.
- `public/js/shop.js` — shop page JS.
- `public/game.html` — dashboard with stats panel, tabbed action panel (Hunt/Inventory).
- `public/js/game.js` — full hunt UI + inventory UI.
## 4. Half-finished / fragile things
- No shop link in game.html top-bar navigation.
- No expedition service/routes yet (step 7.2).
- No leaderboard UI yet (Phase 8).
- HP never regenerates naturally; only level-up restores it.
- No restart-persistence test for sessions.
- `npm run seed` script in package.json points to nonexistent `scripts/seed.js`.
- Equipment bonuses not yet passed into combat (Issue #5 in STATUS.md).
## 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) and `inventoryId` (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:** `sellItem` checks equipped_slot before material type.
- Expedition seed data: 3 definitions (Scout 10min/10energy/1min, Raid 1h/30energy/3min, Delve 4h/60energy/5min) with XP 30-300 and gold 5-150.
## 6. Gotchas learned
- `npm test` must be `node --test` with 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 `fetch` doesn't persist cookies across calls — extract `Set-Cookie` header and pass manually in integration tests.
- SQL `SELECT id` from inventory returns the auto-increment row id; rename with `AS inventory_id` when you also need `item_id`.
- Transaction callback args must match the call order exactly.
- Error responses from route-level `AppError`s do NOT include `data` field.
## 7. Next-step briefing (7.2)
- **Goal:** Expedition API: start, active, claim endpoints.
- **Docs:** GAME_DESIGN.md §Expeditions, DATABASE.md (005_expeditions.sql schema already created).
- **Files to create:** `src/services/expeditionService.js`, `src/routes/expeditions.js`.
- **Key logic:** `startExpedition(characterId, defId)` — checks no active expedition, checks energy, deducts energy, inserts row with started_at/ends_at. `getActive(characterId)` — returns unclaimed expedition. `claimExpedition(characterId, expeditionId)` — checks ends_at <= now, checks claimed_at IS NULL, sets claimed_at, grants XP+gold(+loot for 1h+). All in transactions.
## 8. Open Known Issues
STATUS.md issues 1–6 (balance, dangling `seed` script, restart test, equipment-in-combat, HP regen, zone min_level balance).