15 KiB
15 KiB
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: 5
- Step: 5.2
- Blocked? No
- Last verified working command:
npm test— 98/98 passing (74 unit + 29 integration), 2026-10-20 step 4.5
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 |
Phase 0 — Scaffold
- 0.1
npm init, install deps from NOTES.md §2, add scripts:start,dev(node --watch),test,migrate,seed. Acceptance:npm installsucceeds; scripts exist in package.json. - 0.2
src/config/index.jsloads.env(useprocess.loadEnvFileordotenv), validates required vars, exports a frozen config object. Acceptance: missing SESSION_SECRET in production throws a clear error. - 0.3
src/db/index.jsopens SQLite (WAL mode, foreign_keys ON) and exports the handle.scripts/migrate.jsruns numbered.sqlfiles fromsrc/db/migrations/in order and records them in a_migrationstable. Acceptance:npm run migratetwice 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), staticpublic/,GET /api/health→{ok:true}, central error handler (see CODING_STANDARDS). Acceptance:curl localhost:3000/api/healthreturns{"ok":true}. - 0.5 First test: health endpoint via
node:test+fetchagainstappon an ephemeral port (see TESTING.md). Acceptance:npm testpasses.
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) +
requireAuthmiddleware. - 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,
merequires 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: purecomputeEnergy(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_atback 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), notscripts/seed.js. Balance changes need a NEW migration. - 4.2
src/game/combat.js: pureresolveCombat(hero, monster, rng)→{winner, rounds[], hpRemaining}. Seedable RNG insrc/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 → writecombat_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-logendpoints; 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.
- 5.3 Stackable consumables:
POST /api/inventory/use(health potion heals; energy tonic restores energy, capped). - 5.4 UI: inventory grid, equipment panel, tooltips with stats.
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. - 6.2 Level-gated shop stock. UI page.
- 6.3 Tests: buy with insufficient gold, sell equipped item (must be rejected), concurrent double-buy safety (transaction).
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 beforeends_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|killstop 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:devcreating 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 tosrc/middleware/wrap.js.- Error responses from route-level
AppErrors for validation don't include field details (API.md says they should). npm testprints 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.jsis the only clock.
Test Summary
| Suite | Passing | Failing | Last run |
|---|---|---|---|
| unit | 69 | 0 | 2026-10-20 review pass |
| integration | 24 | 0 | 2026-10-20 review pass |
Session Log
Format: YYYY-MM-DD | step | what changed | result
- 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.jswithprocess.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 migratetwice 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 testpasses (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.jswith 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