Skip to content

نظرة عامة على الواجهة الأمامية

يُنشئ 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:

typescript
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 يُدير حالة المصادقة ويحمي المسارات ويُعرّض فحص الصلاحيات:

typescript
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:

typescript
import { useTranslation } from "@/components/providers/i18n-provider";

function MyComponent() {
  const { t, locale, direction } = useTranslation();

  return <h1>{t("auth.login_title")}</h1>;
}

المسارات المحمية

كلا التطبيقين يستخدمان فحوصات مصادقة على مستوى الـ layout. المستخدمون غير المُصادق عليهم يُعاد توجيههم لصفحة تسجيل الدخول مع URL العودة:

typescript
// 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 للاستيرادات النظيفة:

json
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "paths": {
      "@/*": ["./*"]
    }
  }
}

هذا يسمح بالاستيراد من أي مجلد باستخدام بادئة @/:

typescript
import { api } from "@/lib/api";
import { Button } from "@/components/ui/button";
import type { User } from "@/lib/types";

متغيرات البيئة

كلا التطبيقين يستخدمان نفس نمط متغيرات البيئة:

bash
# 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. هذا يتجنب التوجيه عبر الوكيل العكسي ويوفر اتصال خادم-لخادم أسرع وأكثر موثوقية.

ما التالي

Released under the MIT License.