Skip to content

توليد الأكواد

المهمة الرئيسية لـ FORGE هي تحويل ملف إعدادات تصريحي إلى تطبيق عامل بالكامل. تُحوّل خطوط أنابيب توليد الأكواد قوالب Tera إلى أكواد مصدرية جاهزة للإنتاج للخلفية والواجهة الأمامية التي اخترتها.

خط أنابيب التوليد

تتبع كل عملية توليد أكواد نفس خط الأنابيب المكون من خمس خطوات:

  ┌──────────────┐     ┌──────────────┐     ┌──────────────┐
  │  1. الأمر    │────▶│  2. الإعدادات│────▶│  3. السياق   │
  │  (CLI input) │     │  (forge.yaml)│     │  (variables) │
  └──────────────┘     └──────────────┘     └──────────────┘


                       ┌──────────────┐     ┌──────────────┐
                       │  5. المخرجات │◀────│  4. العرض    │
                       │  (files)     │     │  (Tera engine)│
                       └──────────────┘     └──────────────┘
  1. الأمر -- يُشغّل المستخدم أمر CLI (forge new، forge make:model، إلخ.)
  2. الإعدادات -- يقرأ FORGE ملف forge.yaml لفهم بنية المشروع والميزات المُفعّلة واللغات ومزودي الخدمات
  3. السياق -- يُبنى كائن السياق الذي يحتوي على جميع متغيرات القالب (اسم التطبيق، طريقة المصادقة، اللغات، إلخ.)
  4. العرض -- يُعالج محرك Tera قوالب .tera، ويُقيّم الشروط ويستبدل المتغيرات
  5. المخرجات -- تُكتب الملفات المُولّدة إلى مجلد المشروع مع إزالة امتداد .tera

إنشاء مشروع جديد

يُنشئ أمر forge new تطبيقاً كاملاً من الصفر:

bash
forge new --name=myapp --backend=rust --frontend=nextjs

يُولّد هذا الأمر الواحد:

myapp/
├── forge.yaml                   # Project configuration
├── forge.lock                   # Version tracking
├── .env.example                 # Environment variables template
├── .gitignore

├── apps/
│   ├── api/                     # Rust + Axum backend
│   │   ├── Cargo.toml
│   │   ├── src/
│   │   │   ├── main.rs
│   │   │   ├── config/
│   │   │   ├── models/
│   │   │   ├── handlers/
│   │   │   ├── middleware/
│   │   │   ├── routes/
│   │   │   ├── services/
│   │   │   ├── dto/
│   │   │   ├── providers/
│   │   │   ├── error/
│   │   │   └── utils/
│   │   ├── migrations/
│   │   └── tests/
│   │
│   ├── web/                     # Next.js public web app
│   │   ├── package.json
│   │   ├── next.config.js
│   │   ├── app/
│   │   ├── components/
│   │   └── lib/
│   │
│   └── admin/                   # Next.js admin dashboard
│       ├── package.json
│       ├── app/
│       └── components/

└── infra/
    ├── docker/
    │   ├── docker-compose.yml
    │   └── docker-compose.dev.yml
    └── caddy/
        └── Caddyfile

نصيحة

بعد التوليد، يُشغّل FORGE خطاطيف ما بعد التوليد تلقائياً. لخلفية Rust، يشمل ذلك cargo check للتحقق من أن الكود المُولّد يُترجم بنجاح. لواجهات Next.js، يُشغّل npm install لإعداد التبعيات.

الوضع التفاعلي

تشغيل forge new بدون خيارات يُطلق معالج الإعداد التفاعلي:

bash
$ forge new

مرحباً بك في مصنع تطبيقات FORGE!

? اسم المشروع: myapp
? الاسم المعروض: تطبيقي
? إطار الخلفية: (استخدم مفاتيح الأسهم)
 Rust (Axum) - أداء عالي، آمن للأنواع
    Laravel (PHP) - تطوير سريع، نظام بيئي غني
    FastAPI (Python) - واجهة Python حديثة وسريعة
    Node.js (Express) - JavaScript في كل مكان

? إطار الواجهة الأمامية: (استخدم مفاتيح الأسهم)
 Next.js - React مع SSR
    Nuxt.js - Vue مع SSR
    Angular - TypeScript للمؤسسات
    Vanilla - TypeScript + Vite

? طريقة المصادقة:
 البريد الإلكتروني + كلمة المرور
    الهاتف + OTP
    كلاهما

