refaktor címtár

This commit is contained in:
Roo
2026-07-01 19:49:58 +00:00
parent 6e627d0ebe
commit 7654913d21
198 changed files with 3485 additions and 1609 deletions

View File

@@ -8,318 +8,124 @@ Teljes körű adatbázis konzisztencia ellenőrzés és zombie API végpontok fe
### 🔧 Eredmények
**1. ADATBÁZIS TISZTASÁG:** ✅ PASS
- API modul import: ✅ Sikeres (2 route: GET, POST)
- Sync Engine: ✅ 1210 OK, 0 Fixed, 0 Extra
- E2E test: ⚠️ Pre-existing conftest hiba (verification token timeout - nem kapcsolódó)
## 2026-06-30 - [#343] Fázis 4/7: Gamification kulcsok felvétele backend lokációs fájlokba
### 🎯 Cél
GAMIFICATION szekció létrehozása a `backend/static/locales/en.json` és `hu.json` fájlokban a `docs/gamification_i18n_audit_and_fix_proposal.md` dokumentáció alapján.
### 🔧 Módosított fájlok
## 2026-07-01 - Opening Hours (JSONB) Admin UI támogatás
### 🎯 Cél
Nyitvatartás (Opening Hours) JSONB mező adminisztrációs támogatásának megvalósítása: backend API (GET/PATCH), frontend edit UI (7 napos grid), frontend detail display.
### 🔧 Módosított fájlok
- `backend/app/api/v1/endpoints/admin_providers.py` - ProviderDetail + ProviderUpdateInput sémák `opening_hours` mezővel; get_provider_detail() és update_provider() végpontok kiegészítése a ServiceProfile JSONB oszlop olvasásával/írásával
- `frontend_admin/pages/providers/[id]/edit.vue` - "Nyitvatartás" tab (4. tab) 7 napos grid-del, checkbox + time input párokkal, 24/7 gyorsgombbal, hétköznap másolással, összes törléssel
- `frontend_admin/pages/providers/[id]/index.vue` - Nyitvatartás megjelenítő tábla a részletes nézetben
### ✅ Verifikáció
- Sync Engine: 1297 OK, 0 Fixed, 0 Extra - rendszer tökéletesen szinkronban
- GET /admin/providers/1 → 200, `opening_hours` mező visszatér
- PATCH /admin/providers/1 `opening_hours` → 200, adatok perzisztálódnak és visszaolvashatók
## 2026-06-30 - [#377] M4: Többnyelvű támogatás bevezetése (DE, FR, RO, CZ, SK)
### 🎯 Cél
5 új nyelv (Német, Francia, Román, Cseh, Szlovák) bevezetése a backend és frontend admin i18n rendszerekbe.
### 🔧 Létrehozott fájlok
- `backend/static/locales/de.json` - Backend német lokációs fájl (7 szekció)
- `backend/static/locales/fr.json` - Backend francia lokációs fájl (7 szekció)
- `backend/static/locales/ro.json` - Backend román lokációs fájl (7 szekció)
- `backend/static/locales/cz.json` - Backend cseh lokációs fájl (7 szekció)
- `backend/static/locales/sk.json` - Backend szlovák lokációs fájl (7 szekció)
- `frontend_admin/locales/de.json` - Frontend admin német fő lokációs fájl
- `frontend_admin/locales/fr.json` - Frontend admin francia fő lokációs fájl
- `frontend_admin/locales/ro.json` - Frontend admin román fő lokációs fájl
- `frontend_admin/locales/cz.json` - Frontend admin cseh fő lokációs fájl
- `frontend_admin/locales/sk.json` - Frontend admin szlovák fő lokációs fájl
- `frontend_admin/i18n/locales/de.json` - Frontend admin német közös lokációs fájl
- `frontend_admin/i18n/locales/fr.json` - Frontend admin francia közös lokációs fájl
- `frontend_admin/i18n/locales/ro.json` - Frontend admin román közös lokációs fájl
- `frontend_admin/i18n/locales/cz.json` - Frontend admin cseh közös lokációs fájl
- `frontend_admin/i18n/locales/sk.json` - Frontend admin szlovák közös lokációs fájl
### 🔧 Módosított fájlok
- `frontend_admin/nuxt.config.ts` - 5 új nyelv regisztrálása a @nuxtjs/i18n konfigurációban
### ✅ Verifikáció
- Backend i18n: Mind az 5 nyelv betöltődik (7-7 szekció), leaf key fordítések működnek
- Sync Engine: 1293 OK, 0 Fixed, 0 Extra - rendszer tökéletesen szinkronban
### 🎯 Cél
GAMIFICATION szekció létrehozása a `backend/static/locales/en.json` és `hu.json` fájlokban a `docs/gamification_i18n_audit_and_fix_proposal.md` dokumentáció alapján.
### 🔧 Módosított fájlok
## 2026-06-30 - [#376] M3: Admin nyelvválasztó átalakítása legördülő menüvé
### 🎯 Cél
A jelenlegi kétállású HU/EN kapcsoló átalakítása bővíthető, legördülő nyelvválasztó dropdownná, amely a backend-ből érkező támogatott nyelveket listázza.
### 🔧 Módosított fájlok
- `frontend_admin/components/LanguageSwitcher.vue`**LÉTREHOZVA**: Új önálló LanguageSwitcher dropdown komponens zászló emoji-kkal, nyelv nevével, localStorage + backend perzisztálással
- `frontend_admin/layouts/default.vue`**MÓDOSÍTVA**: 157-170. sorokban a régi gomb-alapú kapcsoló kicserélve `<LanguageSwitcher />` komponensre; felesleges `useI18n` import és `switchLocale`/`getAuthHeaders` függvények eltávolítva
### 📊 Eredmény
- LanguageSwitcher komponens: ✅ Létrehozva (zászló emoji, dinamikus locale lista, backend PATCH perzisztálás, localStorage)
- default.vue cleanup: ✅ 25 sor kód eltávolítva (i18n logika kiszervezve)
- Nuxt production build: ✅ Sikeres
## 2026-06-30 - Admin Provider Root Cause Analysis (#379)
**Vizsgálat típusa:** Rendszer-Architect root cause analysis
**Gitea kártya:** #379
### Felfedezett probléma
Az admin felület (providers list & pending queue) csak 6 rekordot mutat a `marketplace.service_providers` táblából. A robotok által gyűjtött 8569 rekord a `marketplace.service_staging`-ben láthatatlan.
### Root Cause
A `backend/app/api/v1/endpoints/admin_providers.py` `list_providers()` és `get_provider_stats()` endpointjai kizárólag a `ServiceProvider` modellt kérdezik le. A `provider_service.py` `search_providers()` (public API) már helyesen használ UNION ALL-t mindhárom forrásból.
### Javítási terv
1. `ProviderListItem` response model kiegészítése `source_table` mezővel
2. `list_providers()` UNION ALL kiterjesztése ServiceStaging-re
3. `get_provider_stats()` kiterjesztése staging rekordokkal
4. Nem kell új validációs mező - a `provider_validations`, `service_profiles.trust_score` stb. már létezik
### Dokumentáció
`docs/admin_providers_root_cause_analysis.md`
## 2026-06-30 - Admin Provider Discovery Implementáció
### 🎯 Cél
A `list_providers()` admin végpont kiterjesztése UNION ALL lekérdezéssel, hogy a bot által gyűjtött ServiceStaging rekordok (8569 db) és a verified organization-ök is megjelenjenek az admin felületen. Új `rejected.vue` oldal az elutasított szolgáltatók visszaállításához.
### 🔧 Változtatások
1. `backend/app/api/v1/endpoints/admin_providers.py`:
- `_build_unified_providers_query()`: UNION ALL a ServiceProvider, ServiceStaging és Organizations táblákból
- `source_filter` és `source_table_filter` a UNION ALL eredményére alkalmazva (nem az egyes részekre) - kijavítva a SourceType enum ütközési hibát
- `get_provider_stats()`: staging_pending mező hozzáadása
- `restore_provider()`: POST végpont rejected->approved státuszváltáshoz
- `get_provider_history()`, `update_provider()` végpontok
2. `frontend_admin/pages/providers/rejected.vue`: új oldal az elutasított szolgáltatók listázásához és visszaállításához
3. `frontend_admin/pages/providers/index.vue`: source_table, bot/verified_org szűrés támogatás
4. `frontend_admin/pages/providers/pending.vue`: source_table mező hozzáadása
### ✅ Tesztek
- `source=bot` filter: 200 OK, 5 staging rekord visszaadva
- `source=verified_org` filter: 200 OK, 1 organization rekord
- `source_table=service_staging` filter: 200 OK, 3 staging rekord
- Stats: total=8575, staging_pending=5096
- Rejected filter: 200 OK, 2 rejected rekord
## 2026-06-30 - Provider Admin Tabbed Edit UI (Status, Validations, History)
### 🎯 Cél
A szolgáltatók admin felületének bővítése: többfülű szerkesztési nézet, státuszkezelés, gamification validációs lista és állapotváltoztatási előzmények megjelenítése.
### 🔧 Módosított fájlok
**1. `backend/app/api/v1/endpoints/admin_providers.py`**
- `ProviderUpdateInput` séma bővítése: `status` (pending/approved/rejected) és `validation_score` (0-100) mezőkkel
- `ProviderValidationEntry` response séma létrehozása (id, provider_id, voter_user_id, validation_type, weight, validation_metadata, created_at, voter_name)
- `GET /admin/providers/{id}/validations` végpont: gamification validációk lekérése voter névvel
- `PATCH /admin/providers/{id}` módosítása: státuszváltás kezelése (ModerationStatus enum), old_data audit snapshot, validation_score auto-állítás restore/reject esetén
**2. `frontend_admin/pages/providers/[id].vue`**
- Teljes átírás: egysávos layout helyett 4 fül (Adatok, Státusz, Validációk, Előzmények)
- **Adatok fül**: változatlan alapadatok, cím, elérhetőség, moderációs műveletek
- **Státusz fül**: új űrlap státusz select, validation_score range slider (0-100), indoklás textarea
- **Validációk fül**: gamification validációs lista típus-badge-ekkel, szavazó név, súly, metadata, timestamp
- **Előzmények fül**: idővonal action-badge-ekkel, státusz átmenetek (régi→új), user info, expandálható részletek
- Elutasított/Megjelölt szekció: "Szerkesztés" és "Visszaállítás" gombok minden státuszhoz
### ✅ Verifikáció
- Sync Engine: ✅ 1293 OK, 0 Fixed, 0 Extra - teljes szinkron
- Backend syntax: ✅ admin_providers.py AST parse OK
- Backend import: ✅ router modul betöltés sikeres
## 2026-06-30 - P0 Rescue: Admin Providers API Blocker Fixes
### 🎯 Cél
4 darab kritikus blokkoló hiba javítása az Admin Providers flow-ban.
### 🔧 Változtatások
**FIX 1 - Silent Rollback (PATCH endpoint):**
- [`update_provider()`](backend/app/api/v1/endpoints/admin_providers.py:1147) `db.commit()` köré `try/except IntegrityError` blokk került
- IntegrityError esetén `db.rollback()` + `HTTPException(400)` a csendes 200 OK helyett
**FIX 2 - Unique Constraint on Restore:**
- [`_create_provider_validation()`](backend/app/api/v1/endpoints/admin_providers.py:198) átírva PostgreSQL `INSERT ... ON CONFLICT DO UPDATE` (UPSERT) használatára
- A `uq_voter_provider_validation` constraint tiszteletben tartva
**FIX 3 - Wrong Frontend URL:**
- Ellenőrizve: a frontend [`[id].vue`](frontend_admin/pages/providers/[id].vue:761) már a helyes `/api/v1/admin/providers/{id}/validations` URL-t használja
**FIX 4 - AuditLog Attribute Error:**
- [`get_provider_history()`](backend/app/api/v1/endpoints/admin_providers.py:1029) `AuditLog.created_at``AuditLog.timestamp`
- `timestamp=log.created_at``timestamp=log.timestamp`
### ✅ Verifikáció
- Backend syntax: ✅ `py_compile` OK
- Modul import: ✅ `admin_providers` modul betöltés sikeres
- Container: ✅ `sf_api` restart sikeres, státusz Up
## 2026-06-30 - [#381] P0 Fix: Provider validations 500 error & missing edit/flag modals
### 🎯 Cél
Két P0 hibajavítás az Admin Provider Details oldalon.
### 🔧 Módosított fájlok
**Bug #1 - `get_provider_validations()` 500 error:**
- [`admin_providers.py`](backend/app/api/v1/endpoints/admin_providers.py:1018) — `v.voter.display_name``v.voter.email`
- Root cause: `User` modellben nincs `display_name` mező
**Bug #2 - Dead "Szerkesztés" gomb:**
- [`[id].vue`](frontend_admin/pages/providers/[id].vue:540) — Edit modal template hozzáadva (name, city, address, contact, category mezőkkel)
- [`[id].vue`](frontend_admin/pages/providers/[id].vue:603) — Flag modal template hozzáadva (indoklás textarea-val)
- Root cause: A `<template>` szekcióból hiányzott mindkét modal, bár a JavaScript logika (`showEditModal`, `openEditModal`, `saveEdit`, `showFlagModal`, `flagProvider`) definiálva volt
### ✅ Verifikáció
- Backend syntax: ✅ `ast.parse` OK
- Frontend template: ✅ Mind a 3 modal (Reject, Edit, Flag) jelen van a `<template>`-ben
## 2026-07-01 - [#382] P0: Backend Database Models - 3D Filtering Matrix
### 🎯 Cél
A ServiceProvider és ServiceProfile modellek bővítése `supported_vehicle_classes` (ARRAY) és `specializations` (JSONB) oszlopokkal a 3D szűrési mátrix támogatásához. Pydantic schemák frissítése az új mezőkkel.
### 🔧 Módosított fájlok
**1. [`backend/app/models/identity/social.py`](backend/app/models/identity/social.py:55)**
- `ARRAY` import hozzáadva `sqlalchemy.dialects.postgresql`-ből
- `supported_vehicle_classes: Mapped[Optional[list]] = mapped_column(ARRAY(String), server_default=text("'{}'"), nullable=True)`
- `specializations: Mapped[Optional[dict]] = mapped_column(JSONB, server_default=text("'{}'::jsonb"), nullable=True)`
**2. [`backend/app/models/marketplace/service.py`](backend/app/models/marketplace/service.py:40)**
- `ARRAY` import hozzáadva `sqlalchemy.dialects.postgresql`-ből
- Azonos 2 oszlop hozzáadva a ServiceProfile modellhez
**3. [`backend/app/api/v1/endpoints/admin_providers.py`](backend/app/api/v1/endpoints/admin_providers.py:126)**
- `ProviderUpdateInput`: `category_ids`, `supported_vehicle_classes`, `specializations` mezők
- `ProviderDetail`: `category_ids`, `supported_vehicle_classes`, `specializations` mezők
- `get_provider_detail()` és `update_provider()` response-ok frissítve
**4. [`backend/app/schemas/provider.py`](backend/app/schemas/provider.py:137)**
- `ProviderQuickAddIn`: `supported_vehicle_classes`, `specializations` mezők
- `ProviderUpdateIn`: `supported_vehicle_classes`, `specializations` mezők
- `ProviderSearchResult`: `supported_vehicle_classes`, `specializations` mezők
### ✅ Verifikáció
- Sync Engine: ✅ 1293 OK, 4 Fixed (4 új oszlop), 0 Extra
- Adatbázis oszlopok ellenőrizve: `marketplace.service_providers.supported_vehicle_classes` (ARRAY), `marketplace.service_providers.specializations` (JSONB), `marketplace.service_profiles.supported_vehicle_classes` (ARRAY), `marketplace.service_profiles.specializations` (JSONB) — mind jelen van megfelelő típussal és default értékkel
## 2026-07-01 - [#383] P0: Admin PATCH endpoint - ServiceExpertise sync & Array persistence
### 🎯 Cél
A `PATCH /admin/providers/{id}` végpont kiegészítése: `category_ids`, `supported_vehicle_classes`, `specializations` mezők mentése mind a ServiceProvider, mind a ServiceProfile modellekbe, valamint `_sync_service_expertises()` meghívása a ServiceProfile ID-val a taxonomy fa szinkronizálásához.
### 🔧 Módosított fájlok
**1. [`backend/app/api/v1/endpoints/admin_providers.py`](backend/app/api/v1/endpoints/admin_providers.py:1098)**
- **Importok bővítése**: `ServiceProfile` import `app.models.marketplace.service`-ből, `_sync_service_expertises` import `app.services.provider_service`-ből
- **`update_provider()`**: `category_ids`, `supported_vehicle_classes`, `specializations` kiemelése a payload-ból `update_fields.pop()` segítségével; tömbök mentése ServiceProvider-re; ServiceProfile lekérése `service_provider_id` alapján; tömbök mentése ServiceProfile-ra; `_sync_service_expertises(db, profile.id, category_ids)` hívása
- **`get_provider_detail()`**: `category_ids` feloldása a ServiceExpertise join táblából ServiceProfile-on keresztül (korábban hardcoded `None`)
### ✅ Verifikáció
- Backend syntax: ✅ `py_compile` OK (exit code 0)
- Container restart: ✅ `sf_api` sikeresen újraindítva
- Import verifikáció: ✅ `ProviderUpdateInput` séma tartalmazza a `category_ids`, `supported_vehicle_classes`, `specializations` mezőket
## 2026-07-01 - [#384] P0: Service Provider Dedicated Full-Page Editor
### 🎯 Cél
Dedikált teljes oldalas szerkesztő létrehozása a szolgáltatók adminisztrációjához, amely felváltja a hiányzó modális szerkezetet. A szerkesztő 3 tabos struktúrával rendelkezik: Alapadatok & Kapcsolat, Szolgáltatások & Járművek (3D Mátrix), Helyszín & Lokáció.
### 🔧 Létrehozott fájlok
- `frontend_admin/pages/providers/[id]/edit.vue` - Teljes oldalas 3-tabos szerkesztő (Alapadatok, 3D Mátrix, Helyszín)
- `frontend_admin/components/TreeNode.vue` - Rekurzív fa komponens a kategória hierarchia megjelenítéséhez
### 🔧 Módosított fájlok
- `frontend_admin/pages/providers/[id].vue` - "Szerkesztés" gomb átirányítása a modális helyett az új `/providers/{id}/edit` útvonalra
### 📝 Technikai részletek
- **Tab 1 (Alapadatok & Kapcsolat):** Név, Kategória, Forrás (read-only), Telefon, Email, Weboldal
- **Tab 2 (Szolgáltatások & Járművek):** 3D Képesség Mátrix - A: Járműosztályok (8 checkbox), B: Szolgáltatási Kategóriák (rekurzív fa), C: Specializációk (márka + hajtáslánc tag inputok)
- **Tab 3 (Helyszín & Lokáció):** Teljes cím, Város, Irányítószám, Utca, Házszám, Plus Code
- **API integráció:** PATCH `/api/v1/admin/providers/{id}` végpont használata a `ProviderUpdateInput` séma szerint
- **Adatfolyam:** GET provider detail → form mapping → user edit → PATCH save → visszanavigálás a detail oldalra
- **Build:** Sikeres Nuxt build hibák nélkül
## 2026-07-01 - P0 HOTFIX: Edit page data modification fix (3 bugs)
### 🎯 Cél
A `/providers/[id]/edit` oldalon a felhasználó nem tudott adatokat módosítani és menteni. 3 összefüggő hibát azonosítottam és javítottam.
### 🔧 Javítások
**1. Backend - Hiányzó `address` mező a `ProviderUpdateInput` sémában**
- Hely: `backend/app/api/v1/endpoints/admin_providers.py:127`
- Probléma: A PATCH végpont Pydantic sémája nem tartalmazta az `address` mezőt, így a "Teljes cím" módosítása sosem került mentésre.
- Javítás: `address: Optional[str] = Field(None, max_length=500)` hozzáadva a sémához.
**2. Frontend - Hiányzó `address` és `address_street_type` a `hasChanges` computed-ból**
- Hely: `frontend_admin/pages/providers/[id]/edit.vue:579`
- Probléma: A Mentés gomb disabled maradt, ha csak a "Teljes cím" vagy "Utca típusa" mezőt módosították.
- Javítás: `form.address !== (p.address || '')` és `form.address_street_type !== (p.address_street_type || '')` ellenőrzések hozzáadva.
**3. Frontend - Hiányzó `address` a `saveForm` payload-ból**
- Hely: `frontend_admin/pages/providers/[id]/edit.vue:803`
- Probléma: A PATCH kérés törzséből hiányzott az `address` mező.
- Javítás: `address: form.address || null` hozzáadva a payload objektumhoz.
### ✅ Verifikáció
- Backend Python szintaxis: OK
- Sync Engine: 1297 elem OK, 0 hiba, teljes szinkronban
---
## 2026-07-01 - P0 Feature: "Always Open" (0-24) nyitvatartás a provider admin felületen
### 🎯 Cél
A provider admin szerkesztő felületen egy "Folyamatos (0-24) nyitvatartás" checkbox bevezetése, amely:
- Backend: `is_always_open: Optional[bool]` mező a `ProviderUpdateInput` sémában
- Backend: Ha `is_always_open=True`, a `update_provider()` PATCH endpoint automatikusan 00:00-23:59-re állítja mind a 7 napot, és `always_open: true` metadatát tárol a JSONB `opening_hours` mezőben
- Backend: Ha `is_always_open=False`, a meglévő `opening_hours` mentése változatlan, az `always_open` kulcs törlődik
- Frontend: Checkbox a Nyitvatartás tabon, amely bekapcsoláskor letiltja a naponkénti bevitelt és 00:00-23:59-re állít mindent
- Adatbázis: Nincs új migráció - a `always_open` metadata a meglévő JSONB `opening_hours` oszlopban tárolódik
### 🔧 Módosított fájlok
**1. Backend - `backend/app/api/v1/endpoints/admin_providers.py`**
- `ProviderUpdateInput` osztály: `is_always_open: Optional[bool] = Field(None, ...)` hozzáadva (148. sor)
- `update_provider()` PATCH endpoint: `is_always_open` kinyerése `update_fields`-ből, 0-24 kényszerítés True esetén, metadata törlés False esetén (1150-1170. sor)
**2. Frontend - `frontend_admin/pages/providers/[id]/edit.vue`**
- `form` reactive objektum: `is_always_open: false` mező hozzáadva
- Template: "Folyamatos (0-24) nyitvatartás" checkbox a Nyitvatartás tab tetején, amely letiltja a naponkénti grid-et
- `onAlwaysOpenChange()`: Checkbox toggle handler - bekapcsoláskor `setAllDaysOpen('00:00', '23:59')`, kikapcsoláskor `clearAllHours()`
- `mapProviderToForm()`: `always_open` metadata felismerése a JSONB-ből (mind a régi flat, mind az új nested formátum támogatott)
- `hasChanges` computed: `is_always_open` összehasonlítás a `p.opening_hours?.always_open`-val
- `saveForm()`: `is_always_open: form.is_always_open` a PATCH payload-ban
### ✅ 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)