شرح نظام QR Attendance System ============================= 1) السيستم ده بيعمل إيه؟ ------------------------ ده موقع ويب لتسجيل حضور الطلاب للمحاضرات باستخدام QR Code بدل كشف الحضور الورقي أو المناداة على الأسماء. المحاضر بيعمل محاضرة بتاريخ ووقت محددين، ويسجّل الطلاب المسموح لهم فيها، وفي وقت المحاضرة يبدأ جلسة حضور Attendance Session ويعرض كود QR للطلاب. الطالب بيسجل دخول بحسابه، ويفتح صفحة المسح في الموقع ويوجّه الكاميرا للكود، والموقع بيتحقق كمان من موقعه الجغرافي مقارنة بموقع المحاضرة. لو الكود صالح والطالب مسجّل والجلسة شغالة والوقت مسموح والموقع جوه النطاق، بيتسجّل الحضور بحالة "حاضر" أو "متأخر" حسب التوقيت. يعني الكود هنا خاص بالمحاضرة والجلسة، مش كود شخصي لكل طالب. هوية الطالب بتيجي من الحساب اللي عامل تسجيل دخول. السيستم كمان متعدد المؤسسات: كل مؤسسة Organization ليها أعضاء ومحاضرات وبيانات معزولة عن باقي المؤسسات. ده نظام حضور تعليمي، مش نظام بصمة موظفين أو منصة تعليم إلكتروني كاملة. 2) مين بيستخدمه وصلاحيات كل واحد؟ ---------------------------------- الصلاحيات بتتحدد من دور العضوية داخل المؤسسة الحالية، مش من حقل الدور في حساب المستخدم بس. أ) الأدمن Admin (داخل المؤسسة): - عرض قائمة الطلاب وإضافة طالب وتعديل بياناته وحذفه. - بيانات الطالب تشمل: الرقم الدراسي، الاسم، البريد الإلكتروني، رقم الهوية NIC، والكورس أو التخصص. - عند إضافة طالب، السيستم بينشئ له حساب دخول تلقائي مرتبط بملف الطالب. - كلمة المرور الأولية للطالب هي قيمة NIC اللي الأدمن كتبها، وبتتخزن كـ hash مش كنص واضح. - تعديل NIC بعد كده لا يغيّر كلمة المرور تلقائيا؛ كود التعديل بيحدّث بيانات الطالب والاسم والبريد فقط. - إدارة حسابات المحاضرين: إضافة وتعديل وحذف، مع اختيار كلمة مرور عند الإنشاء وإمكانية تغييرها عند التعديل. - إدارة أعضاء المؤسسة: إضافة حساب موجود، تغيير دور العضوية (student/lecturer/admin)، وسحب العضوية مع الاحتفاظ بالسجلات التاريخية. - الأدمن مش واخد تلقائيا صلاحيات المحاضر أو الطالب؛ المسارات بتتحقق من الدور المحدد بالضبط. ب) المحاضر Lecturer: - إنشاء محاضرة بعنوان وتاريخ ووقت بداية ووقت نهاية. - وقت النهاية لازم يكون بعد وقت البداية. - مشاهدة قائمة محاضراته هو فقط، وتعديلها أو حذفها. - إدارة تسجيل الطلاب في المحاضرة: إضافة وإزالة طلاب من قائمة lecture_participants. - تسجيل موقعه الجغرافي على المحاضرة عشان يتحدد نطاق الحضور (geofence). - بدء جلسة حضور للمحاضرة بإعداداته: مدة الحضور في المعاد، سياسة التأخير، مدة سماح التأخير، ووقت قفل التسجيل. - أثناء الجلسة: تعديل الإعدادات، مدّ أو قصّر وقت القفل، قفل يدوي فوري، وإعادة فتح لو مسموح. - فتح صفحة QR للجلسة وعرضه للطلاب، وتنزيله كصورة PNG أو SVG بديل. - متابعة كشف الحضور المباشر لكل محاضرة (roster): من سجّل حاضر ومتأخر ومن لسه ما سجّلش، مع تحديث يدوي أو polling خفيف. - عرض تقارير الحضور بفلاتر (تاريخ/محاضرة/حالة/طالب) وتصديرها Excel أو PDF. - كل ده مقيد بمحاضرات المحاضر نفسه وداخل مؤسسته الحالية فقط. ج) الطالب Student: - تسجيل الدخول وفتح صفحة Scan QR. - السماح للموقع باستخدام الكاميرا والموقع الجغرافي، ومسح QR المحاضرة. - التبديل بين الكاميرات لو الجهاز فيه أكتر من كاميرا. - استلام رسالة نجاح توضح حالة التسجيل (حاضر/متأخر) أو رسالة رفض بسبب واضح. - تكرار المسح لنفس المحاضرة لا ينشئ حضور جديد ولا يغيّر وقت أول تسجيل. د) وظائف مشتركة للحسابات: فيه لوحة رئيسية بتعرض بيانات وإحصائيات حسب الدور (للمحاضر: محاضراته وإحصاءات حضورها)، وإدارة الملف الشخصي وكلمة المرور، وشاشة اختيار/إنشاء المؤسسة والتبديل بين العضويات، وتسجيل خروج. موجودة كمان مسارات نسيان وإعادة تعيين كلمة المرور؛ إرسال الرسائل فعليا محتاج إعداد البريد بشكل صحيح. 3) مثال عملي لدورة الاستخدام ----------------------------- 1. الأدمن يضيف بيانات طالب داخل المؤسسة، فيتعمل له حساب دخول. 2. الأدمن يضيف حساب للمحاضر لو مش موجود، أو مالك المؤسسة يضيفه كعضو بدور lecturer. 3. المحاضر يدخل بحسابه ويعمل محاضرة، مثلا من 10 صباحا إلى 11 صباحا. 4. المحاضر يسجّل الطلاب المسموح لهم في المحاضرة من شاشة Participants. 5. وقت المحاضرة، المحاضر يلتقط موقعه من صفحة المحاضرة/QR ثم يبدأ جلسة الحضور بإعداداته ويعرض الكود. 6. الطالب يدخل بإيميله وكلمة مروره، ويفتح Scan QR من داخل الموقع ويسمح بالكاميرا والموقع. 7. المتصفح يقرأ الكود ويبعت محتواه للسيرفر مع إحداثيات الطالب وجلسة الدخول. 8. السيرفر يراجع بالترتيب: هوية الطالب، صلاحية وتوقيع الكود، تسجيل الطالب في المحاضرة بالظبط، حالة الجلسة، التوقيت بوقت السيرفر، والموقع الجغرافي. 9. لو كل الشروط متحققة، يتسجل حضور بحالة present أو late ووقت المسح، وتظهر رسالة تأكيد. مهم: مسح الكود من كاميرا الموبايل العادية وفتح محتواه مش هو مسار الاستخدام المقصود؛ صفحة المسح داخل الموقع هي اللي بتبعت طلب POST لتأكيد الحضور. 4) إزاي السيستم بيقبل أو يرفض الحضور؟ -------------------------------------- القرار كله بيحصل على السيرفر وبوقت السيرفر بس، بالترتيب ده: 1. المستخدم مسجل دخول ودوره طالب في المؤسسة الحالية، ومرتبط بملف طالب. 2. بيانات QR صحيحة وتوقيعها سليم وصلاحيتها لم تنته، والـ token خاص بجلسة الحضور نفسها. 3. الطالب مسجّل في المحاضرة بالظبط (صف موجود في lecture_participants). حقل course مش وسيلة صلاحية. 4. جلسة الحضور في حالة نشطة (active أو reopened). 5. وقت السيرفر مش قبل بدء الجلسة الفعلي. 6. الجلسة مش مقفولة يدويًا. 7. الوقت مش بعد وقت قفل التسجيل attendance_closes_at. 8. لو الوقت جوه فترة الحضور في المعاد: يتسجل present. 9. لو بعدها: يتسجل late لو late_policy = allow_late ومدة سماح التأخير لسه مفتوحة، وإلا يترفض. 10. موقع الطالب جوه نطاق geofence المسموح وبـ accuracy مقبول. إعدادات جلسة الحضور (بتتحفظ مع بدايتها وبتتغير بعدها بس للمحاولات الجاية): - attendance_window_minutes: عدد دقائق "الحضور في المعاد" بعد بدء الجلسة فعليا. الافتراضي 10 دقائق. صفر معناه مفيش حالة present خالص. - late_policy: allow_late يسمح بالتسجيل المتأخر بحالة late، أو reject يرفض أي مسح بعد فترة المعاد. - late_window_minutes: اختياري؛ لو متحدد، التأخير بيقفل عند أقرب وقت من مهلة التأخير أو وقت القفل. لو null يفضل التأخير مفتوح حتى وقت القفل. - attendance_closes_at: وقت قفل التسجيل نهائيا؛ افتراضيا وقت نهاية المحاضرة المجدول ولازم يكون بعد بداية الجلسة. - حالات الجلسة: scheduled → active → closed / manually_closed، وإعادة الفتح بتدي reopened. إعادة الفتح مش بترجع وقت البداية الأصلي ولا بتعيد مهلة المعاد تلقائيا. - كل تغيير إعدادات بيتسجل في جدول audit باسم الإعداد وقيمته القديمة والجديدة والمستخدم والوقت. - سجلات الحضور الموجودة مابتتعدلش أبدا لما الإعدادات تتغير. مؤقّتان مستقلان لازم نفرّق بينهم: أ) صلاحية QR: افتراضيا 15 دقيقة من لحظة توليده، وقابلة للتغيير من QR_SIGNATURE_EXPIRE_MINUTES. التوقيت ده مستقل تماما عن مواعيد الجلسة: تجديد الكود مابيغيرش بداية الجلسة ولا مواعيدها. كل جلسة ليها qr_secret خاص بيها، فتوقيع الكود مرتبط بالجلسة؛ قفل الجلسة بيبطل الكود فورا حتى لو صلاحيته لسه شغالة، وإعادة فتح الجلسة مش بترجع الكود القديم. ب) مواعيد جلسة الحضور: بداية الجلسة الفعلية started_at، مهلة المعاد on_time_deadline_at، مهلة التأخير المحسوبة، ووقت القفل attendance_closes_at — كلها متخزنة في قاعدة البيانات. مثال: محاضرة من 10 لـ 11، الجلسة بدأت 10:02 بفترة معاد 10 دقائق وتأخير مفتوح حتى القفل 11:00. اللي يمسح من 10:02 لـ 10:12 حاضر، ومن 10:12 لـ 11:00 متأخر، وبعد 11:00 مرفوض حتى لو الكود لسه صالح. لو الكود اتولد 10:00 هينتهي حوالي 10:15 والمحاضر يحتاج يولّد جديد من صفحة QR. أمثلة للرفض أو التنبيه: - الكود غير صحيح أو انتهت صلاحيته أو تابع لجلسة مقفولة. - الطالب مش مسجّل في المحاضرة أو اتشال منها (حذف التسجيل يمنع التسجيل الجديد لكن بيحتفظ بالحضور القديم). - الجلسة مش بدأت، أو مقفولة، أو الوقت بعد القفل أو بعد مهلة المعاد مع رفض التأخير. - الطالب بره نطاق الموقع الجغرافي أو دقة الموقع ضعيفة. - الحساب مالوش ملف طالب مرتبط، أو مالوش عضوية بالدور الصح في المؤسسة. - الحضور متسجل بالفعل؛ السيستم بيرجع تأكيد إنه موجود بدون إضافة سجل مكرر. 5) البيانات متخزنة إزاي؟ ------------------------- الجداول الأساسية: - organizations: المؤسسات؛ عندها مالك owner_user_id وعلامة is_legacy للمؤسسة الترحيلية. - organization_memberships: ربط المستخدم بالمؤسسة مع دور العضوية (student/lecturer/admin) وقيد فريد على الاتنين معا. - users: حسابات الدخول؛ الاسم والبريد وكلمة المرور والدور وdefault_organization_id للمؤسسة المختارة. - students: بيانات الطلاب وربط كل طالب بحساب user؛ القيود الفريدة (الرقم الدراسي والبريد وNIC) بقت لكل مؤسسة. - lecturers: ملف المحاضر وربطه بحساب user؛ unique على (المؤسسة + المستخدم) و(المؤسسة + البريد). - lectures: عنوان المحاضرة وتاريخها ومواعيدها وصاحبها + أعمدة الموقع الجغرافي للمحاضرة ونطاق السماح. - lecture_participants: تسجيل الطلاب في المحاضرات، بقيد فريد (lecture_id, student_id) ومفاتيح مركبة مع المؤسسة للعزل. - attendance_sessions: جلسة حضور واحدة لكل محاضرة؛ الحالة، الإعدادات، وأوقات البداية والمهلات والقفل وqr_secret وإعادة الفتح. - attendance_session_audits: سجل تدقيق لكل تغيير إعدادات جلسة (مين غيّر إيه وإمتى). - attendances: ربط الطالب بالمحاضرة والجلسة مع scanned_at وحالة الحضور attendance_status. ملاحظة تقنية: lecturer_id في جدول lectures بيرجع إلى users، مش إلى جدول lecturers. جدول الحضور بيحتفظ بنسخة من اسم الطالب وعنوان وتاريخ المحاضرة وقت التسجيل، وفيه قيد unique على الطالب والمحاضرة معا لمنع التكرار مع استخدام firstOrCreate/معاملات. العزل بين المؤسسات: كل جدول tenant فيه organization_id، وTrait مشترك BelongsToOrganization بيضيف scope تلقائي للمؤسسة الحالية وبيمنع الكتابة أو الحذف أو إعادة الإسناد عبر مؤسسة تانية؛ المؤسسة الحالية بتتحدد من العضوية على السيرفر (Middleware: ResolveOrganization) مش من قيمة بيبعتها العميل. بيانات التشغيل القديمة اترحلت لمؤسسة اسمها Legacy Organization: كل المستخدمين والطلاب والمحاضرين والمحاضرات والتسجيلات اتربطوا بيها، فما فيش سجلات اتحذفت ولا اتنقلت. التراجع عن ترحيل المؤسسات مش تلقائي؛ الملف بيرمي استثناء في down()، فالرجوع يحتاج نسخة احتياطية مؤكدة قبل الترقية أو ترحيل أمامي مُراجَع. علاقات الحذف cascade لسه موجودة: حذف الطالب أو المحاضرة ممكن يحذف سجلات الحضور المرتبطة. 6) الموجود فعلا وحدود النسخة الحالية ------------------------------------ الموجود: - إدارة المؤسسات والعضويات والأدوار لكل مؤسسة والتبديل بينها. - إدارة الطلاب والمحاضرين وتسجيل الطلاب في محاضرات محددة. - إدارة المحاضرات، والموقع الجغرافي للمحاضرة مع التحقق من geofence. - جلسات حضور بحالات صريحة وإعدادات قابلة للتعديل وسجل تدقيق. - توليد وعرض وتنزيل QR مرتبط بالجلسة، وتسجيل الحضور بالكاميرا بحالة حاضر/متأخر. - كشف حضور مباشر لكل محاضرة مع أعداد المسجلين والحاضرين والمتأخرين واللي ما سجلوش. - تقارير حضور بفلاتر وتصدير XLSX وPDF، مع حماية من حقن المعادلات في خلايا Excel. - منع التكرار والحماية من IDOR على مستوى المحاضر والمؤسسة في المسارات والتصدير. غير موجود حتى الآن: - إنشاء صفوف "غائب" فعلية تلقائيا لكل طالب ما سجّلش؛ العدد الغائب مشتق من التسجيل مقابل الحضور، والتصدير بيعرض absent كحالة محسوبة. - WebSockets أو إشعارات لحظية؛ التحديث المباشر بيتم بطلبات HTTP خفيفة. - إشعار بريد/دفع مخصص بعد نجاح تسجيل الحضور. - إدارة متكاملة للمواد والشعب الدراسية؛ التسجيل لسه لكل محاضرة على حدة. - فوترة أو اشتراكات؛ خارج نطاق النظام الحالي. - تعرّف على الوجه أو تحقق بيومتري؛ الـ geofence يقلل التحايل لكنه مش إثبات حضور شخصي كامل. 7) ملاحظات مهمة قبل الاستخدام الحقيقي --------------------------------------- - موجود تسجيل عام للحسابات من register. بيعمل user بدور student افتراضيا، لكنه لا ينشئ ملف students ولا عضوية مؤسسة؛ المسار المكتمل هو إضافة الطالب من أدمن المؤسسة أو إضافة العضو من شاشة المؤسسات. - رغم وجود verified middleware ومسارات تأكيد بريد، موديل User لا يطبق MustVerifyEmail. - كلمة المرور الأولية المبنية على NIC يُفضّل تغييرها بعد أول دخول، ومفيش إجبار برمجي على ذلك. - لازم ضبط المنطقة الزمنية للسيرفر؛ القيمة الافتراضية في config/app.php هي Asia/Colombo ويمكن تغييرها من APP_TIMEZONE. - الكاميرا والموقع الجغرافي محتاجين إذن المتصفح وسياقا آمنا عادة: HTTPS أو localhost. على شبكة محلية عبر HTTP ممكن الاتنين ميشتغلوش. - قيم geofence الافتراضية: نطاق 20 متر (GEOFENCE_RADIUS_M) ودقة قصوى 50 متر (GEOFENCE_MAX_ACCURACY_M). - مكتبة قراءة QR محمّلة من CDN، فتعطل الوصول للمصدر الخارجي ممكن يعطّل المسح. - أجهزة الطلاب لازم تقدر توصل لسيرفر الموقع؛ تشغيله على الكمبيوتر لا يجعل localhost على الموبايل يشير لنفس الكمبيوتر. - ما تغيّرش مفتاح التطبيق في تشغيل قائم بدون تخطيط؛ وكل جلسة ليها سرها الخاص، وقفلها يبطل أكوادها. - قبل نشر ترحيل المؤسسات على قاعدة بيانات موجودة: خد نسخة احتياطية مؤكدة، لأن التراجع التلقائي غير متاح. 8) التقنيات المستخدمة وبنية الكود --------------------------------- - Laravel 12 وPHP للـ backend. - Laravel Breeze لوظائف الحسابات وتسجيل الدخول. - Blade لصفحات الموقع، مع Tailwind CSS وAlpine.js للواجهة. - Vite لتجميع ملفات الواجهة. - Simple QrCode لتوليد الأكواد، وhtml5-qrcode لقراءة QR بكاميرا المتصفح. - Spatie Image وImage Optimizer ضمن مسار تحسين صور QR عند التنزيل. - Maatwebsite/Excel وPhpSpreadsheet لتصدير XLSX، وBarryvdh DomPDF لتصدير PDF. - المشروع موثق للاستخدام مع MySQL أو MariaDB، والاختبارات بتستخدم SQLite في الذاكرة. أهم الملفات لفهم الوظائف: - routes/web.php: تقسيم المسارات حسب الأدوار والمؤسسة. - app/Support/TenantContext.php + app/Http/Middleware/ResolveOrganization.php: تحديد المؤسسة الحالية من العضوية. - app/Support/BelongsToOrganization.php: العزل التلقائي لنماذج المؤسسة. - app/Http/Controllers/OrganizationController.php: إنشاء المؤسسات وإدارة الأعضاء والتبديل. - app/Http/Controllers/StudentController.php وLecturerController.php: إدارة الطلاب والمحاضرين. - app/Http/Controllers/LectureController.php + LectureParticipantController.php: المحاضرات وتسجيل الطلاب وتوليد QR. - app/Http/Controllers/AttendanceSessionController.php + app/Services/AttendanceSessionService.php: دورة حياة الجلسة وإعداداتها والتدقيق. - app/Http/Controllers/AttendanceController.php + app/Services/AttendanceCheckInService.php + app/Support/Geo.php: قرار تسجيل الحضور والتحقق من الموقع. - app/Http/Controllers/LectureRosterController.php + app/Services/LectureRosterService.php: كشف الحضور المباشر. - app/Http/Controllers/ReportController.php + app/Services/AttendanceReportService.php + app/Exports: التقارير والتصدير. - app/Http/Middleware/RoleMiddleware.php: منع الوصول للدور غير المسموح. - database/migrations: تعريف الجداول بما فيها geofence والجلسات والمؤسسات. - resources/views/lectures/attendance-session.blade.php وparticipants.blade.php وroster، وreports/attendance.blade.php، وorganizations.blade.php، وattendance/scan.blade.php. ملحوظة: بعض أجزاء README قديمة عن الوضع الحالي؛ الشرح هنا مبني على التنفيذ الفعلي، مش README وحده. الخلاصة -------- المؤسسة بتجمّع الأعضاء بأدوار، الأدمن يجهّز حسابات الطلاب والمحاضرين، المحاضر يجهّز المحاضرة ويسجّل طلابها ويحدد موقعها، يبدأ جلسة حضور بإعداداته ويعرض QR مؤقت، والطالب يمسح الكود من داخل الموقع بكاميرا وموقع صالحين فيتسجل حاضر أو متأخر حسب سياسة الجلسة. المحاضر يتابع الكشف المباشر ويصدّر التقارير، وكل مؤسسة معزولة بالكامل عن غيرها. نطاق الشرح: مراجعة للكود والمسارات والجداول، وليس نتيجة تجربة تشغيل شاملة للكاميرا أو قاعدة البيانات.