---
title: "سجل المراجعة للمسؤولين"
url: https://docs.growamal.com/ar/guides/audit-log/
language: ar
---

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

عارض سجل المراجعة (`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` بسقف.

```bash
curl "https://localhost:3000/api/admin/audit-log?limit=50&offset=0" \
  -H "Authorization: Bearer <accessToken>"
```

```json
{
  "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») وعدد الطلاب في تفاصيل الصف.

## أدلة ذات صلة

- [فحوصات ضمان الجودة](https://docs.growamal.com/ar/guides/qa-checks/): سجل ضمان الجودة الذي يشارك صلاحية `VIEW_QA_REGISTRY`
- [سلامة اللغة](https://docs.growamal.com/ar/guides/language-safety/): الطبقة التي تُنتج أحداث الأمان `FORBIDDEN_FREE_TEXT`
