الرؤية المعمارية

مبدأ توجيهي

البنية تقوم على مبدأ فصل المخاوف:

  • المحتوى : ملفات AsciiDoc منظمة مع بيانات تعريفية غنية

  • عرض : قوالب Thymeleaf القابلة لإعادة الاستخدام

  • البيانات : النموذج المستخرج تلقائيًا بواسطة JBake من سمات AsciiDoc

  • النمط: Bootstrap 5 للتّوافق البصري

الخيار الاستراتيجي : AsciiDoc للملف الشخصي

Table 1. لماذا AsciiDoc ؟
معيار ميزة

الاتساق

نفس تنسيق مقالات المدونة

البيانات الوصفية

السمات المنظمة والقابلة للتوسيع (project-*)

قابلية الصيانة

تحرير نصّي بسيط، قابل للتتبع بـ جيت

المرونة

قد يحتوي على محتوى غني (جداول، كود، صور)

القوالب

JBake يستخرج الخصائص تلقائيًا ل Thymeleaf

نموذج البيانات

كل مشروع محفظة هو مستند AsciiDoc مع :

  • بيانات الرأس : معلومات منظمة (العميل، المدة، التقنيات، إلخ)

  • جسم المستند : وصف سردي، التحديات، الحلول، النتائج

  • السمات المخصصة: مسبوقة`project-*`للاستخراج التلقائي

@startuml
skinparam backgroundColor #FEFEFE
skinparam handwritten false

class ProjetAsciiDoc {
  +titre: String
  +jbake-type: "مشروع"
  +jbake-status: published|draft
  +jbake-date: Date
  +jbake-tags: List<String>
  --
  +project-category: String
  +project-client: String
  +project-duration: String
  +project-role: String
  +project-thumbnail: String
  +project-gallery: List<String>
  +project-tech-stack: String
  +project-highlights: List<String>
  +project-demo-url: String
  +project-github-url: String
  --
  +body: HTML (converti)
}

class JBakeEngine {
  +parse(asciidoc)
  +extractMetadata()
  +convertToHTML()
}

class ThymeleafTemplate {
  +portfolio.html
  +project.html
  +partials/project-card.html
}

class PortfolioPage {
  +published_projects: List
  +filtres: categories
}

ProjetAsciiDoc --> JBakeEngine : تحليل
JBakeEngine --> ThymeleafTemplate : يوفر بيانات
ThymeleafTemplate --> PortfolioPage : يولد
@enduml

حالات الاستخدام المفصلة

UC1 : إضافة عنصر إلى المحفظة

التدفق الاسمي

@startuml
skinparam backgroundColor #FEFEFE
actor Développeur as dev
participant "المحرر\nTexte" as editor
participant "ملف\nAsciiDoc" as file
participant "JBake\nEngine" as jbake
participant "موقع\nثابت" as site

dev -> editor : إنشاء ملف جديد
activate editor
editor -> file : المحفظة/nouveau-projet.adoc
activate file

dev -> editor : عدّ الترويسة مع البيانات الوصفية\n(العنوان, النوع=project, status=published,\nالخصائص project-*)
dev -> editor : كتابة محتوى سردي\n(contexte, défis, solutions)
dev -> editor : إضافة الصور في assets/img/portfolio/

editor -> file : احفظ
deactivate editor

dev -> jbake : تشغيل البناء (jbake -b)
activate jbake
jbake -> file : قراءة وتحليل
jbake -> jbake : استخراج البيانات الوصفية
jbake -> jbake : تحويل AsciiDoc → HTML
jbake -> jbake : تطبيق القالب project.html
jbake -> jbake : إضافة إلى القائمة portfolio.html
jbake -> site : إنشاء صفحات ثابتة
deactivate jbake

dev -> site : تحقق من النتيجة
activate site
site --> dev : عرض المشروع
deactivate site
@enduml

قالب الملف المراد إنشاؤه

المطور ينشئ`content/portfolio/nom-projet.adoc`مع بنية موحدة:

  • رأس مع جميع الخصائص المطلوبة

  • الأقسام المعيارية (السياق، التحديات، الحلول، النتائج)

  • التسمية المتسقة للصور

نقاط التحقق

  • السمات الإلزامية موجودة (jbake-type, jbake-status, project-thumbnail)

  • الصور المشار إليها موجودة في`assets/img/portfolio/`

  • ينجح build JBake بدون أي خطأ

  • يظهر المشروع على صفحة المحفظة

  • تعرض صفحة المشروع الفردية بشكل صحيح

UC2 : حذف عنصر من المحفظة

التدفق الاسمي

@startuml
skinparam backgroundColor #FEFEFE
actor Développeur as dev
participant "نظام\nملفات" as fs
participant "JBake\nمحرك" as jbake
participant "موقع\nثابتة" as site
database "ذاكرة التخزين المؤقت\nJBake" as cache

dev -> fs : احذف portfolio/projet-ancien.adoc
activate fs
fs --> dev : ملف محذوف
deactivate fs

