admin_szolgáltatók_
This commit is contained in:
129
docs/admin_providers_root_cause_analysis.md
Normal file
129
docs/admin_providers_root_cause_analysis.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# 🔍 Admin Service Provider Root Cause Analysis
|
||||
|
||||
## Összefoglaló
|
||||
|
||||
**Felfedezett hiba:** Az admin felület szolgáltató (provider) listája és "Jóváhagyásra váró" oldala csak a `marketplace.service_providers` táblában tárolt 6 rekordot jeleníti meg. A robotok által begyűjtött 8569 rekord a `marketplace.service_staging` táblában teljesen láthatatlan az admin számára.
|
||||
|
||||
**Dátum:** 2026-06-30
|
||||
**Vizsgáló:** Rendszer-Architect
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Adatbázis Táblák Állapota
|
||||
|
||||
| Tábla | Séma | Rekordszám | Státuszértékek | Forrás |
|
||||
|-------|------|-----------|----------------|--------|
|
||||
| `service_providers` | `marketplace` | **6** | approved, rejected | API (user/manuális) |
|
||||
| `service_staging` | `marketplace` | **8569** | research_in_progress (5096), no_web_presence (3472), auditing (1) | Robotok (bot) |
|
||||
| `organizations` | `fleet` | **1** (service_provider = true) | active | Regisztráció |
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Root Cause Analysis
|
||||
|
||||
### 1. Admin API csak a `service_providers` táblát kérdezi
|
||||
|
||||
A [`backend/app/api/v1/endpoints/admin_providers.py`](../backend/app/api/v1/endpoints/admin_providers.dart:231) [`list_providers()`](../backend/app/api/v1/endpoints/admin_providers.dart:231) metódusa kizárólag a `ServiceProvider` modellre hivatkozik:
|
||||
|
||||
```python
|
||||
@router.get("", response_model=List[ProviderListItem])
|
||||
async def list_providers(...):
|
||||
query = select(ServiceProvider) # ← CSAK marketplace.service_providers
|
||||
...
|
||||
```
|
||||
|
||||
Ugyanez a helyzet a [`get_provider_stats()`](../backend/app/api/v1/endpoints/admin_providers.dart:261) endpointtal (261. sor).
|
||||
|
||||
**Következmény:** A botok által felfedezett 8569 rekord admin felületről nem látható, nem moderálható, nem kereshető.
|
||||
|
||||
### 2. A Public API már helyesen kezeli a 3 forrást
|
||||
|
||||
A [`backend/app/services/provider_service.py`](../backend/app/services/provider_service.dart:216) [`search_providers()`](../backend/app/services/provider_service.dart:216) (public API) UNION ALL lekérdezéssel egyesíti mindhárom forrást:
|
||||
|
||||
```python
|
||||
org_query = select(Organization.id, Organization.name, ...)
|
||||
staging_query = select(ServiceStaging.id, ServiceStaging.name, ...)
|
||||
provider_query = select(ServiceProvider.id, ServiceProvider.name, ...)
|
||||
union_query = union_all(org_query, staging_query, provider_query)
|
||||
```
|
||||
|
||||
Ezt a mintát kell alkalmazni az admin API-ban is.
|
||||
|
||||
### 3. A "Jóváhagyásra váró" lista azért üres, mert...
|
||||
|
||||
- A `service_providers` táblában **nincs** `pending` státuszú rekord (csak approved/rejected)
|
||||
- A `service_staging` tábla 8569 rekordja **ki van zárva** az admin lekérdezésből
|
||||
- A frontend [`pending.vue`](../frontend_admin/pages/providers/pending.dart:1) ugyanezt az admin API-t hívja `status=pending` paraméterrel
|
||||
|
||||
### 4. Validációs rendszer már létezik, csak csatornázni kell
|
||||
|
||||
A meglévő adatbázis tartalmazza az összes szükséges validációs infrastruktúrát:
|
||||
|
||||
- `marketplace.provider_validations` - upvote/downvote rendszer súlyozással, dedikált validációs tábla
|
||||
- `marketplace.service_providers.validation_score` - közvetlen validációs pontszám
|
||||
- `marketplace.service_providers.status` - moderációs státusz (ModerationStatus enum)
|
||||
- `marketplace.service_profiles.trust_score` - bizalmi pontszám
|
||||
- `marketplace.service_profiles.is_verified` - ellenőrzöttségi jelző
|
||||
- `marketplace.service_profiles.verification_log` - JSON validációs napló
|
||||
|
||||
**Nem kell új mezőket létrehozni** - a `ServiceStaging` adatokat megfelelően be kell csatornázni a meglévő validációs rendszerbe.
|
||||
|
||||
---
|
||||
|
||||
## 🩹 Javasolt Javítási Terv
|
||||
|
||||
### Rövid távú (P0) - Admin API UNION ALL kiterjesztése
|
||||
|
||||
1. **`list_providers()`** módosítása [`admin_providers.py`](../backend/app/api/v1/endpoints/admin_providers.dart:231)-ban:
|
||||
- UNION ALL lekérdezés a `ServiceStaging` táblából is (a [`search_providers()`](../backend/app/services/provider_service.dart:216) mintájára)
|
||||
- A `ServiceStaging` rekordok leképezése a `ProviderListItem` response modelre
|
||||
- A `ServiceStaging` rekordoknál: `status` -> `research_in_progress` mint `pending`, `source` -> `bot`
|
||||
|
||||
2. **`get_provider_stats()`** módosítása [`admin_providers.py`](../backend/app/api/v1/endpoints/admin_providers.dart:261)-ban:
|
||||
- A `pending` count kiegészítése a `research_in_progress` ServiceStaging rekordokkal
|
||||
|
||||
3. **Jóváhagyási flow** (approve/reject):
|
||||
- `ServiceStaging` rekord jóváhagyásakor: `ServiceProvider` rekord létrehozása az adatokkal
|
||||
- A meglévő `provider_validations` és `service_profiles` validációs rendszer használata
|
||||
|
||||
### Implementációs Részletek
|
||||
|
||||
A `ProviderListItem` modelt ki kell egészíteni egy `source_table` mezővel, hogy a frontend tudja, melyik táblából jött a rekord:
|
||||
|
||||
```python
|
||||
class ProviderListItem(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
address: Optional[str]
|
||||
city: Optional[str]
|
||||
status: str # "pending" | "approved" | "rejected"
|
||||
source: str # "api" | "manual" | "bot"
|
||||
source_table: str # "service_providers" | "service_staging" | "organizations"
|
||||
validation_score: Optional[int]
|
||||
created_at: datetime
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Érintett Fájlok
|
||||
|
||||
| Fájl | Szerep |
|
||||
|------|--------|
|
||||
| [`backend/app/api/v1/endpoints/admin_providers.py`](../backend/app/api/v1/endpoints/admin_providers.dart:1) | **Root cause** - Javítandó fájl |
|
||||
| [`backend/app/services/provider_service.py`](../backend/app/services/provider_service.dart:216) | **Minta** - UNION ALL implementáció |
|
||||
| [`backend/app/models/identity/social.py`](../backend/app/models/identity/social.dart:23) | `ServiceProvider` modell |
|
||||
| [`backend/app/models/marketplace/service.py`](../backend/app/models/marketplace/service.dart:162) | `ServiceStaging` modell |
|
||||
| [`frontend_admin/pages/providers/index.vue`](../frontend_admin/pages/providers/index.dart:1) | Admin provider lista oldal |
|
||||
| [`frontend_admin/pages/providers/pending.vue`](../frontend_admin/pages/providers/pending.dart:1) | Admin pending queue oldal |
|
||||
| [`plans/logic_spec_service_provider_discovery_admin.md`](../plans/logic_spec_service_provider_discovery_admin.dart:1) | Meglévő tervdokumentáció |
|
||||
|
||||
---
|
||||
|
||||
## ✅ Következő Lépések
|
||||
|
||||
1. [ ] Gitea kártya létrehozása: Admin API UNION ALL kiterjesztése ServiceStaging táblával
|
||||
2. [ ] `ProviderListItem` response model kiegészítése `source_table` mezővel
|
||||
3. [ ] `list_providers()` módosítása: UNION ALL 3 forrás
|
||||
4. [ ] `get_provider_stats()` módosítása: staging rekordok beszámítása
|
||||
5. [ ] Jóváhagyási flow: ServiceStaging -> ServiceProvider átvezetés
|
||||
6. [ ] Tesztelés: frontend pending lista megjelenése
|
||||
187
docs/gamification_point_rules_disconnect_analysis.md
Normal file
187
docs/gamification_point_rules_disconnect_analysis.md
Normal file
@@ -0,0 +1,187 @@
|
||||
# 🔗 Gamification Point-Rules Admin Kapcsolati Hiányosság Elemzés
|
||||
|
||||
**Dátum:** 2026-06-30
|
||||
**Vizsgálat típusa:** Rendszer-audit
|
||||
**Vizsgált oldal:** `https://admin.servicefinder.hu/gamification/point-rules`
|
||||
**Modul:** Gamification Admin Rendszer 2.0
|
||||
**Gitea Issue:** #364
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Probléma összefoglalása
|
||||
|
||||
A `/gamification/point-rules` admin felületen létrehozott és módosított pontszabályok (action_key -> points) NINCSENEK összekapcsolva a valódi gamification folyamatokkal. Az admin felületen beállított pontértékek csak a folyamatok egy szűk körére (service_submission, daily_quiz_correct) vannak hatással. A többi gamification akció (KYC, költség rögzítés, eszköz regisztráció, fleet esemény, stb.) vagy keménykódolt értékeket, vagy a ConfigService-ből olvasott értékeket használ.
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Technikai háttér
|
||||
|
||||
### 1. Point Rules Adatbázis Tábla (gamification.point_rules)
|
||||
|
||||
Az adatbázisban jelenleg **10 aktív pontszabály** található:
|
||||
|
||||
| ID | action_key | points | description |
|
||||
|----|-----------|-------|-------------|
|
||||
| 3 | ADD_NEW_PROVIDER | 500 | Új szolgáltató rögzítése |
|
||||
| 1 | ASSET_REGISTER | 100 | - |
|
||||
| 2 | ASSET_REVIEW | 75 | - |
|
||||
| 17 | PROVIDER_CONFIRMATION | 150 | Meglévő provider megerősítése |
|
||||
| 16 | PROVIDER_DISCOVERY | 300 | Új provider felfedezése |
|
||||
| 18 | PROVIDER_VERIFIED_USE | 100 | Jóváhagyott provider használata |
|
||||
| 5 | RATE_PROVIDER | 250 | Szolgáltató értékelése |
|
||||
| 6 | UPDATE_PROVIDER | 100 | Szolgáltató adatainak szerkesztése |
|
||||
| 4 | USE_UNVERIFIED_PROVIDER | 200 | Nem ellenőrzött szolgáltató használata |
|
||||
| 7 | TEST_ACTION | 100 | Test rule |
|
||||
|
||||
### 2. GAMIFICATION_MASTER_CONFIG Rendszerparaméter
|
||||
|
||||
A `system.system_parameters` táblában tárolt konfiguráció:
|
||||
- xp_logic: base_xp=500, exponent=1.5
|
||||
- penalty_logic: recovery_rate=0.5, threshold-ok, multiplier-ek
|
||||
- conversion_logic: social_to_credit_rate=100
|
||||
- level_rewards: credits_per_10_levels=50
|
||||
|
||||
---
|
||||
|
||||
## 🚨 A Hiányzó Kapcsolat Részletes Elemzése
|
||||
|
||||
### 1. Elsődleges probléma: award_points() nem támogatja az action_key-t
|
||||
|
||||
A [`GamificationService.award_points()`](backend/app/services/gamification_service.py:44) statikus metódus definíciója:
|
||||
|
||||
```python
|
||||
@staticmethod
|
||||
async def award_points(db, user_id, amount, reason, social_points=0, commit=True):
|
||||
service = GamificationService()
|
||||
return await service.process_activity(
|
||||
db, user_id,
|
||||
xp_amount=amount,
|
||||
social_amount=social_points,
|
||||
reason=reason,
|
||||
commit=commit
|
||||
# NINCS action_key átadva!
|
||||
)
|
||||
```
|
||||
|
||||
A metódus NEM fogad el action_key paramétert, így azt nem is adja át a process_activity()-nak.
|
||||
|
||||
### 2. A process_activity() belső logikája
|
||||
|
||||
A [`process_activity()`](backend/app/services/gamification_service.py:125-134) metódus:
|
||||
|
||||
```python
|
||||
# 1/b. POINT RULES TÁBLA LEKÉRÉSE (ha action_key meg van adva)
|
||||
if action_key:
|
||||
rule = await self._get_point_rule(db, action_key)
|
||||
if rule:
|
||||
xp_amount = rule["points"]
|
||||
```
|
||||
|
||||
A logika MŰKÖDIK, de csak akkor indul be, ha az action_key paraméter átadásra kerül.
|
||||
|
||||
### 3. Hívások elemzése
|
||||
|
||||
#### Helyesen használja az action_key-t (point_rules tábla érvényesül):
|
||||
|
||||
| Hívó helye | action_key | Forrás |
|
||||
|-----------|-----------|--------|
|
||||
| gamification.py:374 | service_submission | Service beküldés |
|
||||
| gamification.py:566 | daily_quiz_correct | Napi kvíz |
|
||||
|
||||
#### NEM használja az action_key-t (point_rules tábla NEM érvényesül):
|
||||
|
||||
| Hívó helye | Pontforrás | Probléma |
|
||||
|-----------|-----------|----------|
|
||||
| auth_service.py:298 | kyc_reward változó | KYC pontok nem módosíthatók |
|
||||
| auth_service.py:303 | ConfigService gamification_p2p_invite_xp | P2P referral pontok nem módosíthatók |
|
||||
| cost_service.py:73 | base_xp * ocr_multiplier | Költség log pontok nem módosíthatók |
|
||||
| asset_service.py:290 | ConfigService xp_reward_asset_register | Asset reg pontok nem módosíthatók |
|
||||
| fleet_service.py:88 | event_rewards config dict | Fleet esemény pontok nem módosíthatók |
|
||||
| social_service.py:73 | Keménykódolt 100 XP, 20 SP | Validáció pontok nem módosíthatók |
|
||||
| social_service.py:98 | Keménykódolt 50 XP | Elutasítás pontok nem módosíthatók |
|
||||
| services.py:40 | ConfigService GAMIFICATION_HUNT_REWARD | Service hunt pontok nem módosíthatók |
|
||||
| services.py:90 | ConfigService GAMIFICATION_VALIDATE_REWARD | Service validation pontok nem módosíthatók |
|
||||
|
||||
### 4. Duplikált logika a provider_service-ben
|
||||
|
||||
A [`provider_service.py:60-135`](backend/app/services/provider_service.py:60) tartalmaz egy `_award_dynamic_points()` függvényt, ami **saját maga kiolvassa** a point_rules táblát, mielőtt meghívná az award_points()-t.
|
||||
|
||||
Ez a logika **MŰKÖDIK**, de:
|
||||
- **Duplikált**: Ugyanezt a logikát a process_activity() is tartalmazza
|
||||
- **Feleslegesen komplex**: Ha az award_points() támogatná az action_key-t, ez a függvény leegyszerűsödne
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Javasolt Javítási Terv
|
||||
|
||||
### 1. Közvetlen javítás: award_points() kiegészítése action_key támogatással
|
||||
|
||||
Módosítandó fájl: [`backend/app/services/gamification_service.py:44-54`](backend/app/services/gamification_service.py:44)
|
||||
|
||||
```python
|
||||
@staticmethod
|
||||
async def award_points(
|
||||
db: AsyncSession,
|
||||
user_id: int,
|
||||
amount: int,
|
||||
reason: str,
|
||||
social_points: int = 0,
|
||||
commit: bool = True,
|
||||
action_key: str | None = None,
|
||||
):
|
||||
service = GamificationService()
|
||||
return await service.process_activity(
|
||||
db, user_id,
|
||||
xp_amount=amount,
|
||||
social_amount=social_points,
|
||||
reason=reason,
|
||||
commit=commit,
|
||||
action_key=action_key,
|
||||
)
|
||||
```
|
||||
|
||||
**Hatás:** Minden award_points() hívó automatikusan használhatja a point_rules táblát, ha átadja az action_key-t.
|
||||
|
||||
### 2. Hívók átállítása action_key használatára
|
||||
|
||||
| Hívó | Javasolt action_key |
|
||||
|------|-------------------|
|
||||
| auth_service.py:298 | KYC_VERIFICATION (új) |
|
||||
| auth_service.py:303 | P2P_REFERRAL_SUCCESS (új) |
|
||||
| cost_service.py:73 | EXPENSE_LOG (új) |
|
||||
| asset_service.py:290 | ASSET_REGISTER (mar létezik!) |
|
||||
| fleet_service.py:88 | FLEET_EVENT (új) |
|
||||
| social_service.py:73 | PROVIDER_VALIDATED (új) |
|
||||
| social_service.py:98 | PROVIDER_REJECTED (új) |
|
||||
| services.py:40 | SERVICE_HUNT (új) |
|
||||
| services.py:90 | SERVICE_VALIDATION (új) |
|
||||
|
||||
### 3. Duplikált logika eltávolítása
|
||||
|
||||
A `_award_dynamic_points()` függvény leegyszerűsíthető, ha az award_points() már támogatja az action_key-t.
|
||||
|
||||
---
|
||||
|
||||
## 📊 Hatáselemzés
|
||||
|
||||
### Milyen akciókra van jelenleg hatással a point_rules módosítása?
|
||||
|
||||
- Service beküldes - hasznalja (action_key=service_submission)
|
||||
- Napi kviz - hasznalja (action_key=daily_quiz_correct)
|
||||
- Provider müveletek - hasznalja (provider_service _award_dynamic_points)
|
||||
|
||||
### Milyen akciókra NINCS hatással a point_rules módosítása?
|
||||
|
||||
- KYC regisztracio - kemenykodolt
|
||||
- P2P referral - ConfigService
|
||||
- Koltség rögzítés - kemenykodolt
|
||||
- Eszköz regisztracio - ConfigService (bar ASSET_REGISTER letezik!)
|
||||
- Flotta esemenyek - kemenykodolt
|
||||
- Szolgaltato validacio/elutasitas - kemenykodolt
|
||||
- Service hunt/validation - ConfigService
|
||||
|
||||
---
|
||||
|
||||
## Következtetés
|
||||
|
||||
A `/gamification/point-rules` admin felület jelenleg **csak a point_rules adatbazis tabla CRUD kezeleset** teszi lehetove, de a tabla tartalma **nincs hatassal a gamification folyamatok tobbsegere**. A javitashoz a `GamificationService.award_points()` metódust kell kiegesziteni `action_key` parameter tamogatasaval, es a hivokat at kell allitani action_key hasznalatara.
|
||||
292
docs/gamification_provider_connection_analysis.md
Normal file
292
docs/gamification_provider_connection_analysis.md
Normal file
@@ -0,0 +1,292 @@
|
||||
# 🔍 Gamification Pontszabályok és Service Provider Kapcsolat Elemzés
|
||||
|
||||
**Dátum:** 2026-06-30
|
||||
**Létrehozva:** Gitea #358
|
||||
**Scope:** Backend, Gamification, Service Provider
|
||||
**Típus:** Audit + Feature Analysis
|
||||
|
||||
---
|
||||
|
||||
## 1. ⚡ Executive Summary
|
||||
|
||||
A vizsgálat célja annak megállapítása volt, hogy a gamification pontszabályok (`gamification.point_rules`) össze vannak-e kötve a szolgáltatók (Service Provider) létrehozásával és validálásával.
|
||||
|
||||
### Főbb Megállapítások
|
||||
|
||||
| Pontszabály | Pont | Státusz | Megjegyzés |
|
||||
|------------|------|---------|------------|
|
||||
| `ADD_NEW_PROVIDER` | 500 | ✅ Bekötve | `quick_add_provider()`, `approve_provider()` |
|
||||
| `UPDATE_PROVIDER` | 100 | ✅ Bekötve | `update_provider()` |
|
||||
| `PROVIDER_DISCOVERY` | 300 | ❌ NINCS bekötve | Soha nem kerül kiosztásra |
|
||||
| `PROVIDER_CONFIRMATION` | 150 | ❌ NINCS bekötve | Soha nem kerül kiosztásra |
|
||||
| `PROVIDER_VERIFIED_USE` | 100 | ❌ NINCS bekötve | Soha nem kerül kiosztásra |
|
||||
| `USE_UNVERIFIED_PROVIDER` | 200 | ❌ NINCS bekötve | Soha nem kerül kiosztásra |
|
||||
| `RATE_PROVIDER` | 250 | ❌ NINCS bekötve | Soha nem kerül kiosztásra |
|
||||
|
||||
Összesen **5 pontszabály** van, amely definiálva van az adatbázisban és a seed scriptben, de **egyetlen kódrészlet sem hívja meg őket** — teljesen használatlanok.
|
||||
|
||||
---
|
||||
|
||||
## 2. 🏗️ Rendszerarchitektúra
|
||||
|
||||
### 2.1 Admin Gamification UI — ÉLES ÉS MŰKÖDŐ
|
||||
|
||||
A [`https://admin.servicefinder.hu/gamification/point-rules`](https://admin.servicefinder.hu/gamification/point-rules) felület **valós adatokat** jelenít meg és **teljes CRUD** műveleteket támogat:
|
||||
|
||||
- **Frontend:** [`frontend_admin/pages/gamification/point-rules.vue`](frontend_admin/pages/gamification/point-rules.vue) — `$fetch('/api/v1/admin/gamification/point-rules')` hívás
|
||||
- **Backend:** [`backend/app/api/v1/endpoints/admin_gamification.py`](backend/app/api/v1/endpoints/admin_gamification.py:214) — valós adatbázis lekérdezés
|
||||
- `GET /point-rules` (214. sor)
|
||||
- `POST /point-rules` (236. sor)
|
||||
- `PUT /point-rules/{rule_id}` (270. sor)
|
||||
- `DELETE /point-rules/{rule_id}` (299. sor)
|
||||
|
||||
**Következtetés:** Nincs szükség új admin felület készítésére. A pontszabályok a meglévő admin UI-n keresztül közvetlenül szerkeszthetők.
|
||||
|
||||
### 2.2 Pontszabály Modell
|
||||
|
||||
[`backend/app/models/gamification/gamification.py`](backend/app/models/gamification/gamification.py:13) — `PointRule` osztály:
|
||||
- `id`, `action_key` (unique), `points`, `description`, `is_active`
|
||||
|
||||
### 2.3 Service Provider Modell
|
||||
|
||||
[`backend/app/models/identity/social.py`](backend/app/models/identity/social.py:23) — `ServiceProvider` osztály:
|
||||
- `status` (pending/approved/rejected/flagged)
|
||||
- `source` (user_submitted/admin_imported/api/external)
|
||||
- `validation_score`
|
||||
- `added_by_user_id`
|
||||
|
||||
---
|
||||
|
||||
## 3. 🔗 Jelenlegi Bekötések (Működő)
|
||||
|
||||
### 3.1 `_award_provider_points()` — Központi függvény
|
||||
|
||||
[`backend/app/services/provider_service.py`](backend/app/services/provider_service.py:59) — Dinamikus pontkiosztó függvény:
|
||||
|
||||
```python
|
||||
async def _award_provider_points(db, user_id, action_key) -> int:
|
||||
# 1. Pontszabály lekérése adatbázisból
|
||||
rule_stmt = select(PointRule).where(
|
||||
PointRule.action_key == action_key, PointRule.is_active == True
|
||||
)
|
||||
rule = (await db.execute(rule_stmt)).scalar_one_or_none()
|
||||
if not rule:
|
||||
return 0
|
||||
# 2. Pont kiosztása GamificationService-en keresztül
|
||||
await gamification_service.award_points(
|
||||
db=db, user_id=user_id, amount=rule.points, ...
|
||||
)
|
||||
# 3. UserStats frissítése
|
||||
stats.providers_added_count += 1
|
||||
return points_to_award
|
||||
```
|
||||
|
||||
### 3.2 `quick_add_provider()` → `ADD_NEW_PROVIDER` (500 XP)
|
||||
|
||||
[`backend/app/services/provider_service.py`](backend/app/services/provider_service.py:611) — Gyors provider hozzáadás API végpont:
|
||||
- Automatikusan meghívja a `_award_provider_points(action_key="ADD_NEW_PROVIDER")` függvényt
|
||||
- 500 XP kerül kiosztásra a user-nek
|
||||
|
||||
### 3.3 `update_provider()` → `UPDATE_PROVIDER` (100 XP)
|
||||
|
||||
[`backend/app/services/provider_service.py`](backend/app/services/provider_service.py:1122) — Provider adatainak frissítése:
|
||||
- Meghívja a `_award_provider_points(action_key="UPDATE_PROVIDER")` függvényt
|
||||
- 100 XP kerül kiosztásra
|
||||
|
||||
### 3.4 Admin Approve → `ADD_NEW_PROVIDER` (500 XP)
|
||||
|
||||
[`backend/app/api/v1/endpoints/admin_providers.py`](backend/app/api/v1/endpoints/admin_providers.py:361) — Admin provider jóváhagyása:
|
||||
- `POST /admin/providers/{id}/approve`
|
||||
- Gamification XP kiosztás a provider beküldőjének
|
||||
- ProviderValidation rekord létrehozása
|
||||
- UserContribution státusz frissítése
|
||||
|
||||
---
|
||||
|
||||
## 4. ❌ HIÁNYZÓ BEKÖTÉSEK (Implementálandó)
|
||||
|
||||
### 4.1 `PROVIDER_DISCOVERY` (300 XP) — Soha nem kerül kiosztásra
|
||||
|
||||
**Tervezett működés:** Amikor egy user költséget rögzít, és az `external_vendor_name` alapján új provider kerül felfedezésre (még nem létezik a `marketplace.service_providers` táblában), a felfedező user 300 XP-t kap.
|
||||
|
||||
**Hiányzó kód:** A [`plans/logic_spec_service_provider_discovery_admin.md`](plans/logic_spec_service_provider_discovery_admin.md:116) specifikáció leírja a `find_or_create_provider_by_name()` függvényt, de az **SOHA nem lett implementálva**.
|
||||
|
||||
**Szükséges lépések:**
|
||||
1. Implementálni a [`find_or_create_provider_by_name()`](plans/logic_spec_service_provider_discovery_admin.md:116) függvényt a `provider_service.py`-ban
|
||||
2. Bekötni az [`expenses.py`](backend/app/api/v1/endpoints/expenses.py:566) create_expense végpontba
|
||||
3. A függvény hívja meg a `_award_provider_points(action_key="PROVIDER_DISCOVERY")`-t
|
||||
|
||||
### 4.2 `PROVIDER_CONFIRMATION` (150 XP) — Soha nem kerül kiosztásra
|
||||
|
||||
**Tervezett működés:** Amikor egy második user használ egy meglévő, de még nem 100%-ban megerősített providert (pl. ugyanaz a `external_vendor_name` egy másik költségben), a confirmation pont jár.
|
||||
|
||||
**Hiányzó logika:** A `find_or_create_provider_by_name()` függvény része kell legyen — ha a provider már létezik, de `validation_score < 100`, akkor `PROVIDER_CONFIRMATION` jár.
|
||||
|
||||
### 4.3 `PROVIDER_VERIFIED_USE` (100 XP) — Soha nem kerül kiosztásra
|
||||
|
||||
**Tervezett működés:** Ha a provider már `approved` státuszú, és valaki használja költség rögzítésénél, a `PROVIDER_VERIFIED_USE` pont jár.
|
||||
|
||||
**Szükséges:** A `find_or_create_provider_by_name()` függvény része — ha `provider.status == "approved"`, akkor `PROVIDER_VERIFIED_USE` jár.
|
||||
|
||||
### 4.4 `USE_UNVERIFIED_PROVIDER` (200 XP) — Soha nem kerül kiosztásra
|
||||
|
||||
**Tervezett működés:** Amikor egy user olyan providert használ, amely még nincs admin által jóváhagyva (pl. `pending` státuszú).
|
||||
|
||||
**Szükséges:** Szintén a `find_or_create_provider_by_name()` függvény része kell legyen.
|
||||
|
||||
### 4.5 `RATE_PROVIDER` (250 XP) — Soha nem kerül kiosztásra
|
||||
|
||||
**Tervezett működés:** Amikor egy user értékeli a providert (csillag/Vote/VoteValue).
|
||||
|
||||
**Hiányzó kód:** A `vote_for_provider()` függvény a [`social_service.py`](backend/app/services/social_service.py:31)-ban NEM hívja meg a `_award_provider_points(action_key="RATE_PROVIDER")` függvényt.
|
||||
|
||||
**Szükséges:**
|
||||
1. A [`social_service.py`](backend/app/services/social_service.py:31) `vote_for_provider()` metódusában meghívni a pontkiosztást
|
||||
|
||||
### 4.6 `social_service.py` — Hardcoded XP `create_service_provider()`-ben
|
||||
|
||||
[`backend/app/services/social_service.py`](backend/app/services/social_service.py:26):
|
||||
```python
|
||||
# HIBA: Hardcoded 50 XP a dinamikus pontszabály helyett
|
||||
await gamification_service.process_activity(db, user_id, 50, 10, f"New Provider: {new_provider.name}")
|
||||
```
|
||||
|
||||
**Javítás:** Ki kell cserélni a `_award_provider_points(action_key="ADD_NEW_PROVIDER")` hívásra, hogy dinamikusan az adatbázisból olvassa a pontértéket.
|
||||
|
||||
---
|
||||
|
||||
## 5. 📊 GamificationService Folyamat
|
||||
|
||||
[`backend/app/services/gamification_service.py`](backend/app/services/gamification_service.py:52) — `process_activity()` metódus:
|
||||
|
||||
```python
|
||||
async def process_activity(self, db, user_id, xp_amount, social_amount, reason,
|
||||
is_penalty=False, commit=True, action_key=None,
|
||||
source_type=None, source_id=None):
|
||||
# 1. Master config betöltése
|
||||
# 2. Ha action_key van, pontszabály lekérése (adatbázisból)
|
||||
if action_key:
|
||||
rule = await self._get_point_rule(db, action_key)
|
||||
if rule:
|
||||
xp_amount = rule["points"]
|
||||
# 3. Büntetés szűrés
|
||||
# 4. Szorzók alkalmazása
|
||||
# 5. Szintszámítás: Level = (XP/500)^(1/1.5) + 1
|
||||
# 6. Kredit átváltás
|
||||
# 7. Naplózás PointsLedger-be
|
||||
```
|
||||
|
||||
**Megjegyzés:** Maga a `process_activity()` és az `_award_provider_points()` működik helyesen — a probléma az, hogy **senki sem hívja meg** ezeket a megfelelő `action_key`-kel.
|
||||
|
||||
---
|
||||
|
||||
## 6. 🗺️ Implementációs Terv
|
||||
|
||||
### 6.1 `find_or_create_provider_by_name()` Implementálása
|
||||
|
||||
**Helye:** [`backend/app/services/provider_service.py`](backend/app/services/provider_service.py) — új függvény
|
||||
|
||||
**Logika:**
|
||||
|
||||
```python
|
||||
async def find_or_create_provider_by_name(
|
||||
db: AsyncSession,
|
||||
external_vendor_name: str,
|
||||
user_id: int
|
||||
) -> tuple[ServiceProvider | None, str]:
|
||||
"""
|
||||
Keres vagy létrehoz egy providert external_vendor_name alapján.
|
||||
|
||||
Visszatérési érték: (provider, action_key)
|
||||
- action_key: "PROVIDER_DISCOVERY" | "PROVIDER_CONFIRMATION" | "PROVIDER_VERIFIED_USE"
|
||||
"""
|
||||
# 1. Pontos match keresése (kisbetűsen, space-sztrippelten)
|
||||
provider = await db.execute(
|
||||
select(ServiceProvider).where(
|
||||
func.lower(ServiceProvider.name) == func.lower(external_vendor_name.strip())
|
||||
)
|
||||
)
|
||||
provider = provider.scalar_one_or_none()
|
||||
|
||||
if not provider:
|
||||
# 2. Ha nem létezik → létrehozás + PROVIDER_DISCOVERY
|
||||
new_provider = ServiceProvider(
|
||||
name=external_vendor_name.strip(),
|
||||
status=ModerationStatus.PENDING,
|
||||
source=SourceType.USER_SUBMITTED,
|
||||
added_by_user_id=user_id,
|
||||
validation_score=10 # Kezdeti alacsony score
|
||||
)
|
||||
db.add(new_provider)
|
||||
await db.flush()
|
||||
return new_provider, "PROVIDER_DISCOVERY"
|
||||
|
||||
# 3. Ha létezik, státusz alapján döntés
|
||||
if provider.status == ModerationStatus.APPROVED:
|
||||
return provider, "PROVIDER_VERIFIED_USE"
|
||||
else:
|
||||
return provider, "PROVIDER_CONFIRMATION"
|
||||
```
|
||||
|
||||
### 6.2 Expense Létrehozás Hook
|
||||
|
||||
**Helye:** [`backend/app/api/v1/endpoints/expenses.py`](backend/app/api/v1/endpoints/expenses.py:566) — `create_expense` végpont
|
||||
|
||||
```python
|
||||
# A provider field feldolgozása után, de a költség létrehozása előtt:
|
||||
if expense_data.service_provider_id:
|
||||
provider = await db.get(ServiceProvider, expense_data.service_provider_id)
|
||||
if provider and provider.added_by_user_id != current_user.id:
|
||||
# Megerősítés más user által
|
||||
await _award_provider_points(db, current_user.id, "PROVIDER_CONFIRMATION")
|
||||
elif expense_data.external_vendor_name:
|
||||
provider, action_key = await find_or_create_provider_by_name(
|
||||
db, expense_data.external_vendor_name, current_user.id
|
||||
)
|
||||
await _award_provider_points(db, current_user.id, action_key)
|
||||
```
|
||||
|
||||
### 6.3 RATE_PROVIDER Bekötése
|
||||
|
||||
**Helye:** [`backend/app/services/social_service.py`](backend/app/services/social_service.py:31) — `vote_for_provider()` metódus
|
||||
|
||||
```python
|
||||
# A Vote létrehozása után:
|
||||
await _award_provider_points(db, voter_id, "RATE_PROVIDER")
|
||||
```
|
||||
|
||||
### 6.4 `social_service.py` Hardcoded XP Javítása
|
||||
|
||||
**Helye:** [`backend/app/services/social_service.py`](backend/app/services/social_service.py:26) — `create_service_provider()` metódus
|
||||
|
||||
```python
|
||||
# Eredeti (hibás):
|
||||
await gamification_service.process_activity(db, user_id, 50, 10, ...)
|
||||
|
||||
# Javítás:
|
||||
await _award_provider_points(db, user_id, "ADD_NEW_PROVIDER")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. ⚠️ Kockázatok
|
||||
|
||||
1. **Duplikált pont kiosztás:** Ha a `social_service.py`-ban lévő `create_service_provider()` és a `provider_service.py`-ban lévő `quick_add_provider()` is meghívásra kerül ugyanarra a providerre, dupla pontot kaphat a user. Megoldás: a `social_service.py`-t át kell irányítani, hogy a `quick_add_provider()`-en keresztül hozzon létre providert.
|
||||
|
||||
2. **Végtelen loop:** Ha a `find_or_create_provider_by_name()` hibát dob, és az `expenses.py` újrapróbálkozik, végtelen loop alakulhat ki. Megoldás: max 1 újrapróbálkozás, utána `logger.error()` + graceful fallback.
|
||||
|
||||
3. **Performance:** Minden expense létrehozásnál egy extra SELECT + esetleg INSERT fut le a `service_providers` táblán. Ez normál terhelés mellett elhanyagolható, de batch importoknál figyelni kell rá.
|
||||
|
||||
---
|
||||
|
||||
## 8. ✅ Jóváhagyási Pont
|
||||
|
||||
A fenti elemzés alapján az alábbi feladatokra van szükség:
|
||||
|
||||
1. **P0 — Kritikus:** `find_or_create_provider_by_name()` implementálása
|
||||
2. **P0 — Kritikus:** Expense auto-discovery hook bekötése
|
||||
3. **P1 — Magas:** `social_service.py` hardcoded XP javítása
|
||||
4. **P1 — Magas:** RATE_PROVIDER bekötése
|
||||
5. **P1 — Magas:** PROVIDER_CONFIRMATION/VERIFIED_USE logika
|
||||
|
||||
Ezek a feladatok a Gitea #358 kártyán kerültek rögzítésre.
|
||||
376
docs/i18n_admin_audit_and_restructure_proposal.md
Normal file
376
docs/i18n_admin_audit_and_restructure_proposal.md
Normal file
@@ -0,0 +1,376 @@
|
||||
# 🌐 Admin i18n Audit & Újrastrukturálási Javaslat
|
||||
|
||||
**Dátum:** 2026-06-30
|
||||
**Készítette:** Rendszer-Architect
|
||||
**Verzió:** 1.0
|
||||
**Cél:** Admin felület nyelvi moduljainak teljes körű felmérése, központi nyelvi állomány kialakítása, oldalakra bontási terv, többnyelvű (dropdown) nyelvválasztó bevezetése
|
||||
|
||||
---
|
||||
|
||||
## 1. Jelenlegi Helyzet (As-Is)
|
||||
|
||||
### 1.1 Három teljesen elkülönülő i18n rendszer
|
||||
|
||||
| Rendszer | Hely | Formátum | Fájlok | Össz. kulcs | Nyelvek |
|
||||
|----------|------|----------|--------|-------------|---------|
|
||||
| **Backend** | `backend/static/locales/` | Nested JSON (UPPER_SNAKE) | 2 db | ~130 sor/fájl | hu, en |
|
||||
| **Frontend Admin** | `frontend_admin/i18n/locales/` | Nested JSON (camelCase) | 2 db | ~800-900 sor/fájl | hu, en |
|
||||
| **Frontend Old (src)** | `frontend/src/i18n/` (korábbi) | TS objektum | 6 db | ~1600 sor/fájl | hu, en, de, ro, cz, sk |
|
||||
|
||||
> **⚠️ A backend és a frontend rendszerek teljesen függetlenek.** Más kulcs-sémát használnak (dot-notation vs UPPER_SNAKE_CASE), így közöttük NINCS kulcs-megosztás.
|
||||
|
||||
### 1.2 Frontend Admin jelenlegi struktúrája
|
||||
|
||||
```
|
||||
frontend_admin/i18n/locales/
|
||||
├── en.json (902 sor / ~700 kulcs)
|
||||
└── hu.json (804 sor / ~650 kulcs)
|
||||
```
|
||||
|
||||
Gyökér-szekciók a JSON-ben:
|
||||
- `permissions` (~29 kulcs)
|
||||
- `packages` (~67 kulcs)
|
||||
- `garages` → `garages.details`, `garages.analytics`, `garages.employees`, `garages.fleet` (~180 kulcs)
|
||||
- `gamification` → `gamification.badges`, `.competitions`, `.config`, `.dashboard`, `.leaderboard`, `.ledger`, `.levels`, `.params`, `.point_rules`, `.seasons`, `.users`, `.user_detail` (~410 kulcs)
|
||||
- `providers` (~85 kulcs)
|
||||
- `users` → `users.details` (~98 kulcs)
|
||||
|
||||
### 1.3 Admin oldalak leképezése (Pages ↔ i18n szekciók)
|
||||
|
||||
| Oldal (Vue fájl) | i18n Szekció | Kulcsszám |
|
||||
|-----------------|-------------|-----------|
|
||||
| `/` (index.vue) | — | — (dashboard nincs lefordítva) |
|
||||
| `/permissions/` | `permissions.*` | ~29 |
|
||||
| `/packages/` | `packages.*` | ~67 |
|
||||
| `/garages/` + `garages/[id]/` | `garages.*`, `garages.details.*`, `garages.analytics.*`, `garages.employees.*`, `garages.fleet.*` | ~180 |
|
||||
| `/gamification/` (index) | `gamification.dashboard.*` | ~25 |
|
||||
| `/gamification/badges` | `gamification.badges.*` | ~35 |
|
||||
| `/gamification/competitions` | `gamification.competitions.*` | ~40 |
|
||||
| `/gamification/config` | `gamification.config.*` | ~25 |
|
||||
| `/gamification/leaderboard` | `gamification.leaderboard.*` | ~40 |
|
||||
| `/gamification/ledger` | `gamification.ledger.*` | ~30 |
|
||||
| `/gamification/levels` | `gamification.levels.*` | ~35 |
|
||||
| `/gamification/params` | `gamification.params.*` | ~25 |
|
||||
| `/gamification/point-rules` | `gamification.point_rules.*` | ~40 |
|
||||
| `/gamification/seasons` | `gamification.seasons.*` | ~30 |
|
||||
| `/gamification/users/` + `[id]` | `gamification.users.*`, `gamification.user_detail.*` | ~40+50 |
|
||||
| `/providers/` + `[id]` | `providers.*` | ~85 |
|
||||
| `/users/` + `[id]` | `users.*`, `users.details.*` | ~98 |
|
||||
|
||||
---
|
||||
|
||||
## 2. Feltárt Problémák
|
||||
|
||||
### 2.1 Hiányzó központi (common/global) nyelvi szekció
|
||||
|
||||
Jelenleg **NINCS** `common` vagy `global` szekció az admin i18n-ben. Minden általános UI művelet (Mentés, Mégse, Törlés, Szerkesztés, Betöltés, Hiba) szekciónként DUPLIKÁLVA van.
|
||||
|
||||
### 2.2 Masszív kulcs-duplikáció
|
||||
|
||||
A `docs/i18n_duplicate_key_analysis.md` által feltárt frontend duplikációk az adminban is jelen vannak. Példák a `frontend_admin` fájlokból:
|
||||
|
||||
| Kulcs (EN) | Előfordulások száma | HU fordítás |
|
||||
|-----------|-------------------|-------------|
|
||||
| `cancel` | **9+** (permissions, packages, garages.employees, gamification.badges, competitions, levels, params, point_rules, seasons, providers) | "Mégse" |
|
||||
| `save` | **10+** (permissions, packages.details, garages.*, gamification.*, providers, users.details) | "Mentés" |
|
||||
| `loading` | **15+** (minden CRUD szekció) | "Betöltés..." |
|
||||
| `error` | **10+** (minden CRUD szekció) | "Nem sikerült..." |
|
||||
| `retry` | **10+** | "Újra" / "Újrapróbálkozás" (két változat!) |
|
||||
| `edit` | **8+** | "Szerkesztés" |
|
||||
| `delete` | **6+** | "Törlés" |
|
||||
| `actions` | **6+** | "Műveletek" |
|
||||
| `no_items` / `no_results` | **8+** | "Nincs..." |
|
||||
| `status` | **6+** | "Státusz" |
|
||||
| `save_error` | **8+** | "Hiba történt..." |
|
||||
|
||||
### 2.3 HU oldalon inkonzisztens fordítások
|
||||
|
||||
- `retry`: hol "Újra" (`permissions.retry`, `packages.retry`), hol "Újrapróbálkozás" (`gamification.badges.retry`)
|
||||
- `cancel`: hol "Mégse" (többnyire), de van ahol nincs következetesen
|
||||
- `save_success` vs `updated` vs `created`: eltérő sablonok
|
||||
|
||||
### 2.4 Csak 2 nyelv támogatott az adminban
|
||||
|
||||
A `nuxt.config.ts` i18n beállításaiban csak `hu` és `en` szerepel:
|
||||
```typescript
|
||||
locales: [
|
||||
{ code: 'hu', iso: 'hu-HU', file: 'hu.json', name: 'Magyar' },
|
||||
{ code: 'en', iso: 'en-GB', file: 'en.json', name: 'English' },
|
||||
]
|
||||
```
|
||||
|
||||
A `frontend_old` LanguageSwitcher már 4 nyelvet támogat (hu, en, de, fr).
|
||||
Előző audit szerint a korábbi `frontend/src/i18n/` is tartalmazott részleges de, ro, cz, sk fordításokat.
|
||||
|
||||
### 2.5 Nyelvválasztó jelenleg kétállású kapcsoló
|
||||
|
||||
A `frontend_admin/layouts/default.vue` topbar-jában a nyelvválasztó **két gomb** (HU / EN), nem pedig egy legördülő menü. Ez nem skálázható 3+ nyelv esetén.
|
||||
|
||||
### 2.6 Backend i18n aszimmetria
|
||||
|
||||
- A `backend/static/locales/hu.json` (83 sor) és `en.json` (76 sor) között eltérés van a kulcsok számában (pl. `SENTINEL.APPROVAL.REQUIRED` EN: "Approval required", HU-ban hosszabb)
|
||||
- Backend hiányzik: német és más nyelvű backend fordítások
|
||||
|
||||
---
|
||||
|
||||
## 3. Javasolt Megoldás (To-Be)
|
||||
|
||||
### 3.1 Központi/globális nyelvi állomány (`common`)
|
||||
|
||||
**Létrehozandó:** új `common` gyökér-szekció mindkét fájlban
|
||||
|
||||
Tartalma (javasolt kulcsok):
|
||||
|
||||
```json
|
||||
{
|
||||
"common": {
|
||||
"save": "Mentés",
|
||||
"saving": "Mentés...",
|
||||
"cancel": "Mégse",
|
||||
"confirm": "Megerősítés",
|
||||
"discard": "Elvetés",
|
||||
"delete": "Törlés",
|
||||
"deleting": "Törlés...",
|
||||
"edit": "Szerkesztés",
|
||||
"create": "Létrehozás",
|
||||
"close": "Bezárás",
|
||||
"back": "Vissza",
|
||||
"next": "Következő",
|
||||
"previous": "Előző",
|
||||
"search": "Keresés",
|
||||
"filter": "Szűrés",
|
||||
"reset": "Visszaállítás",
|
||||
"clear": "Törlés",
|
||||
"retry": "Újra",
|
||||
"loading": "Betöltés...",
|
||||
"error": "Hiba",
|
||||
"success": "Siker",
|
||||
"no_results": "Nincs találat",
|
||||
"no_data": "Nincs adat",
|
||||
"yes": "Igen",
|
||||
"no": "Nem",
|
||||
"continue": "Tovább",
|
||||
"exit": "Kilépés",
|
||||
"save_changes": "Változtatások Mentése",
|
||||
"confirm_delete": "Biztosan törölni szeretnéd?",
|
||||
"unknown_error": "Ismeretlen hiba",
|
||||
"all": "Mind",
|
||||
"none": "Nincs",
|
||||
"optional": "opcionális",
|
||||
"required": "kötelező"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Használati elv:** A Vue komponensek elsődlegesen a `common.*` kulcsokat használják. Csak ha egy gombnak szekció-specifikus szövege van (pl. "Csomag törlése" ≠ általános "Törlés"), akkor kell szekció-specifikus kulcs.
|
||||
|
||||
### 3.2 Oldalakra bontás javaslata (lazy loading támogatás)
|
||||
|
||||
Jelenleg a `nuxt.config.ts`-ben `lazy: false` van beállítva, ami azt jelenti, hogy minden nyelvi fájl betöltődik induláskor. A javasolt struktúra lehetővé teszi a `lazy: true` váltást.
|
||||
|
||||
**Új fájl struktúra:**
|
||||
|
||||
```
|
||||
frontend_admin/i18n/
|
||||
├── locales/
|
||||
│ ├── common.en.json ← központi alapértékek (EN)
|
||||
│ ├── common.hu.json ← központi alapértékek (HU)
|
||||
│ ├── permissions.en.json
|
||||
│ ├── permissions.hu.json
|
||||
│ ├── packages.en.json
|
||||
│ ├── packages.hu.json
|
||||
│ ├── garages.en.json
|
||||
│ ├── garages.hu.json
|
||||
│ ├── providers.en.json
|
||||
│ ├── providers.hu.json
|
||||
│ ├── users.en.json
|
||||
│ ├── users.hu.json
|
||||
│ ├── gamification-dashboard.{en,hu}.json
|
||||
│ ├── gamification-badges.{en,hu}.json
|
||||
│ ├── gamification-competitions.{en,hu}.json
|
||||
│ ├── gamification-config.{en,hu}.json
|
||||
│ ├── gamification-leaderboard.{en,hu}.json
|
||||
│ ├── gamification-ledger.{en,hu}.json
|
||||
│ ├── gamification-levels.{en,hu}.json
|
||||
│ ├── gamification-params.{en,hu}.json
|
||||
│ ├── gamification-point-rules.{en,hu}.json
|
||||
│ ├── gamification-seasons.{en,hu}.json
|
||||
│ ├── gamification-users.{en,hu}.json
|
||||
│ └── gamification-user-detail.{en,hu}.json
|
||||
```
|
||||
|
||||
**`nuxt.config.ts` módosítása:**
|
||||
|
||||
```typescript
|
||||
i18n: {
|
||||
locales: [
|
||||
{ code: 'hu', iso: 'hu-HU', file: 'common.hu.json', name: 'Magyar' },
|
||||
{ code: 'en', iso: 'en-GB', file: 'common.en.json', name: 'English' },
|
||||
{ code: 'de', iso: 'de-DE', file: 'common.de.json', name: 'Deutsch' },
|
||||
],
|
||||
defaultLocale: 'hu',
|
||||
lazy: true,
|
||||
langDir: 'locales/',
|
||||
strategy: 'no_prefix',
|
||||
detectBrowserLanguage: {
|
||||
useCookie: true,
|
||||
cookieKey: 'i18n_redirected',
|
||||
redirectOn: 'root',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 Többnyelvűség (3+ nyelv) bevezetése
|
||||
|
||||
**Új nyelv hozzáadásának lépései:**
|
||||
|
||||
1. Új fájl létrehozása: pl. `common.de.json`, `permissions.de.json`, stb.
|
||||
2. A nyelv felvétele a `nuxt.config.ts` `locales` tömbjébe
|
||||
3. Fordítások elkészítése (kezdetben csak `common` + a leggyakoribb admin oldalak)
|
||||
4. Backend oldalon: új `de.json` fájl a `backend/static/locales/` mappába
|
||||
5. A backend `i18n.py` automatikusan betölti, ha a fájl létezik
|
||||
|
||||
**Előkészített nyelvek (részleges fordítások megléte alapján):**
|
||||
- **Deutsch (de)** — volt már részleges fordítás a régi frontend-ben
|
||||
- **Français (fr)** — volt a LanguageSwitcher-ben
|
||||
- **Română (ro)** — volt részleges fordítás a régi frontend-ben
|
||||
- **Čeština (cz)** — volt részleges fordítás a régi frontend-ben
|
||||
- **Slovenčina (sk)** — volt részleges fordítás a régi frontend-ben
|
||||
|
||||
### 3.4 Nyelvválasztó legördülő menüvé alakítása
|
||||
|
||||
**Jelenlegi kód** (`frontend_admin/layouts/default.vue`, 158-170. sor):
|
||||
|
||||
```html
|
||||
<!-- JELENLEG: kétállású kapcsoló -->
|
||||
<div class="flex items-center bg-slate-700/50 rounded-lg p-0.5">
|
||||
<button v-for="locale in availableLocales" :key="locale.code"
|
||||
@click="switchLocale(locale.code)"
|
||||
class="px-2.5 py-1 text-xs font-medium rounded-md transition"
|
||||
:class="currentLocale === locale.code
|
||||
? 'bg-indigo-600 text-white shadow-sm'
|
||||
: 'text-slate-400 hover:text-white'"
|
||||
>
|
||||
{{ locale.code === 'hu' ? 'HU' : 'EN' }}
|
||||
</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Javasolt új kód:**
|
||||
|
||||
```html
|
||||
<!-- ÚJ: legördülő nyelvválasztó -->
|
||||
<div class="language-switcher relative">
|
||||
<button @click="langDropdownOpen = !langDropdownOpen"
|
||||
class="flex items-center gap-2 px-3 py-1.5 bg-slate-700/50 rounded-lg text-xs font-medium
|
||||
hover:bg-slate-600/50 transition border border-slate-600/50"
|
||||
>
|
||||
<span>{{ getFlagEmoji(currentLocale) }}</span>
|
||||
<span>{{ getCurrentLanguageLabel() }}</span>
|
||||
<svg class="w-3.5 h-3.5 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- Dropdown -->
|
||||
<div v-if="langDropdownOpen"
|
||||
class="absolute right-0 mt-1 bg-slate-800 border border-slate-700 rounded-lg shadow-xl z-50 min-w-[140px]"
|
||||
>
|
||||
<button v-for="locale in availableLocales" :key="locale.code"
|
||||
@click="switchLocale(locale.code); langDropdownOpen = false"
|
||||
class="w-full text-left px-3 py-2 text-xs hover:bg-slate-700 flex items-center gap-2 transition"
|
||||
:class="{ 'text-indigo-400': locale.code === currentLocale }"
|
||||
>
|
||||
<span>{{ getFlagEmoji(locale.code) }}</span>
|
||||
<span>{{ locale.name }}</span>
|
||||
<span v-if="locale.code === currentLocale" class="ml-auto text-indigo-400">✓</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**`script` kiegészítés:**
|
||||
|
||||
```typescript
|
||||
const langDropdownOpen = ref(false)
|
||||
|
||||
function getFlagEmoji(code: string): string {
|
||||
const flags: Record<string, string> = {
|
||||
hu: '🇭🇺', en: '🇬🇧', de: '🇩🇪', fr: '🇫🇷',
|
||||
ro: '🇷🇴', cz: '🇨🇿', sk: '🇸🇰',
|
||||
}
|
||||
return flags[code] || '🌐'
|
||||
}
|
||||
|
||||
function getCurrentLanguageLabel(): string {
|
||||
const lang = availableLocales.value.find(l => l.code === currentLocale.value)
|
||||
return lang?.name || currentLocale.value.toUpperCase()
|
||||
}
|
||||
```
|
||||
|
||||
### 3.5 Backend i18n kiegészítése
|
||||
|
||||
A backend `i18n.py` már támogatja az automatikus betöltést — bármely `.json` fájl a `backend/static/locales/` mappában automatikusan felkerül a cache-be. Új nyelv esetén csak a JSON fájlt kell létrehozni.
|
||||
|
||||
A `nuxt.config.ts`-ben a `PATCH /api/v1/auth/me/language` végpont már támogatja a nyelv perzisztálását a backend felé — ez működni fog új nyelvekkel is, mivel a `preferred_language` mező egy szabad string.
|
||||
|
||||
---
|
||||
|
||||
## 4. Ütemezés (Mérföldkövek)
|
||||
|
||||
### M1: Központi `common` szekció létrehozása
|
||||
- Új `common` szekció felvétele az `en.json` és `hu.json` fájlokba
|
||||
- A duplikált kulcsok (cancel, save, loading, stb.) eltávolítása a szekció-specifikus részekből
|
||||
- Vue komponensek átírása: `$t('common.cancel')` használata a szekció-specifikus helyett
|
||||
- **Érintett fájlok:** `frontend_admin/i18n/locales/*.json`, `frontend_admin/pages/*.vue`, `frontend_admin/layouts/default.vue`
|
||||
|
||||
### M2: Fájlok oldalakra bontása (lazy loading)
|
||||
- A monolit `en.json` és `hu.json` szétbontása oldal-specifikus fájlokra
|
||||
- `nuxt.config.ts` frissítése (`lazy: true`)
|
||||
- Tesztelés: minden oldal megfelelően betölti a saját nyelvi fájlját
|
||||
- **Érintett fájlok:** `frontend_admin/i18n/locales/*`, `frontend_admin/nuxt.config.ts`
|
||||
|
||||
### M3: Nyelvválasztó dropdown bevezetése
|
||||
- `default.vue` layoutban a kétállású HU/EN kapcsoló cseréje legördülő menüre
|
||||
- Flag emoji támogatás
|
||||
- Több nyelv (de, fr) felvétele a konfigurációba
|
||||
- **Érintett fájlok:** `frontend_admin/layouts/default.vue`, `frontend_admin/nuxt.config.ts`
|
||||
|
||||
### M4: Új nyelvek backend támogatása
|
||||
- `de.json`, `fr.json` létrehozása a `backend/static/locales/` mappában
|
||||
- Legalább a COMMON és AUTH szekciók lefordítása
|
||||
- **Érintett fájlok:** `backend/static/locales/*.json`
|
||||
|
||||
### M5: Backend i18n aszimmetria javítása
|
||||
- `hu.json` és `en.json` kulcs-szinkronizációja
|
||||
- Hiányzó kulcsok pótlása
|
||||
- **Érintett fájlok:** `backend/static/locales/*.json`
|
||||
|
||||
---
|
||||
|
||||
## 5. Kockázatok és Függőségek
|
||||
|
||||
| Kockázat | Hatás | Valószínűség | Mérséklés |
|
||||
|----------|-------|-------------|-----------|
|
||||
| Vue komponensekben elszórt `$t('szekcio.kulcs')` hívások eltörnek az átnevezés után | Magas | Közepes | Codebase search (`$t(`) minden hívásra, fokozatos átállás |
|
||||
| Lazy loading miatt inicializálási késleltetés | Alacsony | Alacsony | `common` fájl előtöltése |
|
||||
| Backend és frontend közötti nyelvi kód inkonzisztencia | Közepes | Alacsony | Mindkét oldalon azonos ISO kódok használata |
|
||||
| Új nyelv hozzáadásánál a teljes admin felület nem lesz lefordítva | Közepes | Magas | Részleges fordítási státusz jelzése, angol fallback működik |
|
||||
|
||||
---
|
||||
|
||||
## 6. Összefoglaló
|
||||
|
||||
A jelenlegi admin i18n rendszer funkcionálisan működik, de strukturálisan optimalizálatlan:
|
||||
|
||||
1. **~50%-os kulcs-duplikáció** a `common` szekció hiánya miatt
|
||||
2. **Skálázhatatlan** - a monolit JSON fájlok 800+ sorosak, nehezen karbantarthatók
|
||||
3. **Csak 2 nyelv** - a régi frontend már 6 nyelvet ismert, az admin le van maradva
|
||||
4. **Kétállású kapcsoló** - nem bővíthető 3+ nyelvre
|
||||
|
||||
A javasolt restructuring:
|
||||
- Bevezeti a központi `common` szekciót (30+ általános kulcs)
|
||||
- Oldalakra bontja a monolit fájlokat (lazy loading)
|
||||
- Dropdown nyelvválasztóra cseréli a kapcsolót
|
||||
- Előkészíti a terepet 6+ nyelv támogatásához
|
||||
- Backend szinkronban marad a frontenddel
|
||||
145
docs/p0_provider_taxonomy_vehicle_compatibility_audit.md
Normal file
145
docs/p0_provider_taxonomy_vehicle_compatibility_audit.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# 🔍 P0 RECONNAISSANCE — Provider Taxonomy & Vehicle Compatibility Audit
|
||||
|
||||
**Date:** 2026-07-01
|
||||
**Scope:** Backend models, schemas, admin API endpoints
|
||||
**Status:** READ-ONLY AUDIT COMPLETE — NO FILES MODIFIED
|
||||
|
||||
---
|
||||
|
||||
## 🏁 EXECUTIVE SUMMARY
|
||||
|
||||
| Capability | Status | Details |
|
||||
|-----------|--------|---------|
|
||||
| **ExpertiseTag (4-level hierarchy)** | ✅ **EXISTS** | Full tree with `parent_id`, `level`, `path`, multi-language |
|
||||
| **Many-to-many Service→Tag link** | ✅ **EXISTS** | `ServiceExpertise` junction table with `confidence_level` |
|
||||
| **Vehicle types as Level-0 tags** | ✅ **EXISTS** | 6 vehicle types in taxonomy seed |
|
||||
| **Public API `category_ids` support** | ✅ **EXISTS** | `ProviderUpdateIn` + `ProviderQuickAddIn` accept `category_ids: List[int]` |
|
||||
| **Public API `ServiceExpertise` sync** | ✅ **EXISTS** | `_sync_service_expertises()` in `provider_service.py` |
|
||||
| **Admin API `category_ids` support** | ❌ **MISSING** | `ProviderUpdateInput` has only plain-text `category` field |
|
||||
| **Admin PATCH → ServiceExpertise sync** | ❌ **MISSING** | PATCH endpoint does NOT call `_sync_service_expertises()` |
|
||||
| **Vehicle Type Compatibility field** | ❌ **MISSING** | No `supported_vehicle_types` on any provider model |
|
||||
| **Vehicle Type→Provider junction table** | ❌ **MISSING** | No dedicated relationship table exists |
|
||||
|
||||
---
|
||||
|
||||
## 1️⃣ CATEGORY TAXONOMY (ExpertiseTag) — ✅ FULLY IMPLEMENTED
|
||||
|
||||
### Model: `ExpertiseTag` (`backend/app/models/marketplace/service.py:83`)
|
||||
- **Table:** `marketplace.expertise_tags`
|
||||
- **Multi-language:** `name_hu`, `name_en`, `name_translations` (JSONB)
|
||||
- **4-level hierarchy:** `parent_id`, `level` (0-3), `path`
|
||||
- **Self-referential tree:** `children` / `parent` relationship
|
||||
|
||||
### Junction: `ServiceExpertise` (`backend/app/models/marketplace/service.py:146`)
|
||||
- **Table:** `marketplace.service_expertises`
|
||||
- **Links:** `service_id` → `ServiceProfile.id` ←→ `expertise_id` → `ExpertiseTag.id`
|
||||
- **Extra:** `confidence_level`
|
||||
|
||||
### Vehicle Types in the 4-Level Taxonomy (Level 0)
|
||||
From `seed_expertise_taxonomy.py`:
|
||||
|
||||
| Key | HU Name | EN Name |
|
||||
|-----|---------|---------|
|
||||
| `szemelygepjarmu` | Személygépjármű | Passenger Car |
|
||||
| `motor` | Motorkerékpár | Motorcycle |
|
||||
| `kishaszonjarmu` | Kishaszonjármű | LCV |
|
||||
| `nagyhaszonjarmu_kamion` | Nagyhaszonjármű (Kamion) | HGV / Truck |
|
||||
| `munkagep_traktor` | Munkagép / Traktor | Agricultural / Construction Machinery |
|
||||
| `potkocsi_utanfuto` | Pótkocsi / Utánfutó | Trailer |
|
||||
|
||||
Plus **Universal** Level-1: Fuel Stations, Restaurants, Accommodation, Parking.
|
||||
|
||||
---
|
||||
|
||||
## 2️⃣ VEHICLE TYPE COMPATIBILITY — ❌ COMPLETELY MISSING
|
||||
|
||||
### `ServiceProvider` (`backend/app/models/identity/social.py:23`)
|
||||
- Fields: `id`, `name`, `address`, `category` (str), `city`, contact fields, status, source
|
||||
- **NO** `supported_vehicle_types`
|
||||
- **NO** vehicle type relationship
|
||||
|
||||
### `ServiceProfile` (`backend/app/models/marketplace/service.py:21`)
|
||||
- Has: `expertises` (ServiceExpertise relationship), `specialization_tags` (JSONB)
|
||||
- **NO** `supported_vehicle_types`
|
||||
|
||||
### Implicit tracking only
|
||||
The ONLY way vehicle type compatibility is tracked today is through the 4-level ExpertiseTag hierarchy (Level-0 tags). This is implicit, not explicit — no dedicated queryable field exists.
|
||||
|
||||
### `vehicle.vehicle_types` table exists but UNLINKED
|
||||
`VehicleType` (`backend/app/models/vehicle/vehicle_definitions.py:17`) is in the `vehicle` schema, used for catalog data. No FK link to providers.
|
||||
|
||||
---
|
||||
|
||||
## 3️⃣ ADMIN PROVIDER SCHEMAS — ⚠️ PARTIALLY IMPLEMENTED
|
||||
|
||||
### Public Schemas (✅ Handle `category_ids`)
|
||||
|
||||
| Schema | `category_ids` | `new_tags` |
|
||||
|--------|---------------|-----------|
|
||||
| `ProviderQuickAddIn` (`schemas/provider.py:135`) | ✅ `Optional[List[int]]` | ✅ `Optional[List[str]]` |
|
||||
| `ProviderUpdateIn` (`schemas/provider.py:173`) | ✅ `Optional[List[int]]` | ✅ `Optional[List[str]]` |
|
||||
|
||||
### Admin Schema (❌ MISSING)
|
||||
|
||||
| Schema | `category_ids` | `new_tags` | `supported_vehicle_types` |
|
||||
|--------|---------------|-----------|--------------------------|
|
||||
| `ProviderUpdateInput` (`admin_providers.py:123`) | ❌ **MISSING** | ❌ **MISSING** | ❌ **MISSING** |
|
||||
|
||||
Admin `ProviderUpdateInput` only has: `name`, `city`, `address_zip`, `address_street_name`, `address_street_type`, `address_house_number`, `plus_code`, `contact_phone`, `contact_email`, `website`, plain-text `category`, `status`, `validation_score`.
|
||||
|
||||
### Admin PATCH (`admin_providers.py:1072`) — No ServiceExpertise sync
|
||||
The `update_provider()` function sets fields via `setattr` and logs to AuditLog, but **never** calls `_sync_service_expertises()`.
|
||||
|
||||
Compare with public endpoint in `provider_service.py:1070` which:
|
||||
1. Collects `category_ids` + `new_tag_ids`
|
||||
2. Creates new `ExpertiseTag` for `new_tags`
|
||||
3. Calls `_sync_service_expertises()` at line 1094
|
||||
|
||||
---
|
||||
|
||||
## 4️⃣ REQUIRED BACKEND CHANGES BEFORE FRONTEND MATRIX UI
|
||||
|
||||
### 🔴 P0 — MUST FIX: Admin `ProviderUpdateInput` schema
|
||||
**File:** `backend/app/api/v1/endpoints/admin_providers.py:123`
|
||||
Add: `category_ids: Optional[List[int]]`, `new_tags: Optional[List[str]]`
|
||||
|
||||
### 🔴 P0 — MUST FIX: Admin PATCH endpoint
|
||||
**File:** `backend/app/api/v1/endpoints/admin_providers.py:1072`
|
||||
Add `ServiceExpertise` sync after field updates.
|
||||
|
||||
### 🔴 P0 — MUST CREATE: Vehicle Type Compatibility Model
|
||||
New junction table `marketplace.provider_vehicle_types` linking `service_provider_id` to `expertise_tags.id` (Level-0 vehicle type tags).
|
||||
|
||||
### 🟡 P1 — ADD: `supported_vehicle_type_ids` to ProviderUpdateInput
|
||||
List of Level-0 ExpertiseTag IDs.
|
||||
|
||||
### 🟡 P1 — ADD: Categories + Vehicle Types to ProviderDetail response
|
||||
Add `supported_vehicle_types: List[dict]` and `categories: List[dict]` fields.
|
||||
|
||||
### 🟢 P2 — ADD: Frontend Edit Page `/providers/[id]/edit`
|
||||
Tabbed matrix layout: Basic Info | Categories (4-level tree) | Vehicle Types | Location
|
||||
|
||||
---
|
||||
|
||||
## 5️⃣ DATA FLOW COMPARISON
|
||||
|
||||
```
|
||||
CURRENT STATE:
|
||||
ServiceProvider ──category(str)──→ [plain text, no relationship]
|
||||
│
|
||||
└──ServiceProfile──ServiceExpertise──ExpertiseTag (public API only)
|
||||
|
||||
TARGET STATE:
|
||||
ServiceProvider ──category_ids──→ ServiceExpertise──ExpertiseTag (service categories)
|
||||
│
|
||||
└──supported_vehicle_type_ids──→ ProviderVehicleType──ExpertiseTag (Level-0 types)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6️⃣ KEY TAKEAWAYS
|
||||
|
||||
1. **ExpertiseTag hierarchy is production-ready** — 6 vehicle types at Level-0, full multi-language.
|
||||
2. **Public API already handles `category_ids`** — admin PATCH is the gap.
|
||||
3. **Vehicle type compatibility is entirely new** — reuse Level-0 ExpertiseTags as vehicle type references.
|
||||
4. **`category` varchar field is deprecated** — admin PATCH needs to catch up to structured ServiceExpertise.
|
||||
336
docs/p0_service_provider_gamification_audit_report.md
Normal file
336
docs/p0_service_provider_gamification_audit_report.md
Normal file
@@ -0,0 +1,336 @@
|
||||
# 🔍 P0 RECONNAISSANCE — Service Provider & Gamification State Audit Report
|
||||
|
||||
**Date:** 2026-06-30
|
||||
**Auditor:** Rendszer-Architect (DeepSeek Reasoner)
|
||||
**Mode:** READ-ONLY — NO FILES MODIFIED
|
||||
**Status:** COMPLETE
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This report documents the deep-dive reconnaissance audit of the Service Provider ecosystem, Ratings/Validations, and Gamification modules. The audit covered 3 database schemas (`marketplace`, `identity`, `gamification`), 6 model files, 4 service files, 5 API endpoint files, and 12 router registrations.
|
||||
|
||||
**CRITICAL GAP FOUND:** No `admin_providers.py` router exists — the admin provider approval workflow is completely missing from the API layer. Admin UI for `/providers` pages cannot be built without this foundational layer.
|
||||
|
||||
---
|
||||
|
||||
## 1. Database Model Map
|
||||
|
||||
### 1.1 Marketplace Schema (`marketplace`)
|
||||
|
||||
| Table | File | Purpose |
|
||||
|-------|------|---------|
|
||||
| `service_profiles` | `backend/app/models/marketplace/service.py:21` | Rich service profile linked to orgs or providers |
|
||||
| `expertise_tags` | `backend/app/models/marketplace/service.py:97` | 4-level category hierarchy (L0-L3) |
|
||||
| `service_expertises` | `backend/app/models/marketplace/service.py:147` | Junction table: ServiceProfile ↔ ExpertiseTag |
|
||||
| `service_staging` | `backend/app/models/marketplace/service.py:159` | Robot-collected service data (pre-moderation) |
|
||||
| `service_staging` | `backend/app/models/marketplace/staged_data.py:1` | Extended staging model (extend_existing=True) |
|
||||
| `discovery_parameters` | `backend/app/models/marketplace/service.py:191` | Robot discovery parameters |
|
||||
| `cost` | `backend/app/models/marketplace/service.py:205` | Service cost structure |
|
||||
|
||||
### 1.2 Identity Schema (`identity` — Social)
|
||||
|
||||
| Table | File | Purpose |
|
||||
|-------|------|---------|
|
||||
| `service_providers` | `backend/app/models/identity/social.py:133` | Crowdsourced provider submissions (P0 refactor) |
|
||||
| `votes` | `backend/app/models/identity/social.py:186` | Community validation (+1/-1 per user/provider) |
|
||||
| `competitions` | `backend/app/models/identity/social.py:209` | Social competitions |
|
||||
| `user_scores` | `backend/app/models/identity/social.py:243` | User competition scores |
|
||||
| `service_reviews` | `backend/app/models/identity/social.py:266` | Verified reviews tied to financial transactions |
|
||||
|
||||
### 1.3 Gamification Schema (`gamification`)
|
||||
|
||||
| Table | File | Purpose |
|
||||
|-------|------|---------|
|
||||
| `point_rules` | `backend/app/models/gamification/gamification.py:31` | Dynamic point rules (action_key → points) |
|
||||
| `points_ledger` | `backend/app/models/gamification/gamification.py:89` | Point transaction log |
|
||||
| `user_stats` | `backend/app/models/gamification/gamification.py:103` | User gamification stats |
|
||||
| `user_contributions` | `backend/app/models/gamification/gamification.py:137` | Contribution tracking + moderation |
|
||||
| `level_configs` | `backend/app/models/gamification/gamification.py:179` | Level definitions (positive + penalty) |
|
||||
| `seasonal_competitions` | `backend/app/models/gamification/gamification.py:213` | Seasonal events |
|
||||
| `badges` | `backend/app/models/gamification/gamification.py:252` | Achievement badges |
|
||||
| `user_badges` | `backend/app/models/gamification/gamification.py:275` | User-badge assignments |
|
||||
| `seasons` | `backend/app/models/gamification/gamification.py:296` | Competition seasons |
|
||||
|
||||
---
|
||||
|
||||
## 2. Trust & Validation Score Architecture
|
||||
|
||||
### 2.1 Score Fields on Models
|
||||
|
||||
| Field | Model | Default | Purpose |
|
||||
|-------|-------|---------|---------|
|
||||
| `validation_score` | `ServiceProvider` | `0` | Community validation aggregate (+1/-1 from Votes) |
|
||||
| `trust_score` | `ServiceProfile` | `30` | Trust engine score (Gondos Gazda Index) |
|
||||
| `is_verified` | `ServiceProfile` | `False` | Admin/manual verification flag |
|
||||
| `rating_*_avg` | `ServiceProfile` | `NULL` | Aggregated verified review ratings (4 dimensions) |
|
||||
| `rating_overall` | `ServiceProfile` | `NULL` | Overall rating from verified reviews |
|
||||
|
||||
### 2.2 CRITICAL: `provider_validations` Table NEVER Created
|
||||
|
||||
The Masterbook 2.0 spec mentioned a `provider_validations` table for XP farming prevention, **but it was never created in the codebase**. No model file, no Alembic migration, no sync_engine artifact exists for this table.
|
||||
|
||||
**Impact:** XP farming prevention for provider submissions relies solely on:
|
||||
- `UserContribution` status (pending/approved/rejected) — exists
|
||||
- `UserStats.providers_added_count` — exists
|
||||
- `Vote` table duplicate prevention (UniqueConstraint on user_id + provider_id) — exists
|
||||
|
||||
The dedicated anti-farming table was spec-only and never implemented.
|
||||
|
||||
### 2.3 Review Validation Rules
|
||||
|
||||
`ServiceReview` (from `backend/app/models/identity/social.py:266`):
|
||||
- Mandatory FK to `audit.financial_ledger.transaction_id` (UniqueConstraint)
|
||||
- 4 rating dimensions: `price_rating`, `quality_rating`, `time_rating`, `communication_rating` (1-10 scale)
|
||||
- Only users with verified financial transaction can review
|
||||
- `ServiceProfile.rating_*_avg` fields aggregate these values
|
||||
|
||||
---
|
||||
|
||||
## 3. Gamification Engine Analysis
|
||||
|
||||
### 3.1 Dynamic Point Rules
|
||||
|
||||
The gamification engine uses **dynamic rules** from `gamification.point_rules` table (not hardcoded):
|
||||
|
||||
| Action Key | Points | Description |
|
||||
|------------|--------|-------------|
|
||||
| `ADD_NEW_PROVIDER` | 500 | Adding a new service provider |
|
||||
| `USE_UNVERIFIED_PROVIDER` | 200 | Using an unverified provider |
|
||||
| `RATE_PROVIDER` | 250 | Rating a provider |
|
||||
| `UPDATE_PROVIDER` | 100 | Updating provider info |
|
||||
|
||||
Seeded by `backend/app/scripts/seed_gamification_rules.py`.
|
||||
|
||||
### 3.2 GamificationService Flow
|
||||
|
||||
From `backend/app/services/gamification_service.py`:
|
||||
1. `process_activity(user_id, action_key, ...)` — Main entry point
|
||||
2. Reads `PointRule` from DB by action_key
|
||||
3. Applies level multiplier via `_calculate_multiplier()`
|
||||
4. Penalty system: 4 levels (L0=100%, L1=50%, L2=10%, L3=0%)
|
||||
5. Calls `_handle_level_up()` for cross-level logic
|
||||
6. Social points → credits conversion at configurable rate
|
||||
7. Config loaded from `GAMIFICATION_MASTER_CONFIG` system parameter
|
||||
|
||||
### 3.3 Provider Service Gamification Integration
|
||||
|
||||
From `backend/app/services/provider_service.py`:
|
||||
- `_award_provider_points()` — Reads PointRule from DB, awards through GamificationService
|
||||
- Called on: `quick_add_provider()` and `update_provider()`
|
||||
- `UserContribution` records created with status "pending" for admin review
|
||||
|
||||
---
|
||||
|
||||
## 4. API Endpoint Inventory
|
||||
|
||||
### 4.1 User-Facing Provider Endpoints (`/providers` prefix)
|
||||
|
||||
From `backend/app/api/v1/endpoints/providers.py`:
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| GET | `/providers/categories/tree` | Full hierarchical category tree (4-level) |
|
||||
| GET | `/providers/categories/autocomplete` | Text search for L2-L3 tags |
|
||||
| GET | `/providers/categories` | Flat list of expertise categories |
|
||||
| GET | `/providers/search` | Unified provider search (3 sources) |
|
||||
| POST | `/providers/quick-add` | Quick provider submission (crowdsourced) |
|
||||
| PUT | `/providers/{provider_id}` | Update provider details (hybrid save) |
|
||||
|
||||
### 4.2 Admin Gamification Endpoints (`/admin/gamification` prefix)
|
||||
|
||||
From `backend/app/api/v1/endpoints/admin_gamification.py`:
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| GET/POST | `/admin/gamification/point-rules` | List/Create point rules |
|
||||
| GET/PUT/DELETE | `/admin/gamification/point-rules/{id}` | CRUD single rule |
|
||||
| GET/POST | `/admin/gamification/levels` | List/Create level configs |
|
||||
| PUT | `/admin/gamification/levels/{id}` | Update level config |
|
||||
| GET/POST | `/admin/gamification/badges` | List/Create badges |
|
||||
| GET/PUT | `/admin/gamification/user-stats` | List/Update user stats |
|
||||
| GET | `/admin/gamification/user-stats/{id}` | Get user stat detail |
|
||||
| POST | `/admin/gamification/user-stats/{id}/penalty` | Apply penalty |
|
||||
| POST | `/admin/gamification/user-stats/{id}/reward` | Apply reward |
|
||||
| GET | `/admin/gamification/contributions` | List contributions |
|
||||
| PUT | `/admin/gamification/contributions/{id}/review` | Approve/reject contribution |
|
||||
| GET/POST | `/admin/gamification/seasons` | List/Create seasons |
|
||||
| PUT/DELETE | `/admin/gamification/seasons/{id}` | Update/Delete season |
|
||||
| GET/POST | `/admin/gamification/competitions` | List/Create competitions |
|
||||
| PUT/DELETE | `/admin/gamification/competitions/{id}` | Update/Delete competition |
|
||||
| GET | `/admin/gamification/leaderboard` | Admin leaderboard |
|
||||
| GET | `/admin/gamification/dashboard` | Dashboard summary |
|
||||
| GET/PUT | `/admin/gamification/master-config` | Master config CRUD |
|
||||
|
||||
### 4.3 User-Facing Gamification Endpoints (`/gamification` prefix)
|
||||
|
||||
From `backend/app/api/v1/endpoints/gamification.py`:
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| GET | `/gamification/my-stats` | Current user stats |
|
||||
| GET | `/gamification/leaderboard` | Public leaderboard |
|
||||
| GET | `/gamification/seasons` | List seasons |
|
||||
| GET | `/gamification/my-contributions` | User contributions |
|
||||
| POST | `/gamification/submit-service` | Submit service (gamified) |
|
||||
| GET | `/gamification/quiz/daily` | Daily quiz |
|
||||
| POST | `/gamification/quiz/answer` | Answer quiz |
|
||||
| GET/POST | `/gamification/badges` | Badge listing/awarding |
|
||||
| GET | `/gamification/achievements` | Achievement list |
|
||||
|
||||
### 4.4 Existing Admin Routers
|
||||
|
||||
| Router File | Prefix | Module |
|
||||
|-------------|--------|--------|
|
||||
| `admin.py` | `/admin` | General admin (health, params, pending actions) |
|
||||
| `admin_gamification.py` | `/admin/gamification` | Gamification admin CRUD |
|
||||
| `admin_organizations.py` | `/admin/organizations` | Organization CRM |
|
||||
| `admin_users.py` | `/admin/users` | User management |
|
||||
| `admin_persons.py` | `/admin/persons` | Person management |
|
||||
| `admin_packages.py` | `/admin/packages` | Package management |
|
||||
| `admin_services.py` | `/admin/services` | Service catalog |
|
||||
| `admin_permissions.py` | `(root)` | Permission/RBAC management |
|
||||
|
||||
---
|
||||
|
||||
## 5. GAP ANALYSIS — Missing Admin Provider API
|
||||
|
||||
### 5.1 CRITICAL GAP: No `admin_providers.py` Router
|
||||
|
||||
**There is NO `/admin/providers` router.** The file `admin_providers.py` does not exist in the endpoints directory. The following router files DO exist:
|
||||
- `admin_gamification.py`, `admin_organizations.py`, `admin_users.py`, `admin_persons.py`, `admin_packages.py`, `admin_services.py`, `admin_permissions.py`
|
||||
- `admin.py` (general admin)
|
||||
|
||||
**Impact:** Admin users cannot manage providers through the API. The Nuxt Admin Frontend cannot build `/providers` pages without this backend layer.
|
||||
|
||||
### 5.2 Complete List of Missing Endpoints
|
||||
|
||||
| # | Method | Path | Purpose |
|
||||
|---|--------|------|---------|
|
||||
| 1 | GET | `/admin/providers` | List all providers from 3 sources (orgs, staging, crowd) |
|
||||
| 2 | GET | `/admin/providers/pending` | List pending providers awaiting approval |
|
||||
| 3 | GET | `/admin/providers/{id}` | Get detailed provider info (merged from all sources) |
|
||||
| 4 | PUT | `/admin/providers/{id}/approve` | Approve provider → set status, award submitter XP |
|
||||
| 5 | PUT | `/admin/providers/{id}/reject` | Reject provider with reason → flag UserContribution |
|
||||
| 6 | GET | `/admin/providers/staging` | List robot-collected staging entries |
|
||||
| 7 | PUT | `/admin/providers/staging/{id}/promote` | Promote staging → ServiceProfile (verify & create org) |
|
||||
| 8 | PUT | `/admin/providers/staging/{id}/reject` | Reject staging entry with reason |
|
||||
| 9 | GET | `/admin/providers/{id}/votes` | List community validation votes for a provider |
|
||||
| 10 | GET | `/admin/providers/{id}/reviews` | List service reviews for a provider |
|
||||
| 11 | PUT | `/admin/providers/{provider_id}/verify` | Toggle verified status on ServiceProfile |
|
||||
| 12 | PUT | `/admin/providers/{provider_id}/trust-score` | Manually adjust trust_score |
|
||||
| 13 | GET | `/admin/providers/validations` | List pending community validations (Votes table) |
|
||||
| 14 | PUT | `/admin/providers/staging/{id}` | Update staging entry (edit robot-collected data) |
|
||||
|
||||
### 5.3 Dependencies for Building These Endpoints
|
||||
|
||||
| Dependency | Current Status | Notes |
|
||||
|------------|---------------|-------|
|
||||
| `ServiceProvider` model (`social.py:133`) | Complete | Includes validation_score, status, source |
|
||||
| `ServiceProfile` model (`service.py:21`) | Complete | Includes trust_score, is_verified, verification_log |
|
||||
| `ServiceStaging` model (`service.py:159`) | Complete | Includes status, validation_level, audit_trail |
|
||||
| `Vote` model (`social.py:186`) | Complete | Includes weight, user_id, provider_id |
|
||||
| `ServiceReview` model (`social.py:266`) | Complete | Verified reviews with financial transaction linkage |
|
||||
| `GamificationService` (`gamification_service.py`) | Complete | Can award XP when admin approves |
|
||||
| `UserContribution` model (`gamification.py:137`) | Complete | Status field for pending/approved/rejected |
|
||||
| Permission `providers:manage` | Unknown | Needs to exist in RBAC or be created |
|
||||
| Schemas for admin provider endpoints | MISSING | Need `ProviderAdminOut`, `ProviderAdminList`, etc. |
|
||||
|
||||
### 5.4 Provider Data Flow (Current State)
|
||||
|
||||
```
|
||||
+-------------------+ +-------------------+ +-------------------+
|
||||
| Robot (Staging) | | Crowdsourced | | Verified Org |
|
||||
| service_staging | | service_providers | | fleet.orgs |
|
||||
| status: pending | | status: pending | | is_verified: T |
|
||||
+--------+----------+ +--------+----------+ +--------+----------+
|
||||
| | |
|
||||
v v v
|
||||
+---------------------------------------------------------------+
|
||||
| User-Facing API (providers.py) |
|
||||
| GET /providers/search -- UNION of all 3 sources |
|
||||
| POST /providers/quick-add -- Creates ServiceProvider |
|
||||
| PUT /providers/{id} -- Update with migration logic |
|
||||
+---------------------------------------------------------------+
|
||||
| | |
|
||||
| ** NO ADMIN LAYER EXISTS ** |
|
||||
v v v
|
||||
+---------------------------------------------------------------+
|
||||
| MISSING: Admin Provider Workflow |
|
||||
| - No approval/rejection for pending providers |
|
||||
| - No staging promotion to verified org |
|
||||
| - No trust_score manual adjustment |
|
||||
| - No community validation vote review |
|
||||
| - No service review moderation |
|
||||
+---------------------------------------------------------------+
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Gitea Task Breakdown (Required for Implementation)
|
||||
|
||||
Based on the 3A granularity principle, the implementation of the admin provider layer requires these Gitea tasks:
|
||||
|
||||
### Epic: Admin Provider Management
|
||||
|
||||
| # | Task | Priority | Dependencies |
|
||||
|---|------|----------|-------------|
|
||||
| 1 | Create schemas for admin provider endpoints | P0 | None |
|
||||
| 2 | Implement `admin_providers.py` - List/Get providers | P0 | Schema |
|
||||
| 3 | Implement approve/reject provider logic | P0 | GamificationService |
|
||||
| 4 | Implement staging management (list/promote/reject) | P0 | None |
|
||||
| 5 | Implement community validation vote review | P1 | #4 |
|
||||
| 6 | Implement service review moderation | P1 | #5 |
|
||||
| 7 | Register router in `api.py` at `/admin/providers` | P0 | #2 |
|
||||
| 8 | Implement manual trust_score adjustment endpoint | P1 | #6 |
|
||||
| 9 | Create RBAC permission `providers:manage` | P0 | None |
|
||||
| 10 | E2E tests for admin provider workflow | P1 | #2-#9 |
|
||||
|
||||
---
|
||||
|
||||
## 7. Gamification Gaps & Observations
|
||||
|
||||
### 7.1 No Admin-Triggered Gamification Rewards
|
||||
|
||||
When an admin approves a provider submission, there is **no endpoint** to trigger `GamificationService.process_activity()` for the submitter. The `UserContribution` record exists but there's no automated XP award upon approval.
|
||||
|
||||
**Fix:** The `PUT /admin/providers/{id}/approve` endpoint must call:
|
||||
```python
|
||||
await gamification_service.process_activity(
|
||||
db=db,
|
||||
user_id=submitter_user_id,
|
||||
action_key="ADD_NEW_PROVIDER",
|
||||
source_type="provider_approval",
|
||||
source_id=provider_id
|
||||
)
|
||||
```
|
||||
|
||||
### 7.2 No Rejected Contribution Feedback Loop
|
||||
|
||||
When a provider is rejected, the `UserContribution.status` should be set to `rejected` with a rejection reason, but there's no endpoint to trigger this for admin workflows.
|
||||
|
||||
### 7.3 Gamification Config is Dynamic but Has No Validation
|
||||
|
||||
The `GAMIFICATION_MASTER_CONFIG` system parameter can be edited freely via the admin gamification API, but there's **no schema validation** on the JSONB structure. A malformed config could break the gamification engine.
|
||||
|
||||
---
|
||||
|
||||
## 8. Summary of Findings
|
||||
|
||||
| Category | Status | Details |
|
||||
|----------|--------|---------|
|
||||
| Database Models | COMPLETE | All 15+ models across 3 schemas |
|
||||
| User-Facing Provider API | COMPLETE | 6 endpoints in providers.py |
|
||||
| User-Facing Gamification API | COMPLETE | 15+ endpoints in gamification.py |
|
||||
| Admin Gamification API | COMPLETE | 25+ endpoints in admin_gamification.py |
|
||||
| Gamification Service | COMPLETE | Full engine with dynamic rules, penalties |
|
||||
| Provider Service | COMPLETE | P0 hybrid vendor refactor applied |
|
||||
| **Admin Provider API** | **MISSING** | **No admin_providers.py - 14 endpoints missing** |
|
||||
| **provider_validations table** | **NEVER CREATED** | Spec-only, not in codebase |
|
||||
| **Trust Engine** | **STUB** | trust_score exists but no active scoring logic |
|
||||
| **Admin Rejection Gamification** | **MISSING** | No endpoint to award/reject XP on moderation |
|
||||
|
||||
---
|
||||
|
||||
*End of P0 Reconnaissance Report. This is a READ-ONLY analysis - no files were modified.*
|
||||
Reference in New Issue
Block a user