نظام إدارة نادٍ رياضي

GYM 80

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

دوري بالمشروع
تصميم وتطوير كامل (Full-Stack)
النوع
لوحة تحكم ويب + API للأجهزة
بدون
أي فريمورك أو خطوة بناء
PHP 8 MySQL 8 / PDO Vanilla JS REST API RTL كامل
لوحة التحكم · متصفح
gym80.local 768px
01 — نظرة عامة

الفكرة والمشكلة

أغلب النوادي تدير اشتراكاتها بدفتر أو بملف إكسل: ما تعرف مين اشتراكه خلص إلا لما يجي للباب، ولا تعرف كم جمعت هذا الشهر إلا بالحساب اليدوي، ولا تقدر تمنع عضو معيّن من الدخول بدون ما تعتمد على ذاكرة موظف الاستقبال. GYM 80 يحوّل هذا كله لنظام واحد: كل اشتراك له تاريخ بداية ونهاية وحالة دفع، والنظام نفسه يحسب من هو الفعّال ومن هو المنتهي ومن قرب ينتهي — ويعطي البوابة قرارًا جاهزًا بدل الاجتهاد البشري.

ملف عضو كامل — رقم PIN ثابت لكل عضو، اسم، هاتف، تاريخ ميلاد، وصورة شخصية مرفوعة ومُتحقَّق منها كصورة حقيقية (مو بالامتداد فقط).

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

لوحة تحكم تنبيهية — ستة مؤشرات فورية (إجمالي الأعضاء، الفعّالة، المنتهية، القريبة من الانتهاء، إيراد الشهر، مشتركون جدد) وقوائم جاهزة بالاشتراكات اللي على وشك الانتهاء وبالمنتهية فعلًا.

تجديد بضغطة وحدة — زر تجديد بجانب كل عضو بالقوائم يفتح نافذة سريعة تحسب تاريخ الانتهاء الجديد تلقائيًا حسب المدة المختارة.

تقارير مالية بمدى تاريخي — من تاريخ / إلى تاريخ، مع إجمالي المحصّل، عدد الاشتراكات، متوسط قيمة الاشتراك، والمستحقات غير المدفوعة، قابلة للتصدير والطباعة.

سجل دخول موثّق — كل محاولة تحقق (ناجحة أو فاشلة) تُسجّل بالاسم والرقم والنتيجة وعنوان الـ IP والوقت، فتبقى عندك مرجعية كاملة لحركة الباب.

إيقاف وصول يدوي — الأدمن يقدر يمنع أي عضو من الدخول بغض النظر عن اشتراكه، والمنع له الأولوية على كل الحالات الثانية.

02 — ربط بوابة الدخول

بصمة وجه أو بطاقة RFID · نفس نقطة القرار

النظام ما يفترض نوع جهاز معيّن عند الباب. نقطة التحقق POST /api/verify.php تستقبل رقم العضو وترجّع قرار وصول جاهز بالعربي، وهذا يخلي أي جهاز يقدر يستخدمها: قارئ بطاقات RFID/NFC يحوّل رقم البطاقة لرقم العضو ويرسله، أو بوابة تعرّف على الوجه تتعرّف على العضو محليًا وترسل رقمه، أو حتى موظف استقبال يدخل الرقم بيده من صفحة التحقق. الثلاثة يوصلون لنفس الجواب من نفس المصدر — فما يصير عندك نسختين من الحقيقة.

مسار قرار الدخول
RFID reader Face terminal Admin browser verify.php X-API-KEY · 60 req/min members PIN lookup subscriptions status calc logs every attempt Database MySQL 8 Uploads photos PHP 8 · Apache single server
# الجهاز عند الباب يرسل رقم العضو فقط
curl -X POST https://gym80.local/api/verify.php \
  -H "X-API-KEY: <مفتاح الجهاز>" \
  -H "Content-Type: application/json" \
  -d '{"pin": "1001"}'

