架構決策 (ADR)
IoT Simulator 以 async task 在 FastAPI server-side 運行(非瀏覽器端)
Context
YiBi 需要一個 IoT Simulator Admin Console,讓工程師模擬硬體裝置(配對、放置 Token、控制播放)以便測試整個 MQTT 流程。 模擬裝置需要連接 EMQX Broker 發送 heartbeat、接收 command,並透過 Admin UI 即時查看 MQTT 訊息。
模擬裝置可以在三個地方運行:瀏覽器端(JavaScript MQTT 客戶端)、獨立 Go process(類似 simulator/)、或 FastAPI server-side async task。
Decision
結論:模擬裝置邏輯以 async task 在 FastAPI backend 內運行,透過 WebSocket 跟 Admin UI 溝通。
架構:Browser ↔ WebSocket ↔ FastAPI(SimulatorEngine)↔ MQTT Client ↔ EMQX
Alternatives Considered
- 瀏覽器端 JavaScript MQTT 客戶端(如 MQTT.js over WebSocket) — 考慮過。問題:EMQX Cloud 未設定 MQTT-over-WebSocket,需額外配置;瀏覽器端 MQTT client 難以複用現有 backend auth 和 role 控制;無法共用
mqtt_clientsingleton。 - 獨立 Go process(類似 simulator/ 目錄) — 考慮過。需要管理獨立 process 的生命週期,Admin UI 需要額外的 API 或 IPC 通訊,架構複雜度高。
Consequences
好:
- 直接複用現有
mqtt_clientsingleton,無需額外 MQTT 連線或 credentials - Auth 和 role 控制統一在 backend(WebSocket 連線時驗 JWT + DB user role)
- Admin UI 只需 WebSocket 連線,不需要直接連 MQTT broker
壞 / 代償:
- FastAPI 進程負擔增加(每個 simulator session 佔用 async task + MQTT subscription)
- Backend 重啟後所有 simulator session 消失(in-memory only,見 ADR-0004)
- Session 數量需要硬性上限(MAX_SESSIONS=10)防止資源耗盡
中性:
- 模擬裝置使用
SIM-前綴序號,與真實裝置區隔 - Device serial 格式驗證:
^SIM-[A-Za-z0-9]{1,32}$(防止 MQTT topic injection)