Skip to Content

سجل المراجعة للمسؤولين

عارض سجل المراجعة (GET /api/admin/audit-log) هو قراءة موحّدة بترتيب زمني تنازلي لثلاثة مصادر ذات طابع إلحاقي فقط:

  • SecurityAuditLog يُسجّل انتهاكات حدود الأمان، كمحاولات النص الحر المحظور ومحاولات الوصول إلى الملاحظات الحساسة. الصفوف مُقيَّدة بالمستأجر عبر organizationId.
  • SuperAdminBypassLog يُسجّل كل مرة يقرأ فيها مشغّل المنصة (المسؤول الأعلى SUPER) عبر المؤسسات. تحمل الصفوف targetOrgId (المؤسسة التي جرى الوصول إليها) بدلًا من عمود organizationId.
  • student_data_access_log (النوع student_data_access) يُسجّل كل عرض أو تصدير لبيانات أطفال بأسمائهم: تصدير المعلّم لنتائج التقييم، وصفحات الطلاب وقوائمهم وتصديرها لدى المدير والمشرف والمسؤول. الصفوف مُقيَّدة بالمستأجر عبر organizationId. انظر صفوف الاطلاع على بيانات الطلاب.

المسار والصلاحية

GET /api/admin/audit-log

يتطلّب ثلاث طبقات من البرمجيات الوسيطة: requireAuth وrequireTenantContext و requirePermission("VIEW_QA_REGISTRY"). يُعيد أي رمز مصادقة يفتقر إلى VIEW_QA_REGISTRY استجابة 403.

DTO خالٍ من الأسرار

الاستجابة خالية من الأسرار بموجب العقد. تُحذف الحقول التالية عمدًا من كل صف بصرف النظر عن مستوى صلاحية المستدعي:

الحقل المحذوفالسبب
ipAddressمعلومات تعريفية جنائية؛ غير مطلوبة للإشراف
userAgentمعلومات تعريفية جنائية؛ غير مطلوبة للإشراف
requestIdمعرّف ارتباط؛ غير مطلوب في جدول الإشراف
القيمة المُحاوَلةحساسة؛ يُظهَر طول البايت فقط

attemptedValueLength (عدد صحيح أو null) يُخبرك بأن محاولة جرت وبطول القيمة المحجوبة، دون تخزين القيمة نفسها.

المرشّحات

جميع معاملات التصفية الأربعة اختيارية ومستقلة. يمكنك دمجها بحرية.

المعاملالنوعالوصف
eventTypestringsecurity_attempt أو super_admin_bypass أو student_data_access (احذفه للحصول على الثلاثة)
actorUserIdintegerالتصفية لمُنفِّذ واحد (User.id للمسؤول أو المسؤول الأعلى)
fromstringتاريخ ISO؛ الحد الأدنى الشامل لختم الوقت
tostringتاريخ ISO؛ الحد الأقصى الشامل لختم الوقت

تُسقَط قيمة from أو to غير القابلة للتحليل بصمت بدلًا من إعادة خطأ 400. المرشّح جهد حسن النية لتجربة المستخدم وليس بوابة صحة.

الترقيم الصفحي

المعاملالافتراضيالحد الأقصى
limit50200
offset02000 (فوقه: 422)

يعدّ الحقل total في الاستجابة جميع الصفوف المطابقة عبر المصادر الثلاثة قبل نافذة limit/offset، ما يتيح للمستدعين حساب عدد الصفحات. يُقرأ كل مصدر حتى offset + limit صفًا قبل الدمج، ولهذا حُدّد offset بسقف.

curl "https://localhost:3000/api/admin/audit-log?limit=50&offset=0" \ -H "Authorization: Bearer <accessToken>"
{ "total": 142, "rows": [ { "id": "sec:clx4z2...", "kind": "security_attempt", "eventType": "FORBIDDEN_FREE_TEXT", "actorUserId": 7, "targetOrgId": "clx4z2...", "targetStudentId": 42, "action": null, "attemptedPath": "/api/students/42/context-flag", "attemptedFieldName": "freeText", "attemptedValueLength": 83, "occurredAt": "2026-06-25T08:14:22.000Z" }, { "id": "bypass:clx4z3...", "kind": "super_admin_bypass", "eventType": "BYPASS", "actorUserId": 1, "targetOrgId": "clx4z2...", "targetStudentId": null, "action": "GET /api/admin/audit-log", "attemptedPath": null, "attemptedFieldName": null, "attemptedValueLength": null, "occurredAt": "2026-06-25T07:00:01.000Z" } ] }

حقل id معرّف ثابت مسبوق بالمصدر: sec:<id> لصفوف الأمان، وbypass:<id> لصفوف التجاوز، وaccess:<id> لصفوف الاطلاع على بيانات الطلاب. تُرتَّب النتائج تنازليًا زمنيًا وفق occurredAt؛ وتحتفظ الصفوف التي تتشارك ختم وقت بالميلي ثانية بترتيب ثابت (الأمان ثم التجاوز ثم الاطلاع، وتنازليًا بحسب id داخل كل مصدر) لضمان ترقيم صفحي حتمي (V-6). يقرأ GET /api/admin/audit-log/{id} حدثًا واحدًا بهذا المعرّف (الرابط المباشر) بنطاق المستأجر نفسه؛ والمعرّف المجهول أو الخارج عن النطاق أو المشوَّه يُعيد 404.

