Files
service-finder/.roo/history.md
2026-07-08 08:03:57 +00:00

20 KiB
Raw Blame History

Service Finder Fejlesztési Történet

2026-06-21 - P0 Deep Audit: Database Consistency & Zombie API Hunt

🎯 Cél

...

2026-07-07 - P0 ServiceProvider AddressManager Integration

🎯 Cél

...

2. Seed script létrehozása és futtatása

A seed_dismantler_category.py szkript létrehozva (backend/app/scripts/), amely idempotens módon beszúrja az "Autóbontó / Használt alkatrész" kategóriát.

Verifikáció

  1. Seed script futtatva Sikeresen beszúrva az 'Autóbontó / Használt alkatrész' kategória (ID: 767). Összes rekord: 135.
  2. admin_providers.py szintaxis ellenőrzésimport app.api.v1.endpoints.admin_providers sikeres ( module imports OK)
  3. sync_engine futtatva → 1282 OK, 0 issue, schema fully in sync

2026-07-07 - P0 BUGFIX: Live Provider Advanced Fields & Gas Station Categories

🎯 Cél

P0 kritikus hibajavítás: Live Provider (ID 6, MOL Fót) opening_hours és category_ids mezői elvesztek a backend update_provider() végpontban, mert a ServiceProvider-hez nem tartozott ServiceProfile rekord. Emellett a "Shop / Kisbolt" kategória hiányzott a rendszerből.

🔧 Változtatások

1. Backend fix: admin_providers.py

  • P0 BUGFIX (2026-07-07): Ha egy Live Provider-hez nem létezik ServiceProfile, de a PATCH kérésben advanced mezők (opening_hours, specializations, supported_vehicle_classes, category_ids) érkeznek, a backend MOST automatikusan létrehoz egy ServiceProfile rekordot.
  • Response serialization fix: A category_ids visszaadása előtt a rendszer lekérdezi a tényleges DB állapotot a ServiceExpertise táblából (resolved_category_ids), így a frontend mindig a valóban elmentett adatokat kapja vissza.

2. Seed script: seed_gas_station.py

  • Létrehozva a hiányzó "Shop / Kisbolt" (Convenience Store) kategória (ID: 768) az "Üzemanyag és Töltőállomás" (ID=755) szülő alá.
  • Meglévő kategóriák (ID=755, 756, 757) érintetlenek.

Verifikáció

  1. Seed script futtatva 'Shop / Kisbolt' (ID: 768) már létezik. Összes rekord: 136.
  2. sync_engine futtatva → 1282 OK, 0 issue, schema fully in sync

2026-07-07 - P0 CRITICAL HOTFIX: Promotion Engine v2

🎯 Cél

Javítani a Promotion Engine-t a PATCH /admin/providers/{id} végponton, amely ServiceStaging rekordok jóváhagyásakor nem futott le.

🔍 Root Cause Analysis

  1. Trigger condition too fragile: Az if is_staging and new_status == "approved": feltétel a new_status változóra támaszkodott, amely a update_fields.get("status")-ból származott. Ha a státusz nem volt explicit átadva a PATCH payload-ban (pl. csak name mezőt módosítottak), new_status None volt, és a promotion blokk teljesen kimaradt.
  2. ID handling bug: Promotion után a provider_obj átállításra került az új ServiceProvider-re, de az AuditLog (target_id=str(provider_id)) és a ServiceProfile lekérdezés (ServiceProfile.service_provider_id == provider_id) továbbra is a régi staging ID-t (pl. 1754) használta, nem az új provider ID-t.

🔧 Javítások

  1. Trigger condition → effective_status: A feltétel most a provider_obj.status-t (tényleges DB állapot) ellenőrzi közvetlenül, nem a new_status payload változót. Ez biztosítja, hogy a promotion akkor is lefusson, ha a státusz már "approved" volt a DB-ben, vagy ha nem volt explicit átadva.
  2. ID fix: Minden provider_id hivatkozás (AuditLog, ServiceProfile lookup) provider_obj.id-ra lett cserélve, ami promotion után az új ServiceProvider ID-ját tartalmazza.
  3. Logolás: logger.error("P0 PROMOTION TRIGGERED") hozzáadva a promotion blokk elejére a Docker logokban való trace-elhetőségért.

