انتقل إلى المحتوى
نسخة تجريبية مباشرة

دليل الطالب — منصة الحرم الجامعي الرقمية

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

الدور
تصميم المنتج والتطوير الكامل
التصنيف
منصة تعليمية
الحالة
نسخة تجريبية عامة مباشرة
التقنيات
PHP 8.3 · MySQL 8 · no framework

نظرة عامة

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

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

المشكلة

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

ما الذي يقدّمه دليل الطالب

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

دوري

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

الاستراتيجية: أجب عن خمسة أسئلة، ثم توقّف

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

لذلك أُعيدت صياغة المهمة كخمسة أسئلة يطرحها الطالب فعلًا، بالترتيب الذي تخطر به على باله:

  1. ما محاضراتي اليوم؟
  2. أين محاضرتي القادمة، وكم بقي لديّ من وقت؟
  3. أي قاعة فارغة الآن؟
  4. ما الذي يحتاج انتباهي؟
  5. بماذا يمكنني أن أشارك؟

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

هندسة المعلومات

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

يحصل الموظفون والمسؤولون على شاشات إضافية داخل الهيكل نفسه بدل لوحة تحكم منفصلة — فعضو هيئة التدريس الذي يراجع طلبًا يبعد ضغطة واحدة عن الجدول الذي كان ينظر إليه.

ثلاثة أدوار، هيكل واحد

طالب

لوحة بعدّ تنازلي حيّ، وجدول لليوم والأسبوع والأجندة مع كشف التعارضات، وباحث القاعات، والحجوزات وتسجيل الحضور عبر QR، والطلبات الأكاديمية، والانتخابات، والإشعارات والتفضيلات.

هيئة تدريس

جدول التدريس، وقاعات اليوم مع الإتاحة اللحظية، وقائمة مراجعة: أخذ الطلب إلى المراجعة، والموافقة أو الرفض أو طلب التعديل، إضافة إلى ملاحظات داخلية لا يراها الطالب إطلاقًا.

مدير النظام

المستخدمون والأدوار، والمباني والقاعات، والمساقات، والإعلانات التي تُرسَل كإشعارات، وأنواع الطلبات، والانتخابات وإظهار النتائج، والتقارير مع التصدير إلى CSV، وسجل النشاط.

محرّك إتاحة القاعات

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

لا يوجد عمود is_free في أي مكان. تكون القاعة مشغولة في فترة ما إذا تداخلت معها محاضرة متكررة في ذلك اليوم من الأسبوع، أو تداخل معها حجز غير ملغى. والتداخل هو المقارنة نصف المفتوحة المعتادة — a.start < b.end AND b.start < a.end — لذا تتّسع الفترتان 10:00–11:00 و11:00–12:00 معًا، وهو ما يُفترض أن يفعله حجزان متتاليان.

يجري الحجز داخل معاملة تأخذ أولًا قفلًا على صف القاعة. وهذا يُسلسل كل المحاولات المتزامنة على القاعة نفسها، فلا يمكن لفحص التداخل الذي يليه أن يُسبَق بطلب ثانٍ يصل بعده بجزء من الثانية. ومفتاح فريد على الفترة يمثّل خط دفاع ثانٍ أخشن.

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

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

طلبات أكاديمية لا تتعثّر

خمسة أنواع من الطلبات — نشاط، ودعم أكاديمي، ووثيقة، وبلاغ عن عطل، وخدمة طلابية — يعلن كل نوع منها حقوله في JSON. وهذا الإعلان يقود النموذج المعروض والتحقق على الخادم معًا، فلا يمكن إرسال حقل لم يعلنه النوع، والحمولة التي تحمل status or is_admin تُحذف منها هذه المفاتيح بدل تخزينها.

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

رفض الطلب أو طلب التعديل يستلزم سببًا. فالطالب الذي يُقال له «مرفوض» دون تفسير مضطر لبدء المحادثة من جديد، ولذلك لا يُرسَل النموذج دون سبب.

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

الانتخابات: فصل الناخب عن الصوت

وحدة انتخابات طلابية تستدعي سؤالًا بديهيًا — هل يستطيع من يدير قاعدة البيانات أن يرى لمن صوّتُ؟ كان لا بدّ أن تكون الإجابة الصادقة لا، وأن تكون بنيوية لا مجرد وعد.

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

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

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

