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

E-Commerceحل المشكلات

حل المشكلات

الأخطاء التي قد تواجهها أثناء تثبيت المتجر، وسبب كل منها، وطريقة إصلاحها.

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

Docker لا يعمل

ما تراه
failed to connect to the docker API at unix:///…/docker.sock; check if the path is correct and if the daemon is running

تعرض إصدارات Docker الأقدم الرسالة "Cannot connect to the Docker daemon" بدلًا من ذلك. وفي الحالتين، محرك Docker غير مُشغَّل.

  1. افتح Docker Desktop

    شغّل Docker Desktop وانتظر حتى يُظهر أن المحرك يعمل. على Linux، شغّل الخدمة: sudo systemctl start docker.

  2. تحقق من أن Docker يستجيب

    الطرفية
    docker info

    النتيجة المتوقعة: يطبع قسم Server بدلًا من رسالة خطأ.

  3. شغّل أمر التشغيل مرة أخرى

    docker compose up --build للحزمة الكاملة، أو أمرَي docker build وdocker run الخاصين بك لتطبيق واحد.

المنفذ مستخدم بالفعل

ما تراه
ports are not available: exposing port TCP 0.0.0.0:3030 … bind: address already in use
Error: listen EADDRINUSE: address already in use :::3030

السطر الأول من Docker، والثاني من yarn dev. هناك برنامج آخر يستمع بالفعل على 3030 أو 3031 أو 8000: غالبًا تشغيل سابق للمتجر، أو خادم تطوير لمشروع آخر.

  1. اعرف ما الذي يشغل المنفذ

    على macOS أو Linux:

    الطرفية
    lsof -i :3030

    على Windows، في PowerShell:

    الطرفية
    netstat -ano | findstr :3030
  2. أوقفه

    أغلق ذلك البرنامج، أو أوقف التشغيل السابق: Ctrl+C في طرفيته، أو docker compose down في مجلده، أو docker stop لحاوية شغّلتها بالأمر docker run. ثم شغّل المتجر مرة أخرى.

  3. أو شغّل المتجر على منافذ أخرى

    مع الحزمة الكاملة في Docker، أنشئ ملفًا باسم .env داخل المجلد e-commerce-1 بجوار docker-compose.yml يحدد المنفذ الذي تحتاجه. SITE_PORT ينقل المتجر، وADMIN_PORT لوحة الإدارة، وAPI_PORT واجهة API، وتتبعها العناوين التي تستخدمها التطبيقات تلقائيًا.

    e-commerce-1/.env
    ADMIN_PORT=3041

    ثم شغّل الأمر نفسه من جديد. بعد تشغيل فاشل يكمل من حيث توقف:

    الطرفيةفي e-commerce-1
    docker compose up --build

    النتيجة المتوقعة: يجيب التطبيق على منفذه الجديد، هنا localhost:3041محلي.

بدون Docker تكون المنافذ ثابتة في ملفات .env. لنقل واجهة API هناك، غيّر PORT في back-end/.env، وNEXT_PUBLIC_API_BASE_URL في الواجهتين الأماميتين، وCORS_ORIGIN معًا: يجب أن تتطابق الثلاثة. ومع Docker استخدم API_PORT بدلًا من ذلك. ولتطبيق واحد شُغّل بـ docker run، غيّر الرقم الموجود على يسار -p.

الإعدادات

فشل بناء Docker

ينزّل البناء الأول الصور الأساسية وكل الاعتماديات، ثم يبني الصور. وعندما يعترضه شيء، يتوقف بالرسالة "failed to solve" مع الخطوة التي فشلت.

  • لا اتصال أو انتهت المهلة: يحتاج البناء إلى الإنترنت. شغّل الأمر مرة أخرى بعد عودة الاتصال؛ الخطوات المكتملة محفوظة في ذاكرة التخزين المؤقت.
  • لا توجد مساحة كافية على الجهاز (No space left on device): حرّر مساحة في Docker Desktop، أو تحقق مما يستخدمه Docker بالأمر docker system df.
  • يفشل عند الخطوة نفسها في كل مرة: أعد البناء من دون ذاكرة التخزين المؤقت، ثم شغّل التطبيقات.
الطرفيةفي e-commerce-1
docker compose build --no-cache
docker compose up

لحزمة التطبيق الواحد، أضف --no-cache إلى أمر docker build الخاص بك.

التشغيل الأول الذي يبدو عالقًا يكون غالبًا ما زال يملأ قاعدة البيانات بالمتجر التجريبي. لا يبدأ المتجر ولوحة الإدارة إلا بعد أن تُبلغ واجهة API بأنها سليمة.

