انتقل إلى المقال
Aniq-UI

Learnioمتغيرات البيئة

متغيرات البيئة

ما يفعله كل إعداد في ملفات .env الخاصة بواجهة API والواجهتين الأماميتين، وأيها تحتاج إليه.

لحزمة الحزمة الكاملة

أين توجد الإعدادات

الملفيقرؤهيحتوي على أسرار
back-end/.envواجهة API، مع yarn dev وداخل Dockerنعم. لا تضفه إلى المستودع أبدًا.
frontend/.envموقع الطلاب، أثناء البناءلا. كل القيم عامة.
admin-dashboard/.envلوحة الإدارة، أثناء البناءلا. كل القيم عامة.
.env بجوار docker-compose.ymlDocker Compose، للحزمة الكاملةلا

أنشئ كل ملف من .env.example المجاور له، والذي يوثّق كل متغير: cp .env.example .env. تعمل الأمثلة كما هي للتشغيل المحلي.

أين توجد الإعدادات

ملف واحد، frontend/.env، يُقرأ عند بناء الموقع. كل القيم فيه عامة، لذا لا يحتوي على أي سر أبدًا. أنشئه من .env.example، الذي يوثّق كل متغير: cp .env.example .env.

أين توجد الإعدادات

ملف واحد، admin-dashboard/.env، يُقرأ عند بناء لوحة الإدارة. كل القيم فيه عامة، لذا لا يحتوي على أي سر أبدًا. لا تنشئه إن أردت العمل على المحاكاة؛ وأنشئه من .env.example عندما تربط واجهة API: cp .env.example .env.

أين توجد الإعدادات

ملف واحد، back-end/.env، تقرؤه واجهة API مع yarn dev وداخل Docker. يحتوي على أسرار: لا تضفه إلى المستودع أبدًا. أنشئه من .env.example، الذي يوثّق كل متغير ويعمل كما هو للتشغيل المحلي: cp .env.example .env.

أساسيات واجهة API

تتحقق واجهة API من هذه المتغيرات قبل أن تبدأ. إذا كان أحدها مفقودًا أو غير صالح، تتوقف وتعرض قائمة قصيرة بما يجب إصلاحه.

المتغيروظيفته
NODE_ENVdevelopment محليًا، وproduction على خادم مباشر.
PORTمنفذ واجهة API، وهو 8000. تشير إليه الواجهتان الأماميتان.
DB_TYPEsqlite (الافتراضي) أو mysql.
SQLITE_DATABASEمسار ملف SQLite، وهو ./database.sqlite افتراضيًا.
JWT_SECRETيوقّع كل جلسة تسجيل دخول. مطلوب. القيمة المثال مقبولة في بيئة التطوير فقط.
JWT_EXPIRATIONمدة صلاحية تسجيل الدخول، وهي 7d افتراضيًا.
CORS_ORIGINعنوانا موقع الطلاب ولوحة الإدارة، مفصولين بفاصلة. مطلوب في بيئة الإنتاج.
FRONTEND_URLعنوان موقع الطلاب، ويُستخدم في الروابط التي ترسلها واجهة API.

ولّد JWT_SECRET خاصًا بك بالأمر:

الطرفية
node -e "console.log(require('crypto').randomBytes(48).toString('hex'))"

استخدم MySQL بدلًا من SQLite

أنشئ قاعدة بيانات فارغة، ثم اضبط برنامج التشغيل والاتصال في back-end/.env:

back-end/.env
DB_TYPE=mysql
DB_HOST=your-mysql-host
DB_PORT=3306
DB_USERNAME=your-mysql-username
DB_PASSWORD=your-mysql-password
DB_DATABASE=your-database-name

ثم شغّل yarn seed للبيانات التجريبية، أو yarn db:sync على موقع مباشر، وهو ينشئ الجداول دون كتابة أي صفوف. لا تحدّث واجهة API قيد التشغيل المخطط بنفسها إلا عندما يكون NODE_ENV=development.

موقع الطلاب ولوحة الإدارة

كل قيمة هنا من نوع NEXT_PUBLIC_*، وتُضمَّن في شيفرة JavaScript التي يحمّلها المتصفح. لا تضع أي سر في هذه الملفات أبدًا، وأعد البناء بعد تغيير أي قيمة.