صفوف الاطلاع على بيانات الطلاب

كل استجابة تعرض أطفالًا بأسمائهم أو تصدّرهم تكتب صفًا واحدًا في student_data_access_log قبل تقديمها (تصدير المعلّم لنتائج التقييم، وصفحة الطالب أو تصدير الصف لدى المدير، وغير ذلك). يعرضها سجل المراجعة بالنوع student_data_access (القرار D-R12)، فيرى المسؤول من اطّلع على بيانات أطفال أيّ صف أو صدّرها ومتى. يُطابَق كل صف على الـDTO المشترك هكذا:

حقل الـDTOمصدره في صف الاطلاع
eventTypeaccessKind (مثل export_csv وstudent_page_view وstudent_list_view)
actorUserIdالمعلّم أو المدير أو المشرف أو المسؤول
targetOrgIdorganizationId
targetStudentIdالطفل الوحيد في عرض طفل واحد؛ وnull للقائمة أو التصدير
actionsurface، قالب المسار (لا عنوان URL خامًا أبدًا)
actorPersonaالدور لحظة الاطلاع (TEACHER أو PRINCIPAL أو MANAGER أو ADMIN)
subjectStudentCountعدد الأطفال المسمَّين الذين كشفتهم الاستجابة
targetClassIdالصف الذي اقتصر عليه العرض أو التصدير (null دون نطاق صف)

تكون actorPersona وsubjectStudentCount وtargetClassId بقيمة null في النوعين الأقدم. ولا تُعاد أبدًا حقول صف الاطلاع filters وfiltersHash وqueryLength وrequestId وschoolId وmacroDomainKey وassessmentWindow وrowCount.

تظهر الصفوف نفسها في شاشة النشاط (/admin/activity، وإليها يُحوَّل /admin/audit-log) تحت تبويب «الأمان» بالمصدر access، وتظهر بتسمية عامة إلى أن تُسمّي المتابعةُ في الواجهة هذا النوع.

نطاق المستأجر

يرى مسؤول المؤسسة العادي (الحامل لـVIEW_QA_REGISTRY):

  • صفوف الأمان حيث يطابق organizationId مؤسسته.
  • صفوف التجاوز حيث يطابق targetOrgId مؤسسته (أحداث التجاوز التي وصلت إلى مؤسسته).
  • صفوف الاطلاع على بيانات الطلاب حيث يطابق organizationId مؤسسته.

يرى المسؤول الأعلى (مشغّل المنصة بـskipTenantFilter = true) جميع صفوف الأمان وجميع صفوف التجاوز وجميع صفوف الاطلاع عبر كل المؤسسات، بما في ذلك صفوف التجاوز حيث targetOrgId هو null.

في كل مرة يقرأ فيها المسؤول الأعلى هذه النقطة، يُلحق الخادم صفًا جديدًا في SuperAdminBypassLog يوثّق الوصول. يظهر هذا الصف بدوره للمسؤولين الآخرين في قراءتهم التالية للصفحة. قراءات المسؤول الأعلى لسجل المراجعة هي إذن ذاتية المراجعة.

الثوابت

  • للقراءة فقط. لا يستورد المعالج أي كاتب؛ ولا يُحدِّث أي صف في سجل المراجعة ولا يحذفه ولا يُدرجه بإنشاء أو تحديث. يُطبِّق حارس البناء lint:no-update-on-audit-tables هذا الشرط.
  • جداول مصدر إلحاقية فقط. لا يدعم SecurityAuditLog ولا SuperAdminBypassLog التعديل أو الحذف. كل صف تراه هو السجل الأصلي.
  • خالٍ من الأسرار بموجب العقد (SPEC-AL-4). تُجرَّد عناوين IP الخام ووكيل المستخدم ومعرّف الطلب والقيم المُحاوَلة في طبقة الاختيار عبر قائمة سماح صريحة، فلا يمكن لأي إضافة عمود مستقبلية أن تتسرّب إلى الاستجابة بصمت.
  • معزول بالمستأجر. لا يستطيع المسؤول العادي رؤية سجلات مؤسسة أخرى بأي مجموعة من المرشّحات أو الترقيم الصفحي.

تحديث (WP-TDV3 S8، D-R12): صفوف student_data_access تُقرأ الآن «الاطلاع على بيانات الطلاب أو تصديرها»، مصدرها «سجلّ الاطلاع على بيانات الطلاب»، ولها خيار في مرشّح النوع؛ ويظهر نوع الاطلاع (مثل «تصدير ملف CSV») وعدد الطلاب في تفاصيل الصف.

أدلة ذات صلة