يقول Yarn إن إصداره 1.22

ما تراه
This project's package.json defines "packageManager": "yarn@4…". However the current global version of Yarn is 1.22…

كل تطبيق يثبّت Yarn 4 عبر Corepack. تعني هذه الرسالة أن Corepack غير مفعّل بعد، فأجاب Yarn القديم المثبّت عامًّا بدلًا منه.

الطرفية
corepack enable

ثم شغّل yarn install مرة أخرى. إذا لم يكن مع Node.js لديك Corepack، فثبّته أولًا بالأمر npm install -g corepack.

تتوقف واجهة API قبل أن تبدأ

ما تراه
✖ The API cannot start: JWT_SECRET is not set. Set it in back-end/.env to the output of: …
✖ The API cannot start: JWT_SECRET is still the example value from .env.example, …
✖ The API cannot start: CORS_ORIGIN is not set. List the storefront and admin dashboard origins, …

تتحقق واجهة API من إعداداتها قبل أن تبدأ، وتطبع سطرًا واحدًا لكل مشكلة. الأسباب:

  • لا يوجد ملف `.env`، أو `JWT_SECRET` فارغ. أنشئ الملف في back-end/ بالأمر cp .env.example .env.
  • ما زال `JWT_SECRET` بقيمة المثال مع `NODE_ENV=production`. يستطيع أي شخص توقيع رمز باستخدام المثال العام، لذا يرفضه التشغيل في وضع الإنتاج. ولّد سرًا خاصًا بك.
  • `CORS_ORIGIN` فارغ مع `NODE_ENV=production`. اكتب عنوانَي المتجر ولوحة الإدارة، مفصولين بفاصلة.

ولّد سرًا بالأمر:

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

مع Docker لا تحتاج إلى ذلك: الحاوية التي ليس لها JWT_SECRET خاص بها، أو التي تستخدم قيمة المثال، تولّد سرًا وتحفظه في وحدة تخزين البيانات.

فحص السلامة يُجيب بـ 503

ما تراه
{"status":"unavailable"}
The database has no tables yet. Run `yarn seed` in back-end/, then restart the API.

يُجيب /api/health بـ 503 إلى أن تستجيب قاعدة البيانات وتحتوي على جداولها. السطر الثاني هو ما يكتبه سجل واجهة API عند بدء التشغيل حين تكون الجداول مفقودة.

  • من دون Docker، في وضع التطوير: شغّل yarn seed في back-end/ (الجداول والمتجر التجريبي)، أو yarn db:sync (الجداول فقط)، ثم أعد تشغيل واجهة API.
  • مع `NODE_ENV=production`: لا تنشئ واجهة API الجداول عند بدء التشغيل. شغّل yarn db:sync:prod (جداول فارغة) أو yarn seed:prod (مع المتجر التجريبي) مرة واحدة، بعد yarn build.
  • مع Docker على SQLite: تنشئ الحاوية قاعدة البيانات بنفسها عند أول تشغيل. أما على MySQL فلا تفعل ذلك: شغّل أمر المخطط أو أمر البيانات التجريبية بنفسك مرة واحدة.
  • "The database has no accounts, so nobody can sign in" تعني أن الجداول موجودة لكن لم يُضَف أي حساب قط: شغّل yarn seed في back-end/.

MySQL يرفض البدء أو ملء البيانات

تنشئ واجهة API جداولها في قاعدة بيانات موجودة مسبقًا؛ ولا تنشئ قاعدة البيانات نفسها. أنشئ أولًا قاعدة بيانات فارغة، وضع اسمها في DB_DATABASE داخل back-end/.env، ثم شغّل yarn seed (أو yarn db:sync للجداول من دون المتجر التجريبي).

  • تحقق من قيم الاتصال الخمس DB_*، ومن أن DB_TYPE=mysql.
  • مع NODE_ENV=production لا تنشئ واجهة API العاملة أي جداول أبدًا، لذا يجب تشغيل أحد هذين الأمرين قبل أول تشغيل.

