diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..555cdce --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Such Software LLC, John Winter Murphy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/PAYMENTS_TODO.md b/PAYMENTS_TODO.md new file mode 100644 index 0000000..373caee --- /dev/null +++ b/PAYMENTS_TODO.md @@ -0,0 +1,104 @@ +# Payments System TODO + +This document tracks remaining work for the payment system before production release. + +## โ Completed + +### Mixed Mode Logic Bug - FIXED +~~The backend uses a single `gameMode` value (`PAID_SINGLE` or `PAID_CREDITS`), but the config allows both modes to be enabled simultaneously.~~ + +**Implemented:** +- Added `getEffectiveModeForUser(socketId)` - determines mode per-user based on credits balance +- Refactored `canUserStartGame()` to check credits first, then confirmed payments +- Added `getPaymentOptionsForUser(socketId)` for dynamic UI rendering +- Created `_processGameStartWithCredits()` and `_processGameStartWithPayment()` methods +- Frontend PaymentUI now dynamically shows options based on user's credits and enabled modes + +### Credits Package Amount Bug - FIXED +~~In `src/payments/moneroPayService.js#L150`, credits are hardcoded to +10~~ + +**Implemented:** +- Added `processCreditsPackageConfirmation(socketId, paymentId, packageInfo)` to `gameModeManager.js` +- Credits now parsed from package info (credits + bonus) passed from confirmation handler +- Falls back to parsing from payment description if package info missing +- Updated `paymentHandlers.js` to track `paymentType` and call confirmation method with package data + +### Payment Tests - Added +- Created `test/gameModeManager.test.js` with 17 tests covering: + - `getEffectiveModeForUser` - all mode combinations + - `calculatePayout` - direct and credits modes + - `getPaymentOptionsForUser` - credits, direct, buy options + - `processCreditsPackageConfirmation` - from package info and fallback + - `canUserStartGame` - mixed mode scenarios + +--- + +## ๐ก Important (Should Fix Before Beta) + +### Frontend UX Polish +- [x] Show user's current credit balance in mode selection modal +- [x] If user has credits, highlight "Use 1 Credit" as primary action +- [x] Add "Buy More Credits" secondary button +- [x] Show payout eligibility per mode (Direct = payouts, Credits = no payouts) + +### Session Persistence Documentation +- [x] Add info tooltip near "Manage Payout Address" explaining session persistence +- [x] Update README with session/cookie requirements +- [x] Show warning if localStorage is unavailable (private browsing) + +--- + +## ๐ข Nice to Have (Post-Beta) + +### Smart Payment Flow +- [ ] If user has credits, skip payment modal and start game directly +- [ ] "Auto-buy credits" when balance is low (opt-in) +- [ ] Show estimated games remaining based on credits + +### Payment History +- [ ] `/api/user/:socketId/payments` - List payment history +- [ ] `/api/user/:socketId/payouts` - List payout history +- [ ] Frontend "Transaction History" panel + +### Refund Flow +- [ ] Admin endpoint to refund a payment +- [ ] Partial credit refunds + +--- + +## Session Persistence - User-Facing Documentation + +Add to README and/or in-game help: + +> **How Sessions Work** +> +> Your payout address and credit balance are tied to a session token stored in your browser. +> +> - โ **Works:** Normal browsing, closing/reopening browser, refreshing page +> - โ ๏ธ **Lost if:** You clear cookies/localStorage, use private/incognito mode, switch browsers +> +> **Tip:** After setting your payout address, note your session token (shown once) if you want to recover your session on a new device. + +--- + +## Test Coverage Checklist + +| Area | Unit Tests | Integration Tests | +|------|------------|-------------------| +| Payment creation | โ | โ | +| Payment confirmation | โ | โ | +| Credits purchase | โ | โ | +| Credits deduction | โ | โ | +| Payout creation | โ ๏ธ Mocked | โ | +| Payout processing | โ | โ | +| Mixed mode selection | โ | โ | +| Session resume | โ | โ | + +--- + +## Environment Config Validation + +When both modes are enabled, ensure: +- [ ] `CREDITS_PAYOUTS_ENABLED=false` when credits mode has no payouts (prevent config mistakes) +- [ ] Warn if `DIRECT_PAYOUTS_ENABLED=true` but no wallet RPC configured +- [ ] Validate `CREDITS_PACKAGES` JSON is well-formed at startup \ No newline at end of file diff --git a/README.md b/README.md index 3c64fce..f4ec881 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,32 @@ BLOCK_SOURCE=daemon 2. Regex detection flags the message and issues a warning. 3. Player confirms; the address is persisted for payouts. +## Session Persistence + +Player sessions are tied to an anonymous token stored in the browser's localStorage. This token persists: + +- โ **Across page refreshes** โ Reconnecting reloads your credits and payout address. +- โ **After closing the browser** โ The token survives normal browser sessions. +- โ **Server restarts** โ Session data is stored in PostgreSQL, not memory. + +Sessions are **lost** when: + +- โ ๏ธ Clearing cookies or localStorage +- โ ๏ธ Using private/incognito browsing mode (localStorage may be disabled or ephemeral) +- โ ๏ธ Switching browsers or devices + +**Important notes for players:** + +1. Your payout address and credit balance are tied to your session token. +2. If localStorage is unavailable (private browsing), a warning appears next to the "Manage Payout Address" button. +3. There is no account systemโyour session token *is* your identity. Treat it carefully. + +**For deployment:** + +- Ensure your reverse proxy preserves WebSocket connections for token handshake. +- The `wownerogue_token` key in localStorage contains the resume token. +- Session data (credits, address) is stored in the `users` table with the token in `anon_token`. + ## Testing Run the Jest suite from `src`: diff --git a/TODO.md b/TODO.md index f0e5bb1..063737d 100644 --- a/TODO.md +++ b/TODO.md @@ -4,7 +4,9 @@ - [x] **Verify Server Startup**: Server starts cleanly with `npm run dev` โ - [ ] **Test Payment Flow**: Verify the full payment lifecycle (Request -> QR -> Payment -> Confirmation -> Game Start). - [ ] **Test Payouts**: Confirm payouts are triggered correctly upon winning in paid modes. -- [ ] **Address Persistence**: Verify that payout addresses persist across server restarts via session tokens. +- [x] **Address Persistence**: Verify that payout addresses persist across server restarts via session tokens. โ +- [x] **Mixed Mode Logic**: Per-user mode determination based on credits balance โ +- [x] **Credits Package Bug**: Credits correctly parsed from package info on confirmation โ ## Improvements / Refactoring - [ ] **Error Handling**: Extend `normalizeError` usage to remaining network modules for consistent error reporting. @@ -14,12 +16,15 @@ ## Documentation - [x] **API Documentation**: README updated with accurate API surface including health check and Socket.IO events โ +- [x] **Session Persistence**: README documents session token behavior and localStorage requirements โ - [ ] **Deployment Guide**: Create a detailed deployment guide including reverse proxy setup (Nginx/Caddy). ## Pre-Beta Checklist -- [x] All 21 tests pass โ +- [x] All 38 tests pass (8 test suites) โ - [x] Health check endpoint available at `/health` โ - [x] REST endpoints implemented: `/api/user/:socketId/credits`, `/api/user/:socketId/mode`, `/api/user/:socketId/address` โ +- [x] Payout eligibility shown per payment mode in UI โ +- [x] Session persistence tooltip and localStorage warning added โ - [ ] **TLS/HTTPS**: Configure reverse proxy (Nginx/Caddy) with SSL certificates before exposing to real users. - [ ] **Database Backups**: Implement automated backup strategy for PostgreSQL. - [ ] **Manual Integration Test**: Run full payment flow with real `wownero-wallet-rpc` (not mocked). diff --git a/html/index.html b/html/index.html index 994ce5a..ffe33af 100644 --- a/html/index.html +++ b/html/index.html @@ -12,13 +12,28 @@ @@ -70,7 +85,8 @@ - + + @@ -149,6 +165,7 @@
Enter your Wownero (WOW) or Monero (XMR) address below. This will be used for payouts when you escape.
+๐ก Session Info: Your address and credits are tied to a browser session token stored locally. They will persist across page refreshes but will be lost if you clear cookies, use incognito mode, or switch browsers.