? اللغة الافتراضية: الإنجليزية (en)
? لغات إضافية: العربية (ar)

? مزود الرسائل النصية: Twilio
? مزود البريد الإلكتروني: SMTP
? مزود التخزين: نظام الملفات المحلي

جاري إنشاء myapp...
 تم توليد الخلفية (Rust + Axum)
 تم توليد الواجهة الأمامية (Next.js)
 تم توليد لوحة الإدارة (Next.js)
 تم توليد إعدادات البنية التحتية
 تم إنشاء 17 ترحيل قاعدة بيانات
 تم زرع الصلاحيات والأدوار الافتراضية
 تم تهيئة مستودع git

تطبيقك جاهز في ./myapp
شغّل `cd myapp && forge serve` لبدء التطوير.

أوامر make

بينما يُنشئ forge new مشروعاً كاملاً، تُولّد أوامر make مكونات فردية داخل مشروع موجود. هذه هي أدوات العمل اليومية للتطوير.

forge make:model

يُولّد نموذج قاعدة بيانات مع ملفاته المرتبطة. يمكنك تمرير تعريفات الحقول مباشرة باستخدام صيغة name:type لتوليد أعمدة مُنوّعة وحقول Rust struct ومدخلات نماذج الإدارة في خطوة واحدة.

bash
# Without fields (empty struct, empty migration)
forge make:model Product

# With inline fields
forge make:model Product -m title:string price:decimal is_active:boolean

ينشئ هذا:

الملفالغرض
src/models/product.rsModel struct مع حقول مُنوّعة
migrations/00018_create_products_table.sqlترحيل قاعدة البيانات مع الأعمدة

forge make:model --all

يُولّد خيار --all حزمة الموارد الكاملة — النموذج والترحيل والمعالج وصفحات CRUD الإدارية:

bash
forge make:model Product --all title:string price:decimal status:lookup category:belongs_to

ينشئ هذا كل ما تحتاجه لعمليات CRUD الكاملة:

الملفالغرض
src/models/product.rsModel struct مع حقول مُنوّعة
src/dto/product.rsأنواع الطلبات والاستجابات
src/handlers/admin/products.rsمعالجات CRUD الإدارية
src/handlers/products.rsمعالجات عامة (إن وُجدت)
src/services/product.rsخدمة منطق الأعمال
src/routes/admin.rsمُحدّث بمسارات المنتجات
migrations/00018_create_products_table.sqlترحيل مع أعمدة مُنوّعة ومفاتيح أجنبية
seeders/products.sqlبيانات البذر الافتراضية
admin/app/(dashboard)/products/page.tsxصفحة قائمة الإدارة
admin/app/(dashboard)/products/create/page.tsxنموذج الإنشاء الإداري (مع مدخلات لكل حقل)
admin/app/(dashboard)/products/[id]/edit/page.tsxنموذج التعديل الإداري

تحذير

يُسجّل خيار --all أيضاً الصلاحيات (products.view، products.create، products.edit، products.delete) ويضيف المورد إلى الشريط الجانبي للإدارة. راجع الكود المُولّد دائماً قبل الـ commit.

forge make:migration

يُولّد ملف ترحيل قاعدة البيانات. مثل make:model، يمكنك تمرير حقول مباشرة لتوليد أعمدة مُنوّعة:

bash
# Empty migration
forge make:migration add_price_to_products

# Migration with typed columns
forge make:migration create_products_table title:string price:decimal status:lookup

ينشئ:

migrations/00019_add_price_to_products.sql

يُزاد رقم الترحيل تلقائياً بناءً على الترحيلات الموجودة.

forge make:handler

يُولّد معالج API:

bash
forge make:handler Products

ينشئ:

الملفالغرض
src/handlers/products.rsدوال المعالج
src/handlers/admin/products.rsدوال معالج الإدارة

forge make:dto

يُولّد أنواع Data Transfer Object:

bash
forge make:dto Product

ينشئ:

الملفالغرض
src/dto/product.rsCreateProductRequest، UpdateProductRequest، ProductResponse

forge make:service

يُولّد خدمة منطق الأعمال:

bash
forge make:service Product

ينشئ:

الملفالغرض
src/services/product.rsخدمة مع دوال CRUD

forge make:seeder

يُولّد بذرة قاعدة البيانات:

bash
forge make:seeder Products

ينشئ:

