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

91 lines
6.2 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:** 9.3 (error pages, shared toast system, loading states) — TICKED in STATUS.md
- **Next step:** Phase 9 — 9.4 (Mobile-responsive pass per UI_GUIDE)
- **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` | **175 passing, 0 failing** (85 unit + 90 integration) |
| `npm run seed:dev` | creates demo user "demo"/"demo123", hero "Aldric" (warrior), starter gear |
## 3. What exists now (files that matter)
- `public/404.html` — Custom 404 error page (branding: "Page Not Found", Emberfall theme).
- `public/500.html` — Custom 500 error page (branding: "Something went wrong", retry button).
- `public/js/toast.js` — Shared toast notification system (window.showToast, 3 types: error/info/success).
- `public/game.html` — Dashboard with stats panel, tabbed action panel (Hunt/Inventory/Expedition).
- `public/js/game.js` — hunt UI + inventory UI + expedition UI (uses shared toast.js).
- `public/shop.html` — Dedicated shop page.
- `public/js/shop.js` — buy/sell handlers (uses shared toast.js).
- `public/login.html`, `public/register.html`, `public/create-hero.html` — Auth & hero creation (all include toast.js).
- `public/profile.html` — Public hero profile page.
- `public/js/profile.js` — Fetches GET /api/heroes/:name, renders profile.
- `public/js/auth.js` — Shared API wrapper + showError.
- `public/css/main.css` — All styles including spinner, toast, button loading states, error page shared CSS.
- `scripts/seed-dev.js` — Creates demo account + hero + starter gear (idempotent, skips in production).
- `src/app.js` — Express app with helmet, rate limiters, catch-all 404, 500 HTML serving.
- `src/services/*` — All game services (auth, character, hunt, inventory, shop, expedition, leaderboard, profile).
- `src/routes/*` — All route handlers.
- `src/game/*` — Pure game logic (combat, stats, energy, leveling, rewards).
- `tests/integration/error-pages.test.js` — 3 tests for 404/500 page serving.
- `tests/integration/*.test.js` — 90 integration tests across auth, combat, hunt, inventory, shop, expeditions, profile, leaderboard, error-pages.
- `tests/unit/*.test.js` — 85 unit tests for game logic.
## 4. Half-finished / fragile things
- No leaderboard UI yet (Phase 8 API done but no UI).
- 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).
- Starter gear (GAME_DESIGN.md §Items) documented but not auto-created on character creation.
- `GET /api/zones` documented in API.md but not implemented (Issue #2).
## 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.
- **D-010:** `startExpedition` checks active-expedition before energy.
- **D-011:** `computeEnergy` uses `now()` from utils/time.
- **D-012:** General `/api` rate limiter at 120 req/min per IP (SECURITY.md spec), 1000 in test mode.
- **D-013:** All `innerHTML` with dynamic data removed from game.js and profile.js — use createElement/textContent.
## 6. Gotchas learned
- `npm test` must be `node --test` with NO path/glob; files must be named `*.test.js`.
- better-sqlite3-session-store ignores `expired.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.
- `setNow` affects ALL `now()` calls including those in service logic.
- Shop API returns `{ ok: true, data: { stock: [...], character: {...} } }` — field is `stock`, not `stocks`.
- Shop stock items have flat fields (`itemId`, `buyPrice`), not nested (`item.id`).
- New characters have NO inventory items (starter gear not auto-created yet).
- Hero profile endpoint is PUBLIC — no `requireAuth` middleware.
- Profile page is public: no auth.js guard needed; uses ?name= query param for lookup.
- Rate limiters in tests: set `NODE_ENV=test` to get 1000 req/window limit; otherwise tests fail with 429.
- `seed-dev.js` must check `NODE_ENV=production` before any `require()` that loads config (config throws on placeholder SECRET).
- Express `sendFile` rejects `../` path segments — use `path.resolve()` + `path.join()` for absolute paths.
- `express.static` sends its own 404 responses; catch-all must be placed BEFORE static middleware.
## 7. Next-step briefing (9.4)
- **Goal:** Mobile-responsive pass per UI_GUIDE (< 700px: single column, tabs become bottom nav).
- **Docs:** UI_GUIDE §game.html layout (Mobile section).
- Current CSS has some `@media (max-width: 600px)` rules but needs comprehensive mobile review.
- Should: verify all pages render correctly on mobile viewports.
- Should: tabs → bottom nav on mobile (per UI_GUIDE).
- Should NOT introduce new dependencies — use vanilla HTML/CSS/JS.