سجل المراجعة للمسؤولين
عارض سجل المراجعة (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) يُخبرك بأن محاولة جرت وبطول القيمة
المحجوبة، دون تخزين القيمة نفسها.
المرشّحات
جميع معاملات التصفية الأربعة اختيارية ومستقلة. يمكنك دمجها بحرية.
| المعامل | النوع | الوصف |
|---|---|---|
eventType | string | security_attempt أو super_admin_bypass أو student_data_access (احذفه للحصول على الثلاثة) |
actorUserId | integer | التصفية لمُنفِّذ واحد (User.id للمسؤول أو المسؤول الأعلى) |
from | string | تاريخ ISO؛ الحد الأدنى الشامل لختم الوقت |
to | string | تاريخ ISO؛ الحد الأقصى الشامل لختم الوقت |
تُسقَط قيمة from أو to غير القابلة للتحليل بصمت بدلًا من إعادة خطأ 400.
المرشّح جهد حسن النية لتجربة المستخدم وليس بوابة صحة.
الترقيم الصفحي
| المعامل | الافتراضي | الحد الأقصى |
|---|---|---|
limit | 50 | 200 |
offset | 0 | 2000 (فوقه: 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 | مصدره في صف الاطلاع |
|---|---|
eventType | accessKind (مثل export_csv وstudent_page_view وstudent_list_view) |
actorUserId | المعلّم أو المدير أو المشرف أو المسؤول |
targetOrgId | organizationId |
targetStudentId | الطفل الوحيد في عرض طفل واحد؛ وnull للقائمة أو التصدير |
action | surface، قالب المسار (لا عنوان 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») وعدد الطلاب في تفاصيل الصف.
أدلة ذات صلة
- فحوصات ضمان الجودة: سجل ضمان الجودة الذي يشارك صلاحية
VIEW_QA_REGISTRY - سلامة اللغة: الطبقة التي تُنتج أحداث الأمان
FORBIDDEN_FREE_TEXT