الملفالغرض
seeders/products.sqlعبارات INSERT للبيانات الافتراضية

forge make:page

يُولّد صفحات الواجهة الأمامية:

bash
forge make:page Products --admin

ينشئ:

الملفالغرض
admin/app/(dashboard)/products/page.tsxصفحة القائمة مع جدول البيانات
admin/app/(dashboard)/products/columns.tsxتعريفات أعمدة الجدول
admin/app/(dashboard)/products/create/page.tsxنموذج الإنشاء
admin/app/(dashboard)/products/[id]/edit/page.tsxنموذج التعديل

تعريفات الحقول

تقبل أوامر make:model و make:migration تعريفات حقول مباشرة باستخدام صيغة name:type. يُحلّل كل حقل إلى تعريف مُفصّل يتدفق عبر كل ملف مُولّد — من أعمدة SQL إلى حقول Rust struct إلى مدخلات نماذج الإدارة.

الصيغة المباشرة

مرّر الحقول كوسائط موضعية بعد اسم النموذج أو الترحيل:

bash
forge make:model Product --all title:string price:decimal is_active:boolean status:lookup

يتبع كل حقل النمط:

<field_name>:<field_type>

مرجع الأنواع

النوعSQLRustTypeScriptالنموذج
stringVARCHAR(255)Stringstringحقل نصي
textTEXTStringstringمنطقة نصية
integerINTEGERi32numberحقل رقمي
bigintBIGINTi64numberحقل رقمي
decimalDECIMAL(10,2)BigDecimalnumberحقل رقمي
booleanBOOLEANboolbooleanمفتاح تبديل
dateDATENaiveDatestringمنتقي تاريخ
datetimeTIMESTAMPTZDateTime<Utc>stringمنتقي تاريخ ووقت
uuidUUIDUuidstringحقل نصي
jsonJSONBserde_json::ValueRecord<string, unknown>منطقة نصية
lookupUUIDlookupsUuidstringقائمة منسدلة
belongs_toUUID → الجدول المرتبطUuidstringقائمة منسدلة

حقول Lookup

ينشئ حقل lookup مفتاحاً أجنبياً إلى جدول lookups المركزي. يصبح اسم الحقل الـ slug الأب المستخدم لتصفية قيم البحث:

bash
forge make:model Product --all status:lookup priority:lookup

يُولّد هذا:

  • status_id UUID REFERENCES lookups(id) — مُصفّى بـ slug "status"
  • priority_id UUID REFERENCES lookups(id) — مُصفّى بـ slug "priority"

حقول BelongsTo

ينشئ حقل belongs_to مفتاحاً أجنبياً إلى جدول نموذج آخر، مُشتق من اسم الحقل:

bash
forge make:model Product --all category:belongs_to user:belongs_to

يُولّد هذا:

  • category_id UUID REFERENCES categories(id)
  • user_id UUID REFERENCES users(id)

الوضع التفاعلي

إذا كنت تُفضّل عدم كتابة الحقول مباشرة، استخدم --interactive (-i) لتشغيل منشئ موجّه:

bash
forge make:model Product --all --interactive

يطلب المنشئ اسم ونوع كل حقل، ويتحقق من المدخلات، ويعرض نوع SQL المُحدّد للتأكيد.

مثال على المخرجات المُولّدة

بهذا الأمر:

bash
forge make:model Article --all title:string body:text is_published:boolean author:belongs_to

يتضمن الترحيل المُولّد:

