arc/docs/BUSINESS_BACKUP_FINANCIAL_SECURITY.md
2026-05-21 16:03:45 +03:30

4.9 KiB
Raw Permalink Blame History

امنیت مالی بکاپ کسب‌وکار (.hbx)

فازبندی پیاده‌سازی

فاز وضعیت محتوا
P0 انجام شد حذف جداول کیف‌پول از export/import؛ صفر کردن مانده پس از restore
P1 انجام شد حذف entitlementها؛ اعتبارسنجی مالک؛ ثبت checksum؛ قفل همزمانی
P1+ انجام شد ai_voice_interactions؛ رد بکاپ بدون مالک؛ BACKUP_LEGACY_NOT_ALLOWED
P2 آینده دفتر اعتبار متمرکز در سطح کاربر (ledger)

جداول مستثنی از بکاپ tenant

تعریف در app/services/business_backup_financial_policy.py:

  • wallet_*
  • user_ai_subscriptions, ai_usage_logs, ai_invoices, ai_chat_sessions, ai_voice_interactions
  • business_storage_subscriptions, storage_invoices, storage_usage_transactions
  • business_plugins, marketplace_orders, marketplace_invoices

metadata بکاپ جدید (schema_version: v1.2)

  • financial_data_excluded: true
  • owner_id: مالک کسب‌وکار مبدأ (الزامی در export جدید)
  • excluded_tables: لیست جداول حذف‌شده
  • table_schemas: snapshot نام ستون‌های هر جدول در زمان export (سازگاری import بین نسخه‌ها)

سازگاری اسکیمای دیتابیس (restore/import)

پیاده‌سازی در app/services/business_backup_schema_compat.py — بدون لیست سخت‌کد per-table:

مکانیزم توضیح
introspection SQLAlchemy inspector + information_schema.columns (nullable، column_default)
TableRestorePlan برای هر ستون: from_backup / omit_use_db_default / fill_parsed_default / fill_type_inference
table_schemas union کلیدهای همهٔ ردیف‌ها در export؛ در import با اسکیمای فعلی diff می‌شود
sanitize حذف ستون‌های حذف‌شده از DB از ردیف بکاپ
validate هشدار NULL در ستون NOT NULL یا کلیدهای نامعتبر (لاگ)

بکاپ‌های قدیمی: اسکن تا ۲۰۰ ردیف اول هر jsonl برای کشف union ستون‌ها.

اتمی بودن restore/import

مسیر اتمی؟ توضیح
POST .../backups/restore بله یک get_db_session؛ create_business(defer_commit=True)؛ بدون commit میانی؛ در خطا rollback
POST /businesses/import-from-backup بله (پس از اصلاح) همان الگو؛ قبلاً commit پس از هر جدول داشت و نیمه‌کاره می‌ماند

خارج از تراکنش: وضعیت Job (job_id)، فایل آپلودشده. پس از rollback، ردیف کسب‌وکار و داده‌های tenant در DB باقی نمی‌مانند.

پاک‌سازی کسب‌وکارهای یتیم (import نیمه‌کارهٔ قدیمی)

اسکریپت سیستمی: cleanup_orphan_backup_businesses در مدیریت سیستم → اسکریپت‌ها (/api/v1/admin/scripts).

معیار پیش‌فرض
ثبت‌نشده در business_backup_import_logs بله
نام حاوی «بازیابی شده» بله
داده tenant خالی (سند/شخص/کالا = ۰) اختیاری (include_empty_shell)
حداقل سن ۱ ساعت (min_age_hours)

CLI: hesabixAPI/scripts/cleanup_orphan_backup_businesses.py --dry-run سپس --execute.

اعتبارسنجی مالک

ترتیب استخراج owner_id:

  1. metadata.owner_id
  2. tables/businesses.jsonl → فیلد owner_id
  3. ردیف زنده businesses در DB با metadata.business_id

اگر هیچ‌کدام نبود → BACKUP_LEGACY_NOT_ALLOWED (400).

اگر مالک ≠ کاربر importکننده → BACKUP_OWNER_MISMATCH (403).

ضد تکرار import (new_business)

  1. pg_advisory_xact_lock روی (user_id, checksum) در همان تراکنش
  2. بررسی business_backup_import_logs
  3. در ثبت نهایی: IntegrityError → BACKUP_ALREADY_IMPORTED

migration

20260621_000001_business_backup_import_security — جدول business_backup_import_logs.

cd hesabixAPI && alembic upgrade head

خطاهای API

کد معنی
BACKUP_OWNER_MISMATCH فایل متعلق به کاربر دیگر
BACKUP_ALREADY_IMPORTED همان فایل قبلاً برای new_business استفاده شده
BACKUP_LEGACY_NOT_ALLOWED بکاپ قدیمی بدون مالک قابل تشخیص

بکاپ‌های قدیمی (v1)

  • wallet و entitlementها restore نمی‌شوند و در پایان پاک/صفر می‌شوند.
  • import فقط اگر owner_id از ردیف businesses بکاپ یا DB قابل استخراج باشد.