dev -> fs : (اختياري) حذف الصور المرتبطة\nassets/img/portfolio/projet-ancien-*
activate fs
fs --> dev : الصور المحذوفة
deactivate fs

dev -> cache : مسح الكاش JBake
activate cache
cache --> dev : ذاكرة التخزين المؤقت للفيديو
deactivate cache

dev -> jbake : إعادة بناء كاملة (jbake -b)
activate jbake
jbake -> jbake : مسح المحتوى/portfolio/
jbake -> jbake : مشروع غير موجود → لم يتم إنشاؤه
jbake -> jbake : إعادة توليد portfolio.html\n(بدون المشروع المحذوف)
jbake -> site : نشر بناء جديد
deactivate jbake

dev -> site : تحقق
activate site
site --> dev : المشروع غير موجود في القائمة
deactivate site
@enduml

الاستراتيجية البديلة: الأرشفة

بدلاً من الحذف النهائي، إمكانية إنشاء مجلد`content/portfolio/archive/`: (espace après les deux-points conservé tel quel)

  • انقل الملف بدلاً من حذفه

  • يسمح بالاستعادة بسهولة

  • احتفظ بتاريخ جيت أكثر وضوحًا

تنظيف الموارد

  • التحقق من الصور اليتيمة في`assets/img/portfolio/`

  • احذف الصور غير المُحالة من قبل مشاريع أخرى

  • تنظيف ذاكرة التخزين المؤقت لـ JBake لتجنب المراجع الوهمية

UC3 : وضع في غير منشور (مسودة)

التدفق الاسمي

@startuml
skinparam backgroundColor #FEFEFE
actor Développeur as dev
participant "ملف\nAsciiDoc" as file
participant "JBake\nمحرك" as jbake
participant "موقع\nثابت" as site

dev -> file : افتح portfolio/projet.adoc
activate file

dev -> file : Modifier attribut\n:jbake-status: published\n↓\n:jbake-status: draft

file --> dev : تم الحفظ
deactivate file

dev -> jbake : Rebuild (jbake -b)
activate jbake
jbake -> file : تحليل الملف
jbake -> jbake : اكتشف status=draft
jbake -> jbake : استبعاد من published_projects
jbake -> jbake : لا تنشئ صفحة عامة
note right
المشروع لا يزال موجودًا
لكنه غير منشور
end note
jbake -> site : إنشاء موقع (بدون هذا المشروع)
deactivate jbake

dev -> site : التحقق من المحفظة
activate site
site --> dev : مشروع غائب عن القائمة العامة
deactivate site
@enduml

الحالات الممكنة

@startuml
skinparam backgroundColor #FEFEFE

[*] --> Draft : Création initiale
Draft --> Published : التحقق من الصحة والنشر
Published --> Draft : انسحاب مؤقت
Draft --> Archived : مشروع تم التخلي عنه
Published --> Archived : مشروع منتهي الصلاحية
Archived --> [*] : الحذف النهائي
Published --> Published : تحديثات

note right of Draft
:jbake-status: مسودة
غير مرئي للعلن
مفيد للمشاريع الجارية
end note

note right of Published
:jbake-status: المنشور
مرئي في المحفظة
فهرس بواسطة JBake
end note

note right of Archived
تم وضعه في archive/

أو jbake-status: مؤرشف

غير منشور لكن محفوظ
end note
@enduml

حالات الاستخدام النموذجية

  • مشروع جاري صياغته : إنشاء مسودة، نشر عندما يكون جاهزًا

  • مشروع سري مؤقت : التحويل إلى مسودة خلال فترة اتفاق العميل

  • تحديث رئيسي : التحويل إلى مسودة، تعديل، إعادة النشر

  • A/B testing : إنشاء نسخة مسودة، اختبارها، ثم نشر أفضل نسخة

هندسة القوالب

استراتيجية القوالب القابلة لإعادة الاستخدام

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package "قوالب Thymeleaf" {
  component [index.html] as index
  component [portfolio.html] as portfolio
  component [project.html] as project

  package "أجزاء" {
    component [header.html] as header
    component [footer.html] as footer
    component [project-card.html] as card
    component [tech-badge.html] as badge
    component [gallery.html] as gallery
  }
}

package "البيانات JBake" {
  database "published_projects" as data
  database "محتوى (مشروع)" as content
}

index --> header
index --> footer

portfolio --> header
portfolio --> footer
portfolio --> card
data --> portfolio : تكرار

project --> header
project --> footer
project --> badge
project --> gallery
content --> project : مشروع فردي

note right of card
قطعة قابلة لإعادة الاستخدام
لعرض خريطة
لمشروع مع :
- thumbnail
- titre
- tags
- highlights
end note
@enduml

نمط استخراج البيانات

JBake يحول تلقائيًا سمات AsciiDoc إلى خصائص يمكن الوصول إليها في Thymeleaf:

@startuml
skinparam backgroundColor #FEFEFE

rectangle "مستند AsciiDoc" {
  (":project-client: شركة أكمي") as attr1
  (":project-duration: 6 أشهر") as attr2
  (":project-tags: java, react") as attr3
}

