حل المشكلات
الأخطاء التي قد تواجهها أثناء تثبيت 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 غير مُشغَّل.
افتح Docker Desktop
شغّل Docker Desktop وانتظر حتى يُظهر أن المحرك يعمل. على Linux، شغّل الخدمة:
sudo systemctl start docker.تحقق من أن Docker يستجيب
الطرفيةdocker infoالنتيجة المتوقعة: يطبع قسم Server بدلًا من رسالة خطأ.
شغّل أمر التشغيل مرة أخرى
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، أو خادم تطوير لمشروع آخر.
اعرف ما الذي يشغل المنفذ
على macOS أو Linux:
الطرفيةlsof -i :3030على Windows، في PowerShell:
الطرفيةnetstat -ano | findstr :3030أوقفه
أغلق ذلك البرنامج، أو أوقف التشغيل السابق: Ctrl+C في طرفيته، أو
docker compose downفي مجلده، أوdocker stopلحاوية شغّلتها بـdocker run. ثم شغّل Kinora مرة أخرى.أو شغّل Kinora على منافذ أخرى
مع الحزمة الكاملة في Docker، أنشئ ملفًا باسم
.envفي المجلدkinora-fitness-full-stack، بجوارdocker-compose.yml، يحتوي على المنفذ الذي تحتاجه. ينقلDASHBOARD_PORTلوحة التحكم وAPI_PORTواجهة API؛ وتتبعها العناوين التي تستخدمها التطبيقات تلقائيًا.kinora-fitness-full-stack/.envDASHBOARD_PORT=3040ثم شغّل الأمر نفسه من جديد. بعد تشغيل فاشل يكمل من حيث توقف:
الطرفيةفيkinora-fitness-full-stackdocker 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-stackdocker 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 بعدد الخوادم الوكيلة التي تقف أمامها:
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، لذا تجيب عن كل طلب من البيانات التجريبية داخل المتصفح. وما تغيّره يُحفظ حينها في المتصفح، لا في قاعدة البيانات.
أعطِ لوحة التحكم عنوان واجهة API
أنشئ
dashboard/.envمن.env.exampleإن لم يكن موجودًا. يجب أن يكونNEXT_PUBLIC_API_BASE_URLعنوان واجهة API متضمنًا/api، مثلhttp://localhost:8000/api، وNEXT_PUBLIC_WEBSOCKET_BASE_URLالخادم نفسه من دونه.تحقق من أن واجهة API تستجيب
افتح localhost:8000/api/healthمحلي. يجب أن يجيب بـ
{"status":"ok"}. إذا كان العنوان مضبوطًا لكن واجهة API لا تجيب، فلا تستطيع الصفحات تحميل بياناتها: البيانات التجريبية لا تحل محلها.أعد تشغيل لوحة التحكم أو أعد بناءها
العنوان مُضمَّن أثناء البناء. أعد تشغيل
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، لذا يجب أن يذكرا نطاقك عند استخدامه.
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-stackdocker compose build --no-cache api
docker compose upالمجلد يبدو مختلفًا
شغّل الأوامر داخل المجلد الذي يُستخرج إليه ملف ZIP. إذا لم يكن الأمر unzip متوفرًا، فاستخرجه بمدير الملفات بدلًا من ذلك؛ تضيف بعض الأدوات مجلدًا إضافيًا يحمل اسم ملف ZIP، فانتقل إلى المجلد الداخلي.
| الحزمة | المجلد | يحتوي على |
|---|---|---|
| الحزمة الكاملة | kinora-fitness-full-stack | back-end, dashboard, docker-compose.yml |
| لوحة التحكم | kinora-fitness-dashboard | Dockerfile, package.json, .env.example |
| الخادم | kinora-fitness-backend | Dockerfile, package.json, .env.example |
ابدأ من جديد ببيانات تجريبية جديدة
هذا يحذف بياناتك
يُحذف كل ما أنشأته محليًا، وتُزرع البيانات التجريبية مرة أخرى.
مع Docker Compose، من المجلد kinora-fitness-full-stack:
kinora-fitness-full-stackdocker compose down -v
docker compose upمع حاوية واجهة API منفردة، احذف الحاوية أولًا (يعرضها docker ps -a، ويحذفها docker rm -f مع معرّفها)، ثم احذف وحدة التخزين وشغّلها مرة أخرى:
kinora-fitness-backenddocker 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();