نسخة تجريبية عامة تصمد أمام الجمهور

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

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

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

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

الأمان

  • وسيط CSRF يُحقن قبل وسطاء المسارات، فيصبح أي مسار جديد يغيّر الحالة محميًا افتراضيًا. ويمسح اختبارٌ كل مسار غير GET في المُوجِّه ويتأكد أن كلًا منها يعيد 419 دون رمز.
  • فحوص أدوار على الخادم لكل مسار مميّز، إضافة إلى فحوص ملكية لكل سجل — فلا يستطيع الطالب قراءة طلب طالب آخر، أو إلغاء حجز مستخدم آخر، أو تعليم إشعار غيره كمقروء.
  • عبارات مُجهّزة في كل مكان مع تعطيل المحاكاة؛ وأسماء الأعمدة في الاستعلامات الديناميكية تأتي من قوائم سماح ثابتة، لا من المدخلات أبدًا.
  • تحديد لمحاولات الدخول على الحساب وعلى عنوان المصدر معًا، مع تخزين المعرّفات كبصمة SHA-256 فقط.
  • المرفقات مقيّدة بنوع المحتوى المكتشف فعليًا، وتُخزَّن خارج جذر الويب باسم يولّده الخادم، ويُعاد التحقق منها بنمط صارم قبل قراءة أي ملف.
  • سياسة أمان محتوى default-src 'self' دون unsafe-inline في أي موضع — وهو ممكن لأن خريطة الحرم تحدد مواضع العناصر بسمات SVG، وأشرطة التقارير تستخدم أصناف عرض مولّدة بدل أنماط مضمّنة.

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

العربية والإنجليزية على قدم المساواة

٥١٤ مفتاح ترجمة لكل لغة، مع اختبار يُفشل البناء إذا اختلفت مجموعتا المفاتيح، أو كانت أي قيمة فارغة، أو اختلفت متغيرات الاستبدال بين اللغتين، أو بقيت قيمة عربية نسخة من الإنجليزية.

المحتوى ثنائي اللغة في نموذج البيانات نفسه لا في طبقة ترجمة: المساقات والقاعات والمباني والإعلانات والمرشحون جميعها تحمل أعمدة مزدوجة، فالعربية محتوى حقيقي لا عرضٌ للإنجليزية.

يستخدم التخطيط الخصائص المنطقية في CSS في كل موضع — margin-inline-start, border-inline-start, inset-inline-* — ولهذا يكون العرض من اليمين إلى اليسار انعكاسًا حقيقيًا دون أي تجاوزات خاصة بالاتجاه. وتُعرض التواريخ بالتقويمين الميلادي والهجري، وتُعرض الأرقام بالصيغة العربية الهندية، عبر امتداد intl .

ما الذي كسره اتجاه اليمين إلى اليسار فعلًا. أمران، اكتُشفا بالنظر لا بالافتراض. سهم القائمة المنسدلة كان مرسومًا بتدرّجين في CSS يشكّلان مثلثًا؛ وعند الانعكاس كوّن النصفان علامة مشوّهة، فصار سهمًا واحدًا متماثلًا بصيغة SVG. كما أن صف تصفية الحالات بالعربية أعرض من نظيره الإنجليزي — بما يكفي لدفع الصفحة جانبًا عند عرض 360 بكسل — فصار يتمرر داخل نفسه.

الجوال وإمكانية الوصول

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

كشف هذا القياس عيوبًا حقيقية: تجاوز أفقي في الشبكة سببه القيمة الافتراضية min-width: auto على أبناء الشبكة، وعناوين تبويب تلتفّ وتُقتطع عند 360 بكسل، واقتطاع نصّي لا يعمل لأن text-overflow لا ينطبق على العناصر السطرية، وعدة عناصر تفاعلية دون هدف اللمس 44 بكسل. عولجت جميعها ثم أُعيد القياس.

  • كل عنصر تفاعلي يحقق 44×44 بكسل عند أي عرض.
  • تركيز لوحة مفاتيح مرئي، ورابط تخطٍّ، وعناوين دلالية، وحقول موسومة، وتسميات توضيحية للجداول.
  • المحتوى العريض يتمرر داخل حاويته، ولا يتمرر جسم الصفحة جانبًا أبدًا.
  • prefers-reduced-motion مُحترَم؛ و prefers-color-scheme مُطبَّق مع إمكانية التجاوز الصريح.

