إنتقل إلى المحتوى الرئيسي

تشريح وحدة مدارية كاملة

كل ميزة في Orb هي وحدة مدارية (Orbital). الوحدة المدارية ليست كاملة بدون أجزائها الأربعة.

OrderLifecycleFulfillment/orders/track
Orbital Unit = Entity + Traits + Pages

الأجزاء الأربعة للوحدة المدارية

الوحدة المدارية هي الوحدة الأساسية لتطبيق Orb. يجب أن تحتوي على:

Orbital = Entity + Trait(s) + State Machine + Pages
الجزءالغرضغيابه يعني...
entityما هي البيانات التي تديرهالا توجد بيانات للعمل بها
traitsكيف يتصرف التطبيقلا سلوك ولا واجهة
stateMachineالحالات والأحداث والانتقالاتلا توجد دورة حياة محددة
pagesأين تظهر الواجهة (المسارات)الصفحة تُحمّل فارغة، لا شيء يُعرض

الصفحات (Pages) هي الجزء الأكثر نسياناً. بدون pages، السمة (Trait) موجودة لكنها لا تُثبَّت على أي مسار، والمستخدم لا يرى شيئاً.


الخطوة 1 - تعريف الكيان (Entity)

الكيان هو بنية بياناتك. يصف ما تديره وكيف يُحفظ.

{
"اسم": "Task",
"استمرارية": "دائم",
"مجموعة": "tasks",
"حقول": [
{
"اسم": "id",
"نوع": "نص",
"مطلوب": true
},
{
"اسم": "title",
"نوع": "نص",
"مطلوب": true
},
{
"اسم": "status",
"نوع": "تعداد",
"قيم": [
"pending",
"done"
],
"افتراضي": "pending"
}
]
}

أنواع الحقول: string، number، boolean، date، timestamp، enum، array، object، relation

أوضاع الاستمرارية (Persistence):

  • persistent - مخزن في قاعدة البيانات (Firestore، PostgreSQL)
  • runtime - في الذاكرة، خاص بالجلسة (عربة التسوق، حالة المعالج)
  • singleton - نسخة عامة واحدة (إعدادات التطبيق، المستخدم الحالي)

الخطوة 2 - تعريف آلة الحالة (State Machine)

آلة الحالة تعيش داخل سمة (Trait). تصف الحالات الممكنة للميزة والأحداث التي تسبب الانتقالات (Transitions).

الحالات (States)

كل آلة حالة تحتاج حالة واحدة على الأقل محددة بـ "isInitial": true. الحالات هي كائنات، وليست نصوصاً:

"states": [
{ "name": "Pending", "isInitial": true },
{ "name": "Done", "isTerminal": true }
]

الأحداث (Events)

الأحداث هي محفّزات - إجراءات المستخدم، أحداث النظام، أو خطافات دورة الحياة:

"events": [
{ "key": "INIT", "name": "Initialize" },
{ "key": "COMPLETE", "name": "Complete Task" }
]

INIT إلزامي. بدون انتقال INIT، الصفحة تُحمّل لكن لا تعرض شيئاً.

الانتقالات (Transitions)

الانتقالات تربط الحالات والأحداث ببعضها. يمكن أن تحمل حراساً (Guards) (شروط) وتأثيرات (Effects) (إجراءات):

"transitions": [
{
"from": "Pending",
"event": "INIT",
"to": "Pending",
"effects": [
["fetch", "Task"],
["render-ui", "main", {
"type": "entity-table",
"entity": "Task",
"columns": ["title", "status"],
"itemActions": [
{ "event": "COMPLETE", "label": "Complete" }
]
}]
]
},
{
"from": "Pending",
"event": "COMPLETE",
"to": "Done",
"effects": [
["persist", "update", "Task", "@entity"],
["notify", "success", "Task completed!"]
]
}
]

الخطوة 3 - بناء السمة (Trait)

غلّف آلة الحالة في سمة مع name وlinkedEntity وcategory:

{
"اسم": "TaskLifecycle",
"كيان_مرتبط": "Task",
"فئة": "interaction",
"آلة_حالة": {
"حالات": [
{
"اسم": "Pending",
"أولي": true
},
{
"اسم": "Done",
"نهائي": true
}
],
"أحداث": [
{
"مفتاح": "INIT",
"اسم": "Initialize"
},
{
"مفتاح": "COMPLETE",
"اسم": "Complete Task"
}
],
"انتقالات": [
{
"من": "Pending",
"حدث": "INIT",
"إلى": "Pending",
"تأثيرات": [
[
"جلب",
"Task"
],
[
"عرض_واجهة",
"main",
{
"نوع": "entity-table",
"كيان": "Task",
"columns": [
"title",
"status"
],
"itemActions": [
{
"حدث": "COMPLETE",
"تسمية": "Complete"
}
]
}
]
]
},
{
"من": "Pending",
"حدث": "COMPLETE",
"إلى": "Done",
"تأثيرات": [
[
"حفظ",
"update",
"Task",
"@كيان"
],
[
"إشعار",
"success",
"Task completed!"
]
]
}
]
}
}

category يمكن أن يكون:

  • interaction - لها واجهة، تُطلق تأثيرات render-ui
  • integration - استدعاءات خدمات خلفية، بدون واجهة

الخطوة 4 - إضافة الصفحات (Pages)

الصفحات تربط السمات بمسارات URL. هذا هو الجزء الأكثر نسياناً.

"pages": [
{
"name": "TaskListPage",
"path": "/tasks",
"traits": [
{ "ref": "TaskLifecycle", "linkedEntity": "Task" }
]
}
]
  • path هو مسار URL (يدعم معاملات :id، مثال: /tasks/:id)
  • traits[].ref يشير إلى سمة بالاسم المحدد في نفس الوحدة المدارية
  • traits[].linkedEntity يخبر وقت التشغيل أي كيان يُربط

الوحدة المدارية الكاملة

تجميع كل شيء معاً - وحدة مدارية TaskManager تعمل بالكامل:

;; app TaskManager

مدار Tasks {
كيان Task [دائم: tasks] {
id : نص!
title : نص!
status : نص
}
سمة TaskLifecycle -> Task [تفاعل] {
أولي: Pending
حالة Pending {
تهيئة -> Pending
(جلب Task)
(عرض_واجهة main { type: "entity-table", entity: "Task", fields: ["title", "status"], columns: ["title", "status"], itemActions: [{ event: "COMPLETE", label: "Complete" }] })
COMPLETE -> Done
(حفظ update Task @كيان)
(إشعار success "Task completed!")
}
حالة Done {}
}
صفحة "/tasks" -> TaskLifecycle
}

الأخطاء الشائعة

صفحات مفقودة (pages)

// ❌ غير مكتمل - لا شيء يُعرض على أي مسار
{
"name": "Tasks",
"entity": { ... },
"traits": [ { "name": "TaskLifecycle", ... } ]
}

// ✅ مكتمل - السمة مُثبتة على /tasks
{
"name": "Tasks",
"entity": { ... },
"traits": [ { "name": "TaskLifecycle", ... } ],
"pages": [
{ "name": "TaskListPage", "path": "/tasks", "traits": [{ "ref": "TaskLifecycle", "linkedEntity": "Task" }] }
]
}

الحالات كنصوص (غير صالح)

// ❌ صيغة خاطئة
"states": ["Pending", "Done"]

// ✅ الحالات يجب أن تكون كائنات
"states": [
{ "name": "Pending", "isInitial": true },
{ "name": "Done", "isTerminal": true }
]

انتقال INIT مفقود

// ❌ الصفحة تفتح لكنها فارغة - لا يوجد render-ui أولي
"transitions": [
{ "from": "Pending", "event": "COMPLETE", "to": "Done", "effects": [...] }
]

// ✅ أضف حلقة ذاتية على INIT لعرض الواجهة الأولية
"transitions": [
{
"from": "Pending", "event": "INIT", "to": "Pending",
"effects": [["fetch", "Task"], ["render-ui", "main", { "type": "entity-table", "entity": "Task" }]]
},
{ "from": "Pending", "event": "COMPLETE", "to": "Done", "effects": [...] }
]

الخطوات التالية