Repository navigation
feat(store): backend-backed store purchase flow with wallet balance (Closes #12) - #32
Merged
merlik787-droi merged 3 commits intoAug 27, 2026
Conversation
`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>
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 forGET /api/store/walletandPOST /api/store/purchase, mirroring theDashboardService/LeaderboardServicecontract pattern.src/features/store/storeSlice.ts(new) — wallet state, single-flightpendingItem, and apurchaseItemthunk.loadWalletfalls 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 viaclearSession.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).Note on the base fixes included here
Main's CI is currently red:
npm cifails (lockfile out of sync since the dashboard merges) and two tests fail (leaderboardViewcrash inDashboard.tsx, un-isolatedAuthServicetests). 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 installnpm run build→ passesnpm run lint→ passesnpm test→ 71/71 pass (51 pre-existing + 20 new)Closes #12