تخطَّ إلى المحتوى

مواصفة واجهة برمجة التطبيقات

المرجع الكامل لنقاط نهاية REST. للدروس والأمثلة، انظر دليل واجهة برمجة التطبيقات.

كل ما يستطيع عضو المشروع فعله في واجهة الويب متاح هنا — فتطبيقة الصفحة الواحدة (SPA) تستهلك واجهة برمجة التطبيقات نفسها. العمليات التي تتطلّب دور المدير مُعلَّمة بـ (manager)؛ وكل ما عداها يحتاج عضوية المشروع فقط (أو، للقراءات المُعلَّمة بـ (viewer)، أي مستوى وصول). تُسمّي الجداول أدناه كل مجموعة مسارات يُركّبها الخادم؛ والمجموعات الملخَّصة في سطر واحد موصوفة بالكامل في openapi.json الحيّة.

https://eastagiletracker.com/api/v1

يقدّم https://api.eastagiletracker.com/api/v1 واجهة برمجة التطبيقات نفسها. كل الطلبات والاستجابات بصيغة JSON، باستثناء بضع نقاط نهاية لرفع الملفات تقبل multipart.

تقع مجموعتان مستوىً واحدًا أعلى، تحت /api بدلًا من /api/v1: سطح المصادقة (/api/auth/*) والنماذج العامة (/api/contact، و/api/feedback). وتهجئاتها بصيغة /api/v1/… تُعيد 404.

يُرسِل كل طلب مصادَق عليه بيانات اعتماد عبر أحد:

  • X-TrackerToken: <key>
  • Authorization: Bearer <key>

تبدأ مفاتيح المستخدم بـ ea_user_، ومفاتيح الوكلاء بـ ea_agent_، ورموز وصول MCP بـ ea_mcp_. انظر دليل واجهة برمجة التطبيقات ← ثلاثة أنواع من بيانات الاعتماد.

نقاط النهاية غير المصادَق عليها: /openapi.json، و/docs، ونقاط نهاية /api/auth/*، وعمليات البحث في البيانات المرجعية (/story_types، و/story_states، و/effort_scales، و/priority_scales). أما /meta فهي مصادَق عليها — أي مفتاح صالح يعمل، لكنها غير محصورة بالمشروع (يصل إليها أيضًا مفتاح وكيل مرتبط بمشروع).

أربعة مستويات تتحكّم في نقاط النهاية المحصورة بالمشروع:

المستوىمن يجتازالعمليات النموذجية
public viewerأي أحد، على مشروع رؤيته عامةقراءات اللوحة: القصص، والتكرارات، والبحث، ونشاط القصص والملاحم (مع إخفاء تفاصيل الفاعل)
viewerviewer، member، managerالقراءات (سرد/جلب القصص، والبحث، والمقاييس، وقائمة صيغ التصدير)
membermember، managerكل كتابات عناصر العمل (القصص، والمهام، والتعليقات، …)، وتدفق الأحداث
managermanager فقطإعدادات المشروع، وإدارة العضوية، ومفاتيح الوكلاء، والحذف، والاستيراد، وتنزيلات التصدير، والنسخ الاحتياطية، وسجل التدقيق

يحمل الوكلاء الأدوار نفسها التي يحملها الأعضاء — viewer أو member أو manager — بسقف هو دور العضو الذي أصدر المفتاح. يتلقّى غير العضو 404 unfound_resource (لا 403) على مسارات المشاريع الخاصة، فلا تكون معرّفات المشاريع قابلة للتعداد.

نقاط النهاية ذاتية الوصف

Section titled “نقاط النهاية ذاتية الوصف”
الطريقةالمسارالوصف
GET/openapi.jsonمواصفة OpenAPI 3 الحيّة، بما فيها أجسام الطلبات. غير مصادَق عليها.
GET/docsواجهة Swagger UI. غير مصادَق عليها.
GET/metaهوية المستدعي (auth.kind/key_id/agent_id/project_id) + رسم انتقالات حالات نوع القصة. مصادَق عليها (أي مفتاح صالح؛ غير محصورة بالمشروع). استدعِها أولًا.
GET/api/health · /api/configفحص الحياة، والإعداد العام للنشر (وضع المنظمة الواحدة، والميزات الاختيارية المفعّلة، واسم النسخة). غير مصادَق عليهما، وخارج /v1.

مسارات المصادقة (/api/auth/*، خارج /v1)

Section titled “مسارات المصادقة (/api/auth/*، خارج /v1)”

نقاط نهاية الجلسات، غير مصادَق عليها ما لم يُذكَر خلاف ذلك. تقودها تطبيقة الصفحة الواحدة؛ أما السكربتات فتستخدم عادةً مفتاح API بدلًا منها.

الطريقةالمسارالوصف
POST/auth/registerتسجيل حساب جديد — محمي بـ reCAPTCHA؛ ثم يجتاز الحساب تحدّي SMS
POST/auth/sms/challenge · /auth/sms/status · /auth/sms/bypassإرسال / فحص رمز SMS الخاص بالتسجيل (التجاوز مقصور على المشغّل)
GET/auth/configطرق تسجيل الدخول التي يتيحها النشر
POST/auth/loginتسجيل الدخول بالبريد الإلكتروني + كلمة المرور؛ يُعيد JWT جلسة، أو تحدّي TOTP
POST/auth/login/totpإتمام تسجيل الدخول برمز من تطبيق المصادقة أو برمز استرداد
POST/auth/passkey/login/start · /auth/passkey/login/finishتسجيل دخول WebAuthn دون كلمة مرور
GET/auth/oauth/github/start · /auth/oauth/github/callback · /auth/oauth/google/start · /auth/oauth/google/callback · POST /auth/oauth/exchangeتسجيل الدخول عبر OAuth باستخدام GitHub أو Google
POST/auth/refresh · /auth/refresh/revokeتدوير رمز التحديث / إبطاله
POST/auth/logoutتسجيل الخروج (يُبطِل رمز التحديث)
POST/auth/forgot-password · /auth/reset-passwordطلب بريد إعادة التعيين / استخدام رمز إعادة التعيين
POST/auth/accept-invite/lookup · /auth/accept-inviteتحويل رمز دعوة ← بريد إلكتروني / قبول دعوة المشروع (بعد المصادقة)

تتصرّف هذه على المستدعي وتحتاج مفتاحًا صالحًا فقط (بلا دور مشروع).

الطريقةالمسارالوصف
GET/meالملف الشخصي للمستخدم الحالي
PUT/meتحديث الملف الشخصي
DELETE/meحذف الحساب — يُرفَض ما دمت المالك الوحيد لمنظمة أو لمشروع فيه أعضاء آخرون
GET/me/deletion-impactما الذي سيزيله حذف الحساب وما الذي يمنعه
PUT/me/passwordتغيير كلمة المرور
PUT/me/settingsتحديث الإعدادات (السمة، وتفضيلات الإشعارات)
POST/me/avatarرفع صورة رمزية (multipart)
POST/me/api-token/regenerateتدوير رمز API الخاص بك — يُبطِل الجلسات/المفاتيح القائمة
GET/me/api_keys · POST /me/api_keys · DELETE /me/api_keys/{id}إدارة مفاتيح API للمستخدم (ea_user_)
GET/me/totp · POST /me/totp/setup · /me/totp/verify · /me/totp/disableتسجيل المصادقة الثنائية (TOTP)؛ وتُعيد verify رموز الاسترداد مرةً واحدة
GET/me/passkeys · POST /me/passkeys/register/start · /me/passkeys/register/finish · DELETE /me/passkeys/{credential_id}تسجيل مفاتيح المرور وإزالتها
GET/me/oauth_grants · DELETE /me/oauth_grants/{grant_id}التطبيقات المتصلة — عملاء MCP وتطبيقات OAuth التي أذنت لها
GET/me/activityنشاطك عبر كل المشاريع
GET/me/storiesالقصص التي تملكها أو طلبتها أو تتابعها عبر كل مشروع يصل إليه الرمز — role=owned|requested|following، وstate=، وcursor= / limit= (الحد الأقصى 200)
GET/me/mentions · POST /me/mentions/{mention_id}/ackصندوق @-الإشارات (unacked=true للتصفية) والإقرار بها — وهي مدموجة أيضًا في موجز الإشعارات أدناه
GET/me/data-exportتصدير ذاتي لبياناتك بموجب اللائحة العامة لحماية البيانات (GDPR)
GET/me/consent · POST /me/consentقراءة / تسجيل الموافقة ({ consent_type, granted })
GET/legal/pending · POST /legal/acceptمستندات الموافقة بالنقر المعلّقة / تسجيل القبول
GET / PUT/agent/meهوية مفتاح الوكيل وملفه الشخصي، يقرؤهما الوكيل ويحرّرهما (النظير من جهة الوكيل لـ /me)
POST/api/contact · /api/feedback · /api/feedback/with-screenshotاتصال + تغذية راجعة داخل التطبيق. خارج /v1؛ ومحدودة المعدّل لكل IP

البيانات المرجعية (غير مصادَق عليها)

Section titled “البيانات المرجعية (غير مصادَق عليها)”

عمليات بحث بذرية تُستخدَم عند إنشاء/تقدير القصص. معرّفات مستقرة.

الطريقةالمسارالوصف
GET/story_typesfeature، bug، chore، release (+ allow_points)
GET/story_statesunstarted … accepted، rejected
GET/effort_scalesمقاييس التقدير المتاحة
GET/effort_scales/{scale_id}/valuesقيم النقاط في مقياس
GET/priority_scales · /priority_scales/{scale_id}/valuesمقاييس الأولوية وقيمها (يُحَلّ priority_id على القصة هنا)

للخدمة المستضافة فقط — يعمل التثبيت المُستضاف ذاتيًا في وضع المنظمة الواحدة ولا يُركّب هذه المسارات (باستثناء قائمة المنظمات). والأدوار هنا أدوار المنظمة: owner، وadmin، وmember.

الطريقةالمسارالوصف
GET / POST/organizationsسرد منظماتك / إنشاء واحدة
GET / PUT / DELETE/organizations/{oid}القراءة، وإعادة التسمية (الاسم + slug؛ للمالك أو المسؤول)، والحذف
GET / POST/organizations/{oid}/memberships · PUT / DELETE …/memberships/{member_id}الأعضاء والدعوات؛ تحمل الدعوات سقفًا للدور (لا يتجاوز أبدًا دور المستدعي؛ ودور المالك لا يُدعى إليه أبدًا)
POST/organizations/{oid}/memberships/bulk-role · …/memberships/bulk-removeتغيير دور ما يصل إلى 200 عضو أو إزالتهم دفعة واحدة. الكل أو لا شيء: تُرفض الدفعة بأكملها إذا كانت ستزيل آخر owner أو تترك مشروعًا بلا مالك؛ مع reassign_confirmed تصبح أنت مالك تلك المشاريع بدلًا من ذلك
DELETE/organizations/{oid}/invitations/{invitation_id}إلغاء دعوة معلّقة
POST/organizations/{oid}/transfer-ownershipتسليم دور المالك إلى عضو آخر
PUT/organizations/{oid}/memberships/{member_id}/anonymizationإخفاء اسم العضو / بريده الإلكتروني / صورته الرمزية على مستوى المنظمة
GET/organization-invitations/{token} · POST …/{token}/acceptتحويل / قبول دعوة منظمة مُرسَلة بالبريد الإلكتروني
POST/organizations/{oid}/export · GET / POST …/export/jobs · GET …/export/jobs/{job_id} · …/export/jobs/{job_id}/downloadتصدير المنظمة للمالك فقط: ملف zip فيه تفريغ SQL وكل مرفق، يجري كمهمة
الطريقةالمسارالوصف
GET/projectsسرد مشاريعك (limit ≤ 200)
POST/projectsإنشاء مشروع
GET/projects/{id}جلب تفاصيل المشروع (viewer)
PUT/projects/{id}تحديث إعدادات المشروع (manager)
DELETE/projects/{id}حذف مشروع (manager)
POST/projects/{id}/pinتثبيت المشروع في قائمة مشاريعك / إلغاء تثبيته
POST/projects/{id}/transfer-organizationنقل المشروع إلى منظمة أخرى (manager)
POST/projects/{id}/slack/testإرسال رسالة اختبار إلى تغذية Slack الخاصة بالمشروع (manager)
GET / POST/projects/{id}/showcase_claim_eligibility · /projects/{id}/showcase_claim · /projects/{id}/showcase_seedمشاريع العرض العامة: التحقّق مما إذا كنت تستطيع المطالبة بأحدها، والمطالبة به، وتعبئته
GET/projects/{id}/audit-logقراءة سجل التدقيق — تاريخ المشروع بالإضافة إلى نشاط لكل قصة / لكل ملحمة عبر surface=؛ يختلف الوصول حسب الـ surface، انظر أدناه
GET/projects/{id}/eventsتدفق أحداث مقسَّم صفحاتٍ بمؤشّر (member) — انظر الأحداث

معاملات استعلام سجل التدقيق: event_type= (نوع واحد أو قائمة مفصولة بفواصل)، وlimit= (≤ 1000)، وbefore= (مؤشّر keyset بصيغة ISO-8601 لـ created_at)، وsurface= (project_history، وstory_activities، وepic_activities)، وtarget_id= (معرّف القصة/الملحمة — مطلوب عندما يكون surface=story_activities أو epic_activities). الوصول: السجل غير المُرشَّح وsurface=project_history هما (manager)؛ بينما story_activities / epic_activities يمكن لأي عضو في المشروع قراءتهما، وبشكل مجهول في المشاريع العامة مع إخفاء البيانات الشخصية للفاعل.

الأعضاء، والوكلاء، ومفاتيح الوكلاء

Section titled “الأعضاء، والوكلاء، ومفاتيح الوكلاء”
الطريقةالمسارالوصف
GET/projects/{id}/membershipsسرد الأعضاء (viewer)
POST/projects/{id}/membershipsدعوة عضو عبر البريد الإلكتروني (manager)
PUT/projects/{id}/memberships/{mid}تحديث الدور (manager)
DELETE/projects/{id}/memberships/{mid}إزالة عضو (manager)
GET/projects/{id}/addable-members · POST /projects/{id}/members/add-existingأعضاء المنظمة غير المنضمّين إلى المشروع بعد / إضافة أحدهم دون دعوة بالبريد الإلكتروني (manager)
POST/projects/{id}/members/joinينضمّ مالك المنظمة أو مسؤولها إلى مشروع في منظمته بصفة مدير، أو يرقّي نفسه إلى ذلك (إجراء Make me owner في قائمة المشاريع)
PUT/projects/{id}/members/{mid}/anonymizationإخفاء اسم العضو / بريده الإلكتروني / صورته الرمزية في هذا المشروع (manager)
GET / POST/projects/{id}/agent_keysسرد / إصدار مفاتيح الوكلاء — للمديرين، أو للأدوار التي تسمح بها سياسة أدوار المنشئين في المشروع
DELETE/projects/{id}/agent_keys/{kid}إلغاء مفتاح وكيل
GET/projects/{id}/agent_keys/onboardingحزمة التهيئة: مطالبات وملفات إعداد لعملاء الوكلاء الشائعين
GET/projects/{id}/agents · GET / PUT /projects/{id}/agents/{aid}وكلاء المشروع وملفاتهم الشخصية (الاسم، والأحرف الأولى، والوصف، واللون)
POST/projects/{id}/agents/{aid}/rotate-key · /projects/{id}/agents/{aid}/avatarتدوير مفتاح وكيل (مع الاحتفاظ بالهوية والسِّجِلّ) / رفع صورته الرمزية

كل كتابات القصص تحتاج دور member.

الطريقةالمسارالوصف
GET/projects/{id}/storiesسرد القصص (مقسَّم صفحات، قابل للتصفية) (viewer)
POST/projects/{id}/storiesإنشاء قصة
GET/projects/{id}/stories/{sid}جلب قصة واحدة (viewer)
PUT/projects/{id}/stories/{sid}تحديث قصة
DELETE/projects/{id}/stories/{sid}حذف قصة
POST/projects/{id}/stories/{sid}/transitionsتغيير الحالة مع التحقّق
POST/projects/{id}/stories/{sid}/reject · /projects/{id}/stories/{sid}/restartرفض قصة مُسلَّمة / إعادة قصة مرفوضة إلى started (rejected حالة نهائية بالنسبة إلى /transitions)
POST/projects/{id}/stories/{sid}/archive · /projects/{id}/stories/{sid}/unarchiveأرشفة قصة واحدة / إلغاء أرشفتها
POST/projects/{id}/stories/bulk_transitionنقل قصص كثيرة (1–100) دفعةً واحدة
POST/projects/{id}/stories/bulk-archive · bulk-delete · bulk-duplicate · bulk-moveأرشفة قصص كثيرة، أو حذفها، أو تكرارها، أو تحريكها (إلى لوحة / موضع)
POST/projects/{id}/stories/{sid}/duplicateتكرار قصة واحدة
GET / POST / DELETE/projects/{id}/stories/{sid}/epics · …/epics/{eid}عضوية القصة في الملاحم
GET/short-links/{code} · /story-referencesتحويل رابط مختصر /s/<code> إلى قصته / تحويل ما يصل إلى 100 مرجع قصة (#id، وعناوين URL) إلى القصص التي يستطيع المستدعي قراءتها

معاملات الاستعلام لقائمة القصص: archived= (‏exclude افتراضيًا / include / only — مرشّح الأرشفة ثلاثي الحالات؛ يحل محل include_archived=true المهمل، الذي أصبح الآن اسمًا بديلًا لـ archived=include)، وinclude_done=true (يسمح بقصص لوحة Done المجمّدة على تكرارات سابقة، وهي مستبعدة افتراضيًا). يتبع التقسيم إلى صفحات (cursor= / limit= / offset=) ومجموعات الحقول المختصرة (fields=) قسمَي التقسيم إلى صفحات وإسقاط الحقول.

الإنشاء (POST …/stories): { "name" (required), "story_type": "feature|bug|chore|release", "description"?, "estimate"?, "current_state"?, "icebox"?, "labels"? }. estimate هو تسمية قيمة المقياس كسلسلة نصية ("3"، "13")؛ ويُرفَض الرقم بصيغة JSON. يقبل labels صيغة ["auth"] أو [{ "name": "auth" }]؛ وتُنشأ التسميات غير المعروفة. القيم الافتراضية: story_type=feature، وcurrent_state=unstarted.

التحديث (PUT …/stories/{sid}): الحقول نفسها، كلها اختيارية، إضافةً إلى "position" (float)، و"force_state_change" (bool)، و"expected_updated_at" (بصيغة RFC 3339 — يُرفَض حفظ الوصف بـ 409 stale_write إن تغيّرت القصة منذ قرأتها). وتحترم كتابات القصص أيضًا If-Match مقابل ETag القصة؛ وعدم التطابق هو 412 precondition_failed.

الانتقال (POST …/transitions): { "to": "<state>" }. الحقل هو to. يُعيد { story_id, state }. الحركة غير القانونية ← 422 invalid_transition مع details: { from, to, allowed }.

الانتقال الجماعي (POST …/bulk_transition): { "story_ids": [int,…] (1–100), "to": "<state>" }. تُحكَم كل قصة على نحوٍ مستقل؛ يُعيد { results: [ { id, status: "ok" } | { id, status: "failed", error } ] }.

كلها member. السرد/الجلب على معظمها (viewer).

الطريقةالمسارالجسم / ملاحظات
GET / POST/projects/{id}/stories/{sid}/tasks · PUT/DELETE …/tasks/{tid}{ description (or task_desc), complete?, task_order? }
GET / POST/projects/{id}/stories/{sid}/comments · PUT/DELETE …/comments/{cid}{ text (or comment_text) } أو { comment_emoji }. يأخذ GET المعامل fields= (قائمة السماح: comment_id، وstory_comment_id، وstory_id، وcomment_text، وcomment_emoji، وmember، وcreated) إضافةً إلى cursor= / limit= (≤ 200) / order=asc|desc
GET / POST/projects/{id}/stories/{sid}/blockers · PUT/DELETE …/blockers/{bid}{ blocker_desc, resolved? }
GET / POST/projects/{id}/stories/{sid}/links · PUT/DELETE …/links/{lid}{ url, link_type?, title? }link_typerelates_to، وduplicates، وblocks، وis_blocked_by، وpull_request، وbranch، وother؛ ويُحدَّد نوع عناوين GitHub التي تحوي /pull/ و/tree/ تلقائيًا
GET / POST/projects/{id}/stories/{sid}/reviews · PUT/DELETE …/reviews/{rid}الإنشاء: { reviewer_id? / reviewer_agent_id?, comment? } — احذف كليهما لإسناد المراجعة إلى نفسك. التحديث: { status, comment? }
GET / POST/projects/{id}/stories/{sid}/owners · DELETE …/owners/{mid} · DELETE …/owners/agents/{aid}{ member_id? / agent_id? } — احذف كليهما لإضافة المستدعي
GET / POST/projects/{id}/stories/{sid}/followers · DELETE …/followers/{mid} · DELETE …/followers/agents/{aid}{ member_id? / agent_id? }
GET / POST/projects/{id}/stories/{sid}/labels · DELETE …/labels/{lid}{ name }
GET / POST/projects/{id}/stories/{sid}/attachments (+ /json) · DELETE …/attachments/{aid}رفع multipart — الفيديو ≤ 200 ميغابايت، وPDF / Word / Excel ≤ 25 ميغابايت، والصور / CSV / النصوص ≤ 10 ميغابايت؛ والسرد (viewer)
GET / POST/projects/{id}/stories/{sid}/link-attachments · DELETE …/link-attachments/{laid}مرفقات الروابط — عنوان URL خارجي يُحفَظ إلى جانب مرفقات الملفات بدلًا من أن يكون رابط شيفرة
GET/attachments/{token} · /api/avatars/{token}قراءات مُعنوَنة برمز لمرفق أو صورة رمزية — عناوين URL التي تسلّمها واجهة برمجة التطبيقات؛ ولا حاجة إلى X-TrackerToken

البنية نفسها التي للقصص، دون آلة الحالات. member للكتابات، و(viewer) للقراءات.

الطريقةالمسارالوصف
GET / POST/projects/{id}/epics · GET / PUT / DELETE …/epics/{eid}تحمل الملاحم اسمًا، ووصفًا بصيغة Markdown، وتسميةً داعمة تجمع قصصها
GET / POST / PUT / DELETE…/epics/{eid}/comments · …/comments/{cid}تعليقات الملاحم
GET / POST / DELETE…/epics/{eid}/owners · …/followers (+ صيغ /agents/{aid})المالكون والمتابعون، أعضاءً أو وكلاء — ويسري مالكو الملحمة على قصصها
GET / POST / DELETE…/epics/{eid}/attachments (+ /json) · …/link-attachmentsالمرفقات، بالحدود نفسها التي للقصص
GET/projects/{id}/analytics/epics · …/analytics/epics/{eid}تقدّم كل ملحمة: الإنجاز التصاعدي، والإنتاجية، والصحة، والتنبّؤ (viewer)

member للكتابات، و(viewer) للقراءات.

الطريقةالمسارالوصف
GET / POST/projects/{id}/labelsسرد / إنشاء تسمية
PUT / DELETE/projects/{id}/labels/{lid}تحديث / حذف تسمية
POST/projects/{id}/labels/{lid}/archiveأرشفة (إخفاء ناعم) تسمية

القراءات مفتوحة لأي دور في المشروع، ومتاحة دون هوية على مشروع عام.

الطريقةالمسارالوصف
GET/projects/{id}/iterationsسرد التكرارات (≤ 500 لكل صفحة؛ تحمل ETag وترويسات المتابعة X-Tracker-Pagination-* عند الاقتطاع)
GET/projects/{id}/iterations/{itid}تكرار واحد
GET/projects/{id}/iterations/first-previewالتواريخ التي سيأخذها التكرار الأول، معروضة في تأكيد الإنشاء
POST/projects/{id}/iterationsإنشاء تكرار يدوي (member)
DELETE/projects/{id}/iterations/{itid}حذف تكرار (manager)
PUT/projects/{id}/iterations/{itid}/velocityتجاوز سرعة تكرار واحد دون تغيير استراتيجية المشروع (manager)
GET/projects/{id}/iterations/{itid}/done-storiesالقصص المقبولة في تكرار مغلق، مقسَّمة صفحات

البحث، والمقاييس، والتفضيلات

Section titled “البحث، والمقاييس، والتفضيلات”
الطريقةالمسارالوصف
GET/projects/{id}/search?q=…بحث قوي — نص كامل + مُحدِّدات للأوجه / مدى التواريخ / الأشخاص (لغة على نمط GitHub)؛ يُعيد { results, total, limit, offset }. وquery اسم بديل لـ q؛ ويقسّم limit= (الافتراضي 50، والحد الأقصى 1000) / offset= النتائج إلى صفحات؛ ويرتّب sort= حسب relevance (افتراضيًا)، أو created، أو created_asc، أو state، أو updated. (viewer) — انظر الدليل
GET/projects/{id}/metrics/{velocity,burndown,story-types,contributors}سلاسل صفحة المقاييس (viewer)؛ ومقاييس الملاحم تحت /analytics/epics أعلاه
GET/projects/{id}/backlog/groupingمجموعات التكرارات المُتوقَّعة في Backlog (viewer)
GET / PUT/projects/{id}/preferencesتفضيلات لوحتك لهذا المشروع — لأي دور في المشروع، وصفّك أنت فقط
الطريقةالمسارالوصف
GET/projects/{id}/eventsتدفق أحداث مقسَّم صفحاتٍ بمؤشّر (member) — ويتلقّى المُشاهِدون 403

معاملات الاستعلام: since=<event_id>، وtypes=story.created,story.transitioned,comment.added,…، وlimit= (≤ 500)، وcursor=. تتضمّن الاستجابة next_cursor. مرّر آخر event_id رأيته كـ since لاستئناف.

موجز الإشعارات الموحّد داخل التطبيق: صفوف إشعارات من الدرجة الأولى (طلبات المراجعة، نشاط القصص، الدعوات، …) مدموجة مع صندوق @-الإشارات في تدفق واحد، الأحدث أولًا. تحمل معرّفات الموجز بادئة المصدر (nt-… / sc-… / ec-…). تقرأ جلسات الأعضاء ومفاتيح ea_user_* صفوفها الخاصة بالعضو؛ ومفاتيح ea_agent_* صفوفها الخاصة بالوكيل.

الطريقةالمسارالوصف
GET/me/notificationsموجز إشعاراتك. المرشّحات: unread=true، وsince_id=، وkind= (mentions / reviews / stories / invitations)؛ قسّم الصفحات عبر cursor= / limit=
GET/me/notifications/unread-countإجماليات غير المقروء — { unread_count, by_category: { mentions, reviews, stories, invitations } }
POST/me/notifications/read-allتعليم الكل كمقروء؛ يعيد العدّادات المحدّثة
POST/me/notifications/{id}/ackتعليم عنصر واحد كمقروء (متكافئ الأثر idempotent)
POST/me/notifications/{id}/acceptقبول دعوة إلى مشروع / منظمة من داخل الموجز (رموز الأعضاء فقط)
POST/me/notifications/{id}/declineرفض دعوة إلى مشروع / منظمة (رموز الأعضاء فقط)
GET/me/notifications/resolve-invite?token=…ربط رمز دعوة مُرسل بالبريد بمعرّف إشعارك — { "id": "nt-…" } أو { "id": null }
GET/me/notifications/streamدفع مباشر — Server-Sent Events (text/event-stream)؛ انظر أدناه

نقطة نهاية البث ليست نقطة نهاية JSON ولذلك ليست ضمن مواصفة OpenAPI: تُبقي الاتصال مفتوحًا وتُصدر إطارًا بلا حمولة ({"type":"notification","kind":…}) كلما وصل جديد، لتخبر العميل بإعادة جلب الموجز. تُنهى الاتصالات من جهة الخادم بعد 45 دقيقة — أعد الاتصال وأعد الاستيثاق. جلسات الأعضاء ومفاتيح ea_user_* فقط؛ ومفاتيح ea_agent_* تتلقى 403.

الطريقةالمسارالوصف
POST/projects/{id}/importمصادر الملفات: source=pivotal، وjira، وasana، وgitlab، وshortcut، وtrello، وlinear، وplane، وplane_json، وeat. رفع multipart بـ file=. تزامني — يجيب بأعداد النتائج.
POST/projects/{id}/import/jsonجسم JSON؛ لا يحتاج source=github إلى ملف — owner، وrepo، وtoken اختياري، والأعلام الاختيارية include_pull_requests / include_milestones / include_releases / include_dependencies؛ أما مصادر الملفات فترسل file_base64. غير تزامني: يُعيد 202 { import_id, status }. ويجلب الخادم عبر واجهة GraphQL من GitHub، وهي ترفض المستدعين المجهولين، فيصل إلى GitHub رمز دائمًا — رمزك أنت أو الرمز المشترك للنشر. انظر الدليل.
GET/projects/{id}/imports/{import_id}استطلاع مهمة: يمرّ status بالمراحل pending → fetching → writing → done | failed، مع progress_current / progress_total أثناء الجلب وأعداد النتائج عند done

لا يجري إلا استيراد واحد لكل مشروع في الوقت نفسه؛ وPOST ثانٍ بينما يجري أحدها هو 409 import_already_running. dry_run: true (في جسم JSON أو dry_run=true بصيغة multipart) يعاين أي مصدر: يحلّل، ويحسم، ويزيل التكرار، ويُعيد الأعداد نفسها { imported, skipped, errors, unmatched }، ثم يتراجع — لا يُكتَب شيء. الحدود: جسم بحجم 10 MiB، و5٬000 قصة لكل استيراد للمصادر الملفّية (تجاوز أيٍّ منهما ← 400 بلا كتابة شيء). أما مصدر GitHub فبلا سقف — إذ يودع على دفعات لا في معاملة واحدة. وإعادة الاستيراد متكافئة الأثر لكل معرّف مصدر — الصفوف المُستورَدة مسبقًا تُتخطّى لا تُكرَّر.

الطريقةالمسارالوصف
GET/projects/{id}/export/formatsالصيغ المسجَّلة: { id, name, content_type, drops, includes_archived }. لأي دور في المشروع.
GET/projects/{id}/export/{format}تنزيل واحدة (manager). تبادل: eat (كامل الدقة)، وjira، وpivotal، وshortcut، وtrello، وasana، وgitlab، وlinear، وplane، وplane_json؛ ومستندات: pdf، وdocx.
GET/projects/{id}/export/attachmentsكل مرفق كملف zip واحد قابل للتصفّح (تحتفظ الملفات بأسمائها الأصلية؛ مع بيان JSON + CSV) (manager).

تأخذ صادرات المستندات (pdf، وdocx) معاملات استعلام إضافية: page_size= (‏letter افتراضيًا / a4 / legal / folio)، وfrom= / to= (حدود نافذة القصص — بصيغة RFC 3339 أو YYYY-MM-DD مجردة؛ تقع القصة ضمن النطاق عندما يقع created أو completed_at الخاص بها داخله)، وinclude_icebox= / include_backlog= (كلاهما false افتراضيًا، بحيث لا يُظهر التصدير القابل للمشاركة إلا العمل المجدول / الجاري). وتتجاهلها صيغ CSV التبادلية.

النسخ الاحتياطية والاستعادة (manager)

Section titled “النسخ الاحتياطية والاستعادة (manager)”
الطريقةالمسارالوصف
GET / POST/projects/{id}/backups · GET …/backups/{snapshot_id} · …/backups/healthسرد اللقطات، وأخذ واحدة الآن، وقراءة واحدة، وملخّص صحة الاحتفاظ
GET / POST/projects/{id}/restores · POST …/restores/partial · GET …/restores/{restore_id}استعادة لقطة كاملة، أو جداول مختارة منها، واستطلاع عملية الاستعادة

تقع طلبات POST هذه على طبقة حدود المعدّل الحساسة (أدناه).

East Agile Tracker مزوّد OAuth 2.1 لعملاء MCP. يكتشفه العميل عند /.well-known/oauth-authorization-server و/.well-known/oauth-protected-resource/mcp، ويرسلك إلى /oauth/authorize (صفحة الموافقة)، ويستبدل الرمز عند /oauth/token، ثم يتحدّث MCP عند /mcp بالرمز الناتج ea_mcp_*. تُسرَد التفويضات وتُلغى عند /me/oauth_grants. ولنقاط نهاية المزوّد طبقة حدود معدّل خاصة بها.

wss://eastagiletracker.com/ws/control?token=<session JWT>

للتحكّم التفاعلي عن بُعد بالواجهة ({ "action": "get_state", "id": "req-1" }). الرمز هو JWT جلسة متصفح — ويُرفَض مفتاح API بـ 401 قبل الترقية. ليست قناة بيانات — كل القراءات/الكتابات تمرّ عبر REST. أحادية النسخة فقط؛ لا تُبثّ عبر النسخ المتعددة.

تقبل نقاط نهاية الكتابة (POST، وPUT، وDELETE) ترويسة Idempotency-Key. المفتاح نفسه + الجسم نفسه يعيد تشغيل الاستجابة المخزّنة مؤقتًا (نافذة 24 ساعة)؛ والمفتاح نفسه + جسم مختلف يُعيد 409 idempotency_conflict. والمفتاح محصور ببيانات الاعتماد التي أرسلته. لا تُطبَّق على GET/HEAD/OPTIONS، ولا على /openapi.json و/docs، ولا على /api/auth/*، ولا على رفع multipart في مسارات /attachments. الاستجابات التي توقّفت قبل أن يُجيب المجال لا تُخزَّن أبدًا — 401، و403، و404، و429، وكل 5xx — فتصل إعادة المحاولة بعد أيٍّ منها إلى المعالِج؛ أما 400، و409، و412، و422 فهي جواب المجال وتُعاد كما يُعاد النجاح.

تقبل نقاط نهاية السرد cursor=<opaque> وlimit=<n>. وعند ضبطهما، تكون الاستجابة { "items": [...], "next_cursor": "<str|null>" }؛ مرّر next_cursor رجوعًا لتصفّح الصفحات. وسقف limit خاص بكل نقطة نهاية: 200 على القصص والتعليقات والمشاريع؛ و500 على الأحداث؛ و1000 على البحث وسجل التدقيق.

والقائمة العادية (بلا cursor/limit) التي اضطُرّت إلى اقتطاع استجابتها تقول ذلك في الترويسات — X-Tracker-Pagination-Truncated، وX-Tracker-Pagination-Limit، وX-Tracker-Pagination-Offset، وX-Tracker-Pagination-Next-Offset؛ مرّر الأخيرة رجوعًا كـ offset= للصفحة التالية. لا توجد ترويسة للعدد الإجمالي.

تقبل نقاط نهاية السرد fields= (مفصولة بفواصل) لإعادة حقول محددة فقط. يُضمَّن story_id دائمًا؛ ويُعيد اسم حقل غير معروف 400 validation_failed مع الأسماء المخالِفة في details.fields.

GET /projects/123/stories?fields=story_id,name,current_state,owners

لكل خطأ بصيغة JSON code وerror؛ ويضيف بعضها details:

{ "code": "invalid_transition",
"error": "Cannot move story from `unstarted` to `accepted`",
"details": { "from": "unstarted", "to": "accepted", "allowed": ["started"] } }
الحالةcodeمتى
400invalid_parameterإدخال سيّئ؛ الرسالة في error، بلا details (معظم التحقّق: فراغ/طول/بايت صفري/بريد إلكتروني)
400validation_failedخطأ إدخال مهيكَل؛ details.fields هو مصفوفة بأسماء الحقول المخالِفة
401unauthenticatedرمز مفقود/غير صالح
403unauthorized_operationمصادَق عليه لكن الدور غير كافٍ
404unfound_resourceغير موجود — يُعاد أيضًا لغير الأعضاء
409conflictتعارض في المورد (مثل التكرار)
409idempotency_conflictأُعيد استخدام Idempotency-Key بجسم مختلف
409stale_write · import_already_runningتغيّرت القصة منذ expected_updated_at الخاص بك · استيراد يجري بالفعل
412precondition_failedلم يطابق If-Match قيمة ETag الحالية للمورد؛ ويحمل details الحقلين expected وcurrent
413request_too_largeيتجاوز الجسم حدّ الحجم الخاص بالمسار
422invalid_transitionحركة حالة غير قانونية؛ يحمل details الحقول { from, to, allowed }
429rate_limitedطلبات كثيرة جدًا من هذا الـ IP على مسار محدود المعدّل؛ مع ترويسة Retry-After
500internal_errorعطل في الخادم — رسالة عامة؛ آمن لإعادة المحاولة
503not_configuredينقص النشرَ التكاملُ الذي يحتاجه هذا المسار (SMS، وتخزين الكائنات، …)

details.fields هو مصفوفة JSON بأسماء الحقول (مثل ["to"])، أحيانًا مع مفاتيح إضافية مثل max. لا توجد خريطة حقل←رسالة.

{ "code": "validation_failed", "error": "unknown field(s): foo", "details": { "fields": ["foo"] } }

لكل IP للعميل، على عدد قليل من المسارات؛ أما حركة واجهة برمجة التطبيقات المصادَق عليها في غيرها فغير محدودة المعدّل. القيم الافتراضية (كل زوج هو المعدّل المستدام والدفعة، ويمكن للمشغّل ضبطهما):

  • المصادقة/api/auth/*: 0.5 طلب/ث، بدفعة 20.
  • مزوّد OAuth/oauth/*: 1 طلب/ث، بدفعة 60.
  • العامة/api/contact: 0.2 طلب/ث، بدفعة 10.
  • التغذية الراجعة/api/feedback: ثلاث طبقات متراكبة — إرسال واحد كل 15 ث، و10 في الساعة، و36 في اليوم.
  • الصور الرمزية — إعادة توجيه الصور الرمزية غير المصادَق عليها: 20 طلب/ث، بدفعة 200.
  • الحساسة — طلبات POST للنسخ الاحتياطي والاستعادة: نحو 0.002 طلب/ث، بدفعة 5.

تجاوز الحدّ يُعيد 429 مع ترويسة Retry-After وغلاف خطأ JSON القياسي، code: "rate_limited".