الأعراف

للمسؤولين

تنطبق هذه القواعد على كل نقطة تحت /api/v1. ولا تصف صفحات الموارد إلا ما يختلف عنها.

الشكل

  • المسارات بصيغة الجمع وبأحرف صغيرة مفصولة بشرطات (/org-units، /job-descriptions)، والحقول بصيغة camelCase.
  • النص ثنائي اللغة بصيغة { "ar": …, "en": … }. العربية هي اللغة الأساسية: حيث يكون الاسم مطلوبًا، تكون ar مطلوبة.
  • الأوقات بصيغة ISO 8601 بتوقيت UTC (2026-10-24T09:46:14.331Z).
  • لكل كائن id وexternalRefs وcreatedAt وupdatedAt (ولصفوف التدقيق وآثار الحذف حقول وقت خاصة بها).
  • تُرفض الحقول غير المعروفة في جسم الطلب (422 validation_failed)، فلا يمر خطأ إملائي دون أن تلاحظه.

المعرّفات والمعرّفات الثابتة والمعرّفات الخارجية

المفتاحما هواستخدمه في
idمعرّف جديرون (cuid).استدعاء الواجهة البرمجية داخل بيئة واحدة.
slugمفتاح ثابت لا يتغير على صفوف الكتالوج: القطاعات والقطاعات الفرعية والعائلات الوظيفية والجدارات العامة. وصفوف مساحة العمل الخاصة قيمتها slug: null.ربط صفوف الكتالوج بين بيئات جديرون.
externalRefs[{ system, externalId }]: معرّفاتك أنت، مربوطة بالسجل.ربط سجلاتك أنت بسجلات جديرون، في كل بيئة.

تختلف المعرّفات بين بيئات جديرون (الاختبار، والإنتاج، والنشر المخصص)، وتتغير عند إعادة تعبئة مساحة عمل تجريبية أو اختبارية. لذلك:

  • لا تنسخ المعرّفات بين البيئات. وإن حفظتها فاحفظها لكل بيئة على حدة.
  • اربط صفوف الكتالوج بـ slug.
  • اربط صفوف مساحة العمل بـ externalRefs: أنشئها أو عدّلها بنقاط PUT …/by-external/{system}/{externalId}، وابحث عنها بـ ?externalSystem=&externalId=، وسمّها في أجسام الطلبات بصيغة { "externalSystem": "…", "externalId": "…" }. انظر دليل المزامنة مع ERP.

system نص حر حتى 64 حرفًا (مثل oracle-hcm أو sap-sf)، وexternalId حتى 128 حرفًا.

الترقيم

كل قائمة مرقّمة بالمؤشر:

curl "https://jadiroon.com/api/v1/employees?limit=100" -H "Authorization: Bearer $JADIROON_KEY"
{ "data": [ … ], "nextCursor": "Y212bTdydTBxMDAwNmtuZGxlMGZ4NGl2dA" }
  • limit من 1 إلى 100 (الافتراضي 50).
  • أعد nextCursor في المعامل cursor للصفحة التالية؛ وتعني nextCursor: null أنها الصفحة الأخيرة.
  • المؤشرات معتمة: لا تبنِها ولا تفك ترميزها. المؤشر المشوَّه يُرجع 422، لكن مؤشراً نصياً بسيطاً غير معروف قد يُرجع ببساطة صفحة لاحقة.
  • من دون updatedSince تأتي الصفوف بترتيب id، ومعه بترتيب updatedAt ثم id.
  • يحمل المؤشر موضعه في هذا الترتيب، فلا يُفسد تعديلُ صف أو حذفه أثناء التصفح المسارَ: لا يُتخطّى أي صف بعد المؤشر، ولا تفشل الصفحة التالية لأن آخر صف حُذف. ومع updatedSince ينتقل الصف المعدَّل أثناء التصفح إلى النهاية فتقرؤه مرة أخرى، لذا أزل التكرار بحسب id. وتظل المؤشرات الصادرة قبل 2026-10-25 صالحة.

المزامنة التدريجية بـ updatedSince

تقبل كل قائمة updatedSince (ISO 8601). وتعيد الصفوف التي قيمة updatedAt فيها تساوي هذا الوقت أو بعده، بما فيها الصفوف المؤرشفة (مع archivedAt)، فتعرف بالأرشفة دون طلب منفصل.