rectangle "نموذج JBake" {
  (content['project-client']) as prop1
  (content['project-duration']) as prop2
  (content.tags) as prop3
}

rectangle "قالب Thymeleaf" {
  (th:text="${project['project-client']}") as tmpl1
  (th:text="${project['project-duration']}") as tmpl2
  (th:each="وسم : ${project.tags}") as tmpl3
}

attr1 --> prop1 : parsing
attr2 --> prop2 : parsing
attr3 --> prop3 : parsing

prop1 --> tmpl1 : binding
prop2 --> tmpl2 : binding
prop3 --> tmpl3 : binding
@enduml

اتفاقيات التسمية

  • سمات المشروع : البادئة`project-*` (ex: project-client, project-tech-stack)

  • ملفات : kebab-case (مثال:`ecommerce-platform.adoc`)

  • الصور : بادئة اسم المشروع (مثال:`ecommerce-platform-thumb.jpg`)

  • القوالب : اسم وظيفي (مثال:`project-card.html`, tech-badge.html)

سير عمل النشر

سلسلة التطوير

@startuml
skinparam backgroundColor #FEFEFE
skinparam handwritten false

class ProjetAsciiDoc {
  +titre: String
  +jbake-type: "مشروع"
  +jbake-status: published|draft
  +jbake-date: Date
  +jbake-tags: List<String>
  __
  +project-category: String
  +project-client: String
  +project-duration: String
  +project-role: String
  +project-thumbnail: String
  +project-gallery: List<String>
  +project-tech-stack: String
  +project-highlights: List<String>
  +project-demo-url: String
  +project-github-url: String
  __
  +body: HTML (converti)
}

class JBakeEngine {
  +parse(asciidoc)
  +extractMetadata()
  +convertToHTML()
}

class ThymeleafTemplate {
  +portfolio.html
  +project.html
  +partials/project-card.html
}

class PortfolioPage {
  +published_projects: List
  +filtres: categories
}

ProjetAsciiDoc --> JBakeEngine : تحليل
JBakeEngine --> ThymeleafTemplate : يوفر بيانات
ThymeleafTemplate --> PortfolioPage : يولد
@enduml

بيئات

بيئة الاستخدام الحالة مقبولة

محلي

التطوير والمعاينة

مسودة، منشور

التجهيز

التحقق المسبق للإنتاج

نشر فقط

Production

موقع عام

منشور فقط

قابلية التوسّع

إضافة سمات جديدة

لإثراء نموذج البيانات، ما عليك سوى إضافة سمات جديدة مسبوقة`project-*` :

  • `project-awards`الجوائز والاعترافات

  • project-testimonial: عرض سعر للعميل

  • project-team-size: حجم الفريق

  • `project-budget-range`نطاق الميزانية

هذه الخصائص تصبح متاحة تلقائيًا في القوالب دون تعديل محرك JBake.

تصنيف متقدم

@startuml
skinparam backgroundColor #FEFEFE

object Projet {
  project-category = "ويب"
  project-subcategory = "التجارة الإلكترونية"
  project-industry = "التجزئة"
  project-complexity = "عالي"
}

object Taxonomie {
  categories : [web, mobile, data, devops]
  subcategories : Map<category, List>
  industries : [retail, finance, healthcare, ...]
  complexities : [low, medium, high]
}

Projet --> Taxonomie : مُصنَّف وفقًا

note right of Taxonomie
يسمح بالتصفية المتعددة المعايير في القالب portfolio.html عبر JavaScript أو من جانب الخادم
end note
@enduml

أفضل الممارسات

تنظيم الملفات

  • ملف واحد = مشروع : تجنب خلط عدة مشاريع

  • صور في مجلد مخصصassets/img/portfolio/nom-projet/

  • النومينكلاتور المتسقة : يسهّل البحث والصيانة

  • Versioning Git : المتابعة الكاملة للتعديلات

إدارة المحتوى

  • الحالة الافتراضية للمسودة : نشر فقط عندما يكون جاهزًا

  • مراجعة قبل النشر : التحقق من الجودة والسرية

  • البيانات الكاملة : ملء جميع الحقول ذات الصلة

  • المحتوى السردي الغني : لا تقتصر على البيانات الوصفية

الأداء

  • تحسين الصور : ضغط قبل الالتزام

  • التقسيم إذا لزم الأمر : إذا >20 مشاريع

  • التحميل المتأخر : صور المعارض تُحمَّل عند الطلب

  • ذاكرة التخزين المؤقت للمتصفح : الرؤوس المناسبة للموارد

خاتمة

تسمح هذه المعمارية:

  • سهولة الاستخدام : إضافة مشروع = إنشاء ملف نصي

  • المرونة : قابلة للتوسيع عبر سمات جديدة

  • قابلية الصيانة : فصل المحتوى عن العرض

  • التتبع : الإصدار الكامل لـ Git

  • الأتمتة : build والنشر المستمر ممكنين

اختيار AsciiDoc يضمن التوافق مع بقية الموقع مع توفير ثراء البيانات الوصفية اللازمة لمحفظة احترافية.

مقالات ذات صلة