143 lines
5.7 KiB
Markdown
143 lines
5.7 KiB
Markdown
# 🔍 Subscription Limit Data Binding Bug — Root Cause Analysis
|
||
|
||
**Dátum:** 2026-07-28
|
||
**Issue:** #431 (Gitea)
|
||
**Súlyosság:** P1 — A felhasználó rossz limiteket lát a frontenden
|
||
|
||
---
|
||
|
||
## 1. A Felhasználó Által Jelentett Hiba
|
||
|
||
A frontend "Előfizetés Információ" modális ablakon (SubscriptionStatusWidget) és a FinanceMainView Card 2-n a következő látszik:
|
||
- **Jármű Limit:** 1/1
|
||
- **Garázs Limit:** 2/1
|
||
|
||
Egy Pro/VIP csomag esetén a valós limit `max_vehicles=3` (Pro) vagy `max_vehicles=10` (VIP) lenne.
|
||
|
||
---
|
||
|
||
## 2. Adatbázis Réteg — Valós Állapot
|
||
|
||
| Tábla | Rekord | Kulcs mező | Érték |
|
||
|---|---|---|---|
|
||
| `identity.users` | id=2 (admin@profibot.hu) | `subscription_plan` | `private_vip_v1` |
|
||
| `identity.users` | id=2 | `scope_id` | `67` |
|
||
| `identity.users` | id=2 | `scope_level` | `system` |
|
||
| `identity.users` | id=2 | `ui_mode` | `personal` |
|
||
| `finance.user_subscriptions` | id=34 | `tier_id` | **15** (VIP) ✅ AKTÍV |
|
||
| `finance.user_subscriptions` | id=33 | `tier_id` | 14 (Pro) ❌ inaktív |
|
||
| `finance.org_subscriptions` | org_id=67 | — | **NINCS REKORD** |
|
||
| `system.subscription_tiers` | id=14 (private_pro_v1) | `allowances.max_vehicles` | 3 |
|
||
| `system.subscription_tiers` | id=14 | `allowances.max_garages` | 1 |
|
||
| `system.subscription_tiers` | id=14 | `display_name` | **NULL** ❌ |
|
||
| `system.subscription_tiers` | id=15 (private_vip_v1) | `allowances.max_vehicles` | 10 |
|
||
| `system.subscription_tiers` | id=15 | `allowances.max_garages` | 2 |
|
||
| `system.subscription_tiers` | id=15 | `display_name` | "Privát VIP" ✅ |
|
||
|
||
---
|
||
|
||
## 3. ROOT CAUSE #1 (Elsődleges) — Hibás Vezérlési Logika
|
||
|
||
**Fájl:** [`backend/app/api/v1/endpoints/users.py`](backend/app/api/v1/endpoints/users.py), `read_users_me()` függvény, sorok 212–254.
|
||
|
||
### A problémás kódszakasz (pszeudokód):
|
||
|
||
```python
|
||
if active_org_id is not None: # ← scope_id=67 → active_org_id=67 → IGAZ
|
||
# 1. Org subscription keresés
|
||
tier = org_sub_query(scalar_one_or_none)
|
||
if tier and tier.rules: # ← NINCS org subscription (üres finance.org_subscriptions org_id=67-re)
|
||
allowances = tier.rules.get("allowances", {})
|
||
max_vehicles = int(allowances.get("max_vehicles", 1))
|
||
max_garages = int(allowances.get("max_garages", 1))
|
||
else:
|
||
# 2. Fallback: Organization.base_asset_limit
|
||
org = select(Organization).where(id == active_org_id)
|
||
max_vehicles = org.base_asset_limit or 1 # ← 1-et ad!
|
||
max_garages = 1 # ← 1-et ad!
|
||
# ❌ HIBA: Soha nem nézi meg a user_subscriptions táblát!
|
||
else:
|
||
# 3. Personal mode: user subscription keresés
|
||
# ← SOHA NEM FUT LE, mert active_org_id != None
|
||
tier = user_sub_query(scalar_one_or_none)
|
||
if tier and tier.rules:
|
||
allowances = tier.rules.get("allowances", {})
|
||
max_vehicles = int(allowances.get("max_vehicles", 1)) # ← 10 lenne!
|
||
max_garages = int(allowances.get("max_garages", 1)) # ← 2 lenne!
|
||
```
|
||
|
||
### Miért hibás?
|
||
|
||
A user-nek van `scope_id=67`-e (egy szervezet ID), de az adott szervezethez **nincs org subscription** rekord. A felhasználónak viszont van **aktív user subscription**-e a VIP tier-re (tier_id=15, max_vehicles=10, max_garages=2).
|
||
|
||
A kód hibásan feltételezi, hogy ha van `active_org_id`, akkor:
|
||
1. vagy van org subscription (→ abból olvassa a limiteket),
|
||
2. vagy nincs (→ `Organization.base_asset_limit` fallback, ami 1).
|
||
|
||
**Soha nem esik át a user subscription ágra**, mert `active_org_id is not None`.
|
||
|
||
### Hatás
|
||
|
||
A `GET /auth/me` válaszban:
|
||
```json
|
||
{
|
||
"max_vehicles": 1, // ← 10 helyett
|
||
"max_garages": 1, // ← 2 helyett
|
||
"subscription_display_name": null // ← mert a tier változó None
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. ROOT CAUSE #2 (Másodlagos) — private_pro_v1 display_name NULL
|
||
|
||
**Tábla:** `system.subscription_tiers` id=14
|
||
**Mező:** `rules->>'display_name'` = NULL
|
||
|
||
A seederben (`seed_packages.py:131`) a `display_name` "Privát Pro"-ként van definiálva, de az éles adatbázisban NULL. Valószínűleg egy korábbi migráció vagy kézi módosítás írta felül.
|
||
|
||
Ez jelenleg nem okoz közvetlen hibát a felhasználónál (mert ő VIP-n van), de a Pro csomagra váltó felhasználóknál a display_name üres lenne.
|
||
|
||
---
|
||
|
||
## 5. Javítási Terv
|
||
|
||
### 5.1 Backend Fix (`users.py`)
|
||
|
||
A `read_users_me()` függvényben a fallback láncot ki kell egészíteni:
|
||
|
||
```
|
||
if active_org_id is not None:
|
||
1. Org subscription keresés (MEGLÉVŐ)
|
||
2. Ha nincs → User subscription keresés (ÚJ!)
|
||
3. Ha user subscription sincs → Organization.base_asset_limit (MEGLÉVŐ fallback)
|
||
else:
|
||
4. User subscription keresés (MEGLÉVŐ)
|
||
```
|
||
|
||
Ugyanez a logika kell a `subscription_valid_until` / `subscription_tier_id` feloldására is (sorok 267–308), valamint a `subscription_display_name` feloldására (sor 311–312).
|
||
|
||
### 5.2 DB Fix
|
||
|
||
```sql
|
||
UPDATE system.subscription_tiers
|
||
SET rules = jsonb_set(rules, '{display_name}', '"Privát Pro"')
|
||
WHERE id = 14 AND rules->>'display_name' IS NULL;
|
||
```
|
||
|
||
### 5.3 Frontend
|
||
|
||
A frontend komponensek (`FinanceMainView.vue`, `SubscriptionStatusWidget.vue`) már helyesen olvassák az `authStore.user?.max_vehicles` és `authStore.user?.max_garages` értékeket. A backend fix után automatikusan a helyes értékek jelennek meg.
|
||
|
||
---
|
||
|
||
## 6. Érintett Fájlok
|
||
|
||
| Fájl | Változtatás |
|
||
|---|---|
|
||
| `backend/app/api/v1/endpoints/users.py` | `read_users_me()`: fallback lánc javítása |
|
||
| Adatbázis (SQL) | `private_pro_v1` display_name beállítása |
|
||
| `frontend_app/src/views/FinanceMainView.vue` | Nincs változtatás szükséges (már a helyes mezőket olvassa) |
|
||
| `frontend_app/src/components/dashboard/SubscriptionStatusWidget.vue` | Nincs változtatás szükséges |
|
||
|