สารบัญ

วิสัยทัศน์ด้านสถาปัตยกรรม

หลักการนำทาง

สถาปัตยกรรมมีพื้นฐานอยู่บนหลักการของ การแยกความกังวล

  • เนื้อหา : ไฟล์ AsciiDoc ที่มีโครงสร้างพร้อมด้วยเมตาดาต้าที่อุดมสมบูรณ์

  • การนำเสนอ : เทมเพลต Thymeleaf ที่สามารถใช้ซ้ำได้

  • ข้อมูล : แบบจำลองที่ดึงออกโดยอัตโนมัติจาก JBake จากแอตทริบิวต์ของ AsciiDoc

  • Style : Bootstrap 5 เพื่อความสอดคล้องทางภาพ

ตัวเลือกเชิงกลยุทธ์: AsciiDoc สำหรับพอร์ตโฟลิโอ

Table 1. ทำไม AsciiDoc ?
เกณฑ์ ข้อได้เปรียบ

ความสอดคล้อง

รูปแบบเดียวกับบทความบล็อก

ข้อมูลเมตา

แอตทริบิวต์เชิงโครงสร้างและขยายได้`project-*`)

ความสามารถในการบำรุงรักษา

การแก้ไขข้อความแบบง่าย ๆ รองรับการควบคุมเวอร์ชันด้วย Git

ความยืดหยุ่น

อาจมีเนื้อหาที่อุดมสมบูรณ์ (ตาราง, โค้ด, รูปภาพ)

การกำหนดเทมเพลต

JBake ดึงแอตทริบิวต์โดยอัตโนมัติสำหรับ Thymeleaf

โมเดลข้อมูล

แต่ละโครงการพอร์ตโฟลิโอเป็นเอกสาร AsciiDoc ที่มี :

  • ข้อมูลเมตาดาต้าในส่วนหัว : ข้อมูลที่จัดโครงสร้าง (ลูกค้า, ระยะเวลา, เทคโนโลยี ฯลฯ)

  • Corps du document : คำบรรยายเชิงเรื่องราว, ความท้าทาย, วิธีแก้ปัญหา, ผลลัพธ์

  • แอตทริบิวต์ที่กำหนดเอง : ต่อคำนำหน้า`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 "เว็บไซต์\nStatique" as site

dev -> editor : สร้างไฟล์ใหม่
activate editor
editor -> file : portfolio/nouveau-projet.adoc
activate file

dev -> editor : สร้างส่วนหัวพร้อมเมตาดาต้า\n(titre, type=project, status=published,\nattributs 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 : ใช้ template 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/`

  • บิลด์ JBake สำเร็จโดยไม่มีข้อผิดพลาด

  • โครงการปรากฏบนหน้า portfolio

  • หน้าเฉพาะของโครงการแสดงผลอย่างถูกต้อง

UC2 : ลบรายการออกจากพอร์ตโฟลิโอ

ฟลักซ์มาตรฐาน

@startuml
skinparam backgroundColor #FEFEFE
actor Développeur as dev
participant "ระบบ\nFichiers" as fs
participant "JBake\nEngine" as jbake
participant "ไซต์\nStatique" as site
database "แคช\nJBake" as cache

dev -> fs : ลบ portfolio/projet-ancien.adoc
activate fs
fs --> dev : ไฟล์ถูกลบ
deactivate fs

dev -> fs : (Optionnel) ลบภาพที่เกี่ยวข้อง\nassets/img/portfolio/projet-ancien-*
activate fs
fs --> dev : รูปภาพถูกลบ
deactivate fs

dev -> cache : Nettoyer cache JBake
activate cache
cache --> dev : วิดีโอที่อยู่ในแคช
deactivate cache

dev -> jbake : การสร้างใหม่เต็มรูปแบบ (jbake -b)
activate jbake
jbake -> jbake : สแกน เนื้อหา/portfolio/
jbake -> jbake : ไม่มีโครงการ → ไม่ได้สร้าง
jbake -> jbake : สร้างใหม่ portfolio.html\n(sans le projet supprimé)
jbake -> site : ปรับใช้บิลด์ใหม่
deactivate jbake

dev -> site : ตรวจสอบ
activate site
site --> dev : ไม่มีโครงการอยู่ในรายการ
deactivate site
@enduml

กลยุทธ์ทางเลือก: การจัดเก็บถาวร

แทนที่จะลบอย่างถาวร มีความเป็นไปได้ในการสร้างโฟลเดอร์`content/portfolio/archive/`:

  • ย้ายไฟล์แทนที่จะลบมัน

  • ทำให้สามารถกู้คืนได้อย่างง่ายดาย

  • รักษาประวัติ Git ให้ชัดเจนขึ้น