المتغيرالتطبيقوظيفته
NEXT_PUBLIC_API_BASE_URLكلاهماعنوان واجهة API متضمنًا /api، مثل http://localhost:8000/api. إذا تُرك فارغًا، يستخدم التطبيق بياناته النموذجية.
NEXT_PUBLIC_SITE_URLكلاهماالعنوان العام لموقع الطلاب، ويُستخدم للروابط الأساسية (canonical) ومعاينات المشاركة وخريطة الموقع. اضبطه على نطاقك الحقيقي في بيئة الإنتاج.
NEXT_PUBLIC_MEDIA_HOSTNAMEكلاهماالمضيف العام لمخزن الوسائط لديك، من دون https://. اتركه فارغًا حتى يتوفر لديك مخزن.
NEXT_PUBLIC_WEBSOCKET_BASE_URLلوحة الإدارةعنوان واجهة API من دون /api، للإشعارات المباشرة.
NEXT_PUBLIC_SAMPLE_DATA_NOTICEكلاهمااختياري. القيمة always تعرض إشعار "Sample data" في بناء الإنتاج أيضًا عندما تتوقف واجهة API عن الاستجابة. يضبطه ملف docker-compose.yml في الجذر، أما الموقع المنشور فيتركه عادة دون قيمة.
API_INTERNAL_URLموقع الطلاباختياري، للخادم فقط. العنوان الذي يصل منه خادم الموقع نفسه إلى واجهة API عندما يختلف عن عنوان المتصفح، كما في Docker Compose.

خيارات Docker Compose

لا حاجة إلى ضبط أي شيء للتشغيل المحلي. لتغيير شيء، ضعه في ملف .env بجوار docker-compose.yml وشغّل docker compose up --build مرة أخرى: فالواجهتان الأماميتان تُضمّنان هذه القيم أثناء البناء.

المتغيروظيفته
SITE_PORT, ADMIN_PORT, API_PORTالمنافذ على جهازك: 3030 و3031 و8000 افتراضيًا. اضبط أحدها حين يستخدم برنامج آخر ذلك المنفذ، مثل ADMIN_PORT=3041. وتتبعها العناوين أدناه وCORS_ORIGIN وFRONTEND_URL.
SITE_URL, ADMIN_URL, API_URLالعنوان الذي يصل منه المتصفح إلى كل تطبيق. اضبط الثلاثة عند تشغيل التطبيقات على نطاقاتك الخاصة.
MEDIA_HOSTNAMEالمضيف العام لمخزنك، مع متغيرات R2_* في back-end/.env.
SEED_DEMO_DATAالقيمة false تبدأ بجداول فارغة بدلًا من البيانات التجريبية.

تقرأ حاوية واجهة API أيضًا back-end/.env عند وجوده، فتُضبط مفاتيح البريد والمدفوعات والوسائط والذكاء الاصطناعي في مكان واحد لكل من yarn dev و Docker.

تخزين الوسائط

تُرفع صور الدورات والصور الرمزية وصور المدونة وفيديوهات الدروس والمرفقات إلى مخزن Cloudflare R2، أو أي مخزن متوافق مع S3. اضبط المتغيرات الخمسة في back-end/.env وأعطِ الواجهتين الأماميتين المضيف العام للمخزن عبر NEXT_PUBLIC_MEDIA_HOSTNAME.

back-end/.env
R2_ACCESS_KEY_ID=
R2_SECRET_ACCESS_KEY=
R2_ENDPOINT=
R2_BUCKET_NAME=
R2_PUBLIC_URL=

من دون مخزن، يحفظ سكربت البيانات التجريبية مسارات لملفات نموذجية ترفقها الواجهتان الأماميتان بنفسيهما، فتعمل كل صورة وكل فيديو درس محليًا. يتوقف رفع الوسائط الجديدة فقط.

البريد الإلكتروني

تُرسَل رسائل تأكيد البريد، وإعادة تعيين كلمة المرور، والإيصالات، وتأكيدات التسجيل عبر Resend. ومن دون RESEND_API_KEY يواصل التطبيق العمل ويكتب كل رسالة في سجله.

back-end/.env
RESEND_API_KEY=
MAIL_FROM=Learnio <noreply@example.com>
MAIL_MAX_PER_ADDRESS_PER_DAY=5
MAIL_MAX_PER_SENDER_PER_DAY=20
  • استخدم مفتاحًا بصلاحية الإرسال فقط، لا مفتاحًا بصلاحية كاملة.
  • يجب أن يكون MAIL_FROM على نطاق تحققت منه في Resend، وإلا رُفض كل إرسال.
  • يحدد الحدّان عدد الرسائل التي يمكن أن يستقبلها عنوان واحد، وعدد الرسائل التي يمكن أن يطلقها مُرسِل واحد، في اليوم.
  • اسم المنتج داخل كل رسالة وعنوان الرد عليها ليسا متغيرين: إنهما الإعدادان site_name وsupport_email في تبويب App Settings ضمن Settings في لوحة الإدارة، ويُقرآن لكل رسالة تُرسَل.

المدفوعات

افتراضيًا، تعمل صفحة الدفع على محاكي مدمج: لا يُتصل بأي معالج دفع ولا يُخصم أي مبلغ. يُرفض رقم البطاقة المنتهي بـ 0، لتجرّب مسار الفشل.

