Files
Emberfall/STATUS.md
T
2026-10-21 01:10:23 +11:00

18 KiB
Raw Blame History

STATUS.md — Living Progress Tracker

Agent rules for this file

  • Update it at the end of EVERY step. Do not skip.
  • Only tick a box when the step's Acceptance line is actually verified.
  • Add problems you could not fix to Known Issues instead of hiding them.
  • Keep Session Log entries to one or two lines.

Current Focus

  • Phase: 7
  • Step: 7.1
  • Blocked? No
  • Last verified working command: npm test — 139/139 passing (85 unit + 54 integration), 2026-10-21 step 6.3

Project Health

Item State
App starts (npm start) ✅ smoke-tested: register → create hero → 12 hunts → level-up (real seeded zones)
Tests pass (npm test) ✅ 93/93 (runs EVERY *.test.js; auth/combat/health were previously skipped by a bad glob)
Migrations run clean on empty DB ✅ 001_users, 002_characters, 003_content (also seeds zones/monsters/items), 004_inventory, 006_logs (005 reserved for expeditions)
Can register + login ✅ verified by tests
Data persists across restart ⚠️ sessions use the real SQLite store (also in tests); a restart test is still missing
Inventory/equipment ✅ list, equip, unequip all working; derived stats update on equip/unequip; slot swap works

Phase 0 — Scaffold

  • 0.1 npm init, install deps from NOTES.md §2, add scripts: start, dev (node --watch), test, migrate, seed. Acceptance: npm install succeeds; scripts exist in package.json.
  • 0.2 src/config/index.js loads .env (use process.loadEnvFile or dotenv), validates required vars, exports a frozen config object. Acceptance: missing SESSION_SECRET in production throws a clear error.
  • 0.3 src/db/index.js opens SQLite (WAL mode, foreign_keys ON) and exports the handle. scripts/migrate.js runs numbered .sql files from src/db/migrations/ in order and records them in a _migrations table. Acceptance: npm run migrate twice in a row is safe (second run does nothing).
  • 0.4 src/app.js (builds Express app, no listen) + src/server.js (listens). Add helmet, JSON body parser (limit 10kb), static public/, GET /api/health → {ok:true}, central error handler (see CODING_STANDARDS). Acceptance: curl localhost:3000/api/health returns {"ok":true}.
  • 0.5 First test: health endpoint via node:test + fetch against app on an ephemeral port (see TESTING.md). Acceptance: npm test passes.

Phase 1 — Accounts & Sessions (docs: DATABASE, API, SECURITY)

  • 1.1 Migration 001_users.sql (users table).
  • 1.2 src/services/authService.js: register, verifyLogin. bcryptjs cost 10–12. Case-insensitive unique username.
  • 1.3 Session middleware (httpOnly, sameSite=lax, secure in production, SQLite-backed store) + requireAuth middleware.
  • 1.4 Routes: POST /api/auth/register, POST /api/auth/login, POST /api/auth/logout, GET /api/auth/me. Zod validation. Rate limit login/register.
  • 1.5 Pages public/login.html, public/register.html + public/js/auth.js.
  • 1.6 Tests: register ok, duplicate username, bad password, login ok/fail, me requires session, logout clears session. Acceptance (phase): can register, log in, refresh page and stay logged in, restart server and stay logged in, log out.

Phase 2 — Hero Creation & Profile (docs: GAME_DESIGN §Classes, DATABASE, BALANCE)

  • 2.1 Migration 002_characters.sql.
  • 2.2 src/game/classes.js (class base stats) + src/game/stats.js (derived stats). Unit tests.
  • 2.3 POST /api/character (create; one per user), GET /api/character (full profile incl. derived stats and current energy).
  • 2.4 public/create-hero.html, public/game.html (dashboard shell with stats panel). Acceptance: new user is redirected to create-hero; after creation, dashboard shows stats.

Phase 3 — Energy & Lazy Time (docs: GAME_DESIGN §Time, BALANCE)

  • 3.1 src/game/energy.js: pure computeEnergy(stored, updatedAtMs, nowMs, cfg) → {energy, updatedAtMs}. Unit tests incl. cap, partial intervals, clock going backwards.
  • 3.2 characterService.spendEnergy(characterId, cost) runs in a transaction; rejects when insufficient.
  • 3.3 Dashboard shows energy bar + "next +1 in mm:ss" countdown (client-side countdown only; server remains authoritative). Acceptance: set energy_updated_at back in DB by 30 min → refresh shows regen applied. Verified: energy bar + countdown in game.html/game.js; server returns nextTickInSec; 16 computeEnergy unit tests cover cap/partial/large-gap scenarios.

