step 10.9: done

This commit is contained in:
bepis
2026-10-23 01:06:48 +11:00
parent bf0b3867bd
commit 28210ed56c
6 changed files with 464 additions and 15 deletions
+4 -3
View File
@@ -8,9 +8,9 @@
## Current Focus
- **Phase:** 10
- **Step:** 10.9 — Allocation UI: unspent points display with + buttons per stat on dashboard stats panel
- **Step:** 10.10 — Rest endpoint: POST /api/character/rest costs level*5 gold, heals to full max HP, errors on nothing-to-heal or insufficient gold
- **Blocked?** No
- **Last verified working command:** `npm test` — 214/214 passing (85 unit + 129 integration incl. 12 allocate tests), 2026-10-23 step 10.8
- **Last verified working command:** `npm test` — 222/222 passing (85 unit + 137 integration incl. 8 allocate UI tests), 2026-10-23 step 10.9
## Project Health
| Item | State |
@@ -165,8 +165,9 @@
- [x] **10.8** Add `POST /api/character/allocate` (API.md): body `{str,agi,int,vit}` as points to add (zod `.strict()`, non-negative integers). Use the existing, tested `allocatePoints` from `src/game/leveling.js`. One transaction; reject if the total exceeds `unspent_points` (422 `NOT_ENOUGH_POINTS`); return `{character, derived}`.
*Acceptance:* tests: spend 2 of 3 points on STR → `str` +2, `unspent_points` 1, derived attack increased by the exact expected amount; spending 4 of 3 → 422 and nothing changed; negative / float / unknown keys → 400; another user's character cannot be affected.
*Verified:* 12 integration tests (6 HTTP + 6 direct service) covering partial allocation, overspend rejection, negative/float/unknown validation, cross-user isolation; `allocatePoints` in `characterService.js` uses `allocatePoints` from `leveling.js`, computes `remainingPoints` itself, updates in transaction; 214/214 tests pass.
- [ ] **10.9** Allocation UI: on the dashboard stats panel show unspent points and a `+` button per stat (only when points remain), with a confirm/apply button, loading state, and error toast. Use `textContent`, never `innerHTML` with dynamic data.
- [x] **10.9** Allocation UI: on the dashboard stats panel show unspent points and a `+` button per stat (only when points remain), with a confirm/apply button, loading state, and error toast. Use `textContent`, never `innerHTML` with dynamic data.
*Acceptance:* in the frontend, applying points calls the endpoint and refreshes stats without a page reload. Add a link-checker/DOM-free test only if feasible; otherwise list manual verification steps in HANDOFF.md.
*Verified:* allocation section added to game.html (hidden by default, shown when unspent_points > 0); game.js has buildAllocationRows, handleAllocIncrement, updateAllocState, handleAllocApply, initAllocationUI; + buttons disabled when total reaches unspent; apply button disabled when total is 0 or exceeds unspent; loading state ("Applying...") on apply; success/error toasts; reloads character on success/failure; 8 new integration tests (5 HTML/JS structure + 2 API flow); 222/222 tests pass.
- [ ] **10.10** Add `POST /api/character/rest` (API.md, BALANCE.md §Rest): costs `level * 5` gold, heals to full max HP. Errors: `NOTHING_TO_HEAL` (422) if HP is already full, `INSUFFICIENT_GOLD` (422). One transaction. Add a "Rest (N gold)" button to the dashboard.
*Acceptance:* tests: HP 10/135 level 3 with gold 100 → HP 135, gold 85; full HP → 422 and gold unchanged; gold 5 → 422; HP unchanged on failure.
- [ ] **10.11** Natural HP regeneration (GAME_DESIGN §Time): +1% of max HP per minute, computed lazily like energy. New migration (next unused number) adds `hp_updated_at INTEGER` (backfill existing rows with `energy_updated_at`). Add a pure function `computeHp(current, maxHp, updatedAtMs, nowMs)` in `src/game/hp.js` with unit tests (partial minute, cap at max, clock backwards, large gap). Apply it before the HP check in hunting, in `getCharacterProfile`, in potion use, and in rest. Heals/damage must set `hp_updated_at = now`.