# 🏛️ المعمارية والاتفاقيات — diyaa.de > هاد الملف بيحدّد **الشكل المستهدف** للمشروع. أي feature جديد لازم يتبع هالاتفاقيات. --- ## 1) البنية العامة الموقع بينقسم لـ **واجهة عامة (public)** + **لوحة تحكم (admin)** + **API/Server Actions** + **قاعدة بيانات**. ``` [ الزوّار ] ──> صفحات عامة (app/[locale]/…) ──┐ ├──> Server Actions / Route Handlers ──> Prisma ──> PostgreSQL [ المالك ] ──> لوحة التحكم (app/admin/…) ─────┘ │ ملفات مرفوعة (volume على الـ VPS) ``` --- ## 2) أقسام الموقع (من رؤية المالك) > كل هالأقسام (عدا الألحان) = صفوف بجدول `Project` واحد تتفلتر بحقل `type`. الفصل بالـ UI فقط. 1. **الأعمال / المعرض (Portfolio)** — `type=PORTFOLIO` بتصنيفات (شعارات، بروشورات، متاجر، أدوات ذكاء اصطناعي…). 2. **التطبيقات (Apps)** — `type=APP` تطبيقات Swift، مع **سكرين شوتس** + حقول iOS (App Store، TestFlight، الإصدار، رابط الدعم، سياسة خصوصية التطبيق). 3. **المواقع (Websites)** — `type=WEBSITE` مواقع Next.js/WordPress، مع سكرين شوتس ورابط حي. 4. **التصاميم (Designs)** — `type=DESIGN` (أو ضمن PORTFOLIO) — شعارات، هويات بصرية. 5. **الألحان (Melodies)** — جدول `Melody` منفصل، عرض وتشغيل بتصنيفات (عربية، شرقية…) + تحميل اختياري. 6. **صفحات رسمية** — سياسة الخصوصية، الشروط، **Impressum** (إلزامي قانونياً بألمانيا). 7. **تواصل** — موجود، بنربطه بإرسال إيميل عبر SMTP + **Honeypot + Rate limiting**. 8. **لوحة تحكم** — إضافة/تعديل/حذف كل ما سبق + التصنيفات. --- ## 3) مخطط قاعدة البيانات (Prisma) — **الخيار A المعتمد** > **القرار (2026-08-05):** جدول **`Project` موحّد** لكل الأعمال والتطبيقات والمواقع والتصاميم (يتميّزوا بحقل `type`)، و**`Melody` منفصل** (طبيعته صوتية). التقنيات والسكرين شوتس كـ `String[]` (بدون جداول join)؛ نضيف جداول `Technology`/`Media` منفصلة لاحقاً فقط لو لزم فلترة بالتقنية أو إدارة alt-text متقدمة. التصنيف علاقة **واحد-لواحد** (مش many-to-many). > > ⚠️ هاد **يستبدل** مخطط `Work/App/Melody` القديم يلي انبنى بـ T-03/T-06. الاستبدال آمن لأنو ما في داتا إنتاجية بعد. شوف مهمة الـ refactor بـ `TODO.md`. ```prisma enum ProjectType { PORTFOLIO // شعار، بروشور، هوية بصرية… (سابقاً "أعمال/تصاميم") APP // تطبيق Swift/iOS WEBSITE // موقع Next.js أو WordPress DESIGN // تصميم منفصل لو حبيت تفصله عن PORTFOLIO } enum CategoryKind { PROJECT // تصنيفات المشاريع (شعارات، بروشورات، مواقع، متاجر، أدوات AI…) MELODY // تصنيفات الألحان (عربي، شرقي…) } enum PublishStatus { DRAFT PUBLISHED ARCHIVED } model Category { id String @id @default(cuid()) kind CategoryKind slug String @unique nameAr String nameEn String order Int @default(0) projects Project[] melodies Melody[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Project { // جدول موحّد: أعمال + تطبيقات + مواقع + تصاميم id String @id @default(cuid()) type ProjectType slug String @unique titleAr String titleEn String summaryAr String? summaryEn String? descAr String? descEn String? coverImage String? // مسار الغلاف images String[] // معرض صور / سكرين شوتس technologies String[] // التقنيات المستخدمة (بسيط، بدون جدول منفصل) externalUrl String? // رابط المشروع/الموقع الحي repoUrl String? // GitHub اختياري // ── حقول خاصة بالتطبيقات (تبقى فاضية لغير APP) ── platform String? // "iOS/Swift" | "Next.js" | "WordPress"… appStoreUrl String? testflightUrl String? appVersion String? supportUrl String? appPrivacyUrl String? // ── حالة وترتيب ── status PublishStatus @default(DRAFT) isFeatured Boolean @default(false) sortOrder Int @default(0) publishedAt DateTime? categoryId String? category Category? @relation(fields: [categoryId], references: [id]) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([type, status]) } model Melody { // لحن (منفصل بسبب طبيعته الصوتية) id String @id @default(cuid()) slug String @unique titleAr String titleEn String descAr String? descEn String? audioFile String // مسار ملف الصوت coverImage String? // artwork durationSec Int? isDownloadable Boolean @default(false) // سماح/منع التحميل status PublishStatus @default(DRAFT) isFeatured Boolean @default(false) sortOrder Int @default(0) categoryId String category Category @relation(fields: [categoryId], references: [id]) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model ContactMessage { // رسائل نموذج التواصل id String @id @default(cuid()) name String email String message String createdAt DateTime @default(now()) } enum AnalyticsEventType { PAGE_VIEW PROJECT_OPEN MELODY_PLAY PROJECT_LINK_CLICK CONTACT_SUBMITTED } model AnalyticsEvent { // عدّادات داخلية بدون خدمة خارجية id String @id @default(cuid()) type AnalyticsEventType path String? projectId String? melodyId String? createdAt DateTime @default(now()) } model User { // مستخدم لوحة التحكم (أنت) id String @id @default(cuid()) email String @unique password String // hashed createdAt DateTime @default(now()) } // (مؤجّل) إعدادات الموقع من الأدمن — نضيفه عند الحاجة // model SiteSetting { id String @id key String @unique value String } ``` --- ## 4) اتفاقيات المجلدات (الشكل المستهدف) ``` diyaa.de/ ├── app/ │ ├── [locale]/ # الموقع العام │ │ ├── page.tsx # الرئيسية │ │ ├── work/ # المعرض (PORTFOLIO) + [slug] │ │ ├── apps/ # التطبيقات (APP) + [slug] │ │ ├── websites/ # المواقع (WEBSITE) + [slug] │ │ ├── designs/ # التصاميم (DESIGN) + [slug] │ │ ├── melodies/ # الألحان + [slug] │ │ ├── legal/ # privacy, terms, impressum │ │ ├── about/ · contact/ │ ├── maintenance/ · coming-soon/ # صفحات الأوضاع │ ├── admin/ # 🔒 لوحة التحكم (محميّة بـ Auth) │ │ ├── projects/ · melodies/ · categories/ · settings/ │ │ └── layout.tsx │ ├── api/ # Route Handlers (health, upload, …) │ └── globals.css ├── components/ │ ├── ui/ # 🧩 shadcn/ui (مكوّنات أساسية) │ ├── public/ # مكوّنات الواجهة العامة │ ├── admin/ # مكوّنات لوحة التحكم │ └── shared/ # مشتركة ├── lib/ │ ├── db.ts # Prisma client (singleton) │ ├── auth.ts # إعداد Auth.js │ ├── email.ts # Nodemailer + SMTP │ ├── upload.ts # منطق رفع الملفات │ ├── validations/ # مخططات Zod │ ├── i18n.ts · site.ts · metadata.ts ├── prisma/ │ └── schema.prisma # 🎯 مصدر الحقيقة لبنية الداتا ├── content/ # قواميس الترجمة الثابتة (ar/en) ├── docs/ # 📚 التوثيق └── (Docker, Makefile, …) ``` --- ## 5) اتفاقيات المكوّنات (Components) - **كل شي كمكوّن قابل لإعادة الاستخدام.** لا تكرّر UI. - مكوّنات `components/ui/` = shadcn الأساسية (Button, Card, Dialog, Input…). لا تعدّل سلوكها الأساسي، ابنِ فوقها. - مكوّنات الأقسام (ProjectCard مشترك لكل الأنواع + MelodyCard + AudioPlayer) بتعيش بـ `components/public/`. - **Server Components افتراضياً**؛ استخدم `"use client"` فقط عند الحاجة للتفاعل (مشغّل صوت، فورمات، ثيم). - كل مكوّن عام لازم يدعم **العربي والإنجليزي** ويحترم اتجاه RTL/LTR. - الأنماط عبر **Tailwind utilities** + متغيّرات الثيم؛ لا CSS خام جديد (نحافظ على متغيّرات الثيم الموجودة لكن عبر إعداد Tailwind). ## 6) اتفاقيات Server Actions / API - عمليات لوحة التحكم (إنشاء/تعديل/حذف) → **Server Actions** بـ فاليديشن Zod. - كل action بيتحقق من الجلسة (Auth) قبل أي كتابة. - endpoints العامة (رفع، health، ربما RSS للألحان) → `app/api/`. - كل مدخلات المستخدم تمرّ بـ Zod schema من `lib/validations/`. - **نموذج التواصل:** يتحمّى بـ **Honeypot** (حقل مخفي) + **Rate limiting** (تحديد عدد الطلبات) لمنع السبام. - **رفع الملفات:** تحقّق من نوع الملف وحجمه، أسماء ملفات آمنة، `altText` للصور، و**حذف الملف الفعلي من الـ volume عند حذف المحتوى**. ## 7) الوسائط والملفات - الملفات المرفوعة تُخزّن على **volume** بالـ VPS (مش داخل صورة Docker). - الصور تُعالَج بـ `sharp` (تصغير + webp). - مسارات الملفات تُخزّن كـ نصوص بالداتابيس (مش الملف نفسه). - الرفع يتم عبر `app/api/upload/` بعد التحقق من جلسة الأدمن، والملفات تُقدّم عبر `app/api/uploads/`. - مسار التخزين قابل للضبط عبر `UPLOAD_DIR`، والـ Docker volume الافتراضي هو `/app/uploads`. ## 8) الأوضاع (Site modes) - `NEXT_PUBLIC_SITE_MODE` بيقبل **ثلاث قيم**: `full` · `maintenance` · `coming-soon`. - `coming-soon`: يعرض `ComingSoonPanel` ويخفي الأقسام (موجود حالياً). - `maintenance`: يعرض صفحة صيانة (جديد — T-14). - `full`: الموقع الكامل. - ✅ **T-17 منجز:** `.env.example` يستخدم `full` بدل `live`، و`lib/site.ts` يعتمد `coming-soon | maintenance | full`. واجهة الصيانة الفعلية والاستثناء المرئي للأدمن ضمن T-14. - لوحة التحكم بتشتغل **بغضّ النظر عن الوضع** (محميّة بالـ Auth) عشان تحضّر المحتوى قبل الإطلاق. --- ## 9) البيئة والنشر - بيضاف خدمة **postgres** لـ `docker-compose.yml` + volume للبيانات + volume للملفات المرفوعة. - الـ **Makefile** بينضاف عليه أوامر: `db-up`, `migrate`, `seed`, `studio` (Prisma Studio). - migrations تنطبق تلقائياً عند النشر (خطوة بالـ start أو entrypoint). - أسرار (SMTP, DB URL, AUTH secret) بـ `.env` فقط — **ولا تُرفع للـ git**.