Files
star-cloud/docs/architecture_plan.md
sky121113 8ee14eaa29
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 48s
[DOCS] 新增並更新 Phase 1 核心機台通訊 API 技術規範文件 (B010~B710)
2026-03-11 17:37:05 +08:00

628 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Star Cloud — 智能販賣機管理平台技術架構規劃
> **目標**:為上千至上萬台智能販賣機建構集中式管理後台,承接所有機台透過 API 回寫的資料,並提供完整的營運管理介面。
---
## 一、系統架構全景
```
┌──────────────────────────────────────────────┐
│ Star Cloud 管理後台 │
│ (Laravel 12 + Blade + Tailwind) │
│ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
│ │ 儀表板 │ │ 機台管理 │ │ 銷售分析 │ │
│ │ Dashboard │ │ Machines │ │ Analytics │ │
│ └──────────┘ └──────────┘ └───────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
│ │ 倉庫管理 │ │ 會員系統 │ │ 遠端操控 │ │
│ │Warehouses │ │ Members │ │ Remote │ │
│ └──────────┘ └──────────┘ └───────────┘ │
└──────────┬───────────────┬───────────────────┘
│ Web Routes │
│ (Blade SSR) │
┌──────────┴───────────────┴───────────────────┐
│ Laravel Application │
│ │
│ Controllers → Services → Models → MySQL │
│ │
└──────┬────────────────────┬──────────────────┘
│ │
┌──────────┴────┐ ┌───────┴───────┐
│ API Routes │ │ Redis Queue │
│ /api/v1/app │ │ (異步處理) │
└──────┬────────┘ └───────┬───────┘
│ │
┌──────┴────────┐ ┌───────┴───────┐
│ API Controller│──────►│ Jobs │
│ (驗證 + 分派) │ dispatch│ (Worker 執行) │
└───────────────┘ └───────┬───────┘
▲ │
┌────────────────┤ ▼
│ │ ┌──────────────┐
┌─────┴─────┐ ┌────┴─────┐ │ Services │
│ 販賣機 #1 │ │販賣機 #N │ │ (業務邏輯) │
│ B010 │ │ B600 │ └──────┬───────┘
│ B600 │ │ B602 │ │
│ B602 │ │ ... │ ▼
└────────────┘ └──────────┘ ┌──────────────┐
│ MySQL │
│ (持久化) │
└──────────────┘
```
---
## 二、技術棧確認
| 層級 | 技術 | 說明 |
|------|------|------|
| **後端框架** | PHP 8.5 / Laravel 12 | 單體架構Blade SSR |
| **資料庫** | MySQL 8.0 | 資料持久化 |
| **快取/隊列** | Redis | B010 心跳、B600 金流等高頻 API 必須異步 |
| **前端視圖** | Blade + Tailwind CSS + Preline UI | 極簡奢華風 |
| **前端互動** | Alpine.js | 輕量 DOM 互動 |
| **建置工具** | Vite | 前端資源編譯 |
| **開發環境** | Laravel Sail (Docker) | 本地開發 |
| **IoT 通訊** | Redis Queue + Jobs | 異步寫入,避免 API 直連 DB |
| **認證** | Laravel Sanctum | 後台用 SessionAPI 用 Token |
---
## 三、多租戶與權限架構 (Multi-Tenant RBAC)
為支援系統管理員(內部營運)與租戶(客戶公司及子帳號)的雙層管理模式,平台採用以下三層級權限隔離架構:
### 3.1 租戶隔離層 (Tenant Isolation)
* **核心機制**:導入 `companies` 資料表作為租戶實體,所有歸屬於客戶的資源(`users`, `machines` 等)均需綁定 `company_id`
* **身份判定**
* **系統管理員 (內部)**`company_id = null`,具備跨租戶檢視與管理機台、設定全局參數的最高權限。
* **客戶端帳號 (租戶)**`company_id` 有值,所有查詢(透過 Eloquent Global Scopes 或 Middleware自動注入 `where('company_id', $user->company_id)`,達成資料物理隔離。
### 3.2 角色與權限層 (Roles & Permissions)
* 採用 `spatie/laravel-permission` 套件並進行多租戶改造。
* **多租戶角色 (Tenant-Aware Roles)**:擴充 `roles` 表,加入 `company_id` 欄位。
* **系統預設角色** (`company_id = null`):如 Super Admin, System Support。
* **客戶自建角色** (`company_id = N`):如客戶建立的「分區維修員」、「會計」,確保客戶只能看見與分配屬於自己公司的角色給員工。
* **權限 (Permissions)**:定義系統最小操作單位(如 `machine.view`, `user.create`),供角色綁定。
### 3.3 流程控制與防禦 (Flow Control)
* **介面隔離**:依據身份動態隱藏/顯示系統級選單(例如「全站設定」、「合約管理」等多租戶不可見的功能)。
* **越權防禦**:客戶創建子帳號時,後端必定強制攔截並覆寫 `user->company_id = Auth::user()->company_id`,確保子帳號牢牢綁在自己的公司名下。同時限制其只能撈與分配自己公司名下的 Role。
---
## 四、資料庫完整設計
### 4.1 資料表總覽
分為 **6 大領域**,共 **28 張表**
```mermaid
graph LR
subgraph 系統管理
A1[users] --> A2[sessions]
A1 --> A3[personal_access_tokens]
A4[failed_jobs]
end
subgraph 機台領域
B1[machines] --> B2[machine_slots]
B1 --> B3[machine_logs]
B1 --> B4[coin_inventories]
B1 --> B5[timer_statuses]
B1 --> B6[remote_commands]
B1 --> B7[machine_heartbeats]
end
subgraph 商品領域
C1[products]
C2[product_categories]
end
subgraph 交易領域
D1[orders] --> D2[order_items]
D1 --> D3[invoices]
D1 --> D4[dispense_records]
D5[payment_types]
end
subgraph 會員領域
E1[members] --> E2[social_accounts]
E1 --> E3[member_wallets]
E3 --> E4[wallet_transactions]
E1 --> E5[member_points]
E5 --> E6[point_transactions]
E7[point_rules]
E8[deposit_bonus_rules]
E1 --> E9[membership_tiers]
E1 --> E10[member_memberships]
E1 --> E11[gift_definitions]
E1 --> E12[member_gifts]
end
subgraph APP設定
F1[app_configs]
end
```
### 4.2 需新增的資料表Migration 設計)
> 以下為 API 分析後推導出的缺失表,搭配各 API 欄位產生對應。
---
#### 👑 多租戶與權限基礎表 (RBAC & Tenant)
##### 🆕 `companies` — 租戶/客戶主表
所有客戶端的資料邊界,用來實現資料物理隔離。
| 欄位 | 類型 | 說明 |
|------|------|------|
| `id` | BIGINT PK | — |
| `name` | VARCHAR(255) | 公司/組織名稱 |
| `tax_id` | VARCHAR(20) NULL | 統一編號 |
| `contact_name` | VARCHAR(100) NULL | 聯絡人姓名 |
| `contact_phone` | VARCHAR(50) NULL | 聯絡電話 |
| `status` | TINYINT DEFAULT 1 | 狀態 (1:啟用, 0:停用) |
| `valid_until` | DATE NULL | 合約使用期限 |
| `timestamps` | — | — |
| `deleted_at` | TIMESTAMP NULL | 軟刪除 (SoftDeletes) |
##### 🟡 `users` 表 — 需擴充欄位
將 Laravel 預設的使用者表與租戶綁定。
| 新增欄位 | 類型 | 說明 |
|----------|------|------|
| `company_id` | BIGINT FK NULL | → `companies` (NULL 代表系統管理員) |
| `status` | TINYINT DEFAULT 1 | 帳號狀態 (1:啟用, 0:停用) |
##### 🟡 `roles` 表 (Spatie 權限擴充)
Spatie 預設的 roles 表必須加上多租戶設計,確保留戶只能管理自己的角色。
| 新增/調整欄位 | 類型 | 說明 |
|----------|------|------|
| `company_id` | BIGINT FK NULL | → `companies` (NULL 代表系統全域角色) |
| **UNIQUE** | `(name, guard_name, company_id)` | 原套件無 `company_id`,需修改為複合唯一鍵 |
---
#### 🟡 `machines` 表 — 需擴充欄位
現有 `machines` 表僅有基礎欄位,需為 B010 API 補充:
| 新增欄位 | 類型 | 說明 | 來源 API |
|----------|------|------|----------|
| `serial_no` | `VARCHAR UNIQUE` | 機台序號API 用此識別) | B010 `machine` |
| `model` | `VARCHAR` | 機台型號 | B010 `M_Stus` |
| `current_page` | `TINYINT` | 當前頁面狀態碼 | B010 `M_Stus2` |
| `door_status` | `VARCHAR` | 門禁狀態 | B010 `door` |
| `is_online` | `BOOLEAN` | 是否在線(心跳超時判斷) | 計算欄位 |
| `api_token` | `VARCHAR` | 機台專屬 API Token | 取代硬編碼 key |
---
#### 🆕 `products` — 商品資料
| 欄位 | 類型 | 說明 |
|------|------|------|
| `id` | BIGINT PK | — |
| `name` | VARCHAR(255) | 商品名稱 (預設語系) |
| `name_dictionary_key` | VARCHAR(100) NULL | 多語系字典鍵值 (對應 translations 表) |
| `sku` | VARCHAR(100) UNIQUE | 商品編號 |
| `price` | DECIMAL(10,2) | 售價 |
| `cost` | DECIMAL(10,2) NULL | 成本 |
| `category_id` | BIGINT FK NULL | → product_categories |
| `image` | VARCHAR NULL | 圖片 URL |
| `barcode` | VARCHAR NULL | 條碼 |
| `is_timer_product` | BOOLEAN | 是否為計時型商品 |
| `is_active` | BOOLEAN | 是否上架 |
| `timestamps` | — | — |
---
#### 🌐 多語系支援表 (i18n)
為了支援後台介面與 APP 端顯示的多語系內容(如商品名稱、分類名稱、系統提示),統一採用字典表架構。
##### 🆕 `translations` — 多語系字典表
| 欄位 | 類型 | 說明 |
|------|------|------|
| `id` | BIGINT PK | — |
| `group` | VARCHAR(50) | 分組 (例如: `product`, `category`, `system`) |
| `key` | VARCHAR(100) | 字典鍵值 (例如: `prod_name_001`) |
| `locale` | VARCHAR(10) | 語系代碼 (例如: `zh_TW`, `en_US`, `ja_JP`) |
| `value` | TEXT | 翻譯內容 |
| `timestamps` | — | — |
| **UNIQUE** | `(group, key, locale)` | 確保同一組鍵值在同一語系下唯一 |
> **多語系實作策略**
> 1. **靜態文案**:後台介面的靜態文字直接使用 Laravel 內建的 `lang/` 目錄 (JSON 或 PHP 陣列)。
> 2. **動態資料**:資料庫內容(如商品名稱 `products.name`)保留預設語系供後台快速搜尋。同時新增 `name_dictionary_key`。當對接外部 APP 或前台需要多語系時,透過 API 關聯 `translations` 表,回傳當前語系對應的 `value`。
---
#### 🆕 `machine_slots` — 機台貨道
| 欄位 | 類型 | 說明 | 來源 |
|------|------|------|------|
| `id` | BIGINT PK | — | — |
| `machine_id` | BIGINT FK | → machines | B017, B055, B710 |
| `slot_no` | VARCHAR(20) | 貨道編號 | B017 `tid`, B710 `cid` |
| `product_id` | BIGINT FK NULL | → products | B710 `pid` |
| `stock` | INT DEFAULT 0 | 當前庫存 | B017 `num` |
| `max_stock` | INT DEFAULT 0 | 最大容量 | — |
| `is_active` | BOOLEAN | 是否啟用 | — |
| `timestamps` | — | — | — |
| **UNIQUE** | `(machine_id, slot_no)` | 複合唯一鍵 | — |
---
#### 🆕 `orders` — 訂單主表
| 欄位 | 類型 | 說明 | 來源 |
|------|------|------|------|
| `id` | BIGINT PK | — | — |
| `flow_id` | VARCHAR UNIQUE | Cloud 金流 ID | B600 response |
| `order_no` | VARCHAR | APP 訂單號 | B600 `req9` |
| `machine_id` | BIGINT FK | → machines | B600 `req2` |
| `member_id` | BIGINT FK NULL | → members | B650 關聯 |
| `payment_type` | SMALLINT | 金流類型碼 | B600 `req3` |
| `total_amount` | DECIMAL(10,2) | 消費金額 | B600 `req7` |
| `change_amount` | DECIMAL(10,2) | 找零 | B600 `req13` |
| `points_used` | INT DEFAULT 0 | 使用點數 | B600 `req14` |
| `original_amount` | DECIMAL(10,2) NULL | 折扣前金額 | B602 `req15` |
| `payment_status` | TINYINT | 0:失敗/1:成功 | B600 `req12` |
| `payment_request` | TEXT NULL | 金流送出 data | B600 `req4` |
| `payment_response` | TEXT NULL | 金流回傳 data | B600 `req5` |
| `member_barcode` | VARCHAR NULL | 會員條碼 | B600 `req10` |
| `invoice_info` | VARCHAR NULL | 發票歸戶 | B600 `req8` |
| `machine_time` | DATETIME NULL | 機台時間 | B600 `req11` |
| `timestamps` | — | — | — |
| **INDEX** | `(machine_id, created_at)` | 查詢最佳化 | — |
| **INDEX** | `(payment_type)` | 金流類型篩選 | — |
---
#### 🆕 `order_items` — 訂單明細
| 欄位 | 類型 | 說明 | 來源 |
|------|------|------|------|
| `id` | BIGINT PK | — | — |
| `order_id` | BIGINT FK | → orders | — |
| `product_id` | BIGINT FK | → products | B600 `req16.pid` |
| `quantity` | INT | 數量 | B600 `req16.num` |
| `unit_price` | DECIMAL(10,2) | 單價 | B600 `req16.amount` |
| `subtotal` | DECIMAL(10,2) | 小計 | 計算 |
| `timestamps` | — | — | — |
---
#### 🆕 `invoices` — 發票紀錄
| 欄位 | 類型 | 說明 | 來源 |
|------|------|------|------|
| `id` | BIGINT PK | — | — |
| `order_id` | BIGINT FK | → ordersvia flow_id | — |
| `flow_id` | VARCHAR | 金流 ID | B601 `req3` |
| `machine_id` | BIGINT FK | → machines | B601 `req2` |
| `rtn_code` | VARCHAR NULL | 回傳碼 | B601 `req4` |
| `rtn_msg` | VARCHAR NULL | 回傳訊息 | B601 `req5` |
| `invoice_no` | VARCHAR NULL | 發票號碼 | B601 `req6` |
| `invoice_date` | DATE NULL | 發票日期 | B601 `req7` |
| `random_number` | VARCHAR NULL | 隨機碼 | B601 `req8` |
| `love_code` | VARCHAR NULL | 愛心碼 | B601 `req9` |
| `timestamps` | — | — | — |
---
#### 🆕 `dispense_records` — 出貨紀錄
| 欄位 | 類型 | 說明 | 來源 |
|------|------|------|------|
| `id` | BIGINT PK | — | — |
| `order_id` | BIGINT FK NULL | → orders | — |
| `flow_id` | VARCHAR NULL | 金流 ID | B602 `req3` |
| `machine_id` | BIGINT FK | → machines | B602 `req2` |
| `product_id` | VARCHAR | 商品 ID | B602 `req5` |
| `slot_no` | VARCHAR | 貨道編號 | B602 `req6` |
| `amount` | DECIMAL(10,2) | 消費金額 | B602 `req7` |
| `remaining_stock` | INT NULL | 剩餘庫存 | B602 `req9` |
| `dispense_status` | TINYINT | 0:成功/1:失敗 | B602 `req13` |
| `member_barcode` | VARCHAR NULL | 會員條碼 | B602 `req10` |
| `machine_time` | DATETIME NULL | 機台時間 | B602 `req11` |
| `points_used` | INT DEFAULT 0 | 使用點數 | B602 `req16` |
| `timestamps` | — | — | — |
---
#### 🆕 `remote_commands` — 遠端指令佇列
| 欄位 | 類型 | 說明 | 來源 |
|------|------|------|------|
| `id` | BIGINT PK | — | — |
| `machine_id` | BIGINT FK | → machines | — |
| `command_type` | VARCHAR(20) | 指令類型 | B010 response status |
| `status` | ENUM | pending/sent/success/failed | — |
| `payload` | JSON NULL | 指令附加資料 | — |
| `executed_at` | TIMESTAMP NULL | 執行時間 | — |
| `timestamps` | — | — | — |
> 對應 B010 遠端指令reboot, lock, unlock, checkout, dispense 等)以及 B055 遠端出貨。
---
#### 🆕 `coin_inventories` — 零錢機庫存
| 欄位 | 類型 | 說明 | 來源 |
|------|------|------|------|
| `id` | BIGINT PK | — | — |
| `machine_id` | BIGINT FK | → machines | B220 `machine` |
| `value_1` | INT DEFAULT 0 | 1 元 | B220 |
| `value_5` | INT DEFAULT 0 | 5 元 | B220 |
| `value_10` | INT DEFAULT 0 | 10 元 | B220 |
| `value_50` | INT DEFAULT 0 | 50 元 | B220 |
| `value_100` | INT DEFAULT 0 | 100 元 | B220 |
| `value_500` | INT DEFAULT 0 | 500 元 | B220 |
| `value_1000` | INT DEFAULT 0 | 1000 元 | B220 |
| `operator` | VARCHAR NULL | 操作人 (0=消費者) | B220 `account` |
| `timestamps` | — | — | — |
---
#### 🆕 `timer_statuses` — 計時器狀態
| 欄位 | 類型 | 說明 | 來源 |
|------|------|------|------|
| `id` | BIGINT PK | — | — |
| `machine_id` | BIGINT FK | → machines | B710 `req2` |
| `slot_no` | VARCHAR | 貨道 ID | B710 `cid` |
| `product_id` | BIGINT FK NULL | → products (0=未設定) | B710 `pid` |
| `status` | TINYINT | 0:未啟用/1:使用中/2:異常 | B710 `status` |
| `remaining_seconds` | INT | 剩餘秒數 | B710 `num` |
| `timestamps` | — | — | — |
---
#### 🆕 `payment_types` — 金流類型參照
| 欄位 | 類型 | 說明 |
|------|------|------|
| `id` | BIGINT PK | — |
| `code` | SMALLINT UNIQUE | 金流代碼 (1,2,3...120) |
| `name` | VARCHAR | 中文名稱 |
| `category` | VARCHAR | 大分類 |
| `is_active` | BOOLEAN | 是否啟用 |
| `timestamps` | — | — |
---
## 五、IoT API 路由設計
### 5.1 路由結構
```php
// routes/api.php
Route::prefix('v1/app')->middleware(['throttle:iot'])->group(function () {
// B010 - 機台狀態上傳 & 指令撈回
Route::post('/machine/status', [MachineStatusController::class, 'heartbeat']);
// B017 - 遠端撈庫存
Route::post('/machine/reload', [MachineStockController::class, 'reload']);
// B055 - 遠端出貨
Route::post('/machine/dispense', [DispenseController::class, 'getCommands']);
Route::put('/machine/dispense', [DispenseController::class, 'updateStatus']);
// B220 - 零錢機庫存
Route::post('/coin/inventory', [CoinInventoryController::class, 'store']);
// B600 - 消費金流
Route::post('/transaction', [TransactionController::class, 'store']);
// B601 - 發票回傳
Route::post('/invoice', [InvoiceController::class, 'store']);
// B602 - 出貨回傳
Route::post('/dispense-record', [DispenseRecordController::class, 'store']);
// B650 - 驗證會員
Route::post('/member/verify', [MemberVerifyController::class, 'verify']);
// B710 - 計時器狀態
Route::post('/timer/status', [TimerStatusController::class, 'sync']);
});
```
### 5.2 處理管線
> [!IMPORTANT]
> 遵循 IoT 通訊技能規範:**嚴禁** API Controller 直接寫入 DB。
| API | 處理方式 | 原因 |
|-----|----------|------|
| B010 | **異步** (Redis Queue) | 最高頻,每台數秒一次 |
| B017 | **同步** (直接回應) | 低頻,需即時回傳庫存數據 |
| B055 GET | **同步** | 需即時回傳指令列表 |
| B055 PUT | **異步** | 出貨結果可背景處理 |
| B220 | **異步** | 庫存變動日誌可背景寫入 |
| B600 | **異步** | 高頻交易,核心數據 |
| B601 | **異步** | 發票資訊可背景寫入 |
| B602 | **異步** | 出貨紀錄可背景寫入 |
| B650 | **同步** | 需即時回傳驗證結果與折抵金額 |
| B710 | **異步** | 計時器狀態批量更新 |
---
## 六、後台模組 ↔ 資料表對應
| 後台模組web.php | 對應資料表 | 資料來源 API |
|---------------------|-----------|-------------|
| 1. 儀表板 Dashboard | orders, machines, dispense_records | 統計彙整 |
| 2. 會員管理 Members | members, social_accounts, member_wallets... | B650 |
| 3. 機台管理 Machines | machines, machine_logs, machine_slots | B010, B017 |
| 4. APP 管理 App | app_configs, timer_statuses | B710 |
| 5. 倉庫管理 Warehouses | products, machine_slots | B017, B602 |
| 6. 銷售管理 Sales | orders, order_items, dispense_records | B600, B602 |
| 7. 分析管理 Analysis | orders, dispense_records, coin_inventories | 全部 |
| 8. 稽核管理 Audit | orders, dispense_records | B600, B602 |
| 9. 資料設定 DataConfig | products, payment_types, users | — |
| 10. 遠端管理 Remote | remote_commands | B010, B055 |
| 11. Line 管理 | members (Line 綁定) | — |
| 12. 預約系統 Reservation | (未來擴充) | — |
| 13. 特殊權限 SpecialPerm | machines, app_configs | — |
| 14. 權限設定 Permission | users, roles | — |
---
## 七、效能預估與應對
### 10,000 台機台的流量預估
| API | 頻率 | 每秒請求量 (QPS) | 每日資料量 |
|-----|------|-----------------|-----------|
| B010 心跳 | 每 5 秒/台 | **~2,000** | ~173M 筆 |
| B600 金流 | 每筆交易 | ~10-50 | ~50K-200K 筆 |
| B602 出貨 | 每筆交易 | ~10-50 | ~50K-200K 筆 |
| B710 計時器 | 每 10 秒/台 | ~1,000 | ~86M 筆 |
### 應對策略
| 策略 | 實作方式 |
|------|----------|
| **Redis Queue 異步寫入** | 所有高頻 API 進 QueueWorker 批量寫入 |
| **心跳資料瘦身** | B010 不逐筆寫 DB僅更新 `machines` 表的即時欄位 + 異常時寫 log |
| **資料分區** | `orders``dispense_records` 按月份分區 |
| **索引策略** | 所有查詢欄位建立適當 INDEXmachine_id + created_at 複合索引) |
| **速率限制** | 單台機台 60 req/min全站 100,000 req/min |
| **快取** | 機台列表、商品列表等低變動資料用 Redis Cache |
---
## 八、實作路線圖與預估時程
> **總結報告**:為確保開發品質與應對突發狀況,本專案預計總開發時程擴展為 **16 - 18 週**。以 1 人天 = 8 小時純開發時間計算,預估總投入約 **80 - 90 個工作天**。
### 🗓️ 專案開發甘特圖 (自動排除週末)
```mermaid
gantt
title Star Cloud 實作時程規劃
dateFormat YYYY-MM-DD
excludes weekends
section 第一階段 MVP
Phase 1 基礎設施與資料表 :active, p1, 2026-03-11, 14d
Phase 2 IoT API 與異步管線 :p2, after p1, 24d
Phase 3 後台 MVP 頁面整合 :p3, after p2, 18d
section 第二階段 進階
Phase 4 進階功能與報表分析 :p4, after p3, 30d
```
### 📅 詳細時程對照表
| 階段 (Phase) | 關鍵任務摘要 | 預估天數 | 預計工作日期 | 狀態 |
| :--- | :--- | :---: | :---: | :---: |
| **Phase 1** | 基礎架構、28張表設計、資料遷移基礎 | 14 工作天 | 03/11 ~ 03/30 | 準備啟動 |
| **Phase 2** | B010~B710 核心 API、Redis 異步 Job、Service | 24 工作天 | 03/31 ~ 05/01 | 規劃中 |
| **Phase 3** | 儀表板、機台/銷售/遠端管理 MVP 介面 | 18 工作天 | 05/04 ~ 05/27 | 規劃中 |
| **Phase 4** | 數據分析統計圖表、補貨演算法、自動對帳模組 | 30 工作天 | 05/28 ~ 07/08 | 規劃中 |
---
### 🔵 第一階段MVP 營運核心 (最優先上線)
**目標**:確保機台金流與指令能穩定連通,完成基礎營運管理功能。
#### Phase 1基礎設施與核心資料表 (預計: 14 工作天)
- [ ] 擴充 `machines`serial_no, model 等欄位)
- [ ] 建立 多租戶與權限基礎表 (`companies`, `spatie/laravel-permission` 相關表)
- [ ]`company_id` 欄位加入 `users`, `machines`, `roles` 等核心表
- [ ] 建立 `translations` 多語系字典表,並擴充 `products` 語系關聯
- [ ] 新增 `products` + `product_categories`
- [ ] 新增 `machine_slots`
- [ ] 新增 `orders` + `order_items`
- [ ] 新增 `invoices` + `dispense_records`
- [ ] 新增 `remote_commands` 表 (遠端管理與對接用)
- [ ] 新增 `payment_types` 表 + Seeder
#### Phase 2核心營運 IoT API 與異步管線 (預計: 24 工作天)
- [ ] 實作 **B010** API (心跳上報 + 狀態更新 + 遠端管理)
- [ ] 實作 **B017 / B055** API (遠端改庫存/出貨)
- [ ] 實作 **B600 / B601 / B602** API (金流/發票/出貨紀錄)
- [ ] 實作 **B650** API (會員驗證 + 點數折抵)
- [ ] 建立上述對應的 **Redis Queue Job + Service** 異步處理邏輯
#### Phase 3後台 MVP 頁面整合 (預計: 18 工作天)
- [ ] **多租戶權限與身份切換機制 (Middleware & Views)**
- [ ] 儀表板 Dashboard即時數據看板 (營收、機台數,依據租戶隔離資料)
- [ ] 機台管理 Machines連線狀態、貨道庫存、指令操作 UI
- [ ] 銷售管理 Sales訂單列表、出貨/發票追蹤
- [ ] 系統基礎設定:帳號與權限設定 (RBAC UI)、商品建檔、金流代碼設定、**多語系字典維護介面**
---
### 🟢 第二階段:進階營運與智慧分析 (持續優化)
**目標**:強化報表分析能力與自動化稽核。
#### Phase 4進階功能與報表分析模組 (預計: 30 工作天)
- [ ] **分析管理 Analysis**:趨勢圖、商品熱銷分析、機台產能報表
- [ ] **倉庫管理 Warehouses**:補貨建議、入/出庫流程優化
- [ ] **擴充支持**B220 (零錢機) + B710 (計時器) 支援
- [ ] **自動化稽核 Audit**:對帳機制、異常提醒
- [ ] **行銷模組**Line 聯動、預約系統、UI 動態設定
---
## 九、目錄結構建議
```
app/
├── Http/Controllers/
│ ├── Admin/ ← 後台管理(已存在 14 模組)
│ └── Api/V1/
│ ├── App/ ← 機台 IoT API新增
│ │ ├── MachineStatusController.php (B010)
│ │ ├── MachineStockController.php (B017)
│ │ ├── DispenseController.php (B055)
│ │ ├── CoinInventoryController.php (B220)
│ │ ├── TransactionController.php (B600)
│ │ ├── InvoiceController.php (B601)
│ │ ├── DispenseRecordController.php (B602)
│ │ ├── MemberVerifyController.php (B650)
│ │ └── TimerStatusController.php (B710)
│ ├── MemberController.php ← 會員 API已存在
│ └── MachineController.php ← 機台日誌(已存在)
├── Jobs/
│ └── Machine/ ← IoT 異步任務(新增)
│ ├── ProcessHeartbeat.php
│ ├── ProcessTransaction.php
│ ├── ProcessDispenseRecord.php
│ ├── ProcessInvoice.php
│ ├── ProcessCoinInventory.php
│ └── ProcessTimerStatus.php
├── Services/
│ └── Machine/ ← 業務邏輯(新增)
│ ├── HeartbeatService.php
│ ├── TransactionService.php
│ ├── DispenseService.php
│ └── MemberVerifyService.php
└── Models/
├── Machine/ ← 已存在
│ ├── Machine.php
│ └── MachineLog.php
├── Transaction/ ← 新增
│ ├── Order.php
│ ├── OrderItem.php
│ ├── Invoice.php
│ ├── DispenseRecord.php
│ └── PaymentType.php
├── Product/ ← 新增
│ ├── Product.php
│ └── ProductCategory.php
└── Member/ ← 已存在
```