frontend 2026-06-10 bontva a 2 felület
This commit is contained in:
Binary file not shown.
890
docs/auth_registration_full_audit_2026-06-07.md
Normal file
890
docs/auth_registration_full_audit_2026-06-07.md
Normal file
@@ -0,0 +1,890 @@
|
||||
# 🔐 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ó<br/>1. Fázis] -->|Email + Jelszó| B[Email Verifikáció<br/>Magic Link<br/>2. Fázis]
|
||||
B -->|Auto-login JWT| C[KYC 1. lépés<br/>Cím - Soft KYC<br/>3. Fázis]
|
||||
C --> D[KYC 2. lépés<br/>Személyes adatok<br/>4. Fázis]
|
||||
D --> E[Fiók Aktiválva<br/>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<string, any>): Promise<boolean> {
|
||||
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 <token>
|
||||
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)*
|
||||
138
docs/company_garage_onboarding_plan.md
Normal file
138
docs/company_garage_onboarding_plan.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# 🏗️ Logic Spec: Cég Garázsa (Company Onboarding & Garage UI)
|
||||
|
||||
## 1. Cél
|
||||
|
||||
Lehetővé tenni a felhasználó számára, hogy:
|
||||
1. Létrehozzon egy céget/szervezetet (Company Onboarding) 3 egyszerű lépésben
|
||||
2. A jobb felső sarokban lévő "Cég Garázsa" gombbal gyorsan elérje a cég flottáját
|
||||
3. Válthasson a személyes garázsa és a cég garázsa között
|
||||
|
||||
## 2. Meglévő Backend API
|
||||
|
||||
### Már létező végpontok:
|
||||
- **POST /api/v1/organizations/onboard** - Szervezet létrehozása (CorpOnboardIn séma)
|
||||
- **GET /api/v1/organizations/my** - Felhasználó szervezeteinek listája
|
||||
|
||||
### CorpOnboardIn séma mezői:
|
||||
full_name, name, display_name, tax_number, reg_number, country_code, language, default_currency, address_zip, address_city, address_street_name, address_street_type, address_house_number, address_stairwell, address_floor, address_door, address_hrsz, contacts
|
||||
|
||||
### Modell: Organization (fleet.organizations) + OrganizationMember + Branch
|
||||
|
||||
## 3. 3 Kártyára Bontva
|
||||
|
||||
### #217 - Backend API bővítés
|
||||
**Végpontok:**
|
||||
1. GET /api/v1/organizations/{org_id} - Részletes adatok
|
||||
2. PUT /api/v1/organizations/{org_id} - Frissítés
|
||||
3. PATCH /api/v1/users/me/active-organization - Aktív szervezet váltás
|
||||
4. DELETE /api/v1/organizations/{org_id} - Soft-delete
|
||||
|
||||
### #218 - Frontend 3-lépéses Onboarding UI
|
||||
**Komponensek:**
|
||||
1. CompanyOnboardingView.vue - 3-lépéses wizard (/company/onboard)
|
||||
2. CompanyGarageView.vue - Cég garázs (/company/garage)
|
||||
3. i18n kulcsok bővítése
|
||||
4. Router bővítés
|
||||
|
||||
### #219 - Cég Garázsa gomb + szervezetváltás
|
||||
**Header gomb 3 állapota:**
|
||||
1. Nincs cég -> "Cég létrehozása" -> /company/onboard
|
||||
2. Van cég, személyes mód -> "Cég Garázsa" -> PATCH + /company/garage
|
||||
3. Cég mód -> "Személyes mód" -> PATCH null + /dashboard
|
||||
|
||||
## 4. Header Layout
|
||||
```
|
||||
LOGO [≡ Funkciók] [🏢 Cég Garázsa] [🌐 EN] 👤
|
||||
```
|
||||
|
||||
## 5. Végrehajtási Sorrend
|
||||
1. #217 Backend API (előfeltétel)
|
||||
2. #218 Frontend Onboarding UI
|
||||
3. #219 Cég Garázsa gomb integráció
|
||||
|
||||
---
|
||||
|
||||
## 6. Vizsgálati Eredmények (2026-06-07) - users.py audit
|
||||
|
||||
### 6.1 PATCH /users/me/active-organization - MÁR IMPLEMENTÁLVA!
|
||||
A [`users.py`](backend/app/api/v1/endpoints/users.py:371) (371-434. sor) tartalmazza az aktív szervezet váltás végpontot:
|
||||
- Validálja, hogy a user tagja-e a szervezetnek (`OrganizationMember` lekérdezés)
|
||||
- Frissíti a `scope_id`-t az adatbázisban
|
||||
- Új JWT tokent generál a frissített `scope_id`-val
|
||||
- Visszaadja `UserWithTokenResponse`-t (user + új token)
|
||||
|
||||
### 6.2 PersonUpdate schema - NEM alkalmas cégadatokra
|
||||
A [`PersonUpdate`](backend/app/schemas/user.py:69) séma (69-91. sor) CSAK személyes adatokat tartalmaz:
|
||||
- `first_name`, `last_name`, `phone`
|
||||
- `mothers_last_name`, `mothers_first_name`
|
||||
- `birth_place`, `birth_date`
|
||||
- `identity_docs` (személyi, útlevél, jogsi)
|
||||
- `address_*` mezők
|
||||
- **NINCSENEK benne cég/business mezők**
|
||||
|
||||
### 6.3 Aktív szervezet váltás frontend integráció
|
||||
A frontend [`auth store`](frontend/src/stores/auth.ts:53) már tartalmazza:
|
||||
- `active_organization_id: number | null` a `UserProfile` interfészben
|
||||
- `scope_level`, `scope_id` mezők
|
||||
|
||||
### 6.4 Következtetés
|
||||
A **#217** kártya eredeti tervéből a `PATCH /users/me/active-organization` végpont **MÁR KÉSZ**.
|
||||
**Amit még kell a #217-ben:**
|
||||
- `GET /api/v1/organizations/{org_id}` - cég részletes adatainak lekérése
|
||||
- `PUT /api/v1/organizations/{org_id}` - cég adatainak frissítése
|
||||
- `DELETE /api/v1/organizations/{org_id}` - soft-delete
|
||||
|
||||
### 6.5 Típus inkonzisztencia
|
||||
Az [`ActiveOrganizationUpdate`](backend/app/schemas/user.py:107) séma `organization_id` mezője `Optional[str]` típusú, de az adatbázisban `integer`-ként használódik. Javítandó: `Optional[int]`.
|
||||
|
||||
## 7. Végrehajtási Sorrend (Frissítve)
|
||||
1. **#217** Backend API (már csak GET/PUT/DELETE kell - PATCH kész)
|
||||
2. **#218** Frontend Onboarding UI
|
||||
3. **#219** Cég Garázsa gomb integráció
|
||||
|
||||
---
|
||||
|
||||
## 8. KYC Privát Cég Vizsgálat (2026-06-07)
|
||||
|
||||
### 8.1 Hogyan jön létre a privát cég?
|
||||
A KYC lezárásakor az [`AuthService.complete_kyc`](backend/app/services/auth_service.py:249) metódus automatikusan létrehoz egy privát szervezetet:
|
||||
|
||||
```python
|
||||
new_org = Organization(
|
||||
full_name=org_full_name, # "{last_name} Flotta"
|
||||
name=f"{p.last_name} Széfe", # pl. "Nagy Széfe"
|
||||
org_type=OrgType.individual, # <-- PRIVÁT CÉG FLAG!
|
||||
owner_id=user.id,
|
||||
status="verified", # Azonnal verified
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
### 8.2 Van flag a privát cég azonosítására?
|
||||
**IGEN.** Az [`OrgType`](backend/app/models/marketplace/organization.py:19) enum `individual` értéke szolgál privátcég-jelzőként.
|
||||
|
||||
| org_type érték | Jelentés | Hol jön létre? |
|
||||
|---|---|---|
|
||||
| `individual` | Privát személyes "széf" | KYC lezárás (`auth_service.py:255`) |
|
||||
| `business` | Valódi cég | `/organizations/onboard` végpont (`organizations.py:70`) |
|
||||
| `service` | Szerviz | Későbbi regisztráció |
|
||||
| `service_provider` | Szolgáltató partner | Későbbi regisztráció |
|
||||
| `fleet_owner` | Flottatulajdonos | Későbbi regisztráció |
|
||||
| `club` | Klub | Későbbi regisztráció |
|
||||
|
||||
### 8.3 Különbségek: Privát vs Valódi cég
|
||||
|
||||
| Tulajdonság | Privát (KYC) | Valódi (/onboard) |
|
||||
|---|---|---|
|
||||
| `org_type` | `individual` | `business` |
|
||||
| `status` | `verified` | `pending_verification` |
|
||||
| `tax_number` | NULL | Kötelező |
|
||||
| Név | `"{last_name} Flotta"` | Valós cégnév |
|
||||
| Branch | `"Home Base"` | `"Központi Telephely"` |
|
||||
|
||||
### 8.4 Hatás a #219-es kártyára
|
||||
A "Cég Garázsa" gomb logikája:
|
||||
1. `GET /organizations/my` → visszaadja a user összes szervezetét
|
||||
2. `org_type == "individual"` → privát garázs gomb
|
||||
3. `org_type == "business"` → cég garázs gomb
|
||||
4. `PATCH /users/me/active-organization` → váltás a kettő között
|
||||
239
docs/frontend_architecture_2_0_feasibility_analysis.md
Normal file
239
docs/frontend_architecture_2_0_feasibility_analysis.md
Normal file
@@ -0,0 +1,239 @@
|
||||
# Frontend Architektúra 2.0 & Dinamikus Megjelenítési Rendszer
|
||||
## Megvalósíthatósági Elemzés
|
||||
|
||||
**Dátum:** 2026-06-08
|
||||
**Készítette:** Rendszer-Architect
|
||||
**Mérföldkő:** #26 - Frontend Architektúra 2.0 & Dinamikus Megjelenítési Rendszer
|
||||
|
||||
---
|
||||
|
||||
## 📊 Készültségi Összesítő
|
||||
|
||||
| Kártya | Cím | Készültség | Függőség | Fázis |
|
||||
|--------|-----|-----------|---------|-------|
|
||||
| #228 | JSONB `visual_settings` | **0%** | - | 1. Backend |
|
||||
| #229 | RBAC/ABAC Engedélyezés | **40%** | #228 (opc.) | 1. Backend |
|
||||
| #230 | Dinamikus/Statikus Fordítás | **80%** | - | 3. i18n |
|
||||
| #231 | Layout komponensek | **60%** | #232 | 2. Frontend |
|
||||
| #232 | Vue Router Nested Routing | **50%** | #231 | 2. Frontend |
|
||||
| #233 | i18n audit | **30%** | #230, #232 | 3. i18n |
|
||||
| #234 | Tailwind Témaváltó | **0%** | #228, #229 | 3. Téma |
|
||||
| #235 | Expansion Card | **0%** | #232 | 4. UI Kit |
|
||||
| #236 | Vészjelző Rendszer | **10%** | #232 | 4. UI Kit |
|
||||
|
||||
---
|
||||
|
||||
## 1. FÁZIS: Adatbázis és Backend Alapozás
|
||||
|
||||
### 🔴 #228 - JSONB `visual_settings` (0% kész)
|
||||
|
||||
**Már létezik:**
|
||||
- Nincs `visual_settings` mező sem a `User` modellen, sem az `Organization` modellen
|
||||
- Az `Organization.notification_settings` (`JSON`) és `Organization.external_integration_config` (`JSON`) mintaként szolgálnak a JSONB használathoz
|
||||
- A `User.custom_permissions` (`JSON`) szintén minta a JSON mezőkhöz
|
||||
|
||||
**Hiányzik:**
|
||||
- `visual_settings` JSONB mező a `User` táblában (pl.: `theme_mode`, `primary_color`, `animations_enabled`, `compact_mode`)
|
||||
- `visual_settings` JSONB mező az `Organization` táblában (pl.: `wall_logo_url`, `brand_color`, `custom_css_overrides`)
|
||||
- Backend API végpont: `PATCH /users/me/visual-settings`, `PATCH /organizations/{id}/visual-settings`
|
||||
- A `UserProfile` interface-ben nincs `visual_settings` mező
|
||||
- Az `OrganizationItem` interface-ben nincs `visual_settings` mező
|
||||
|
||||
---
|
||||
|
||||
### 🟡 #229 - RBAC/ABAC Engedélyezés (40% kész)
|
||||
|
||||
**Már létezik:**
|
||||
- `UserRole` enum: `superadmin`, `admin`, `user`, `fleet_manager`, `sales`, `guest`
|
||||
- `OrgUserRole` enum: `owner`, `admin`, `manager`, `driver`, `viewer`
|
||||
- `User.subscription_plan`: `server_default="FREE"`
|
||||
- `Organization.subscription_plan`: létező mező
|
||||
- `User.custom_permissions`: JSON mező (kiterjeszthető ABAC-hoz)
|
||||
- `UserProfile`: `role`, `subscription_plan`, `scope_level` mezők léteznek
|
||||
- `OrganizationItem`: `subscription_plan` mező létezik
|
||||
|
||||
**Hiányzik:**
|
||||
- `allow_custom_skin` és `allow_advanced_animations` feature flag-ok a subscription_plan JSON-ben
|
||||
- Backend feature flag check utility/service
|
||||
- Frontend `hasFeature(featureName: string): boolean` metódus
|
||||
- Subscription plan definíciók (FREE=max 3 vehicle, BASIC=10, PREMIUM=unlimited)
|
||||
|
||||
---
|
||||
|
||||
## 2. FÁZIS: Frontend Struktúra & Layout Szétválasztás
|
||||
|
||||
### 🟡 #231 - Layout komponensek (60% kész)
|
||||
|
||||
**Már létezik:**
|
||||
- `ConsumerLayout.vue`: **195 sor**, teljes layout headerrel, footerral, dekorációs elemekkel, quick actions grid-del
|
||||
- `CorporateLayout.vue`: **98 sor**, céges sidebar, quick stats placeholder-ekkel
|
||||
- `AdminLayout.vue`: **195 sor**, admin sötét sidebar
|
||||
- Mindhárom layout `<slot />`-ot használ a tartalom beillesztésére
|
||||
|
||||
**Hiányzik:**
|
||||
- **KRITIKUS**: `<slot />` → `<router-view />` csere mindhárom layout-ban
|
||||
- `ConsumerLayout.vue` átnevezése `PrivateLayout.vue`-ra
|
||||
- `CorporateLayout.vue` átnevezése `OrganizationLayout.vue`-ra
|
||||
- "Privát felület" gomb az `OrganizationLayout.vue`-ban (auth store `switchOrganization(null)` hívás)
|
||||
- "Céges felület" gomb a `PrivateLayout.vue`-ban (első business org-ra váltás)
|
||||
- Layout transition animációk (`<Transition>` wrapper)
|
||||
|
||||
---
|
||||
|
||||
### 🟡 #232 - Vue Router átírás Nested Routing (50% kész)
|
||||
|
||||
**Már létezik:**
|
||||
- `router/index.ts`: **83 sor**, globális `beforeEach` guard, auth ellenőrzés, landing redirect
|
||||
- Route-ok: `/`, `/dashboard`, `/complete-kyc`, `/profile`, `/verify`, `/reset-password`, `/company/onboard`, `/company/garage`
|
||||
- `beforeEach` guard: kezeli a `requiresAuth` meta-t, token ellenőrzést
|
||||
|
||||
**Hiányzik:**
|
||||
- **Nincs nested routing** - minden route gyökér szinten
|
||||
- Nincs layout wrapper pattern
|
||||
- `/company/garage` route-nak nincs `/:id` paramétere
|
||||
- Route meta kiterjesztése: `meta: { layout: 'private' | 'organization' | 'admin', requiresOrg: boolean }`
|
||||
|
||||
**Cél nested struktúra:**
|
||||
```typescript
|
||||
{
|
||||
path: '/',
|
||||
component: PrivateLayout,
|
||||
children: [
|
||||
{ path: '', name: 'Landing', component: LandingView },
|
||||
{ path: 'dashboard', name: 'Dashboard', component: DashboardView, meta: { requiresAuth: true } },
|
||||
{ path: 'profile', name: 'Profile', component: ProfileView, meta: { requiresAuth: true } },
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/company/:id',
|
||||
component: OrganizationLayout,
|
||||
children: [
|
||||
{ path: 'dashboard', name: 'OrgDashboard', component: OrgDashboardView, meta: { requiresAuth: true, requiresOrg: true } },
|
||||
{ path: 'garage', name: 'OrgGarage', component: CompanyGarageView, meta: { requiresAuth: true, requiresOrg: true } },
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. FÁZIS: Többnyelvűség (i18n) & Vizuális Témaváltó
|
||||
|
||||
### 🟢 #230 - Dinamikus és Statikus Fordítási Rendszer (80% kész)
|
||||
|
||||
**Már létezik:**
|
||||
- **Backend**: `Translation` modell - **TELJESEN KÉSZ** (`system.translations` tábla)
|
||||
- **Frontend**: `vue-i18n` beüzemelve `legacy: false` módban, `detectLocale()` függvénnyel
|
||||
- 6 nyelvi fájl: `hu.ts`, `en.ts`, `de.ts`, `ro.ts`, `cz.ts`, `sk.ts`
|
||||
- `translationService.ts`: `fetchTranslations()`, `fetchAllTranslations()`, `updateTranslation()`
|
||||
- `appModeStore.ts`: `setLanguage(lang)`, `loadTranslations(lang)`, `getTranslation(key, defaultValue)`
|
||||
- `LanguageSwitcher.vue`: létező komponens
|
||||
|
||||
**Hiányzik:**
|
||||
- Backend API végpontok ellenőrzése (létezik-e `GET /api/v1/translations`?)
|
||||
- Cache stratégia a dinamikus fordításokhoz (localStorage + verziószám)
|
||||
|
||||
---
|
||||
|
||||
### 🟠 #233 - i18n audit és szövegek kiszervezése (30% kész)
|
||||
|
||||
**Már létezik:**
|
||||
- 6 db nyelvi fájl a `frontend/src/i18n/` mappában
|
||||
- `hu.ts` kulcsstruktúra: `menu.*`, `header.*`, `dashboard.*`, `zen.*`, `auth.*`
|
||||
- `DashboardHeader.vue` részleges i18n használat (`{{ t('menu.features') }}`)
|
||||
- Backend JSON locale fájlok: `backend/static/locales/hu.json`
|
||||
|
||||
**Hiányzik - Hardcoded szövegek:**
|
||||
|
||||
1. **`DashboardView.vue`**: `SZERVIZNAPTÁR`, `SERVICE FINDER`, `Irányítópultod és járműveid áttekintése`
|
||||
2. **`ConsumerLayout.vue`**: `Vehicle Registration`, `Service Booking`, `Cost Tracking`, `Tracking`, `Documents` (6 db), `© 2024 Your Company. All rights reserved.`
|
||||
3. **`CorporateLayout.vue`**: `Organization`, `Overview`, `Vehicles`, `Drivers`, `Maintenance`, `Reports` (6 db sidebar), `42 vehicles`, `7 pending`, `€12,450`
|
||||
4. **`CompanyGarageView.vue`**: `Céges garázs`
|
||||
|
||||
**Hiányzó i18n kulcsok:**
|
||||
- `garage.private.title`, `garage.company.title`
|
||||
- `buttons.next`, `buttons.save`, `buttons.cancel`
|
||||
- `errors.*` (validációs hibák)
|
||||
- `organization.*` (szervezeti nézetek)
|
||||
- `layout.*` (layout elemek)
|
||||
- `quickActions.*` (gyors akciók)
|
||||
|
||||
---
|
||||
|
||||
### 🔴 #234 - Tailwind CSS Változók és Témakezelő (0% kész)
|
||||
|
||||
**Már létezik:**
|
||||
- `tailwind.config.js`: **38 sor**, egyedi színrendszer (sf-wall, sf-green, sf-blue, sf-accent, sf-dark stb.)
|
||||
- `main.css`: **117 sor**, `btn-premium`, `hotspot-pulse`, `hotspot-ring` animációk
|
||||
|
||||
**Hiányzik:**
|
||||
- **CSS Custom Properties** a `tailwind.config.js`-ben - nincs `var(--theme-*)` referencia
|
||||
- `AppThemeStore` Pinia store - nem létezik
|
||||
- Témaváltó logika: `light`, `dark`, `corporate` módok
|
||||
- `:root` CSS változók (`--theme-bg`, `--theme-primary`, `--theme-text`, `--theme-accent`, `--theme-glass`)
|
||||
- Sötét mód CSS (`dark:` osztályok hiányoznak)
|
||||
- `applyTheme(settings)` függvény
|
||||
|
||||
---
|
||||
|
||||
## 4. FÁZIS: Animált UI Készlet
|
||||
|
||||
### 🔴 #235 - Expansion Card komponens (0% kész)
|
||||
|
||||
**Már létezik:**
|
||||
- Nincs dedikált Expansion/ExpandableCard komponens
|
||||
- A `DashboardView.vue` jármű kártyái group hover effekteket használnak
|
||||
|
||||
**Hiányzik:**
|
||||
- Teljes `ExpansionCard.vue` komponens (Vue 3 `<script setup lang="ts">`)
|
||||
- Props: `title`, `subtitle`, `icon`, `expanded` (v-model), `variant` ('default' | 'premium' | 'glass')
|
||||
- Animációk: `@keyframes expandIn` / `expandOut`
|
||||
- Slots: `#header`, `#default`, `#actions`
|
||||
|
||||
---
|
||||
|
||||
### 🟠 #236 - Kontextuális Vészjelző Rendszer (10% kész)
|
||||
|
||||
**Már létezik:**
|
||||
- `hotspot-pulse` és `hotspot-ring` animációk a `main.css`-ben
|
||||
- `ConsumerLayout.vue` scoped CSS pulse animáció
|
||||
- Base alert stílus a `btn-premium` osztályban (glassmorphism)
|
||||
|
||||
**Hiányzik:**
|
||||
- `ContextAlert.vue` komponens - nem létezik
|
||||
- Props: `type` ('info' | 'warning' | 'error' | 'success'), `message`, `autoClose`, `dismissible`, `action`
|
||||
- Alert store (`useAlertStore` Pinia store)
|
||||
- Animációk: belépés (`slideInDown`), kilépés (`fadeOutUp`)
|
||||
- Global alert renderelés (App.vue)
|
||||
- Z-index kezelés
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Ajánlott Implementációs Sorrend
|
||||
|
||||
```
|
||||
Fázis 1 (Backend alapozás):
|
||||
#228 (JSONB) ──► #229 (RBAC)
|
||||
|
||||
Fázis 2 (Frontend struktúra):
|
||||
#231 (Layout-ok) ──► #232 (Router)
|
||||
|
||||
Fázis 3 (i18n + Téma):
|
||||
#230 (Fordítás) ──► #233 (i18n audit)
|
||||
#234 (Témaváltó) - független a #228/#229-től, de azok adják az adatforrást
|
||||
|
||||
Fázis 4 (UI Kit):
|
||||
#235 (Expansion Card) - független
|
||||
#236 (Alert System) - független
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Breaking Change Kockázatok
|
||||
|
||||
| Változtatás | Érintett komponensek | Kockázat |
|
||||
|------------|---------------------|---------|
|
||||
| `<slot />` → `<router-view />` | Minden view | 🔴 Magas |
|
||||
| Layout átnevezés | Importok minden fájlban | 🟡 Közepes |
|
||||
| CSS variable bevezetés | Minden komponens színe | 🔴 Magas |
|
||||
| Router nested átírás | beforeEach guard, view path-ok | 🔴 Magas |
|
||||
| i18n kulcs átnevezés | Minden `$t()` hívás | 🟡 Közepes |
|
||||
114
docs/frontend_white_screen_analysis_2026-06-07.md
Normal file
114
docs/frontend_white_screen_analysis_2026-06-07.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# Frontend White Screen Analysis - 2026-06-07
|
||||
|
||||
## Summary
|
||||
|
||||
The `app.servicefinder.hu` page was loading as a blank/white screen.
|
||||
**Root cause:** Missing `flag-icons` npm package inside the frontend container.
|
||||
|
||||
---
|
||||
|
||||
## 1. Investigation Steps
|
||||
|
||||
### 1.1 Docker Container Status
|
||||
- `sf_public_frontend`: **Up** (running)
|
||||
- `sf_api`: **Up** (running)
|
||||
- Backend API reachable: `localhost:8000/api/v1/health` → responds
|
||||
|
||||
### 1.2 Frontend Container Logs
|
||||
**Primary error (repetitive):**
|
||||
```
|
||||
[vite] Internal server error: Failed to resolve import "flag-icons/css/flag-icons.css" from "src/main.ts". Does the file exist?
|
||||
File: /app/src/main.ts:13:7
|
||||
11 | import sk from "./i18n/sk";
|
||||
12 | import "./assets/main.css";
|
||||
13 | import "flag-icons/css/flag-icons.css";
|
||||
| ^
|
||||
```
|
||||
|
||||
### 1.3 Critical File Verification (all exist)
|
||||
- `frontend/src/components/Logo.vue` - Exists
|
||||
- `frontend/src/stores/vehicle.ts` - Exists
|
||||
- `frontend/src/views/organization/CompanyOnboardingView.vue` - Exists
|
||||
- `frontend/src/views/organization/CompanyGarageView.vue` - Exists
|
||||
|
||||
### 1.4 Dependency Check
|
||||
- `frontend/package.json` contains `"flag-icons": "^7.5.0"` - OK
|
||||
- Container `/app/node_modules/flag-icons`: **MISSING** - FAIL
|
||||
|
||||
---
|
||||
|
||||
## 2. Root Cause Analysis
|
||||
|
||||
### 2.1 System Architecture
|
||||
From `docker-compose.yml:302-318`:
|
||||
```yaml
|
||||
sf_public_frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile.dev
|
||||
volumes:
|
||||
- ./frontend:/app
|
||||
- /app/node_modules # Anonymous volume isolates node_modules
|
||||
```
|
||||
|
||||
From `frontend/Dockerfile.dev:10`:
|
||||
```dockerfile
|
||||
RUN npm install # Runs at BUILD time
|
||||
```
|
||||
|
||||
### 2.2 Failure Mechanism
|
||||
1. `flag-icons` was added to `package.json` (and `package-lock.json` updated)
|
||||
2. The container was **not rebuilt** after the package.json change
|
||||
3. The anonymous volume (`/app/node_modules`) **preserved the old node_modules state**
|
||||
4. Since volumes take precedence over `COPY`/`RUN` instructions, `npm install` never ran
|
||||
5. Vite couldn't find `flag-icons/css/flag-icons.css` at startup
|
||||
6. Result: **Internal server error** → **White screen**
|
||||
|
||||
---
|
||||
|
||||
## 3. Fix Applied
|
||||
|
||||
### 3.1 Install Package Inside Container
|
||||
```bash
|
||||
docker exec sf_public_frontend npm install
|
||||
```
|
||||
Result: `added 6 packages, changed 15 packages, and audited 281 packages`
|
||||
|
||||
### 3.2 Restart Vite Dev Server
|
||||
```bash
|
||||
docker compose restart sf_public_frontend
|
||||
```
|
||||
Result: `VITE v5.4.21 ready in 341 ms` - **running without errors**
|
||||
|
||||
---
|
||||
|
||||
## 4. Secondary Observations (non-blocking)
|
||||
|
||||
### 4.1 ProfileView Address Display Issue
|
||||
In `frontend/src/views/ProfileView.vue:370-382`, the read-only view uses:
|
||||
```vue
|
||||
<template v-if="person?.address?.address_zip || person?.address?.address_city">
|
||||
```
|
||||
This references a **nested** `address` object, but the new backend format sends address fields **flat** (e.g., `person.address_zip`, not `person.address.address_zip`). The edit mode correctly uses flat `editForm.address_zip`.
|
||||
|
||||
**Recommendation:** Change read-only display from `person?.address?.address_*` to `person?.address_*`.
|
||||
|
||||
### 4.2 Circular Dependency (safe)
|
||||
- `router/index.ts` dynamically imports `stores/auth` in `beforeEach` guard
|
||||
- `stores/auth.ts` statically imports `router`
|
||||
- This is **safe** because the dynamic import runs only on navigation events, after the router is fully initialized.
|
||||
|
||||
---
|
||||
|
||||
## 5. Prevention Recommendations
|
||||
|
||||
### 5.1 Future Prevention
|
||||
1. **Rebuild trigger**: When `package.json` changes, always rebuild the image:
|
||||
```bash
|
||||
docker compose up -d --build sf_public_frontend
|
||||
```
|
||||
2. **Pre-start npm install**: Modify `CMD` to run `npm install` before starting:
|
||||
```dockerfile
|
||||
CMD npm install && npm run dev -- --host 0.0.0.0
|
||||
```
|
||||
3. **Anonymous volume awareness**: The anonymous volume preserves old node_modules. When package.json changes, rebuild the container, don't just restart.
|
||||
145
docs/gitea_open_cards_summary_2026-06-09.md
Normal file
145
docs/gitea_open_cards_summary_2026-06-09.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# Gitea Nyitott Kártyák Összefoglaló
|
||||
|
||||
**Dátum:** 2026-06-09
|
||||
**Lekérdezés:** `docker exec roo-helper python3 /scripts/gitea_manager.py list`
|
||||
**Összes nyitott kártya:** **63 db**
|
||||
|
||||
---
|
||||
|
||||
## Összesítés Mérföldkövek Szerint
|
||||
|
||||
| Mérföldkő | Kártyák száma |
|
||||
|---|---|
|
||||
| Grafikai Komponensek & Frontend Skin Rendszer | 4 |
|
||||
| Frontend Architektúra 2.0 & Dinamikus Megjelenítési Rendszer | 20 |
|
||||
| Phase 4: Testing & Deployment | 7 |
|
||||
| Phase 3: Advanced Features & Epic 11 | 6 |
|
||||
| Phase 2: Dashboard & Analytics Wiring | 6 |
|
||||
| Phase 1: Core Functionality Fixes | 4 |
|
||||
| Nincs mérföldkő (egyéb / dashboard) | 16 |
|
||||
|
||||
---
|
||||
|
||||
## 1. Grafikai Komponensek & Frontend Skin Rendszer (4 kártya)
|
||||
|
||||
| ID | Cím |
|
||||
|----|------|
|
||||
| #256 | Skin Rendszer Alapok - Dinamikus Háttérv |
|
||||
| #255 | Lucide Ikonkészlet Integráció (lucide-vu) |
|
||||
| #253 | Háttérkép: garage_theme_dark.png |
|
||||
| #252 | Háttérkép: garage_company_clean.png (sf_) |
|
||||
|
||||
---
|
||||
|
||||
## 2. Frontend Architektúra 2.0 & Dinamikus Megjelenítési Rendszer (20 kártya)
|
||||
|
||||
| ID | Cím |
|
||||
|----|------|
|
||||
| #250 | 4.2-A: ContextAlert.vue komponens + useA |
|
||||
| #249 | 4.1-A: ExpansionCard.vue komponens + ani |
|
||||
| #248 | 3.2-B: AppThemeStore létrehozása + apply |
|
||||
| #247 | 3.2-A: CSS Custom Properties + tailwind. |
|
||||
| #246 | 3.1-B: Hardcoded szövegek cseréje 5 komp |
|
||||
| #245 | 3.1-A: Hiányzó i18n kulcsok felvétele |
|
||||
| #244 | 2.2-B: View-ok áthelyezése nested strukt |
|
||||
| #243 | 2.2-A: Route meta kiterjesztés + beforeE |
|
||||
| #242 | 2.1-B: Layout-váltó gombok (Privat <-> C) |
|
||||
| #241 | 2.1-A: Layout-ok átnevezése és <slot /> |
|
||||
| #240 | 1.2-B: Frontend useFeatureFlag() composa |
|
||||
| #239 | 1.2-A: Backend subscription_service.py + |
|
||||
| #238 | 1.1-B: Frontend useVisualSettings() comp |
|
||||
| #236 | 4.2: Kontextuális Vészjelző Rendszer |
|
||||
| #234 | 3.2: Tailwind CSS Változók és Témakezelő |
|
||||
| #233 | 3.1: Jelenlegi állapot felmérése |
|
||||
| #232 | 2.2: Vue Router átírás (Nested Routing) |
|
||||
| #231 | 2.1: Független Layout komponensek felépí |
|
||||
| #230 | 1.3: Dinamikus és Statikus f |
|
||||
| #229 | 1.2: Engedélyezési szintek és Funkciókap |
|
||||
|
||||
---
|
||||
|
||||
## 3. Phase 4: Testing & Deployment (7 kártya)
|
||||
|
||||
| ID | Cím |
|
||||
|----|------|
|
||||
| #165 | Production Deployment and Monitoring Set |
|
||||
| #164 | CI/CD Pipeline Setup (GitHub Actions) |
|
||||
| #163 | Security Audit (Penetration Testing) |
|
||||
| #162 | Accessibility Audit and Fixes (WCAG 2.1) |
|
||||
| #161 | Performance Optimization |
|
||||
| #160 | Implement Integration Tests (Playwright) |
|
||||
| #159 | Write Unit Tests for Critical Components |
|
||||
|
||||
---
|
||||
|
||||
## 4. Phase 3: Advanced Features & Epic 11 (6 kártya)
|
||||
|
||||
| ID | Cím |
|
||||
|----|------|
|
||||
| #158 | Implement Advanced Search with Filters |
|
||||
| #157 | Add Bulk Operations (Vehicle Import) |
|
||||
| #156 | Implement Webhook and Notification Syste |
|
||||
| #155 | Add Admin Control Panels |
|
||||
| #154 | Implement Service Booking Flow |
|
||||
| #153 | Complete Profile Selector |
|
||||
|
||||
---
|
||||
|
||||
## 5. Phase 2: Dashboard & Analytics Wiring (6 kártya)
|
||||
|
||||
| ID | Cím |
|
||||
|----|------|
|
||||
| #152 | Implement Historical Data (occurrence_da) |
|
||||
| #151 | Connect User Management Table to Real Da |
|
||||
| #150 | Wire Service Map with Real Provider Data |
|
||||
| #149 | Implement Analytics Service (TCO/km) |
|
||||
| #148 | Connect Gamification Components to Real |
|
||||
| #147 | Wire Financial Dashboard to Real Finance |
|
||||
|
||||
---
|
||||
|
||||
## 6. Phase 1: Core Functionality Fixes (4 kártya)
|
||||
|
||||
| ID | Cím |
|
||||
|----|------|
|
||||
| #178 | Vehicle Transfer Requests - Implement Du |
|
||||
| #146 | Implement Basic Error Handling in Fronte |
|
||||
| #145 | Standardize API Base URL Usage in Fronte |
|
||||
| #142 | Implement Catalog API Endpoints |
|
||||
|
||||
---
|
||||
|
||||
## 7. Egyéb / Nincs mérföldkő (16 kártya)
|
||||
|
||||
| ID | Cím |
|
||||
|----|------|
|
||||
| #227 | [FIX] NAV API v3 queryTaxpayer - .env qu |
|
||||
| #226 | Frontend: flag-icons CSS import hiba |
|
||||
| #225 | Hiba: Frontend - flag-icons CSS import |
|
||||
| #224 | Hiba: NAV API aláírás (INVALID_REQUEST) |
|
||||
| #218 | Frontend: Cég létrehozás 3-lépéses Onboa |
|
||||
| #217 | Backend: Cég (Organization) CRUD API bőv |
|
||||
| #216 | Profil UI hiányosságok (Person & User) |
|
||||
| #175 | Advanced Analytics & Reporting Engine |
|
||||
| #174 | Real-time Notification System |
|
||||
| #173 | Service Finder Rendszer Áttekintő Dokume |
|
||||
| #140 | Connect Service Moderation Map to Backen |
|
||||
| #139 | Integrate Gamification Control Panel |
|
||||
| #138 | Connect Financial Dashboard Tile |
|
||||
| #137 | Implement Real-time System Health Monito |
|
||||
| #136 | Implement AI Researcher Logs Backend |
|
||||
| #135 | Connect User Management Table to Real AP |
|
||||
|
||||
---
|
||||
|
||||
## Főbb Megállapítások
|
||||
|
||||
1. Legnagyobb blokk: A Frontend Architektúra 2.0 mérföldkő tartalmazza a legtöbb nyitott kártyát (20 db) - ez a jelenlegi aktív fejlesztési fókusz.
|
||||
2. Grafikai előkészületek: 4 kártya a Skin rendszerhez és háttérképekhez tartozik.
|
||||
3. Hibajavítások: 3 kritikus hibajelzés van nyitva (#224, #225, #227) - NAV API és CSS import problémák.
|
||||
4. Tesztelési fázis: 7 kártya vár a Phase 4 (Testing & Deployment) mérföldkőben.
|
||||
5. Fázisok közötti egyensúly: A Phase 1-4 mérföldkövek összesen 23 kártyát tartalmaznak, míg a mérföldkő nélküli kártyák száma 16.
|
||||
|
||||
---
|
||||
|
||||
Összefoglaló készítve: 2026-06-09 23:20 UTC
|
||||
311
docs/identity_schema_complete_audit.md
Normal file
311
docs/identity_schema_complete_audit.md
Normal file
@@ -0,0 +1,311 @@
|
||||
# 🔬 identity Séma Teljes Audit (2026-06-06)
|
||||
|
||||
## Áttekintés
|
||||
Az `identity` séma **9 táblát** tartalmaz, amelyek együttesen a teljes felhasználói identitáskezelést lefedik: a természetes személyt (Person), a login entitást (User), a pénztárcát, a közösségi kapcsolatokat, a bizalmi profilt, az eszközöket és a vouchereket.
|
||||
|
||||
---
|
||||
|
||||
## 1. 📊 TÁBLÁK ÉS ADATAIK
|
||||
|
||||
### 1.1 👤 `users` — Login Entitás (Központi tábla)
|
||||
**Oszlopok (24 db):**
|
||||
| Oszlop | Típus | Kötelező? | Default | Leírás |
|
||||
|--------|-------|-----------|---------|--------|
|
||||
| `id` | INTEGER | PK | nextval(...) | Elsődleges kulcs |
|
||||
| `email` | VARCHAR(255) | **YES** | — | E-mail cím (UNIQUE) |
|
||||
| `hashed_password` | VARCHAR | NO | — | Hash-elt jelszó |
|
||||
| `role` | USERRODE (ENUM) | **YES** | 'user' | Szerepkör (lásd ENUM lent) |
|
||||
| `person_id` | BIGINT | NO | — | FK → persons(id) |
|
||||
| `subscription_plan` | VARCHAR(30) | **YES** | 'FREE' | Előfizetési csomag |
|
||||
| `subscription_expires_at` | TIMESTAMPTZ | NO | — | Előfizetés lejárata |
|
||||
| `is_vip` | BOOLEAN | **YES** | false | VIP státusz |
|
||||
| `referral_code` | VARCHAR(20) | NO | — | Meghívókód (UNIQUE) |
|
||||
| `referred_by_id` | INTEGER | NO | — | FK → users(id) (aki meghívta) |
|
||||
| `current_sales_agent_id` | INTEGER | NO | — | FK → users(id) (értékesítő) |
|
||||
| `is_active` | BOOLEAN | **YES** | false | Aktív-e a fiók |
|
||||
| `is_deleted` | BOOLEAN | **YES** | false | Soft-delete |
|
||||
| `folder_slug` | VARCHAR(12) | NO | — | Fájltároló slug (UNIQUE) |
|
||||
| `preferred_language` | VARCHAR(5) | **YES** | 'hu' | Nyelv |
|
||||
| `region_code` | VARCHAR(5) | **YES** | 'HU' | Régió |
|
||||
| `preferred_currency` | VARCHAR(3) | **YES** | 'HUF' | Pénznem |
|
||||
| `ui_mode` | VARCHAR(20) | **YES** | 'personal' | UI mód (personal/fleet) |
|
||||
| `scope_level` | VARCHAR(30) | **YES** | 'individual' | Scope szint |
|
||||
| `scope_id` | VARCHAR(50) | NO | — | Scope azonosító |
|
||||
| `custom_permissions` | JSON | **YES** | '{}' | Egyedi jogosultságok |
|
||||
| `alternative_emails` | JSON | **YES** | '[]' | Alternatív e-mailek |
|
||||
| `email_history` | JSON | **YES** | '[]' | E-mail cím történet |
|
||||
| `created_at` | TIMESTAMPTZ | **YES** | — | Létrehozás ideje |
|
||||
|
||||
**Indexek (7 db):**
|
||||
- `users_pkey` — UNIQUE BTREE (id)
|
||||
- `users_email_key` — UNIQUE BTREE (email)
|
||||
- `users_referral_code_key` — UNIQUE BTREE (referral_code)
|
||||
- `ix_identity_users_folder_slug` — UNIQUE BTREE (folder_slug)
|
||||
- `ix_identity_users_email` — UNIQUE BTREE (email) (duplikáció!)
|
||||
- `ix_identity_users_id` — BTREE (id)
|
||||
|
||||
---
|
||||
|
||||
### 1.2 🧑 `persons` — Természetes Személy
|
||||
**Oszlopok (22 db):**
|
||||
| Oszlop | Típus | Kötelező? | Default | Leírás |
|
||||
|--------|-------|-----------|---------|--------|
|
||||
| `id` | BIGINT | PK | nextval(...) | Elsődleges kulcs |
|
||||
| `user_id` | INTEGER | NO | — | FK → users(id) (aktív fiók) |
|
||||
| `id_uuid` | UUID | **YES** | gen_random_uuid() | Publikus UUID |
|
||||
| `address_id` | UUID | NO | — | FK → system.addresses(id) |
|
||||
| `identity_hash` | VARCHAR(64) | NO | — | Hash: Név+Anyja+DOB (UNIQUE) |
|
||||
| `last_name` | VARCHAR | **YES** | — | Vezetéknév |
|
||||
| `first_name` | VARCHAR | **YES** | — | Keresztnév |
|
||||
| `phone` | VARCHAR | NO | — | Telefonszám |
|
||||
| `mothers_last_name` | VARCHAR | NO | — | Anyja vezetékneve |
|
||||
| `mothers_first_name` | VARCHAR | NO | — | Anyja keresztneve |
|
||||
| `birth_place` | VARCHAR | NO | — | Születési hely |
|
||||
| `birth_date` | TIMESTAMP | NO | — | Születési dátum |
|
||||
| `identity_docs` | JSON | **YES** | '{}' | Okmányok (ID_CARD, LICENSE, stb.) |
|
||||
| `ice_contact` | JSON | **YES** | '{}' | Vészhelyzeti kapcsolattartó |
|
||||
| `lifetime_xp` | BIGINT | **YES** | -1 | Élettapasztalat pont |
|
||||
| `penalty_points` | INTEGER | **YES** | -1 | Büntetőpontok |
|
||||
| `social_reputation` | NUMERIC(3,2) | **YES** | 0.00 | Társadalmi reputáció |
|
||||
| `is_sales_agent` | BOOLEAN | **YES** | true | Értékesítő-e |
|
||||
| `is_active` | BOOLEAN | **YES** | true | Aktív-e |
|
||||
| `is_ghost` | BOOLEAN | **YES** | false | Ghost (soft-delete) |
|
||||
| `merged_into_id` | BIGINT | NO | — | Összevonva ebbe a Person-ba (csak ORM szinten FK) |
|
||||
| `created_at` | TIMESTAMPTZ | **YES** | — | Létrehozás |
|
||||
| `updated_at` | TIMESTAMPTZ | NO | — | Módosítás |
|
||||
|
||||
**Indexek (4 db):**
|
||||
- `persons_pkey` — UNIQUE BTREE (id)
|
||||
- `persons_id_uuid_key` — UNIQUE BTREE (id_uuid)
|
||||
- `ix_identity_persons_identity_hash` — UNIQUE BTREE (identity_hash)
|
||||
- `ix_identity_persons_id` — BTREE (id)
|
||||
|
||||
---
|
||||
|
||||
### 1.3 💰 `wallets` — Pénztárca
|
||||
**Oszlopok (6 db):**
|
||||
| Oszlop | Típus | Kötelező? | Default |
|
||||
|--------|-------|-----------|---------|
|
||||
| `id` | INTEGER | PK | nextval(...) |
|
||||
| `user_id` | INTEGER | **YES** | — (UNIQUE, FK → users(id)) |
|
||||
| `earned_credits` | NUMERIC(18,4) | **YES** | 0 |
|
||||
| `purchased_credits` | NUMERIC(18,4) | **YES** | 0 |
|
||||
| `service_coins` | NUMERIC(18,4) | **YES** | 0 |
|
||||
| `currency` | VARCHAR(3) | **YES** | — |
|
||||
|
||||
**Indexek:**
|
||||
- `wallets_pkey` — UNIQUE BTREE (id)
|
||||
- `wallets_user_id_key` — UNIQUE BTREE (user_id)
|
||||
|
||||
---
|
||||
|
||||
### 1.4 🎫 `active_vouchers` — Aktív Voucher-ek
|
||||
**Oszlopok (6 db):**
|
||||
| Oszlop | Típus | Kötelező? | Default |
|
||||
|--------|-------|-----------|---------|
|
||||
| `id` | INTEGER | PK | nextval(...) |
|
||||
| `wallet_id` | INTEGER | **YES** | — (FK → wallets(id) ON DELETE CASCADE) |
|
||||
| `amount` | NUMERIC(18,4) | **YES** | — |
|
||||
| `original_amount` | NUMERIC(18,4) | **YES** | — |
|
||||
| `expires_at` | TIMESTAMPTZ | **YES** | — |
|
||||
| `created_at` | TIMESTAMPTZ | **YES** | now() |
|
||||
|
||||
---
|
||||
|
||||
### 1.5 🤝 `social_accounts` — Közösségi Bejelentkezés
|
||||
**Oszlopok (7 db):**
|
||||
| Oszlop | Típus | Kötelező? | Default |
|
||||
|--------|-------|-----------|---------|
|
||||
| `id` | INTEGER | PK | nextval(...) |
|
||||
| `user_id` | INTEGER | **YES** | — (FK → users(id) ON DELETE CASCADE) |
|
||||
| `provider` | VARCHAR(50) | **YES** | — |
|
||||
| `social_id` | VARCHAR(255) | **YES** | — |
|
||||
| `email` | VARCHAR(255) | **YES** | — |
|
||||
| `extra_data` | JSON | **YES** | '{}' |
|
||||
| `created_at` | TIMESTAMPTZ | **YES** | now() |
|
||||
|
||||
**Unique:** `uix_social_provider_id` (provider, social_id)
|
||||
**Indexek:** social_id
|
||||
|
||||
---
|
||||
|
||||
### 1.6 🏆 `user_trust_profiles` — Gondos Gazda Index
|
||||
**Oszlopok (9 db):**
|
||||
| Oszlop | Típus | Kötelező? | Default |
|
||||
|--------|-------|-----------|---------|
|
||||
| `user_id` | INTEGER | **PK+FK** | — (FK → users(id) ON DELETE CASCADE) |
|
||||
| `trust_score` | INTEGER | **YES** | 0 |
|
||||
| `maintenance_score` | NUMERIC(5,2) | **YES** | 0.00 |
|
||||
| `quality_score` | NUMERIC(5,2) | **YES** | 0.00 |
|
||||
| `preventive_score` | NUMERIC(5,2) | **YES** | 0.00 |
|
||||
| `identity_score` | INTEGER | **YES** | 0 |
|
||||
| `verification_level` | INTEGER | **YES** | 0 |
|
||||
| `verified_channels` | JSONB | **YES** | '{}' |
|
||||
| `identity_risk_flag` | BOOLEAN | **YES** | false |
|
||||
| `last_calculated` | TIMESTAMPTZ | **YES** | now() |
|
||||
|
||||
---
|
||||
|
||||
### 1.7 📧 `verification_tokens` — Verifikációs Tokenek
|
||||
**Oszlopok (8 db):**
|
||||
| Oszlop | Típus | Kötelező? | Default |
|
||||
|--------|-------|-----------|---------|
|
||||
| `id` | INTEGER | PK | nextval(...) |
|
||||
| `token` | UUID | **YES** | — (UNIQUE) |
|
||||
| `user_id` | INTEGER | **YES** | — (FK → users(id) ON DELETE CASCADE) |
|
||||
| `token_type` | VARCHAR(20) | **YES** | — |
|
||||
| `extra_data` | JSON | NO | '{}' |
|
||||
| `created_at` | TIMESTAMPTZ | **YES** | now() |
|
||||
| `expires_at` | TIMESTAMPTZ | **YES** | — |
|
||||
| `is_used` | BOOLEAN | **YES** | — |
|
||||
|
||||
---
|
||||
|
||||
### 1.8 📱 `devices` — Eszközök
|
||||
**Oszlopok (4 db):**
|
||||
| Oszlop | Típus | Kötelező? |
|
||||
|--------|-------|-----------|
|
||||
| `fingerprint_hash` | VARCHAR(255) | **PK** |
|
||||
| `risk_score` | INTEGER | **YES** (default 100) |
|
||||
| `is_banned` | BOOLEAN | **YES** (default false) |
|
||||
| `created_at` | TIMESTAMPTZ | **YES** |
|
||||
|
||||
---
|
||||
|
||||
### 1.9 🔗 `user_device_links` — Eszköz-Felhasználó Kapcsolat
|
||||
**Oszlopok (6 db):**
|
||||
| Oszlop | Típus | Kötelező? | Default |
|
||||
|--------|-------|-----------|---------|
|
||||
| `id` | UUID | **PK** | — |
|
||||
| `user_id` | INTEGER | **YES** | — (FK → users(id) ON DELETE CASCADE) |
|
||||
| `device_hash` | VARCHAR(255) | **YES** | — (FK → devices(fingerprint_hash) ON DELETE CASCADE) |
|
||||
| `first_seen_at` | TIMESTAMPTZ | **YES** | — |
|
||||
| `last_seen_at` | TIMESTAMPTZ | NO | — |
|
||||
| `login_count` | INTEGER | **YES** | 1 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 🔗 KAPCSOLATOK (FOREIGN KEYS)
|
||||
|
||||
### 2.1 Belső Kapcsolatok (identity → identity)
|
||||
|
||||
```
|
||||
users.person_id ─────────────► persons.id
|
||||
persons.user_id ─────────────► users.id (aktív fiók)
|
||||
users.referred_by_id ────────► users.id (MLM: ki hívta meg)
|
||||
users.current_sales_agent_id ► users.id (értékesítő)
|
||||
|
||||
social_accounts.user_id ─────► users.id [CASCADE]
|
||||
verification_tokens.user_id ─► users.id [CASCADE]
|
||||
user_trust_profiles.user_id ─► users.id [CASCADE]
|
||||
wallets.user_id ─────────────► users.id
|
||||
user_device_links.user_id ───► users.id [CASCADE]
|
||||
|
||||
wallets ◄──────────────────── active_vouchers.wallet_id [CASCADE]
|
||||
devices ◄──────────────────── user_device_links.device_hash [CASCADE]
|
||||
```
|
||||
|
||||
### 2.2 Külső Kapcsolatok (identity → system)
|
||||
|
||||
```
|
||||
persons.address_id ──────────► system.addresses(id)
|
||||
```
|
||||
|
||||
### 2.3 ORM Szintű Kapcsolatok (nincs DB FK constraint)
|
||||
|
||||
```
|
||||
persons.merged_into_id ──────► persons(id) -- SQLAlchemy ORM, use_alter=True
|
||||
persons.user_id ─────────────► users(id) -- SQLAlchemy ORM (fk_person_active_user), use_alter=True
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 🌐 KÜLSŐ HIVATKOZÁSOK (Más sémák hivatkoznak identity táblákra)
|
||||
|
||||
| Séma | Tábla | Oszlop | Hivatkozott tábla |
|
||||
|------|-------|--------|-------------------|
|
||||
| `audit` | audit_logs | user_id | identity.users |
|
||||
| `audit` | financial_ledger | user_id, person_id | identity.users, identity.persons |
|
||||
| `audit` | operational_logs | user_id | identity.users |
|
||||
| `finance` | withdrawal_requests | user_id | identity.users |
|
||||
| `fleet` | organization_members | user_id, person_id | identity.users, identity.persons |
|
||||
| `gamification` | points_ledger | user_id | identity.users |
|
||||
| `gamification` | user_badges | user_id | identity.users |
|
||||
| `gamification` | user_contributions | user_id | identity.users |
|
||||
| `gamification` | user_scores | user_id | identity.users |
|
||||
| `gamification` | user_stats | user_id | identity.users |
|
||||
| `marketplace` | service_requests | user_id | identity.users |
|
||||
| `marketplace` | service_reviews | user_id | identity.users |
|
||||
| `marketplace` | votes | user_id | identity.users |
|
||||
| `system` | internal_notifications | user_id | identity.users |
|
||||
| `system` | user_scores_deprecated | user_id | identity.users |
|
||||
|
||||
**Összesen: 17 külső FK hivatkozás 7 különböző sémából.**
|
||||
|
||||
---
|
||||
|
||||
## 4. 🏷️ ENUM TÍPUSOK
|
||||
|
||||
### `identity.userrole` ENUM
|
||||
| Érték | Leírás |
|
||||
|-------|--------|
|
||||
| `owner_old` | (régi, deprecated) |
|
||||
| `ADMIN` | Rendszergazda |
|
||||
| `FLEET_MANAGER` | Flottakezelő |
|
||||
| `DRIVER` | Sofőr |
|
||||
| `owner` | Tulajdonos |
|
||||
| `admin` | Adminisztrátor |
|
||||
| `user` | **Alapértelmezett** — sima felhasználó |
|
||||
|
||||
**Megjegyzés:** Több érték is duplikált (pl. owner/owner_old, ADMIN/admin). Valószínűleg refaktorálásra szorul, hogy csak a kívánt 9 érték maradjon meg.
|
||||
|
||||
---
|
||||
|
||||
## 5. 🗺️ KAPCSOLATI ÁBRA (ERD)
|
||||
|
||||
```
|
||||
┌──────────────────────────────────┐
|
||||
│ identity.users │ ◄──── social_accounts
|
||||
│ (24 oszlop - központi entitás) │ ◄──── verification_tokens
|
||||
└───┬────┬────┬────┬────┬──────────┘ ◄──── user_trust_profiles
|
||||
│ │ │ │ │ ◄──── wallets
|
||||
│ │ │ │ │ ◄──── user_device_links
|
||||
┌───────────┘ │ │ │ └───────────────┐
|
||||
▼ ▼ ▼ ▼ ▼
|
||||
┌──────────┐ ┌───────────┐ ┌───────────────┐ ┌──────────┐
|
||||
│ persons │ │ wallets │ │ devices │ │ (saját) │
|
||||
│(22 oszl.)│ │ (6 oszl.) │ │ (4 oszlop) │ │ referrer │
|
||||
└────┬─────┘ └─────┬─────┘ └───────┬───────┘ │ sales_ag.│
|
||||
│ │ │ └──────────┘
|
||||
▼ ▼ ▼
|
||||
system.addresses active_vouchers user_device_links
|
||||
(GPS, cím) (FIFO voucher) (kapcsolótábla)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 📝 MEGJEGYZÉSEK
|
||||
|
||||
1. **Körkörös függőség:** A `users` és `persons` táblák között **körkörös FK** van: `users.person_id → persons(id)` és `persons.user_id → users(id)`. Ezt az ORM szinten `post_update=True` és `use_alter=True` paraméterekkel oldják fel.
|
||||
|
||||
2. **ORM-only FKs:** A `persons.merged_into_id` és a `persons.user_id` (második FK, `fk_person_active_user`) **csak ORM szinten** léteznek, adatbázis szintű FK constraint nélkül.
|
||||
|
||||
3. **JSON mezők:** 5 JSON típusú mező van a sémában, amelyek rugalmas adattárolást tesznek lehetővé: `identity_docs`, `ice_contact`, `custom_permissions`, `alternative_emails`, `email_history`, `extra_data` (social_accounts), `verified_channels`.
|
||||
|
||||
4. **UNIQUE megszorítások:** Összesen 7 UNIQUE constraint van, ezek közül az `identity_hash` a legkritikusabb — ez biztosítja a deduplikációt.
|
||||
|
||||
---
|
||||
|
||||
## 7. KÖVETKEZTETÉS
|
||||
|
||||
Az identity séma **teljes körű emberközpontú identitáskezelést** valósít meg, amely lefedi:
|
||||
- ✅ Személyes adatok (Person)
|
||||
- ✅ Bejelentkezési adatok (User)
|
||||
- ✅ Pénzügyek (Wallet, Vouchers)
|
||||
- ✅ Okmányok (identity_docs JSON)
|
||||
- ✅ Közösségi kapcsolatok (Social accounts)
|
||||
- ✅ Bizalmi index (Trust Profile)
|
||||
- ✅ Eszközazonosítás (Devices)
|
||||
- ✅ MLM/Referral rendszer (referred_by, sales_agent)
|
||||
- ✅ Verifikáció (Verification tokens)
|
||||
|
||||
111
docs/nav_api_lookup_tax_analysis.md
Normal file
111
docs/nav_api_lookup_tax_analysis.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# 🔍 NAV API Tax Number Lookup - Hibaelemzés és Javítási Terv
|
||||
|
||||
**Dátum:** 2026-06-07
|
||||
**Gitea Issue-ek:** #224 (NAV API aláírás), #226 (Frontend CSS import)
|
||||
**Elemző:** Rendszer-Architect
|
||||
|
||||
---
|
||||
|
||||
## 1. Összefoglaló
|
||||
|
||||
Két független hibát azonosítottam:
|
||||
|
||||
1. **Frontend**: A Vite fejlesztői szerver nem tudja feloldani a `flag-icons/css/flag-icons.css` importot → `npm install` hiányzik
|
||||
2. **Backend (NAV API)**: A NAV Online Számla API v3 `queryTaxpayer` hívása `INVALID_REQUEST_SIGNATURE` hibát ad → valószínűleg érvénytelen `NAV_API_SIGN_KEY`
|
||||
|
||||
---
|
||||
|
||||
## 2. Frontend Hiba: flag-icons CSS import
|
||||
|
||||
### 2.1. Helyszín
|
||||
|
||||
- [`frontend/src/main.ts:13`](/opt/docker/dev/service_finder/frontend/src/main.ts) - `import 'flag-icons/css/flag-icons.css'`
|
||||
- [`frontend/package.json:14`](/opt/docker/dev/service_finder/frontend/package.json) - `"flag-icons": "^7.5.0"` függőség
|
||||
|
||||
### 2.2. Ok
|
||||
|
||||
A `flag-icons` npm csomag deklarálva van a `package.json`-ban, de **nincs telepítve** a `node_modules`-ban. Ez tipikusan akkor fordul elő, ha:
|
||||
- A függőséget kézzel adták hozzá a `package.json`-hoz, de `npm install` nem futott le
|
||||
- A `node_modules` mappa régi, és `npm install` vagy `npm update` szükséges
|
||||
|
||||
### 2.3. Javítás
|
||||
|
||||
```bash
|
||||
cd /opt/docker/dev/service_finder/frontend && npm install
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Backend Hiba: NAV API INVALID_REQUEST_SIGNATURE
|
||||
|
||||
### 3.1. Helyszín
|
||||
|
||||
- [`backend/app/services/nav_service.py`](/opt/docker/dev/service_finder/backend/app/services/nav_service.py) - Teljes NAV API integráció
|
||||
- [`backend/app/api/v1/endpoints/organizations.py:124`](/opt/docker/dev/service_finder/backend/app/api/v1/endpoints/organizations.py) - `/lookup-tax/{tax_number}` végpont
|
||||
- [`backend/app/core/config.py:130`](/opt/docker/dev/service_finder/backend/app/core/config.py) - NAV konfigurációs mezők
|
||||
- [`.env:90`](/opt/docker/dev/service_finder/.env) - NAV API hitelesítő adatok
|
||||
|
||||
### 3.2. A Hiba Lánca
|
||||
|
||||
1. Felhasználó meghívja: `GET /api/v1/organizations/lookup-tax/24742063`
|
||||
2. `NavService.query_taxpayer()` összeállítja a SOAP/XML kérést
|
||||
3. Kiszámolja az aláírást: `SHA3-512(requestId + timestamp + NAV_API_SIGN_KEY)`
|
||||
4. NAV API válasz: `HTTP 400` → `INVALID_REQUEST_SIGNATURE` ("Érvénytelen kérés aláírás")
|
||||
5. `query_taxpayer()` visszatér `None`-nal
|
||||
6. A végpont `HTTP 404`-et ad: "Cég nem található a NAV adatbázisában"
|
||||
|
||||
### 3.3. Tesztelt Aláírási Módszerek
|
||||
|
||||
| Módszer | Eredmény |
|
||||
|---------|----------|
|
||||
| SHA3-512(requestId + timestamp + signKey) | ❌ INVALID_REQUEST_SIGNATURE |
|
||||
| SHA3-512(requestId + timestamp + passwordHash) | ❌ INVALID_REQUEST_SIGNATURE |
|
||||
| SHA3-512(requestId + timestamp + exchangeKey) | ❌ INVALID_REQUEST_SIGNATURE |
|
||||
| HMAC-SHA3-512(signKey, requestId + timestamp) | ❌ INVALID_REQUEST_SIGNATURE |
|
||||
| SHA3-512(requestId + timestamp) (no key) | ❌ INVALID_REQUEST_SIGNATURE |
|
||||
|
||||
### 3.4. Következtetés
|
||||
|
||||
**Minden** aláírási módszer ugyanazt a hibát adja vissza, ami arra utal, hogy **nem a kódban lévő aláírás-számítás a hibás, hanem maguk a hitelesítő adatok érvénytelenek**.
|
||||
|
||||
Gyanús elemek:
|
||||
- `NAV_API_SIGN_KEY=02-b52b-3d9e7d638c695EPWNIUAEGHS` - a formátuma nem szabványos (nem UUID, nem base64)
|
||||
- `NAV_API_EXCHANGE_KEY=a5cf5EPWNIU9DP8O` - szintén rövid, nem szabványos
|
||||
|
||||
### 3.5. Javítási Terv
|
||||
|
||||
#### 1. lépés: Új NAV API kulcsok igénylése
|
||||
Látogass el a NAV Online Számla teszt portáljára:
|
||||
- https://onlineszamla.nav.gov.hu/
|
||||
- Regisztráció után generálj új `signKey` és `exchangeKey` párost
|
||||
|
||||
#### 2. lépés: Frissítsd a `.env` fájlt
|
||||
```env
|
||||
NAV_API_USER=<új felhasználónév>
|
||||
NAV_API_PASSWORD=<új jelszó>
|
||||
NAV_API_SIGN_KEY=<új signKey>
|
||||
NAV_API_EXCHANGE_KEY=<új exchangeKey>
|
||||
NAV_API_CALLER_TAX_NUMBER="48952046133"
|
||||
```
|
||||
|
||||
#### 3. lépés: Teszteld a kapcsolatot
|
||||
```bash
|
||||
docker exec sf_api python3 -c "
|
||||
from app.services.nav_service import NavService
|
||||
import asyncio
|
||||
result = asyncio.run(NavService.query_taxpayer('24742063'))
|
||||
print(result)
|
||||
"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Kapcsolódó Gitea Issue-ek
|
||||
|
||||
| ID | Cím | Státusz |
|
||||
|----|-----|---------|
|
||||
| #224 | 🔴 Hiba: NAV API aláírás (INVALID_REQUEST_SIGNATURE) | Nyitott |
|
||||
| #225 | 🔴 Hiba: Frontend - flag-icons CSS import | Nyitott (duplikátum?) |
|
||||
| #226 | Frontend: flag-icons CSS import hiba | Nyitott |
|
||||
|
||||
---
|
||||
94
docs/nav_api_v3_fix_audit.md
Normal file
94
docs/nav_api_v3_fix_audit.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# 🔍 NAV API v3 Fix Audit - Hiányosságjelentés
|
||||
|
||||
**Dátum:** 2026-06-07
|
||||
**Vizsgált Issue:** #227
|
||||
**Forrásdokumentáció:** [`docs/nav_api_v3_fix_summary.md`](docs/nav_api_v3_fix_summary.md)
|
||||
|
||||
## Összefoglaló
|
||||
|
||||
A [`docs/nav_api_v3_fix_summary.md`](docs/nav_api_v3_fix_summary.md) dokumentációban leírt 3 javítási lépésből **egyik sem lett végrehajtva**. Az alábbi táblázat mutatja a pontos állapotot.
|
||||
|
||||
## Részletes Hiányosság-leképezés
|
||||
|
||||
### 1. `.env` fájl - ❌ Idezőjelek még mindig jelen
|
||||
|
||||
| Mező | Jelenlegi érték | Helyes érték |
|
||||
|------|----------------|--------------|
|
||||
| [`NAV_API_PASSWORD`](.env:91) | `'Tevelegelek&99'` (aposztrófokkal, 14 karakter) | `Tevelegelek&99` (12 karakter) |
|
||||
| [`NAV_API_CALLER_TAX_NUMBER`](.env:94) | `"48952046133"` (idézőjellel, 12 karakter) | `48952046133` (11 karakter) |
|
||||
|
||||
**Következmény:**
|
||||
- `passwordHash = SHA-512("'Tevelegelek&99'")` → **ROSSZ hash** (aposztrófokkal)
|
||||
- `caller_tax_number_core[:8]` → `'"4895204'` → **ROSSZ adószám**
|
||||
|
||||
### 2. [`backend/app/core/config.py`](backend/app/core/config.py) - ❌ HIÁNYZIK a `strip_quotes` field_validator
|
||||
|
||||
A [`config.py:130-136`](backend/app/core/config.py:130) sorokban a NAV_API_* mezők definiálva vannak, de **nincs hozzáadva** a `field_validator`.
|
||||
|
||||
**Hiányzó kód** (beszúrandó a [`config.py:136`](backend/app/core/config.py:136) sor után):
|
||||
```python
|
||||
@field_validator('NAV_API_PASSWORD', 'NAV_API_SIGN_KEY', 'NAV_API_EXCHANGE_KEY', 'NAV_API_CALLER_TAX_NUMBER')
|
||||
@classmethod
|
||||
def strip_quotes(cls, v: str) -> str:
|
||||
if v:
|
||||
v = v.strip()
|
||||
if len(v) >= 2 and v[0] == v[-1] and v[0] in ('"', "'"):
|
||||
v = v[1:-1]
|
||||
return v
|
||||
```
|
||||
|
||||
### 3. [`backend/app/services/nav_service.py`](backend/app/services/nav_service.py) - ❌ HIÁNYZIK a `.strip()` hívás
|
||||
|
||||
A [`nav_service.py:134-138`](backend/app/services/nav_service.py:134) sorokban és a [`nav_service.py:127-131`](backend/app/services/nav_service.py:127) sorokban is hiányzik a `.strip()`:
|
||||
|
||||
```python
|
||||
# JELENLEGI (hibás):
|
||||
target_tax_number_core = (
|
||||
tax_number
|
||||
.replace("-", "")
|
||||
.replace(" ", "")[:8]
|
||||
)
|
||||
|
||||
# HELYES:
|
||||
target_tax_number_core = (
|
||||
tax_number
|
||||
.strip()
|
||||
.replace("-", "")
|
||||
.replace(" ", "")[:8]
|
||||
)
|
||||
```
|
||||
|
||||
```python
|
||||
# JELENLEGI (hibás) - caller_tax_number_core:
|
||||
caller_tax_number_core = (
|
||||
settings.NAV_API_CALLER_TAX_NUMBER
|
||||
.replace("-", "")
|
||||
.replace(" ", "")[:8]
|
||||
)
|
||||
|
||||
# HELYES:
|
||||
caller_tax_number_core = (
|
||||
settings.NAV_API_CALLER_TAX_NUMBER
|
||||
.strip()
|
||||
.replace("-", "")
|
||||
.replace(" ", "")[:8]
|
||||
)
|
||||
```
|
||||
|
||||
## Javítási Sorrend (Kötelező)
|
||||
|
||||
| # | Fájl | Művelet | Parancs |
|
||||
|---|------|---------|---------|
|
||||
| 1 | `.env` | Idézőjelek eltávolítása | Kézi szerkesztés |
|
||||
| 2 | [`backend/app/core/config.py`](backend/app/core/config.py) | `strip_quotes` field_validator hozzáadása | Szerkesztés |
|
||||
| 3 | [`backend/app/services/nav_service.py`](backend/app/services/nav_service.py) | `.strip()` hozzáadása mindkét helyen | Szerkesztés |
|
||||
| 4 | Konténer újraindítás | `docker compose restart sf_api` | `docker compose restart sf_api` |
|
||||
| 5 | Teszt | Lekérdezés futtatása | `docker exec sf_api python3 -c "from app.services.nav_service import NavService; import asyncio; result = asyncio.run(NavService.query_taxpayer('24742063')); print(result)"` |
|
||||
|
||||
## Gyökérok Elemzés
|
||||
|
||||
A jelenlegi `INVALID_REQUEST_SIGNATURE` hiba oka:
|
||||
|
||||
1. A `passwordHash` aposztrófokkal együtt lett hash-elve → a NAV szerver nem ismeri fel a jelszót
|
||||
2. A `caller_tax_number` idézőjellel együtt kerül a `<user><taxNumber>` mezőbe → a NAV szerver a hívó felet sem tudja azonosítani
|
||||
3. Mivel a fenti két érték hibás, a teljes `requestSignature` is érvénytelen lesz, mert a NAV szerver a felhasználó azonosítása után számolja ki a saját oldalán a várható signature-t
|
||||
235
docs/nav_api_v3_fix_summary.md
Normal file
235
docs/nav_api_v3_fix_summary.md
Normal file
@@ -0,0 +1,235 @@
|
||||
# 🔧 NAV Online Számla API v3 - Hibajavítási Összefoglaló
|
||||
|
||||
**Dátum:** 2026-06-07
|
||||
**Forrás:** `Online_Szamla_interfesz specifikacio_HU_v3.0. (2026.02.12).pdf`
|
||||
**Érintett fájlok:**
|
||||
- `.env` (NAV konfigurációs értékek)
|
||||
- `backend/app/services/nav_service.py` (NAV API integráció)
|
||||
- `backend/app/api/v1/endpoints/organizations.py` (lookup-tax végpont)
|
||||
- `backend/app/core/config.py` (Pydantic Settings)
|
||||
|
||||
---
|
||||
|
||||
## 1. A NAV API v3 Működési Modellje
|
||||
|
||||
A NAV Online Számla API v3.0 **nem REST/JSON**, hanem **SOAP-alapú XML** kommunikációt használ, amit modern HTTP(S) kérésekbe csomagoltak.
|
||||
|
||||
### 1.1. Kommunikációs Rétegek
|
||||
|
||||
```
|
||||
FastAPI endpoint (organizations.py)
|
||||
|
|
||||
v
|
||||
NavService (nav_service.py)
|
||||
| XML body osszeallitas
|
||||
| Kriptografiai alairasok szamitasa
|
||||
| HTTP fejlecek beallitasa
|
||||
v
|
||||
httpx.AsyncClient POST
|
||||
|
|
||||
v
|
||||
NAV API szerver (api-test.onlineszamla.nav.gov.hu)
|
||||
|
|
||||
v
|
||||
XML valasz feldolgozasa (ElementTree)
|
||||
```
|
||||
|
||||
### 1.2. Vegpont
|
||||
|
||||
```
|
||||
POST https://api-test.onlineszamla.nav.gov.hu/invoiceService/v3/queryTaxpayer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Kriptografiai Reszletek (A Legkritikusabb Resz)
|
||||
|
||||
### 2.1. passwordHash (SHA-512)
|
||||
|
||||
A jelszo **nyers UTF-8** stringkent kerul a hash-be. Nincs semmilyen elofeldolgozas (salt, peppering).
|
||||
|
||||
### 2.2. requestSignature (SHA3-512) - KET KULONBOZO HELYEN
|
||||
|
||||
| Hely | Algoritmus | Input | Kulcs |
|
||||
|------|-----------|-------|-------|
|
||||
| **HTTP Header** `RequestSignature` | SHA3-512 | requestId + timestamp + NAV_API_EXCHANGE_KEY | Exchange Key |
|
||||
| **XML body** `<user><requestSignature>` | SHA3-512 | requestId + timestamp + NAV_API_SIGN_KEY | Sign Key |
|
||||
|
||||
### 2.3. HTTP Fejlecek
|
||||
|
||||
- `Content-Type`: application/xml; charset=UTF-8
|
||||
- `Accept`: application/xml
|
||||
- `User`: NAV_API_USER
|
||||
- `PasswordHash`: SHA-512(password) hex, UPPERCASE
|
||||
- `ExchangeKey`: NAV_API_EXCHANGE_KEY
|
||||
- `RequestId`: UUID (max 30 karakter, kotojelek nelkul)
|
||||
- `Timestamp`: YYYY-MM-DDTHH:MM:SS.000Z
|
||||
- `RequestSignature`: SHA3-512(requestId + timestamp + exchangeKey)
|
||||
|
||||
### 2.4. XML Body Szerkezet
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<QueryTaxpayerRequest xmlns="http://schemas.nav.gov.hu/OSA/3.0/api">
|
||||
<header xmlns="http://schemas.nav.gov.hu/NTCA/1.0/common">
|
||||
<requestId>{uuid_30_char}</requestId>
|
||||
<timestamp>{UTC_ISO}</timestamp>
|
||||
<requestVersion>3.0</requestVersion>
|
||||
<headerVersion>1.0</headerVersion>
|
||||
</header>
|
||||
<user xmlns="http://schemas.nav.gov.hu/NTCA/1.0/common">
|
||||
<login>{NAV_API_USER}</login>
|
||||
<passwordHash cryptoType="SHA-512">{SHA512(password)}</passwordHash>
|
||||
<taxNumber>{hivo_fel_adoszama_8_jegy}</taxNumber>
|
||||
<requestSignature cryptoType="SHA3-512">{SHA3(requestId+timestamp+signKey)}</requestSignature>
|
||||
</user>
|
||||
<software>
|
||||
<softwareId>SF-NAV-API-001-000</softwareId>
|
||||
<softwareName>ServiceFinder</softwareName>
|
||||
<softwareOperation>LOCAL_SOFTWARE</softwareOperation>
|
||||
<softwareMainVersion>1.0</softwareMainVersion>
|
||||
<softwareDevName>ServiceFinder Kft</softwareDevName>
|
||||
<softwareDevContact>dev@sftest.hu</softwareDevContact>
|
||||
<softwareDevCountryCode>HU</softwareDevCountryCode>
|
||||
<softwareDevTaxNumber>12345678</softwareDevTaxNumber>
|
||||
</software>
|
||||
<taxNumber>{lekerdezendo_ceg_adoszama_8_jegy}</taxNumber>
|
||||
</QueryTaxpayerRequest>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. AZONOSITOTT HIBAK
|
||||
|
||||
### HIBA #1 (KRITIKUS): .env fajlban idezojelek a NAV ertekek korul
|
||||
|
||||
**Hely:** `.env` sorok 90-94
|
||||
|
||||
A `.env` fajlban a NAV ertekek korul idezojelek (aposztróf, dupla idezojel) vannak, amiket a Pydantic Settings literalisan olvas be.
|
||||
|
||||
```env
|
||||
NAV_API_PASSWORD='Tevelegelek&99' <- aposztrofokkal egyutt! (12 helyett 14 kar.)
|
||||
NAV_API_SIGN_KEY=02-b52b-3d9e7d638c695EPWNIUAEGHS <- OK
|
||||
NAV_API_EXCHANGE_KEY=a5cf5EPWNIU9DP8O <- OK
|
||||
NAV_API_CALLER_TAX_NUMBER="48952046133" <- idezojellel egyutt! (11 helyett 12 kar.)
|
||||
```
|
||||
|
||||
**Kovetkezmenyek:**
|
||||
1. `passwordHash = SHA-512("'Tevelegelek&99'")` -> **ROSSZ hash** (aposztrofokkal)
|
||||
2. `caller_tax_number[:8] = '"4895204'` -> **ROSSZ adoszam** (az elso 8 karakterbe beleesik a ")
|
||||
|
||||
**Bizonyitas:**
|
||||
```
|
||||
SHA-512('Tevelegelek&99') -> 452506A930168C81DB06...
|
||||
SHA-512(Tevelegelek&99) -> CC854A1E4F49B484396A...
|
||||
^ NEM egyezik!
|
||||
```
|
||||
|
||||
### HIBA #2 (MODSZERTANI): Nincs beepitett quote stripping a config-ban
|
||||
|
||||
**Hely:** `backend/app/core/config.py` (NAV_API_* mezo definiciok)
|
||||
|
||||
A Pydantic Settings nem strippeli automatikusan az idezojeleket.
|
||||
|
||||
### NEM HIBA: A kod logikaja helyes
|
||||
|
||||
A `nav_service.py` kod szerkezetileg megfelel a NAV API v3 specifikacionak:
|
||||
- SHA-512 a passwordHash-hoz
|
||||
- SHA3-512 a requestSignature-hoz
|
||||
- Ket kulonbozo kulcs: exchangeKey (HTTP) vs signKey (XML)
|
||||
- UUID max 30 karakter, timestamp UTC formaban
|
||||
- Helyes XML namespace-ek (OSA/3.0/api es NTCA/1.0/common)
|
||||
- Helyes HTTP hibakezeles (503 ha NAV nem elerheto, 404 ha nincs talalat)
|
||||
|
||||
---
|
||||
|
||||
## 4. JAVITASI TERV
|
||||
|
||||
### 4.1. .env fajl javitasa
|
||||
|
||||
Valtoztasd meg a kovetkezo sorokat:
|
||||
|
||||
```
|
||||
# REGI (hibas):
|
||||
NAV_API_PASSWORD='Tevelegelek&99'
|
||||
NAV_API_CALLER_TAX_NUMBER="48952046133"
|
||||
|
||||
# UJ (helyes):
|
||||
NAV_API_PASSWORD=Tevelegelek&99
|
||||
NAV_API_CALLER_TAX_NUMBER=48952046133
|
||||
```
|
||||
|
||||
### 4.2. Config quote stripping (vedohalo)
|
||||
|
||||
Add hozza a kovetkezo validatort `backend/app/core/config.py`-hoz a Settings osztalyba a NAV_API_* mezok utan:
|
||||
|
||||
```python
|
||||
from pydantic import field_validator
|
||||
|
||||
# Add this validator for all NAV fields:
|
||||
@field_validator('NAV_API_PASSWORD', 'NAV_API_SIGN_KEY', 'NAV_API_EXCHANGE_KEY', 'NAV_API_CALLER_TAX_NUMBER')
|
||||
@classmethod
|
||||
def strip_quotes(cls, v: str) -> str:
|
||||
if v:
|
||||
v = v.strip()
|
||||
if len(v) >= 2 and v[0] == v[-1] and v[0] in ('"', "'"):
|
||||
v = v[1:-1]
|
||||
return v
|
||||
```
|
||||
|
||||
### 4.3. Service biztonsagi javitas
|
||||
|
||||
`nav_service.py`-ban a `_build_query_taxpayer_xml()` modositas:
|
||||
|
||||
```python
|
||||
target_tax_number_core = (
|
||||
tax_number
|
||||
.strip()
|
||||
.replace("-", "")
|
||||
.replace(" ", "")[:8]
|
||||
)
|
||||
```
|
||||
|
||||
### 4.4. Teszteles
|
||||
|
||||
A javitas utan:
|
||||
|
||||
```bash
|
||||
# 1. Kontener ujrainditas
|
||||
docker compose restart sf_api
|
||||
|
||||
# 2. Teszt lekerdezes
|
||||
docker exec sf_api python3 -c "
|
||||
from app.services.nav_service import NavService
|
||||
import asyncio
|
||||
result = asyncio.run(NavService.query_taxpayer('24742063'))
|
||||
print(result)
|
||||
"
|
||||
```
|
||||
|
||||
Sikeres valasz formatuma:
|
||||
```json
|
||||
{
|
||||
"full_name": "CEG NEVE KFT.",
|
||||
"name": "CEG NEVE KFT.",
|
||||
"display_name": "CEG NEVE KFT.",
|
||||
"address_zip": "1234",
|
||||
"address_city": "BUDAPEST",
|
||||
"address_street_name": "Fo utca",
|
||||
"address_street_type": "utca",
|
||||
"address_house_number": "1"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Alternativak (Ha a NAV API tovabbra sem mukodik)
|
||||
|
||||
| Megoldas | Tipus | Elony | Hatrany |
|
||||
|----------|-------|-------|---------|
|
||||
| VIES (EU VAT) | SOAP/XML | Ingyenes, EU-s hivatalos | Csak EU-s adoszamok |
|
||||
| OpenCorporates | REST/JSON | Konnyu integracio | Ingyenes verzio limitalt |
|
||||
| Opten / Bisnode | Fizetos API | Teljes magyar cegadatok | Fizetos |
|
||||
| ceginfo.hu | REST API | Magyar fokusz | Fizetos |
|
||||
|
||||
Ha tovabbra is `INVALID_REQUEST_SIGNATURE`, akkor a NAV portalon (https://onlineszamla.nav.gov.hu/) uj signKey/exchangeKey part kell igenyelni.
|
||||
191
docs/profile_person_user_audit_2026-06-06.md
Normal file
191
docs/profile_person_user_audit_2026-06-06.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# 📋 Person & User Profil Adatkezelés Audit (2026-06-06)
|
||||
|
||||
## 🎯 Cél
|
||||
A Person és User entitások által nyilvántartott adatok összehasonlítása a frontend ProfileView által megjelenített és szerkeszthető mezőkkel.
|
||||
|
||||
---
|
||||
|
||||
## 📊 Adatbázis Modellek (Backend)
|
||||
|
||||
### 🧑 Person (identity.persons) – Természetes Személy
|
||||
**Séma:** `identity.persons`
|
||||
|
||||
| Mező | Típus | Nullable | Cél |
|
||||
|------|-------|----------|-----|
|
||||
| `id` | BigInteger | **NOT NULL** | Elsődleges kulcs |
|
||||
| `id_uuid` | UUID | **NOT NULL** | Külső API-khoz UUID azonosító |
|
||||
| `address_id` | UUID | NULL | FK → `system.addresses` |
|
||||
| `identity_hash` | String(64) | NULL | Deduplikáció: Név+Anyja+DOB hash |
|
||||
| **`last_name`** | String | **NOT NULL** | ✅ **Frontend használja** |
|
||||
| **`first_name`** | String | **NOT NULL** | ✅ **Frontend használja** |
|
||||
| **`phone`** | String | NULL | ✅ **Frontend használja** |
|
||||
| **`mothers_last_name`** | String | NULL | ✅ **Frontend használja** |
|
||||
| **`mothers_first_name`** | String | NULL | ✅ **Frontend használja** |
|
||||
| **`birth_place`** | String | NULL | ✅ **Frontend használja** |
|
||||
| **`birth_date`** | DateTime | NULL | ✅ **Frontend használja** |
|
||||
| **`identity_docs`** | JSON | **NOT NULL** (default `{}`) | ✅ **Részben használva** (ID_CARD, LICENSE) |
|
||||
| **`ice_contact`** | JSON | **NOT NULL** (default `{}`) | ❌ **NEM használja a frontend!** |
|
||||
| `lifetime_xp` | BigInteger | **NOT NULL** (default -1) | ❌ **Gamification – nem látható** |
|
||||
| `penalty_points` | Integer | **NOT NULL** (default -1) | ❌ **Gamification – nem látható** |
|
||||
| `social_reputation` | Numeric(3,2) | **NOT NULL** | ❌ **Nem látható** |
|
||||
| `is_sales_agent` | Boolean | **NOT NULL** | ⚙️ **Belső rendszer, nem látható** |
|
||||
| `is_active` | Boolean | **NOT NULL** | ⚙️ **Belső rendszer** |
|
||||
| `is_ghost` | Boolean | **NOT NULL** | ⚙️ **Soft-delete logika** |
|
||||
| `merged_into_id` | BigInteger | NULL | FK (self) – MDM merge logika |
|
||||
|
||||
### 👤 User (identity.users) – Login Entitás
|
||||
**Séma:** `identity.users`
|
||||
|
||||
| Mező | Típus | Nullable | Frontend látható? |
|
||||
|------|-------|----------|-------------------|
|
||||
| `id` | Integer | **NOT NULL** | – |
|
||||
| **`email`** | String | **NOT NULL** (unique) | ✅ **Readonly a profilban** |
|
||||
| `hashed_password` | String | NULL | ✅ **Külön modal változtatáshoz** |
|
||||
| **`role`** | UserRole ENUM | **NOT NULL** | ❌ **Nem látható** |
|
||||
| `person_id` | BigInteger | NULL | FK |
|
||||
| `subscription_plan` | String(30) | **NOT NULL** (default 'FREE') | ❌ **Nem látható** |
|
||||
| `subscription_expires_at` | DateTime | NULL | ❌ **Nem látható** |
|
||||
| `is_vip` | Boolean | **NOT NULL** | ❌ **Nem látható** |
|
||||
| `referral_code` | String(20) | NULL (unique) | ❌ **Nem látható** |
|
||||
| **`preferred_language`** | String(5) | **NOT NULL** (default "hu") | ❌ **Nem látható/szerkeszthető!** |
|
||||
| **`region_code`** | String(5) | **NOT NULL** (default "HU") | ❌ **Nem látható!** |
|
||||
| **`preferred_currency`** | String(3) | **NOT NULL** (default "HUF") | ❌ **Nem látható!** |
|
||||
| **`ui_mode`** | String(20) | **NOT NULL** (default "personal") | ❌ **Nem látható!** |
|
||||
| `alternative_emails` | JSON | **NOT NULL** (default `[]`) | ❌ **Nem látható** |
|
||||
| `email_history` | JSON | **NOT NULL** (default `[]`) | ❌ **Nem látható** |
|
||||
|
||||
### 🏠 Address (system.addresses)
|
||||
|
||||
| Mező | Típus | Frontend használja? |
|
||||
|------|-------|---------------------|
|
||||
| **`street_name`** | String(200) | ✅ `address_street_name` |
|
||||
| **`street_type`** | String(50) | ✅ `address_street_type` |
|
||||
| **`house_number`** | String(50) | ✅ `address_house_number` |
|
||||
| **`stairwell`** | String(20) | ✅ `address_stairwell` |
|
||||
| **`floor`** | String(20) | ✅ `address_floor` |
|
||||
| **`door`** | String(20) | ✅ `address_door` |
|
||||
| **`parcel_id`** (HRSZ) | String(50) | ⚠️ **EditForm-ban van, de UI-on HIÁNYZIK!** |
|
||||
| `.zip` (property) | String | ✅ `address_zip` |
|
||||
| `.city` (property) | String | ✅ `address_city` |
|
||||
|
||||
---
|
||||
|
||||
## 🖥️ Frontend ProfileView.vue
|
||||
|
||||
### ✅ Megjelenített és Szerkeszthető Mezők
|
||||
|
||||
#### 1️⃣ Fiók Adatok (User)
|
||||
- `email` ❌ **Readonly**
|
||||
- `password` ✅ **Külön modal**
|
||||
|
||||
#### 2️⃣ Személyes Adatok (Person)
|
||||
- `first_name`, `last_name`, `phone`
|
||||
- `birth_place`, `birth_date`
|
||||
- `mothers_last_name`, `mothers_first_name`
|
||||
|
||||
#### 3️⃣ Okmányok (identity_docs JSON)
|
||||
- **ID_CARD**: `number`, `expiry_date`
|
||||
- **LICENSE**: `number`, `expiry_date`, `categories`
|
||||
|
||||
#### 4️⃣ Lakcím (Address)
|
||||
- `address_zip`, `address_city` (auto-fill)
|
||||
- `address_street_name`, `address_street_type`, `address_house_number`
|
||||
- `address_stairwell`, `address_floor`, `address_door`
|
||||
- ⚠️ **`address_hrsz` NINCS UI-on!**
|
||||
|
||||
---
|
||||
|
||||
## 🚨 KRITIKUS HIÁNYOSSÁGOK
|
||||
|
||||
### 🔴 1. HRSZ (helyrajzi szám) mező hiányzik a UI-ból
|
||||
**Probléma:** Az `editForm.address_hrsz` reactive változóban szerepel, a backend támogatja (`Address.parcel_id`), de **nincs input mező a template-ben**.
|
||||
|
||||
**Hatás:** Vidéki ingatlanok (telek, tanya) esetén a HRSZ kötelező adat lehet, ezt jelenleg nem lehet megadni.
|
||||
|
||||
### 🟠 2. Vészhelyzeti Kapcsolattartó (ICE Contact) hiányzik
|
||||
**Probléma:** A `Person.ice_contact` JSON mező az adatbázisban létezik (default `{}`), de **sehol sem szerkeszthető**.
|
||||
|
||||
**Hatás:** Balesetnél vagy vészhelyzetben nem tud a rendszer értesítést küldeni.
|
||||
|
||||
**Javasolt struktúra:**
|
||||
```json
|
||||
{
|
||||
"name": "Nagy János",
|
||||
"relationship": "testvér",
|
||||
"phone": "+36 30 123 4567",
|
||||
"email": "janos.nagy@example.com"
|
||||
}
|
||||
```
|
||||
|
||||
### 🟡 3. User Preferenciák nem szerkeszthetők
|
||||
**Probléma:** Az alábbi User-szintű beállítások NEM láthatók/módosíthatók:
|
||||
- `preferred_language` (jelenleg "hu" fix)
|
||||
- `region_code` (jelenleg "HU" fix)
|
||||
- `preferred_currency` (jelenleg "HUF" fix)
|
||||
- `ui_mode` (personal/fleet váltás)
|
||||
|
||||
**Hatás:**
|
||||
- A nyelvet a LanguageSwitcher komponens kezeli, de nem kerül mentésre a User táblába
|
||||
- A többdevizás költségkövetés (EUR, USD) nem működik
|
||||
- A "personal" vs "fleet" mód nem váltható
|
||||
|
||||
### 🟢 4. Passport (Útlevél) és Tax Number (Adószám) hiányzik
|
||||
**Javasolt bővítés (identity_docs JSON):**
|
||||
```json
|
||||
{
|
||||
"PASSPORT": { "number": "...", "expiry_date": "...", "issuing_country": "HU" },
|
||||
"TAX_ID": { "number": "...", "country": "HU" }
|
||||
}
|
||||
```
|
||||
|
||||
### 🔵 5. Gamification és Trust Score adatok nem láthatók
|
||||
**Probléma:** A felhasználó **nem láthatja a saját** statisztikáit:
|
||||
- `Person.lifetime_xp`, `penalty_points`, `social_reputation`
|
||||
- `UserTrustProfile.trust_score` (Gondos Gazda Index)
|
||||
|
||||
**Hatás:** A gamification funkciók nem motiválják a felhasználót.
|
||||
|
||||
**Megoldás:** A backend már támogatja: `GET /users/me/trust`
|
||||
|
||||
### 🟣 6. Subscription (Előfizetés) információk elrejtve
|
||||
**Probléma:** `subscription_plan`, `subscription_expires_at`, `is_vip` **sehol sem látszódnak**.
|
||||
|
||||
**Hatás:** A felhasználó nem tudja, meddig érvényes a PRO csomagja.
|
||||
|
||||
---
|
||||
|
||||
## 📝 ÖSSZEFOGLALÓ TÁBLÁZAT
|
||||
|
||||
| Kategória | Backend (DB) | Frontend (UI) | Státusz |
|
||||
|-----------|--------------|---------------|---------|
|
||||
| **Person főbb adatok** | ✅ Teljes | ✅ Teljes | 🟢 **SZINKRONBAN** |
|
||||
| **Identity Docs (ID, License)** | ✅ JSON | ✅ Szerkeszthető | 🟢 **SZINKRONBAN** |
|
||||
| **Lakcím alapadatok** | ✅ 8 mező | ✅ 8 mező | 🟢 **SZINKRONBAN** |
|
||||
| **HRSZ (parcel_id)** | ✅ Létezik | ❌ **Hiányzik** | 🔴 **GAP!** |
|
||||
| **ICE Contact** | ✅ JSON | ❌ **Hiányzik** | 🔴 **GAP!** |
|
||||
| **User preferenciák** | ✅ 4 mező | ❌ **Nem szerkeszthető** | 🟠 **GAP!** |
|
||||
| **Passport, Tax ID** | ⚠️ JSON-ban lehetne | ❌ **Hiányzik** | 🟡 **Fejlesztendő** |
|
||||
| **Gamification** | ✅ Létezik | ❌ **Nem látható** | 🟡 **Fejlesztendő** |
|
||||
| **Subscription** | ✅ Létezik | ❌ **Nem látható** | 🟡 **Fejlesztendő** |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 KÖVETKEZŐ LÉPÉSEK
|
||||
|
||||
### 🔴 Kritikus (Immediate)
|
||||
1. **HRSZ mező hozzáadása** a ProfileView.vue-hoz (~10 perc)
|
||||
2. **PersonUpdate schema audit**: Megkeresni a sémát
|
||||
|
||||
### 🟠 Fontos (Short-term)
|
||||
3. **ICE Contact szerkesztő** (~1 óra)
|
||||
4. **User Preferences** szerkeszthetővé tétele (~2 óra)
|
||||
|
||||
### 🟡 Hasznos (Mid-term)
|
||||
5. **Passport és Tax ID** (~1 óra)
|
||||
6. **Gamification/Trust Score megjelenítés** (~30 perc)
|
||||
7. **Subscription info megjelenítése** (~20 perc)
|
||||
|
||||
---
|
||||
|
||||
**Dokumentum:** 2026-06-06 | Service Finder System Audit
|
||||
|
||||
Reference in New Issue
Block a user