8. สถาปัตยกรรม#
8.1 ภาพรวม#
flowchart TB
subgraph USERS["ผู้ใช้"]
U1["พนักงาน<br/>เบราว์เซอร์ / มือถือ"]
U2["พนักงาน<br/>ผ่าน Claude"]
U3["Google Chat"]
end
subgraph EDGE["Caddy — HTTPS อัตโนมัติ"]
CD["*.keycake.com"]
end
subgraph APPS["Docker บน Hetzner VPS"]
SPEC["spec<br/>nginx + static<br/>:3003"]
WEB["web<br/>Next.js<br/>:3005"]
KB["kb<br/>Next.js<br/>:3006"]
MCP["MCP endpoint<br/>อยู่ในแอป web"]
end
subgraph DATA["ข้อมูล"]
PG[("PostgreSQL 17<br/>+ pgvector<br/>:5434")]
BK["Backup รายวัน"]
end
subgraph EXT["ภายนอก"]
GW["Google Workspace<br/>OAuth"]
GC["Google Chat API"]
end
U1 --> CD
U2 --> CD
CD --> SPEC
CD --> WEB
CD --> KB
U2 -.->|MCP over HTTPS| MCP
MCP --- WEB
WEB --> PG
KB --> PG
WEB --> GW
WEB --> GC --> U3
PG --> BK
classDef vps fill:#e0e7ff,stroke:#4f46e5,color:#1e1b4b
classDef db fill:#fce7f3,stroke:#db2777,color:#831843
class SPEC,WEB,KB,MCP vps
class PG,BK db
8.2 การจัดสรร URL และพอร์ต#
| URL | บริการ | พอร์ตภายใน | สถานะ |
|---|---|---|---|
https://work-spec.keycake.com |
เอกสารออกแบบ (หน้านี้) | 127.0.0.1:3003 |
✅ ใช้งานแล้ว |
https://work.keycake.com |
ระบบงานหลัก + MCP endpoint | 127.0.0.1:3005 |
🔨 Phase 1 |
https://kb.keycake.com |
คลังความรู้ | 127.0.0.1:3006 |
📋 Phase 3 |
| — | PostgreSQL | 127.0.0.1:5434 |
🔨 Phase 1 |
ทุกบริการผูกกับ 127.0.0.1 เท่านั้น เข้าถึงจากภายนอกได้ผ่าน Caddy (HTTPS) เท่านั้น
ไฟร์วอลล์เปิดเฉพาะพอร์ต 22 / 80 / 443
ทำไมใช้ชื่อแบบแบน (work-spec) ไม่ใช่ spec.work
Wildcard DNS *.keycake.com รองรับได้ระดับเดียว
ชื่อซ้อน (spec.work.keycake.com) ใช้ได้วันนี้แต่จะพังเงียบ ๆ วันที่มี DNS record ปรากฏที่ระดับ work
8.3 เทคโนโลยีที่เลือกและเหตุผล#
| ส่วน | เลือกใช้ | เหตุผล |
|---|---|---|
| ฐานข้อมูล | PostgreSQL 17 + pgvector | ตัวเดียวจบทั้งข้อมูลธุรกรรมและการค้นหาเชิงความหมาย ไม่ต้องเพิ่ม vector DB แยก |
| แอปหลัก | Next.js (App Router) + TypeScript | เว็บ + API + MCP endpoint อยู่ใน codebase เดียว ลดของที่ต้องดูแล |
| ORM | Drizzle | schema เป็น TypeScript ตรง ๆ migration ชัดเจน ควบคุม SQL ได้เมื่อรายงานต้องการ |
| ยืนยันตัวตน | Google OAuth จำกัดโดเมน | ทีมมี Workspace อยู่แล้ว ไม่ต้องจัดการรหัสผ่านเอง ลาออกปุ๊บตัดสิทธิ์ปั๊บ |
| เอกสาร | MkDocs Material | เขียน Markdown อย่างเดียว build เป็น static แก้ง่าย รองรับ Mermaid |
| Deploy | Docker Compose + Caddy | มาตรฐานเดิมของเซิร์ฟเวอร์อยู่แล้ว ได้ HTTPS อัตโนมัติ |
หลักที่ยึด: เลือกของน้อยชิ้นที่สุดที่ทำงานได้
บริษัทมีคนดูแลระบบจำกัด ทุกเทคโนโลยีที่เพิ่มเข้ามาคือภาระระยะยาว ไม่มี message queue · ไม่มี microservice · ไม่มี cache layer จนกว่าจะพิสูจน์ได้ว่าจำเป็นจริง
8.4 โครงสร้างโปรเจ็กต์#
wai-work/
├── docker-compose.yml
├── CLAUDE.md
├── apps/
│ ├── spec/ # เอกสารนี้ → work-spec.keycake.com
│ │ ├── Dockerfile
│ │ ├── mkdocs.yml
│ │ └── docs/*.md
│ ├── web/ # ระบบหลัก → work.keycake.com (Phase 1)
│ │ ├── Dockerfile
│ │ ├── app/ # หน้าเว็บ + API routes
│ │ ├── app/api/mcp/ # MCP endpoint
│ │ └── lib/
│ └── kb/ # คลังความรู้ → kb.keycake.com (Phase 3)
├── packages/
│ ├── db/ # schema + migration + views (Drizzle)
│ └── core/ # ตรรกะคิดต้นทุน ใช้ร่วมกันทุกแอป
└── db/
└── seed/ # ข้อมูลตั้งต้น
ตรรกะคิดต้นทุนต้องอยู่ที่เดียว
packages/core เป็นแหล่งเดียวที่คำนวณต้นทุน
ทั้งหน้าเว็บ MCP tool และรายงานเรียกใช้ฟังก์ชันเดียวกัน
ถ้าปล่อยให้แต่ละที่คำนวณเอง ตัวเลขจะไม่ตรงกันภายในสองเดือน
8.5 การนำขึ้นระบบ#
deploy wai-work
คำสั่งเดียวจบ — rebuild และ restart ทุกบริการของโปรเจ็กต์ แล้วพิมพ์ URL ทั้งหมดออกมา
การเพิ่ม URL ใหม่:
addsite work 3005 -p wai-work
8.6 การสำรองข้อมูล#
| อะไร | ความถี่ | เก็บไว้ | ที่ไหน |
|---|---|---|---|
PostgreSQL (pg_dump) |
ทุกวัน ตี 3 | 30 วัน | บนเซิร์ฟเวอร์ + สำเนานอกเครื่อง |
| ไฟล์แนบ (ถ้ามี) | ทุกวัน | 30 วัน | เดียวกัน |
| Source code | ทุก commit | ตลอด | Git |
ต้องทดสอบการกู้คืนจริง
ทำ restore drill หนึ่งครั้งก่อนเริ่มใช้งานจริง และทุกไตรมาสหลังจากนั้น backup ที่ไม่เคยกู้คืนสำเร็จ ไม่นับว่าเป็น backup
8.7 ตัวแปรสภาพแวดล้อม#
| ตัวแปร | ใช้ทำอะไร |
|---|---|
DATABASE_URL |
เชื่อมต่อ PostgreSQL |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET |
OAuth |
ALLOWED_EMAIL_DOMAIN |
buildupclick.com |
AUTH_SECRET |
เข้ารหัส session |
MCP_TOKEN_PEPPER |
เพิ่มความปลอดภัยของ token ที่เก็บแบบ hash |
GOOGLE_CHAT_WEBHOOK_URL |
ส่งแจ้งเตือน |
เก็บใน .env บนเซิร์ฟเวอร์เท่านั้น ห้าม commit เข้า Git