🌙 Moon ERP — نظام التوزيع والتحديث الذاتي

خطة مقترحة لتحويل المشروع إلى منتج يتنصّب على أي استضافة (زي ووردبريس) — مع تحديثات تلقائية تحافظ على بيانات العميل وتاخد الكود والـ migrations الجديدة.

حالة المستند: مسودة للمراجعة — مفيش تنفيذ لسه · الهدف: نتفق على القرارات قبل ما نبدأ أي حاجة.

Laravel modular monolith (BE) Angular static build (FE) cPanel / shared hosting PHP 8.2 · MySQL
الفكرة في سطر: نفصل الكود (اللي بيتغيّر مع كل تحديث) عن الداتا (اللي بتفضل للعميل للأبد). التحديث بيستبدل الكود + يشغّل migrations آمنة، ومش بيلمس قاعدة البيانات ولا الملفات ولا الـ APP_KEY أبداً.

1. الهدف والنموذج (The WordPress model)

زي ووردبريس بالظبط:

  1. تنزيل نسخة = حزمة (package) واحدة فيها كل اللي محتاجه المشروع يشتغل.
  2. تركيب على أي هوست = معالج تنصيب (Installer wizard) يسأل عن قاعدة البيانات ويجهّز كل حاجة.
  3. عند إصدار تحديث = النسخة المركّبة عند العميل تعرف إن فيه تحديث، تنزّله، تعمل backup، تركّبه، وتشغّل الـ migrations — والداتا زي ما هي.

كل عميل عنده نسخته الخاصة + قاعدة بياناته الخاصة (مش SaaS مشترك). ده بيدّي العميل تحكّم وخصوصية، وبيخلّينا نبيع المنتج «منتَج» مش «خدمة».

2. المبدأ الأساسي: فصل الكود عن الداتا

