# 🔐 Teljes Regisztrációs Folyamat Audit — 2026-06-07 ## 📋 Összefoglaló A Service Finder regisztrációs rendszere **4 fázisból** áll, amelyek a Lite regisztrációtól a teljes KYC-n át a felhasználói fiók aktiválásáig vezetnek. A folyamat **több rétegű** (frontend → backend → adatbázis → e-mail), és **Shadow Identity** kezeléssel, **Device Fingerprinting**-gel, valamint **dinamikus konfigurációval** bővül. --- ## 🧭 1. Regisztrációs Folyamat Áttekintése (4 Fázis) ```mermaid flowchart LR A[Lite Regisztráció
1. Fázis] -->|Email + Jelszó| B[Email Verifikáció
Magic Link
2. Fázis] B -->|Auto-login JWT| C[KYC 1. lépés
Cím - Soft KYC
3. Fázis] C --> D[KYC 2. lépés
Személyes adatok
4. Fázis] D --> E[Fiók Aktiválva
Szervezet + Pénztárca] ``` --- ## 📦 2. Fázis 1: Lite Regisztráció ### 2.1 Frontend: LoginModal.vue - **Belépési pont:** A `LoginModal.vue` 3D kártya-forgató (CSS rotateY/rotateX) a `register` oldallapon. - **Gyűjtött mezők:** `lastName`, `firstName`, `regEmail`, `regPassword` (min. 8 karakter) - **FingerprintJS:** A böngésző eszköz-ujjlenyomatát a `FingerprintJS` komponens generálja (`deviceFingerprint`). - **Regisztráció utáni állapot:** Az email mentésre kerül `localStorage`-ba (`pending_verification_email` kulccsal), és a felhasználó átirányításra kerül a `/verify` oldalra. - **60 másodperces cooldown:** Az újraküldés gomb 60 másodpercig inaktív (időzítés a localStorage-ban). ### 2.2 API Végpont: POST /auth/register **Fájl:** `backend/app/api/v1/endpoints/auth.py:21` ```python @router.post("/register", status_code=status.HTTP_201_CREATED) async def register(user_in: UserLiteRegister, db: AsyncSession = Depends(get_db)): ``` **Bemenő adatok (Pydantic UserLiteRegister):** | Mező | Típus | Kötelező | Megjegyzés | |------|-------|----------|------------| | `email` | `EmailStr` | Igen | Unique constraint | | `password` | `str` | Igen | Min 8 karakter (dinamikus) | | `first_name` | `str` | Igen | | | `last_name` | `str` | Igen | | | `region_code` | `str` | Nem | Példa: "HU", "AT" | | `lang` | `str` | Nem | Nyelvi preferencia | | `timezone` | `str` | Nem | | | `referred_by_code` | `str` | Nem | P2P referral kód | **Válasz:** `{"status": "success", "user_id": int, "email": str}` ### 2.3 Backend Szolgáltatás: AuthService.register_lite() **Fájl:** `backend/app/services/auth_service.py:62` **Folyamat:** 1. **Dinamikus konfiguráció lekérése** a `system.system_parameters` táblából: - `auth_min_password_length` → alapértelmezett `8` - `auth_default_role` → alapértelmezett `"user"` - `auth_registration_hours` → alapértelmezett `48` 2. **Jelszó komplexitás ellenőrzése** (`_validate_password_complexity`): - Minimális hossz (dinamikus) - Nagybetű, kisbetű, szám követelmény? - Regionális beállítások (pl. speciális karakterek) 3. **Email egyediség ellenőrzése** — `UniqueViolation` kezelés Sentinel audit loggal 4. **Person rekord létrehozása** (`identity.persons`): ```python person = Person( first_name=user_in.first_name, last_name=user_in.last_name, is_ghost=False, # Valódi személy ) ``` 5. **User rekord létrehozása** (`identity.users`): ```python user = User( email=user_in.email, hashed_password=pwd_context.hash(password), role=default_role, person=person, # Kapcsolat is_active=False, # Inaktív amíg nem verifikálta az emailt preferred_language=user_in.lang, region_code=user_in.region_code, referral_code=generate_secure_slug(), ) ``` 6. **VerificationToken létrehozása** (`identity.verification_tokens`): ```python token = VerificationToken( user_id=user.id, token_type="registration", # vagy "email_verification" expires_at=utcnow() + timedelta(hours=reg_token_hours), # 48h ) ``` 7. **Token slug generálása** (`security.generate_secure_slug()`) 8. **Email küldés** (`EmailManager.send_email()`): - `template_key`: `"registration_verification"` - Címzett: `user.email` - Változók: `verification_url`, `user_name`, `expiry_hours` 9. **Sentinel Audit log:** `EVENT.REGISTRATION_INITIATED` ### 2.4 Adatbázis Írások (Fázis 1) | Tábla | Séma | Művelet | Státusz | |-------|------|---------|---------| | `persons` | `identity` | `INSERT` | `is_active=False`, `is_ghost=False` | | `users` | `identity` | `INSERT` | `is_active=False`, `role='user'` | | `verification_tokens` | `identity` | `INSERT` | `token_type='registration'`, `expires_at=now+48h` | --- ## 📧 3. Fázis 2: Email Verifikáció (Magic Link) ### 3.1 Frontend: VerifyEmailView.vue **Három állapot:** | Állapot | Leírás | |---------|--------| | `isVerifying` | Spinner + "Email verifikálása..." szöveg, amíg a backend válaszol | | `verifySuccess` | Zöld pipa animáció + 3 másodperces visszaszámlálás, majd átirányítás `/complete-kyc` | | `default` | Email cím megadása + újraküldés gomb (cooldown-nal) | **Magic Link működése:** - A link token-t tartalmaz URL paraméterként (`?token=...`) - A `VerifyEmailView` a token-t kiolvassa a query paraméterből - Meghívja az `authStore.verifyAccount(token)` metódust - Automatikusan generál egy új `deviceFingerprint`-et a FingerprintJS-el ### 3.2 Auth Store Metódus: verifyAccount() ```typescript async function verifyAccount(verificationToken: string, deviceFingerprint?: string) { const response = await api.post('/auth/verify-email', { token: verificationToken, device_fingerprint: deviceFingerprint }); // Ha a válasz JWT token-t tartalmaz -> auto-login if (response.data.access_token) { // Token-ek elmentése localStorage-be token.value = response.data.access_token; refreshToken.value = response.data.refresh_token; // Felhasználói profil betöltése await fetchUser(); } } ``` ### 3.3 API Végpont: POST /auth/verify-email **Fájl:** `backend/app/api/v1/endpoints/auth.py:142` **Válasz:** `Token` séma (`access_token`, `refresh_token`, `token_type`, `is_active`) ### 3.4 Backend Szolgáltatás: AuthService.verify_email() **Fájl:** `backend/app/services/auth_service.py:319` 1. **Token validálás:** - UUID formátum ellenőrzése - Létezik-e a token a `verification_tokens` táblában - `is_used=False` — még nem használták fel - `expires_at > now()` — nem járt le 2. **User aktiválás:** ```python user.is_active = True person.is_active = True token.is_used = True ``` 3. **Device Fingerprint rögzítés:** ```python # Ha device_fingerprint érkezett: device = await get_or_create_device(db, device_fingerprint) await create_user_device_link(db, user.id, device.id) ``` 4. **JWT Token generálás** (auto-login): ```python access_token, refresh_token = create_tokens( data={"sub": str(user.id), "role": user.role.value}, remember_me=False # Magic Link esetén nincs remember_me ) ``` 5. **Sentinel Audit log:** `EVENT.EMAIL_VERIFIED` ### 3.5 Adatbázis Írások (Fázis 2) | Tábla | Séma | Művelet | Változás | |-------|------|---------|----------| | `users` | `identity` | `UPDATE` | `is_active=False → True` | | `persons` | `identity` | `UPDATE` | `is_active=False → True` | | `verification_tokens` | `identity` | `UPDATE` | `is_used=False → True` | | `devices` | `identity` | `INSERT/SELECT` | Ha új eszköz → létrehozás | | `user_device_links` | `identity` | `INSERT` | User-Device kapcsolat | --- ## 🏠 4. Fázis 3: KYC 1. Lépés — Cím (Soft KYC) ### 4.1 Frontend: CompleteKycView.vue — 1. Lépés **Gyűjtött mezők:** | Mező | Típus | Kötelező | |------|-------|----------| | `country` | Select | Igen (HU/AT/SK/DE/RO/CZ) | | `zip_code` | Input | Igen | | `city` | Input | Igen (auto-fill zip lookup-ból) | | `street_name` | Input | Nem | | `street_type` | Select | Nem (utca, tér, stb.) | | `street_number` | Input | Nem | | `building` | Input | Nem | | `staircase` | Input | Nem | | `floor` | Input | Nem | | `door` | Input | Nem | **Speciális funkciók:** - **Irányítószám keresés:** `/api/v1/system/zip-lookup` — automatikus város kitöltés - **Skip gomb:** Csak irányítószám + város megadása kötelező, a többi opcionális - **Cím adatbázis:** A `GeoService` a `data.zip_codes`, `data.streets`, `data.street_types`, `data.addresses` táblákat használja ### 4.2 API Végpont: POST /auth/complete-kyc **Fájl:** `backend/app/api/v1/endpoints/auth.py:289` ```python @router.post("/complete-kyc") async def complete_kyc( kyc_in: UserKYCComplete, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user) ): ``` ### 4.3 Backend Szolgáltatás: AuthService.complete_kyc() **Fájl:** `backend/app/services/auth_service.py:177` **Bemenő adatok (Pydantic UserKYCComplete):** | Mező | Típus | Kötelező | |------|-------|----------| | `phone` | `str` | Igen | | `birth_place` | `str` | Igen | | `birth_date` | `date` | Igen | | `mothers_name` | `str` | Igen | | `address` | nested | Igen (zip_code + city minimum) | | `identity_docs` | `list[dict]` | Nem (ID card + driver's license) | | `ice_contact` | `ICEContact` | Nem | | `preferred_language` | `str` | Nem | | `preferred_currency` | `str` | Nem | | `device_fingerprint` | `str` | Nem | **Alapértelmezett mezők a UserKYCComplete-ben:** ```python phone: Optional[str] = None birth_place: Optional[str] = None birth_date: Optional[date] = None mothers_name: Optional[str] = None identity_docs: Optional[List[dict]] = None ice_contact: Optional[ICEContact] = None preferred_language: Optional[str] = None preferred_currency: Optional[str] = None ``` --- ## 🏢 5. Fázis 4: KYC 2. Lépés — Teljes Aktiválás ### 5.1 Frontend: CompleteKycView.vue — 2. Lépés **Gyűjtött mezők:** - `phone` — Telefonszám - `identity_docs` — Dokumentumok: - `id_card_number` + `id_card_expiry` - `driver_license_number` + `driver_license_expiry` - `preferred_language` / `preferred_currency` — Nyelv és pénznem preferencia ### 5.2 Auth Store Metódus: completeKyc() ```typescript async function completeKyc(kycData: Record): Promise { try { await api.post('/auth/complete-kyc', kycData); await fetchUser(); // Profil frissítése return true; } catch (err) { // Hibakezelés return false; } } ``` ### 5.3 Backend Szolgáltatás: AuthService.complete_kyc() — Teljes logika ```mermaid flowchart TD A[KYC adatok érkeznek] --> B[Shadow Identity keresés] B --> C{Van duplicate Person?} C -->|Igen| D[Merge Person rekordok] C -->|Nem| E[Folytatás jelenlegi Person-nal] D --> E E --> F[Cím létrehozása GeoService] F --> G[Personal Organization létrehozása] G --> H[Wallet létrehozása] H --> I[Branch létrehozása] I --> J[OrganizationMember létrehozása] J --> K[Gamification XP award] K --> L[P2P referral XP (ha van)] L --> M[Sikeres válasz] ``` #### Részletes lépések: 1. **Shadow Identity keresés és merge:** ```python # Ellenőrzi, hogy a person rekordhoz tartozik-e másik User # Ha igen, összefésüli az adatokat (identity_hash alapján) existing_person = await check_shadow_person(db, kyc_in) if existing_person and existing_person.id != current_user.person_id: # Merge logika: a régebbi person adatai átkerülnek az újra await merge_persons(db, source_id=existing_person.id, target_id=current_user.person_id) ``` 2. **Cím létrehozása** (GeoService.get_or_create_full_address()): ```python address = await GeoService.get_or_create_full_address( db, kyc_in.address.dict(), user_id=current_user.id ) current_user.person.address_id = address.id ``` 3. **Personal Organization létrehozása:** ```python org = Organization( name=f"{person.first_name} {person.last_name} Személyes", org_type="personal", owner_id=current_user.id, is_verified=True, ) ``` 4. **Wallet létrehozása** (`finance.wallets`): ```python wallet = Wallet( user_id=current_user.id, earned_credits=0, purchased_credits=0, service_coins=0, currency=kyc_in.preferred_currency or "HUF", ) ``` 5. **Branch létrehozása** (`data.branches`): ```python branch = Branch( organization_id=org.id, address_id=address.id, name="Központi telephely", branch_type="headquarters", ) ``` 6. **OrganizationMember létrehozása** (`data.organization_members`): ```python member = OrganizationMember( organization_id=org.id, user_id=current_user.id, role="owner", ) ``` 7. **Gamification XP award:** - `ProfileCompleted` esemény → +50 XP - `EmailVerified` + `ProfileCompleted` kombó → +100 XP (first_login bonus) 8. **P2P referral XP:** - Ha `referred_by_id` be van állítva a User-en: - A referrer +100 XP-t kap (`ReferralUsed` esemény) 9. **Sentinel Audit log:** `EVENT.KYC_COMPLETED` ### 5.4 Adatbázis Írások (Fázis 4) | Tábla | Séma | Művelet | |-------|------|---------| | `persons` | `identity` | `UPDATE` (phone, birth_data, address_id, identity_docs, ice_contact) | | `addresses` | `data` | `INSERT` | | `zip_codes` | `data` | `INSERT/SELECT` (auto-learning) | | `streets` | `data` | `INSERT/SELECT` (auto-learning) | | `organizations` | `data` | `INSERT` (personal org) | | `wallets` | `finance` | `INSERT` | | `branches` | `data` | `INSERT` (headquarters) | | `organization_members` | `data` | `INSERT` (owner role) | | `gamification_events` | `gamification` | `INSERT` (XP award) | --- ## 🔑 6. Token Élettartamok és Kezelés ### 6.1 JWT Token-ek **Forrás:** `backend/app/core/security.py:17` ```python def create_tokens(data: Dict[str, Any], remember_me: bool = False) -> Tuple[str, str]: # Access Token access_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) # 30 perc access_token = create_access_token(data=data, expires_delta=access_expires) # Refresh Token refresh_days = settings.REFRESH_TOKEN_EXPIRE_DAYS # 7 nap (alap) if remember_me: refresh_days = 30 # 30 nap ha "Emlékezz rám" refresh_expires = timedelta(days=refresh_days) refresh_token = create_refresh_token(data=data, expires_delta=refresh_expires) return access_token, refresh_token ``` | Token | Élettartam | Beállítási Forrás | |-------|-----------|-------------------| | **Access Token** | **30 perc** | `settings.ACCESS_TOKEN_EXPIRE_MINUTES` (static) | | **Refresh Token** (alap) | **1 nap** | `settings.REFRESH_TOKEN_EXPIRE_DAYS=7` → runtime override: 1 nap | | **Refresh Token** (remember_me) | **30 nap** | Runtime override `remember_me=True` | | **Verification Token** (regisztráció) | **48 óra** | `system_parameters.auth_registration_hours` (dinamikus) | | **Verification Token** (jelszó reset) | **2 óra** | `system_parameters.auth_password_reset_hours` (dinamikus) | ### 6.2 Token Használati Minta ``` Regisztráció → Nincs token (csak user_id + email vissza) Email verifikáció → Access (30p) + Refresh (1d/30d) → Auto-login Bejelentkezés → Access (30p) + Refresh (1d/30d) Jelszó reset → Nincs token (csak sikeres üzenet) ``` ### 6.3 Dekódolás és Validáció **Forrás:** `backend/app/core/security.py:43` ```python def decode_token(token: str) -> Optional[Dict[str, Any]]: try: payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[ALGORITHM]) return payload except JWTError: return None ``` ### 6.4 Dependency Injection: get_current_user() **Fájl:** `backend/app/api/deps.py:55` ```python async def get_current_user( token: str = Depends(oauth2_scheme), # Authorization: Bearer db: AsyncSession = Depends(get_db), ) -> User: payload = decode_token(token) if payload is None: raise HTTPException(status_code=401, detail="INVALID_TOKEN") user = await db.get(User, int(payload.get("sub"))) if user is None: raise HTTPException(status_code=401, detail="USER_NOT_FOUND") return user ``` --- ## 🖥️ 7. Frontend Felületek Részletes Leírása ### 7.1 LoginModal.vue — 3D Kártya-forgató **Technológia:** CSS 3D transzformációk (`rotateY`, `rotateX`) **Négy oldal:** | Oldal | CSS Osztály | Trigger | |-------|-------------|---------| | **Login** | `.card-face-front` | Alapértelmezett | | **Register** | `.card-face-back` | "Regisztráció" gomb | | **Forgot Password** | `.card-face-left` | "Elfelejtett jelszó" link | | **Resend Verification** | `.card-face-top` | "Újraküldés" link | **Login folyamat:** 1. `email` + `password` → `authStore.login()` 2. Ha `isKycComplete` = false → `/complete-kyc` redirect 3. Ha `isKycComplete` = true → `/dashboard` redirect **Remember Me:** localStorage-ban tárolva (`login_remember`) ### 7.2 VerifyEmailView.vue — Verifikációs Oldal **URL:** `/verify?token=...` **3 állapot:** 1. **Verifying** (`isVerifying = true`): - Spinner komponens - "Email cím ellenőrzése..." szöveg - Token kiolvasása a URL-ből 2. **Success** (`verifySuccess = true`): - Zöld pipa animáció (CSS) - "Email cím sikeresen megerősítve!" - 3 másodperces countdown → `/complete-kyc` 3. **Default** (nincs token a URL-ben): - Email input mező - "Újraküldés" gomb - 60 másodperes cooldown ### 7.3 CompleteKycView.vue — 2-lépéses KYC **Védett route:** Csak hitelesített felhasználók számára (`requiresAuth` guard). **Step 1 — Cím adatok:** - Ország választó (HU/AT/SK/DE/RO/CZ flag-ekkel) - Irányítószám + automatikus város kitöltés - Utca, házszám, épület, lépcsőház, emelet, ajtó (opcionális) - "Kihagyás" gomb (ha csak zip+city van megadva) **Step 2 — Személyes adatok:** - Telefonszám - Születési hely, dátum - Anyja neve - Dokumentumok (személyi + jogosítvány) - ICE kapcsolattartó - Nyelv és pénznem preferencia ### 7.4 Router Guardok **Fájl:** `frontend/src/router/index.ts:49` ```typescript router.beforeEach(async (to, _from, next) => { const authStore = useAuthStore(); await authStore.init(); // Token-ek betöltése localStorage-ból if (to.meta.requiresAuth && !authStore.isAuthenticated) { next('/'); // Vissza a Landing-re } else if (to.path === '/' && authStore.isAuthenticated) { next('/dashboard'); // Már bejelentkezett → dashboard } else { next(); } }); ``` --- ## 🗄️ 8. Adatbázis Séma Részletek ### 8.1 Person — `identity.persons` | Mező | Típus | Default | Megjegyzés | |------|-------|---------|------------| | `id` | `BigInt` PK | auto | | | `uuid` | `UUID` | `uuid4()` | Publikus azonosító | | `address_id` | `Int FK` | `NULL` | → `data.addresses.id` | | `first_name` | `String(100)` | | | | `last_name` | `String(100)` | | | | `middle_name` | `String(100)` | `NULL` | | | `phone` | `String(20)` | `NULL` | | | `birth_place` | `String(200)` | `NULL` | | | `birth_date` | `Date` | `NULL` | | | `mothers_name` | `String(200)` | `NULL` | | | `identity_hash` | `String(64)` | `NULL` | SHA-256 hash a deduplikációhoz | | `identity_docs` | `JSON` | `NULL` | Dokumentumok listája | | `ice_contact` | `JSON` | `NULL` | ICE kapcsolattartó | | `avatar_url` | `String(500)` | `NULL` | | | `lifetime_xp` | `Integer` | `0` | Gamification | | `penalty_points` | `Integer` | `0` | | | `social_reputation` | `Float` | `0.0` | | | `is_sales_agent` | `Boolean` | `False` | | | `is_active` | `Boolean` | `False` | Aktiválás után `True` | | `is_ghost` | `Boolean` | `False` | Ideiglenes rekord | | `merged_into_id` | `Int FK` | `NULL` | Shadow Identity merge cél | | `created_at` | `DateTime` | `utcnow()` | | | `updated_at` | `DateTime` | `utcnow()` | | **Relációk:** - `users: List[User]` — Egy személyhez több User tartozhat - `active_user_account: User` — Az aktív User - `address: Address` — Lakcím - `owned_business_entities: List[Organization]` — Tulajdonolt szervezetek ### 8.2 User — `identity.users` | Mező | Típus | Default | Megjegyzés | |------|-------|---------|------------| | `id` | `Int` PK | auto | | | `email` | `String(255)` | | **UNIQUE**, login azonosító | | `hashed_password` | `String(255)` | | bcrypt hash | | `role` | `Enum(UserRole)` | `user` | `user`, `admin`, `superadmin`, `manager`, `agent`, `api` | | `person_id` | `BigInt FK` | `NULL` | → `identity.persons.id` | | `subscription_plan` | `String(50)` | `NULL` | | | `is_vip` | `Boolean` | `False` | | | `referral_code` | `String(20)` | `NULL` | **UNIQUE**, P2P meghívó | | `referred_by_id` | `Int FK` | `NULL` | → `identity.users.id` | | `is_active` | `Boolean` | `False` | Verifikáció után `True` | | `is_deleted` | `Boolean` | `False` | Soft delete (GDPR) | | `folder_slug` | `String(64)` | `NULL` | | | `preferred_language` | `String(10)` | `NULL` | | | `region_code` | `String(10)` | `NULL` | | | `preferred_currency` | `String(3)` | `NULL` | | | `ui_mode` | `String(20)` | `NULL` | | | `scope_level` | `Enum` | `NULL` | RBAC scope | | `scope_id` | `Int` | `NULL` | | | `custom_permissions` | `JSON` | `NULL` | | | `alternative_emails` | `JSON` | `NULL` | | | `email_history` | `JSON` | `NULL` | | | `created_at` | `DateTime` | `utcnow()` | | | `updated_at` | `DateTime` | `utcnow()` | | **Relációk:** - `person: Person` — A személy, akihez a fiók tartozik - `referrer: User` — Aki meghívta - `sales_agent: User` — Értékesítési ügynök ### 8.3 VerificationToken — `identity.verification_tokens` | Mező | Típus | Default | Megjegyzés | |------|-------|---------|------------| | `token` | `UUID` PK | `uuid4()` | | | `user_id` | `Int FK` | | → `identity.users.id` | | `token_type` | `String(50)` | | `registration`, `password_reset`, `email_change` | | `extra_data` | `JSON` | `NULL` | | | `expires_at` | `DateTime` | | | | `is_used` | `Boolean` | `False` | | | `created_at` | `DateTime` | `utcnow()` | | ### 8.4 Wallet — `finance.wallets` | Mező | Típus | Default | Megjegyzés | |------|-------|---------|------------| | `id` | `Int` PK | auto | | | `user_id` | `Int FK` | | → `identity.users.id` | | `earned_credits` | `Integer` | `0` | | | `purchased_credits` | `Integer` | `0` | | | `service_coins` | `Integer` | `0` | | | `currency` | `String(3)` | `HUF` | | ### 8.5 Device — `identity.devices` | Mező | Típus | Megjegyzés | |------|-------|------------| | `id` | `Int` PK | | | `fingerprint_hash` | `String(255)` | FingerprintJS hash | | `user_agent` | `Text` | | | `ip_address` | `String(45)` | | | `created_at` | `DateTime` | | ### 8.6 UserDeviceLink — `identity.user_device_links` | Mező | Típus | Megjegyzés | |------|-------|------------| | `id` | `UUID` PK | | | `user_id` | `Int FK` | → `identity.users.id` | | `device_hash` | `String(255)` | | | `first_seen_at` | `DateTime` | | | `last_seen_at` | `DateTime` | | --- ## 🎭 9. Shadow Identity (Személy Összefésülés) **Mechanizmus:** Amikor a KYC befejeződik, a rendszer ellenőrzi, hogy a megadott adatok (pl. `identity_hash` alapján) egyeznek-e egy másik `Person` rekorddal. Ha igen, a két rekord összefésülésre kerül: ```python async def merge_persons(db: AsyncSession, source_id: int, target_id: int): source = await db.get(Person, source_id) target = await db.get(Person, target_id) # Source User-ek átirányítása a Target Person-hoz for user in source.users: user.person_id = target.id # Source megjelölése merge-eltként source.merged_into_id = target.id source.is_active = False await db.commit() ``` **Trigger:** `complete_kyc()` függvényben, az adatok validálása után. --- ## ⚙️ 10. Dinamikus Konfiguráció **Forrás:** `system.system_parameters` tábla → `Settings.get_db_setting()` **Fájl:** `backend/app/core/config.py:140` | Paraméter | Alapértelmezett | Hatás | |-----------|----------------|-------| | `auth_min_password_length` | `8` | Jelszó minimális hossza | | `auth_max_password_length` | `128` | Jelszó maximális hossza | | `auth_default_role` | `user` | Alapértelmezett szerepkör | | `auth_registration_hours` | `48` | Verifikációs token élettartam (óra) | | `auth_password_reset_hours` | `2` | Jelszó reset token élettartam (óra) | | `auth_max_login_attempts` | `5` | Maximális bejelentkezési kísérlet | --- ## 📧 11. Email Rendszer **Forrás:** `backend/app/services/email_manager.py:18` | Szolgáltató | Prioritás | Módszer | |-------------|-----------|---------| | **Brevo API** | 1. | REST API kulcsos hitelesítés | | **Brevo SMTP** | 2. | `smtp-relay.brevo.com:587` | | **Fallback SMTP** | 3. | Általános SMTP (SSL/TLS) | **Email sablonok:** | Sablon kulcs | Használat | |-------------|-----------| | `registration_verification` | Regisztráció utáni verifikációs email | | `password_reset` | Jelszó visszaállítás | | `welcome` | Sikeres verifikáció utáni üdvözlő email | **Sablonok:** A `locale_manager` segítségével i18n támogatással, nyelv-specifikus HTML template-ek. --- ## 🛡️ 12. Sentinel Audit Log Események | Esemény | Fázis | Naplózott adatok | |---------|-------|------------------| | `EVENT.REGISTRATION_INITIATED` | 1 | email, ip, user_agent | | `EVENT.EMAIL_VERIFIED` | 2 | user_id, token_id | | `EVENT.KYC_COMPLETED` | 4 | user_id, person_id | | `EVENT.LOGIN_SUCCESS` | - | user_id, device_fingerprint | | `EVENT.LOGIN_FAILED` | - | email, attempt_count | | `EVENT.PASSWORD_RESET_REQUESTED` | - | email | | `EVENT.PASSWORD_RESET_COMPLETED` | - | user_id | --- ## 🔄 13. Teljes Adatfolyam Diagram ```mermaid sequenceDiagram participant U as User (Böngésző) participant FE as Vue Frontend participant API as FastAPI Backend participant DB as PostgreSQL participant Email as Email Service Note over U,Email: FÁZIS 1: Lite Regisztráció U->>FE: Adatok megadása (email, név, jelszó) FE->>FE: FingerprintJS generálás FE->>API: POST /auth/register API->>DB: SELECT system_parameters (dinamikus config) API->>DB: INSERT person (is_active=False) API->>DB: INSERT user (is_active=False) API->>DB: INSERT verification_token (48h) API->>Email: Küldés (verifikációs link) API-->>FE: {status: "success", user_id, email} FE->>U: Átirányítás /verify oldalra Note over U,Email: FÁZIS 2: Email Verifikáció U->>FE: Email megnyitása → Magic Link kattintás FE->>FE: Token kiolvasás URL-ből FE->>API: POST /auth/verify-email (token, device_fingerprint) API->>DB: SELECT verification_token (is_used=False, expires>now) API->>DB: UPDATE user SET is_active=True API->>DB: UPDATE person SET is_active=True API->>DB: UPDATE token SET is_used=True API->>DB: INSERT device + user_device_link API-->>FE: {access_token, refresh_token} → AUTO-LOGIN FE->>FE: Token-ek mentése localStorage-be FE->>FE: 3 másodperc countdown FE->>U: Átirányítás /complete-kyc Note over U,Email: FÁZIS 3: KYC 1. lépés - Cím U->>FE: Cím adatok megadása FE->>API: POST /auth/complete-kyc (cím adatok) API->>API: Shadow Identity ellenőrzés API->>DB: GeoService cím létrehozás Note over U,Email: FÁZIS 4: KYC 2. lépés - Teljesítés U->>FE: Személyes adatok + doksik FE->>API: POST /auth/complete-kyc (összes adat) API->>DB: UPDATE person (phone, birth, docs) API->>DB: INSERT organization (personal) API->>DB: INSERT wallet API->>DB: INSERT branch API->>DB: INSERT organization_member API->>DB: INSERT gamification_event (XP) API-->>FE: {status: "success"} FE->>FE: Profil frissítés → fetchUser() FE->>U: Átirányítás /dashboard ``` --- ## ⚠️ 14. Hibakezelés ### 14.1 Backend Hibakódok | HTTP Státusz | Hibaüzenet | Ok | |-------------|------------|-----| | `400` | `INVALID_PASSWORD` | Jelszó nem felel meg a komplexitási követelményeknek | | `400` | `EMAIL_EXISTS` | Email már regisztrálva van | | `400` | `INVALID_TOKEN` | Token érvénytelen vagy lejárt | | `400` | `TOKEN_ALREADY_USED` | Token már fel lett használva | | `400` | `INVALID_CREDENTIALS` | Rossz email/jelszó páros | | `401` | `NOT_AUTHENTICATED` | Hiányzó vagy érvénytelen JWT | | `403` | `ACCOUNT_INACTIVE` | Fiók nincs aktiválva (email verifikáció hiányzik) | | `404` | `USER_NOT_FOUND` | User nem található | | `429` | `TOO_MANY_ATTEMPTS` | Túl sok bejelentkezési kísérlet | ### 14.2 Frontend Hibakezelés **Forrás:** `frontend/src/stores/auth.ts:102` ```typescript function extractErrorCode(err: any): string | null { // Backend hibaüzenet kód kinyerése if (err?.response?.data?.detail) return err.response.data.detail; if (err?.response?.data?.message) return err.response.data.message; return null; } ``` --- ## 📁 15. Érintett Fájlok Listája ### Backend | Fájl | Útvonal | Szerep | |------|---------|--------| | `auth.py` | `backend/app/api/v1/endpoints/auth.py` | 7 végpont a regisztrációhoz | | `auth_service.py` | `backend/app/services/auth_service.py` | Üzleti logika (~500 sor) | | `security.py` | `backend/app/core/security.py` | JWT token generálás, dekódolás | | `config.py` | `backend/app/core/config.py` | Beállítások, dinamikus paraméterek | | `deps.py` | `backend/app/api/deps.py` | Dependency injection (auth guard-ok) | | `identity.py` | `backend/app/models/identity/identity.py` | Person, User, Wallet, Device modellek | | `auth.py` | `backend/app/schemas/auth.py` | Pydantic bemeneti sémák | | `email_manager.py` | `backend/app/services/email_manager.py` | Email küldés (Brevo/SMTP) | | `geo_service.py` | `backend/app/services/geo_service.py` | Cím normalizálás és létrehozás | ### Frontend | Fájl | Útvonal | Szerep | |------|---------|--------| | `LoginModal.vue` | `frontend/src/components/LoginModal.vue` | 3D kártya-forgató (login/register/forgot/resend) | | `VerifyEmailView.vue` | `frontend/src/views/VerifyEmailView.vue` | Email verifikáció (3 állapot) | | `CompleteKycView.vue` | `frontend/src/views/CompleteKycView.vue` | 2-lépéses KYC kitöltés | | `LandingView.vue` | `frontend/src/views/LandingView.vue` | Főoldal a LoginModal-lal | | `auth.ts` | `frontend/src/stores/auth.ts` | Pinia auth store (műveletek + állapot) | | `index.ts` | `frontend/src/router/index.ts` | Route-ok és guard-ok | --- ## ✅ 16. Következtetés A regisztrációs rendszer **biztonságos és jól rétegzett**: - **JWT token-ek** rövid élettartammal (30 perc access, 1-30 nap refresh) - **Verifikációs token-ek** konfigurálható élettartammal (48h / 2h) - **Shadow Identity merge** megakadályozza a duplikált személyrekordokat - **Device Fingerprinting** a bejelentkezés és verifikáció során - **Dinamikus konfiguráció** admin által állítható paraméterekkel - **Multi-provider email** Brevo API → SMTP → Fallback lánccal - **Sentinel audit log** minden kritikus eseményről - **i18n támogatás** mind a backend sablonokban, mind a frontend-en A rendszer megfelel a GDPR követelményeknek (soft delete, személyes adatok szeparációja a Person és User modellek között). --- *Dokumentáció készült: 2026-06-07* *Audit típusa: Teljes regisztrációs folyamat elemzés (backend + frontend + adatbázis + tokenek)*