Files
service-finder/docs/address_api_consistency_audit.md
2026-07-01 19:49:58 +00:00

210 lines
9.3 KiB
Markdown

# 🏗️ Cím API Végpontok Egységességi Auditja
**Dátum:** 2026-07-01
**Auditor:** Rendszer-Architect
**Cél:** Annak ellenőrzése, hogy a címet kezelő API végpontok be- és kimeneti formátuma egységes-e, és alkalmas-e egy központi címmodul (Address Module) kezelésére.
---
## 📊 Összefoglaló
**Verdikt: 🔴 NEM EGYSÉGES — 3 párhuzamos címformátum létezik, súlyos inkonzisztenciákkal.**
A rendszerben jelenleg **3 féle cím séma** és **2 teljesen eltérő címkezelési stratégia** fut párhuzamosan. Egy központi címmodul bevezetése **sürgős refaktorálást** igényel.
---
## 🔍 Feltárt címformátumok
### 1. `AddressIn` / `AddressOut` (Unified P0 Refactored)
**Fájl:** `backend/app/schemas/address.py`
| Mező | Típus | Leírás |
|------|-------|--------|
| `zip` | `Optional[str]` | Irányítószám |
| `city` | `Optional[str]` | Város |
| `street_name` | `Optional[str]` | Utca neve |
| `street_type` | `Optional[str]` | Közterület jellege |
| `house_number` | `Optional[str]` | Házszám |
| `stairwell` | `Optional[str]` | Lépcsőház |
| `floor` | `Optional[str]` | Emelet |
| `door` | `Optional[str]` | Ajtó |
| `parcel_id` | `Optional[str]` | Helyrajzi szám |
| `full_address_text` | `Optional[str]` | Teljes cím szöveg |
| `latitude` | `Optional[float]` | GPS szélesség |
| `longitude` | `Optional[float]` | GPS hosszúság |
**Használja:** `organizations.py` (P0 refactored — nested `AddressIn` bemenet, `AddressOut` kimenet)
### 2. `AddressResponse` (user.py séma)
**Fájl:** `backend/app/schemas/user.py`
| Mező | Típus | Eltérés |
|------|-------|---------|
| `address_zip` | `Optional[str]` | 🟡 **address_ előtaggal** |
| `address_city` | `Optional[str]` | 🟡 **address_ előtaggal** |
| `address_street_name` | `Optional[str]` | |
| `address_street_type` | `Optional[str]` | |
| `address_house_number` | `Optional[str]` | |
| `address_stairwell` | `Optional[str]` | |
| `address_floor` | `Optional[str]` | |
| `address_door` | `Optional[str]` | |
| `address_hrsz` | `Optional[str]` | 🟡 **eltérő név: hrsz vs parcel_id** |
| `full_address_text` | `Optional[str]` | |
| `latitude` | `Optional[float]` | |
| `longitude` | `Optional[float]` | |
**Használja:** `users.py` (response), `admin_persons.py` (response + input: `PersonAddressUpdate`)
### 3. Admin endpointok saját belső sémái
**Fájl:** `backend/app/api/v1/endpoints/admin_providers.py`
| Mező | Típus | Megjegyzés |
|------|-------|------------|
| `address` | `Optional[str]` | 🟡 **Szabad szöveges cím (legacy)** |
| `city` | `Optional[str]` | 🟡 **city (előtag nélkül)** |
| `address_zip` | `Optional[str]` | 🟡 **address_ előtaggal** |
| `address_street_name` | `Optional[str]` | |
| `address_street_type` | `Optional[str]` | |
| `address_house_number` | `Optional[str]` | |
| `plus_code` | `Optional[str]` | 🟢 Csak itt van |
| `contact_phone` | `Optional[str]` | |
**Használja:** `admin_providers.py` (`ProviderListItem`, `ProviderDetail`, `AdminProviderUpdate`), `admin_organizations.py`
### 4. Admin user list (`admin.py`)
**Fájl:** `backend/app/api/v1/endpoints/admin.py`
| Mező | Típus | Megjegyzés |
|------|-------|------------|
| `postal_code` | `Optional[str]` | 🔴 **Teljesen eltérő név** |
| `city` | `Optional[str]` | 🟡 **előtag nélkül** |
| `street` | `Optional[str]` | 🔴 **street (nem street_name)** |
| `house_number` | `Optional[str]` | 🟢 Ok |
| `address` | `Optional[str]` | 🟡 **Összefűzött string** |
---
## 🗺️ Érintett API Végpontok és Formátumuk
| # | Végpont fájl | Cím bemenet | Cím kimenet | Formátum azonosság |
|---|-------------|-------------|-------------|-------------------|
| 1 | `organizations.py` | `AddressIn` (nested) | `AddressOut` (nested) | ✅ Egységes (P0) |
| 2 | `users.py` | Denormalizált `address_*` | `AddressResponse` (`address_*`) | ⚠️ Részben |
| 3 | `admin.py` | — | Saját dict: `postal_code`, `city`, `street` | 🔴 **Eltérő** |
| 4 | `admin_providers.py` | Saját `AdminProviderUpdate` | Saját `ProviderDetail` | ⚠️ Részben |
| 5 | `admin_organizations.py` | Denormalizált `address_*` | Denormalizált `address_*` | ⚠️ Részben |
| 6 | `admin_persons.py` | `PersonAddressUpdate` (`address_*`) | `AddressResponse` (`address_*`) | ⚠️ Részben |
| 7 | `providers.py` | `ProviderQuickAddIn` / `ProviderUpdateIn` | `ProviderSearchResult` | ⚠️ Saját séma |
| 8 | `gamification.py` | `city`, `address` (string) | — | 🔴 **Eltérő** |
---
## 🚨 Kritikus Inkonzisztenciák
### 1. 🔴 Mezőelnevezési konfliktus: `zip` vs `address_zip` vs `postal_code`
A 3 különböző séma 3 különböző néven hivatkozik ugyanarra az adatra:
- `zip` (`AddressIn`/`AddressOut` — P0 refactored)
- `address_zip` (`AddressResponse`, `PersonUpdate` — user séma)
- `postal_code` (`admin.py` user list response)
**Következmény:** A frontend fejlesztőknek tudniuk kell, hogy melyik endpoint melyik mezőnevet várja/adja. Ez magas hibalehetőséget hordoz.
### 2. 🔴 `address_hrsz` vs `parcel_id` — névütközés
- `AddressResponse` / `PersonAddressUpdate`: `address_hrsz`
- `AddressIn` / `AddressOut`: `parcel_id`
- Modell (`Address`): `parcel_id`
**Következmény:** Ugyanaz az adat (helyrajzi szám) két különböző néven szerepel.
### 3. 🔴 Kétféle címkezelési stratégia (FK vs denormalizált)
**Stratégia A — Unified (P0 Refactored):**
- `system.addresses` tábla + `address_id` FK
- `AddressIn` / `AddressOut` séma
- **Használja:** `organizations.py`
**Stratégia B — Denormalizált:**
- Címmezők közvetlenül a szülő táblában (`address_city`, `address_zip`, stb.)
- Külön `Address` entitás nélkül
- **Használja:** `admin_organizations.py`, `admin_providers.py`, `providers.py`, `users.py`
### 4. 🟡 Duplikált séma definíciók
Az `admin_providers.py` fájlban a `ProviderListItem`, `ProviderDetail`, `AdminProviderCreate` és `AdminProviderUpdate` osztályok saját Pydantic sémákként vannak definiálva a fájlon belül. Ezek mezői részben átfednek az `AddressIn`/`AddressOut` sémákkal, de nem azokat használják.
### 5. 🟡 ProviderSearchResult duplikált címmezőkkel
A `ProviderSearchResult` (`backend/app/schemas/provider.py`) tartalmaz egy `address` (string) mezőt **és** atomizált mezőket is (`address_zip`, `address_street_name`, stb.). Ez redundáns.
---
## 📋 Javasolt Refaktor Terv
### Fázis 1: Egységes címmodul megerősítése
Az `AddressIn`/`AddressOut` séma megtartása és kiterjesztése:
```python
class AddressIn(BaseModel):
"""Unified address input schema."""
zip: Optional[str] = None
city: Optional[str] = None
street_name: Optional[str] = None
street_type: Optional[str] = None
house_number: Optional[str] = None
stairwell: Optional[str] = None
floor: Optional[str] = None
door: Optional[str] = None
parcel_id: Optional[str] = None
full_address_text: Optional[str] = None
latitude: Optional[float] = None
longitude: Optional[float] = None
```
### Fázis 2: Érintett endpointok átállítása
| Prioritás | Végpont | Jelenlegi | Átállás |
|-----------|---------|-----------|---------|
| 🔴 P1 | `admin.py` user list | `postal_code`/`city`/`street` dict | `AddressOut`-ra váltás |
| 🔴 P1 | `admin_persons.py` | `PersonAddressUpdate` | `AddressIn` használata |
| 🟡 P2 | `users.py` | Denormalizált `address_*` | `AddressIn` + FK |
| 🟡 P2 | `admin_providers.py` | Saját `ProviderDetail` etc. | `AddressOut` beágyazás |
| 🟡 P2 | `admin_organizations.py` | Denormalizált `address_*` | `AddressIn`/`AddressOut` |
| 🟢 P3 | `providers.py` | `ProviderSearchResult` | `AddressOut` beágyazás |
| 🟢 P3 | `gamification.py` | `city`/`address` string | `AddressIn` használata |
### Fázis 3: `AddressResponse` eltávolítása
- `AddressResponse` (`backend/app/schemas/user.py`) → eltávolítani
- Helyette `AddressOut`-t használni mindenhol
- Frontend kompatibilitás: mapping réteg a frontenden, ha az `address_*` előtagot várja
---
## ⚙️ Technikai Megvalósítási Javaslat
### Backend oldalon:
1. `AddressIn` bővítése `country` mezővel
2. Az összes admin endpoint átállítása `AddressIn`/`AddressOut` használatára
3. `Organization` modell denormalizált `address_*` mezőinek deprecated flaggelése
4. `create_or_update_address` service kiterjesztése az összes használati esetre
### Frontend oldalon:
1. Egységes `address` komponens bevezetése, ami `AddressOut` formátumot vár
2. Mapping réteg a régi `address_*` formátumról az új `AddressOut` formátumra
---
## 📈 Következtetés
**A rendszer JELENLEG NEM alkalmas egy központi címmodul kezelésére.**
A P0 refactored `AddressIn`/`AddressOut` séma irányába történő elmozdulás elkezdődött (`organizations.py`), de a többi endpoint és séma még a régi, denormalizált megközelítést használja. A kettősség komoly karbantartási terhet és hibalehetőséget jelent.
**Javasolt lépések:**
1. 🔴 **Azonnal:** `admin.py` user list válasz átállítása `AddressOut` formátumra
2. 🔴 **Rövidtávon:** `AddressResponse` (`user.py`) és `PersonAddressUpdate` (`admin_persons.py`) lecserélése `AddressOut`/`AddressIn`-re
3. 🟡 **Középtávon:** Az összes admin provider/organization endpoint átállítása
4. 🟢 **Hosszútávon:** Provider sémák (`ProviderSearchResult`, `ProviderQuickAddIn`) átállítása