diff --git a/.agents/rules/framework.md b/.agents/rules/framework.md index af200ab..9d56e5f 100644 --- a/.agents/rules/framework.md +++ b/.agents/rules/framework.md @@ -4,193 +4,46 @@ trigger: always_on # 開發框架規範說明書:Cloud 後台管理系統 (star-cloud) -## 1. 專案概述 -* **目標**:打造一個強大且穩定的智能販賣機後台管理系統(Cloud 平台),負責管理機台、商品、銷售數據以及提供給端點機台串接的 API。 -* **核心架構**:採用 **Monorepo 單體式架構**,以 Laravel 為核心進行伺服器端渲染 (SSR) 與 API 服務,並搭配 **Go MQTT Gateway** 作為高併發 IoT 通訊的前置接收層。兩者透過 **Redis** 進行異步橋接,確保職責分離與系統穩定性。 -* **工作流程**:後端處理業務邏輯與資料庫存取,並透過 Blade 引擎渲染包含 Tailwind CSS 類別的 HTML。前端互動行為由輕量級 Alpine.js 負責,UI 元件以 Preline UI 為主體。 +## 1. 專案概述 & 技術棧 +* **目標**:智能販賣機後台管理系統,負責機台、商品、銷售數據與 IoT API。 +* **核心架構**:Monorepo 單體式架構。 + * **後端核心**:PHP 8.5 / Laravel 12, MySQL 8.0, Redis(快取與異步橋接)。 + * **IoT 通訊層**:EMQX 5 (MQTT Broker) + Go MQTT Gateway。 + * **前端視圖**:Laravel Blade (SSR) + Alpine.js (互動) + Tailwind CSS + Preline UI (組件)。 + * **開發環境**:Laravel Sail (Docker / WSL2) -## 2. 技術棧 (Tech Stack) +## 2. 系統架構與資料流向 -### 2.1 後端核心 (Laravel) -* **後端框架**:PHP 8.5 / Laravel 12 -* **核心組件**:Redis (用於高併發 IoT 隊列、MQTT 橋接與快取,為系統穩定之必要條件) -* **資料庫**:MySQL 8.0 -* **開發環境**:Laravel Sail (Docker / WSL2) +本系統採用 **MQTT 與 HTTP 雙軌並行** 策略: -### 2.2 IoT 通訊層 (MQTT Gateway) -* **MQTT Broker**:EMQX 5 (負責維持機台長連線與訊息路由) -* **Gateway 語言**:Go (負責訂閱 MQTT Topic、預處理訊息、轉發至 Redis) -* **橋接機制**:Redis List (`mqtt_incoming_jobs`),由 Laravel 常駐指令 (`mqtt:listen`) 消費 - -### 2.3 前端 -* **前端視圖 (View)**:Laravel Blade -* **前端互動 (JS)**:Alpine.js (專注於行為,不負責渲染) -* **介面與樣式 (CSS)**:Tailwind CSS + Preline UI (直接寫作於 Blade 模板中)。 - * **重要規範**:Preline UI 僅作為「原子組件」與「JS 互動邏輯」的參考庫。整體的「佈局」與「美學」必須嚴格遵守「極簡奢華風 UI 實作規範 (SKILL.md)」。 -* **前端建置工具**:Vite - -## 3. 目錄結構與慣例 - -### 3.1 後端 (Laravel) -與標準 Laravel 結構保持一致,無過度拆分的模組化(與 ERP 的 Modular Monolith 區別): -* **Controllers**:`app/Http/Controllers/`,負責接收請求並回傳 `view()` 或 JSON。 -* **Models**:`app/Models/{Domain}/`,按領域分群 (例如 `Machine`, `Member`, `System`)。 -* **Routes**:`routes/web.php` 用於後台管理介面;`routes/api.php` 提供外部或機台調用介面 (需 V1 版本化)。 -* **Services** (建議):`app/Services/{Domain}/`,將商業邏輯與資料異動封裝於 Service 中。 -* **Traits**:`app/Traits/ApiResponse.php` 用於統一 API JSON 回傳格式。 -* **Jobs**:`app/Jobs/{Domain}/`,用於異步處理 IoT 資料寫入、通知發送等背景任務。 -* **Console Commands**:`app/Console/Commands/`,包含 MQTT 橋接守護進程 (`mqtt:listen`) 等常駐指令。 - -### 3.2 前端 (Blade / Tailwind / Alpine) -* **Views (頁面)**:位於 `resources/views/`。通常依功能建立資料夾(如 `resources/views/admin/machines/index.blade.php`)。 -* **Layouts (版面)**:位於 `resources/views/layouts/`。定義全站的共用版面結構(如 header, sidebar, footer)。 -* **Components (組件)**:位於 `resources/views/components/`。封裝可重用的 Blade 元件(如 Button, Modal, Table),支援透過 `` 語法呼叫。 - -### 3.3 MQTT Gateway (Go) -Go 專案以 Monorepo 形式置於專案根目錄下的 `mqtt-gateway/` 資料夾,獨立於 Laravel 程式碼: -* **進入點**:`mqtt-gateway/main.go` -* **模組管理**:`mqtt-gateway/go.mod` / `go.sum` -* **內部分層**: - * `mqtt-gateway/internal/handler/` — 各 Topic 的訊息處理邏輯(如 heartbeat、transaction、error)。 - * `mqtt-gateway/internal/bridge/` — Redis 橋接層,負責將處理後的 JSON 推入 `mqtt_incoming_jobs` List。 - * `mqtt-gateway/config/` — 環境變數與 EMQX / Redis 連線設定。 - -> [!CAUTION] -> Go Gateway 的職責僅限於「接收、驗證、轉發」。**嚴禁**在 Go 中實作任何商業邏輯(如庫存扣減、通知發送),所有業務處理必須統一在 Laravel Service 層完成。 - -## 4. IoT 通訊架構 (MQTT + HTTP 雙軌制) - -本系統的機台通訊採用 **MQTT 與 HTTP 雙軌並行** 的策略,依據通訊特性選擇最適合的協議。 - -### 4.1 整體資料流向 - -``` +```text 機台 (Android APP) │ - ├─ [高頻/即時] MQTT 長連線 ──→ EMQX Broker ──→ Go Gateway ──→ Redis List ──→ Laravel mqtt:listen ──→ Job ──→ MySQL + ├─ [高頻/即時] MQTT ──→ EMQX Broker ──→ Go Gateway ──→ Redis List ──→ Laravel Job ──→ MySQL │ - └─ [低頻/大檔] HTTP REST ──→ Laravel API Controller ──→ (必要時) Job ──→ MySQL + └─ [低頻/大檔] HTTP REST ──→ Laravel API Controller ──→ MySQL ``` -### 4.2 MQTT 通訊端點 (高頻與事件驅動) -以下端點因高頻率或即時性需求,採用 MQTT 協議通訊: +* **Go Gateway 職責**:僅限「接收、驗證、轉發」。**嚴禁**在 Go 中實作商業邏輯,統一交由 Laravel Service/Job 處理。 +* **橋接機制**:Go 收到 MQTT 訊息後轉為 JSON,推入 Redis List,Laravel 透過常駐指令 (`mqtt:listen`) 消費並分派至對應的 Job 處理。 -| API 代碼 | Topic 格式 | 用途 | QoS | -| :--- | :--- | :--- | :--- | -| B010 | `machine/{serial_no}/heartbeat` | 心跳上報 (每 10 秒) | 0 | -| B013 | `machine/{serial_no}/error` | 故障與異常狀態上報 | 1 | -| B600 | `machine/{serial_no}/transaction` | 交易紀錄回傳 | 1 | +## 3. 核心目錄結構特徵 +除標準 Laravel 結構外,本專案的特殊慣例: +* **`mqtt-gateway/`**:Go 獨立專案目錄,負責 MQTT 訊息接收與轉發。 +* **`app/Jobs/`**:用於處理 Go 轉發過來的 IoT 非同步資料寫入與背景邏輯。 +* **`app/Console/Commands/`**:包含常駐守護進程 (如 `mqtt:listen`)。 +* **`resources/views/components/`**:全站共用的 Blade UI 元件(如 ``),支援 x- 前綴呼叫。 -**雲端→機台指令下發**:透過 `machine/{serial_no}/command` Topic 推送,取代原本 B010 Response 中的 `status` 欄位輪詢機制,實現毫秒級即時指令。 +## 4. 前端與 UI 開發規範 +* **樣式與組件**:全面使用 Tailwind CSS utility classes,遵循 Preline UI 的 HTML 結構進行開發。**避免撰寫自訂 CSS**。 +* **互動邏輯**:優先使用輕量級 **Alpine.js** (`x-data`, `x-show`, `@click`) 於 Blade 內完成,**禁用 React / Vue / Inertia.js**。 +* **【警告:Preline 冗餘】**:Preline 官方範例常有多餘控制項。必須確保介面佈局極簡,嚴格遵守「極簡奢華風 UI 實作規範 (SKILL.md)」。 +* **多語系 (I18n)**:所有 UI 可見文字必須使用 `@lang('key')` 或 `__('key')` 處理。Key 統一採用**英文原始詞彙**,並同步更新 `zh_TW.json`, `en.json`, `ja.json`。 -### 4.3 HTTP 通訊端點 (資料拉取與敏感操作) -以下端點因資料量大、安全性要求高或為 Request/Response 模式,維持使用 HTTP REST API: - -| API 代碼 | 用途 | 維持 HTTP 的原因 | -| :--- | :--- | :--- | -| B000 | 維運人員登入 | 無狀態認證,HTTP 更自然 | -| B012 | 商品配置同步 | 大量資料的 GET 拉取 | -| B014 | 金鑰與參數下載 | 高安全性敏感操作,需嚴格 RBAC | -| B009 | 貨道庫存回報 | 低頻操作,由維運人員觸發 | - -### 4.4 Redis 橋接機制 (Go ↔ Laravel) -Go Gateway 與 Laravel 之間透過 Redis List 進行單向異步橋接: - -* **Redis Key (邏輯名)**:`mqtt_incoming_jobs` -* **Redis Key (實際名)**:`starcloud_database_mqtt_incoming_jobs` (含 Laravel 前綴) -* **Go 端 (生產者)**:將 MQTT 收到的 Payload 包裝成標準 JSON 後,執行 `RPUSH starcloud_database_mqtt_incoming_jobs {json}`。Go 程式碼中透過 `"starcloud_database_" + cfg.IncomingQueueKey` 手動加入前綴。 -* **Laravel 端 (消費者)**:常駐指令 `php artisan mqtt:listen` 持續執行 `BLPOP mqtt_incoming_jobs`(Laravel Redis 驅動自動加上前綴),取得 JSON 後解碼並分派至對應的 Laravel Job (如 `ProcessHeartbeat`, `ProcessTransaction`)。 - -> [!CAUTION] -> **Redis 前綴一致性**:Laravel 的 Redis 驅動會自動在 Key 前加上 `config('database.redis.options.prefix')` (預設 `starcloud_database_`)。Go 端不使用 Laravel 的 Redis 客戶端,因此**必須在程式碼中手動加上此前綴**,否則雙方會操作不同的 Key,導致訊息永遠無法傳達。 - -**JSON 橋接格式規範**: -```json -{ - "type": "heartbeat", - "serial_no": "M-001", - "received_at": "2026-04-14T09:00:00+08:00", - "payload": { - "current_page": 1, - "firmware_version": "1.0.5", - "temperature": 25.5 - } -} -``` - -> [!IMPORTANT] -> **為何不讓 Go 直接寫入 Laravel Queue?** 因為 Laravel Queue 的 Payload 包含 PHP 序列化物件字串 (`serialize()`),Go 無法安全產生此格式。透過獨立的 Redis List + 純 JSON,可徹底解耦兩端的技術依賴。 - -### 4.5 MQTT 連線認證 -機台連線 EMQX 時,使用 `serial_no` 作為 Username、`api_token` (SHA256) 作為 Password。驗證流程: - -1. **Laravel 端 (Token 派發時)**:B014 下發 `api_token` 時,同步執行 `Redis::hset("machine_auth:{serial_no}", "password", hash('sha256', $api_token))`。 -2. **EMQX 端 (連線驗證時)**:配置 Redis Auth Plugin,使用 `HMGET machine_auth:${username} password` 查詢 Redis Hash 進行極速驗證 (毫秒級),不經過 MySQL。 -3. **Token 更新/撤銷時**:Laravel 更新或刪除機台 Token 時,必須同步更新或刪除 Redis 中的對應 Hash。 -4. **Go Gateway 認證**:Gateway 使用固定帳號 `star-cloud-gateway` 連線 EMQX,其認證資料同樣以 Hash 結構存放於 Redis (`machine_auth:star-cloud-gateway`)。 - -> [!CAUTION] -> **認證資料結構為 Redis Hash (HSET)**,非 String (SET)。EMQX 5.x 預設的 Redis 認證插件使用 `HMGET` 指令讀取,若誤用 `SET` 儲存為 String 類型,認證將永遠失敗。 -> 批量同步指令:`php artisan mqtt:sync-auth`。 - -## 5. 開發標準 (Coding Standards) -* **命名規範**: - * Controllers: `PascalCaseController.php` (例如 `MachineController.php`) - * Models: `PascalCase.php` (例如 `Machine.php`) - * Blade Views: `kebab-case.blade.php` 或按資源名稱 (例如 `index.blade.php`, `create.blade.php`) - * Routes uri: `kebab-case` (例如 `/machine-logs`) - * Go 檔案: `snake_case.go` (例如 `heartbeat_handler.go`) -* **回傳格式**: - * Web 路由:回傳 `view()`,表單驗證失敗時直接使用 Laravel 內建的 redirect with errors。 - * API 路由:回傳標準 JSON 格式的 `JsonResponse`。 - -## 6. UI 與前端開發指南 -* **樣式撰寫**:全面使用 Tailwind CSS utility classes,**避免撰寫自訂 CSS**(除非少數特定動畫或覆寫)。 -* **UI 元件庫**:遵循 **Preline UI** 的類別與 HTML 結構進行開發。 -* **前端腳本**: - * 優先使用 **Alpine.js** (`x-data`, `x-show`, `@click` 等) 在 HTML 標籤內完成簡單的 DOM 狀態切換與互動邏輯。 - * 避免在 Blade 內撰寫冗長的 `