662 lines
42 KiB
Markdown
662 lines
42 KiB
Markdown
# Service Finder Fejlesztési Történet
|
||
|
||
## 2026-06-14 - Admin Search Bugs Fix & Sticky UX
|
||
|
||
### 🎯 Cél
|
||
Backend SQL hibák javítása a GET /admin/users végponton (Address outerjoin, phone search), valamint frontend UX fejlesztések (sticky bulk action bar, clear/X gomb, üres állapot üzenet, HeaderProfile az AdminLayout-ban).
|
||
|
||
### 🔧 Változtatások
|
||
|
||
**1. BACKEND - [`admin.py`](backend/app/api/v1/endpoints/admin.py:502):**
|
||
- **Kritikus SQL javítás:** A `selectinload` helyett explicit `outerjoin` + `contains_eager` használata a `Person` és `Address` táblákhoz. A `selectinload` külön query-ben tölti be a kapcsolódó adatokat, így a `WHERE` feltételek a `Person.phone`, `Person.first_name` stb. oszlopokra nem működtek (500-as hiba).
|
||
- **Address keresés javítás:** Az `Address.zip` és `Address.city` Python property-k, nem DB oszlopok. A tényleges SQL lekérdezésben a `GeoPostalCode.zip_code` és `GeoPostalCode.city` oszlopokat kell használni. Ehhez egy 3. outerjoin került a `GeoPostalCode` táblára.
|
||
- **Phone search:** A `query = query.where(Person.phone.ilike(...))` értékadás most már működik, mert a `Person` tábla explicit outerjoin-olva van.
|
||
- **404 hiba:** Nem volt 404-es hiba az üres találatnál - a végpont helyesen 200 OK-val és üres listával tér vissza.
|
||
|
||
**2. FRONTEND - [`AdminUsersView.vue`](frontend/src/views/admin/AdminUsersView.vue):**
|
||
- **Sticky Bulk Action Bar:** `sticky top-0 z-20 bg-gray-800 shadow-lg` osztályok hozzáadva, hogy görgetésnél a táblázat tetején tapadjon.
|
||
- **Clear/X gomb:** A kereső input mezőbe egy X gomb került (csak akkor látszik, ha van szöveg), ami üríti a `searchQuery`-t és alapállapotba állítja a listát.
|
||
- **clearSearch() metódus:** Új metódus, ami nullázza a keresési paramétereket és újratölti a listát.
|
||
- **Üres állapot:** Barátságos üzenet ikonnal és "Keresés törlése" gombbal, ha nincs találat.
|
||
|
||
**3. FRONTEND - [`AdminLayout.vue`](frontend/src/layouts/AdminLayout.vue):**
|
||
- **HeaderProfile komponens:** Importálva és elhelyezve a top bar jobb oldalán a `LanguageSwitcher` és `ModeSwitcher` mellett. Ezzel az admin felületen is látszik a felhasználó neve, profilba lépés és kilépés lehetősége.
|
||
|
||
### ✅ Eredmény
|
||
- Python szintaxis ellenőrzés: OK
|
||
- Backend SQL lekérdezések: outerjoin-ök helyesen használva, nincs 500-as hiba keresésnél
|
||
- Frontend: sticky, clear gomb, üres állapot, HeaderProfile mind implementálva
|
||
|
||
## 2026-06-14 - 405 DELETE Debugging & Fix
|
||
|
||
### 🎯 Cél
|
||
A `DELETE /api/v1/users/me` végpont 405 Method Not Allowed hibát dobott. Felderíteni a hiba okát és javítani.
|
||
|
||
### 🔍 Vizsgálat lépései
|
||
|
||
**1. LÉPÉS - Végpont fizikai ellenőrzése ([`users.py`](backend/app/api/v1/endpoints/users.py:502)):**
|
||
- A `@router.delete("/me", status_code=200)` dekorátor létezik, helyes útvonallal (`/me`, nincs perjel a végén)
|
||
- A végpont implementálva van, meghívja az `AuthService.soft_delete_user()` függvényt
|
||
- A router listában a DELETE `/me` regisztrálva van
|
||
|
||
**2. LÉPÉS - CORS és Proxy ellenőrzése:**
|
||
- CORS: `allow_methods=["*"]` - minden metódus engedélyezve
|
||
- Nginx proxy: `location /api/` blokk minden kérést továbbít, nincs metódus-szűrés
|
||
- Router bekötés: `users.router` a `/users` prefix alá kötve
|
||
|
||
**3. LÉPÉS - Belső tesztelés:**
|
||
- Közvetlen teszt a konténerben (`localhost:8000`, proxy-t megkerülve) szintén 405-öt adott
|
||
- A konténer `--reload` nélkül indult, így a kód módosításai nem léptek életbe
|
||
- **Megoldás:** `docker compose restart sf_api` után a DELETE `/me` **200 OK** választ adott
|
||
|
||
### ✅ Eredmény
|
||
- A 405-ös hibát **nem a kód**, hanem a konténer újraindításának hiánya okozta
|
||
- A `DELETE /api/v1/users/me` végpont a `tester_pro2@profibot.hu` fiókkal tesztelve **200 OK** választ ad
|
||
- A soft-delete funkció helyesen anonimizálja az email címet és inaktiválja a felhasználót
|
||
- Teszt után a `tester_pro2@profibot.hu` fiók visszaállításra került
|
||
|
||
## 2026-06-13 - Emergency Fix: Vehicle Creation 500 Error (FK Violation on catalog_id)
|
||
|
||
### 🎯 Cél
|
||
A `POST /api/v1/assets/vehicles` végpont 500 Internal Server Error-t dobott új jármű rögzítésekor. A hiba oka az `AssetMatcherService` által visszaadott `VehicleModelDefinition.id` közvetlen hozzárendelése volt az `Asset.catalog_id` mezőhöz, amelynek FK-ja a `vehicle.vehicle_catalog` (`AssetCatalog`) táblára mutat, nem a `vehicle.vehicle_model_definitions` táblára.
|
||
|
||
### 🔧 Változtatások
|
||
|
||
**1. `backend/app/services/asset_service.py` (228-255. sorok):**
|
||
- A matcher integrációs blokkban a `new_asset.catalog_id = matched_def.id` sor kicserélve.
|
||
- Az új logika először megkeresi a `VehicleModelDefinition`-hez tartozó `AssetCatalog` rekordot (`master_definition_id` alapján).
|
||
- Ha nem létezik, automatikusan létrehozza a megfelelő `AssetCatalog` bejegyzést a definíció adataiból.
|
||
- Csak ezután állítja be a `catalog_id`-t a valódi `AssetCatalog.id`-ra.
|
||
|
||
### ✅ Eredmény
|
||
- A teszt `POST /api/v1/assets/vehicles` kérés `201 Created` státusszal tért vissza.
|
||
- A jármű `catalog_id: 1312975` (AssetCatalog ID) értékkel jött létre, adatgazdagítással (`engine_capacity: 176`, `power_kw: 13`, `data_status: enriched`).
|
||
- Nincs több ForeignKeyViolationError a logokban.
|
||
|
||
## 2026-06-08 - F5 Refresh Logout Bug Fix & HeaderLogo Contextual Navigation
|
||
|
||
### 🎯 Cél
|
||
Két frontend hiba javítása: (1) F5 oldalfrissítéskor a Vue Router guard hamarabb fut le, mint a Pinia Auth Store init() befejeződik, ami kijelentkezést okoz. (2) A HeaderLogo komponens fixen a /dashboard-ra navigált, nem vette figyelembe a /organization/:id útvonalat.
|
||
|
||
### 🔧 Változtatások
|
||
|
||
**1. `frontend/src/stores/auth.ts`:**
|
||
- Új `isInitialized` ref állapot (alapértelmezett: `false`) hozzáadva a store state-hez.
|
||
- Az `init()` függvény legvégén `isInitialized.value = true` beállítás, így a router guard meg tudja várni az inicializálás végét.
|
||
- Az `isInitialized` exportálva a return objektumban.
|
||
|
||
**2. `frontend/src/router/index.ts`:**
|
||
- A `beforeEach` guard elején ellenőrzés: ha `!authStore.isInitialized`, akkor `await authStore.init()` meghívása.
|
||
- Ezzel a router garantáltan megvárja a token kiolvasását és a user profil lekérését, mielőtt a `requiresAuth` ellenőrzést elvégezné.
|
||
|
||
**3. `frontend/src/components/header/HeaderLogo.vue`:**
|
||
- `useRoute()` importálva a Vue Router-ből.
|
||
- Quick Action gombok: már nem néma hibásak, figyelmeztetnek ha nincs jármű
|
||
- FUEL kategória: dinamikus feloldás API-ból, nem hardcoded ID
|
||
- OdometerReading tábla létrehozva a `vehicle` sémában
|
||
- CostCategory.min_tier oszlop hozzáadva `'free'` default értékkel
|
||
- subscription_service.py elkészítve (Gitea #239)
|
||
- AssetCost.document_id oszlop hozzáadva
|
||
- 20 CostCategory rekord tier beállítva
|
||
|
||
## 2026-06-12 - Dynamic Parameters Check & Centralized Odometer Implementation
|
||
|
||
### 🎯 Cél
|
||
1. Rendszerparaméter-tábla vizsgálata (no hardcoding elv érvényesítése)
|
||
2. Odometer (kilométeróra) automatikus bekötése a költségrögzítésbe
|
||
3. Valós km állás visszaadása a frontend felé
|
||
|
||
### 🔍 1. Rendszerparaméterek Vizsgálata
|
||
|
||
**Megállapítás:** A `system.system_parameters` tábla létezik és használatban van az alábbi struktúrával:
|
||
- `key` (VARCHAR) - paraméter kulcs
|
||
- `category` (VARCHAR) - kategória (pl. vehicle, finance, security)
|
||
- `value` (JSONB) - érték (tetszőleges JSON struktúra)
|
||
- `scope_level` (ENUM: global, organization, user) - hatókör
|
||
- `scope_id` (VARCHAR) - opcionális hatókör azonosító
|
||
- `is_active` (BOOLEAN) - aktív/inaktív flag
|
||
|
||
**Példa bejegyzések:** `VEHICLE_DRAFT_MAX_EXPENSES`, `VEHICLE_DRAFT_MAX_DAYS`, `VEHICLE_LIMIT`, `EXCHANGE_RATE_EUR_HUF`, `auth_min_password_length`, stb.
|
||
|
||
**Következtetés:** A 30 napos trial logika dinamikus paraméterezéséhez a `system.system_parameters` tábla használható. A trial periódus bevezetése előtt létre kell hozni egy `TRIAL_PERIOD_DAYS` kulcsú rekordot ebben a táblában.
|
||
|
||
### 🔧 2. Backend: Odometer bekötése (expenses.py)
|
||
|
||
**Módosított fájlok:**
|
||
- [`backend/app/api/v1/endpoints/expenses.py`](backend/app/api/v1/endpoints/expenses.py) - Odometer integráció hozzáadva
|
||
- [`backend/app/models/__init__.py`](backend/app/models/__init__.py) - `OdometerReading` export hozzáadva
|
||
- [`backend/app/models/vehicle/__init__.py`](backend/app/models/vehicle/__init__.py) - `OdometerReading` export hozzáadva
|
||
|
||
**Implementáció részletei:**
|
||
- Az `AssetCostCreate` séma már tartalmazza a `mileage_at_cost` mezőt
|
||
- A `create_expense` végpont most:
|
||
1. Létrehoz egy `OdometerReading` rekordot (`source="cost_entry"`, `cost_id=new_cost.id`) ha `mileage_at_cost` meg van adva
|
||
2. Frissíti az `Asset.current_mileage` mezőt, ha az új km állás nagyobb, mint a jelenlegi
|
||
- Az `OdometerReading` modell már létezett a `vehicle.odometer_readings` táblában (korábban nem volt exportálva a modell `__init__`-ből)
|
||
|
||
### ✅ 3. Frontend / API: Valós Km állás Visszaadása
|
||
|
||
**Megállapítás:** A teljes frontend-backend lánc már működik:
|
||
- `AssetResponse.current_mileage` (Pydantic schema) - tartalmazza a mezőt
|
||
- `GET /api/v1/assets/{id}` végpont - visszaadja a `current_mileage`-t
|
||
- `VehicleData` TypeScript típus - definiálja a `current_mileage` mezőt
|
||
- `VehicleDetailModal.vue` - "Alapadatok" fülön megjeleníti (`vehicle.current_mileage`)
|
||
- `VehicleCardStandard.vue` - kártyanézetben is megjelenik
|
||
|
||
### 📊 Összefoglalás
|
||
- A rendszerparaméterek dinamikus kezelése biztosított a `system.system_parameters` táblán keresztül
|
||
- Az OdometerReading automatikusan rögzítésre kerül minden költségbejegyzésnél, ahol `mileage_at_cost` meg van adva
|
||
- Az `Asset.current_mileage` mindig a legmagasabb rögzített km állást tükrözi
|
||
- A frontend valós időben látja a frissített km állást
|
||
|
||
## 2026-06-12 - Auth Registration 500 Error Fix & Container Startup Repair
|
||
|
||
### Cél
|
||
A `POST /api/v1/auth/register` végpont 500 Internal Server Error hibájának kijavítása. A hiba oka a PostgreSQL `audit.log_severity` enum és a Python `LogSeverity` enum közötti mismatch volt.
|
||
|
||
### Változtatások
|
||
|
||
**1. `backend/app/services/auth_service.py`:**
|
||
- `LogSeverity` enum import hozzáadva
|
||
- `severity="INFO"` → `severity=LogSeverity.info` (line 149)
|
||
- `severity="WARNING"` → `severity=LogSeverity.warning` (line 494)
|
||
|
||
**2. `backend/app/models/vehicle/vehicle.py`:**
|
||
- `CostCategory.__table_args__`: `extend_existing=True` hozzáadva
|
||
- `VehicleUserRating.id`: `UUID` → `PG_UUID` javítás (NameError)
|
||
|
||
**3. `backend/app/scripts/unified_db_sync.py`:**
|
||
- `dynamic_import_models()` átírva: egyszerű `import app.models`
|
||
|
||
**4. `backend/app/models/__init__.py`:**
|
||
- Import sorrend javítva: Organization/Branch a Rating elé került
|
||
|
||
### Eredmény
|
||
- `POST /api/v1/auth/register` → **201 Created** sikeres regisztráció
|
||
- `GET /health` → **200 OK** (database connected)
|
||
- Container stabilan fut, nincs restart loop
|
||
|
||
## 2026-06-12 - KYC Flow Bugfix & Repair (verify_email + Gamification commit)
|
||
|
||
### 🎯 Cél
|
||
Két kritikus hiba javítása a KYC (Know Your Customer) folyamatban, ami miatt a `gy.krisztina76@gmail.com` felhasználó nem tudott aktiválódni. A light regisztráció → email verifikáció → KYC kitöltés után nem jöttek létre a szükséges adatbázis kapcsolatok (Organization, Wallet, Branch, OrgMember, UserStats).
|
||
|
||
### 🔧 Változtatások
|
||
|
||
**1. `backend/app/services/auth_service.py` - `verify_email()` metódus (320-359. sor):**
|
||
- **Bug:** A Person rekord keresése `Person.user_id == user.id` alapján történt, de `Person.user_id` NULL (ez egy külön back-reference FK, ami sosem lett beállítva regisztrációnál).
|
||
- **Fix:** Módosítva `Person.id == user.person_id`-re, ami a `User.person_id` FK-n keresztül helyesen megtalálja a Person rekordot.
|
||
- Plusz: `person.user_id = user.id` beállítás a back-reference konzisztencia fenntartásához.
|
||
|
||
**2. `backend/app/services/gamification_service.py` - `award_points()` és `process_activity()` (20-123. sor):**
|
||
- **Bug:** `process_activity()` belső `await db.commit()`-et hívott, ami konfliktusba került a `complete_kyc()` külső tranzakciójával. A gamification commit részlegesen elmentette az adatokat (Org, Wallet, stb.), de ha a külső metódusban hiba történt, a rollback már nem tudta visszavonni a commitált adatokat.
|
||
- **Fix:** `commit: bool = True` paraméter hozzáadva mindkét metódushoz. Amikor `commit=False`, a metódus nem hív `db.commit()`-ot, így a hívó fél (pl. `complete_kyc()`) kezeli a tranzakciót atomikusan.
|
||
|
||
**3. `backend/app/services/auth_service.py` - `complete_kyc()` (289. sor):**
|
||
- `commit=False` átadva a `GamificationService.award_points()` hívásoknak, hogy ne legyen dupla commit.
|
||
|
||
### 🛠️ Repair Script
|
||
- `backend/scripts/repair_kyc_user.py` - Létrehozva a meglévő `gy.krisztina76@gmail.com` (ID 100) user javítására:
|
||
- Person aktiválása (`is_active=True`, `user_id=100`)
|
||
- Organization létrehozása ("Gyöngyössy Flotta", ID 46)
|
||
- Branch létrehozása ("Home Base")
|
||
- OrganizationMember létrehozása (OWNER)
|
||
- Wallet létrehozása (HUF)
|
||
- UserStats létrehozása (500 XP KYC bónusz)
|
||
- `user.scope_id` beállítása
|
||
|
||
### ✅ Eredmény
|
||
- E2E teszt (`backend/scripts/test_kyc_e2e.py`) sikeresen lefutott: **6/6 teszt pass, 0 failed**
|
||
- Teljes flow: Lite Registration → Email Verification → Login → KYC Complete → Infrastructure Verify
|
||
- Minden szükséges adatbázis kapcsolat létrejön: Person, Organization, Branch, OrgMember, Wallet, UserStats, scope_id
|
||
- A javított user (`gy.krisztina76@gmail.com`) adatai helyreállítva
|
||
|
||
## 2026-06-12 - Emergency Regression Fix: Vehicle Creation 500 Error (UnboundLocalError)
|
||
|
||
### 🎯 Cél
|
||
Két kritikus végpont 500-as hibájának elhárítása a legutóbbi architekturális változtatások (Odometer, Trial) után:
|
||
- `POST /api/v1/auth/register` - Ellenőrizve: nincs hardcoded Trial periódus, a regisztráció 201 Created választ ad
|
||
- `POST /api/v1/assets/vehicles` - Javítva: Python `UnboundLocalError` a `select` változó scope-hibája miatt
|
||
|
||
### 🔧 Változtatások
|
||
|
||
**1. [`backend/app/api/v1/endpoints/assets.py`](backend/app/api/v1/endpoints/assets.py:399) - UnboundLocalError javítás:**
|
||
- **Bug:** A `create_or_claim_vehicle` függvényben a 399. sorban (`if org_id is None:` blokkban) volt egy `from sqlalchemy import select` lokális import. Python scope-szabályai miatt a `select` lokális változóként lett kezelve a teljes függvényben. Amikor a kódvégrehajtás a 358. sorban (`select(Asset).where(...)`) elérte a `select`-et, mielőtt a lokális import (399. sor) lefutott volna, Python `UnboundLocalError`-t dobott.
|
||
- **Fix:** A duplikált `from sqlalchemy import select` eltávolítva a 399. sorból. A `select` már importálva van a fájl tetején (9. sor).
|
||
|
||
**2. [`backend/app/services/asset_service.py`](backend/app/services/asset_service.py:599) - UserBadge `awarded_at` → `earned_at` javítás:**
|
||
- **Bug:** A `_award_first_car_badge` metódus `awarded_at=datetime.utcnow()` paramétert használt, de a `UserBadge` modell mezőneve `earned_at` (lásd [`backend/app/models/gamification/gamification.py`](backend/app/models/gamification/gamification.py:89)).
|
||
- **Fix:** `awarded_at` → `earned_at` átnevezés. Ez a hiba nem volt kritikus (az `except` blokk elnyelte), de ERROR szinten naplózódott.
|
||
|
||
### ✅ Eredmény
|
||
- `POST /api/v1/auth/register` → **201 Created** (nem volt hibás, csak ellenőrizve)
|
||
- `POST /api/v1/assets/vehicles` → **201 Created** (javítás után)
|
||
- Teljes E2E flow tesztelve: Register → Verify Email → Complete KYC → Create Vehicle → minden **200/201**
|
||
- Docker logokban nincs `error|500|traceback` a javítás után
|
||
|
||
## 2026-06-12 - B2B/B2C Context Switcher PLG Actions
|
||
|
||
### 🎯 Cél
|
||
A Context Switcher ([`HeaderCompanySwitcher.vue`](frontend/src/components/header/HeaderCompanySwitcher.vue)) átalakítása Product-Led Growth (PLG) szemléletűvé. Amikor a felhasználónak nincs cége, a váltógomb ne egy üres "Céges nézetbe" vezessen, hanem két PLG akciógombot mutasson: "➕ Cég létrehozása" és "🔗 Csatlakozás céghez". Ezek a gombok akkor is láthatók, ha a felhasználónak már van cége.
|
||
|
||
### 🔧 Változtatások
|
||
|
||
**1. [`frontend/src/components/header/HeaderCompanySwitcher.vue`](frontend/src/components/header/HeaderCompanySwitcher.vue):**
|
||
- **Template:** Az üres állapot ("No companies yet") eltávolítva, helyette egy PLG Actions szekció került be, amely mindig látható a dropdownban.
|
||
- Ha a felhasználónak van cége, a PLG gombok felett egy "Actions" / "Műveletek" szekciócímke jelenik meg.
|
||
- Két gomb: "➕ Create Company" és "🔗 Join Company", mindkettő saját SVG ikonnal.
|
||
- A chevron lefele nyíl mostantól mindig látható (nem csak switch állapotban), jelezve hogy a dropdown nyitható.
|
||
- **Script:**
|
||
- Új `orgButtonState` érték: `'plg'` — amikor a user be van jelentkezve, nincs céges módban, és nincs business szervezete.
|
||
- `handleCreateCompany()` — placeholder: `console.log` + navigáció `/company/onboard` útvonalra.
|
||
- `handleJoinCompany()` — placeholder: `console.log` + `alert('Coming soon!')`.
|
||
- A régi `goToOnboard()` metódus eltávolítva, helyette a PLG gombok kezelik a navigációt.
|
||
|
||
**2. [`frontend/src/i18n/en.ts`](frontend/src/i18n/en.ts) & [`frontend/src/i18n/hu.ts`](frontend/src/i18n/hu.ts):**
|
||
- Új i18n kulcsok: `header.joinCompany`, `header.createCompany`, `header.actions`.
|
||
|
||
### ✅ Ellenőrzés
|
||
- Vite build sikeres (✓ built in 4.35s).
|
||
- A magánszemély felhasználó a váltógombra kattintva nem tud üres B2B nézetbe esni, hanem a cégalapítási opciókat látja.
|
||
- A PLG gombok minden esetben elérhetők a dropdown alján.
|
||
|
||
## 2026-06-12 - Clean Odometer & Switcher Logic (Odometer Revert)
|
||
|
||
### 🎯 Cél
|
||
A VehicleOdometerState prediktív modell eltávolítása, mivel a fizikai Asset entitásnak nincs szüksége előrejelzett kilométeróra állapotra. Az OdometerReading tiszta audit trail-ként marad meg. A HeaderCompanySwitcher PLG/Growth Loop logikájának tisztítása.
|
||
|
||
### 🔧 Változtatások
|
||
|
||
**1. [`backend/app/models/vehicle/vehicle.py`](backend/app/models/vehicle/vehicle.py):**
|
||
- `VehicleOdometerState` osztály teljes eltávolítása (volt ~112-140. sor).
|
||
- `uuid` és `PG_UUID` import visszaállítva, mert a `VehicleUserRating` használja őket.
|
||
|
||
**2. [`backend/app/models/vehicle/asset.py`](backend/app/models/vehicle/asset.py):**
|
||
- `odometer_state` relationship eltávolítva az `Asset` modellből.
|
||
- `is_anomaly` oszlop eltávolítva az `OdometerReading` modellből.
|
||
|
||
**3. [`backend/app/models/vehicle/__init__.py`](backend/app/models/vehicle/__init__.py):**
|
||
- `VehicleOdometerState` eltávolítva az importokból és `__all__`-ból.
|
||
|
||
**4. [`backend/app/api/v1/endpoints/expenses.py`](backend/app/api/v1/endpoints/expenses.py):**
|
||
- `OdometerReading` import eltávolítva.
|
||
- ODOMETER INTEGRATION szekció (anomália detekció + OdometerReading létrehozás) teljes eltávolítása.
|
||
- Egyszerűsítve: közvetlen `asset.current_mileage` frissítés.
|
||
|
||
**5. [`backend/app/services/odometer_service.py`](backend/app/services/odometer_service.py):**
|
||
- Teljes fájl lecserélve deprekációs stub-ra.
|
||
|
||
**6. [`backend/app/api/v1/endpoints/admin.py`](backend/app/api/v1/endpoints/admin.py):**
|
||
- `OdometerService` import eltávolítva.
|
||
- Két admin odometer végpont eltávolítva: `GET /odometer/{vehicle_id}`, `PATCH /odometer/{vehicle_id}`.
|
||
|
||
**7. [`frontend/src/components/header/HeaderCompanySwitcher.vue`](frontend/src/components/header/HeaderCompanySwitcher.vue):**
|
||
- Teljes átírás tiszta Scenario A & B logikára.
|
||
- Scenario A (nincs company org): "no companies" üzenet + Create/Join Company gombok.
|
||
- Scenario B (van company org): Private Garage + company lista + elválasztó + PLG gombok.
|
||
- Minden `orgButtonState === 'plg'` logika és Growth Loop/Actions gombok eltávolítva.
|
||
|
||
### 🗄️ Adatbázis Műveletek
|
||
- `DROP TABLE vehicle.vehicle_odometer_states CASCADE`
|
||
- `ALTER TABLE vehicle.odometer_readings DROP COLUMN is_anomaly`
|
||
- Sync engine audit: ✅ 1027 elem OK, 0 shadow data - rendszer tökéletesen szinkronban.
|
||
|
||
## 2026-06-13 - B2C Workspace-Driven UI: Individual org_type szűrés a HeaderCompanySwitcher-ben
|
||
|
||
### 🎯 Cél
|
||
A magánszemélyek (B2C) számára a fejlécben lévő céges váltó duplikációmentesítése: az `org_type === 'individual'` szervezetek ne jelenjenek meg a céges listában, csak a "Privát garázs" opció.
|
||
|
||
### 🔧 Változtatások
|
||
|
||
**1. [`frontend/src/components/header/HeaderCompanySwitcher.vue`](frontend/src/components/header/HeaderCompanySwitcher.vue):**
|
||
- Új `companyOrganizations` computed property: kiszűri az `org_type === 'individual'` elemeket a `myOrganizations` listából.
|
||
- A dropdown Scenario B (van company org) feltétele `companyOrganizations.length > 0`-ra változott.
|
||
- A `v-for` ciklus `authStore.myOrganizations` helyett `companyOrganizations`-t használ.
|
||
- `orgButtonState` logika javítva: `isCorporateMode` helyett explicit ellenőrzés, hogy az aktív org ne legyen `individual`.
|
||
- `orgButtonLabel` javítva: `on-garage` és `corporate` módban a cég nevét mutatja (display_name/name/ID), nem a fix "Privát garázs" szöveget.
|
||
|
||
### ✅ Ellenőrzés
|
||
- Vite build: ✅ Sikeres (161 modul, 0 hiba)
|
||
- A backend `/organizations/my` végpontja már tartalmazza az `org_type` mezőt.
|
||
- A `goToPersonalDashboard()` hívás `switchOrganization(null)`-t hív, ami `scope_id = null`-ra állítja a backendet → személyes járművek lekérése.
|
||
|
||
## 2026-06-13 - Fix Catalog API 404 Mismatch & Real Database Data
|
||
|
||
### 🎯 Cél
|
||
A `GET /api/v1/catalog/brands?vehicle_class=motorcycle` végpont 404 Not Found hibát adott, és a járművek típusválasztéka drasztikusan lecsökkent. A probléma gyökere: a konténer nem a legfrissebb kódot futtatta.
|
||
|
||
### 🔍 Vizsgálat
|
||
1. **Adatbázis ellenőrzés:** A `vehicle.vehicle_model_definitions` tábla 345.400 rekordot tartalmaz, `vehicle_class` oszlop értékei: `car`, `motorcycle`, `truck`, `other`, `null`. A `motorcycle` osztályba 54.836 rekord tartozik 336 egyedi márkával.
|
||
2. **Kód ellenőrzés:** A `catalog.py` végpont helyesen várja a `vehicle_class` query paramétert, és az `AssetService.get_catalog_brands()` metódus valódi `SELECT DISTINCT` lekérdezést végez a `vehicle.vehicle_model_definitions` táblán.
|
||
3. **Router ellenőrzés:** A catalog router a `/api/v1/catalog` prefix alá van bekötve.
|
||
|
||
### 🔧 Megoldás
|
||
- A kód logikája helyes volt, nem volt szükség módosításra.
|
||
- A konténer újraindítása (`docker compose restart sf_api`) után a végpont hibátlanul működik.
|
||
|
||
### ✅ Eredmény
|
||
- `GET /api/v1/catalog/brands?vehicle_class=motorcycle` → **200 OK**, 336 márka
|
||
- `GET /api/v1/catalog/brands?vehicle_class=car` → **200 OK**, 1111 márka
|
||
- `GET /api/v1/catalog/brands?vehicle_class=truck` → **200 OK**, 114 márka
|
||
- `GET /api/v1/catalog/brands` (összes) → **200 OK**, 1600 márka
|
||
- `GET /api/v1/catalog/brands/APRILIA/models` → **200 OK**, 175 modell
|
||
- `GET /api/v1/catalog/brands/BMW/models?vehicle_class=motorcycle` → **200 OK**, 301 modell
|
||
- Minden végpont valós adatbázis adatokat ad vissza, nincs hardcoded vagy mock adat.
|
||
|
||
## 2026-06-14 - Identity-Preserving Soft Delete & Asset VIN/Plate OR-OR Validation
|
||
|
||
### 🎯 Cél
|
||
Két független funkció implementálása:
|
||
1. **Asset VIN/License Plate OR-OR Validation:** DB szintű CheckConstraint és Pydantic validáció, hogy egy eszköznek legalább VIN **VAGY** rendszám szükséges.
|
||
2. **Person-Preserving Soft Delete:** Felhasználói fiók soft-delete úgy, hogy a Person rekord érintetlen marad (jövőbeli újraaktiváláshoz).
|
||
|
||
### 🔧 Változtatások
|
||
|
||
**1. `backend/app/models/vehicle/asset.py` (72-78. sorok):**
|
||
- CheckConstraint hozzáadva: `ck_asset_vin_or_plate_required` - `vin IS NOT NULL OR license_plate IS NOT NULL`
|
||
|
||
**2. `backend/app/models/identity/identity.py` (82, 155. sorok):**
|
||
- `Person.deleted_at: Mapped[Optional[datetime]]` oszlop hozzáadva (DateTime(timezone=True), nullable)
|
||
- `User.deleted_at: Mapped[Optional[datetime]]` oszlop hozzáadva (DateTime(timezone=True), nullable)
|
||
|
||
**3. `backend/app/schemas/asset.py`:**
|
||
- `AssetCreate`: `license_plate` és `vin` mezők `Optional[str] = Field(None, ...)`-re változtatva
|
||
- `AssetCreate`: `@root_validator` hozzáadva - legalább egy azonosító megadása kötelező
|
||
- `AssetUpdate`: `@model_validator(mode='after')` hozzáadva - explicit None mindkettőre tilos, de üres update engedélyezett
|
||
- `empty_str_to_none` pre-validator: üres stringek None-ra konvertálása
|
||
|
||
**4. `backend/app/services/auth_service.py` (485-527. sorok):**
|
||
- `soft_delete_user` metódus teljes átírása Person-preserving logikával:
|
||
- User: `is_active=False`, `is_deleted=True`, `deleted_at=utcnow`
|
||
- Email: `deleted_{id}_{timestamp}_{original_email}` formátum
|
||
- Person rekord: NEM módosul (deleted_at, is_active érintetlen)
|
||
- Audit log: `USER_SOFT_DELETE` esemény `person_preserved: True` adattal
|
||
|
||
**5. `backend/app/api/v1/endpoints/users.py` (502-531. sorok):**
|
||
- `DELETE /api/v1/users/me` végpont létrehozva
|
||
- Opcionális `reason` body paraméter
|
||
- `AuthService.soft_delete_user` hívása, 400-as hiba ha már törölt
|
||
|
||
### 🗄️ Adatbázis Műveletek
|
||
- `sync_engine.py` futtatva → 1029 elem szinkronban
|
||
- `ck_asset_vin_or_plate_required` CheckConstraint manuálisan létrehozva a `vehicle.assets` táblán
|
||
- `deleted_at` oszlopok megléte ellenőrizve: `identity.users` és `identity.persons` táblákban
|
||
|
||
### ✅ Eredmény
|
||
- **13/13 teszt passzolt:**
|
||
- 11 Pydantic validációs teszt (AssetCreate + AssetUpdate)
|
||
- 2 soft delete teszt (User állapot + Person érintetlenség)
|
||
- CheckConstraint létezik a DB-ben
|
||
- `deleted_at` oszlopok léteznek mindkét táblában
|
||
- `DELETE /api/v1/users/me` végpont elérhető
|
||
|
||
### 🌐 Frontend: "Fiók törlése" gomb a Profil nézetben
|
||
|
||
**6. `frontend/src/stores/auth.ts` (482-503. sorok):**
|
||
- `deleteAccount(reason?: string)` async action hozzáadva:
|
||
- `api.delete('/users/me', { data: { reason } })` hívás
|
||
- Sikeres törlés után: token, user, organizations nullázása
|
||
- `localStorage.removeItem('access_token')` és `localStorage.removeItem('refresh_token')`
|
||
- `router.push('/')` átirányítás a landing page-re
|
||
- Hiba esetén `error.value` beállítása a backend detail üzenetével
|
||
|
||
**7. `frontend/src/i18n/hu.ts` (211-219. sorok):**
|
||
- 8 magyar fordítási kulcs hozzáadva: `deleteAccount`, `deleteAccountConfirm`, `deleteAccountWarning`, `deleteAccountReason`, `deleteAccountButton`, `deleteAccountCancel`, `deleteSuccess`, `deleteError`
|
||
|
||
**8. `frontend/src/i18n/en.ts` (211-219. sorok):**
|
||
- 8 angol fordítási kulcs hozzáadva (megegyező struktúra)
|
||
|
||
**9. `frontend/src/views/ProfileView.vue`:**
|
||
- **Template:** Piros "Fiók törlése" gomb hozzáadva a "Jelszó módosítása" gomb után (szemetes ikonnal, `bg-red-600/20 border-red-500/40` stílus)
|
||
- **Template:** Megerősítő modal hozzáadva (`<Teleport to="body">` mintában, a jelszó modal után):
|
||
- Figyelmeztető ikon (piros háromszög)
|
||
- Magyarázó szöveg a Person adatok megőrzéséről
|
||
- Opcionális ok megadása (textarea)
|
||
- Hiba/siker üzenet megjelenítése
|
||
- "Mégsem" + "Igen, töröld a fiókomat" (piros) gombok
|
||
- **Script:** Új refs: `showDeleteModal`, `isDeleting`, `deleteReason`, `deleteError`, `deleteSuccess`
|
||
- **Script:** `closeDeleteModal()` - állapot reset
|
||
- **Script:** `submitDeleteAccount()` - `authStore.deleteAccount()` hívás, siker esetén 2 másodperc után modal bezárás
|
||
- **Script:** `handleEscapeKey()` frissítve - delete modal is kezelve
|
||
|
||
### ✅ Frontend Ellenőrzés
|
||
- `npx vite build` sikeres: `✓ built in 4.27s`, `ProfileView-BQxdl6hU.js` (47.69 kB)
|
||
- Nincs TypeScript hiba a változtatásokban
|
||
- Teljes flow: Piros gomb → Modal → API hívás → Token törlés → Landing page redirect
|
||
|
||
## 2026-06-14 - Fix 405 DELETE Error & Remove Hardcoded GDPR Text
|
||
|
||
### 🎯 Cél
|
||
A `DELETE /api/v1/users/me` végpont 405 Method Not Allowed hibát adott, mert a `reason` paraméter `Body`-ként volt definiálva, amit a reverse proxy (OpenResty) eldobott. Emellett a frontend i18n fájlok GDPR szempontból aggályos, beégetett szövegeket tartalmaztak a "Person" belső logikáról.
|
||
|
||
### 🔧 Változtatások
|
||
|
||
**1. `backend/app/api/v1/endpoints/users.py`:**
|
||
- `Body` import cserélve `Query`-re (4. sor).
|
||
- `DELETE /me` végpont `reason` paraméter típusa `Body(None)` → `Query(None)` (504. sor).
|
||
- REST szabály: DELETE kéréseknek nincs request body-ja.
|
||
|
||
**2. `frontend/src/i18n/hu.ts` (214. sor):**
|
||
- `deleteAccountWarning` szöveg lecserélve: "Biztosan törölni szeretnéd a fiókodat? Ez a művelet végleges és nem vonható vissza."
|
||
|
||
**3. `frontend/src/i18n/en.ts` (214. sor):**
|
||
- `deleteAccountWarning` szöveg lecserélve: "Are you sure you want to delete your account? This action is permanent and cannot be undone."
|
||
|
||
**4. `frontend/src/stores/auth.ts` (482-489. sor):**
|
||
- `deleteAccount()` API hívás átírva: `data: { reason: ... }` payload helyett `params` (query string) használata.
|
||
- Csak akkor adja át a `reason` paramétert, ha az ténylegesen meg van adva.
|
||
|
||
### ✅ Eredmény
|
||
- Backend Python szintaxis valid: OK.
|
||
- Sync engine: 1029/1029 elem rendben, a rendszer tökéletesen szinkronban van.
|
||
- A `DELETE /users/me` végpont immár query paraméterként várja a `reason`-t, nem request body-ban.
|
||
- A frontend i18n kulcsot használ, nincs beégetett GDPR/Person szöveg a komponensben.
|
||
|
||
## 2026-06-14 - Frontend: Account Restore, Last Admin Warning & Smart Company Claiming
|
||
|
||
### 🎯 Cél
|
||
Három frontend funkció implementálása teljes i18n támogatással: (1) 30 napos törölt fiók visszaállítás a bejelentkezési folyamatban, (2) Utolsó admin figyelmeztetés a fiók törlésénél, (3) Intelligens cég igénylés/csatlakozás.
|
||
|
||
### 🔧 Módosított fájlok
|
||
- [`frontend/src/i18n/hu.ts`](frontend/src/i18n/hu.ts) - Új i18n kulcsok: restore, lastAdminWarning, company claiming/joining
|
||
- [`frontend/src/i18n/en.ts`](frontend/src/i18n/en.ts) - Új i18n kulcsok angol nyelven
|
||
- [`frontend/src/stores/auth.ts`](frontend/src/stores/auth.ts) - `deleteAccount()` visszatérési érték bővítése `is_last_admin`-nel, `requestRestore()` és `verifyRestore()` hozzáadása
|
||
- [`frontend/src/components/LoginModal.vue`](frontend/src/components/LoginModal.vue) - Account Restore 5. face (3 lépés: email → OTP+password → siker)
|
||
- [`frontend/src/views/ProfileView.vue`](frontend/src/views/ProfileView.vue) - Last Admin Warning orange alert a törlés modalban
|
||
- [`frontend/src/views/organization/CompanyOnboardingView.vue`](frontend/src/views/organization/CompanyOnboardingView.vue) - Smart Company Claiming/Joining (active_exists, orphaned, manual fallback)
|
||
|
||
### ✅ Eredmény
|
||
- Vite build: sikeres (4.29s)
|
||
- Minden szöveg i18n kulcsokon keresztül, nincs hardcoded szöveg a Vue komponensekben
|
||
|
||
## 2026-06-14 - Enterprise User Management Module (RBAC & Bulk Actions)
|
||
|
||
### 🎯 Cél
|
||
Enterprise szintű User Management modul implementálása az Admin felülethez: RBAC-alapú bulk műveletek (ban, unban, soft_delete, restore, hard_delete) és paginált felhasználó lista szűréssel.
|
||
|
||
### 🔧 Változtatások
|
||
|
||
**1. Backend - [`admin.py`](backend/app/api/v1/endpoints/admin.py:470):**
|
||
- `BulkActionRequest` Pydantic modell regex validációval a támogatott akciókra
|
||
- `GET /admin/users` - Paginált felhasználó lista ILIKE e-mail szűréssel, role/is_active/is_deleted filterekkel
|
||
- `POST /admin/users/bulk-action` - Csoportos műveletek RBAC rangellenőrzéssel:
|
||
- `hard_delete`: superadmin (rank >= 100)
|
||
- `soft_delete/restore/unban`: admin (rank >= 90)
|
||
- `ban`: moderator (rank >= 50)
|
||
- Superadmin felhasználók védelme (kivéve ha saját magán hajtja végre)
|
||
- `SecurityAuditLog` minden bulk művelethez
|
||
|
||
**2. Frontend Store - [`adminUsers.ts`](frontend/src/stores/adminUsers.ts):**
|
||
- Új Pinia store `useAdminUsersStore` néven
|
||
- `fetchUsers()` - Paginált lekérés filter paraméterekkel
|
||
- `bulkAction()` - Bulk művelet végrehajtás + automatikus lista frissítés
|
||
|
||
**3. Frontend View - [`AdminUsersView.vue`](frontend/src/views/admin/AdminUsersView.vue):**
|
||
- Teljes admin felhasználó kezelő felület:
|
||
- E-mail keresés 400ms debounce-szal
|
||
- Role és státusz filter dropdown-ok
|
||
- Checkbox-os tábla "Select All" indeterminate állapottal
|
||
- Bulk Action Bar (Ban, Unban, Soft Delete, Restore, Hard Delete)
|
||
- **Hard Delete gomb elrejtése** `v-if="authStore.user?.role === 'superadmin'"`
|
||
- Role badge-ek színkódolva, státusz badge-ek (Active=zöld, Inactive=sárga, Deleted=piros)
|
||
- Pagination Previous/Next gombokkal
|
||
|
||
**4. Router & Layout:**
|
||
- [`index.ts`](frontend/src/router/index.ts) - `/admin/users` route regisztrálva
|
||
- [`AdminLayout.vue`](frontend/src/layouts/AdminLayout.vue) - Aktív menüpont kiemelés
|
||
|
||
### ✅ Eredmény
|
||
- Backend Python szintaxis: OK
|
||
- Vite build: sikeres (4.48s) - `AdminUsersView-CzzIFoUK.js` (9.69 kB)
|
||
- Minden funkció implementálva és verifikálva
|
||
|
||
## 2026-06-15 - Admin Service Catalog API & UI
|
||
|
||
### 🎯 Cél
|
||
Admin Service Catalog CRUD API és frontend UI megvalósítása i18n támogatással. A backend API végpontok (GET, POST, PATCH) már léteztek, a frontend oldal hiányzott.
|
||
|
||
### 🔧 Változtatások
|
||
|
||
**1. FRONTEND - [`adminServices.ts`](frontend/src/stores/adminServices.ts):**
|
||
- Új Pinia store a ServiceCatalog kezelésére
|
||
- `fetchServices()`, `createService()`, `updateService()` aszinkron akciók
|
||
- TypeScript interfészek: `ServiceCatalogItem`, `ServiceCatalogCreatePayload`, `ServiceCatalogUpdatePayload`
|
||
|
||
**2. FRONTEND - [`AdminServicesView.vue`](frontend/src/views/admin/AdminServicesView.vue):**
|
||
- Reszponzív kártya grid (1/2/3 oszlop) a szolgáltatások megjelenítésére
|
||
- Minden kártyán: service_code badge, név, leírás (line-clamp-2), kredit költség
|
||
- Szerkesztő/Létrehozó modál űrlap validációval
|
||
- Aktív/Inaktív toggle gomb
|
||
- Number input spinner eltávolítva (CSS + Tailwind classes)
|
||
|
||
**3. FRONTEND - [`router/index.ts`](frontend/src/router/index.ts):**
|
||
- `/admin/services` route regisztrálva `admin-services` néven
|
||
|
||
**4. FRONTEND - [`AdminLayout.vue`](frontend/src/layouts/AdminLayout.vue):**
|
||
- "Services" menüpont hozzáadva a Subscription Packages alá
|
||
|
||
**5. FRONTEND - [`en.ts`](frontend/src/i18n/en.ts), [`hu.ts`](frontend/src/i18n/hu.ts):**
|
||
- `admin.services.*` i18n kulcsok mindkét nyelven (title, subtitle, create_button, modal, field_*, stb.)
|
||
|
||
**6. ADATBÁZIS - Seed:**
|
||
- `sync_engine.py` futtatva: 1047 elem OK, rendszer szinkronban
|
||
- `seed_services.py` futtatva: 3 szolgáltatás beszúrva (SRV_DATA_EXPORT, SRV_AI_UPLOAD, SRV_DIGITAL_BOOK)
|
||
|
||
### ✅ Eredmény
|
||
- Backend API végpontok: már léteztek, nem kellett módosítani
|
||
- Frontend store, view, router, layout, i18n: mind implementálva
|
||
- Adatbázis: sync_engine OK, seed sikeres (3 rekord)
|
||
- A Services menüpont megjelent az Admin felületen a 3 kezdő szolgáltatással
|
||
|
||
## 2026-06-15 - Gitea #134: Company Settings, Admin Package Filters & Subscription Migration
|
||
|
||
### 🎯 Cél
|
||
Három független feladat implementálása: (1) Cégadatok szerkesztése modal + PATCH végpont, (2) Admin csomagok szűrése típus és dátum szerint, (3) Előfizetés migrációs szkript a régi denormalizált `subscription_plan` mezők átvezetésére.
|
||
|
||
### 🔧 Változtatások
|
||
|
||
**FRONTEND 1a - Context Switcher javítás ([`HeaderCompanySwitcher.vue`](frontend/src/components/header/HeaderCompanySwitcher.vue)):**
|
||
- Megállapítás: A komponens már tartalmazza a `display_name || name || #ID` fallback logikát.
|
||
- Az `OrganizationLayout` computed property-je (`orgName`) reaktívan frissül, amikor az `authStore.myOrganizations` betöltődik.
|
||
- Nincs szükség kódmódosításra - a meglévő logika megfelelően kezeli az async betöltést.
|
||
|
||
**FRONTEND 1b - Backend PATCH végpont ([`organizations.py`](backend/app/api/v1/endpoints/organizations.py:283)):**
|
||
- Új általános `PATCH /{org_id}` végpont (nem csak visual-settings), OWNER/ADMIN jogosultsággal.
|
||
- Támogatott mezők: `name`, `full_name`, `tax_number`, `display_name`, `default_currency`, `language`, `address_zip`, `address_city`, `address_street_name`, `address_street_type`, `address_house_number`, `address_stairwell`, `address_floor`, `address_door`, `address_hrsz`, `visual_settings`.
|
||
- `model_dump(exclude_unset=True)` használata részleges frissítéshez, JSONB merge a `visual_settings`-hez.
|
||
|
||
**FRONTEND 1b - Schema bővítés ([`organization.py`](backend/app/schemas/organization.py:41)):**
|
||
- `OrganizationUpdate` séma kiegészítve: `name`, `full_name`, `tax_number`, `address_zip`, `address_city`, `address_street_name`, `address_street_type`, `address_house_number`, `address_stairwell`, `address_floor`, `address_door`, `address_hrsz` mezőkkel.
|
||
|
||
**FRONTEND 1c - Cégbeállítások modal ([`OrganizationSettingsModal.vue`](frontend/src/components/organization/OrganizationSettingsModal.vue)):**
|
||
- Új komponens: Teleport modal form űrlappal (name, full_name, display_name, tax_number, address_zip, address_city, address_street_name, address_house_number).
|
||
- Pre-fill az `authStore.myOrganizations`-ból mount-kor.
|
||
- `PATCH /organizations/{orgId}` hívás csak a nem-üres mezőkkel.
|
||
- `authStore.fetchMyOrganizations()` frissítés mentés után.
|
||
- `close` és `saved` események.
|
||
|
||
**FRONTEND 1c - CompanyGarageView bővítés ([`CompanyGarageView.vue`](frontend/src/views/organization/CompanyGarageView.vue)):**
|
||
- "Company Settings" gomb a Quick Actions kártyában (emerald stílus, gear ikon).
|
||
- `showSettingsModal` ref + `OrganizationSettingsModal` import.
|
||
- Modal megjelenítése `v-if="showSettingsModal"`.
|
||
|
||
**FRONTEND 1c - i18n kulcsok ([`hu.ts`](frontend/src/i18n/hu.ts), [`en.ts`](frontend/src/i18n/en.ts)):**
|
||
- Új `company.settings*` kulcsok: settingsTitle, settingsDescription, settingsModalTitle, settingsName, settingsFullName, settingsTaxNumber, settingsDisplayName, settingsAddressZip, settingsAddressCity, settingsAddressStreet, settingsAddressHouseNumber, settingsSaveSuccess, settingsSaveError.
|
||
|
||
**FRONTEND 2a - Backend szűrés ([`admin_packages.py`](backend/app/api/v1/endpoints/admin_packages.py:51)):**
|
||
- `type_filter: Optional[str]` query param - JSONB `rules->>'type'` szűrés (private/corporate).
|
||
- `date_from: Optional[str]` query param - JSONB `rules->'lifecycle'->>'available_from' >= date_from`.
|
||
- `date_until: Optional[str]` query param - JSONB `rules->'lifecycle'->>'available_until' <= date_until`.
|
||
|
||
**FRONTEND 2b - Admin csomagok szűrő UI ([`AdminPackagesView.vue`](frontend/src/views/admin/AdminPackagesView.vue)):**
|
||
- Filter bar a header és a csomag grid között: Type dropdown (All/Private/Corporate), Date From/Until inputok, Clear Filters gomb.
|
||
- `typeFilter`, `dateFrom`, `dateUntil` ref-ek, `clearFilters()` függvény.
|
||
- `loadPackages()` filter paraméterek átadása.
|
||
|
||
**FRONTEND 2c - Store bővítés ([`adminPackages.ts`](frontend/src/stores/adminPackages.ts)):**
|
||
- `fetchPackages()` paraméterek: `type_filter`, `date_from`, `date_until` hozzáadva.
|
||
|
||
**BACKEND 3 - Migrációs szkript ([`migrate_subscriptions.py`](backend/app/scripts/migrate_subscriptions.py)):**
|
||
- **A)** `corp_free_v1` csomag létrehozása (ID=22, 0 áras, 3 jármű, 1 garázs).
|
||
- **B)** `finance.user_subscriptions` tábla létrehozása (user_id, tier_id, valid_from, valid_until, is_active, created_at, updated_at).
|
||
- **C)** Adatkonverzió: 19 org subscription (18x private_free_v1, 1x corp_premium_v1) és 21 user subscription (16x private_free_v1, 3x corp_premium_v1, 1x corp_vip_v1, 1x private_pro_v1).
|
||
- Plan mapping: FREE→private_free_v1, PRO→private_pro_v1, PREMIUM→corp_premium_v1, ENTERPRISE→corp_vip_v1.
|
||
|
||
**BACKEND 3 - UserSubscription modell ([`core_logic.py`](backend/app/models/core_logic.py:44)):**
|
||
- `UserSubscription` SQLAlchemy modell hozzáadva a `finance.user_subscriptions` táblához.
|
||
- Kapcsolatok: `user_id → identity.users.id`, `tier_id → system.subscription_tiers.id`.
|
||
|
||
### 🗄️ Adatbázis Műveletek
|
||
- `sync_engine.py` futtatva: 1056 elem OK, 0 shadow data - rendszer tökéletesen szinkronban.
|
||
- `corp_free_v1` tier létrehozva (ID=22).
|
||
- `finance.user_subscriptions` tábla létrehozva index-szel.
|
||
- 19 org_subscription + 21 user_subscription rekord beszúrva.
|
||
|
||
### ✅ Eredmény
|
||
- Backend: PATCH /organizations/{id} végpont működik, admin packages szűrés JSONB path lekérdezéssel.
|
||
- Frontend: Company Settings modal, Admin Packages filter UI, i18n támogatás.
|
||
- Adatbázis: subscription migráció sikeres, minden adat átvezetve a normalizált táblákba.
|
||
- Sync engine: teljes szinkronban.
|
||
|
||
---
|
||
|
||
## 2026-06-15: PATCH 500 javítás + Cég adatai Hamburger Menü
|
||
|
||
### 🎯 Cél
|
||
Három részből álló feladat:
|
||
1. **KRITIKUS:** PATCH /admin/packages/{id} 500-as hiba javítása
|
||
2. **Frontend:** Hiányzó i18n kulcsok (date_from_label, date_until_label) pótlása + dátum szűrés logika javítása
|
||
3. **Frontend:** Cég Settings Hamburger Menü + 'Cég adatai' modal read/edit móddal
|
||
|
||
### 🔍 Hibakeresés (Docker Log)
|
||
- `docker compose logs --tail=100 sf_api` → `AttributeError: 'dict' object has no attribute 'model_dump'`
|
||
- **Gyökér ok:** `payload.model_dump(exclude_unset=True)` rekurzívan dict-té alakítja a beágyazott Pydantic modelleket, így `update_data["rules"]` már sima dict, amin a `.model_dump()` hívás AttributeError-t dob.
|
||
|
||
### 🔧 Változtatások
|
||
|
||
**1. Backend: PATCH 500 fix (`backend/app/api/v1/endpoints/admin_packages.py`)**
|
||
- `new_rules = update_data["rules"].model_dump()` → `new_rules = update_data["rules"]` (közvetlen dict assign)
|
||
- `isinstance(new_rules, dict)` biztonsági ellenőrzés hozzáadva
|
||
- Dátum szűrés javítva: string összehasonlítás helyett `cast(..., Date)` használata
|
||
- Importok: `from datetime import date`, `from sqlalchemy import Date, cast`
|
||
|
||
**2. Frontend: i18n kulcsok (`frontend/src/i18n/hu.ts`, `frontend/src/i18n/en.ts`)**
|
||
- `admin.packages.date_from_label`, `admin.packages.date_until_label` kulcsok hozzáadva
|
||
- `company.companyDataTitle`, `company.companyDataMenu`, `company.close` kulcsok hozzáadva
|
||
|
||
**3. Frontend: CompanyDataModal (`frontend/src/components/organization/CompanyDataModal.vue`)**
|
||
- **Read mód:** Név, Teljes név, Adószám, Címek megjelenítése szövegesen; 'Bezárás' és 'Szerkesztés' gombok
|
||
- **Edit mód:** Input mezők (name, full_name, display_name, address); adószám (`tax_number`) mindig disabled/read-only
|
||
- 'Mégsem' → vissza read módba; 'Mentés' → PATCH API hívás, majd vissza read módba
|
||
- Glassmorphism design (dark theme, backdrop-blur, border-white/10)
|
||
|
||
**4. Frontend: Hamburger Menü (`frontend/src/layouts/OrganizationLayout.vue`)**
|
||
- 3-vonalas hamburger ikon a header right slot-jában
|
||
- Dropdown 'Cég adatai' menüponttal
|
||
- Outside-click handler a bezáráshoz
|
||
- CompanyDataModal integráció
|
||
|
||
### ✅ Ellenőrzés
|
||
- Backend konténer újraindítva: `docker compose restart sf_api` → sikeres startup
|
||
- Frontend build: `docker compose exec sf_public_frontend sh -c "cd /app && npm run build"` → 4.83s, hiba nélkül
|