🔁 كود (يُستبدَل في كل تحديث)

  • Modules/, app/, config/, routes/
  • database/migrations/ (تعريف التغييرات)
  • vendor/ (الحزم — متجمّعة جاهزة)
  • artisan, composer.json/lock
  • الواجهة Angular مبنية جاهزة (app/*.js/.css)

🔒 داتا (تُحفَظ للأبد — ممنوع المساس)

  • قاعدة البيانات MySQL (migrations فقط)
  • .env — وبالذات APP_KEY
  • storage/app/ (مرفقات / ملفات مرفوعة)
  • public/uploads/ (صور / ملفات)
  • أي إعدادات أو ضبط خاص بالعميل
⚠️ قاعدة حياة أو موت — APP_KEY: الـ APP_KEY بيتولّد مرة واحدة وقت التنصيب ومايتغيّرش أبداً. لو اتغيّر، كل الأعمدة المشفّرة في قاعدة البيانات بتبوظ (The MAC is invalid — اللي حصل معانا فعلاً في صفحة الـ AI settings). المُحدِّث ممنوع منعاً باتاً يلمس .env.

3. الواقع اللي بيحكم كل القرارات: استضافة cPanel

دي مش تفصيلة — دي اللي بتحدّد التصميم كله. على cPanel/الاستضافة المشتركة:

القيدالنتيجة على التصميم
مفيش root ولا Docker ولا SSH مضمونالمُحدِّث لازم يشتغل من المتصفّح بـ PHP (زي شاشة Updates في ووردبريس)، مش بأوامر طرفية.
composer install غالباً مش متاح/بطيءنشحن vendor/ جاهز داخل الحزمة (vendored). على الهوست بنعمل dump-autoload بس (من غير إنترنت).
أحياناً exec() / mysqldump مقفوليننعمل backup للداتا بـ PHP خالص (fallback) بدل ما نعتمد على أوامر النظام.
ملفات بملكية root بتعمل 500كل عمليات الملفات والـ artisan تشتغل بمستخدم الويب (اللي بيشغّل PHP-FPM).
الواجهة Angular محتاجة build (Node)نشحن النسخة المبنية جاهزة في الحزمة — العميل مش هيعمل ng build أبداً.
mod_proxy مش متاح في .htaccessكل حاجة PHP-native (ZipArchive للفك، cURL للتنزيل).

الخلاصة: مُحدِّث ويب بـ PHP + حزمة self-contained (vendor مدمج + FE مبني) هو الطريق الوحيد العملي هنا.

4. المكوّنات اللي هنبنيها

① خط بناء الحزمة عندنا

سكربت بناء يطلّع حزمة مُوقّعة بإصدار محدّد: BE + vendor + FE مبني + manifest. بيستبعد .env وبيانات storage.

② سيرفر التحديث والترخيص عندنا

سيرفر مركزي: يستضيف الحِزَم + manifest بالإصدارات + يتحقّق من الترخيص + سجل النسخ المركّبة (phone-home).

③ المُنصِّب (Installer) داخل الحزمة

معالج أول تشغيل: فحص البيئة ← إعداد قاعدة البيانات ← توليد .env+APP_KEYmigrate+seed ← إنشاء أول أدمن/شركة.

④ المُحدِّث داخل التطبيق داخل الحزمة

شاشة «التحديثات» + محرّك: يفحص ← ينزّل ← يتحقّق ← backup ← يركّب ← migrate ← reseed ← يمسح الكاش ← يبدّل الـ FE ← rollback لو فشل.

5. مسار التحديث خطوة بخطوة (قلب النظام)

فحص (Check): النسخة تكلّم السيرفر بـ {license_key, current_version, php_version} ← يرجّع آخر إصدار + سجل التغييرات + المتطلبات + رابط التنزيل + sha256 + التوقيع (حسب صلاحية الترخيص).
فحص مسبق (Pre-flight): توافق نسخة PHP والإضافات + مساحة قرص كافية + صلاحيات كتابة. لو حاجة ناقصة → نوقف قبل ما نبدأ.
وضع الصيانة (Maintenance): artisan down — صفحة «جاري التحديث» للمستخدمين.
نسخة احتياطية (Backup): dump لقاعدة البيانات + ضغط الكود الحالي + storage. تتخزّن في storage/updates/backups/<version>/. دي شبكة الأمان.
تنزيل + تحقّق: ننزّل الحزمة، نتأكد من sha256 + التوقيع (ضد التلاعب وللتأكد إنها مننا).
تجهيز + تركيب (Stage & Apply): نفك في مجلد staging، نبدّل ملفات الكود — مع الحفاظ على .env وstorage/ وpublic/uploads/. الـ vendor/ بييجي جاهز من الحزمة.
Migrate: php artisan migrate --force (إضافي وآمن للداتا) + seeders idempotent للبيانات المرجعية (صلاحيات، تعريفات إعدادات).
إعادة بناء: dump-autoload -o (من غير إنترنت) + optimize:clear + كاش config/route.
تبديل الواجهة (FE): نمسح ملفات app/ القديمة الأول (gotcha معروفة عندنا) وننسخ الـ dist الجديد.
رجوع للخدمة: artisan up + فحص صحة (health endpoint).
تقرير: نبلّغ السيرفر «اتحدّثنا لـ vX». عند أي فشل في أي خطوة → Rollback (نرجّع الداتا + الكود من الـ backup ونرجّع للخدمة).

6. القواعد المؤسِّسة (اللي لازم نلتزم بيها للأبد)

1
ثبات الـ APP_KEY. يُولَّد مرة واحدة وقت التنصيب، ومايتغيّرش. كل التشفير معتمد عليه. التحديث ممنوع يلمس .env.
2
فصل الكود عن الداتا عبر «بيان مسارات» (manifest). ملف يحدّد المسارات اللي «داتا» وممنوع تتكتب فوقها: .env, storage/app/**, public/uploads/**.
3
انضباط الـ Migrations. كل migration إضافي وآمن للداتا. الحذف (drop column/table) يتم على إصدارين فقط (إضافة الجديد ← ترحيل الداتا ← في إصدار لاحق نحذف القديم). ممنوع تعديل migration اتشحن قبل كده — دايماً نضيف جديد. والقفزات بين عدة إصدارات لازم تشتغل (Laravel بيشغّل كل المعلّق بالترتيب).
4
Seeders idempotent. البيانات المرجعية (صلاحيات، تعريفات إعدادات، أنواع القيود) تُزرَع بـ firstOrCreate في كل تحديث — من غير truncate أبداً. (عندنا النمط ده فعلاً في RolePermissionSeeder.)
5
حزم مُجمّعة (vendored). نشحن vendor/ جاهز — مفيش composer install على الهوست. الإصدارات مثبّتة، والبناء يحصل عندنا بس.
6
Backup قبل أي تحديث — إجباري وأوتوماتيك، مع زر استرجاع بضغطة.
7
توقيع + checksum للحزم. سلامة (sha256) + أصالة (توقيع بمفتاحنا الخاص، والنسخة بتتحقّق بالمفتاح العام المدمج فيها).
8
بوّابة توافق. كل إصدار يعلن حد أدنى لـ PHP/الإضافات/الإصدار السابق. لو مش متحقّق → نرفض التركيب.
9
التنفيذ بمستخدم الويب. كل عمليات الملفات والـ artisan بمستخدم PHP (تفادياً لـ 500 من كاش بملكية root).
10
ذرّي وقابل للرجوع (Atomic & reversible). stage ثم swap؛ rollback عند أي فشل. ملاحظة MySQL: الـ DDL مش transactional — عشان كده الـ backup-أولاً هو الضمان الحقيقي.
11
لا افتراض لوجود طرفية (shell). المُحدِّث الويب هو الأساسي؛ الـ CLI اختياري للهوستات اللي فيها SSH.
12
تتبّع الإصدار في قاعدة البيانات. نسجّل app_version + schema_version؛ المُحدِّث يفرض ترتيباً صحيحاً بلا تخطّي.
13
الترخيص والاستحقاق. النسخ المرخّصة بس هي اللي بتنزّل تحديثات (تحكّم تجاري).
14
ممنوع تعديل ملفات الـ core عند العميل. أي تخصيص عبر إعدادات/موديولات إضافية — مش بتعديل الكود الأساسي (لإن التحديث بيكتب فوقه). نفس فلسفة ووردبريس.

7. الترخيص والتفعيل (نموذج ووردبريس التجاري)

8. القرارات المفتوحة — محتاجين رأيك (مع توصيتي)

توصيتي = اللي أنصح بيه نبدأ بيه.

القرارالخياراتتوصيتي
آلية التحديث(أ) مُحدِّث ويب داخل التطبيق · (ب) CLI artisan · (ج) الاتنينأ أساسي + ب اختياري — الويب يناسب cPanel.
نموذج الترخيص(أ) تحديثات مجانية · (ب) مرخّص باستحقاق · (ج) هجين (أمان مجاني + مزايا مرخّصة)ب أو ج لو تجاري.
سيرفر التحديث(أ) خدمة مخصّصة · (ب) توسيع moon-support · (ج) حِزَم ثابتة موقّعة على CDN + API ترخيص خفيفج — أبسط وأأمن وأرخص.
المُنصِّب(أ) معالج ويب كامل · (ب) سكربت موجَّهأ — تجربة احترافية زي ووردبريس.
تعدّد الشركات للنسخة الواحدة(أ) شركة واحدة · (ب) متعدّد (الكود بيدعم company_id)ب متاح، أ افتراضي — مايغيّرش آلية التحديث.
تلقائي ولا يدوي(أ) يدوي بضغطة · (ب) تلقائي للترقيعات · (ج) مجدوَلأ افتراضي — تحكّم للعميل.
تخزين الـ Backups(أ) محلي + احتفاظ N · (ب) خارجي (S3) للنسخ الكبيرةأ يبدأ + ب اختياري.
قنوات الإصدار(أ) Stable فقط · (ب) Stable + Betaأ للبداية.
backup قاعدة البيانات على الاستضافة المشتركة(أ) mysqldump لو متاح · (ب) PHP خالص fallback (للهوستات اللي مقفّلة exec())الاتنين — نجرّب mysqldump ونرجع لـ PHP لو مقفول.

9. المخاطر وكيف نتعامل معاها

الخطرالمعالجة
exec()/composer/mysqldump مقفولينvendor مدمج + ZipArchive بـ PHP + backup قاعدة بيانات PHP خالص.
تحديث اتقطع في النصوضع صيانة + backup + rollback أوتوماتيك.
ضياع/تغيّر APP_KEYالمُنصِّب يخزّنه، المُحدِّث مايلمسوش، وتنبيه واضح «اعمل backup لـ .env».
فشل migration في النص (DDL مش transactional)backup-أولاً إجباري + migrations قابلة لإعادة التشغيل ومحميّة (guarded).
مساحة قرص للـ backupفحص مساحة مسبق قبل البدء.
صلاحيات الملفاتالتشغيل بمستخدم الويب + فحص كتابة مسبق.
العميل عدّل في الـ coreسياسة «ممنوع تعديل core» + التخصيص عبر إعدادات/موديولات.

10. خطة البناء على مراحل

Phase 0
الأساسات: توثيق القواعد (manifest الداتا، انضباط الـ migrations، ثبات APP_KEY، مراجعة الـ seeders idempotent) + إضافة تتبّع app_version/schema_version. مخاطرة قليلة
Phase 1
خط بناء الحزمة: سكربت يطلّع حزمة موقّعة بإصدار (BE+vendor+FE dist+manifest).
Phase 2
المُنصِّب: معالج ويب (فحص بيئة ← قاعدة بيانات ← .env/APP_KEY ← migrate+seed ← أدمن/شركة).
Phase 3
سيرفر التحديث: API الـ manifest + استضافة الحِزَم الموقّعة + ترخيص/استحقاق + سجل النسخ.
Phase 4
المُحدِّث داخل التطبيق: محرّك فحص/تنزيل/تحقّق/backup/تركيب/migrate/rollback + شاشة «التحديثات».
Phase 5
تقوية الـ Backup/Restore + الـ Rollback.
Phase 6
واجهة الترخيص/التفعيل + فرض الاستحقاق.
Phase 7
تجربة Pilot: تنصيب ← تحديث ← rollback كامل على حساب cPanel نظيف (dry-run حقيقي).
نقطة قوة عندنا بالفعل: النمط الأساسي موجود — Laravel migrations مرتّبة، seeders idempotent (RolePermissionSeeder)، واجهة مبنية static، وvendor/ موجود. يعني Phase 0–1 أغلبه تنظيم وتوثيق، مش بناء من الصفر.

11. الخطوة الجاية

راجع القسم 8 (القرارات المفتوحة) وقول لي اختياراتك — وبعد ما نتفق عليها، أبدأ بـ Phase 0 (الأساسات والقواعد) لأنه أقل مخاطرة وبيمهّد لكل اللي بعده. ممكن كمان أعمل إثبات مفهوم (PoC) صغير لمسار تحديث واحد على نسخة تجريبية قبل ما نلتزم بالبناء الكامل.

مفيش أي تنفيذ اتعمل لسه — ده مستند مراجعة بس.