التصميم بالعقود أولاً
يتبنى FORGE نهج العقود أولاً في توليد التطبيقات. كل تطبيق يُنتجه FORGE يلتزم بعقود صارمة تُحدد نقاط نهاية API ومخطط قاعدة البيانات والصلاحيات وصفحات الواجهة الأمامية. تعمل هذه العقود كطبقة المواصفات بين الخلفيات والواجهات الأمامية، مما يضمن أن أي خلفية مدعومة يمكنها تشغيل أي واجهة أمامية مدعومة بدون تعديل.
يُحدد العقد ما يجب أن يوجد. يُحدد التنفيذ كيف يعمل.
لماذا العقود؟
عند توليد تطبيقات متكاملة عبر أُطر خلفية متعددة (Rust، Laravel، FastAPI، Node.js) وأُطر واجهة أمامية متعددة (Next.js، Nuxt.js، Angular)، الاتساق غير قابل للتفاوض. بدون عقود، ستُنفذ كل خلفية أشكال API مختلفة قليلاً، وستتوقع كل واجهة أمامية تنسيقات استجابة مختلفة، واستبدال تقنية بأخرى سيتطلب إعادة كتابة كود التكامل.
نصيحة
فكر في العقود كمخطط بناء. سواء بُني المنزل بالطوب أو الخشب أو الفولاذ، يبقى مخطط الأرضية كما هو. الغرف في نفس الأماكن، والأبواب تُفتح بنفس الطريقة، والسباكة تتصل بشكل متطابق.
FORGE CLI
│
┌─────────────┼─────────────┐
│ │ │
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ عقود │ │ عقود │ │ عقود │
│ المزودين │ │ الخلفية │ │ الواجهة │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
┌────┬──┴──┐ ┌─────┼─────┐ ┌────┼────┐
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
Twilio Uni أخرى Rust Laravel … Next Nuxt Angularعقود API
تُحدد عقود API مسارات نقاط النهاية بالضبط وطرق HTTP وأجسام الطلبات وأشكال الاستجابة التي يجب أن تُنفذها كل خلفية مُولّدة. المصدر الموثوق هو مواصفات OpenAPI التي تلتزم بها جميع الخلفيات.
تعريفات نقاط النهاية
كل تطبيق FORGE يكشف نفس سطح API بغض النظر عن الخلفية:
المصادقة (AUTH)
├── POST /api/v1/auth/register → { data: { user, token } }
├── POST /api/v1/auth/login → { data: { user, token } }
├── POST /api/v1/auth/logout → { message }
├── POST /api/v1/auth/refresh → { data: { token } }
└── GET /api/v1/auth/me → { data: { user } }
الإدارة (ADMIN) (تتطلب مصادقة + صلاحيات)
├── GET /api/v1/admin/users → { data: [...], meta: {...} }
├── POST /api/v1/admin/users → { data: user }
├── GET /api/v1/admin/users/:id → { data: user }
├── PUT /api/v1/admin/users/:id → { data: user }
├── DELETE /api/v1/admin/users/:id → { message }
├── ... (نفس النمط للأدوار، المحتويات، القوائم، الإعدادات، إلخ.)
العامة (PUBLIC) (لا تتطلب مصادقة)
├── GET /api/v1/contents/:slug → { data: content }
└── GET /api/v1/menus → { data: [...] }تنسيق الاستجابة
جميع الخلفيات تُرجع استجابات في مُغلّف متسق:
// Success (single resource)
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"name": "Ahmed"
}
}
// Success (list with pagination)
{
"data": [{ ... }, { ... }],
"meta": {
"total": 42,
"page": 1,
"per_page": 15
}
}
// Error
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": {
"email": ["The email field is required"]
}
}
}رموز الأخطاء القياسية
كل خلفية تستخدم نفس مجموعة رموز الأخطاء:
| الرمز | حالة HTTP | المعنى |
|---|---|---|
VALIDATION_ERROR | 422 | فشل التحقق من جسم الطلب |
UNAUTHORIZED | 401 | مصادقة مفقودة أو غير صالحة |
FORBIDDEN | 403 | مُصادق لكن يفتقر للصلاحية |
NOT_FOUND | 404 | المورد غير موجود |
RATE_LIMITED | 429 | عدد طلبات كثير جداً |
INTERNAL_ERROR | 500 | خطأ خادم غير متوقع |
تحذير
يجب ألا تُرجع الخلفيات أخطاء الإطار الخام أبداً. يجب تغليف جميع الأخطاء في مُغلّف الخطأ القياسي. هذا يضمن أن الواجهات الأمامية يمكنها تحليل كل استجابة بمعالج أخطاء واحد.
OpenAPI كمصدر موثوق
عقد API مُعرّف رسمياً كمواصفات OpenAPI 3.0:
# contracts/api/openapi.yaml
openapi: 3.0.3
info:
title: FORGE Application API
version: 1.0.0
paths:
/api/v1/auth/login:
post:
summary: تسجيل دخول المستخدم
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [email, password]
properties:
email:
type: string
format: email
password:
type: string
minLength: 8
responses:
'200':
description: تم تسجيل الدخول بنجاح
content:
application/json:
schema:
$ref: '#/components/schemas/AuthResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'422':
$ref: '#/components/responses/ValidationError'تُولّد أنواع TypeScript للواجهة الأمامية مباشرة من مواصفات OpenAPI هذه، مما يضمن استهلاك API آمن للأنواع.
عقود قاعدة البيانات
تُحدد عقود قاعدة البيانات الجداول المطلوبة والأعمدة والأنواع والفهارس التي يجب أن يحتويها كل تطبيق مُولّد. بينما قد تختلف تسمية الأعمدة قليلاً حسب اتفاقية الخلفية (snake_case مقابل camelCase)، المخطط المنطقي متطابق.
الجداول المطلوبة
كل تطبيق FORGE يتضمن هذه الجداول الأساسية:
| الجدول | الغرض |
|---|---|
languages | لغات التطبيق المدعومة |
users | حسابات المستخدمين |
roles | تعريفات الأدوار المُسماة |
permissions | إدخالات الصلاحيات التفصيلية |
role_user | علاقة متعدد-لمتعدد: تعيين مستخدم-دور |
permission_role | علاقة متعدد-لمتعدد: تعيين دور-صلاحية |
password_resets | رموز إعادة تعيين كلمة المرور |
otp_codes | رموز كلمة المرور لمرة واحدة (إذا كان OTP مُفعّلاً) |
settings | إعدادات التطبيق مفتاح-قيمة |
translations | سلاسل UI قابلة للترجمة |
api_keys | إدارة مفاتيح API الخارجية |
audit_logs | سجل تتبع الإجراءات |
media | مرفقات الملفات متعددة الأشكال |
contents | صفحات محتوى CMS |
menus | هياكل قوائم التنقل |
عقود الأعمدة
كل جدول له أعمدة مطلوبة. على سبيل المثال، users:
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
phone VARCHAR(50) UNIQUE,
password VARCHAR(255) NOT NULL,
avatar VARCHAR(500),
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);نصيحة
جميع الجداول تستخدم مفاتيح أساسية UUID وتتضمن طوابع created_at / updated_at. هذه الاتفاقية مُفروضة عبر كل مولّد خلفية.
عقود الفهارس
الفهارس الحرجة للأداء هي جزء من العقد:
-- Users
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_phone ON users(phone);
-- Contents
CREATE INDEX idx_contents_slug ON contents(slug);
CREATE INDEX idx_contents_type ON contents(type);
CREATE INDEX idx_contents_status ON contents(status);
-- Audit logs
CREATE INDEX idx_audit_logs_user ON audit_logs(user_id);
CREATE INDEX idx_audit_logs_action ON audit_logs(action);
CREATE INDEX idx_audit_logs_created ON audit_logs(created_at);عقود الصلاحيات
يستخدم FORGE نظام التحكم في الوصول المبني على الأدوار (RBAC). يُحدد عقد الصلاحيات أي صلاحيات يجب أن توجد لكل وحدة وكيف ترتبط بنقاط نهاية API.
اتفاقية تسمية الصلاحيات
تتبع الصلاحيات النمط {module}.{action}:
users.view users.create users.edit users.delete
roles.view roles.create roles.edit roles.delete
permissions.view
contents.view contents.create contents.edit contents.delete
menus.view menus.create menus.edit menus.delete
settings.view settings.edit
translations.view translations.edit
api_keys.view api_keys.create api_keys.edit api_keys.delete
audit.viewربط الصلاحيات بنقاط النهاية
كل نقطة نهاية إدارية تتطلب صلاحية محددة:
| نقطة النهاية | الصلاحية المطلوبة |
|---|---|
GET /api/v1/admin/users | users.view |
POST /api/v1/admin/users | users.create |
PUT /api/v1/admin/users/:id | users.edit |
DELETE /api/v1/admin/users/:id | users.delete |
GET /api/v1/admin/contents | contents.view |
POST /api/v1/admin/contents | contents.create |
PUT /api/v1/admin/contents/:id | contents.edit |
DELETE /api/v1/admin/contents/:id | contents.delete |
الأدوار الافتراضية
كل تطبيق مُولّد يزرع دورين:
| الدور | الصلاحيات |
|---|---|
super_admin | جميع الصلاحيات (wildcard) |
admin | جميع الصلاحيات ما عدا permissions.view، api_keys.*، audit.view |
تحذير
يجب تعيين دور super_admin بحذر. في الإنتاج، معظم المديرين يجب أن يستخدموا دور admin أو أدوار مخصصة بصلاحيات محددة.
عقود الصفحات
تُحدد عقود الصفحات أي صفحات واجهة أمامية يجب أن توجد في كل تطبيق مُولّد. هذا يضمن أنه بغض النظر عن إطار الواجهة الأمامية، التطبيق الموجه للمستخدم له تغطية كاملة.
الصفحات العامة المطلوبة
/ الصفحة الرئيسية
/login تسجيل الدخول
/register التسجيل
/password/forgot نسيت كلمة المرور
/password/reset إعادة تعيين كلمة المرور برمز
/:slug صفحة محتوى CMS ديناميكيةالصفحات المحمية المطلوبة
/profile عرض الملف الشخصي (تتطلب مصادقة)
/profile/edit تعديل الملف الشخصي (تتطلب مصادقة)
/profile/password تغيير كلمة المرور (تتطلب مصادقة)صفحات الإدارة المطلوبة
/admin لوحة التحكم
/admin/users قائمة المستخدمين (users.view)
/admin/users/create إنشاء مستخدم (users.create)
/admin/users/:id/edit تعديل مستخدم (users.edit)
/admin/roles قائمة الأدوار (roles.view)
/admin/roles/create إنشاء دور (roles.create)
/admin/roles/:id/edit تعديل دور (roles.edit)
/admin/permissions قائمة الصلاحيات (permissions.view)
/admin/contents قائمة المحتوى (contents.view)
/admin/contents/create إنشاء محتوى (contents.create)
/admin/contents/:id عرض المحتوى (contents.view)
/admin/contents/:id/edit تعديل المحتوى (contents.edit)
/admin/menus قائمة القوائم (menus.view)
/admin/menus/create إنشاء قائمة (menus.create)
/admin/menus/:id/edit تعديل قائمة (menus.edit)
/admin/settings إعدادات التطبيق (settings.view)
/admin/translations إدارة الترجمات (translations.view)
/admin/api-keys إدارة مفاتيح API (api_keys.view)
/admin/audit سجلات التدقيق (audit.view)كل صفحة إدارة تُفرض الصلاحية المطلوبة لها. إذا انتقل مستخدم إلى صفحة يفتقر لصلاحيتها، تعرض الواجهة الأمامية عرض "الوصول مرفوض" بدون إجراء استدعاء API.
التحقق من العقود
يوفر FORGE أوامر CLI للتحقق من أن التطبيق المُولّد يلتزم بعقوده.
التحقق من API
# Verify all required endpoints exist and return correct shapes
forge validate:api
# Verify specific backend
forge validate:api --backend=rustيُشغّل المُحقق خادم الخلفية، ويُرسل طلبات إلى كل نقطة نهاية مُتعاقد عليها، ويتحقق من:
- نقطة النهاية موجودة ولا تُرجع 404
- الاستجابة تُطابق مخطط JSON المتوقع
- استجابات الأخطاء تستخدم مُغلّف الخطأ القياسي
- فحوصات المصادقة والصلاحيات مُفروضة
التحقق من الصفحات
# Verify all required pages exist in frontend
forge validate:pages
# Verify specific frontend
forge validate:pages --frontend=nextjsمُحقق الصفحات يتحقق من:
- كل ملف مسار مطلوب موجود في المشروع
- الصفحات المحمية تتضمن حراسات المصادقة
- صفحات الإدارة تتضمن فحوصات الصلاحيات
- الصفحات العامة قابلة للوصول بدون مصادقة
مجموعة اختبارات العقود الكاملة
# Run the full contract test suite
forge test:contractsهذا يُشغّل اختبارات التكامل التي تُمارس الحزمة الكاملة: الخلفية تخدم API، والاختبارات الآلية تتحقق من كل سلوك مُتعاقد عليه من النهاية إلى النهاية.
نصيحة
شغّل forge test:contracts قبل النشر للإنتاج. يلتقط انتهاكات العقود التي قد تفوتها اختبارات الوحدات، مثل فحص صلاحية مفقود على نقطة نهاية إدارية.
الفوائد
| الفائدة | الوصف |
|---|---|
| خلفيات قابلة للتبديل | ابدأ بـ Rust، انتقل إلى Laravel لاحقاً -- نفس API، نفس الواجهة الأمامية |
| واجهات أمامية قابلة للتبديل | ابدأ بـ Next.js، أضف Nuxt.js لاحقاً -- نفس API، نفس السلوك |
| مزودون قابلون للتبديل | انتقل من Twilio إلى Unifonic بتغيير إعداد |
| قابلية الاختبار | محاكاة أي مزود أو خلفية خلف واجهة العقد |
| توثيق مُولّد تلقائياً | مواصفات OpenAPI تُنتج توثيق API تلقائياً |
| أمان الأنواع | أنواع TypeScript مُولّدة من OpenAPI للاستهلاك في الواجهة الأمامية |
| أمان الترقية | اختبارات العقود تلتقط التغييرات الكاسرة قبل وصولها للإنتاج |