فشل تسجيل الدخول

  • تحقق من الحساب ومن التطبيق. تسجّل حسابات الموظفين الدخول إلى لوحة الإدارة على المنفذ 3031: admin@example.com مع Admin@123. ويسجّل العملاء الدخول إلى المتجر على المنفذ 3030: john.doe@example.com مع password123.
  • تحقق من سجل واجهة API. الرسالة "The database has no accounts, so nobody can sign in" تعني أن المتجر التجريبي لم يُضَف قط. من دون Docker، شغّل yarn seed في back-end/. ومع Docker، فقد أُنشئت وحدة التخزين مع SEED_DEMO_DATA=false.
  • الرسالة "The database has no tables yet" تعني أن مخطط قاعدة البيانات لم يُنشأ قط: شغّل yarn seed في back-end/ وأعد تشغيل واجهة API.
  • غيّرت كلمة مرور المدير العام ولم تعد تعرفها: ابدأ من جديد ببيانات تجريبية جديدة، كما هو موضح أدناه.
  • «البريد الإلكتروني أو كلمة المرور غير صحيحة. يرجى المحاولة مرة أخرى.» هي الإجابة نفسها لبريد إلكتروني غير معروف ولكلمة مرور خاطئة، لذا تحقق من الاثنين.
  • «محاولات كثيرة جدًا. انتظر دقيقة ثم حاول مرة أخرى.» تعني أن عنوانًا واحدًا أجرى أكثر من 10 محاولات على مسار تسجيل الدخول أو كلمة المرور خلال دقيقة. انتظر دقيقة ثم حاول مرة أخرى.

فشل تسجيل الدخول

  • تحقق من سجل واجهة API. الرسالة "The database has no accounts, so nobody can sign in" تعني أن المتجر التجريبي لم يُضَف قط: شغّل yarn seed، أو شغّل حاوية Docker مع -e SEED_DEMO_DATA=true على وحدة تخزين جديدة.
  • الرسالة "The database has no tables yet" تعني أن مخطط قاعدة البيانات لم يُنشأ قط: شغّل yarn seed وأعد تشغيل واجهة API.
  • تحقق من الحساب ومن المسار. يسجّل الموظفون الدخول عبر POST /api/auth/login (المدير العام هو admin@example.com مع Admin@123)؛ والعملاء عبر POST /api/auth/customer/login (john.doe@example.com مع password123). يُجاب تسجيل الدخول الفاشل بـ 401 مع الرسالة نفسها، سواء كان البريد الإلكتروني أو كلمة المرور هو الخطأ.
  • الإجابة `429` تعني أن عنوانًا واحدًا أجرى أكثر من 10 محاولات على مسار تسجيل الدخول أو التسجيل أو كلمة المرور أو تتبّع الطلب خلال دقيقة. ترويسة Retry-After تحدد عدد الثواني التي يجب انتظارها.

فشل تسجيل الدخول

على المتجر النموذجي، يسجّل دخولك إلى المتجر أي بريد إلكتروني وكلمة مرور، ويسجّل دخولك إلى لوحة الإدارة أي بريد إلكتروني صالح مع كلمة مرور من 6 أحرف على الأقل. بعد ربط واجهة API، سجّل الدخول بحساب موجود فيها: المدير العام التجريبي هو admin@example.com مع Admin@123، والعميل التجريبي john.doe@example.com مع password123.

كل زائر يرى رسالة «محاولات كثيرة جدًا» خلف خادم وكيل

تسمح مسارات تسجيل الدخول والتسجيل وإعادة تعيين كلمة المرور وتتبّع طلبات الضيوف بـ 10 طلبات في الدقيقة لكل عنوان ومسار، ثم تُجيب بـ 429. وغرفة القياس تحسب لكل عنوان أيضًا. لا تأخذ واجهة API عنوان الزائر من X-Forwarded-For إلا عندما يأتي الطلب من خادم وكيل على عنوان خاص أو محلي (loopback) أو عنوان المنصة، كما في Railway أو خلف Caddy أو nginx على الجهاز نفسه.

عندما يصل خادمك الوكيل إلى واجهة API من عنوان عام، يبدو كل الزوار كأنهم ذلك الخادم الوكيل نفسه، فيتشاركون حصة واحدة. أخبر واجهة API بعدد الخوادم الوكيلة التي تقف أمامها:

back-end/.env
TRUST_PROXY=1

مع TRUST_PROXY=false لا تُقرأ الترويسة أبدًا. اتركه غير مضبوط عندما يُوصَل إلى واجهة API مباشرة أو عبر خادم وكيل على عنوان خاص. تُحفظ العدّادات في ذاكرة واجهة API، لذا تُمسح عند إعادة التشغيل.

يظهر تنبيه «بيانات تجريبية»

