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,251 @@
# 🔧 Admin OOM Crash Fix & User Relations Repair — Code Mode Hand-off
**Author:** Architect Mode
**Date:** 2026-07-26
**Target Mode:** `code` (Fast Coder)
---
## 📊 Diagnosztikai Összefoglaló
### Issue 1: Admin Frontend OOM (`admin.servicefinder.hu` → 500)
**Jelenlegi állapot:**
- A [`sf_admin_frontend`](docker-compose.yml:281) konténer jelenleg FUT (742MiB RAM, 0.42%), az OOM korábban történt.
- A [`Dockerfile.dev`](frontend_admin/Dockerfile.dev:1) `node:20-slim`-et használ, a CMD `npm run dev` (Nuxt dev mode SSR + HMR).
- A [`docker-compose.yml`](docker-compose.yml:289) szekcióban **nincs** `NODE_OPTIONS` környezeti változó és **nincs** `deploy.resources.limits.memory` beállítva.
- A bot-scanner forgalom (`.env` probing) csak Vue Router warningokat generál, nem ez okozza az OOM-t.
**Root Cause:** A Nuxt 3 dev módban az SSR (Server-Side Rendering) + HMR (Hot Module Replacement) + a dashboard oldal API hívása (`/api/v1/admin/users/stats`) együtt képes kimeríteni a Node.js default heap limitjét (~2GB). A `node:20-slim` image-nek nincs explicit `--max-old-space-size` beállítása.
### Issue 2: User 86 Wallet Status & Missing User Relations
**User 86 (`zs.gyongyossy@gmail.com`) státusza:**
- Wallet: **RENDBEN**`identity.wallets` id=12, earned=0, purchased=0, service_coins=0, currency=HUF, org_id=45
- Subscription: **RENDBEN**`finance.user_subscriptions` id=9, tier_id=13 (`private_free_v1`), is_active=true
**6 aktív user-nek NINCS walletje és subscription-je:**
| ID | Email | Wallet | Subscription |
|----|-------|--------|-------------|
| **1** | `superadmin@profibot.hu` | ❌ MISSING | ❌ MISSING |
| 136 | `no_perm_1782770270_8c9970@test.com` | ❌ MISSING | ❌ MISSING |
| 138 | `no_perm_1782778366_243628@test.com` | ❌ MISSING | ❌ MISSING |
| 153 | `commission_test_gen2@test.com` | ❌ MISSING | ❌ MISSING |
| 154 | `commission_test_gen1@test.com` | ❌ MISSING | ❌ MISSING |
| 155 | `commission_test_buyer@test.com` | ❌ MISSING | ❌ MISSING |
**Végpont viselkedés:** [`get_wallet_summary`](backend/app/services/billing_engine.py:598) `ValueError`-t dob ha nincs wallet → a végpont 404-et ad. Ez helyes.
---
## 🛠️ Javítási Terv
### FIX-1: Admin Frontend Memory Limit
**Fájl:** [`docker-compose.yml`](docker-compose.yml:281-299)
**Módosítás — a `sf_admin_frontend` szekcióban:**
1. Az `environment` blokkhoz add hozzá:
```yaml
- NODE_OPTIONS=--max-old-space-size=4096
```
2. Adj hozzá egy `deploy` blokkot:
```yaml
deploy:
resources:
limits:
memory: 8G
```
**A módosított szekció:**
```yaml
sf_admin_frontend:
build:
context: ./frontend_admin
dockerfile: Dockerfile.dev
container_name: sf_admin_frontend
env_file: .env
ports:
- "8502:8502"
environment:
- NUXT_PORT=8502
- NUXT_HOST=0.0.0.0
- NUXT_PUBLIC_API_BASE_URL=https://dev.servicefinder.hu
- NODE_OPTIONS=--max-old-space-size=4096 # ← NEW
volumes:
- ./frontend_admin:/app
- /app/node_modules
networks:
- sf_net
- shared_db_net
restart: unless-stopped
deploy: # ← NEW
resources:
limits:
memory: 8G
```
**Futtatás:**
```bash
docker compose up -d --force-recreate sf_admin_frontend
docker compose logs --tail=20 sf_admin_frontend
```
---
### FIX-2: User Relations Repair Script
**Fájl létrehozása:** [`backend/scripts/repair_user_relations.py`](backend/scripts/repair_user_relations.py)
**Cél:** Minden `is_active = true` user számára biztosítja:
1. Personal Organization (`fleet.organizations`) — ha még nincs
2. Wallet (`identity.wallets`) — ha még nincs
3. User Subscription (`finance.user_subscriptions`, tier=private_free_v1) — ha még nincs
**Adatbázis séma referencia:**
| Tábla | Séma | Kulcs mezők |
|-------|------|-------------|
| `wallets` | `identity` | id (serial PK), user_id (FK), earned_credits, purchased_credits, service_coins, currency, organization_id |
| `user_subscriptions` | `finance` | id (serial PK), user_id (FK), tier_id (FK→system.subscription_tiers), valid_from, is_active |
| `organizations` | `fleet` | id (serial PK), name, full_name, display_name, folder_slug, owner_id (FK), org_type, status, is_active, ... |
**Alapértelmezett értékek:**
- **Wallet:** `earned_credits=0`, `purchased_credits=0`, `service_coins=0`, `currency='HUF'`
- **Subscription:** `tier_id=13` (`private_free_v1`), `valid_from=now()`, `is_active=true`
- **Organization:** `name="{user.email}'s Garage"`, `org_type='individual'`, `status='active'`, `owner_id=user.id`
**Script pszeudokód:**
```python
#!/usr/bin/env python3
"""
User Relations Repair Script — Idempotens: csak hiányzó rekordokat hoz létre.
Futtatás: docker compose exec sf_api python3 /app/backend/scripts/repair_user_relations.py
"""
import asyncio, sys
sys.path.insert(0, '/app')
sys.path.insert(0, '/app/backend')
from app.core.database import async_session_factory
from sqlalchemy import select
from app.models.identity import User, Wallet
from app.models.finance import UserSubscription
from app.models.fleet import Organization
from datetime import datetime, timezone
from decimal import Decimal
DEFAULT_TIER_ID = 13
DEFAULT_CURRENCY = "HUF"
async def ensure_organization(db, user):
result = await db.execute(select(Organization).where(Organization.owner_id == user.id))
org = result.scalar_one_or_none()
if org:
return org.id
folder_slug = f"user-{user.id}-{int(datetime.now(timezone.utc).timestamp())}"
org = Organization(
name=f"{user.email}'s Garage", full_name=f"{user.email}'s Personal Garage",
display_name=f"{user.email}'s Garage", folder_slug=folder_slug,
owner_id=user.id, org_type="individual", status="active",
is_active=True, is_deleted=False, subscription_plan="FREE",
base_asset_limit=5, purchased_extra_slots=0,
notification_settings={}, external_integration_config={},
is_verified=False, first_registered_at=datetime.now(timezone.utc),
current_lifecycle_started_at=datetime.now(timezone.utc),
lifecycle_index=1, is_anonymized=False, default_currency="HUF",
country_code="HU", language="hu", is_ownership_transferable=False,
visual_settings={}, is_affiliate_partner=False, aliases=[],
tags=[], settings={}, custom_features={},
)
db.add(org)
await db.flush()
return org.id
async def ensure_wallet(db, user, org_id):
result = await db.execute(select(Wallet).where(Wallet.user_id == user.id))
if result.scalar_one_or_none():
return False
wallet = Wallet(user_id=user.id, earned_credits=Decimal('0'),
purchased_credits=Decimal('0'), service_coins=Decimal('0'),
currency=DEFAULT_CURRENCY, organization_id=org_id)
db.add(wallet)
await db.flush()
return True
async def ensure_subscription(db, user):
result = await db.execute(select(UserSubscription).where(UserSubscription.user_id == user.id))
if result.scalar_one_or_none():
return False
sub = UserSubscription(user_id=user.id, tier_id=DEFAULT_TIER_ID,
valid_from=datetime.now(timezone.utc), is_active=True)
db.add(sub)
await db.flush()
return True
async def repair_all_users():
async with async_session_factory() as db:
result = await db.execute(select(User).where(User.is_active == True))
users = result.scalars().all()
stats = {"total": len(users), "wallets_created": 0, "subs_created": 0, "errors": []}
for user in users:
try:
org_id = await ensure_organization(db, user)
if await ensure_wallet(db, user, org_id):
stats["wallets_created"] += 1
if await ensure_subscription(db, user):
stats["subs_created"] += 1
except Exception as e:
stats["errors"].append(f"User {user.id}: {e}")
await db.commit()
print(f"=== REPAIR: total={stats['total']} wallets_new={stats['wallets_created']} subs_new={stats['subs_created']} errors={len(stats['errors'])}")
for e in stats["errors"]: print(f" ERR: {e}")
if __name__ == "__main__":
asyncio.run(repair_all_users())
```
**Futtatás:**
```bash
docker compose exec sf_api python3 /app/backend/scripts/repair_user_relations.py
```
**Ellenőrzés:**
```sql
SELECT u.id, u.email, w.id as wallet_id, s.id as sub_id
FROM identity.users u
LEFT JOIN identity.wallets w ON u.id = w.user_id
LEFT JOIN finance.user_subscriptions s ON u.id = s.user_id
WHERE u.id IN (1, 136, 138, 153, 154, 155);
```
---
### FIX-3 (OPTIONAL): get_wallet_summary Auto-Create
**Architect döntés:** **NEM módosítjuk.** A 404 helyes válasz. A repair script után a probléma megszűnik. A wallet auto-create a regisztrációs flow-ban garantálandó — külön feladat.
---
## 📋 Végrehajtási Sorrend (Code Mode)
| # | Feladat | Fájl | Parancs |
|---|---------|------|---------|
| 1 | `NODE_OPTIONS` + memory limit | [`docker-compose.yml`](docker-compose.yml:289) | Szerkesztés |
| 2 | Admin restart | — | `docker compose up -d --force-recreate sf_admin_frontend` |
| 3 | Repair script létrehozása | [`backend/scripts/repair_user_relations.py`](backend/scripts/repair_user_relations.py) | Fájl létrehozása |
| 4 | Repair script futtatása | — | `docker compose exec sf_api python3 /app/backend/scripts/repair_user_relations.py` |
| 5 | SQL ellenőrzés | — | MCP Postgres query |
| 6 | Böngésző ellenőrzés | — | `https://admin.servicefinder.hu/` |
---
## ⚠️ Kockázatok
1. **superadmin (ID=1):** Lehet hogy szándékosan nincs walletje. Ha nem kívánatos, skip-elni kell ID=1-et a scriptben.
2. **Organization folder_slug:** Egyedi kell legyen. A `user-{id}-{timestamp}` minta garantálja.
3. **Tier ID=13:** Ellenőrizve — létezik `system.subscription_tiers`-ben, `tier_level=0`.
4. **Docker restart:** ~30-60 másodperc downtime a Nuxt újraépítése miatt.
5. **A repair script IDEMPOTENS:** Többször futtatható, nem duplikál.