# 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.