felhasználói felületre pü

This commit is contained in:
Roo
2026-07-27 08:39:18 +00:00
parent c9118bf52f
commit 6f28d3e70d
72 changed files with 6311 additions and 749 deletions

View File

@@ -0,0 +1,149 @@
# P0 Bug #420: `GET /api/v1/billing/wallet/balance` - 500 Internal Server Error
**Dátum:** 2026-07-26
**Súlyosság:** P0 - Blokkoló (minden wallet/balance hívást érint)
**Státusz:** Megoldva (pycache purge + restart)
---
## 1. Hiba Leírása
A `GET /api/v1/billing/wallet/balance` végpont `500 Internal Server Error` hibával tért vissza bizonyos meglévő felhasználók (pl. user_id=86, 28) esetén.
### Hibaüzenet a logból:
```
2026-07-26 12:37:49,388 [ERROR] app.api.v1.endpoints.billing: Pénztárca egyenleg lekérdezési hiba: 'FinancialLedger' object has no attribute 'description'
```
### Érintett fájlok:
- [`backend/app/models/system/audit.py:78`](backend/app/models/system/audit.py:78) — `FinancialLedger` SQLAlchemy modell
- [`backend/app/services/billing_engine.py:1078`](backend/app/services/billing_engine.py:1078) — `get_user_balance()`
- [`backend/app/services/billing_engine.py:598`](backend/app/services/billing_engine.py:598) — `get_wallet_summary()`
- [`backend/app/api/v1/endpoints/billing.py:298`](backend/app/api/v1/endpoints/billing.py:298) — `get_wallet_balance()` endpoint
---
## 2. Root Cause Analysis
### 2.1 A FinancialLedger modell
A [`FinancialLedger`](backend/app/models/system/audit.py:78) modell **NEM rendelkezik `description` oszloppal**. Az egyetlen "leíró" mező a `details` (JSONB). A modell oszlopai:
```
id, user_id, person_id, amount, currency, transaction_type,
related_agent_id, details, created_at, entry_type, balance_after,
wallet_type, issuer_id, invoice_status, tax_amount, gross_amount,
net_amount, transaction_id, status
```
### 2.2 A jelenlegi forráskód helyes
A [`billing_engine.py`](backend/app/services/billing_engine.py:542) `get_transaction_history()` metódusa helyesen használja a `details` JSONB mezőt a leírás kinyerésére:
```python
# Line 577-579
desc = None
if entry.details and isinstance(entry.details, dict):
desc = entry.details.get("description") or entry.details.get("desc") or None
```
A [`billing.py`](backend/app/api/v1/endpoints/billing.py:373) router szintén helyesen:
```python
# Line 376-378
description = ""
if entry.details and isinstance(entry.details, dict):
description = entry.details.get("description", "")
```
### 2.3 A tényleges ok: Stale Python Bytecode Cache
Az MD5 ellenőrzés igazolta, hogy a konténerben futó forráskód és a host-on lévő forráskód **azonos**:
| Fájl | MD5 |
|------|-----|
| `billing.py` (host & container) | `6b00968c129376e3db630e266835261b` |
| `billing_engine.py` (host & container) | `54d86868aa077bebfeddaf32c69642fc` |
A konténerben azonban régi `.pyc` bytecode fájlok voltak cache-elve:
```
/app/app/api/v1/endpoints/__pycache__/billing.cpython-312.pyc
/app/app/services/__pycache__/billing_engine.cpython-312.pyc
```
Ezek a `.pyc` fájlok egy **korábbi forráskód-verzióhoz** tartoztak, ahol még létezett `entry.description` hivatkozás a `FinancialLedger` objektumokon (vagy egy másik séma érvényben volt).
### 2.4 Miért nem frissültek a .pyc fájlok?
A `docker-compose.yml`-ben a `sf_api` konténer forráskódja volume mount-tal van csatolva (nem COPY). Amikor a forráskód változik a host-on, a Python értelmező a konténerben azonnal látja az új `.py` fájlokat, de a már legenerált `.pyc` cache fájlok megmaradnak. Ha a `.py` fájl timestamp-je régebbi, mint a `.pyc`-é (vagy a Python nem érzékeli a változást), a régi bytecode fut.
---
## 3. Megoldás
### Végrehajtott lépések:
1. **Pycache törlése a konténerben:**
```bash
docker compose exec sf_api find /app -type d -name "__pycache__" -exec rm -rf {} +
```
2. **Konténer újraindítása:**
```bash
docker compose restart sf_api
```
3. **Verifikáció:** A restart után az endpoint már NEM dob 500-as hibát. A logokban nem jelenik meg több `description` hiba.
---
## 4. Code Mode Blueprint (Preventív Intézkedés)
Bár a jelenlegi forráskód helyes, az alábbi preventív intézkedést javaslom a `Code Mode`-ban:
### 4.1 Docker Compose: pycache purge a startup előtt
A `docker-compose.yml` `sf_api` szolgáltatás `command` sorában futtassunk egy automatikus pycache purge-öt a Uvicorn indítása előtt:
```yaml
command: >
/bin/sh -c "
find /app -type d -name '__pycache__' -exec rm -rf {} + 2>/dev/null;
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
"
```
### 4.2 Opcionális: `.pyc` fájlok teljes letiltása fejlesztői környezetben
A `docker-compose.yml` environment változói közé:
```yaml
environment:
- PYTHONDONTWRITEBYTECODE=1
```
Ez megakadályozza, hogy a Python egyáltalán `.pyc` fájlokat generáljon, így mindig a forráskódból fog futni.
---
## 5. Függelék: Mermaid Folyamatábra
```mermaid
sequenceDiagram
participant Client
participant FastAPI as billing.py router
participant BillingEngine as billing_engine.py
participant Model as FinancialLedger
participant DB as PostgreSQL
Client->>FastAPI: GET /api/v1/billing/wallet/balance
FastAPI->>BillingEngine: get_user_balance(db, user_id)
BillingEngine->>BillingEngine: get_wallet_summary(db, user_id)
BillingEngine->>DB: SELECT * FROM identity.wallets WHERE user_id=?
BillingEngine->>DB: SELECT * FROM audit.financial_ledger LIMIT 10
BillingEngine->>Model: entry.details.get("description")
Note over Model: Helyes: details JSONB mezőből olvas
Model-->>BillingEngine: description string
BillingEngine-->>FastAPI: {"earned": X, "purchased": Y, ...}
FastAPI-->>Client: 200 OK + JSON balances
```
**A hiba idején** a `.pyc` bytecode `entry.description`-t próbált elérni, ami nem létező attribútum a `FinancialLedger` modellen. Ez `AttributeError`-t okozott, amit a `billing.py` router `except Exception` ága elkapott és 500-ra fordított.