Verifikáció

  1. Szintaxis ellenőrzés py_compile sikeres
  2. Konténer újraindítás docker compose restart sf_api sikeres
  3. API elérhető Uvicorn fut a 8000-es porton

2026-07-07 - DDD Database Refactoring 1.0 (P0 - 3 Phase)

🎯 Cél

DDD Database Refactoring 1.0 három fázisban: address_id FK bevezetése, admin_providers.py egyszerűsítése, frontend cleanup.

🔧 Változtatások

#396 - Phase 1: address_id FK (Already Complete)

  • ServiceProvider.address_id és address_rel már létezett a modellben
  • Mind a 7 provider rekord rendelkezik address_id-vel
  • sync_engine 1282 OK, 0 drift - nincs teendő

#397 - Phase 2: admin_providers.py Simplify

  • _build_unified_providers_query(): ServiceProvider.address_id hozzáadva a SELECT-hez (12. oszlop)
  • ServiceStaging és Organization UNION ágak: literal(None).label("address_id") placeholder a column parityért
  • list_providers(): address_detail feloldása AddressManager.get_normalized() segítségével minden sorban
  • Ellenőrizve: list_providers endpoint minden provider esetén visszaadja az address_detail-t

#398 - Phase 3: Frontend Cleanup

  • garages/index.vue line 157: garage.city fallback eltávolítva → csak garage.address_detail?.city
  • providers/index.vue line 137: már address_detail-t használ (nem kellett módosítani)
  • providers/[id]/index.vue lines 144-166: már address_detail-t használ (nem kellett módosítani)
  • providers/[id]/edit.vue lines 1133-1148: már data.address_detail-t használ (nem kellett módosítani)

Verifikáció

  1. #397 API teszt list_providers endpoint 5 provider-t ad vissza address_detail mezővel
  2. #398 Frontend regex audit Nincs több provider.address vagy provider.city flat field referencia
  3. Konténer újraindítás docker compose restart sf_api sikeres

2026-07-07 - P0 BUGFIX: Category Sync & Parent-Child UX Automation

🎯 Cél

A provider admin felület kategória szinkronizációjának javítása legacy provider-eknél (ahol a ServiceProfile organization_id-n keresztül kapcsolódik), valamint a frontend kategória-választó UX automatizálása.

🔧 Változtatások

Backend: backend/app/api/v1/endpoints/admin_providers.py

  • get_provider_detail (line 615-618): ServiceProfile lekérdezés kiterjesztve OR-ra: (ServiceProfile.service_provider_id == provider_id) | (ServiceProfile.organization_id == provider_id)
  • update_provider (line 1575-1578): Ugyanez a javítás a PATCH végpontban, provider_obj.id-t használva
  • Root Cause: Legacy provider-eknél (pl. ID 6) a ServiceProfile organization_id mezőn keresztül kapcsolódik, nem service_provider_id-n. Az egyszerű FK keresés miatt a profil nem található -> category_ids elveszett a válaszból és a mentésből.

Frontend: frontend_admin/pages/providers/[id]/edit.vue

  • Import (line 626): watch hozzáadva a Vue import-hoz
  • parentLookupMap (line 942): Flat Map<number, number> a kategória fa rekurzív bejárásához
  • buildParentLookupMap() (line 944): Rekurzív fa bejáró, ami minden gyermek node-hoz hozzárendeli a szülő ID-t
  • watch(categoryTree, ...) (line 956): A map újraépítése minden fa betöltéskor
  • toggleCategory() (line 961): Gyermek kategória kiválasztásakor automatikusan hozzáadja a szülő kategória ID-t is a form.category_ids tömbhöz

Verifikáció

  1. Backend szintaxis -> OK: admin_providers modul sikeresen betöltve a konténerben
  2. Sync Engine -> OK: 1282 OK, 0 hiba, adatbázis szinkronban
  3. Frontend -> OK: Import és toggleCategory módosítva, watch + parentLookupMap beépítve

2026-07-07 - P0 BUGFIX: ServiceProfile Auto-Creation on PATCH for New Providers

🎯 Cél

P0 kritikus hibajavítás: PATCH /admin/providers/{id} 500-as hibát dobott, ha a provider-hez nem tartozott ServiceProfile rekord. A _sync_service_expertises() hívás profile.id-t használt, de profile None maradt, mert a ServiceProfile létrehozás feltételes volt (has_advanced_fields).

