ข้ามไปที่เนื้อหา

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