14 KiB
14 KiB
سناریوی پشتیبانگیری و بازیابی جامع کسبوکار (با فایلهای الصاقی)
این سند حاصل بررسی پروژه است و فقط سناریو را شرح میدهد؛ در این مرحله تغییری در کد اعمال نشده است.
۱. وضعیت فعلی پروژه
۱.۱ خروجی اکسل (پشتیبان فعلی کسبوکار)
- مسیر:
BackupController::createBackup→ API:POST /api/backup/create - خروجی: یک فایل Excel با چندین شیت:
- اطلاعات کسب و کار، اشخاص، کالاها، حسابهای بانکی
- اسناد حسابداری، جدول حسابها، تراکنشها (HesabdariRow)
- فاکتورهای فروش/خرید، برگشت از خرید/فروش، دریافت/پرداخت اشخاص
- انبارها
- محدودیتها:
- هیچ فایل الصاقی (تصویر، PDF، سند اسکن و …) در این خروجی نیست.
- هیچ قابلیت بازیابی (Restore) از همین فایل اکسل در سیستم وجود ندارد؛ فقط برای مشاهده/گزارش است.
- وابسته به افزونه accpro است.
۱.۲ پشتیبان دیتابیس (سیستم)
- مسیر:
DatabaseController→ APIهای admin برای backup/upload به FTP - خروجی: فایل
.sqlباmysqldumpبرای کل دیتابیس (همه کسبوکارها). - محدودیتها:
- سطح سیستم/ادمین است، نه سطح یک کسبوکار.
- فایلهای داخل
hesabixArchiveرا شامل نمیشود.
۱.۳ محل و نوع فایلهای الصاقی
| منبع | Entity / محل ذخیره | مسیر فیزیکی (نسبت به hesabixArchive) |
|---|---|---|
| الصاق به حواله انبار | ArchiveFile (cat: storeroom_ticket) |
storage/{bid}/storeroom_attachments/ |
| اسناد پرونده واردات | ImportWorkflowDocument.filePath |
storage/{bid}/import_docs/ |
| آواتار و مهر کسبوکار | Business.avatar, Business.sealFile |
avatars/, seal/ |
- سرویس FileStorage همه فایلهای کسبوکار را زیر
hesabixArchive/storage/{businessId}/{context}ذخیره میکند. - رکوردهای ArchiveFile با فیلدهای
bid,filename(مسیر نسبی),relatedDocType,relatedDocCodeبه اسناد (مثلاً حواله) وصل میشوند.
نتیجه: برای پشتیبان کامل یک کسبوکار، علاوه بر دادههای دیتابیس، باید تمام فایلهای زیر برای همان bid هم در آرشیو قرار بگیرند:
storage/{bid}/- در صورت وجود:
avatars/{avatar}وseal/{sealFile}مربوط به همان کسبوکار
۲. اهداف راهکار پیشنهادی
- یک فایل آرشیو واحد برای هر کسبوکار که شامل:
- دادههای دیتابیس مربوط به همان کسبوکار، و
- همه فایلهای الصاقی (انبار، پرونده واردات، آواتار، مهر) باشد.
- بازیابی در دو حالت:
- بازگردانی در کسبوکار جدید: ایجاد یا انتخاب یک کسبوکار خالی و بارگذاری آرشیو روی آن.
- بازنویسی روی کسبوکار فعلی: جایگزینی کامل دادهها و فایلهای همان کسبوکار با محتوای آرشیو (با تأیید صریح کاربر).
۳. محتوای پیشنهادی فایل آرشیو
فرمت پیشنهادی: یک فایل ZIP با ساختار ثابت تا نسخههای بعدی قابل توسعه باشند.
BusinessBackup_{businessName}_{YYYY-MM-DD_HH-mm}.zip
├── manifest.json # نسخه فرمت، شناسه و نام کسبوکار مبدأ، تاریخ، لیست بخشها
├── data/
│ ├── business.json # یک رکورد Business (بدون وابستگی به User/سایر جداول)
│ ├── entities/ # هر entity به صورت JSON (یا یک فایل تکی با آرایهها)
│ │ ├── persons.json
│ │ ├── commodities.json
│ │ ├── bank_accounts.json
│ │ ├── hesabdari_table.json
│ │ ├── hesabdari_docs.json
│ │ ├── hesabdari_rows.json
│ │ ├── years.json
│ │ ├── storerooms.json
│ │ ├── storeroom_tickets.json
│ │ ├── storeroom_items.json
│ │ ├── archive_files.json # متادیتای فایلهای آرشیو (برای نگاشت مسیر بعد از بازیابی)
│ │ ├── import_workflows.json
│ │ ├── import_workflow_documents.json
│ │ ├── ... (سایر entityهای وابسته به bid)
│ └── registry.json # رکوردهای Registry که root = شناسه همان کسبوکار
└── files/
└── storage/
└── {bid}/ # همان ساختار فعلی: storeroom_attachments/, import_docs/, ...
├── storeroom_attachments/
│ └── ...
└── import_docs/
└── ...
└── avatars/ # در صورت استفاده: فایل آواتار این کسبوکار
└── {filename}
└── seal/
└── {filename}
- manifest.json حداقل شامل:
version,sourceBusinessId,sourceBusinessName,exportedAt,dataFormatVersion, و در آینده میتوانchecksumsیا لیست فایلها را اضافه کرد. - ترتیب و وابستگی entityها (مثلاً ابتدا Person و Commodity و Year و HesabdariTable، بعد HesabdariDoc و HesabdariRow و …) در مرحله بازیابی باید رعایت شود تا ارجاع به شناسهها درست باشد.
۴. مراحل پیادهسازی پیشنهادی
فاز ۱: تعریف فرمت و سرویس پشتیبان (Export)
-
تعریف رسمی فرمت آرشیو
- نسخه فرمت (مثلاً
1.0) و ساختارmanifest.json. - لیست entityهایی که باید export شوند و ترتیب وابستگی آنها.
- نسخه فرمت (مثلاً
-
سرویس/کلاس Export (مثلاً
BusinessArchiveExporter)- ورودی:
Business $business(یاbid). - خروجی: مسیر فایل ZIP موقت یا stream.
- مراحل:
- ساخت پوشه/ساختار موقت.
- نوشتن
manifest.json. - استخراج تمام entityهای وابسته به این
bidاز دیتابیس و ذخیره درdata/entities/*.json(با حذف یا جایگزینی ارجاعات به entityهای خارج از این کسبوکار در صورت نیاز). - کپی فایلهای فیزیکی از
hesabixArchive/storage/{bid}/*به داخلfiles/storage/{bid}/در ZIP. - در صورت وجود، کپی
avatars/{avatar}وseal/{sealFile}این کسبوکار به داخل ZIP. - نوشتن رکوردهای
Registryباroot = (string)$bidدرdata/registry.json. - فشردهسازی به ZIP و برگرداندن فایل یا پاسخ با فایل برای دانلود.
- ورودی:
-
API و UI
- یک endpoint مثلاً
POST /api/backup/archive/createکه همان کسبوکار جاری کاربر را export کند و فایل ZIP را برگرداند. - در صفحه تنظیمات کسبوکار (مثلاً تب پشتیبان فعلی)، دکمه «پشتیبان کامل (با فایلها)» که همین API را صدا بزند و ZIP را دانلود کند.
- یک endpoint مثلاً
فاز ۲: سرویس بازیابی (Import / Restore)
-
سرویس اعتبارسنجی آرشیو
- خواندن ZIP، استخراج
manifest.json، بررسی نسخه و یکپارچگی (و در آینده checksum). - برگرداندن لیست بخشهای موجود (کدام entityها و فایلها وجود دارند).
- خواندن ZIP، استخراج
-
سرویس Restore (مثلاً
BusinessArchiveRestorer)- ورودی: مسیر فایل ZIP آپلود شده + پارامترهای بازیابی:
- حالت A – کسبوکار جدید:
یا شناسه کسبوکار از پیش ساختهشده خالی، یا «ایجاد کسبوکار جدید» و سپس پر کردن آن از آرشیو. - حالت B – بازنویسی کسبوکار فعلی:
شناسه کسبوکار فعلی؛ قبل از بازنویسی حذف/جایگزینی دادههای قبلی (و در صورت نیاز پشتیبان اضطراری از وضع فعلی).
- حالت A – کسبوکار جدید:
- مراحل کلی:
- استخراج ZIP به پوشه موقت.
- خواندن ترتیبی entityها از JSON و نگاشت شناسه قدیم → جدید (old bid → new bid، old person id → new person id، و غیره) تا ارجاعات درون آرشیو درست شوند.
- غیرفعال کردن موقت constraintها یا استفاده از ترتیب درست insert (مثلاً اول Business/Year/Person/Commodity/HesabdariTable، بعد HesabdariDoc، بعد HesabdariRow، و …).
- وارد کردن رکوردهای Registry با بهروزرسانی
rootبه شناسه کسبوکار مقصد. - کپی فایلها از
files/storage/{oldBid}/بهhesabixArchive/storage/{newBid}/و در صورت نیاز بهavatars/وseal/با نامهای صحیح. - بهروزرسانی مسیرها در
ArchiveFileوImportWorkflowDocument(و در Business برای avatar/seal) با مسیرهای جدید و شناسههای جدید. - پاکسازی فایلهای موقت و در حالت «بازنویسی»، حذف یا آرشیو داده/فایلهای قبلی آن کسبوکار (با سیاستی که تعریف شود).
- ورودی: مسیر فایل ZIP آپلود شده + پارامترهای بازیابی:
-
API و UI
- آپلود فایل ZIP: مثلاً
POST /api/backup/archive/uploadکه فایل را ذخیره موقت کند و فقط اعتبارسنجی + خلاصه محتوا برگرداند. - اجرای بازیابی: مثلاً
POST /api/backup/archive/restoreبا پارامترهای:fileToken(شناسه فایل آپلود شده)mode:new_business|overwrite_businesstargetBusinessId(در حالت overwrite یا وقتی کسبوکار از قبل ساخته شده)
- در UI:
- در تنظیمات کسبوکار یا صفحه جدا: آپلود ZIP، انتخاب حالت (کسبوکار جدید / بازنویسی فعلی)، تأیید و سپس فراخوانی restore.
- آپلود فایل ZIP: مثلاً
فاز ۳: امنیت و بهینهسازی
- دسترسی: فقط نقشهای مجاز (مثلاً settings یا admin) بتوانند export/restore انجام دهند؛ برای overwrite حتماً تأیید دومرحلهای یا رمز.
- حجم و زمان: برای کسبوکارهای بزرگ، export میتواند به صورت job پسزمینه انجام شود و لینک دانلود بعداً به کاربر داده شود؛ restore هم میتواند async باشد و وضعیت پیشرفت را گزارش دهد.
- نسخهپذیری: با افزایش entityها یا تغییر ساختار،
dataFormatVersionدر manifest و کد خواندن نسخههای قدیمی (در صورت نیاز) نگه داشته شود.
۵. نکات فنی مهم
- وابستگی بین entityها: در export باید ترتیب وابستگی رعایت شود (مثلاً Year، Money، Person، Commodity، HesabdariTable، BankAccount، Storeroom، بعد اسناد و ردیفها و حواله و آرشیو و پرونده واردات). در restore هم باید با همان ترتیب و با نگاشت شناسه، insert انجام شود.
- User و Permission: رکوردهای User و Permission معمولاً جزو «داده یک کسبوکار» نیستند یا سیاست جدا دارند؛ در بازیابی روی کسبوکار جدید میتوان کاربر جاری را به عنوان مالک/دسترسی اولیه تنظیم کرد و در حالت overwrite، دسترسیهای فعلی حفظ یا مطابق سیاست بهروز شوند.
- Submitter در ArchiveFile: در export میتوان شناسه User را نگه داشت؛ در restore به کسبوکار جدید اگر آن User در سیستم نباشد، میتوان به کاربر جاری یا یک کاربر پیشفرض نگاشت کرد.
- Pluginها: وضعیت افزونهها (فعال/غیرفعال، تاریخ انقضا) میتواند در آرشیو ذخیره شود؛ در restore به کسبوکار جدید معمولاً فقط داده و فایل بازگردانده میشود و مجوز افزونهها جداگانه مدیریت شود.
۶. جمعبندی
| مورد | وضع فعلی | هدف پیشنهادی |
|---|---|---|
| خروجی | فقط Excel بدون فایل | یک فایل ZIP شامل داده + فایلهای الصاقی |
| بازیابی | وجود ندارد | Restore به کسبوکار جدید یا بازنویسی کسبوکار فعلی |
| فایلهای انبار/واردات/آواتار/مهر | خارج از پشتیبان کسبوکار | داخل همان آرشیو ZIP |
| قابلیت انتقال | فقط گزارش Excel | انتقال کامل با یک فایل به محیط دیگر یا بازنویسی |
با این سناریو میتوان در مراحل بعد دقیقاً روی طراحی کلاسها، نام APIها و تغییرات UI تصمیم گرفت و پیادهسازی را شروع کرد.