Skip to content

feat(store): backend-backed store purchase flow with wallet balance (Closes #12) - #32

Merged
merlik787-droi merged 3 commits into
Riddlrealm:mainfrom
DanielCharis1:feat/issue-12-store-purchase-flow
Aug 27, 2026
Merged

merlik787-droi merged 3 commits into
Riddlrealm:mainfrom
DanielCharis1:feat/issue-12-store-purchase-flow

Conversation

@DanielCharis1

Copy link
Copy Markdown
Contributor

Summary

Implements #12 — Store Purchase Flow With Wallet And Coin Deduction. The store is no longer a static catalog: every buy button now runs a real purchase through the Mindmint backend, and the coin balance / lifeline inventory persist and reflect in the store and gameplay header.

Trust boundary (documented): the backend is the sole authority on pricing, deduction, and balances. The client only sends what is being bought ({ itemType, itemId }) — never a price — and a purchase is only complete when the server responds with the authoritative post-purchase wallet. A failed or unconfirmed purchase never touches the displayed balance.

What changed

  • src/services/StoreService.ts (new) — authenticated, fail-closed client for GET /api/store/wallet and POST /api/store/purchase, mirroring the DashboardService/LeaderboardService contract pattern.
  • src/features/store/storeSlice.ts (new) — wallet state, single-flight pendingItem, and a purchaseItem thunk. loadWallet falls back to the cached per-user wallet when the backend is unreachable.
  • src/features/store/walletCache.ts (new) — per-user localStorage snapshot (STORAGE_KEYS.WALLET_STATE), never served to a different user, cleared on logout via clearSession.
  • src/pages/Store.tsx — live balance display, loading spinners + disabled buttons while a purchase is in flight, inline error banner, and success/error toasts via the existing toast system.
  • src/components/gameplay/GameHeader.tsx — live coin balance and owned lifeline counts.
  • .env.example / README.md — endpoint contracts and the trust-boundary decision documented (mirroring the Dashboard/Leaderboard docs).
  • Tests (20 new) — service (token attach, price never sent, fail-closed), slice (confirmed purchase adopts authoritative wallet; failed purchase leaves balance untouched; pending state; caching), wallet cache (per-user keying, corruption guards), and Store page (confirmed purchase updates balance + toast; error renders error state without incrementing).

Note on the base fixes included here

Main's CI is currently red: npm ci fails (lockfile out of sync since the dashboard merges) and two tests fail (leaderboardView crash in Dashboard.tsx, un-isolated AuthService tests). PRs #30 and #31 (by @rudra496) already fix these but are still open, so any new PR based on main inherits the red CI. To keep this PR's checks green, I included those exact base fixes as a separate commit (fix(ci): restore lockfile entries and resolve red tests on main). If #30/#31 land first, that commit can be dropped or rebased away — happy to adjust.

Verification

  • npm ci → clean install
  • npm run build → passes
  • npm run lint → passes
  • npm test → 71/71 pass (51 pre-existing + 20 new)

Closes #12

DanielCharis1 and others added 3 commits August 26, 2026 18:41
`npm ci` fails on main since the dashboard merges: package.json's coverage
stack (@vitest/coverage-v8 and its istanbul chain) was added without
updating package-lock.json. Also fixes the two real test failures the CI
run surfaced once installs worked: Dashboard.tsx referenced an undeclared
`leaderboardView`, and AuthService tests were not isolated from persisted
session entries. No pins change in the lockfile.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
Makes the store a real purchase flow instead of a static catalog:

- StoreService (new): GET /api/store/wallet and POST /api/store/purchase
  with the bearer token, fail-closed when the API URL or session is
  missing. Only the item reference is sent — never a price — and a
  purchase is complete only when the server returns the authoritative
  post-purchase wallet.
- storeSlice (new): wallet state, single-flight pending item, and a
  purchase thunk whose failure never mutates the balance. The confirmed
  wallet is cached per signed-in user (STORAGE_KEYS.WALLET_STATE) and
  cleared on logout via clearSession.
- Store page: buy buttons show loading/error states, surface failures
  through the toast system and an inline banner, and reflect the live
  balance.
- GameHeader: shows live coin balance and owned lifeline counts.
- Documents the trust boundary and endpoint contracts in README and
  .env.example.

Trust boundary: the backend is the sole authority on pricing, deduction,
and balances; the client renders only wallets the server confirmed.
Closes Riddlrealm#12.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@merlik787-droi
merlik787-droi merged commit 353a375 into Riddlrealm:main Aug 27, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Store Purchase Flow With Wallet And Coin Deduction

2 participants