felhasználói felületre pü
This commit is contained in:
307
plans/finance_layout_clone_and_enum_fix_2026-07-26.md
Normal file
307
plans/finance_layout_clone_and_enum_fix_2026-07-26.md
Normal file
@@ -0,0 +1,307 @@
|
||||
# 🔵 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`](frontend_app/src/views/vehicles/FleetView.vue) wrapped in [`OrganizationLayout.vue`](frontend_app/src/layouts/OrganizationLayout.vue)
|
||||
|
||||
### FleetView.vue DOM Hierarchy (Key Elements)
|
||||
|
||||
```html
|
||||
<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`](frontend_app/src/layouts/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`](frontend_app/src/layouts/FinanceLayout.vue) provides:
|
||||
- `BaseHeader` with `HeaderLogo` + `LanguageSwitcher` + `HeaderProfile`
|
||||
- **ALREADY HAS background** — `fixed 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):
|
||||
```html
|
||||
<!-- 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`](frontend_app/src/views/FinanceMainView.vue):
|
||||
|
||||
```html
|
||||
<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`](frontend_app/src/views/FinanceWalletsView.vue), [`FinancePackagesView.vue`](frontend_app/src/views/FinancePackagesView.vue), [`FinanceTransactionsView.vue`](frontend_app/src/views/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`](backend/app/models/system/audit.py:70-75):
|
||||
```python
|
||||
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`](backend/scripts/seed_financial_ledger.py:20):
|
||||
```python
|
||||
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:**
|
||||
```python
|
||||
DB_STATUSES = ["PENDING", "SUCCESS", "FAILED", "REFUNDED"]
|
||||
```
|
||||
|
||||
**Fix B — Database cleanup SQL:**
|
||||
```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`](frontend_app/src/views/FinanceMainView.vue)
|
||||
|
||||
Replace the entire `<template>` section. The current outer structure:
|
||||
```html
|
||||
<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:
|
||||
```html
|
||||
<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-full` → `relative 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-5` → `lg: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`](frontend_app/src/views/FinanceWalletsView.vue)
|
||||
|
||||
Same structural change:
|
||||
- Outer: `flex flex-col justify-start min-h-[85vh] py-8` → `relative min-h-screen`
|
||||
- Inner content: `mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 w-full` → `relative 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`](frontend_app/src/views/FinancePackagesView.vue)
|
||||
|
||||
Same structural change as Task 2.
|
||||
|
||||
### Task 4: Restructure FinanceTransactionsView layout
|
||||
|
||||
**File:** [`frontend_app/src/views/FinanceTransactionsView.vue`](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`](backend/scripts/seed_financial_ledger.py:20)
|
||||
|
||||
Change:
|
||||
```python
|
||||
DB_STATUSES = ["pending", "completed", "failed", "cancelled"]
|
||||
```
|
||||
To:
|
||||
```python
|
||||
DB_STATUSES = ["PENDING", "SUCCESS", "FAILED", "REFUNDED"]
|
||||
```
|
||||
|
||||
### Task 6: Fix existing DB ledger_status bad data (3B)
|
||||
|
||||
Run SQL:
|
||||
```bash
|
||||
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:**
|
||||
```bash
|
||||
docker compose exec sf_public_frontend npm run build 2>&1 | tail -5
|
||||
```
|
||||
|
||||
2. **Backend wallet balance API (no enum crash):**
|
||||
```bash
|
||||
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`](frontend_app/src/views/FinanceMainView.vue) |
|
||||
| 2 | Clone FleetView layout to FinanceWalletsView | [`FinanceWalletsView.vue`](frontend_app/src/views/FinanceWalletsView.vue) |
|
||||
| 3 | Clone FleetView layout to FinancePackagesView | [`FinancePackagesView.vue`](frontend_app/src/views/FinancePackagesView.vue) |
|
||||
| 4 | Clone FleetView layout to FinanceTransactionsView | [`FinanceTransactionsView.vue`](frontend_app/src/views/FinanceTransactionsView.vue) |
|
||||
| 5 | Fix seed enum: `ledger_status` | [`seed_financial_ledger.py:20`](backend/scripts/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
|
||||
|
||||
- [`FleetView.vue`](frontend_app/src/views/vehicles/FleetView.vue) — reference pattern
|
||||
- [`OrganizationLayout.vue`](frontend_app/src/layouts/OrganizationLayout.vue) — reference pattern
|
||||
- [`FinanceLayout.vue`](frontend_app/src/layouts/FinanceLayout.vue) — already correct (provides background)
|
||||
- [`BaseHeader.vue`](frontend_app/src/components/layout/BaseHeader.vue) — working
|
||||
- [`router/index.ts`](frontend_app/src/router/index.ts) — correct
|
||||
Reference in New Issue
Block a user