# Architecture Decisions — HomAroma Platform
> บันทึกการตัดสินใจเชิงสถาปัตยกรรม (ADR) จากการประชุมทีม
> อัปเดตล่าสุด: 2026-07-12
---
## 1. Page Builder CMS — Section Types ที่มีอยู่
ระบบมี Block/Section ทั้งหมด **19 แบบ** กำหนดใน `packages/types/index.ts` → `PAGE_SECTION_TYPES`
### กลุ่ม Headers & Banners
| Type | คำอธิบาย |
|---|---|
| `HERO` | Hero หลัก (image, text, 1 button) |
| `HERO_V2` | Hero อัปเกรด (2 buttons, alignment, ornament) |
| `BANNER` | แบนเนอร์รูปภาพ + link |
| `ANNOUNCEMENT_BAR` | แถบประกาศด้านบน (auto-slide, ปรับสีได้) |
### กลุ่ม Products & Categories
| Type | คำอธิบาย |
|---|---|
| `PRODUCTS` | แสดงสินค้า (by brand/category/custom, grid/carousel) |
| `PRODUCT_CAROUSEL` | สไลด์สินค้าแนวนอน |
| `CATEGORIES` | แสดงหมวดหมู่สินค้า |
### กลุ่ม Content & Editorials
| Type | คำอธิบาย |
|---|---|
| `TEXT` | ข้อความทั่วไป (จัดตำแหน่งได้) |
| `RICH_TEXT` | เนื้อหาจัดรูปแบบได้ |
| `EDITORIAL_TILE` | รูปภาพ + เนื้อหา (สลับซ้าย-ขวาได้) |
| `EDITORIAL_CAROUSEL` | สไลด์บทความ (standard / split screen) |
| `HERO_ARTICLE` | หัวบทความ (ผู้เขียน, วันที่, หมวดหมู่) |
| `QUOTE_CALLOUT` | โควทคำพูด / คำโปรย |
### กลุ่ม Brand Features
| Type | คำอธิบาย |
|---|---|
| `SCENT_NOTES_BREAKDOWN` | แสดง Top/Heart/Base Notes ของกลิ่น |
| `USP_BAR` | จุดเด่นของร้าน (max 4 items) |
| `ACCORDION` | Q&A / FAQ แบบย่อ-ขยาย |
### กลุ่ม Forms & Contacts
| Type | คำอธิบาย |
|---|---|
| `NEWSLETTER` | ฟอร์มรับอีเมล + privacy checkbox |
| `CONTACT_INFO` | ที่อยู่, อีเมล, LINE, เวลาทำการ |
| `CONTACT_FORM` | ฟอร์มส่งข้อความ |
---
## 2. Multi-Client White-Label Strategy
### หลักการสำคัญ
> **CMS เก็บข้อมูล (Data + Semantics) — Renderer คือสิ่งที่เปลี่ยนตาม Client**
ความแตกต่างระหว่าง Client มี 2 ระดับที่แก้ต่างกัน:
| ระดับ | ตัวอย่าง | แก้ด้วย |
|---|---|---|
| **Visual Style** | สี, font, spacing ต่างกัน | Design Tokens / CSS Variables |
| **Layout Structure** | Card ตั้ง vs Card นอน (HTML ต่างกัน) | Component Variants ใน Renderer |
> Theme Token ช่วยไม่ได้กับ Layout Structure เพราะ HTML shape ต่างกันทั้งหมด
### Git Repository Strategy
```
[product-template] ← Source of Truth เสมอ
│
├── fork → [homaroma-client]
├── fork → [client-a-repo]
│ └── good feature → cherry-pick กลับ product-template
└── fork → [client-b-repo] ← clone จาก product-template (ที่ updated แล้ว)
```
**กฎ:** Client B ไม่ได้ start จาก Client A แต่ start จาก **product-template ที่รับ feature ดีๆ กลับมาแล้ว**
### Commit Discipline (สำคัญมาก)
```bash
# ✅ แยก commit ให้ชัดเสมอ
git commit -m "feat(categories): add horizontal-card layout variant" # generic → กลับ master ได้
git commit -m "feat(client-a): set default theme to warm-beige" # client-specific
git commit -m "fix(checkout): correct discount calculation" # generic → กลับ master ได้
# ❌ อย่าทำแบบนี้
git commit -m "client A changes" # cherry-pick ยากมาก
```
### Decision: Feature กลับ master ได้หรือไม่?
| ลักษณะ Feature | กลับ master? |
|---|---|
| Generic component / layout variant ใหม่ | ✅ ควร |
| Bug fix | ✅ เสมอ |
| Infrastructure / DevOps | ✅ เสมอ |
| Branding เฉพาะ client (สี, logo) | ❌ |
| Business logic เฉพาะ client | ❌ |
| Config ที่ structure generic แต่ค่าต่างกัน | ✅ structure กลับ, ค่าอยู่ที่ client |
---
## 3. componentRegistry Pattern
### เป้าหมาย
ให้ **Backend + Schema กลางไม่ต้องเปลี่ยน** เมื่อ Client ต้องการ Layout ที่ต่างออกไป
### โครงสร้างที่ควรมี
```
apps/spa/src/
config/
componentRegistry.ts ← Client-specific (ไม่ขึ้น master)
themeConfig.ts ← Client-specific
components/
dynamic/
categories/
VerticalCard.tsx ← Generic variant (ขึ้น master)
HorizontalCard.tsx ← Generic variant (ขึ้น master)
```
### การทำงาน
```ts
// apps/spa/src/config/componentRegistry.ts
export const componentRegistry = {
CATEGORIES: DynamicCategoriesVertical, // HomAroma เลือก vertical
HERO: DynamicHeroV2,
}
// DynamicPageRenderer.tsx — generic, ไม่มี hardcode switch-case
sections.map(section => {
const Component = componentRegistry[section.type]
return