متغيرات البيئة
ما يفعله كل إعداد في ملفات .env الخاصة بواجهة API والواجهتين الأماميتين، وأيها تحتاج إليه.
لحزمة الحزمة الكاملة
أين توجد الإعدادات
| الملف | يقرؤه | يحتوي على أسرار |
|---|---|---|
back-end/.env | واجهة API، مع yarn dev وداخل Docker Compose | نعم. لا تضفه إلى المستودع أبدًا. |
storefront/.env | موقع الإقامات، وقت البناء | لا. كل قيمة NEXT_PUBLIC_* عامة. |
admin-dashboard/.env | لوحة تحكم الحجوزات، وقت البناء | لا. كل القيم عامة. |
.env بجوار docker-compose.yml | Docker Compose، للحزمة الكاملة | لا |
أنشئ ملف كل تطبيق من .env.example الموجود بجانبه، وهو يشرح كل متغير: cp .env.example .env. تعمل الأمثلة كما هي للتشغيل المحلي، ولا يحتاج تشغيل Docker Compose إلى أي ملف.
أين توجد الإعدادات
ملف واحد هو .env في مجلد الموقع، يُقرأ عند بناء الموقع. كل قيمة NEXT_PUBLIC_* فيه عامة، فلا يحتوي سرًا أبدًا. أنشئه من .env.example الذي يشير إلى واجهة API على http://localhost:8000: cp .env.example .env. مع Docker مرّر القيم نفسها بـ --build-arg.
أين توجد الإعدادات
ملف واحد هو .env في مجلد لوحة التحكم، يُقرأ عند بناء لوحة التحكم. كل قيمة فيه عامة، فلا يحتوي سرًا أبدًا: مفاتيح الدفع والذكاء الاصطناعي في .env الخاص بواجهة API. أنشئه من .env.example الذي يشير إلى واجهة API على http://localhost:8000: cp .env.example .env. مع Docker مرّر القيم نفسها بـ --build-arg.
أين توجد الإعدادات
ملف واحد هو .env في مجلد واجهة API، تقرؤه واجهة API عند yarn dev، وتقرؤه الحاوية عندما تضيف --env-file .env -e NODE_ENV=production إلى docker run. يحوي أسرارًا: لا تضفه إلى المستودع أبدًا. أنشئه من .env.example الذي يشرح كل متغير ويعمل كما هو للتشغيل المحلي: cp .env.example .env.
صورة Docker تضبط قيمها الافتراضية بنفسها، فيعمل docker run بلا ملف: SQLite على /data/database.sqlite، والملفات المرفوعة في /data/uploads، وCORS_ORIGIN للواجهتين الأماميتين المحليتين، وFRONTEND_URL=http://localhost:3031 وSITE_URL=http://localhost:3030 وPUBLIC_MEDIA_URL=http://localhost:8000/media وSEED_DEMO_DATA=false. تجاوز أيًا منها بـ -e.
أساسيات واجهة API
تتحقق واجهة API من JWT_SECRET، ومن CORS_ORIGIN في الإنتاج، قبل أن تبدأ. إذا كان أحدهما ناقصًا أو غير صالح، تتوقف وتطبع سطرًا واحدًا يوضح ما يجب إصلاحه.
| المتغير | وظيفته |
|---|---|
NODE_ENV | development محليًا، وهو ينشئ الجداول ويحدّثها عند بدء التشغيل. وproduction على خادم مباشر، وهو لا يلمس الجداول أبدًا. |
PORT | منفذ واجهة API، وهو 8000. تشير إليه الواجهتان الأماميتان. |
DB_TYPE | sqlite (كما في .env.example) أو mysql. إذا لم يُضبط فالمقصود MySQL، لذلك أبقِ السطر. |
SQLITE_DATABASE | مسار ملف SQLite، وهو ./database.sqlite افتراضيًا. |
JWT_SECRET | يوقّع كل جلسة تسجيل دخول. مطلوب. قيمة المثال مقبولة خارج الإنتاج فقط. |
JWT_EXPIRATION | مدة صلاحية تسجيل الدخول، 7d افتراضيًا. تعيدها استجابة تسجيل الدخول باسم expires_in. |
CORS_ORIGIN | عنوانا الموقع ولوحة التحكم، مفصولان بفاصلة. إذا لم يُضبط فلا يُسمح إلا بـ http://localhost:3030 وhttp://localhost:3031، وليس بكل الأصول أبدًا؛ مطلوب في الإنتاج. |
FRONTEND_URL | عنوان لوحة التحكم، وتتصل منه إشعاراتها المباشرة، وهو http://localhost:3031 عند عدم الضبط. |
SITE_URL | عنوان الموقع. يعيد معالج الدفع الضيف إلى هنا، إلى صفحة حجزه، لذلك يجب أن يكون العنوان الذي يتصفح به الضيف. |
TRUST_PROXY | اختياري. عدد الوكلاء العكسيين أمام واجهة API، كي تحسب الحدود لكل عنوان (تسجيل الدخول والحجوزات والأسئلة والتقييمات) الزائر الحقيقي. |
RATE_LIMIT_LOGIN | اختياري. عدد محاولات الدخول الفاشلة التي يمكن لعنوان واحد القيام بها خلال 15 دقيقة قبل 429، وهو 10 افتراضيًا. |
SEED_DEMO_DATA | تقرؤه صورة Docker فقط، على وحدة تخزين بلا قاعدة بيانات بعد: true ينشئها مع الشركة التجريبية، وfalse بالجداول فقط. |
ولّد JWT_SECRET خاصًا بك بالأمر:
node -e "console.log(require('crypto').randomBytes(48).toString('hex'))"كل ميزة اختيارية أدناه تبقى متوقفة ما دامت أسطرها في .env.example معلّقة كتعليقات.
المدفوعات
بدون أي من هذه يقبل المحاكي المرفق كل حجز بالبطاقة أو PayPal، فيعمل إتمام الطلب كله بلا حساب تاجر، ويقول سجل بدء واجهة API Payment simulator active ما دام يعمل. يؤكد تلك الحجوزات دون أخذ أي مال، لذا اضبط Stripe أو PayPal أو الاثنين قبل استقبال حجوزات حقيقية: عندها يتوقف المحاكي، ولا يعرض إتمام الطلب إلا الطرق المضبوطة مع الدفع عند الوصول، وتُرفض الطريقة التي ليس لها معالج. يبيّن تبويب المدفوعات في إعدادات لوحة التحكم أي المعالجات مضبوطة، وهل مفاتيحها تجريبية أم حقيقية، وهل المحاكي قيد الاستخدام، ولا يعرض المفاتيح نفسها أبدًا.
STRIPE_SECRET_KEY=your-stripe-secret-key
STRIPE_WEBHOOK_SECRET=your-stripe-webhook-signing-secret
PAYPAL_CLIENT_ID=your-paypal-client-id
PAYPAL_CLIENT_SECRET=your-paypal-client-secret
PAYPAL_WEBHOOK_ID=your-paypal-webhook-id
PAYPAL_ENV=sandbox| المتغير | وظيفته |
|---|---|
STRIPE_SECRET_KEY | يفعّل الدفع بالبطاقة عبر Checkout المستضاف من Stripe. مفتاح sk_test_ لا يحرّك مالًا حقيقيًا. |
STRIPE_WEBHOOK_SECRET | سر التوقيع لنقطة webhook في Stripe، أو الذي يطبعه stripe listen. بدونه يُرفض كل webhook من Stripe، فلا يُسوّى حجز بالبطاقة أبدًا. |
PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET | يفعّل PayPal عبر Orders v2، الاثنان معًا. |
PAYPAL_WEBHOOK_ID | معرّف اشتراك webhook في PayPal، الذي يتحقق من توقيع PayPal. |
PAYPAL_ENV | sandbox (الافتراضي) أو live. |
الدفع عند الوصول لا يحتاج إلى مفتاح: هو مفتاح التبديل allow_pay_on_arrival في تبويب المدفوعات في لوحة التحكم، ومفعّل في البيانات الأولية.
استخدم MySQL بدلًا من SQLite
أنشئ قاعدة بيانات فارغة، ثم اضبط المشغّل والاتصال في ملف .env الخاص بواجهة API:
DB_TYPE=mysql
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=
DB_DATABASE=hollinaثم شغّل yarn seed للشركة التجريبية، أو yarn db:sync للجداول بلا بيانات. لا تنشئ واجهة API العاملة الجداول وتحدّثها بنفسها إلا حين NODE_ENV=development، لذلك مع NODE_ENV=production يُشغَّل أحد هذين الأمرين قبل أول تشغيل (yarn seed:prod أو yarn db:sync:prod بعد yarn build).
الصور والملفات المرفوعة
تخدم واجهة API الصور الأولية بنفسها، من public/media/hollina، على /media/hollina/…. وتُخزَّن الملفات المرفوعة من لوحة التحكم (صور الإقامات، وأغلفة الوجهات، والصور الشخصية) على قرص واجهة API تحت MEDIA_UPLOAD_DIR وتُخدم على /media/uploads/…، ما لم تُضبط حاوية تخزين.
PUBLIC_MEDIA_URL=http://localhost:8000/media
MEDIA_UPLOAD_DIR=./public/media/uploadsPUBLIC_MEDIA_URL هو العنوان الذي يُوصَل به إلى /media من المتصفح. تُبنى منه كل عناوين الصور، وتنقل واجهة API العناوين المخزنة إليه عند بدئها، فنقل واجهة API يُبقي كل صورة. على الخادم وجّه MEDIA_UPLOAD_DIR إلى تخزين دائم؛ ومع Docker هو في وحدة تخزين البيانات.
لإرسال الملفات المرفوعة إلى Cloudflare R2، أو أي حاوية متوافقة مع S3، اضبط المتغيرات الخمسة كلها. أعطِ الواجهتين الأماميتين المضيف العام للحاوية عبر NEXT_PUBLIC_MEDIA_HOSTNAME (مع Docker Compose، MEDIA_HOSTNAME) كي يغيّر Next.js أحجام تلك الصور.
R2_ACCESS_KEY_ID=your-r2-access-key-id
R2_SECRET_ACCESS_KEY=your-r2-secret-access-key
R2_ENDPOINT=https://your-account-id.r2.cloudflarestorage.com
R2_BUCKET_NAME=your-bucket-name
R2_PUBLIC_URL=https://your-public-url.r2.devتُعاد ترميز الصور عند الرفع بصيغة JPEG، بعرض أقصاه 1920 بكسل، مع نسخة أصغر لبطاقات الإقامات. تُقبل الفيديوهات بصيغة MP4 أو WebM أو MOV أو M4V، حتى 150 ميغابايت.
موقع الإقامات ولوحة تحكم الحجوزات
كل قيمة NEXT_PUBLIC_* تُضمَّن في كود JavaScript الذي يحمّله المتصفح، ويستطيع أي شخص يفتح الصفحة قراءتها. لا تضع أي سر في هذه الملفات أبدًا، وأعد البناء بعد تغيير أي قيمة.
| المتغير | التطبيق | وظيفته |
|---|---|---|
NEXT_PUBLIC_API_BASE_URL | كلاهما | عنوان واجهة API مع /api، وهو http://localhost:8000/api افتراضيًا. |
NEXT_PUBLIC_SITE_URL | كلاهما | العنوان العام للموقع، http://localhost:3030 افتراضيًا. في الموقع تُبنى منه العناوين الأساسية وبدائل اللغات وبطاقات المشاركة وrobots.txt وخريطة الموقع؛ وفي لوحة التحكم يُبنى منه الشعار النصي في صفحة تسجيل الدخول و«العودة إلى الموقع» ورابط الخصوصية، و«عرض الإقامة» في محرر الإقامة. |
NEXT_PUBLIC_MEDIA_HOSTNAME | كلاهما | اختياري. مضيفات https التي تخدم الصور، مفصولة بفاصلة: المضيف العام لحاويتك، مثل pub-1234.r2.dev، أو نطاق واجهة API، أو الاثنان. تُغيَّر أحجام الصور عليها بواسطة Next.js؛ وأي صورة أخرى تُحمَّل كما هي. مضيفات فقط، بدون https://. يقرأ التطبيقان القائمة نفسها، فقيمة واحدة تخدمهما. اتركه فارغًا ما دامت واجهة API تعمل على localhost. |
NEXT_PUBLIC_WEBSOCKET_BASE_URL | لوحة التحكم | عنوان واجهة API من دون /api، للإشعارات المباشرة. |
NEXT_PUBLIC_MAP_STYLE_LIGHT, NEXT_PUBLIC_MAP_STYLE_DARK | الموقع | أنماط MapLibre اختيارية لخريطة صفحة الإقامة. إن لم تُضبط ترسم السمتان نمط Positron من OpenFreeMap، وهو لا يحتاج إلى مفتاح. |
API_INTERNAL_URL | الموقع | اختياري، للخادم فقط، ويُقرأ وقت التشغيل وليس وقت البناء. هو المكان الذي يصل منه خادم الموقع نفسه إلى واجهة API عندما لا يعمل عنوان المتصفح من داخله، كما في Docker (http://api:8000/api في Docker Compose). اتركه بلا ضبط في غير ذلك. |
BUILD_STANDALONE | كلاهما | القيمة true تجعل yarn build يُخرج خادمًا مستقلًا بذاته، وهي القيمة التي تضبطها ملفات Dockerfile. اتركه غير مضبوط في غير ذلك. |
أوسمة التسويق في الموقع هي أيضًا قيم NEXT_PUBLIC_*: Google Tag Manager وGA4 وMeta وTikTok وSnapchat وPinterest، ويُفعَّل كل منها بمعرّف واحد.
خيارات Docker Compose
لا تحتاج إلى ضبط أي شيء للتشغيل المحلي. لتغيير شيء، ضعه في ملف .env بجوار docker-compose.yml وشغّل docker compose up --build مرة أخرى: تُضمِّن الواجهات الأمامية هذه القيم.
| المتغير | القيمة الافتراضية | وظيفته |
|---|---|---|
SITE_PORT | 3030 | منفذ الموقع على جهازك. |
ADMIN_PORT | 3031 | منفذ لوحة التحكم على جهازك. |
API_PORT | 8000 | منفذ واجهة API على جهازك. |
SITE_URL, ADMIN_URL, API_URL | العناوين المحلية على هذه المنافذ | العنوان الذي يصل منه المتصفح إلى كل تطبيق. اضبط الثلاثة عند تشغيل التطبيقات على نطاقاتك الخاصة. |
MEDIA_HOSTNAME | فارغ | مضيفات https التي تخدم الصور، مفصولة بفاصلة: المضيف العام لحاويتك (مع متغيرات R2_* في back-end/.env)، أو نطاق واجهة API نفسها، أو الاثنان. |
SEED_DEMO_DATA | true | false يبدأ بجداول فارغة وبلا حسابات بدلًا من الشركة التجريبية. ولا يهم إلا على وحدة تخزين جديدة. |
NEXT_PUBLIC_GTM_ID, NEXT_PUBLIC_GA4_MEASUREMENT_ID, NEXT_PUBLIC_META_PIXEL_ID, NEXT_PUBLIC_TIKTOK_PIXEL_ID, NEXT_PUBLIC_SNAPCHAT_PIXEL_ID, NEXT_PUBLIC_PINTEREST_TAG_ID | فارغ | وسوم التسويق في الموقع، وكلها اختيارية. |
NEXT_PUBLIC_ANALYTICS_CURRENCY, NEXT_PUBLIC_ANALYTICS_DEBUG | USD, false | العملة المرسلة مع كل سعر يُتتبَّع، وتسجيل كل حدث في وحدة تحكم المتصفح. |
NEXT_PUBLIC_MAP_STYLE_LIGHT, NEXT_PUBLIC_MAP_STYLE_DARK | فارغ | أنماط خريطة صفحة الإقامة؛ وإذا تُرك فارغًا استُخدم Positron من OpenFreeMap. |
غيّر المنفذ حين يستخدمه برنامج آخر، مثل ADMIN_PORT=3041. أما CORS_ORIGIN وFRONTEND_URL وSITE_URL وPUBLIC_MEDIA_URL في واجهة API، وعنوانا واجهة API والموقع في الواجهتين الأماميتين، فكلها تُبنى من المنافذ والعناوين الثلاثة، فتتبعها من تلقاء نفسها.
تقرأ حاوية واجهة API الملف back-end/.env أيضًا عندما يوجد، فتُضبط مفاتيح الدفع والذكاء الاصطناعي وR2 وMCP في مكان واحد لكل من yarn dev وDocker. ويتغلب ملف compose في القيم التي تختلف داخل الحاوية: مسار قاعدة البيانات، ومجلد الملفات المرفوعة، والمنفذ، وNODE_ENV=production، والعناوين أعلاه. وقاعدة البيانات والملفات المرفوعة في وحدة التخزين hollina-data.
المساعد الذكي
مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.
تفعيل المساعد الذكي: مفتاح Google Gemini وما يُحاسَب عليه.
خادم MCP
مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.
السماح لوكلاء البرمجة وعملاء MCP الآخرين باستخدام أدوات المساعد: المفتاح ونقطة النهاية.
وضع العرض التجريبي
مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.
مفتاح التبديل للعرض التجريبي العام، ولماذا يبقى متوقفًا لشركة حقيقية.