218 lines
13 KiB
Markdown
218 lines
13 KiB
Markdown
# Service Finder Fejlesztési Történet
|
|
|
|
## 2026-06-21 - P0 Deep Audit: Database Consistency & Zombie API Hunt
|
|
|
|
### 🎯 Cél
|
|
Teljes körű adatbázis konzisztencia ellenőrzés és zombie API végpontok felderítése a `vehicle`, `finance`, `fleet_finance` sémákban, mielőtt a frontend fejlesztés elkezdődik.
|
|
|
|
### 🔧 Eredmények
|
|
|
|
**1. ADATBÁZIS TISZTASÁG:** ✅ PASS
|
|
|
|
### ✅ Verifikáció
|
|
- Backend Python szintaxis: OK
|
|
- Sync Engine: 1297 elem OK, 0 hiba, teljes szinkronban
|
|
- API Test 1: `PATCH is_always_open=True` → `{"always_open": true, "days": {"monday": {"open": "00:00", "close": "23:59"}, ...}}` ✅
|
|
- API Test 2: `PATCH is_always_open=False` → `{"monday": {"open": "09:00", "close": "17:00"}}` (always_open metadata stripped) ✅
|
|
|
|
## 2026-07-01 - Unified Address API Refactoring (Gitea #386-#391)
|
|
|
|
### 🎯 Cél
|
|
Teljes körű cím API egységesítés a backend összes endpointján. Az audit során 4 különböző címformátumot és 5 kritikus inkonzisztenciát azonosítottunk. A refaktoring 3 fázisban (P1/P2/P3) 6 Gitea kártyán keresztül valósult meg.
|
|
|
|
### 🔧 Eredmények
|
|
|
|
**1. Audit & Tervezés:** ✅
|
|
- Audit dokumentum: `docs/address_api_consistency_audit.md`
|
|
- Logic spec: `plans/logic_spec_unified_address_refactoring.md`
|
|
- 6 Gitea kártya létrehozva (#386-#391)
|
|
|
|
**2. P1 #386 — Admin endpointok (admin.py, admin_persons.py):** ✅
|
|
- `admin.py list_users`: Flat dict → `AddressOut.model_validate(address)` nested object
|
|
- `admin_persons.py`: `AddressResponse` → `AddressIn`/`AddressOut`, `PersonAddressUpdate` törölve
|
|
- 3 `AddressResponse(...)` → `AddressOut.model_validate(person.address)`
|
|
- Address update field mapping javítva (address_zip→zip, address_hrsz→parcel_id)
|
|
|
|
**3. P2 #387 — User endpointok (users.py, schemas/user.py):** ✅
|
|
- `PersonUpdate`: 9 flat `address_*` field → `address: Optional[AddressIn]`
|
|
- `_build_user_response`: Manual dict → `AddressOut.model_validate(person.address)`
|
|
- `.dict()` → `.model_dump()` (Pydantic v2)
|
|
|
|
**4. P2 #388 — Admin providers (admin_providers.py):** ✅
|
|
- `ProviderDetail`: Flat fields → `address_detail: Optional[AddressOut]`
|
|
- `ProviderUpdateInput`: Flat fields → `address_detail: Optional[AddressIn]`
|
|
- STEP 0: address_detail extraction + flat field mapping (zip→address_zip, city→city, stb.)
|
|
|
|
**5. P2 #389 — Admin Organizations (admin_organizations.py):** ✅
|
|
- `GarageDetailsResponse`: 15 flat address fields → `address_detail: Optional[AddressOut]`, `billing_address_detail: Optional[AddressOut]`, `notification_address_detail: Optional[AddressOut]` (3 AddressOut nested objects)
|
|
- `OrganizationUpdate`: 15 flat address fields → `address_detail: Optional[AddressIn]`, `billing_address_detail: Optional[AddressIn]`, `notification_address_detail: Optional[AddressIn]` (3 AddressIn nested objects)
|
|
- `get_org_detail`: AddressOut construction from denormalized org fields for all 3 address types
|
|
- `update_organization`: STEP 0 with 3 address_detail extraction + flat field mapping blocks (primary/billing/notification)
|
|
- Response includes `address_detail` as unified AddressOut object
|
|
|
|
**6. P3 #390 — Public providers (schemas/provider.py, provider_service.py):** ✅
|
|
- `ProviderSearchResult`: `address_detail: Optional[AddressOut]`
|
|
- `ProviderQuickAddIn`: `address_detail: Optional[AddressIn]`
|
|
- `ProviderUpdateIn`: `address_detail: Optional[AddressIn]`
|
|
- `search_providers`: AddressOut construction from flat SQL columns
|
|
|
|
**7. P3 #391 — Gamification (gamification.py):** ✅
|
|
- `submit_new_service` uses `city`/`address` as plain `Body()` string params
|
|
- Maps directly to `ServiceStaging.city`/`ServiceStaging.address_line1`
|
|
- Simple crowdsourcing — AddressIn conversion would be over-engineering
|
|
|
|
**8. Phase 4 — AddressResponse removal:** ✅
|
|
- `AddressResponse` class completely removed from `schemas/user.py`
|
|
- `PersonResponse.address`: `Optional[AddressResponse]` → `Optional[AddressOut]`
|
|
|
|
### ✅ Verifikáció
|
|
- Backend Python szintaxis: OK (all files pass py_compile)
|
|
- Sync Engine: 1274 OK, 0 Fixed, 26 Shadow Data (pre-existing)
|
|
- All 6 Gitea cards (#386-#391): CLOSED ✅
|
|
|
|
## 2026-07-01 - Service Provider Auto-Discovery (Gitea #348, #347)
|
|
|
|
### 🎯 Cél
|
|
Implementálni a `find_or_create_provider_by_name()` service függvényt (#348) és az auto-discovery hook-ot az expense creation-ben (#347) a logic_spec alapján.
|
|
|
|
### 🔧 Eredmények
|
|
|
|
**1. find_or_create_provider_by_name() (#348):** ✅
|
|
- **Exact match:** ILIKE keresés a ServiceProvider.name mezőn
|
|
- **Fuzzy match:** pg_trgm similarity > 0.3 threshold, legjobb találat kiválasztása
|
|
- **Create new:** Ha nincs találat, új ServiceProvider létrehozása `pending` státusszal, `source=SourceType.api_import` ("api_import"), `validation_score=0`
|
|
- **Gamification:** PROVIDER_DISCOVERY (300 XP), PROVIDER_CONFIRMATION (150 XP), PROVIDER_VERIFIED_USE (100 XP), USE_UNVERIFIED_PROVIDER (200 XP)
|
|
|
|
**2. Auto-discovery hook expense creation-ben (#347):** ✅
|
|
- Már implementálva volt a `POST /expenses/` végpontban
|
|
- Ha `external_vendor_name` meg van adva, de `service_provider_id` nincs, meghívja a `find_or_create_provider_by_name()`-t
|
|
- Hiba esetén warning log, nem blokkolja a költség létrehozását
|
|
|
|
**3. Adatbázis módosítások:**
|
|
- `pg_trgm` extension telepítve
|
|
- `marketplace.source_type` enum kiegészítve `'api_import'` értékkel
|
|
|
|
### ✅ Verifikáció
|
|
- Sync Engine: 1297 elem OK, 0 hiba, teljes szinkronban
|
|
- Test `test_use_unverified_provider.py`: ALL TESTS PASSED ✅
|
|
- PROVIDER_DISCOVERY (300 XP): ✅ User A created provider
|
|
- PROVIDER_CONFIRMATION (150 XP): ✅ User A reused own provider
|
|
- USE_UNVERIFIED_PROVIDER (200 XP): ✅ User B used pending provider
|
|
|
|
## 2026-07-01 - P0 ARCHITECTURE CLEANUP: Final Address Refactor (Ghost Columns & AddressManager)
|
|
|
|
### 🎯 Cél
|
|
A `docs/p0_address_manager_usage_audit_2026-07-01.md` auditban feltárt P0 kritikus hiba és P1 hiányosságok javítása.
|
|
|
|
### 🔧 Eredmények
|
|
|
|
**1. P0 FIX — `admin.py:search_organizations_by_name`:** ✅
|
|
- `Organization.address_city` → `GeoPostalCode.city` (JOIN `Address` → `GeoPostalCode`)
|
|
- Hozzáadva: `outerjoin(Address, Organization.address_id == Address.id)`
|
|
- Hozzáadva: `outerjoin(GeoPostalCode, Address.postal_code_id == GeoPostalCode.id)`
|
|
- Változás: `row.address_city` → `row.city` a response builderben
|
|
|
|
**2. P1 FIX — `admin_persons.py:update_person`:** ✅
|
|
- 50+ sor direkt Address mező írás → egyetlen `AddressManager.create_or_update()` hívás
|
|
- Import hozzáadva: `from app.services.address_manager import AddressManager`
|
|
|
|
**3. P1 FIX — `admin_organizations.py:list_organizations`:** ✅
|
|
- `org.address_city` → `org.address.city if org.address else None` (relationship-based)
|
|
|
|
**4. P1 FIX — `OrganizationUpdate` séma:** ✅
|
|
- Minden flat address field `[DEPRECATED]` prefixet kapott a description-ben
|
|
|
|
**5. SQL Cleanup Script:** ✅
|
|
- `docs/sql/cleanup_ghost_columns_2026_07.sql` — 15 DROP COLUMN utasítás `IF EXISTS` védelemmel
|
|
|
|
### ✅ Verifikáció
|
|
- Backend Python szintaxis: OK (all 3 files pass py_compile)
|
|
- Import verifikáció: `Organization.address_id`=True, `Organization.address_city`=False (confirmed removed)
|
|
- Sync Engine: 1274 OK, 0 Fixed, 26 Shadow Data (pre-existing ghost columns confirmed)
|
|
|
|
## 2026-07-01 - P0 CRITICAL HOTFIX: Fix 500 Error on /admin/providers List View
|
|
|
|
### 🎯 Cél
|
|
A GET /api/v1/admin/providers végpont 500-as hibát dobott a denormalizált cím oszlopok eltávolítása után.
|
|
|
|
### 🔧 Root Cause & Fix
|
|
**Root Cause 1 — Wrong ServiceStaging import:**
|
|
Az `admin_providers.py` a `ServiceStaging`-et az `app.models.marketplace.service` modulból importálta, amely NEM tartalmazza a `full_address` és `city` mezőket. A helyes import az `app.models.marketplace.staged_data` modulból származik, amely rendelkezik ezekkel a mezőkkel.
|
|
|
|
**Root Cause 2 — AddressOut missing required `id` field:**
|
|
A `get_provider_detail` és `update_provider` végpontok `AddressOut(...)`-ot konstruáltak a ServiceProvider flat address mezőiből, de az `AddressOut` séma `id: uuid.UUID` mezője kötelező (nem Optional). Mivel a ServiceProvider nem rendelkezik Address kapcsolattal, az `address_detail` mezőt `None`-ra kell állítani.
|
|
|
|
### 🔧 Változtatások
|
|
1. **`backend/app/api/v1/endpoints/admin_providers.py:41`** — Import csere: `from app.models.marketplace.service import ServiceStaging` → `from app.models.marketplace.staged_data import ServiceStaging`
|
|
2. **`backend/app/api/v1/endpoints/admin_providers.py:568`** — `address_detail=AddressOut(...)` → `address_detail=None` (get_provider_detail)
|
|
3. **`backend/app/api/v1/endpoints/admin_providers.py:1340`** — `address_detail=AddressOut(...)` → `address_detail=None` (update_provider)
|
|
|
|
### ✅ Verifikáció
|
|
- `GET /api/v1/admin/providers` (default): 200 ✅ (50 items)
|
|
- `GET /api/v1/admin/providers?status=pending`: 200 ✅ (50 items)
|
|
- `GET /api/v1/admin/providers/4`: 200 ✅ (address_detail=None)
|
|
- Sorting by name/validation_score/status: 200 ✅
|
|
- Search: 200 ✅ (4 results)
|
|
|
|
## 2026-07-01 - P0 BUGFIX: Organization Details 500 Error & Provider Raw Data
|
|
|
|
### 🎯 Cél
|
|
Két P0 hibajavítás:
|
|
1. **Organization Details 500 error** - A `fleet.organizations` táblából fizikailag eltávolított denormalizált cím oszlopok (15 db: address_city, billing_zip, notification_street_name, stb.) miatt a `PUT /{org_id}` végpont `setattr`-nál 500-as hibát dobott, ha a frontend elküldte ezeket a mezőket.
|
|
2. **Provider Raw Data hiány** - A `GET /admin/providers/{id}` végpont ServiceProvider rekordoknál nem adta vissza a `raw_data` mezőt, így a frontend "Nyers adatok" tab üresen/mock adatként jelent meg.
|
|
|
|
### 🔧 Eredmények
|
|
|
|
**1. `admin_organizations.py` - Deprecated address field filter** (1341-1361. sor)
|
|
- Bevezetve a `DEPRECATED_ADDRESS_FIELDS` halmaz, amely tartalmazza mind a 15 ghost oszlopot
|
|
- A `update_organization` függvény `setattr` ciklusa előtt ezek a mezők kiszűrésre kerülnek `logger.warning` kíséretében
|
|
- A GET végpont (`get_organization_details`) már korábban is helyesen, relationship-ekből töltötte a denormalizált mezőket (1114-1139. sor)
|
|
|
|
**2. `admin_providers.py` - Raw data hozzáadása ServiceProvider válaszhoz** (589-591. sor)
|
|
- A `get_provider_detail` ServiceProvider ágához hozzáadva: `raw_data=sp.raw_data or {}`
|
|
- Ezzel a frontend `RawDataViewer` komponense valós adatokat kap, nem üres/mock állapotot
|
|
|
|
### ✅ Verifikáció
|
|
- Mindkét fájl Python szintaxis ellenőrzése: **OK**
|
|
- `sync_engine.py` futtatás: **1274 elem OK, 0 hiba** - teljes szinkronban
|
|
|
|
---
|
|
|
|
## 2026-07-02: Bugfix - Provider validációs érték és research_in_progress státusz (Gitea #393)
|
|
|
|
### 🎯 Cél
|
|
Provider 1752 (Carnanny) esetén a validációs érték üres volt (validation_score=0), és a `research_in_progress` státusz nem jelent meg helyesen a frontend státuszablakában.
|
|
|
|
### 🔧 Root Cause & Fix - 4 bug javítva
|
|
|
|
**Bug 1 - Backend: `validation_score` hardcoded to 0 for staging providers**
|
|
- **Hely:** [`admin_providers.py:613`](backend/app/api/v1/endpoints/admin_providers.py:613)
|
|
- **Ok:** A `get_provider_detail` ServiceStaging ágában `validation_score=0` volt keménykódolva
|
|
- **Fix:** `validation_score=ss.trust_score or 0` - így a trust_score értéke jelenik meg validation_score-ként
|
|
|
|
**Bug 2 - Frontend: `research_in_progress` hiányzott a statusLabel/statusDescription függvényekből**
|
|
- **Hely:** [`index.vue:869-887`](frontend_admin/pages/providers/[id]/index.vue:869)
|
|
- **Ok:** A switch csak 'approved', 'pending', 'rejected' eseteket kezelte
|
|
- **Fix:** Hozzáadva: `case 'research_in_progress': return 'Kutatás folyamatban'` és magyarázó leírás
|
|
|
|
**Bug 3 - Frontend: `research_in_progress` hiányzott a CSS computed property-kből**
|
|
- **Hely:** [`index.vue:774-808`](frontend_admin/pages/providers/[id]/index.vue:774)
|
|
- **Ok:** A `statusBannerClass`, `statusIconClass`, `statusTextClass`, `statusSubtextClass` nem kezelték ezt a státuszt → piros (elutasított) stílust kapott
|
|
- **Fix:** Mind a 4 computed property-hez hozzáadva a `research_in_progress` case kék színű (blue-500) Tailwind osztályokkal
|
|
|
|
**Bug 4 - Frontend: Moderációs műveletek rossz ágba kerültek**
|
|
- **Hely:** [`index.vue:283`](frontend_admin/pages/providers/[id]/index.vue:283)
|
|
- **Ok:** `v-if="provider.status === 'pending'"` csak a pending státuszt kezelte, a `research_in_progress` a `v-else` ágba esett ("elutasításra került")
|
|
- **Fix:** `v-if="provider.status === 'pending' || provider.status === 'research_in_progress'"` - így a research_in_progress státuszú provider-ek is látják az Approve/Reject gombokat
|
|
|
|
### 📊 Adatbázis megállapítás
|
|
- A `service_staging.trust_score` mező értéke 0 a DB-ben, de a `raw_data` JSON tartalmazza: `"trust_score": 20`
|
|
- Ez egy OSM scout bot enrichment pipeline hiányosság - a bot nem extractálja a `trust_score`-t a `raw_data`-ból a staging oszlopba
|
|
- A fix biztosítja, hogy AMIKOR a trust_score populálva lesz, az helyesen megjelenjen validation_score-ként
|
|
|
|
### ✅ Verifikáció
|
|
- Backend Python szintaxis: **OK**
|
|
- API konténer restart: **OK**
|
|
- API hívás provider 1752-re: **200 OK** - status=research_in_progress, validation_score=0 (trust_score=0 miatt), raw_data jelen van
|
|
- Frontend: mind a 4 Vue komponens módosítás érvényben
|