# والرد يحمل القرار + بيانات العرض على شاشة البوابة
{
  "status": "valid",
  "member": { "name": "...", "photo_url": "/uploads/members/1001.jpg" },
  "subscription": { "end_date": "2026-04-01", "days_remaining": 12 },
  "message_ar": "الاشتراك فعّال"
}
validاشتراك فعّال — البوابة تفتح، وتقدر تعرض اسم العضو وصورته على الشاشة.
expiring_soonفعّال لكن باقي له أيام معدودة — تفتح مع تنبيه للعضو بأن اشتراكه قارب على الانتهاء.
expiredالاشتراك منتهي — ترفض مع عدد الأيام اللي مرّت على الانتهاء.
unpaidالاشتراك الأخير مسجّل كغير مدفوع — ترفض وتحوّله للاستقبال.
disabledعضو موقوف يدويًا من الإدارة — ترفض دائمًا، حتى لو اشتراكه فعّال ومدفوع.
not_foundرقم غير موجود أصلًا — بطاقة غير مسجّلة أو وجه غير معروف.
🔑

مفتاح مستقل لكل جهاز — كل بوابة أو قارئ ياخذ مفتاح X-API-KEY خاص فيه، يتولّد ويتعطّل من الإعدادات بدون ما تلمس بقية الأجهزة. الجهاز اللي ينسرق أو ينفصل، تلغي مفتاحه وخلص.

⏱️

حد استخدام تلقائي — 60 طلب بالدقيقة لكل مفتاح، فجهاز معطّل أو سكربت مكرر ما يقدر يغرق السيرفر.

🧾

كل محاولة تُسجّل — الرقم والنتيجة وعنوان الـ IP والوقت، تظهر بصفحة "سجل الدخول" بلوحة التحكم، سواء جت من البوابة أو من موظف الاستقبال.

📡

نقاط إضافية للأجهزةGET /api/member.php يرجّع ملف العضو وسجل اشتراكاته الكامل، و GET /api/expiring.php يرجّع كل من قرب اشتراكه على الانتهاء — مفيدة لشاشة استقبال أو تنبيهات تلقائية.

نتيجة تحقق فورية من رقم عضو — الاشتراك فعّال
نفس القرار اللي ترجعه أي بوابة — نتيجة تحقق فورية بالاسم والحالة والأيام المتبقية
سجل كل محاولة تحقق بالنتيجة وعنوان IP
سجل الدخول — كل محاولة ناجحة أو مرفوضة، من أي جهاز، بالوقت وعنوان IP
03 — لوحة التحكم

كل شي بصفحة وحدة

اللوحة مبنية بقائمة جانبية ثابتة: الرئيسية، الأعضاء، البحث، تسجيل الدخول، سجل الدخول، التقارير المالية، الإعدادات. الصفحة الرئيسية تفتح على ستة مؤشرات — إجمالي الأعضاء، الاشتراكات الفعّالة، المنتهية ولم تُجدَّد، القريبة من الانتهاء، إيراد الشهر الحالي، والمشتركين الجدد هذا الشهر — وتحتها مباشرة قائمتان عمليتان: من قرب اشتراكه على الانتهاء ومن انتهى فعلًا، وكل صف فيها عنده زر تجديد فوري. وبالأسفل آخر عشر عمليات دخول، عشان تعرف بنظرة وحدة شنو صار اليوم على الباب.

عتبة التنبيه قابلة للضبط — تحدد من الإعدادات كم يوم قبل الانتهاء يُعتبر الاشتراك "قريب الانتهاء"، والنظام كله (اللوحة والـ API) يمشي على نفس الرقم.

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

بحث سريع — بالاسم أو الرقم أو الهاتف، للوصول لملف أي عضو بثوانٍ وقت الازدحام على الاستقبال.

