# Service Finder Fejlesztési Történet ## 2026-06-21 - P0 Deep Audit: Database Consistency & Zombie API Hunt ### 🎯 Cél Teljes körű adatbázis konzisztencia ellenőrzés és zombie API végpontok felderítése a `vehicle`, `finance`, `fleet_finance` sémákban, mielőtt a frontend fejlesztés elkezdődik. ### 🔧 Eredmények **1. ADATBÁZIS TISZTASÁG:** ✅ PASS - API modul import: ✅ Sikeres (2 route: GET, POST) - Sync Engine: ✅ 1210 OK, 0 Fixed, 0 Extra - E2E test: ⚠️ Pre-existing conftest hiba (verification token timeout - nem kapcsolódó) ## 2026-06-23 - Cost Entry Wizard (CostEntryWizard.vue) - 4-lépéses Számla Űrlap ### 🎯 Cél 4-lépéses stepper wizard építése részletes számla/invoice költségek rögzítésére a CostsActionsCard-ból indíthatóan. ### 🔧 Módosított fájlok - **`frontend/src/components/cost/CostEntryWizard.vue`** (ÚJ) - 4-step stepper wizard komponens - **`frontend/src/components/dashboard/CostsActionsCard.vue`** - "🧾 Részletes Számla" gomb hozzáadva, CostEntryWizard import és modal state - **`frontend/src/i18n/en.ts`** - costWizard i18n szekció hozzáadva - **`frontend/src/i18n/hu.ts`** - costWizard i18n szekció hozzáadva ### 🧩 CostEntryWizard lépések 1. **Alapadatok**: Jármű (read-only), kategória cascade (fő+alkategória), dátum 2. **Pénzügyek**: Nettó összeg, ÁFA kulcs (0/5/10/20/27%), Bruttó összeg (GROSS-FIRST), Pénznem 3. **Admin & Szállító**: Dinamikus vendor autocomplete (GET /organizations?org_type=SERVICE_PROVIDER) szabad szöveges fallbackkel, számlaszám, számla dátuma, fizetési határidő 4. **Fájlok**: Drag & drop fájl feltöltő UI (csak UI szintű file picker) ### 🔌 API Integráció - POST `/expenses/` a `costStore.addExpense()`-on keresztül AssetCostBase payload-dal - Payload tartalmazza: amount_gross (GROSS-FIRST), category_id, currency, date, data JSONB (net_amount, vat_rate, invoice_number, invoice_date, payment_deadline, vendor_id, vendor_name, file_names) ### ✅ Verifikáció - Vite build: ✅ Sikeres (253 modules, 6.94s) - Gitea kártya: #277 ## 2026-06-23 - Dashboard Cost Card Navigation Fix & Dedicated Costs Page ### 🎯 Cél A dashboard költség kártya üres területére kattintva és a "További költségek" gombbal is a költségek oldalra navigálás. Dedikált CostsView oldal létrehozása vissza gombbal és garázs háttérrel. ### 🔧 Módosított fájlok - **`frontend/src/views/costs/CostsView.vue`** (ÚJ) - Teljes költség oldal garázs háttérrel, vissza gombbal, költség táblázattal és paginációval - **`frontend/src/router/index.ts`** - `/dashboard/costs` route hozzáadva a CostsView-hoz - **`frontend/src/components/dashboard/CostsActionsCard.vue`** - Header bar kattinthatóvá téve + "További költségek" gomb átirányítva a `/dashboard/costs` oldalra - **`frontend/src/layouts/PrivateLayout.vue`** - Hamburger menü "Költségek" navigáció `/dashboard/costs`-ra módosítva - **`frontend/src/i18n/hu.ts`** - `costs.backToDashboard` kulcs hozzáadva - **`frontend/src/i18n/en.ts`** - `costs.backToDashboard` kulcs hozzáadva ### ✅ Verifikáció - Vite build: ✅ Sikeres (CostsView-DaFsqPnD.js chunk generálva) ## 2026-06-23 - Hotfix: Backend Expenses GET / endpoint & AssetCost.organization FK fix ### 🎯 Cél Két kritikus backend hiba javítása: 1. A `GET /api/v1/expenses/` hívás 404-et adott (nem létezett `GET /` végpont), amit a reverse proxy 307-es HTTPS→HTTP átirányítással válaszolt, ami Mixed Content blokkolást okozott a böngészőben. 2. A backend indításkor `InvalidRequestError`-ral összeomlott az `AssetCost.organization` relationship hibás konfigurációja miatt (két FK ugyanarra a táblára, de a `foreign_keys` paraméter hiányzott). ### 🔧 Módosított fájlok - **`backend/app/api/v1/endpoints/expenses.py`** - `GET /` végpont hozzáadva: list_all_expenses() - szervezet összes költségének listázása paginációval, Asset, CostCategory, Organization JOIN-okkal - **`backend/app/models/fleet_finance/models.py`** - `AssetCost.organization` relationship javítva: `foreign_keys=[organization_id]` paraméter hozzáadva a kétértelmű FK kapcsolat feloldásához ### 🔧 Eredmények - Backend konténer: ✅ Tisztán indul, nincs SQLAlchemy hiba - Login: ✅ Működik (nem omlik össze) - `GET /api/v1/expenses/`: ✅ Végpont elérhető, paginált költség listát ad vissza ## 2026-06-23 - Hotfix #2: Expenses API 307 redirect / Mixed Content - trailing slash fix ### 🎯 Cél A `GET /api/v1/expenses` hívás 307-es HTTPS→HTTP átirányítást kapott, mert a backend route `@router.get("/")` (perjellel) volt definiálva, de a frontend `/expenses` (perjel nélkül) hívta. A Starlette automatikus 307 redirect-je a külső openresty proxy miatt `http://` címmé alakult → Mixed Content blokk. ### 🔧 Módosított fájlok - **`backend/app/api/v1/endpoints/expenses.py`** - `@router.get("/")` → `@router.get("")` (perjel eltávolítva a route-ból) ### 🔧 Eredmények - Backend konténer: ✅ Tisztán indul - `GET /api/v1/expenses` most direkt egyezik a route-tal → nincs 307 redirect → nincs Mixed Content ## 2026-06-23 - Hotfix #3: Expenses API 500 Internal Server Error - AssetCost.cost_date → AssetCost.date ### 🎯 Cél A `GET /api/v1/expenses` végpont 500-as hibát dobott: `AttributeError: type object 'AssetCost' has no attribute 'cost_date'`. Az `AssetCost` modellben a mező neve `date` (110. sor), de a kód `cost_date`-t használt. ### 🔧 Módosított fájlok - **`backend/app/api/v1/endpoints/expenses.py`** - 2 helyen javítva: - 157. sor: `AssetCost.cost_date` → `AssetCost.date` - 193. sor: `cost.cost_date.isoformat()` → `cost.date.isoformat()` ### 🔧 Eredmények - Backend konténer: ✅ Tisztán indul - `GET /api/v1/expenses`: ✅ Várhatóan 200 OK (nem 500) --- ## 2026-06-23: Dashboard üres AdPlacementWidget elrejtése ### 🎯 Cél A felhasználó kérésére: a dashboardon a "PRO" feliratú `SubscriptionStatusWidget` mellett egy üres csempe volt látható (`AdPlacementWidget`), mert nincs hirdetés beállítva a rendszerben. A kérés az volt, hogy rejtsük el ezt az üres csempét. ### 🔧 Módosított fájlok - **`frontend/src/components/dashboard/AdPlacementWidget.vue`** - `defineEmits` hozzáadva: `ads-loaded` esemény, amely jelzi a szülőnek, hogy van-e hirdetés (`hasAds: boolean`). Az esemény a `fetchAds` siker és hiba ágában is meghívásra kerül. - **`frontend/src/views/DashboardView.vue`** - `adWidgetHasAds` ref hozzáadva (alapértelmezett: `false`). A hirdetési csempe wrapper `
`-je `v-if="adWidgetHasAds"` feltételt kapott, így csak akkor jelenik meg, ha az API ténylegesen adott vissza hirdetéseket. Az `@ads-loaded` esemény frissíti a ref értékét. ### ✅ Verifikáció - Frontend build: ✅ Sikeres (Vite build, 0 hiba) ## 2026-06-23 - P0 Fix: cost_date vs date mezőnév mismatch + CostsView.vue upgrade ### 🎯 Cél Két produkciós hiba javítása a cost rögzítésben: 1. **P0 - 500 Internal Server Error** POST `/api/v1/expenses/` végponton: négyrétegű mezőnév-eltérés (`cost_date` vs `date`) a frontend, Pydantic séma, endpoint és SQLAlchemy model között. 2. **P1 - `/dashboard/costs` oldal** nem mutatott semmilyen információt és nem volt költség hozzáadási lehetőség. ### 🔧 Módosított fájlok **Fix 1a - Backend endpoint** (`backend/app/api/v1/endpoints/expenses.py:464`): - `cost_date=expense.cost_date` → `date=expense.cost_date` (SQLAlchemy model mezőneve `date`) **Fix 1b - Backend Pydantic schema** (`backend/app/schemas/asset_cost.py:37`): - `validation_alias="date"` hozzáadva a `cost_date` mezőhöz, hogy mind a `date`, mind a `cost_date` kulcsot elfogadja **Fix 2 - Frontend CostsView.vue** (`frontend/src/views/costs/CostsView.vue`): - Vezérlősáv hozzáadva járműszűrő dropdown-nal - "➕ Új Költség" gomb hozzáadva - CostEntryWizard integráció (modal formában) - Mezőnevek javítva: `cost_type` → `category_name`, `amount` → `amount_gross`, `vehicle_label` → `vehicle_name` - `useVehicleStore` importálva a járművek listájához ### ✅ Verifikáció - Python szintaxis: ✅ asset_cost.py OK, expenses.py OK - Backend indítás: ✅ Uvicorn fut, nincs hiba - Frontend build: ✅ Sikeres (Vite build 6.77s, 0 hiba) - Gitea kártyák: #278 (P0) és #279 (P1) lezárva ## 2026-06-23 - #280 Vizsgálat: Miért nem jelennek meg költségek? ### 🎯 Cél Annak kivizsgálása, hogy az admin@profibot.hu teszt felhasználó miért nem lát költségeket. ### 🔍 Vizsgálat - `fleet_finance.asset_costs` táblában összesen **1 rekord** van (org_id=43, asset=PTB162 Mazda 2, 18118 HUF, "Finanszírozás") - admin@profibot.hu (user_id=2) tagja: org 1 (Test Company), 57, 58, 62, 67 - admin **NEM tagja** org 43-nak ("Accipe garage"), ahova az egyetlen költség tartozik - admin szervezeteiben (1, 57, 58, 62, 67) összesen **0 db költség** van ### ✅ Következtetés **NINCS backend/frontend hiba.** A probléma egyszerű **adathiány**: 1. Nincs rögzítve költség admin egyetlen járművéhez sem 2. Az egyetlen DB-ben lévő költség egy másik szervezethez tartozik 3. A #278 és #279 javítások után most már lehetővé vált a költségrögzítés - Dokumentáció: `/opt/docker/docs/cost_visibility_investigation_280.md` ## 2026-06-23 - #281 Hotfix: Hiányos #278 javítás - expenses.py:533 new_cost.cost_date → new_cost.date ### 🎯 Cél A #278-as javítás hiányos volt: a konstruktor paramétert kijavítottuk (expenses.py:464: cost_date= → date=), de a response dict-ben (expenses.py:533) továbbra is `new_cost.cost_date`-et használtunk az SQLAlchemy AssetCost modellen, aminek a mezőneve `date`. Ez `AttributeError: 'AssetCost' object has no attribute 'cost_date'` hibát okozott minden POST /api/v1/expenses/ híváskor. ### 🔧 Módosított fájlok - **`backend/app/api/v1/endpoints/expenses.py:533`** - `new_cost.cost_date.isoformat()` → `new_cost.date.isoformat()` ### ✅ Verifikáció - Python szintaxis: ✅ OK - Backend újraindítás: ✅ OK (Application startup complete) - POST /api/v1/expenses/ teszt: ✅ **201 Created** - sikeres költség rögzítés a QWE432 járműre - Response tartalmazza: `"date":"2026-06-23T13:07:34.785065+00:00"` (helyes) - Gitea kártya: #281 lezárva ## 2026-06-23 - P0 Fix: User 28 Data Anomaly Resolution ### 🎯 Cél User 28 (tester_pro@profibot.hu) adat-anomália javítása ORM szkript segítségével. ### 🔧 Végrehajtott műveletek **A) Org 1 javítása:** `fleet.organizations` ID=1 org_type átállítva `fleet_owner` → `individual` **B) Tag hozzáadása:** `fleet.organization_members` rekord létrehozva: org=1, user=28, role=OWNER, status=active. Org 1 owner_id=28 beállítva. **C) Scope törlése:** User 28 `scope_level` visszaállítva `individual`-ra (NOT NULL constraint miatt), `scope_id` None-ra. **D) Fantom garázs törlése:** Org 68 ("Tester Garázsa") és hozzá tartozó OrganizationMember rekordok törlése. ### ✅ Verifikáció - Org 1: org_type=individual, owner_id=28 - Org 1 Member: role=OWNER, status=active, is_verified=True - User 28: scope_level=individual, scope_id=None - Org 68: nem létezik (deleted) - Ideiglenes szkript törölve: `backend/scripts/fix_user_28.py` ## 2026-06-23 - P0 Cost Pipeline Visibility Audit (#282) ### 🔍 Felfedezés A `/dashboard/costs` oldal üres User 28 számára, annak ellenére, hogy Org 1-ben 5 db asset_cost rekord van (BMW123, QWE432). ### 🐛 Gyökér Ok A `GET /expenses/` endpoint (`backend/app/api/v1/endpoints/expenses.py:130-139`) a user első aktív tagságát használja org feloldáshoz (`.limit(1)` ORDER BY nélkül). User 28-nak 3 tagsága van: org 63 (ADMIN, nincs költség), org 21 (OWNER), org 1 (OWNER, 5 költség). Az első tagság org 63-ra mutat, ami üres. ### 📄 Dokumentáció `docs/cost_pipeline_audit.md` - Teljes pipeline audit a frontendtől a DB-ig. ## 2026-06-23 - P0 Architecture Audit Fixes: Vendor Leak & Expense Priority ### 🎯 Cél Az Architect által auditált P0 hibák kijavítása: vendor org szivárgás megszüntetése, expense organization_id prioritás javítása, frontend payload kiegészítése vendor_organization_id-val. ### 🔧 Módosított fájlok - **`backend/app/services/provider_service.py`** (632-651. sor) - `quick_add_provider`: Eltávolítva az OrganizationMember létrehozás. A létrehozó user NEM lesz tagja a beszállító szervezetének. Owner_id=None marad. - **`backend/app/api/v1/endpoints/expenses.py`** (398-429. sor) - `create_expense`: Átírva az organization_id feloldási prioritás: 1) asset.current_organization_id, 2) asset.owner_org_id, 3) user active org membership fallback. - **`frontend/src/components/cost/CostEntryWizard.vue`** (690-714. sor) - `vendor_organization_id` és `external_vendor_name` root szintű payload mezők hozzáadva. - **`frontend/src/stores/cost.ts`** - `AddExpensePayload` interface kiegészítve `vendor_organization_id` és `external_vendor_name` mezőkkel; `addExpense()` body-ba is átadva. ### 🗄️ Adatbázis Cleanup - **`backend/scripts/fix_vendor_leak.py`** (ideiglenes, futás után törölve) - A) Törölve `fleet.organization_members` rekord (org_id=63, user_id=28) - phantom ADMIN jog megvonva - B) Javítva `fleet_finance.asset_costs` rekord: organization_id=63 → 21, vendor_organization_id=63 beállítva ### ✅ Verifikáció - Backend restart: ✅ Sikeres - Python syntax check: ✅ provider_service.py OK, expenses.py OK - Vite build: ✅ Sikeres (255 modules, 6.97s) ## 2026-06-23 - P0 Tenant Isolation & Vehicle Mapping Audit ### Scope Full-stack audit of vehicle dropdown tenant isolation failure in CostsView.vue ### Elemzett fájlok - `backend/app/api/v1/endpoints/assets.py` - GET /assets/vehicles (229-318) - `frontend/src/views/costs/CostsView.vue` - Vehicle dropdown & org switch (330-565) - `frontend/src/stores/vehicle.ts` - fetchVehicles() (141-158) - `frontend/src/stores/auth.ts` - switchOrganization() & active_organization_id (687-717) - `frontend/src/stores/cost.ts` - defense-in-depth org injection (71) ### Adatbázis: tester_pro (User ID: 28) - 2 organization: Test Company (ID:1, 19 vehicles) + Private_28 (ID:21, 6 vehicles) = 25 total - Schema: identity.users, fleet.organization_members, fleet.organizations, vehicle.assets ### Root Cause Frontend cache staleness: vehicles load once in onMounted(), never refresh on org switch. The watch on active_organization_id only re-fetches costs, not vehicles. ### Verdict Backend filtering is correct (JWT scope_id). Database schema is correct. Fix requires adding `vehicleStore.fetchVehicles()` to the org switch watch in CostsView.vue:549. ### Report `docs/p0_tenant_isolation_vehicle_mapping_audit_report.md` ## 2026-06-23 - P0 Tenant Isolation Fix: CostsView.vue org switch watcher ### 🎯 Cél Frontend tenant isolation fix: garázsváltáskor a CostsView.vue watch blokkja most már reseteli a jármű szűrőt (`selectedVehicleFilter.value = null`), újratölti a járműveket az új garázs scope-jával (`vehicleStore.fetchVehicles()`), és frissíti a költségeket. ### 🔧 Módosított fájlok - `frontend/src/views/costs/CostsView.vue` — watch blokk kiegészítése: jármű szűrő reset + vehicleStore.fetchVehicles() hívás ### ✅ Verifikáció - Vite build: ✅ Sikeres (0 hiba) - `vehicleStore.fetchVehicles()` mindig küld GET kérést (nincs belső cache guard) ## 2026-06-23 - P0 EXECUTION: UI Switcher, Subscription Widget & Menu Alignment ### 🎯 Cél A P0 audit riportban azonosított hibák kijavítása: garázsválasztó szűrés, előfizetés widget jármű limit megjelenítés, mobil menü igazítás, backend admin jogosultság javítás. ### 🔧 Változtatások **1. HeaderCompanySwitcher.vue — Garázsválasztó javítás** - Eltávolítva az `org_type !== 'individual'` szűrő a `companyOrganizations` computed property-ből - Létrehozva új `individualOrganizations` computed property a privát garázsokhoz - Dropdown most két csoportra van osztva: "👤 Saját garázsok" (individual) és "🏢 Céges garázsok" (business) - Privát garázsokra kattintva `switchOrganization()` hívódik, majd `/dashboard` navigáció - Eltávolítva a keménykódolt "Private Garage" gomb — helyette dinamikus lista **2. SubscriptionStatusWidget.vue — Jármű limit megjelenítés** - Hozzáadva `useVehicleStore` import és `vehicleCount` computed property - Hozzáadva `maxVehicles` computed property (org vagy user szintről) - Második progress bar a jármű telítettséghez (🚗 Járművek: X / Y) - Színkódolt sáv: zöld (<75%), sárga (75-90%), piros (>90%) - Ha nincs limit (0 vagy null): "Korlátlan" felirat - Dátum formázás és lejárati információ hozzáadva **3. PrivateLayout.vue — Mobil menü igazítás** - "Költségek" gombhoz hozzáadva `justify-end` és `text-right` osztályok - A gomb ikonja és szövege jobbra igazítva **4. organizations.py — Backend admin jogosultság javítás** - `PUT /{org_id}/subscription` végpontról eltávolítva a `RequireSystemCapability(Capability.CAN_MANAGE_SUBSCRIPTIONS)` függőség - Helyette `_check_org_admin_access(org_id, current_user.id, db)` hívás — így org ADMIN/OWNER is kezelheti a saját előfizetését **5. organization.ts — TypeScript típus javítás** - `org_type` mező kötelezővé téve (eltávolítva a `?` optional flag) ### ✅ Verifikáció - Vite build: ✅ Sikeres (6.75s, 0 hiba) - Backend Python szintaxis: ✅ Sikeres - API konténer újraindítás: ✅ Sikeres ## 2026-06-23 - P0 HOTFIX: Cost Wizard Edit Mode Bug (POST vs PUT) ### 🎯 Cél A CostEntryWizard szerkesztés módban POST helyett PUT hívást indítson, hogy ne hozzon létre duplikátumot. ### 🔧 Módosított fájlok 1. **`backend/app/schemas/asset_cost.py`** - Új `AssetCostUpdate` Pydantic schema (minden mező opcionális) 2. **`backend/app/api/v1/endpoints/expenses.py`** - Új `PUT /expenses/{expense_id}` végpont a meglévő költségrekordok módosítására 3. **`frontend/src/stores/cost.ts`** - Új `updateExpense(id, payload)` action a store-ban, ami `PUT /expenses/{id}`-t hív 4. **`frontend/src/components/cost/CostEntryWizard.vue`** - `handleSubmit()` logika javítva: ha `props.editCost.id` létezik, `updateExpense()`-t hív, egyébként `addExpense()`-t ### 🗑️ Adatbázis cleanup - Duplikált rekord törölve: `55214098-74be-4261-a101-7fd9159e10d8` (asset_id=`deb42aea-1f48-4a70-85b5-ba451d005577`, amount_gross=5500.00) ### ✅ Verifikáció - Vite build: ✅ Sikeres (7.09s, 255 module, 0 hiba) - Backend Python AST parse: ✅ Sikeres (expenses.py, asset_cost.py) - `AssetCostUpdate` schema import: ✅ Sikeres (14 field) - Duplikátum törlés: ✅ Sikeres ## 2026-06-23 - P0 Final Polish: Wizard UX & Menu Alignment ### 🎯 Cél Három kritikus UI hiba javítása: dátum hydratáció Edit módban, Fizetési Mód logika és UI átrendezés, mobil menü jobbra igazítás. ### 🔧 Módosított fájlok 1. **`frontend/src/components/cost/CostEntryWizard.vue`** - **Date Hydration Fix (watch block):** `form.invoiceDate` és `form.paymentDeadline` most már mindig érvényes `YYYY-MM-DD` stringet kap (vagy `''` ha null). Két forrást is ellenőriz: `data.invoice_date` (JSONB) és `editData.invoice_date` (top-level). Használ `rawDate.split('T')[0] || rawDate.slice(0, 10) || ''` fallback láncot. - **Payment Method UI áthelyezés:** A `