IoT Workshop #3: ตั้ง Project & DevOps ให้พร้อมรบ
IoT Workshop #3: ตั้ง Project & DevOps ให้พร้อมรบ
Branch:
workshop/plan-03-project-setupPhase: Planning (3/3) Repo: kangana1024/iot-workshop
สวัสดีน้องๆ! พี่โชว์กลับมาแล้ว ╰(°▽°)╯
สองบทที่แล้วเราวางแผน Architecture และ Database Design กันไปแล้ว วันนี้ถึงเวลา ตั้ง project จริงๆ ซะที ก่อน code ได้ เราต้องจัดบ้านให้เรียบร้อยก่อน — Monorepo, Docker, Makefile, Git Strategy ครบหมด พอตั้งเสร็จแล้ว workshop ทุก step ที่ตามมาจะ smooth มาก มาลุยกันเลย!
ทำไมต้องตั้ง Dev Environment ให้ดี? (WHY ก่อนเสมอ)
ลองนึกภาพว่าเรากำลังจะทำอาหารกับเพื่อน 10 คน แต่ครัวยังไม่ได้จัดเลย มีด กะทะ เขียง กระจายอยู่ทั่วบ้าน บางคนใช้ gas หุงข้าว บางคนใช้ไฟฟ้า แน่นอนว่า chaos ตั้งแต่ยังไม่ได้เริ่มทำ
Dev Environment คือครัวของ developer ถ้าไม่จัดก่อน:
- น้องแต่ละคน setup นานคนละ 2-3 ชั่วโมง (เสียเวลา workshop ไปเลย)
- “แต่มันรันได้บน machine เรานะ!” — classic 555
- Service versions ต่างกัน → bug ที่หาไม่เจอ
เราจะแก้ปัญหานี้ด้วย Docker Compose (ทุกคน run environment เดียวกัน 100%) + Makefile (command เดียวกันทุกคน) + Monorepo (code ทุกส่วนอยู่ที่เดียว)
สิ่งที่น้องๆ จะได้เรียนรู้
- Monorepo Structure — จัดบ้านให้ backend + 2 frontends อยู่ด้วยกันอย่างเป็นระเบียบ
- Docker Compose — spin up 7 services พร้อมกันในคำสั่งเดียว
- Makefile — ทำ CLI ของตัวเองให้ทีมใช้ได้โดยไม่ต้องจำ command ยาวๆ
- Service Configs — ตั้งค่า Mosquitto, Telegraf, Kapacitor ให้คุยกันได้
- Git Branching Strategy — วิธีจัด branch ให้ workshop ไหลลื่น
- CI/CD Pipeline — GitHub Actions ที่ run test อัตโนมัติทุก push
ภาพรวม Dev Environment
ก่อนลงมือ มาดูภาพรวมว่า services ทั้งหมดเชื่อมกันยังไง:
ดูแล้วเข้าใจเลยว่า Telegraf เป็น “พนักงานเก็บข้อมูล” ที่นั่งฟัง MQTT แล้วยก data ไปเก็บใน InfluxDB ส่วน Kapacitor เป็น “นาฬิกาปลุก” ที่คอยดู pattern แล้ว alert กลับมาที่ API ของเรา
Monorepo Structure — จัดบ้านก่อนเริ่มงาน
Monorepo คือการเอา project ทั้งหมด (backend, frontend-mobile, frontend-admin, deployments) ใส่ไว้ใน repo เดียว แทนที่จะกระจาย 4 repos
เปรียบเหมือน คอนโดรวม vs บ้านแยก — ถ้าอยู่คอนโดรวม จะใช้ lift ร่วม, ใช้ไฟส่วนกลาง, ไปมาหาสู่กันง่าย แต่ถ้าบ้านแยก 4 หลัง กว่าจะไปหากันแต่ละทีก็เหนื่อยแล้ว
Project Initialization
# Clone workshop repository
git clone https://github.com/kangana1024/iot-workshop.git
cd iot-workshop
# Create directory structure
mkdir -p backend/cmd/server
mkdir -p backend/internal/{config,handler,middleware,model,repository,service,mqtt,websocket}
mkdir -p backend/pkg/utils
mkdir -p frontend-mobile/src/{screens,components,services,stores,utils}
mkdir -p frontend-admin/src/{pages,components,hooks,services,stores,types}
mkdir -p deployments/{mosquitto,telegraf,kapacitor}
mkdir -p docs scripts
โครงสร้างที่ได้จะหน้าตาแบบนี้:
iot-workshop/
├── backend/ # Go Fiber API
│ ├── cmd/server/
│ ├── internal/
│ │ ├── config/
│ │ ├── handler/
│ │ ├── middleware/
│ │ ├── model/
│ │ ├── repository/
│ │ ├── service/
│ │ ├── mqtt/
│ │ └── websocket/
│ └── pkg/utils/
├── frontend-mobile/ # LynxJS Mobile App
│ └── src/
├── frontend-admin/ # Vite Admin Panel
│ └── src/
├── deployments/ # Docker & Configs
│ ├── docker-compose.yml
│ ├── docker-compose.dev.yml
│ ├── mosquitto/
│ ├── telegraf/
│ └── kapacitor/
├── scripts/
├── docs/
├── Makefile # <=== ตัวนี้สำคัญมาก!
└── .env.example
Makefile — CLI ของทีมเรา
Makefile เปรียบเหมือน รีโมทคอนโทรล ของ project แทนที่จะต้องจำ docker compose -f deployments/docker-compose.yml -f deployments/docker-compose.dev.yml up -d ทุกครั้ง แค่พิมพ์ make dev ก็จบ!
# Makefile - ใช้จัดการ commands ทั้งหมด
.PHONY: help dev dev-up dev-down build test clean seed
help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
# ========== Development ==========
dev: dev-up ## Start development environment
@echo "✅ Development environment is ready!"
@echo "📡 API: http://localhost:3000"
@echo "📊 Chronograf: http://localhost:8888"
@echo "🔌 MQTT: localhost:1883"
@echo "🗄️ MongoDB: localhost:27017"
dev-up: ## Start all services
docker compose -f deployments/docker-compose.yml \
-f deployments/docker-compose.dev.yml up -d
dev-down: ## Stop all services
docker compose -f deployments/docker-compose.yml \
-f deployments/docker-compose.dev.yml down
dev-logs: ## Show logs (use SERVICE=api to filter)
docker compose -f deployments/docker-compose.yml logs -f $(SERVICE)
dev-restart: ## Restart a specific service
docker compose -f deployments/docker-compose.yml restart $(SERVICE)
# ========== Backend ==========
api-run: ## Run Go API locally (without Docker)
cd backend && air
api-build: ## Build Go API binary
cd backend && go build -o bin/server ./cmd/server
api-test: ## Run Go tests
cd backend && go test ./... -v -cover
api-lint: ## Run Go linter
cd backend && golangci-lint run
# ========== Frontend Mobile ==========
mobile-dev: ## Start LynxJS mobile dev server
cd frontend-mobile && npm run dev
mobile-build: ## Build LynxJS mobile app
cd frontend-mobile && npm run build
mobile-test: ## Run mobile tests
cd frontend-mobile && npm test
# ========== Frontend Admin ==========
admin-dev: ## Start Vite admin dev server
cd frontend-admin && npm run dev
admin-build: ## Build Vite admin panel
cd frontend-admin && npm run build
admin-test: ## Run admin tests
cd frontend-admin && npm test
# ========== Database ==========
seed: ## Seed sample data
./scripts/seed-data.sh
db-reset: ## Reset databases (WARNING: deletes all data)
docker compose -f deployments/docker-compose.yml exec mongodb \
mongosh iot_workshop --eval "db.dropDatabase()"
docker compose -f deployments/docker-compose.yml exec influxdb \
influx -execute "DROP DATABASE iot_workshop"
$(MAKE) seed
# ========== Utilities ==========
clean: ## Clean build artifacts
cd backend && rm -rf bin/
cd frontend-admin && rm -rf dist/
cd frontend-mobile && rm -rf dist/
mqtt-sub: ## Subscribe to all MQTT topics (for debugging)
docker compose -f deployments/docker-compose.yml exec mosquitto \
mosquitto_sub -h localhost -t '#' -v
mqtt-pub-test: ## Publish test sensor data
docker compose -f deployments/docker-compose.yml exec mosquitto \
mosquitto_pub -h localhost \
-t 'devices/sensor-test-001/telemetry' \
-m '{"temperature":25.5,"humidity":60.2,"battery":85}'
ลองพิมพ์ make help แล้วจะเห็น menu สวยงามแบบนี้:
dev Start development environment
dev-up Start all services
dev-down Stop all services
dev-logs Show logs (use SERVICE=api to filter)
api-run Run Go API locally (without Docker)
api-test Run Go tests
seed Seed sample data
mqtt-pub-test Publish test sensor data
...
เปรียบเหมือนร้านอาหารที่มีเมนู ดีกว่าต้องไปถามพ่อครัวทุกครั้งว่า “วันนี้มีอะไรบ้าง” 555
Docker Compose — ทีมงาน 7 คน ทำงานพร้อมกัน
Docker Compose เปรียบเหมือน ผู้จัดการทีม ที่รู้ว่าต้องเรียก service ไหนก่อน-หลัง service ไหนต้องรอ service ไหน ใครต้องคุยกับใครผ่าน network อะไร
Main Compose File
# deployments/docker-compose.yml
version: '3.8'
services:
# ========== Backend API ==========
api:
build:
context: ../backend
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- APP_ENV=development
- APP_PORT=3000
- MONGO_URI=mongodb://mongodb:27017/iot_workshop
- INFLUX_URL=http://influxdb:8086
- INFLUX_DB=iot_workshop
- MQTT_BROKER=tcp://mosquitto:1883
- JWT_SECRET=workshop-dev-secret-change-in-prod
depends_on:
mongodb:
condition: service_healthy
mosquitto:
condition: service_started
influxdb:
condition: service_healthy
networks:
- iot-network
restart: unless-stopped
# ========== MongoDB ==========
mongodb:
image: mongo:7
ports:
- "27017:27017"
volumes:
- mongodb_data:/data/db
- ../scripts/init-mongo.js:/docker-entrypoint-initdb.d/init.js:ro
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
networks:
- iot-network
# ========== MQTT Broker ==========
mosquitto:
image: eclipse-mosquitto:2
ports:
- "1883:1883"
- "9001:9001"
volumes:
- ./mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf:ro
- mosquitto_data:/mosquitto/data
- mosquitto_log:/mosquitto/log
networks:
- iot-network
# ========== InfluxDB ==========
influxdb:
image: influxdb:1.8
ports:
- "8086:8086"
environment:
- INFLUXDB_DB=iot_workshop
- INFLUXDB_HTTP_AUTH_ENABLED=false
- INFLUXDB_REPORTING_DISABLED=true
volumes:
- influxdb_data:/var/lib/influxdb
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8086/ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- iot-network
# ========== Telegraf ==========
telegraf:
image: telegraf:1.30
volumes:
- ./telegraf/telegraf.conf:/etc/telegraf/telegraf.conf:ro
depends_on:
- mosquitto
- influxdb
networks:
- iot-network
# ========== Chronograf ==========
chronograf:
image: chronograf:1.10
ports:
- "8888:8888"
environment:
- INFLUXDB_URL=http://influxdb:8086
- KAPACITOR_URL=http://kapacitor:9092
volumes:
- chronograf_data:/var/lib/chronograf
depends_on:
- influxdb
- kapacitor
networks:
- iot-network
# ========== Kapacitor ==========
kapacitor:
image: kapacitor:1.7
ports:
- "9092:9092"
environment:
- KAPACITOR_HOSTNAME=kapacitor
- KAPACITOR_INFLUXDB_0_URLS_0=http://influxdb:8086
volumes:
- ./kapacitor/kapacitor.conf:/etc/kapacitor/kapacitor.conf:ro
- kapacitor_data:/var/lib/kapacitor
depends_on:
- influxdb
networks:
- iot-network
volumes:
mongodb_data:
mosquitto_data:
mosquitto_log:
influxdb_data:
chronograf_data:
kapacitor_data:
networks:
iot-network:
driver: bridge
สังเกตว่าเราใช้ depends_on + condition: service_healthy — นี่คือการบอกว่า “API จะเริ่มได้ก็ต่อเมื่อ MongoDB พร้อมแล้วจริงๆ นะ ไม่ใช่แค่ container ขึ้นมา” เหมือนบอกน้องใหม่ว่า “รอ senior deploy เสร็จก่อนนะ ค่อยเริ่มทำงาน”
Development Overrides
# deployments/docker-compose.dev.yml
version: '3.8'
services:
api:
build:
target: development
volumes:
- ../backend:/app
command: air -c .air.toml
environment:
- APP_ENV=development
- APP_DEBUG=true
frontend-admin:
build:
context: ../frontend-admin
target: development
ports:
- "5173:5173"
volumes:
- ../frontend-admin:/app
- /app/node_modules
command: npm run dev -- --host 0.0.0.0
networks:
- iot-network
Dev override file นี้สำคัญมาก มันทำให้ air (Go hot reload) ทำงานได้ และ mount source code เข้า container ตรงๆ — แก้ code ปุ๊บ reload ปั๊บ ไม่ต้อง rebuild image ทุกครั้ง
Service Configurations — ตั้งค่าให้แต่ละ service คุยกันได้
Mosquitto MQTT Broker
MQTT Broker เปรียบเหมือน ไปรษณีย์กลาง — sensor ส่ง message มา broker รับ แล้ว forward ไปให้ subscriber ทุกคนที่สนใจ topic นั้น
# deployments/mosquitto/mosquitto.conf
listener 1883
protocol mqtt
listener 9001
protocol websockets
allow_anonymous true
persistence true
persistence_location /mosquitto/data/
log_dest stdout
log_type all
connection_messages true
Port 1883 ใช้สำหรับ native MQTT ส่วน port 9001 ใช้ WebSocket เพราะ browser ไม่สามารถ connect MQTT ตรงๆ ได้ ต้องผ่าน WebSocket ก่อน
Telegraf — ตัวรับ-ส่งข้อมูล
Telegraf คือ พนักงานสายพาน ที่คอยหยิบ message จาก MQTT แล้วแปลง JSON ไปเก็บใน InfluxDB ในรูปแบบ time-series ที่ query ได้ง่าย:
# deployments/telegraf/telegraf.conf
[global_tags]
environment = "development"
[agent]
interval = "10s"
round_interval = true
flush_interval = "10s"
flush_jitter = "0s"
# ========== Input: MQTT Consumer ==========
[[inputs.mqtt_consumer]]
servers = ["tcp://mosquitto:1883"]
topics = [
"devices/+/telemetry"
]
qos = 1
data_format = "json"
topic_tag = "topic"
# Extract device_id from topic
[[inputs.mqtt_consumer.topic_parsing]]
topic = "devices/+/telemetry"
measurement = "measurement/_/measurement"
tags = "_/device_id/_"
[inputs.mqtt_consumer.json_v2]
measurement_name = "sensor_data"
[[inputs.mqtt_consumer.json_v2.field]]
path = "temperature"
type = "float"
[[inputs.mqtt_consumer.json_v2.field]]
path = "humidity"
type = "float"
[[inputs.mqtt_consumer.json_v2.field]]
path = "pressure"
type = "float"
[[inputs.mqtt_consumer.json_v2.field]]
path = "battery"
type = "int"
# ========== Output: InfluxDB ==========
[[outputs.influxdb]]
urls = ["http://influxdb:8086"]
database = "iot_workshop"
retention_policy = "raw"
write_consistency = "any"
timeout = "5s"
ส่วน topic_parsing เจ๋งมาก มันดึง device_id ออกจาก topic path devices/{device_id}/telemetry โดยอัตโนมัติ แล้วเก็บเป็น tag ใน InfluxDB ทำให้ query per device ได้ง่ายมาก
Kapacitor — นาฬิกาปลุก Alert
# deployments/kapacitor/kapacitor.conf
hostname = "kapacitor"
data_dir = "/var/lib/kapacitor"
[http]
bind-address = ":9092"
[[influxdb]]
enabled = true
name = "default"
default = true
urls = ["http://influxdb:8086"]
[smtp]
enabled = false
[[httppost]]
endpoint = "api-webhook"
url = "http://api:3000/api/v1/alerts/webhook"
headers = { "Content-Type" = "application/json" }
Kapacitor เชื่อม webhook กลับมาที่ API ของเรา — เมื่อ temperature สูงเกิน threshold มันจะ POST ไปที่ /api/v1/alerts/webhook แล้ว API จะส่ง notification ต่อให้ user ผ่าน WebSocket
Environment Variables
# .env.example (root level)
# ========== App ==========
APP_ENV=development
APP_PORT=3000
APP_DEBUG=true
# ========== MongoDB ==========
MONGO_URI=mongodb://localhost:27017/iot_workshop
# ========== InfluxDB ==========
INFLUX_URL=http://localhost:8086
INFLUX_DB=iot_workshop
# ========== MQTT ==========
MQTT_BROKER=tcp://localhost:1883
MQTT_CLIENT_ID=iot-workshop-api
MQTT_QOS=1
# ========== JWT ==========
JWT_SECRET=your-secret-key-change-in-production
JWT_EXPIRY=24h
JWT_REFRESH_EXPIRY=168h
# ========== Frontend ==========
VITE_API_URL=http://localhost:3000
VITE_WS_URL=ws://localhost:3000/ws
VITE_CHRONOGRAF_URL=http://localhost:8888
อย่าลืม copy .env.example ไปเป็น .env ก่อน run — script setup ด้านล่างจะทำให้อัตโนมัติ แต่ถ้าทำเองก็แค่ cp .env.example .env
Git Branching Strategy — ถนนของ workshop
พี่โชว์ออกแบบ branch structure ให้ workshop ไหลเป็นเส้นตรง น้องๆ สามารถ checkout ทีละ step แล้วดู diff ระหว่าง step ได้เลย เหมือน ถนนที่มี milestone ชัดเจน:
main
├── workshop/plan-01-architecture # Planning: System Architecture
├── workshop/plan-02-database-design # Planning: Database Design
├── workshop/plan-03-project-setup # Planning: Project Setup <-- เราอยู่ตรงนี้
├── workshop/dev-01-fiber-bootstrap # Backend: Go Fiber Setup
├── workshop/dev-02-mongodb-models # Backend: MongoDB Models
├── workshop/dev-03-device-api # Backend: Device API
├── workshop/dev-04-sensor-ingestion # Backend: Sensor Ingestion
├── workshop/dev-05-mqtt-broker # Backend: MQTT Integration
├── workshop/dev-06-websocket # Backend: WebSocket
├── workshop/dev-07-tick-setup # TICK: Stack Setup
├── workshop/dev-08-telegraf-pipeline # TICK: Telegraf Pipeline
├── workshop/dev-09-alerting # TICK: Kapacitor Alerting
├── workshop/dev-10-lynxjs-setup # Mobile: LynxJS Setup
├── workshop/dev-11-lynxjs-dashboard # Mobile: Dashboard
├── workshop/dev-12-lynxjs-control # Mobile: Device Control
├── workshop/dev-13-lynxjs-charts # Mobile: Charts
├── workshop/dev-14-lynxjs-alerts # Mobile: Notifications
├── workshop/dev-15-vite-setup # Admin: Vite Setup
├── workshop/dev-16-admin-crud # Admin: CRUD
├── workshop/dev-17-admin-monitoring # Admin: Monitoring
└── workshop/dev-18-admin-auth # Admin: Auth & RBAC
Workshop Flow สำหรับน้องๆ
- Clone repository
- Checkout branch ของแต่ละ content ตามลำดับ
- เขียน code ตาม tutorial
- Compare กับ solution ใน branch
- Merge เข้า main เมื่อเสร็จแต่ละ step
# เริ่มต้น
git clone https://github.com/kangana1024/iot-workshop.git
cd iot-workshop
# ดู branch ทั้งหมด
git branch -a
# เริ่ม Workshop Step 1
git checkout workshop/dev-01-fiber-bootstrap
# ดู diff ระหว่าง steps — เจ๋งมาก ดูได้เลยว่า step นี้เพิ่มอะไรบ้าง
git diff workshop/dev-01-fiber-bootstrap..workshop/dev-02-mongodb-models
One-Click Setup Script
สิ่งที่เราชอบมากในฐานะ developer — script ที่ทำให้ทุกอย่าง setup ได้ด้วยคำสั่งเดียว เหมือน สูตรอาหารสำเร็จรูป แค่กด start รอนิดนึง ทุกอย่างพร้อม!
#!/bin/bash
# scripts/setup.sh - One-click development environment setup
set -e
echo "🚀 Setting up IoT Workshop Development Environment..."
echo ""
# Check prerequisites
echo "📋 Checking prerequisites..."
command -v docker >/dev/null 2>&1 || { echo "❌ Docker is required. Install: https://docs.docker.com/get-docker/"; exit 1; }
command -v docker compose >/dev/null 2>&1 || { echo "❌ Docker Compose v2 is required."; exit 1; }
command -v go >/dev/null 2>&1 || { echo "⚠️ Go is optional for local development (Docker handles it)."; }
command -v node >/dev/null 2>&1 || { echo "⚠️ Node.js is optional for local development (Docker handles it)."; }
echo "✅ Prerequisites OK"
echo ""
# Copy environment file
if [ ! -f .env ]; then
echo "📝 Creating .env from template..."
cp .env.example .env
echo "✅ .env created"
fi
# Start services
echo "🐳 Starting Docker services..."
make dev-up
echo ""
# Wait for services
echo "⏳ Waiting for services to be healthy..."
sleep 10
# Seed data
echo "🌱 Seeding sample data..."
make seed
echo ""
# Summary
echo ""
echo "╔══════════════════════════════════════════════════╗"
echo "║ 🎉 IoT Workshop Environment Ready! ║"
echo "╠══════════════════════════════════════════════════╣"
echo "║ ║"
echo "║ 📡 API Server: http://localhost:3000 ║"
echo "║ 📊 Chronograf: http://localhost:8888 ║"
echo "║ 🔌 MQTT Broker: localhost:1883 ║"
echo "║ 🗄️ MongoDB: localhost:27017 ║"
echo "║ 📈 InfluxDB: localhost:8086 ║"
echo "║ ║"
echo "║ Run 'make help' to see all available commands ║"
echo "╚══════════════════════════════════════════════════╝"
Script นี้ฉลาดตรงที่ check ก่อนว่า .env มีอยู่แล้วหรือเปล่า ถ้ายังไม่มีค่อย copy มา — ไม่ทับ config ที่น้องๆ แก้ไปแล้ว
CI/CD Pipeline — GitHub Actions ยามเฝ้าค่ายอัตโนมัติ
CI/CD คือ ยามเฝ้าค่าย ที่ทำงาน 24/7 ทุกครั้งที่ push code มา มันจะ run test อัตโนมัติ ถ้า test fail ก็จะ block merge ทันที ไม่มีใครแอบ push code พัง production ได้:
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, 'workshop/**']
pull_request:
branches: [main]
jobs:
backend-test:
runs-on: ubuntu-latest
services:
mongodb:
image: mongo:7
ports: ['27017:27017']
mosquitto:
image: eclipse-mosquitto:2
ports: ['1883:1883']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.22'
- name: Run tests
working-directory: backend
run: go test ./... -v -cover -race
admin-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install & Build
working-directory: frontend-admin
run: |
npm ci
npm run build
npm test
สังเกตว่า GitHub Actions สามารถ spin up MongoDB และ Mosquitto เป็น service ได้เลยระหว่าง test — ไม่ต้อง mock database จริงๆ test coverage ก็ดีขึ้นด้วย
สรุปสิ่งที่เราทำในบทนี้
น้องๆ เก่งมากที่อ่านมาถึงตรงนี้! (ノ◕ヮ◕)ノ*:・゚✧
ในบทนี้เราได้วางรากฐาน dev environment ครบ:
| สิ่งที่ทำ | ประโยชน์ |
|---|---|
| Monorepo Structure | code ทุกส่วนอยู่ที่เดียว ง่ายต่อการ cross-reference |
| Docker Compose 7 services | ทุกคน environment เดียวกัน 100% |
| Makefile | command กลางที่ทุกคนใช้ได้โดยไม่ต้องจำ |
| Service Configs | Mosquitto, Telegraf, Kapacitor คุยกันได้ตั้งแต่แรก |
| Git Branching Strategy | workshop flow ชัดเจน เรียนทีละ step |
| CI/CD Pipeline | GitHub Actions test อัตโนมัติทุก push |
Next Step — เริ่ม Phase 2: Development!
Phase 1: Planning เสร็จแล้ว! เราวางแผนครบทั้ง Architecture, Database Design และ Project Setup
ตอนนี้ถึงเวลาลงมือ code จริงๆ แล้ว! บทต่อไปเราจะ bootstrap Go Fiber API ตั้งแต่ศูนย์ มี middleware, health check, router structure ครบถ้วน มาลุยกัน!
Navigation:
- Prev: #2 Database Design
- Next: #4 Go Fiber Bootstrap — Phase 2 เริ่มแล้ว!