Skip to content

บทที่ 0 — ภาพรวม Full-Stack Architecture

สารบัญ | บทถัดไป →


ทำไมต้องเรียน full-stack แบบ "ต่อกัน"

ภาพรวมก่อนเริ่ม: Frontend = หน้าจอที่ผู้ใช้เห็นและกด (React); Backend = หลังบ้านที่จัดการข้อมูล/business logic + คุยกับฐานข้อมูล (Spring Boot). ทั้งสองคุยกันผ่าน HTTP + JSON — Full-stack book = สอนให้สองฝั่งคุยกันได้สะอาด ปลอดภัย และ deploy ได้จริง

ถ้าคุณอ่าน Spring Boot กับ React Book จบแล้ว คุณรู้:

  • Spring Boot = สร้าง REST API (อ่าน: เร็สท์-เอ-พี-ไอ; ย่อจาก Representational State Transfer Application Programming Interface — Representational อ่าน เร็พ-รี-เซน-เท-ชั่น-แนล = ช่องทางให้โปรแกรมอื่นเรียกข้อมูล/สั่งงานผ่าน HTTP) ที่ return JSON (อ่าน: เจ-สัน; JavaScript Object Notation = รูปแบบข้อความที่ใช้ส่งข้อมูลระหว่างเครื่อง) ได้
  • React = สร้าง UI (อ่าน: ยู-ไอ; User Interface = หน้าจอที่ผู้ใช้เห็นและกด) ที่เรียก API แล้ว render (เรน-เดอร์ = วาด/แสดงผลออกหน้าจอ) ได้

แต่ตอนต่อจริง จะเจอปัญหาที่ไม่มีในหนังสือแต่ละเล่ม:

ปัญหาอธิบาย
CORS (อ่าน: คอร์ส; Cross-Origin Resource Sharing — Cross-Origin อ่าน ครอส-ออ-ริ-จิ้น = กฎความปลอดภัยของเบราว์เซอร์เรื่องเรียกข้าม origin)browser (เบราว์เซอร์) block (บล็อก/ห้าม) request ข้าม domain (โดเมน คนละที่อยู่เว็บ)
Auth flow (auth = authentication การยืนยันตัวตน; flow = ลำดับขั้นตอน)login อยู่ React แต่ JWT (อ่าน: จ๊อต หรือ เจ-ดับเบิ้ลยู-ที; JSON Web Token = บัตรผ่านดิจิทัลที่เซิร์ฟเวอร์ออกให้หลัง login) อยู่ Spring → เก็บ token (โทเคน บัตรผ่าน) ที่ไหน? ส่งยังไง?
Error formatbackend ส่ง error มายังไง React ถึงจะแสดงได้สวย?
File uploadReact ส่ง file → Spring เก็บ → React preview
Environmentdev ใช้ localhost:8080 แต่ prod ใช้ domain จริง → config ยังไง?
Deployfrontend กับ backend ต้อง run ด้วยกันยังไง?

บทนี้จะให้ภาพรวม → บทถัดไปจะลงมือทำทีละเรื่อง


1. Architecture ที่เราจะสร้าง

📦 เครื่องมือที่จะเห็นใน diagram (อธิบายเต็มในบทถัดไป — ตอนนี้รู้ชื่อพอ):

  • TanStack Query (แทน-สแต็ก-คิวรี่) = ไลบรารีฝั่ง React ที่จัดการเรียก API + cache + retry ให้อัตโนมัติ
  • JPA (เจ-พี-เอ; Java Persistence API) = มาตรฐาน Java สำหรับคุยกับฐานข้อมูลแบบ object (Spring Boot ใช้ Hibernate เป็น implementation)
  • PostgreSQL (โพสต์-เกรส-คิว-แอล) = ฐานข้อมูล relational ที่นิยมมากในงาน production
  • Spring Security Filter Chain = ชั้นกรอง request ของ Spring ที่ตรวจ token/permission ก่อนเข้าถึง endpoint

⚠️ JWT storage — 2 แบบ:

  • MVP / เรียน: เก็บใน localStorage หรือ memory (ง่าย, debug สบาย)
  • Production (2026 best practice): เก็บใน HttpOnly cookie + CSRF protection (กัน XSS อ่าน token ไม่ได้) — ดูบทที่ 2 §7

หนังสือเล่มนี้สอน localStorage ก่อนเพราะเห็นภาพชัด แล้วค่อยอัพเกรดเป็น HttpOnly cookie ในบทที่ 2

