انتقل إلى المحتوى

التدقيق والحذف الناعم

ما هو

نمطا بيانات عابران للقطع مبنيان على أصناف الكيان الأساسية:

  • تسجيل التدقيق — تُسجَّل لحظات العمل المهمة كصفوف audit_events غير قابلة للتغيير. هذا انتقائي ويُستدعى يدويًا، لا ظلٌّ تلقائي لكل كتابة.
  • الحذف الناعم — لا تُزال معظم الكيانات فيزيائيًا أبدًا؛ بل تحمل علم IsDeleted، ويخفي مرشّح الاستعلام العام الصفوف المحذوفة.

حالة الصفحة partial بسبب نصف التدقيق: فهو حيّ لكنه يغطّي فقط الكتابات التي تستدعيه صراحةً.

لماذا بُني بهذه الطريقة

التدقيق اشتراكي بالتصميم. بدلًا من معترض EF SaveChanges يعكس كل تغيير، تستدعي الخدمات IAuditLogger.LogAsync عند النقاط المهمة (نشر، اعتماد، تغيير إعداد). يُبقي هذا صفوف التدقيق ذات معنى — حقائق عمل، لا سجل تغييرات على مستوى الصف — وكان القرار المتعمَّد (الورقة 01 §how-it-works، MIQ005_Report.md §1). المقايضة، والشيء الذي يجب ألّا يُخطأ فيه: كتابة بلا استدعاء صريح لا تُدقَّق.

AuditEvent ملحَق-فقط وعمدًا ليس AuditableEntityid فيه bigint للحجم، ولا تحديث/حذف فيه، ولا حذف ناعم، ولا RowVersion. صفوف التدقيق حقائق غير قابلة للتغيير (الورقة 01 §decisions، AuditEvent.cs، MIQ005_Report.md §1). الملحَق-فقط حاليًا مُنفَّذ على مستوى التطبيق فقط — لا يوجد بعد دور INSERT-only على مستوى قاعدة البيانات (مؤجّل لما بعد MVP، MIQ005_Report.md §6.3).

الحذف الناعم يحفظ التاريخ والسلامة المرجعية: حذف مستخدم، مثلًا، لا يمزّق مسار تدقيقه (مفتاح actor_user_id الأجنبي هو ON DELETE SET NULL، مع actor_username مُزال التطبيع ليبقى) (الورقة 01 edge-cases، MIQ105…cs:63-69).

كيف يعمل

التدقيق

  • يكتب AuditLogger.LogAsync صفّ audit_events واحدًا ويبتلع الإخفاقات — لا يحجب التدقيق عملية العمل أبدًا (الورقة 01 §rules، AuditLogger.cs:30-65).
  • يُستدعى يدويًا من خدمات فردية؛ ~30 خدمة تحقن IAuditLogger. لا يوجد معترض SaveChanges للتدقيق (الورقة 01 §build-status).
  • عقد الكتابة: BU = tenant.BusinessUnitId؛ يُعيَّن المُنفِّذ افتراضيًا إلى tenant.UserId / tenant.Username ?? "system"؛ IP + الارتباط من HttpContext؛ details مُسلسَل إلى JSON (AuditLogger.cs:30-65).
  • تتضمّن حقول AuditEvent: event_type، entity_type، entity_id، action، actor_user_id? (FK→users، ON DELETE SET NULLactor_username، occurred_at، correlation_id?، reason?، details jsonb?، severity (varchar(20) حر، افتراضيًا "Info") (الورقة 01 §entities، AuditEvent.cs:3-20).

الحذف الناعم

  • يحمل AuditableEntity الأساسي IsDeleted، DeletedAt?، DeletedBy?، إضافةً إلى RowVersion (التزامن المتفائل) وIsActive (الورقة 01 §entities، AuditableEntity.cs:3-15).
  • مرشّح الاستعلام العام هو !IsDeleted && (BusinessUnitId == t.BusinessUnitId || t.IsSuperAdmin) — فتكون الصفوف المحذوفة ناعمًا غير مرئية للقراءات العادية (الورقة 01 §rules، ManpowerIQDbContext.cs:124-319). الحذف الناعم هو نصف IsDeleted؛ وعزل المستأجر هو الآخر (انظر تعدّد المستأجرين).
  • قيود الفرادة مرشَّحة على is_deleted = false، فيمكن إعادة استخدام رمز بعد حذف حامله ناعمًا (الورقة 01 §entities، مثلًا Permission.code UNIQUE مرشَّح).

مزالق / قيود

  • التدقيق انتقائي/يدوي — لا تدّعِ "كل تغيير يُدقَّق." لا يوجد معترض؛ كتابة غير مُدقَّقة صامتة (الورقة 01 MUST-NOT #3). كتابة جديدة ينبغي تدقيقها يجب أن تستدعي IAuditLogger صراحةً.
  • AuditEvent لا يرث AuditableEntity — لا IsDeleted، ولا RowVersion، ولا IsActive، ولا CreatedBy؛ id هو bigint (الورقة 01 MUST-NOT #5).
  • الحذف الناعم والحالة مختلفان. إلغاء LeaveRequest يضبط Status = Cancelled، لا IsDeleted؛ الحذف الناعم محجوز لإزالة المسؤول/البيانات الشخصية PII (الورقة 01 edge-cases، ManpowerIQDbContext.cs:296-300).
  • severity نص حر، لا تعداد. تُدرِج الوثائق "Info/Warning/Critical" لكن "Error" مستخدمة في الممارسة (الورقة 01 discrepancies، AllocationRuleEngine.cs:17).
  • RowVersion (bytea) يحتاج افتراضيًا من جهة Postgres '\x'::bytea؛ توجد سلسلة كاملة من هجرات "RowVersionDefault" لأن مسارات الإدراج الأقدم فشلت دونه (الورقة 01 edge-cases، UserConfiguration.cs:29-31).

حالة البناء

  • الحذف الناعم + نمط الفهرس الفريد الجزئيAvailable، عام عبر صفوف AuditableEntity (الورقة 01 §build-status).
  • تسجيل التدقيقPartial: حيّ لكنه انتقائي/يدوي (لا معترض لكل الكتابات)؛ الملحَق-فقط مُنفَّذ على مستوى التطبيق فقط، لا دور INSERT-only على مستوى قاعدة البيانات بعد (الورقة 01 §build-status، MIQ005_Report.md §6.3).

ذات صلة

  • تعدّد المستأجرين — علم الحذف الناعم هو نصف مرشّح الاستعلام نفسه.
  • Clean Architecture — لماذا التدقيق استدعاء صريح، لا سلوك خطّ أنابيب.
  • ورقة الحقائق: 01 (الأساس).