# Goals & Wallet Behavior - How Money Works ## 📊 **Current Implementation: Virtual Allocation (No Freeze)** ### **Your Scenario:** **Initial State:** ``` Wallet A: Rp 5,000,000 Wallet B: Rp 2,000,000 Goal: MacbookPro M4 (Target: Rp 4,000,000) ``` **After Adding Money to Goal:** ``` Action 1: Add Rp 2,000,000 from Wallet A to Goal Action 2: Add Rp 1,000,000 from Wallet B to Goal ``` --- ## **What Happens:** ### **Current Behavior (Virtual Allocation):** ``` ┌─────────────────────────────────────────────────────────────┐ │ Wallet A │ ├─────────────────────────────────────────────────────────────┤ │ Balance: Rp 5,000,000 │ │ Status: STILL AVAILABLE │ │ │ │ ❌ Money is NOT frozen │ │ ❌ Money is NOT deducted │ │ ✅ You can still spend all Rp 5,000,000 │ │ │ │ Note: Goal allocation is just a "tracking record" │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Wallet B │ ├─────────────────────────────────────────────────────────────┤ │ Balance: Rp 2,000,000 │ │ Status: STILL AVAILABLE │ │ │ │ ❌ Money is NOT frozen │ │ ❌ Money is NOT deducted │ │ ✅ You can still spend all Rp 2,000,000 │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Goal: MacbookPro M4 │ ├─────────────────────────────────────────────────────────────┤ │ Target: Rp 4,000,000 │ │ Current: Rp 3,000,000 (75%) │ │ │ │ Allocations: │ │ - From Wallet A: Rp 2,000,000 │ │ - From Wallet B: Rp 1,000,000 │ │ │ │ ⚠️ This is just a TRACKING record │ │ ⚠️ Money still exists in wallets │ └─────────────────────────────────────────────────────────────┘ ``` --- ## **⚠️ Problem with Current Implementation:** ### **Issue: Double Counting** You can spend the same money twice: ``` Scenario: 1. Add Rp 2,000,000 from Wallet A to Goal ✅ 2. Goal shows Rp 2,000,000 saved ✅ 3. Spend Rp 2,000,000 from Wallet A for something else ✅ 4. Wallet A now has Rp 3,000,000 5. But Goal still shows Rp 2,000,000 saved! ❌ Result: Goal tracking becomes inaccurate! ``` --- ## **💡 Recommended Solutions:** ### **Option 1: Virtual Allocation (Current - Simple but Inaccurate)** **How it works:** - Goal allocation is just a record - Money stays in wallet - No restrictions on spending **Pros:** - ✅ Simple to implement (already done) - ✅ Flexible - can spend money anytime - ✅ No complex logic needed **Cons:** - ❌ Can spend allocated money elsewhere - ❌ Goal progress becomes inaccurate - ❌ User might think they saved money but actually spent it **Best for:** - Simple goal tracking - Users who just want to see progress - Not critical if goals are just aspirational --- ### **Option 2: Reserved Balance (Recommended)** **How it works:** - When you allocate money to a goal, it's "reserved" - Wallet shows: Total Balance vs Available Balance - Reserved money can't be spent on transactions - Can only be used for the goal or released back **Example:** ``` Wallet A: ├── Total Balance: Rp 5,000,000 ├── Reserved for Goals: Rp 2,000,000 └── Available Balance: Rp 3,000,000 ← Only this can be spent When creating transaction: - System checks Available Balance (not Total Balance) - If you try to spend Rp 4,000,000 → Error: Insufficient available balance ``` **Implementation:** ```typescript // Add to Wallet model interface Wallet { totalBalance: number; reservedBalance: number; // ← New field availableBalance: number; // = totalBalance - reservedBalance } // When adding money to goal 1. Check wallet.availableBalance >= amount 2. Create goal allocation 3. Update wallet.reservedBalance += amount 4. Update goal.currentAmount += amount // When removing allocation 1. Delete allocation 2. Update wallet.reservedBalance -= amount 3. Update goal.currentAmount -= amount // When creating transaction 1. Check wallet.availableBalance >= amount (not totalBalance) 2. If sufficient, allow transaction ``` **Pros:** - ✅ Accurate goal tracking - ✅ Prevents double-spending - ✅ Clear separation of allocated vs available money - ✅ User sees exactly how much they can spend **Cons:** - ⚠️ More complex implementation - ⚠️ Need to update wallet model - ⚠️ Need to update transaction validation --- ### **Option 3: Actual Transfer (Most Strict)** **How it works:** - Create a special "Goal Wallet" for each goal - When allocating money, create a transaction that transfers money - Money is physically moved from Wallet A → Goal Wallet - Goal Wallet balance = Goal progress **Example:** ``` Before: Wallet A: Rp 5,000,000 Goal Wallet (MacbookPro): Rp 0 Add Rp 2,000,000 to goal: 1. Create transaction: Wallet A → Goal Wallet (Rp 2,000,000) 2. Wallet A: Rp 3,000,000 3. Goal Wallet: Rp 2,000,000 Result: - Money is actually moved - Wallet A balance decreases - Goal Wallet balance increases ``` **Pros:** - ✅ Most accurate - ✅ Real money movement - ✅ Easy to understand - ✅ Can see goal money as a separate wallet **Cons:** - ⚠️ Creates many wallets - ⚠️ More complex to manage - ⚠️ Harder to "un-allocate" money --- ## **📊 Comparison:** | Feature | Virtual (Current) | Reserved Balance | Actual Transfer | |---------|-------------------|------------------|-----------------| | **Accuracy** | ❌ Low | ✅ High | ✅ Very High | | **Complexity** | ✅ Simple | ⚠️ Medium | ❌ Complex | | **Flexibility** | ✅ High | ⚠️ Medium | ❌ Low | | **User Understanding** | ⚠️ Confusing | ✅ Clear | ✅ Very Clear | | **Double Spending** | ❌ Possible | ✅ Prevented | ✅ Prevented | | **Implementation Time** | ✅ Done | ⚠️ 2-3 hours | ❌ 4-6 hours | --- ## **🎯 My Recommendation:** ### **Use Option 2: Reserved Balance** **Why:** 1. **Accurate** - Goals show real progress 2. **Prevents confusion** - Users know what they can spend 3. **Not too complex** - Can implement in 2-3 hours 4. **Flexible** - Can still release money if needed **Implementation Steps:** 1. **Update Prisma Schema:** ```prisma model Wallet { // ... existing fields reservedBalance Decimal @default(0) @db.Decimal(18, 2) } ``` 2. **Update Goals Service:** ```typescript // When adding allocation const wallet = await prisma.wallet.findUnique({ where: { id: walletId } }); const availableBalance = wallet.totalBalance - wallet.reservedBalance; if (amount > availableBalance) { throw new Error('Insufficient available balance'); } // Update reserved balance await prisma.wallet.update({ where: { id: walletId }, data: { reservedBalance: { increment: amount } } }); ``` 3. **Update Transaction Validation:** ```typescript // Check available balance instead of total balance const availableBalance = wallet.totalBalance - wallet.reservedBalance; if (transactionAmount > availableBalance) { throw new Error('Insufficient available balance'); } ``` 4. **Update Frontend:** ```tsx // Show both balances