الصفحة الرئيسية بلوحة GYM 80 — المؤشرات والاشتراكات القريبة من الانتهاء والمنتهية
الرئيسية — ستة مؤشرات فورية، قوائم عمل جاهزة، وآخر عمليات الدخول
قائمة الأعضاء مع الحالة وتاريخ الانتهاء
قائمة الأعضاء — بحث وفلترة حسب الحالة
ملف عضو كامل بسجل اشتراكاته
ملف العضو — سجل اشتراكات كامل لا يُعدَّل
04 — التقارير المالية

من تاريخ… إلى تاريخ

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

تقرير مالي بمدى تاريخي مع إجمالي المحصّل والمستحقات
تقرير مالي بمدى تاريخي — خمسة أرقام + جدول تفصيلي لكل عملية
05 — الأمان

مبني على أساس آمن من البداية

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

🛡️

PDO بالكامل — كل استعلام SQL بالنظام يمر بعبارات مُجهّزة (Prepared Statements)، فما فيه أي مكان يُدمج فيه إدخال المستخدم داخل الاستعلام.

🛡️

CSRF على كل عملية — كل فورم وكل طلب Fetch يغيّر بيانات يحمل توكن مرتبط بالجلسة ويُتحقق منه بالسيرفر.

🛡️

رفع صور محكوم — الصورة تُفحص كصورة حقيقية بمحتواها لا بامتدادها، بحد أقصى للحجم، وتُعاد ترميز PNG إلى JPEG — ومجلد الرفع نفسه معطّل فيه تنفيذ PHP.

🛡️

كلمات المرور مُعمّاة — تُخزّن بـ password_hash() وتُتحقق بـ password_verify()، وتقدر تغيّرها من الإعدادات.

🛡️

مفتاح الـ API ما يوصل للمتصفح — صفحات الأدمن ما تحمل المفتاح بأي JavaScript؛ التحقق من داخل اللوحة يمر عبر وسيط محمي بالجلسة، والمفتاح يبقى حصرًا بين الجهاز والسيرفر.

صفحة الإعدادات: عتبة التنبيه، تغيير كلمة المرور، ومفاتيح API لأجهزة الاستقبال
الإعدادات — عتبة التنبيه، تغيير كلمة المرور، وإدارة مفاتيح API لكل جهاز
06 — البنية التقنية وبيئة التشغيل

التقنيات المستخدمة

لا فريمورك ولا خطوة بناء — PHP 8 وMySQL وJavaScript مباشرة، على خادم Apache عادي يشتغل بموارد بسيطة ويكفي نادي كامل.

خادم النظام · Linux
root@gym80: ~ $ systemctl status apache2 active (running) since 18d ago [ 0.412] apache2: reload ok · 4 workers [ 0.733] ufw: 22/tcp 443/tcp allow [ 1.058] fail2ban: 0 banned · armed $ METRICS CPU MEM NET UPTIME 18d 04:21:07 web-01 debian 12 · apache2 cpu 0.34 · 2 vCPU load 0.41 0.38 0.33 HEALTHY db-01 debian 12 · mysql 8 conns 42 · repl ok disk 61% · iops 1.2k HEALTHY backup-01 debian 12 · rsync last backup · 2h ago size 1.8 / 20 GB HEALTHY

🖥️ الواجهة

  • HTML/CSS خام — نظام تصميم واحد
  • Vanilla JS — بدون مكتبات
  • Fetch API — تحديث بدون إعادة تحميل
  • RTL عربي كامل

⚙️ الباك اند

  • PHP 8 — بدون فريمورك
  • MySQL 8 / MariaDB
  • PDO — عبارات مُجهّزة
  • GD — معالجة صور الأعضاء

📡 API الأجهزة

  • REST / JSON — عربي UTF-8 خالص
  • X-API-KEY — مفتاح لكل جهاز
  • Rate limit — 60 طلب/دقيقة
  • سجل تحقق — لكل محاولة
→ رجوع لكل المشاريع