diff --git a/backend/app/schemas/__pycache__/auth.cpython-312.pyc b/backend/app/schemas/__pycache__/auth.cpython-312.pyc index ff49eba..04b8240 100644 Binary files a/backend/app/schemas/__pycache__/auth.cpython-312.pyc and b/backend/app/schemas/__pycache__/auth.cpython-312.pyc differ diff --git a/backend/app/schemas/auth.py b/backend/app/schemas/auth.py index b4d9c8d..0d862c4 100644 --- a/backend/app/schemas/auth.py +++ b/backend/app/schemas/auth.py @@ -1,7 +1,8 @@ from pydantic import BaseModel, EmailStr, Field -from typing import Optional +from typing import Optional, Dict from datetime import date +# --- STEP 1: LITE REGISTRATION --- class UserLiteRegister(BaseModel): email: EmailStr password: str = Field(..., min_length=8) @@ -13,6 +14,26 @@ class UserLogin(BaseModel): email: EmailStr password: str +# --- STEP 2: KYC & ONBOARDING --- +class ICEContact(BaseModel): + name: str + phone: str + relationship: Optional[str] = None + +class DocumentDetail(BaseModel): + number: str + expiry_date: date + +class UserKYCComplete(BaseModel): + phone_number: str + birth_place: str + birth_date: date + mothers_name: str + # Rugalmas okmánytár, pl: {"id_card": {"number": "123", "expiry_date": "2030-01-01"}} + identity_docs: Dict[str, DocumentDetail] + ice_contact: ICEContact + +# --- COMMON & SECURITY --- class PasswordResetRequest(BaseModel): email: EmailStr diff --git a/backend/app/services/__pycache__/auth_service.cpython-312.pyc b/backend/app/services/__pycache__/auth_service.cpython-312.pyc index 40fcca9..36c5e0d 100644 Binary files a/backend/app/services/__pycache__/auth_service.cpython-312.pyc and b/backend/app/services/__pycache__/auth_service.cpython-312.pyc differ diff --git a/backend/app/services/auth_service.py b/backend/app/services/auth_service.py index 64098ff..7805f84 100644 --- a/backend/app/services/auth_service.py +++ b/backend/app/services/auth_service.py @@ -2,9 +2,9 @@ from datetime import datetime, timedelta, timezone import uuid from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, text -from app.models.identity import User, Person, UserRole, VerificationToken +from app.models.identity import User, Person, UserRole, VerificationToken, Wallet from app.models.organization import Organization -from app.schemas.auth import UserLiteRegister +from app.schemas.auth import UserLiteRegister, UserKYCComplete from app.core.security import get_password_hash, verify_password from app.services.email_manager import email_manager from app.core.config import settings @@ -12,9 +12,9 @@ from app.core.config import settings class AuthService: @staticmethod async def register_lite(db: AsyncSession, user_in: UserLiteRegister): - """Step 1: Lite regisztráció kormányozható token élettartammal.""" + """Step 1: Lite regisztráció + Token generálás + Email.""" try: - # 1. Person shell + # 1. Person alap létrehozása new_person = Person( first_name=user_in.first_name, last_name=user_in.last_name, @@ -23,7 +23,7 @@ class AuthService: db.add(new_person) await db.flush() - # 2. User fiók + # 2. User technikai fiók new_user = User( email=user_in.email, hashed_password=get_password_hash(user_in.password), @@ -35,10 +35,8 @@ class AuthService: db.add(new_user) await db.flush() - # 3. Biztonsági Token (Beállítható élettartam) - # Default: 48 óra, ha nincs megadva a settingsben + # 3. Kormányozható Token generálása expire_hours = getattr(settings, "REGISTRATION_TOKEN_EXPIRE_HOURS", 48) - token_val = uuid.uuid4() new_token = VerificationToken( token=token_val, @@ -49,9 +47,8 @@ class AuthService: db.add(new_token) await db.flush() - # 4. Email küldés + # 4. Email küldés gombbal verification_link = f"{settings.FRONTEND_BASE_URL}/verify?token={token_val}" - try: await email_manager.send_email( recipient=user_in.email, @@ -62,7 +59,7 @@ class AuthService: } ) except Exception as email_err: - print(f"CRITICAL: Email sending failed: {str(email_err)}") + print(f"CRITICAL: Email failed: {str(email_err)}") await db.commit() await db.refresh(new_user) @@ -73,11 +70,9 @@ class AuthService: @staticmethod async def verify_email(db: AsyncSession, token_str: str): - """Token ellenőrzése és regisztráció megerősítése.""" + """Token ellenőrzése (Email megerősítés).""" try: - # Token UUID-vá alakítása az összehasonlításhoz token_uuid = uuid.UUID(token_str) - stmt = select(VerificationToken).where( VerificationToken.token == token_uuid, VerificationToken.is_used == False, @@ -89,18 +84,7 @@ class AuthService: if not token_obj: return False - # Token elhasználása token_obj.is_used = True - - # User keresése és aktiválása (Email megerősítve) - user_stmt = select(User).where(User.id == token_obj.user_id) - user_res = await db.execute(user_stmt) - user = user_res.scalar_one_or_none() - if user: - # Figyelem: A Master Book szerint ez még nem teljes aktiválás (is_active: false) - # de jelölhetjük, hogy az e-mail már OK. - pass - await db.commit() return True except Exception as e: @@ -108,19 +92,70 @@ class AuthService: await db.rollback() return False + @staticmethod + async def complete_kyc(db: AsyncSession, user_id: int, kyc_in: UserKYCComplete): + """Step 2: KYC adatok, Telefon, Privát Flotta és Wallet aktiválása.""" + try: + # 1. User és Person lekérése + stmt = select(User).where(User.id == user_id).join(User.person) + result = await db.execute(stmt) + user = result.scalar_one_or_none() + + if not user: + return None + + # 2. Személyes adatok rögzítése (tábla szinten) + p = user.person + p.phone = kyc_in.phone_number + p.birth_place = kyc_in.birth_place + p.birth_date = datetime.combine(kyc_in.birth_date, datetime.min.time()) + p.mothers_name = kyc_in.mothers_name + + # JSONB mezők mentése Pydantic modellekből + p.identity_docs = {k: v.dict() for k, v in kyc_in.identity_docs.items()} + p.ice_contact = kyc_in.ice_contact.dict() + p.is_active = True + + # 3. PRIVÁT FLOTTA (Organization) automata generálása + new_org = Organization( + name=f"{p.last_name} {p.first_name} - Privát Flotta", + owner_id=user.id, + is_active=True, + org_type="individual" + ) + db.add(new_org) + await db.flush() + + # 4. WALLET automata generálása + new_wallet = Wallet( + user_id=user.id, + coin_balance=0.00, + xp_balance=0 + ) + db.add(new_wallet) + + # 5. USER TELJES AKTIVÁLÁSA + user.is_active = True + + await db.commit() + await db.refresh(user) + return user + except Exception as e: + await db.rollback() + raise e + @staticmethod async def authenticate(db: AsyncSession, email: str, password: str): stmt = select(User).where(User.email == email, User.is_deleted == False) res = await db.execute(stmt) user = res.scalar_one_or_none() - if not user or not user.hashed_password or not verify_password(password, user.hashed_password): return None return user @staticmethod async def initiate_password_reset(db: AsyncSession, email: str): - """Jelszó-emlékeztető kormányozható élettartammal.""" + """Jelszó-visszaállítás indítása.""" stmt = select(User).where(User.email == email, User.is_deleted == False) res = await db.execute(stmt) user = res.scalar_one_or_none() @@ -137,7 +172,6 @@ class AuthService: db.add(new_token) reset_link = f"{settings.FRONTEND_BASE_URL}/reset-password?token={token_val}" - await email_manager.send_email( recipient=email, template_key="password_reset", diff --git a/docs/V01_gemini/05_AUTH_AND_IDENTITY_SPEC.md b/docs/V01_gemini/05_AUTH_AND_IDENTITY_SPEC.md index 27ef3c3..bd0bb7a 100644 --- a/docs/V01_gemini/05_AUTH_AND_IDENTITY_SPEC.md +++ b/docs/V01_gemini/05_AUTH_AND_IDENTITY_SPEC.md @@ -77,4 +77,27 @@ Minden regisztrációnál létrejön: ## IV. CÉGES AZONOSÍTÁS ÉS VERIFIKÁCIÓ ... - **Hibrid Validálás:** Ha a VIES API nem ad eredményt, a rendszer céges dokumentum feltöltését kéri. -- **Ellenőrzés:** Adminisztrátori jóváhagyás vagy AI-alapú dokumentum-validálás után válik `Verified` státuszúvá. \ No newline at end of file +- **Ellenőrzés:** Adminisztrátori jóváhagyás vagy AI-alapú dokumentum-validálás után válik `Verified` státuszúvá. + +# 🆔 Identitás Validációs és Bizalmi Protokoll + +A rendszer a fokozatos adatszolgáltatás és a "Tier-based Access Control" (szintezett hozzáférés) elvét alkalmazza. + +## 1. Bizalmi Szintek (Trust Tiers) + +| Szint | Megnevezés | Követelmény | Jogosultságok | +| :--- | :--- | :--- | :--- | +| **Tier 0** | Anonymous | Nincs | Csak publikus adatok megtekintése. | +| **Tier 1** | Verified Email | Step 1 sikeres | Belépés, saját profil megtekintése. | +| **Tier 2** | KYC Submitted | Step 2 (Személyi adatok + Telefon) | **Privát Széf/Flotta aktiválása**, Wallet használat. | +| **Tier 3** | AI/OCR Verified | Okmánykép AI általi ellenőrzése | Harmadik fél szolgáltatásainak igénybevétele. | + +## 2. Kötelező Adatkör (Step 2 - Tier 2) +A "Privát Széf" aktiválásához az alábbi adatok megadása kötelező: +- **Kapcsolat:** Valós telefonszám (nemzetközi formátum). +- **Személyi:** Születési hely, idő, anyja neve. +- **Okmány:** Típus, sorszám és **lejárati dátum**. +- **Biztonság:** ICE (In Case of Emergency) név és telefonszám. + +## 3. Adattárolási Stratégia +- A rugalmas okmányadatokat és vészhelyzeti kapcsolatokat a `persons.identity_docs` és `persons.ice_contact` JSONB mezőkben tároljuk a kereshetőség és bővíthetőség érdekében. \ No newline at end of file