بُني من مسح متوازي بـ 5 وكلاء على كل نظام MoonStack (KB + Packaging + Installer + Updater + Build-modes)، مُتحقَّق بـ file:line. الهدف: زيب يُفكّ جاهز على الروت (install) ويعمل update لو نسخة موجودة — لـ build-mode الاتنين، من غير ما نكسر شريان تحديث الأسطول.
.htaccess في جذر الحزمة يحوّل كل الطلبات لـ public/ → الفك في public_html يبقى جاهز وآمن، والـ updater ما يتلمسش.نظام توزيع/تحديث ذاتي‑الاستضافة لـ Moon‑ERP، معزول تمامًا عن نظام أحمد (Moon Central). كل المسارات تمرّ على نقطة تجميع واحدة.
moonstack:build/ship → PackageBuilder::build() يزيب الكود + vendor + الـFE المبني + manifest، ويوقّع (RSA) ويعمل sha256.Publisher يكتب الزيب + sig + sha لـ moonui/public_html/moonstack/ ويحدّث versions.json.public/moonstack-setup.php → App\MoonStack\Installer\Installer (requirements → DB → .env/APP_KEY → migrate → seed → company/admin → finalize).public/moonstack-update.php (delta-first، موقّع، backup → migrate → sync-reference seeders → health-check → finalize).| الوضع | إزاي بيجمّع المصدر | ملاحظة |
|---|---|---|
current servermoonstack-release.php | يزيب الشجرة الحيّة base_path() على moonui + الـ FE المبني مسبقًا /app (بدون node). | الافتراضي للصفحة (CageFS كان يمنع node). |
from gitscripts/moonstack-release-from-git.sh | clone نظيف + composer install --no-dev + ng build → moonstack:ship --source=<be> --frontend=<fe>. | يشحن المُلتزَم فقط؛ يتشغّل كـ root (node متاح). |
PackageBuilder::build() — فإصلاح واحد هناك بيغطّي الاتنين. لا الـ script ولا الصفحة بيلمسوا الـ layout.الـ layout بالكامل بيتحدّد من config/moonstack.php → package.include (سطور 149-156) اللي بيعدّد جذور لارافيل حرفيًا:
'include' => ['app','bootstrap','config','database','Modules','routes', 'resources','lang','public','vendor','artisan','composer.json', 'composer.lock','modules_statuses.json','.env.example']
PackageBuilder::addDir() (سطر 208) يحسب $rel = substr($abs, strlen($source)+1) ويضيفه بمساره الخام — بدون أي prefix. النتيجة: جذر الزيب = جذر لارافيل، public/ فولدر جوّه، والـ FE في public/app/. (مُتحقَّق من زيب moon-erp-v2.2.15.zip الحيّ: 15,978 ملف، top-level خام، vendor/ جوّاه 11,206 entry — يعني vendor مش ناقص في الـbuild؛ نقص prod كان فكّ ناقص/مقطوع لزيب 164MB).
| الحاجة | الواقع |
|---|---|
فكّيت الزيب في /home/prod/public_html | نزل لارافيل خام في الـ webroot (app/ config/ public/ vendor/ .env.example …) |
prod.elbaset.com/moonstack-setup.php | 404 — الملف فعليًا في /public/moonstack-setup.php (= 200) |
| الـ docroot = جذر لارافيل | خطر أمني — .env/config/storage/composer.json مكشوفين، مفيش root .htaccess |
…/public — self-hosted-distribution-plan). أنت فكّيت في public_html ومعملتش/ماتقدرش تعيد توجيه docroot → العَرَض حتمي.| المشكلة | المكان | الأثر |
|---|---|---|
تضارب علامة التثبيت: المثبّت يكتب storage/moonstack/installed بينما index.php:19 يقرأ storage/installed القديمة | Installer.php:202 vs public/index.php:19 | كامن (مُقنّع بوجود .env) — يتصلّح بكتابة العلامتين في finalize |
مفيش storage:link في مثبّت MoonStack (القديم install.php كان فيه) | Installer.php (غايب) | روابط public/storage للـ uploads مش بتتعمل |
مفيش guard على vendor: لو with_vendor=true وvendor/ غايب، الـbuild بيعدّي بصمت | PackageBuilder.php:74-86 | زيب بلا vendor → تثبيت ميّت عند الـboot. (RequirementsChecker مابيتشيكش على vendor → «أخضر» بعدين يموت) |
| seeders التحديث subset + non-fatal | moonstack.php:217-222 | reference data جديدة مش في القايمة دي ماتوصلش للعملاء (seeder-gap) |
أحمد يملك public/{install,update,deploy}.php + App\Services\* + config/{license,update}.php + moon:*. MoonStack يملك App\MoonStack\* + moonstack-*.php + moonstack:*. public/index.php مشترَك — أي تعديل فيه يخاطر بالتصادم → نتجنّبه.
الـ updater = شريان الأسطول؛ bug بيوقّف العملاء. بيكتب الـFE في public_path('app') = <root>/public/app ويطبّق الكود على base_path($rel) بمسارات نسبية لجذر لارافيل. أي حل يجب أن يُبقي مسارات الـzip نسبية لجذر لارافيل (un-wrapped) وإلا الـ delta/updater يتكسر.
+ نخليها بسيطة (لا licensing/telemetry) · نحافظ على حماية DATA (.env, storage/app, public/uploads never overwritten) + APP_KEY ثابت · plan-first إجباري لأي حاجة تلمس الـupdater.
.htaccess docroot-shimنُبقي الحزمة لارافيل قياسي (مسارات نسبية لجذر لارافيل = الـupdater سليم 100%) ونضيف ملف واحد: .htaccess في جذر الحزمة يحوّل كل الطلبات لـ public/.
# .htaccess (جذر الحزمة = جذر لارافيل) — يخدم public/ كأنه الـ docroot
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/public/
RewriteRule ^(.*)$ public/$1 [L]
</IfModule>
# دفاع في العمق: امنع dotfiles/الأسرار من الجذر مباشرةً
RedirectMatch 404 /\.(?!well-known)
<FilesMatch "^(\.env.*|composer\.(json|lock)|artisan|.*\.sqlite)$">
Require all denied
</FilesMatch>
public_html → prod.elbaset.com/moonstack-setup.php يشتغل (يتحوّل لـ public/…). بدون تغيير docroot يدوي.public/ → /.env→public/.env (404)، /config/app.php→404. ملفات الكور غير قابلة للوصول..htaccess الجديد مجرد ملف عادي — فعّال للتثبيت الجديد، وغير مؤذٍ للتثبيتات القديمة (لو docroot=public/ فالملف فوق الـdocroot = Apache يتجاهله).PackageBuilder::build() يغطّي build-mode الاتنين.| البديل | ليه اترفض |
|---|---|
إعادة توجيه docroot لـ …/public (الموثّق) | يتطلّب root/WHM (تعديل userdata + rebuild) — مش أوتوماتيك من الويب، والمالك مش عايز خطوة يدوية. |
تغليف الكور في subfolder (public_html/core/) ونقل محتوى public للجذر | يكسر افتراض الـupdater public_path()=<root>/public، ويكسر توافق الـ delta (المسارات تتبدّل) → خطر على الأسطول. أنظف بصريًا لكن يلمس الشريان. |
| وضع الكور فوق الـwebroot (شقيق public_html) | يتطلّب الفك في home + يكسر public_path للـupdater. خطر. |
.htaccess دلوقتي (آمن وحلّ المشكلة الوظيفية)، والنضافة البصرية لاحقًا لو أصرّيت.| # | التغيير | المكان (hook) |
|---|---|---|
| A | حقن root .htaccess (الـ shim أعلاه) في الـ full build، بجوار حقن manifest.json/skeleton | PackageBuilder::build() ~:130-138 (addFromString('.htaccess',…)) |
| B | guard على vendor: لو withVendor و!is_dir("$source/vendor") → فشل الـbuild بوضوح | PackageBuilder::build() ~:74 |
| C | storage:link + كتابة العلامتين (storage/moonstack/installed وstorage/installed) في finalize | Installer::install()/finalize() ~:54-64 / :189-198 |
| D | RequirementsChecker: شيك على vendor/autoload.php + layout (يفشل بصوت بدل ما يموت عند الـboot) | RequirementsChecker::check() ~:29-60 |
| E | (اختياري) توسيع moonstack.updater.seeders لتغطية أي definition seeder جديد + جعلها fatal-on-error | config/moonstack.php:217-222 + moonstack-update.php:378-386 |
لا تغيير في scripts/moonstack-release-from-git.sh ولا moonstack-release.php — الاتنين بيلتقوا على PackageBuilder. ولا تغيير في public/index.php المشترَك (نحترم عزل أحمد): الـ layout الناتج لارافيل قياسي فالكشف $basePath=dirname(__DIR__) يشتغل صح.
moon-erp-v<ver>.zip جوّه public_html وفُكّه كامل (تأكد من اكتمال الفك — الزيب ~164MB).https://<domain>/moonstack-setup.php → معالج WordPress-style (requirements → DB → admin) → تمام.مفيش تغيير docroot. مفيش حفر في /public/. الكور محمي تلقائيًا.
prod دلوقتي عليه v2.2.15 مفكوك خام، docroot=جذر لارافيل، لسه مش متسطّب (مفيش .env/marker). نطبّق الإصلاح يدويًا عشان يشتغل حالًا:
/home/prod/public_html/.htaccess (نفس الـ shim) → prod.elbaset.com/moonstack-setup.php يشتغل + الكور يتحمي.vendor/ موجود ~11k ملف) — لو ناقص، إعادة فك.prod, IP 151.80.18.217). /home/whats/prod تطبيق تاني لا علاقة له./home/moonui/moon-erp-be + commit على hazemdev..htaccess في الجذر + vendor + public/app..htaccess + الـshim صح، والكشف يلاقي artisan.dev-workflow/moonstack-update) بالرَنبوك الجديد + الـshim..htaccess shim) — آمن وبيحلّ المشكلة وظيفيًا وأمنيًا فورًا؟ ولا عايز الـ«نضافة البصرية» (الكور في subfolder، شغل أكتر + يلمس الـupdater)؟.htaccess وأكمّل التثبيت)، ولا تفضّل أبني/أنشر النسخة المُصلَّحة الأول وتفك من جديد؟