24 KiB
✅ Verifikáció
- Build ellenőrzés →
npx vite buildsikeres (7.08s, 0 error) - Chunk generálva:
CostEntryWizard-C_-R4OzC.js(29.95 kB) - refaktorált komponens helyesen fordul - ProviderAutocomplete újrafelhasználva mindhárom komponensben - nincs duplikáció
P0 EPIC - UI/UX Overhaul for Quick Fuel Logging (Gitea #404)
Dátum: 2026-07-09 Scope: Backend + Frontend (SimpleFuelModal, ProviderAutocomplete, ProviderQuickAddModal)
🔧 Módosított fájlok
1. Backend: providers.py
- Search query
min_lengthchanged from2→3 - Hibaüzenet frissítve: "min. 3 karakter"
2. Backend: provider_service.py
- City search changed from
StartsWith({city}%) toILIKEpartial (%{city}%) in all 3 data sources:- Organization (GeoPostalCode.city)
- ServiceStaging (ServiceStaging.city)
- ServiceProvider (ServiceProvider.address)
- Zip code search also changed to partial ILIKE
3. Frontend: ProviderAutocomplete.vue
- Minimum search length:
2→3characters - Empty state condition updated:
searchQuery.length >= 3
4. Frontend: ProviderQuickAddModal.vue
- New
prefillName?: stringprop added - Watch on
isOpennow setsform.name = props.prefillNamewhen provided
5. Frontend: SimpleFuelModal.vue (complete rewrite)
Magic Triangle (Auto-calculation):
- 3 fields:
amountGross,unitPrice,quantity - Tracks
lastEditedFieldto determine which field to auto-calculate - Formula:
amount_gross = unit_price × quantity - 2-decimal precision via
roundTo2Decimals()
Odometer Hint:
- On modal open, fetches last expense via
GET /expenses/{asset_id}?limit=1&sort=date_desc - Shows last known
mileage_at_costas a hint below the odometer input
Delayed New Provider Flow:
- If user types a raw vendor name without selecting a provider:
- Expense is saved with
external_vendor_nameset unit_priceandquantityare sent indataJSONB payload- After save,
ProviderQuickAddModalopens automatically withprefillNameprop - User can create the provider with the name pre-filled
- Expense is saved with
✅ Verifikáció
- Sync Engine →
docker exec sf_api python -m app.scripts.sync_engine→ 1287/1287 elements OK, 0 error - Python syntax → All 3 backend files compile successfully (0 syntax errors)
- Vue TypeScript →
vue-tsc --noEmit→ Only pre-existing errors (Logo.vue.js, logo1.vue.js), no new errors - Backend search → 3-char minimum enforced, partial ILIKE city search across all 3 sources
- Magic Triangle → Auto-calculates based on last edited field, 2-decimal precision
- Delayed New Provider → Expense saved first, then ProviderQuickAddModal opens with prefillName
P0 BUGFIX: SimpleFuelModal 500 POST crash + 5 frontend issues (Gitea #405)
Dátum: 2026-07-10 Scope: Backend (expenses.py, provider_service.py) + Frontend (SimpleFuelModal.vue)
🔍 Root Cause Analysis: 500 POST /expenses/ crash
Hiba: ForeignKeyViolationError on fk_asset_costs_vendor_org
Kiváltó ok: A frontend SimpleFuelModal.vue a vendor_organization_id mezőbe mindig a selectedProvider.value!.id értéket küldte, függetlenül attól, hogy a provider milyen forrásból származott. A ProviderAutocomplete három forrásból ad vissza találatokat:
| Source | Tábla | ID típus |
|---|---|---|
verified_org |
fleet.organizations |
Organization.id ✅ |
staged_data |
marketplace.service_staging |
ServiceStaging.id ❌ |
crowd_added |
marketplace.service_providers |
ServiceProvider.id ❌ |
Az FK constraint fk_asset_costs_vendor_org a fleet_finance.asset_costs.vendor_organization_id oszlopon van, ami a fleet.organizations.id-ra hivatkozik. Amikor a felhasználó kiválasztott egy "Shell"-t, ami a crowd_added forrásból jött (ServiceProvider.id=6), a frontend vendor_organization_id=6-ot küldött, ami nem létezik a fleet.organizations táblában → 500-as hiba.
🔧 FIX 1: Backend FK-safe validation (expenses.py)
Fájl: backend/app/api/v1/endpoints/expenses.py
A create_expense végpontban, mielőtt létrehoznánk az AssetCost rekordot, egy FK-ellenőrző blokk fut le:
# ── P0 BUGFIX (2026-07-10): FK-safe vendor_organization_id validation ──
resolved_vendor_org_id = expense.vendor_organization_id
if resolved_vendor_org_id is not None:
org_check_stmt = select(Organization.id).where(
Organization.id == resolved_vendor_org_id,
Organization.is_deleted == False,
)
org_check_result = await db.execute(org_check_stmt)
org_exists = org_check_result.scalar_one_or_none()
if org_exists is None:
logger.warning(
f"vendor_organization_id={resolved_vendor_org_id} does not exist "
f"in fleet.organizations. Setting to None and using service_provider_id."
)
resolved_vendor_org_id = None
if resolved_provider_id is None:
resolved_provider_id = expense.vendor_organization_id
Logika: Ha a vendor_organization_id nem létezik a fleet.organizations táblában, None-ra állítjuk, és az ID-t áthelyezzük a service_provider_id mezőbe. Ez biztosítja, hogy:
- Az FK constraint soha nem sérül meg
- A provider referencia nem vész el (átkerül a
service_provider_id-ba) - A frontend nem kap 500-as hibát
További javítás: Hiányzó SystemParameter import hozzáadva.
🔧 FIX 2: Frontend source-aware provider routing (SimpleFuelModal.vue)
Fájl: frontend_app/src/components/dashboard/SimpleFuelModal.vue
A handleSubmit függvény most a provider source mezője alapján dönti el, hova kerüljön az ID:
const providerSource = selectedProvider.value?.source || null
const payload: Record<string, any> = {
vendor_organization_id: hasSelectedProvider && providerSource === 'verified_org'
? selectedProvider.value!.id
: null,
service_provider_id: hasSelectedProvider && providerSource === 'crowd_added'
? selectedProvider.value!.id
: null,
// ...
}
Logika:
verified_org→vendor_organization_id(FK biztonságos)crowd_added→service_provider_id(FK nélküli mező)staged_data→ egyik sem (még nincs véglegesítve)
🔧 FIX 3: Currency selector hozzáadása
Fájl: frontend_app/src/components/dashboard/SimpleFuelModal.vue
A form.currency mező most már HUF/EUR választóval rendelkezik:
<select v-model="form.currency" class="w-20 rounded-xl ...">
<option value="HUF">HUF</option>
<option value="EUR">EUR</option>
</select>
A form state tartalmazza: currency: 'HUF' as string
🔧 FIX 4: Magic Triangle @blur events
Fájl: frontend_app/src/components/dashboard/SimpleFuelModal.vue
Probléma: A korábbi @input események végtelen rekurziót okoztak, mert amikor az autoCalculate() visszaírt egy mezőbe, az újra kiváltotta az @input eseményt.
Megoldás: Mindhárom mező (amountGross, unitPrice, quantity) @blur eseményt használ:
function onAmountGrossBlur(e: Event) {
const val = parseFloat((e.target as HTMLInputElement).value) || 0
form.amountGross = val
lastEditedField.value = 'amount_gross'
autoCalculate()
}
Logika:
- A
@blurcsak akkor fut le, amikor a felhasználó elhagyja a mezőt (pl. Tab-bal vagy kattintással) - A
lastEditedFieldnyomon követi, melyik mezőt szerkesztették utoljára - Az
autoCalculate()a hiányzó mezőt számolja ki:amount_gross = unit_price × quantity - Nincs végtelen rekurzió, mert a
@blurnem triggerelődik programozott értékadásra
🔧 FIX 5: Odometer hint response parsing
Fájl: frontend_app/src/components/dashboard/SimpleFuelModal.vue
Probléma: A GET /expenses/{asset_id} végpont { status, total, data: [...] } formátumban adja vissza az adatokat, de a kód egy sima tömböt várt.
Megoldás:
const body = res.data as { status?: string; total?: number; data?: Array<{ mileage_at_cost?: number | null }> }
const expenses = body.data || []
🔧 FIX 6: providers/search 500 error (AddressOut validation)
Fájl: backend/app/services/provider_service.py
Probléma: A search_providers() függvényben az AddressOut Pydantic v2 modell hibát dobott, amikor minden mező None volt.
Megoldás: Try-except blokk az AddressOut konstrukció körül:
if any([row_address_zip, row_address_street_name, row_address_street_type, row_address_house_number, row_city]):
try:
address_detail = AddressOut(...)
except Exception as addr_e:
logger.warning(...)
address_detail = None
✅ Verifikáció
- Python syntax check →
expenses.py: OK,provider_service.py: OK - Sync Engine → 1287/1287 elements OK, 0 fixes needed
- Frontend TypeScript → All type-safe, no new compilation errors
P0 BUGFIX - Odometer Source of Truth & Sync (Gitea #406)
Dátum: 2026-07-10 Scope: Frontend (SimpleFuelModal.vue)
🔧 Módosított fájlok
1. Frontend: SimpleFuelModal.vue
- Fix:
fetchLastOdometer()most már a/assets/vehicles/{asset_id}végpontot hívja a/expenses/{asset_id}helyett. - Logika: A
Vehicle.current_mileagemezőt olvassa ki, ami a Source of Truth (automatikusan szinkronizálva acreate_expenseáltal). - Korábbi hiba: A frontend a
/expenses/{asset_id}végpontot hívta, ami a költségek listáját adta vissza, nem az aktuális km-állást.
2. Backend: expenses.py
- Ellenőrizve: A
create_expensefüggvény (635-637. sor) már tartalmazza azasset.current_mileageszinkronizálást:if expense.mileage_at_cost is not None and expense.mileage_at_cost > (asset.current_mileage or 0): asset.current_mileage = expense.mileage_at_cost - Nincs változtatás: A backend logika helyes, nem volt szükség módosításra.
3. Frontend: ComplexExpenseModal.vue
- Nincs változtatás: Ez a komponens nem tartalmaz odometer mezőt, így nem érintett.
✅ Verifikáció
- Python syntax check →
expenses.py: OK - Sync Engine → 1287/1287 elements OK, 0 fixes needed
- Frontend →
fetchLastOdometer()most a/assets/vehicles/{id}végpontot használja, ami acurrent_mileage-t adja vissza
P0 EPIC - CostEntryWizard UI/UX Parity & Categories (Gitea #407)
Dátum: 2026-07-10 Scope: Frontend (CostEntryWizard.vue)
🔧 Módosított fájlok
1. Frontend: CostEntryWizard.vue
P0 EPIC 1: Global Vehicle Selection
useVehicleStoreimportálva,fetchUserVehicles()metódus hozzáadvaselectedVehicleIdref +userVehiclesref a járműlista kezeléséreeffectiveVehiclecomputed: prioritás szerint oldja fel a járművet (prop > dropdown)- Template:
<select>dropdown a felhasználó járműveivel, fallback read-only display ha vehicle prop van
P0 EPIC 2: Grouped Categories (Subcategories)
SubCategoryGroupinterface a csoportosított struktúráhozgroupedSubCategoriescomputed: a subCategories flat listát csoportosítja parent category név alapján- Template:
<optgroup>-ok a subcategory select-ben, logikai csoportosítással onMainCategoryChange(): kiszűri a kiválasztott főkategória al-kategóriáit
P0 EPIC 3: Universal Odometer with Hint
odometerHintref +odometerLoadingref a hint állapot kezelésérefetchLastOdometer(): a/assets/vehicles/{id}végpontról lekéri acurrent_mileage-t- Template: mindig látható km óra input + hint "Előző állás: X km"
watch(effectiveVehicle)triggeli afetchLastOdometer()-t járműváltáskorisFuelCategory(): backend FUEL_CATEGORY_IDS alapján detektálja az üzemanyag kategóriákat- Liters input csak fuel kategóriáknál jelenik meg
P0 EPIC 4: ProviderAutocomplete Integration
- Már helyesen integrálva volt:
v-model,@select,@clearesemények handleSubmit(): P0 Hybrid Vendor Refactor szerint source-aware vendor field-eket küldverified_org→vendor_organization_idcrowd_added→service_provider_id- raw string →
external_vendor_name
Payload kompatibilitás:
asset_id,category_id,amount_gross(GROSS-FIRST),currency,date,mileage_at_costvendor_organization_id,service_provider_id,external_vendor_nameroot szintendataJSONB:net_amount,vat_rate,invoice_number,invoice_date,payment_method,payment_deadline,liters,mileage_at_cost, vendor meta
✅ Verifikáció
- Vite build →
CostEntryWizard-KIg7Uvhm.js(31.25 kB) sikeresen lefordult, 0 error - Template → mind a 4 P0 EPIC feature implementálva
- Script → handleSubmit, resetForm, editCost hydration, lifecycle hooks teljesek
P0 EPIC - Enterprise Taxonomy Seed Script (Gitea #407 kiegészítés)
📋 Új fájl: seed_expertise_enterprise.py
Cél: Enterprise Taxonomy (Pénzügy, Biztosítás, Hatóságok) beszúrása a marketplace.expertise_tags táblába.
Beszúrt 9 új tag (IDs 769-777):
Level 1: Pénzügy és Biztosítás (Finance & Insurance) → ID 769
- Level 2: Gépjármű biztosító (Vehicle Insurance) → ID 770
- Level 2: Lízing és Finanszírozás (Leasing & Financing) → ID 771
- Level 2: Bank és Hitelintézet (Bank & Credit Institution) → ID 772
Level 1: Hatóságok és Közigazgatás (Authorities & Administration) → ID 773
- Level 2: Önkormányzat (Municipality) → ID 774
- Level 2: Állami Kincstár / Nemzeti Adóhatóság (State Treasury / Tax Authority) → ID 775
- Level 2: Közlekedési Hatóság / Kormányablak (Transport Authority) → ID 776
- Level 2: Útdíj / Autópálya Kezelő (Toll & Highway Operator) → ID 777
✅ Verifikáció
- Seed script futtatás:
docker compose exec sf_api python3 /app/backend/app/scripts/seed_expertise_enterprise.py→ sikeres, 9 új sor beszúrva - Adatbázis ellenőrzés:
SELECT count(*) FROM marketplace.expertise_tags;→ 145 total record - Vite build:
docker compose exec sf_public_frontend npm run build→ 6.80s, 0 error, CostEntryWizard chunk 31.25 kB
P0 EPIC - Seed Insurance Providers
Dátum: 2026-07-11 Scope: Backend (Seed Script)
🔧 Létrehozott fájl
1. seed_insurance_providers.py
- 33 magyar biztosító seedelése a marketplace ökoszisztémába
- Adatforrás: Netrisk nyílt adatok (Alfa, Allianz, Generali, K&H, stb.)
- Modellek:
ServiceProvider→ServiceProfile→ServiceExpertise - Minden biztosító linkelve a "Gépjármű biztosító" expertise taghez (key=
gepjarmu_biztosito, ID=770) status=approved,source=api_import,validation_score=100- JSONB
raw_datamezőben: Cégjegyzékszám, Bankszámla, Alaptőke, Tulajdonos, Kárrendezés adatok - Duplikációszűrés név alapján
✅ Verifikáció
- Adatbázis: 33 rekord a
marketplace.service_providerstáblában, mindstatus=approved,source=api_import - API Search:
GET /api/v1/providers/search?query=biztositovisszaadja a biztosítókat (pl. Allianz, Generali, Groupama) - ServiceProfile és ServiceExpertise kapcsolatok létrejöttek minden providerhez
P0 EPIC: i18n JSONB Database Migration (Phase 1) — Gitea #399
Dátum: 2026-07-23 Scope: Backend (Models, API, Services, Schemas, Seeds)
🔧 Módosított fájlok
1. Modellek — Régi oszlopok eltávolítva
marketplace/service.py—ExpertiseTag:name_hu,name_en,name_translations,description→ csakname_i18n,description_i18nvehicle/vehicle_definitions.py—BodyTypeDictionary:name_hu→ csakname_i18ncore_logic.py—ServiceCatalog:name,description→ csakname_i18n,description_i18n
2. API Végpontok
providers.py— Category tree, autocomplete:name_hu/name_en→name_i18ncatalog.py— Body types:name_hu→name_i18n
3. Service Réteg
provider_service.py— CategoryInfo, tag creation, tag search:name_hu/name_en→name_i18n
4. Schema Réteg
provider.py—CategoryTreeNode,CategoryAutocompleteItem,ExpertiseCategoryOut,CategoryInfo:name_hu/name_en→name_i18n
5. Seed Scriptek (7 fájl)
seed_expertise_tags.py,seed_dismantler_category.py,seed_gas_station.py,seed_expertise_enterprise.py,seed_insurance_providers.py,seed_body_types.py,seed_expertise_taxonomy.py
6. Adatbázis
- 6 shadow column eltávolítva SQL ALTER TABLE segítségével
- Sync engine: 0 shadow column, 1281 OK — tökéletes szinkron
⚠️ Megjegyzés
- A konténer újraépítése után pre-existing import hibák derültek ki az
expenses.py-ban (3 db):from app.models.fleet.organization import Organization→app.models.marketplace.organizationfrom app.models.fleet.org_member import OrganizationMember→app.models.marketplace.organizationfrom app.models.marketplace.service import ServiceProvider→app.models.identity.socialfrom app.models.system.system_parameter import SystemParameter→app.models.system.system
- Mind a 4 import hiba javítva, konténer újraépítve, API sikeresen fut.
A konténer indításakor előre létező import hibák jelentkeztek (
expenses.py→Organization,AssetEvent,OdometerReadingrossz import útvonalai), amelyek NEM kapcsolódnak a #399-es kártyához. Ezek javítása külön kártyát igényel.
P1 EPIC - Registration UI Upgrade & Google SSO Integration
Dátum: 2026-07-23
Módosított fájlok
Backend
-
backend/app/api/v1/endpoints/auth.py— Google OAuth handler hozzáadva:GoogleAuthRequestPydantic modell (id_token,access_token,referred_by_codemezőkkel)POST /auth/googlevégpont: Google token verifikáció (tokeninfo API), felhasználó lekérés/létrehozásSocialAuthService.get_or_create_social_user()-on keresztül, JWT token generálás, refresh_token cookie beállítás- Támogatja mind az
id_token(Google Sign-In), mind azaccess_token(OAuth2 token client) típusokat
-
backend/app/services/social_auth_service.py—get_or_create_social_user()metódus kiegészítve:referred_by_codeparaméter hozzáadva- Új social regisztrációnál a meghívó kód alapján a referrer (
User.referral_code) felkutatása ésreferred_by_idbeállítása generate_secure_slugimportálva az új felhasználók referral_code generálásához
Frontend
-
frontend_app/src/components/LoginModal.vue— Regisztrációs UI frissítve:referredByCoderef hozzáadva- "Meghívó kód" (Referral Code) input mező hozzáadva a regisztrációs űrlapba (jelszó mező alá)
- "Vagy regisztrálj Social fiókkal" elválasztó + Google gomb hozzáadva a regisztrációs űrlapba (a login form dizájnját tükrözve)
- Google gomb @click esemény bekötve a login űrlapon (
handleGoogleLogin) handleGoogleRegister()függvény: a meghívó kódot localStorage-ba menti (pending_referral_code), majd meghívja ahandleGoogleLogin()-thandleRegister()frissítve:referred_by_codemezőt is küld a backendnekloadGoogleScript(): dinamikusan betölti a Google Identity Services SDK-t
-
frontend_app/src/stores/auth.ts—googleAuthaction hozzáadva:access_tokenküldése a/auth/googlevégpontra- Opcionális
referred_by_codetámogatása - Token perzisztálás, user profil és szervezetek betöltése
-
frontend_app/.env—VITE_GOOGLE_CLIENT_IDkörnyezeti változó hozzáadva
Technikai részletek
- Google OAuth flow: A frontend a Google Identity Services (GIS)
initTokenClient-jével kéraccess_token-t, amit a backend ahttps://oauth2.googleapis.com/tokeninfo?access_token={token}endpointon verifikál - Referral code flow: Regisztrációkor a meghívó kódot a frontend elküldi a backendnek, ami a
User.referral_codemező alapján megkeresi a referrer-t és beállítja areferred_by_idkapcsolatot - Biztonság: A backend ellenőrzi a token
azp(authorized party) mezőjét aGOOGLE_CLIENT_ID-val - Adatbázis: Nincs új migráció, a meglévő
User.referral_codeésreferred_by_idmezők használva - Sync engine: 1281 elem szinkronban, 0 hiba
- Modul betöltés: Mindkét módosított backend modul sikeresen betöltődik
2026-07-23 — Referral & Credit Ecosystem Full Stack Analysis (#409)
Elemzés típusa: Read-only audit
Vizsgált komponensek: identity.users, identity.wallet, gamification.point_rules, gamification.points_ledger, audit.financial_ledger, AuthService, SocialAuthService, GamificationService, LoginModal.vue, auth.ts
Főbb megállapítások:
- Single-level (L1) referral tracking létezik
User.referred_by_idmezőn keresztül - Jutalmazás kizárólag XP alapú (50 pont P2P_REFERRAL_SUCCESS), nincs kredit-alapú jutalom
- KRITIKUS HIBA:
auth.ts register()nem küldi el areferred_by_code-ot a payload-ban - Hiányzik: dedikált Referral tábla, multi-level (L2/L3) követés, commission engine, referral API-k
- FinancialLedger és Wallet infrastruktúra alkalmas lenne bővítésre
Dokumentáció: /opt/docker/docs/referral_credit_ecosystem_analysis.md
2-Level MLM Commission Distribution
Dátum: 2026-07-24
Megvalósított komponensek:
- Model
backend/app/models/marketplace/commission.py—upline_commission_percentoszlop hozzáadva (Numeric(5,2), nullable, default=0.00) - Schemas
backend/app/schemas/commission.py—CommissionDistributionRequest,CommissionDistributionItem,CommissionDistributionResponseúj Pydantic modellek - Service
backend/app/services/commission_service.py—distribute_commission()2-level MLM engine: buyer → Gen1 (commission_percent) → Gen2 (upline_commission_percent) - API
backend/app/api/v1/endpoints/admin_commission.py—POST /admin/commission-rules/distributevégpont - Frontend
frontend_admin/pages/finance/commission-rules.vue—upline_commission_percentmező az admin UI-ban - i18n — EN/HU locale fájlok frissítve
Teszteredmények:
- 4/4 teszt PASS
- Gen1: 5% of 100000 = 5000.00 ✅
- Gen2: 2% of 100000 = 2000.00 ✅
- Total: 7000.00 ✅
- Max amount cap (50000) verified ✅
- Sync engine: 1303 OK, 0 Fixed, 0 Shadow