---
name: ghayth-state
description: لقطة الحالة الحالية لنظام غيث (Ghayth ERP) — حالة المسارات، الـ PRs المفتوحة، فجوات السلامة المالية، الديون التقنية، والمبادئ المتراكمة. استخدمها لفهم أين وصل النظام وما هي القضايا المفتوحة قبل البدء بأي عمل. تنبيه: هذه لقطة بتاريخ محدد ولا تتحدث تلقائيًا — تحقق من الكود الفعلي وحالة الـ PRs عند أي تعارض.
---

# لقطة حالة نظام غيث

> **تاريخ اللقطة: 18 يونيو 2026 — محدَّثة جزئيًا 21–26 يونيو، وقسما الحوكمة والمالية محدَّثان 7 يوليو 2026**

## ⚖️ نظام الحوكمة والدمج الساري (محدَّث 2026-07-07 — اقرأه أولًا)

سلسلة PRs حوكمة دُمجت 6–7 يوليو (‎#3230، ‎#3237، ‎#3255، ‎#3256، ‎#3261، ‎#3264، ‎#3265، ‎#3267) غيّرت قواعد اللعبة — المرجع الحاكم CLAUDE.md والدستور v3.1، وخلاصتها:

- **الدمج المفوَّض:** الوكيل يدمج PR بنفسه (squash مباشر — auto-merge مطفأ عمدًا) باجتماع: لا تكرار + الفحوص الإلزامية الثلاثة خضراء (`guard`+`constitution-audits`+`db-audits`) + حكم مجلس «يُعتمد». التصعيد لإبراهيم محصور في: الدفتر / المعماري / «يُرفض أو يُعتمد بشرط».
- **انضباط الدمج:** مهمة مكتملة = PR واحد (لا PRs جزئية)، والتحديث من `main` أول بأول (fetch+rebase عند البدء وأثناء العمل وقبل فتح الـPR — `main` نشط جدًا وسباق النوافذ حقيقي).
- **الدستور v3.1:** تعريف التكرار الموحد (المادة 15/8)، سياسة التفويض مدوّنة (المادة 21)، سجل تعديلات بدل «مجمّد».
- **قالب PR موحد** (`.github/pull_request_template.md` = صيغة CLAUDE.md) وفيه بند **«البحث عن الأصل القائم» إلزامي**.
- **مصفوفة الملكية المعلنة:** `scripts/governance/ownership-matrix.json` (يستهلكها `audit:boundaries`) + `docs/governance/ownership-matrix.md` — المرجع الوحيد لملكية الجداول؛ تعديل ملكية = تغيير معماري يُصعَّد.
- **حُرّاس جدد في guard.sh:** `check:cross-domain-reads` **بوابة مانعة** (17 نقطة التقاء معلنة معفاة + 139 زوج `file:table` مجمّد في `scripts/cross-domain-reads-allowlist.txt` لا يكبر — قراءة عابرة جديدة تُرفض) · `check:near-duplicate-components` تقريري (تشابه ≥90%) · `check:dup-filenames` صار يرفض تصادم اسم بتشابه ≥70% حتى لو مدرجًا (الأسماء الـ15 المدرجة قيست 0–13% = صفحات مختلفة لا نسخًا).
- **بيئة الاختبار محليًا:** حزم اختبار تتطلب `JWT_SECRET` — استعمل قيمة CI الوهمية من `guard.yml` عند تشغيل guard/الاختبارات خارج CI.
- **دَين مفتوح للتصفية التدريجية:** أزواج القراءات العابرة الـ139 (تُصفّى بتمريرها عبر عقود المسار المالك وحذف الزوج من الـallowlist)، و51 صفحة قائمة بلا طباعة و53 بلا بحث (تقرير ux في guard).

> **تحديث 7 يوليو 2026 — سدّ ثغرات المعاملات المالية الثلاث (PR #3262، مدموج بقرار إبراهيم، مجلس «يُعتمد»):**
> 1. **سداد الأطراف في «تسجيل واقعة مالية»:** وضع «تسوية مع طرف» — عميل+قبض يضمّن تحصيل FIFO القائم (`CustomerCollectionPanel embedded`، إنفاذ docs/25 §٩.٣)؛ ومورد عبر `POST /finance/documents` بحمولة `party` (قبض من مورد = DR نقد/CR ذمم 2111 ببُعد vendorId، وصرف على الحساب بالعكس) + `POST /vendor-advances/:id/refund` جديد (استرداد دفعة مقدمة، سقف المتبقي، idempotent) + `cashAccountCode` صريح في إنشاء الدفعة. حارس خزنة مشترك `lib/moneyAccountGuard.ts`.
> 2. **سطر الصنف مربوط بالكتالوج:** الصفحات الموحّدة الثلاث (واقعة/مبيعات/مشتريات) صارت `ProductSelect` (بحث ذكي + درج إنشاء + «بند حر» صريح) مع تمرير `itemId`/`productId`. ✅ **أُكمل على الصفحتين القديمتين أيضًا (#3272، بلا هجرة):** بنود فاتورة المورد القديمة والمصروفات تقبل `productId` بُعدًا على `journal_lines` عبر `lineAllocation` (البنود لا تُخزَّن جدولًا — تصير سطور قيد بأبعاد؛ `itemId` هناك يبقى لذاكرة أصناف المورد supplier_items، مرجعان مختلفان عمدًا).
> 3. **الحساب الفرعي والخزنة:** البينية على حسابات «جاري الشركات الشقيقة» (1136/2114/4935/5396، هجرة seed 488) ببُعد `sisterCompanyId` + إصلاح الاحتساب المزدوج في تقرير التوحيد (فلتر `type != 'intercompany'` في byCompany)؛ الضمانات البنكية صار لها أثر دفتري (هجرة 489: هامش 1128 نقد مقيّد + عمولة 5390 عند الإصدار، ورد الهامش عند التحرير/الإلغاء)؛ عمولة تحويل الحسابات 5510→5390 (كانت تُرحَّل على الوقود!). بنّاؤون نقيون (`intercompanyJournalPlan`/`bankGuaranteeJournalPlan`) + assertion وحدة 29 وديناميكي حي 8. ✅ **مصادرة الضمان منمذجة (#3272):** `POST /bank-guarantees/:id/forfeit` — انتقال `active→forfeited` بسبب إلزامي + قيد DR «خسائر مصادرة ضمانات بنكية» 5391 / CR هامش 1128 بنفس المعاملة (هجرة seed 490؛ التسييل فوق الهامش = مطالبة بنك بمسارها عند وقوعها). **متبقٍّ موثّق:** stub تحويل الحسابات في تطبيق الجوال معطّل أصلًا (تطبيق غير مشغَّل — قرار تنفيذه أو إزالته لإبراهيم).
> ملاحظة تشغيلية مثبتة: `db:provision-agent` يعمل في بيئة الوكلاء (بعد `PATH=/usr/lib/postgresql/16/bin` وتشغيله كمستخدم postgres) ويفكّ الفحوص الحية والاختبارات الديناميكية.

> **تحديث 7 يوليو 2026 مساءً — مرحلة الحارس المالي (بعد إغلاق الثغرات الثلاث؛ كلها مجلس «يُعتمد» + فحوص خضراء):**
> - **#3279:** stub تحويل الحسابات في الجوال أُعيد بناؤه شاشة عاملة (كان قائمة جرد مستودعي منسوخة)، وإصلاح عقد `journal-new` بالجوال (accountCode/date)، ورسائل صدق «مسودة تُرحَّل بعد الاعتماد» في الويب.
> - **#3284 (اعتماد إبراهيم «نعم»):** منفذ مخصّص `POST /finance/treasury-transfer` — فرض خادمي أن المصدر/الهدف نقديان/بنكيان + وسم القيد `type='transfer'` + عمولة عبر غرض `bank_fee_expense` (تجاوز صريح يُتحقق postable مباشرة لا عبر mapping)؛ الويب والجوال يستهلكانه.
> - **#3295 (دفعة ٨ — تصفية العهدة بالمصروفات):** مسح دورة العهد كشف أن المصروف من حساب العهدة غير مرئي لتقارير العهد (تعدّ `CUSTODY-SETTLE%` فقط) وساق CR ترث بُعد كيان المصروف لا حامل العهدة. الحل بلا جداول: `custodyId` اختياري على `POST /expenses` → ختم `dimensionJson.custodyRef` + `employeeId` الحامل على ساق المصدر وحدها (`buildExpenseLines custodyContext`)، `fetchCustodySettledMap` موحّدة (نقدي+مصروفات مربوطة) للقائمة/التقرير/الملخص/التفاصيل وحارسَي تجاوز التسوية، وحارس «المصروف ≤ متبقي العهدة» بقفل داخل المعاملة، ومنتقي «العهدة المصروف منها» في صفحة المصروفات. اختبار حي: منحة 1000 → مصروف مربوط 400 + تسوية 300 → المُصفّى 700.
> - **#3298 (دفعة ٩ — شاشات الجوال):** خريطة وصول كاملة لشاشات الجوال المالية: 18 متاحة (منها 12 مكسورة قطعًا أُصلحت عقودها: منافذ صحيحة، منتقيات clientId/supplierId/موظف/أصل/فاتورة بدل النص الحر، receiptKey idempotency، `lines→items` وأخواتها، دمج ما لا مكان له في notes بدل الإسقاط الصامت؛ `vendor-payment-new` أُعيد توجيهها لمسار تسوية الطرف `/finance/documents`) و**20 شاشة معزولة** لا يصل إليها مستخدم (منها عائلة دليل الحسابات كاملة) = مرشحة حذف بقرار.
> - **#3301 (دفعة ١٠):** شاشات ٩ب الأربع أُعيد بناؤها على الأصول القائمة: `insurance-new` على `/finance/insurance/premium` بعقد صفحة الويب حرفيًا؛ `commitment-new` على عقود الموردين بمنتقي مورد + endDate؛ `obligation-new` على `/obligations` بعقده الفعلي (كيان من منتقٍ + نوع من تعداد المحرك + dueAt، المبلغ/الأولوية في metadata)؛ `bank-account-new` تنشئ عقدة دليل `accountUsage='bank'` (لا كيان «حساب بنكي» في الخادم — فجوة تصميم موثقة، IBAN في nameEn مؤقتًا).
> - **#3304 (دفعة ١١ — حذف بالمادة ٤):** حُذفت الـ20 شاشة الجوال المالية الميتة قطعًا (معزولة عن كل ملاحة + مكسورة داخليًا + بدائلها عاملة: عائلة دليل الحسابات الست، gl-helpers، 11 نسخة create يتيمة، customer-receipt-new/expense-new) مع 4 تسجيلات `_layout` يتيمة. **بهذا كل شاشات الجوال المالية المتبقية إما عاملة أو مُصلحة.** ملاحظة: إدارة دليل الحسابات بلا شاشة جوال (كانت أصلًا غير قابلة للوصول) — تُبنى صحيحًا عند الطلب.
> - **#3312 (دفعة ١٢ — ملاحظات إبراهيم بلقطات شاشة 2026-07-08):** (أ) درج «إضافة منتج/خدمة» كان يفشل — بوابة `/warehouse` فُتحت `("warehouse","finance")` بسابقة `/clients` (الكتالوج صار بيانات رئيسة لنماذج المالية)، وفشل «التصنيفات» لم يعد يحجب النموذج (تحذير مضمّن + «بدون تصنيف»)، والعنوان «منتج / خدمة» والنوع أول حقل. (ب) كيانات توزيع البند اكتملت على مستوى القيد اليدوي: 6→14 كيانًا (منتقيا ContractSelect/AssetSelect مشتركان جديدان قراءة فقط) و`ENTITY_DIM_COLUMN` يختم القسم/المنتج/موسم ووكيل العمرة أبعادًا على سطر القيد الموزَّع (assertion حيّ). (ج) عمود ضريبة الواقعة صار منتقي رموز النظام و`taxCodeId` يُرسل.
> - **#3317 (دفعة ١٣ — تعميم أنماط ١٢ على كل النماذج المالية، أمر إبراهيم):** نمط الضريبة اليدوية عولج في 5 نماذج إضافية: `financial-invoice-create` + `financial-vendor-invoice-create` (نسبة رأسية حرة → منتقي رموز، «نسبة من المستند» لعينة OCR فقط)، `vendor-invoice-create` (مبلغ ضريبة البند يُشتق من رمزه × مبلغ البند، وحلّ حقن معرّف الرمز مكان code من ذاكرة الصنف)، جوال `vendor-invoice-new` + `invoice-new` (0/5/15 المثبتة → رموز النظام باحتياطٍ عند غيابها). نمط الحجب: الباقي كله على بيانات جوهرية — نظيف. نمط بوابات الوحدات: فُتحت للقراءة بحامل المالية على `/employees` و`/fleet` و`/properties` و`/projects` و`/umrah` (authorize لكل مسار يبقى الحارس؛ 4 ملفات تثبيت حُدّثت بتعليل «الوحدة مسجَّلة وحيدةً أو أولى قائمة»).
> **تحديث 8 يوليو 2026 مساءً — «نفذها كلها»: القرارات الثلاثة + ملاحظة الأطراف كلها مُنفَّذة ومدموجة:**
> - **#3322 (دفعة ١٤ — توحيد العهد + إلزام الموظف):** حساب العهد الرقابي للموظفين وُحِّد على «عهد مالية للموظفين» (غرض `employee_custody`→1142) بورقة موظف postable تُفتح آليًا عند أول عهدة عبر المحرك الموحّد؛ أُزيل التفتّت (1113/1142/**1400** — و1400 حساب المخزون أصلًا!) من مرساتَي الإلحاق (`employees.ts`+`admin.ts`). و`createCustodySchema` يُلزم `assignmentId` (الاسم الحر يُرفض 422). 1113 يبقى لعهد السائقين/المركبات. اختبار HTTP حي.
> - **#3328 (دفعة ١٥ — سجل الشيكات، جدول جديد معتمد):** هجرة 492 (`cheques` + ضمان 1134/2113 + غرضَي `cheques_under_collection`/`postdated_cheques_payable`). القبض بشيك (`method=check`) يوجّه المال إلى **1134** «تحت التحصيل» لا بنك، ويُسجّل الشيك مربوطًا بقيد سند القبض. مسار `finance-cheques.ts`: بنّاؤون نقيون `chequeJournalPlan` + أفعال `/cheques/:id/{collect,bounce,present,cancel}` + `/cheques/outgoing` (تحصيل DR بنك/CR 1134 · ارتداد DR ذمة/CR 1134 · تقديم DR 2113/CR بنك · إلغاء DR 2113/CR المقابل) — قفل صف، بوابة فترة، idempotent. صفحة «سجل الشيكات» + تبويب. اختبار HTTP حي.
> - **#3330 (دفعة ١٦ — حسابات الأطراف الفرعية، ملاحظة إبراهيم):** الفجوة الوحيدة كانت مسار مورد المستودع (`warehouse.ts` — نفس جدول suppliers) لا يفتح ورقة الذمّة (بخلاف `finance-vendors.ts`) — أُلحق نداء المحرك (AP تحت 2110). و`POST /finance/subsidiary-accounts/backfill-parties` (requireMinLevel 70، idempotent) يفتح الأوراق الناقصة للأطراف القائمة + زر في صفحة الحسابات الفرعية. اختبار HTTP حي.
> - **#3334 (دفعة ١٧ — إصلاح تراجع):** PR تدقيق #3323 تفرّع قبل #3312 فأسقط صامتًا عمود رمز الضريبة في `financial-event-create.tsx` وحده (بقية دفعتَي ١٢/١٣ سليمة) — استُعيد منتقي رموز الضريبة. **درس: rebase PRs طويلة الأمد قبل الدمج.**
> - **بهذا لا قرارات معلّقة على إبراهيم في هذا الخط** — التكليف الأصلي (الثغرات الثلاث) + مرحلة الحارس المالي + ملاحظات تسجيل الواقعة + تعميمها + القرارات الثلاثة + ملاحظة الأطراف = كلها مدموجة على main (١٩ PR).

> **سياق لقطة 18–26 يونيو** (تحقّق فجوات السلامة المالية، اكتمال درج الإنشاء، توحيد الإدخال المالي، مسح المسارات 9–14، إغلاق بنود معمارية: RBAC حوكمة + توحيد مساري CRM + بُعدا fleetEngine وجرد دورة العد؛ FX revaluation الخيار أ مُنفَّذ #2873 + إصلاح خلل idempotency #2897 بتحقّق تشغيلي؛ لوحة الصدق مُكمَّلة: قياس القيود اليتيمة #2874 + بوابة إقفال حاجبة B3 #2902؛ FX مكتمل ومتماسك: تنظيف legacy #2907 + إحياء الطابور المؤجَّل بحارس ازدواج صلب #2924 + إصلاح تعدّد العملات #2927؛ توحيد preflight #2909؛ مسح آمن #2917). هذه نقطة زمنية ثابتة من ذاكرة إدارة المشروع، **لا تتحدث تلقائيًا.** عند أي تعارض، الكود الفعلي وحالة الـ PRs الحية هي الحقيقة. حدّث هذا الملف يدويًا بعد كل تغيير جوهري.

## البنية التقنية الجارية (تطوّرت عن المواصفات الأصلية)

pnpm monorepo: `api-server` (Node.js/Express + PostgreSQL + Drizzle ORM) — `ghayth-erp` (React 19 + TypeScript + Tailwind) — `ghayth-erp-deck`. الهجرات (migrations) ملفات مرقّمة في `src/migrations`. النطاق: 3500+ commit، 3500+ ملف، 14 نطاقًا وظيفيًا، 300+ هجرة، 600+ صفحة، 100+ ملف مسار backend، 1200+ نقطة API.

## حالة المسارات

- **المالية (S7):** PR #1997 معتمد (معاينة فاتورة تعرض حسابات AR/إيراد/VAT — للقراءة فقط، لا تغيير ترحيل). محرك إطفاء التأمين معتمد للبناء: Engine A ينشئ جداول الاعتراف عند الرسملة؛ إطفاء شهري idempotent عبر `postJournalEntry`. تأمين العقار والتأمين الطبي بلا محركات ترحيل GL بعد. ⚠️ **محرك الترحيل الدوري `lib/engines/recurringPostingEngine.ts` — على `main` الحالي يحوي بروفايل الإهلاك فقط** (`assetDepreciationProfile`، يُرحَّل آليًا عبر cron `monthly_auto_depreciation`). بروفايلات EOS/الإجازات و cron حساب FX الآلي و`lib/badDebtPolicy.ts` (الديون القابلة للتحكم) **ليست على هذا الفرع/main** — هي عمل جلسات متوازية على فروع/PRs منفصلة لم تُدمج بعد إلى ما بُني عليه هذا الفرع. الموجود فعليًا للديون: cron تذكير فقط (`monthly_bad_debt_reminder` → `/finance/bad-debt/post`)، ولـFX: cron تذكير فقط (`monthly_fx_revaluation_reminder`). **لا تَفترض اكتمالها — تحقّق من الكود قبل الادّعاء.** ✅ **المُضاف فعليًا في هذا الفرع (جلسة 26 يونيو، `claude/ghaath-ui-experience-qdj81q`): بروفايل تسوية ضريبة القيمة المضافة — قياسي قابل للتحكم + ترحيل بشري:** `lib/taxSettlementPolicy.ts` (مفتاح `finance.tax_settlement_policy`: دورية + مهلة استحقاق + **حساب تسوية افتراضي عام `2131` قابل للتخصيص** — اعتماد إبراهيم 2026-06-25؛ `2130` تجميعي لا يقبل الحركة). النسبة تبقى مصدرها `getCompanyVatRate` وأكواد المخرجات/المدخلات من accounting_mappings (لا تكرار، دستور §5). سطح في `finance-zatca.ts`: GET/PUT `/tax-settlement/policy` + GET `/tax-settlement/preview` + **POST `/tax-settlement/post`** (ترحيل بشري idempotent عبر ref `VAT-SETTLE-{period}` + sourceKey، بوابة فترة مفتوحة، قيد متوازن مدين المخرجات/دائن المدخلات/الصافي للتسوية مع تجميع البنود حسب الحساب). الواجهة في `vat-reconciliation.tsx`: بطاقة سياسة قابلة للتعديل + لوحة معاينة/ترحيل التسوية. و cron تذكير `monthly_vat_settlement_reminder` (إشعار فقط) يذكّر المدير المالي بالفترة المنتهية غير المُرحَّلة ذات الحركة، بالدورية ومهلة الاستحقاق من السياسة. اختبارات: وحدة resolver + حيّ HTTP بتأكيدات على سطور القيد المرحَّل + اختبار cron التذكير (يُذكّر ثم يصمت بعد الترحيل).
- **الموارد البشرية:** Wave 0 مكتملة (كل النقاط مبوّبة بـ `authorize()`، اختبارات RBAC ratchet، ترتيب H0→H8). Wave 1B بدأت. ✅ **قوالب الأدوار «المكسورة» في لقطة 18 يونيو أُغلقت/لا فعليّة (تحقّق 24 يونيو على الكود):** `attendance_officer`/`discipline_officer`/`performance_reviewer` نالت `rbac_role_grants` فعلية + استنساخ لكل شركة + إصلاح الـbinds عبر **migration 354** (و`payroll_officer` عبر 306)؛ و`hr_admin` **ليس دورًا حقيقيًا** — يظهر مرّة واحدة فقط في تعليق بـmigration 278، بلا تعريف rbac_roles وبلا أي مرجع في مسار/افتراضي/واجهة/seed، فلا إجراء (المادة 5: لا إنشاء كيان غير مطلوب). ✅ **منح الأدوار موحَّد بالكامل عبر النظام على خدمة مركزية واحدة `lib/rbacService.ts grantUserRole`** (تجد/تحلّ الدور، تفرض SoD بإعادة استخدام `findSeparationOfDutiesConflict`/`getActiveRoleKeysForUser` بلا تكرار قواعد، idempotent INSERT، تُبطل الكاشين [authzEngine grant cache + per-user roleGuard]، تنضمّ لمعاملة `withTransaction` عبر ALS): **(أ) إنشاء الموظف العادي + الدرج السريع** #2940 (واجهة `useRbacRoles` متعدّدة الاختيار، soft-fail، أول صالح=primary). **(ب) `admin.ts` onboard** #2944 (كان بلا SoD؛ صار soft-fail عبر الخدمة، صدق تشغيلي بـskippedRoles، ذرّية #1413 §6 محفوظة). **(ج) `admin.ts` POST /user-roles (منح يدوي) + PATCH /users/:id (استبدال دور)** #2947 (كانا يفوّتان إبطال كاش الصلاحيات [تقادم حتى 30 ث]؛ /user-roles صار عبر الخدمة بفشل SoD **حاد 403** مع seed-on-demand #1791 محفوظ، و PATCH أُضيف له bump+invalidate). مسار `rbac/v2 POST /users/:userId/roles` كان سليمًا أصلًا (SoD + كاش) فتُرك. assertion دينامي حيّ لكل المسارات (3/3 لكل). لا migration. كل منح/تعديل دور يُفعَّل فورًا.
- **النقل:** الفرع النظيف معتمد — commit السقالة أُسقط، الهجرة 282 مؤكدة (لا تمس القيود).
- **الأملاك:** PR #1999 معتمد (contractType موحّد، هجرة idempotent 286). الـ PRs الماسة للقيود 4/5/6 معلّمة لتحقق خاص.
- **المستودعات:** قلق ProductSelect العابر للنطاقات حُلّ (وكيل المستودعات عدّل `invoices-create.tsx` المملوك للمالية)؛ الإصلاح مؤكد (`sellPrice` هو الحقل الصحيح).
- **المشاريع:** فشلان صامتان أُصلحا — أخطاء 500 في إكمال المرحلة (كانت تعطّل فوترة المعالم)، وترحيل WIP ميت بسبب مفاتيح GL غير مزروعة.
- **العمرة:** PRs #1920 و#1931 و#1995 جاهزة للدمج. PRs #1996 و#1998 فيها bug واجهة حقيقي (`formatDateAr` بدل `formatUmrahDate` — يخالف تفضيل التقويم الهجري) — مأذون بإصلاحه، لا بتجاوز الحارس.

## ديون البنية التحتية (تتطلب حلًا)

- ✅ **أرقام الهجرات المكرّرة — مُدارة** (تحقّق 25 يونيو عبر `check-duplicate-migrations`): 0 تكرار غير مُدرَج؛ يبقى زوج واحد مُدرَج عمدًا (`fleet_rental_inspection` 282/293 — استعادة + إصلاح idempotency، تُزال علامته فقط بعد تأكيد كل DB إنتاج/staging على بادئة واحدة). لا عمل آمن متبقٍّ بلا وصول DB إنتاج.
- تفريغ مخطط فاسد (HR-022) ينقصه 13+ هجرة وكل بذور البيانات — السبب الجذري لصعوبة التحقق من قاعدة البيانات.
- خلل إعداد حماية الفرع: عدم تطابق اسم الفحص المطلوب يحجب 10+ PRs خضراء.
- 3 سكربتات تدقيق DB (`check-schema-drift`، `check-ghost-rows`، `check-sql-ambiguity`) لم تُشغّل على الهجرات المتراكمة — تحتاج `DATABASE_URL` حيًا.

## فجوات السلامة المالية

> **تحقّق 2026-06-21 على الكود الفعلي:** ثلاث من الفجوات الأربع أُغلقت، والرابعة كانت لقطة خاطئة. لا عمل دفتر آمن متبقٍّ.

- ✅ **مُغلقة** — إطفاء أقساط التأمين: `insuranceEngine.ts` + `prepaidAmortizationEngine.ts` يوفّران محرك اعتراف + إطفاء شهري idempotent (DR مصروف / CR 1172) لنوعَي التأمين العقاري والطبي عبر `prepaid_amortization_schedules` + `prepaid_amortization_postings`.
- ✅ **لا فجوة (تصحيح لقطة)** — `propertiesEngine.ts` يستخدم حساب **2150** الصحيح (مستحقات صيانة، `property_maintenance_payable`)، لا 2160. حساب 2160 محفوظ للإيراد المؤجّل للعملاء.
- ✅ **مُغلقة** — القيد اليدوي: `finance-hardening.ts` يفرض سير `draft→review→approve→post` + maker-checker (المنشئ لا يراجع/يعتمد قيده) + `requireMinLevel(70)` + فحص توازن وفترة مفتوحة.
- 🟢 **مُغلق تشغيليًا** — تعبئة الأبعاد: `journalLineDimensionalEnricher.ts` + المحركات (umrah/fleet/hr/properties/finance) تمرّر أبعادها على كل السطور. أُغلقت فجوتا فقد بُعد صامتتان مع assertion tests: `fleetEngine.postViolationPaymentGL` (vehicleId على سطر النقد، #2863) و`post-cycle-count-journal` (warehouseId عبر dimensionJson، #2866). **FX revaluation — مكتمل ومتماسك (سلسلة #2873/#2897/#2907/#2924/#2927):** القيد المجمّع القديم كان مرفوضًا عند الترحيل (إنفاذ الأبعاد على 1131/2111)، فصار مفصّلًا لكل كيان (AR لكل عميل بـclientId، AP لكل مورد بـvendorId + سطرَي مكسب/خسارة) — #2873. وأُصلح خلل idempotency (`revaluationDate`→`period`، كان 500 لأي طلب، كشفه التحقّق التشغيلي) — #2897. ونُظّف `ensureFxTables` المضلِّل — #2907. **التدفّقان متماسكان:** المسار المباشر `POST /finance/fx/revaluation/post` + مسار الطابور المؤجَّل (`compute`→`runPeriodEndRevaluation`→طابور gl-posting-queue→`postFxRevaluationJournal`) أُحيي — #2924، مع **حارس ازدواج صلب (DB)** عبر UNIQUE(companyId, period) على `fx_revaluations` يكتبه كلا المسارين (أيّهما سبق يحجب الآخر، assertion 5/5). وأُصلح فشل المباشر عند تعدّد العملات (كان يُدرج صفًا لكل عملة → 23505؛ صار صفًا واحدًا لكل فترة + تفصيل perCurrency، assertion 6/6) — #2927. المصادر بلا بُعد طبيعي (قيد يدوي/تسوية بنكية/إقفال) = null مقبول بحكم التصميم.

## سكربتات التدقيق

تعمل بدون `node_modules`: `node scripts/src/[name].mjs`. منها: `audit-domain-boundaries.mjs`، `audit-stop-ship.mjs`، `audit-event-bus.mjs`، `check-frontend-backend-wiring.mjs`، `check-duplicate-migrations.mjs`. ثلاثة تحتاج `DATABASE_URL` حيًا وتُشغّل على الخادم.

## على الأفق

- المسارات 9–14 (القانونية، الدعم، CRM، الاتصالات، الوثائق، الحوكمة/BI): ✅ مرّت بمسح تنظيف 2026-06-21 — معرَّبة بالكامل، مصطلحات موحّدة، حالات تحميل/خطأ/فراغ شاملة، لا روابط/imports مكسورة. أُغلقت ملاحظتان عبر #2862 (حماية زر «إصدار جديد» بـRBAC في governance/policies؛ عنوان CRM ديناميكي حسب المرحلة). ✅ وُحِّد مسارا CRM عبر #2865 — المسار الكنسي `/crm/:id` (opportunity-detail)، و`/crm/leads/:id` صار redirect يحفظ المعرّف (صفر كسر روابط، الميزات منقولة).
- لا يوجد harness لاختبار سلوك الواجهة — مؤجل بالكامل.
- ✅ **لوحة الصدق (Truthfulness) — مبنية ومُكمَّلة:** الـendpoint `/finance/reports/ledger-truth` + صفحة `ledger-truth.tsx` قائمان أصلًا (% P&L المُبعّد، fallback، يدوي أعمى). أُغلقت فجوة القياس الوحيدة عبر #2874 (القيود اليتيمة بالمصدر — قيد آلي مُرحَّل بلا sourceType/sourceId، تُحقّق تشغيليًا). وبوابة الإقفال صارت **تحجب** الإقفال على أي قيد يتيم (B3، #2902 — قرار إبراهيم: حاجب صفر تسامح، مع assertion على البوابة 3/3). ✅ **B4 مُنجز (تحقّق 25 يونيو):** صفحة `period-close-preflight.tsx` تستهلك المنسّق الكنسي `GET /finance/fiscal-periods-v2/:id/close-preview` مباشرة (الحاجزات + canClose منه)، فلا ازدواج preflight.
- ✅ **تعميم نمط AllowCreateDrawer مكتمل لكل الكيانات المسجَّلة** (vendor/driver/vehicle/account عبر #2859؛ client/project/employee عبر #2860). cost-center يستخدم Dialog inline؛ department/branch بلا صفحات قوائم تنقل لـ/create. صفحات /create المعقّدة (رواتب/عقود/أوامر شراء/فواتير) تبقى كاملة بحكم التصميم.
- ✅ **توحيد شاشات الإدخال المالي على نمط الجدول مكتمل** — الفاتورة (#2853) وفاتورة المورد (#2855) حُوِّلتا من بطاقات عمودية لجدول سطور مضغوط (عرض فقط، حمولة الدفتر متطابقة). باقي الشاشات جداول/موحّدة أصلًا.
- ✅ **دمج دفعة PRs من جلسات أخرى (24 يونيو، اعتماد إبراهيم + مراجعة مجلس لكل diff فعلي):** #2946 تقطيع umrah-group-transport (نقل حرفي، حد الخدمة محفوظ) · #2899 بوابة قبول UX (وثائق + فحص `check:dangerous-actions` حاجب مُجمَّد على 38 confirm() قائمة في `guard.sh` + workflow ux-gate غير إلزامي) · #2630 ضمان ربط مركز التكلفة عند الإنشاء عبر `ensureCostCenterForEntity` المُنتظَر (لا يرمي، idempotent، علامة LINK_GAP غير صامتة بدل fire-and-forget؛ لا يمس الدفتر — مركز تكلفة فقط؛ أُصلح انجراف سطر allowlist لـfinance-period-drift). #2856 (تقطيع umrah-refunds، Phase 3) **أُغلق متقادمًا** — الملف موجود أصلًا على main عبر Phase 14. ملاحظة تشغيلية: حماية الفرع «require branches up to date» + نشاط دمج متوازٍ كثيف على main يجعل الدمج سباق نوافذ (يلزم مزامنة فوقتًا مناسبًا).
- مسار `db:provision-agent` — مفتاح فك العمل المتوقف server-side عبر المالية/العمرة/الأملاك.
- معمارية الاشتراك/الاستحقاق لكل وحدة: `subscriptionGate.ts` على مستوى الشركة فقط؛ الاستقلال لكل وحدة ~25–30% متحقق.
- الجوال: إكمال PWA أولًا (manifest، أيقونات، caching) ثم Capacitor (سائق الأسطول، الموافقات، الحضور الميداني).
- ZATCA Phase 2 وتعدد العملات: مؤجلة.
- 🟢 **`FIN-RECURRING-POSTING-ENGINE` (المحرّك الدوري الموحّد) — قيد البناء التدرّجي** (المواصفة `plans/fin-recurring-posting-engine-spec-2026-06-24.md`، اعتماد إبراهيم «نعم»). على main: عقد `RecurringProfile` + `assetDepreciationProfile` (موصول حيًّا بـcron الإهلاك، مُثبَت بالتكافؤ) + runner `planRecurringPostings` + **profilا `eosAccrualProfile`/`leaveAccrualProfile`** (#2970 — دوال نقية per-employee، EOS 1/24→1/12 · الإجازات (راتب/30)×(أيام/12)، DR5260/CR2220 و DR5270/CR**2150**، assertion 15/15). ✅ **توصيل استحقاقات HR حيًّا**: cron `monthly_hr_accruals` (يوم 3 شهريًّا) يؤتمت `hr.ts /accruals/monthly` اليدوي — يحسب المبالغ من الـprofiles ويُرحّل عبر `hrEngine.postMonthlyAccrualsGL`، **بلا migration**، idempotent عبر مرجع `HR-ACCRUAL-{period}` **المشترك** مع المسار اليدوي (لا ازدواج)، بوابة فترة، assertion على سطور القيد الحيّة (متوازن + الحسابات + idempotency). ✅ **التفصيل per-employee** (#2973): سطور الاستحقاق تحمل بُعد `employeeId`/`branchId` (معامل `breakdown` اختياري؛ المساران اليدوي + cron يمرّرانه؛ توافق خلفي للإجمالي؛ بلا migration — عمود `journal_lines.employeeId` بهجرة 122؛ الحساب 2150 المشترك: البُعد مُسجَّل لا مُنفَّذ). ✅ **سياسة مخصّص الديون قابلة للتحكم + قياسية** (#2977): `lib/badDebtPolicy.ts` — افتراضي قياسي (0/5/25/50/75% بالتقادم) قابل للتحكم لكل شركة عبر مفتاح settings `finance.bad_debt_policy` (القياسي←الشركة←الطلب، قصّ [0,1])؛ المعاينة/الترحيل يحلّانه؛ بلا migration؛ assertion unit 9 + dynamic 3. **المتبقّي:** `tax_settlement` (تابع لـ#2280 خارجي) + أتمتة ترحيل مخصّص الديون cron (مؤجّلة عمدًا — قرار حُكمي للمستخدم). FX **لا يناسب** عقد الـprofile (تجميع per-period) — يبقى على تدفّقه المخصّص. **الخلاصة: استحقاقات HR مُؤتمتة per-employee، ومخصّص الديون قابل للتحكم بقياسي — كلها آمنة ومدموجة.**

## مبادئ متراكمة (إضافة للدستور)

- **فهرسة الحقول المشفّرة:** لا يمكن فهرسة الحقول المشفّرة مباشرة (AES-GCM IVs عشوائية). استخدم نمط Encrypted+Hash: AES-256-GCM للتخزين، HMAC-SHA256 للبحث.
- **Mock-First للتكاملات الخارجية:** 3 شروط مسبقة قبل بناء المحوّلات الحقيقية.
- **ProductSelect مشترك واحد** يُبنى مرة (المستودعات) ويُعاد استخدامه — لا تكرار.
