Files
service-finder/plans/finance_layout_clone_and_enum_fix_2026-07-26.md
2026-07-27 08:39:18 +00:00

12 KiB

🔵 Finance Module — FleetView Layout Clone + Enum Fix Blueprint

Date: 2026-07-26
Author: Architect Mode
Status: Pending Code Mode Execution
Priority: MEDIUM — Layout fix and enum data repair


STEP 1: THE WORKING LAYOUT — FleetView Analysis

Route: /organization/:org_id/vehicles
Component: FleetView.vue wrapped in OrganizationLayout.vue

FleetView.vue DOM Hierarchy (Key Elements)

<div class="relative min-h-screen">
  <!-- Fixed background -->
  <div class="fixed inset-0 z-0">
    <div class="absolute inset-0 bg-[url('@/assets/garage-bg.png')] bg-cover bg-center bg-fixed"></div>
  </div>
  <!-- Dark overlay -->
  <div class="fixed inset-0 z-0 bg-slate-900/65 pointer-events-none"></div>

  <!-- ═══ MAIN CONTENT CONTAINER ═══ -->
  <div class="relative z-10 mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
    <!-- Page header: flex justify-between -->
    <div class="mb-8 flex items-center justify-between">
      <div>
        <h1 class="text-3xl font-bold text-white">{{ title }}</h1>
        <p class="mt-1 text-sm text-white/60">{{ subtitle }}</p>
      </div>
      <div class="flex items-center gap-3">
        <!-- Action buttons + Back button -->
      </div>
    </div>

    <!-- Content Grid -->
    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
      <!-- Cards -->
    </div>
  </div>
</div>

OrganizationLayout.vue Role

OrganizationLayout.vue provides:

  • BaseHeader with company name + hamburger menu
  • main class="relative z-10"<router-view />
  • NO background — the child view (FleetView) provides its own

FinanceLayout.vue Current State

FinanceLayout.vue provides:

  • BaseHeader with HeaderLogo + LanguageSwitcher + HeaderProfile
  • ALREADY HAS backgroundfixed inset-0 z-0 + bg-[url('@/assets/garage-bg.png')] + dark overlay bg-black/30
  • main class="relative z-10"<router-view />

Critical Difference: FinanceLayout vs OrganizationLayout

Property OrganizationLayout FinanceLayout
Background None (child provides) Already provides garage-bg.png
Dark overlay None Already provides bg-black/30
Header Company name + hamburger Logo + lang switcher + profile
main class relative z-10 relative z-10

Conclusion: Since FinanceLayout already provides the background + overlay, the child views should NOT duplicate them. The fix is to make FinanceMainView.vue use the same inner container pattern as FleetView (line 12: relative z-10 mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8) but SKIP the background/overlay divs (which are in FinanceLayout).

What's Currently Wrong with FinanceMainView

Current structure (after previous fixes):

<!-- FinanceMainView.vue template: -->
<div class="flex flex-col justify-end min-h-[85vh] pb-8">
  <div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 w-full">
    <div class="mb-8 flex items-center justify-between"> ...header... </div>
    <div class="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-5 gap-4"> ...cards... </div>
  </div>
</div>

Problems:

  1. justify-end min-h-[85vh] — This is the DashboardView pattern (bottom-aligned). FleetView uses py-8 (top-aligned). The finance cards should be top-aligned with proper padding.
  2. lg:grid-cols-5 — Dashboard uses 5-column for its 5 cards. Finance has 4 cards. Should use whatever fits well.
  3. No relative on outer wrapper — needed for z-index context.

STEP 2: THE FIX — Clone FleetView Inner Structure

For FinanceMainView.vue:

<template>
  <div class="relative min-h-screen">
    <!-- ═══ MAIN CONTENT CONTAINER (FleetView.vue line 12 clone) ═══ -->
    <div class="relative z-10 mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
      <!-- ── Page header ── -->
      <div class="mb-8 flex items-center justify-between">
        <div>
          <h1 class="text-3xl font-bold text-white">💰 {{ t('menu.finance') }}</h1>
        </div>
        <div class="flex items-center gap-3">
          <button
            @click="router.push('/dashboard')"
            class="flex items-center gap-2 rounded-xl bg-white/10 px-4 py-2 text-sm text-white/80 transition-all duration-200 hover:bg-white/20 hover:text-white"
          >
            <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
            </svg>
            {{ t('garage.backToDashboard') }}
          </button>
        </div>
      </div>

      <!-- ── 4-Card Grid ── -->
      <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
        ...cards...
      </div>
    </div>
  </div>
</template>

Key changes:

  1. Outer wrapper: <div class="relative min-h-screen"> (replaces flex flex-col justify-end min-h-[85vh] pb-8)
  2. Content container: <div class="relative z-10 mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8"> — exact clone of FleetView:12
  3. Header stays nested inside the mx-auto container
  4. Grid: lg:grid-cols-4 instead of lg:grid-cols-5 (4 cards instead of 5)
  5. NO background divs (FinanceLayout provides them)

Same fix for other 3 finance views

FinanceWalletsView.vue, FinancePackagesView.vue, FinanceTransactionsView.vue — each needs the same structural fix: remove flex flex-col justify-start min-h-[85vh] py-8 wrapper and replace with relative min-h-screen + relative z-10 mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8.


STEP 3: LEDGER_STATUS ENUM FIX

3A: The Enum Definition

audit.py:

