7.0 KiB
🔧 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)
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:
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
- Log in as any user
- Navigate to
/organization/:id/vehicles - 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)
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:
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:
"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
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
- 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; - Apply both fixes
- 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:
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:
vehicles: 'jármű',
unlimited: 'korlátlan',
timeRemaining: 'Hátralévő idő',
days: 'nap',
en.ts — add:
vehicles: 'vehicles',
unlimited: 'unlimited',
timeRemaining: 'Time Remaining',
days: 'days',
📋 Execution Order (Code Mode)
- Bug 1 — HeaderLogo.vue: Change targetRoute to always return /dashboard
- Bug 4 — hu.ts + en.ts: Add 4 missing i18n keys
- Bug 2 — billing_engine.py: Add
or 0to all float() conversions - Bug 2 (DB) — Run SQL to NULL→0 on identity.wallets credit columns
- 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.