حلقة مزامنة آمنة:

  1. سجّل الوقت الحالي T.
  2. اقرأ كل الصفحات مع updatedSince = آخر علامة مائية لديك.
  3. حدّث سجلاتك حسب id (قد يظهر الصف نفسه مرتين إذا تغير أثناء التصفح).
  4. اقرأ سجل المحذوفات مع since = العلامة نفسها.
  5. احفظ T ناقص دقيقة واحدة علامةً مائية جديدة.

ما ينبغي معرفته:

  • يتغير updatedAt أيضًا عند تغيير السجل في التطبيق، وعندما يمسه تغيير مرتبط (مثل وظيفة تصبح بلا وحدة تنظيمية عند حذف وحدتها).
  • أول مزامنة بعد إطلاق الواجهة البرمجية: السجلات الموجودة قبل الإطلاق تحمل كلها updatedAt = تاريخ الإطلاق، فتعيد أول مزامنة بـ updatedSince كل شيء. ابدأ بقراءة كاملة.
  • سجل التدقيق يصفّي حسب occurredAt بدلًا من ذلك، وصفوفه لا تتغير أبدًا.
  • تغييرات الكتالوج التي يجريها جديرون (القطاعات والقطاعات الفرعية والعائلات الوظيفية العامة) لا ترسل أحداث خطافات ويب. أعد قراءة /sectors و/sub-sectors و/job-families دوريًا (مرة يوميًا تكفي).
  • إزالة قطاع فرعي أو عائلة وظيفية أو قطاع من الهيكل الوظيفي لمساحة عملك ترسل أحداث <resource>.deleted، لكنها لا تترك أثر حذف (لم يُحذف شيء). قارن بقراءة كاملة للقائمة لاكتشافها دون خطافات الويب.

سجل المحذوفات

يمكن مزامنة الحذف النهائي دون خطافات الويب:

curl "https://jadiroon.com/api/v1/deleted?since=2026-10-24T00:00:00Z&resource=position" \
  -H "Authorization: Bearer $JADIROON_KEY"
{
  "data": [
    { "resource": "position", "id": "cmv…", "externalRefs": [{ "system": "oracle-hcm", "externalId": "POS-310" }], "deletedAt": "2026-10-24T10:02:11.000Z" }
  ],
  "nextCursor": null
}
  • كل حذف نهائي لسجل عام، في التطبيق أو عبر الواجهة البرمجية، يكتب أثر حذف يحمل externalRefs كما كانت. وتُحفظ آثار الحذف 180 يومًا.
  • المعاملان since وresource (مثل employee وorg_unit وjob_description) اختياريان، وlimit وcursor كالمعتاد.
  • لا ترى إلا آثار حذف الموارد التي يستطيع مفتاحك قراءتها. و?resource= لمورد لا يستطيع قراءته تعيد 403 forbidden، والمورد غير المعروف يعيد 422 validation_failed.
  • إنهاء خدمة موظف (DELETE /api/v1/employees/{id}) ليس حذفًا: يبقى السجل بالحالة FORMER_EMPLOYEE.

الكتابة

  • POST ينشئ، وPATCH يعدّل جزئيًا، وDELETE يحذف، وPUT …/by-external/… ينشئ أو يعدّل.
  • PATCH لا يمسح أبدًا ما لم ترسله. تبقى الحقول غير المرسلة كما هي، بما فيها المصفوفات الفرعية مثل جدارات الوصف الوظيفي. أرسل null لمسح حقل يقبل القيمة الفارغة.
  • لتغييرات الحالة نقاط خاصة بها (…/archive و…/close و…/stage و…/hire)، فتعمل قواعد التطبيق نفسها.

الأخطاء

لكل خطأ الجسم نفسه:

{ "error": { "code": "unresolved_reference", "message": "Could not resolve org_unit reference", "details": { "resource": "org_unit", "ref": { "externalSystem": "oracle-hcm", "externalId": "ORG-999" } } } }
  • اعتمد على code (وعلى details.reason حين يوجد)، لا على message. الرسائل بالإنجليزية وقد تتغير.
  • details اختياري ويختلف حسب الخطأ: issues (مشكلات على مستوى الحقول مع path)، وreason (القاعدة المحددة، مثل already_applied أو duplicate_person)، وrequired (مفاتيح الصلاحيات الناقصة)، وغيرها.
  • رموز أخطاء شاشات التطبيق لا تتسرب إلى الواجهة البرمجية؛ والقائمة التالية مغلقة. وتُعلن الرموز الجديدة في سجل التغييرات.
