# πŸ”§ Code Mode Hand-off Blueprint: 4-Bug Fix Bundle **Created:** 2026-07-26 | **Mode:** Architect β†’ Code **Target Branch:** `main` --- ## πŸ“Š Root Cause Analysis Summary | # | Bug | Root Cause File | Severity | |---|-----|----------------|----------| | 1 | Logo navigation traps user in org scope | HeaderLogo.vue:33 | Medium | | 2 | GET /wallet/balance β†’ 500 for user 106 | billing_engine.py:625-633 | Critical | | 3 | "705,000" shown for all users (N/A β€” no mock found) | N/A β€” see analysis below | Info | | 4 | [intlify] Not found 'subscription.vehicles' | SubscriptionStatusWidget.vue:67,81 | Low | --- ## πŸ› Bug 1: Logo Navigation β€” Always Redirect to /dashboard ### File `frontend_app/src/components/header/HeaderLogo.vue` ### Current Behavior (Lines 32-38) ```typescript const targetRoute = computed(() => { if (route.path.startsWith('/organization/')) { const orgId = route.params.id return orgId ? `/organization/${orgId}` : route.path } return '/dashboard' }) ``` When user is on `/organization/5/vehicles`, `route.path.startsWith('/organization/')` is `true`, so the logo navigates to `/organization/5` β€” the org root β€” NOT to `/dashboard`. This traps the user; there is no way to return to the private garage dashboard via the logo. ### Root Cause The logo's `targetRoute` logic intentionally scopes the user to the org when on org pages, but this prevents escaping back to `/dashboard`. ### Fix **Replace the entire `targetRoute` computed with:** ```typescript const targetRoute = computed(() => '/dashboard') ``` **Rationale:** The `HeaderCompanySwitcher` component already provides organization context switching. The logo should always be a "global home" escape hatch. This follows the web standard: clicking the brand logo always returns to the root dashboard. ### Lines to Change - **DELETE:** Lines 32-38 - **REPLACE WITH:** Single line `const targetRoute = computed(() => '/dashboard')` ### Verification 1. Log in as any user 2. Navigate to `/organization/:id/vehicles` 3. Click the `HeaderLogo` β†’ must navigate to `/dashboard` (not stay on org pages) --- ## πŸ› Bug 2: Backend 500 Error β€” `float(None)` on Wallet Balance ### File `backend/app/services/billing_engine.py` β€” `AtomicTransactionManager.get_wallet_summary()` ### Current Behavior (Lines 622-635) ```python return { "wallet_id": wallet.id, "balances": { "earned": float(wallet.earned_credits), # πŸ’₯ CRASHES if None "purchased": float(wallet.purchased_credits), # πŸ’₯ CRASHES if None "service_coins": float(wallet.service_coins), # πŸ’₯ CRASHES if None "voucher": float(voucher_balance), "total": float( wallet.earned_credits + # πŸ’₯ CRASHES if None wallet.purchased_credits + wallet.service_coins + voucher_balance ) }, ``` ### Root Cause The `Wallet` model defines credit columns as: ```python earned_credits: Mapped[float] = mapped_column(Numeric(18, 4), server_default=text("0")) ``` `server_default` only applies at the DB level on INSERT. If a wallet row was created with explicit `None` values, or if the DB column contains `NULL` (e.g., from a migration or manual SQL), then `wallet.earned_credits` will be Python `None`. Calling `float(None)` raises `TypeError`, which falls through to the generic `Exception` handler returning HTTP 500. Also: if the wallet row does NOT exist at all, `get_wallet_summary()` raises `ValueError(f"Wallet not found for user_id={user_id}")` β†’ which IS caught as 404. So the 500 specifically means: **wallet row EXISTS but has NULL credit columns**. ### Fix **Option A (Defensive β€” Preferred): Wrap all `float()` calls with `or 0`** Change lines 625-634 to: ```python "earned": float(wallet.earned_credits or 0), "purchased": float(wallet.purchased_credits or 0), "service_coins": float(wallet.service_coins or 0), "voucher": float(voucher_balance or 0), "total": float( (wallet.earned_credits or 0) + (wallet.purchased_credits or 0) + (wallet.service_coins or 0) + (voucher_balance or 0) ) ``` **Option B (Root Fix β€” also recommended): Run a DB repair script to fix NULL columns** ```sql UPDATE identity.wallets SET earned_credits = 0 WHERE earned_credits IS NULL; UPDATE identity.wallets SET purchased_credits = 0 WHERE purchased_credits IS NULL; UPDATE identity.wallets SET service_coins = 0 WHERE service_coins IS NULL; ``` **BOTH Option A and Option B should be applied.** ### Verification 1. Find NULL wallets: `SELECT id, user_id FROM identity.wallets WHERE earned_credits IS NULL OR purchased_credits IS NULL OR service_coins IS NULL;` 2. Apply both fixes 3. GET /api/v1/billing/wallet/balance with JWT for user 106 β†’ must return 200 --- ## πŸ› Bug 3: "705,000" Mock Data β€” NOT a Code Issue ### Finding **No mock/hardcoded data was found in any frontend file.** Searched all .vue, .ts, and .json files for 705000 β€” zero results. The finance store properly fetches from the API and has zero-fallback: ```typescript const totalCredits = computed(() => balance.value?.total ?? 0) ``` The "705,000" value is from a real database record β€” likely the admin test user's wallet. User 106 sees an error because their wallet has NULL credits. Once Bug 2 is fixed, user 106 will see 0 (either no wallet β†’ creates one, or NULL columns β†’ returned as 0). ### Action **No code change needed for Bug 3.** Fixing Bug 2 resolves the 500 error cascade. --- ## πŸ› Bug 4: Missing i18n Keys in SubscriptionStatusWidget ### File `frontend_app/src/components/dashboard/SubscriptionStatusWidget.vue` ### Missing Keys (Lines 52, 53, 67, 81) - `subscription.vehicles` (Line 67, 81) - `subscription.unlimited` (Line 81) - `subscription.timeRemaining` (Line 52) - `subscription.days` (Line 53) None of these exist in `hu.ts` or `en.ts`. ### Fix Add to BOTH `frontend_app/src/i18n/hu.ts` AND `frontend_app/src/i18n/en.ts` inside the `subscription` block, after `indefinite`: **hu.ts β€” add:** ```typescript vehicles: 'jΓ‘rmΕ±', unlimited: 'korlΓ‘tlan', timeRemaining: 'HΓ‘tralΓ©vΕ‘ idΕ‘', days: 'nap', ``` **en.ts β€” add:** ```typescript vehicles: 'vehicles', unlimited: 'unlimited', timeRemaining: 'Time Remaining', days: 'days', ``` --- ## πŸ“‹ Execution Order (Code Mode) 1. **Bug 1** β€” HeaderLogo.vue: Change targetRoute to always return /dashboard 2. **Bug 4** β€” hu.ts + en.ts: Add 4 missing i18n keys 3. **Bug 2** β€” billing_engine.py: Add `or 0` to all float() conversions 4. **Bug 2 (DB)** β€” Run SQL to NULLβ†’0 on identity.wallets credit columns 5. **Bug 3** β€” Verify fix, no code change needed --- ## πŸ”— Files Summary | File | Bug | Operation | |------|-----|-----------| | frontend_app/src/components/header/HeaderLogo.vue | #1 | Replace lines 32-38 | | frontend_app/src/i18n/hu.ts | #4 | Add 4 keys after line 83 | | frontend_app/src/i18n/en.ts | #4 | Add 4 keys after line 83 | | backend/app/services/billing_engine.py | #2 | Modify lines 625-634 | | identity.wallets (DB) | #2 | SQL UPDATE NULLβ†’0 | --- *Blueprint ready for Code Mode hand-off.*