توليد الأكواد
المهمة الرئيسية لـ FORGE هي تحويل ملف إعدادات تصريحي إلى تطبيق عامل بالكامل. تُحوّل خطوط أنابيب توليد الأكواد قوالب Tera إلى أكواد مصدرية جاهزة للإنتاج للخلفية والواجهة الأمامية التي اخترتها.
خط أنابيب التوليد
تتبع كل عملية توليد أكواد نفس خط الأنابيب المكون من خمس خطوات:
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 1. الأمر │────▶│ 2. الإعدادات│────▶│ 3. السياق │
│ (CLI input) │ │ (forge.yaml)│ │ (variables) │
└──────────────┘ └──────────────┘ └──────────────┘
│
▼
┌──────────────┐ ┌──────────────┐
│ 5. المخرجات │◀────│ 4. العرض │
│ (files) │ │ (Tera engine)│
└──────────────┘ └──────────────┘- الأمر -- يُشغّل المستخدم أمر CLI (
forge new،forge make:model، إلخ.) - الإعدادات -- يقرأ FORGE ملف
forge.yamlلفهم بنية المشروع والميزات المُفعّلة واللغات ومزودي الخدمات - السياق -- يُبنى كائن السياق الذي يحتوي على جميع متغيرات القالب (اسم التطبيق، طريقة المصادقة، اللغات، إلخ.)
- العرض -- يُعالج محرك Tera قوالب
.tera، ويُقيّم الشروط ويستبدل المتغيرات - المخرجات -- تُكتب الملفات المُولّدة إلى مجلد المشروع مع إزالة امتداد
.tera
إنشاء مشروع جديد
يُنشئ أمر forge new تطبيقاً كاملاً من الصفر:
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 بدون خيارات يُطلق معالج الإعداد التفاعلي:
$ 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 ومدخلات نماذج الإدارة في خطوة واحدة.
# 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.rs | Model struct مع حقول مُنوّعة |
migrations/00018_create_products_table.sql | ترحيل قاعدة البيانات مع الأعمدة |
forge make:model --all
يُولّد خيار --all حزمة الموارد الكاملة — النموذج والترحيل والمعالج وصفحات CRUD الإدارية:
forge make:model Product --all title:string price:decimal status:lookup category:belongs_toينشئ هذا كل ما تحتاجه لعمليات CRUD الكاملة:
| الملف | الغرض |
|---|---|
src/models/product.rs | Model 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، يمكنك تمرير حقول مباشرة لتوليد أعمدة مُنوّعة:
# 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:
forge make:handler Productsينشئ:
| الملف | الغرض |
|---|---|
src/handlers/products.rs | دوال المعالج |
src/handlers/admin/products.rs | دوال معالج الإدارة |
forge make:dto
يُولّد أنواع Data Transfer Object:
forge make:dto Productينشئ:
| الملف | الغرض |
|---|---|
src/dto/product.rs | CreateProductRequest، UpdateProductRequest، ProductResponse |
forge make:service
يُولّد خدمة منطق الأعمال:
forge make:service Productينشئ:
| الملف | الغرض |
|---|---|
src/services/product.rs | خدمة مع دوال CRUD |
forge make:seeder
يُولّد بذرة قاعدة البيانات:
forge make:seeder Productsينشئ:
| الملف | الغرض |
|---|---|
seeders/products.sql | عبارات INSERT للبيانات الافتراضية |
forge make:page
يُولّد صفحات الواجهة الأمامية:
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 إلى مدخلات نماذج الإدارة.
الصيغة المباشرة
مرّر الحقول كوسائط موضعية بعد اسم النموذج أو الترحيل:
forge make:model Product --all title:string price:decimal is_active:boolean status:lookupيتبع كل حقل النمط:
<field_name>:<field_type>مرجع الأنواع
| النوع | SQL | Rust | TypeScript | النموذج |
|---|---|---|---|---|
string | VARCHAR(255) | String | string | حقل نصي |
text | TEXT | String | string | منطقة نصية |
integer | INTEGER | i32 | number | حقل رقمي |
bigint | BIGINT | i64 | number | حقل رقمي |
decimal | DECIMAL(10,2) | BigDecimal | number | حقل رقمي |
boolean | BOOLEAN | bool | boolean | مفتاح تبديل |
date | DATE | NaiveDate | string | منتقي تاريخ |
datetime | TIMESTAMPTZ | DateTime<Utc> | string | منتقي تاريخ ووقت |
uuid | UUID | Uuid | string | حقل نصي |
json | JSONB | serde_json::Value | Record<string, unknown> | منطقة نصية |
lookup | UUID → lookups | Uuid | string | قائمة منسدلة |
belongs_to | UUID → الجدول المرتبط | Uuid | string | قائمة منسدلة |
حقول Lookup
ينشئ حقل lookup مفتاحاً أجنبياً إلى جدول lookups المركزي. يصبح اسم الحقل الـ slug الأب المستخدم لتصفية قيم البحث:
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 مفتاحاً أجنبياً إلى جدول نموذج آخر، مُشتق من اسم الحقل:
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) لتشغيل منشئ موجّه:
forge make:model Product --all --interactiveيطلب المنشئ اسم ونوع كل حقل، ويتحقق من المدخلات، ويعرض نوع SQL المُحدّد للتأكيد.
مثال على المخرجات المُولّدة
بهذا الأمر:
forge make:model Article --all title:string body:text is_published:boolean author:belongs_toيتضمن الترحيل المُولّد:
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 المُولّد:
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 يُنتج هذا السياق:
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 تشغيل أوامر التحقق المُعرّفة في بيان الخلفية أو الواجهة الأمامية:
# 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 عن الخطأ لتتمكن من التحقيق قبل كتابة أي كود مخصص فوق أساس معطّل.