الرمزالحالةالمعنى
unauthorized401مفتاح مفقود أو غير معروف أو ملغى أو منتهٍ.
forbidden403المفتاح ينقصه صلاحية (details.required)، أو التكامل موقوف مؤقتًا، أو العنوان ليس في القائمة المسموحة، أو حاول مفتاح على مستوى النشر الكتابة.
not_found404لا يوجد هذا السجل في مساحة عملك (وكذلك لسجلات مساحات العمل الأخرى).
validation_failed422الطلب غير سليم أو يخالف قاعدة: الجسم ليس JSON أو غير صالح (details.issues أو details.reason)، أو قيمة خاطئة لـ limit أو cursor أو updatedSince أو since، أو resource غير معروف، أو غياب Idempotency-Key في الإدراج المجمّع.
conflict409التغيير يتعارض مع الحالة الحالية؛ ويوضح details.reason كيف (مثل أن المعرّف الخارجي مربوط بسجل آخر، أو already_applied، أو opening_not_open).
has_people409ما زال في الوظيفة موظفون.
has_openings409ما زال للوظيفة شواغر أو نماذج تقييم مقابلات.
has_children409ما زال للوحدة التنظيمية وحدات فرعية.
unresolved_reference422مرجع في الجسم (parent أو orgUnit أو jobDescription أو manager …) غير موجود في مساحة عملك.
ssco_managed409الوصف الوظيفي من الكتالوج الوطني SSCO وهو للقراءة فقط.
idempotency_conflict409استُخدم Idempotency-Key لطلب مختلف، أو ما زال الطلب الأول به قيد التنفيذ.
rate_limited429أكثر من 600 طلب في الدقيقة؛ انتظر Retry-After ثانية.
too_many_jobs429للتكامل بالفعل مهمتا إدراج مجمّع في الانتظار أو قيد التشغيل.
workspace_inactive403مساحة العمل موقوفة أو محذوفة.
webhook_egress_not_configured422هذا النشر لا يسمح بأي خطافات ويب صادرة (لا توجد له قائمة مضيفين مسموحة).
forbidden_host422مضيف عنوان خطاف الويب ليس عامًا أو ليس في القائمة المسموحة لهذا النشر.
internal500 أو 502فشل شيء من جهتنا (502: تعذرت قراءة ملف محفوظ). أعد المحاولة مع مهلة متزايدة؛ ومع Idempotency-Key تكون إعادة المحاولة آمنة.

منع التكرار

تقبل نقاط POST الترويسة Idempotency-Key (أي نص حتى 255 حرفًا، مثل UUID). وهي مطلوبة في الإدراج المجمّع.

  • تُحفظ المفاتيح 24 ساعة لكل تكامل.
  • المفتاح نفسه مع الطلب نفسه (الطريقة والمسار والجسم) يعيد الاستجابة المحفوظة (الحالة والجسم نفسيهما) دون تنفيذ الطلب مجددًا. وتحمل الاستجابة المعادة Idempotent-Replayed: true؛ ولا تُعاد ترويسات الاستجابة الأصلية.
  • المفتاح نفسه مع طلب مختلف يعيد 409 idempotency_conflict. وكذلك طلب ثانٍ بينما الأول ما زال يعمل: أعد المحاولة بعد لحظة. وإذا لم يكتمل الطلب الأول (كأن انقطع)، يُحرَّر المفتاح بعد 90 ثانية من أول استخدام له، وعندها تُنفِّذ إعادة المحاولة الطلب.
  • استجابات 4xx تُحفظ أيضًا. بعد تصحيح طلب مرفوض أرسله بمفتاح جديد، وإلا عاد إليك الخطأ المحفوظ طوال 24 ساعة.
  • استجابات 5xx لا تُحفظ: إعادة المحاولة بالمفتاح نفسه تنفذ الطلب مجددًا.
  • لا يحتاج PUT …/by-external/… إلى مفتاح: فهو بطبيعته لا يتكرر أثره.