sql
CREATE TABLE articles (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    title VARCHAR(255) NOT NULL,
    body TEXT NOT NULL,
    is_published BOOLEAN NOT NULL DEFAULT false,
    author_id UUID REFERENCES users(id),
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

يتضمن نموذج Rust المُولّد:

rust
pub struct Article {
    pub id: Uuid,
    pub title: String,
    pub body: String,
    pub is_published: bool,
    pub author_id: Option<Uuid>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

ونموذج الإنشاء الإداري يعرض مدخلات مناسبة لكل نوع حقل — حقول نصية للنصوص، ومنطقة نصية للمحتوى، ومفتاح تبديل للقيمة المنطقية، وقائمة منسدلة لعلاقة المؤلف.

مرجع الأوامر

هذه القائمة الكاملة لأوامر make وما يُولّده كل منها:

forge make:model <Name>              Model file
forge make:model <Name> --all        Full resource bundle (model + all below)
forge make:migration <name>          Database migration
forge make:handler <Name>            API handler(s)
forge make:dto <Name>                Request/response types
forge make:service <Name>            Business logic service
forge make:seeder <Name>             Database seeder file
forge make:page <Name>               Frontend page(s)
forge make:page <Name> --admin       Admin dashboard pages
forge make:page <Name> --web         Public web pages

نصيحة

استخدم forge make:model Product --all للموارد الجديدة. يُولّد كل شيء بأمر واحد ويضمن أن جميع الأجزاء متصلة بشكل صحيح -- المسارات مُسجّلة، الشريط الجانبي مُحدّث، الصلاحيات مزروعة.

كيف تتدفق متغيرات السياق

عند تشغيل أمر make، يبني FORGE سياقاً من مصادر متعددة:

┌──────────────┐
│  forge.yaml  │──→ app.name, auth.method, languages, providers
└──────────────┘
       +
┌──────────────┐
│  خيارات CLI  │──→ اسم النموذج، --all، --admin، --web
└──────────────┘
       +
┌──────────────┐
│  حقول CLI    │──→ fields[], has_fields, lookup_fields, relation_fields
│  (name:type) │
└──────────────┘
       +
┌──────────────┐
│  القيم       │──→ اسم الجدول (مُجمّع، snake_case)،
│  المُشتقة    │    اسم الـ struct (PascalCase)، مسار المسار (kebab-case)،
└──────────────┘    رقم الترحيل التالي، الطوابع الزمنية


┌──────────────┐
│   سياق      │──→ السياق الكامل يُمرّر لمحرك Tera
│   القالب     │
└──────────────┘

على سبيل المثال، forge make:model ProductCategory --all title:string status:lookup يُنتج هذا السياق:

yaml
model:
  name: "ProductCategory"            # PascalCase
  snake: "product_category"          # snake_case
  kebab: "product-category"          # kebab-case
  plural: "product_categories"       # مُجمّع
  table: "product_categories"        # اسم جدول قاعدة البيانات

  # من forge.yaml
  app_name: "myapp"
  auth_method: "email_password"
  languages: [{ code: "en", ... }, { code: "ar", ... }]

  # من تعريفات حقول CLI
  has_fields: true
  fields:
    - name: "title"
      field_type: "string"
      column_name: "title"
      sql_type: "VARCHAR(255)"
      rust_type: "String"
      ts_type: "string"
      form_component: "Input"
      zod_schema: "z.string().min(1)"
      is_relation: false
    - name: "status"
      field_type: "lookup"
      column_name: "status_id"
      sql_type: "UUID"
      rust_type: "Uuid"
      ts_type: "string"
      form_component: "Select"
      is_relation: true
      is_lookup: true
      lookup_slug: "status"
      foreign_table: "lookups"

التوليد مقابل وقت التشغيل

من المهم فهم أن FORGE يعمل في وقت التوليد، وليس وقت التشغيل. بمجرد توليد الكود، ينتهي دور FORGE. يعمل التطبيق المُولّد بشكل مستقل بدون أي اعتماد على أداة FORGE CLI.

وقت التوليد (forge)              وقت التشغيل (تطبيقك)
─────────────────────           ──────────────────
forge.yaml + القوالب      →     الكود المصدري
forge make:model Product  →     product.rs، الترحيل، المعالج، إلخ.
forge serve               →     يُشغّل خوادم التطوير (للراحة)

الكود المُولّد ليس له             تطبيقك يعمل بأدوات
اعتماد على FORGE في             قياسية: cargo، npm، docker
وقت التشغيل.

تحذير

إذا عدّلت ملفات مُولّدة ثم أعدت تشغيل أمر make يستهدف نفس الملف، سيُحذّرك FORGE من التعارض. لن يُستبدل تغييراتك بصمت.

خطاطيف ما بعد التوليد

بعد توليد الملفات، يمكن لـ FORGE تشغيل أوامر التحقق المُعرّفة في بيان الخلفية أو الواجهة الأمامية:

yaml
# manifest.yaml
hooks:
  post_generate:
    - "cd apps/api && cargo check"
    - "cd apps/web && npm run lint"
    - "cd apps/admin && npm run lint"

تلتقط هذه الخطاطيف أخطاء التوليد فوراً. إذا فشل cargo check، يُبلّغ FORGE عن الخطأ لتتمكن من التحقيق قبل كتابة أي كود مخصص فوق أساس معطّل.

Released under the MIT License.