املأ مفاتيح معالج دفع لتنتقل طريقة الدفع تلك إلى المعالج الحقيقي. اضبط Stripe و PayPal كليهما قبل استقبال طلبات حقيقية: فصفحة الدفع تعرض دائمًا البطاقة و PayPal، والطلب المدفوع عبر المحاكي يكتمل دون خصم أي مبلغ من أحد.

لا تحتاج الدورات المجانية (السعر 0) إلى أي معالج دفع: يكتمل دفعها على واجهة API من دونه، أيًّا كانت المفاتيح المضبوطة.

معالج الدفعالمتغيراتنقطة نهاية الـ webhook
StripeSTRIPE_SECRET_KEY, STRIPE_PUBLISHABLE_KEY, STRIPE_WEBHOOK_SECRETPOST <api>/api/webhooks/payments/stripe
PayPalPAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PAYPAL_WEBHOOK_ID, PAYPAL_ENVPOST <api>/api/webhooks/payments/paypal

الـ webhook هو ما يمنح المقعد

يُسجَّل الطالب في الدورة عندما يؤكد معالج الدفع العملية عبر الـ webhook، لا عند عودته من صفحة الدفع. من دون الاشتراك في الـ webhook، تبقى الطلبات معلّقة.

  • اشترك في أحداث Stripe التالية: checkout.session.completed وpayment_intent.payment_failed وcharge.refunded.
  • اشترك في أحداث PayPal التالية: PAYMENT.CAPTURE.COMPLETED وPAYMENT.CAPTURE.DENIED وPAYMENT.CAPTURE.REFUNDED وPAYMENT.CAPTURE.REVERSED.
  • قيمة PAYPAL_ENV هي sandbox افتراضيًا، ولا تأخذ أموالًا حقيقية. بيانات الاعتماد المباشرة تخص تطبيق PayPal مختلفًا، لذا يعني التحول إلى البيئة المباشرة مفاتيح جديدة إضافة إلى PAYPAL_ENV=live.

المساعد الذكي

مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.

تشغيل المساعد الذكي: مفاتيح المزوّدين، وكيف يُعرض كل نموذج، وما يراه المدير بلا مفتاح.

الحصص المباشرة

مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.

إعداد الفصول المباشرة: ربط خادم Jitsi Meet، ورموز الدخول الآمنة، وأدوات المضيف.

البيانات النموذجية في الواجهات الأمامية

تستمر الواجهتان الأماميتان في العمل عندما يتعذر الوصول إلى واجهة API: تقدّمان البيانات النموذجية المرفقة وتعرضان إشعار "Sample data" أسفل الصفحة. في بناء الإنتاج لا يظهر الإشعار إلا عندما لا تكون أي واجهة API مضبوطة على الإطلاق، ما لم يُبنَ التطبيق مع NEXT_PUBLIC_SAMPLE_DATA_NOTICE=always كما يفعل ملف docker-compose.yml في الجذر.

  • تغطي البيانات النموذجية في لوحة الإدارة تسجيل الدخول، والطلاب، والطاقم، والأدوار، والفئات، والإعدادات، والإشعارات، والبحث، وسجل محادثات المساعد. أما شاشاتها الأخرى (أرقام النظرة العامة، والدورات، والمدرّسون، والتسجيلات، والطلبات، والتقييمات، والمدونة، والجدول، والاختبارات، والرسائل) فتحتاج إلى واجهة API.
  • يقبل تسجيل الدخول في لوحة الإدارة أي بريد إلكتروني وأي كلمة مرور على البيانات النموذجية، ويحفظ تغييراتك في المتصفح. لتبدأ من جديد، شغّل localStorage.removeItem("mock_db_v1"); location.reload(); في وحدة تحكم المتصفح.
  • المساعد الذكي غير متاح على البيانات النموذجية، لأنه يحتاج إلى مفاتيح واجهة API.
  • بمجرد أن تصبح واجهة API مباشرة، يحذف yarn remove:mock في أي من التطبيقين طبقة البيانات النموذجية.

كيف تعمل طبقة البيانات النموذجية

مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.

كيف تُوجَّه الطلبات إلى البيانات المرفقة، وكيف تغيّرها أو توسّعها.

وضع العرض التجريبي

مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.

تشغيل عرض تجريبي عام: مفتاح العرض التجريبي، وحسابات الزوار، وحصة الرسائل، وطريقة إزالة كل ذلك.

توقفت عند خطوة؟

ابحث عن الحل قبل أن تبدأ من جديد.

حل المشكلات

تفضيلات ملفات تعريف الارتباط

نستخدم ملفات تعريف الارتباط لتعزيز تجربة التصفح الخاصة بك وتحليل حركة المرور على الموقع وتخصيص المحتوى. بالنقر على "قبول الكل"، فإنك توافق على استخدامنا لملفات تعريف الارتباط للتحليلات والإعلانات المخصصة.