class LedgerStatus(str, enum.Enum):
    PENDING = "PENDING"
    SUCCESS = "SUCCESS"
    FAILED = "FAILED"
    REFUNDED = "REFUNDED"
    REFUND = "REFUND"

3B: The Seed Script (BROKEN)

seed_financial_ledger.py:20:

DB_STATUSES = ["pending", "completed", "failed", "cancelled"]

Mapping to valid enum values:

Seed value Valid Enum Reason
pending PENDING Case fix only
completed SUCCESS Closest semantic match (completed payment = success)
failed FAILED Case fix only
cancelled REFUNDED Cancelled payments are typically refunded

3C: Fix Plan

Fix A — Seed script:

DB_STATUSES = ["PENDING", "SUCCESS", "FAILED", "REFUNDED"]

Fix B — Database cleanup SQL:

UPDATE audit.financial_ledger SET status = 'PENDING'  WHERE status::text = 'pending';
UPDATE audit.financial_ledger SET status = 'SUCCESS'  WHERE status::text = 'completed';
UPDATE audit.financial_ledger SET status = 'FAILED'   WHERE status::text = 'failed';
UPDATE audit.financial_ledger SET status = 'REFUNDED' WHERE status::text = 'cancelled';

STEP 4: CODE MODE HAND-OFF — Task List

Task 1: Restructure FinanceMainView layout (FleetView clone)

File: frontend_app/src/views/FinanceMainView.vue

Replace the entire <template> section. The current outer structure:

<div class="flex flex-col justify-end min-h-[85vh] pb-8">
  <div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 w-full">
    <!-- header inside container (already correct from previous fix) -->
    <!-- grid: lg:grid-cols-5 -->
  </div>
</div>

Replace with:

<div class="relative min-h-screen">
  <div class="relative z-10 mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
    <!-- header (same as current, already correct) -->
    <!-- grid: change lg:grid-cols-5 → lg:grid-cols-4 -->
  </div>
</div>
  1. Change the outermost <div>: remove flex flex-col justify-end min-h-[85vh] pb-8 → add relative min-h-screen
  2. Change the content container: mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 w-fullrelative z-10 mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8 (add relative z-10 and py-8, remove w-full)
  3. Change all card grid: lg:grid-cols-5lg:grid-cols-4 (4 cards, not 5)
  4. Also change Card 1: remove lg:col-span-2 since on a 4-col grid each card gets 1 column

Task 2: Restructure FinanceWalletsView layout

File: frontend_app/src/views/FinanceWalletsView.vue

Same structural change:

  • Outer: flex flex-col justify-start min-h-[85vh] py-8relative min-h-screen
  • Inner content: mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 w-fullrelative z-10 mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8

Task 3: Restructure FinancePackagesView layout

File: frontend_app/src/views/FinancePackagesView.vue

Same structural change as Task 2.

Task 4: Restructure FinanceTransactionsView layout

File: frontend_app/src/views/FinanceTransactionsView.vue

Same structural change as Task 2.

Task 5: Fix seed_financial_ledger.py ledger_status enum (3A)

File: backend/scripts/seed_financial_ledger.py:20

Change:

DB_STATUSES = ["pending", "completed", "failed", "cancelled"]

To:

DB_STATUSES = ["PENDING", "SUCCESS", "FAILED", "REFUNDED"]

Task 6: Fix existing DB ledger_status bad data (3B)

Run SQL:

docker compose exec shared-postgres psql -U service_finder_app -d service_finder -c "
UPDATE audit.financial_ledger SET status = 'PENDING'  WHERE status::text = 'pending';
UPDATE audit.financial_ledger SET status = 'SUCCESS'  WHERE status::text = 'completed';
UPDATE audit.financial_ledger SET status = 'FAILED'   WHERE status::text = 'failed';
UPDATE audit.financial_ledger SET status = 'REFUNDED' WHERE status::text = 'cancelled';
SELECT status::text, COUNT(*) as cnt FROM audit.financial_ledger GROUP BY status ORDER BY status;
"

Task 7: Full verification

  1. Frontend build:

    docker compose exec sf_public_frontend npm run build 2>&1 | tail -5
    
  2. Backend wallet balance API (no enum crash):

    docker compose exec sf_api python3 -c "
    import requests, json
    r = requests.post('http://localhost:8000/api/v1/auth/login', data={'username': 'admin@profibot.hu', 'password': 'Admin123!'})
    token = r.json()['access_token']
    resp = requests.get('http://localhost:8000/api/v1/billing/wallet/balance', headers={'Authorization': f'Bearer {token}'})
    print(f'Status: {resp.status_code}')
    if resp.status_code == 200:
        d = resp.json()
        print(f'total={d.get(\"total\")} earned={d.get(\"earned\")}')
    else:
        print(f'ERROR: {resp.text}')
    "
    

📋 Summary

# Task File(s)
1 Clone FleetView layout to FinanceMainView FinanceMainView.vue
2 Clone FleetView layout to FinanceWalletsView FinanceWalletsView.vue
3 Clone FleetView layout to FinancePackagesView FinancePackagesView.vue
4 Clone FleetView layout to FinanceTransactionsView FinanceTransactionsView.vue
5 Fix seed enum: ledger_status seed_financial_ledger.py:20
6 Fix DB: normalize ledger_status values PostgreSQL audit.financial_ledger
7 Verify: build + API Build + /billing/wallet/balance

⚠️ DO NOT MODIFY