gemification_admin bekötve

This commit is contained in:
Roo
2026-06-30 08:56:55 +00:00
parent df4a0f07ff
commit cbfb955580
313 changed files with 18490 additions and 2895 deletions

View File

@@ -0,0 +1,548 @@
# Gamification Nyelvi Modul Audit és Javítási Javaslat
## Összefoglaló
**Dátum:** 2026-06-29
**Auditor:** Rendszer-Architect
**Vizsgált fájlok:** 16 db (3 backend + 12 frontend admin + 1 konfig)
**Gitea Issue:** #339
---
## 1. Vizsgált Fájlok Listája
### Backend (3 fájl)
| # | Fájl | Sorok | Érintettség |
|---|------|-------|-------------|
| 1 | `backend/app/models/gamification/gamification.py` | 174 | Nincs hardcoded string (ORM modellek) |
| 2 | `backend/app/services/gamification_service.py` | 231 | 1 db hardcoded emoji string (L197) |
| 3 | `backend/app/api/v1/endpoints/gamification.py` | 907 | **~25+ hardcoded string** (hibaüzenetek, kvíz, achievementek) |
### Frontend Admin (12 Vue fájl)
| # | Fájl | Sorok | Hardcoded szövegek |
|---|------|-------|-------------------|
| 1 | `frontend_admin/pages/gamification/badges.vue` | 363 | Minden UI szöveg magyar |
| 2 | `frontend_admin/pages/gamification/competitions.vue` | 494 | Minden UI szöveg magyar |
| 3 | `frontend_admin/pages/gamification/config.vue` | 543 | Minden UI szöveg magyar |
| 4 | `frontend_admin/pages/gamification/index.vue` | 220 | Minden UI szöveg magyar |
| 5 | `frontend_admin/pages/gamification/leaderboard.vue` | 398 | Minden UI szöveg magyar |
| 6 | `frontend_admin/pages/gamification/ledger.vue` | 390 | Minden UI szöveg magyar |
| 7 | `frontend_admin/pages/gamification/levels.vue` | 369 | Minden UI szöveg magyar |
| 8 | `frontend_admin/pages/gamification/parameters.vue` | 283 | Minden UI szöveg magyar |
| 9 | `frontend_admin/pages/gamification/point-rules.vue` | 362 | Minden UI szöveg magyar |
| 10 | `frontend_admin/pages/gamification/seasons.vue` | 406 | Minden UI szöveg magyar |
| 11 | `frontend_admin/pages/gamification/users/index.vue` | 250 | Minden UI szöveg magyar |
| 12 | `frontend_admin/pages/gamification/users/[id].vue` | 390 | Minden UI szöveg magyar |
### Lokációs fájlok (4 db)
| # | Fájl | Meglévő kulcsok | Gamification kulcsok |
|---|------|-----------------|---------------------|
| 1 | `frontend_admin/locales/en.json` | packages, permissions, garages, persons, users, dashboard | **NINCS** |
| 2 | `frontend_admin/locales/hu.json` | packages, permissions, garages, persons, users, dashboard | **NINCS** |
| 3 | `backend/static/locales/en.json` | AUTH, SENTINEL, COMMON, EMAIL, ORGANIZATION, REGISTRATION_DOCUMENTS | **NINCS** |
| 4 | `backend/static/locales/hu.json` | AUTH, SENTINEL, COMMON, EMAIL, ORGANIZATION, REGISTRATION_DOCUMENTS | **NINCS** |
---
## 2. Részletes Hardcoded Stringek
### 2.1 Backend API (`backend/app/api/v1/endpoints/gamification.py`)
#### 2.1.1 Magyar nyelvű hibaüzenetek
| Sor | Kód | Szöveg |
|-----|-----|--------|
| 289 | `detail=` | `"Önvédelmi korlátozás miatt nem küldhetsz be új szerviz adatokat."` |
| 380 | `detail=` | `f"Hiba a pontozás során: {str(e)}"` |
| 387 | `message:` | `"Szerviz beküldve a rendszerbe elemzésre!"` |
| 394 | `detail=` | `f"Hiba a beküldés során: {str(e)}"` |
#### 2.1.2 Angol nyelvű hibaüzenetek
| Sor | Kód | Szöveg |
|-----|-----|--------|
| 191 | `detail=` | `"Season not found"` |
| 488-492 | `detail=` | `"You have already played the daily quiz today..."` |
| 810-811 | `detail=` | `"Badge not found"` |
#### 2.1.3 Keménykódolt kvíz tartalom (magyar)
| Sor | Tartalom |
|-----|----------|
| 496-517 | 3 db kvíz kérdés teljes egészében magyar nyelven: kérdések, válaszlehetőségek, magyarázatok |
| 553-557 | Kvíz válasz adatok magyar nyelven |
#### 2.1.4 Achievement címek (angol)
| Sor | Cím |
|-----|-----|
| 857-861 | `"Novice"`, `"Apprentice"`, `"Expert"`, `"Master"` (XP achievementek) |
| 884-888 | `"Quiz Beginner"`, `"Quiz Enthusiast"`, `"Quiz Master"` (kvíz achievementek) |
### 2.2 Backend Service (`backend/app/services/gamification_service.py`)
| Sor | Kód |
|-----|-----|
| 197 | `f"🔴 PENALTY: {reason}"` - emoji + angol szöveg a penalty bejegyzéshez |
### 2.3 Frontend Admin Vue Oldalak
Minden a 12 gamification Vue oldal **100%-ban hardcoded magyar nyelvű szövegeket** használ. Sehol sem található `useI18n()` vagy `$t()` hívás.
#### Kulcskategóriák oldalanként:
| Oldal | Hardcoded szövegek kategóriái |
|-------|-------------------------------|
| **badges.vue** | "Kitüntetések", "Még nincsenek kitüntetések", "Új kitüntetés", "Név", "Leírás", "Ikon URL", "Mégse", "Mentés", "Létrehozás", "Biztosan törölni szeretnéd?" |
| **competitions.vue** | "Versenyek", "Szezonális versenyek kezelése", "Új Verseny", "Draft", "Aktív", "Befejezett", "Törölt", "Érvénytelen JSON formátum!" |
| **config.vue** | "Rendszer Konfig", "XP Logic", "Conversion Logic", "Penalty Logic", "Level Rewards", "Hatás Kalkulátor", "Nyers JSON Szerkesztő" |
| **index.vue** | "Gamification HQ", "Összes Felhasználó", "Aktív Szezon", "Függő Hozzájárulások", "Ma Szerzett XP", "Gyors Műveletek" |
| **leaderboard.vue** | "Ranglista", "Keresés", "Név vagy email...", "Szint", "Összes szint", "Minimum XP", "Rendezés", "Enyhe", "Közepes", "Súlyos" |
| **ledger.vue** | "Pontnapló", "User ID", "Dátumtól", "Dátumig", "Keresés", "Törlés", "CSV", "Előző", "Következő" |
| **levels.vue** | "Szintek", "Új szint", "Rang", "Min. Pont", "Típus", "Büntető", "Normál", "Szint Fa Diagram" |
| **parameters.vue** | "Rendszerparaméterek", "Kulcs", "Érték", "Kategória", "Hatósugár", "Scope ID" |
| **point-rules.vue** | "Pontszabályok", "Új pontszabály", "Akció Kulcs", "Pont", "Leírás", "Státusz", "Aktív", "Inaktív" |
| **seasons.vue** | "Szezonok", "Új Szezon", "Név", "Kezdő dátum", "Záró dátum", "Szezon Aktiválása" |
| **users/index.vue** | "Gamification Felhasználók", "Összes szint", "Csak büntetettek", "Csak büntetlenek", "Részletek" |
| **users/[id].vue** | "Vissza a listához", "Összes XP", "Büntetőpontok", "Restrikciós Szint", "Büntetés Kiszabása", "Jutalom Kiosztása" |
---
## 3. Javítási Javaslat (Fix Proposal)
### 3.1 Frontend Admin - i18n Migráció
#### 3.1.1 Lokációs kulcs struktúra javaslat
A `frontend_admin/locales/en.json` és `frontend_admin/locales/hu.json` fájlokba be kell vezetni egy új `gamification` kulcs hierarchical struktúrát.
**Teljes kulcs struktúra:**
```json
{
"gamification": {
"dashboard": {
"title": "Gamification HQ",
"subtitle": "Gamification system overview dashboard",
"total_users": "Total Users",
"active_season": "Active Season",
"pending_contributions": "Pending Contributions",
"xp_today": "XP Earned Today",
"quick_actions": "Quick Actions",
"manage_point_rules": "Manage Point Rules",
"manage_badges": "Manage Badges",
"manage_seasons": "Manage Seasons",
"recent_ledger": "Recent Ledger Entries",
"top_5_leaderboard": "Top 5 Leaderboard"
},
"badges": {
"title": "Badges",
"subtitle": "Badge management — CRUD",
"loading": "Loading badges...",
"error": "Failed to load badges",
"create_new": "Create New Badge",
"edit": "Edit Badge",
"delete": "Delete Badge",
"name": "Name",
"description": "Description",
"icon_url": "Icon URL",
"cancel": "Cancel",
"save": "Save",
"create": "Create",
"delete_confirm": "Are you sure you want to delete this badge?",
"save_success": "Badge saved successfully!",
"create_success": "Badge created successfully!",
"no_badges": "No badges yet. Create one with the button above!"
},
"competitions": {
"title": "Competitions",
"subtitle": "Seasonal competition management",
"create_new": "Create Competition",
"filter_season": "Filter by season:",
"all_seasons": "All seasons",
"active": "(Active)",
"loading": "Loading competitions...",
"error": "Failed to load competitions",
"no_competitions": "No competitions created yet.",
"create_first": "Create First Competition",
"name": "Name",
"description": "Description",
"season": "Season",
"start_date": "Start Date",
"end_date": "End Date",
"status": "Status",
"status_draft": "Draft",
"status_active": "Active",
"status_completed": "Completed",
"status_cancelled": "Cancelled",
"view_rules": "View Rules",
"edit": "Edit",
"invalid_json": "Invalid JSON format!"
},
"config": {
"title": "System Config",
"subtitle": "Gamification master configuration editor",
"loading": "Loading configuration...",
"error": "Failed to load configuration",
"last_saved": "Last saved:",
"save": "Save Configuration",
"xp_logic": "XP Logic",
"conversion_logic": "Conversion Logic",
"penalty_logic": "Penalty Logic",
"level_rewards": "Level Rewards",
"impact_calculator": "Impact Calculator",
"raw_json_editor": "Raw JSON Editor",
"user_level": "User Level:",
"daily_activities": "Daily Activities:",
"social_points": "Social Points:",
"estimated_results": "Estimated Results",
"daily_xp": "Daily XP",
"xp_to_next_level": "XP Until Next Level"
},
"leaderboard": {
"title": "Leaderboard",
"subtitle": "Gamification leaderboard admin view",
"search": "Search",
"search_placeholder": "Name or email...",
"level": "Level",
"all_levels": "All levels",
"min_xp": "Minimum XP",
"sort": "Sort",
"sort_xp": "By XP",
"sort_points": "By Points",
"sort_social": "By Social Points",
"sort_level": "By Level",
"filter": "Filter",
"reset": "Reset",
"ascending": "Ascending",
"descending": "Descending",
"rank": "#",
"user": "User",
"email": "Email",
"xp": "XP",
"level": "Level",
"points": "Points",
"social": "Social",
"penalty": "Penalty",
"restriction": "Restriction",
"discoveries": "Discoveries",
"services": "Services",
"last_modified": "Last Modified",
"actions": "Actions",
"restriction_mild": "Mild",
"restriction_moderate": "Moderate",
"restriction_severe": "Severe",
"prev": "Previous",
"next": "Next",
"per_page": "/ page"
},
"ledger": {
"title": "Points Ledger",
"subtitle": "Gamification points ledger with filtering and detailed logging",
"loading": "Loading ledger...",
"error": "Failed to load ledger",
"user_id": "User ID",
"date_from": "Date From",
"date_to": "Date To",
"reason": "Reason (text)",
"search": "Search",
"clear": "Clear",
"csv": "CSV Export",
"no_results": "No results with the current filters.",
"id": "ID",
"user": "User",
"points": "Points",
"penalty": "Penalty",
"xp": "XP",
"reason_col": "Reason",
"source": "Source",
"date": "Date",
"prev": "Previous",
"next": "Next",
"of": "of",
"showing": "Showing",
"filtered": "(filtered)"
},
"levels": {
"title": "Levels",
"subtitle": "Level configurations management — CRUD",
"create_new": "Create New Level",
"level": "Level",
"rank": "Rank",
"min_points": "Min Points",
"type": "Type",
"actions": "Actions",
"type_penalty": "Penalty",
"type_normal": "Normal",
"level_tree": "Level Tree Diagram",
"no_levels": "No level configurations yet.",
"level_number": "Level Number",
"rank_name": "Rank Name",
"minimum_points": "Minimum Points",
"is_penalty": "Penalty Level",
"positive_hint": "Positive: normal level, Negative: penalty level"
},
"parameters": {
"title": "System Parameters",
"subtitle": "Gamification category system parameters",
"loading": "Loading parameters...",
"key": "Key",
"value": "Value",
"category": "Category",
"scope": "Scope",
"scope_id": "Scope ID",
"actions": "Actions",
"edit": "Edit Parameter",
"cancel": "Cancel",
"save": "Save"
},
"point_rules": {
"title": "Point Rules",
"subtitle": "Gamification point rules management — CRUD",
"create_new": "Create New Point Rule",
"action_key": "Action Key",
"points": "Points",
"description": "Description",
"status": "Status",
"active": "Active",
"inactive": "Inactive",
"edit": "Edit Point Rule",
"point_value": "Point Value",
"cancel": "Cancel",
"save": "Save",
"delete": "Delete",
"duplicate_key": "A rule with this action key already exists.",
"save_success": "Point rule saved successfully!",
"create_success": "Point rule created successfully!"
},
"seasons": {
"title": "Seasons",
"subtitle": "Gamification season management",
"create_new": "Create Season",
"loading": "Loading seasons...",
"error": "Failed to load seasons",
"no_seasons": "No seasons created yet.",
"create_first": "Create First Season",
"active": "Active",
"inactive": "Inactive",
"edit": "Edit Season",
"new_season": "New Season",
"name": "Name",
"start_date": "Start Date",
"end_date": "End Date",
"activate_on_create": "Activate on creation",
"activate": "Activate Season",
"activate_confirm": "Are you sure you want to activate this season?",
"save_success": "Season saved successfully!",
"create_success": "Season created successfully!"
},
"users": {
"title": "Gamification Users",
"subtitle": "User gamification statistics management",
"level": "Level",
"all_levels": "All levels",
"min_xp": "Minimum XP",
"max_xp": "Maximum XP",
"penalty": "Penalty",
"all_penalty": "All",
"only_penalized": "Penalized only",
"only_non_penalized": "Non-penalized only",
"filter": "Filter",
"reset": "Reset",
"user_id": "User ID",
"xp": "XP",
"level": "Level",
"points": "Points",
"penalty": "Penalty",
"restriction": "Restriction",
"services": "Services",
"discoveries": "Discoveries",
"last_modified": "Last Modified",
"actions": "Actions",
"restriction_mild": "Mild",
"restriction_moderate": "Moderate",
"restriction_severe": "Severe",
"restriction_none": "None",
"details": "Details",
"prev": "Previous",
"next": "Next",
"user_detail_title": "User Gamification Details",
"back_to_list": "Back to list",
"total_xp": "Total XP",
"total_points": "Total Points",
"social_points": "Social Points",
"penalty_points": "Penalty Points",
"restriction_level": "Restriction Level",
"penalty_quota": "Penalty Quota",
"banned": "Banned",
"services": "Services",
"discovered_places": "Discovered Places",
"validated_places": "Validated Places",
"added_providers": "Added Providers",
"assign_penalty": "Assign Penalty",
"assign_reward": "Assign Reward",
"penalty_points_label": "Penalty Points",
"reason": "Reason",
"xp_reward": "XP Reward",
"social_reward": "Social Points Reward",
"apply_penalty": "Apply Penalty",
"apply_reward": "Apply Reward",
"ledger": "Points Ledger",
"entries": "entries",
"date": "Date",
"points": "Points",
"penalty": "Penalty",
"xp": "XP",
"reason": "Reason",
"source": "Source"
}
}
}
```
#### 3.1.2 Vue komponensek átalakítása
Minden Vue fájlban a következő módosításokat kell elvégezni:
**1. `useI18n()` import hozzáadása:**
```typescript
const { t } = useI18n()
```
**2. Template szövegek cseréje:**
```vue
<!-- Eredeti: -->
<h1 class="text-2xl font-bold text-white">Kitüntetések</h1>
<!-- Javított: -->
<h1 class="text-2xl font-bold text-white">{{ t('gamification.badges.title') }}</h1>
```
**3. Script szekcióban használt szövegek:**
```typescript
// Eredeti:
message.value = 'Kitüntetés sikeresen frissítve!'
// Javított:
message.value = t('gamification.badges.save_success')
```
### 3.2 Backend - i18n Migráció
#### 3.2.1 Lokációs kulcs struktúra backendhez
A `backend/static/locales/en.json` és `backend/static/locales/hu.json` fájlokba be kell vezetni:
```json
{
"GAMIFICATION": {
"SUBMIT_SERVICE": {
"SELF_DEFENSE_BLOCKED": "You cannot submit new service data due to self-defense restriction.",
"SUCCESS": "Service submitted to the system for analysis!",
"POINTS_ERROR": "Error during scoring: {error}",
"SUBMIT_ERROR": "Error during submission: {error}"
},
"QUIZ": {
"ALREADY_PLAYED": "You have already played the daily quiz today. Come back tomorrow!",
"NO_QUIZ_AVAILABLE": "No quiz available for today."
},
"BADGE": {
"NOT_FOUND": "Badge not found.",
"ALREADY_AWARDED": "Badge already awarded to this user."
},
"SEASON": {
"NOT_FOUND": "Season not found."
},
"ACHIEVEMENTS": {
"XP_NOVICE": "Novice",
"XP_APPRENTICE": "Apprentice",
"XP_EXPERT": "Expert",
"XP_MASTER": "Master",
"QUIZ_BEGINNER": "Quiz Beginner",
"QUIZ_ENTHUSIAST": "Quiz Enthusiast",
"QUIZ_MASTER": "Quiz Master"
}
}
}
```
#### 3.2.2 Backend API módosítások
A backend végpontokban a hardcoded stringek helyett egy i18n/lokalizációs segédfüggvényt kell használni, amely a kérés nyelvi preferenciája (`Accept-Language` header vagy a felhasználó beállított nyelve) alapján választja ki a megfelelő szöveget.
Példa implementáció (`app/core/i18n.py`):
```python
import json
from pathlib import Path
_LOCALES_DIR = Path(__file__).parent.parent.parent / "static" / "locales"
_cache = {}
def get_locale(lang: str = "hu") -> dict:
if lang not in _cache:
path = _LOCALES_DIR / f"{lang}.json"
if path.exists():
with open(path, "r", encoding="utf-8") as f:
_cache[lang] = json.load(f)
else:
_cache[lang] = {}
return _cache[lang]
def t(key: str, lang: str = "hu", **kwargs) -> str:
"""Translate a dot-notation key using the locale file."""
locale = get_locale(lang)
parts = key.split(".")
value = locale
for part in parts:
if isinstance(value, dict):
value = value.get(part, key)
else:
return key
if isinstance(value, str) and kwargs:
return value.format(**kwargs)
return value if isinstance(value, str) else key
```
#### 3.2.3 Kvíz tartalom lokalizációja
A kvíz kérdéseket ki kell venni a kódból, és adatbázisba vagy JSON fájlba kell helyezni nyelvi kulcsokkal.
### 3.3 Backend Service módosítás
A `backend/app/services/gamification_service.py` L197-es sorában:
```python
# Eredeti:
f"🔴 PENALTY: {reason}"
# Javasolt:
# A reason paraméter tartalmazza a lokalizált szöveget, amit a hívó fél (API endpoint) már lefordított
reason
```
### 3.4 Migrációs Terv (Ütemezés)
| Fázis | Feladat | Érintett fájlok | Logikai készültség |
|-------|---------|----------------|-------------------|
| **1. fázis** | Gamification i18n kulcsok felvétele a `frontend_admin/locales/*.json` fájlokba | 2 db | Előkészület |
| **2. fázis** | 12 Vue oldal átalakítása: `useI18n()` bevezetése, `t()` hívások | 12 db | Tervezés alatt |
| **3. fázis** | Backend i18n helper megírása (`app/core/i18n.py`) | 1 db | Tervezés alatt |
| **4. fázis** | Gamification kulcsok felvétele a `backend/static/locales/*.json` fájlokba | 2 db | Előkészület |
| **5. fázis** | Backend API endpointok átalakítása, hardcoded stringek eltávolítása | 1 db | Tervezés alatt |
| **6. fázis** | Kvíz tartalom kiszervezése JSON/DB-be, nyelvi kulcsokkal | 1 db | Tervezés alatt |
| **7. fázis** | Tesztelés: magyar és angol nyelvű felület ellenőrzése | - | Függőben |
---
## 4. Konklúzió
A gamification modulban **súlyos nyelvi modul hiányosság** áll fenn:
1. **A frontend admin felület 12 Vue oldalán 0% az i18n használat** - minden UI szöveg hardcoded magyar nyelven van.
2. **A lokációs fájlok egyetlen gamification kulcsot sem tartalmaznak** - a teljes gamification szótár hiányzik.
3. **A backend API vegyesen használ magyar és angol hardcoded szövegeket**.
4. **A kvíz rendszer teljes egészében hardcoded magyar nyelvű**.
5. **A meglévő i18n infrastruktúra (`@nuxtjs/i18n`) jól konfigurált** - csak a gamification modul nem használja.
A javítási javaslat 7 fázisban, körülbelül 15-20 fájl módosításával oldható meg.