Skip to main content

API Response Comparison - Before vs After

GET /api/v1/wallet/me

BEFORE (Old System)

User had single wallet regardless of country:

{
"data": {
"_id": "507f1f77bcf86cd799439011",
"user": "507f191e810c19729de860ea",
"availableZishPoints": 150,
"withdrawalBalance": 50,
"ledger": ["..."],
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-02T00:00:00.000Z"
}
}

Issue: User in US could see/use points earned in UK


AFTER (Country-Specific System)

Scenario 1: User in US (has US wallet)

{
"data": {
"_id": "507f1f77bcf86cd799439011",
"user": "507f191e810c19729de860ea",
"country": "US", // ⭐ NEW: Country field
"availableZishPoints": 150,
"withdrawalBalance": 50,
"ledger": ["..."],
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-02T00:00:00.000Z"
}
}

Scenario 2: User changed to UK (no UK wallet yet)

{
"data": null // ⭐ NEW: null when no wallet for current country
}

Scenario 3: User changed to UK (has UK wallet)

{
"data": {
"_id": "507f1f77bcf86cd799439012",
"user": "507f191e810c19729de860ea",
"country": "UK", // ⭐ NEW: Shows UK wallet
"availableZishPoints": 0, // ⭐ NEW: Separate balance
"withdrawalBalance": 0,
"ledger": [],
"createdAt": "2025-01-15T00:00:00.000Z",
"updatedAt": "2025-01-15T00:00:00.000Z"
}
}

Benefit: User only sees balance for current country ✅


POST /api/v1/payments/stripe/webhook (Plan Purchase)

BEFORE

Credits were added to user's single wallet:

// Old code
let wallet = await Wallet.findOne({ user: userId })
wallet.availableZishPoints += points

Issue: points from different countries mixed in one wallet


AFTER

Credits go to country-specific wallet:

// New code
const user = await User.findById(userId).select('address')
const country = String(user?.address?.country || '').toUpperCase() || 'UNKNOWN'

let wallet = await Wallet.findOne({ user: userId, country })
if (!wallet) {
wallet = await Wallet.create({ user: userId, country, ... })
}
wallet.availableZishPoints += points

Benefit: points isolated per country ✅


GET /admin/wallets/:userId

BEFORE

Returned single wallet:

{
"_id": "507f1f77bcf86cd799439011",
"user": "507f191e810c19729de860ea",
"availableZishPoints": 150,
"withdrawalBalance": 50,
"ledger": ["..."]
}

AFTER

Without country query parameter

Returns ALL wallets for user:

{
"user": "507f191e810c19729de860ea",
"wallets": [ // ⭐ NEW: Array of wallets
{
"_id": "507f1f77bcf86cd799439011",
"user": "507f191e810c19729de860ea",
"country": "US", // ⭐ NEW
"availableZishPoints": 150,
"withdrawalBalance": 50,
"ledger": ["..."]
},
{
"_id": "507f1f77bcf86cd799439012",
"user": "507f191e810c19729de860ea",
"country": "UK", // ⭐ NEW
"availableZishPoints": 200,
"withdrawalBalance": 75,
"ledger": ["..."]
},
{
"_id": "507f1f77bcf86cd799439013",
"user": "507f191e810c19729de860ea",
"country": "IN", // ⭐ NEW
"availableZishPoints": 300,
"withdrawalBalance": 100,
"ledger": ["..."]
}
]
}

With country query parameter

Returns specific country wallet:

Request: GET /admin/wallets/:userId?country=US

{
"user": "507f191e810c19729de860ea",
"country": "US",
"availableZishPoints": 150,
"withdrawalBalance": 50,
"ledger": ["..."],
"_virtual": false
}

Benefit: Admin can see all country wallets separately ✅


POST /api/v1/tournaments/:id/join

BEFORE

Debited from single wallet:

// Old code
const wallet = await Wallet.findOne({ user: userId })
wallet.availableZishPoints -= entryFee

Issue: Could use points earned in any country


AFTER

Debits only from current country wallet:

// New code
const user = await User.findById(userId)
const country = String(user?.address?.country || '').toUpperCase() || 'UNKNOWN'

const wallet = await Wallet.findOne({ user: userId, country })
if (!wallet) {
throw new Error("No wallet found for your current country")
}
wallet.availableZishPoints -= entryFee

Error Response (if no wallet for current country):

{
"error": "NOT_FOUND",
"message": "No wallet found for your current country"
}

Benefit: Enforces country isolation ✅


Database Schema Comparison

BEFORE

{
_id: ObjectId,
user: ObjectId, // ref: User
availableZishPoints: Number,
withdrawalBalance: Number,
ledger: [ObjectId], // ref: Ledger
createdAt: Date,
updatedAt: Date
}

// Index: { user: 1 }
// Constraint: One wallet per user

AFTER

{
_id: ObjectId,
user: ObjectId, // ref: User
country: String, // ⭐ NEW: Required, uppercase, default: 'UNKNOWN'
availableZishPoints: Number,
withdrawalBalance: Number,
ledger: [ObjectId], // ref: Ledger
createdAt: Date,
updatedAt: Date
}

// Index: { user: 1, country: 1 } // ⭐ NEW: Compound unique index
// Constraint: One wallet per user per country

Real-World Example: User Journey

Scenario: User travels from US to UK

EventOld SystemNew System
1. Register in USSingle wallet createdWallet created with country: "US"
2. Buy $10 plan in USBalance: $10US wallet: $10, UK wallet: doesn't exist
3. Join tournament in USBalance: $5US wallet: $5, UK wallet: doesn't exist
4. Travel to UK, update profileSame walletNew UK wallet created (balance: $0)
5. Check wallet in UKShows: $5 (US balance) ❌Shows: $0 (UK balance) ✅
6. Buy £20 plan in UKBalance: $25 (mixed!) ❌US wallet: $5, UK wallet: £20 ✅
7. Join tournament in UKUses mixed balance ❌Uses only UK balance ✅
8. Travel back to USShows: mixed balance ❌US wallet: $5 (preserved) ✅

Migration Impact

For Existing Users

Before Migration:

{
"_id": "...",
"user": "507f191e810c19729de860ea",
"availableZishPoints": 150,
// No country field
}

After Migration:

{
"_id": "...",
"user": "507f191e810c19729de860ea",
"country": "US", // ⭐ Added based on user's current country
"availableZishPoints": 150, // Balance preserved
}

For New Users

All new users get country-specific wallets from the start:

  • User registers with country → Wallet created with that country
  • User has no country → Wallet created with country: "UNKNOWN"
  • User changes country → New wallet created automatically

Backward Compatibility Summary

Old Wallet StateAfter MigrationBehavior
No country fieldCountry added (user's current)✅ Works normally
Had balanceBalance preserved✅ Balance intact
User had no countrycountry: "UNKNOWN"✅ Still accessible
Ledger entriesPreserved✅ History intact

Key Takeaways

✅ What Works the Same

  • Wallet creation on user registration
  • Balance tracking
  • Ledger entries
  • Admin operations

⭐ What's New

  • country field on every wallet
  • Multiple wallets per user (one per country)
  • API returns null if no wallet for current country
  • Admin can see all country wallets

🚫 What's Different

  • Users can't access other countries' balances
  • Country change creates new wallet (starts at 0)
  • Tournament/topup/payout use current country wallet only
  • API response structure changed for admin endpoints

🎯 The Goal

Isolation: Keep country finances separate for compliance and clarity ✅