Phase 4 — Combat (Hunting) (docs: GAME_DESIGN §Combat, BALANCE)

  • 4.1 Content tables + seed data (zones, monsters, items, loot). Done inside migration 003_content.sql (INSERT OR IGNORE), not scripts/seed.js. Balance changes need a NEW migration.
  • 4.2 src/game/combat.js: pure resolveCombat(hero, monster, rng) → {winner, rounds[], hpRemaining}. Seedable RNG in src/utils/rng.js. Unit tests with fixed seed. Acceptance: 10 combat unit tests pass; deterministic with same seed; speed determines turn order; mage bonus vs high-def; 20-round cap.
  • 4.3 src/game/rewards.js: XP, gold, loot roll. src/game/leveling.js: XP curve, level-up, stat points. Acceptance: 23 unit tests pass; xpToNext matches BALANCE.md; level-up handles multi-level; points allocation validated.
  • 4.4 POST /api/hunt { zoneId }: spend energy → pick monster → resolve → apply rewards/penalty → write combat_log → return summary + round log. All inside one DB transaction. Acceptance: hunt returns winner, rounds, xpGained, goldGained, loot, leveledUp, zone, monster. Verified: 9 service tests (tests/integration/hunt-service.test.js) cover persistence, level-up, defeat, locked zone, energy, stacking.
  • 4.5 UI: zone list, "Hunt" button, combat log display, result summary, level-up message. Acceptance: hunting repeatedly drains energy, awards XP/gold, levels the hero, and persists. Verified: GET /api/zones + GET /api/combat-log endpoints; zone cards with locked/unlocked states; Hunt button with energy cost display; result panel showing victory/defeat, XP, gold, loot, level-up; combat log replay; energy re-sync after hunt. 98/98 tests pass (5 new integration tests).

Phase 5 — Inventory & Equipment (docs: GAME_DESIGN §Items, DATABASE)

  • 5.1 Migration 004_inventory.sql. Acceptance: migration creates inventory table with FK constraints and indexes.
  • 5.2 Services + routes: list inventory, equip, unequip (slots: weapon, armor, trinket). Equipment modifies derived stats via calcDerived(). Acceptance: list returns items with derived stats; equip moves previous item; unequip clears slot; wrong-type/level/missing-item rejected.
  • 5.3 Stackable consumables: POST /api/inventory/use (health potion heals; energy tonic restores energy, capped). Acceptance: heal effect caps at maxHp; energy effect caps at ENERGY_MAX; quantity decrements; row removed at qty 0; non-consumable rejected.
  • 5.4 UI: inventory grid, equipment panel, tooltips with stats. Acceptance: inventory grid, equipment panel, tooltips with stats. Verified: tab switching (Hunt/Inventory), equipment panel shows 3 slots with item names, rarity colors, stat bonuses, unequip button; inventory grid shows unequipped items with emoji icons, rarity badges, compact stats, quantity display, and hover tooltips showing full item details (name, type, stats/effect, level requirement).

Phase 6 — Shop & Economy (docs: GAME_DESIGN §Economy)

  • 6.1 GET /api/shop, POST /api/shop/buy, POST /api/shop/sell. Sell value = 40% of base price. Gold can never go negative. Acceptance: shop endpoints return stock, buy deducts gold, sell adds gold at 40%, gold never goes negative. Verified: 14 integration tests covering stock listing, level gating, buy/sell, gold math, error paths, round-trip spread.
  • 6.2 Level-gated shop stock. UI page. Acceptance: shop page loads with buy/sell tabs; stock filtered by character level; materials always visible for selling. Verified: shop.html + shop.js created; 5 integration tests covering stock listing, level gating, sell pricing, buy/sell round-trip.
  • 6.3 Tests: buy with insufficient gold (already covered), sell equipped item (must be rejected), concurrent double-buy safety (transaction). Acceptance: sell equipped item → 400 VALIDATION_ERROR; concurrent double-buy → exactly one succeeds with INSUFFICIENT_GOLD for the other; insufficient gold already covered. Verified: 2 new integration tests added to shop.test.js; sellItem check moved before material type check so equipped items are rejected regardless of type.

Phase 7 — Expeditions (Offline Progress) (docs: GAME_DESIGN §Time, §Expeditions)

  • 7.1 Migration 005_expeditions.sql. Expedition definitions in seed data.
  • 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.
  • 7.3 UI: start panel, progress bar, claim button. Acceptance: start → close browser → return after duration → claim → rewards granted exactly once.

Phase 8 — Leaderboards & Social-lite (docs: GAME_DESIGN §Leaderboards)

  • 8.1 GET /api/leaderboard?type=level|gold|kills top 50, with pagination param.
  • 8.2 Public profile GET /api/heroes/:name (no private data).
  • 8.3 UI page.

