42 KiB
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
selectinloadhelyett explicitouterjoin+contains_eagerhasználata aPersonésAddresstáblákhoz. Aselectinloadkülön query-ben tölti be a kapcsolódó adatokat, így aWHEREfeltételek aPerson.phone,Person.first_namestb. oszlopokra nem működtek (500-as hiba). - Address keresés javítás: Az
Address.zipésAddress.cityPython property-k, nem DB oszlopok. A tényleges SQL lekérdezésben aGeoPostalCode.zip_codeésGeoPostalCode.cityoszlopokat kell használni. Ehhez egy 3. outerjoin került aGeoPostalCodetáblára. - Phone search: A
query = query.where(Person.phone.ilike(...))értékadás most már működik, mert aPersontá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-lgosztá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ésModeSwitchermellett. 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
/meregisztrá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.routera/usersprefix 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
--reloadnélkül indult, így a kód módosításai nem léptek életbe - Megoldás:
docker compose restart sf_apiután a DELETE/me200 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/mevégpont atester_pro2@profibot.hufió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.hufió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.idsor kicserélve. - Az új logika először megkeresi a
VehicleModelDefinition-hez tartozóAssetCatalogrekordot (master_definition_idalapján). - Ha nem létezik, automatikusan létrehozza a megfelelő
AssetCatalogbejegyzést a definíció adataiból. - Csak ezután állítja be a
catalog_id-t a valódiAssetCatalog.id-ra.
✅ Eredmény
- A teszt
POST /api/v1/assets/vehicleskérés201 Createdstá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
isInitializedref állapot (alapértelmezett:false) hozzáadva a store state-hez. - Az
init()függvény legvégénisInitialized.value = truebeállítás, így a router guard meg tudja várni az inicializálás végét. - Az
isInitializedexportálva a return objektumban.
2. frontend/src/router/index.ts:
- A
beforeEachguard elején ellenőrzés: ha!authStore.isInitialized, akkorawait 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
requiresAuthellenő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
vehiclesé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
- Rendszerparaméter-tábla vizsgálata (no hardcoding elv érvényesítése)
- Odometer (kilométeróra) automatikus bekötése a költségrögzítésbe
- 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 kulcscategory(VARCHAR) - kategória (pl. vehicle, finance, security)value(JSONB) - érték (tetszőleges JSON struktúra)scope_level(ENUM: global, organization, user) - hatókörscope_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- Odometer integráció hozzáadvabackend/app/models/__init__.py-OdometerReadingexport hozzáadvabackend/app/models/vehicle/__init__.py-OdometerReadingexport hozzáadva
Implementáció részletei:
- Az
AssetCostCreateséma már tartalmazza amileage_at_costmezőt - A
create_expensevégpont most:- Létrehoz egy
OdometerReadingrekordot (source="cost_entry",cost_id=new_cost.id) hamileage_at_costmeg van adva - Frissíti az
Asset.current_mileagemezőt, ha az új km állás nagyobb, mint a jelenlegi
- Létrehoz egy
- Az
OdometerReadingmodell már létezett avehicle.odometer_readingstá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őtGET /api/v1/assets/{id}végpont - visszaadja acurrent_mileage-tVehicleDataTypeScript típus - definiálja acurrent_mileagemezőtVehicleDetailModal.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_parameterstáblán keresztül - Az OdometerReading automatikusan rögzítésre kerül minden költségbejegyzésnél, ahol
mileage_at_costmeg van adva - Az
Asset.current_mileagemindig 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:
LogSeverityenum import hozzáadvaseverity="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=TruehozzáadvaVehicleUserRating.id:UUID→PG_UUIDjaví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.idalapján történt, dePerson.user_idNULL (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 aUser.person_idFK-n keresztül helyesen megtalálja a Person rekordot. - Plusz:
person.user_id = user.idbeá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 acomplete_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 = Trueparaméter hozzáadva mindkét metódushoz. Amikorcommit=False, a metódus nem hívdb.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 aGamificationService.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_idbeállítása
- Person aktiválá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 adPOST /api/v1/assets/vehicles- Javítva: PythonUnboundLocalErroraselectvá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_vehiclefüggvényben a 399. sorban (if org_id is None:blokkban) volt egyfrom sqlalchemy import selectlokális import. Python scope-szabályai miatt aselectloká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 aselect-et, mielőtt a lokális import (399. sor) lefutott volna, PythonUnboundLocalError-t dobott. - Fix: A duplikált
from sqlalchemy import selecteltávolítva a 399. sorból. Aselectmár importálva van a fájl tetején (9. sor).
2. backend/app/services/asset_service.py - UserBadge awarded_at → earned_at javítás:
- Bug: A
_award_first_car_badgemetódusawarded_at=datetime.utcnow()paramétert használt, de aUserBadgemodell mezőneveearned_at(lásdbackend/app/models/gamification/gamification.py). - Fix:
awarded_at→earned_atátnevezés. Ez a hiba nem volt kritikus (azexceptblokk 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|tracebacka 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.
- Új
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:
VehicleOdometerStateosztály teljes eltávolítása (volt ~112-140. sor).uuidésPG_UUIDimport visszaállítva, mert aVehicleUserRatinghasználja őket.
2. backend/app/models/vehicle/asset.py:
odometer_staterelationship eltávolítva azAssetmodellből.is_anomalyoszlop eltávolítva azOdometerReadingmodellből.
3. backend/app/models/vehicle/__init__.py:
VehicleOdometerStateeltávolítva az importokból és__all__-ból.
4. backend/app/api/v1/endpoints/expenses.py:
OdometerReadingimport 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_mileagefrissí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:
OdometerServiceimport 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 CASCADEALTER 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
companyOrganizationscomputed property: kiszűri azorg_type === 'individual'elemeket amyOrganizationslistából. - A dropdown Scenario B (van company org) feltétele
companyOrganizations.length > 0-ra változott. - A
v-forciklusauthStore.myOrganizationshelyettcompanyOrganizations-t használ. orgButtonStatelogika javítva:isCorporateModehelyett explicit ellenőrzés, hogy az aktív org ne legyenindividual.orgButtonLabeljavítva:on-garageéscorporatemó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/myvégpontja már tartalmazza azorg_typemezőt. - A
goToPersonalDashboard()hívásswitchOrganization(null)-t hív, amiscope_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
- Adatbázis ellenőrzés: A
vehicle.vehicle_model_definitionstábla 345.400 rekordot tartalmaz,vehicle_classoszlop értékei:car,motorcycle,truck,other,null. Amotorcycleosztályba 54.836 rekord tartozik 336 egyedi márkával. - Kód ellenőrzés: A
catalog.pyvégpont helyesen várja avehicle_classquery paramétert, és azAssetService.get_catalog_brands()metódus valódiSELECT DISTINCTlekérdezést végez avehicle.vehicle_model_definitionstáblán. - Router ellenőrzés: A catalog router a
/api/v1/catalogprefix 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árkaGET /api/v1/catalog/brands?vehicle_class=car→ 200 OK, 1111 márkaGET /api/v1/catalog/brands?vehicle_class=truck→ 200 OK, 114 márkaGET /api/v1/catalog/brands(összes) → 200 OK, 1600 márkaGET /api/v1/catalog/brands/APRILIA/models→ 200 OK, 175 modellGET /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:
- 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.
- 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ésvinmezőkOptional[str] = Field(None, ...)-re változtatvaAssetCreate:@root_validatorhozzá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élyezettempty_str_to_nonepre-validator: üres stringek None-ra konvertálása
4. backend/app/services/auth_service.py (485-527. sorok):
soft_delete_usermetó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_DELETEeseményperson_preserved: Trueadattal
- User:
5. backend/app/api/v1/endpoints/users.py (502-531. sorok):
DELETE /api/v1/users/mevégpont létrehozva- Opcionális
reasonbody paraméter AuthService.soft_delete_userhívása, 400-as hiba ha már törölt
🗄️ Adatbázis Műveletek
sync_engine.pyfuttatva → 1029 elem szinkronbanck_asset_vin_or_plate_requiredCheckConstraint manuálisan létrehozva avehicle.assetstáblándeleted_atoszlopok megléte ellenőrizve:identity.usersésidentity.personstá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_atoszlopok léteznek mindkét táblábanDELETE /api/v1/users/mevé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')éslocalStorage.removeItem('refresh_token')router.push('/')átirányítás a landing page-re- Hiba esetén
error.valuebeá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/40stí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 buildsikeres:✓ 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:
Bodyimport cserélveQuery-re (4. sor).DELETE /mevégpontreasonparaméter típusaBody(None)→Query(None)(504. sor).- REST szabály: DELETE kéréseknek nincs request body-ja.
2. frontend/src/i18n/hu.ts (214. sor):
deleteAccountWarningszö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):
deleteAccountWarningszö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 helyettparams(query string) használata.- Csak akkor adja át a
reasonparamé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/mevégpont immár query paraméterként várja areason-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- Új i18n kulcsok: restore, lastAdminWarning, company claiming/joiningfrontend/src/i18n/en.ts- Új i18n kulcsok angol nyelvenfrontend/src/stores/auth.ts-deleteAccount()visszatérési érték bővítéseis_last_admin-nel,requestRestore()ésverifyRestore()hozzáadásafrontend/src/components/LoginModal.vue- Account Restore 5. face (3 lépés: email → OTP+password → siker)frontend/src/views/ProfileView.vue- Last Admin Warning orange alert a törlés modalbanfrontend/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:
BulkActionRequestPydantic modell regex validációval a támogatott akciókraGET /admin/users- Paginált felhasználó lista ILIKE e-mail szűréssel, role/is_active/is_deleted filterekkelPOST /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)
SecurityAuditLogminden bulk művelethez
2. Frontend Store - adminUsers.ts:
- Új Pinia store
useAdminUsersStorenéven fetchUsers()- Paginált lekérés filter paraméterekkelbulkAction()- 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:
index.ts-/admin/usersroute regisztrálvaAdminLayout.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:
- Ú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/servicesroute regisztrálvaadmin-servicesnéven
4. FRONTEND - AdminLayout.vue:
- "Services" menüpont hozzáadva a Subscription Packages alá
admin.services.*i18n kulcsok mindkét nyelven (title, subtitle, create_button, modal, field_*, stb.)
6. ADATBÁZIS - Seed:
sync_engine.pyfuttatva: 1047 elem OK, rendszer szinkronbanseed_services.pyfuttatva: 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 || #IDfallback logikát. - Az
OrganizationLayoutcomputed property-je (orgName) reaktívan frissül, amikor azauthStore.myOrganizationsbetö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 avisual_settings-hez.
FRONTEND 1b - Schema bővítés (organization.py):
OrganizationUpdatesé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_hrszmező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éssavedesemények.
FRONTEND 1c - CompanyGarageView bővítés (CompanyGarageView.vue):
- "Company Settings" gomb a Quick Actions kártyában (emerald stílus, gear ikon).
showSettingsModalref +OrganizationSettingsModalimport.- 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 - JSONBrules->>'type'szűrés (private/corporate).date_from: Optional[str]query param - JSONBrules->'lifecycle'->>'available_from' >= date_from.date_until: Optional[str]query param - JSONBrules->'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,dateUntilref-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_untilhozzáadva.
BACKEND 3 - Migrációs szkript (migrate_subscriptions.py):
- A)
corp_free_v1csomag létrehozása (ID=22, 0 áras, 3 jármű, 1 garázs). - B)
finance.user_subscriptionstá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):
UserSubscriptionSQLAlchemy modell hozzáadva afinance.user_subscriptionstáblához.- Kapcsolatok:
user_id → identity.users.id,tier_id → system.subscription_tiers.id.
🗄️ Adatbázis Műveletek
sync_engine.pyfuttatva: 1056 elem OK, 0 shadow data - rendszer tökéletesen szinkronban.corp_free_v1tier létrehozva (ID=22).finance.user_subscriptionstá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:
- KRITIKUS: PATCH /admin/packages/{id} 500-as hiba javítása
- Frontend: Hiányzó i18n kulcsok (date_from_label, date_until_label) pótlása + dátum szűrés logika javítása
- 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, ígyupdate_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_labelkulcsok hozzáadvacompany.companyDataTitle,company.companyDataMenu,company.closekulcsok 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