6.4 KiB
🏗️ Logic Spec: Identity-Preserving Soft Delete & Asset Validation
1. Modul Célja és Masterbook 2 Illeszkedés
Mérföldkő: Identity & Security Hardening
Masterbook 2 Referencia: docs/v201/05_AUTH_AND_IDENTITY_SPEC.md (Soft Delete / Anonymization szekció)
Masterbook 2 Referencia: docs/v201/18_ASSET_AND_FLEET_SPECIFICATION.md (Asset specifikáció)
Jelenlegi állapot a Masterbook szerint:
- A Soft Delete már létezik, de hiányos: nincs
deleted_attimestamp, nincs token invalidáció, nem védi a Person rekordot. - Az Asset modellben nincs
CheckConstrainta VIN/Rendszám "Vagy-Vagy" szabályhoz. - A Pydantic sémákban nincs
model_validatora kötelező azonosító validációhoz.
2. Adatmodell változások
2.1 Asset CheckConstraint (backend/app/models/vehicle/asset.py)
Jelenlegi állapot: A Asset osztály __table_args__-ja csak a sémát adja meg:
__table_args__ = {"schema": "vehicle"}
Módosítás: Bővítsük ki a __table_args__-t egy CheckConstraint-tel:
__table_args__ = (
CheckConstraint(
"vin IS NOT NULL OR license_plate IS NOT NULL",
name="ck_asset_vin_or_plate_required"
),
{"schema": "vehicle"}
)
Import: A CheckConstraint már elérhető az SQLAlchemy importok között? Ellenőrizendő: jelenleg csak UniqueConstraint van importálva. Ki kell egészíteni:
from sqlalchemy import String, Boolean, DateTime, ForeignKey, Numeric, text, Text, UniqueConstraint, CheckConstraint, BigInteger, Integer, Float
2.2 deleted_at oszlop a User modellhez (backend/app/models/identity/identity.py)
Jelenlegi állapot: A User osztályban már van is_deleted: Mapped[bool] (149. sor), de hiányzik a deleted_at.
Módosítás: Add hozzá a deleted_at mezőt a User osztályhoz a created_at után:
# === SOFT DELETE ===
deleted_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
2.3 deleted_at oszlop a Person modellhez (opcionális, struktúra miatt)
Jelenlegi állapot: A Person osztályban nincs deleted_at.
Módosítás: Add hozzá a struktúra konzisztencia miatt:
# === SOFT DELETE (structure only - never delete Person data) ===
deleted_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
3. Pydantic Séma Módosítások
3.1 AssetCreate séma (backend/app/schemas/asset.py)
Jelenlegi állapot: A license_plate kötelező (Field(...)), a vin opcionális.
Módosítás: Mindkét mező legyen Optional[str] = None:
license_plate: Optional[str] = Field(None, min_length=2, max_length=20, description="Rendszám")
vin: Optional[str] = Field(None, min_length=1, max_length=50, description="VIN szám (opcionális)")
Validátor: Adj hozzá egy @model_validator (Pydantic V2 mód) vagy @root_validator (Pydantic V1 mód) metódust, ami:
- Üres string (
"") átalakításaNone-ra mindkét mezőnél - Ha mindkettő
None, dobjonValueError-t (422-es HTTP válasz)
3.2 AssetUpdate séma (backend/app/schemas/asset.py)
Jelenlegi állapot: A license_plate és vin már Optional[str] = None.
Módosítás: Adj hozzá egy @model_validator-t vagy @root_validator-t, ami csak akkor dob hibát, ha a felhasználó explicitly None-ra akarja állítani mindkettőt.
4. Backend Service Logika: Person-Preserving Soft Delete
4.1 AuthService.soft_delete_user módosítása (backend/app/services/auth_service.py)
Jelenlegi kód: soft_delete_user
Módosítások sorrendben:
-
deleted_atbeállítás:user.deleted_at = datetime.now(timezone.utc) -
E-mail átírás (már létezik, de pontosítva):
old_email = user.email timestamp = datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S') user.email = f"deleted_{user.id}_{timestamp}_{old_email}" -
Person rekord érintetlenül hagyása (CRITICAL - maradjon ahogy van, NE módosítsuk)
-
Token invalidáció: Töröljük az összes aktív Refresh Token-t
-
Naplózás bővítése
deleted_at-tal
5. API Végpont: DELETE /api/v1/users/me
5.1 Új endpoint (backend/app/api/v1/endpoints/users.py)
@router.delete("/me", status_code=200)
async def delete_my_account(
reason: Optional[str] = Body(None, description="Törlés oka (opcionális)"),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""
Saját fiók soft-delete.
- Anonimizálja az e-mail címet
- is_active = False, is_deleted = True, deleted_at = timestamp
- Person rekordot NEM bántja
- Érvényteleníti az összes refresh token-t
- Wallet és Gamification adatokat megőrzi (inaktív user miatt freeze)
"""
success = await AuthService.soft_delete_user(
db=db,
user_id=current_user.id,
reason=reason or "user_requested_self_delete",
actor_id=current_user.id
)
if not success:
raise HTTPException(
status_code=400,
detail="A felhasználó már törölve van."
)
return {"status": "ok", "message": "Fiók sikeresen törölve."}
6. Adatbázis Szinkronizáció
A módosítások után futtatni kell a sync_engine-t:
docker exec -it sf_api python -m app.scripts.sync_engine
7. Tesztterv
7.1 Asset validáció tesztelése
- Hozz létre járművet csak VIN-nel → sikeres
- Hozz létre járművet csak rendszámmal → sikeres
- Hozz létre járművet mindkettővel → sikeres
- Hozz létre járművet egyik nélkül sem → 422-es hiba
7.2 Soft Delete tesztelése
- Hozz létre usert, authentikálj
- DELETE
/api/v1/users/mehívás - Ellenőrizd:
User.is_deleted = True,User.is_active = False,User.deleted_atbeállítva - Ellenőrizd:
Personrekord adatai változatlanok,Person.is_activeváltozatlan - Ellenőrizd: Refresh token törölve (régi session nem működik)