# Service Finder Fejlesztési Történet ## 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. - `targetRoute` computed property: ha a jelenlegi útvonal `/organization/`-t tartalmaz, akkor a logó a jelenlegi útvonalra navigál (önmagát tölti újra), egyébként `/dashboard`. - A prop-alapú `to` helyett a `:to="targetRoute"` használata a template-ben. ### ✅ Eredmény - Vite build hiba nélkül lefutott (136 modul, 3.23s). - Nincs több F5 utáni hamis kijelentkezés. - A logó szervezeti oldalon nem dobja ki a felhasználót a dashboard-ra. ## 2026-06-08 - Issue #237: API Endpoints for visual_settings ### 🎯 Cél Backend API végpontok felkészítése a `visual_settings` módosítására. Pydantic sémák (`OrganizationUpdate`, `OrganizationResponse`) létrehozása a `visual_settings` mezővel, valamint `PATCH /organizations/{org_id}/visual-settings` végpont implementálása JSONB merge logikával. ### ✅ Implementáció #### 1. Pydantic Sémák - **`OrganizationUpdate`**: [`backend/app/schemas/organization.py`](backend/app/schemas/organization.py:40) - Új séma `visual_settings: Optional[dict]`, `display_name`, `default_currency`, `language` mezőkkel - **`OrganizationResponse`**: [`backend/app/schemas/organization.py`](backend/app/schemas/organization.py:49) - Új DTO séma `visual_settings: Optional[dict]` mezővel, `from_attributes=True` konfigurációval #### 2. API Végpont - **`PATCH /organizations/{org_id}/visual-settings`**: [`backend/app/api/v1/endpoints/organizations.py`](backend/app/api/v1/endpoints/organizations.py:207) - Új végpont JSONB merge logikával: - OWNER/ADMIN jogosultság ellenőrzés - Mély merge: a meglévő `visual_settings` kulcsok megmaradnak, csak a kapottak frissülnek - Pl. `{"theme": "dark"}` küldése nem írja felül a `wall_logo_url`-t - Egyéb mezők (`display_name`, `language`, `default_currency`) is frissíthetők #### 3. Meglévő Végpontok Bővítése - **`GET /organizations/my`**: [`backend/app/api/v1/endpoints/organizations.py`](backend/app/api/v1/endpoints/organizations.py:203) - `visual_settings` mező hozzáadva a response-hoz - **`PATCH /users/me/preferences`**: [`backend/app/api/v1/endpoints/users.py`](backend/app/api/v1/endpoints/users.py:333) - Már támogatja a `visual_settings`-et a generikus `exclude_unset=True` logikával #### 4. Verifikáció - Python syntax check: minden fájl hibátlanul lefordul - Import teszt: `OrganizationUpdate`, `OrganizationResponse`, `UserUpdate`, `UserResponse` mindegyike tartalmazza a `visual_settings` mezőt ## 2026-06-08 - Issue #228: Add visual_settings to Models ### 🎯 Cél `visual_settings` JSONB mező hozzáadása a User és Organization modellekhez, a Pydantic sémák frissítése, majd az adatbázis szinkronizálása a sync_engine segítségével. ### ✅ Implementáció #### 1. SQLAlchemy Modellek - **User modell**: [`backend/app/models/identity/identity.py`](backend/app/models/identity/identity.py:157) - `visual_settings` JSONB oszlop hozzáadva a `ui_mode` után, `server_default` JSONB default értékkel (`{"theme": "default", "primary_color": null, "wall_logo_url": null}`) - **Organization modell**: [`backend/app/models/marketplace/organization.py`](backend/app/models/marketplace/organization.py:109) - `visual_settings` JSONB oszlop hozzáadva az `external_integration_config` után, azonos default értékkel #### 2. Pydantic Sémák - **UserResponse**: [`backend/app/schemas/user.py`](backend/app/schemas/user.py:62) - `visual_settings: Optional[dict]` mező hozzáadva default értékkel - **UserUpdate**: [`backend/app/schemas/user.py`](backend/app/schemas/user.py:107) - `visual_settings: Optional[dict]` mező hozzáadva #### 3. Adatbázis Szinkronizálás - `sync_engine` sikeresen lefuttatva: 2 hiányzó oszlopot észlelt és hozzáadott (`identity.users.visual_settings` és `fleet.organizations.visual_settings`) - Verifikáció: mindkét oszlop `jsonb` típusként létezik az adatbázisban ## 2026-06-04 (B) - Magic Link Implementáció (Auto-Login Email Verification) ### 🎯 Cél Az email verifikációs folyamat átalakítása "Magic Link" élménnyé. A felhasználónak NEM kell manuálisan bejelentkeznie az aktiválás után - a verifikációs link automatikusan belépteti! ### ✅ Implementáció #### 1. Backend: JWT Token Generálás Verifikációnál **Fájl**: [`backend/app/api/v1/endpoints/auth.py`](backend/app/api/v1/endpoints/auth.py:93) - A `/verify-email` végpont most `response_model=Token`-t ad vissza - Sikeres verifikáció után a backend meghívja az [`AuthService.verify_email()`](backend/app/services/auth_service.py:316) metódust - Az `AuthService.verify_email()` mostantól User objektumot ad vissza (nem csak boolean-t) - A végpont generál JWT access és refresh tokent ugyanúgy, mint a `/login` endpoint - A tokenek HTTP-only cookie-ban és JSON response-ban is megjelennek **Változtatások**: ```python # AuthService.verify_email() módosítás - return True # RÉGI + return user # ÚJ: visszaadja az aktivált User objektumot # auth.py verify_email végpont + user = await AuthService.verify_email(db, request.token) + if not user: + raise HTTPException(...) + + # JWT token generálás (ugyanaz a logika, mint login-nál) + token_data = {"sub": str(user.id), "role": ..., "rank": ..., ...} ``` #### 2. Frontend Magic Link Handler **Fájl**: [`frontend/src/router/index.js`](frontend/src/router/index.js:1) - Új route: `/magic-link` a verify email oldalhoz - A route guard ellenőrzi a `token` query paramétert - Sikeres verifikáció után a kapott tokeneket elmenti és átirányít a dashboardra #### 3. Teszt Script **Fájl**: [`backend/test_auth_e2e.py`](backend/test_auth_e2e.py:1) - Teljes E2E teszt: Regisztráció → Email verifikáció → Magic Link → Dashboard elérés - Ellenőrzi, hogy a Magic Link után a felhasználó már hitelesítve van ### 🔗 Gitea - **Issue**: #201 - Magic Link: Auto-Login on Email Verification - **Státusz**: Completed --- ## 2026-06-05 - Soft KYC, Trust Profile Extension & Device Hub ### 🎯 Cél A KYC (Know Your Customer) folyamat kiterjesztése "Soft KYC" módra, a Trust Profile kibővítése identity score-ral, valamint a Device Hub (Device Fingerprinting) bevezetése. ### ✅ Implementáció #### 1. Soft KYC Backend Végpontok **Fájl**: [`backend/app/api/v1/endpoints/kyc.py`](backend/app/api/v1/endpoints/kyc.py:1) - Új `POST /kyc/soft` végpont: lehetővé teszi a részleges KYC adatok mentését - Új `GET /kyc/status` végpont: visszaadja a KYC státuszt és a hiányzó mezőket - A `PUT /users/me/person` végpont most már fogadja a `mothers_last_name`, `mothers_first_name`, `birth_place`, `birth_date` mezőket #### 2. Trust Profile Extension **Fájl**: [`backend/app/models/identity/identity.py`](backend/app/models/identity/identity.py:271) - `UserTrustProfile` modell bővítése: `identity_score`, `verification_level`, `verified_channels`, `identity_risk_flag` mezőkkel - Automatikus trust score újraszámítás KYC adatok módosításakor #### 3. Device Hub (Device Fingerprinting) **Fájl**: [`backend/app/models/identity/identity.py`](backend/app/models/identity/identity.py:302) - Új `Device` modell: `fingerprint_hash`, `risk_score`, `is_banned` mezőkkel - Új `UserDeviceLink` kapcsolótábla: `user_id`, `device_hash`, `first_seen_at`, `last_seen_at`, `login_count` - API végpontok: `POST /devices/register`, `GET /devices/my` #### 4. Adatbázis Migráció - Új táblák: `identity.devices`, `identity.user_device_links` - `UserTrustProfile` bővítése új oszlopokkal - `sync_engine` futtatva: 1017/1017 elem szinkronban ### 🔗 Gitea - **Issue**: #202 - Soft KYC, Trust Profile Extension & Device Hub - **Státusz**: Completed --- ## 2026-06-05 - Fix KYC Data Binding & Magic Link Device Registration ### 🎯 Cél A KYC adatok (address, identity_docs) nem jelentek meg a profilban a hibás adatkötés miatt. Emellett a Magic Link folyamatból hiányzott a Device Hub regisztráció. ### ✅ Javítás #### 1. ProfileView Address Binding Fix **Fájl**: [`frontend/src/views/ProfileView.vue`](frontend/src/views/ProfileView.vue:1) - A `person.address` mezőből hiányzott a `stairwell`, `floor`, `door` kiolvasása - Hozzáadva: `addressStairwell`, `addressFloor`, `addressDoor` computed property-k - A `handleSave` metódus most már ezeket is elküldi a `PUT /users/me/person` végpontnak #### 2. Magic Link Device Registration **Fájl**: [`frontend/src/views/MagicLinkView.vue`](frontend/src/views/MagicLinkView.vue:1) - Sikeres Magic Link belépés után a frontend meghívja a `POST /devices/register` végpontot - A device fingerprint hash-t a `fingerprintjs` library generálja ### 🔗 Gitea - **Issue**: #204 - Fix KYC Data Binding & Magic Link Device Registration - **Státusz**: Completed --- ## 2026-06-05 - Fix: SQLAlchemy JSON mutation for identity_docs ### 🎯 Cél A `PUT /users/me/person` végponton keresztül küldött `identity_docs` JSON mező módosításai nem perzisztálódtak az adatbázisban, mert az SQLAlchemy nem detektálta a JSON mutációt. ### ✅ Javítás #### 1. Végpont javítása **Fájl**: [`backend/app/api/v1/endpoints/users.py`](backend/app/api/v1/endpoints/users.py:223) - A `identity_docs` mező módosításakor most `flag_modified(person, "identity_docs")` hívással jelezzük az SQLAlchemy-nek, hogy a JSON mező megváltozott - Mély másolat (deep copy) készítése a meglévő adatokról a referencia integritás megőrzéséhez ### 🔗 Gitea - **Issue**: #207 - Fix: SQLAlchemy JSON mutation for identity_docs - **Státusz**: Completed --- ## 2026-06-05 - Internal Zip Lookup & Identity Docs Payload Fix ### 🎯 Cél A frontend által használt zip-lookup (irányítószám → város) végpont áttérése a külső zippopotam.us API-ról a belső backend végpontra. Emellett az identity_docs payload hibás szerializációjának javítása. ### ✅ Implementáció #### 1. Backend: Új Zip Lookup Végpont **Fájl**: [`backend/app/api/v1/endpoints/geo.py`](backend/app/api/v1/endpoints/geo.py:1) - Új `GET /geo/zip-lookup/{zip_code}` végpont - Ellenőrzi a `system.geo_postal_codes` táblát a megadott irányítószámra - Válasz: `{"zip": "1111", "city": "Budapest"}` vagy 404 #### 2. Frontend: Zip Lookup Átállítás - [`frontend/src/views/CompleteKycView.vue`](frontend/src/views/CompleteKycView.vue:1) - zippopotam.us → internal API - [`frontend/src/views/ProfileView.vue`](frontend/src/views/ProfileView.vue:1) - Debounced zip lookup watcher ### 🧪 Tesztelési Eredmény 1. ✅ Backend zip-lookup endpoint működik: `1111` → `{"city": "Budapest"}` (200) 2. ✅ Ismeretlen irányítószám: 404 hibakód megfelelő üzenettel 3. ✅ Frontend CompleteKycView belső API-t használ 4. ✅ Frontend ProfileView debounced zip lookup implementálva 5. ✅ identity_docs payload már helyesen működik (nem kellett javítás) ### 🔗 Gitea - **Issue**: #208 - Internal Zip Lookup & Identity Docs Payload Fix - **Státusz**: Completed --- ## 2026-06-05 - Fix Missing Address Fields (stairwell/floor/door) in GeoService Pipeline ### 🎯 Cél A `PUT /users/me/person` végponton keresztül küldött `address_stairwell`, `address_floor` és `address_door` mezők nem mentődtek az adatbázisba, mert a GeoService hívásból hiányoztak ezek a paraméterek. ### ✅ Javítás #### 1. Végpont javítása **Fájl**: [`backend/app/api/v1/endpoints/users.py`](backend/app/api/v1/endpoints/users.py:238) - A `GeoService.get_or_create_full_address()` hívásból hiányzott a `stairwell`, `floor` és `door` paraméterek átadása - Hozzáadva: `stairwell=update_dict.get("address_stairwell")`, `floor=update_dict.get("address_floor")`, `door=update_dict.get("address_door")` #### 2. Ellenőrzött fájlok (nem volt szükség módosításra) - [`backend/app/services/geo_service.py`](backend/app/services/geo_service.py:46) - A `get_or_create_full_address` metódus szignatúrája már tartalmazta a `stairwell`, `floor`, `door` paramétereket, és az Address entitásba is mentette őket - [`backend/app/schemas/user.py`](backend/app/schemas/user.py:87) - A `PersonUpdate` séma már deklarálta az `address_stairwell`, `address_floor`, `address_door` mezőket ### 🔍 Root Cause A `PUT /users/me/person` végpont a `GeoService.get_or_create_full_address()` híváskor nem adta át a `stairwell`, `floor` és `door` paramétereket, így azok mindig `None`-ként kerültek az adatbázisba, függetlenül attól, hogy a frontend mit küldött. ### 🔍 További javítás: full_address_text formátum javítása A `GeoService.get_or_create_full_address()` metódusban a `full_address_text` generátor a `door` paraméterhez `ajtó` szöveget fűzött, de a magyar címírási konvenció szerint `a.` (ajtó rövidítése) a helyes. **Javítás**: - [`backend/app/services/geo_service.py`](backend/app/services/geo_service.py:136) - `{door}. ajtó` → `{door}. a.` **Példa a helyes formátumra**: `2120 Dunakeszi, Határ utca 8. A. lph. 5. em. 10. a.` **Ellenőrzés**: A `sync_engine` futása után a rendszer 1017/1017 elemmel szinkronban van. --- ## 2026-06-05 - E2E Test Browserless Container Support ### 🎯 Cél Az [`tests/active/e2e_profile_address.py`](tests/active/e2e_profile_address.py) Playwright E2E teszt frissítése, hogy támogassa a távoli Browserless/Chrome Docker konténerhez való csatlakozást. ### ✅ Implementáció - **Dinamikus böngésző indítás**: A statikus `pw.chromium.launch()` hívás helyett a kód most ellenőrzi a `BROWSERLESS_URL` környezeti változót. - Ha be van állítva → `pw.chromium.connect_over_cdp(browserless_url)` segítségével csatlakozik a távoli konténerhez. - Ha nincs beállítva → lokális `pw.chromium.launch()` fallback, a `HEADLESS` env var figyelembevételével. - **Gitea Issue**: #215 - létrehozva, elindítva és lezárva. ## 2026-06-07 (C) - NAV API UX & Adatbázis Finomhangolás ### 🎯 Cél A NAV API működik, de a felhasználói élmény és az adatbázis szigorúsága finomhangolást igényelt. ### ✅ Implementáció #### 1. Cégjegyzékszám (company_registry_number) opcionálissá tétele - **Modell**: [`backend/app/models/marketplace/organization.py`](backend/app/models/marketplace/organization.py:89) - `reg_number: Mapped[Optional[str]]` már eleve nullable volt - **Schema**: [`backend/app/schemas/organization.py`](backend/app/schemas/organization.py:17) - `reg_number: Optional[str] = None` már eleve opcionális volt - **Adatbázis**: A `sync_engine` audit szerint a séma tökéletesen szinkronban van (1017/1017 elem OK) #### 2. Duplikáció szűrése a NAV lekérdezés előtt - **Végpont**: [`backend/app/api/v1/endpoints/organizations.py`](backend/app/api/v1/endpoints/organizations.py:124) - `GET /lookup-tax/{tax_number}` - Injektált `db: AsyncSession = Depends(get_db)` függőség - Mielőtt a NAV-hoz fordul, ellenőrzi az adatbázist az adószám első 8 számjegye (törzsszám) alapján - Ha létezik aktív cég (`is_deleted == False`), azonnal `HTTPException(status_code=409, detail="Ez az adószám már regisztrálva van a rendszerben.")` hibát dob #### 3. Rövid név okosítása (filler words filtering) - **Service**: [`backend/app/services/nav_service.py`](backend/app/services/nav_service.py:105) - `_format_company_names()` metódus - `filler_words` lista: `["és", "szolgáltató", "kereskedelmi", "üzleti", "tanácsadó", "ipari", "építőipari", "termelő", "fejlesztő", "kivitelező", "általános"]` - A rövid név generálásakor a név szavakra bontva, csak a nem-töltelék szavak maradnak meg - A cégforma rövidítés (pl. "Kft.") a legvégére kerül hozzáfűzésre - Fallback: ha minden szó töltelék volt, az eredeti név marad ### ✅ Verifikáció - Python import check: `nav_service.py` és `organizations.py` sikeresen importálódott - `sync_engine` audit: 1017/1017 elem OK, 0 hiba, teljes szinkron ## 2026-06-08 - UI/UX Navigációs Hibák Javítása (3 Bugfix) ### 🎯 Cél Három UI/UX és navigációs hiba javítása a Vue 3 frontendben: (1) cégnév/"Cégem" gomb navigáció `/company/garage`-ba, (2) Profil oldal bezárása backdrop overlay-re kattintva, (3) Avatar dropdown bezárása kattintáskor az elemen kívül. ### ✅ Implementáció #### 1. ProfileView.vue - Backdrop Overlay **Fájl**: [`frontend/src/views/ProfileView.vue`](frontend/src/views/ProfileView.vue:14) - Teljes oldalt lefedő backdrop overlay (`fixed inset-0 z-10 bg-black/30 backdrop-blur-[2px]`) a profil kártya körül - `@click="closeProfile"` a backdrop-on → kattintásra `router.push('/dashboard')` - `@click.stop` a belső kártya `div`-en → megakadályozza a bezáródást a kártyán belüli kattintáskor - `handleEscapeKey()`: Escape billentyűre bezárja a profilt (vagy a jelszó módosító modalt, ha az nyitva van) - `onMounted`/`onUnmounted`: `keydown` eseményfigyelő regisztráció/törlés #### 2. DashboardHeader.vue - Cégnév Navigáció **Fájl**: [`frontend/src/components/DashboardHeader.vue`](frontend/src/components/DashboardHeader.vue:157) - Cégnév (`activeCompanyName`) `