تعمل الواجهة الأمامية على متجرها النموذجي المدمج بدلًا من واجهة API، لأنها شُغّلت أو بُنيت من دون NEXT_PUBLIC_API_BASE_URL. وعندها يُحفظ ما تغيّره في المتصفح لا في قاعدة البيانات، ولا يُحصَّل أي مبلغ عن أي طلب.

  1. أعطِ الواجهة الأمامية عنوان واجهة API

    أنشئ ملف .env للواجهة الأمامية من .env.example إن لم يكن لديها ملف. يجب أن يكون NEXT_PUBLIC_API_BASE_URL عنوان واجهة API متضمنًا /api، مثل http://localhost:8000/api.

  2. تحقق من أن واجهة API تستجيب

    افتح localhost:8000/api/healthمحلي. يجب أن يُجيب بـ {"status":"ok"}. إذا كان العنوان مضبوطًا لكن واجهة API لا تستجيب، فلن تتمكن الصفحات من تحميل بياناتها: المتجر النموذجي لا يحل محلها.

  3. أعد تشغيل الواجهة الأمامية أو أعد بناءها

    العنوان مُضمَّن أثناء البناء. أعد تشغيل yarn dev بعد تغييره، أو شغّل yarn build مجددًا قبل yarn start، أو مع Docker شغّل docker compose up --build مجددًا.

تغيير ملف .env للواجهة الأمامية لا يُحدث أي أثر

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

طريقة التشغيلبعد تغيير قيمة
yarn devأوقفه وشغّل yarn dev مجددًا.
yarn build وyarn startشغّل yarn build مجددًا، ثم yarn start.
Docker Composeشغّل docker compose up --build. اضبط القيمة في ملف .env المجاور لـ docker-compose.yml، لا في مجلد التطبيق.
docker build لتطبيق واحدابنِ الصورة مجددًا مع القيمة كوسيط --build-arg.

ميزة تقول إنها غير مُعدّة

لا يعمل الدفع بالبطاقة، ورفع الملفات، والمساعد الذكي، واستوديو الذكاء الاصطناعي، وإزالة الخلفية، وغرفة القياس إلا عندما تكون مفاتيحها في back-end/.env. وتحتاج غرفة القياس والاستوديو وإزالة الخلفية أيضًا إلى مخزن الوسائط. والمفتاح الذي ما زال يحمل قيمته في .env.example تمامًا يُعامَل كأنه غير مضبوط، فيبدأ ملف .env.example المنسوخ دون مشكلات، وتُظهر كل ميزة من هذه الميزات أنها متوقفة بدلًا من أن تفشل عند أول استدعاء.

  • الصق مفتاحك الحقيقي مكان قيمة المثال، لا بجوارها.
  • أعد تشغيل واجهة API بعد تغيير back-end/.env. مع Docker Compose تقرأ واجهة API هذا الملف أيضًا، فيكفي تشغيل docker compose up مجددًا؛ أما حاوية واجهة API المنفردة فتحتاج إلى --env-file .env في أمر docker run الخاص بها.

رفع الملفات يُجيب بـ 503

ما تراه
File uploads are not set up yet. Add the R2 storage settings to the server's .env file to enable them.

كل رفع من لوحة الإدارة (صور المنتجات، والصور الرمزية، ومرفقات المحادثة، ونتائج استوديو الذكاء الاصطناعي) يذهب إلى مخزن Cloudflare R2 أو مخزن آخر متوافق مع S3، ويُجاب بـ 503 إلى أن تُضبط متغيرات R2_* الخمسة كلها في back-end/.env. وتحتاج غرفة القياس والاستوديو وإزالة الخلفية إلى المخزن أيضًا، وتبقى متوقفة من دونه. أما المتجر التجريبي فلا يحتاج إلى مخزن: تُعرض صوره من نسخ مرفقة مع الواجهتين الأماميتين في public/mock-media/.

الصور المرفوعة تُحمَّل ببطء أو بحجمها الكامل

لا تغيّر الواجهتان الأماميتان حجم الصور ولا تضغطانها إلا إذا جاءت من مضيفين بُنيتا لتثقا بهم. الصورة القادمة من مخزنك على أي مضيف آخر تظهر مع ذلك، لكن من دون تحسين.

  1. حدّد المضيف العام لمخزنك

    من دون Docker، اضبط NEXT_PUBLIC_MEDIA_HOSTNAME في ملف .env لكل واجهة أمامية على مضيف R2_PUBLIC_URL، مثل pub-1234.r2.dev. ومع Docker Compose، ضع MEDIA_HOSTNAME=pub-1234.r2.dev في ملف .env بجوار docker-compose.yml. اكتب اسم المضيف فقط، من دون https:// ومن دون شرطة مائلة في النهاية.

  2. أعد بناء الواجهتين الأماميتين

    المضيف مُضمَّن أثناء البناء. أعد تشغيل yarn dev وأعد البناء للإنتاج، أو شغّل docker compose up --build مجددًا.

