pénzügyi modul továbbfejlesztése (csomagkezelés)
This commit is contained in:
119
docs/subscription_info_modal_planDisplayName_bug_analysis.md
Normal file
119
docs/subscription_info_modal_planDisplayName_bug_analysis.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# SubscriptionInfoModal planDisplayName Bug Analysis
|
||||
|
||||
**Date:** 2026-07-28
|
||||
**Issue:** #433 - P0: Avatar Menu Subscription Modal - planDisplayName bugfix & DB audit
|
||||
|
||||
---
|
||||
|
||||
## 1. Database Investigation: admin@profibot.hu
|
||||
|
||||
### User Profile
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| `id` | 2 |
|
||||
| `email` | admin@profibot.hu |
|
||||
| `role` | ADMIN |
|
||||
| `subscription_plan` | private_vip_v1 |
|
||||
| `subscription_expires_at` | 2026-08-27 16:36:24+00 |
|
||||
| `is_vip` | true |
|
||||
| `scope_level` | system |
|
||||
| `scope_id` | 67 |
|
||||
| `ui_mode` | personal |
|
||||
|
||||
### Organization Memberships (3 orgs)
|
||||
| org_id | role | name | type | status | base_asset_limit |
|
||||
|--------|------|------|------|--------|-------------------|
|
||||
| 1 | ADMIN | Profibot Tester - Privat Garazs (#28) | individual | active | 100 |
|
||||
| 67 | OWNER | User Admin - Privat Garazs (#2) | individual | active | 100 |
|
||||
| 57 | OWNER | Teszt Autoszerviz Kft. | service_provider | pending_verification | 3 |
|
||||
|
||||
### Vehicle Distribution (vehicle.assets via current_organization_id)
|
||||
| org_id | Count | Sample plates |
|
||||
|--------|-------|---------------|
|
||||
| 1 | 19 | TEST-API-999, TEST-123, DRAFT-456, TEST-999, DRAFT-999, TEST-888, DRAFT-888, TEST-777 |
|
||||
| 67 | 3 | TEST-API-01 (archived), ABB112 (archived), ABC-123 (archived) |
|
||||
| 57 | 0 | No vehicles |
|
||||
|
||||
### Key Finding: No Duplication, No Data Corruption
|
||||
Vehicles are NOT duplicated across organizations. Each org has distinct vehicles. The perception of "azonos adatok" (same data) likely arises because:
|
||||
- Org 1 has 19 test vehicles (TEST-XXX, DRAFT-XXX pattern) making it appear bloated
|
||||
- Org 67 has only 3 archived vehicles
|
||||
- The KEP 3 showing "private_pro_v1" is the UI bug, not a data issue (admin's actual plan is private_vip_v1)
|
||||
|
||||
---
|
||||
|
||||
## 2. Root Cause: planDisplayName in SubscriptionInfoModal.vue
|
||||
|
||||
### Bug Location
|
||||
`SubscriptionInfoModal.vue:175-179` — the `planDisplayName` computed property:
|
||||
|
||||
```typescript
|
||||
const planDisplayName = computed(() => {
|
||||
const plan = authStore.user?.subscription_plan
|
||||
if (!plan || plan === 'FREE') return t('subscription.free')
|
||||
return plan // BUG: returns raw slug like "private_vip_v1"
|
||||
})
|
||||
```
|
||||
|
||||
### Why It's Broken
|
||||
The backend `_resolve_subscription_data()` in `users.py:45-191` already:
|
||||
1. Queries the `SubscriptionTier` assigned to the user/org
|
||||
2. Extracts `display_name` from `tier.rules` JSONB
|
||||
3. Returns it as `subscription_display_name` in `/auth/me` and `/users/me`
|
||||
|
||||
The `UserProfile` TypeScript interface in `auth.ts:68` already declares:
|
||||
```typescript
|
||||
subscription_display_name?: string | null
|
||||
```
|
||||
|
||||
The `SubscriptionInfoModal` ignores this field completely.
|
||||
|
||||
### Reference Fix (Already Implemented in SubscriptionStatusWidget)
|
||||
`SubscriptionStatusWidget.vue:124-150` has the correct 3-level fallback:
|
||||
1. `authStore.user?.subscription_display_name` (backend-resolved human name)
|
||||
2. Org-level `subscription_display_name` (corporate mode)
|
||||
3. Static slug-to-human mapping (fallback)
|
||||
4. Raw plan name (ultimate fallback)
|
||||
|
||||
### Additional Data Binding Verification
|
||||
|
||||
| Computed | Current Code | Status |
|
||||
|----------|-------------|--------|
|
||||
| maxVehicles | `authStore.user?.max_vehicles ?? 1` | CORRECT |
|
||||
| maxGarages | `authStore.user?.max_garages ?? 1` | CORRECT |
|
||||
| vehicleCount | `vehicleStore.vehicles.length` | CORRECT |
|
||||
| garageCount | `authStore.myOrganizations?.length ?? 0` | Context-dependent |
|
||||
| vehiclePercent/garagePercent | `count / max * 100` | CORRECT |
|
||||
|
||||
---
|
||||
|
||||
## 3. Fix Specification
|
||||
|
||||
### Required Change
|
||||
Replace `planDisplayName` computed in `SubscriptionInfoModal.vue:175-179` with the same 3-level fallback logic used by `SubscriptionStatusWidget.vue:124-150`.
|
||||
|
||||
### New Code
|
||||
```typescript
|
||||
const planDisplayName = computed(() => {
|
||||
// Priority 1: Backend-supplied human-readable name
|
||||
const displayName = authStore.user?.subscription_display_name
|
||||
if (displayName) return displayName
|
||||
|
||||
// Priority 2: Slug-to-human mapping fallback
|
||||
const plan = authStore.user?.subscription_plan
|
||||
if (!plan || plan === 'FREE') return t('subscription.free')
|
||||
|
||||
const slugToHuman: Record<string, string> = {
|
||||
'private_basic_v1': 'Privat Alap',
|
||||
'private_pro_v1': 'Privat Pro',
|
||||
'private_vip_v1': 'Privat VIP',
|
||||
'corp_free_v1': 'Ceges Ingyenes',
|
||||
'corp_basic_v1': 'Ceges Alap',
|
||||
'corp_pro_v1': 'Ceges Pro',
|
||||
}
|
||||
if (slugToHuman[plan]) return slugToHuman[plan]
|
||||
|
||||
// Priority 3: Raw plan name as ultimate fallback
|
||||
return plan
|
||||
})
|
||||
```
|
||||
Reference in New Issue
Block a user