نظرة عامة على الواجهة الأمامية
يُنشئ FORGE تطبيقين مستقلين بـ Next.js 14+ يُشكّلان معاً طبقة الواجهة الأمامية الكاملة: تطبيق ويب عام (apps/web) ولوحة تحكم إدارية (apps/admin). كلا التطبيقين يتشاركان نفس الأنماط المعمارية ومكدس التقنيات لكنهما يخدمان جمهورين مختلفين جذرياً.
المعمارية
┌─────────────────────────────────────────────────────────────┐
│ وكيل عكسي Caddy │
│ (HTTPS تلقائي، توجيه) │
├─────────────────────┬───────────────────────────────────────┤
│ │ │
│ myapp.test │ admin.myapp.test │
│ ┌───────────────┐ │ ┌───────────────────────────────┐ │
│ │ تطبيق الويب │ │ │ لوحة التحكم الإدارية │ │
│ │ (Next.js) │ │ │ (Next.js) │ │
│ │ │ │ │ │ │
│ │ صفحات عامة │ │ │ إدارة المستخدمين/الأدوار │ │
│ │ تدفقات مصادقة │ │ │ محرر المحتوى │ │
│ │ ملف المستخدم │ │ │ منشئ القوائم │ │
│ │ تنقل ديناميكي│ │ │ إدارة الترجمات │ │
│ └───────┬───────┘ │ └──────────────┬────────────────┘ │
│ │ │ │ │
├───────────┴─────────┴──────────────────┴────────────────────┤
│ REST API (Rust/Axum) │
│ api.myapp.test │
└─────────────────────────────────────────────────────────────┘كلا التطبيقين يتواصلان مع نفس الـ API الخلفي عبر HTTPS. لا يتشاركان أي كود وقت التشغيل، لكنهما يتبعان نفس الاصطلاحات للتواصل مع الـ API والمصادقة والتدويل وبنية المكونات.
مكدس التقنيات
| التقنية | الغرض |
|---|---|
| Next.js 14+ | App Router، Server Components، توجيه قائم على الملفات |
| TypeScript | الوضع الصارم مُفعّل في كلا التطبيقين |
| Tailwind CSS | تنسيق utility-first مع design tokens |
| shadcn/ui | مكتبة مكونات قابلة للوصول (Radix UI + Tailwind) |
| React Hook Form | إدارة حالة النماذج بأداء عالٍ |
| Zod | تحقق من الصحة مبني على المخططات مع استنتاج TypeScript |
| TanStack Query | إدارة حالة الخادم مع التخزين المؤقت |
| Lucide React | مجموعة أيقونات tree-shakeable |
| Sonner | إشعارات toast |
| TinyMCE | تحرير نص غني لإدارة المحتوى |
الأنماط المشتركة
كلا التطبيقين يُنفّذان أربعة أنماط أساسية تضمن الاتساق عبر طبقة الواجهة الأمامية.
عميل API
غلاف fetch مُنمّط يتعامل مع حقن JWT token وردود الأخطاء وإعادة توجيه 401 ورفع الملفات. كل استدعاء API يمر عبر هذا الـ singleton:
import { api } from "@/lib/api";
// GET request with query params
const users = await api.get<PaginatedResponse<User>>("/admin/users", {
params: { page: 1, per_page: 20 },
});
// POST request with body
const newUser = await api.post<ApiResponse<User>>("/admin/users", {
name: "Jane Doe",
email: "jane@example.com",
});
// File upload with multipart/form-data
const media = await api.upload<ApiResponse<Media>>("/media", file, "file");Auth Provider
React context يُدير حالة المصادقة ويحمي المسارات ويُعرّض فحص الصلاحيات:
import { useAuth, usePermission } from "@/components/providers/auth-provider";
function MyComponent() {
const { user, isAuthenticated, logout } = useAuth();
const canEditUsers = usePermission("users.edit");
if (!canEditUsers) return null;
return <div>Welcome, {user?.name}</div>;
}I18n Provider
يُحمّل الترجمات من الخلفية ويوفر دالة t() مع interpolation ويُدير اتجاه RTL:
import { useTranslation } from "@/components/providers/i18n-provider";
function MyComponent() {
const { t, locale, direction } = useTranslation();
return <h1>{t("auth.login_title")}</h1>;
}المسارات المحمية
كلا التطبيقين يستخدمان فحوصات مصادقة على مستوى الـ layout. المستخدمون غير المُصادق عليهم يُعاد توجيههم لصفحة تسجيل الدخول مع URL العودة:
// Redirect preserves the intended destination
router.push(`/login?redirect=${encodeURIComponent(pathname)}`);بنية المشروع
كلا التطبيقين يتبعان نفس تخطيط المجلدات. هذه البنية المعيارية:
تطبيق الويب (apps/web)
apps/web/
├── app/
│ ├── layout.tsx # Root layout (providers, html dir/lang)
│ ├── page.tsx # Home page with multilingual hero
│ ├── globals.css # Tailwind base styles
│ ├── (auth)/
│ │ ├── layout.tsx # Auth pages layout
│ │ ├── login/page.tsx # Login (email/password or mobile/OTP)
│ │ ├── register/page.tsx # Registration
│ │ └── password/
│ │ ├── forgot/page.tsx # Forgot password
│ │ └── reset/page.tsx # Reset password
│ ├── (protected)/
│ │ ├── layout.tsx # Auth guard layout
│ │ └── profile/
│ │ ├── page.tsx # View profile
│ │ ├── edit/page.tsx # Edit profile
│ │ └── password/page.tsx # Change password
│ └── [slug]/
│ ├── page.tsx # Dynamic content pages
│ └── not-found.tsx # 404 for missing content
├── components/
│ ├── site-header.tsx # Header with dynamic navigation
│ ├── site-footer.tsx # Footer component
│ ├── dynamic-nav.tsx # Navigation built from Menu API
│ ├── language-switcher.tsx # Language dropdown
│ ├── providers/
│ │ └── i18n-provider.tsx # I18n context
│ └── ui/ # shadcn/ui primitives
├── lib/
│ ├── api.ts # API client singleton
│ ├── types.ts # TypeScript type definitions
│ ├── utils.ts # Helper functions (cn, etc.)
│ └── validations.ts # Zod schemas for forms
└── public/
└── messages/ # Static translation JSON filesلوحة التحكم الإدارية (apps/admin)
apps/admin/
├── app/
│ ├── layout.tsx # Root layout (providers)
│ ├── globals.css # Tailwind + shadcn theme
│ ├── (auth)/
│ │ └── login/page.tsx # Admin login
│ └── (dashboard)/
│ ├── layout.tsx # Sidebar + header layout
│ ├── page.tsx # Dashboard with statistics
│ ├── users/ # User CRUD pages
│ ├── roles/ # Role management
│ ├── permissions/ # Permissions viewer
│ ├── contents/ # Content editor (create, edit, list)
│ ├── menus/ # Navigation menu builder
│ ├── lookups/ # Reference data
│ ├── translations/ # Translation management
│ ├── settings/ # Application settings
│ ├── api-keys/ # API key management
│ ├── audit/ # Audit log viewer
│ └── profile/ # Admin profile
├── components/
│ ├── layout/
│ │ ├── sidebar.tsx # Collapsible sidebar navigation
│ │ └── header.tsx # Top header bar
│ ├── dashboard/
│ │ ├── stats.tsx # Dashboard statistics cards
│ │ └── recent-activity.tsx # Recent activity feed
│ ├── providers/
│ │ ├── auth-provider.tsx # Auth context
│ │ ├── i18n-provider.tsx # I18n context
│ │ └── theme-provider.tsx # Dark/light mode provider
│ └── ui/ # shadcn/ui + custom components
│ ├── data-table.tsx # Sortable and filterable table
│ ├── rich-text-editor.tsx # TinyMCE wrapper
│ ├── language-switcher.tsx
│ ├── confirm-dialog.tsx
│ ├── translations-input.tsx
│ ├── content-translations-input.tsx
│ ├── permission-selector.tsx
│ └── ... # shadcn/ui primitives
├── lib/
│ ├── api.ts # API client singleton
│ ├── types.ts # TypeScript type definitions
│ ├── utils.ts # Helper functions
│ └── validations.ts # Zod schemas for all forms
└── public/
└── messages/ # Static translation JSON filesإعدادات TypeScript
كلا التطبيقين يُفعّلان الوضع الصارم ويستخدمان path aliases للاستيرادات النظيفة:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"paths": {
"@/*": ["./*"]
}
}
}هذا يسمح بالاستيراد من أي مجلد باستخدام بادئة @/:
import { api } from "@/lib/api";
import { Button } from "@/components/ui/button";
import type { User } from "@/lib/types";متغيرات البيئة
كلا التطبيقين يستخدمان نفس نمط متغيرات البيئة:
# API URL for client-side requests
NEXT_PUBLIC_API_URL=https://api.myapp.test
# API URL for server-side requests (Docker internal network)
INTERNAL_API_URL=http://api:8080
# API version prefix
NEXT_PUBLIC_API_VERSION=v1نصيحة
يُستخدم INTERNAL_API_URL لجلب البيانات من جانب الخادم داخل Docker Compose. هذا يتجنب التوجيه عبر الوكيل العكسي ويوفر اتصال خادم-لخادم أسرع وأكثر موثوقية.
ما التالي
- لوحة التحكم — بنية لوحة الإدارة وصفحات CRUD
- تطبيق الويب — التطبيق العام وتدفقات المصادقة وصفحات المحتوى
- المكونات — مكونات UI قابلة لإعادة الاستخدام واستخدامها
- النماذج والتحقق — أنماط React Hook Form + Zod
- جلب البيانات — عميل API وأنماط تحميل البيانات
- التدويل — دعم تعدد اللغات ومعالجة RTL