Total: {formatCurrency(wallet.totalBalance)}

Reserved: {formatCurrency(wallet.reservedBalance)}

Available: {formatCurrency(wallet.availableBalance)}

``` --- ## **🤔 What Should We Do?** **Questions for you:** 1. **Do you want accurate goal tracking?** - If YES → Implement Reserved Balance - If NO → Keep current (Virtual Allocation) 2. **Is it okay if users can spend allocated money elsewhere?** - If NO → Implement Reserved Balance - If YES → Keep current 3. **Do you want to prevent double-spending?** - If YES → Implement Reserved Balance - If NO → Keep current **My suggestion:** Implement **Reserved Balance** because: - Goals become meaningful (not just aspirational) - Users won't be confused about their actual available money - Prevents the "I thought I saved money but I spent it" problem - Still flexible (can release reserved money if needed) --- ## **Current State Summary:** **Right now with your example:** ``` Wallet A: Rp 5,000,000 (can spend all of it) Wallet B: Rp 2,000,000 (can spend all of it) Goal: Shows Rp 3,000,000 saved ⚠️ But if you spend from wallets, goal progress doesn't decrease! ⚠️ Goal is just a "wish list" not actual savings ``` **With Reserved Balance:** ``` Wallet A: Total: Rp 5,000,000 Reserved: Rp 2,000,000 Available: Rp 3,000,000 ← Can only spend this Wallet B: Total: Rp 2,000,000 Reserved: Rp 1,000,000 Available: Rp 1,000,000 ← Can only spend this Goal: Rp 3,000,000 saved (accurate!) ✅ Goal progress is protected ✅ Can't accidentally spend goal money ``` --- **What would you like to do?** 🤔 1. Keep current implementation (simple but inaccurate) 2. Implement Reserved Balance (recommended) 3. Implement Actual Transfer (most accurate but complex)