🔧 Változtatások

1. Import fix: admin_providers.py

  • ServiceExpertise hozzáadva az import-hoz (hiányzott, NameError-t okozott futásidőben)

2. ServiceProfile unconditional creation: admin_providers.py

  • Előtte: ServiceProfile csak akkor jött létre, ha has_advanced_fields True volt
  • Utána: Ha nincs ServiceProfile, MINDIG létrejön egy alapértelmezett profil (fingerprint: auto-created-{provider_id}, status: active, trust_score: 30)
  • Debug logolás hozzáadva (print + logger.info) a sync hívás előtt

Verifikáció

  1. Sync Engine -> OK: 1282 OK, 0 hiba, adatbázis szinkronban
  2. E2E teszt -> PATCH 200 SUCCESS: provider #21 (Test Provider No Address - Fixed v4) sikeresen frissítve category_ids=[12, 13, 14]-gyel
  3. Docker log -> P0 BUGFIX: Auto-created ServiceProfile #24 for Live provider #21

2026-07-07 - P0 HOTFIX: Edit Form Chips & Reactivity Deep Clone

🎯 Cél

P0 kritikus hibajavítás: A provider edit űrlapon a kiválasztott kategória chipek nyers ID-kat jelenítettek meg (#760) név helyett, és a "Mentés" gomb disabled maradt kategória toggle után.

🔍 Root Cause Analysis

  1. Chip Display: A template már {{ getCategoryName(id) }}-t használt (line 243), és a useCategories composable getCategoryName() függvénye helyesen visszaadja a nevet, ha a categoryMap be van töltve. A #760 fallback akkor jelenik meg, ha a kategóriák még nem töltődtek be — ez normális átmeneti állapot.
  2. Reactivity Bug (Fő probléma): A mapProviderToForm() függvényben a form.category_ids = data.category_ids || [] direkt referenciát másolt, nem deep clone-t. Mivel a form.category_ids és a provider.value.category_ids ugyanarra a tömbre mutattak, a hasChanges computed property sosem érzékelte a változást — a kategória toggle mindkét referenciát egyszerre módosította.

🔧 Változtatások

frontend_admin/pages/providers/[id]/edit.vue

  • mapProviderToForm() (lines 1137-1148): Minden tömb értékadás deep clone-ra javítva:
    • form.supported_vehicle_classes = [...(data.supported_vehicle_classes || [])]
    • form.category_ids = [...(data.category_ids || [])]
    • form.specializations.brands = Array.isArray(spec.brands) ? [...spec.brands] : []
    • form.specializations.propulsion = Array.isArray(spec.propulsion) ? [...spec.propulsion] : []

Verifikáció

  1. Deep clone ellenőrzés: form.category_ids és provider.value.category_ids most külön referenciák — a toggleCategory() hívás után a hasChanges helyesen true-t ad vissza.
  2. Chip display: A template már {{ getCategoryName(id) }}-t használ (line 243), a useCategories.getCategoryName() pedig a categoryMap-ből adja vissza a nevet, vagy #${id} fallback-et, ha még nem töltődött be.

2026-07-07 - P0 EPIC: i18n JSONB Database Migration (Phase 1 & 2)

🎯 Cél

Architect által jóváhagyott i18n JSONB migrációs terv (plans/logic_spec_i18n_jsonb_migration_phase1.md) első két fázisának implementálása: Séma bővítés (Phase 1) és Adatmigráció (Phase 2).

🔧 Változtatások

Phase 1: Schema Expansion (3 SQLAlchemy model)

  1. backend/app/models/marketplace/service.pyExpertiseTag osztály:

    • name_i18n: Mapped[dict] = mapped_column(JSONB, nullable=False, server_default=text("'{\"hu\": \"\"}'::jsonb"))
    • description_i18n: Mapped[Optional[dict]] = mapped_column(JSONB, nullable=True)
    • GIN index: Index('idx_expertise_tags_name_i18n', 'name_i18n', postgresql_using='gin')
  2. backend/app/models/vehicle/vehicle_definitions.pyBodyTypeDictionary osztály:

    • name_i18n: Mapped[dict] = mapped_column(JSONB, nullable=False, server_default=text("'{\"hu\": \"\"}'::jsonb"))
    • GIN index: Index('idx_dict_body_types_name_i18n', 'name_i18n', postgresql_using='gin')
  3. backend/app/models/core_logic.pyServiceCatalog osztály:

    • name_i18n: Mapped[dict] = mapped_column(JSONB, nullable=False, server_default=text("'{\"hu\": \"\"}'::jsonb"))
    • description_i18n: Mapped[Optional[dict]] = mapped_column(JSONB, nullable=True)
    • GIN index: Index('idx_service_catalog_name_i18n', 'name_i18n', postgresql_using='gin')

Phase 2: Data Migration Script

  1. backend/app/scripts/migrate_i18n_jsonb.py — Létrehozva:
    • Aszinkron migrációs script, amely a régi name_hu/name_en oszlopokat JSONB struktúrába csomagolja
    • Kezeli a name_translations meglévő JSONB mező merge-elését is
    • json.dumps() használata az asyncpg JSONB kompatibilitás miatt
    • Idempotens: ON CONFLICT DO NOTHING + meglévő adatok felülírása

📊 Migrációs Eredmények

Tábla Sorok name_i18n description_i18n
marketplace.expertise_tags 136 {"hu": "...", "en": "..."} {"hu": "..."}
vehicle.dict_body_types 16 {"hu": "Szedán", ...} N/A
system.service_catalog 3 {"hu": "Adat Export"} {"hu": "PDF és Excel..."}

🗄️ GIN Indexek

Index Tábla Típus
idx_expertise_tags_name_i18n marketplace.expertise_tags GIN on name_i18n
idx_dict_body_types_name_i18n vehicle.dict_body_types GIN on name_i18n
idx_service_catalog_name_i18n system.service_catalog GIN on name_i18n

Verifikáció

  1. sync_engine futtatva → 1287 OK, 0 Fixed, 0 Shadow — schema fully in sync
  2. 5 új JSONB oszlop létrehozva a DB-ben (3× name_i18n, 2× description_i18n)
  3. 3 GIN index manuálisan létrehozva (sync_engine nem kezeli az indexeket)
  4. 155 sor sikeresen migrálva (136 expertise_tags + 16 dict_body_types + 3 service_catalog)
  5. Régi oszlopok (name_hu, name_en, name, description) érintetlenek — backward compatibility biztosítva

2026-07-08 - P0 i18n Static Dictionary Cleanup (Admin Frontend)

🎯 Cél

Az admin frontend összes providers oldalának és a layout sidebar menüjének teljes i18n konverziója. Minden hardcoded magyar szöveg $t() / t() hívásokra cserélése, és a hiányzó fordítási kulcsok felvétele a hu.json és en.json fájlokba.

🔧 Változtatások

1. Layout (default.vue)

  • menuGroups array összes label-je i18n kulcsokra cserélve (menu.center, menu.dashboard, menu.providers, stb.)
  • pageTitle computed property összes hardcoded string i18n kulcsokra cserélve
  • Key fix: menu.ledgermenu.points_ledger, gamification.users.detailgamification.users.user_detail_title

2. Providers oldalak

  • index.vue - Teljes konverzió: template + script (statusLabel())
  • pending.vue - Teljes konverzió: template + script (toast üzenetek)
  • rejected.vue - Teljes konverzió: template + script (toast üzenetek)
  • [id]/index.vue - Teljes konverzió: template (minden szekció, modal, drawer) + script (tabs, DAYS, statusLabel, statusDescription, vehicleClassLabel, validationTypeLabel, historyActionLabel, toast üzenetek)
  • [id]/edit.vue - Teljes konverzió: template (minden tab, szekció, drawer) + script (tabs, VEHICLE_CLASSES, DAYS, copyWeekdays, saveForm toasts)

3. Lokalizációs fájlok

  • hu.json - ~200+ új providers kulcs (index, pending, rejected, detail, edit)
  • en.json - ~200+ új providers kulcs angol fordítással

Verifikáció

  1. Buildnpm run build sikeres (sf_admin_frontend konténerben)
  2. Nincs fordítási hiba - minden használt i18n kulcs létezik a locale fájlokban

2026-07-08 - P0 Architectural Upgrade: Modular i18n Locales Migration

🎯 Cél

Migrate the Nuxt admin frontend from monolithic i18n locale files (single hu.json, en.json) to Nuxt i18n Modular Locales (multiple domain-specific JSON files per locale).

🔧 Változtatások

  1. frontend_admin/nuxt.config.ts (31. sor): Changed langDir from 'i18n/locales/' to 'locales/' to avoid path doubling with Nuxt i18n module's automatic i18nDir detection. Updated hu and en locale configs to use files array pattern instead of single file.

  2. frontend_admin/i18n/locales/hu/common.json (CREATED): Extracted all common.* keys from old monolithic hu.json (loading, saving, error, retry, save, cancel, delete, edit, search, filter, status, permissions, etc.)

  3. frontend_admin/i18n/locales/en/common.json (CREATED): English equivalents of all common.* keys.

  4. frontend_admin/i18n/locales/hu/menu.json (CREATED): Extracted all menu.* keys (center, dashboard, providers, garages, users, finance, packages, gamification, system, etc.)

  5. frontend_admin/i18n/locales/en/menu.json (CREATED): English equivalents of all menu.* keys.

  6. frontend_admin/i18n/locales/hu/providers.json (UPDATED): Expanded from ~84 lines to ~280 lines with all provider-related keys from old monolithic file.

  7. frontend_admin/i18n/locales/en/providers.json (UPDATED): English equivalents, expanded similarly.

  8. frontend_admin/locales/hu.json (DELETED): Old monolithic Hungarian locale file (1003 lines).

  9. frontend_admin/locales/en.json (DELETED): Old monolithic English locale file (1003 lines).

🔍 Megjegyzések

  • A Nuxt i18n modul automatikusan detektálja az i18n/ könyvtárat a projekt gyökerében, és azt használja i18nDir-ként. Ezért a langDir-t relatívan kell megadni ehhez a könyvtárhoz ('locales/'), nem pedig abszolút módon ('i18n/locales/').
  • A többi nyelv (de, fr, ro, cz, sk) továbbra is a régi frontend_admin/locales/ könyvtárban található monolit fájlokat használja.
  • A konténer újraindítás után sikeresen elindult, a Nitro szerver és a Vite klienst is felépítette.
  • A @intlify/message-compiler Invalid linked format hibát dobott az info@example.com email placeholder értékben lévő @ karakter miatt. A javítás: {'@'} Intlify szintaxis használata a hu/providers.json és en/providers.json fájlokban.

2026-07-08 - P0 CRITICAL i18n Audit & Repair (HU/EN) - Fix #6: Missing persons.json

🎯 Cél

A Nuxt i18n modul computeLocaleHashes függvénye ENOENT hibát dobott, mert a persons.json fájl nem létezett a frontend_admin/i18n/locales/en/ és hu/ könyvtárakban, pedig a nuxt.config.ts files tömbje hivatkozott rá.

🔧 Végrehajtott Javítások

  1. frontend_admin/i18n/locales/en/persons.json (LÉTREHOZVA): Angol nyelvű személykezelő fordítások (3456 byte), 80+ kulcs a persons.* és persons.details.* névtérben.
  2. frontend_admin/i18n/locales/hu/persons.json (LÉTREHOZVA): Magyar nyelvű személykezelő fordítások (3898 byte), azonos struktúrával.

📝 Technikai Részletek

  • A persons.* kulcsokat a pages/persons/index.vue (lista nézet) és pages/persons/[id]/index.vue (részletek nézet) template-ek használják.
  • A hiányzó fájl a nuxt.config.ts 24 moduláris fájljának egyike volt, amelyet a Fix #3 során adtunk hozzá a files tömbhöz, de a fájl ténylegesen nem létezett a lemezen.
  • A .nuxt cache törlése (sudo rm -rf frontend_admin/.nuxt/dev) és a konténer újraindítása után a build sikeresen lefutott i18n hibák nélkül.

Verifikáció

  1. Konténer újraindítvadocker compose restart sf_admin_frontend
  2. Build logok✔ Vite client built in 40ms, ✔ Vite server built in 445ms, [nitro] ✔ Nuxt Nitro server built in 1526ms
  3. i18n hibák → Nincs ERROR, nincs ENOENT, nincs i18n compilation error