تطبيق الجامعة — دليل الفريق الكامل
إحنا فين دلوقتي، وإيه اللي اتعمل، وليه اتعمل كده، وإيه اللي فاضل عشان نخلّص. دليل عملي للموبايل تيم والباك إند تيم — شاشة شاشة، بأرقام حقيقية من داتابيز شغالة.
★ الجديد ٢ — الحضور، حجز الساعات المكتبية، رسالة للسكاشن، الخطط الدراسية
طلبات نادر الخمسة: اتعمل فيها إيه، إنت كموبايل تنادي إيه وتقرا أنهي حقل، وإيه اللي بيتظبط من الأدمن.
كله متنزّل على السيرفر (109.123.243.32:9300)، ومعروض في الديمو (:9301) بنفس الريكوستات.
الجولة اللي قبلها (ميتنج 30 سبتمبر) لسه تحت في الجديد ١.
كل الحقول القديمة زي ما هي — اللي اتضاف حقول وروابط جديدة بس، ومفيش عمود ولا جدول اتضاف للداتابيز: الحجوزات وجلسات الـ QR متخزّنة في داتا السيرفس (JSON جنب بروفايل الأدمن)، والإعدادات في الأدمن.
تغيير في المعنى لازم تاخد بالك منه — كشف الحضور:
قبل كده «مالوش سطر غياب» كان معناه «حاضر». دلوقتي زي البورتال بالظبط: الحاضر ليه سطر (ATTEND_FLG = 1)،
والمتأخر ليه سطر تأخير، واللي مالوش أي سطر يبقى «لسه ماتاخدش» مش «حاضر».
يعني: ماتستنتجش الحالة من EdStudAbsenceId (الحاضر بقى عنده رقم) — اقرا AttendanceState اللي بقى جاي مع كل طالب.
وعلى Innovation الاعتماد اتلغى من الأدمن: ApprovalRequired: false ← خبّي زرار «اعتماد»، وكل علامة نهائية أول ما تتحفظ.
| # | المطلوب | اتعمل إيه | الموبايل يعمل إيه | ⚙️ من الأدمن | فين |
|---|---|---|---|---|---|
| 1 | الدكتور يبعت رسالة لكل طلبة المقرر — ولو عنده أكتر من سكشن يختار | رسالة واحدة بتتبعت لكل طالب في سكاشن الدكتور هو بس في المقرر (أو السكاشن اللي اختارها)، والطالب ياخدها مرة واحدة حتى لو في سكشنين. | academicstaff/SendMessageToCourse بـ EdCourseId + ScScheduleDtlIds (فاضية = كل سكاشنه). السكاشن من academicstaff/GetMySections. | مفيش | تفاصيل ↓ |
| 2 | جدول محاضرات الدكتور يظهر فيه حجوزات الساعات المكتبية | جدول الدكتور وجدول الطالب الاتنين بيرجّعوا الحجوزات الجاية جنب المحاضرات. | اقرا officeHourBookings[] الجديدة في رد academicstaff/GetStaffSchedule وstudents/schedule. | مفيش | تفاصيل ↓ |
| 3 | لو طالب حجز ميعاد، الدكتور مايقدرش يحذفه أو يعدّله — والحجوزات ترجع مع المواعيد | حجز كامل: الطالب يشوف المواعيد المتاحة ويحجز/يلغي، الدكتور يشوف مين حاجز وإمتى وعن إيه، ويلغي بسبب بيوصل للطالب. الميعاد المحجوز بيرفض التعديل والحذف. | دكتور: Bookings[] وHasBookings في academicstaff/GetMyOfficeHours، وإلغاء بـ academicstaff/CancelOfficeHourBooking. طالب: students/GetOfficeHourOpenings وstudents/BookOfficeHour. | Attendance & office hours ← Office-hour booking | تفاصيل ↓ |
| 4 | بيانات الجامعة/الكلية/البرنامج ترجع معاها الخطط الدراسية | كل برنامج في الشجرة معاه Plan: الحزم (إجباري/اختياري…) بساعاتها ومقرراتها — من غير لوجين. |
GET Info/University (فيها الخطط)، أو ?plans=false للشجرة خفيفة + GET Info/AcademicPlan?programId= لبرنامج واحد. | University ← Show study plans | تفاصيل ↓ |
| 5 | الحضور والغياب | زي صفحة البورتال: محدش حاضر افتراضيًا · حاضر / متأخر / غياب / عذر · «حضور الكل» · QR بيتغيّر كل شوية بفترة سماح · كود رقمي للي مش عارف يمسح · مصدر كل علامة (يدوي / QR / كود) · «قفل الحضور» = إخفاء الـ QR بس · كل علامة بتتحفظ فورًا (الاعتماد اتلغى). | التفاصيل نقطة نقطة تحت. | Attendance & office hours ← Register approval + Lecture QR | تفاصيل ↓ |
5 · الحضور والغياب — نقطة نقطة
| المطلوب | تنادي إيه | بيرجع / بيعمل إيه |
|---|---|---|
| مفيش حالة افتراضية | Staff/GetAbsenceDetails |
كل طالب معاه AttendanceState: NotTaken · Present · Late · Absent · Excused،
وAttendanceSource: Manual · QR · Code · Location، وLateMinutes.
وفوق: PresentCount · LateCount · AbsentCount · ExcusedCount · NotTakenCount · ApprovalRequired.
ابدأ كل الأزرار مش متدوسة لما الحالة NotTaken. |
| حاضر / غياب / متأخر / عذر | Staff/SaveAttendanceSheet |
كل عنصر في MARKS: STATE = present · late (+ LATE_MINUTES) · absent · excused · clear (يرجّعه «لسه»).
ابعت اللي اتغيّر بس. القيم القديمة (present/absent/excused) شغالة زي ما هي. |
| كل علامة بتتحفظ فورًا | — | مفيش خطوة «اعتماد» بعد الحفظ لما ApprovalRequired: false (Innovation دلوقتي). ممكن تحفظ مع كل دوسة (طالب واحد في MARKS) — مفيش حاجة بتستنى. |
| زرار «حضور الكل» | Staff/MarkAllPresent{SC_SCHEDULE_DTL_ID, SC_SCHEDULE_DTL_DAY_ID, ABS_DATE} |
بيعلّم «حاضر» على اللي لسه مالوش علامة بس — اللي مسح أو اتعلّم غياب/عذر بيفضل زي ما هو. الرد {marked, alreadyMarked}. ينفع من شاشة الـ QR ومن الكشف. |
| QR بيتغيّر كل فترة + سماح | academicstaff/GetLectQRCode |
الرد زاد: refreshSeconds · nextRefreshAt · sessionCode · sessionOpen، والـ qrPayload فيه QR_TOKEN وQR_WINDOW.
نادي تاني عند nextRefreshAt واعرض الكود الجديد. الكود القديم بيفضل شغال لحد فترة السماح (لكاميرا بطيئة). الفترتين من الأدمن. |
| الطالب بيمسح | students/GetStudentAttend |
ابعت QR_TOKEN وQR_WINDOW من الـ payload زي ما هم جنب الحقول القديمة. كود انتهى ← details = «الكود ده انتهى — امسح الكود اللي على شاشة الدكتور دلوقتي».
والمسح بيسجّل «حاضر» في الكشف على طول (مصدره QR). |
| كود الجلسة للي مش عارف يمسح | students/AttendByCode{ED_STUD, CODE} |
6 أرقام بتظهر تحت الـ QR (sessionCode) وثابتة طول المحاضرة. نفس شروط المسح (اليوم، وقت المحاضرة، مسجّل في السكشن). الرد زي رد المسح، ومصدره Code. |
| قفل الحضور = قفل جلسة الـ QR بس | academicstaff/SetQrSession{SC_SCHEDULE_DTL_ID, SC_SCHEDULE_DTL_DAY_ID, OPEN} |
OPEN: false ← الكود يختفي والمسح والكود الرقمي بيترفضوا («الحضور للمحاضرة دي اتقفل»). مش بيكتب غياب لحد.
يفتح تاني بـ OPEN: true أو GetLectQRCode بـ OPEN: true.
(Staff/CloseLectureAttendance القديم لسه موجود لو حد عايز «غياب لكل اللي مامسحش» بعد المحاضرة — اختياري.) |
| مصدر الحضور | Staff/GetAbsenceDetails |
AttendanceSource لكل طالب — اعرضه شارة صغيرة جنب الاسم (يدوي / QR / كود / موقع). متخزّن في ABS_NOTES بنفس عرف الـ SIS (QrCode). |
5 شكلها في الديمو Setup ← Attendance & office hours



| الخانة | بتأثر على | Innovation |
|---|---|---|
| A lecturer approves each register | ApprovalRequired وزرار الاعتماد وترتيب الاعتماد | مقفول |
| New code every (seconds) | refreshSeconds — 0 = كود ثابت للمحاضرة | 30 |
| Grace after a code changes | الكود القديم يفضل مقبول قد إيه | 15 |
| Show a six-digit session code | sessionCode وstudents/AttendByCode | مفتوح |
| Also accept the old fixed QR | المسح من غير QR_TOKEN (الأبلكيشن القديم) | مفتوح — اقفله لما كل النسخ تبعت التوكن |
3 · حجز الساعات المكتبية
| مين | تنادي إيه | بيرجع / بيعمل إيه |
|---|---|---|
| طالب | students/GetOfficeHourOpenings{EdStudId, SaStfMemberId} (0 = كل دكاترته) |
تحت Data: BookingEnabled · Openings[] (SaOfficeHourId, StaffNameAr, Date, DayAr, FromTime, ToTime, Capacity, Booked, Available, MyBookingId)
· MyBookings[] · CancelledByLecturer[] (فيها CancelReason — اعرضها للطالب، عشان الإلغاء مايبقاش في صمت). |
| طالب | students/BookOfficeHour{EdStudId, SaOfficeHourId, Date, Topic} |
Data.Status + Data.Booking، أو Data.Error بسبب واضح (مش دكتورك، اليوم مش يوم الميعاد، فات، مليان، أبعد من المسموح…). الإلغاء: نفس الرابط بـ {Cancel: true, BookingId}. |
| دكتور | academicstaff/GetMyOfficeHours |
كل ميعاد في Items[] بقى معاه Bookings[] (BookingId, StudentNameAr, Date, Topic…) وHasBookings. لو true ← اقفل «تعديل/حذف». |
| دكتور | academicstaff/SaveOfficeHour |
على ميعاد محجوز بيرفض: «This office hour is booked by N student(s) (next on …); cancel the booking first.» |
| دكتور | academicstaff/CancelOfficeHourBooking{BookingId, Reason} |
بيلغي الحجز، والسبب بيوصل للطالب في CancelledByLecturer. |
3 في الديمو والأدمن Setup ← Attendance & office hours ← Office-hour booking


| الخانة | معناها | Innovation |
|---|---|---|
| Students can book… | مقفول ← BookingEnabled: false والحجز بيترفض | مفتوح |
| Students per slot | Capacity لكل ميعاد في يوم | 1 |
| Book up to (days ahead) | المواعيد المعروضة والمسموح حجزها | 14 |
| Student can cancel until (minutes before) | بعدها الطالب مايقدرش يلغي (الدكتور يقدر) | 60 |
الحجوزات مش في الـ SIS (مفيش جدول ليها) — متخزّنة في داتا السيرفس، فمش هتظهر في البورتال.
2 · الحجوزات في الجدول
رد academicstaff/GetStaffSchedule (الدكتور) وstudents/schedule (الطالب) زاد فيه officeHourBookings[] —
نفس شكل الحجز فوق (Date, DayAr, FromTime, ToTime, StudentNameAr / StaffNameAr, Topic).
اعرضها في يومها جنب المحاضرات بلون مختلف. جدول الدكتور بيرجع Ok حتى لو عنده حجوزات بس ومفيش محاضرات.
1 · رسالة لطلبة المقرر / سكاشن مختارة
POST academicstaff/SendMessageToCourse (أو students/SendMessageToCourse — نفس الشغل)
{ "message": "محاضرة الأحد في المدرج الكبير",
"EdCourseId": 14,
"ScScheduleDtlIds": [2136] } // [] = كل سكاشن الدكتور في المقرر
→ { "result": "Ok", "State": "Done", "Sent": 27, "Sections": 1 }
السكاشن للاختيار من academicstaff/GetMySections بـ EdCourseId: ScScheduleDtlId, GroupDescrAr, Students, وSlots[].TeachingAr (محاضرة/عملي — عشان السكشنين اللي اسمهم «01» يبانوا مختلفين).
سكشن مش بتاع الدكتور ← Error. الرسالة بتوصل للطالب في الشات زي أي سؤال.

4 · الخطط الدراسية مع بيانات الجامعة
GET Info/University // من غير Authorization
→ Faculties[].Children[] … { "Type": "Program", "Id": 10, "NameAr": "…",
"Plan": { "ProgramId": 10, "TotalMinHours": 60,
"Packages": [ { "TitleAr": "مقررات الكلية الأجبارية", "TypeAr": "إجبارى", "MinHours": 30,
"Courses": [ { "Code": "BAS101", "NameAr": "…", "CreditHours": 3 } ] } ] } }
GET Info/University?plans=false // الشجرة بس (≈19KB بدل ≈314KB)
GET Info/AcademicPlan?programId=10 // → { "Plan": {…} } لبرنامج واحد
خد بالك: البرنامج ممكن يبقى تحت الكلية على طول (من غير قسم) أو تحت قسم — اعتمد على Type: "Program" مش على العمق.
الخطة = الحالية للبرنامج، ولو مفيش «حالية» ← أحدث سنة.

Plan في الرد
جرّبها بنفسك
| عايز تجرّب | الحساب | تتوقّع |
|---|---|---|
| QR بيتغيّر + كود الجلسة + حضور الكل | atef.dahesh ← BAS112 (2136 / 3239) |
كود جديد كل 30 ثانية، 6 أرقام تحت الكود، «حضور الكل» يرجّع marked. الطلبة: ahmed.elsayed.24010214 · mohamed.rabeea.24010230 |
| الحجز | طالب: basmala.nabih.25010008 · دكتور: atef.dahesh |
بسملة حاجزة الثلاثاء 6 أكتوبر 10:00 «مراجعة الميدتيرم» ← عند الدكتور الميعاد «محجوز» ومش بيتحذف. |
| رسالة لسكشن | atef.dahesh | BAS112 ← سكشن 2136 ← Sent: 27 |
| الخطط | من غير حساب | GET Info/AcademicPlan?programId=10 |
كل الأسامي اللي فوق بالظبط زي الـ JSON اللي بيرجع. الديمو (:9301) بينادي نفس الروابط دي — افتح الـ DevTools وشوف الريكوست.
★ الجديد ١ — مخرجات ميتنج 30 سبتمبر (اتنفّذت 1 أكتوبر)
كل بند اتقال في الميتنج، اتعمل فيه إيه، إنت كموبايل تعمل إيه، واتشرح فين في الدليل.
للبيزنس: نفس النقط بكلام من غير كود ومعاها إعدادات الأدمن في شرح البيزنس.
كله متنزّل على السيرفر (109.123.243.32:9300) ومتجرّب على داتابيز Innovation.
مفيش حاجة شغالين عليها اتكسرت. كل التغييرات إضافة حقول — مفيش حقل اتشال ولا اتغيّر اسمه
ولا معناه. ده مش كلام: قبل ما ننزّل سجّلنا شكل رد 25 إندبوينت من السيرفر القديم، وبعد التعديل قارنّاهم حقل حقل
(tools/contract-snapshot.js). النتيجة: حقول جديدة بس. ومفيش ولا عمود ولا جدول اتضاف للداتابيز —
أي إعداد جديد متخزّن في بروفايل الأدمن.
| # | المطلوب في الميتنج | اتعمل إيه | الموبايل يعمل إيه | ⚙️ من الأدمن | فين في الدليل |
|---|---|---|---|---|---|
| 1 | المقر والسكاشن: أيام التدريس وموقع التدريس | كل سكشن في students/schedule وacademicstaff/GetStaffSchedule بقى بيرجّع الأيام والوقت والقاعة والمبنى والمقر — بنفس أسامي حقول شاشة التسجيل. |
اعرض DaysAr · FromTime–ToTime · CampusAr · HallAr، أو اعمل سطر لكل عنصر في meetings[]. | مفيش | الجدول الدراسي · شاشات الدكتور |
| 2 | المتطلبات الدراسية: الدرجة / «مسجل» / «-----» | students/AcadPlan: كل مقرر معاه COURSE_STATUS وDISPLAY_GRADE_AR جاهز للعرض. |
اعرض DISPLAY_GRADE_AR في عمود الدرجة بدل Course_Grading_AR. | مفيش | خطة الدراسة |
| 3 | D- وبعدين مسجّله تاني ← الحالي بس «مسجل». D- وبعدين A ← الأفضل ولا الأخير؟ | المسجّل حاليًا بيغلب أي محاولة قديمة ← «مسجل». واللي خلص أكتر من مرة: القاعدة متسجّلة على لائحة الطالب في الـ SIS (الأعلى / الأحدث / الأحدث بحد أقصى) — نفس منطق تقرير الخطة في النظام القديم. مش قرار في الكود. | ولا حاجة زيادة — DISPLAY_GRADE_AR بيجيب الصح. GRADE_RULE وATTEMPTS لو حابب تعرض «معاد». | من الـ SIS مش الأدمن: قاعدة الإعادة على لائحة الطالب | خطة الدراسة |
| 4 | التقويم الأكاديمي مش بيرجّع داتا | السبب: قاعدة قديمة بتعرض بس الأنشطة المعلّم عليها «للطلاب»، والمسجّل هنا بيعلّم «يظهر». بقت إعداد في الأدمن ← 48 بند للربيع. | POST semester/semsterCalnd بـ EdAcadYearId وEdCodeSemesterId من اللوجين. | Academic rules ← «Academic calendar shows» = Shown الإعداد بالصورة ↓ |
التقويم الأكاديمي |
| 5 | الساعات المكتبية فاضية في دليل الأساتذة | كانت فاضية لأن مفيش مواعيد للربيع، والدكتور كان بيدخل على الصيفي فمواعيده بتروح هناك. اتصلّح ترم الدكتور، واتحطّت مواعيد تجريبية لـ 9 دكاترة، والمواعيد بقت جوّه الدليل نفسه. | من getInstructorsAndAdvisorForAsk: Instructors[].officeHours[] وAcademicAdvisior.officeHours[]. | Academic rules ← «A lecturer’s term…» مفتوح الإعداد بالصورة ↓ |
دليل الأساتذة |
| 6 | بيانات صفحة الأدمن | اللينك: http://109.123.243.32:9300/Admin · اليوزر: admin · الباسورد عند محمد عطية (مش هيتكتب في دليل منشور). والأدمن نفسه اتنظّم — شوف الفصل. |
— | Overview + Setup الإعداد بالصورة ↓ |
لوحة الإدارة |
| 7 | ريكوست من غير Authorization يرجّع بيانات الجامعة (عشان الستور) | GET Info/University: بيانات الجامعة من الأدمن + الشجرة الأكاديمية لايف من الـ SIS (8 كليات بأقسامها وبرامجها). |
نادِيه قبل اللوجين، من غير هيدر Authorization. | Public info & contact ← الاسم واللوجو والنبذة وسياسة الخصوصية الإعداد بالصورة ↓ |
عن الجامعة |
| 8 | تواصل معنا — عامة ولا إرسال إيميل؟ | قرار: بيانات عامة بس دلوقتي. GET Info/ContactUs من غير توكن: كروت المكاتب (تليفون، إيميل، واتساب، مواعيد). |
اعرض الكروت بأزرار tel: / mailto: / واتساب. | Public info & contact ← Contact cards الإعداد بالصورة ↓ |
تواصل معنا |
| 9 | اللوجين بـ 3 طرق: افتراضي · Active Directory · Azure | الـ 3 شغالين والأدمن بيختار. ① الافتراضي: «أي باسورد» أو باسورد موحّد. ② AD: كان TODO بيرفض دايمًا ← بقى LDAP bind حقيقي + زرار تجربة. ③ Azure: كان بيفك التوكن من غير ما يتأكد منه (أي حد يزوّر توكن لأي طالب) ← بقى بيتحقق من التوقيع والـ tenant والـ audience والصلاحية. | ① و② ← auth/login زي ما هو. ③ ← students/LoginAZ بالـ id_token (مش توكن Graph). | Sign-in methods ← الطريقة + «Token checking» (فلاج التيست) الإعداد بالصورة ↓ |
تسجيل الدخول · دليل دخول مايكروسوفت |
⚙️ إعدادات الأدمن لكل نقطة — بالصورة
كل اللي تحت في http://109.123.243.32:9300/Admin ← Setup. غيّر الخانة، واضغط Save changes تحت —
الحفظ بيحفظ التاب اللي غيّرته بس (عليه ●) ومش بيلمس أي إعداد تاني. النقط 1 و2 و3 مالهاش إعداد: بتشتغل لكل الجامعات من بيانات الـ SIS.
4 التقويم الأكاديمي — Setup ← Academic rules ← «Academic calendar shows»
الاختيار ده بيحدد أنهي أنشطة من أجندة الفصل تظهر للطالب:
| الاختيار | بيظهر |
|---|---|
| Only activities ticked "for students" | المعلّم عليه «للطلاب» بس — القديم، والافتراضي لأي جامعة جديدة |
| Every activity ticked "show" or "for students" | المعلّم «يظهر» أو «للطلاب» — ده اللي على Innovation |
| Every activity of the term | كل أنشطة الفصل |
لو التقويم فاضي عند جامعة: غالبًا المسجّل بيعلّم «يظهر» بس — اختار التاني.

5 الساعات المكتبية وجدول الدكتور — Setup ← Academic rules ← «A lecturer’s term is the one they teach in»
سيبه مفتوح (الافتراضي، وده اللي على Innovation). مفتوح = الدكتور بيدخل على الترم الحالي، ولو مالوش فيه سكاشن ← آخر ترم بيدرّس فيه، فجدوله مايبقاش فاضي والساعات المكتبية اللي يسجّلها تروح لنفس ترم الطلبة — وتظهر في دليل الأساتذة عندهم.
مقفول = الدكتور بيدخل على اللي «Which semester a student sees» بيقوله بالظبط.
الساعات المكتبية نفسها بيكتبها الدكتور (من التطبيق أو من النظام القديم) — مش من الأدمن.

6 لوحة الإدارة نفسها
Overview = سطر لكل جزء: الجامعة دي متظبطة على إيه، ولو فيه مشكلة تحذير أحمر و«Change →» بيوديك على الخانة. Setup = التابات متجمّعة بالترتيب: الجامعة ← الاتصال والدخول ← الأكاديمي ← التكاملات ← الإدارة.
اللينك http://109.123.243.32:9300/Admin · اليوزر admin · الباسورد عند محمد عطية.

7 بيانات الجامعة قبل الدخول — Setup ← Public info & contact
اكتب مرة واحدة: الاسم المختصر، رابط اللوجو، الألوان، النبذة بالعربي والإنجليزي، الموقع والإيميل والتليفون والعنوان، ورابط سياسة الخصوصية (الستورين بيطلبوه — Overview بيحذّر لحد ما يتكتب).
الكليات والأقسام والبرامج مابتتكتبش هنا — بتتقري من الـ SIS لوحدها. الخانة الوحيدة ليها: «Include the academic tree» (مفتوحة).
على Innovation: الكليات ظاهرة، والباقي لسه محتاج يتكتب.

8 تواصل معنا — Setup ← Public info & contact ← Contact cards
«+ Add a contact card» لكل مكتب: الاسم بالعربي والإنجليزي، التليفون، الإيميل، الواتساب، مواعيد العمل. وتحتها «Social links» لصفحات الجامعة.
كل كارت بيظهر في شاشة «تواصل معنا» بأزرار اتصال / إيميل / واتساب. لو مفيش كروت، الشاشة بتقول إن الجامعة لسه مكتبتش بيانات التواصل.
على Innovation: مفيش كروت لسه.

9 اللوجين بـ 3 طرق — Setup ← Sign-in methods
«Main sign-in method» بيختار الطريقة، والخانات اللي تحته بتتغيّر حسب الاختيار:

① يوزر + باسورد افتراضي — «Password rule»: Any password (أي باسورد — اللي على Innovation دلوقتي عن قصد عشان التيست)
أو One shared default password تكتبه في «Default password» (زي 123). بيتخزّن مشفّر، والخانة بتفضل فاضية بعد الحفظ وده طبيعي.

② Active Directory — «Domain controller» (المسار القديم من النظام القديم ينفع زي ما هو) و«Users' domain». لو الدومين رافض الاتصال العادي علّم «Use LDAPS». قبل الحفظ جرّب: اكتب يوزر وباسورد حقيقيين واضغط «Test sign-in» — بيقولك نجح ولا ليه لأ، ومش بيحفظ حاجة.

③ Microsoft — «Sign-in domain» (زي ku.edu.bh)، «Tenant id» (اختياري)، و«Accepted audience(s)» = Client ID بتاع تطبيق الموبايل على Azure.
«Also accept user name + password» بيسيب ① أو ② شغالين جنبه.

🚩 فلاج التيست: «Token checking»
ده الفلاج اللي بيتحكّم في الجزء ده بالظبط: «كان بيفك التوكن من غير ما يتأكد منه ← بقى بيتحقق من التوقيع والـ tenant والـ audience والصلاحية».
| الاختيار | بيعمل إيه | إمتى تستخدمه |
|---|---|---|
| Verify signature, tenant, audience and expiry (الافتراضي) | التوكن بيتراجع مع مايكروسوفت فعلًا. توكن متزوّر أو منتهي أو من تطبيق تاني بيترفض برسالة واضحة. | الإنتاج، وأي تيست بـ App Registration حقيقي أو بتوكن الـ Sandbox. |
| Decode only (القديم) | التوكن بيتقري من غير تحقق — زي النظام القديم بالظبط. أي توكن عليه إيميل الطالب بيدخل. | تيست بس: لو الموبايل تيم عايز يجرّب بتوكن مايكروسوفت اللي معاه دلوقتي (حتى توكن Graph) قبل ما الجامعة تعمل App Registration. بيظهر أحمر في الأدمن وOverview وReadiness لحد ما يرجع Verify — ماينفعش يتساب كده على جامعة حقيقية. |
اتجرّب فعلًا — نفس التوكنات في الوضعين:
| التوكن | Verify | Decode only |
|---|---|---|
| سليم (للطالب 73) | ✔ دخل | ✔ دخل |
| نفس التوكن بعد ما غيّرنا الاسم جوّاه لاسم دكتور | ✕ اترفض | ✔ دخل كالدكتور 148 — دي الثغرة |
| منتهي الصلاحية | ✕ اترفض | ✔ دخل |
| معمول لتطبيق تاني | ✕ اترفض | ✔ دخل |
| توكن Microsoft Graph | ✕ اترفض ومعاه «ابعت الـ id_token» | بيتقري — ولو الإيميل جوّاه لطالب موجود بيدخل |

دورة التيست الكاملة من غير Azure خالص: ① Sign-in methods ← «3 · Microsoft sign-in» + Token checking = Verify ← Save.
② Sandbox ← علّم «Microsoft sign-in» ← Save. ③ POST /__sandbox/identity/token {"userName":"…"} بيدّيك توكن موقّع ←
ابعته لـ students/LoginAZ ← بيدخل. ④ عدّل حرف في التوكن ← بيترفض. ⑤ غيّر Token checking لـ «Decode only» ← التوكن المتعدّل بيدخل —
ده بالظبط الثغرة القديمة، وبيوضّح ليه Verify لازم. ⑥ رجّع Verify و«1 · default password» بعد التجربة.

وكمان اتصلّح في السكة
| الحاجة | كانت بتعمل إيه | دلوقتي |
|---|---|---|
جدول الدكتور (GetStaffSchedule) |
«data not found» لأي دكتور سكاشنه مش في «مجموعة سكاشن» — وده السبب إن الاتنين اللي كانوا مع التيست جدولهم فاضي. واللي بيرجع، كل سكشن مكرر 3 مرات. | سطر لكل سكشن. للتيست: atef.dahesh (7 سكاشن في الصيفي، 12 في الربيع)، وكمان الدكاترة 66 و160 و231 عندهم 11–12 سكشن في الربيع. |
| ترم الدكتور في اللوجين | كان ممكن ييجي على ترم مالوش فيه تدريس. | الترم الحالي، ولو مالوش فيه سكاشن ← آخر ترم بيدرّس فيه. |
academicstaff/scheduledays بـ EdStudId = 0 |
كان بيرجّع جدول كل طلبة الترم لأي دكتور. | بيرجّع فاضي — الجدول بتاع طالب واحد. |
students/GetOfficeHours |
كان بيعرض «الأيام المفضّلة للتدريس» كأنها ساعات مكتبية، والوقت بتاريخ وهمي. | ساعات مكتبية بس، وFromTime/ToTime بـ HH:mm. |
الساعات المكتبية للدكتور في auth/me |
الخاصية كانت متعرّفة «للطالب بس» فمش ظاهرة للدكتور. | ظاهرة للاتنين. |
📷 جرّب الحضور بالـ QR النهاردة
الدكتور atef.dahesh بقى عنده محاضرتين يوم الخميس (بيانات تجريبية مضافة جنب جدوله الأصلي — مالمسناش مواعيده):
| المحاضرة | السكشن / الجلسة | المسح شغال لحد | القفل (الغياب) يشتغل من | طلبة للتجربة |
|---|---|---|---|---|
| BAS112 — 27 طالب | 2136 / 3239 | اليوم كله | 07:00 صباح الجمعة (مصر) | ahmed.elsayed.24010214 · mohamed.rabeea.24010230 · basmala.nabih.25010008
(omar.mahmoud.25010184 اتجرّب بيه ومسجّل حضور خلاص) |
| BAS115 — 27 طالب | 2143 / 3240 | 9 مساءً (مصر) | بعد 9 مساءً (مصر) | abdlahady.abdlahady.23010040 · mona.esmaeel.24010002 · malak.awad.24010043 |
الدورة: ① الدكتور يدخل ← محاضراته ← يختار المحاضرة ← يعرض الكود (academicstaff/GetLectQRCode).
② الطالب يمسح (students/GetStudentAttend) ← «تم تسجيل الحضور بنجاح»؛ مرة تانية ← «حضورك مسجّل بالفعل»؛ طالب مش في السكشن ← «إنت مش مسجّل في السكشن ده».
②½ جديد كشف الدكتور (Staff/GetAbsenceDetails) بيقول لكل طالب Scanned / ScannedAt وفوقه ScannedCount —
والمسح بقى بيسجّل «حاضر» في الكشف على طول، والباقي «لسه» (AttendanceState: NotTaken) — شوف الجديد ٢.
③ اختياري بعد ما المحاضرة تخلص: Staff/CloseLectureAttendance ← كل اللي مامسحش بيتسجّل غياب، والرد بيقول كام حضر وكام اتسجّل غياب.
(إخفاء الكود نفسه بقى academicstaff/SetQrSession.)
قبل نهاية المحاضرة القفل بيترفض برسالة «it can be closed after 14:00» — اتصلّح (كان بيقول «اتقفلت» ومايكتبش ولا غياب).
ساعة السيرفر مش ساعة الموبايل. كل مواعيد المحاضرات (المسح والقفل وجدول النهاردة) بتتحسب بساعة سيرفر الداتابيز، وسيرفر Innovation_Demo على توقيت شرق أمريكا — 7 ساعات ورا مصر. عشان كده المواعيد في الجدول فوق مكتوبة بتوقيت مصر بعد التحويل. على سيرفر جامعة حقيقية في مصر الفرق ده مش هيبقى موجود — بس لو حد قال «الكود بيقول مش وقته» وهو في المحاضرة، أول حاجة تتشاف هي ساعة السيرفر.
حسابات التيست — تجرّب إيه بإيه
| عايز تجرّب | الحساب | تتوقّع |
|---|---|---|
| الخطة الدراسية العادية | mahmoued.eprahim.23010062 | 49 ناجح بالدرجة، 39 «-----» |
| مقرر راسب ومسجّل تاني | ahmed.ghanem.25060211 | BSM112/BSM113/MEC112 ← «مسجل»، وATTEMPTS: 2 |
| الساعات المكتبية في الدليل | mahmoued.eprahim.23010062 | 12 دكتور كلهم معاهم مواعيد |
| جدول الدكتور + ساعاته | atef.dahesh | 7 سكاشن بالمقر، وميعادين مكتبيين |
| بيانات الجامعة | من غير حساب | GET /Info/University |
الباسورد على Innovation لسه «أي حاجة» — بقصد، عشان شغلكم. لو الجامعة عايزة باسورد موحّد، ده من الأدمن من غير ما حد يغيّر كود.
لسه مستني: داتابيز BOX_HILL_Stage (74.208.186.99) — البورت 1433 مقفول من عندنا ومن السيرفر.
محتاج حد يفتحه للـ IP 109.123.243.32. أول ما يتفتح: نسخة تانية من السيرفس على بورت 9303 ببروفايل BoxHill،
من غير ما نلمس نسخة Innovation اللي إنتوا شغالين عليها — والتيست تيم يشوف من النظام القديم اللي بيعمله الموبايل.
★ شرح البيزنس — كل نقطة اتعمل فيها إيه، وإعداداتها
للبيزنس والتيست تيم: من غير كود. كل نقطة من ميتنج 30 سبتمبر — المطلوب، اللي بقى بيحصل،
الإعداد اللي بيتحكم فيها من لوحة الإدارة (فين، اختياراته، الافتراضي، ومتظبط على إيه دلوقتي)، وإزاي تتأكد بنفسك.
لوحة الإدارة: http://109.123.243.32:9300/Admin ← Setup. الديمو: http://109.123.243.32:9301.
قاعدة عامة: المنتج واحد لكل الجامعات، والفرق بينهم إعدادات مش كود. أي حاجة جامعة عايزاها بشكل مختلف (زي الدرجة الأفضل ولا الأخيرة) إما بتيجي من بيانات الـ SIS بتاعتها، أو من إعداد في الأدمن. ومفيش أي تعديل حصل في داتابيز الـ SIS — لا أعمدة ولا جداول.
1 المقر والسكاشن — أيام وموقع التدريس
المطلوب: كل مقرر/سكشن يبان عليه بيتدرّس أنهي أيام، الساعة كام، وفين (المقر والمبنى والقاعة).
اللي بقى بيحصل: في جدول الطالب وقايمة مقرراته، وفي جدول الدكتور، كل سكشن بيظهر عليه الأيام والوقت والمقر. ولو السكشن ليه أكتر من ميعاد في أماكن مختلفة (محاضرة في مبنى ومعمل في مبنى تاني) كل ميعاد بيظهر لوحده.
✅ تتأكد إزاي: ادخل الديمو بالطالب ← «المقررات الدراسية»: تحت اسم المقرر هتلاقي مثلًا «الأربعاء · 09:00–12:00 · Main Campus · …». لو المقرر مالوش ميعاد متسجّل في الـ SIS مش هيظهر سطر.

2 المتطلبات الدراسية — الدرجة / «مسجل» / «-----»
المطلوب: في الخطة الدراسية: لو الطالب خلّص المقرر تظهر درجته، لو مسجّله دلوقتي تظهر كلمة «مسجل»، ولو عمره ما سجّله تظهر «-----».
اللي بقى بيحصل: بالظبط كده. كل مقرر في الخطة بقى عليه واحدة من التلاتة، ولو المقرر اتاخد أكتر من مرة بيبان عليه «معاد». والدرجة مابتظهرش غير لما النتيجة تتعتمد في الـ SIS.
✅ تتأكد إزاي: الديمو ← «خطة الدراسة» ← دوس على أي مسار: قدام كل مقرر A- أو B+… أو «مسجل» أو «-----».

3 الإعادة — D- وبعدين سجّله تاني / D- وبعدين A
المطلوب: (أ) طالب جاب D- وسجّل المقرر تاني الترم ده ← يظهر الحالي بس «مسجل». (ب) جاب D- وبعدين A ← يظهر الأفضل ولا الأخير حسب اللائحة، والرجوع للبيزنس في النظام القديم.
اللي بقى بيحصل: (أ) اتعمل: المحاولة الحالية بتغلب أي محاولة قديمة. (ب) رجعنا للنظام القديم ولقينا إن القرار متسجّل على لائحة كل طالب في الـ SIS نفسه — كل لائحة ليها «قاعدة الإعادة»: تاخد الأعلى، أو الأحدث، أو الأحدث بحد أقصى للتقدير. والمنتج بيقرا القاعدة دي ويطبّقها، بنفس منطق تقرير الخطة في النظام القديم. يعني مش إحنا اللي بنقرر، والجامعة لو غيّرت لائحتها في الـ SIS التطبيق بيمشي معاها لوحده.
✅ تتأكد إزاي: بالطالب ahmed.ghanem.25060211: مقررات راسب فيها في الربيع ومسجّلها في الصيفي (BSM112، BSM113، MEC112) بتظهر «مسجل» ومعاها «معاد».
4 التقويم الأكاديمي مش بيرجّع داتا
المطلوب: التقويم يرجّع مواعيد الفصل.
اللي بقى بيحصل: اتصلّح. السبب: القاعدة القديمة بتعرض على الموبايل بس الأنشطة اللي المسجّل علّم عليها «للطلاب»، والمسجّل عندنا بيعلّم «يظهر» بس — فالتقويم كان فاضي رغم إن فيه أنشطة. بقى إعداد، والتقويم دلوقتي فيه مواعيد الربيع كلها (48 نشاط لكل الكليات، و6 لكلية الطالب).
✅ تتأكد إزاي: الديمو ← الخدمات ← «التقويم الأكاديمي»: العنوان بيقول «من الـ SIS · N نشاط» والأنشطة بتواريخها الحقيقية. ولو حبيت تشوف الفرق: غيّر الإعداد لـ «للطلاب» واحفظ ← التقويم هيفضى.

5 الساعات المكتبية في دليل أعضاء هيئة التدريس
المطلوب: دليل الأساتذة يعرض الساعات المكتبية لكل دكتور.
اللي بقى بيحصل: بقت جوّه الدليل نفسه: كل دكتور (والمرشد الأكاديمي) تحت اسمه أيامه ومواعيده. كانت فاضية لسببين: مفيش مواعيد متسجّلة للربيع أصلًا، والدكتور كان بيدخل على ترم الصيفي فأي ميعاد يسجّله من الموبايل كان بيروح للصيفي والطالب (اللي على الربيع) مش شايفه. اتصلّح ترم الدكتور (نقطة 10)، واتحطّت مواعيد تجريبية لـ 9 دكاترة عشان التيست. ودكتور مالوش مواعيد بيظهر عنده «لا توجد ساعات مكتبية».
✅ تتأكد إزاي: الديمو ← «دليل أعضاء هيئة التدريس»: كل كارت تحته «الساعات المكتبية» (الإثنين 10:00–12:00…). المواعيد التجريبية مكتوب عليها «بيانات تجريبية 2026-10-01».

6 بيانات صفحة الأدمن
المطلوب: اللينك واليوزر والباسورد، وتنظيم الصفحات عشان تبقى سهلة لكل عميل.
اللي بقى بيحصل: اللينك: http://109.123.243.32:9300/Admin · اليوزر: admin · الباسورد: عند محمد عطية (مابيتكتبش في دليل منشور).
والصفحات اتنظّمت: Overview بتقول في سطر لكل جزء الجامعة دي متظبطة على إيه، ولو فيه مشكلة بتحذّر وتوديك على مكانها. وSetup بقى منيو جانبي بترتيب ما بتظبط عميل جديد (الجامعة ← الاتصال والدخول ← الأكاديمي ← التكاملات ← الإدارة). والحفظ بيحفظ اللي غيّرته بس (عليه علامة ●) — مفيش إعداد تاني بيتلمس بالغلط، وكل حفظ بياخد نسخة احتياطي من القديم.
✅ تتأكد إزاي: ادخل الأدمن ← Overview: هتلاقي «Sign-in: User name + ANY password» ومعاه تحذير، و«Academic rules: … calendar: Shown».

7 ريكوست من غير Authorization يرجّع بيانات الجامعة (عشان الستور)
المطلوب: مراجع الـ App Store / Google Play بيفتح التطبيق من غير حساب — لازم يلاقي بيانات الجامعة.
اللي بقى بيحصل: في شاشة الدخول فيه زرار «عن الجامعة» بيفتح من غير حساب: اسم الجامعة ولوجو ونبذة وتواصل عام، وكل الكليات بأقسامها وبرامجها. البيانات من مصدرين زي ما اتقال في الميتنج: الكليات والأقسام والبرامج من الـ SIS لايف (الشجرة الأكاديمية)، والباقي (اللوجو، النبذة، الإيميل…) بيتكتب مرة في الأدمن لأن الـ SIS مفيهوش.
✅ تتأكد إزاي: الديمو ← شاشة الدخول ← «عن الجامعة»: 8 كليات، دوس على كلية تشوف أقسامها وبرامجها. قبل الرفع على الستور: لينك سياسة الخصوصية لازم يتكتب — صفحة Overview بتحذّر لحد ما يتكتب.

8 تواصل معنا
المطلوب: بيانات عامة ولا إرسال إيميل للموظفين؟ ومن غير Authorization عشان مراجعة الستور.
اللي بقى بيحصل: القرار: بيانات عامة بس دلوقتي. شاشة «تواصل معنا» (من شاشة الدخول ومن غير حساب) بتعرض كارت لكل مكتب — القبول، شؤون الطلاب، الدعم الفني… — بأزرار اتصال وإيميل وواتساب ومواعيد العمل. الإرسال من التطبيق للموظفين اتأجّل لأنه من غير حساب ومحتاج حماية من الإزعاج.
✅ تتأكد إزاي: اكتب كارت واحد في الأدمن واحفظ ← الديمو ← «تواصل معنا» هيظهر فيها الكارت بأزراره.

9 اللوجين بـ 3 طرق
المطلوب: (1) الدخول الافتراضي باليوزر والباسورد الافتراضي، (2) Active Directory، (3) Microsoft Azure — ومراجعة هل شغالين.
اللي بقى بيحصل: قبل: (1) كان بيقبل أي باسورد. (2) كان موجود في الأدمن بس مش متنفّذ — بيرفض أي حد دايمًا. (3) كان بيقبل توكن مايكروسوفت من غير ما يتأكد إنه حقيقي — يعني أي حد يقدر يزوّر دخول باسم أي طالب (ونفس المشكلة في النظام القديم).
دلوقتي الـ 3 شغالين والأدمن بيختار: (1) إما «أي باسورد» للديمو، أو «باسورد موحّد» تكتبه (زي 123). (2) التطبيق بيسأل الـ Active Directory بتاع الجامعة هل الباسورد صح — وفي الأدمن زرار «Test sign-in» تجرّب بحساب حقيقي. (3) التوكن بيتراجع مع مايكروسوفت فعلًا (التوقيع، والجامعة، والتطبيق، والصلاحية)؛ وتقدر تسيب اليوزر والباسورد شغالين جنبه أو تقفلهم.
✅ تتأكد إزاي: (1) غيّر لـ «باسورد موحّد» واكتب 123 واحفظ ← الدخول بأي باسورد غير 123 بيترفض «password not correct». (رجّعه بعد التجربة.) (3) من غير Azure: Sandbox ← «Microsoft sign-in» بيدّي توكن تجريبي — التفاصيل في دليل دخول مايكروسوفت. (2) محتاج بيانات الـ AD من الجامعة.

10 ترم الدكتور + جدوله (اتصلّح في السكة)
المطلوب: عضو هيئة تدريس يكون عنده جدول — الاتنين اللي مع التيست جدولهم فاضي.
اللي بقى بيحصل: جدول الدكتور كان بيرجّع «data not found» لأي دكتور سكاشنه مش متربطة بـ «مجموعة سكاشن» في الـ SIS — ودول أغلب الدكاترة. اتصلّح، واتصلّح كمان إن كل سكشن كان بيتكرر 3 مرات. وكمان الدكتور بقى بيدخل على الترم اللي بيدرّس فيه: الترم الحالي، ولو مالوش فيه ولا سكشن ← آخر ترم درّس فيه.
✅ تتأكد إزاي: ادخل بـ atef.dahesh ← جدوله فيه سكاشن بأيامها ومقرها. ودكاترة تانيين عندهم جداول في الربيع: الأرقام 66 و160 و231.
طلبات نادر (الجولة التانية) — للبيزنس
التفاصيل التقنية للموبايل في الجديد ٢.
11 رسالة من الدكتور لطلبة المقرر — أو لسكاشن يختارها
المطلوب: الدكتور يبعت رسالة لكل طلبة المقرر، ولو بيدرّس أكتر من سكشن يختار أنهي.
اللي بقى بيحصل: من «مقرراتي» ← «رسالة للطلبة»: السكاشن بتظهر بعدد طلبتها (كلها متعلّمة افتراضيًا)، يكتب مرة ويبعت. الرسالة بتوصل لكل طالب مرة واحدة حتى لو في سكشنين، وبتروح لطلبة سكاشن الدكتور نفسه بس — مايقدرش يبعت لسكشن مش بتاعه.
✅ تتأكد إزاي: ادخل بـ atef.dahesh ← مقرراتي ← BAS112 ← رسالة للطلبة ← اختار سكشن ← ابعت ← «اتبعتت لـ N طالب»؛ وادخل بطالب من السكشن تلاقيها في الشات.

12 حجز الساعات المكتبية — ومايتحذفش وهو محجوز
المطلوب: الطالب يحجز ميعاد من الساعات المكتبية؛ لو محجوز الدكتور مايقدرش يحذفه أو يعدّله؛ والحجوزات تظهر مع المواعيد وفي جدول الدكتور.
اللي بقى بيحصل: الطالب بيشوف المواعيد المتاحة لدكاترته ومرشده للأسبوعين الجايين ويحجز (ويكتب الموضوع) أو يلغي. الدكتور بيشوف تحت كل ميعاد مين حاجز وإمتى وعن إيه، والميعاد المحجوز مقفول للتعديل والحذف لحد ما الحجز يتلغي. الدكتور يقدر يلغي حجز بسبب — والطالب بيشوف الإلغاء والسبب. الحجوزات بتظهر في جدول الدكتور وجدول الطالب.
✅ تتأكد إزاي: طالب basmala.nabih.25010008 حاجز عند atef.dahesh الثلاثاء 6 أكتوبر ← ادخل بالدكتور ← ساعاتي المكتبية ← الميعاد «محجوز» وزرار الحذف مقفول ← «إلغاء» بسبب ← الطالبة تشوف السبب.

13 الخطط الدراسية مع بيانات الجامعة
المطلوب: بيانات الجامعة والكلية والبرنامج ترجع معاها الخطط الدراسية.
اللي بقى بيحصل: شاشة «عن الجامعة» (من غير حساب) بقت تعرض لكل برنامج خطته: المجموعات (متطلبات جامعة، كلية، إجباري، اختياري) بعدد ساعاتها ومقرراتها بالكود والساعات. الخطة = الخطة الحالية للبرنامج في الـ SIS.
✅ تتأكد إزاي: افتح الديمو من غير لوجين ← عن الجامعة ← كلية ← «الخطة الدراسية» جنب البرنامج.

14 الحضور زي صفحة البورتال: مفيش افتراضي، 4 حالات، حضور الكل، والمصدر
المطلوب: مفيش حالة افتراضية؛ زرار «حضور الكل»؛ الحالات حاضر / غياب / متأخر / عذر؛ تسجيل مصدر الحضور؛ كل علامة تتحفظ فورًا لأن الاعتماد هيتلغي.
اللي بقى بيحصل: الكشف بيفتح ومحدش متعلّم — اللي مالوش علامة «لسه» (مش «حاضر»)، عشان محاضرة الدكتور نسي ياخد غيابها ماتطلعش «الكل حضر». الحالات الأربعة زي البورتال بالظبط (المتأخر بعدد دقايقه). «حضور الكل» بيعلّم اللي لسه بس، ومش بيلمس اللي مسح أو اتعلّم غياب/عذر. جنب كل طالب مصدر علامته: يدوي / QR / كود / موقع. وكل علامة بتتسجّل في الـ SIS أول ما تتحفظ — والاعتماد اتقفل من الأدمن على Innovation.
✅ تتأكد إزاي: atef.dahesh ← الحضور ← BAS112 ← الكل «لسه» ← دوس «حضور الكل» ← العدّاد يتغيّر، وافتح نفس اليوم في البورتال تلاقيهم حاضرين.

15 QR بيتغيّر كل شوية + كود للي مش عارف يمسح + قفل الحضور
المطلوب: آلية تجديد الـ QR كل فترة بفترة سماح من الأدمن؛ كود للجلسة؛ قفل الحضور = قفل جلسة الـ QR (إظهار/إخفاء).
اللي بقى بيحصل: الكود على شاشة الدكتور بيتغيّر لوحده كل 30 ثانية، فصورة الكود اللي اتبعتت على جروب مابتشتغلش بعد دقيقة. الكود القديم بيفضل مقبول 15 ثانية بعد ما يتغيّر (لكاميرا بطيئة). تحت الـ QR رقم من 6 أرقام ثابت طول المحاضرة للي موبايله مش بيمسح. «اقفل الحضور» بيخفي الكود وبيرفض أي مسح أو كود بعدها — ومش بيسجّل غياب لحد؛ «افتح تاني» بيرجّعه.
✅ تتأكد إزاي: atef.dahesh ← الحضور بالـ QR ← BAS112 ← اعرض الكود ← العدّاد بيعد ← طالب يكتب الرقم ← «اتسجّل» ← «اقفل الحضور» ← طالب تاني يكتب الرقم ← «الحضور للمحاضرة دي اتقفل».

مستني: داتابيز BOX_HILL — البورت مقفول؛ أول ما يتفتح للـ IP
109.123.243.32 هتطلع نسخة على 9303 ببروفايل BoxHill من غير ما نلمس نسخة Innovation.
1 المقدمة — إحنا فين بالظبط؟
اقرا الجزء ده الأول. هيوفر عليك ساعات من الأسئلة.
خلينا نبدأ من الأول. في 3 حاجات منفصلة، ولازم تفرق بينهم:
1️⃣ البروتوتايب (Vercel)
تطبيق React اتعمل على university-pwlm.vercel.app. 27 شاشة كاملة، تصميم نهائي، عربي RTL.
بس… كل الداتا اللي فيه متكتبة بالإيد في الكود. مفيش ولا ريكوست واحد للسيرفر. ده «فيلم» للتطبيق مش تطبيق.
2️⃣ السيرفس (Informatique.SIS.MobileService)
باك إند .NET 10 بيتكلم مع داتابيز الـ SIS مباشرة بـ Dapper. مفيش stored procedures بتتنشر — كل الـ SQL جوّه الكود.
فيه ~90 إندبوينت. كلهم متنقلين — اللي مش بيرجّع داتا بيرجّع كده لأن الداتا نفسها مش موجودة للحالة اللي جرّبناها، مش لأن الكود ناقص.
3️⃣ الديمو (MobileDemo)
أخدنا نفس كود البروتوتايب بالظبط (استخرجناه من البِلد المنشور) وحطينا تحته طبقة داتا بتنادي السيرفس.
يعني اللي بتشوفه دلوقتي على الشاشة بيانات طالب حقيقي من الداتابيز، مش عيّنة.
الخلاصة: الواجهة خلصت. الباك إند نصه خلص. اللي فاضل هو ربط الباقي + كتابة اللي لسه متكتبش. التيوتوريال ده بيقولك بالظبط إيه اللي خلص وإيه اللي لأ، شاشة شاشة.
جديد: كان فيه 7 خصائص واقفة مش بسبب كود — بسبب إننا مستنيين بيانات فوري وTeams وMoodle وFirebase.
دلوقتي فيه Sandbox جوّه السيرفس بيقلّد البوابات دي بنفس بروتوكولها الحقيقي، فمبقاش فيه ولا خاصية واحدة
Blocked، ورحلة الدفع كاملة بقت شغالة من التطبيق للداتابيز.
الموبايل تيم يقدر يبني كل الشاشات دي النهاردة. اقرا القسم 10.
طب مين اللي جرّب ده؟
كل الأرقام اللي في التيوتوريال ده مش تخمين — إحنا شغّلنا السيرفس على داتابيز
Innovation_Demo الحقيقية (984 جدول) وناديّنا كل إندبوينت واحد واحد وسجّلنا رد كل واحد.
الطالب اللي بنجرّب بيه:
محمود محمد ابراهيم عوض — كلية العلاج الطبيعي · المستوى الثالث · المعدل التراكمي 2.42 · 101 ساعة منجزة
يوزر: mahmoued.eprahim.23010062 — وأي باسورد بيعدّي (هنشرح ليه في جزء الإعدادات).
2 الصورة الكبيرة
إزاي الـ 3 حتت بيتكلموا مع بعض.
┌─────────────────────────────────────────────────────────────────────┐
│ الموبايل / MobileDemo (React, عربي RTL) │
│ ───────────────────────────────────────────────────────────────── │
│ app/api.js ← بينادي السيرفس ويفك الـ envelope القديم │
│ app/data.jsx ← بيحوّل رد السيرفس لشكل الشاشات بالظبط │
│ screens-*.jsx ← الشاشات (نفس كود البروتوتايب) │
└────────────────────────────┬────────────────────────────────────────┘
│ HTTP (JWT في هيدر Authorization)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Informatique.SIS.MobileService (.NET 10) │
│ ───────────────────────────────────────────────────────────────── │
│ EndPoints/ ← المسارات القديمة زي ما هي (students/login…) │
│ FeatureGate ← لو الخدمة مقفولة → يرد رسالة، ما يقعش أبدًا │
│ Business/ ← الـ handlers + الـ SQL جوّه الكود │
│ ClientProfile ← كل سلوك العميل من ملف JSON واحد │
└────────────────────────────┬────────────────────────────────────────┘
│ Dapper (SQL نصّي، مفيش SP بيتنشر)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ داتابيز العميل (Innovation_Demo) 984 جدول │
└─────────────────────────────────────────────────────────────────────┘
3 قواعد لازم تفهمها قبل ما تكتب سطر
📜 الـ Envelope القديم
السيرفس دايمًا بيرد HTTP 200 — حتى في الغلط. الغلط بيتعرف من جوّه الـ body:
{ "result": "Ok", "details": "NO ERROR", ... }
{ "result": "ERROR", "details": "data not found" }
وكمان: أي string فاضي بيرجع "" مش null. ده عشان التطبيقات القديمة المنشورة تفضل شغالة.
🎛️ الـ Feature Gate
كل خدمة ليها حالة: Active (شغالة) / Disabled (مقفولة بالإيد) / Blocked (مفتوحة بس ناقصها إعدادات أو جداول).
لو Blocked، الإندبوينت بيرد رسالة مهذّبة بدل ما يضرب 500. يعني إعداد ناقص عمره ما هيوقّع السيرفس.
🗄️ مفيش حاجة بتتنشر على الداتابيز
السيرفس ما بيعملش deploy لأي SP ولا view ولا سكريبت. بيعمل مسح على sys.objects ويتأكد إن الجداول اللي محتاجها موجودة.
لو ناقص جدول → الخدمة تبقى Blocked ومكتوب الجدول الناقص بالاسم. مش هتكتشفها في الإنتاج.
للموبايل تيم: بعد اللوجين على طول نادي GET Info/Capabilities.
هيرجّعلك حالة كل خدمة على التركيب ده، فتخفي الشاشات اللي مش متاحة بدل ما الزرار يضرب غلط في وش المستخدم.
3 شغّل النظام عندك
من الصفر لحد ما تشوف بيانات طالب حقيقي — 3 خطوات.
-
شغّل السيرفس
من فولدر
Informatique.SIS.MobileService. لازم تحدد مكان ملف البروفايل:# Windows CMD set ClientProfile__Path=C:\path\to\clientprofile.json dotnet run --project Informatique.SIS.MobileService.WebApi ^ --no-launch-profile --urls http://localhost:5099اتأكد إنه شغال:
http://localhost:5099/healthلازم يرد{"status":"up","setupMode":false} -
شغّل الديمو
من فولدر
MobileDemo— محتاج Node 18 أو أحدث بس:node server.js # أو دوس دبل كليك على start.batافتح
http://localhost:4173/— واختار حساب من الكروت اللي في شاشة الدخول. -
افتح لوحة الإدارة
http://localhost:5099/Admin— منها تظبط البروفايل وتشغّل فحص الجاهزية. -
شغّل الـ Sandbox جديد
من Profile → تاب Sandbox. ده اللي بيخلّي الدفع والإرشاد والمنصة التعليمية والإشعارات تشتغل من غير بيانات اعتماد حقيقية. ظبّط اللينكين دول:
Browser base URL http://localhost:5099 Loopback base URL http://127.0.0.1:5099
اتأكد:
http://localhost:5099/healthلازم يرد"sandbox":["payments","meetings","lms","push"]، وصفحة التحكّم علىhttp://localhost:5099/__sandbox.
ليه فيه سيرفر للديمو أصلاً؟ السيرفس مافيهوش CORS. بدل ما نغيّر سيرفس إنتاجي عشان ديمو،
server.js بيعمل proxy لـ /api/* على السيرفس — فالمتصفح يفضل شايف
كل حاجة من نفس الـ origin. مغيّرناش حاجة في السيرفس عشان الديمو يشتغل.
الحسابات الجاهزة
| اليوزر | مين ده | ليه مفيد |
|---|---|---|
| mahmoued.eprahim.23010062 | محمود محمد ابراهيم عوض — طالب | أغنى حساب: 8 مقررات، 14 حصة، 3 سنين ترانسكريبت، غياب، رسوم |
| ahmed.said.23010035 | أحمد سعيد — طالب | للمقارنة بين طالبين |
| Hassana.Gamal | حسناء جمال — عضو هيئة تدريس | لتجربة شاشات الدكتور (50 طالب تحت الإشراف) |
الباسورد: أي حاجة. مش بيتشيك عليه — اعرف ليه.
كوليكشن تسجيل المقررات — كل عملية في فولدر
غير الكوليكشنات المقسّمة بالشاشات، فيه كوليكشن مخصوص لتسجيل المقررات مقسّم بالعمليات: كل عملية فولدر لوحدها، وكل فولدر كامل — بيدخل، بيقرا اللي محتاجه، بينفّذ، وبيقرا تاني عشان يتأكد إن اللي اتكتب بان.
1 تسجيل مقرر جديد دخول → المسموح → المتاح → سجّل ✍️ → 🔎 تأكيد
2 تغيير سكشن دخول → مقرراتي → السكاشن المرشّحة → انقل ✍️ → 🔎 تأكيد
3 حذف سكشن دخول → مقرراتي → حذف ✍️ → 🔎 المقرر لسه مسجّل
4 حجز مقعد + الخروج منه دخول → سكشن مليان → احجز ✍️ → 🔎 → اخرج ✍️ → 🔎
5 إسقاط مقرر دخول → مقرراتي → احذف ✍️ → 🔎 الحالة بقت 6
6 تراجع عن الإسقاط دخول → مقرراتي → السكاشن → تراجع ✍️ → 🔎 رجع وفي سكشن
7 قراءات مرجعية نداءات مابتكتبش حاجة⬇️ حمّل كوليكشن تسجيل المقررات (٧ فولدرات · ٣٥ ريكوست)
newman run workflow-course-registration.postman_collection.json --folder "5 · إسقاط مقرر"
يعني لو بتشتغل على شاشة الإسقاط بس، مالكش دعوة بالستة التانية.
Status: true ومابتظهرش في أي شاشة هي أخطر عطل ممكن —
مافيش فرق بينها وبين النجاح وقت النداء. عشان كده كل فولدر بيقفل بقراءة بتتأكد.
العناوين — HTTPS
التلات خدمات بقى ليها دومينات بشهادات Let's Encrypt حقيقية، عن طريق
sslip.io اللي بيحوّل أي
<ip>.sslip.io للـ IP نفسه — يعني من غير ما نشتري دومين ولا نظبط DNS.
| الخدمة | العنوان | كان |
|---|---|---|
| الـ API | https://api.109.123.243.32.sslip.io |
:9300 |
| الديمو | https://demo.109.123.243.32.sslip.io |
:9301 |
| الدليل ده | https://docs.109.123.243.32.sslip.io |
:9302 |
البورتات القديمة لسه شغالة زي ما هي — الدومينات إضافة مش بديل.
الـ baseUrl في كل كوليكشنات الـ Postman بقى على دومين الـ API، وتقدر ترجّعه
http://localhost:5099 لو بتجرّب على جهازك.
HTTP-01 اللي بيحتاج بورت 80. الـ proxy (Caddy) بيشتغل كـ
مشروع compose مستقل عشان أي up عليه ما يقدرش يلمس حاويات حد تاني.
حساب واحد بيشغّل كل الشاشات
كل شاشات الطالب في الديمو وفي الدليل ماشية على حساب واحد بس — من تسجيل الدخول لحد آخر شاشة، من غير ما حد يضطر يغيّر المستخدم في نص العرض.
| الحساب | مين | بيغطي إيه |
|---|---|---|
mahmoued.eprahim.23010062 |
طالب علاج طبيعي · ED_STUD_ID 73 |
٨٢ إندبوينت — كل شاشات الطالب من غير استثناء، وفيها التسجيل والإسقاط والتراجع |
atef.dahesh |
عضو هيئة تدريس | شاشات الدكتور (كشوف الحضور، الـ QR، الجدول) — دور تاني، مش بديل |
ده مكانش الوضع قبل كده: التسجيل كان محتاج حساب طالب تاني، لأن جدول كلية العلاج الطبيعي
للترم ده كان متعمول بالكامل بس ماتعتمدش، وMOB_GET_STD_CRS_REG_PLN_SEC
مابيرجّعش سكشن إلا لو عرضها معتمد. بعد اعتماد الجداول وفتح السكاشن للتسجيل الذاتي
(ONLINE_FLG = 1 — الطالب مابيشوفش غيرها) بقى عند الطالب
٣٠ مقرر من خطته و١٢٩ سكشن، وقدامه ٨ مقررات متاحة للإضافة بسكاشن مفتوحة —
فالعرض يتكرر أكتر من مرة من غير ما الليستة تفضى.
4 مفتاح الرموز
هتشوف الرموز دي في كل الجداول اللي جاية — افهمها مرة واحدة.
حالة الإندبوينت
حالة الخاصية في الباك إند
فرق مهم جدًا: «شغال / فاضي» مش زي «مش موجود». الأولى معناها الكود خلص وعايز بيانات بس (زي جدول الامتحانات — محتاج الكنترول يدخّله). التانية معناها لازم حد يقعد يكتب كود. ما تخلطش بينهم لما تقدّر الوقت.
عمود «الحساب» في جداول الإندبوينتات
كل رقم في الدليل ده جه من نداء حقيقي، والنداء مابيرجّعش داتا غير لما يتعمل بالحساب الصح. عشان كده كل إندبوينت مكتوب جنبه اتنادى بحساب مين:
| العلامة | الحساب | يعني إيه |
|---|---|---|
| 🎓 طالب | mahmoued.eprahim.23010062 | توكن طالب. ED_STUD_ID = 73 |
| 👨🏫 دكتور | atef.dahesh | توكن عضو هيئة تدريس. SA_STF_MEMBER_ID = 148 · SE_USER_ID = 2991 |
| 🌐 من غير توكن | — | بيشتغل قبل الدخول (Info/Capabilities، اللوجين نفسه، صورة الطالب) |
data not found —
وده شكله زي إندبوينت باظ وهو مش باظ. الحساب غلط مش الإندبوينت.
الباسورد أي حاجة (LegacyTrust)، بس نوع الحساب فارق.
الردود محفوظة جوّه الكوليكشن
كل ريكويست في الـ Postman جايّ معاه الرد الحقيقي بتاعه محفوظ كـ Example — تقدر تفتحه وتشوف شكل الرد من غير ما تبعت حاجة. الردود دي مش مكتوبة بالإيد: اتسجّلت من تشغيل فعلي لكل إندبوينت على السيرفر المنشور، بالحساب المكتوب جنبه.
| اسم الـ Example | معناه |
|---|---|
| رد حقيقي — فيه داتا | الحالة الطبيعية |
| رد حقيقي — ملف/صورة | زي صورة الطالب وكود الـ QR |
| رفض قاعدة شغلانية (رد صح) | «عندك طلب مفتوح بالفعل» — المنتج شغال صح |
| رد ناجح من غير داتا | عمليات كتابة مالهاش ريسبونس |
| الرد لما الخاصية مقفولة | بيقول الناقص إيه بالظبط |
5 الشاشات — واحدة واحدة
33 شاشة. لكل واحدة: صورتها، بتشتغل إزاي، جدول الإندبوينتات اللي محتاجاها، وجدول الخصائص بإيه المتعمل وإيه الناقص وإيه المطلوب — وكوليكشن Postman جاهز للتحميل.
الـ Postman: كل شاشة ليها كوليكشن لوحدها. جوّه كل كوليكشن فيه ريكوست اسمه
0) Login — شغّله الأول وهو هيملأ التوكن وكل الـ ids (رقم الطالب، السنة، الفصل…) لوحده
في متغيرات الكوليكشن، وبعدها كل الريكوستات تشتغل من غير ما تكتب أي رقم بإيدك.
وفيه كمان كوليكشن واحد بكل الشاشات لو تحب تستوردها مرة واحدة.
تسجيل الدخول
Login

دي أول شاشة الطالب بيشوفها. فيها طريقتين للدخول: زرار «المتابعة عبر مايكروسوفت» (SSO)، أو «الدخول بالرقم الجامعي» (يوزر وباسورد). الشاشة كمان بتعرض حسابات جاهزة للتجربة عشان الديمو يشتغل من غير ما حد يحفظ رقم جامعي.
بيشتغل إزاي؟
الموبايل بيبعت auth/login — إندبوينت واحد للاتنين. السيرفس بيعمل 3 حاجات:
(1) يتأكد من الباسورد حسب auth.mode، (2) يجيب هوية الطالب من
SE_USER ⨝ SE_USER_ACCNT ⨝ ENTITY_MAIN، (3) يحدد السنة والفصل الحاليين.
الرد بيرجع UserMainData + التوكن. التوكن ده لازم يتخزن ويتبعت في كل ريكوست بعد كده
في هيدر Authorization: Bearer <token>.
الفرع بيتحدد من الرد مش من الشاشة: في UserMainData فيه فلاج
IsStudent. لو true الفرونت إند يمشي في مسار الطالب، ولو false يمشي في
مسار عضو هيئة التدريس. مفيش سؤال للمستخدم «انت طالب ولا دكتور؟» — السيرفس هو صاحب الإجابة دي،
والمستخدم مالوش إنه يدّعي دور.
students/login وacademicstaff/login لسه شغالين كأسماء قديمة لنفس الهاندلر
بالظبط، وكل واحد فيهم بيقبل الاتنين — فاختيار المسار حسب الدور مجرد وهم. استخدم
auth/login.
خد بالك: الرد بيحط نفس الرقم في ED_STUD_ID وSA_STAFF_MEMBER_ID،
فالحقل اللي مالوش معنى للدور الحالي لازم يتجاهَل مش يتصدّق.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | auth/login | ● شغال | 🌐 من غير توكن | ⭐ ده الإندبوينت الرسمي — للطالب وللدكتور. الرد فيه IsStudent وهو اللي بيحدد المسار |
| POST | auth/login | ● شغال | 🌐 من غير توكن | ⭐ نفس الإندبوينت بحساب دكتور — IsStudent: false |
| POST | students/login | ● شغال | 🌐 من غير توكن | اسم قديم لنفس الهاندلر — بيقبل الطالب والدكتور. متسيبه للتوافق بس |
| POST | academicstaff/login | ● شغال | 🌐 من غير توكن | اسم قديم كمان — نفس الهاندلر بالظبط |
| POST | students/LoginAZ | 🔑 محتاج بيانات | 🌐 من غير توكن | جديد ⭐ دخول مايكروسوفت — التوكن بقى بيتراجع فعلًا (التوقيع، الـ tenant، الـ audience، الصلاحية). ابعت الـ id_token مش توكن Graph. مقفول على Innovation لأن طريقة الدخول الرئيسية «1» — شوف دليل دخول مايكروسوفت |
| POST | __sandbox/identity/token | 🧪 شغال بالـ Sandbox | 🌐 من غير توكن | جديد 🧪 توكن مايكروسوفت تجريبي موقّع من الـ Sandbox — ابعته لـ students/LoginAZ وجرّب الدورة كلها من غير tenant. شغال بس لما «Microsoft sign-in» مفتوح في تاب Sandbox |
| POST | students/GetForgetPasswordCode | 🔑 محتاج بيانات | 🌐 من غير توكن | بيولّد كود ويبعته إيميل — محتاج بيانات SMTP صح |
| POST | students/ResetPasswordUsingCode | ● شغال | 🌐 من غير توكن | تغيير الباسورد الفعلي على الـ AD لسه متكتبش |
| POST | auth/me | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ جديد ده اللي بيقول لك الشخص ده يشوف إيه — بيرجّع home وscreens[] بـ allowed/reason وfeatures[] بتاعة دوره بس. شوف فصل الشاشات المسموحة |
| GET | Info/Capabilities | ● شغال | 🌐 من غير توكن | حالة التركيب نفسه — بيتنادى قبل شاشة الدخول ومش عارف مين بيسأل. مش بديل لـ auth/me |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| إندبوينت دخول واحد + فلاج IsStudent | متعمل | ⭐ auth/login بيخدم الاتنين، والرد بيقول IsStudent. الديمو حذف اختيار «طالب / عضو هيئة تدريس» من شاشة الدخول خالص — المستخدم مايتسألش عن حاجة السيرفس عارفها. |
— |
| ① الدخول الافتراضي (يوزر + باسورد افتراضي) | متعمل | جديد الـ SIS مفيهوش باسوردات أصلًا، فالطريقة دي ليها وضعين من الأدمن: «أي باسورد» (زي النسخ القديمة — وده اللي على Innovation دلوقتي عشان شغلكم مايقفش) أو «باسورد موحّد» زي 123 بتاع Lotus. لو الباسورد غلط الرد: details: "password not correct". |
— |
| ② Active Directory | متعمل | جديد اتعمل فعلًا (كان TODO بيرفض دايمًا): LDAP bind بـ user@domain زي الكود القديم بالظبط، وفي الأدمن زرار «Test sign-in» يجرّب بحساب حقيقي. لو الـ DC مش بيرد، الرد بييجي في ثواني: «The university directory could not be reached». | بيانات الـ domain controller من الجامعة |
| ③ Microsoft (Azure) | متعمل | جديد التوكن بيتراجع مقابل مفاتيح الـ tenant — التوقيع والـ issuer والـ audience والصلاحية. توكن Graph بيترفض برسالة بتقول تبعت إيه بداله. اتجرّب بـ 6 حالات على الـ Sandbox. | App Registration من الجامعة + الموبايل يبعت id_token |
| الاتنين مع بعض | متعمل | جديد لو الرئيسي مايكروسوفت، الأدمن يقدر يسيب اليوزر والباسورد شغالين جنبه (بـ ① أو ②) أو يقفلهم. مقفولين ← auth/login بيرد «Sign in with your Microsoft account.» |
— |
| تحديد السنة والفصل | متعمل | 4 أوضاع (GlobalCurrent / StudentLastSemester / FacultyCurrentYear / ByUserType). |
⚠️ في الداتابيز دي CURRENT_YEAR لسه على 2023/24 والفصل المفتوح 2025/26 — فمستخدمين ByUserType |
| JWT للموبايل | متعمل | HS256، المدة من البروفايل، فيه claims: seUserId / edStudId / userType. | — |
| نسيت الباسورد | جاهز · مستني بيانات | بيولّد الكود ويحفظه، لكن الإيميل بيقع. | بيانات SMTP حقيقية في تبويب E-mail |
الرئيسية
Home
قلب التطبيق. بتعرض: تحية باسم الطالب، محاضرات النهارده على خط زمني، المحاضرة اللي شغالة دلوقتي بزرار تسجيل حضور، اختصارات سريعة، آخر الإعلانات، والخدمات المتصلة.
بيشتغل إزاي؟
الشاشة دي مش بتنادي إندبوينت خاص بيها — بتتبني من الداتا اللي اتحمّلت بعد اللوجين.
الجدول بيتقسم بالأيام (GS_CODE_WEEK_DAY_ID: 2=السبت … 7=الخميس)، وبنقارن ساعة
الموبايل بـ FROM_TIME/TO_TIME عشان نعرف المحاضرة past / current / upcoming.
ملاحظة مهمة: النهارده بره فترة الفصل، فالتطبيق بيعرض أقرب يوم دراسي جاي بدل ما يعرض يوم فاضي.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/scheduledays | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
مصدر محاضرات النهارده (قاعة، دكتور، مجموعة) |
| POST | students/get | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ كارت الطالب — وفيه STUD_PHOTO اترجع: لينك كامل جاهز للـ <img>، مش اسم ملف. الخدمة بتركّبه من إعداد Media.StudentPhotoBaseUrl، ولو مفيش مجلد صور متظبّط بترجّع صورة افتراضية من عندها عشان الشاشة ماتبانش مكسورة |
| POST | students/GetMobileNotifications | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
عدّاد الجرس |
| POST | students/schedulePerday | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ محاضرات النهارده — محتاج SC_SCHEDULE_DTL_Date يغطّي النهاردة |
| GET | Info/Capabilities | ● شغال | 🌐 من غير توكن | بيحدد الخدمات المتصلة اللي تتعرض |
| POST | students/GetStudentAttend | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ ✍️ الطالب بيمسح كود المحاضرة. لازم يكون مسجّل في السكشن ده — والمثال هنا سكشن الطالب نفسه. بيرفض بسبب واضح لو الجلسة مش موجودة، أو مش يوم المحاضرة، أو برّه الوقت، أو مش مسجّل. ومسح مرتين = سطر واحد · جديد ٢ ابعت QR_TOKEN وQR_WINDOW من الـ payload؛ المسح بيسجّل «حاضر» في الكشف على طول |
| POST | students/AttendByCode | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ٢ للي مش عارف يمسح: الـ 6 أرقام اللي تحت الـ QR |
| POST | students/CheckInByLocation | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ ✍️ جديد الحضور بالموقع — الطريق التاني الموازي للـ QR. التطبيق بيبعت القراية بس، والسيرفر هو اللي بيحدد المحاضرة من جدول الطالب ويتأكد إنه جوه الحرم. جرّبناه على الداتابيز الحقيقية: من جوه الحدود اتسجّل حضور في SUR311، ومن ميدان التحرير رجّع «إنت بره حرم الجامعة بحوالي 1639 متر»، وتاني ضغطة = نفس السطر |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| محاضرات النهارده | متعمل | 14 محاضرة راجعة فعليًا للطالب التجريبي. | — |
| تحديد المحاضرة الحالية | متعمل | بيتحسب في الموبايل من ساعة الجهاز — مفيش إندبوينت مطلوب. | — |
| تسجيل الحضور بالموقع (GPS) | متعمل | ⭐ جديد زرار تاني جنب الـ QR: التطبيق بياخد إحداثيات الجهاز ويبعتها، والسيرفر بيرد اتسجّل ولا لأ وليه. مابتبعتش رقم محاضرة — السيرفر بيلاقيها لوحده، ومافيش أي حساب في التطبيق. الطريقتين مستقلين والطالب يختار. التفاصيل في شاشة تسجيل الحضور بالموقع. والبصمة اتحذفت من الشاشة — كانت رسمة لتحقق مش موجود أصلاً. | إذن الموقع في التطبيق + الجامعة ترسم حدودها مرة واحدة |
| الحضور بالـ QR | متعمل | ⭐ جديد اتعمل كامل: عرض الكود، المسح بكل التحققات، وقفل المحاضرة اللي بيسجّل غياب اللي مامسحش. شوف فصل الحضور. | — |
| الإعلانات | ناقص | الإعلانات اللي في الشاشة ثابتة في الكود. | إندبوينت إعلانات (ممكن يتبني على SV_MESSAGE) أو استخدام الإشعارات |
| عدّاد الإشعارات | متعمل | الإندبوينت شغال، بس صندوق الطالب ده فاضي. | إرسال إشعارات من الباك أوفيس |
| الخدمات المتصلة (Teams/Moodle) | جاهز · مستني بيانات | بيتعرضوا حسب Info/Capabilities، وعليهم علامة «غير مفعّل». |
بيانات Teams و Moodle في تبويب Integrations |
الجدول الدراسي
Schedule
الجدول الأسبوعي كامل من السبت للخميس، وكل يوم بيعرض محاضراته بالتوقيت والقاعة والدكتور. فيه كمان تبويب لجدول الاختبارات، وعرض شهري.
بيشتغل إزاي؟
students/scheduledays بيرجع صف لكل حصة في الأسبوع (مش لكل مقرر). التطبيق
بيجمّعهم بـ GS_CODE_WEEK_DAY_ID ويرتّبهم بـ FROM_TIME.
students/schedule بيرجع المقررات المسجلة نفسها (مستخدم في شاشة المقررات).
جديد كل سكشن بقى بيقول بيتدرّس إمتى وفين — في students/schedule
وفي academicstaff/GetStaffSchedule، بنفس أسامي حقول شاشة التسجيل:
DaysAr · FromTime · ToTime · HallAr ·
BuildingAr · CampusAr (المقر) للسطر الواحد، وmeetings[] لكل
يوم لوحده (DayAr, FromTime, HallAr, CampusAr,
TeachingMethodAr) — لأن المعمل ممكن يبقى في قاعة غير المحاضرة. سكشن مالوش مواعيد متسجّلة
بيرجع meetings: [].
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/scheduledays | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ الأساسي — 14 حصة بالتفاصيل |
| POST | students/schedule | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
المقررات المسجلة (كود، ساعات، مجموعة) جديد + الأيام والمقر والقاعة وmeetings[] · جديد ٢ + officeHourBookings[] — حجوزات الطالب الجاية |
| POST | students/GetExamSchdule | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ جدول الامتحانات بالقاعات — بيحتاج IS_EXAM_APPROVED=1 وتوزيع لجان للطالب |
| POST | semester/semsterCalnd | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
اتصلّح التقويم الأكاديمي — 48 بند للربيع |
| POST | academicstaff/GetStaffSchedule | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ اتصلّح جدول الدكتور — سطر لكل سكشن (مش مكرر 3 مرات) + SC_SCHEDULE_DTL_ID وmeetings[] · جديد ٢ + officeHourBookings[] — حجوزات الساعات المكتبية الجاية |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| الجدول الأسبوعي | متعمل | شغال بالكامل بأسماء القاعات والدكاترة والمجموعات. | — |
| جدول الاختبارات | متعمل | الإندبوينت والـ feature شغالين، بس ED_EXAM_SCHDL فاضي للطالب ده. |
إدخال جدول الامتحانات من الباك أوفيس |
| العرض الشهري | ناقص | الأيام اللي عليها محاضرات/امتحانات ثابتة في الكود (مايو 2026). | اشتقاقها من scheduledays + جدول الامتحانات — شغل موبايل مش باك إند |
| التقويم الأكاديمي | متعمل | اتصلّح بيرجّع 48 بند للربيع. شوف شاشة التقويم — السبب كان قاعدة «يظهر للطالب» القديمة. | — |
| جدول الدكتور | متعمل | اتصلّح كان بيرد «data not found» لأي دكتور سكاشنه مش جوّه «مجموعة سكاشن» (وده أغلب الدكاترة). وكل سكشن كان بيتكرر 3 مرات. الاتنين اتصلّحوا في الكود. | — |
| أيام التدريس والمقر لكل سكشن | متعمل | جديد DaysAr / CampusAr / meetings[] في الجدولين — نفس شكل شاشة التسجيل. |
— |
المقررات الدراسية
Courses

قايمة مقررات الفصل الحالي، وكل مقرر بيعرض الكود والساعات ونسبة الحضور والتقدّم. الضغط على مقرر بيفتح صفحة تفاصيله.
بيشتغل إزاي؟
التطبيق بيدمج 3 مصادر: students/schedule (المقررات المسجلة)،
students/getabs (نسبة الغياب لكل مقرر)، students/semresult (الدرجة لو ظهرت).
الدمج بيحصل بـ ED_COURSE_ID.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/schedule | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ المقررات المسجلة · جديد ٢ + officeHourBookings[] — حجوزات الطالب الجاية |
| POST | students/getabs | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
نسبة الحضور لكل مقرر |
| POST | students/GetCourseworkMarks | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ⭐ درجات أعمال الفصل — الدرجات اللي بتتجمّع خلال الترم لكل مقرر ولكل عنصر تقييم (امتحان نصفي، عملي، مشروع…) ومن كام. دي شاشة StudSemWork في منيو الـ SIS نفسه، وكانت ناقصة تمامًا: كان عندنا النتيجة النهائية والسجل الأكاديمي بس. لو ماتبعتش سنة/فصل بيرجّع فصل الطالب الحالي |
| POST | students/semresult | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
الدرجة والحالة |
| POST | Faculties/CoursesCatalogNew | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
وصف المقرر والمصروفات |
| POST | lms/MyCourses | 🧪 شغال بالـ Sandbox | 🎓 طالب mahmoued.eprahim.23010062 |
جديد مقررات Moodle بنسبة الإنجاز — 4 مواد راجعة |
| POST | lms/Assignments | 🧪 شغال بالـ Sandbox | 🎓 طالب mahmoued.eprahim.23010062 |
جديد التكليفات ومواعيد التسليم — مرتّبة بالأقرب |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| قايمة المقررات | متعمل | 8 مقررات راجعة فعليًا. | — |
| نسبة الحضور لكل مقرر | متعمل | من getabs — بيرجع كمان حدود الإنذار (15%) والحرمان (25%) من إعدادات العميل نفسه. |
— |
| الدرجة الحالية | متعمل | شغال، بس درجات الفصل ده لسه ما اعتُمدتش (GRADING_AR فاضي). |
اعتماد النتيجة من الكنترول |
| نسبة التقدّم في المقرر | متعمل | ⭐ الموبايل بقى بياخد نسبة الإنجاز الحقيقية من Moodle لكل مقرر، وبيرجع لتقدّم الفصل بس للمقررات اللي Moodle مايعرفهاش — والشاشة بتقول ده صراحةً، بدل ما رقم تقريبي يبان كأنه داتا. | — |
| تكليفات ومواعيد تسليم (Moodle) | متعمل | جديد MoodleLmsProvider شغال ومتجرَّب على الـ Sandbox: بيطابق الطالب، يجيب مواده وتكليفاته، ويرتّبهم بالأقرب تسليمًا. اتصلّح هنا باج: الكود كان بيقرا STUD_FACULTY_CODE من جدول ED_STUD وهو أصلاً على ED_STUD_FACULTY، فالشاشة كلها كانت بترمي 500. |
baseUrl + wsToken من أدمن Moodle الحقيقي |
| اسم الدكتور في الكارت | متعمل | الموبايل بيدمج schedule مع scheduledays — التاني هو اللي فيه اسم الدكتور. الدمج اتعمل والكارت بيعرض الاسم. |
— |
| محتوى المقرر والمراجع | متعمل | ⭐ COURSE_CONTENTS_AR بقى معروض في صفحة المقرر. |
— |
نتيجة الفصل
Grades
السجل الأكاديمي كامل: كل فصل بمعدله ومعدله التراكمي والساعات، وجوّاه درجات كل مقرر، مع منتقي فصول ورسم لتطور المعدل.
بيشتغل إزاي؟
students/transcript بيرجع شجرة: سنة ← فصل ← مقررات. كل صف مقرر جواه كمان
SEM_GPA وACCUM_GPA وACCUM_CH، فالتطبيق بياخد أول صف
في الفصل كمصدر لإحصائيات الفصل كله.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/transcript | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ 3 سنين × فصولها × مقرراتها |
| POST | students/semresult | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
نتيجة الفصل الحالي بس |
| GET | students/GetSTudentTranscriptApi | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⚠️ GET مش POST · بيحتاج RESULT_APPROVE_FLG=1 |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| السجل الأكاديمي الكامل | متعمل | 3 سنين دراسية راجعة بالمقررات والدرجات والنقاط. | — |
| المعدل الفصلي والتراكمي | متعمل | جاي جاهز من الـ SQL — مش محسوب في الموبايل. | — |
| تطور المعدل (رسم) | متعمل | بيتبني من نفس بيانات الترانسكريبت. | — |
| حارس «النتيجة معتمدة؟» | متعمل | ⭐ القرار اتاخد من البوابة نفسها: فلتر الاعتماد في CurrentCourseResultResults.aspx.cs متعلّق عليه كومنت — يعني البوابة بتعرض النتيجة سواء اتعمدت أو لأ. فالموبايل بيعرضها كمان وبيعلّم عليها «غير معتمدة» بدل ما يخفيها. اللي فعلاً متقفل على الاعتماد هو السجل الرسمي وده مظبوط. |
— |
| تحميل الترانسكريبت PDF | ناقص | مفيش أي إندبوينت لده. | إندبوينت يولّد PDF أو يوصل لتقرير الـ SIS |
تسجيل الحضور بالموقع
Location check-in


الطالب بيسجّل حضوره لإنه موجود في الجامعة فعلاً. التطبيق بيبعت إحداثيات الجهاز، والسيرفر بيحكم. طريق موازي للـ QR — مش بديل ليه ولا خطوة قبله.
بيشتغل إزاي؟
إنت بتبعت 3 أرقام وبس — LAT وLNG وACC (دقة القراية
بالمتر زي ما الجهاز إداهالك). مابتبعتش رقم مقرر ولا رقم محاضرة: السيرفر بيدوّر لوحده في
جدول الطالب على المحاضرة الشغالة دلوقتي، فالزرار واحد في كل الشاشات ومفيش حاجة تظبّطها قبل ما تبعت.
وماتعملش أي حساب عندك: حدود الجامعة عمرها ما بتوصل للتطبيق — مفيش مكتبة geofence ولا
مسافات ولا حدود متخزّنة عندك. إنت بتبعت قراية والسيرفر بيحكم.
الرد: نجاح فيه messageAr جاهزة للعرض + session (اسم المقرر)
+ presenceTime + locationAr. وalreadyRecorded: true معناها
ضغط تاني — <u>ده مش error</u>، اعرضه بشكل النجاح.
الرفض بيرجع HTTP 200 بـ result: "ERROR" وdetails رسالة عربي
جاهزة للطالب — اعرضها زي ما هي.
الأذونات: iOS NSLocationWhenInUseUsageDescription، أندرويد
ACCESS_FINE_LOCATION (الـ COARSE لوحده السيرفر هيرفض دقته). اقرا قراية جديدة
(maximumAge = 0) بدقة عالية وtimeout ~15 ثانية، ولو المستخدم رفض الإذن
سيبله الـ QR شغال. وفي الويب/WebView على http المتصفح بيمنع الموقع خالص.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| GET | Info/Capabilities | ● شغال | 🌐 من غير توكن | فيه campus.checkInEnabled — التطبيق بيخفي الزرار لو الجامعة مافعّلتش الخاصية أو مرسمتش حدود |
| POST | students/CheckInByLocation | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ ✍️ جديد من جوّه الحدود: اتسجّل حضور في SUR311 والسيرفس هو اللي اختار المحاضرة. تاني ضغطة = نفس السطر |
| POST | students/CheckInByLocation | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ من ميدان التحرير: «إنت بره حرم الجامعة بحوالي 1639 متر» |
| POST | students/CheckInByLocation | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ قراية دقتها ±800 متر: «إشارة الموقع ضعيفة» — بيترفض قبل ما يبص للحدود أصلاً |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| الزرار يبان امتى | متعمل | من Info/Capabilities → campus.checkInEnabled. لو false ماتعرضهوش أصلاً بدل ما الطالب يدوس وياخد رفض. |
— |
| قراية الموقع | متعمل | إذن + قراية جديدة بدقة عالية. أول قراية بتيجي وحشة وبعد ثانيتين بتتحسّن — استنى الكويسة قبل ما تبعت. | ربط الـ GPS في التطبيق الحقيقي |
| التحقق نفسه | متعمل | ⭐ كله في السيرفر: دقة القراية، جوه الحدود ولا لأ، وأنهي محاضرة. مفيش أي منطق عندك — والحدود مابتتبعتش للتطبيق عن قصد. | — |
| رسائل الرفض | متعمل | أربع حالات وكلها بتيجي جاهزة بالعربي في details: بره الحرم (وبالمسافة)، إشارة ضعيفة، مفيش محاضرة دلوقتي، الخاصية مقفولة. |
— |
| ضغط مرتين | متعمل | السيرفر مابيسجّلش مرتين وبيرجّع أول وقت — بس اقفل الزرار وقت الانتظار للـ UX. | — |
| حدود الجامعة | متعمل | بترسمها الجامعة مرة واحدة من لوحة الإدارة (تبويب Campus map) — مش شغلك. لو مرسموش، الخاصية بتيجي مقفولة في Capabilities. |
الأدمن يرسمها |
| تخزين مسار الطالب | ناقص | مش متعمل عن قصد. الإحداثيات بتتفحص وتترمي — مفيش سجل بمكان الطالب. لو الجامعة طلبت ده، بيبقى قرار وشغل جديد. | قرار من الجامعة |
الحضور والغياب
Attendance
أهم شاشة للطالب عمليًا. بتعرض نسبة الغياب في كل مقرر بالألوان (أخضر/أصفر/أحمر)، وكام يوم فاضل قبل الإنذار، وتواريخ الغياب بالتفصيل.
بيشتغل إزاي؟
students/getabs بيرجع لكل مقرر: StudAbs (عدد مرات الغياب)،
StudAbsPrcnt (النسبة)، وقايمة absences بالتواريخ.
والأهم: بيرجع كمان ABS_RATE_WARNINIG_1 وABS_RATE_COURSE_FAIL —
يعني حدود الإنذار والحرمان بتيجي من إعدادات الجامعة نفسها مش ثابتة في الموبايل.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/getabs | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ 8 مقررات بتواريخ الغياب والحدود |
| POST | academicstaff/getabs | ● شغال | 👨🏫 دكتور atef.dahesh |
نفس الإندبوينت لمسار الموظفين |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| نسبة الغياب لكل مقرر | متعمل | شغال بالكامل بداتا حقيقية. | — |
| حدود الإنذار والحرمان | متعمل | بتيجي من الداتابيز (15% إنذار / 25% حرمان هنا). | — |
| تواريخ الغياب بالتفصيل | متعمل | مع نوع الحصة (محاضرة/عملي) وهل معذور. | — |
| وضع نظام الساعات مقابل السنوي | متعمل | الفلاج isModular بيبدّل الاستعلام تلقائيًا. |
— |
| تقديم عذر غياب | ناقص | مفيش إندبوينت خالص. | إندبوينت رفع عذر + مرفق + دورة موافقة |
جدول الاختبارات
Exams
عدّاد لأقرب امتحان، وقايمة الامتحانات بالتاريخ والوقت والقاعة ورقم الجلوس.
بيشتغل إزاي؟
students/GetExamSchdule بيقرا من ED_EXAM_SCHDL. الشاشة محكومة
بـ feature examSchedule.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/GetExamSchdule | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ جدول الامتحانات بالقاعات — بيحتاج IS_EXAM_APPROVED=1 وتوزيع لجان للطالب |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| جدول الامتحانات | متعمل | الكود والـ feature والجدول موجودين — بس ED_EXAM_SCHDL فاضي. |
إدخال الجدول من الكنترول — مش شغل برمجة |
| رقم الجلوس والقاعة | متعمل | الأعمدة موجودة في الـ SQL. | نفس الكلام — بيانات |
| تذكير قبل الامتحان | ناقص | مفيش جدولة إشعارات. | مهمة مجدولة تبعت push قبل الامتحان بيوم |
الملف الشخصي
Profile
بيانات الطالب الكاملة: الرقم الجامعي، الكلية، التخصص، المستوى، الحالة القيدية، المعدل، الساعات المنجزة، المرشد الأكاديمي، والتواصل. وتحتها قايمة الخدمات والإعدادات.
بيشتغل إزاي؟
students/get بيرجع صف واحد فيه ~35 عمود — ده الـ «كارت» بتاع الطالب.
بيستخدم dbo.fn_GetStudContactMethod عشان يجيب الإيميل والموبايل.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/get | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ كل بيانات الطالب |
| POST | academicstaff/get | ● شغال | 👨🏫 دكتور atef.dahesh |
بيانات الدكتور |
| GET | Files/UserImages/{name} | ● شغال | 🌐 من غير توكن | صورة الطالب — بيقرا من فولدر Files/UserImages، اسم الملف هو الكود الجامعي + .jpg |
| POST | students/GetContactMethods | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد 🔒 وسائل التواصل — مقفول افتراضيًا (studentContactEdit) |
| POST | students/SaveContactMethod | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد 🔒 ✍️ إضافة/تعديل/حذف — مقفول افتراضيًا |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| بيانات الطالب | متعمل | كله راجع: الاسم، الكود، الكلية، المستوى، GPA 2.42، 101 ساعة، المرشد. | — |
| كارت الموظف | متعمل | academicstaff/get بيرجّع بيانات الدكتور. نفس القصة: الحساب المجرّب هو اللي مكانش عليه داتا. |
— |
| صورة الطالب | ناقص | Files/UserImages لسه متعملش. |
ستريم للملف + مسار الصور في الإعدادات |
| تعديل البيانات (موبايل/إيميل) | ناقص | العرض بس، مفيش تعديل. | إندبوينت تحديث + دورة موافقة |
| تغيير اللغة | ناقص | التطبيق عربي بس دلوقتي (SHOW_EN = false). |
تفعيل الفلاج + مراجعة النصوص الإنجليزية |
البطاقة الجامعية
Digital ID
بطاقة الطالب الرقمية بالاسم والكلية والرقم الجامعي وكود QR للدخول والمكتبة.
بيشتغل إزاي؟
دلوقتي البطاقة بتتبني من students/get، والـ QR شكل بس مش قابل للمسح —
نمط ثابت مشتق من بيانات الطالب. الإندبوينت الحقيقي students/GetStudentQRCode موجود
ومربوط بـ feature qrCard بس بيرجع «data not found».
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/get | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
بيانات البطاقة |
| POST | students/GetStudentQRCode | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⚠️ بيرجّع صورة PNG مش JSON · UserName بياخد اسم الدخول أو الكود الجامعي، ولو بعتّه بودي فاضي بيرجّع كارنيه صاحب التوكن |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| بيانات البطاقة | متعمل | الاسم والكلية والرقم كلهم حقيقيين. | — |
| كود QR حقيقي | متعمل | students/GetStudentQRCode بيرجّع صورة PNG فعلية. كان بيرد «data not found» لما تبعتله اسم الدخول لأنه كان بيدوّر بـالكود الجامعي بس — دلوقتي بيقبل الاتنين، وبودي فاضي بيرجّع كارنيه صاحب التوكن. |
— |
| صلاحية مؤقتة للكود | ناقص | العدّاد «صالح 04:58» ديكور في الموبايل. | كود موقّع بوقت انتهاء + إندبوينت تحقق للبوابة |
| إضافة لـ Apple/Google Wallet | ناقص | الزرار موجود بس مش موصّل. | توليد pass موقّع — شغل كبير ومحتاج شهادات |
المحادثات
Chat

شات نص، فرد لفرد، بين الطالب والدكتور. الطالب بيكلّم مرشده أو دكاترة مقرراته، والدكتور بيكلّم طلبة إشرافه أو طلبة مقرراته. الطرفين بيشوفوا نفس المحادثة بالظبط.
بيشتغل إزاي؟
٣ شاشات، وكل واحدة نداء واحد:
١) شاشة «ابعت لمين» (اختيار جهة اتصال جديدة)
الطالب ينادي getInstructorsAndAdvisorForAsk → بيرجّع AcademicAdvisior
(المرشد) وInstructors (دكاترة مقرراته الترم ده).
الدكتور ينادي getStudentsForAsk → بيرجّع Advisees (طلبة إشرافه)
وCourses (مقرراته) وCourseStudents (طلبة المقررات).
٢) شاشة الصندوق (المحادثات القايمة)
الطالب: GetStudMailInBox · الدكتور: GetStaffMailInBox.
كل صف = محادثة. فيه اسم الطرف التاني، عدد الرسايل، تاريخ آخر رسالة، وحقول لازم تخزّنها
وتبعتها زي ما هي لما تفتح المحادثة أو تبعت رد.
٣) شاشة المحادثة نفسها
GetaskById بيرجّع courses[] — مصفوفة رسايل مرتّبة بالتاريخ.
وAddAsk بيبعت رسالة جديدة.
ــــــــــــــــــــ
🎨 إزاي ترسم الفقاعة يمين ولا شمال
كل رسالة في courses[] معاها AdvChat:
AdvChat: true ← الرسالة من الدكتور / المرشد
AdvChat: false ← الرسالة من الطالب
خلاص، مفيش مقارنة IDs ولا حسابات. الفلاج ده دايمًا موجود في كل رسالة.
(فيه كمان FROM_STUD — ده القديم، وبيرجع
null في الرسايل المكتوبة من بوابة الويب. متعتمدش عليه، استخدم
AdvChat.)
⚠️ أهم حاجة: AdvChat في الريكوست ≠ AdvChat في الرسالة
الاتنين اسمهم واحد بس معناهم مختلف:
• جوّه الرسالة → مين كتبها (اقراه بس)
• في بودي AddAsk → قناة المحادثة (اكتبه بس)
القاعدة الذهبية: الـ AdvChat اللي هتبعته في AddAsk خده
زي ما هو من صف الصندوق (أو من صف جهة الاتصال). متحطّش قيمة ثابتة من عندك —
ده اللي كان بيخلّي المحادثة تفتح فاضية.
📋 الحقول اللي بتنتقل من الصندوق للمحادثة
من صف الصندوق خُد: SA_STF_MEMBER_ID (أو ED_STUD_ID لو إنت في تطبيق
الدكتور) + ED_ACAD_YEAR_ID + ED_CODE_SEMESTER_ID +
AS_FACULTY_INFO_ID + AdvChat — وابعتهم زي ما هم في
GetaskById وAddAsk. مفيش أي رقم تحسبه إنت.
🔒 حاجات السيرفر بيتجاهلها من الريكوست
رقمك إنت (رقم الطالب لو داخل بحساب طالب، رقم الدكتور لو داخل بحساب دكتور) بيتاخد من
التوكن مش من البودي. فمهما بعت رقم تاني، السيرفر هيستخدم بتاعك. سيبه في البودي عادي
(مفيش حاجة هتقع)، بس متتوقعش إنك تقرا محادثة حد تاني بيه.
🔁 مفيش إشعارات لسه
لما الطرف التاني يبعت، مفيش push بيوصل. لو عايز الشاشة تتحدّث، اعمل polling على
GetaskById وإنت فاتح المحادثة.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/getInstructorsAndAdvisorForAsk | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
👤 شاشة «ابعت لمين» — الطالب. الرد: AcademicAdvisior (أوبچكت واحد، ممكن يرجع فاضي) + Instructors[] (15 صف هنا). الدكتور الواحد ممكن يتكرر لو بيدّي أكتر من مقرر — اعمل distinct على SA_STF_MEMBER_ID لو عايز قايمة أشخاص |
| POST | academicstaff/getStudentsForAsk | ● شغال | 👨🏫 دكتور atef.dahesh |
👨🏫 شاشة «ابعت لمين» — الدكتور. ⭐ جديد. الرد فيه ٣ قوايم: Advisees[] (25) + Courses[] (7، كل مقرر بعدد طلبته) + CourseStudents[] (920). كل صف طالب جايب AdvChat وMessagesCount والسنة/الترم/الكلية → افتح المحادثة منه على طول |
| POST | academicstaff/getStudentsForAsk | ● شغال | 👨🏫 دكتور atef.dahesh |
⚡ نفس النداء بس بمقرر واحد. CourseStudents بترجع 26 بدل 920. الطريقة المفضّلة: النداء الأول من غير EdCourseId واعرض Advisees + Courses بس، وأول ما يدوس على مقرر نادي تاني بالـ id بتاعه |
| POST | students/GetStudMailInBox | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
📥 صندوق الطالب. صف لكل دكتور. اعرض StaffNameAr/En وcount وLastMessageDate، وحطّ شارة «مرشدك» لو IsAdvisor=true. خزّن SA_STF_MEMBER_ID وAdvChat للخطوة اللي بعدها |
| POST | students/GetStaffMailInBox | ● شغال | 👨🏫 دكتور atef.dahesh |
📥 صندوق الدكتور. صف لكل طالب — StudentNameAr/En. خزّن ED_STUD_ID وAdvChat والسنة/الترم/الكلية من نفس الصف |
| POST | students/GetaskById | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
💬 شاشة المحادثة — عين الطالب. saStaffMemberId = الدكتور اللي بتكلمه (مش إنت). الرد courses[] مرتّب بالتاريخ، وكل رسالة فيها AdvChat (مين كتبها) وRE_DTL (النص) وRE_DATE |
| POST | academicstaff/GetaskById | ● شغال | 👨🏫 دكتور atef.dahesh |
💬 نفس المحادثة — عين الدكتور. بيرجّع نفس المصفوفة بالظبط. يعني تقدر تستخدم نفس الـ model ونفس الـ widget في التطبيقين |
| POST | students/AddAsk | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
✍️ الطالب بيبعت. FromStud: true ثابت من تطبيق الطالب. AdvChat خده من الصندوق. الرد courses: true يعني اتبعتت — بعدها نادي GetaskById تاني عشان تجيب الرسالة بتاريخها |
| POST | academicstaff/AddAsk | ● شغال | 👨🏫 دكتور atef.dahesh |
✍️ الدكتور بيرد. FromStud: false ثابت من تطبيق الدكتور — ده اللي بيخلّي الفقاعة تطلع للطالب على إنها منك |
| POST | students/SendMessageToCourse | ● شغال | 👨🏫 دكتور atef.dahesh |
📢 إعلان لكل طلبة مقرر. نداء واحد بيبعت لكل مسجّل. بيوصل كل طالب كـ رسالة شخصية في صندوقه (مش جروب) — فمتستغربش لو الصندوق كبر فجأة · جديد ٢ اختار سكاشن: ScScheduleDtlIds (فاضية = كل سكاشن الدكتور). بيروح لطلبة سكاشن الدكتور بس، ولكل طالب مرة واحدة. الرد Sent وSections — التفاصيل |
| POST | academicstaff/SendMessageToCourse | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ٢ نفس الإعلان من حساب الدكتور، لسكاشن يختارها (من academicstaff/GetMySections) |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| قايمة «ابعت لمين» للطالب | متعمل | المرشد + دكاترة المقررات المسجّلة الترم ده، باسم المقرر. | — |
| قايمة «ابعت لمين» للدكتور | متعمل | ⭐ جديد. academicstaff/getStudentsForAsk — طلبة الإشراف + المقررات + طلبة المقررات في نداء واحد. قبل كده الدكتور كان لازم يستنى الطالب يبعت الأول. |
— |
| صندوق المحادثات | متعمل | الطرفين. صف لكل محادثة بالاسم والعدد وتاريخ آخر رسالة. | — |
| قراءة المحادثة | متعمل | نفس المصفوفة بالظبط من الناحيتين — نفس الـ model في التطبيقين. | — |
| إرسال رسالة | متعمل | من الطالب ومن الدكتور. بتوصل للطرف التاني فورًا من غير أي موافقة في النص. | — |
| مصدر الرسالة (يمين/شمال) | متعمل | اقرا AdvChat من الرسالة: true = الدكتور/المرشد، false = الطالب. موجود في كل رسالة من غير استثناء. |
— |
| شارة «مرشدك» / «طالب إشراف» | متعمل | IsAdvisor في صندوق الطالب، وIsAdvisee في قايمة الدكتور. |
— |
| إعلان لكل طلبة مقرر | متعمل | SendMessageToCourse شغال فعلًا وبيكتب — بيوصل لكل طالب كرسالة شخصية في صندوقه، مش كجروب. |
— |
| عدّاد رسايل غير مقروءة | ناقص | مفيش عمود «مقروء» في الـ SIS. count اللي راجع = إجمالي الرسايل مش الجديد. |
إما عمود جديد في الداتابيز، أو تخزّن آخر LastMessageDate شفتها محليًا في التطبيق وتقارن |
| إشعار عند وصول رد | ناقص | مفيش push. الطرف التاني مش هيعرف غير لما يفتح التطبيق. | ربط AddAsk بالـ push — شغل باك اند. مؤقتًا: polling وإنت فاتح المحادثة |
| مؤشر «بيكتب» / علامات التسليم | ناقص | مفيش. الشات ده REST عادي مش realtime. | WebSocket / SignalR — قرار منتج |
| مجموعات وملفات وصور ومكالمات | ناقص | الشات نص فقط وفرد لفرد. | جداول جديدة + تخزين ملفات — قرار منتج |
| تعديل / مسح رسالة | ناقص | مفيش إندبوينت. موجود في بوابة الويب بس. | إندبوينتين جداد |
الإشعارات
Notifications
صندوق الإشعارات: المقروء وغير المقروء، مع إمكانية التعليم كمقروء أو الإسقاط.
بيشتغل إزاي؟
GetMobileNotifications بيقرا SV_USER_MESSAGE ⨝ SV_MESSAGE.
الضغط على إشعار بينادي SetReadedNotification، والإسقاط بينادي
SetDeletedNotification — الاتنين بيكتبوا في الداتابيز.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/GetMobileNotifications | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
الصندوق — فيه رسايل دلوقتي |
| POST | students/SetReadedNotification | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
✍️ تعليم كمقروء |
| POST | students/SetDeletedNotification | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
✍️ حذف |
| GET | students/GetTokenHelp | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
أنواع الأجهزة واللغات |
| POST | students/SaveToken | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
تسجيل توكن الإشعارات — SE_USER_ID بتاع صاحب الطلب نفسه |
| POST | students/SendNotification | 🧪 شغال بالـ Sandbox | 🎓 طالب mahmoued.eprahim.23010062 |
إرسال — بيشتغل بالـ Sandbox والرسالة بتتسجّل في الصندوق |
| POST | students/SendNotificationSIS | 🔑 محتاج بيانات | 🎓 طالب mahmoued.eprahim.23010062 |
من الباك أوفيس (X-Api-Key) |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| قراءة الصندوق | متعمل | شغال وفيه رسايل دلوقتي — بعتنا إشعار من SendNotification وظهر في الصندوق. |
— |
| تعليم كمقروء / حذف | متعمل | بيكتبوا في الداتابيز فعليًا. | — |
| تسجيل جهاز للـ push | متعمل | SaveToken بيعمل upsert بالتوكن. |
الموبايل يبعت توكن FCM الحقيقي بعد اللوجين |
| إرسال Push فعلي | متعمل | الكود موجود (FcmLegacyKey و FcmV1) وشغال دلوقتي بالـ Sandbox — الرسايل بتروح لـ outbox تقدر تقراه من /__sandbox/control/outbox. الجرس نفسه مش هيرن غير بـ Firebase حقيقي، بس صندوق الوارد جوّه التطبيق شغال بالكامل. اتصلّح هنا باجان: MSG_SUBJECT عموده 50 حرف والكود كان بيحشر فيه JSON باللغتين (كل الإشعارات كانت بتفشل)، والسنة والفصل بقوا بيتجابوا لوحدهم لو المرسل مبعتهمش. |
push.fcmServerKey الحقيقي أو ملف الـ service account |
| هوك الباك أوفيس | جاهز · مستني بيانات | محمي بـ X-Api-Key ومقفول دلوقتي. |
تفعيل feature backOfficeNotifications + مفتاح |
الرسوم والمدفوعات
Payments

الشاشة بتعرض ملخص الحساب المالي (شغال بداتا حقيقية)، وبعدين رحلة دفع من 4 خطوات: اختيار الرسوم ← المبلغ ← تأكيد ← طريقة الدفع. الرحلة دي بقت شغالة من الأول للآخر دلوقتي على البوابة المزيّفة بتاعة الـ Sandbox — الطالب بياخد كود دفع حقيقي الشكل، ولما يتسدّد الإشعار بيرجع موقّع والرسوم بتتسجّل مدفوعة في الداتابيز.
بيشتغل إزاي؟
الاستعلام شغال، والدفع بقى شغال بالـ Sandbox.
students/GetTotalFeesInfo بيرجع الأرصدة والفواتير مقسّمة (دراسية / أخرى / غرامات) —
وده راجع فعليًا: 240,000 مدفوعة، خصم 5,600، متبقي 0.
الدفع الأونلاين اتبنى جديد بالكامل. واكتشاف مهم: الداتابيز أصلاً فيها جداول تكامل الدفع
بتاعة الـ SIS — INTEG_Fawry_Payment فيها 2,570 رقم فوري حقيقي،
وOnlinePaymentRequests فيها لينكات دفع MasterCard، وFEE_STUD_VOUCHER
فيها 18,235 سند. فالكود الجديد بيكتب في نفس الجداول دي مش في جداول جديدة، عشان شاشات
التسوية في الباك أوفيس تفضل شغالة.
الدورة اللي اتجرّبت فعليًا: التطبيق ينادي CreatePayment ← البوابة ترجّع كود
9 أرقام ولينك ← الطالب يدفع ← البوابة تبعت POST /payments/callback/Fawry موقّع ←
السيرفس يتحقق من التوقيع ويحدّث OnlinePaymentRequests وINTEG_Fawry_Payment
← التطبيق يشوف Paid. وجرّبنا كمان نبعت نفس الإشعار 3 مرات: اتسجّل مرة واحدة بس.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/GetTotalFeesInfo | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ ملخص الحساب — شغال |
| POST | students/fees | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
الرسوم مجمّعة بالعملة |
| POST | students/PaymentMethods | 🧪 شغال بالـ Sandbox | 🎓 طالب mahmoued.eprahim.23010062 |
جديد طرق الدفع المتاحة — بيرجّع kiosk + card |
| POST | students/CreatePayment | 🧪 شغال بالـ Sandbox | 🎓 طالب mahmoued.eprahim.23010062 |
جديد بدء الدفع — بيرجّع كود منافذ ولينك دفع |
| POST | students/PaymentStatus | 🧪 شغال بالـ Sandbox | 🎓 طالب mahmoued.eprahim.23010062 |
جديد متابعة الحالة — بيسأل البوابة مباشرة |
| POST | payments/callback/Fawry | 🧪 شغال بالـ Sandbox | 🎓 طالب mahmoued.eprahim.23010062 |
جديد إشعار السداد — بيتحقق من التوقيع، و idempotent (متجرَّب بـ replay) |
| POST | students/EfinancePay | 🔑 محتاج بيانات | 🎓 طالب mahmoued.eprahim.23010062 |
eFinance (السويس) — الـ SQL اتصلّح، بس محتاج صف رقم 7 في GS_CODE_PAY_METHOD (عميل eFinance) |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| ملخص الحساب المالي | متعمل | الإجماليات والمدفوع والخصم والمتبقي — كله حقيقي. | — |
| بنود الرسوم بالتفصيل | متعمل | الإندبوينت بيرجع StudyFees/OtherFees/FineFees، بس الطالب ده سدّد كل حاجة فالقوايم فاضية. |
طالب عليه متأخرات للتجربة |
| فوري (رقم مرجعي) | متعمل | جديد FawryPaymentProvider متكتب ومتجرَّب من الأول للآخر على بوابة الـ Sandbox: توقيع SHA-256، إنشاء الرقم، استعلام الحالة، وتحقق من إشعار V1/V2. |
merchantCode + securityKey من فوري — الكود نفسه مش هيتغيّر |
| محافظ (فودافون كاش / أورنج / اتصالات) | متعمل | جديد PaymobPaymentProvider متكتب ومتجرَّب: توكن → أوردر → مفتاح دفع → دفع بالمحفظة، وتحقق HMAC-SHA512. |
تظبيط payments.provider = Paymob + apiKey وhmacSecret وwalletIntegrationId |
| فيزا / ماستر كارد | متعمل | جديد MpgsPaymentProvider — نفس عيلة اللينكات الموجودة في الداتابيز، ومتجرَّب على الـ Sandbox. |
merchantId + apiPassword من البنك |
| إشعار السداد (callback) | متعمل | جديد متكتب وآمن ومتجرَّب: بيتحقق من التوقيع، والتحديث idempotent — بعتنا نفس الإشعار 3 مرات واتسجّل مرة واحدة. هنا لقينا باج خطير: الـ body مكانش بيتقري لو البوابة بعتت بـ chunked encoding، يعني كل إشعارات السداد كانت هتتفقد بصمت. | callbackBaseUrl عام بـ https + تسجيله عند البوابة |
| المحفظة الجامعية | ناقص | الرصيد دلوقتي في localStorage في الموبايل — مش حقيقي. |
إندبوينتات رصيد وشحن + قرار: جدول جديد ولا بند رسوم |
| سند سداد (Voucher) | جاهز · مستني بيانات | السند في شاشة الموبايل لسه وهمي، بس EfinancePay بينشئ سند حقيقي في FEE_STUD_VOUCHER — وده الكود اللي المفروض يتنقل لمسار الدفع الجديد. (اتصلّح فيه إن ED_CODE_SEMESTER_ID كان ناقص من الـ INSERT أصلاً، فمكانش بيشتغل خالص.) |
ربط CreatePayment بإنشاء السند + بنوده |
| إيصال ومطبوعات | ناقص | مفيش. | إندبوينت إيصال PDF |
خطة الدراسة
Study Plan

مسار التخرج: نسبة الإنجاز، الساعات المتبقية، والمقررات مقسّمة على حزم (متطلبات جامعة / كلية / تخصص / اختياري) وكل مقرر عليه علامة تم أو لأ.
بيشتغل إزاي؟
students/AcadPlan بيرجع الحزم (PKG_HDR_TITLE_AR) وجوّه المقررات
بدرجاتها. إجمالي الساعات المنجزة والمطلوبة بييجي من كارت الطالب (ACCUM_CH
وFULLFILLED_CH) لأنها الأدق.
جديد اعرض عمود الدرجة من DISPLAY_GRADE_AR على طول — جاهز للطباعة:
<table style="margin:8px 0"><tr><th>COURSE_STATUS</th><th>DISPLAY_GRADE_AR</th><th>معناها</th></tr>
<tr><td>Passed / Failed</td><td>الدرجة (A-، F…)</td><td>الدرجة اللي بتتحسب حسب لائحة الطالب</td></tr>
<tr><td>Registered</td><td>مسجل</td><td>مسجّله الترم ده ولسه مالوش درجة معتمدة — حتى لو أخده قبل كده وجاب D-: بيظهر الحالي بس</td></tr>
<tr><td>NotTaken</td><td>-----</td><td>عمره ما سجّله</td></tr>
<tr><td>Withdrawn / Incomplete / Transferred…</td><td>رمز الحالة (W، I، P)</td><td>حصل له حاجة غير الدرجة</td></tr></table>
مقرر اتعاد وخلص (D- وبعدين A): مش إحنا اللي بنقرر — كل لائحة في الـ SIS متسجّل عليها قاعدة الإعادة
(الأعلى / الأحدث / الأحدث بحد أقصى). GRADE_RULE بيقول اتطبّق أنهي (Best / Latest)،
وATTEMPTS عدد المحاولات، وIS_REPEATED لو أكتر من محاولة.
Course_Grading_AR القديم زي ما هو (آخر محاولة بس) — ماتعتمدش عليه في العمود ده.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/AcadPlan | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ 5 حزم بمقرراتها — جديد COURSE_STATUS + DISPLAY_GRADE_AR (الدرجة / مسجل / -----) |
| POST | students/get | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
إجمالي الساعات |
| GET | students/GetSTudentPaln | 🔒 مقفول | 🎓 طالب mahmoued.eprahim.23010062 |
نسخة KU من نفس الشاشة — بديل لـ students/AcadPlan مش إضافة ليه، والشاشة بتستخدم AcadPlan. مقفول بفيتشر kuStudyPlanReport لأنه بيرجّع صفر صفوف على داتابيز Innovation (اتجرّب على 8 طلبة). مش KU-only بالتصميم — أي تركيب داتاه متوافقة يفتحه ويشتغل. ولو فتحته لازم تبعت المدى كامل: edStudId لوحده بيخلّي مدى السنين فاضي والرد بيرجع فاضي مهما كان |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| تقرير الخطة نسخة KU | جاهز · مستني بيانات | students/GetSTudentPaln بديل قديم لنفس الشاشة، متقفل بفيتشر kuStudyPlanReport. بيرجّع صفر صفوف على Innovation، فبدل ما يرد «نجاح فاضي» — وده شكله زي إندبوينت باظ — بقى بيقول صراحةً إنه مقفول على التركيب ده. |
تركيب داتاه متوافقة يفتح الفيتشر ويشتغل |
| حزم الخطة الدراسية | متعمل | 5 حزم راجعة بالمقررات والدرجات. | — |
| الساعات المنجزة والمتبقية | متعمل | 101 من 200 ساعة = 51%. | — |
| المقررات المتبقية لكل حزمة | متعمل | المقرر اللي مالوش درجة = لسه. | — |
| الدرجة / مسجل / ----- | متعمل | جديد من الميتنج: DISPLAY_GRADE_AR جاهز للعرض. اتجرّب على طالب شايل مقررات متعادة (ahmed.ghanem.25060211): اللي راسب في الربيع ومسجّله في الصيفي بيظهر «مسجل». |
— |
| الأفضل ولا الأخير عند الإعادة | متعمل | جديد بيتقرأ من لائحة الطالب نفسها في الـ SIS (نفس منطق تقرير الخطة القديم) — مش قرار في الكود. GRADE_RULE بيقول اتطبّق إيه. |
— |
| التخرج المتوقع | ناقص | كان مكتوب «يونيو 2028» ثابت — اتحذف. | حساب من الساعات المتبقية ÷ متوسط الفصل — قرار سياسة |
| إنذارات أكاديمية | متعمل | ⭐ بقى بيتعرض كبانر فوق نتيجة الفصل. | — |
دليل الأساتذة
Faculty Directory
دليل دكاترة الطالب: المرشد الأكاديمي + دكاترة المقررات المسجلة، مع أزرار تواصل.
بيشتغل إزاي؟
نفس مصدر شاشة المحادثات — getInstructorsAndAdvisorForAsk. يعني الدليل
مخصّص للطالب (دكاترته هو)، مش دليل الكلية كلها.
جديد كل دكتور بقى جاي معاه officeHours[] — والمرشد كمان
(courses.AcademicAdvisior.officeHours). كل ميعاد: DayAr · FromTime
· ToTime (HH:mm) · Notes. يعني الشاشة مش محتاجة نداء تاني لكل دكتور.
المواعيد بتاعة ترم الطالب الحالي؛ دكتور مادخلش مواعيد ← officeHours: [] ← اكتب «لا توجد ساعات مكتبية».
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/getInstructorsAndAdvisorForAsk | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ 12 دكتور + المرشد — جديد كل واحد معاه officeHours[] |
| POST | students/GetOfficeHours | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
نفس المواعيد بشكل كروت (دكتور ← مقرراته ← مواعيده). جديد FromTime/ToTime بـ HH:mm، ومبقاش بيرجّع «الأيام المفضّلة للتدريس» على إنها ساعات مكتبية · جديد ٢ والحجز من students/GetOfficeHourOpenings / students/BookOfficeHour |
| POST | students/GetOfficeHourOpenings | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ٢ المواعيد المتاحة للحجز (Openings[]) + MyBookings[] + CancelledByLecturer[] — التفاصيل |
| POST | students/BookOfficeHour | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ٢ حجز ميعاد؛ الإلغاء بـ {Cancel: true, BookingId} |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| دكاترة الطالب | متعمل | بأسماء المقررات اللي بيدرّسوها له. | — |
| المرشد الأكاديمي | متعمل | راجع من نفس الإندبوينت + كارت الطالب. | — |
| الإيميل والتليفون والمكتب | ناقص | الإندبوينت بيرجع الاسم والـ ID بس. | إضافة أعمدة التواصل للـ SQL من SA_STF_MEMBER |
| الساعات المكتبية | متعمل | ⭐ اتصلّحت كانت فاضية لسببين: مفيش مواعيد متسجّلة للربيع (اتحطّت بيانات تجريبية لـ 9 دكاترة)، والدكتور كان بيدخل على ترم الصيفي فأي ميعاد يسجّله من الموبايل كان بيروح للصيفي والطالب مش شايفه. ودلوقتي جوّه الدليل نفسه. | الدكاترة يدخلوا مواعيدهم الحقيقية |
| دليل الكلية كاملة | ناقص | دلوقتي دكاترة الطالب بس. | إندبوينت بحث في كل هيئة التدريس |
تسجيل المقررات
Course Registration
إضافة وإسقاط المقررات في فترة التسجيل: المقررات المتاحة، السلة، حدود الساعات، وموافقة المرشد.
بيشتغل إزاي؟
مجموعة CourseReg/* اتعملت أصلاً لـ KU. الإندبوينتات كلها موجودة والـ feature
courseRegistration مفعّل والجداول المطلوبة كلها موجودة — بس الـ SQL بتاع
الكتابة (تسجيل / حذف / تراجع) كلها شغالة ومتحقّقة — بترجّع نتيجة العملية وسببها لما ترفض.
v2/MyCourses وGetNewCourses بيردّوا 200 بقايمة فاضية لأن باب التسجيل
مقفول دلوقتي (مش لأنهم بايظين).
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | CourseReg/GetAllowedActions | ● شغال | 🎓 طالب (تسجيل) menna.elsayed.25010015 |
جديد ⭐ ابدأ بيه — بيقولك الأزرار المسموحة دلوقتي: نوافذ الأجندة الخمسة، وكل واحدة بتسمح بإيه، وسقف الساعات والمحمّل منه. الموبايل مالوش داعي يعرف قواعد الـ SIS، بس يقرا الفلاجز |
| POST | CourseReg/v2/MyCourses | ● شغال | 🎓 طالب (تسجيل) menna.elsayed.25010015 |
جديد ⭐ تاب «مقرراتي» — كل تسجيلات الفصل بكل الحالات (مسجّل · محذوف · منسحب · انتظار). كل مقرر معاه State ككلمة مش رقم، وTeachingMethods = كل طرق تدريسه وحالة الطالب في كل واحدة (REGISTERED · NOT_REGISTERED · NO_SECTIONS_OFFERED) — حتى للمقرر المحذوف. وSections فضلت مسطّحة وكل سكشن شايل طريقة تدريسه، فالربط شغلة التطبيق |
| POST | CourseReg/v2/AvailableCourses | ● شغال | 🎓 طالب (تسجيل) menna.elsayed.25010015 |
جديد ⭐ تاب «المتاح» — مش «المقررات اللي تقدر تسجّلها» بل المقرر × طريقة التدريس اللي لسه ينفع تتضاف. المقرر اللي الطالب ماسكه بيظهر هنا كمان بطرق التدريس الناقصة بس (Mode: ADD_METHOD)، والمحذوف مش بيظهر فيها خالص — التراجع عن الإسقاط من تاب «مقرراتي»، لأنه عملية على تسجيل قايم مش إضافة. وأول ما آخر فراغ يتملي المقرر بيختفي من التاب — عشان كده التابين بيكمّلوا بعض ومابيتقاطعوش |
| POST | CourseReg/RegisterNewCourse | ● شغال | 🎓 طالب (تسجيل) menna.elsayed.25010015 |
⭐ ✍️ تسجيل شغّال ومتجرَّب — ولو مقاعد السكشن خلصت والطابور فيه مكان بيسجّل في الطابور تلقائياً (حالة 7 + WAIT_NO) زي البورتال بالظبط. — بيرجّع Status: true والمقرر بيظهر في القائمة بحالة 1. ScScheduleDtlId هي السكشن اللي الطالب هيتحط فيها لما المقرر مش متجمّع في مجموعة سكاشن |
| POST | CourseReg/DropCourse | ● شغال | 🎓 طالب (تسجيل) menna.elsayed.25010015 |
⭐ ✍️ حذف شغّال ومتجرَّب — الحالة بتبقى 6 والصف مابيتمسحش. edStudCourseRegId اختياري — لو بعتّ EdCourseId لوحده الخدمة بتلاقي التسجيل من فصل الطالب نفسه. ومربوط بنافذة الإسقاط (6) في أجندة الفصل |
| POST | CourseReg/UnDropCourse | ● شغال | 🎓 طالب (تسجيل) menna.elsayed.25010015 |
⭐ ✍️ تراجع شغّال ومتجرَّب — الحالة بترجع 1. ده الطريق الوحيد لإرجاع مقرر مسقَط، مش تسجيل جديد. اتغيّر مابقاش يختار سكشن لوحده: الحذف بيمسح صفوف ED_STUD_GROUP فيزيكال ومفيش جدول بيفتكرها، فأي اختيار تلقائي تخمين — والقديم كان بيفلتر على IS_CLOSED بس، من غير فحص مقاعد ولا تعارض. بيرجّع دلوقتي TeachingMethods وNeedsSection وNextAction على البيكر. عايز القديم؟ AssignSection: true — وبقى آمن: واحد لكل طريقة تدريس، وبس اللي فيه مقعد ومافيهوش تعارض |
| POST | CourseReg/GetSectionsToReplace | ● شغال | 🎓 طالب (تسجيل) menna.elsayed.25010015 |
جديد ⭐ بيكر السكاشن — بيجاوب على الحالتين: «أنقل لفين؟» و«أختار إيه؟». الرد مقسّم أربع قوايم + Summary، وكل صف بيقول Mode: REPLACE (عنده سكشن من النوع ده) ولا PICK (مالوش — بعد حذف مثلاً) وجنبه الـ actions بالإندبوينت الصح. وفوق: NeedsSection وMissingTeachingMethods = النوع الناقص بالاسم.جديد ابعت EdCodeCourseTeachingId عشان تفتح طريقة تدريس بعينها — ده السؤال الوحيد اللي ماكانش ينفع يتسأل، لأن طريقة التدريس اللي الطالب مالوش فيها سكشن مفيهاش ED_STUD_GROUP نستنتج منه. وبترجّع كمان TeachingMethods وRequiresUnDrop+NextAction للمقرر المحذوف.اتغيّر بترجّع كل سكاشن الطريقة — اللي مايتسجلش بيرجع في BlockedSections ومعاه BlockedReason بمصطلحات البورتال (NOT_ALLOW_ONLINE · INTERNAL · IS_CLOSED · EXAM_CONFLICT · SCHEDULE_CONFLICT · FULL) بدل ما تختفي. ودي اللي كانت بتخفي على الطالب سكشنه هو لما شؤون التسجيل بتقفل التسجيل الإلكتروني عليه |
| POST | CourseReg/DeleteSection | ● شغال | 🎓 طالب (تسجيل) menna.elsayed.25010015 |
جديد ✍️ حذف سكشن واحد من مقرر بيتدرّس على أكتر من سكشن (محاضرة/عملي/إكلينيكي) — التسجيل نفسه بيفضل قايم. مفتوح بنافذة تسجيل السكاشن (70). والرد بيقولك الفراغ اللي عمله: NeedsSection وMissingTeachingMethod (النوع الناقص وكام مرشّح ليه) وNextAction فيها نداء البيكر جاهز |
| POST | CourseReg/SetSection | ● شغال | 🎓 طالب (تسجيل) menna.elsayed.25010015 |
⭐ ✍️ «حطّني في السكشن دي» — النداء الوحيد للسكاشن. AddSection وReplaceSection اتشالوا: كانوا اسمين للنداء ده نفسه. الخدمة بتشوف إن الطالب عنده سكشن من نوع التدريس ده ولا لأ، وتقرّر نقل ولا إضافة، وترجّع Action: REPLACED · ADDED · UNCHANGED (هو فيها أصلاً). الفرق ده بيعتمد على حال الداتابيز لحظة الدوسة مش على الشاشة، عشان كده الخدمة هي اللي بتقرّره. EdStudGroupId اختياري — وماينفعش إلا في مقرر فيه أكتر من سكشن من نفس النوع.جديد لو المقعد راح وانت بتختار، الرفض بيرجّع Reason: SEAT_TAKEN ومعاه Alternatives = بدايل نفس طريقة التدريس، حيّة، بأزرارها — من غير نداء تاني |
| POST | CourseReg/CancelWaitList | ● شغال | 🎓 طالب (تسجيل) menna.elsayed.25010015 |
✍️ الخروج من قائمة الانتظار — AddToWaitList اتشال: الدخول للطابور بقى جوّه SetSection وRegisterNewCourse زي البورتال، فمافيش زرار تاني. — الصف بيتمسح خالص مش بيتعلّم كمسقَط، لأنه أصلاً ماكانش تسجيل |
| POST | Faculties/CoursesCatalogNew | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ 85 مقرر بالمصروفات |
| POST | EdSemesterAgenda/GetAllByEdSemesterOpen | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
مواعيد فتح وقفل التسجيل |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| كتالوج المقررات | متعمل | 85 مقرر بالوصف والساعات والمصروفات. | — |
| مواعيد فتح التسجيل | متعمل | EdSemesterAgenda بيرجع 6 أنشطة بتواريخها. |
— |
| عرض المسجَّل حاليًا | متعمل | ⭐ 8 مقررات. كان فاضي لسببين مع بعض: فترة التسجيل كانت قافلة، والهاندلر كان بيبعت 0 مكان NULL لفلتر الحالة. |
— |
| تسجيل مقرر | متعمل | CourseReg/RegisterNewCourse شغال ومتحقق — بيرجّع نتيجة العملية وسببها لما ترفض. |
— |
| إسقاط مقرر | متعمل | CourseReg/DropCourse شغال ومتحقق — بيرجّع سبب الرفض لما العملية مترفض. |
— |
| التراجع عن الإسقاط | متعمل | CourseReg/UnDropCourse شغال ومتحقق — بيرجّع المقرر من غير ما يختار سكشن، ومعاه طرق التدريس والخطوة اللي بعدها. |
— |
| حدود الساعات والمتطلبات السابقة | متعمل | اتعمل بمحرّك الـ SIS نفسه. المتطلب السابق: CHK_STUD_CRS_PREREQ بيتنده مرة لكل مقرر، والنتيجة بتقفل كل سكاشنه: CanRegister=false وBlockedReason=PREREQ_NOT_MET وPrereqProblem فيه مفتاح الرسالة بتاع الـ SIS. والتسجيل بيترفض قبل ما يكتب. سقف الساعات: GetAcadLoadMinMax — التسجيل والتراجع وحجز المقعد كلهم بيشيكوا عليه، وMinCreditHours/MaxCreditHours/CurrentCreditHours راجعين في GetAllowedActions عشان تحذّر قبل الرفض. |
— |
| موافقة المرشد | ناقص | 🚫 في الموبايل بس. مفيش دورة موافقة مرشد على التسجيل في الـ SIS — الموافقة اللي موجودة هي على الانسحاب (WithdrawCoursesApprv). |
قرار: هل الجامعة عايزة دورة موافقة على التسجيل أصلاً؟ لو أيوه لازم تتعمل في البوابة الأول |
الإرشاد الأكاديمي
Advising
بيانات المرشد الأكاديمي، حجز موعد (حضوري أو عبر Teams)، ومتابعة المواعيد السابقة.
بيشتغل إزاي؟
اسم المرشد بييجي حقيقي من كارت الطالب وgetInstructorsAndAdvisorForAsk.
لكن المواعيد نفسها كلها في الموبايل — مفيش جدول ولا إندبوينت.
الجديد: meetings/Create بيعمل لينك Teams حقيقي لما الإعدادات تكون موجودة.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/getInstructorsAndAdvisorForAsk | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
المرشد |
| POST | students/get | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
ACAD_ADV_AR |
| POST | meetings/Create | 🧪 شغال بالـ Sandbox | 🎓 طالب mahmoued.eprahim.23010062 |
جديد لينك Teams — بيرجّع joinWebUrl |
| POST | academicstaff/GetStudentUnderSuperVision | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ 25 طالب تحت إشراف الدكتور |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| بيانات المرشد | متعمل | الاسم حقيقي من الداتابيز. | — |
| الطلاب تحت الإشراف (شاشة الدكتور) | متعمل | 50 طالب راجعين فعليًا. | — |
| حجز موعد | متعمل | ⭐ اتعمل — GetAppointmentSlots + BookAppointment. المتاح جاي من البروسيجر ED_STUD_SEM_TIME_AVAILABLE (أهلية + سعة)، وقاعدة «حجز واحد لكل نشاط» متطبّقة. الأجندة نفسها الإدارة بتعرّفها. |
— |
| لينك Teams للموعد | متعمل | جديد TeamsMeetingProvider متكتب بالكامل بـ client credentials، وبيرجّع joinWebUrl فعليًا دلوقتي على Graph المزيّف بتاع الـ Sandbox — فشاشة الإرشاد تتبني النهاردة. |
tenantId/clientId/clientSecret/organizer + صلاحية OnlineMeetings.ReadWrite.All + application access policy — الكود نفسه مش هيتغيّر |
| ملاحظات وتوصيات المرشد | ناقص | مفيش. | ممكن تستخدم الشات الموجود بدل جدول جديد |
الطلبات والوثائق
Requests & Documents
طلب وثائق رسمية: بيان درجات، إفادة قيد، خطاب تجنيد… مع متابعة حالة الطلب.
بيشتغل إزاي؟
الشاشة دي كلها بروتوتايب. مفيش أي إندبوينت. الكاتالوج والحالات والمسار الزمني
كله ثابت في الموبايل. الـ feature serviceRequests معرّف في الكتالوج ومتطلباته
(GS_ATTCHD_DOC, GS_CODE_DOC_TYPE) متحققة في الداتابيز — بس مفيش handlers.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/get | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
بيانات الطالب في الطلب |
| POST | students/GetClearanceRequests | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ إخلاء الطرف بالتوقيعات الناقصة — ده طلب الـ SIS الحقيقي |
| POST | students/GetCampusRequests | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ الخزانة وملصق العربية وطلبات الخصم |
| POST | students/AddCampusRequest | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
✍️ تقديم طلب خزانة / ملصق |
| POST | students/ServiceRequestTypes | ✕ مش موجود | 🎓 طالب mahmoued.eprahim.23010062 |
🚫 مش موجود في الـ SIS. كتالوج الوثائق (بيان درجات، إفادة قيد…) مالوش فورم في البوابة — شوف تحليل الفجوة |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| كتالوج الوثائق | ناقص | ثابت في الموبايل. | جدول أنواع الطلبات + رسومها + إندبوينت |
| تقديم طلب | ناقص | الفورم شغال في الموبايل بس مش بيبعت. | إندبوينت إنشاء + جدول طلبات + رقم طلب |
| متابعة الحالة | متعمل | ⭐ بقى حقيقي — المسار الزمني بيتبني من حالة الـ SIS نفسها (توقيعات إخلاء الطرف، تسليم مفتاح الخزانة، طباعة الملصق، اعتماد الخصم). | — |
| الدفع مقابل الوثيقة | ناقص | مربوط بالمدفوعات. | ربط الطلب بسند سداد |
| استلام الوثيقة PDF | ناقص | مفيش. | توليد/رفع الوثيقة + تحميل |
الانسحاب والاعتذار
Withdrawals
الاعتذار عن مقرر، أو الانسحاب من الجامعة كلها (بتاريخ ومرفقات).
بيشتغل إزاي؟
بروتوتايب بالكامل. الـ feature withdrawalRequests معرّف ومتطلباته
(ED_STUD_COURSE_REG, ED_STUD_SEMESTER) موجودة، بس مفيش handlers.
المقررات اللي بتظهر للاعتذار بتيجي من students/schedule الحقيقي.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/schedule | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
المقررات المتاحة للاعتذار |
| POST | students/GetCourseWithdrawals | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ طلبات الانسحاب + المقررات المؤهلة + الأسباب |
| POST | students/RequestCourseWithdrawal | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
✍️ انسحاب من مقرر — طلب بس؛ حالة التسجيل مبتتغيّرش غير باعتماد العميد |
| POST | students/GetEnrollmentChanges | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ الانسحاب من الجامعة وتغيير القيد + الحالات المتاحة والأسباب وحد التأجيل |
| POST | students/RequestEnrollmentChange | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ✍️ تقديم انسحاب من الجامعة / تأجيل / إعادة قيد — الحالة القديمة بتتقرا من قيد الطالب مش من الطلب |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| اختيار المقرر | متعمل | المقررات حقيقية من الجدول. | — |
| تقديم اعتذار عن مقرر | متعمل | ⭐ students/RequestCourseWithdrawal — بيسجّل طلب في ED_STUD_COURSE_CHNG. وED_STUD_COURSE_REG مبتتلمسش: العميد هو اللي بيعتمد وبيغيّر الحالة. |
— |
| انسحاب من الجامعة | متعمل | ⭐ اتعمل — students/RequestEnrollmentChange (انسحاب رسمي / نهائي / تأجيل / إعادة قيد). الحالة القديمة بتتقرا من قيد الطالب مش من الطلب، وAPPROVE_FLG=0 — قيد الطالب مبيتغيّرش غير بقرار شؤون التسجيل. قاعدة «مفيش طلبين معلّقين» وحد التأجيل من ENT_POLICY_EXCUSE متطبّقين. |
— |
| رفع مستندات | ناقص | الزرار ديكور — رفع الملفات نفسه مش متعمل في السيرفس. | رفع ملفات + GS_ATTCHD_DOC (الجدول موجود) |
| حساب المسترد ماليًا | ناقص | مفيش. | قواعد الاسترداد حسب تاريخ الانسحاب |
استطلاع الرأي
Survey
تقييم المقررات والدكاترة: أسئلة تقييم بنجوم وأسئلة نصية.
بيشتغل إزاي؟
مجموعة Survey/* كاملة ومتكتبة — قايمة المقررات، الاستبيانات، الأسئلة،
وحفظ الإجابات (تقييم ونص). كلها بترجع 200 بقوايم فاضية لأن مفيش استبيان منشور
للفصل ده — مش لأنها بايظة.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | Survey/GetCoursesUnderSurvey | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ المقررات المفتوح عليها تقييم (7) |
| POST | Survey/GetMadatorySurvy | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
التقييم الإجباري (REG_FLG) |
| POST | Survey/GetSurveyByCourse | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⚠️ الباراميتر اسمه EdCourseId مش ED_COURSE_ID |
| POST | Survey/GetSurvyQuestions | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ 40 سؤال |
| POST | Survey/InsertItemAnswer | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
✍️ إجابة سؤال تقييم — SV_COURSE_EVAL_ITEM_ID لازم يكون سؤال حقيقي من GetSurvyQuestions، وإلا الـ FK بيرفض |
| POST | Survey/InsertTextAnswer | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
✍️ إجابة نصية — SV_COURSE_EVAL_EXT_ID من نفس الاستبيان |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| قايمة الاستبيانات | متعمل | الكود كامل — بس مفيش استبيان منشور. | نشر استبيان من الباك أوفيس — مش شغل برمجة |
| الأسئلة ومقاييس التقييم | متعمل | بيرجع EvalItems وEvalTEXT. |
نفس الكلام — بيانات |
| حفظ الإجابات | متعمل | بيكتب في SV_STUD_COURSE_EVAL. |
— |
| الاستبيان الإجباري قبل النتيجة | متعمل | GetMadatorySurvy موجود. |
ربطه في الموبايل: منع دخول النتيجة قبل التقييم |
التقويم الأكاديمي
Academic Calendar
مواعيد الفصل الرسمية: بداية ونهاية التسجيل، الامتحانات، الإجازات.
بيشتغل إزاي؟
الريكوست المطلوب: POST semester/semsterCalnd بـ
{ "EdAcadYearId": 16, "EdCodeSemesterId": 2 } (السنة والفصل من UserMainData
بتاع اللوجين). ابعت AsFacultyInfoId لو عايز كلية الطالب بس — 0 أو من غيره = كل الكليات.
الرد items[]: ACTV_AR (اسم النشاط) · FROM_DATE · TO_DATE ·
ENT_DESCR_AR (الكلية) · SEM_AR.
اتصلّح كان بيرد «data not found» لأن القاعدة القديمة بتعرض بس الأنشطة اللي مسجّل الـ
«للطلاب» بتاعها — والمسجّل هنا بيعلّم «يظهر» بس. بقت إعداد في الأدمن (Academic rules ← «Academic calendar shows»)،
وInnovation عليه «Shown» ← 48 بند.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | semester/semsterCalnd | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ اتصلّح التقويم الأكاديمي — 48 بند للربيع |
| POST | EdSemesterAgenda/GetAllByEdSemesterOpen | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ 6 أنشطة بتواريخها |
| GET | EdSemesterOpen/GetAll | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
30 فصل بتواريخ البداية والنهاية |
| GET | EdAcademicYear/GetAll | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
7 سنين دراسية |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| أنشطة الفصل | متعمل | EdSemesterAgenda بيرجع داتا حقيقية. |
ربطه في الموبايل بدل الداتا الثابتة |
| تواريخ الفصول | متعمل | 30 فصل بـ FROM_DATE / TO_DATE. | — |
| تقويم الكلية | متعمل | اتصلّح 48 بند للربيع. أي جامعة تانية تختار من الأدمن: «للطلاب» بس (القديم) أو «الظاهر» أو «الكل». | — |
| إضافة للتقويم الشخصي | ناقص | مفيش. | توليد ملف ICS — شغل موبايل |
حجز القاعات
Room Booking
حجز قاعات مذاكرة أو مشاريع بالتاريخ والوقت وعدد الأفراد.
بيشتغل إزاي؟
بروتوتايب بالكامل. بس فيه اكتشاف حلو: الداتابيز فيها موديول سكن كامل
(ACCOM_* — 28 جدول) فيه قاعات وحجوزات ودورة موافقات جاهزة.
الـ feature roomBooking معرّف على الجداول دي ومتطلباته متحققة.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | campus/Rooms | ✕ مش موجود | 🎓 طالب mahmoued.eprahim.23010062 |
⚠️ لسه — القاعات المتاحة |
| POST | campus/BookRoom | ✕ مش موجود | 🎓 طالب mahmoued.eprahim.23010062 |
⚠️ لسه — حجز |
| POST | campus/MyBookings | ✕ مش موجود | 🎓 طالب mahmoued.eprahim.23010062 |
⚠️ لسه — حجوزاتي |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| قايمة القاعات | ناقص | ثابتة في الموبايل. | استعلام على ACCOM_ROOM + ACCOM_CDE_ROOM_TYPE |
| المتاح في وقت معين | ناقص | مفيش. | استعلام تعارض مع ACCOM_STUD_BOOK |
| الحجز | ناقص | مفيش. | insert في ACCOM_STUD_BOOK + ACCOM_CDE_BOOK_STATUS |
| الموافقة على الحجز | ناقص | مفيش. | ACCOM_WF_REQUEST_APPROVE موجود وجاهز للاستخدام |
الأنشطة والرحلات
Trips & Events
الرحلات والفعاليات الطلابية، والتسجيل فيها بعدد المشاركين.
بيشتغل إزاي؟
بروتوتايب بالكامل. الداتابيز فيها ED_STUD_ACTIVITY، والـ feature
studentActivities معرّف عليه ومتطلباته متحققة — بس مفيش handlers.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | campus/Activities | ✕ مش موجود | 🎓 طالب mahmoued.eprahim.23010062 |
⚠️ لسه — الفعاليات |
| POST | campus/JoinActivity | ✕ مش موجود | 🎓 طالب mahmoued.eprahim.23010062 |
⚠️ لسه — التسجيل |
| POST | campus/MyActivities | ✕ مش موجود | 🎓 طالب mahmoued.eprahim.23010062 |
⚠️ لسه — اشتراكاتي |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| كتالوج الفعاليات | ناقص | ثابت في الموبايل. | استعلام على ED_STUD_ACTIVITY + جدول تعريف الفعاليات |
| طلب مشاركة | ناقص | مش بيتحفظ. | insert + حالة + منع التكرار |
| تعديل/إلغاء الطلب | ناقص | في الموبايل بس. | update/delete مع شرط إن الطلب لسه معلّق |
| الدفع للرحلة | ناقص | مفيش. | ربط بالمدفوعات |
خدمات الحرم الجامعي
Services Hub
صفحة تجميعية لكل الخدمات (14 خدمة) مقسّمة لمجموعات، مع بحث.
بيشتغل إزاي؟
مفيش إندبوينت — دي شاشة تنقّل بس. لكن المفروض تستخدم
Info/Capabilities عشان تخفي الخدمات اللي التركيب ده مش بيدعمها.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| GET | Info/Capabilities | ● شغال | 🌐 من غير توكن | ⭐ لإخفاء الخدمات غير المتاحة |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| قايمة الخدمات | متعمل | شاشة تنقّل — مش محتاجة باك إند. | — |
| إخفاء الخدمات غير المفعّلة | متعمل | ⭐ كروت الخدمات بقت بتتفلتر بـ Info/Capabilities — الخدمة المقفولة مابتتعرضش أصلاً، بدل ما تتعرض وتفشل عند الضغط. |
— |
| شارة عدد (طلبات معلّقة مثلاً) | ناقص | الأرقام ثابتة. | إندبوينت عدّادات مجمّع |
الإعلانات
Announcements
إعلانات الكلية والإدارات، مقسّمة بالتصنيف مع تمييز العاجل.
بيشتغل إزاي؟
كل الإعلانات ثابتة في الموبايل. مفيش إندبوينت إعلانات في السيرفس.
أقرب حاجة موجودة هي جداول الرسايل SV_MESSAGE / SV_USER_MESSAGE
اللي بتستخدمها الإشعارات.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/GetMobileNotifications | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
أقرب بديل موجود |
| POST | students/Announcements | ✕ مش موجود | 🎓 طالب mahmoued.eprahim.23010062 |
⚠️ لسه |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| قايمة الإعلانات | ناقص | ثابتة في الكود. | إما إندبوينت إعلانات جديد، أو استخدام SV_MESSAGE بتصنيف |
| التصنيفات والعاجل | ناقص | ثابتة. | أعمدة تصنيف وأولوية |
| استهداف (كلية/مستوى) | ناقص | مفيش. | قواعد استهداف في الباك أوفيس |
المساعد الذكي
AI Assistant
مساعد بيرد على أسئلة الطالب الشائعة وبيوديه للشاشة المناسبة.
بيشتغل إزاي؟
دلوقتي مطابقة نوايا بسيطة في الموبايل (كلمات مفتاحية → رد جاهز + زرار تنقّل). مفيش أي ذكاء اصطناعي حقيقي ولا إندبوينت.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | assistant/Ask | ✕ مش موجود | 🎓 طالب mahmoued.eprahim.23010062 |
⚠️ لسه |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| الردود الجاهزة | متعمل | شغالة في الموبايل، والتحية بقت باسم الطالب الحقيقي. | — |
| التنقّل للشاشات | متعمل | شغال. | — |
| ذكاء اصطناعي حقيقي | ناقص | مفيش. | إندبوينت يوصّل لـ LLM + سياق الطالب (جدوله/درجاته) + قرار خصوصية مهم: إيه اللي يتبعت للموديل |
شاشات عضو هيئة التدريس
Staff Screens



التطبيق بيشتغل بدورين. لما تدخل بحساب دكتور، الشاشات بتتغير: مقرراته، طلابه، أخذ الحضور، والطلاب تحت إشرافه.
بيشتغل إزاي؟
الدور بيتحدد من IsStudent في رد اللوجين. الإندبوينتات بتاعة الموظفين
شغالة جزئيًا: GetStudentUnderSuperVision بيرجع 50 طالب،
وGetInstructorSectionSolts بيرجع حصص فعلية.
الحضور بالـ QR بقى كامل من الآخر للآخر — عرض الكود، المسح، وقفل المحاضرة اللي بيحوّل
«مامسحش» لغياب فعلي. التفاصيل في فصل الحضور.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | academicstaff/login | ● شغال | 🌐 من غير توكن | دخول الدكتور |
| POST | academicstaff/GetStudentUnderSuperVision | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ 25 طالب تحت إشراف الدكتور |
| POST | Staff/GetInstructorSectionSolts | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ حصص السكشن |
| POST | academicstaff/GetStaffCourse | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ 7 مقررات |
| POST | academicstaff/GetStaffSchedule | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ اتصلّح جدول الدكتور — كان «data not found» لأي دكتور سكاشنه مش في «مجموعة سكاشن». سطر لكل سكشن ومعاه SC_SCHEDULE_DTL_ID والأيام والمقر وmeetings[] · جديد ٢ + officeHourBookings[] — حجوزات الساعات المكتبية الجاية |
| POST | academicstaff/GetTeachingLoad | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ⭐ العبء التدريسي — كل مقرر بيدرّسه وكام سكشن وكام طالب، والإجماليات (٧ مقررات · ١٢ سكشن · ٤٨٥ طالب). دي Faculty Academic Load في منيو عضو هيئة التدريس. رقم عضو هيئة التدريس بيتاخد من التوكن مش من الـ body، والساعات بتتحسب مرة لكل مقرر مش لكل سكشن |
| POST | academicstaff/GetMyOfficeHours | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ساعاتي المكتبية — الطالب كان يقدر يشوفها (students/GetOfficeHours) وصاحبها ماكانش يقدر يعدّلها من الموبايل · جديد ٢ كل ميعاد معاه Bookings[] وHasBookings — المحجوز مايتعدّلش ولا يتحذف |
| POST | academicstaff/CancelOfficeHourBooking | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ٢ الدكتور يلغي حجز بسبب — بيوصل للطالب في CancelledByLecturer |
| POST | academicstaff/SaveOfficeHour | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ✍️ إضافة/تعديل/حذف ميعاد مكتبي واحد. ابعت SaOfficeHourId عشان تعدّل، وDelete: true عشان تحذف. مربوط بصاحبه: رقم ميعاد بتاع دكتور تاني بيترفض بـ «مش بتاعك» |
| POST | Staff/GetInstructorCourseSections | ● شغال | 👨🏫 دكتور atef.dahesh |
سكاشن المقرر — بيرجّع SectionId مش SC_SCHEDULE_DTL_ID |
| POST | students/GetStudentsForCourse | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ 52 طالب — كشف السكشن، بيتنادى بحساب الدكتور رغم إن المسار بادئ بـ students/ |
| POST | Staff/GetAbsenceDetails | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ كشف الغياب — 26 طالب. لازم سكشن في الفصل المفتوح ويوم يوافق يوم المحاضرة، وإلا بيرجّع رسالة مش كشف. جديد كل طالب معاه Scanned وScannedAt (مسح كود المحاضرة؟ وإمتى)، والكشف معاه ScannedCount — قبل قفل المحاضرة الكل بيظهر «حاضر» لأن الغياب لسه ماتكتبش، فدي الطريقة الوحيدة تعرف مين مسح فعلًا · جديد ٢ لكل طالب AttendanceState (NotTaken افتراضي) وAttendanceSource وLateMinutes، وفوق العدّادات وApprovalRequired — التفاصيل |
| POST | Staff/SetAbsence | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ تسجيل غياب — بيرفض اليوم المستقبلى واليوم اللى مش يوم الحصة |
| POST | Staff/SaveAttendanceSheet | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ⭐ ✍️ الكشف كله في نداء واحد — 30 طالب = ريكوست واحد مش 30. STATE: present / absent / excused، و«حاضر» معناها إلغاء الغياب. الرد بيقول saved / unchanged / failed · جديد ٢ STATE بقى: present · late (+LATE_MINUTES) · absent · excused · clear. «حاضر» بقى بيكتب سطر حضور زي البورتال |
| POST | Staff/MarkAllPresent | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ٢ «حضور الكل» — للي لسه مالوش علامة بس. الرد {marked, alreadyMarked} |
| POST | Staff/ApproveAbsence | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ اعتماد الغياب — بيفرض اعتماد المحاضرة السابقة الأول |
| POST | Staff/GetGradeEntrySheet | ● شغال | 👨🏫 دكتور atef.dahesh |
🔒 المكوّنات المسموح للدكتور يرصدها + كشف الطلاب (26 طالب). الصلاحية من SE_USER_CRS_ASSESS بالـ SE_USER_ID بتاع الدكتور |
| POST | Staff/SaveGrade | ● شغال | 👨🏫 دكتور atef.dahesh |
🔒 ✍️ رصد درجة. المكوّن والتسجيل لازم يكونوا من كشف الدكتور نفسه — مكوّن مصرّح لدكتور تاني بيترفض. والدرجة المعتمدة مبتتغيّرش |
| POST | academicstaff/GetLectQRCode | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ⭐ الدكتور بيعرض كود المحاضرة — بيرفض لو مش بيدرّس السكشن، وبيكتب في QRCode_Log · جديد ٢ الكود بيتغيّر: refreshSeconds / nextRefreshAt + sessionCode وsessionOpen؛ OPEN: true يفتح جلسة مقفولة |
| POST | academicstaff/SetQrSession | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ٢ «اقفل الحضور» = إخفاء الكود ورفض أي مسح بعدها (مش بيكتب غياب)؛ OPEN: true يفتحه |
| POST | Staff/CloseLectureAttendance | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ⭐ ✍️ قفل المحاضرة — هنا بيتسجّل غياب اللي مامسحش. مابيشتغلش قبل ما ميعاد المحاضرة ينتهي — ودلوقتي بيقول كده: result: ERROR + «can be closed after HH:mm» بدل «اتقفلت» من غير ولا غياب. التجربة النهاردة: جرّب الـ QR · جديد ٢ اختياري — قفل الحضور نفسه بقى academicstaff/SetQrSession |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| دخول الدكتور | متعمل | شغال ونفس شكل رد الطالب. | — |
| ترم الدكتور | متعمل | جديد الدكتور بيدخل على الترم الحالي، ولو مالوش فيه ولا سكشن ← آخر ترم بيدرّس فيه (مش ترم جاي). قبل كده كان ممكن يدخل على ترم فاضي فالجدول فاضي والساعات المكتبية تتسجّل في ترم الطلبة مش فيه. ED_ACAD_YEAR_ID/ED_CODE_SEMESTER_ID في رد اللوجين هم اللي تبعتهم. |
— |
| الطلاب تحت الإشراف | متعمل | 50 طالب راجعين. | — |
| حصص السكشن | متعمل | راجعة بالأيام والفترات. | — |
| مقررات الدكتور | متعمل | ⭐ 7 مقررات لحساب atef.dahesh. الـ join كان سليم — الحساب اللي كان بيتجرّب (31) هو اللي مالوش تحميل تدريس. |
— |
| أخذ الحضور | متعمل | شغال على ED_STUD_ABSENCE — insert/update/delete مع تحقق اليوم. وغلطة الكود القديم (تبديل EdStudId و EdCourseId) اتصلّحت مش اتنقلت. |
— |
| اعتماد الغياب | متعمل | شغال وبيفرض اعتماد المحاضرة السابقة الأول — وده بقى إعداد في تبويب Academic بدل ما يكون فرق بين راوتين. | — |
| كشف الحضور اليدوي | متعمل | ⭐ جديد شاشة كاملة للدكتور: 3 قوايم + تاريخ، الكشف بأسامي الطلاب ونِسَب غيابهم، تعليم حاضر / بعذر / غائب، وحفظ بنداء واحد. الطريقة التالتة للحضور — مش محتاجة كود ولا GPS. التفاصيل في شاشة كشف الحضور اليدوي. | — |
| عرض كود الـ QR | متعمل | ⭐ جديد بيتحقق إن الدكتور فعلاً بيدرّس السكشن (SC_SCHEDULE_DTL_EXT_STF)، وبيرجّع الـ payload مش صورة — الرسم شغل الكلاينت. وبيكتب في QRCode_Log اللي التطبيق القديم عمره ما كتب فيه. |
— |
| قفل المحاضرة وتحويل الحضور لغياب | متعمل | ⭐ جديد ده كان الجزء الناقص خالص. بينادي Integ_QRCodeInsertStudentAbsence بتاع المنتج. اتجرّب: 27 مسجّل، واحد مسح، 26 اتسجّلوا غياب، واللي مسح مادخلش فيهم. شوف فصل الحضور. |
— |
| رصد الدرجات | متعمل | ⭐ اتعمل ومقفول افتراضيًا (staffGradeEntry). الصلاحية من SE_USER_CRS_ASSESS (مين يرصد إيه ولحد إمتى)، الدرجة المعتمدة بتترفض، وكل تعديل بينزل في الـ audit trail الموجود. |
قرار الجامعة تفتحه |
كشف الحضور اليدوي
Manual attendance





الطريقة التالتة للحضور، واللي مش محتاجة أي حاجة: الدكتور بيعلّم بنفسه. الكود محتاج شاشة تعرضه، والموقع محتاج حدود مرسومة وإشارة GPS — والاتنين ممكن ما يكونوش موجودين في معمل أو مستشفى أو قاعة تحت الأرض.
بيشتغل إزاي؟
دوسة واحدة. الشاشة بتفتح على سكاشن الدكتور من
academicstaff/GetMySections — نداء واحد بيرجّع كل سكشن ومعاه الـ IDs ومواعيده وعدد
طلابه. يدوس على سكشن ← الكشف يفتح على طول.
ليه GetMySections ومش GetStaffSchedule؟ الجدول كان تقرير من غير IDs؛
دلوقتي بيرجّع SC_SCHEDULE_DTL_ID وmeetings[].ScScheduleDtlDayId، بس
GetMySections لسه الأنسب للكشف لأنه بيرجّع Slots بالترتيب اللي الكشف محتاجه.
الموعد مش السكشن: Slots هي مواعيد السكشن في الأسبوع، والحضور بيتسجّل على
الموعد. فلما يدوس، اختار الموعد اللي DayEn بتاعه يساوي يوم التاريخ المختار،
ولو مفيش رجّع التاريخ لآخر مرة الموعد حصل فيها. السكشن اللي ليه أكتر من موعد بيبان بأزرار يوم.
الكشف (Staff/GetAbsenceDetails) بيرجّع data = قايمة الطلاب. من كل
سطر: EdStudId (هتبعته تاني وقت الحفظ)، الاسم والرقم، StudAbsPrcnt
وAbsWarnStatusId (تحذير لما يعدّي الحد)، وEdStudAbsenceId — لو مش فاضي
يبقى الطالب متعلّم عليه غياب قبل كده.
الحالة الابتدائية: مافيش EdStudAbsenceId ← حاضر · فيه وExcuseFlag=1
← بعذر · فيه من غير عذر ← غائب.
تلات حالات وبس: present / absent / excused.
مفيش «متأخر» — النظام مايعرفهاش. و«حاضر» معناها إلغاء الغياب مش حالة بتتخزن.
الحفظ (Staff/SaveAttendanceSheet): ابعت كل الطلاب ومعاهم
ED_STUD_ABSENCE_ID اللي جه من الكشف (أو 0). الرد فيه
saved / unchanged / failed وerrors. وبعد الحفظ اقرا الكشف تاني،
لأن السطور الجديدة بقى ليها أرقام والنِسَب اتغيّرت.
وسلسلة «اعتمد اللي قبلها» بقت بتتحل لوحدها: الكشف بيفتح، والخدمة بتعتمد المحاضرات
المستنية بالترتيب من الأقدم وبترجّعهم في AutoApprovedDates — اعرضهم للدكتور.
ولو الجامعة قافلة الإعداد ده، بيرجع BlockedReason (كود ثابت) ومعاه
PendingApprovals = السلسلة كلها بتواريخها وسلوتاتها، بدل ما تكتشفها رفض ورا رفض.
والاعتماد غير الحفظ: Staff/ApproveAbsence زرار منفصل، وماتعرضهوش غير لما
الرد يقول AllowApprove: true — لأنه بيقفل اليوم.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | academicstaff/GetMySections | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ جديد نداء واحد بيبني الشاشة كلها — 12 سكشن للدكتور التجريبي، كل واحد بالـ IDs وعدد الطلاب وSlots (اليوم والوقت والقاعة وآخر تاريخ اتعمد). رقم الدكتور من التوكن. ابعت EdCourseId لو عايز مقرر واحد بس |
| POST | academicstaff/GetStaffSchedule | ● شغال | 👨🏫 دكتور atef.dahesh |
جدول الدكتور للعرض — بقى فيه SC_SCHEDULE_DTL_ID وmeetings[]، بس للكشف استخدم GetMySections · جديد ٢ + officeHourBookings[] — حجوزات الساعات المكتبية الجاية |
| POST | Staff/GetAbsenceDetails | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ الكشف — 26 طالب بأسامي وأكواد ونِسَب غياب. لو رجع فاضي اقرا MessageAr · جديد ٢ لكل طالب AttendanceState (NotTaken افتراضي) وAttendanceSource وLateMinutes، وفوق العدّادات وApprovalRequired — التفاصيل |
| POST | Staff/SaveAttendanceSheet | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ⭐ ✍️ الكشف كله في نداء واحد. بيرجّع saved / unchanged / failed وقايمة بالطلاب اللي مانفعوش — الحفظ الجزئي بيتقال مش بيتخبّى · جديد ٢ STATE بقى: present · late (+LATE_MINUTES) · absent · excused · clear. «حاضر» بقى بيكتب سطر حضور زي البورتال |
| POST | Staff/MarkAllPresent | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ٢ «حضور الكل» — للي لسه مالوش علامة بس. الرد {marked, alreadyMarked} |
| POST | Staff/ApproveAbsence | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ ✍️ اعتماد المحاضرة — بيقفل اليوم. والمحاضرات المستنية قبلها بتتعتمد معاها بالترتيب من الأقدم (إعداد Approve the backlog automatically، مفتوح افتراضيًا) وApprovedDates بتقول اللي اتعمد. ابعت ApprovePrevious: false لو عايز تعرض السلسلة للدكتور وتاخد موافقته الأول |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| قايمة السكاشن | متعمل | ⭐ جديد academicstaff/GetMySections — نداء واحد بدل 3 قوايم و3 نداءات. كل سكشن بمواعيده وعدد طلابه، ودوسة واحدة بتفتح الكشف. |
— |
| اختيار الموعد تلقائي | متعمل | الحضور بيتسجّل على الموعد مش السكشن. الشاشة بتختار الموعد اللي يومه يساوي يوم التاريخ، والسكشن اللي ليه أكتر من موعد بيبان بأزرار يوم. | — |
| فتح الكشف | متعمل | ⭐ 26 طالب بأسامي وأكواد ونِسَب غياب، والتعليم المحفوظ بيتقري من EdStudAbsenceId وExcuseFlag. |
— |
| تلات حالات | متعمل | present / absent / excused. مفيش «متأخر» — كانت في البروتوتايب والنظام مايعرفهاش. |
— |
| التعليم محلي | متعمل | كل ضغطة بتغيّر الـ state في الشاشة بس — مفيش نداء لحد ما يدوس حفظ. العدّادات فوق بتتحسب عندك. | — |
| حفظ بنداء واحد | متعمل | ⭐ جديد SaveAttendanceSheet — 30 طالب = ريكوست واحد مش 30. اتجرّب: واحد غائب + واحد بعذر = saved 2 · unchanged 1 · failed 0. |
— |
| الحفظ الجزئي | متعمل | لو failed > 0، errors بتقولك مين بالظبط وليه — علّم السطور دي بدل ما تقول «تم الحفظ». |
— |
| الكشف الفاضي | متعمل | ⭐ BlockedReason كود ثابت (مش نص عربي تقارن عليه): محاضرة سابقة مش معتمدة / اليوم اتعمد / أجازة / التاريخ مش يوم المحاضرة. |
— |
| سلسلة الاعتماد بتتحل لوحدها | متعمل | ⭐ جديد فتح الكشف بيعتمد المحاضرات المستنية بالترتيب من الأقدم وبيرجّعهم في AutoApprovedDates — الترتيب لسه مفروض، بس مابقاش مشوار على الدكتور. ولو الجامعة قافلة الإعداد: PendingApprovals = السلسلة كلها (تاريخ + ScTchngSlotId بتاعها + عدد التعليمات عليها) عشان تعرضها وتاخد موافقة. |
— |
| الاعتماد | متعمل | زرار منفصل، وبيظهر بس لما AllowApprove: true. بيقفل اليوم فخليه فعل واضح مش جزء من الحفظ. |
— |
| الدخول من شاشة المحاضرة | متعمل | لمس محاضرة في الجدول بيفتح اختيار بين «اعرض كود المحاضرة» و«كشف الحضور اليدوي». | — |
الحضور بالـ QR
QR Attendance


شاشتين على طرفين الدورة: الدكتور بيختار المقرر والسكشن والمحاضرة ويعرض الكود، والطالب
بيمسحه. وبعد ما المحاضرة تخلص الدكتور بيقفلها — والقفل هو اللي بيحوّل «مامسحش» لغياب فعلي.
وفيه طريق تاني موازي: الطالب يسجّل حضوره بموقعه من غير كود أصلاً. الاتنين بيخلّصوا لنفس
السطر، فالدكتور اللي مابيعرضش كود لسه بيطلع بكشف حضور.
بيشتغل إزاي؟
الكود اللي في الصورة كود QR حقيقي مرسوم في الكلاينت من الـ payload اللي رجع من
academicstaff/GetLectQRCode — السيرفس بيرجّع بيانات مش صورة، عشان الرسم شغل
الكلاينت والصورة ماينفعش تتكاش ولا يتأكد منها في تست.
شاشة الطالب في الديمو بتلزق الـ payload بدل ما تفتح الكاميرا (مفيش كاميرا جوه الديمو)، لكن كل
حاجة بعد كده هي النداء الحقيقي بنفس القواعد — كل رفض في الشاشة جاي من السيرفس.
التفاصيل الكاملة في فصل الحضور.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | academicstaff/GetLectQRCode | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ الـ payload + وقت الصلاحية · جديد ٢ الكود بيتغيّر: refreshSeconds / nextRefreshAt + sessionCode وsessionOpen؛ OPEN: true يفتح جلسة مقفولة |
| POST | academicstaff/SetQrSession | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ٢ «اقفل الحضور» = إخفاء الكود ورفض أي مسح بعدها (مش بيكتب غياب)؛ OPEN: true يفتحه |
| POST | students/GetStudentAttend | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ ✍️ الطالب بيمسح كود المحاضرة. لازم يكون مسجّل في السكشن ده — والمثال هنا سكشن الطالب نفسه. بيرفض بسبب واضح لو الجلسة مش موجودة، أو مش يوم المحاضرة، أو برّه الوقت، أو مش مسجّل. ومسح مرتين = سطر واحد · جديد ٢ ابعت QR_TOKEN وQR_WINDOW من الـ payload؛ المسح بيسجّل «حاضر» في الكشف على طول |
| POST | students/AttendByCode | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ٢ للي مش عارف يمسح: الـ 6 أرقام اللي تحت الـ QR |
| POST | students/CheckInByLocation | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
⭐ ✍️ جديد الطريق التاني: الطالب يسجّل بموقعه بدل ما يمسح كود. بيوصل لنفس المكان بالظبط، فقفل المحاضرة بيتعامل معاه زي المسح — شوف شاشة تسجيل الحضور بالموقع |
| POST | Staff/CloseLectureAttendance | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ ✍️ القفل — بيسجّل غياب اللي مامسحش ولا سجّل بالموقع · جديد ٢ اختياري — قفل الحضور نفسه بقى academicstaff/SetQrSession |
| POST | academicstaff/GetStaffCourse | ● شغال | 👨🏫 دكتور atef.dahesh |
⭐ 7 مقررات |
| POST | Staff/GetInstructorCourseSections | ● شغال | 👨🏫 دكتور atef.dahesh |
سكاشن المقرر — بيرجّع SectionId مش SC_SCHEDULE_DTL_ID |
| POST | Staff/GetInstructorSectionSolts | ● شغال | 👨🏫 دكتور atef.dahesh |
المحاضرات — الرد أوبجكت فيه slots، مش قائمة |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| عرض كود المحاضرة | متعمل | بيتحقق إن الدكتور بيدرّس السكشن، وبيكتب في QRCode_Log. |
— |
| رسم الـ QR في الكلاينت | متعمل | الديمو بيرسمه SVG بمكتبة qrcode-generator — كود حقيقي بيتقري بالكاميرا. |
الموبايل يستخدم مكتبة QR بتاعته |
| مسح الطالب | متعمل | خمس حالات رفض مختلفة، والمسح مرتين بيسيب سطر واحد. | ربط الكاميرا في التطبيق الحقيقي |
| قفل المحاضرة | متعمل | ⭐ بينادي Integ_QRCodeInsertStudentAbsence. اتجرّب: 27 مسجّل، واحد مسح، 26 غياب. |
— |
| الحضور بالموقع (GPS) | متعمل | ⭐ جديد طريق تاني موازي للكود، بيكتب نفس السطر. الحدود بتترسم على خريطة في تبويب Campus map وبتتخزن في الـ Client Profile — صفر تعديل على داتابيز العميل. البصمة اتحذفت خالص: مفيش تسجيل أجهزة ولا بصمة في أي جدول، ودي كانت رسمة لتحقق مش موجود. | الأدمن يرسم حدود الحرم |
إضافة وإسقاط · سداد · اسأل المرشد
Add/Drop, Payment, Ask


تلات مسارات كتابة كانت لسه بروتوتايب: إضافة/إسقاط المقررات، طلب كود سداد eFinance، وأسئلة المرشد. دلوقتي التلاتة بينادوا الـ SIS فعلاً.
بيشتغل إزاي؟
الإضافة والإسقاط بيكتبوا في ED_STUD_COURSE_REG على طول، والباقي بيكمّل من البوابة.
خد بالك من تلات حاجات: CourseReg/v2/MyCourses وGetNewCourses
بياخدوا ED_STUD_ID كنص — الرقم بيتقري 0 في صمت؛ والتسجيل بيعدّي على قواعد
اللائحة جوّه الـ SIS فالرفض رد حقيقي مش عطل؛ والإسقاط مش بيرجّع المقرر لقائمة «المتاح للتسجيل»
لأن الـ SIS بيستنى «تراجع عن الإسقاط» مش تسجيل جديد. التفاصيل في
فصل لما الإندبوينت يرجع فاضي.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | CourseReg/DropCourse | ● شغال | 🎓 طالب (تسجيل) menna.elsayed.25010015 |
جديد ✍️ إسقاط مقرر |
| POST | CourseReg/UnDropCourse | ● شغال | 🎓 طالب (تسجيل) menna.elsayed.25010015 |
جديد ✍️ تراجع عن الإسقاط |
| POST | CourseReg/RegisterNewCourse | ● شغال | 🎓 طالب (تسجيل) menna.elsayed.25010015 |
جديد ✍️ تسجيل مقرر — الـ XML كان بيتبعت كنص فالتسجيل عمره ما اشتغل؛ اتصلّح |
| POST | students/EfinancePayList | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد أكواد السداد المفتوحة |
| POST | Questions/GetQuestions | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
أسئلة الطالب للمرشد — لازم تبعت AsFacultyInfoId، الاستعلام بيفلتر بيه وبدونه بيرجّع «data not found» |
| POST | Questions/GetAnswers | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
ردود سؤال — الـ id بييجي من GetQuestions |
| POST | Questions/AddQuestion | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
✍️ سؤال جديد. خد بالك: الرد بيرجّع result فيه جملة نجاح مش كلمة Ok — لو التطبيق بيتأكد من result === 'Ok' هيقراها غلط |
| POST | Questions/AddAnswer | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ✍️ رد على السؤال |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| عرض المقررات المسجّلة | متعمل | 8 مقررات بالساعات والحالة. | — |
| إسقاط مقرر | متعمل | ⭐ شغال — الصف بيتغيّر لحالة «مسقَط» على طول. | — |
| تراجع عن الإسقاط | متعمل | ⭐ شغال. ده الطريق الصح لإرجاع مقرر مسقَط — مش تسجيل جديد. | — |
| تسجيل مقرر جديد | متعمل | ⭐ الباج اتصلّح (الـ XML كان nvarchar). النداء بيوصل لقواعد اللائحة، واللي بيرفض هو المنتج نفسه. | — |
| سداد eFinance | جاهز · مستني بيانات | قائمة الأكواد شغالة. إصدار كود جديد محتاج بيانات بوابة الدفع. | بيانات eFinance في تبويب Integrations |
| اسأل المرشد | متعمل | ⭐ سؤال + رد، الاتنين بيكتبوا في SV_STUD_ASK_ADV. |
— |
شؤون الطلاب — المخالفات والطلبات
Student Affairs










الشاشات دي اتبنت من المنيو نفسه (SE_MODULE / SE_FORM) مش من البروتوتايب —
كل واحدة فيها مأخوذة من الويب فورم بتاعها في البوابة القديمة. بتغطّي: المخالفات والعقوبات،
إخلاء الطرف، تغيير القيد والانسحاب، الشكاوى، ساعات مكتب الدكاترة، وحجز المواعيد.
بيشتغل إزاي؟
كل إندبوينت هنا بيقرا من نفس الجداول اللي البوابة بتكتب فيها، والعمليات اللي بتكتب (الشكوى وحجز الميعاد) بتتبع نفس قواعد الفورم بالظبط. مهم: الموبايل بياخد نص الدورة بتاعة الطالب بس — التظلمات والموافقات وتعريف الأجندة كلها بتتعمل من البوابة. اقرا فصل الـ SIS مصدر الحقيقة قبل ما تزوّد حاجة هنا.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| POST | students/GetViolations | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ⭐ المخالفات والعقوبات — عبر GetStudentViolations (بيتحوّل لـ C_) |
| POST | students/GetClearanceRequests | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ⭐ إخلاء الطرف — بيوضّح أنهي إدارة لسه ماوقّعتش |
| POST | students/GetEnrollmentChanges | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد تغيير القيد والانسحاب الرسمي |
| POST | students/GetOfficeHours | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ساعات المكتب — كارت لكل دكتور مش صف لكل مقرر · جديد ٢ والحجز من students/GetOfficeHourOpenings / students/BookOfficeHour |
| POST | students/GetOfficeHourOpenings | ● شغال | 👨🏫 دكتور atef.dahesh |
جديد ٢ المواعيد المتاحة للحجز (Openings[]) + MyBookings[] + CancelledByLecturer[] — التفاصيل |
| POST | students/BookOfficeHour | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ٢ حجز ميعاد؛ الإلغاء بـ {Cancel: true, BookingId} |
| POST | students/GetComplaints | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد شكاويّ + قوايم الأنواع |
| POST | students/AddComplaint | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ✍️ تقديم شكوى — الموظف بيرد من البوابة |
| POST | students/GetAppointmentSlots | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد المواعيد المتاحة — من ED_STUD_SEM_TIME_AVAILABLE |
| POST | students/BookAppointment | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ✍️ حجز / إلغاء — حجز واحد لكل نشاط |
| POST | students/GetMyRecords | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد الأنشطة والتدريب ومذكرات المحاضرات |
| POST | students/GetCampusRequests | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد الخزائن وملصق العربية وطلبات الخصم |
| POST | students/AddCampusRequest | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ✍️ طلب خزانة / ملصق — العميد بيسلّم المفتاح ويطبع الملصق |
| POST | students/GetHousingRequests | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد السكن + أنواع الغرف + النافذة الزمنية |
| POST | students/AddHousingRequest | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ✍️ طلب سكن — بيرفض برّه النافذة |
| POST | students/GetCourseWithdrawals | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد طلبات الانسحاب + المقررات المؤهلة |
| POST | students/RequestCourseWithdrawal | ● شغال | 🎓 طالب mahmoued.eprahim.23010062 |
جديد ✍️ انسحاب من مقرر — بيسجّل طلب بس؛ حالة التسجيل مبتتغيّرش غير باعتماد العميد |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| المخالفات والعقوبات | متعمل | عرض فقط — بما فيه التظلم لو الموظف سجّله. | — |
| تقديم تظلم من الموبايل | ناقص | مقصود إنه مش موجود. فورم التظلم بتاع عميد شؤون الطلاب (14) وشؤون التسجيل (27) — الطالب مالوش صلاحية يقدّمه من البوابة أصلاً. | مايتعملش إلا لو البوابة نفسها إدّت الطالب الصلاحية |
| إخلاء الطرف | متعمل | بيعرض التوقيعات الناقصة بالاسم. | — |
| تغيير القيد والانسحاب | متعمل | عرض. ملاحظة: APPROVE_FLG عليه DEFAULT 0 فالداتابيز مش بتفرّق بين "لسه" و"مرفوض". |
— |
| ساعات المكتب | متعمل | مجمّعة لكل دكتور بمقرراته. | — |
| الشكاوى | متعمل | تقديم من الموبايل والرد من البوابة — دورة كاملة. | — |
| حجز المواعيد | متعمل | حجز وإلغاء بقاعدة حجز واحد لكل نشاط وفحص السعة. | — |
| الخزائن وملصق العربية | متعمل | الطالب بيطلب من الموبايل، والعميد بيسلّم المفتاح ويطبع الملصق من البوابة. فيه منع تكرار: طلب خزانة مفتوح واحد، وملصق واحد لكل عربية في السنة. | — |
| طلبات الخصم | متعمل | عرض فقط — النسبة والموافقة قرار مالي البوابة هي اللي بتاخده. | — |
| الأنشطة والتدريب ومذكرات المحاضرات | متعمل | عرض فقط — الصفوف دي بتتكتب من البوابة مش من التطبيق. | — |
| السكن الجامعي | متعمل | دورة تلاتية: الطالب يطلب (2) · العميد ينفّذ (14) · المالية توافق وتسعّر (25). وبنافذة زمنية زي الفورم بالظبط. | — |
| الانسحاب من مقرر | متعمل | الطالب بيسجّل طلب في ED_STUD_COURSE_CHNG بس — ED_STUD_COURSE_REG مبتتلمسش. العميد هو اللي بيعتمد وبيغيّر الحالة من 1 لـ 2/4. |
— |
| كتالوج طلبات المستندات في البروتوتايب | ناقص | مش موجود في الـ SIS أصلاً. شاشة الطلبات في البروتوتايب اتصمّمت حوالين بيان درجات وإفادة قيد وخطاب تعريف — ومفيش فورم في البوابة يكمّل الطلبات دي. الشاشة دلوقتي بتعرض طلبات الـ SIS الحقيقية. | قرار إداري: هل الجامعة عايزة الخدمات دي أصلاً؟ لو أيوه لازم تتعمل في البوابة الأول |
عن الجامعة (قبل الدخول)
About the University
جديد شاشة بتتفتح من غير حساب — عشان مراجع الـ App Store / Google Play، والطالب الجديد، وولي الأمر. بتعرض اسم الجامعة ولوجو وألوانها ونبذة، وأسامي الكليات والأقسام والبرامج.
بيشتغل إزاي؟
GET Info/University — من غير Authorization. الرد:
University { nameAr · nameEn · shortNameAr · logoUrl ·
primaryColor · aboutAr · website · email · phone ·
addressAr · location {lat,lng} · privacyPolicyUrl · termsUrl ·
bylawUrl · social[] {type,url} } +
Faculties[] (شجرة: Type = Faculty ← Department ← Program، كل واحد
NameAr/NameEn/Children[]) + Contacts[].
مصدرين: بيانات الجامعة والتواصل بتتكتب مرة في الأدمن (تاب «Public info & contact») لأن الـ SIS
مفيهوش حاجة منها؛ والشجرة الأكاديمية بتتقري لايف من الـ SIS فمبتختلفش أبدًا عن اللي المسجّل عامله.
حقل فاضي بييجي "" — اخفي السطر بتاعه. الرد عليه كاش 5 دقايق.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| GET | Info/University | ● شغال | 🌐 من غير توكن | ⭐ جديد من غير توكن — بيانات الجامعة + 8 كليات بأقسامها وبرامجها · جديد ٢ كل برنامج معاه Plan (الخطة الدراسية)؛ ?plans=false من غيرها |
| GET | Info/AcademicPlan?programId=10 | ● شغال | 🌐 من غير توكن | جديد ٢ خطة برنامج واحد، من غير توكن — التفاصيل |
| GET | Info/ByLawPage | ● شغال | 🌐 من غير توكن | لينك اللائحة (نص) — وبقى كمان جوّه University.bylawUrl |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| الشجرة الأكاديمية | متعمل | جديد 8 كليات ← أقسام ← برامج، الفعّال والظاهر بس. | — |
| الاسم واللوجو والألوان والنبذة | متعمل | جديد من الأدمن. | حد من الجامعة يكتبهم في تاب Public info |
| سياسة الخصوصية | متعمل | الستورين بيطلبوا لينك — privacyPolicyUrl. صفحة Overview في الأدمن بتحذّر لو فاضي. |
اللينك من الجامعة |
تواصل معنا
Contact Us
جديد أرقام وإيميلات المكاتب اللي الطالب بيحتاجها (القبول، شؤون الطلاب، الدعم الفني) — من غير حساب، عشان مراجعة الستور.
بيشتغل إزاي؟
GET Info/ContactUs — من غير توكن. الرد: Contacts[] كارت لكل مكتب:
TitleAr · TitleEn · Phone · Email · WhatsApp ·
HoursAr · NotesAr — ومعاه University (التليفون والإيميل والعنوان والخريطة العامة).
زرار «اتصال» ← tel:، «إيميل» ← mailto:، «واتساب» ← https://wa.me/، «الموقع» ← location.
قرار البيزنس: دلوقتي بيانات عامة بس — مفيش إرسال رسالة من التطبيق. الإرسال للموظفين (زي صفحة النظام القديم)
محتاج حماية من الإزعاج لأنه من غير توكن، فاتأجّل.
الإندبوينتات اللي الشاشة دي محتاجاها
| الطريقة | المسار | الحالة | الحساب | ملاحظات |
|---|---|---|---|---|
| GET | Info/ContactUs | ● شغال | 🌐 من غير توكن | ⭐ جديد من غير توكن — كروت التواصل + البيانات العامة |
| POST | Info/ContactUs/Send | ✕ مش موجود | 🌐 من غير توكن | إرسال رسالة للجامعة — اتأجّل بقرار (بيانات عامة بس دلوقتي) |
الخصائص — إيه المتعمل وإيه الناقص
| الخاصية | الباك إند | الوضع الحالي | محتاجة إيه؟ |
|---|---|---|---|
| كروت التواصل | متعمل | جديد بتتكتب في الأدمن (جدول «Contact cards»). | بيانات المكاتب من الجامعة |
| إرسال رسالة | ناقص | اتأجّل بقرار. | قرار بيزنس + حماية من الإزعاج |
6 الـ Client Profile — قلب النظام كله
لو فهمت الجزء ده، فهمت السيرفس كله. الجزء ده هو سبب وجود المشروع أصلاً.
القصة من الأول
قبل كده كان فيه 17 نسخة منفصلة من نفس الباك إند — واحدة لكل جامعة. كل ما جامعة تطلب تعديل، حد يروح ينسخ الكود ويعدّله ويعمل fork جديد. النتيجة: 17 كود بيس، كل واحد بيبعد عن التاني، وأي إصلاح لازم يتعمل 17 مرة.
الفكرة الجديدة: كود واحد فيه كل الخصائص بتاعة الـ 17 نسخة.
والاختلاف بين جامعة وجامعة بيتحدد من ملف JSON واحد اسمه clientprofile.json.
مفيش if (client == "KU") في الكود خالص.
الملف ده فيه إيه؟
{
"client": // اسم وكود الجامعة
"connectionStrings": // الاتصال بالداتابيز (كتابة + قراءة اختيارية)
"auth": // طريقة الدخول + إعدادات الـ JWT
"academic": // نظام ساعات ولا سنوي + إزاي نحدد الفصل الحالي
"features": // { "اسم الخدمة": true/false } لكل خدمة
"payments": // بوابة الدفع وبياناتها ← جديد
"wallet": // المحفظة الجامعية ← جديد
"meetings": // Microsoft Teams ← جديد
"lms": // Moodle ← جديد
"campus": // حدود حرم الجامعة على الخريطة ← جديد
"push": // إعدادات FCM للإشعارات
"mail": // SMTP (لكود نسيت الباسورد)
"infoPages": // لينكات اللائحة ورسالة الرئيس
"backOffice": // مفتاح API للباك أوفيس
"admin": // يوزر وباسورد لوحة الإدارة
"sandbox": // تقليد التكاملات وقت التطوير ← جديد
}
الأسرار بتتشفّر لوحدها. باسورد الداتابيز، مفتاح الـ JWT، مفتاح فوري،
توكن Moodle… كلهم بيتحفظوا مشفّرين بـ DPAPI وبيبدأوا بـ ENC:.
ما تحطش سر في الملف بإيدك — استخدم لوحة الإدارة، هي اللي بتشفّر.
لوحة الإدارة اتنظّمت
روح http://109.123.243.32:9300/Admin (أو http://localhost:5099/Admin عندك). اليوزر
admin، والباسورد عند محمد عطية. أول مرة على سيرفر جديد (لو مفيش بروفايل) هتدخل على طول
في «وضع الإعداد» وتقدر تبدأ من preset جاهز. فوق فيه 4 صفحات: Overview · Setup ·
Readiness · Sandbox control (لو شغال) — و«Sign out».
«Save changes» بيحفظ التابات اللي غيّرتها بس — عليها علامة ● برتقالي. قبل كده الفورم كله كان بيتحفظ مرة
واحدة، فغلطة في تاب كانت بتمنع حفظ تاب تاني، وأي إعداد الفورم مايعرفوش كان بيرجع للافتراضي مع أول حفظ في أي حتة.
دلوقتي باقي البروفايل بيفضل زي ما هو بالحرف، والرسالة بتقول «Saved: Academic rules» عشان تعرف اتحفظ إيه.
ونسخة من البروفايل القديم بتتحفظ في profile-history كل مرة.
التابات واحد واحد
① Identity — هوية الجامعة

كود الجامعة واسمها بالعربي والإنجليزي والدولة. الكود ده بيظهر في /health وInfo/Capabilities،
والاسم في Info/University.
② Public info & contact — اللي بيظهر قبل الدخول جديد

الاسم المختصر، اللوجو، الألوان، النبذة، الموقع والإيميل والتليفون والعنوان ودبوس الخريطة، ولينك سياسة الخصوصية
(الستورين بيطلبوه)، وكروت التواصل (مكتب لكل كارت: تليفون، إيميل، واتساب، مواعيد) ولينكات السوشيال.
ده اللي بيطلع في Info/University وInfo/ContactUs
من غير توكن. الكليات والأقسام مابتتكتبش هنا — بتتقري لايف من الـ SIS.
③ SIS database — الاتصال

سيرفر وداتابيز ويوزر وباسورد. فيه خانة اختيارية لـ read replica — لو حطيتها، كل القراءات هتروح عليها والكتابات بس على الأساسي. لو سيبتها فاضية، الاتنين على نفس الاتصال.
④ Sign-in methods — الدخول بـ 3 طرق اتعمل

كل الطرق بتنتهي بنفس الحاجة: اليوزر لازم يكون موجود في الـ SIS، والتطبيق بياخد نفس التوكن ونفس
UserMainData. اللي بيختلف إزاي الباسورد بيتثبت:
| الطريقة | الموبايل بينادي | بتعمل إيه | الحالة |
|---|---|---|---|
| 1 · يوزر + باسورد افتراضي | auth/login |
الـ SIS مفيهوش باسوردات، فليها وضعين: «أي باسورد» (زي النسخ القديمة) أو «باسورد موحّد»
تكتبه هنا (زي 123 بتاع Lotus) — بيتخزن hash. للتيست والديمو. |
● شغال |
| 2 · Active Directory | auth/login |
LDAP bind بـ user@domain على الـ domain controller — الـ AD هو اللي بيقول الباسورد صح ولا لأ. تحط الـ DC (المسار القديم ينفع زي ما هو) والدومين، وفيه «Test sign-in» تجرّب بحساب حقيقي من غير ما تحفظ. | ● شغال |
| 3 · Microsoft | students/LoginAZ |
الدومين، الـ Tenant ID (اختياري)، والـ audience = Client ID بتاع app الموبايل. «Token checking»: Verify (الصح) أو «Decode only» (القديم — بيظهر أحمر). وتقدر تسيب يوزر + باسورد شغالين جنبه (بـ 1 أو 2) أو تقفلهم. تفاصيل الموبايل في دليل دخول مايكروسوفت. | ● شغال |
Innovation لسه على «1 · أي باسورد» — بقصد، عشان شغل الموبايل تيم والتيست مايقفش. Overview وReadiness بيحذّروا منها. قبل أي جامعة حقيقية: 2 أو 3، أو على الأقل باسورد موحّد على سيرفر تيست.
⑤ Academic rules — القواعد الأكاديمية

حاجتين:
- النظام:
YearBased(سنوي) ولاModular(ساعات معتمدة). ده بيغيّر استعلام الغياب مثلاً. - تحديد الفصل الحالي: وده أهم إعداد وأكترهم بيتنسي. 4 أوضاع:
| الوضع | بيحدد الفصل إزاي |
|---|---|
GlobalCurrent | من ED_ACAD_YEAR.CURRENT_YEAR = 1 + ED_SEMESTER_OPEN.IS_CURRENT = 1 |
StudentLastSemester | من آخر فصل الطالب نفسه (ED_STUD_SEMESTER.IS_LAST = 1) |
FacultyCurrentYear | سنة الكلية (ED_ACAD_YEAR_FACULTY) |
ByUserType | طالب → آخر فصله · موظف → السنة العامة |
دي بالظبط اللي وقعتنا: في Innovation_Demo الـ CURRENT_YEAR
لسه على 2023/2024 بينما الفصل المفتوح فعليًا 2025/2026 ربيع.
فلما جربنا GlobalCurrent اللوجين رجّع ED_CODE_SEMESTER_ID = null
وكل الشاشات وقعت. حوّلناها ByUserType واشتغل كل حاجة.
الدرس: أول حاجة تعملها مع عميل جديد — اتأكد إن اللوجين بيرجّع سنة وفصل صح.
لو null، غيّر الوضع ده.
جديد وجنبهم إعدادين من الميتنج:
| الإعداد | الافتراضي | بيعمل إيه |
|---|---|---|
A lecturer's term is the one they teach in | مفتوح | الدكتور بيدخل على الترم الحالي، ولو مالوش فيه سكاشن ← آخر ترم بيدرّس فيه (مش ترم جاي). من غيره الدكتور كان ممكن يدخل على ترم فاضي: جدوله فاضي، والساعات المكتبية اللي يسجّلها تروح لترم الطلبة مش فيه. |
Academic calendar shows | «للطلاب» (القديم) | إيه اللي يظهر في semester/semsterCalnd: الأنشطة المعلّم عليها «للطلاب» بس، ولا «الظاهر»،
ولا الكل. كتير من المسجّلين بيعلّموا «يظهر» بس — والقاعدة القديمة ساعتها بترجّع تقويم فاضي. Innovation على «Shown». |
وتحتيها سياسة الحضور — إعدادين:
| الإعداد | الافتراضي | بيعمل إيه |
|---|---|---|
Lectures must be approved in order | مفتوح | كشف حضور محاضرة مابيفتحش طالما فيه محاضرة أقدم في نفس السكشن لسه مش معتمدة. القاعدة بتمنع إن كشف الترم كله يتملي بأثر رجعي آخر السنة — ومش كل جامعة بتطبّقها، فالقرار بقى إعداد. |
Approve the backlog automatically جديد |
مفتوح | لما الدكتور يفتح (أو يعتمد) كشف وفيه محاضرات أقدم مستنية، بتتعتمد لوحدها بالترتيب من الأقدم — كل واحدة بتعدّي على نفس الشيك. الترتيب لسه مفروض، بس بقى مش مشوار يدوي على الدكتور. اقفله لو الجامعة عايزة كل محاضرة تتأكد بإيد. |
اللي يخصّك كموبايل: مع الإعداد التاني مفتوح (الافتراضي)،
Staff/GetAbsenceDetails بيفتح عادي وبيرجّع
AutoApprovedDates = المحاضرات اللي اعتمدها بالنيابة عنك.
اعرضها للدكتور — «تم اعتماد ٣ محاضرات سابقة» — مش لأنها مشكلة، لكن لأن اعتماد محاضرة
كلام على قاعة، ومن حقه يعرف إنه اتقال باسمه.
ولو الجامعة قفلته: هيرجع كشف فاضي بـ
BlockedReason: "PreviousLectureNotApproved" ومعاه PendingApprovals
(السلسلة كلها). ده مش عطل — اعرض العدد وزرار يعتمدها. شوف
شاشة كشف الحضور اليدوي.
⑥ Campus map — الجامعة على الخريطة

هنا الجامعة بترسم حدودها على الخريطة. ودي الحاجة الوحيدة اللي خاصية «تسجيل الحضور بالموقع» بتشتغل عليها: من غير حدود مرسومة، الخاصية بتفضل Blocked وبتقفل نفسها — مش بتعتبر الدنيا كلها حرم جامعي.
لو إنت مبرمج موبايل: الصفحة دي مش شغلك، ومحتاج تعرف منها حاجة واحدة —
الحدود دي عمرها ما بتنزل للتطبيق. إنت بتبعت إحداثيات الجهاز والسيرفر بيحكم. اللي يخصّك
هو campus.checkInEnabled في Info/Capabilities: لو false،
يبقى الجامعة لسه مرسمتش حدودها ↩ ماتعرضش الزرار.
الأدمن بيعملها إزاي:
- يدوّر على الجامعة بالاسم. كتير من الجامعات حدودها متراسمة في OpenStreetMap خلاص، وساعتها بياخدها بضغطة بدل ما يرسمها.
- أو يرسم بنفسه: «Draw a fence» وكل كليك نقطة (3 على الأقل)، وللمواقع الصغيرة «Add a circle here».
- التعديل: يسحب النقطة يحرّكها، كليك يمين يحذفها، وكليك على الضلع بيزوّد نقطة.
الجامعة ممكن تكون أكتر من مكان — حرم رئيسي، ومستشفى تعليمي، ومبنى مستأجر — فدي قايمة، والطالب اللي جوّه أي واحدة منهم بيعتبر في الجامعة.
| الإعداد | معناه | بيبان للموبايل؟ |
|---|---|---|
Tolerance (25م) |
سماحية برّه الحدود — الموبايل وهو لازق في السور بيقول إنه برّه بمتر أو اتنين. | لأ |
Max accuracy (100م) |
أوحش دقة السيرفر هيقبلها. القراية اللي بتقول «±500 متر» بتوصف برج المحمول مش الطالب. | أيوه — campus.maxAccuracyMeters |
Grace (10 دقايق) |
قد إيه بدري يقدر يسجّل وقد إيه بعد ما تخلص المحاضرة. | أيوه — campus.checkInGraceMinutes |
مكتبة الخريطة متحطوطة جوه المشروع نفسه مش جاية من CDN — عشان اللوحة تشتغل على سيرفر على شبكة مقفولة. اللي محتاج نت فعلاً هو صور الخريطة والبحث، ولو مفيش نت فيه «Advanced — the fences as coordinates» تحت الخريطة تعدّل منها بإيدك.
★ دخول مايكروسوفت — دليل الموبايل تيم
إيه اللي تبعته لـ students/LoginAZ، إيه الأخطاء اللي ممكن ترجع وتعمل فيها إيه،
وإزاي تجرّب النهارده من غير Azure.
التوكن الصح
التطبيق بيعمل Sign-in بمايكروسوفت (MSAL) وبياخد توكن. مش أي توكن ينفع:
| التوكن | ينفع؟ | ليه |
|---|---|---|
id_token (scopes: openid profile email) | ✔ ده اللي تبعته | الـ aud بتاعه = الـ Client ID بتاع app registration الموبايل، والسيرفس يقدر يتأكد من توقيعه. |
access token لـ API بتاعنا (scope api://<api-client-id>/access_as_user) | ✔ ينفع | لو الجامعة عملت app registration للـ API نفسه. |
access token لـ Microsoft Graph (User.Read…) | ✕ بيترفض | ده اللي الكود القديم كان بياخده. مايكروسوفت نفسها بتقول محدش يقدر يتأكد من توقيعه غير Graph — فالرد بيقول تبعت إيه بداله. |
POST /students/LoginAZ
Content-Type: application/json
{ "JWTAccessToken": "<id_token>" }
الرد نفس رد auth/login بالظبط: UserMainData + token.data — وكمل عادي.
اسم اليوزر في الـ SIS = الجزء قبل @ في الإيميل (زي النظام القديم).
لو رجع result: "ERROR"
details بيبدأ بـ | معناه | تعمل إيه |
|---|---|---|
| This is a Microsoft Graph token… | بعت توكن Graph | ابعت الـ id_token |
| The Microsoft token has expired… | التوكن خلص | اعمل sign-in تاني (silent) |
| The Microsoft token is for a different application… | الـ Client ID مش المسجّل في الأدمن | كلّم الباك إند — إعداد |
| …issued by a different tenant / Token UPN is not from tenant… | حساب من جامعة/tenant تاني | اعرض «الحساب ده مش تبع الجامعة» |
| User not found. | التوكن سليم بس اليوزر مش في الـ SIS | اعرض «حسابك مش مفعّل على النظام» |
| Azure AD login is not enabled on this installation. | الجامعة دي مش على مايكروسوفت | اخفي الزرار (Info/Capabilities) |
عايز تجرّب بالتوكن اللي معاك دلوقتي (حتى لو Graph)؟ الأدمن يغيّر «Token checking» لـ Decode only على سيرفر التيست — التوكن هيتقري زي النظام القديم من غير تحقق. للتيست بس، وبيظهر أحمر لحد ما يرجع Verify. التفاصيل والصورة في فلاج التيست.
جرّب النهارده من غير Azure — الـ Sandbox
فيه «مايكروسوفت مزيّفة» جوّه السيرفس بتنشر مفاتيح وبتمضي توكنات حقيقية (RS256)، والسيرفس بيتأكد منها بنفس الكود اللي هيتأكد بيه من مايكروسوفت الحقيقية. الأدمن يفتح: Sign-in methods ← «3 · Microsoft sign-in»، و Sandbox ← «Microsoft sign-in». بعدها:
POST /__sandbox/identity/token
{ "userName": "mahmoued.eprahim.23010062" }
→ { "id_token": "eyJ…", "expires_in": 3600 }
POST /students/LoginAZ
{ "JWTAccessToken": "eyJ…" } → result: Ok
# جرّب الأخطاء:
{ "userName": "…", "ExpiresInMinutes": -5 } → «has expired»
{ "userName": "…", "Audience": "someone-else" } → «for a different application»
اتجرّبت 6 حالات: سليم ✔، توكن متلعب فيه (غيّرنا الاسم لدكتور) ✕، منتهي ✕، تطبيق تاني ✕، Graph ✕، ويوزر + باسورد جنبه ✔. على Innovation الطريقة الرئيسية لسه «1» عشان شغلكم الحالي مايتأثرش.
المطلوب من الجامعة (مرة واحدة)
- App registration للموبايل على Azure (Redirect URI بتاع MSAL) ← الـ Client ID.
- في الأدمن: Sign-in methods ← «3»، الدومين (زي
ku.edu.bh)، والـ Client ID في «Accepted audience(s)»، و Token checking = Verify. - Readiness يبقى أخضر على «Authentication (Microsoft)».
7 الـ Features — إزاي تفتح وتقفل الخدمات
النظام اللي بيمنع الإعدادات الناقصة إنها توقّع السيرفس.
الـ 3 حالات
Disabled مقفولة
حد قفلها بالإيد من التبويب ده. الإندبوينت بيرد «الخدمة دي مش متاحة».
Active شغالة
مفتوحة + كل الإعدادات المطلوبة موجودة + كل الجداول المطلوبة موجودة في الداتابيز.
Blocked مفتوحة بس ناقصة
مفتوحة لكن ناقصها إعداد أو جدول أو خدمة تانية بتعتمد عليها. بتتصرف زي المقفولة بالظبط — بترد رسالة، ما بتضربش 500.
إزاي كل خاصية بتعرّف نفسها؟
في ملف FeatureCatalog.cs، كل خاصية بتقول محتاجة إيه:
new() { Key = "onlinePaymentFawry", DisplayName = "Fawry payment reference", // الجداول اللي الـ SQL بتاعها بيلمسها RequiredTables = ["INTEG_Fawry_Payment", "FEE_STUD_VOUCHER", ...], // خدمات تانية لازم تكون شغالة الأول DependsOn = ["payments"], // الإعدادات الإجبارية — بترجع اللي ناقص بالاسم ConfigRequirements = p => { if (string.IsNullOrWhiteSpace(p.Payments.Fawry.MerchantCode)) missing.Add("payments.fawry.merchantCode"); ... } }
الفايدة العملية: لما تفتح خاصية وتنسى إعداد، مش هتكتشفها لما مستخدم يشتكي — هتلاقيها مكتوبة بالاسم في لوحة الإدارة وفي صفحة Readiness. زي كده بالظبط:
Feature onlinePaymentFawry is BLOCKED: Missing configuration: payments.fawry.merchantCode | Missing configuration: payments.fawry.securityKey | Depends on feature 'Online payments' which is Blocked.
8 Readiness — الفحص قبل ما تسلّم
الصفحة اللي بتقولك: هل التركيب ده جاهز فعلاً ولا لأ.
بيفحص إيه؟
- الاتصال بالداتابيز
بيفتح اتصال فعلي ويقولك اتصل بإيه وعلى أنهي سيرفر.
- مسح الـ Schema
بيقرا
sys.objectsويجيب كل الجداول والفانكشنز (1001 جدول و359 فانكشن هنا) ويقارنها باللي الخصائص محتاجاه. - الـ Schema الأساسي
الجداول اللي أي تركيب لازم يكون فيه (اللوجين وكارت الطالب). لو ناقصة، الداتابيز دي مش SIS أصلاً.
- اكتمال الخصائص
كل خاصية Blocked بتظهر بسبب واضح.
- سلامة الدخول
بيحذّر لو لسه على LegacyTrust.
- الـ Sandbox شغّال ولا لأ 🧪 جديد
لو فيه أي تكامل متقلّد، بيظهر صف أصفر مكتوب عليه
SANDBOXبدل الأخضر، والنتيجة فوق بتبقى READY (sandboxed) مش READY. الفكرة إن الصفحة تفضل تعدّي وانت بتطوّر — بس عمرها ما تدّيك إحساس زائف إنك جاهز للإنتاج. - الاتصال بالخدمات الخارجية ● جديد
وده الجزء المهم: بيتصل فعلاً بالبوابات والخدمات — مش بيقرا الإعدادات وبس.
مثال حقيقي من تشغيل على بيانات فوري الحقيقية: الفحص راح لسيرفر فوري التجريبي فعلاً ورجّع:
Payments: Fawry — OK — atfawry.fawrystaging.com reachable (HTTP 200)
وكمان قالنا اللينك اللي المفروض نسجّله عندهم:
Register https://mobile.innovation.edu.eg/payments/callback/Fawry with the gateway.
ولما الـ Sandbox بيبقى شغّال، نفس الصف بيبقى أصفر ومكتوب فيه صراحةً
this is the built-in fake gateway, not Fawry — عشان محدش يقرا الأخضر غلط.
حتة ذكية في فحص Teams: عشان Teams يشتغل لازم حاجتين مع بعض:
(1) صلاحية OnlineMeetings.ReadWrite.All بموافقة الأدمن، و(2) application access policy
على حساب المنظّم. لو ناقص أي واحدة فيهم، Graph بيرد 403 في الحالتين — فمش هتعرف مين الناقص.
الفحص عندنا بيفرّق بينهم ويقولك بالظبط تعمل إيه.
9 بوابات الدفع و Teams و Moodle
الجزء ده كله جديد — اتعمل من الصفر. اقراه كويس لو انت في الباك إند تيم.
الاكتشاف اللي غيّر التصميم
قبل ما نكتب أي كود دفع، بصينا في الداتابيز الأول. ولقينا حاجة مهمة جدًا:
الداتابيز مش فاضية من ناحية الدفع. الـ SIS القديم كان بيكتب فيها فعلاً:
| الجدول | عدد الصفوف | بيحتوي إيه |
|---|---|---|
| INTEG_Fawry_Payment | 2,570 | أرقام فوري المرجعية الحقيقية + الحالة (UNPAID/PAID) |
| OnlinePaymentRequests | 10 | سجل طلبات الدفع + لينكات دفع MasterCard حقيقية (test-nbe.gateway.mastercard.com/pbl/PAYLINK…) |
| PaymentMethodAccountConfigurations | 2 | حسابات البنوك: «Misr MasterCard» و«NBE MasterCard» |
| FEE_STUD_VOUCHER | 18,235 | سندات السداد — ده اللي المفروض الدفع يسدّده |
| GS_CODE_PAY_METHOD | 7 | نقدي · تحويل بنكي · كارت فيزا · شيك · فوري · إيداع · أهلي |
القرار: الكود الجديد بيكتب في نفس الجداول دي — مش في جداول جديدة.
ليه؟ عشان شاشات التسوية والتقارير في الباك أوفيس تفضل شغالة زي ما هي.
والجداول دي بقت RequiredTables على الخصائص، يعني لو عميل داتابيزه قديمة ومفيهاش
الجداول دي → الخاصية تبقى Blocked تلقائيًا ومكتوب الجدول الناقص.
البوابات المتاحة
🟠 فوري (Fawry)
بيدي الطالب رقم مرجعي يدفع بيه من أي منفذ فوري أو من تطبيق myFawry، وفوري بتبعتلنا إشعار سيرفر-لـ-سيرفر لما يتسدد.
- التوقيع SHA-256 على ترتيب حقول محدد + المفتاح السري
- بيدعم كمان CARD و MWALLET لو فوري فعّلتهم للتاجر
- بيكتب في
INTEG_Fawry_Payment
محتاج: merchantCode + securityKey من فوري
🔴 Paymob — والمحافظ
ده اللي بيدينا فودافون كاش وأورنج كاش واتصالات كاش — مش بوابة منفصلة لكل واحدة، دي integration id مختلف عند Paymob.
- 3 نداءات: توكن ← أوردر ← مفتاح دفع
- التوكن بيعيش 60 دقيقة وبيتخزن عندنا
- المبالغ بالـ قروش مش الجنيه — غلطة هنا = خصم 100 ضعف
- الإشعار بيتحقق بـ HMAC-SHA512 على ترتيب حقول ثابت
محتاج: apiKey + hmacSecret + walletIntegrationId
💳 MPGS — فيزا/ماستر
نفس عيلة اللينكات الموجودة في الداتابيز أصلاً. صفحة دفع مستضافة عند البنك.
- الدخول Basic auth بـ
merchant.{merchantId} - Credimax البحريني نفس المنتج بالظبط
محتاج: merchantId + apiPassword من البنك
🔔 إشعار السداد (Callback)
لما البوابة تسدّد، بتبعتلنا على /payments/callback/{provider}. 3 حاجات مهمة اتعملت:
- التحقق من التوقيع — أي إشعار مزوّر بيترفض
- Idempotent — البوابات بتعيد الإرسال لحد ما تاخد 200، فالتحديث مشروط بإن الصف لسه مش مدفوع
- أكواد HTTP حقيقية — مش الـ envelope القديم. 401 = ما تعيدش، 500 = أعِد
Microsoft Teams
بيعمل لينك اجتماع لمواعيد الإرشاد. الإعداد له خطوتين في Azure والاتنين لازم:
- App registration + صلاحية
سجّل تطبيق في Entra، وأضف صلاحية
OnlineMeetings.ReadWrite.Allكـ Application (مش Delegated) — وبموافقة الأدمن. - Application access policy
ده اللي الناس بتنساه. من PowerShell:
New-CsApplicationAccessPolicy -Identity mobile-meetings ` -AppIds "<client-id>" -Description "University mobile" Grant-CsApplicationAccessPolicy -PolicyName mobile-meetings ` -Identity "<organizer-object-id>"
من غيرها Graph هيرد 403 حتى لو الصلاحية موجودة.
Moodle
بيعرض مقررات الطالب وتكليفاته جنب بيانات الـ SIS. كل حاجة بتمشي على إندبوينت واحد:
{baseUrl}/webservice/rest/server.php?wstoken=…&wsfunction=…&moodlewsrestformat=json
حتتين بيوقعوا الناس في Moodle:
(1) Moodle بيرد HTTP 200 حتى في الغلط — الغلط بيبان جوّه الـ body في حقل exception.
فما تحكمش على النجاح من الـ status code.
(2) التوكن لازم يبقى لـ role عنده صلاحية يقرا بيانات مستخدمين تانيين،
مش بيانات صاحب التوكن بس — وإلا كل استعلام هيرجع accessexception.
ملخص: كل تكامل ومحتاج إيه
| التكامل | الكود | محتاج إيه عشان يشتغل | مين يجيبه |
|---|---|---|---|
| فوري | متعمل | merchantCode, securityKey, callbackBaseUrl عام | تعاقد مع فوري |
| Paymob (محافظ + كروت) | متعمل | apiKey, hmacSecret, walletIntegrationId, cardIntegrationId, iframeId | حساب Paymob |
| MPGS / Credimax | متعمل | merchantId, apiPassword | البنك المستحوذ |
| Microsoft Teams | متعمل | tenant + app + secret + organizer + access policy | أدمن Azure بتاع الجامعة |
| Moodle | متعمل | baseUrl + wsToken + REST مفعّل | أدمن Moodle |
| FCM (إشعارات) | متعمل | fcmServerKey أو ملف service account | Firebase بتاع الجامعة |
| SMTP (نسيت الباسورد) | نص نص | host + user + password صح | IT بتاع الجامعة |
| Active Directory | ناقص | الكود نفسه لسه متكتبش + بيانات الدومين | باك إند تيم |
حالة كل التكاملات دلوقتي: الكود متكتب ومتوثّق ومربوط بالـ Readiness،
ومفيش بيانات اعتماد حقيقية عندنا لسه — بس ده مبقاش بيوقّف الشغل.
فيه Sandbox جوّه السيرفس بيقلّد البوابات دي بنفس البروتوكول بتاعها، فكل الخصائص بتبقى
Active والموبايل تيم يشتغل دلوقتي. تفاصيله في القسم اللي بعده.
10 الـ Sandbox — نشتغل دلوقتي من غير ما نستنى البوابات
المشكلة: كل اللي واقفنا تكاملات خارجية. الحل: نقلّد البوابة نفسها، مش نقلّد كودنا.
المشكلة بالظبط
لو فتحت صفحة الـ Readiness قبل الشغل ده، كنت هتلاقي الكلام ده:
| الخاصية | واقفة ليه | مين بيجيب الحل |
|---|---|---|
| الدفع أونلاين | merchantCode و securityKey بتوع فوري | تعاقد مع فوري |
| إشعارات السداد | لازم callbackBaseUrl عام بـ https | دومين + شهادة |
| اجتماعات تيمز | tenant + app + secret + access policy | أدمن Azure بتاع الجامعة |
| Moodle | baseUrl + wsToken | أدمن الـ LMS |
| الإشعارات | مفتاح Firebase | Firebase بتاع الجامعة |
مفيش حاجة فيهم دي بتتحل بكود. كلها ورق وتعاقدات ممكن تاخد أسابيع. ومعنى كده إن الموبايل تيم يقعد مستني — وده مش مقبول.
الحل: نقلّد البوابة، مش نقلّد نفسنا
أسهل حاجة كانت إننا نحط في الكود if (sandbox) return fakeData; — ودي أسوأ حاجة ممكن نعملها.
ليه؟ لأنك ساعتها بتختبر فرع كود مش هيشتغل في الحقيقة أبداً، ويوم ما البيانات الحقيقية تيجي
تكتشف إن التوقيع غلط والـ HMAC غلط والـ callback مش بيتقري — كل ده يوم الإطلاق.
اللي عملناه بدل كده: كل تكامل بيتكلم HTTP على baseUrl متظبّط من الـ profile.
الـ Sandbox بيقوّم سيرفر مزيّف جوّه نفس الخدمة بيتكلم نفس بروتوكول الشركة الحقيقية،
وبيوجّه الـ baseUrl عليه.
يعني FawryPaymentProvider لسه بيبني توقيع SHA-256 حقيقي، وPaymobPaymentProvider
لسه بيعمل الأربع نداءات ويتحقق من الـ HMAC-SHA512، وGraph لسه بيعمل client-credentials.
مفيش سطر واحد اتغيّر في أي provider، ومفيش أي فرع كود جديد.
يوم الإطلاق = تغيير baseUrl والبيانات. خلاص. نفس الكود اللي جرّبناه هو اللي هيشتغل.
تشغّله إزاي
من لوحة الإدارة: Profile → تاب Sandbox → اختار تشغّل إيه:
| السويتش | بيقلّد إيه | بيفكّ إيه |
|---|---|---|
payments | فوري / Paymob / MPGS + صفحة دفع + callbacks موقّعة | 5 خصائص دفع |
meetings | Entra token + Graph onlineMeetings | لينكات تيمز في الإرشاد |
lms | Moodle web services + مواد وتكليفات جاهزة | شاشة المنصة التعليمية |
push | FCM — الرسايل بتروح لـ outbox تقدر تقراه | الإشعارات وصندوق الوارد |
identity جديد | مايكروسوفت مزيّفة — بتنشر مفاتيح وبتمضي توكنات دخول تجريبية (POST /__sandbox/identity/token) | دخول مايكروسوفت |
محتاج كمان تحدّد مكان الخدمة: Browser base URL (اللي الموبايل بيوصله)
وLoopback base URL (اللي الخدمة بتوصل بيه لنفسها — جوّه دوكر بيبقى http://127.0.0.1:8080).
حاجة مهمة عن البيانات: الـ Sandbox بيفرّق بين نوعين:
• البيانات السرية (merchant code, security key, token) — بيكتبها بس لو الخانة فاضية،
فبيانات حقيقية دخّلها حد عمرها ما هتتمسح.
• الـ baseUrl — بياخده دايمًا، حتى لو فيه لينك حقيقي. لأن الـ host هو المفصلة
اللي الفكرة كلها قايمة عليها: لو سبناه على فوري الحقيقية وحطينا بيانات مزيّفة، النتيجة تركيبة
مستحيل تشتغل، والرفض هيبان كإنه باج في كودنا. اللينك القديم بيتحفظ في
sandbox.overriddenBaseUrls وبيرجع مكانه أول ما تقفل الـ Sandbox.
وده اتكشف وقت النشر فعلاً: السيرفر على الـ VPS كان فيه لينك فوري حقيقي،
فالـ Sandbox ساب اللينك وغيّر البيانات بس — وكل عملية دفع رجعت
Something went wrong لحد ما اتصلّحت.
المبلغ هو اللي بيحدد النتيجة
عشان مطوّر الموبايل يجرّب حالة فشل من غير أي أدوات — الكسور في المبلغ بتتحكم في السيناريو (نفس فكرة كروت الاختبار عند Stripe):
| المبلغ | بيحصل إيه | بتختبر بيه إيه |
|---|---|---|
1500.00 | طبيعي — يفضل معلّق لحد ما تدفع | المسار السعيد |
1500.11 | البوابة ترفض من الأصل | رسالة الرفض في الشاشة |
1500.22 | يتعمل، وبعدين يفشل لوحده | أصعب حالة — الفشل المتأخر |
1500.33 | ينتهي صلاحيته من غير دفع | الكود اللي بيتلغي |
1500.44 | يتلغي | الإلغاء |
1500.99 | البوابة متردّش خالص | الـ timeout |
صفحة التحكّم: /__sandbox
بتشوف فيها كل عملية شغّالة، وتضغط زرار تخليها مدفوعة أو مرفوضة أو منتهية.
وكل ده متاح كمان JSON لو عايز تأتمته:
GET /__sandbox/control/transactions // كل العمليات POST /__sandbox/control/transactions/{ref}/PAID POST /__sandbox/control/transactions/{ref}/replay GET /__sandbox/control/outbox // الإشعارات اللي اتبعتت POST /__sandbox/control/reset
ليه Replay مهم؟ البوابات الحقيقية بتبعت نفس إشعار السداد أكتر من مرة لحد ما تاخد 200. لو الكود بتاعنا مش idempotent، الطالب هيتحسبله السداد مرتين. الطريقة الوحيدة إنك تتأكد إنه سليم هي إنك تبعت الإشعار مرتين بنفسك — وده اللي الزرار ده بيعمله.
جرّبناه فعلاً: أول إشعار رجّع Duplicate: false، والتاني والتالت رجّعوا
Duplicate: true، والقيد اتكتب مرة واحدة بس. ✅
الدورة كاملة — اللي اتجرّب فعلاً
التطبيق → students/CreatePayment
السيرفس → البوابة المزيّفة (بتوقيع SHA-256 حقيقي)
البوابة → بترجّع كود دفع 9 أرقام + لينك صفحة الدفع
الطالب → يفتح الصفحة ويضغط "ادفع"
البوابة → POST /payments/callback/Fawry (إشعار موقّع بجد)
السيرفس → يتحقق من التوقيع → يحدّث OnlinePaymentRequests + INTEG_Fawry_Payment
التطبيق → students/PaymentStatus → Paid
الـ Sandbox طلّع 7 باجات حقيقية كانت هتظهر يوم الإطلاق بس — 4 منهم كانوا تعطيل كامل للخاصية:
1. الـ callback مكانش بيتقري لو البوابة بعتت بـ chunked encoding — كل إشعارات السداد كانت هتتفقد بصمت.
2. INTEG_Fawry_Payment عموده identity والكود كان بيكتب فيه رقم بإيده (SQL 544).
3. الـ provider كان بيرمي exception لو فوري بعتت null في مبلغ عملية لسه متدفعتش.
4. شاشة الـ LMS كانت بتقرا STUD_FACULTY_CODE من جدول غلط.
5. MSG_SUBJECT عموده 50 حرف والكود كان بيحشر فيه JSON باللغتين — الإشعارات كانت بتفشل كلها.
6. الإشعار كان بيفشل لو المرسل مبعتش أرقام السنة والفصل — بقى بيجيبهم لوحده.
7. EfinancePay كان ناسي عمود ED_CODE_SEMESTER_ID من الـ INSERT أصلاً — يعني
الإندبوينت ده عمره ما اشتغل.
دي بالظبط الحاجات اللي مكانش فيه طريقة تكتشفها من غير ما تشغّل الدورة كاملة. التفاصيل والدروس المستفادة في القسم 12.
قبل ما ننزل production: اقفل الـ Sandbox من نفس التاب، وشغّل Readiness تاني. الصفوف اللي هتولّع أحمر دي هي الشغل اللي فاضل بالظبط.
الـ Sandbox بيعلن عن نفسه في كل مكان — /health، Info/Capabilities،
صف أصفر في Readiness، هيدر X-Sandbox على كل رد مزيّف، وشريط أصفر فوق شاشة التطبيق.
بس مفيش حاجة بتمنعك إنك تنزله غلط — فخلي بالك.
11 الـ SIS هو مصدر الحقيقة — قواعد لازم تشتغل بيها
الشاشات القديمة (الـ webforms) في Innovation/ هي مصدر الحقيقة لكل workflow.
الموبايل اتصمّم من رؤية البروتوتايب، وساعات الرؤية دي ما تتطابقش مع الـ workflow الحقيقي.
الفصل ده بيشرح القواعد الخمسة اللي لازم تمشي عليها، وكل واحدة فيهم غلطها بيعدّي في صمت —
مش بيرمي exception، بيرجّع داتا شكلها صح.
قاعدة 1 الموبايل بيعمل نص الدورة، والبوابة بتكمّلها
الطالب بيبدأ الطلب من الموبايل، والموظف بيكمّله من البوابة. يعني أي حاجة الموبايل بيعملها لازم يكون ليها استكمال عند الموظف — لو ملهاش، يبقى إحنا اخترعنا flow مش موجود.
| مثال حقيقي حصل | الاكتشاف |
|---|---|
| زرار "قدّم تظلم" على المخالفات كنا حاطين فيلد canAppeal في الـ API |
رجعنا للمنيو: الطالب (user type 2) عنده StudViol_view.aspx عرض
وRPT_StudViolation.aspx تقرير — وبس.
فورم التظلم AppealProblem.aspx بتاع عميد شؤون الطلاب (14)
وشؤون التسجيل (27).
يعني الطالب أصلاً مالوش صلاحية يقدّم تظلم من البوابة — الفيلد كان بيخترع flow
مالوش استكمال عند الموظف. اتحذف، وبقى hasAppeal عرض بس:
الموظف يسجّل التظلم من بوابة العميد، والطالب يشوف النتيجة على الموبايل.
|
| حجز المواعيد |
الطالب بيحجز بس (STUD_RSRV_REG_TIME.aspx)، لكن الأجندة نفسها
(ED_SEM_AGENDA_DTL / _TIME) الإدارة هي اللي بتعرّفها.
فالموبايل بيحجز ويلغي — وعمره ما بيعمل أجندة.
|
SE_FORM، شوف الـ SE_MODULE بتاعه راجع لأنهي
SE_CODE_USER_TYPE_ID. لو كل خطوات الـ cycle بتاعة الموظف — الموبايل يعرض بس.
قاعدة 2 اسم الـ stored procedure بيتغيّر وقت النداء
المنتج بيسمّي البروسيجر باسم منطقي، وبعدين التركيبة بتاعة كل عميل ممكن تستبدله بنسخة مخصّصة.
ده بيحصل في StoredProcedureProvider.GetCommandWrapper:
| الاسم موجود في | البادئة | اللي بيتنفّذ فعلاً |
|---|---|---|
CustomProcedures.xml | C_ | dbo.C_GetStudentViolations |
ProceduresUpdated.xml | U_ | dbo.U_<name> |
| ولا واحد | — | dbo.<name> زي ما هو |
dbo.GetStudentViolations بتنفّذ
dbo.C_GetStudentViolations، والاسم الأصلي مش موجود في الداتابيز خالص.
إحنا كنا مستخدمين C_ED_STUD_VIOL_Students — بروسيجر موجود فعلاً وبيرجّع مخالفات،
فشكله شغال تمام — بس مش اللي المنتج بينادي عليه، وبيرجّع أعمدة مختلفة
(من غير ED_STUD_VIOL_APPEAL_ID ولا EXE_FLG_REG).
الغلط ده مبيرميش exception، عشان كده خطير.
C_ أو U_ بإيدك، وممنوع تعدّل أو تعمل
stored procedure. استخدم ISisProcedures.ResolveAsync("<الاسم المنطقي>") —
بيجرّب C_ ثم U_ ثم الاسم العادي وياخد أول واحد موجود.
وRequiredProcedures في الـ FeatureCatalog بتحذف الاسم المنطقي،
والـ Readiness بيدوّر على أي نسخة من التلاتة.
لاقينا نفس المشكلة في مسار الغياب الـ Modular اللي كان موجود من الأول:
C_GetAttendanceFWforStudent كان مكتوب بالبادئة، وGetAllABSOfStud من غيرها —
كل واحد صح على الداتابيز دي بس غلط على عميل تركيبته مختلفة.
قاعدة 3 "مفيش فلتر" ساعات بيبقى 0 مش NULL
أغلب شروط البروسيجرز مكتوبة @p is null or @p = 0 or col = @p — فـ NULL تمام.
بس فيه شروط مكتوبة @p = 0 or col = @p بس، ومن غير is null.
NULL للشرط ده، الـ WHERE كله بيبقى false،
والطالب بيشوف سجله فاضي بدل مخالفاته. الصفحة القديمة بتبعت أصفار عشان كده بالظبط.
دايمًا اقرا جسم البروسيجر قبل ما تقرر تبعت إيه.
قاعدة 4 الأعمدة الرقمية مش سلاسل نصية
أعمدة زي EXE_FLG_REG وDrop_Flg وAPPROVE_FLG نوعها
numeric، فبترجع 1.0 مش "1".
value.ToString() == "1" بتخلي كل عقوبة منفّذة تبان غير منفّذة.
اعمل decimal.TryParse وقارن != 0.
APPROVE_FLG عليه DEFAULT 0 — يعني طلب لسه محدش بصّله
متخزّن بنفس شكل طلب مرفوض، والداتابيز مش قادرة تفرّق بينهم.
عشان كده بنكتب NotApproved مش Rejected:
ما ينفعش نحط على شاشة الطالب قرار محدش خده.
قاعدة 5 اسم الـ property في الكود القديم مش اسم العمود
الكود القديم بيستخدم ORM مولّد (nettiers)، وده بيحوّل أسماء الأعمدة لأسماء properties
بيحذف منها الشرط السفلي. فلو قريت ObjStud.GsCountryInfoId1 في الكود ونقلتها
زي ما هي، هتكتب GS_COUNTRY_INFO_ID1 — والعمود الحقيقي اسمه
GS_COUNTRY_INFO_ID_1.
Invalid column name 'GS_COUNTRY_INFO_ID1'.
خد الأعمدة من INFORMATION_SCHEMA.COLUMNS، مش من أسماء الـ properties.
مهم جداول أكواد فاضية عليها Foreign Key
الفورم القديم بيكتب قيم ثابتة (زي SV_CDE_REQ_STATUS_ID = 1) — وجدول الأكواد نفسه
ممكن يكون فاضي في داتابيز العميل.
Innovation_Demo جدول SV_CDE_REQ_STATUS كان فاضي وعليه FK،
يعني تقديم أي شكوى كان هيقع بـ FK violation. الهاندلر بتاعنا بيسيب العمود
NULL لو مفيش صف بدل ما يقع — نفس مبدأ "الإعداد الناقص بيهبّط الخاصية، ما بيكسرهاش".
12 تحليل الفجوة — الديمو مقابل الـ SIS
الديمو اتصمّم من بروتوتايب، والـ SIS هو اللي بيشتغل فعلاً. الفصل ده بيقسّم كل حاجة في التطبيق لتلات قوايم: مش موجود في الـ SIS خالص، وموجود بس دور الطالب فيه مختلف، وينفع يتعمل. كل سطر مبني على فورم حقيقي من المنيو مش على تخمين.
SE_MODULE وSE_FORM. الطالب هو
SE_CODE_USER_TYPE_ID = 2. فلو حاجة مالهاش SE_FORM في منيو الطالب —
يبقى الطالب مالوش صلاحيتها. ولو ليها فورم بس خطوات تانية بتاعة موظف — يبقى دوره جزئي.
🚫 القائمة الأولى — مش موجود في الـ SIS أصلاً
دول مش «لسه متعملوش» — دول مفيش لهم فورم في البوابة يكمّل الدورة. لو بنينا نص الموبايل منهم، هنعمل سجلات محدش يقدر يعالجها. الشاشات دي عليها علامة غير موجود في الـ SIS في التطبيق نفسه.
| الشاشة / الخاصية | البروتوتايب متخيّل إيه | الدليل من الـ SIS |
|---|---|---|
| كتالوج الوثائق بيان درجات، إفادة قيد، خطاب تعريف، شهادة تخرج، بدل فاقد كارنيه |
تقديم طلب + دفع رسوم + متابعة + استلام PDF | مفيش أي SE_FORM لطلب وثيقة في منيو الطالب. وحدة «طلباتي» الحقيقية في الـ SIS حاجة تانية خالص (إخلاء طرف، خزانة، ملصق، خصم، تغيير قيد). |
| حجز القاعات | قايمة قاعات + المتاح في وقت + حجز + موافقة | جداول ACCOM_* بتاعة السكن مش حجز قاعات، ومفيش فورم حجز قاعة في منيو الطالب. |
| الأنشطة والرحلات كتالوج فعاليات، طلب مشاركة، دفع |
يتصفّح فعاليات ويشترك ويدفع | ED_STUD_ACTIVITY سجل بعدي لنشاط الطالب (الموظف بيكتبه)، مش كتالوج ولا اشتراك. مفيش فورم اشتراك في فعالية. |
| المحفظة الجامعية | رصيد + شحن + دفع منها | مفيش جدول محفظة في الـ SIS. المدفوعات كلها بتعدّي على FEE_STUD_VOUCHER. |
| المساعد الذكي | شات ذكاء اصطناعي | مش جزء من الـ SIS — feature تطبيق محتاج قرار وخدمة منفصلة. |
| مجموعات وملفات ومكالمات في الشات | شات كامل | SV_STUD_ASK_ADV رسائل نصية بين طالب ومرشد بس. |
| Apple/Google Wallet · تذكير قبل الامتحان · إضافة للتقويم الشخصي | تكامل مع الجهاز | مميزات جهاز مش داتا SIS — بتتعمل في التطبيق نفسه. |
⚠️ القائمة التانية — موجود بس دور الطالب مختلف عن الديمو
دول أخطر من الأولى: الشاشة موجودة والداتا موجودة، بس الديمو بيفترض إن الطالب بيكتب والحقيقة إنه بيقرا بس — أو العكس. لو مشينا على افتراض الديمو، هنعمل زرار الطالب مالوش صلاحيته أصلاً.
| الحاجة | الديمو بيفترض | الحقيقة في الـ SIS | اتعمل إيه |
|---|---|---|---|
| التظلم على المخالفة | الطالب يقدّم تظلم | الطالب عنده StudViol_view عرض والتقرير وبس.
AppealProblem.aspx بتاع عميد شؤون الطلاب (14) وشؤون التسجيل (27). |
✅ اتحذف canAppeal وبقى hasAppeal عرض بس |
| الأنشطة والتدريب | الطالب يشترك ويعدّل | سجل بيتكتب من البوابة؛ التدريب بيتدار من القسم (RPT_StudTraining لأنواع 15/16/24/27). |
✅ اتعمل عرض بس |
| مذكرات المحاضرات | — | الدكتور بيرفعها على المقرر؛ الطالب بيشوف مقرراته المسجّلة بس. | ✅ اتعمل عرض بس |
| طلبات الخصم | — | الطالب يقدّم، بس DISC_PERCENT وUPDATED_PERCENT والموافقة قرار مالي البوابة بتاخده. |
✅ اتعمل عرض بس |
| الخزانة وملصق العربية | مش موجودين في الديمو أصلاً | فورم واحد منشور للطالب (2) وللعميد (14) — دورة هجينة مثالية. | ✅ اتعمل كتابة؛ التسليم والطباعة من البوابة |
| السكن الجامعي | مش موجود في الديمو | ٣ أدوار: الطالب يطلب (2)، العميد ينفّذ (14)، المالية توافق وتسعّر (25) — وبنافذة زمنية. | ✅ اتعمل كتابة بنفس شرط النافذة |
| رصد الدرجات (شاشة الدكتور) | الدكتور يرصد من الموبايل | موجود في البوابة، وأخطر إجراء أكاديمي في المنتج. | ✅ اتعمل ومقفول افتراضيًا — staffGradeEntry |
✅ القائمة التالتة — ينفع يتعمل
دول ليهم فورم في منيو الطالب، وليهم استكمال واضح عند الموظف. كلهم خلصوا — مفيش حاجة في القائمة دي مستنية كود. (والاتنين المقفولين فوق كمان اتعملوا، بس بيتفتحوا بقرار.)
خلص ١٣ مجموعة قدرات شغالة على الداتا الحقيقية
| القدرة | الفورم | دور الطالب |
|---|---|---|
| المخالفات والعقوبات | StudViol_view | عرض |
| إخلاء الطرف | PerStudClrncReqSearch | عرض + التوقيعات الناقصة |
| تغيير القيد والانسحاب | StudEnrollChangeSearch | عرض |
| ساعات المكتب | OfficeHours | عرض |
| الشكاوى | StudentComplain | كتابة — الموظف يرد |
| حجز المواعيد | STUD_RSRV_REG_TIME | كتابة — الإدارة تعرّف الأجندة |
| الأنشطة والتدريب والمذكرات | StudActivity · StudTraining · StudLecturesNotes | عرض |
| الخزانة وملصق العربية | ToolBoxOrderReg · CARSTIKR_Trans | كتابة — العميد ينفّذ |
| طلبات الخصم | FeeStudentDiscRequest | عرض |
| السكن الجامعي | AccomOrderDetails | كتابة بنافذة زمنية |
| الانسحاب من مقرر | WithdrawCoursesReq | كتابة — طلب بس، العميد يعتمد |
| الانسحاب من الجامعة والتأجيل | StudEnrollChngReq | كتابة — طلب بس، شؤون التسجيل تعتمد |
| أخذ الحضور واعتماد الغياب | شاشات الدكتور | كتابة — بقواعد اليوم والحصة السابقة |
مقفول اتعمل بالكامل — بس بيتفتح بقرار
الاتنين دول كانوا «محتاجين قرار». دلوقتي اتعملوا بالكامل وبقواعد الـ SIS نفسها، ومقفولين افتراضيًا. يعني البيزنس متطبّق، والجامعة هي اللي تقرر تفتح أو تقفل من Admin → Profile → Features — من غير ما حد يلمس كود. لما يكونوا مقفولين، الإندبوينت بيرد «الخدمة غير متاحة» زي أي feature مقفولة.
| الشغلانة | الفورم والدورة | الميكانيزم |
|---|---|---|
تعديل بيانات التواصلstudentContactEdit |
ContactMethod.aspx — الطالب (2)، بس تحت «Hidden Pages» |
الطالب يضيف/يعدّل/يمسح موبايله وإيميله وعنوانه. ليه مقفول: الجامعة مخفياه من المنيو عن قصد — بعض الجامعات بتخلي المسجّل هو اللي يغيّرهم لأنهم بيتحكموا في الإشعارات الرسمية. كل جملة SQL متقيّدة بالطالب نفسه، فـ id مزوّر ميوصلش لسجل طالب تاني. |
رصد الدرجاتstaffGradeEntry |
شاشات الدكتور | الدكتور يرصد درجة مكوّن تقييم.
الصلاحية مش من عندنا: SE_USER_CRS_ASSESS هي اللي بتقول مين يرصد
أنهي مكوّن لأنهي مقرر ولحد إمتى (FROM_DATE/TO_DATE).
الدرجة المعتمدة (Approve_Flg) بتترفض، والدرجة السالبة بتترفض،
وكل تعديل بينزل في AUDT_ED_STUD_COURSE_REG_ASSESS — اتأكدنا:
غيّرنا درجة والـ audit سجّلها. |
13 مسارات عضو هيئة التدريس
الستاف مش «طالب بصلاحيات زيادة» — هويّته مختلفة، والإندبوينت بتاعة بروفايله مختلفة، وحتى الفصل الدراسي بيتحسبله بطريقة تانية. الفصل ده بيشرح الفروق دي والسيناريوهات الشغالة فعلًا، بأرقام من تشغيل حقيقي.
١) اللوجن — إزاي تعرف هو مين
auth/login. students/login وacademicstaff/login أسماء قديمة لنفس الهاندلر بالظبط،
وكل واحد فيهم بيقبل الاتنين. النوع بيتحدد من الداتابيز:
IsStudent = (SE_CODE_USER_TYPE_ID == 2).
يعني لو التطبيق نادى الراوت «الغلط» الرد هيفضل صح.
ED_STUD_ID وSA_STAFF_MEMBER_ID:
طالب: ED_STUD_ID 73 · SA_STAFF_MEMBER_ID 73
ستاف: ED_STUD_ID 31 · SA_STAFF_MEMBER_ID 31
ده شكل
MOB_LOGIN القديم. الحقل اللي مالوش معنى للدور الحالي لازم يتتجاهل —
متبنيش أي منطق على إن الرقمين مختلفين، لأنهم مش مختلفين.
| الخطوة | الطالب | الستاف |
|---|---|---|
| اللوجن |
auth/login — إندبوينت واحد، والدور بيتحدد من IsStudent في الرد | |
| البروفايل | students/getبيرجّع CardProfile |
academicstaff/getبيرجّع مصفوفة فيها SA_STF_MEMBER_ID · STF_CODE · STF_FULL_NAME_AR/EN ·
AS_FACULTY_INFO_ID · SA_CODE_JOB_STATUS_ID |
| الـ id المستخدم | ED_STUD_ID |
SA_STAFF_MEMBER_ID |
٢) حساب التجربة — atef.dahesh
SA_STF_MEMBER_ID = 148 · SE_USER_ID = 2991 ·
السنة 16 الفصل 2. (الباسورد أي حاجة — LegacyTrust لسه شغال.)
| الإندبوينت | البودي | بيرجّع |
|---|---|---|
auth/login | {"UserName":"atef.dahesh","Password":"x"} | IsStudent = false |
academicstaff/get | {"ED_STUD_ID":"148"} | بيانات الدكتور |
academicstaff/GetStaffCourse | {"saStaffMemberId":148} | 7 مقررات |
academicstaff/GetStudentUnderSuperVision | {"EdAcadYearId":16,"EdCodeSemesterId":2,"saStaffMemberId":148} | 25 طالب |
Staff/GetInstructorCourseSections | {"saStaffMemberId":148,"EdCourseId":33} | 2 سكشن |
students/GetStudentsForCourse | {"EdCourseId":33} | 388 طالب |
Staff/GetInstructorSectionSolts | {"SC_SCHEDULE_DTL_ID":866} | الحصص + أيامها |
Staff/GetGradeEntrySheet | {"SE_USER_ID":"2991","ED_COURSE_ID":"33","ED_CODE_COURSE_ASSESS_ID":"55"} | 21 مكوّن · 194 طالب |
Staff/SetAbsence | {"EdStudId":1262,"EdCourseId":33,"ScTchngSlotId":1253,"AbsDate":"2026-07-28","IsAbsence":1} | «تم الحفظ» — 2026-07-28 يوم ثلاثاء وده يوم الحصة |
Staff/GetAbsenceDetails | {"EdCourseId":6,"SC_SCHEDULE_DTL_ID":1678,"ScTchngSlotId":2729,"AbsDate":"<أقرب يوم حد>"} | 26 طالب + الاعتماد مفتوح |
academicstaff/GetLectQRCode | {"SA_STF_MEMBER_ID":148,"SC_SCHEDULE_DTL_ID":1678,"SC_SCHEDULE_DTL_DAY_ID":2729} | الـ payload + وقت الصلاحية |
Staff/CloseLectureAttendance | {"SC_SCHEDULE_DTL_ID":1678,"SC_SCHEDULE_DTL_DAY_ID":2729,"STF_CODE":"70","SESSION_DATE":"<نفس اليوم>"} | حاضر + عدد اللي اتسجّلوا غياب |
2026-07-31 فاتمدّ؛ وED_ABSENCE_APPROVE كان
فاضي تمامًا فسلسلة «اعتمد المحاضرة السابقة الأول» مكانش ليها بداية — اتعمل اعتماد
للمحاضرات السابقة. ودي قواعد حقيقية من المنتج مش قيود اخترعناها.
1678 · محاضرة 2729 · يوم الحد · مقرر
6 · 27 مسجّل. اختارناها لأنها في الفصل المفتوح —
السكشن اللي كنا بنجرّب عليها قبل كده كانت بتاعة الفصل الأول، وده كان بيخلّي كشف الغياب
يرجع فاضي لسبب مالوش علاقة بالكود. التفاصيل في فصل الحضور.
خد بالك: الجلسة دي وقتها متوسّع لليوم كله عشان تنفع تتجرّب في أي ساعة — باقي الجلسات مواعيدها ضيّقة عشان رفض «الكود مابقاش صالح» يفضل قابل للتجربة.
٥) مين بيشوف إيه — خريطة الشاشات لكل طرف
التطبيق بيخدم طرفين من نفس البيلد، بس كل شاشة مبنية على معرّف مختلف:
شاشات الطالب كلها على ED_STUD_ID، وشاشات الدكتور كلها على
SA_STF_MEMBER_ID. لو عرضنا واحدة للتاني، هي مش بس هتبان غلط —
هتسأل الداتابيز بمعرّف مالوش معنى للشخص ده.
| الطرف | بيهبط على | الـ tabs بتاعته | شاشاته |
|---|---|---|---|
| الطالب IsStudent = true |
home |
الرئيسية · الخدمات · الجدول · الملف | الجدول، المقررات، الدرجات، الحضور، الاختبارات، خطة الدراسة، التسجيل، الإرشاد، الطلبات، الانسحاب، المدفوعات، الاستطلاع، شؤون الطلاب بكل شاشاتها، ومسح كود الحضور. |
| عضو هيئة التدريس IsStudent = false |
staff-home |
الرئيسية · مقرراتي · الحضور · الملف | لوحة الدكتور، الطلاب تحت الإشراف، مقرراته، رصد الدرجات، وعرض كود الحضور وقفل المحاضرة. |
| مشترك | — | — | الملف الشخصي، البطاقة الجامعية، الإشعارات، المحادثات، المساعد. |
٣) السيناريوهات الشغالة
| السيناريو | الإندبوينت | النتيجة الفعلية |
|---|---|---|
| بروفايلي | academicstaff/get |
✅ بيانات الدكتور كاملة |
| طلابي تحت الإشراف | academicstaff/GetStudentUnderSuperVision |
✅ ٢٥ طالب |
| مقرراتي | academicstaff/GetStaffCourse |
✅ ٧ مقررات |
| أخذ الحضور | Staff/SetAbsence |
✅ بيرفض اليوم المستقبلى واليوم اللى مش يوم الحصة |
| اعتماد الغياب | Staff/ApproveAbsence |
✅ بيفرض اعتماد المحاضرة السابقة الأول |
| رصد الدرجات 🔒 | Staff/GetGradeEntrySheet · Staff/SaveGrade |
✅ ٢١ مكوّن مسموح · كشف ١٩٤ طالب — مقفول افتراضيًا (staffGradeEntry) |
SE_USER_CRS_ASSESS هي اللي بتقول مين يرصد أنهي مكوّن لـأنهي مقرر
ولحد إمتى (FROM_DATE/TO_DATE). الشاشة بتعرض المسموح بس،
والدرجة المعتمدة (Approve_Flg) بتترفض، وكل تعديل بينزل في
AUDT_ED_STUD_COURSE_REG_ASSESS — اتأكدنا: غيّرنا درجة والـ audit سجّلها.
٤) باجين اتصلحوا وإنت محتاج تعرفهم
باج 1 الفصل الدراسي كان بيرجع NULL للستاف
أي لوجن ستاف كان بيولّد ١١ ريكوست فاشل (400) على طول. السبب داتا مش كود:
ED_ACAD_YEAR.CURRENT_YEAR فلاج بيتحط بالإيد، ولسه مأشّر على 2023/24
والفصل المفتوح فعلًا 2025/26. فالـ resolver بيقرا السنة المأشّرة، مبيلاقيش
ED_SEMESTER_OPEN ليها، ويرجّع سنة من غير فصل.
ED_STUD_SEMESTER بتاعه هو المرجع.
الستاف مالوش صف زي ده، فالانحراف وقع عليه هو بس.
الحل: لو السنة المأشّرة مفيهاش فصل مفتوح، الـ resolver بياخد السنة اللي فيها فصل مفتوح فعلًا (
IS_CURRENT = 1) — دي الحقيقة التشغيلية — ويكتب warning بالسنتين
عشان الفلاج يتصلّح مش يتلف حواليه.
النتيجة: من ١١ ريكوست فاشل لـ صفر، والطلاب تحت الإشراف من صف واحد لـ ٥٠ على الحساب اللي جرّبناه ساعتها.
باج 2 الـ API كان مفتوح من غير توكن
السؤال «هل بروفايل الستاف محتاج توكن زي كارت الطالب؟» كشف إن ٧٧ من ٨٨ كلاس إندبوينت
مكانش عليهم [Authorize] أصلًا.
{"ED_STUD_ID":"31"} من غير لوجن يقرا بروفايل أي دكتور،
أو غياب أي طالب، أو مصروفاته، أو جدوله.
الحل مكانش إضافة
[Authorize] ٧٧ مرة — ده بيسيب نفس الفخ لأي إندبوينت جديد.
بقى deny by default (SetFallbackPolicy): الراوت محمي لأن اللي كتبه معملش حاجة،
مش مكشوف لأنه نسي حاجة. والعام منهم بيقول كده صراحة ومعاه السبب.
| عام عن قصد | ليه |
|---|---|
students/login · LoginAZ | لسه مفيش توكن |
| نسيت الباسورد + إعادة التعيين | نفس السبب، وبالتعريف |
Info/Capabilities | التطبيق بيقراها قبل شاشة اللوجن |
Files/UserImages/{name} | بتتحط في <img> واللي مبيبعتش bearer token |
payments/callback/{provider} | البوابة مش مستخدم مسجّل دخول |
الساندبوكس · /health | بيقلّدوا بوابة · فحص صحة الكونتينر |
Authorization: Bearer هيرجع 401 ما عدا القايمة اللي فوق.
خد التوكن من token.data في رد اللوجن وابعته في كل ريكوست بعد كده.
14 الحضور — الدورة كاملة بتلات طرق
الفصل ده بيشرح أهم حاجة في الموضوع ده كله: المسح مش بيسجّل حضور بس — عدم المسح بيسجّل غياب.
والجزء التاني ده هو اللي كان ناقص في التطبيق القديم، وعشان كده الحضور كان بيتسجّل سنين
من غير ما يتحوّل لولا سطر غياب واحد.
وفيه تلات طرق دلوقتي بيوصلوا لنفس المكان: كود المحاضرة، أو الطالب بموقعه، أو الدكتور
بيعلّم بإيده. مش مراحل ورا بعض — كل واحدة بتشتغل لوحدها، والتالتة هي اللي مش محتاجة أي حاجة خالص.
الدورة تلات خطوات، اتنين بني آدمين
| # | مين | الإندبوينت | بيحصل إيه |
|---|---|---|---|
| 1 | الدكتور | academicstaff/GetLectQRCode |
بيعرض كود المحاضرة على الشاشة. بيتكتب سطر في QRCode_Log. |
| 2 | الطالب | students/GetStudentAttend |
بيمسح الكود جوه وقت المحاضرة. بيتكتب سطر في Integ_QRCode_Presence. |
| 3 | الدكتور | Staff/CloseLectureAttendance |
بيقفل المحاضرة. هنا بس بيتنادى إجراء المنتج Integ_QRCodeInsertStudentAbsence
اللي بيسجّل غياب لكل طالب مسجّل في السكشن ومامسحش في ED_STUD_ABSENCE.
|
لو الخطوة 3 ماحصلتش، المسح بيفضل مجرد سطر في جدول لوج. ده بالظبط اللي كان حاصل:
Integ_QRCode_Presence فيه 39,196 سطر حضور متسجّل،
وED_STUD_ABSENCE مافيهوش ولا سطر جاي منهم.
اللي كان ناقص التطبيق القديم كان بيعمل الخطوة الوسطانية بس
رجعنا لتطبيق Lotus/ القديم وقرينا الكود. كان فيه GetStudentAttend بس،
وكان بيتحقق من حاجة واحدة: الساعة. مش أكتر.
| الفحص | القديم | دلوقتي |
|---|---|---|
| الجلسة موجودة أصلاً؟ | لأ | أيوه — بيرفض بسبب واضح |
| النهاردة يوم المحاضرة؟ | لأ | أيوه — كود يوم التلات مايشتغلش يوم الحد |
| جوه وقت المحاضرة؟ | أيوه | أيوه |
| الطالب مسجّل في السكشن دي؟ | لأ | أيوه — ED_STUD_GROUP |
| مسح قبل كده؟ | لأ — سطر جديد كل مرة | أيوه — سطر واحد مهما مسح |
| الدكتور ده بيدرّس السكشن ده؟ | مفيش إصدار كود أصلاً | أيوه — SC_SCHEDULE_DTL_EXT_STF |
وفيه تفصيلة تستاهل تتحكي: القديم كان بيعمل استعلام مكافحة غش — بيدوّر على نفس الجهاز
(UDID) متسجّل لطالب تاني — وعمره ما بصّ في النتيجة. الاستعلام كان بيتنفّذ
وبيترمي. مش باج بيرمي exception، ده باج بيسكت.
قرار السيرفس بيرجّع الـ payload مش صورة
القديم كان بيرجّع JPEG فيه الكود مرسوم. إحنا بنرجّع الـ JSON نفسه، والرسم شغل الكلاينت.
السبب: الصورة مينفعش تتكاش، ومينفعش تتأكد منها في تست، ومينفعش الموبايل يغيّر حجمها أو لونها.
الديمو بيرسمها SVG بمكتبة qrcode-generator — كود حقيقي بيتقري بالكاميرا.
{"STUD_FACULTY_CODE":"70","saStaffMemberId":148,"STF_CODE":"70",
"SC_SCHEDULE_DTL_ID":1678,"SC_SCHEDULE_DTL_DAY_ID":2729,"ED_COURSE_ID_STAFF":6}تجربة حقيقية شغّلناها على الداتابيز
الجلسة المرجعية: سكشن 1678 / محاضرة 2729 / يوم الحد / الفصل المفتوح.
| الخطوة | النتيجة |
|---|---|
| عدد المسجّلين في السكشن | 27 |
| الدكتور عرض الكود | Ok — وQRCode_Log اتكتب |
| دكتور تاني حاول يعرض كود نفس السكشن | اترفض — مش بيدرّسها |
| طالب مسجّل مسح | تم تسجيل الحضور |
| مسح تاني | "حضورك مسجّل بالفعل" — وفضل سطر واحد |
| طالب مش في السكشن مسح | اترفض — "إنت مش مسجّل في السكشن ده" |
| مسح بعد ما المحاضرة خلصت | اترفض — الكود مابقاش صالح |
| الدكتور قفل المحاضرة | حاضر 1 · اتسجّل غياب 26 |
| اللي مسح اتسجّل غايب؟ | لأ — وده بيت القصيد |
مهم القفل مش بيشتغل قبل ما المحاضرة تخلص
إجراء المنتج نفسه فيه شرط GETDATE() > TO_TIME. يعني لو ناديت القفل والمحاضرة
لسه شغالة، هيرجّع 0 غياب — مش عطل، ده الإجراء بيرفض إنه يحكم على محاضرة لسه ما انتهتش.
وكمان بيتخطّى أيام الأجازات من GS_AGENDA_HOLIDAY.
جديد الطريقة التانية: الحضور بالموقع
الطالب بيدوس زرار، التطبيق بياخد إحداثيات الجهاز ويبعتها، والسيرفر بيرد: اتسجّل ولا لأ وليه. مش بديل للـ QR — الاتنين موجودين في نفس الشاشة والطالب يختار.
شغلك في التطبيق: 4 خطوات وخلاص
- اتأكد الخاصية مفتوحة أصلاً — من
Info/Capabilitiesاقراcampus.checkInEnabled. لوfalseماتعرضش الزرار من أوله. - اطلب إذن الموقع واقرا قراية جديدة (مش مخزّنة).
- ابعت 3 أرقام بس.
- اعرض رد السيرفر زي ما هو.
POST students/CheckInByLocation
Authorization: Bearer <token>
{ "ED_STUD_ID": 73, "LAT": 30.026, "LNG": 31.206, "ACC": 12 }ACC هي دقة القراية بالمتر اللي الجهاز نفسه بيديهالك
(accuracy / horizontalAccuracy). ابعتها زي ما هي — السيرفر بيستعملها
عشان يرفض القرايات الوحشة. لو مش عارفها ابعت 0.
مالكش دعوة بالمحاضرة. إنت مابتبعتش رقم مقرر ولا رقم محاضرة — السيرفر بيدوّر لوحده في جدول الطالب على المحاضرة الشغالة دلوقتي. ده معناه إن الزرار واحد في كل الشاشات، ومفيش حاجة تظبّطها قبل ما تبعت.
الرد لما يتسجّل
{
"result": "Ok",
"recorded": true,
"alreadyRecorded": false,
"presenceTime": "2026-08-09T14:09:27",
"session": { "COURSE_CODE": "SUR311", "COURSE_DESCR_AR": "العلاج الطبيعي للأورام",
"FROM_TIME": "...", "TO_TIME": "..." },
"location": "Main campus", "locationAr": "الحرم الرئيسي",
"distanceMeters": 0,
"messageAr": "تم تسجيل الحضور من الحرم الرئيسي"
}- اعرض
messageArزي ما هي، واسم المقرر منsession، والوقت منpresenceTime. alreadyRecorded: trueيعني ضغط تاني — ده مش error. اعرضله «حضورك مسجّل بالفعل» بنفس شكل النجاح.locationArللعرض في واجهة عربي، وlocationلو الواجهة إنجليزي.
الرد لما يترفض
{ "result": "ERROR",
"details": "إنت بره حرم الجامعة بحوالي 1639 متر — لازم تكون جوه عشان تسجّل حضورك" }خد بالك: الرفض بيرجع بـ HTTP 200 زي باقي الـ API القديم — الفرق في
result. وdetails رسالة جاهزة للطالب بالعربي: اعرضها زي ما هي،
ماتترجمهاش وماتحطش مكانها رسالة من عندك.
| الطالب شايف إيه | إنت تعمل إيه |
|---|---|
| «إنت بره حرم الجامعة بحوالي … متر» | اعرض الرسالة وسيب زرار «جرّب تاني». وممكن تفكّره بالـ QR كطريق تاني. |
| «إشارة الموقع ضعيفة (±… متر)» | قوله يطلع في مكان مفتوح ويجرّب. متعملش retry أوتوماتيك في لوب. |
| «مفيش محاضرة مسجّلة ليك في الوقت ده» | الزرار مش هيفيد دلوقتي — عادي، مش عطل. |
| «تسجيل الحضور بالموقع مش مفعّل في جامعتك» | يبقى ماكانش المفروض تعرض الزرار — راجع Capabilities. |
ماتعملش أي حساب في التطبيق. حدود الجامعة مابتوصلش للتطبيق خالص — وده مقصود: أي حاجة موجودة في الموبايل ممكن تتقري وتتغيّر. إنت بتبعت قراية، والسيرفر بيحكم. يعني مفيش مكتبة geofence ولا حسابات مسافات ولا تخزين للحدود عندك.
حاجات هتقابلك وإنت بتنفّذ
| الحاجة | التفاصيل |
|---|---|
| الأذونات |
iOS: NSLocationWhenInUseUsageDescription ·
Android: ACCESS_FINE_LOCATION.
الـ COARSE لوحده مش كفاية — دقته بالكيلومترات والسيرفر هيرفضها. |
| قراية جديدة | مش cached: maximumAge = 0،
دقة عالية (desiredAccuracy: best)، وtimeout حوالي 15 ثانية.
الأول قراية بتيجي وحشة وبعد ثانيتين بتتحسّن — استنى الكويسة. |
| المستخدم رفض الإذن | اعرضله إزاي يفتحها من الإعدادات، وسيبله الـ QR شغال — الطريقتين مستقلين. |
ويب / WebView على http |
المتصفح بيمنع الموقع خالص على أي origin مش https (ما عدا localhost)،
وبيرجّعها كأن المستخدم رافض. ده بالظبط اللي بيحصل على لينك الديمو. |
| التجربة | حط إحداثيات وهمية من الـ simulator (iOS: Features → Location → Custom) أو الـ emulator (Extended controls → Location) وجرّب من جوه ومن برّه. |
| ضغط مرتين | مش مشكلة — السيرفر مابيسجّلش مرتين وبيرجّع أول وقت. بس اقفل الزرار وقت الانتظار عشان الـ UX. |
| اتجرّب فعلًا على الداتابيز | النتيجة |
|---|---|
| من جوه الحدود والطالب عنده محاضرة شغالة | اتسجّل حضور في SUR311 — والسيرفر هو اللي اختار المحاضرة |
| ضغط تاني | «حضورك مسجّل بالفعل» — ومافيش تسجيل مكرر |
| من ميدان التحرير (1.6 كم) | اترفض — «إنت بره حرم الجامعة بحوالي 1639 متر» |
| قراية دقتها ±800 متر | اترفض — «إشارة الموقع ضعيفة» |
جديد الطريقة التالتة: الكشف اليدوي (شاشة دكتور)
الكود محتاج شاشة تعرضه، والموقع محتاج GPS كويس. الاتنين ممكن ما يكونوش متاحين — معمل، مستشفى، قاعة تحت الأرض. فالطريقة التالتة: الدكتور بيعلّم الكشف بنفسه، وهي الوحيدة اللي مش محتاجة أي حاجة.
الشاشة ماشية إزاي
- اعرض سكاشن الدكتور:
academicstaff/GetMySections— نداء واحد بيرجّع كل سكاشنه ومعاها الـ IDs ومواعيدها وعدد طلابها. - هو يدوس على سكشن ← الكشف يفتح على طول من
Staff/GetAbsenceDetails؛ كل اللي الإندبوينت ده محتاجه موجود في السطر اللي اتضغط عليه. - علّم محليًا — من غير أي نداء لكل ضغطة.
- احفظ الكشف كله في نداء واحد:
Staff/SaveAttendanceSheet.
ليه إندبوينت جديد ومش GetStaffSchedule؟ جدول الدكتور بيعرض نفس
القايمة بالظبط، بس كان تقرير من غير IDs (دلوقتي بيرجّع
SC_SCHEDULE_DTL_ID وmeetings[]، بس لسه مش مرتّب على مواعيد الكشف). GetMySections هو نفس القايمة بالـ IDs — وقبل كده كانت
الشاشة 3 قوايم و3 نداءات (مقرر ← سكشن ← محاضرة) قبل ما تقدر تطلب الكشف أصلاً.
POST academicstaff/GetMySections
{ } // أو { "EdCourseId": 6 } لمقرر واحد بس
{ "sections": [
{ "EdCourseId": 6, "CourseCode": "BAS103", "CourseDescrAr": "علم الأنسجة I",
"ScScheduleDtlId": 1678, "GroupDescrAr": "01", "Students": 27,
"Slots": [ { "ScScheduleDtlDayId": 2729, "DayAr": "الأحد", "DayEn": "Sunday",
"FromTime": "11:00", "ToTime": "13:00",
"TeachingAr": "محاضرة", "HallAr": "مدرج 2",
"LastApprovedDate": "2026-07-26T00:00:00" } ] } ] }رقم الدكتور بيتاخد من التوكن مش من الـ body، فمستحيل ترجع سكاشن حد تاني.
وSlots هي مواعيد السكشن في الأسبوع: السكشن اللي بيتقابل مرتين ليه موعدين،
والحضور بيتسجّل على الموعد مش على السكشن. فلما يدوس على سكشن، اختار الموعد اللي
DayEn بتاعه يساوي يوم التاريخ المختار — ولو مفيش، رجّع التاريخ لآخر مرة الموعد ده
حصل فيها.
افتح الكشف
POST Staff/GetAbsenceDetails
{ "EdCourseId": 6, "SC_SCHEDULE_DTL_ID": 1678, "ScTchngSlotId": 2729,
"AbsDate": "2026-08-09", "SortBy": 2 }الرد فيه data = قايمة الطلاب. اللي يهمك من كل سطر:
| الحقل | تعمل بيه إيه |
|---|---|
EdStudId | مفتاح السطر — هتبعته تاني وقت الحفظ. |
StudFullNameAr · StudCode | الاسم والرقم الجامعي. |
EdStudAbsenceId | لو مش فاضي يبقى الطالب متعلّم عليه غياب قبل كده. ابعته زي ما هو وقت الحفظ (لو فاضي ابعت 0). |
ExcuseFlag | بيفرّق بين «غائب» و«بعذر» في التعليم المحفوظ. |
StudAbsPrcnt · AbsWarnStatusId | نسبة غيابه، وعلامة تحذير لما يعدّي الحد (555 = تمام). |
الحالة الابتدائية لكل طالب: مافيش EdStudAbsenceId ← حاضر ·
فيه وExcuseFlag = 1 ← بعذر · فيه من غير عذر ← غائب.
تلات حالات وبس
حاضر · بعذر · غائب. مفيش «متأخر» — النظام مايعرفهاش أصلاً، فمتحطهاش في الـ UI. و«حاضر» معناها إلغاء الغياب مش حالة بتتخزن: لو الطالب كان متعلّم عليه غياب ورجّعته حاضر، الحفظ بيحذف الغياب.
احفظ
POST Staff/SaveAttendanceSheet
{ "ED_COURSE_ID": 6, "SC_SCHEDULE_DTL_ID": 1678, "SC_SCHEDULE_DTL_DAY_ID": 2729,
"ABS_DATE": "2026-08-09",
"MARKS": [
{ "ED_STUD_ID": 2122, "ED_STUD_ABSENCE_ID": 0, "STATE": "absent" },
{ "ED_STUD_ID": 3011, "ED_STUD_ABSENCE_ID": 0, "STATE": "excused" },
{ "ED_STUD_ID": 1830, "ED_STUD_ABSENCE_ID": 91350, "STATE": "present" }
] }STATE واحدة من: present · absent · excused.
ابعت كل الطلاب — السيرفر بيعرف لوحده مين اتغيّر ومين لأ.
{ "result":"Ok", "saved":2, "unchanged":1, "failed":0,
"isSaved": true, "errors": [], "messageAr": "تم حفظ الكشف" }failed > 0يعني حفظ جزئي:errorsفيهاEdStudId+ سبب لكل طالب مانفعش. علّم السطور دي بالأحمر بدل ما تقول «اتحفظ».- بعد الحفظ اقرا الكشف تاني. السطور الجديدة بقى ليها أرقام
(
EdStudAbsenceId) والنِسَب اتغيّرت — من غير إعادة قراءة، تاني حفظ هيبعت أرقام قديمة.
لو الكشف رجع فاضي — مش عطل
الجامعة عندها قواعد بتمنع فتح الكشف في حالات. الرد بيقولك السبب بـكود ثابت — اتعامل معاه بالكود، مش بمقارنة نص عربي هيتغيّر أول ما حد يحسّن الصياغة:
BlockedReason | تعمل إيه |
|---|---|
None + AutoApprovedDates فيها تواريخ |
الكشف فتح عادي، والخدمة اعتمدت المحاضرات المستنية قبل ما تفتحه. اعرض للدكتور إن ده حصل: «تم اعتماد ٣ محاضرات سابقة». |
PreviousLectureNotApproved |
(بيظهر بس لو الجامعة قافلة الاعتماد التلقائي) جنبه
PendingApprovalDate = تاريخ المحاضرة اللي لازم تتعمد الأول،
وPendingApprovalSlotId = السلوت اللي بيفتحها —
خد الاتنين مع بعض لما تفتحها.
وفيه PendingApprovals = السلسلة كلها من الأقدم للأحدث،
عشان تعرض «فيه ٤ محاضرات ناقصة» بدل ما تكتشفها واحدة واحدة. |
AlreadyApproved | اليوم اتقفل — اعرض للقراية بس. |
Holiday | أجازة رسمية. |
NotThisWeekday | التاريخ مش يوم المحاضرة — رجّعه للتاريخ الصح. |
None | الكشف مفتوح عادي. |
وMessageAr موجودة برضه للعرض المباشر، وLastApproveDate
بتقول آخر محاضرة اتعمدت.
الاعتماد ≠ الحفظ
Staff/ApproveAbsence زرار منفصل، وماتعرضهوش غير لما الرد يقول
AllowApprove: true. الحفظ بيعدّل الكشف، والاعتماد بيقفل اليوم ويخلّي
الغياب رسمي — فخليه فعل واضح ومقصود، مش جزء من زرار الحفظ.
سلسلة «اعتمد اللي قبلها» — بقت بتتحل لوحدها
دي كانت أكتر حاجة وقّفت الستاف: تعتمد محاضرة، يقول لك «اعتمد اللي قبلها»؛ تفتح اللي قبلها، يقول لك نفس الكلام على اللي قبلها؛ وهكذا — من غير ما حد يقولك السلسلة طولها كام ولا يدّيك طريقة تخلّصها في مرة واحدة. القاعدة نفسها صح (عشان محدش يملا الترم بأثر رجعي في آخر يوم)، بس هي قاعدة ترتيب — مش مشوار المفروض الدكتور يمشيه بإيده.
Approve the backlog automatically (مفتوح افتراضيًا في الـ
Client Profile) بيخلّي Staff/GetAbsenceDetails يعتمد المحاضرات المستنية
بالترتيب من الأقدم وبعدين يفتح كشف النهاردة عادي. كل واحدة بتعدّي على نفس الشيك بتاع
الـ SIS — مافيش قاعدة اتكسرت، اللي اتشال هو المشوار.
والرد بيرجّع
AutoApprovedDates — التواريخ اللي اتعمدت بالنيابة.
اعرضها: «تم اعتماد ٣ محاضرات سابقة». اعتماد محاضرة كلام على قاعة، والدكتور من حقه
يعرف إنه اتقال باسمه — وخصوصًا إن كشف فاضي معناه «محدش غاب».
ولو الجامعة قفلت الإعداد ده، بترجع الحالة الصارمة: الرفض بيوصل ومعاه السلسلة كلها، وانت اللي بتقرّر تعرضها إزاي:
| في الرد | معناه |
|---|---|
BlockedReason: "PreviousLectureNotApproved" |
الاعتماد اترفض — وIsSaved = false. |
PendingApprovals[] |
كل المحاضرات الواقفة في السكة، من الأقدم للأحدث. كل واحدة فيها
AbsDate وScTchngSlotId بتاعها هي (مش بتاع المحاضرة اللي انت
فيها) وMarked = عدد التعليمات المتسجّلة عليها. |
ApprovePrevious (في الطلب — اختيارية) |
ماتبعتهاش وهياخد إعداد الجامعة (الافتراضي: يعتمد السلسلة
وبعدين اليوم ده، نداء واحد). true = اعتمدها حتى لو الإعداد مقفول.
false = ماتعتمدش، رجّع لي السلسلة الأول. والرد بيرجّع
ApprovedDates[] باللي اتعمد فعلًا. |
ApprovePrevious: false؟
لما تكون عايز تسأل الدكتور الأول — «فيه ٤ محاضرات قبلها مش معتمدة، تعتمدهم كلهم؟».
وMarked = 0 على أي واحدة فيهم معناها كشفها فاضي، يعني اعتمادها بيقول
«محدش غاب» — ودي المعلومة اللي بتخلّي السؤال ده يستاهل يتسأل.
MOB_GetPervSectionDate والاعتماد بينده
GetPervSectionDate. بقى حساب واحد جوّه الخدمة، فالشاشة
والزرار مابقوش يختلفوا على أنهي محاضرة واقفة.
وكمان: المقارنة بقت على التاريخ مش على الـ datetime بحاله — صف اعتماد
متسجّل ومعاه وقت كان بيبقى موجود والشيك مش شايفه، يعني تعتمد المحاضرة وتفضل «مش معتمدة».
فيه كمان Staff/SetAbsence اللي بيحفظ طالب واحد — البوابة بتستعمله
كده. للموبايل استعمل SaveAttendanceSheet: 30 طالب = ريكوست واحد مش 30 على
شبكة قاعة محاضرات، ولو النت قطع في النص مش هتلاقي نص كشف متسجّل.
| اتجرّب فعلًا على الداتابيز | النتيجة |
|---|---|
| حفظ: واحد غائب، واحد بعذر، والباقي حاضر | saved 2 · unchanged 1 · failed 0 |
| إعادة قراءة الكشف | التعليم رجع زي ما هو والنسبة اتحدّثت لوحدها |
| رجّعنا الاتنين «حاضر» | الغياب اتحذف |
| تاريخ في المستقبل | اترفض — «لا يمكن الحفظ فى يوم مستقبلى» |
لغز اتحل ليه كشف الغياب كان بيرجع فاضي
Staff/GetAbsenceDetails كان بيرجّع كشف فاضي على سكشن فيها طلبة، وكان مفهوم إنه باج
في الكود. طلع مش باج — طلع تلات قواعد شغالة صح فوق بعض:
| القاعدة | الرسالة | معناها |
|---|---|---|
| المحاضرة السابقة لازم تكون معتمدة | المحاضرة السابقة غير معتمدة | مش هينفع تسجّل غياب النهاردة قبل ما تعتمد اللي فات — MOB_GetPervSectionDate. |
| ماينفعش تعتمد مرتين | تم الاعتماد مسبقا | اليوم اللي اتعمد اتقفل. |
| السكشن لازم تكون في الفصل المفتوح | — | السكشن اللي كنا بنجرّب عليها كانت بتاعة الفصل الأول والفصل المفتوح هو التاني، فدالة "المحاضرة السابقة" كانت بترجع تاريخ من يناير. غيّرنا الجلسة المرجعية لسكشن في الفصل المفتوح — الكشف رجع 26 طالب بأسمائهم والاعتماد مفتوح. |
الدرس: الكشف الفاضي هنا مش دايمًا باج. اقرا الرسالة اللي راجعة قبل ما تدوّر في الكود.
15 لما الإندبوينت يرجع فاضي — الداتا اللي لازم تكون موجودة
كان في 23 إندبوينت بيرجّعوا «شغال بس فاضي». دلوقتي كلهم بيرجّعوا داتا. الفصل ده بيقول لكل واحد فيهم ليه كان فاضي — لأن نفس السبب هيتكرر على أي داتابيز جديدة، والفرق بين «الإندبوينت باظ» و«الداتا مش متظبطة» هو أهم فرق هتحتاجه وانت بتجرّب.
أولاً أربع باجات حقيقية — كانوا بيرجّعوا نجاح فاضي
دول مكانوش بيرموا exception ولا بيرجّعوا رسالة غلط. كانوا بيرجّعوا result: Ok
وليستة فاضية — وعشان كده فضلوا متسجّلين في الدليل على إنهم «شغالين» شهور.
| الإندبوينت | السبب |
|---|---|
CourseReg/v2/MyCourses |
الهاندلر كان بيبعت 0 لفلتر حالة المقرر. الـ SQL كاتب «كل الحالات» كده:
@ED_CODE_COURSE_STATUS_ID IS NULL OR @… = <column> —
يعني 0 معناها «هات الصفوف اللي حالتها 0»، وده رقم مفيش صف بيحمله.
بقت NULL ← رجعت 8 مقررات.
|
CourseReg/RegisterNewCourse |
كان بيبعت الـ XML كنص عادي، فـ Dapper بيبعته nvarchar و SQL Server بيرفض
.nodes() عليه: «The XMLDT method 'nodes' can only be invoked on columns of
type xml». يعني التسجيل عمره ما اشتغل. بقى DbType.Xml.
|
students/GetSTudentTranscriptApi |
اتنين مع بعض: التقرير بيقرا @RegHeadFlg وعمره ما عرّفه، ونسخة
GetCourseRepeatFlg في الداتابيز دي بتاخد باراميتر تالت التقرير مش
بيبعته. الأولاني بقى NULL، والتاني بيتحل بنفس طريقة
ChkCrsInPlan: نسأل sys.parameters الداتابيز بتاخد كام
باراميتر ونكمّل — من غير ما نلمس الفانكشن.
|
ثانياً سويتشات الإدارة — الداتا موجودة بس مقفولة
| الإندبوينت | اللي كان ناقص |
|---|---|
students/GetExamSchdule |
جدول الامتحانات كان موجود (133 صف) بس ED_OFFERING.IS_EXAM_APPROVED كان 1 من 12، والطالب مكانش موزّع على لجنة في CO_EXAM_PLACE_STUD. الاتنين اتظبطوا ← 8 امتحانات بالقاعات. |
Survey/* (٤ إندبوينت) |
مكانش في ولا استبيان مربوط بمقررات الطالب. اتعمل تقييم لكل مقرر من مقرراته بنفس الـ 40 سؤال بتوع الاستبيان الموجود، واتفتحت فترة التقييم (PUB_FLG + EVAL_DATE/EVAL_DUE_DATE). |
CourseReg/v2/AvailableCourses |
فترة التسجيل في أجندة الفصل كانت قافلة من 2026-07-30. الإندبوينت كان بيقول كده صراحةً: «التسجيل غير متاح حاليا» — رد صح مش عطل. |
students/schedulePerday |
SC_SCHEDULE_DTL_Date كان فاضي تمامًا، والاستعلام بيشترط إن النهاردة يقع جوّه المدى ده. اتحطّ مدى الفصل لكل سكشن ← رجعت محاضرات النهارده. |
academicstaff/GetStaffSchedule |
التقرير بينتهي بـ WHERE SC_SECTION_GROUP_HDR.IS_ACTIVE = 1 على جدول
مربوط بـ LEFT JOIN — وده بيحوّل الـ LEFT لـ INNER في صمت. أي سكشن مش متربطة
بمجموعة سكاشن مفعّلة بتختفي من التقرير خالص.
اتصلّح في الكود: السكشن بتتشال بس لو المجموعة بتاعتها متوقفة، والتكرار (36 صف لـ 12 سكشن) اتلمّ.
|
students/GetSTudentTranscriptApi |
محتاج كمان ED_STUD_SEMESTER.RESULT_APPROVE_FLG = 1 — يعني نتيجة الفصل معتمدة، وده شرط عشان السجل الأكاديمي يطلع رسمي. |
Files/UserImages/{name} |
بيخدم ملف من على الديسك. الفولدر كان فاضي، فالرد الوحيد الممكن كان 404. |
ثالثاً باراميتر غلط في الدليل نفسه — مش في الكود
دي أسهل حاجة تضيّع وقتك: الإندبوينت شغال تمام، بس البودي اللي بتبعته مش بيوصل.
| الإندبوينت | الغلط | الصح |
|---|---|---|
CourseReg/v2/MyCourses | EdStudId: 73 |
ED_STUD_ID: "73" — نص. الرقم بيتقري 0 في صمت ويطلع «مفيش فصل نشط». |
Survey/GetSurveyByCourse | ED_COURSE_ID | EdCourseId |
students/GetStudentQRCode | اسم الدخول | بقى بياخد الاتنين — اسم الدخول أو الكود الجامعي، وكمان بودي فاضي (بيقرا صاحب التوكن). الرد صورة PNG مش JSON. |
students/GetSTudentTranscriptApi | POST | GET بـ query string |
| إندبوينتات الدكتور | saStaffMemberId: 31 | 148 — حساب atef.dahesh هو اللي عليه داتا |
401 التوكن بيخلص بعد ٢٤ ساعة
عشان ده مايحصلش تاني، كوليكشن الـ Postman فيه سكريبت قبل كل ريكويست بيبص على تاريخ
انتهاء التوكن، ولو خلص (أو قرّب يخلص بدقيقة) بيعمل لوجين لوحده ويجدّد
token وstaffToken. يعني مش محتاج تفتكر تشغّل اللوجين.
ولو بتجرّب من غير Postman: التوكن الفاضي والتوكن المنتهي والتوكن الغلط — كلهم 401.
مهم جدًا رفض القاعدة بييجي كـ result: ERROR
لما الـ SIS يرفض عملية لسبب شغلاني — «عندك طلب خزانة مفتوح بالفعل»، «الكود ده مش بتاع
النهاردة»، «عندك حجز في النشاط ده» — الرد بييجي result: ERROR ومعاه
جملة مفهومة للمستخدم في details.
ده المنتج شغال صح، مش عطل. التطبيق لازم يعرض الجملة دي زي ما هي بدل ما يقول
«حصل خطأ غير متوقع».
| الرد | يعني إيه |
|---|---|
result: "Ok" | تمام |
جملة نجاح في result |
نجاح كمان. Questions/AddQuestion بيرجّع
«Success New Question has been Added». لو بتتأكد من result === 'Ok' بس، هتقراها غلط |
result: "ERROR" + جملة عربي/إنجليزي مفهومة |
قاعدة رفضت. اعرض الجملة للمستخدم |
result: "ERROR" + «An unexpected error occurred» |
ده اللي يستاهل تبلّغ عنه |
details: "data not found" |
مفيش نتايج — غالبًا باراميتر ناقص مش عطل |
تحقق شامل كل الإندبوينتات اتشغّلت فعلاً
الجدول ده مش تقدير — اتولّد من تشغيل كل إندبوينت في الدليل، كل واحد بالحساب المكتوب جنبه، على السيرفر المنشور.
| الحالة المكتوبة | اللي رجع فعلاً |
|---|---|
| شغال (87) | 75 رجّعوا داتا · 2 رجّعوا صورة · 7 رفضتهم قاعدة شغلانية (رد صح) ·
3 عمليات كتابة مالهاش ريسبونس (SaveToken، AddQuestion، AddAnswer) |
| Sandbox (7) | كلهم رجّعوا داتا من البوابة المزيّفة |
| محتاج بيانات (4) | كل واحد بيقول بالظبط الناقص إيه |
| مقفول (1) | تقرير خطة KU — بيقول إنه مش متاح على التركيب ده |
| مش موجود (9) | لسه متعملوش — مستنيين الجامعة |
401 وصفر إندبوينت مكتوب «شغال» ورجع فاضي.
لو لقيت واحد بيخالف الجدول ده، ابدأ بالتوكن وبالحساب — الاتنين دول سبب أغلب المفاجآت.
سكاشن فاضية sections: [] — سببين مختلفين تمامًا
الموبايل تيم لقوا GetNewCourses بيرجّع مقرر ومعاه sections: [].
مقرر تقدر تسجّله من غير سكشن تختارها — ده مالوش معنى. طلعوا سببين، واحد اتصلّح والتاني
حدود داتا.
| السبب | التفاصيل |
|---|---|
| عدّاد المقاعد بايظ اتصلّح |
SC_SCHEDULE_DTL.NO_STUDENTS عدّاد بيتحدّث مع كل تسجيل، وكان
مايتحدّثش — فـكل سكاشن الفصل المفتوح (565) كانت قارية «مليانة»،
والاستعلام بيستبعد المليان. اتحسب من الحقيقة (ED_STUD_GROUP):
484 سكشن اتصلّحت، و480 بقى فيها أماكن.
|
| خطة الكلية ناقصة حدود داتا |
حتى بعد التصليح، طلبة العلاج الطبيعي (كلية 1) لسه بيرجّعوا سكاشن فاضية لأي مقرر، وطلبة الهندسة (كلية 6) بيرجّعوا تمام: 6 مقررات و18 سكشن. يعني الإندبوينت سليم — خطة/حزم كلية 1 في الداتابيز دي مش بتوصل لسكاشن. (استبعدنا: السعة، النوع، حجز السكاشن، فلاجات السكشن، سنة الحزمة، ومجموعات السكاشن.) |
ED_OFFERING.IS_APPROVED = 0)،
وMOB_GET_STD_CRS_REG_PLN_SEC مابيشوفش سكشن إلا لو عرضها معتمد.
اعتمدنا الجداول (٥ عروض)، وفتحنا السكاشن المبنية أصلاً للتسجيل الذاتي
(ONLINE_FLG = 1 — الطالب مابيشوفش غيرها)، فبقى عند الطالب
٣٠ مقرر من خطته و١٢٩ سكشن.
يعني كل الشاشات دلوقتي بتشتغل بحساب واحد:
mahmoued.eprahim.23010062 — وده الحساب اللي الديمو كله ماشي عليه.
القاعدة اقرا الرسالة قبل ما تدوّر في الكود
الـ SIS بيتكلم. «التسجيل غير متاح حاليا»، «المحاضرة السابقة غير معتمدة»، «تم الاعتماد مسبقا»، «Student has no active semester» — كل واحدة فيهم قاعدة شغالة صح، مش باج. الحاجات اللي كانت محتاجة إصلاح فعلي كانت هي بالظبط اللي ماقالتش حاجة ورجّعت ليستة فاضية.
16 بعد اللوجين — إزاي تعرف الشاشات والخصائص المسموحة؟
السؤال ده بيتسأل كتير وكانت إجابته ناقصة: auth/login بيقول لك مين ده،
وInfo/Capabilities بيقول لك الجامعة اشترت إيه — لكن ولا واحد فيهم كان بيقول
الشخص ده بالذات يشوف أنهي شاشات. فكل تطبيق كان بيكتب خريطة أدوار عنده،
والخرايط دي بتفرق عن السيرفس مع الوقت. دلوقتي في نداء واحد بيجاوب.
نداءين الترتيب الصح بعد الدخول
| # | النداء | بيجاوب على |
|---|---|---|
| 1 | POST auth/login |
مين ده؟ الرد فيه IsStudent + التوكن.
true ← مسار الطالب · false ← مسار عضو هيئة التدريس. |
| 2 | POST auth/me جديد |
وده يشوف إيه؟ بالتوكن. بيرجّع home اللي تفتحها،
وscreens[] كل شاشة ومعاها allowed،
وfeatures[] المتعلقة بالدور ده بس.
|
ماتسألش المستخدم هو مين. مفيش «انت طالب ولا دكتور؟» في شاشة الدخول — دي حاجة السيرفس صاحب الإجابة فيها، والمستخدم مالوش إنه يدّعي دور. وكمان ماتبنيش خريطة أدوار في التطبيق: أي خريطة عندك هي نسخة، والنسخ بتفرق عن الأصل.
الرد شكل auth/me
{
"result": "Ok",
"isStudent": true,
"role": "student",
"home": "home", // ← افتح دي بعد اللوجين
"allowedScreens": ["home","schedule","courses", ...],
"screens": [
{ "key":"grades", "titleAr":"نتيجة الفصل", "audience":"Student",
"feature": null, "allowed": true, "reason": null },
{ "key":"payments", "titleAr":"الرسوم والمدفوعات", "audience":"Student",
"feature":"payments", "allowed": false, "reason":"FeatureBlocked" },
{ "key":"staff-grades","titleAr":"رصد الدرجات", "audience":"Staff",
"feature":"staffGradeEntry", "allowed": false, "reason":"OtherRole" }
],
"features": [ { "key":"surveys", "status":"Active", "available":true, "audience":"Student" }, ... ]
}reason | يعني إيه | تعمل إيه في التطبيق |
|---|---|---|
null | مسموحة | اعرضها عادي |
OtherRole | الشاشة بتاعة الطرف التاني | ماتعرضهاش خالص — مش موجودة في تطبيق الشخص ده |
FeatureDisabled | الجامعة قافلة الخاصية دي | اخفيها — مش مشتراة/مش مفعّلة |
FeatureBlocked | مفعّلة بس ناقصها إعدادات أو دعم من الداتابيز | اخفيها كمان. السبب التفصيلي للأدمن مش للتطبيق |
لاحظ الفرق بين OtherRole وFeatureDisabled: الأولانية معناها
مش بتاعتك أصلاً، والتانية معناها بتاعتك بس مقفولة. لو خلطتهم، هتقول لطالب
«الخاصية دي مقفولة» عن شاشة أصلاً مالهاش أي معنى بالنسبة له.
مثال حقيقي نفس النداء بحسابين مختلفين
طالب — mahmoued.eprahim.23010062 | دكتور — atef.dahesh | |
|---|---|---|
home | home | staff-home |
| شاشات مسموحة | 27 من 32 | 8 من 32 |
| خصائص ظاهرة له | 31 | 9 |
OtherRole |
staff-home · staff-courses · staff-advisees · staff-qr · staff-grades | كل شاشات الطالب |
FeatureBlocked |
بيتغيّر من تركيب لتركيب. الأرقام فوق من سيرفر التجربة. على تركيب ناقصه بيانات
الدفع أو الـ push مثلاً، شاشات زي payments وnotifications
بترجع FeatureBlocked والعدد بيقل. وده بالظبط سبب وجود النداء ده —
ماتفترضش رقم، اسأل.
| |
الدكتور بيشوف 9 خصائص مش 31 — لأن اللي مش بتاعته مابيتبعتلوش أصلاً. رصد الدرجات مش «خاصية مقفولة» عند الطالب، هي مش خاصية بتاعته.
ليه كده ده نفس اللي البوابة بتعمله
الـ SIS نفسه بيحل نفس المشكلة بنفس الطريقة: صفوف SE_FORM مربوطة بـ
SE_CODE_USER_TYPE_ID، فمنيو البوابة جاي من السيرفر مش متكتب في الصفحات.
auth/me هو نفس الفكرة للموبايل — قايمة الشاشات داتا، مش حاجة كل كلاينت
يخترعها لوحده. لو الجامعة قفلت خاصية بكرة، التطبيق بيعرف من غير نسخة جديدة.
وInfo/Capabilities؟ لسه ليه دور — بس دور تاني
Info/Capabilities | auth/me | |
|---|---|---|
| محتاج توكن؟ | لأ — بيتنادى قبل شاشة الدخول | أيوه |
| بيعرف مين بيسأل؟ | لأ | أيوه |
| بيرجّع إيه | التركيب: العميل، الـ sandbox، بوابة الدفع، وحالة كل الخصائص | الشاشات والخصائص بتاعة الشخص ده |
| استخدمه لـ | بانر «بيانات تجريبية»، وشكل شاشة الدخول (SSO ظاهر ولا لأ) | المنيو، الـ tabs، والراوتر بعد الدخول |
الخلاصة تلات سطور تحطهم في التطبيق
const login = await post('auth/login', { UserName, Password }); // مين ده
const me = await post('auth/me', {}, login.token.data); // يشوف إيه
open(me.home); // افتح رئيسيته
// وبعد كده، قبل ما تعرض أي شاشة:
const s = me.screens.find(x => x.key === target);
if (!s || !s.allowed) return; // reason بيقولك ليهauth/me. اللي بيتحكم فعليًا هو رد السيرفس.
17 التسجيل — الحكاية من الأول
ده الفصل اللي تقعد تقراه قبل ما تبدأ تبني. مافيش فيه أسماء جداول ولا استعلامات — فيه إيه اللي بيحصل، وبأي ترتيب، والرد بيقولك إيه، وانت تعمل بيه إيه.
الفكرة إحنا بنسجّل إيه بالظبط؟
خد بالك من الحتة دي لأن الفصل كله مبني عليها: الطالب مابيتسجّلش في «مقرر». الطالب بيتسجّل في سكشن من المقرر.
المقرر هو «العلاج الطبيعي للجراحة». السكشن هو الميعاد والمكان والدكتور — «LEC1 يوم السبت ٢:٠٠ إلى ٣:٠٠». المقرر ممكن يكون ليه عشر سكاشن، والطالب بياخد واحد.
وفيه حاجة تانية: مقرر واحد ممكن يحتاج أكتر من سكشن في نفس الوقت. مقرر عملي زي
SUR310 بيتدرّس محاضرة + عملي + إكلينيكي — تلات مواعيد مختلفة،
والطالب لازم يبقى في تلات سكاشن عشان يبقى مسجّل فيه صح.
ماتفكّرش أبدًا إن مقرر = سكشن واحد.
١ رحلة التسجيل — أربع خطوات بالترتيب
الخطوة صفر: هو أصلاً مسموح له يسجّل النهاردة؟
قبل ما تجيب أي داتا، اسأل السؤال ده. مواعيد التسجيل في الـ SIS اسمها أجندة الفصل، وبتختلف من كلية لكلية ومن فصل لفصل — فماينفعش التطبيق يحفظ تواريخ.
Agenda فيها خمس نوافذ: Register · Add · Drop · Withdraw · RegisterSection — كل واحدة true/false. ومعاها MaxCreditHours وCurrentCreditHours.Agenda.AnyOpen = false اعرض رسالة واحدة «مفيش تسجيل دلوقتي»
وخلاص — أحسن من خمس أزرار رمادية.
وفيه فلاج مهم:
Agenda.IsActiveStudent. لو false يبقى الطالب
موقوف مالياً — وساعتها مفيش أي عملية تنفع مهما كانت النوافذ مفتوحة.
الخطوة الأولى: المقررات اللي مسموح له بيها
Courses[] — مش كل مقررات الجامعة، دي المقررات اللي خطة الطالب بتسمح له بيها الفصل ده.الـ SIS بيعمل الفلترة دي بنفسه: مستوى الطالب، خطته، اللي نجح فيه، اللي رسب فيه ولازم يعيده. انت مش هتفلتر حاجة.
GetNewCourses بيرجّع المقررات اللي خطة الطالب لسه فيها مكان
ليها ومتاحة بسكاشن الترم ده. الاتنين مع بعض. فالقايمة بتبقى فاضية في تلات حالات
كلها سليمة:
| الحالة | تعرفها إزاي | تعرض للطالب |
|---|---|---|
| خلّص خطته | طالب متقدّم خد أغلب مقررات خطته، واللي فاضل مش متاح الترم ده | «مفيش مقررات زيادة متاحة على خطتك دلوقتي» |
| وصل سقف الساعات | CurrentCreditHours قرّبت من
MaxCreditHours |
«وصلت الحد الأقصى — اسقط مقرر الأول» |
| الأجندة مقفولة | Agenda.Register وAdd الاتنين
false |
«فترة التسجيل مقفولة» |
GetAllowedActions الأول — منها تعرف أنهي حالة من التلاتة،
وتعرض رسالة تفرق، بدل «مفيش مقررات» اللي مابتقولش للطالب يعمل إيه.
الحساب اللي باقي الدليل شغّال بيه (
mahmoued.eprahim.23010062)
طالب سنة متقدمة: خد ٤٩ من ٧٩ مقرر في خطته، واللي فاضل مفيش منه حاجة
معروضة الترم ده — يعني قايمة التسجيل بتاعته فاضية بحق وحقيق، والباقي كله شغّال عليه.
عشان كده فولدرات التسجيل في الكوليكشن بتدخل بحساب تاني:
menna.elsayed.25010015 — عنده ٥ مقررات مسجّلة و٢٧ متاح
و14/21 ساعة، يعني الدورة كاملة تمشي عليه.
نفس الباسورد، ومتغيّر regUserName في الكوليكشن هو اللي بيحدّده.
prereqProblem. لو فاضية يبقى تمام.
لو فيها كلام، ده سبب مانع جاي من الـ SIS نفسه — يعني المقرر باين في القايمة
بس فيه مشكلة تمنع التسجيل.
وماتعرضش النص ده للطالب — هو مفتاح داخلي زي
ExamCourseConfilict. الترجمة اللي تعرضها موجودة في
flags.BlockedReason على السكشن (جدول الرسايل في آخر الفصل).
الخطوة التانية: سكاشن المقرر
السكاشن جايّة جوّه نفس الرد — مش محتاج نداء تاني. كل مقرر جوّاه
sections[]، وكل سكشن جوّاه flags.
Courses[] → {
ED_COURSE_ID, COURSE_CODE, COURSE_DESCR_AR, CREDIT_HOURS,
prereqProblem,
sections: [ {
SC_SCHEDULE_DTL_ID, ← ده اللي هتبعته وانت بتسجّل
GROUP_ORDER_DESCR_EN, ← اسم السكشن: "LEC1"
TCHNG_AR, ← طريقة التدريس: "محاضرة"
Dayes, FROM_TIME, TO_TIME, ← الميعاد
NO_STUDENTS, NO_STUD_WAIT, ← السعة وسعة الانتظار
IS_CLOSED, WAITLIST_FLG,
flags: { … } ← القرار جاهز
} ]
}الخطوة التالتة: حالات السكشن — دي أهم حتة في الفصل
السكشن مالوش «حالة» واحدة مكتوبة في فيلد. الحالة بتتقري من مجموعة فلاجز، والفلاجز دي الخدمة حسبتها لك. بص على الجدول ده وانت بتبني الكارت:
| الحالة | بتعرفها إزاي | تعرض إيه | الزرار |
|---|---|---|---|
| ✅ فاضي ومتاح | flags.CanRegister = true |
الميعاد + SeatsLeft «فاضل ٣٠ مكان» |
«سجّل» |
| 🎟️ مليان بس فيه طابور | flags.CanAddSeat = true( IsFull وWaitLeft > 0) |
«مليان — فاضل WaitLeft مكان في الانتظار» |
«احجز مقعد» |
| 🚫 مليان وخلاص | IsFull = true وWaitLeft = 0 |
«مليان» — رمادي | مفيش |
| ⏰ متعارض | HasClash أو HasExamClash |
«بيتعارض مع محاضرة تانية» | مفيش |
| 🔒 مقفول | IsClosed = true |
«مقفول من الكلية» | مفيش |
CanRegister وCanAddSeat
عمرهم ما بيبقوا true مع بعض. واحد منهم بس هو اللي شغّال —
فالكارت بيرسم زرار واحد، مش اتنين.
ولو الاتنين
false، بص على flags.BlockedReason
واعرضه. ماترمّدش الزرار وتسكت.
SeatsLeft = -1 مش معناها صفر، معناها
السكشن من غير سقف أصلاً (بياخد أي عدد). اعرضها «مفتوح» مش «فاضل -1 مكان».
نفس الكلام على WaitLeft = -1.
الخطوة الرابعة: سجّل — وبعدين اتأكد
Status: true — أو false ومعاه Error بالسبب.ScScheduleDtlId دايمًا.
من غيره الطالب هيتسجّل في المقرر ومش هيبقى في أي سكشن — يعني مالوش ميعاد ولا
هيظهر في جدوله. دي الحالة اللي اتكلمنا عنها فوق، بس حصلت بالغلط.
Courses[] — لازم تلاقيه بـ ED_CODE_COURSE_STATUS_ID = 1 وsections[] مش فاضية.true ومابتظهرش في القايمة هي أخطر عطل ممكن —
مافيش فرق بينها وبين النجاح وقت النداء، وماتبانش غير لما الطالب يقول
«أنا سجّلت ومش لاقي المقرر». اقرا بعد كل كتابة.
٢ المقرر اللي ليه أكتر من طريقة تدريس
خد SUR310 من الديمو. الطالب مسجّل فيه بـ تلات سكاشن:
SUR310 → sections: [
{ GROUP_DESCR_EN: "LEC", TCHNG_AR: "محاضرة" }
{ GROUP_DESCR_EN: "SEC 1", TCHNG_AR: "عملى" }
{ GROUP_DESCR_EN: "HOSPITAL 1", TCHNG_AR: "اكلينكى" }
]ده الطبيعي مش استثناء — ٤٨٪ من التسجيلات في الداتابيز فيها أكتر من سكشن. وبيترتّب عليه تلات حاجات في الشاشة:
- اعرض السكاشن التلاتة تحت المقرر، وكل واحد باسم طريقة تدريسه
(
TCHNG_AR) — مش رقم لوحده. - زرار «حذف» لكل سكشن، مش زرار واحد للمقرر. لو بعتّ المقرر لوحده، الخدمة هي اللي تختار — وغالبًا مش اللي الطالب دوس عليه.
- «غيّر السكشن» بيبدّل زي بزي: المحاضرة بمحاضرة والعملي بعملي.
الخدمة بترجّع لك المرشّحين من نفس النوع بس — وكل مرشّح كاتب
ReplacesEdStudGroupIdيعني هيقف مكان أنهي سكشن بالظبط.
وكل سكشن بيجيلك ومعاه ميعاده ومكانه
«إنت في SEC 1» معلومة ناقصة. الطالب فاتح الشاشة عشان يعرف إمتى وفين.
عشان كده كل سكشن في sections[] بيجي ومعاه:
sections[] → {
GROUP_DESCR_EN: "SEC 1", DESCR_AR: "عملى",
DaysAr / DaysEn: "الأحد" ← اليوم (أو الأيام)
FromTime / ToTime: "11:00" / "13:00" ← أول بداية وآخر نهاية
HallAr / HallEn: "معمل 107" ← القاعة
BuildingAr / …: "مبني كلية العلاج الطبيعي" ← المبنى
CampusAr / …: "الحرم الجامعى" ← الفرع
meetings: [ … ] ← التفصيل يوم بيوم
}meetings ومعاها ملخّص فوقيها؟
لأن السكشن بيتقابل أكتر من مرة في الأسبوع، والمرات دي مش زي بعض —
المعمل ممكن يكون في قاعة مختلفة ومبنى مختلف كل يوم.
· في صف القايمة اعرض الملخّص (
DaysAr + الميعاد + القاعة) — سطر واحد يكفي.
· في شاشة التفاصيل لُفّ على
meetings واعرض كل يوم بقاعته.
والملخّص أمين: لو السكشن في أكتر من قاعة،
HallAr بيرجّعهم كلهم
مفصولين بفاصلة — مش بيختار واحدة ويسكت.
BSM131 سكشن 01 بيتقابل يومين:
السبت ٩:٠٠–١٠:٤٠ والأربعاء ١١:٠٠–١٣:٠٠، الاتنين في
Lecture hall E1.1 بمبنى الهندسة.
فالملخّص بيقول «السبت، الأربعاء · 09:00–13:00» —
وmeetings فيها السطرين بالظبط.
null وmeetings بتبقى
[] — يعني ماتشيكش على وجود الحقل، شيك على قيمته.
واعرض «الميعاد لسه متحطّش» بدل ما تسيب الصف فاضي.
٣ حذف سكشن — مش إسقاط المقرر
دي أكتر واحدة بيحصل فيها لبس، فخليني أقولها بالبلدي: حذف السكشن بيحذف الميعاد، والمقرر بيفضل مسجّل.
EdStudGroupId بتاع السكشن اللي الطالب دوس عليه — جايلك في sections[].ED_STUD_GROUP_ID. والرد بيقولك الفراغ اللي عمله: NeedsSection، وMissingTeachingMethod (محاضرة؟ عملي؟)، وNextAction فيها النداء الجاي جاهز.Mode: "PICK".Action: ADDED · REPLACED · UNCHANGED (كان فيها أصلاً).CourseReg/SetSection بنفس الـ body، والفرق فضل
في الكلام بس (Mode بيقولك تكتب «انقل هنا» ولا «خد السكشن ده»).
ReplaceSection وAddSection لسه شغّالين
وبنفس الـ contract — بس بقوا نفس النداء، فمابقاش فيه واحد فيهم بيرفض نص الشغلانة اللي
بتاعة التاني.
وبعد خطوة ١ الطالب بيبقى في الحالة اللي قلنا عليها في الأول: مسجّل في المقرر ومن غير ميعاد. وده اللي لازم تعرضه:
| اللي بيرجع | يعني إيه | تعرض إيه |
|---|---|---|
NeedsSection: true | ناقصه سكشن من نوع معيّن | علامة «من غير سكشن محاضرة» + زرار «اختار سكشن» |
MissingTeachingMethod | النوع الناقص وكام مرشّح ليه | سمّي النوع في الرسالة — «اختار محاضرة تاني» |
RemainingSections: 0 | مفيش ولا ميعاد خالص | علامة «من غير سكشن» على صف المقرر |
flags.CanDrop: true | المقرر لسه مسجّل | «أسقط المقرر» يفضل ظاهر كمان |
v2/MyCourses بقى بيدّي على كل مقرر
needsSection وmissingTeachingMethods،
والـ actions فيها pickSection جاهز.
ودي بتشتغل كمان على المقرر اللي ليه محاضرة وعملي واتحذف العملي بس —
لسه عنده سكشن، وبرضو ناقص.
٤ أسقط المقرر (Drop) — ومعناه إيه
الإسقاط معناه: المقرر بيتلغي من فصل الطالب، وساعاته بترجع له فيقدر يسجّل غيره. بس فيه حتة مهمة: المقرر مابيتمسحش — بيتعلّم عليه إنه «مسقَط».
flags.CanDrop = true — يعني نافذة الإسقاط مفتوحة والمقرر نشط.flags.IsDropped = true وED_CODE_COURSE_STATUS_ID = 6.وفي رسالة التأكيد قبل الإسقاط، قول للطالب إنه بيترجع. ده بيريّحه، وبيمنع سؤال الدعم الفني اللي بييجي بعد كده على طول.
٥ التراجع عن الإسقاط — ومنين بتجيبه
سؤالك: «الطالب لو حب يرجّعه بيجيبه منين؟» الإجابة: مش من قايمة المتاح للتسجيل.
GetNewCourses.
استعلام الخطة بيستبعد أي مقرر ليه تسجيل في الفصل ده مهما كانت حالته.
فلو التطبيق حاول يسجّله من جديد، مش هيلاقيه أصلاً.
الطريق الوحيد هو التراجع، وبتلاقيه في نفس قايمة مقرراتي.
إزاي تعرف إن المقرر ينفع يرجع؟ من الفلاج:
flags.CanUnDrop = true — دي المقررات اللي تقدر ترجّعها. (بتبقى true لما نافذة الإضافة تكون مفتوحة والمقرر حالته مسقَطة.)flags اللي اتعوّدت عليها.IsDropped = false وفي سكشن.٦ غيّر السكشن — نفس المقرر، ميعاد تاني
الطالب مسجّل في المقرر ومبسوط، بس الميعاد مش مناسبه. مش عايز يسيب المقرر، عايز يقعد في سكشن تاني من نفس المقرر.
وهنا فيه سؤالين مختلفين، وخد بالك من الفرق لأنه بيلخبط: «هل ينفع أغيّر أصلاً؟» غير «أغيّر لأنهي سكشن؟». الأول بيتجاوب من فلاج على المقرر، والتاني محتاج نداء لوحده.
flags.CanReplaceSection = true هو اللي ينفع. ومعاه alternativeSectionCount — فيه كام سكشن بديل.EdStudGroupId بتاع السكشن اللي الطالب دوس عليه. الرد بييجي مقسّم على أربع قوايم جاهزة + Summary بالأعداد.| القايمة | معناها | الزرار المناسب |
|---|---|---|
Sections |
فاضي ومفيهوش تعارض — تقدر تروح له دلوقتي | «انقل هنا» |
WaitListSections |
مليان بس الطابور مفتوح | «احجز مقعد» |
ConflictingSections |
فيه مكان، بس بيتعارض مع محاضرة تانية في جدوله | «شوف التعارض» |
FullSections |
مليان ومفيش انتظار | رمادي، من غير زرار |
Summary.Available = طول Sections بالظبط،
وTotal = مجموع الأربعة. فتقدر تكتب «فيه ٢ متاحين و٣ متعارضين»
من Summary على طول من غير ما تلف على المصفوفات.
Mode.
REPLACE = الطالب عنده سكشن من النوع ده والصف ده يقف مكانه («انقل هنا»)،
وPICK = مالوش سكشن من النوع ده خالص («خد السكشن ده»).
الفرق في الكلام بس — النداء واحد:
CourseReg/SetSection، والـ actions بتاعة الصف
جايالك بيه وبالـ Body جاهز.
وفوق القوايم فيه
NeedsSection وMissingTeachingMethods:
لو true، العنوان اللي الخدمة بترجّعه بيبقى «اختار سكشن» بدل
«انقل لسكشن تاني» — اعرضه زي ما هو.
التعارض بيجيلك باسم صاحبه — دي أهم حتة
لما سكشن يبقى متعارض، الرد مابيقولكش «متعارض» وخلاص. بيقولك متعارض مع مين:
"Conflict": {
"Type": "TIME_CLASH",
"WithCourseCode": "BSM131", ← المقرر اللي بيتعارض معاه
"WithSectionNameEn": "01", ← وسكشنه
"WithDaysAr": "الأربعاء, السبت",
"WithFromTime": "09:00",
"WithToTime": "13:00",
"WithEdStudGroupId": 135172, ← سكشن الطالب نفسه في المقرر ده
"CanResolve": true ← يعني هو يقدر يحلّها بنفسه
}
يعني الرسالة اللي تعرضها مش «مينفعش». الرسالة هي:
«السكشن ده بيتعارض مع محاضرة BSM131 يوم الأربعاء ٩–١»،
وجنبها زرار «روح احذف سكشن BSM131» —
وWithEdStudGroupId هو الرقم اللي هتبعته.
الطالب يحلّها ويرجع يكمّل. ده الفرق بين رسالة خطأ ورسالة فيها حل.
CanResolve هو اللي بيقرّر تعرض الزرار ولا لأ.
true = التعارض مع حاجة الطالب مسجّل فيها فيقدر يحلّها.
false = حاجة مالوش فيها يد، اعرض السبب وبس من غير ما توعده بحل.
EdStudGroupId اختياري ومالوش لازمة غير في حالة واحدة: مقرر الطالب فيه أكتر من سكشن من نفس النوع. والرد بيقول Action: "REPLACED".Conflict — فاعرضه بنفس شاشتك، مش برسالة «حصل خطأ».
CanReplace: false؟
الـ Reason بيقول ليه، وكل واحد فيهم رسالة مختلفة للطالب:
NO_ALTERNATIVE (مفيش سكشن تاني من نوعه) ·
ALL_FULL (فيه بدايل بس كلها مليانة) ·
ALL_CONFLICT (كلها متعارضة — وده اللي ينفع يعمله حاجة) ·
NONE_AVAILABLE (خليط) ·
GROUPED_REGISTRATION (السكشن مربوط بمجموعة، التغيير من شؤون التسجيل).
التلاتة الأولانيين دول كانوا كلهم قايمة فاضية قبل كده — والطالب ماكانش يعرف يستنى ولا يفضّي جدوله ولا ياخد باله إن مفيش أصلاً.
٧ احجز مقعد — لما السكشن يبقى مليان
السكشن اللي عايزه مليان. بدل ما التطبيق يقوله «مش متاح» ويقفل الموضوع، الـ SIS بيسمح إنه يقف في الطابور — ولما حد يسيب مكانه، مسؤول التسجيل بيدخّله.
الزرار بيظهر لما flags.CanAddSeat = true — وده بيبقى
true في حالة واحدة بس: السكشن مليان والطابور
مفتوح وفيه مكان.
CanRegister وCanAddSeat
عمرهم ما بيبقوا true مع بعض.
لو فيه مكان → «سجّل». لو مليان والطابور مفتوح → «احجز مقعد». الكارت بيرسم زرار واحد.
وقبل ما يدوس، وريه هو واقف فين:
| الفيلد | معناه |
|---|---|
WaitCapacity | طول الطابور اللي الكلية سامحة بيه |
WaitTaken | واقف فيه كام واحد دلوقتي |
WaitLeft | فاضل كام مكان · و-1 يعني الطابور من غير سقف |
WaitNo — رقم دور الطالب. اعرضه له، ده أهم حاجة عايز يعرفها.flags.IsWaiting = true وED_CODE_COURSE_STATUS_ID = 7.· ساعاته مش محسوبة عليه في السقف
· المحاضرة مش هتظهر في جدوله
· ومحدش بيضمن له إنه هيدخل
فاعرضه بعلامة صفرا «انتظار» ومعاه رقم الدور — مش زي المقررات المسجّلة. لو عرضته عادي، الطالب هيفتكر نفسه مسجّل ويصحى آخر الترم يلاقي نفسه مش في المقرر.
٨ اخرج من الانتظار — ألغِ الحجز
الطالب غيّر رأيه، أو لقى سكشن تاني فاضي، أو الدور طويل ومش مستني. عايز يسيب الطابور.
الزرار بيظهر لما flags.CanCancelWait = true — يعني المقرر
حالته انتظار (7).
وده منطقي: ده ماكانش تسجيل من الأصل عشان يتساب له أثر. ده كان دور في طابور، والطالب خرج منه. فمافيش «تراجع» هنا — لو غيّر رأيه تاني، بيحجز من الأول (ولو الطابور كان اتملى في الوقت ده، يبقى فات عليه).
٩ بدّل مقرر بمقرر — العملية الوحيدة اللي فيها اتنين مع بعض
الطالب عايز يستغنى عن مقرر ويحط غيره مكانه. مثلاً سقف ساعاته اتملى، أو لقى مقرر أنسب لخطته.
وساعتها القديم بقى مسقَط، وهو مش هيلاقيه في «المتاح للتسجيل» عشان يرجّعه (شوف قسم التراجع فوق). يعني حطّيته في مشكلة.
flags.CanDrop = true ينفع يتبدّل.flags.CanRegister — مش على مقرر. المقرر ممكن يكون متاح وكل سكاشنه مليانة.IsDropped = true، والجديد ظهر مسجّل وفي سكشن.· نفس المقرر على الجهتين → «ده تغيير سكشن، استخدم
ReplaceSection»
· المقرر القديم مش مسجّل أصلاً
· المقرر الجديد مسجّل بالفعل
· السكشن المبعوت بتاع مقرر تاني
· ومن غير سكشن خالص → «لازم تختار سكشن»
وكلهم قبل أي كتابة — يعني بعد أي رفض فيهم، المقرر القديم لسه مكانه بالظبط. فيه فولدر في الكوليكشن بيجرّب الخمسة دول واحدة واحدة وبعدين بيعمل التبديل الحقيقي، عشان تشوف بعينك إن «يا الاتنين يا ولا واحد» شغّالة.
١٠ اطلب انسحاب — العملية الوحيدة اللي مابتنفّذش
الطالب بدأ المقرر فعلاً، حضر محاضرات، وبعدين لقى نفسه مش قادر يكمّله. مش عايز إسقاط — الإسقاط ليه ميعاد وفات. هو عايز ينسحب.
الطالب بيقدّم طلب. والجامعة هي اللي بتنفّذه بعد الموافقة.
الزرار بيظهر لما المقرر يكون نشط (حالة 1) وAgenda.Withdraw
مفتوحة. مش على المقرر المسقَط ولا اللي في الانتظار.
requestId — رقم الطلب.refresh لـ«مقرراتي» بعد النداء ده وانت مستني المقرر يتشال أو
يتعلّم عليه — مش هيحصل حاجة. المقرر هيفضل نشط زي ما هو،
وهتفتكر إن النداء فشل وهو نجح.
الصح: بعد النجاح اقفل الشيت، ووَدّي الطالب على شاشة «طلباتي»، وماتلمسش صف المقرر خالص.
وطيب لما الجامعة توافق، بيحصل إيه؟
| الإسقاط | الانسحاب | |
|---|---|---|
| مين بينفّذه | الطالب على طول | الجامعة بعد الموافقة |
| الساعات | بترجع له | بتفضل محسوبة كـ attempted |
| في السجل | مفيش أثر — كأنه ما سجّلش | بيفضل بتقدير W |
| بيترجع؟ | آه — «تراجع» | لأ بعد الموافقة |
١١ display وactions — الرد جاهز للرسم
كل اللي فات بيقولك إيه المسموح. فاضل شغل تاني كان هيتعمل في كل تطبيق على حدة:
تختار الاسم العربي ولا الإنجليزي لست حاجات، تلزق اليوم على الميعاد على القاعة،
تحوّل ست بوليانات لقايمة أزرار مرتبة، وتفتكر كل زرار بينده أنهي إندبوينت وبأي body.
أربع تطبيقات بيعملوا ده = أربع فرص إن نفس الزرار يتسمّى باسمين مختلفين، وواحد فيهم
هيغلط في الـ body على مقرر ليه أكتر من سكشن.
عشان كده كل صف بقى جايله كمان display (النصوص جاهزة) و
actions (الأزرار، وكل زرار معاه الإندبوينت والـ body بالظبط).
والحقول القديمة كلها مكانها زي ما هي — ده إضافة، مش تغيير.
شكل display
"display": {
"Title": "SUR310",
"Subtitle": "العلاج الطبيعى للجراحة العامة",
"Meta": "4 ساعة",
"Place": "معمل 107 · مبني كلية العلاج الطبيعي", ← على السكشن
"Badge": "مسقَط",
"BadgeTone": "danger", ← neutral · success · warning · danger
"Note": "فترة الإسقاط مقفولة"
}BadgeTone معنى، مش لون.
الخدمة بتقولك الشارة معناها إيه — والألوان تفضل عندك في التصميم.
ماينفعش الـ API يبعت #FEE2E2.
وشكل actions — وده الجزء اللي بيوفّر شغل حقيقي
"actions": [
{ "Key": "replaceSection", "Label": "غيّر السكشن", "Tone": "secondary",
"Enabled": true,
"Endpoint": "CourseReg/GetSectionsToReplace",
"Body": { "EdCourseId": 46, "EdStudGroupId": 0 } },
{ "Key": "deleteSection", "Label": "احذف SEC 1 · عملى", "Tone": "secondary",
"Endpoint": "CourseReg/DeleteSection",
"Body": { "EdCourseId": 46, "EdStudGroupId": 124534 } }, ← السكشن بالظبط
{ "Key": "drop", "Label": "أسقط المقرر", "Tone": "danger",
"Endpoint": "CourseReg/DropCourse",
"Body": { "EdCourseId": 46 } }
]يعني التطبيق بقى بيعمل ده وخلاص:
actions.map(a => <Button tone={a.Tone} disabled={!a.Enabled}
onClick={() => post(a.Endpoint, a.Body)}>
{a.Label}
</Button>)EdStudGroupId بتاع سكشنه. مافيش تخمين، ومافيش «الخدمة تختار».
Key ثابت — اتعامل بيه مش بالنص.
register · addSeat · cancelWait · drop ·
undrop · replaceSection · deleteSection ·
pickSection.
معظمهم بتنده الـ
Endpoint على طول. اتنين بس بيفتحوا شاشة بدل ما يبعتوا:
replaceSection وpickSection — دول بيرجّعوا بيكر السكاشن.
"LANG": "en" في الـ body وكل نصوص display و
actions هتيجي إنجليزي. من غيره بتيجي عربي.
الحقول الخام (_AR و_EN) بتيجي الاتنين دايمًا —
اللغة بتأثر على النصوص المركّبة بس.
flags لسه مكانها.
لو محتاج تبني شكل مختلف عن اللي الخدمة اقترحته، الفلاجز والحقول الخام كلها موجودة.
display وactions اختصار، مش قيد.
١٢ جدول الرسايل — اعرض اللي جايلك
كل رفض بيجي ومعاه سبب بالاسم في flags.BlockedReason
أو في Error. ترجمهم مرة واحدة واعرضهم بدل «حصل خطأ»:
| السبب | اعرض للطالب | وبعدين؟ |
|---|---|---|
WINDOW_CLOSED | الفترة مقفولة دلوقتي | مفيش — استنى |
SECTION_FULL | السكشن مليان | شوف لو الطابور مفتوح |
SECTION_CLOSED | السكشن مقفول من الكلية | اختار سكشن تاني |
TIME_CLASH | بيتعارض مع محاضرة تانية | اعرض مع مين ووَدّيه يحذفه |
EXAM_CLASH | امتحانه مع امتحان مقرر تاني | اعرض مع مين |
MAX_LOAD | هتعدّي حد الساعات | يإسقاط مقرر الأول |
ALREADY_REGISTERED | مسجّل فيه بالفعل | مفيش |
INCOMPLETE_COURSE | فيه محاولة سابقة لسه مفتوحة | شؤون التسجيل |
PREREQ_NOT_MET | المتطلب السابق مش مكتمل | مفيش |
STUDENT_BLOCKED | حسابك موقوف | شؤون الطلاب |
flags — وأي شرط تكتبه انت هيختلف عن الجامعة
أول ما مسؤول التسجيل يغيّر ميعاد.
وبعد أي عملية كتابة، اقرا القايمة تاني واتعامل مع اللي راجع — ماتعدّلش النسخة اللي عندك من عندك.
18 دورة تسجيل المقررات — بالتفصيل
ده المسار الوحيد اللي فيه حالات بتتغيّر وعمليات كتابة حقيقية: تسجيل، حذف، وتراجع عن الإسقاط. الفصل ده بيمشي معاك خطوة خطوة، بيوريك كل خطوة بتدّي إيه للّي بعدها، وبيحكي التلات باجات اللي كانت مخبّية بعض وخلّت التسجيل عمره ما اشتغل.
الدورة كل عملية في فولدر لوحدها
الكوليكشن كان سكريبت واحد مترتب: تضغط Run ويمشي الدورة كلها. ده أثبت إنها شغالة، بس مش الشكل اللي يفيد حد بيبني شاشة واحدة — كان لازم يقرا ١٧ خطوة عشان يلاقي الأربعة اللي تخصّه، ولو حب يشغّلهم لوحدهم لازم يعرف أنهي خطوة قبلهم بتحطّ أنهي متغيّر.
دلوقتي كل عملية فولدر، وكل فولدر كامل لوحده: بيدخل، بيقرا اللي محتاجه، بينفّذ، وبيقرا تاني عشان يتأكد إن اللي اتكتب بان. تقدر تشغّل فولدر واحد، أو الكوليكشن كله، أو ريكوست واحد.
| # | الفولدر | الخطوات |
|---|---|---|
| 1 | تسجيل مقرر جديد | دخول ← المسموح ← المتاح وسكاشنه ← سجّل ← 🔎 تأكيد إنه في القايمة بحالة 1 وبسكشن |
| 2 | تغيير سكشن | دخول ← مقرراتي ← GetSectionsToReplace ← انقل ← 🔎 تأكيد إن السكشن اتغيّر |
| 3 | حذف سكشن | دخول ← مقرراتي ← حذف ← 🔎 تأكيد إن المقرر لسه مسجّل والفلاجز اتقفلت |
| 4 | حجز مقعد + الخروج منه | دخول ← سكشن مليان ← احجز ← 🔎 حالة 7 ← اخرج ← 🔎 اختفى |
| 5 | إسقاط مقرر | دخول ← مقرراتي ← احذف ← 🔎 تأكيد إن الحالة بقت 6 والصف موجود |
| 6 | التراجع عن الإسقاط | دخول ← مقرراتي ← السكاشن ← تراجع ← 🔎 تأكيد إنه رجع 1 وفي سكشن |
| 7 | بدّل مقرر بمقرر — كل الحالات | دخول ← مقرراتي ← المتاح ← ٤ رفضات متوقّعة ← 🔎 لسه محصلش حاجة ← بدّل ← 🔎 القديم مسقَط والجديد مسجّل ← ترجيع |
| 8 | طلب انسحاب | دخول ← مقرراتي ← اطلب ← 🔎 مقرراتي ما اتغيّرتش ← ألغِ الطلب |
| 9 | قراءات مرجعية | النداءات اللي بتقرا بس — شغّلها في أي وقت من غير ما تغيّر حاجة |
Status: true ومابتظهرش في أي شاشة هي أخطر عطل في الخدمة
دي: مافيش فرق بينها وبين النجاح وقت النداء، وماتبانش غير لما الطالب يقول «أنا سجّلت ومش لاقي
المقرر». عشان كده كل فولدر بيقفل بقراءة بتتأكد إن اللي اتكتب بان فعلًا.
Staff/GetInstructorSectionSolts عشان «تفاصيل السكشن»،
واتحذفت: دي نظرة الدكتور للسكشن، والطالب أصلاً بياخد كل التفاصيل جوّه رد
«المتاح للتسجيل». لو لقيت نفسك بتنادي مسار بادئ بـ Staff/ في مسار طالب —
غالبًا الداتا موجودة عندك بالفعل.
flags وخلاص.
ورقم الطالب من التوكن: الإندبوينتات الجديدة مافيهاش EdStudId أصلاً.
الحالة المقرر بيتنقل بين حالتين — ومابيتمسحش أبدًا
DropCourse →UnDropCourse —
الإسقاط مش بيمسح الصف — بيغيّر حالته لـ 6. وده مش تفصيلة شكلية: استعلام الخطة بيستبعد
أي مقرر ليه صف تسجيل في الفصل ده مهما كانت حالته، فالمقرر المسقَط
مش بيرجع تاني في «المتاح للتسجيل». الطريق الوحيد لإرجاعه هو
UnDropCourse. لو التطبيق حاول يسجّله من جديد، مش هيلاقيه أصلاً في القايمة.
دول الحالتين اللي الطالب بيحرّكهم بنفسه من التطبيق. فيه حالتين كمان بتوصلك في الرد — 2 و4 (انسحاب) — بس دول مش من الموبايل: الجامعة هي اللي بتحطّهم. الفرق ده كله في اللي بعده.
أهم فرق «حذف السكشن» ≠ «أسقط المقرر» ≠ «انسحب»
تلات أزرار مختلفة، والاسم بتاعهم بيخلّي حد يفتكرهم درجات من نفس الحاجة — وهما مش كده. كل واحد بيعمل حاجة مختلفة على الشاشة، وبيرجّع شكل مختلف، والطالب بيفهم منه حاجة مختلفة. الكروت دي مكتوبة من ناحيتك انت: الزرار، إمتى تعرضه، بتنادي إيه، وبيحصل إيه بعد النجاح.
- الزرار
- ✕ صغيّرة جنب السكشن نفسها — مش جنب المقرر
- اعرضه لما
flags.CanDeleteSection- بتنادي
CourseReg/DeleteSection
ومعاهاEdStudGroupIdبتاع السكشن- بعد النجاح الشاشة تبقى إيه
- المقرر يفضل مكانه في «مقرراتي». لو دي كانت آخر سكشن،
sectionsترجع فاضية. والرد نفسه بيقولNeedsSectionوMissingTeachingMethodوNextAction - الخطوة اللي بعدها
GetSectionsToReplace←AddSection— البيكر بيرجّع مرشّحين بـMode: PICK- الطالب يفهم إيه
- «لسه مسجّل في المقرر، بس محتاج يختار سكشن»
- الزرار
- «أسقط» على صف المقرر
- اعرضه لما
flags.CanDrop- بتنادي
CourseReg/DropCourse- بعد النجاح الشاشة تبقى إيه
- المقرر يفضل في القايمة بس بـ
flags.IsDropped = true— علّم عليه، وحوّل زراره لـ «تراجع» (flags.CanUnDrop) - الطالب يفهم إيه
- «المقرر اتلغى وساعاته رجعتلي» — ويقدر يسجّل غيره
- الزرار
- «اطلب انسحاب» — في شاشة الطلبات، مش في شاشة التسجيل
- اعرضه لما
- المقرر نشط ونافذة الانسحاب مفتوحة
(
Agenda.Withdraw) - بتنادي
students/RequestCourseWithdrawal- بعد النجاح الشاشة تبقى إيه
- مافيش أي حاجة تتغيّر في «مقرراتي». الطلب بيروح للجامعة — اعرضه في «طلباتي» بحالة تحت الموافقة
- الطالب يفهم إيه
- «قدّمت طلب، ولسه مستني الرد» — والمقرر هيبان في سجلّه بتقدير W
RequestCourseWithdrawal وبعدها عملت refresh لـ «مقرراتي»
وانت مستني المقرر يتحذف أو يتعلّم عليه — مش هيحصل، والشاشة هتبان كأن النداء فشل.
الانسحاب طلب، مش تنفيذ. حد في الجامعة لازم يوافق عليه الأول، وساعتها بس المقرر بيتغيّر. يعني بعد النجاح: اقفل الشيت، ووَدّي الطالب على «طلباتي» — وماتلمسش صف المقرر. والطالب يقدر يلغي طلبه طول ما هو لسه تحت الموافقة (نفس النداء بـ
Cancel: true).
سؤال جه من الموبايل تيم: «حذفت السكشن والمقرر لسه راجع — ليه؟»
LoadRequest عادي
بـ sections: [].
وده نفس اللي بيحصل في بورتال الجامعة بالظبط: المقرر بيفضل ظاهر من غير سكشن، وبيتعرضله «اختر سكشن» و«أسقط المقرر». يعني دي حالة ليها معنى — «إنت مسجّل، فاضل تختار سكشن» — مش عطل.
لو عايز المقرر يتحذف فعلًا، الزرار الصح هو «أسقط المقرر» (
DropCourse) مش «حذف السكشن».
| الحقل | بيبقى | يعني إيه على الشاشة |
|---|---|---|
sections | [] |
اعرض الصف بعلامة «من غير سكشن» + زرار «اختر سكشن» |
flags.CanDeleteSection | false |
خبّي زرار «حذف السكشن» — مافيش حاجة تتحذف |
flags.CanReplaceSection | false |
خبّي «غيّر السكشن» — مافيش سكشن حالية أصلاً |
flags.CanDrop | true |
«أسقط المقرر» هو اللي يفضل ظاهر |
DeleteSection بيقبل EdStudGroupId
(الصح — السكشن بالظبط)، أو EdCourseId لوحده كـتسهيل.
ولو بعتّ EdCourseId بس، بتتحذف أول سكشن فيهم —
فمقرر فيه محاضرة + عملي هتتحذف منه واحدة والتانية تفضل،
وهتفتكر إن النداء «ما اشتغلش».
القاعدة: ابعت
EdStudGroupId اللي جايلك من
sections[].ED_STUD_GROUP_ID — وانت أصلاً عارفه، لأن الطالب
دوس على السكشن ده بإيده.
LoadRequest تاني واتعامل مع اللي راجع
بدل ما تعدّل القايمة من عندك.
الباجات تلاتة فوق بعض — والتسجيل عمره ما اشتغل
كل واحدة فيهم كانت بتخبّي اللي بعدها، والأولانية كانت بتتنكّر في هيئة قاعدة شغلانية.
<Courses> تحت
WITH XMLNAMESPACES (DEFAULT 'http://www.w3.org/2005/Atom') —
في خمس جمل مختلفة. والـ XPath لما يتنفّذ مع namespace افتراضي
مابيطابقش غير العناصر اللي جوّه الـ namespace ده.
المستند اللي كان بيتبعت من غير namespace، فـ
nodes() رجّع صفر صفوف،
والـINSERT ماأدخلش حاجة، والإجراء خلص من غير أي خطأ.
<Courses><Course>…<Courses xmlns="http://www.w3.org/2005/Atom">…FK_ED_STUD_COURSE_REG_SC_SECTION_GROUP_HDR:
الكود كان بيكتب GroupId في SC_SECTION_GROUP_HDR_ID على طول،
و0 مش مفتاح موجود — 0 معناها «مفيش مجموعة»، يعني NULL.
دلوقتي مابيتكتبش غير لما تكون فيه مجموعة فعلاً.
GetNewCourses بيرجّع
SC_SCHEDULE_DTL_ID على كل سكشن، وSC_SECTION_GROUP_HDR_ID بيبقى
null في أغلب الحالات. يعني من غير مجموعة، مكانش فيه حاجة تحطّ الطالب فيها،
وكان هيتسجّل في المقرر ومش مربوط بأي سكشن.
بقى فيه
ScScheduleDtlId في الطلب — السكشن اللي الطالب اختارها فعلاً.
جرّبها نزّل الكوليكشن وشغّل اللي يخصّك
مش مجرد مجموعة ريكويستات: كل عملية فولدر، وكل فولدر بيدخل بنفسه وبيقرا بعد ما يكتب عشان يتأكد. وفيه تحققات على كل خطوة، والرد الحقيقي محفوظ جنب كل ريكوست تقدر تشوفه من غير ما تبعت حاجة.
⬇️ حمّل كوليكشن تسجيل المقررات (٩ فولدرات · ٥٧ ريكوست · ٨٨ تحقّق)
newman run workflow-course-registration.postman_collection.json --folder "2 · تغيير سكشن مقرر مسجّل"
| الحساب | ليه هو بالذات |
|---|---|
mahmoued.eprahim.23010062طالب علاج طبيعي · ED_STUD_ID 73 |
نفس الحساب اللي كل الشاشات التانية ماشية عليه — الدليل كله بقى على طالب واحد عشان العرض يمشي من غير ما حد يغيّر تسجيل الدخول في النص. الطالب ده مسجّل ١٠ مقررات الترم ده، وقدامه مقررات راسب فيها متاحة للإعادة بسكاشن مفتوحة — فالدورة الكاملة (عرض ← تسجيل ← حذف ← تراجع) بتكمل بيه. |
6 registered MEC111 into section 1764
7 now registered in 7 course(s); new one present: true
8 dropped MEC111
9 can go back to 5 section(s)
10 restored MEC111
11 final: 7 rows — 6 active, 1 droppedفي التطبيق نفس الدورة على الشاشة
الشاشة بتعرض المسجّل بزرار «أسقط»، والمتاح بزرار «سجّل»، والمسقَط بيتعلّم عليه وزراره بيتغيّر لـ «تراجع عن الإسقاط» — لأن ده الطريق الصح في الـ SIS. وأي رفض من اللائحة بيتعرض بنصّه للمستخدم بدل «حصل خطأ».
اتظبط باقي بيزنس التسجيل زي ما هو في الـ SIS
الجزء ده اتعمل بعد مراجعة كود البورتال نفسه
(UcRegisteredCourses، UCRegisterAddReplaceCourse،
AddStudCourseChngReq) — مش من شكل الريكوست القديم.
باجّين الموبايل تيم بلّغوا عنهم
| اللي كان بيحصل | السبب | اتعمل إيه |
|---|---|---|
إسقاط مقرر بـ EdCourseId لوحده بيرجّع Status: true والمقرر مايتحذفش |
الخدمة كانت بتنفّذ
UPDATE … WHERE ED_STUD_COURSE_REG_ID = 0 —
صفر صف اتغيّر، ومع ذلك بترد نجاح، وكمان بتسجّل صف تغيير لحذف ماحصلش. |
لو رقم التسجيل مش مبعوت، الخدمة بتلاقيه من فصل الطالب نفسه. ولو مفيش حاجة تتحذف بترفض بوضوح بدل ما تدّعي النجاح. وده قفل كمان ثغرة صلاحيات: قبل كده أي حد كان يقدر يبعت رقم تسجيل بتاع طالب تاني ويتنفّذ. |
| شاشة «مقرراتي» مابترجّعش لا السكشن اللي هو فيها ولا السكاشن المتاحة | الاستعلام بيرجّع صف لكل سكشن، والكود كان بياخد أول صف بس
(g.First()) — فمقرر فيه محاضرة + عملي + إكلينيكي كان بيوصل
كـ ٣ صفوف ويتقفل على واحد. |
كل مقرر دلوقتي بيجيب سكاشنه تحت sections،
وبـ IncludeAvailableSections: true بيجيب كمان
availableSections — السكاشن اللي ينفع يغيّر ليها. |
خمس عمليات زوّدناها من الـ SIS
| الإندبوينت | بيعمل إيه | النافذة اللي بتحكمه |
|---|---|---|
CourseReg/SetSection جديد |
«حطّني في السكشن دي» — نداء واحد لكل الحالات. الخدمة بتشوف
إن الطالب عنده سكشن من نوع التدريس ده ولا لأ، وتقرّر نقل ولا إضافة،
وترجّع Action. ReplaceSection و
AddSection بقوا نفس النداء ده بأسمائهم القديمة. |
النقل: الإضافة (5) · الإضافة: (70) أو (5) |
CourseReg/ReplaceSectionبقى CourseReg/SetSection |
تغيير سكشن مقرر مسجّل. بيتأكد إن السكشن بتاع نفس المقرر ومن نفس نوع التدريس، وإن فيها مكان، وإنها ماتتعارضش مع الجدول — والتأكد من التعارض بيتعمل مرتين: قبل النقل وبعده جوّه نفس الترانزاكشن. | الإضافة (5) — زي البورتال، مش نافذة الإسقاط |
CourseReg/DeleteSection |
حذف سكشن واحد من مقرر متدرّس على أكتر من سكشن، والتسجيل يفضل قايم. والرد بيسمّي النوع اللي بقى ناقص وكام مرشّح ليه، ومعاه نداء البيكر جاهز. | تسجيل السكاشن (70) |
CourseReg/AddSectionبقى CourseReg/SetSection |
ضم سكشن لتسجيل قايم — الرجعة من الحذف. نفس ضمانات النقل (نفس المقرر · مفتوحة · فيها مكان · ماتتعارضش)، بس مافيش صف بينتقل: بيتزاد صف جديد لنوع تدريس الطالب مالوش فيه سكشن. والساعات ماتتغيّرش — ده مش تسجيل مقرر. | تسجيل السكاشن (70) أو الإضافة (5) |
CourseReg/AddToWaitListبقى جوّه SetSection وRegisterNewCourse |
حجز مقعد في سكشن مليان: تسجيل بحالة 7 (انتظار)
ومعاه رقم الدور. مسؤول التسجيل هو اللي بيحوّله لـ 1 لما يفضى مكان. مابقاش نداء لوحده — زي البورتال، التسجيل العادي هو اللي بيحطّك في الطابور لما المقاعد تخلص والطابور يبقى فيه مكان. |
الإضافة (5) · وبيترفض لو فيه منع في SE_BLOCK_TRANS |
CourseReg/CancelWaitList |
خروج من الطابور — الصف بيتمسح خالص، لأنه أصلاً ماكانش تسجيل. | — |
CourseReg/SetSection بالـ body
{ EdCourseId, ScScheduleDtlId } — مش محتاج تعرف هي نقل ولا
إضافة، ولا تبعت EdStudGroupId إلا في المقرر اللي فيه أكتر من سكشن
من نفس النوع. والبيكر أصلاً بيبعتلك الـ Endpoint والـ Body
جاهزين في actions.
قواعد كانت ناقصة واتضافت
- الإسقاط مربوط بنافذة الإسقاط (نشاط 6) في أجندة الفصل — البورتال بيرفض بـ «dropdateout». قبل كده الموبايل كان بيسمح بالإسقاط في أي وقت.
- صف التغيير بقى بسبب
1(«رغبة الطالب») وAPPROVE_FLGفاضية في الإسقاط — بالظبط زي البورتال، اللي بيملاها في الإضافة والتراجع بس. - التراجع بيكتب صف التغيير بتاعه (نوع 5)، عشان سجلّ التغييرات عند المسجّل يبان فيه الرجوع مش الإسقاط بس.
- سقف الساعات بيتشيك قبل التراجع وقبل حجز المقعد
(
GetAcadLoadMinMax) — زي ما البورتال بيعمل بالظبط.
ED_STUD_COURSE_REG_ID بيتغيّر وتاريخ الصف القديم بيضيع.
التطبيق ماسك الرقم ده وهو ماشي بين الشاشات، والمقرر أصلاً مش بيتغيّر، فإحنا
بنحرّك صف السكشن الموجود بدل كده — وده نفس اللي الـ SIS بيعمله لما مسؤول التسجيل
بيطلّع طالب من قائمة الانتظار.
للموبايل الأزرار جايالك جاهزة — ماتحسبهاش بنفسك
قواعد إيه اللي مسموح إمتى كلها في الـ SIS: أجندة الفصل (وبتختلف من كلية لكلية ومن فصل لفصل)، وأماكن السكشن، وحالة التسجيل. أي كلاينت يحاول يستنتجها بنفسه هيختلف عن البورتال أول ما مسؤول التسجيل يزوّد أو يقفل نافذة. عشان كده الخدمة بترد بالقرار نفسه مش بالمكوّنات.
١ — على مستوى الشاشة: CourseReg/GetAllowedActions
| الحقل | معناه |
|---|---|
Agenda.Register / Add / Drop / Withdraw / RegisterSection |
نوافذ الأجندة الخمسة (الأنشطة 3 / 5 / 6 / 7 / 70) — مفتوحة النهاردة ولا لأ |
Agenda.IsActiveStudent |
false لو الطالب موقوف مالياً — ساعتها مفيش أي إجراء مهما كانت النوافذ مفتوحة |
Agenda.AnyOpen |
مفيش أي حاجة متاحة خالص — اعرض رسالة واحدة بدل خمس أزرار مقفولة |
CanRegisterCourses · CanDropCourses · CanUnDropCourses |
الإجابة الجاهزة لكل شاشة — النافذة + حالة الطالب متجمّعين |
MaxCreditHours · CurrentCreditHours |
سقف اللائحة والمحمّل منه — عشان تحذّر قبل ما التسجيل يترفض |
ونفس بلوك Agenda بيرجع كمان مع LoadRequest و
GetNewCourses وGetUnDropCourse،
فمش محتاج نداء زيادة وانت فاتح الشاشة.
٢ — على مستوى كل سكشن: flags
كل سكشن في sections وavailableSections جايّة ومعاها:
| الفلاج | يعني إيه للزرار |
|---|---|
CanRegister | اعرض زرار «سجّل» |
CanAddSeat |
اعرض زرار «احجز مقعد» — وده بيبقى true في
حالة واحدة بس: السكشن مليانة وقائمة الانتظار مفتوحة وفيها مكان.
يعني الزرارين عمرهم ما بيظهروا مع بعض. |
IsFull · SeatsTotal · SeatsTaken · SeatsLeft |
عدّاد الأماكن. SeatsLeft = -1 يعني السكشن من غير سقف |
WaitCapacity · WaitTaken · WaitLeft |
طول طابور الانتظار وفاضل فيه كام |
HasClash · HasExamClash |
تعارض مع محاضرة تانية أو مع امتحان في جدول الطالب |
BlockedReason |
ليه الزرار مقفول — واحدة من:
WINDOW_CLOSED · SECTION_FULL · SECTION_CLOSED ·
TIME_CLASH · EXAM_CLASH · MAX_LOAD ·
INCOMPLETE_COURSE · ALREADY_REGISTERED ·
PREREQ_NOT_MET · STUDENT_BLOCKED.
اعرض السبب بدل ما ترمّد الزرار وخلاص. |
PrereqProblem |
رد محرّك القواعد بنصّه لما يكون فيه مشكلة.
ماتعرضهوش للطالب — هو مفتاح داخلي (زي ExamCourseConfilict)،
وBlockedReason هو الترجمة بتاعته. موجود للتشخيص بس. |
INT404 في الديمو —
سكشن مليان وسكشن فاضية):
sec 2132 CanRegister=false CanAddSeat=true IsFull=true seats 1/1 wait 0/10 BlockedReason=SECTION_FULL
sec 2133 CanRegister=true CanAddSeat=false IsFull=false seats 0/30 wait 0/10 BlockedReason=null
٣ — على مستوى كل مقرر مسجّل: flags
| الفلاج | الزرار | النافذة اللي بتحكمه |
|---|---|---|
CanDrop | «أسقط المقرر» | الإسقاط (6) + الحالة نشطة |
CanUnDrop | «تراجع عن الإسقاط» | الإضافة (5) + الحالة مسقَطة |
CanReplaceSection | «غيّر السكشن» | الإضافة (5) + عنده سكشن + فيه بديل فعلاً
(alternativeSectionCount > 0) |
CanDeleteSection | «حذف السكشن» | تسجيل السكاشن (70) |
needsSection (على المقرر نفسه) |
«اختار سكشن» — زرار أساسي | ناقصه سكشن من نوع بيتدرّس، اسمه في
missingTeachingMethods |
CanCancelWait | «اخرج من الانتظار» | الحالة انتظار (7) |
IsDropped · IsWaiting | شكل الصف نفسه | — |
يعني الصف في القايمة بيوصلك وهو عارف أزراره: CanDrop بقى false
يوم ما نافذة الإسقاط تتقفل، من غير ما تعدّل سطر واحد في التطبيق.
مهم رقم الطالب بيتاخد من التوكن — مش من الـ body
العقد القديم بتاع KU بيبعت ED_STUD_ID في جسم الريكوست، وإحنا سيبناه زي
ما هو عشان كود الموبايل الموجود يشتغل من غير تعديل. ده كان قرار صح على مستوى شكل
الريكوست، وغلط على مستوى الثقة: الرقم ده كان بيتستخدم عشان يقرّر داتا مين ترجع.
73، وتبعت
{ "LANG": "ar" } لـ CourseReg/v2/MyCourses —
ويرجعلك مقررات الطالب 2084 التمانية. نفس الشيء على الإندبوينتات اللي بتكتب.
اتظبطت في مكان واحد مش في ٢٧ إندبوينت: فيلتر عام بيستبدل رقم الطالب في أي موديل بالرقم اللي في التوكن، بعد ما الريكوست يتقري وقبل ما أي هاندلر يشوفه.
| الحالة | اللي بيحصل دلوقتي |
|---|---|
| بعتّ رقمك أنت (الطبيعي) | مافيش أي فرق — الحقل لسه في العقد وشغال زي ما هو |
| بعتّ رقم طالب تاني بتوكن طالب | بيترد عليك داتاك انت — الرقم بيتتجاهل |
| بعتّ رقم طالب بتوكن دكتور | بيشتغل عادي — الدكتور بيتعامل مع طلبة مش هو، وصلاحيته جاية من دوره |
يعني عمليًا: ماتعتمدش على الرقم اللي بتبعته عشان تعرض داتا حد تاني — مش هيشتغل. ولو محتاج تعرض بيانات طالب لموظف، لازم توكن الموظف.
اتعمل سقف الساعات والمتطلبات السابقة — بمحرّك الـ SIS نفسه
الاتنين دول كانوا مكتوبين في جدول النواقص إن «التحقق كله لسه» — وده كان صح لما راجعناه على البورتال. دلوقتي الاتنين شغالين، ومش بمنطق كتبناه إحنا: بنستخدم نفس الإجراءات اللي البورتال بيستخدمها.
| القاعدة | مصدرها في الـ SIS | بتتنفّذ فين |
|---|---|---|
| المتطلب السابق | CHK_STUD_CRS_PREREQ — بيرجّع مفتاح مشكلة
(زي ExamCourseConfilict) أو فاضي يعني مسموح |
مرة لكل مقرر في GetNewCourses و
GetUnDropCourse وavailableSections،
وتاني مرة في RegisterNewCourse قبل الكتابة |
| سقف الساعات | GetAcadLoadMinMax — بيرجّع
«الحد الأدنى - الأقصى - عدد المقررات» من لائحة الطالب |
RegisterNewCourse · UnDropCourse ·
AddToWaitList |
CanRegister=false CanAddSeat=false BlockedReason=PREREQ_NOT_MET PrereqProblem=ExamCourseConfilict
PrereqProblem هو مفتاح رسالة الـ SIS نفسه — ترجمه في التطبيق زي ما البورتال بيترجمه.
register BAS111 (prereq not met) → Status:false · "prerequisites have not been met" · key=ExamCourseConfilict
register ORT407 (allowed) → Status:true
register NUR502 (5h) at 24/30 → Status:true → 29
register NUR504 (4h) at 29/30 → Status:false · "would take the student to 33.00, over the 30 allowed"
MinCreditHours راجع في
GetAllowedActions عشان التطبيق يحذّر لوحده لو حب.
اتأكدنا كل عملية كتابة بتظهر فعلًا في القايمة اللي المفروض تعرضها
أخطر عطل في الخدمة دي كان: عملية بترد Status: true ومابتظهرش في أي شاشة —
مافيش فرق بينها وبين النجاح وقت النداء، وماتبانش غير لما الطالب يقول «أنا سجّلت المقرر ومش لاقيه».
عشان كده كل عملية كتابة اتشغّلت بين قراءتين للإندبوينت اللي التطبيق بيعمله refresh بعدها،
والقراءتين اتقارنوا.
| العملية | القايمة اللي بتظهر فيها | النتيجة |
|---|---|---|
RegisterNewCourse | LoadRequest |
✅ المقرر ظهر بحالة 1 |
ReplaceSection | LoadRequest |
✅ السكشن الجديدة هي اللي بتترجع |
DeleteSection | LoadRequest |
✅ sections بقت فاضية والمقرر لسه مسجّل —
وneedsSection = true ومعاه زرار «اختار سكشن» |
AddSection | LoadRequest |
✅ السكشن رجعت والمقرر بقى كامل — واتجرّبت على مقرر MEC111 لطالب تسجيله كان من غير سكشن: زوّدنا محاضرة، والنداء التاني على نفس النوع اترفض صح («استعمل ReplaceSection») |
DropCourse | LoadRequest |
✅ الحالة بقت 6 |
UnDropCourse | LoadRequest |
✅ رجعت 1 ومعاها سكشن |
AddToWaitList | LoadRequest |
✅ ظهر بحالة 7 |
CancelWaitList | LoadRequest |
✅ الصف اختفى |
AddComplaint | GetComplaints |
✅ 35 ← 36 |
AddQuestion | GetQuestions |
✅ 26 ← 27 |
AddAnswer | GetAnswers |
✅ 23 ← 24 |
SaveContactMethod | GetContactMethods |
✅ 38 ← 39 |
AddCampusRequest | GetCampusRequests |
⚖️ رفض «عندك طلب مفتوح» — والطلب موجود في القايمة |
RequestCourseWithdrawal | GetCourseWithdrawals |
⚖️ نفس الحالة |
RequestEnrollmentChange | GetEnrollmentChanges |
⚖️ نفس الحالة |
AddHousingRequest | GetHousingRequests |
⚖️ نفس الحالة — واتأكدنا منها بالكامل (تحت) |
BookAppointment | GetMyRecords |
⚖️ نفس الحالة |
list = 4 → delete the open request → list = 3 → AddHousingRequest → Ok → list = 4
يعني الرفض بيحصل لأن الصف موجود، والصف ظاهر، ولما يتحذف العملية بتشتغل وبتبان.
مراجعة منيو الـ SIS كله — إيه اللي يستاهل يبقى موبايل؟
رجعنا لمنيو الـ SIS نفسه (SE_MODULE / SE_FORM)
لكل نوع مستخدم، مش لتخميناتنا:
| نوع المستخدم | موديولات | شاشات |
|---|---|---|
| مسؤول التسجيل | 41 | 448 |
| رئيس القسم | 23 | 144 |
| عضو هيئة تدريس | 14 | 109 |
| الطالب | 11 | 102 |
| عميد الكلية · شؤون الطلاب · الشؤون المالية · القبول … | — | 579 |
معظم ده مش شغل موبايل — اعتمادات بالجملة، بناء الجداول والعروض، اعتماد النتائج، تقارير، إعدادات لائحة. دي شاشات مكتب: بتتعمل مرة في الترم، على شاشة كبيرة، وبتتطلب تركيز. اللي يستاهل الموبايل هو اللي صغير ومتكرر وبيحصل وانت واقف.
اللي اتعمل
| الشاشة في الـ SIS | الإندبوينت | ليه موبايل |
|---|---|---|
| طالب · Academic Affairs → Semester Activity Marks |
students/GetCourseworkMarks |
الدرجات اللي بتتجمّع خلال الترم. كان عندنا النتيجة النهائية والسجل بس — يعني الطالب يشوف نتيجته بعد ما تخلص، وعمره ما يشوف هو واقف فين. ١٤٢٬٥٣٩ صف داتا حقيقية، وبيقرا اللي شيت الدرجات بتاع الدكتور بيكتبه. |
| دكتور · My Academic Duties → Faculty Academic Load |
academicstaff/GetTeachingLoad |
«أنا بدرّس قد إيه؟» — سؤال بيتسأل في الممشى. كان عندنا الجدول وقائمة المقررات، ومحدش فيهم بيرد عليه. |
| دكتور · My Academic Duties → Office Hours |
academicstaff/GetMyOfficeHoursacademicstaff/SaveOfficeHour |
الطالب كان بيقراها وصاحبها ماكانش بيقدر يعدّلها — بالعكس. تأجيل ميعاد ساعة واحدة حاجة بتحصل بين محاضرتين، ومابتتعملش لأنها بتحتاج فتح البورتال. |
coursework marks → 26 marks, e.g. INT302 Clinical Exam 20/20 · Final Exam 26.5/30
teaching load → 7 courses · 12 sections · 485 students · 19 credit hours
office hours → add → visible · move → visible · delete → gone
and the STUDENT's GetOfficeHours now shows what the lecturer saved
اللي مااتعملش — وبسبب واضح
| الشاشة | ليه اتساب |
|---|---|
| تغيير كلمة السر (My Preferences) |
التنصيب ده شغّال بـ LegacyTrust — مابيتحققش من كلمة السر أصلًا،
وSE_USER مافيهاش عمود كلمة سر. الإندبوينت كان هيكتب في حتة
محدش بيقراها — شاشة بتكدب. |
| استطلاعات الرأي (Poll) | الجداول موجودة وفاضية تمامًا
(SV_POLL_HDR/DTL/STUD_POLL = صفر صف). |
| ملاحظات المحاضرات · ملصق السيارة · الهوايات · التدريب · الإعفاءات والخصومات |
مفيش جداول ليها خالص في السكيما دي. |
| الاعتمادات بالجملة · اعتماد النتائج · بناء العروض والجداول · التقارير |
شغل مكتب بطبيعته — مرة في الترم، على شاشة كبيرة. |
القاعدة اللي مشينا بيها: ماننزّلش شاشة مالهاش داتا. شاشة بترد فاضي دايمًا أسوأ من شاشة مش موجودة — الأولى بتخلّي الفريق يدوّر في الكود، والتانية بتقول الحقيقة.
إعداد صورة الطالب — لينك جاهز مش اسم ملف
الخدمة القديمة كانت بترجّع STUD_PHOTO اسم ملف بس، وكل كلاينت
يخمّن اللي قبله. ده كان ماشي لما الصور كانت جنب الخدمة — دلوقتي الصور متنشورة على
سيرفر ملفات الجامعة، فاللي قبل الاسم بقى إعداد، وتركيب اللينك مكانه الخدمة
مش كل تطبيق لوحده.
الإعداد — قسم Media في البروفايل
| المفتاح | معناه |
|---|---|
StudentPhotoBaseUrl |
جذر مجلد الصور العام، مثلاً
https://files.university.edu/students |
StudentPhotoPattern |
شكل اسم الملف تحت الجذر ده. الافتراضي {id}.jpg —
و{id} رقم الطالب، {code} الكود الجامعي،
لأن فيه تنصيبات بتسمّي الملف بده وفيه بتسمّيه بده |
DefaultPhotoUrl |
اللي يترجع لما مفيش مجلد منشور. سيبه فاضي وهتترجع الصورة الافتراضية بتاعة الخدمة |
// with Media.StudentPhotoBaseUrl configured
"STUD_PHOTO": "https://files.university.edu/students/73.jpg"
// with nothing configured — still a usable link, never an empty string
"STUD_PHOTO": "https://api.109.123.243.32.sslip.io/Files/UserImages/default.jpg"
نفس الحاجة في GetStudentUnderSuperVision وكشف طلاب المقرر —
كانوا بيرجّعوا "<code>.jpg" وبقوا لينك كامل.
http:// على هوست https.
السبب إن الـ proxy بينده الخدمة على HTTP جوّه، فـ Request.Scheme
بيقول «http» رغم إن المستخدم جاي على TLS — والمتصفح بيرفض صورة http في صفحة https
(mixed content)، يعني الصورة كانت هتختفي من غير أي رسالة. اللينك بقى بيتبني من
X-Forwarded-Proto لما الـ proxy يبعته.
والصورة الافتراضية مرسومة مش مستعارة: لو حطينا صورة طالب حقيقي كبديل، هتبقى وش راجل واحد على كل بروفايل مالوش صورة. وهي رسمة مش صورة فوتوغرافية عن قصد — عشان محدش يفتكرها الشخص نفسه.
إزاي تغيير السكشن — الدورة الكاملة
flags.CanReplaceSection بيقولك إن المقرر ينفع تتغيّر سكشنه.
اللي بعده نداء واحد بيدّيك كل حاجة: السكاشن اللي تقدر تروحلها دلوقتي، واللي مليانة،
واللي متعارضة — ومتعارضة مع مين بالظبط.
| # | النداء | بتاخد منه إيه |
|---|---|---|
| 1 | CourseReg/v2/MyCourses |
المقررات المسجّلة. اللي فيها flags.CanReplaceSection = true
هي اللي ينفع تتغيّر. وalternativeSectionCount بيقولك
فيه كام سكشن بديل — والرقم ده مطابق لإجمالي اللي هيرجع في الخطوة اللي بعدها |
| 2 | CourseReg/GetSectionsToReplace{ EdCourseId, EdStudGroupId } |
السكاشن مقسومة على ٤ قوايم جاهزة + Summary بالأعداد.
ابعت EdStudGroupId بتاع السكشن اللي الطالب دوس عليه —
مهم جدًا في المقررات اللي فيها محاضرة + عملي + إكلينيكي |
| 3 | CourseReg/SetSection{ EdCourseId, ScScheduleDtlId } |
✍️ النقل — أو الإضافة لو مالوش سكشن من النوع ده؛ الخدمة بتقرّر
وبترجّع Action. رقم التسجيل مابيتغيّرش — السكشن بس.
ولو اترفض بسبب تعارض، بيرجّع Conflict فيه مع مين |
| 4 | CourseReg/v2/MyCourses |
🔎 اقرا تاني واتعامل مع اللي راجع |
الأربع قوايم — كل واحدة ليها زرار مختلف
| القايمة | معناها | الزرار المناسب |
|---|---|---|
Sections |
فاضية ومفيهاش تعارض — تقدر تروحلها دلوقتي | «انقل هنا» ← ReplaceSection |
WaitListSections |
مليانة بس قائمة الانتظار مفتوحة | «احجز مقعد» ← AddToWaitList |
ConflictingSections |
فيها مكان، بس بتتعارض مع محاضرة تانية في جدول الطالب | «شوف التعارض» ← تعرض Conflict وتوديه يحذفه |
FullSections |
مليانة ومفيش انتظار — مفيش حاجة تتعمل | اعرضها رمادي، من غير زرار |
Summary.Available = طول Sections بالظبط،
وTotal = مجموع الأربعة. تقدر تكتب «فيه ٢ متاحين و٣ متعارضين»
من Summary على طول من غير ما تلف على المصفوفات.
وفيه رقمين زايدين بيقطعوا عرض القوايم:
WithTimeClash (كام سكشن فيها تعارض — حتى لو مليانة) و
ResolvableConflicts (كام تعارض منهم الطالب يقدر يحلّه بنفسه).
لو التانية أكبر من صفر، ساعتها بس اعرض رسالة «فضّي جدولك وارجع».
التعارض بيجيلك باسم صاحبه — دي أهم حاجة في النداء ده
كل سكشن في ConflictingSections جايّة ومعاها بلوك Conflict.
رد حقيقي من الديمو (مقرر SUR310، السكشن الإكلينيكية):
"Conflict": {
"Type": "TIME_CLASH",
"WithCourseCode": "BSM131",
"WithSectionNameEn": "01",
"WithDaysEn": "Saturday, Wednesday",
"WithFromTime": "09:00",
"WithToTime": "13:00",
"WithEdStudGroupId": 135172,
"CanResolve": true
}
(WithDaysAr جايّة معاها بالعربي، وWithEdStudGroupId
ده رقم سكشن الطالب نفسه في المقرر المتعارض — مش رقم السكشن اللي هو رايحلها.)
يعني تقدر تكتب للطالب بالحرف: «السكشن ده بتتعارض مع محاضرة BSM131 يوم الأربعاء ٩–١»،
وتحط جنبها زرار «روح احذف سكشن BSM131» —
وWithEdStudGroupId هو الرقم اللي هتبعته لـ
DeleteSection أو GetSectionsToReplace بتاع المقرر ده.
بعدها يرجع ويكمّل. ده الفرق بين رسالة خطأ ورسالة فيها حل.
CanResolve هو اللي بيقرّر تعرض الزرار ولا لأ.
true يعني التعارض مع حاجة الطالب مسجّل فيها فيقدر يحذفه.
false يعني حاجة مالوش فيها يد — اعرض السبب وبس، من غير ما توعده بحل.
مقرر بأكتر من نوع تدريس — ابعت EdStudGroupId
SUR310 مسجّل فيه الطالب بـ ٣ سكاشن: محاضرة + عملي + إكلينيكي.
«غيّر السكشن» لوحدها كلمة مالهاش معنى — أنهي واحدة فيهم؟ عشان كده الرد بيختلف:
| اللي بعتّه | الرد |
|---|---|
من غير EdStudGroupId |
٢ بدايل — واحد للعملي وواحد للإكلينيكي، وكل واحد فيهم كاتب
ReplacesEdStudGroupId يعني هيقف مكان أنهي سكشن |
| سكشن المحاضرة | NO_ALTERNATIVE — مفيش محاضرة تانية للمقرر ده |
| سكشن العملي | بديل واحد (SEC 2) — مليان 28/28 |
| سكشن الإكلينيكي | بديل واحد (HOSPITAL 2) — مليان، وكمان متعارض مع BSM131 |
CanReplace: false، الـReason بيقول ليه:
NO_ALTERNATIVE (مفيش سكشن تاني من نوعها) ·
ALL_FULL (فيه بدايل بس كلها مليانة) ·
ALL_CONFLICT (كلها متعارضة — وده اللي ينفع تعمله حاجة) ·
NONE_AVAILABLE (خليط) ·
GROUPED_REGISTRATION ·
WINDOW_CLOSED · STUDENT_BLOCKED · NOT_REGISTERED ·
NO_SECTION.
اعرض السبب زي ما هو — «مفيش سكاشن تانية» و«كلها مليانة» و«كلها متعارضة» تلات رسايل مختلفة للطالب، وكانوا كلهم قبل كده قايمة فاضية.
ReplaceSection بيتأكد من التعارض تاني وقت الكتابة (لأن حد تاني
ممكن يكون خد المكان في الوقت ده). لو رفض بسبب تعارض بيرجّع نفس بلوك
Conflict — فاعرضه بنفس الشاشة بتاعتك، مش برسالة «حصل خطأ».
GROUPED_REGISTRATION
فيه تسجيلات بتتعمل على مجموعة سكاشن — الجدول بيربط المحاضرة بالعملي بتاعها عشان يتاخدوا مع بعض. في الداتا دي ٣١٨٥ تسجيل من ٥٧٦٦٧ (٥٫٥٪) من النوع ده.
البورتال بيبدّل المجموعة كلها مرة واحدة. إحنا بنحرّك صف سكشن واحد — ولو عملناها على تسجيل مربوط بمجموعة، التسجيل هيفضل مسجّل على المجموعة القديمة وواحدة من سكاشنه خرجت منها. عشان كده الخدمة بترفض، ومابتعملش نُص عملية.
في التطبيق: اعرض «السكشن ده مربوطة بمجموعة — التغيير من شؤون التسجيل». والرفض ده متحطّ في النداءين (البيكر و
ReplaceSection)
عشان محدش يعدّي عليه بنداء مباشر.
CurrentSections لوحدها، عشان تعرضها فوق كـ«إنت هنا دلوقتي».
وأي سكشن تاني من نفس المقرر مابتتحسبش تعارض لو هي اللي خارج منها — كانت دي
بتخلّي كل البدايل تبان متعارضة والقايمة تطلع فاضية.
قاعدة هوية المستخدم من التوكن — للطالب وللدكتور
مش محتاج تبعت رقم الطالب ولا رقم عضو هيئة التدريس. الخدمة بتاخدهم من التوكن، وأي رقم في الـ body بيتتجاهل.
| التوكن | فيه إيه | بيتحط فين |
|---|---|---|
| طالب | edStudId |
أي حقل اسمه ED_STUD_ID / EdStudId في أي ريكوست |
| دكتور | stfMemberId |
أي حقل اسمه SaStfMemberId / saStaffMemberId |
الإندبوينتات الجديدة حذفت الحقل من العقد أصلاً (JsonIgnore) —
يعني مش هتلاقيه في الـ body: ReplaceSection،
DeleteSection، AddToWaitList،
CancelWaitList، GetCourseworkMarks.
القديمة سايبة الحقل عشان الكود القديم مايقعش، بس مابتصدّقهوش.
حقل بتبعته ويتغيّر في السكوت بيوحي إنه مهم — وهو مش مهم.
SE_USER_ACCNT.USER_TABLE_ID بيشاور على ED_STUD
لو الحساب طالب، وعلى SA_STF_MEMBER لو موظف.
والأرقام بتتقاطع: الرقم 148 في الداتابيز دي هو الدكتور اللي بنجرّب بيه،
وكمان رقم طالب لشخص تاني خالص. والرقم 73 هو الطالب بتاعنا
وكمان رقم دكتورة.
عشان كده الرقم دلوقتي بيتأكد من الجدول اللي نوع المستخدم بيقوله قبل ما يتحط في التوكن —
يا إما يشاور على شخص حقيقي من النوع الصح، يا إما مايترجعش أصلاً.
USER_TABLE_ID بيتملي على حساب واحد بس منهم والباقي فاضي.
كنا بناخد أول صف من غير ترتيب، فالرقم كان بيرجع فاضي لأي حد عنده أكتر من حساب:
٢٧٩ من ٤٩١ صف موظف بس اللي كان بيتحل. بعد ما رتّبنا «اللي فيه رقم الأول»
بقى ٢١١ من ٢٢٢ مستخدم.
19 التسجيل المطوّر — تابين ووحدة القياس بقت «طريقة التدريس»
التسجيل في الـ SIS مش لكل مقرر — هو لكل مقرر × كل طريقة تدريس. الطالب اللي مسجّل تمارين BS100 ومش مسجّل محاضرتها هو مسجّل ومش مسجّل في نفس الوقت، والقايمة الواحدة القديمة كانت تقدر تقول واحدة بس من الاتنين. الشاشة دلوقتي تابين، ووحدة القياس فيهم طريقة التدريس.
القاعدة التابين بيكمّلوا بعض، مابيتقاطعوش
اللي تاب «مقرراتي» بيقول عليه مسجّل هو بالظبط اللي غايب من تاب «المتاح». المقرر اللي اتسجّلت محاضرته ولسه معمله فاضي بيظهر في الاتنين: في الأول بطريقة التدريس المسجّلة، وفي التاني بطريقة التدريس الناقصة بس. وأول ما آخر فراغ فيه يتملي بيختفي من تاب «المتاح» خالص.
| التاب | الإندبوينت | فيه إيه |
|---|---|---|
| مقرراتي | CourseReg/v2/MyCourses |
كل تسجيلات الفصل بكل الحالات — مسجّل، محذوف، منسحب، في الانتظار.
كل مقرر معاه TeachingMethods (كل طرق تدريسه وحالة الطالب في كل واحدة)
وSections مسطّحة زي ما هي |
| المتاح | CourseReg/v2/AvailableCourses |
كل حاجة لسه ينفع تتضاف — مقرر كامل، أو النص الناقص من مقرر الطالب ماسكه بالفعل. المحذوف مش منهم: إرجاعه مش إضافة |
على الشاشة طريقة التدريس سطر، مش صندوق
أول نسخة من الشاشة عملت كل طريقة تدريس صندوق بشارة حالة وزرارين. على مقرر بيتدرّس بتلات طرق ده طلّع تلات صناديق متداخلة، ستة أزرار، «غيّر السكشن» مكتوبة مرتين ومفيش على الزرار حاجة تقول بيغيّر أنهي واحدة، وشارتين — «مفيش سكاشن معروضة» و«مافيش سكشن» — شكلهم واحد بالعربي ومعناهم عكس بعض (واحدة مشكلة الكلية، والتانية مشكلة الطالب). الكارت طلع أطول من الموبايل والطالب مش عارف يدوس على إيه.
دلوقتي: سطر واحد لكل طريقة تدريس، والسطر نفسه هو الزرار، ونصّ السطر هو حالته — إما «اختار سكشن» بالبرتقالي، أو ميعاد ومكان السكشن اللي هو فيه. مفيش شارات على السطور خالص. وكل الإجراءات نزلت دوسة واحدة لجوه — في الـ sheet اللي بتفتح على طريقة التدريس، وهي كمان المكان الوحيد اللي «احذف السكشن» فيه مالهاش غير معنى واحد. وإسقاط المقرر كله بقى لينك أحمر صغير مش زرار عريض بينافس الحاجة اللي الطالب جاي يعملها.
الشكل السكاشن فضلت مسطّحة — والربط شغلة التطبيق
كان الشكل البديهي إننا نحطّ السكاشن جوّه طرق التدريس. ده كان غلط: بيقرّر تصميم الشاشة
نيابةً عن التطبيق، وشاشة عايزة جدول عادي هتفكّ الشجرة الأول عشان ترسمه. فالسكشن فضل في
Sections مسطّحة، وكل سكشن شايل TeachingMethodId بتاعه،
والربط سطر واحد عند الموبايل — وده اللي الديمو بيعمله بالظبط.
TeachingMethods[].RegisteredSectionIds، وصفوف الطالب اللي بيتشال منها
في RegisteredEdStudGroupIds.الحالات أربع كلمات بس — وكل واحدة بتودّي لمكان مختلف
State | يعني | الخطوة اللي بعدها |
|---|---|---|
REGISTERED | الطالب ماسك سكشن من النوع ده | غيّر السكشن (SetSection) أو احذفه
(DeleteSection) |
NOT_REGISTERED | مش ماسك ولا واحد، وفيه سكاشن يختار منها | افتح البيكر على طريقة التدريس دي — ده اللي التاب اتعمل عشانه |
NO_SECTIONS_OFFERED | المقرر بيتدرّس كده بس مفيش سكشن معروض خالص | مفيش — دي مش مشكلة الطالب، وماينفعش يتعرض عليه زرار |
UNKNOWN | الـ offering مش شايل رابط طريقة تدريس أصلاً | مفيش — أحسن ماتقولش حاجة عن النوع من إنك تقول حاجة غلط |
والكورس المحذوف بقى بيرجّع طرق تدريسه. الاستعلام القديم كان فيه
ED_CODE_COURSE_STATUS_ID = 1، فالمقرر المحذوف كان بيرجع من غير أي طرق
تدريس — وده بالظبط الطالب اللي على وشك يرجّعه ومحتاج يشوف هيحتاج إيه بعد كده.
البيكر «افتح المعمل» — سؤال ماكانش ينفع يتسأل
GetSectionsToReplace كان بياخد السكشن اللي هيتبدّل ويستنتج منه
طريقة التدريس. طب وطريقة التدريس اللي الطالب مش ماسك فيها ولا سكشن؟ مفيش
ED_STUD_GROUP نستنتج منه، فالرد كان بيرجع المقرر كله. بقى ياخد
EdCodeCourseTeachingId على طول.
| الحقل الجديد | بيعمل إيه |
|---|---|
EdCodeCourseTeachingId |
يحصر الرد على طريقة تدريس واحدة — سواء الطالب ماسك فيها سكشن أو لأ |
TeachingMethodId |
نفس السؤال بالـ id التاني، للعروض اللي مش شايلة رابط تدريس |
TeachingMethods |
كل طرق تدريس المقرر وحالة الطالب فيها — عشان بيكر جاي من نوتيفيكيشن مايحتاجش ينده الكارت كمان |
RequiresUnDrop + NextAction |
المقرر محذوف: السكاشن بتترجع كاملة (الطالب بيقرّر يرجّعه ولا لأ) بس كل الأزرار متقفلة والزرار الشغال الوحيد هو التراجع عن الإسقاط |
وكمان: لما كنت تبعت EdStudGroupId، صفوف الـ PICK كانت
بتتشال. يعني الشاشة اللي بتقولك «أنا ببدّل السكشن ده» كانت بتخفي عنك طرق التدريس الناقصة.
دلوقتي بتفضل.
التراجع الـ UnDrop بقى ميختارش السكشن
الحذف بيمسح صفوف ED_STUD_GROUP فيزيكال، ومفيش أي جدول في الـ SIS بيفتكر
السكاشن دي كانت إيه — ED_STUD_COURSE_CHNG على مستوى المقرر بس، مفيهاش
SC_SCHEDULE_DTL_ID. يعني مفيش حاجة اسمها «تراجع عن حذف سكشن»؛
اللي بيحصل هو تسجيل من جديد. وبعد كام يوم يكون السكشن اتملى من طلبة تانيين أصلاً.
فالاختيار التلقائي كان تخمين من غير أي معلومة وراه — وأسوأ: الاستعلام بتاعه كان بيفلتر
على IS_CLOSED بس. من غير فحص مقاعد، ولا
ONLINE_FLG، ولا INTERNAL_FLG، ولا تعارض، ولا
طريقة تدريس. يعني كان بيقدر يقعّد الطالب في سكشن فوق سعته أو سكشن ماكانش المفروض يشوفه.
UnDropCourse بيرجّع المقرر بس، وبيرجّع
معاه TeachingMethods وNeedsSection وNextAction على
البيكر. اللي عايز الاختيار التلقائي يبعت AssignSection: true — وساعتها
بقى آمن: واحد لكل طريقة تدريس، وبس اللي فيه مقعد ومافيهوش تعارض.إصلاحات تلاتة اتشحنوا للكل — مش ورا flag
التلاتة من نفس العيلة: كانوا بيدّوا نتيجة تبان ناجحة والداتا وراها غلط. حاجة زي دي ماينفعش تفضل هي السلوك الافتراضي.
| # | كان بيحصل إيه | بقى |
|---|---|---|
| 1 | فحص «المقرر مسجّل بالفعل» في RegisterGuards مكتوب
ISNULL(...) <> 6 — يعني المقرر المحذوف بيعدّي
ويتعمله صف ED_STUD_COURSE_REG تاني لنفس المقرر في نفس الفصل،
والساعات تتحسب مرتين |
بيترفض بـ Reason: COURSE_DROPPED ورسالة بتقول اعمل تراجع.
وتاب «المتاح» بيعرض تراجع مش سجّل على المقرر ده |
| 2 | الاختيار التلقائي في التراجع، بالتفصيل اللي فوق | اتشال من الافتراضي، وبقى آمن لما يتطلب صراحةً |
| 3 | فحص المقعد كان برّه الترانزاكشن في
AddSection وReplaceSection — التعارض
كان بيتفحص مرتين (قبل وجوّه) والمقعد مرة واحدة برّه. طالبين شايفين «فاضل مقعد
واحد» يعدّوا الاتنين ويكتبوا الاتنين → السكشن فوق سعته |
فحص المقعد نزل جوّه الترانزاكشن بعد الكتابة، وRollback لو
راح. والرفض بيرجّع Alternatives — بدايل نفس طريقة التدريس، حيّة
دلوقتي، بأزرارها — فالطالب يشوف «المقعد راح، دول المتاح» في نداء واحد |
SectionsWithSeats. الأرقام دي بتبوظ مع الوقت — كل فتح للبيكر = نداء جديد.القوانين السكشن بيتعرض ومقفول بسبب — مش بيتخفي
دورة العمل (التابين وطرق التدريس) تصميم جديد. لكن قوانين التسجيل مش تصميم — مرجعها
الويب فورمز، وأول نسخة من الشاشة اجتهدت فيها بدل ما تقراها. البورتال في
UcRegisteredCourses وUCRegisterAddReplaceCourseDirect_SEC
بيعرض كل السكاشن للطالب وبيقفل اللي مايتسجلش ويكتب السبب — وإحنا كنا بنخفيها.
الفرق مش شكلي: أكتر من نص سكاشن العملي والمحاضرات على الداتابيز دي
ONLINE_FLG = 0 (شؤون التسجيل بتقعّد الدفعة يدوي). الطالب اللي قاعد في
واحدة منها كان بيفتح البيكر فيلاقيه فاضي — لا سكشنه ظاهر ولا فيه زرار يحذفه. اتقفل عليه
في سكشن من الشاشة اللي وظيفتها تطلّعه منه.
| الشرط | BlockedReason | الكلمة في البورتال |
|---|---|---|
ONLINE_FLG = 0 (للطالب بس) | NOT_ALLOW_ONLINE | NotAllowOnline |
INTERNAL_FLG = 1 (للطالب بس) | INTERNAL | Internal |
IS_CLOSED = 1 | IS_CLOSED | IsClosed |
| تعارض امتحان | EXAM_CONFLICT | ExamConflict |
SEC_CONF_SC_SCHEDULE_DTL_ID مش null | SCHEDULE_CONFLICT | ScheduleConflict |
| المقاعد والانتظار خلصوا الاتنين | FULL | Full |
الانتظار زرار واحد — والـ SIS يقرر مقعد ولا طابور
«مليان» عند البورتال معناها NO_STUDENTS = Reg_Stud_Count
و NO_STUD_WAIT = Wait_Stud_Count. يعني المقاعد خلصت والطابور فيه
مكان = مش مليان: الصف يفضل شغّال، والتسجيل بيكتب
WAIT_NO = عدد اللي في الطابور + 1.
CourseReg/AddToWaitList اتشال كـ endpoint — الهاندلر بتاعه فضل
جوّه RegisterNewCourse عشان المقرر اللي الطالب مش ماسكه أصلاً: الطابور
هناك معناه تسجيل بحالة 7، مش صف سكشن.الامتحانات القاعدة التلاتية — بالحرف
مكتوبة كده بالظبط في أربع كنترولز في البورتال:
OperationType != Replace && EXP_FOR_GRAD != 1 && EXM_CONF_ED_EXAM_SCHDL_ID != nullيعني تعارض الامتحان بيمنع السكشن بس لو العملية مش استبدال و الطالب مش متوقع تخرجه. الاستبدال معفى لأن امتحان المقرر أصلاً على جدول الطالب — النقل بين سكاشنه مش هيغيّر ده. والمتوقع تخرجه معفى عشان اللائحة تفضّل يمتحن متعارض على إنه يستنى ترم كمان.
المصاحب القاعدة حقيقية والأتمتة بتاعتها مكسورة
ED_COURSE_COREQ أربع أعمدة بس، والزوج جروب فيه صف
IS_MAIN = 1 وجنبه IS_MAIN = 0. على الداتابيز دي
٣١ زوج، كلهم تمريض/إكلينيكي (NUR203↔CLN202، NUR201↔CLN201 …).
البورتال بيحاول يسجّل المصاحب تلقائياً — والكود غلط: بيبعت
objEdCourseCoreq.EdCourseCoreqId، وده المفتاح الأساسي، في مكان
رقم المقرر (المفاتيح ١..٦٢ وأرقام المقررات بتبدأ من ٤٣٢). الفحص اللي فوقه بيستخدم
EdCourseId الصح، فالنية واضحة والتنفيذ مكسور.
CoRequisites وCoRequisiteNote — «لازم يتاخد مع CLN201 — سجّله معاه» —
والطالب يسجّله بنفسه. مافيش صف بيتكتب البورتال مش قادر يكتبه.
١٢٩ طالب على الترم الحالي عندهم نص زوج ناقص.استثناء تجاوز التعارض بقى فلاج في البروفايل
البورتال بيقارن كود العميل بـ "ecu" / "baha" / "ucb" في السورس عشان يقرر هل السكشن المتعارض
ينفع يتسجّل. نفس القرار بقى داتا:
registration.allowConflictOverride في الـ Client Profile، مقفول
افتراضياً. تشغيله لجامعة جديدة بقى تعديل بروفايل مش تعديل كود.
وNO_STUD_MAX ماتنفذتش عن قصد: مافيهاش أي استخدام في مسار
التسجيل في البورتال — بتظهر بس في شاشات تجهيز السكشن وبتتقارن بسعة القاعة — وعلى الداتابيز
دي هي مطابقة لـ NO_STUDENTS في كل الـ ١٨٥٤ سكشن. تنفيذها كان هيدي نفس
الرقم بالظبط وكود يوهم إن فيه سعتين.
بيانات الاختبار سكاشن مزروعة — وإزاي تشيلها
الترم الحالي على Innovation_Demo كان بيعرض سكشن واحد لكل (مقرر × طريقة
تدريس) في كل الحالات تقريباً، فتلات حالات من أربعة في البيكر ماكانش ينفع توصلها أصلاً:
اختيار حقيقي بين بدائل، تعارض في الجدول، وسكشن مليان بطابور. مش عيب في الكود — الداتا هي اللي
مافيهاش الحالات دي.
فاتزرعت ٧ سكاشن على خمس أزواج (مقرر × طريقة تدريس) بيمسّوا طلبة الاختبار فعلاً، و سعة سكشنين قايمين اتنزّلت لعدد المسجلين فيهم بالظبط عشان يقروا «مليان» — واحد بطابور مفتوح وواحد من غير، لأن الاتنين ردّين مختلفين على الشاشة. مافيش تسجيلات طلبة اتلمست، ومافيش جدول أي سكشن الطالب قاعد فيه اتغيّر.
| الطالب | الحالة اللي بيوصلها |
|---|---|
abdelrahman.baker.24040153 |
الأربعة في شاشة واحدة — NUR203 نظري: متاح واسع · متاح بـ٣ مقاعد · مليان بطابور · متعارض مع CLN202. وCLN202 ميداني فيه بديل واحد لـ«انقل هنا» |
ziad.shehata.25030040 |
CF127 معمل — سكشنه القديم مش معروض أونلاين، فبقى فيه بديل معروض |
moaz.ibrahim.25060107 |
BSM114 محاضرة — أول سكشن معروض للطالب |
abdelrahman.elsayed.24010068 |
BAS210 عملى — أول سكشن معروض للطالب |
mohamed.mohamed.24040217 |
UNI101 محذوف ومعمله مليان من غير طابور — «مليان» من غير زرار، وفوقيهم «تراجع عن الإسقاط» |
·
abdelrahman.baker.24040153 (تمريض) — وحده فيه كل حاجة تقريباً:
مسجل · محذوف · منسحب · مقرر مسجّل من غير سكشن · متطلب مصاحب ناقص · والثمانية أسباب في
البيكر (متاح · انتظار · مليان · تعارض جدول · تعارض امتحان · مش متاح إلكتروني · لطلبة القسم · مقفول).
·
ziad.shehata.25030040 (علاج طبيعي) — مقرر ناقصه معمل وراه ٥
سكاشن بحالات مختلفة · استبدال · محذوف · منسحب.NOTES = 'MOBILE-DEMO-SEED-20260910'، وكل الـ ids والقيم القديمة مسجّلة في
ZZ_MOBILE_DEMO_SEED_20260910: امسح صفوف INSERTED_*، رجّع
OldValues لصفوف CHANGED_CAP، وامسح الجدول. مافيش بروسيدجر ولا سكيما
اتغيّرت.القديم مجمّد، شغال، ومحدّش بيناديه
LoadRequest وGetNewCourses و
GetUnDropCourse وGetCourseSections ماتغيّرش
فيهم حرف — التطبيق المنشور شغال زي ما هو. اتعمل راوت جديد بدل ما نزوّد flag على
GetNewCourses لسبب واحد: الـ flag ممكن ما يتبعتش، وساعتها الهجرة تبقى
نُص هجرة ومحدّش واخد باله. الراوت الجديد إما اتنده أو لأ.
والكتابة اتوسّعت في مكانها ما اتفرّعتش: SetSection بيقرّر لوحده
إضافة ولا نقل من حالة الداتابيز، ولو عملنا نسخة تانية منه أول باج نصلّحه في واحد يخلّي طالبين
اتسجّلوا بقاعدتين مختلفتين.
20 مرجع البرمجة — التسجيل المطوّر
الفصل اللي فات بيقول ليه الشاشة بقت كده. الفصل ده مكتوب لواحد بيكتب الشاشة: ترسم إيه، وتبعت إيه، وتعمل إيه بالردّ. كل الحقول والأرقام اللي هنا مقروءة من ردّ السيرفس الشغّالة — مش من الذاكرة.
ابدأ من هنا إنت بتبني إيه بالظبط
شاشة واحدة، تابين، وثلاث نداءات مش أكتر. كل اللي بعد كده تفاصيل.
| اللي بترسمه | جاي منين |
|---|---|
| تاب «مقرراتي» — كروت المقررات اللي الطالب مسجّلها (بكل الحالات) | POST CourseReg/v2/MyCourses |
| تاب «المتاح» — كروت اللي لسه ينفع يتضاف | POST CourseReg/v2/AvailableCourses |
| الشيت اللي بيفتح لما يدوس على سطر طريقة تدريس | POST CourseReg/GetSectionsToReplace |
وأهم فكرة في الموضوع كله:
عشان كده الكارت جوّاه سطر لكل طريقة تدريس (
TeachingMethods[])،
وكل سطر ليه حالته وزراره. الكارت نفسه بيحمل اسم المقرر وحالته العامة بس.
ولو عايز تعرف إنت بتشتغل صح ولا لأ، دي أربع قواعد تختصر الدليل كله:
| # | القاعدة | ليه |
|---|---|---|
| ١ | ماتحسبش حاجة بنفسك. المقاعد والتعارضات والصلاحيات كلها محسوبة وجايالك جاهزة | التعارض بيتحسب من جدول الطالب كله — التطبيق ماعندوش نُصّ المعلومة دي |
| ٢ | الزرار جايلك ومعاه نداءه. إنت بترسم
Label وتبعت Endpoint وBody زي ما هما |
أكتر مكان اتغلط فيه قبل كده هو تركيب الـ body باليد على مقرر بأكتر من طريقة |
| ٣ | صدّق Data.Status — مش
result ولا الـ HTTP |
الرفض بييجي بـ 200 و"result": "Ok" |
| ٤ | بعد أي كتابة، نادِ التابين. مش واحد | الكتابة الواحدة بتغيّر الاتنين: سجّلت من «المتاح» → ظهر في «مقرراتي» واختفى من «المتاح» |
الردّ شكل اللي هيوصلك — بالحقل
| النداء | الـ body اللي بتبعته |
|---|---|
POST CourseReg/v2/MyCourses |
{ "LANG": "ar" } |
POST CourseReg/v2/AvailableCourses |
{ "LANG": "ar" } |
POST CourseReg/GetSectionsToReplace |
{ "EdCourseId": 528, "EdCodeCourseTeachingId": 33, "LANG": "ar" } |
POST CourseReg/GetAllowedActions | { } |
EdStudId
تحطه في الـ body بيتكتب فوقه. فمتبعتوش أصلاً — في القراءة والكتابة.«مقرراتي»:
Data
Agenda { Register, Add, Drop, Withdraw, RegisterSection, IsActiveStudent, AnyOpen }
IncompleteCount : int <- البادچ اللي على التاب
Courses[]
EdCourseId, EdStudCourseRegId, CourseCode, CourseNameAr, CourseNameEn, CreditHours
State : "ACTIVE" | "DROPPED" | "WITHDRAWN" | "WAITING" | ...
StateLabelAr / StateLabelEn <- الكلمة الجاهزة للعرض
StatusId : 1|2|6|7|... <- لو محتاج تفرّع برقم
IsComplete : bool <- ماسك سكشن من كل طريقة تدريس؟
TeachingMethods[] <- سطور الكارت
MissingTeachingMethods[] <- نفس الشكل، الناقص بس
Sections[] <- اللي هو قاعد فيها، مسطّحة
CoRequisites[] , CoRequisiteNote
Flags { CanDrop, CanUnDrop, CanReplaceSection, CanDeleteSection, IsDropped, BlockedReason }
Display { Title, Subtitle, Place, Meta, Badge, BadgeTone, Note }
Actions[] <- الأزرار
Error : string|null
«المتاح» — نفس الشكل تقريبًا، وفيه حقلين زيادة:
Data
PartialCount : int <- مقررات مسجّلة لسه ناقصها طريقة
Courses[]
Mode : "REGISTER_COURSE" <- ماسكهوش خالص
| "ADD_METHOD" <- ماسكه، ودي الطريقة الناقصة بس
PrereqProblem <- في REGISTER_COURSE بس
Sections[] <- SectionOption كامل (مش مسطّح)
الشيت (البيكر) — الردّ سلال، مش لستة واحدة:
Data
CurrentSections[] <- اللي هو فيها من الطريقة دي (ممكن تكون فاضية)
Sections[] <- يتاخدوا دلوقتي
WaitListSections[] <- يتاخدوا برضه — وبيحطّوه في الطابور
ConflictingSections[] <- مطفيين
FullSections[] <- مطفيين
BlockedSections[] <- مطفيين
TeachingMethods[] , MissingTeachingMethods[] , NeedsSection
RequiresUnDrop , NextAction , ExamClashes[] , Reason , Summary , Display
[...Sections, ...WaitListSections] (دول اللي زرارهم شغّال)، وتحتيهم
تحت عنوان «مش متاحة دلوقتي»
[...ConflictingSections, ...FullSections, ...BlockedSections]
مطفيّين ومكتوب تحت كل واحد سببه. ده اللي الديمو بيعمله.أهم سؤال ليه مقرر أنا مسجّله بيظهر في «المتاح»؟
لأن وحدة التسجيل مش المقرر — هي المقرر × طريقة التدريس. الطالب اللي ماسك نظري UNI101 ومش ماسك المعمل هو مسجّل ومش مسجّل في نفس الوقت، والنص الناقص ده لازم يكون ليه مكان في تاب الإضافة — مش مستني الطالب يعرف لوحده إنه يرجع لتاب «مقرراتي».
فتاب «المتاح» بيرجّع حاجتين مختلفتين، ومعاهم أربع علامات بتفرّق بينهم:
| الحقل | مقرر جديد بالكامل | مقرر ماسكه وناقصه طريقة |
|---|---|---|
Mode | REGISTER_COURSE | ADD_METHOD |
EdStudCourseRegId | مش موجود | موجود — ده تسجيله الحالي |
Display.Badge | مافيش | «ناقص» بـ BadgeTone: "warning" |
Display.Subtitle | مافيش | «لسه ناقص: معمل» |
TeachingMethods[] | كل طرق تدريس المقرر | الناقصة بس — المحاضرة اللي هو ماسكها مش راجعة |
Sections[].Actions[0] |
→ CourseReg/RegisterNewCourse |
→ CourseReg/SetSection |
// كارت تاب «المتاح» — فرّق بين الاتنين وخلاص
if (c.Mode === 'ADD_METHOD') {
return <Card title={c.Display.Title}
badge={c.Display.Badge} // «ناقص»
hint={'إنت مسجّل في المقرر ده بالفعل — ' + c.Display.Subtitle}
methods={c.TeachingMethods} />; // الناقصة بس
}
return <Card title={c.Display.Title} badge="جديد" methods={c.TeachingMethods} />;
PartialCount في نفس الردّ = عدد المقررات اللي من النوع
التاني. ينفع تحطه كعدّاد جنب عنوان في الشاشة («ناقصك سكشن في مقررين»)، أو تستخدمه تتأكد
إنك بترسم الصح.IsComplete بيبقى true.
والمقرر المحذوف مش في المتاح أصلًا — إرجاعه من «مقرراتي» بس.
السطر TeachingMethod — الحاجة اللي بترسمها أكتر من غيرها
| الحقل | يعني إيه | بتعمل بيه إيه في الشاشة |
|---|---|---|
TeachingMethodAr / En | محاضرة · معمل · عملي · إكلينيكي… | عنوان السطر |
State |
REGISTERED · NOT_REGISTERED ·
NO_SECTIONS_OFFERED · UNKNOWN |
شكل السطر والدوسة — الجدول اللي بعده |
EdCodeCourseTeachingId |
مفتاح «المقرر × الطريقة» | ده اللي بتبعته للشيت، وبتربط بيه سكاشن تاب المتاح |
TeachingMethodId |
نوع الطريقة (١ محاضرة · ٢ تمارين · ٣ معمل · ٤ عملي · ١٢ إكلينيكي · ٢١ نظري · ٢٢ ميداني) | للأيقونة، وللربط لو الأولاني رجع null |
RegisteredSectionIds[] |
أرقام السكاشن اللي هو فيها من الطريقة دي | بتفلتر بيها Sections عشان تكتب ميعاده ومكانه تحت اسم الطريقة |
RegisteredEdStudGroupIds[] |
صفوف تسجيله | الحذف بيشتغل عليها — بس إنت مش محتاج تلمسها، الزرار جاهز |
SectionsAvailableToTake |
كام سكشن فيه مكان ومش اللي هو قاعد فيه | الرقم اللي تكتبه: «اختار سكشن (٣ متاح)» |
SectionsOffered | كل سكاشن الطريقة دي | صفر = الكلية ما نزّلتش سكاشن. مش غلط عندك |
IsRegistered · CanPick |
اختصارين محسوبين من State |
لو مش عايز تكتب switch |
وده شكل رسم الكارت في الكود:
{course.TeachingMethods.map(k => {
const held = course.Sections.filter(s => k.RegisteredSectionIds.includes(s.SC_SCHEDULE_DTL_ID));
if (k.State === 'NO_SECTIONS_OFFERED')
return <Row title={k.TeachingMethodAr} note="الكلية لسه ما نزّلتش سكاشن" disabled />;
if (k.State === 'REGISTERED')
return <Row title={k.TeachingMethodAr} ok
subtitle={held[0]?.display?.Subtitle} place={held[0]?.display?.Place}
onPress={() => openSheet(course.EdCourseId, k.EdCodeCourseTeachingId)} />;
return <Row title={k.TeachingMethodAr}
note={'اختار سكشن (' + k.SectionsAvailableToTake + ' متاح)'}
onPress={() => openSheet(course.EdCourseId, k.EdCodeCourseTeachingId)} />;
})}
السكشن SectionOption — اللي بيتعرض في الشيت
| الحقل | يعني إيه |
|---|---|
ScScheduleDtlId | رقم السكشن — المفتاح اللي كل حاجة ماشية عليه |
Status |
AVAILABLE · WAITLIST · CONFLICT ·
EXAM_CONFLICT · FULL · BLOCKED · CURRENT |
Blocked + BlockedReason |
مايتاخدش، والسبب بكود |
GoesToWaitList |
المقاعد خلصت والطابور مفتوح — السكشن لسه يتاخد. مش زرار تاني |
Mode |
PICK (اختيار جديد) · REPLACE (هينقل من سكشنه) · CURRENT (هو فيه) |
Display |
النص جاهز: Title · Subtitle (اليوم والميعاد) ·
Place (القاعة والمبنى) · Meta (المقاعد) ·
Badge + BadgeTone · Note (جملة السبب أو التعارض) |
Actions[] | الزرار — أو زرار مطفي ومعاه DisabledReason |
Conflict |
لو فيه تعارض: WithCourseCode ·
WithSectionNameAr · WithDaysAr ·
WithFromTime/ToTime — لو حابب تبني الجملة بشكلك |
SeatsTotal / SeatsTaken / SeatsLeft |
المقاعد. SeatsLeft = -1 يعني بلا سقف — متعرضش رقم |
WaitCapacity / WaitTaken / WaitLeft | الطابور، ونفس قاعدة الـ -1 |
OnlineFlg · InternalFlg · IsClosed |
فلاجات الظهور. مهمة في حالة واحدة — اقرا التحذير اللي تحت |
IsCurrent · EdStudGroupId | هو فيها دلوقتي، وصفّ تسجيله |
ReplacesEdStudGroupId | هتحلّ محلّ أنهي سكشن |
Display.Note بييجي جاهز كده:
«بيتعارض مع NUR203 — سكشن ٢ (الأحد ٠٩:٠٠–١١:٠٠)». اعرضه زي ما هو. «فيه تعارض» لوحدها
معلومة ملهاش لازمة — الطالب قدامه أربع سكاشن ومحتاج يعرف أنهي اختيار بيحلّ المشكلة.Blocked: false (لازم كده، وإلا ماكنتش هترسمه). بص على
OnlineFlg: لو false — أو InternalFlg
بـ true أو IsClosed بـ true — يبقى
شؤون الطلبة هي اللي حطّته هنا، والشيت عمره ما هيدّيه زرار يرجع بيه.
يعني «احذف السكشن» أو «أسقط المقرر» هنا باب في اتجاه واحد. ماتمنعش العملية — بس حذّره قبل التأكيد.
قرار السطر ← ترسمه إزاي والدوسة تودّي فين
State | شكل السطر | الدوسة | اللي في الشيت |
|---|---|---|---|
REGISTERED |
اسم الطريقة + ميعاد سكشنه ومكانه + علامة ✓ خضرا | بتفتح الشيت | سكشنه فوق، والبدايل تحته، وزرار احذف السكشن |
NOT_REGISTERED |
اسم الطريقة + «اختار سكشن (٣ متاح)» + شيفرون | بتفتح الشيت | لستة السكاشن، وكل واحد وزراره |
NO_SECTIONS_OFFERED |
اسم الطريقة + «الكلية لسه ما نزّلتش سكاشن» — رمادي | مافيش — السطر مش زرار | — |
UNKNOWN | زي NOT_REGISTERED من غير رقم |
بتفتح الشيت | الشيت بيحسم |
NO_SECTIONS_OFFERED وNOT_REGISTERED لازم يبانوا مختلفين.
الأولانية مشكلة عند الكلية والطالب ملوش فيها حاجة؛ التانية دوره هو. أول نسخة من الشاشة
عرضتهم بنفس الشكل، فالطالب فضل يدوس على سطر مالوش جوّه حاجة.قرار السكشن ← زرار ولا جملة
Status | الشكل | الزرار | الجملة تحته |
|---|---|---|---|
AVAILABLE | عادي | شغّال — «خد السكشن ده» / «انقل هنا» / «سجّل» | — |
WAITLIST | عادي + بادچ «الطابور» | شغّال — «سجّل في قايمة الانتظار» | «المقاعد خلصت — هتتحطّ في الطابور» |
CURRENT | مميّز بإطار + بادچ «إنت هنا دلوقتي» | احذف السكشن | — |
CONFLICT | مطفي | مقفول | «بيتعارض مع NUR203 — سكشن ٢ (الأحد ٠٩:٠٠–١١:٠٠)» |
EXAM_CONFLICT | مطفي | مقفول | «امتحانه في نفس ميعاد امتحان BS100» |
FULL | مطفي | مقفول | «اتملى والطابور اتقفل» |
BLOCKED | مطفي | مقفول | حسب BlockedReason — الجدول اللي بعده |
Actions[0].Enabled بيقولك
الزرار شغّال ولا لأ، وDisabledReason وDisplay.Note
فيهم الجملة. الجدول هنا عشان تفهم ليه السكشن طلع كده.وBlockedReason بيتقري إزاي:
| الكود | الجملة اللي بتتعرض | الطالب يعمل إيه |
|---|---|---|
NOT_ALLOW_ONLINE |
«السكشن ده مش متاح للتسجيل الإلكتروني — التسجيل فيه من شؤون التسجيل» | يروح شؤون الطلبة. مافيش حاجة في التطبيق |
INTERNAL | «السكشن ده لطلبة القسم» | مش ليه — يختار غيره |
IS_CLOSED | «السكشن مقفول» | يختار غيره |
FULL | «اتملى والطابور اتقفل» | يختار غيره |
SCHEDULE_CONFLICT | جملة التعارض بالاسم | يشيل سكشن المقرر التاني أو يختار غيره |
EXAM_CONFLICT | جملة الامتحان بالاسم | مافيش حلّ من الشاشة — لازم يغيّر مقرر |
قرار الكارت ← المسموح فيه إيه
State | يبان في | الكارت شكله إيه |
|---|---|---|
ACTIVE (1) |
مقرراتي + المتاح (لو ناقصه طريقة) | كارت كامل: سطور طرق التدريس + لينك «أسقط المقرر» أحمر صغيّر |
WAITING (7) | مقرراتي | بادچ «في الانتظار» + زرار «اخرج من الانتظار» |
DROPPED (6) | مقرراتي بس | كارت مضغوط: سطرين وزرار «تراجع عن الإسقاط». من غير سطور طرق تدريس |
WITHDRAWN (2) | مقرراتي | كارت للعرض بس — مافيش أزرار خالص |
| (4 · 5 · 9) انسحاب إجباري / إلغاء / بعذر | مقرراتي | للعرض بس |
| (3 · 12 · 15) غير مكتمل / معافى / مستمع | مقرراتي | للعرض بس |
ACTIVE بيبان هناك عادي لو ناقصه سكشن.
وممكن تلاقي
CanUnDrop: false ومعاه
BlockedReason: "MAX_LOAD" — إرجاعه هيعدّي سقف الساعات. الزرار ساعتها
مطفي والسبب مكتوب، مش يتضغط ويترفض.المتطلب المصاحب مقررين بيتسجّلوا مع بعض
اللايحة بتربط مقررات ببعضها: NUR203 مع CLN202، NUR201 مع
CLN201… ٣١ زوج، كل زوج مقررين بالظبط. لما الطالب يسجّل نص الزوج،
السيرفس بتسجّل النص التاني معاه في نفس العملية.
IsComplete
بتاعه false، والطالب يختار سكاشنه من البيكر زي أي مقرر ناقص. ودي حالة إنت بترسمها
أصلاً — نفس حالة المقرر اللي رجع من الإسقاط.قبل الدوسة: كارت المقرر في تاب «المتاح» بيجيلك ومعاه الخطة كاملة.
"CoRequisitePlan": {
"WillRegister": [ <- اللي هيتسجّل معاه
{ "EdCourseId": 437, "CourseCode": "NUR105", "CreditHours": 2,
"IsRegistered": false, "IsDropped": false,
"RegisteredBefore": false, <- خده في ترم فات؟ يبقى معفي
"PassedBefore": false, "IsOffered": true }
],
"PairCreditHours": 4, <- المقرر + المصاحب
"CreditRoom": 4, <- الفاضل تحت السقف (null = مفيش سقف)
"Fits": true, <- false يعني الزرار مطفي
"BlockedReason": null,
"Note": "هيتسجّل معاه NUR105 (المجموع 4.00 ساعة) — تختار سكاشنه بعد كده."
}
Fits: false بييجي
Enabled: false ومعاه DisabledReason. ولو ماشي،
بييجي Confirm — وهي الجملة اللي تعرضها في تأكيد قبل ما تبعت.
إنت مش محتاج تحسب ولا تجمع ساعات.بعد الكتابة: الردّ بيقول اللي حصل بالاسم.
POST CourseReg/RegisterNewCourse -> Data
{ "Status": true,
"CoRegistered": [ { "CourseCode": "NUR105", ... } ],
"Note": "اتسجّل معاه NUR105 — اختار سكاشنه دلوقتي." }
| الحالة | الكارت بيقول إيه | الزرار |
|---|---|---|
| المصاحب هيتسجّل عادي | «هيتسجّل معاه NUR105 (المجموع ٤ ساعة)» | شغّال + Confirm |
| الاتنين مع بعض بيعدّوا السقف | «المجموع ٧ ساعة وإنت فاضلك ٥ — اسقط مقرر الأول» | مطفي · COREQ_MAX_LOAD |
| المصاحب متطلبه السابق مش مكتمل | «لازم يتاخد مع NUR103، ومتطلبه السابق مش مكتمل» | حسب الفلاج · COREQ_PREREQ_NOT_MET |
| المصاحب مش مطروح الفصل ده | «لازم يتاخد مع CLN201، وهو مش مطروح — راجع شؤون الطلبة» | حسب الفلاج · COREQ_NOT_OFFERED |
| الطالب خد المصاحب في ترم فات | مافيش خطة أصلاً — القاعدة «يتاخدوا مع بعض» مش «يتاخدوا تاني» | شغّال عادي |
والإسقاط والتراجع بيمشوا مع بعض برضه:
| العملية | اللي بيحصل | اللي بيوصلك |
|---|---|---|
DropCourse |
بيسقط الاتنين في عملية واحدة | CoRegistered[] + Note: «اتسقط معاه NUR105»وقبلها زرار drop بييجي ومعاه Confirm بنفس الكلام |
UnDropCourse |
بيرجّع الاتنين، والسقف بيتحسب على المجموع | CoRestored[] + Note: «رجع معاه NUR105 — اختار سكاشنه هو كمان» |
| قايمة الانتظار | مابيسجّلش المصاحب — مقعد لسه ماجاش | Note: «هيتسجّل معاه NUR105 أول ما تاخد مقعد» |
• المصاحب مش مطروح → «سجّل وحذّر» (الافتراضي) أو «ارفض».
• إسقاط/إرجاع نص الزوج → «حرّك الاتنين» (الافتراضي) أو «حرّك اللي اختاره وحذّر».
الفلاج التاني بيحكم الاتجاهين عن قصد — جامعة بتسمح بإسقاط نص زوج وبترفض إرجاع نصه بتقول للطالب قاعدتين مختلفتين.
الأكشنز الزرار جايلك ومعاه نداءه
كل زرار في الشاشة بييجي من السيرفس بالشكل ده. اللي بتعمله: ترسم Label، ولو
Enabled = false تطفّيه وتكتب DisabledReason،
ولو اتضغط تبعت Endpoint بالـ Body زي ما هو.
{
"Key": "pickSection",
"Label": "خد السكشن ده",
"Tone": "primary",
"Enabled": true,
"DisabledReason": "",
"Endpoint": "CourseReg/SetSection",
"Body": { "EdCourseId": 528, "ScScheduleDtlId": 2279, "EdStudGroupId": 0 }
}
async function run(action) {
if (!action.Enabled) return; // مطفي = متبعتش
const res = await post(action.Endpoint, action.Body);
const d = res.Data || {};
if (d.Status !== true) return showRefusal(d); // القاعدة الذهبية تحت
if (d.Reason === 'PLACED_ON_WAITLIST') toast('تمّ — إنت في قايمة الانتظار');
await Promise.all([loadMyCourses(), loadAvailable()]); // التابين، مش واحد
}
Key | بيعمل إيه | بيروح فين |
|---|---|---|
register | تسجيل مقرر جديد + سكشنه | CourseReg/RegisterNewCourse |
pickSection على الكارت |
يفتح الشيت — قراءة مش كتابة | CourseReg/GetSectionsToReplace |
pickSection جوّه الشيت |
ياخد سكشن لطريقة فاضية | CourseReg/SetSection |
replaceSection | ينقل من سكشن لسكشن | الشيت من الكارت، وSetSection جوّه |
deleteSection | يشيل السكشن والمقرر يفضل مسجّل | CourseReg/DeleteSection |
drop | يسقط المقرر كله | CourseReg/DropCourse |
undrop | يتراجع عن الإسقاط | CourseReg/UnDropCourse |
cancelWait | يخرج من الطابور | CourseReg/CancelWaitList |
replaceCourse | يبدّل مقرر بمقرر | CourseReg/ReplaceCourse |
Confirm لو موجود، اعرضه واستنى موافقة قبل ما تبعت. ده بيتحط على الأكشن
اللي بيعمل حاجة الليبل مابيقولهاش — «الإسقاط ده هيسقط CLN202 معاه»، «التسجيل ده هيسجّل NUR105
كمان». السيرفس هي اللي بتقرر أنهي أكشن يستاهل سؤال.Key ممكن يوّدي لإندبوينتين — pickSection على الكارت بيفتح
الشيت، وجوّه الشيت بيكتب. اتبع Endpoint دايمًا، وسيب Key
للأيقونة والتفريع بس.SetSection بيعمل «اختيار» ولا «نقل»
حسب EdStudGroupId اللي بعتّه. المقرر اللي بيتدرّس بتلات طرق عنده تلات
صفوف مختلفة، ولو بعتّ صفّ المحاضرة وإنت واقف على المعمل، هيتشال المحاضرة — والسيرفس
هتنفّذ اللي بعتّه بالظبط. الزرار الجاهز بيلغي المشكلة دي خالص.القاعدة الذهبية صدّق Data.Status — مش result
المغلّف القديم بيرجّع "result": "Ok" وHTTP 200
حتى لما العملية ترفض. لو التطبيق بيتأكد من الـ HTTP بس، التسجيل اللي اترفض هيبان
ناجح للطالب — وده حصل فعلاً.
// رفض حقيقي — بـ HTTP 200
{
"result": "Ok",
"Data": {
"Status": false,
"Error": "This would take the student to 11.00 credit hours, over the 9.00 limit",
"Reason": "MAX_LOAD",
"Conflict": null,
"Alternatives": []
}
}
if (res.Data.Status !== true) → اعرض الرفض.
وError جملة إنجليزي من محرّك التسجيل — متعرضهاش للطالب. Reason
هو الكود اللي بتترجمه، والجدول اللي تحت فيه الترجمة جاهزة.Conflict بيقول اتعارض مع أنهي مقرر
وسكشن، وAlternatives[] بيدّيك سكاشن بديلة من نفس طريقة
التدريس لسه فيها مكان — وكل واحد معاه Display وActions جاهزين.
اعرضهم في نفس الديالوج وخلّي الطالب يختار من غير ما يقفل ويفتح تاني.Status: true +
Reason: "PLACED_ON_WAITLIST" = نجحت بس بشكل مختلف — المقعد راح
والطالب اتحطّ في الطابور. الرسالة لازم تقول كده، مش «تم التسجيل» ساكت.مرجع كل أكواد الرفض — Reason
Reason | حصل إيه | تكتب للطالب إيه | وتعمل إيه |
|---|---|---|---|
MAX_LOAD | هيعدّي سقف الساعات | «العدد ده هيوصّلك ١١ ساعة والسقف ٩ — اسقط مقرر الأول» | اعرض ساعاته الحالية والسقف جنب الرسالة |
SEAT_TAKEN | آخر مقعد راح وهو بيضغط | «المقعد راح دلوقتي حالاً» | اعرض Alternatives فورًا — دي الحالة اللي اتعملت عشانها |
SECTION_FULL | مقاعد وطابور خلصوا | «السكشن اتملى والطابور اتقفل» | اعرض Alternatives |
SCHEDULE_CONFLICT · TIME_CLASH |
تعارض مواعيد | «بيتعارض مع NUR203 — سكشن ٢ (الأحد ٠٩:٠٠–١١:٠٠)» | Conflict فيه الاسم والميعاد |
EXAM_CONFLICT | تعارض امتحانات | «امتحانه في نفس ميعاد امتحان BS100» | مافيش حلّ من الشاشة |
SECTION_NOT_AVAILABLE |
السكشن مش متاح إلكتروني / مقفول / لطلبة القسم | «السكشن ده مش متاح للتسجيل الإلكتروني» | اعمل ريفريش للشيت — البيانات اتغيّرت |
COURSE_DROPPED | المقرر محذوف | «المقرر ده محذوف — ارجعه من «مقرراتي» الأول» | ودّيه لتاب مقرراتي |
ALREADY_REGISTERED | مسجّل فيه بالفعل | «إنت مسجّل في المقرر ده» | ريفريش — شاشتك قديمة |
NOT_DROPPED · NOT_REGISTERED |
طلب على مقرر مش في الحالة دي | «المقرر مش محذوف / مش في تسجيلاتك» | ريفريش |
WINDOW_CLOSED | فترة العملية مقفولة | «فترة التسجيل مقفولة دلوقتي» | ماكانش المفروض توصل هنا — اطفي الزرار من Agenda |
STUDENT_BLOCKED | الطالب موقوف | «حسابك موقوف عن التسجيل — راجع شؤون الطلبة» | اقفل الشاشة كلها من Agenda.IsActiveStudent |
GROUPED_REGISTRATION | الكلية مسجّلة المجموعة كلها | «تسجيل السكاشن للمقرر ده بيتم من الكلية» | اقفل الشيت واكتب السبب |
COREQ_MAX_LOAD | المقرر ومصاحبه مع بعض بيعدّوا السقف | «NUR203 لازم يتاخد مع CLN202 — المجموع ٧ ساعة وإنت فاضلك ٥» | ماكانش المفروض توصل هنا: الزرار بييجي مطفي من تاب المتاح |
COREQ_NOT_OFFERED | المصاحب مش مطروح الفصل ده | «لازم يتاخد مع CLN201، وهو مش مطروح — راجع شؤون الطلبة» | بيظهر بس لو الجامعة مفعّلة «ارفض» |
COREQ_PREREQ_NOT_MET | متطلب المصاحب مش مكتمل | «لازم يتاخد مع NUR103 ومتطلبه السابق مش مكتمل» | زيها |
COREQ_REFUSED | المصاحب اترفض وقت الكتابة | «المقرر المصاحب اترفض، فالاتنين ماتسجلوش» | مفيش نص تسجيل — العملية اترجعت بالكامل |
SECTION_REQUIRED | تسجيل من غير سكشن | — | باج عندك — الزرار الجاهز عمره ما بيعمل كده |
PLACED_ON_WAITLIST | نجاح — اتحط في الطابور | «تمّ — إنت في قايمة الانتظار» | ريفريش — والمقرر هيبان WAITING لو كان تسجيل مقرر جديد |
النوافذ اطفي الزرار قبل ما يترفض
كل عملية ليها فترة مفتوحة في تقويم الفصل. Agenda بيرجع مع التابين فمفيش
نداء زيادة. الزرار اللي فترته مقفولة يتعرض مطفي ومكتوب سببه — مش يتضغط ويترفض.
| الفلاج | بيفتح إيه في الشاشة |
|---|---|
Register | تسجيل مقرر جديد |
Add | الإضافة بعد بداية الفصل — والتراجع عن الإسقاط |
RegisterSection | اختيار وتغيير وحذف السكاشن |
Drop | الإسقاط |
Withdraw | الانسحاب (طلب، مش تنفيذ فوري) |
IsActiveStudent | لو false اقفل كل حاجة |
AnyOpen | لو false اعرض «مفيش فترة تسجيل مفتوحة» بدل الشاشة |
CourseReg/GetAllowedActions باسم CurrentCreditHours
وMaxCreditHours.الورك فلوهات تسعة مسارات — كل واحد بنداءاته بالترتيب
دول كل المسارات اللي الشاشة بتعملها. كل خطوة مكتوب جنبها الإندبوينت، والأخضر معناه
كتابة. وبعد أي كتابة القاعدة واحدة: اقرا Data.Status،
وبعدين نادِ التابين.
ونفس التسعة موجودين في كوليكشن الـ Postman بنفس الترتيب ونفس الأسامي — فتقدر تشغّل اللي بتقراه وتشوف الردّ الحقيقي قبل ما تكتب سطر.
ورك فلو ١ · تسجيل مقرر جديد
من تاب «المتاح» — مقرر الطالب ماسكهوش خالص، والمود REGISTER_COURSE.
TeachingMethods وSections — مافيش نداء تاني لعرض سكاشنه.Courses[] (Mode = REGISTER_COURSE)Sections بطرق التدريس بـ EdCodeCourseTeachingId. السكاشن مسطّحة عمداً عشان الربط يبقى عندكم.action.Body زي ما هو. لو السكشن GoesToWaitList السيرفس بتحوّله لتسجيل انتظار لوحدها وترجّع PLACED_ON_WAITLIST.Status · Reason · Conflict · AlternativesMAX_LOAD وSCHEDULE_CONFLICT وSEAT_TAKEN.IsComplete = false.ورك فلو ٢ · مقرر ناقصه طريقة تدريس
الطالب ماسك المحاضرة ومش ماسك المعمل. الحالة دي ليها مدخلين بيوصّلوا لنفس البيكر.
Mode = ADD_METHOD.MissingTeachingMethods[] · IncompleteCountEdCodeCourseTeachingId. من غيره البيكر بيرجّع سكاشن المقرر كله وبيبان إنه بيعرض سكاشن طريقة تانية.Sections · WaitListSections · Conflicting · Full · BlockedCurrentSections هنا هترجع فاضية — طبيعي، هو مش ماسك حاجة من النوع ده.EdStudGroupId = 0 هي اللي بتقول «ده اختيار جديد مش نقل».Status · ReasonIsComplete بقى true، والمقرر اختفى من «المتاح» خالص.ورك فلو ٣ · تغيير سكشن مسجّل
نفس طريقة التدريس، سكشن تاني. عملية واحدة — مش حذف وبعده إضافة.
RegisteredSectionIds · RegisteredEdStudGroupIdsCurrentSections بـ Status = CURRENT، والباقي بـ Mode = REPLACE ومعاهم ReplacesEdStudGroupId.CurrentSections[] + باقي السلالStatus · Reason · Alternativesورك فلو ٤ · حذف السكشن ← اختيار بديل
حذف السكشن مش إسقاط المقرر. المقرر بيفضل مسجّل، وطريقة التدريس بتبقى فاضية.
Status · DisplayIncompleteCount زاد واحد — البادچ على التاب بيتحرّك.State = NOT_REGISTERED · IsComplete = falseورك فلو ٥ · سكشن مليان ← قايمة الانتظار
مفيش زرار «احجز مقعد». نفس زرار التسجيل — واللي بيتغيّر هو الليبل بس.
FULL ودي بس اللي بتطفّي الزرار.Status = WAITLIST · GoesToWaitList = trueStatus: true ومعاه Reason — يعني نجح، بس في الطابور مش في مقعد.Status = true · Reason = PLACED_ON_WAITLISTReason، مش من حالة المقرر — للسبب اللي تحت.WAITING وعليه زرار إلغاء الانتظار. لكن نقل سكشن جوّه مقرر هو ماسكه خلاص → رقم الدور بيتكتب على صفّ السكشن والمقرر بيفضل ACTIVE.WAITING في «مقرراتي» — يعني الشكل الأول بس.ورك فلو ٦ · إسقاط مقرر
المقرر كله — مش سكشن منه. والمقرر مابيختفيش من الشاشة: بيفضل في «مقرراتي» بحالة DROPPED.
OnlineFlg: false يبقى مش هيعرف يرجع مكانه — حذّره قبل التأكيد.Status · ErrorState = DROPPEDورك فلو ٧ · التراجع عن الإسقاط
من «مقرراتي» بس. مافيش أي مدخل تاني ليه.
CanUnDrop = false وBlockedReason = "MAX_LOAD" — الزرار مطفي والسبب مكتوب. إرجاعه كان هيعدّي السقف.Flags.CanUnDrop · Flags.BlockedReasonGetUnDropCourse — إندبوينت قراءة اتشال خلاص — فالكارت كان بيفضل محذوف من غير أي رسالة.Status · TeachingMethods · NeedsSection · NextActionAssignSection: true — بتختار واحد لكل طريقة، بشرط يكون معروض وفيه مقعد ومفيش تعارض، وبتسيبها لو مالقتش.ورك فلو ٨ · تبديل مقرر بمقرر
يسيب مقرر مسجّل وياخد مكانه واحد تاني — في عملية واحدة، عشان مايقعش في نُصّ الطريق من غير الاتنين.
ToEdCourseId · ScScheduleDtlId · CourseCode · CreditHoursStatus · Errorورك فلو ٩ · قراءات مرجعية
حاجات بتحتاجها مرة على الشاشة، مش مع كل دوسة.
Agenda في التابين — فالنداء ده للشريط العلوي بس، ومش لازم.Register · Add · Drop · Withdraw · RegisterSectionتشيك ليست عشر حاجات عدّيها قبل ما تقفل التاسك
| الغلط | الصح |
|---|---|
قراية result أو الـ HTTP status بس |
Data.Status !== true = رفض، حتى مع 200 |
عرض Error الإنجليزي للطالب |
ترجم Reason من جدول الأكواد |
| بناء الـ body باليد | ابعت action.Body زي ما هو |
فتح الشيت من غير EdCodeCourseTeachingId |
ابعته دايمًا — من غيره بترجع سكاشن المقرر كله جوّه سطر المعمل |
| زرار «احجز مقعد» منفصل | نفس الزرار — الليبل بيتغيّر لوحده لما GoesToWaitList |
| إخفاء السكشن المقفول | اعرضه مطفي ومكتوب تحته سببه |
| «فيه تعارض» من غير اسم | Display.Note فيه اسم المقرر والسكشن والميعاد |
| زرار حذف واحد للمقرر | زرار لكل سكشن — المقرر ممكن يكون فيه أكتر من صفّ |
| «تراجع عن الإسقاط» في تاب المتاح | من «مقرراتي» بس — والمحذوف أصلًا مش بيظهر في المتاح |
| ريفريش لتاب واحد بعد الكتابة | التابين — الكتابة الواحدة بتغيّر الاتنين |
جرّب حسابات فيها الحالات كلها
أي باسورد بتعدّي — اللوجين بيتأكد من الهوية بس. الاتنين الأولانيين متحطوطين في شاشة دخول الديمو عشان متكتبش حاجة، والتالت موجود في كوليكشن الـ Postman.
| الحساب | ينفع تجرّب بيه إيه |
|---|---|
abdelrahman.baker.24040153تمريض · في الديمو |
الحالات: مسجّل · محذوف (٢) · منسحب (٢) · مقرر ناقصه معمل ·
ملاحظة مقرر مصاحب على NUR203. وفي الشيت بتاع «نظري» بتاع NUR203 هتلاقي في شاشة واحدة: سكشنه الحالي، واتنين متاحين، وواحد WAITLIST زراره شغّال، والتلاتة المقفولين
— NOT_ALLOW_ONLINE وINTERNAL وIS_CLOSED.
ده أحسن مكان تظبط عليه شكل السكشن المطفي |
ziad.shehata.25030040علاج طبيعي · في الديمو |
السكاشن: ٦ مقررات مسجّلة، تلاتة منهم محاضرة + معمل فينفع
تجرّب «غيّر السكشن» و«احذف السكشن» على السطر الصح. وعنده مقرر محذوف زراره مطفي بـ MAX_LOAD — لأنه أصلًا فوق سقف
الساعات (١٢ من ٩). ده الشكل اللي لازم تتعامل معاه: زرار مطفي وسبب مكتوب |
mohamed.mohamed.24040217تمريض · في الـ Postman |
التسجيل الجديد: ٦ ساعات من ٩، وقدامه مقررات في «المتاح» — فده الحساب اللي ينفع تجرّب عليه تسجيل مقرر فعلاً ينجح، وقايمة الانتظار، والتراجع عن الإسقاط |
21 خطة الإنهاء — إيه اللي فاضل بالترتيب
46 خاصية ناقصة تمامًا و0 نص نص. بس مش كلهم نفس الأهمية ولا نفس الحجم — ده الترتيب اللي إحنا نرشّحه ولييه.
مرحلة 1 اللي بيمنع النزول للإنتاج أصلاً
من غير دول، التطبيق ما ينفعش ينزل — مش مسألة خصائص، دي مسألة أمان وصحة.
| الشغلانة | ليه دلوقتي | مين |
|---|---|---|
| التحقق الحقيقي من الباسورد ActiveDirectory أو AzureAd ● الكود خلص |
اتعمل الـ LDAP bind والتحقق من توكن مايكروسوفت شغالين (شاشة الدخول).
اللي فاضل تركيب مش كود: بيانات الـ domain controller، أو App Registration على Azure،
والموبايل يبعت id_token (الدليل). وInnovation لسه على «أي باسورد» بقصد عشان التيست. |
تركيب + موبايل |
| مراجعة تحديد الفصل لكل عميل | لو غلط، اللوجين يرجّع فصل null وكل الشاشات تفضى. اتأكد من الـ 4 أوضاع مع كل داتابيز. |
باك إند + تركيب |
ربط Info/Capabilities في الموبايل |
عشان الشاشات غير المتاحة تختفي بدل ما الزرار يضرب غلط قدام المستخدم. | موبايل |
مرحلة 2 الفلوس — أكبر قيمة وأكبر خطر
الكود متكتب ومتجرَّب من الأول للآخر على الـ Sandbox. اللي فاضل بيانات حقيقية + الحتة اللي بتربط الدفع بسند السداد. وخلي بالك: البيانات دي مبقتش بتوقّف الشغل — الموبايل يقدر يبني ويجرّب دلوقتي.
| الشغلانة | الوضع | محتاج إيه |
|---|---|---|
| بيانات بوابة واحدة على الأقل | 🔑 بيانات | اختاروا بوابة (فوري أنسب للجامعات المصرية) وهاتوا الـ merchant code والمفتاح.
الكود جاهز واتجرّب فعليًا — التغيير الوحيد هو الـ baseUrl والبيانات. |
| ربط الدفع بسند السداد | ✕ ناقص | دلوقتي بنسجّل محاولة الدفع بس. لازم إنشاء FEE_STUD_VOUCHER + _ITEM
عند بدء الدفع، وتسوية البنود لما يتسدد. دي أهم حتة ناقصة في المدفوعات. |
| المحفظة الجامعية | ✕ ناقص | الرصيد دلوقتي في localStorage في الموبايل — وهمي تمامًا.
محتاج قرار أول: جدول جديد ولا بند في FEE_STUD_FEE_ITEM؟ |
| عنوان عام للـ callback | 🔑 بيانات | السيرفس لازم يكون متاح على https عام عشان البوابة تعرف تبلّغنا بالسداد. مسار الاستقبال نفسه اتجرّب: التوقيع بيتحقق، والتحديث idempotent. |
| إقفال الـ Sandbox | 🧪 قبل الإنتاج | اقفله من Profile → Sandbox وشغّل Readiness تاني.
الصفوف اللي هتولّع أحمر دي هي الشغل اللي فاضل بالظبط. و/health لازم يرجّع
"sandbox":[]. |
مرحلة 3 نقل الـ SQL اللي لسه
دي شغلانات واضحة المعالم: الإندبوينت موجود، الـ DTOs موجودة، والـ SP القديم موصوف في الكتالوج. مجرد نقل.
| الشغلانة | الشاشة | مصدر الـ SQL |
|---|---|---|
| تسجيل / حذف / تراجع المقررات | تسجيل المقررات | MOB_Insert_STD_CRS_REG_PLN + MOB_ED_STUD_GROUP_Insert — جوّه transaction واحدة |
| تسجيل واعتماد الغياب | شاشات الدكتور | ED_STUD_ABSENCE + Mob_ConfirmAttendance.
خد بالك: الكود القديم كان بيبدّل EdStudId وEdCourseId بالغلط |
| جدول الدكتور | الجدول | EF join موصوف في staff spec |
| تغيير الباسورد على AD | الدخول | مربوط بمرحلة 1 |
| صورة الطالب | الملف الشخصي | ستريم ملف بسيط |
| كود QR الحقيقي | البطاقة | مكتبة QRCoder مضافة أصلاً — الـ handler بيرجّع فاضي، محتاج مراجعة |
مرحلة 4 الخدمات الجديدة بالكامل
دي شاشات شغالة على داتا وهمية 100%. الخصائص معرّفة في الكتالوج ومتطلباتها من الجداول متحققة — بس مفيش handlers.
| الخدمة | الجداول الموجودة فعلاً | الشغل المطلوب |
|---|---|---|
| الطلبات والوثائق | GS_ATTCHD_DOC, GS_CODE_DOC_TYPE | كتالوج أنواع + إنشاء طلب + حالات + ربط بالدفع |
| الانسحاب والاعتذار | ED_STUD_COURSE_REG, ED_STUD_SEMESTER | إنشاء طلب + دورة موافقات + حساب المسترد |
| مواعيد الإرشاد | SV_STUD_ASK_ADV, SA_STF_MEMBER | أوقات متاحة + حجز + إلغاء (+ لينك Teams — ده جاهز) |
| حجز القاعات | ACCOM_ROOM, ACCOM_STUD_BOOK, ACCOM_WF_REQUEST_APPROVE | 🎁 موديول السكن كامل موجود (28 جدول) بدورة موافقات جاهزة — استغلوه |
| الأنشطة والرحلات | ED_STUD_ACTIVITY | كتالوج + تسجيل + إلغاء |
| الإعلانات | SV_MESSAGE (بديل مقترح) | قرار أول: جدول جديد ولا نستخدم الرسايل بتصنيف؟ |
| تسجيل الحضور من الموبايل | ED_STUD_ABSENCE | زرار «تسجيل حضوري» في الشاشة الرئيسية مش بيكتب حاجة. محتاج تحقق مكان/وقت |
الأشياء اللي مش شغل برمجة — بيانات بس
الحاجات دي بتظهر «فاضية» في التطبيق، بس الكود بتاعها خلص. محتاجة إدخال بيانات من الباك أوفيس:
- جدول الامتحانات —
ED_EXAM_SCHDLفاضي - الاستبيانات — مفيش استبيان منشور للفصل
- الإشعارات — محدش بعت إشعار للطالب
- الساعات المكتبية الحقيقية — اتحطّت بيانات تجريبية لـ 9 دكاترة؛ الحقيقي يدخلوه الدكاترة
- بيانات «عن الجامعة» و«تواصل معنا» — بتتكتب مرة في الأدمن
- بنود الرسوم المتأخرة — الطالب التجريبي سدّد كل حاجة، فمفيش بنود تظهر
لما تقدّر الوقت، ما تحسبش دول كشغل برمجة.
22 حاجات لازم تعرفها قبل ما تبدأ
دي حاجات اكتشفناها بالتجربة، وهتوفر عليك وقت كتير.
🔑 التوكن في كل ريكوست
ما عدا اللوجين، كل إندبوينت محتاج:
Authorization: Bearer <token>
التوكن بييجي من token.data في رد اللوجين.
📛 أسماء الحقول مش متسقة
الإرث القديم سايب لخبطة في التسمية — خد بالك:
ED_STUD_IDفي إندبوينتاتEdStudIdفي إندبوينتات تانيةsaStaffMemberIdبحرف صغير في الأول
دايمًا راجع الكوليكشن بتاع الشاشة قبل ما تكتب.
🕐 الوقت والتاريخ
FROM_TIME بيرجع "09:00:00" — مش تاريخ كامل.
أيام الأسبوع بـ GS_CODE_WEEK_DAY_ID:
1=الجمعة، 2=السبت، 3=الأحد، 4=الإثنين، 5=الثلاثاء، 6=الأربعاء، 7=الخميس.
لاحظ إن الأسبوع بيبدأ من السبت.
🈳 "" مش null
السيرفس بيحوّل أي string فاضي لـ "" عشان التطبيقات القديمة.
يعني if (x == null) مش هتشتغل — استخدم فحص فاضي.
📄 «data not found» مش error
لما مفيش نتايج، السيرفس بيرد result: "ERROR" وdetails: "data not found".
ده مش عطل — ده «مفيش داتا». في api.js عندنا بنحوّلها null والشاشة تعرض حالة فاضية.
💸 المبالغ بالقروش في Paymob
Paymob بياخد amount_cents. 1500 جنيه = 150000.
غلطة هنا = خصم 100 ضعف من الطالب. التحويل بيحصل في مكان واحد بس في الكود عن قصد.
🔁 البوابات بتعيد الإرسال
لو ما رجّعتش 200 للـ callback، البوابة هتعيد. فالتحديث لازم يكون idempotent.
عملناها بـ UPDATE … WHERE PaymentStatus <> 1 — العدد الراجع بيقولنا لو دي أول مرة.
🧪 بيانات الطالب التجريبي
الطالب 73 سدّد كل مصروفاته — فشاشة الرسوم مش هتوريك بنود متأخرة.
لو عايز تجرّب الدفع، دوّر على طالب عليه متأخرات في FEE_STUD_FEE_ITEM.
7 باجات اتصلّحت — واللي تتعلّمه منها
دول مش تاريخ. كل واحد فيهم فخ ممكن تقع فيه تاني وانت بتضيف إندبوينت جديد، وكلهم اتكشفوا لما شغّلنا الدورة كاملة على الـ Sandbox مش بالقراءة.
| الباج | كان هيحصل إيه | الدرس |
|---|---|---|
| الـ callback مكانش بيقرا الـ body كان بيشرط وجود Content-Length |
أي بوابة بتبعت بـ chunked → الـ body يرجع فاضي → التوقيع يفشل →
كل إشعارات السداد تتزقّ في الزبالة على إنها مزوّرة، من غير أي صوت |
اقرا الـ stream على طول. Content-Length مش مضمون |
INTEG_Fawry_Payment عموده identity |
الكود كان بيحسب MAX(id)+1 ويكتبه → SQL 544 → أرقام فوري مبتتسجّلش →
التسوية في الباك أوفيس عمياء |
العميل ممكن يكون identity وممكن لأ. اسأل الـ schema بـ COLUMNPROPERTY |
TryGetDecimal بيرمي exception على null |
فوري بتبعت paymentAmount: null لعملية لسه متدفعتش → استعلام الحالة يضرب |
اتأكد من ValueKind الأول. الـ TryGet* مش آمنة زي ما اسمها بيوحي |
STUD_FACULTY_CODE من جدول غلط |
الكود كان بيقراه من ED_STUD وهو على ED_STUD_FACULTY →
شاشة المنصة التعليمية كلها 500 |
الرقم الجامعي على التسجيل في الكلية مش على الطالب. خد اللي IS_LAST = 1 |
MSG_SUBJECT عموده 50 حرف |
الكود كان بيحط فيه {"TitleEn":…,"TitleAr":…} → SQL 8152 →
كل الإشعارات كانت بتفشل، وحتى لو عدّت التطبيق كان هيعرض JSON خام |
شوف عرض العمود قبل ما تكتب فيه. ومتحطش JSON في عمود المستخدم بيقراه |
| الإشعار بيطلب سنة وفصل والمرسل مش بيبعتهم | أعمدة NOT NULL → الإرسال يفشل لأي عميل مش عارف الأرقام دي | لو السيرفس يقدر يجيب القيمة بنفسه، يجيبها. متحمّلش المستدعي معرفة داخلية |
EfinancePay ناسي ED_CODE_SEMESTER_ID من الـ INSERT |
عمود NOT NULL مش موجود أصلاً في قايمة الأعمدة → الإندبوينت ده عمره ما اشتغل | البارامتر موجود في الـ SQL ≠ البارامتر مستخدم. راجع قايمة الأعمدة نفسها |
الخلاصة المهمة: ولا واحد من السبعة دول كان ممكن يتكشف بقراءة الكود أو بـ unit test. كلهم ظهروا لأن الدورة اتشغّلت كاملة: تطبيق ← سيرفس ← بوابة ← إشعار موقّع ← داتابيز. ده السبب الحقيقي لوجود الـ Sandbox.
ملفات مهمة تعرف مكانها
| الملف | فيه إيه |
|---|---|
| Application/Features/FeatureCatalog.cs | تعريف كل خاصية ومتطلباتها — ابدأ من هنا لو بتضيف خاصية |
| Application/Infrastructure/ClientProfile/ClientProfile.cs | شكل ملف الإعدادات كله |
| Application/Business/<Feature>/ | الـ handlers والـ SQL — كل SQL جوّه const string جنب الـ handler بتاعه |
| WebApi/EndPoints/ | المسارات — مقسّمة بالموضوع |
| docs/legacy-specs/ENDPOINT-CATALOG.md | كل مسار قديم + الـ SP اللي اتنقل منه — مرجعك لما تنقل SQL |
| MobileDemo/app/api.js | عميل السيرفس في الموبايل |
| MobileDemo/app/data.jsx | تحويل رد السيرفس لشكل الشاشات — مثال حي لكل حقل بيتقرا منين |
| Application/Infrastructure/Sandbox/ | جديد الـ overlay اللي بيملا البيانات المزيّفة، وحالة البوابات، وباعت الإشعارات |
| WebApi/EndPoints/Sandbox/ | جديد البوابات المزيّفة نفسها (فوري / Paymob / MPGS / Graph / Moodle / FCM) + صفحة الدفع وصفحة التحكّم |
| docs/SANDBOX.md | جديد شرح الـ Sandbox بالتفصيل بالإنجليزي |
قواعد الكود (لو هتضيف)
- Vertical slice: إندبوينت في WebApi + handler quad في Application
- الـ SQL يبقى
const stringجنب الـ handler — بارامترات، أعمدة محددة - عرّف الخاصية في
FeatureCatalogبجداولها وإعداداتها، وحُط[FeatureGate]على الإندبوينت - لو بتضيف تكامل خارجي: خلي الـ host جاي من البروفايل (
BaseUrl) عشان الـ Sandbox يقدر يوجّهه، واعمل النسخة المزيّفة تحتWebApi/EndPoints/Sandbox/. ممنوعif (sandbox)جوّه أي provider. - ممنوع: EF · استدعاء stored procedures ·
if (client == "KU")