SPA (อ่าน: เอส-พี-เอ) = Single Page Application (เว็บหน้าเดียว) — โหลด HTML/JS ครั้งเดียวตอนแรก แล้วหลังจากนั้น React สลับหน้า/ดึงข้อมูลเองโดยไม่ refresh ทั้งหน้า

Request Flow (เมื่อ user กดปุ่ม "Load Users")

ฉบับย่อ (เห็นภาพรวมก่อน):

  1. React เรียก API → 2. Backend ตรวจ token → 3. Backend คุย database → 4. Return JSON → 5. React render

ฉบับเต็ม (ค่อยทำความเข้าใจในบทถัดไป):

  1. React component เรียก useQuery → TanStack Query เรียก fetchUsers()
  2. fetchUsers()fetch('http://localhost:8080/api/users', { headers: { Authorization: 'Bearer xxx' } })
  3. Browser ส่ง HTTP request ไป Spring Boot
  4. Spring Security Filter Chain:
    • JwtAuthFilter อ่าน header → validate token → ถ้า valid ใส่ user เข้า SecurityContext
  5. UserController.getAll() ถูกเรียก
  6. UserService.findAll()UserRepository.findAll() → PostgreSQL
  7. Return List<UserDto> → Spring แปลงเป็น JSON → ส่ง HTTP Response กลับ
  8. TanStack Query รับ JSON → cache → trigger re-render
  9. React component ได้ data → render UI

🔜 ยังไม่ต้องเข้าใจ TanStack Query / Spring Security Filter Chain / JwtAuthFilter ตอนนี้ — บทที่ 1 + 2 จะอธิบายทีละขั้น

ถ้า token หมดอายุ?

  1. Spring Security ส่ง 401 Unauthorized กลับ
  2. React API layer detect 401 → redirect ไป /login
  3. User login ใหม่ → ได้ token ใหม่ → retry request เดิม

2. Project Structure

เรา แยก repo (หรือ folder) ระหว่าง frontend กับ backend

ขั้นที่ 1 — โครงสร้าง minimal (เริ่มจากตรงนี้)

my-fullstack-app/
├── backend/                    ← Spring Boot project
│   ├── src/main/java/com/example/app/
│   │   ├── auth/               ← JWT, login, signup
│   │   ├── user/               ← User CRUD
│   │   └── config/             ← Security, CORS
│   ├── src/main/resources/application.yml
│   └── pom.xml

├── frontend/                   ← React project
│   ├── src/
│   │   ├── api/                ← API layer (axios/fetch wrapper)
│   │   ├── auth/               ← login, token management
│   │   ├── components/         ← shared UI
│   │   ├── pages/              ← route-level components
│   │   ├── App.tsx
│   │   └── main.tsx
│   └── package.json

ขั้นที่ 2 — เพิ่ม Docker + Production (บทที่ 5)

my-fullstack-app/
├── backend/
│   ├── src/main/resources/db/migration/  ← Flyway migrations
│   ├── src/test/
│   ├── Dockerfile                        ← container image
│   └── pom.xml
├── frontend/
│   ├── src/features/                     ← feature modules (users/, posts/)
│   ├── src/hooks/                        ← custom hooks
│   ├── src/types/                        ← TypeScript types
│   ├── Dockerfile
│   ├── nginx.conf                        ← production reverse proxy
│   ├── .env.development
│   └── .env.production
└── docker-compose.yml                    ← run ทั้ง stack

🔜 Docker (ด็อก-เกอร์) = เครื่องมือบรรจุแอปลงในกล่อง (container) เพื่อ run ได้เหมือนกันทุกเครื่อง — ยังไม่ต้องเข้าใจตอนนี้ บทที่ 5 จะสอน

ทำไมแยก? เพราะ frontend กับ backend:

  • Deploy (ดีพลอย = เอาขึ้นเซิร์ฟเวอร์ให้คนใช้จริง) ต่างที่ได้ (CDN อ่าน ซี-ดี-เอ็น = Content Delivery Network เครือข่ายเซิร์ฟเวอร์กระจายไฟล์ static อ่าน ส-แต-ติก = ไฟล์ที่ไม่ต้องประมวลผล เช่น HTML/CSS/JS/รูป — ให้โหลดเร็วใกล้ผู้ใช้ vs server ปกติ)
  • Scale ต่างจังหวะ (frontend = static, backend = CPU/memory)
  • Team คนละทีมดูแลได้
  • CI/CD pipeline แยกกัน

CDN ทำงานยังไง (ภาพย่อ):