البنية التقنية

PHP 8.3 على MySQL 8 مع صفر اعتماديات تشغيل. لا يوجد ملف composer.json لأنه لا شيء لتثبيته: المُوجِّه وطبقة الخدمات والمُحقِّق والمترجم ومدير الترحيلات ومشغّل الاختبارات كلها جزء من التطبيق.

كانت تلك مقايضة مقصودة. إطار عمل كان سيوفّر أسبوعًا ربما؛ وعدم استخدامه يعني أن هذا المشروع سيظل يُثبَّت ويعمل بعد سنوات بأمر git cloneوقاعدة بيانات وأمرين اثنين — وكل سطر من سلوكه قابل للفحص في مستودع واحد.

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

الاختبار

٥٥٦ تأكيدًا موزعة على مجموعات الوحدة والوظائف والأمان، تُرسَل عبر النواة الحقيقية داخل العملية — فالتوجيه والوسطاء وحماية CSRF والتفويض والمتحكمات والقوالب تشارك جميعها. هذه اختبارات وظيفية لا محاكاة.

وحدات

مصفوفة تداخل الإتاحة، وحراسات تسجيل الحضور، والجدول وكشف التعارضات، وفرض صوت واحد في الانتخابات وسرية الاقتراع، وقواعد التحقق.

الوظائف

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

الأمان

مسح شامل لحماية CSRF على كل مسار يغيّر الحالة، والحقن والهروب، والتحكم في الوصول ومعالجة الملفات، والترويسات وتسرّب الأسرار.

ترفض المجموعة العمل على بيئة إنتاج أو على قاعدة بيانات لا تحمل اسم هذا المشروع، وتعيد أي حالة تغيّرها فلا يترك التشغيل أثرًا.

النشر

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

  • مستخدم نظام مخصص، ومجمّع PHP-FPM ومقبس ودليل جلسات وقاعدة بيانات ومستخدمو قاعدة بيانات بأقل الصلاحيات — مع open_basedir لا يمكنه الوصول إلى أي تطبيق آخر.
  • نقطة استعادة موثّقة قبل كل عملية نشر، تسجّل التطبيق وقاعدة البيانات والإعدادات وحالة الخدمات وخط أساس صحّي لكل موقع مستضاف معه، ومجاميع التحقق الخاصة بها.
  • يتحقق المثبّت من php-fpm -t and nginx -t قبل إعادة تحميل أي شيء، ويرفض أي حزمة تحتوي على ملفات PHP في جذر الويب أو أي ملف قابل للكتابة من الجميع.
  • سكربت تراجع مُختبَر، ونسخ احتياطية ليلية تُختبر استعادتها في قاعدة بيانات منفصلة.

خللان كشفتهما عملية النشر نفسها. قاعدة دفاع متعمّق في nginx تمنع أسماء أدلة الشيفرة كانت تطابق بصمت مسار /app/ الخاص بالتطبيق نفسه، فتعيد 404 لكل مسار بعد تسجيل الدخول — واكتُشف ذلك بالتحقق من الإنتاج لا بافتراض سلامته. كما أن الملفات الثابتة المخدومة بترويسة immutable لمدة شهر كانت تعني أن تغييرًا في CSS لن يصل إلى زائر عائد، فصارت روابط الملفات تحمل بصمة لكل إصدار.

نتائج موثّقة

556اختبار آلي ناجح
514مفتاح ترجمة لكل لغة، مع فرض التطابق
0اعتماديات تشغيل
0أخطاء خادم منذ النشر

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

هذه نتائج هندسية. ولا توجد هنا أرقام تبنٍّ أو استخدام لأن المنتج بلا مستخدمين — فهو عرض توضيحي، واختلاق رواج له ينسف الغاية من نشر الشيفرة.

الحدود، بصراحة

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

شاهده وهو يعمل

النسخة التجريبية عامة ومزوّدة ببيانات وهمية. سجّل الدخول بصفة طالب أو عضو هيئة تدريس أو مسؤول — الحسابات معروضة في صفحة الدخول — وتُعاد البيانات كل ليلة.