Phase 9 — Hardening & Polish (docs: SECURITY, UI_GUIDE, TESTING)

  • 9.1 Walk the SECURITY.md checklist; fix gaps.
  • 9.2 Add npm run seed:dev creating a demo account and hero.
  • 9.3 Global error pages / friendly UI error toasts. Loading states.
  • 9.4 Mobile-responsive pass (see UI_GUIDE).
  • 9.5 Final full run of "Definition of playable" from NOTES.md §7. Record results below.
  • 9.6 Update README with real run instructions.

Stretch Goals (only after Phase 9)

  • S1 Async PvP duels (attack another hero's snapshot; cooldown; rating).
  • S2 Skills / talent points spent on level-up.
  • S3 Guilds (create, join, leave, guild board).
  • S4 Player market (list/buy items between players, 5% tax gold sink).
  • S5 Daily login reward + daily quests.
  • S6 In-game chat via polling (no websockets).
  • S7 Achievements.

Known Issues

# Area Description Severity Status Found in step
1 Balance Level-1 heroes of every class win 100% of Meadows fights (design target ≈80%) and lose 100% of Crags fights. Tune monster stats via a NEW migration. minor open 4.4 review
2 API GET /api/zones (list zones + unlocked) is documented in API.md but not implemented; step 4.5 needs it. major open 4.4 review
3 Scripts npm run seed points at scripts/seed.js, which doesn't exist (seeds are in migration 003). Remove the script or add the file. cosmetic open 0.1
4 Tests No test proves sessions survive a server restart (two apps on one DB file). minor open 1.3
5 Combat Hero equipment bonuses are not passed into combat yet (Phase 5). resolveCombat already accepts bonus_* fields. minor open 5.x
6 Combat Natural HP regeneration is not implemented: HP only restores on level-up (rest/potions arrive in Phases 5–6). minor open 4.4
7 Combat/Hunt (Fixed in review) only the faster side attacked; mage bonus never applied; level-up kept XP and overwrote stat points; deaths never counted; zone min_level ignored; stackable loot duplicated rows; energy countdown showed time-to-full. blocker fixed review

Severity: blocker / major / minor / cosmetic. Status: open / fixing / wontfix / fixed.

Technical Debt / TODOs

  • wrap() async helper is copy-pasted in each route file; move to src/middleware/wrap.js.
  • Error responses from route-level AppErrors for validation don't include field details (API.md says they should).
  • npm test prints a lot of TAP noise; consider --test-reporter=spec.
  • src/db/seeds/ is empty (kept for later content seeds).

Open Questions (for the human)

  • none yet

Decisions Made (short; long form goes in docs/DECISIONS.md)

  • D-004: every combat round BOTH sides attack (faster first). D-005: equipment stats counted once in derived stats. D-006: unref the session-store cleanup timer; use the real SQLite store in tests. D-007: utils/time.js is the only clock.

Test Summary

Suite Passing Failing Last run
unit 85 0 2026-10-21 step 6.1
integration 54 0 2026-10-21 step 6.3

Session Log

Format: YYYY-MM-DD | step | what changed | result

  • 2026-10-21 | 6.3 | Added 2 integration tests to shop.test.js (sell equipped item rejection, concurrent double-buy safety); moved equipped check before material type check in sellItem so equipped items are rejected regardless of type | 139/139 tests pass
  • 2026-10-21 | 6.2 | Created shop UI: public/shop.html + public/js/shop.js (buy/sell tabs, level-gated stock display, material sell list, toast notifications); 5 integration tests for shop page API coverage | 137/137 tests pass
  • 2026-10-21 | 6.1 | Ticked step 6.1 — acceptance criteria verified: GET /api/shop, POST /api/shop/buy, POST /api/shop/sell all implemented with 40% sell value and gold-negative protection; 14 integration tests all passing | 132/132 tests pass
  • 2026-10-21 | 6.1 | Created src/services/shopService.js (getStock, buyItem, sellItem) + src/routes/shop.js (GET /api/shop, POST /api/shop/buy, POST /api/shop/sell); registered routes in app.js; 14 integration tests covering stock listing, level gating, buy/sell, gold math, error paths, round-trip spread | 132/132 tests pass
  • 2026-10-20 | 5.4 | Added inventory UI: tab switching (Hunt/Inventory), equipment panel (3 slots with item names, rarity colors, stat bonuses, unequip button), inventory grid (unequipped items with emoji icons, rarity badges, compact stats, quantity, hover tooltips with full details), click-to-equip/use handlers | 118/118 tests pass
  • 2026-10-20 | 5.3 | Added useConsumable() to inventoryService (heal/energy effects, qty decrement, row removal at 0) + POST /api/inventory/use route; 7 integration tests covering heal, energy, cap, non-consumable rejection, missing item, qty-0 removal | 118/118 tests pass
  • 2026-10-20 | 5.2 | Created src/services/inventoryService.js (listInventory, equipItem, unequipItem) + src/routes/inventory.js (GET /api/inventory, POST /api/inventory/equip, POST /api/inventory/unequip); registered routes in app.js; 13 integration tests covering empty inventory, equip/unequip, slot swap, stat updates, all error paths | 111/111 tests pass
  • 2026-10-20 | 5.1 | Verified 004_inventory.sql migration (inventory table, FK constraints, indexes) applies clean; all tests pass | 98/98 tests pass
  • 2026-10-20 | 4.5 | Added GET /api/zones (zoneService + zones route), GET /api/combat-log (combatLogService + combatLog route); extended game.html with zone list/combat log/result panels; rewrote game.js with hunt UI (zone cards, hunt button, result display, combat log replay, toast notifications); added CSS for zone cards/combat log/toasts; 5 new integration tests | 98/98 tests pass
  • 2026-10-20 | review | Fixed npm test (ran 62 of 79 tests; auth/combat/health were skipped by an unquoted glob). Rewrote combat (slower side never attacked; mage bonus dead; hpRemaining wrong on loss). Rewrote huntService (XP not deducted on level-up, unspent points overwritten, deaths never counted, min_level ignored, stackable loot duplicated, duplicate stat formulas). Fixed nextTickInSec (was time-to-full). Added utils/time.js, WeakMap stmt cache, session store unref, ok:false error envelope, removed connect-sqlite3 | 93/93 tests pass; smoke test OK
  • 2026-10-20 | 4.4 | Created 004_inventory.sql + 006_logs.sql migrations; fixed huntService transaction (db.transaction() returns wrapper, must call separately); added huntService to helpers.js cache invalidation; session middleware uses memory store in tests | 62/62 tests pass, hunt endpoint working
  • 2026-10-20 | 3.3 | Fixed game.js countdown: separated updateEnergyBar (pure display) from startCountdown (client-side timer), added energyData store and startEnergySync (60s server refetch) | 35/35 tests pass, energy bar + countdown working correctly
  • 2026-10-20 | 0.1 | npm init -y, installed express, better-sqlite3, bcryptjs, express-session, better-sqlite3-session-store, helmet, express-rate-limit, zod; added start/dev/test/migrate/seed scripts | verified all 5 scripts present in package.json
  • 2026-10-20 | 0.2 | Created src/config/index.js with process.loadEnvFile, required var validation, frozen export | verified config loads; production check rejects placeholder SECRET
  • 2026-10-20 | 0.3 | Created src/db/index.js (WAL, FK ON) + scripts/migrate.js (runs numbered .sql, tracks in _migrations) | npm run migrate twice is safe
  • 2026-10-20 | 0.4 | Created src/utils/errors.js, src/app.js (helmet, JSON parser, static, health, error handler) + src/server.js | curl localhost:3000/api/health → {"ok":true}
  • 2026-10-20 | 0.5 | Created tests/health.test.js — boots app on ephemeral port, hits /api/health | npm test passes (1/1)
  • 2026-10-20 | 1.1 | Created src/db/migrations/001_users.sql | migration applies clean
  • 2026-10-20 | 1.2 | Created src/services/authService.js: register + verifyLogin with bcrypt cost 12, timing-safe | service loads
  • 2026-10-20 | 1.3 | Created src/middleware/session.js: better-sqlite3-session-store, requireAuth | middleware loads
  • 2026-10-20 | 1.4 | Created src/routes/auth.js with Zod validation, rate limiting; integrated into app.js | app loads
  • 2026-10-20 | 1.5 | Created public/login.html, public/register.html, public/css/main.css, public/js/auth.js, login.js, register.js | static files served
  • 2026-10-20 | 1.6 | Created tests/helpers.js + tests/auth.test.js (6 tests) | 6/6 auth tests pass
  • 2026-10-20 | 2.1 | Created src/db/migrations/002_characters.sql | migration applies clean
  • 2026-10-20 | 2.2 | Created src/game/classes.js, src/game/stats.js + unit tests (23 tests) | 23/23 pass
  • 2026-10-20 | 2.3 | Created src/services/characterService.js, src/routes/character.js; integrated into app.js | app loads
  • 2026-10-20 | 2.4 | Created public/create-hero.html, public/game.html, public/js/create-hero.js, public/js/game.js | app loads