Files
service-finder/.roo/history.md

42 KiB
Raw Blame History

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:

  • 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:

  • 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:

  • 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):

  • 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:

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: UUIDPG_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/register201 Created sikeres regisztráció
  • GET /health200 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 - 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 - UserBadge awarded_atearned_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).
  • Fix: awarded_atearned_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/register201 Created (nem volt hibás, csak ellenőrizve)
  • POST /api/v1/assets/vehicles201 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) á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:

  • 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/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:

  • 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:

  • 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:

  • VehicleOdometerState eltávolítva az importokból és __all__-ból.

4. 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:

  • Teljes fájl lecserélve deprekációs stub-ra.

6. 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:

  • 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:

  • Ú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=motorcycle200 OK, 336 márka
  • GET /api/v1/catalog/brands?vehicle_class=car200 OK, 1111 márka
  • GET /api/v1/catalog/brands?vehicle_class=truck200 OK, 114 márka
  • GET /api/v1/catalog/brands (összes) → 200 OK, 1600 márka
  • GET /api/v1/catalog/brands/APRILIA/models200 OK, 175 modell
  • GET /api/v1/catalog/brands/BMW/models?vehicle_class=motorcycle200 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

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:

  • 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:

  • Ú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:

  • 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:

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:

  • Új Pinia store a ServiceCatalog kezelésére
  • fetchServices(), createService(), updateService() aszinkron akciók
  • TypeScript interfészek: ServiceCatalogItem, ServiceCatalogCreatePayload, ServiceCatalogUpdatePayload

2. FRONTEND - 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:

  • /admin/services route regisztrálva admin-services néven

4. FRONTEND - AdminLayout.vue:

  • "Services" menüpont hozzáadva a Subscription Packages alá

5. FRONTEND - en.ts, 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):

  • 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):

  • Ú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):

  • 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):

  • Ú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):

  • "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, 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):

  • 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):

  • 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):

  • fetchPackages() paraméterek: type_filter, date_from, date_until hozzáadva.

BACKEND 3 - Migrációs szkript (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):

  • 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_apiAttributeError: '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