ผู้ใช้ในไทย ─┐
             ├─→ CDN edge ไทย (cache ไฟล์ static) ─→ เร็ว
ผู้ใช้ในสหรัฐ ─┐
             ├─→ CDN edge สหรัฐ (cache ไฟล์เดียวกัน) ─→ เร็ว
                      ↕ (sync จาก origin)
             Origin server (Vercel/Cloudflare/Netlify)

2026 CDN ยอดนิยม: Cloudflare, Vercel Edge, Netlify, AWS CloudFront


3. เครื่องมือ + Port ที่ใช้ตอน Development

เครื่องมือPortหมายเหตุ
Vite dev server (React)5173hot reload
Spring Boot8080API server
PostgreSQL5432database
pgAdmin (optional)5050database GUI

ปัญหาตอน dev — "Cross Origin"

React run ที่ localhost:5173
Spring Boot run ที่ localhost:8080

Browser มองว่าคนละ origin (port ต่างกัน) → browser block request ด้วย CORS policy

วิธีแก้ 2 ทาง (บทที่ 1 จะอธิบายละเอียด):

  1. Backend เปิด CORS — Spring Boot config ว่า "อนุญาตให้ 5173 เรียก"
  2. Frontend proxy — Vite ตั้ง proxy ให้ /api/* forward ไป 8080

4. Shared Contract — API Response Format

📖 API Contract คืออะไร? = ข้อตกลงระหว่าง backend กับ frontend ว่า "ฉันจะส่ง/รับข้อมูลรูปร่างแบบนี้นะ" — เหมือนสัญญา ถ้าฝั่งใดฝั่งหนึ่งเปลี่ยนรูปร่างโดยไม่บอก อีกฝั่งจะพัง ทำไมต้องมี? เพราะคนเขียน frontend กับ backend คนละคน (หรือคนเดียวกันแต่คนละเวลา) ถ้าไม่ตกลงล่วงหน้า → debug นาน, bug เยอะ, type ไม่ตรง

Backend กับ Frontend ต้อง ตกลงกัน ว่า response (คำตอบที่เซิร์ฟเวอร์ส่งกลับ) หน้าตาเป็นยังไง — หนังสือเล่มนี้เลือก convention เดียวใช้ทั้งเล่ม:

  • Success = ส่ง object/array ตรง ๆ ไม่มี wrapper (เช่น login response = { accessToken, user, ... } ส่งออกมาเลย)
  • Error = ห่อในรูปแบบเดียวกันทุก endpoint ({ error: { code, message, details }, timestamp }) เพื่อให้ frontend มี handleApiError() ตัวเดียว

ดูตัวอย่างจริงที่ บทที่ 1 §9–10

💡 มี convention อีกแบบที่บางทีมใช้ — ห่อ success ใน { data, message, timestamp } ด้วย ดีตรง consistent กับ error format แต่ verbose กว่า หนังสือเล่มนี้เลือกแบบไม่ห่อเพราะใช้กับ TypeScript ได้ตรงไปตรงมากว่า (ไม่ต้อง unwrap .data ทุก request)

Error Response

json
{
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "Validation failed",
        "details": [
            { "field": "email", "message": "must be a valid email" },
            { "field": "name", "message": "must not be blank" }
        ]
    },
    "timestamp": "2026-05-18T10:00:00Z"
}

ทำไมต้อง consistent?

ถ้า backend บาง endpoint ส่ง { "users": [...] } บาง endpoint ส่ง [...] ตรง ๆ
→ Frontend ต้อง handle case ต่าง → code ซับซ้อน → bug เยอะ

ถ้า error format เหมือนกันหมด → Frontend มี handleApiError() ตัวเดียว → สะอาด


5. TypeScript Types ที่ Share กัน

React ต้องมี Type ที่ตรงกับ DTO (อ่าน: ดี-ที-โอ; Data Transfer Object = คลาส/อ็อบเจกต์ที่ใช้ส่งข้อมูลเข้า-ออก API โดยเฉพาะ แยกจาก entity ในฐานข้อมูล) ของ Spring Boot:

typescript
// types/api.ts — error format ที่ใช้ทั้งระบบ (success ไม่มี wrapper)
interface ApiError {
    error: {
        code: string;
        message: string;
        details?: { field: string; message: string }[];
    };
    timestamp: string;
}

// types/user.ts — match กับ Spring Boot DTO
interface User {
    id: number;
    email: string;
    name: string;
    role: 'USER' | 'ADMIN';
    createdAt: string;    // ISO date string
}

interface CreateUserRequest {
    email: string;
    name: string;
    password: string;
}

interface LoginRequest {
    email: string;
    password: string;
}

interface LoginResponse {
    accessToken: string;     // JWT ใช้แนบ Authorization header
    refreshToken: string;    // ใช้ขอ accessToken ใหม่เมื่อหมดอายุ
    expiresIn: number;       // อายุ accessToken (วินาที)
    user: User;
}

💡 Tip: เขียน type ตรงนี้ → Zod (ไลบรารีตรวจสอบความถูกต้องของข้อมูล/validate ในฝั่ง TypeScript) schema (สคีมา = แบบกำหนดรูปร่างข้อมูล) ที่ validate (ตรวจสอบความถูกต้อง) form → API layer (ชั้นรวมโค้ดเรียก API) ที่ส่ง request → ทุกอย่างเชื่อมกัน

🔜 ยังไม่ต้องเข้าใจ Zod/API layer ตอนนี้ — เดี๋ยวเจอเต็ม ๆ ใน บทที่ 1 และ บทที่ 2


6. Development Workflow

ก่อนเริ่ม — ต้องติดตั้งอะไรบ้าง

เครื่องมือใช้ทำอะไรลิงก์ติดตั้ง
Java 25 (LTS, แนะนำ; min Java 21)run Spring BootEclipse Temurin (แนะนำ) หรือ Oracle JDK
Node.js 22 LTSrun Vite / Reactnodejs.org — เลือก LTS
Docker Desktoprun PostgreSQL ใน containerdocker.com/products/docker-desktop
Gitversion controlgit-scm.com

✅ verify ติดตั้งสำเร็จด้วยคำสั่ง: java --version, node --version, docker --version, git --version

เปิดทำงาน (ทุกวัน)

bash
# Terminal 1 (หน้าต่างคำสั่งที่ 1): Database — ฐานข้อมูล
docker compose up db -d

# Terminal 2: Backend — เซิร์ฟเวอร์ฝั่งหลังบ้าน
cd backend
./mvnw spring-boot:run

# Terminal 3: Frontend — เว็บฝั่งผู้ใช้
cd frontend
npm run dev

เปิด browser ที่ http://localhost:5173

React app จะ render → เรียก API ไปที่ localhost:8080 (ผ่าน proxy หรือ direct)

Workflow เมื่อแก้ code

แก้ที่ไหนเกิดอะไร
React componentVite HMR (Hot Module Replacement = สลับเฉพาะโค้ดที่แก้เข้าไปทันทีโดยไม่โหลดหน้าใหม่) → browser update ทันที (ไม่ reload)
Spring Boot controllerSpring DevTools → auto restart (~2 วิ)
Database schemaเพิ่ม Flyway migration → restart backend
API contract เปลี่ยนแก้ทั้ง backend DTO + frontend type

7. Production Architecture

ตอน production ไม่มี Vite dev server:

ข้อดี:

  • Same domain → ไม่มีปัญหา CORS
  • Nginx → serve static file เร็วมาก + caching + gzip
  • Security → เปิดแค่ port 80/443 สู่ outside

8. เรื่องที่ต้องรู้ก่อนเริ่มบทถัดไป

HTTP Methods ที่ใช้บ่อย

Idempotent (อ่าน: ไอ-เดม-โพ-เทนต์) = "เรียกซ้ำกี่ครั้งผลก็เหมือนเรียกครั้งเดียว"

  • DELETE /users/5 ซ้ำ 3 ครั้ง → user id 5 ก็หายไป อันเดียว เท่าเดิม (idempotent)
  • POST /users ซ้ำ 3 ครั้ง → สร้าง user ใหม่ 3 ตัว (ไม่ idempotent)
Methodใช้ทำอะไรBodyIdempotent
GETอ่านข้อมูลไม่มี
POSTสร้างข้อมูลใหม่มี
PUTแก้ไขทั้ง objectมี
PATCHแก้ไขบางส่วนมี
DELETEลบไม่มี/มีก็ได้

HTTP Status Code ที่ใช้บ่อย

Codeความหมายเมื่อไหร่
200OKrequest สำเร็จ
201Createdสร้าง resource ใหม่สำเร็จ
204No Contentสำเร็จ แต่ไม่มี body (เช่น DELETE)
400Bad Requestrequest ผิด format / validation fail
401Unauthorizedไม่มี token / token invalid
403Forbiddenมี token แต่ไม่มีสิทธิ์
404Not Foundresource ไม่มี
409Conflictข้อมูลซ้ำ (เช่น email ซ้ำ)
500Internal Server Errorserver พัง

สิ่งที่ต้องมีบนเครื่องก่อนเริ่ม

  • [ ] Java 25 LTS (แนะนำ; min 21) — java --version · ดาวน์โหลด: Eclipse Temurin
  • [ ] Node.js 22 LTSnode --version · ดาวน์โหลด: nodejs.org
  • [ ] Docker + Docker Composedocker --version · ดาวน์โหลด: docker.com
  • [ ] IDE: ตามถนัด — แนะนำ IntelliJ IDEA สำหรับ Java + VS Code/Cursor/Zed สำหรับ TS (จะใช้ IDE ตัวเดียวรวมทั้งคู่ก็ได้)
  • [ ] Gitgit --version · ดาวน์โหลด: git-scm.com

9. Checkpoint

🛠️ Checkpoint 0.1 — Setup ทุกอย่าง

  1. สร้าง Spring Boot project ด้วย Spring Initializr (Web, JPA, Security, PostgreSQL, Validation)
  2. สร้าง React project ด้วย npm create vite@latest frontend -- --template react-ts
  3. สร้าง docker-compose.yml ที่ run PostgreSQL
  4. verify: backend start ได้ + frontend start ได้ + db connect ได้

🛠️ Checkpoint 0.2 — วาด architecture

เอากระดาษหรือ draw.io วาด architecture ของ app ที่คุณอยากทำ:

  • กี่ entity?
  • API endpoint อะไรบ้าง?
  • หน้าไหนบ้าง?
  • หน้าไหน public / protected?

ไม่ต้องสมบูรณ์ — วาดก่อน แก้ทีหลัง


คำย่อที่จะเจอบ่อยในเล่มนี้ (Acronym Cheatsheet)

ย่อเต็มคำอ่านความหมายสั้น
APIApplication Programming Interfaceเอ-พี-ไอช่องทางให้โปรแกรมเรียกกัน
RESTRepresentational State Transferเร็สท์สถาปัตยกรรม API ผ่าน HTTP
JSONJavaScript Object Notationเจ-สันรูปแบบข้อความส่งข้อมูล
HTTPHyperText Transfer Protocolเอช-ที-ที-พีโปรโตคอลคุยกันบนเว็บ
URLUniform Resource Locatorยู-อาร์-แอลที่อยู่ของ resource
UIUser Interfaceยู-ไอหน้าจอผู้ใช้
UXUser Experienceยู-เอ็กซ์ประสบการณ์ผู้ใช้
SPASingle Page Applicationเอส-พี-เอเว็บหน้าเดียว
CORSCross-Origin Resource Sharingคอร์สกฎเรียก API ข้าม origin
JWTJSON Web Tokenจ๊อต / เจ-ดับเบิ้ลยู-ทีบัตรผ่านดิจิทัล
CRUDCreate, Read, Update, Deleteครัดสร้าง/อ่าน/แก้/ลบ
DTOData Transfer Objectดี-ที-โอobject ส่งข้อมูลเข้า-ออก API
JPAJava Persistence APIเจ-พี-เอมาตรฐาน Java คุยฐานข้อมูล
ORMObject-Relational Mappingโอ-อาร์-เอ็มแปลง table ↔ object
CDNContent Delivery Networkซี-ดี-เอ็นเครือข่ายกระจายไฟล์ static
HMRHot Module Replacementเอช-เอ็ม-อาร์สลับโค้ดทันทีไม่ reload
LTSLong Term Supportแอล-ที-เอสเวอร์ชันซัพพอร์ตยาว
MVPMinimum Viable Productเอ็ม-วี-พีเวอร์ชันแรกที่ใช้งานได้
CI/CDContinuous Integration / Continuous Deploymentซี-ไอ / ซี-ดีระบบ build + deploy อัตโนมัติ

สรุป

✅ Full-stack = React (frontend) + Spring Boot (backend) + Database
✅ แยก project → deploy + scale ได้อิสระ
CORS + Auth + Error format = 3 เรื่องที่ต้องตกลงก่อน
✅ Dev ใช้ 2 port (5173 + 8080) + proxy/CORS → Production ใช้ Nginx same domain
✅ ตกลง API contract (response format) ก่อนเริ่มเขียน → ลด bug


บทถัดไป → เชื่อม React กับ Spring Boot


Glossary: ../glossary.md · Style guide: ../CONTRIBUTING.md last_verified: 2026-06-03 · review report: ../REVIEW-2026-06-03.md