210 lines
9.3 KiB
Markdown
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
|