انتقل إلى المقال

Kinoraحل المشكلات

حل المشكلات

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

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

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 أو 8000: غالبًا تشغيل سابق لـ Kinora، أو خادم تطوير لمشروع آخر.

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

    على macOS أو Linux:

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

    على Windows، في PowerShell:

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

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

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

    مع الحزمة الكاملة في Docker، أنشئ ملفًا باسم .env في المجلد kinora-fitness-full-stack، بجوار docker-compose.yml، يحتوي على المنفذ الذي تحتاجه. ينقل DASHBOARD_PORT لوحة التحكم وAPI_PORT واجهة API؛ وتتبعها العناوين التي تستخدمها التطبيقات تلقائيًا.

    kinora-fitness-full-stack/.env
    DASHBOARD_PORT=3040

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

    الطرفيةفي kinora-fitness-full-stack
    docker compose up --build

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

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

الإعدادات

فشل بناء Docker

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

  • لا اتصال أو انتهت المهلة: يحتاج البناء إلى الإنترنت. شغّل الأمر مرة أخرى بعد عودة الاتصال؛ الخطوات المكتملة محفوظة في ذاكرة التخزين المؤقت.
  • لا توجد مساحة كافية على الجهاز (No space left on device): حرّر مساحة في Docker Desktop، أو تحقق مما يستخدمه Docker بالأمر docker system df.
  • يفشل عند الخطوة نفسها في كل مرة: أعد البناء من دون ذاكرة التخزين المؤقت، ثم شغّل التطبيقات.
الطرفيةفي kinora-fitness-full-stack
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.8.1…". 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 dashboard origin (comma separated if there are several), …

تتحقق واجهة 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 فلا تفعل: يطلب سجلها تشغيل node dist/database/sync-schema.js (الجداول) أو node dist/database/seeder.js (الجداول والبيانات التجريبية) مرة واحدة بنفسك.
  • "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 قيد التشغيل الجداول أبدًا، لذا يُشغَّل أحد هذين الأمرين قبل التشغيل الأول: yarn db:sync:prod أو yarn seed:prod بعد yarn build.

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

  • تحقق من الحساب. يسجّل الجميع الدخول من النموذج نفسه على المنفذ 3030: المدرب الرئيسي هو headcoach@example.com مع Coach@123، والعضو member@example.com مع Member@123.
  • تحقق من سجل واجهة 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.
  • غيّرت كلمة مرور المدرب الرئيسي ولم تعد تعرفها: ابدأ من جديد ببيانات تجريبية جديدة، كما هو موضح أدناه.
  • «البريد الإلكتروني أو كلمة المرور غير صحيحة. يرجى المحاولة مرة أخرى.» هي الإجابة نفسها لبريد إلكتروني غير معروف ولكلمة مرور خاطئة، لذا تحقق من الاثنين.
  • "Too many attempts. Wait a minute and try again." تعني أن عنوانًا واحدًا أجرى أكثر من 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: المدرب الرئيسي هو headcoach@example.com مع Coach@123، والعضو member@example.com مع Member@123. تسجيل الدخول الفاشل يُرجع 401 بالرسالة نفسها سواء كان البريد الإلكتروني خاطئًا أو كلمة المرور.
  • الاستجابة `429` تعني أن عنوانًا واحدًا أجرى أكثر من 10 محاولات على مسار تسجيل الدخول أو التسجيل أو حذف الحساب خلال دقيقة. تحدد الترويسة Retry-After عدد الثواني التي يجب انتظارها.

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

على البيانات التجريبية لا يُتحقق من كلمة المرور، لكن النموذج لا يزال يطلب 6 أحرف على الأقل. البريد الإلكتروني الذي يخص حسابًا تجريبيًا يسجّل الدخول بذلك الحساب، وأي بريد إلكتروني آخر يسجّل الدخول بصفته المدرب الرئيسي. بعد ربط واجهة API، سجّل الدخول بحساب موجود فيها: المدرب الرئيسي التجريبي هو headcoach@example.com مع Coach@123، والعضو التجريبي member@example.com مع Member@123.

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

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

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

back-end/.env
TRUST_PROXY=1

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

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

ما تراه
No API is connected (NEXT_PUBLIC_API_BASE_URL is empty), so the dashboard is running on built-in sample data: …

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

  1. أعطِ لوحة التحكم عنوان واجهة API

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

  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. اضبط API_URL أو DASHBOARD_URL أو MEDIA_HOSTNAME في ملف .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 الخاص بها.

الرفع مرفوض

ما تراه
File storage is not configured on this server. Set the R2 variables in .env to enable uploads.

تُرفع الصور الشخصية وصور التقدم ومرفقات الرسائل إلى حاوية Cloudflare R2 أو حاوية أخرى متوافقة مع S3، ويُرجع الرفع 400 بهذه الرسالة إلى أن تُضبط متغيرات R2_* الخمسة في back-end/.env. لا تحتاج البيانات التجريبية إلى حاوية: صورها مسارات /assets/images/… تقدّمها لوحة التحكم من مجلدها public/.

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

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

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

back-end/.env
CORS_ORIGIN=https://app.your-domain.com
FRONTEND_URL=https://app.your-domain.com

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

"Forgot password" لا ترسل شيئًا

صفحتا نسيان كلمة المرور وإعادة تعيينها في لوحة التحكم واجهتان فقط: لا يُرسَل أي رابط لإعادة التعيين، ولا تتغير أي كلمة مرور من خلالهما. تستدعيان POST /api/auth/forgot-password وPOST /api/auth/reset-password، وهما مساران لا تحتويهما واجهة API الخاصة بالقالب، لذا يعرض النموذج خطأً مع واجهة API. ومع البيانات التجريبية يعرض النموذج رسالة التأكيد، لكن لا يُرسَل شيء هناك أيضًا. لمنح عضو كلمة مرور جديدة، يعيّنها حساب طاقم يملك members.update من صفحة العضو ضمن «النادي». أما إعادة التعيين الذاتية فتحتاج إلى المسارين وإلى مزوّد بريد خاص بك.

حاوية واجهة 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، ثم أعد البناء من دون ذاكرة التخزين المؤقت.

الطرفيةفي kinora-fitness-full-stack
docker compose build --no-cache api
docker compose up

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

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

الحزمةالمجلديحتوي على
الحزمة الكاملةkinora-fitness-full-stackback-end, dashboard, docker-compose.yml
لوحة التحكمkinora-fitness-dashboardDockerfile, package.json, .env.example
الخادمkinora-fitness-backendDockerfile, package.json, .env.example

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

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

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

مع Docker Compose، من المجلد kinora-fitness-full-stack:

الطرفيةفي kinora-fitness-full-stack
docker compose down -v
docker compose up

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

الطرفيةفي kinora-fitness-backend
docker volume rm kinora-data
docker run -p 8000:8000 -v kinora-data:/data -e SEED_DEMO_DATA=true kinora-api

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

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

في PowerShell:

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

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

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

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

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

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

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

حل المشكلات

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

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