الطلبات محظورة على نطاقاتك الخاصة

ما تراه
Access to fetch at 'https://api.your-domain.com/api/…' from origin 'https://shop.your-domain.com' has been blocked by CORS policy

لا تُجيب واجهة API المتصفحات إلا من العناوين الموجودة في CORS_ORIGIN، ولا تقبل الإشعارات المباشرة للوحة الإدارة إلا من FRONTEND_URL. القيمة الافتراضية لكليهما هي المنفذان المحليان، لذا يجب أن يحددا مواقعك عندما تستخدم نطاقاتك الخاصة.

back-end/.env
CORS_ORIGIN=https://shop.your-domain.com,https://admin.your-domain.com
FRONTEND_URL=https://admin.your-domain.com

اكتب كل عنوان تمامًا كما يعرضه المتصفح، مع https:// ومن دون شرطة مائلة في النهاية، ثم أعد تشغيل واجهة API. ومع Docker Compose، اضبط بدلًا من ذلك SITE_URL وADMIN_URL وAPI_URL في ملف .env المجاور لـ docker-compose.yml وشغّل docker compose up --build: يبني ملف compose القائمتين منها.

حاوية واجهة API لا تجد نقطة الدخول الخاصة بها

ما تراه
exec /usr/local/bin/docker-entrypoint.sh: no such file or directory

يحتوي السكربت على نهايات أسطر بنمط Windows، وقد يضيفها محرر نصوص أو Git على Windows. يزيلها ملف back-end/Dockerfile المرفق أثناء البناء، لذا لا تظهر هذه المشكلة إلا مع صورة بُنيت من ملف Dockerfile معدّل. أبقِ السطر sed -i 's/\r$//' الخاص به، أو احفظ السكربت بنهايات أسطر LF، ثم أعد البناء من دون ذاكرة التخزين المؤقت.

الطرفيةفي e-commerce-1
docker compose build --no-cache api
docker compose up

المجلد يبدو مختلفًا

شغّل الأوامر داخل المجلد الذي يُستخرج إليه ملف ZIP. إذا لم يكن الأمر unzip متوفرًا، فاستخرجه بمدير الملفات بدلًا من ذلك؛ تضيف بعض الأدوات مجلدًا إضافيًا يحمل اسم ملف ZIP، فانتقل إلى المجلد الداخلي.

الحزمةالمجلديحتوي على
الحزمة الكاملةe-commerce-1admin-dashboard, back-end, storefront, docker-compose.yml
المتجرstorefrontDockerfile, package.json, .env.example
لوحة الإدارةadmin-dashboardDockerfile, package.json, .env.example
واجهة API (Backend API)back-endDockerfile, package.json, .env.example

ابدأ من جديد ببيانات تجريبية جديدة

هذا يحذف بياناتك

يُحذف كل ما أنشأته محليًا، وتُملأ قاعدة البيانات بالمتجر التجريبي من جديد.

مع Docker Compose، من المجلد e-commerce-1:

الطرفيةفي e-commerce-1
docker compose down -v
docker compose up

مع حاوية واجهة API منفردة، احذف الحاوية أولًا (يعرضها docker ps -a، ويحذفها docker rm -f مع معرّفها)، ثم احذف وحدة التخزين وشغّلها مرة أخرى:

الطرفيةفي back-end
docker volume rm ecommerce-data
docker run -p 8000:8000 -v ecommerce-data:/data -e SEED_DEMO_DATA=true ecommerce-api

من دون Docker، أوقف واجهة API، ثم:

الطرفيةفي back-end
rm -f database.sqlite* && yarn seed

في PowerShell:

الطرفيةفي back-end
Remove-Item database.sqlite*; yarn seed

تشغيل yarn seed مجددًا على قاعدة بيانات تحتفظ بها ليس إعادة ضبط: فهو يضيف ما هو ناقص فقط، ولا يعيد أبدًا أي قيمة غيّرتها في لوحة الإدارة. على MySQL، يحذف yarn db:reset كل الجداول قبل yarn seed.

ابدأ من جديد على المتجر النموذجي

من دون واجهة API، تُحفظ تغييراتك في المتصفح. لإعادة المتجر النموذجي إلى حالته الأولى، شغّل هذا في وحدة تحكم المتصفح على صفحة التطبيق:

وحدة تحكم المتصفح
localStorage.removeItem("mock_db_v1"); location.reload();

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

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

حل المشكلات

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

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