Master Plan: สร้าง IoT Platform ครบวงจร 18 step + E2E
เคยมั้ยที่อยากสร้าง IoT system เองตั้งแต่ต้นจนจบ แต่ไม่รู้จะเริ่มจากตรงไหน? เรามาแก้ปัญหานั้นด้วยกันเลยดีกว่า workshop นี้เราจะสร้าง IoT Platform จริงๆ ครบทุก layer ตั้งแต่ sensor ส่งข้อมูลขึ้นมา ผ่าน MQTT ไปจนถึง mobile app และ admin panel — ใช่ ครบจริงๆ ไม่ใช่แค่ hello world นะ ^^ และทั้งหมดเป็น โค้ดที่รันได้จริง ที่อยู่ใน repo เดียวกัน
Repo: github.com/kangana1024/showkhun-workshop โครงสร้าง branch: ทุก step มี branch ของตัวเอง (
step-01-...ถึงstep-18-...) และstep-19-e2eคือ branch ที่รวมทุกอย่างไว้ครบ (รวม Playwright E2E test ของ admin)
สิ่งที่น้องๆ จะได้จาก Workshop นี้
ก่อนจะลุยกัน ขอ spoil ก่อนว่าพอจบ workshop นี้น้องๆ จะทำอะไรได้บ้าง:
- ออกแบบ IoT architecture แบบ event-driven ได้อย่างมั่นใจ รู้ว่า service ไหนคุยกับใคร ผ่านอะไร
- เขียน Go + Fiber backend รับ sensor data ผ่านทั้ง REST และ MQTT (ingestion path เดียวกัน)
- เก็บ device registry/users ใน MongoDB 8 และเก็บ time-series ใน InfluxDB 2.7 อ่านกลับด้วย Flux
- ต่อ pipeline แบบ config ล้วนด้วย Telegraf (MQTT → InfluxDB)
- เขียน alerting engine เป็น Go เอง (threshold / offline / anomaly) — ไม่พึ่ง Kapacitor
- สร้าง mobile app ด้วย LynxJS ดู real-time dashboard บนมือถือได้เลย
- สร้าง admin panel ด้วย Vite + React + TypeScript จัดการ device/user/alert ทั้งหมด
- ใส่ Authentication + RBAC ด้วย JWT (argon2id + HS256) บังคับสิทธิ์ที่ฝั่ง server
- Run infra ทั้งหมดด้วย Docker Compose คำสั่งเดียวขึ้นหมด (
make up)
Tech Stack ที่เราจะใช้ (ของจริง pin version หมด)
ลองนึกภาพ IoT system เหมือน “ระบบไปรษณีย์อัจฉริยะ” นะ:
- อุปกรณ์ IoT = คนส่งจดหมาย (sensor ส่งข้อมูล)
- MQTT Broker (Mosquitto) = ที่ทำการไปรษณีย์ (รับและกระจายข้อความ)
- Go + Fiber Backend = ผู้จัดการไปรษณีย์ (validate, เก็บ, ส่งต่อ, alert)
- MongoDB + InfluxDB = คลังเก็บจดหมาย (ต่างประเภทเก็บต่างที่)
- LynxJS Mobile = แอปติดตามพัสดุ (ดู status real-time)
- Vite + React Admin = dashboard ของ supervisor (ควบคุมทั้งระบบ)
| Layer | Technology | เวอร์ชัน | หน้าที่ |
|---|---|---|---|
| Backend API | Go + Fiber | Go 1.26 / Fiber v2.52 | REST API, WebSocket hub, MQTT handler |
| Registry DB | MongoDB | mongo:8.0.16 |
Device registry, users, groups, alert rules/history |
| Time-Series | InfluxDB 2.7 + Flux | influxdb:2.7.12 |
เก็บ sensor telemetry, query ด้วย Flux |
| Ingestion agent | Telegraf | telegraf:1.39.0 |
MQTT consumer (json_v2) → InfluxDB |
| Message Broker | Mosquitto (MQTT) | eclipse-mosquitto:2.0.22 |
Device ↔ cloud (pub/sub) |
| Alerting | Go engine (ในตัว backend) | — | threshold / offline / anomaly + webhook |
| Mobile App | LynxJS (Rspeedy) | — | Real-time dashboard + device control |
| Admin Panel | Vite + React + TypeScript | — | Device/user/alert management + monitoring |
| Auth | JWT (HS256) + argon2id | — | RBAC: admin / operator / viewer |
| Container | Docker + Docker Compose | — | Development infrastructure |
เกร็ดสำคัญ: เดิมแพลนวางไว้ว่าจะใช้ TICK Stack เต็มชุด (Telegraf + InfluxDB + Chronograf + Kapacitor) แต่พอลงมือทำจริง เราเลือก เขียน alerting engine เป็น Go เอง แทน Kapacitor และไม่ได้รัน Chronograf เป็น service — เพราะ engine ที่เขียนเองประเมินได้ทันที ตอน ingest, unit-test ได้ละเอียด, และจัดการ rule ผ่าน REST + MongoDB ได้เหมือน resource อื่น. infra จริงจึงมีแค่ 4 service: MongoDB, Mosquitto, InfluxDB, Telegraf
ทำไม InfluxDB 2.7 (ไม่ใช่ 1.8 หรือ 3)
- 2.7 มี UI / Org / Bucket / Token ในตัว provision ผ่าน
DOCKER_INFLUXDB_INIT_*ได้คำสั่งเดียว เหมาะกับการสอน และยังใช้ Flux ได้เต็มที่ - 1.8 เป็นยุค InfluxQL + retention policy + continuous query แบบเก่า — เราไม่ใช้แล้ว (workshop นี้ออกแบบรอบใหม่ทั้งหมดบน 2.7)
- 3.x rewrite ใหม่ (Apache Arrow/DataFusion), ตัด Flux ออก, ไม่มี Chronograf/Kapacitor — เหมาะ edge/production บางเคสมากกว่าการสอนพื้นฐาน
ภาพรวม Architecture ของทั้งระบบ
มาดูกันก่อนว่าข้อมูลจาก sensor มันเดินทางยังไง ตั้งแต่วัดอุณหภูมิจนถึงโชว์บนหน้าจอมือถือ — สังเกตว่า telemetry เข้ามาได้ 2 ทาง (REST และ MQTT) แล้ววิ่งผ่าน ingestion path เดียวกัน:
graph LR
A[🌡️ Sensors] -->|MQTT 1883| B[📡 Mosquitto]
A -->|REST 3000| C[🖥️ Go + Fiber]
B -->|subscribe| C
B -->|subscribe| T[🔁 Telegraf]
C -->|registry CRUD| M[(🍃 MongoDB 8)]
C -->|write sensor_data| I[(📈 InfluxDB 2.7)]
T -->|write telegraf_sensor_data| I
C -->|Flux query| I
C -->|WebSocket fan-out| F[📱 Mobile + 🖥️ Admin]
C -->|alert engine| W[🔔 Webhook]
ข้อมูลไหลแบบนี้แหละ — sensor ยิงขึ้นมาทาง MQTT หรือ REST แล้ว backend รับไป validate กับ registry (MongoDB), เขียน time-series ลง InfluxDB, fan-out ไป frontend แบบ real-time ผ่าน WebSocket และ run alert engine ไปพร้อมกัน ส่วน Telegraf ก็เป็น pipeline แบบ config ล้วนที่วิ่งคู่ขนาน เขียน measurement ของตัวเองแยกไว้ (กัน double-write) สวยงามมาก (งง) ฮ่าๆ แต่ไม่ต้องกังวล เราจะค่อยๆ build ทีละ step กัน
โครงสร้าง Monorepo (ของจริง)
showkhun-workshop/
├── backend/ # Go + Fiber API server
│ ├── cmd/server/ # main entry point + graceful shutdown
│ ├── internal/
│ │ ├── config/ # โหลด config จาก env ด้วย Viper
│ │ ├── logger/ # zap structured logger
│ │ ├── middleware/ # request logger
│ │ ├── health/ # /healthz (dependency checks) + /api/v1/ping
│ │ ├── database/ # MongoDB + InfluxDB connection/setup/query
│ │ ├── model/ # domain entities (Device, User, Group, Alert)
│ │ ├── validate/ # shared validator
│ │ ├── repository/ # interfaces + MongoDB impl (mongo/)
│ │ ├── service/ # business logic + alert engine + tests
│ │ ├── handler/ # thin HTTP handlers
│ │ ├── auth/ # JWT, argon2id, RBAC middleware
│ │ ├── httpx/ # JSON error/list envelope helpers
│ │ ├── ratelimit/ # per-device token-bucket rate limiter
│ │ ├── tsquery/ # bounded, parameterised Flux query builder
│ │ ├── notify/ # webhook notifier (Slack-compatible)
│ │ ├── mqtt/ # Paho client: telemetry sub + command pub
│ │ ├── ws/ # WebSocket hub (rooms, fan-out, heartbeat)
│ │ └── server/ # ประกอบ Fiber app + middleware + routes
│ ├── Dockerfile # multi-stage build → distroless
│ ├── .env.example
│ ├── go.mod
│ └── go.sum
├── frontend-mobile/ # LynxJS mobile app (Rspeedy)
│ └── src/
│ ├── screens/ # Dashboard, Devices, Alerts, Settings
│ ├── navigation/ # tab bar
│ ├── ui/ # Card, Button, Badge, Dialog ...
│ ├── api/ # client + realtime (WebSocket)
│ └── theme/
├── frontend-admin/ # Vite + React + TypeScript admin panel
│ └── src/
│ ├── pages/ # Login, Overview, Devices, AlertRules, ...
│ ├── features/ # devices, alertRules, monitoring, users
│ ├── components/ # DataTable, layout, ui
│ ├── api/ # client, endpoints, realtime, types
│ ├── stores/ # auth, toast, confirm
│ └── routes/ # router + ProtectedRoute
├── infra/ # Infrastructure (development)
│ ├── docker-compose.yml # MongoDB, Mosquitto, InfluxDB, Telegraf
│ ├── mosquitto/mosquitto.conf # broker config (anonymous, dev only)
│ ├── telegraf/telegraf.conf # MQTT consumer (json_v2) → InfluxDB 2.x
│ └── .env.example
├── e2e/ # Playwright E2E tests (admin)
│ ├── tests/admin.spec.ts
│ └── playwright.config.ts
├── Makefile # คำสั่งสำหรับงานที่ใช้บ่อย
├── .gitignore
└── README.md
เรื่องโครงสร้าง เราเลือก Monorepo เพราะ workshop นี้ต้องการให้น้องๆ เห็นภาพรวมทั้งหมดในที่เดียว เปิด editor ครั้งเดียวเห็นทุก service เลย — backend, mobile, admin, infra อยู่ครบ ไม่ต้อง clone หลาย repo
Roadmap: 18 Step + E2E (4 ช่วงงาน)
( •_•)
( •_•)>⌐■-■
(⌐■-■) ← เตรียมตัวลุยกันได้เลย!
ก่อนเริ่ม แอบบอกว่าโรดแมปนี้ map กับ branch จริงในรีโป — แต่ละ post จะอ้างถึง branch ของมัน (step-NN-...) และ branch step-19-e2e คือตัวรวมสุดท้ายที่มีทุกอย่างครบ
Phase 1: Planning (3 บท) — วางรากฐานให้แน่น
ก่อนจะเขียน code สักบรรทัด เราต้องออกแบบก่อน เหมือนสร้างบ้านต้องมีแปลนก่อนสร้าง ไม่งั้นสร้างไปก็รื้อทิ้งทีหลัง
| # | Post | เนื้อหา |
|---|---|---|
| 1 | System Architecture | event-driven architecture, data flow (ingest/command/query), communication patterns |
| 2 | Database & Data Model | MongoDB collections + InfluxDB 2.7 buckets/measurements |
| 3 | Project Setup & DevOps | monorepo, Docker Compose, Makefile, env, git strategy |
Phase 2: Backend — Go + Fiber + Data Layer + Alerting (9 step)
Backend ก็เหมือนครัวของร้านอาหาร ลูกค้า (frontend) ไม่เห็น แต่ถ้าครัวพัง ทุกอย่างพัง เราจะสร้างครัวที่แน่นมากๆ
| # | Branch | Post | เนื้อหา |
|---|---|---|---|
| 4 | step-01-fiber-bootstrap |
Go Fiber Bootstrap | project structure, middleware, Viper config, health check, graceful shutdown |
| 5 | step-02-mongodb-models |
MongoDB Models & Repository | domain models, repository pattern, BSON, indexes, pooling |
| 6 | step-03-device-api |
Device Management API | CRUD + bulk + filter/sort/pagination, ingestion token |
| 7 | step-04-sensor-ingestion |
Sensor Ingestion | REST ingest → InfluxDB, validate, registry tags, rate limit |
| 8 | step-05-mqtt-broker |
MQTT Integration | Paho client, topic structure, QoS, auto-reconnect, commands |
| 9 | step-06-websocket |
WebSocket Real-time | Fiber WS, hub pattern, rooms, fan-out, heartbeat |
| 10 | step-07-influx-setup |
InfluxDB 2.7 + Telegraf Setup | org/bucket/token, retention, downsample bucket |
| 11 | step-08-telegraf-pipeline |
Telegraf Pipeline + Flux | mqtt_consumer + json_v2 + processors → influxdb_v2, Flux read |
| 12 | step-09-alerting |
Go Alerting Engine | threshold/offline/anomaly, cooldown, history (TTL), webhook |
Phase 3: Mobile Frontend — LynxJS (5 step)
นี่คือส่วนที่น้องๆ จะโชว์คนอื่นได้ “เฮ้ ดูนี่สิ app IoT ที่ฉันสร้างเอง!” บน mobile จริงๆ เลย
| # | Branch | Post | เนื้อหา |
|---|---|---|---|
| 13 | step-10-lynxjs-setup |
LynxJS App Setup | tab navigation, base components, theme, API layer |
| 14 | step-11-lynxjs-dashboard |
Real-time Dashboard | live sensor cards, WebSocket manager, pull-to-refresh |
| 15 | step-12-lynxjs-control |
Device Control UI | device list, search/filter, command controls |
| 16 | step-13-lynxjs-charts |
Data Visualization | line chart, range selector, CSV export |
| 17 | step-14-lynxjs-alerts |
Notifications & Alerts | alert list, severity badges, notification preferences |
Phase 4: Admin Panel — Vite + React (4 step)
Admin panel คือ “ห้องควบคุม” ที่ผู้ดูแลระบบใช้ manage ทุกอย่าง ตั้งแต่ device ยันสิทธิ์การเข้าถึง
| # | Branch | Post | เนื้อหา |
|---|---|---|---|
| 18 | step-15-vite-setup |
Vite Admin Setup | Vite + React + TS, Tailwind, React Router, Zustand, Axios |
| 19 | step-16-admin-crud |
Admin CRUD | DataTable, React Hook Form + Zod, toast, confirm, bulk |
| 20 | step-17-admin-monitoring |
Monitoring Dashboard | overview cards, device status grid, alert overview, real-time |
| 21 | step-18-admin-auth |
Authentication & RBAC | JWT (Go + React), protected routes, admin/operator/viewer |
แล้ว
step-19-e2eล่ะ? เป็น branch สุดท้ายที่รวมทุก step เข้าด้วยกัน แล้วเพิ่ม Playwright E2E test ของ admin (login → overview → device CRUD → alert rule → monitoring) เพื่อ verify ว่าทั้งระบบทำงานต่อกันได้จริง ไม่ใช่แค่แยกชิ้นผ่าน — นี่คือ branch ที่เราใช้อ้างอิงโค้ดจริงในทุก post
Checklist ติดตามความคืบหน้า
Phase 1: Planning
- System Architecture Design
- Database & Data Model Design
- Project Setup & DevOps
Phase 2: Backend (Go + Fiber + Data + Alerting)
-
step-01Go Fiber Bootstrap -
step-02MongoDB Models & Repository -
step-03Device Management API -
step-04Sensor Data Ingestion -
step-05MQTT Integration -
step-06WebSocket Real-time -
step-07InfluxDB 2.7 + Telegraf Setup -
step-08Telegraf Pipeline + Flux Query -
step-09Go Alerting Engine
Phase 3: Mobile (LynxJS)
-
step-10LynxJS App Setup -
step-11Real-time Dashboard -
step-12Device Control UI -
step-13Data Visualization -
step-14Notifications & Alerts
Phase 4: Admin (Vite + React)
-
step-15Vite Admin Setup -
step-16Admin CRUD Operations -
step-17Monitoring Dashboard -
step-18Authentication & RBAC
Integration
-
step-19End-to-End (Playwright) — ทั้งระบบทำงานต่อกันได้จริง
พอร์ตที่ใช้ (ของจริง)
| Service | Port | หมายเหตุ |
|---|---|---|
| Backend API | 3000 |
REST + WebSocket ที่ /api/v1/ws |
| MongoDB | 27017 |
|
| Mosquitto (MQTT) | 1883 |
+ WebSocket ที่ 9001 |
| InfluxDB | 8086 |
UI + HTTP API |
⚠️ ค่า default ทั้งหมด (รหัสผ่าน Mongo/InfluxDB, InfluxDB token, anonymous MQTT) ตั้งไว้เพื่อความสะดวกใน local เท่านั้น ห้ามนำไป production และ API auth (JWT + RBAC) เปิดเป็น default — ต้องตั้ง
APP_AUTH_JWT_SECRET(อย่างน้อย 32 bytes) มิฉะนั้น backend จะไม่ยอม start
สรุปภาพรวม
Workshop นี้ครอบคลุม 18 step + E2E ใน monorepo เดียว พอเดินครบ น้องๆ จะมี IoT Platform ที่ทำงานได้จริง — รับ telemetry ได้ทั้ง REST/MQTT, เก็บ time-series ใน InfluxDB 2.7, แจ้งเตือนอัตโนมัติด้วย Go engine, มี mobile app ดู sensor real-time และ admin panel ที่ล็อกสิทธิ์ด้วย JWT/RBAC
สิ่งสำคัญที่สุดที่เราอยากให้น้องๆ เข้าใจจาก workshop นี้ไม่ใช่แค่ code แต่คือ วิธีคิดการออกแบบระบบ ว่า service ต่างๆ ควรแบ่งหน้าที่ยังไง ข้อมูลควรไหลผ่านตรงไหน และเลือก technology ตามโจทย์ ไม่ใช่ตาม trend (อย่างที่เราเลือกเขียน alert engine เองแทน Kapacitor นั่นแหละ)