ทำความสะอาดทรัพยากร

  • ตรวจสอบภาพที่กำพร้าใน`assets/img/portfolio/`

  • ลบภาพที่ไม่ได้ถูกอ้างอิงโดยโครงการอื่น

  • ทำความสะอาดแคช JBake เพื่อหลีกเลี่ยงการอ้างอิงผี

UC3 : ตั้งเป็นร่าง (draft)

ฟลักซ์โนมินัล

@startuml
skinparam backgroundColor #FEFEFE
actor Développeur as dev
participant "ไฟล์\nAsciiDoc" as file
participant "JBake\nEngine" as jbake
participant "เว็บไซต์\nStatique" as site

dev -> file : เปิดพอร์ตโฟลิโอ/projet.adoc
activate file

dev -> file : แก้ไขคุณสมบัติ\n:jbake-status: เผยแพร่\n↓\n:jbake-status: ร่าง

file --> dev : บันทึกแล้ว
deactivate file

dev -> jbake : สร้างใหม่ (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: archived
ไม่ได้เผยแพร่ แต่ยังคงเก็บไว้
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
ส่วนที่สามารถนำกลับมาใช้ใหม่
เพื่อแสดงบัตร
ของโครงการ :
- ภาพขนาดย่อ
- ชื่อเรื่อง
- แท็ก
- ไฮไลท์
end note
@enduml

รูปแบบการสกัดข้อมูล

JBake จะทำการแปลงอัตโนมัติของคุณลักษณะ AsciiDoc เป็นคุณสมบัติที่สามารถเข้าถึงได้ใน Thymeleaf :

@startuml
skinparam backgroundColor #FEFEFE

rectangle "เอกสาร AsciiDoc" {
  (":project-client: Acme Corp") 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 : การวิเคราะห์
attr2 --> prop2 : การวิเคราะห์
attr3 --> prop3 : การแยกวิเคราะห์

prop1 --> tmpl1 : การผูกมัด
prop2 --> tmpl2 : การผูกพัน
prop3 --> tmpl3 : การผูกมัด
@enduml

หลักเกณฑ์การตั้งชื่อ

  • คุณลักษณะโครงการ : คำนำหน้า`project-*` (ex: project-client, project-tech-stack)

  • ไฟล์ : kebab-case (ตัวอย่าง:`ecommerce-platform.adoc`)

  • Images : คำนำหน้าชื่อโครงการ (เช่น:`ecommerce-platform-thumb.jpg`)

  • Templates : ชื่อฟังก์ชั่น (ex:`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

สภาพแวดล้อม

สภาพแวดล้อม การใช้งาน สถานะที่ยอมรับ

ท้องถิ่น

การพัฒนาและการแสดงตัวอย่าง

ฉบับร่าง, เผยแพร่

การเตรียมความพร้อม

การตรวจสอบก่อนการผลิต

เผยแพร่เฉพาะ

การผลิต

เว็บไซต์สาธารณะ

เผยแพร่เท่านั้น

ความสามารถในการขยาย

การเพิ่มคุณสมบัติใหม่

เพื่อเสริมสร้างโมเดลข้อมูล ให้เพียงเพิ่มคุณสมบัติใหม่ที่มีการกำหนดชื่อขึ้นต้น`project-*`(No output provided)

  • `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 : การติดตามการแก้ไขแบบครบถ้วน

การจัดการเนื้อหา

  • satus draft par défaut : publier seulement quand prêt becomes:

สถานะดราฟต์โดยค่าเริ่มต้น : เผยแพร่เฉพาะเมื่อพร้อม

  • Review ก่อนการเผยแพร่ : การตรวจสอบคุณภาพและความลับ

  • ข้อมูลเมตาครบถ้วน : กรอกฟิลด์ทั้งหมดที่เกี่ยวข้อง

  • เนื้อเรื่องที่อุดมสมบูรณ์ : อย่าจำกัดตัวเองอยู่ที่เมตาดาต้า

ประสิทธิภาพ

  • การบีบอัดภาพ : การบีบอัดก่อน commit

  • การแบ่งหน้าเมื่อจำเป็น : ถ้า >20 โครงการ

  • การโหลดเมื่อต้องการ : รูปภาพของแกลเลอรี่ที่โหลดเมื่อต้องการ

  • Cache เบราว์เซอร์ : headers ที่เหมาะสมสำหรับทรัพย์สิน

สรุป

สถาปัตยกรรมนี้ทำให้ :

บทความที่เกี่ยวข้อง