🔥 Firebase 帳號總表與一鍵帶入
瀏覽所有在 Firebase 註冊的使用者帳號,勾選後即可直接「帶入/轉為管理者」並開通權限。
| 使用者 / Email | Firebase UID | 註冊時間 | 最後登入 | 管理者狀態 | 方案 / 設備 | 操作 | |
|---|---|---|---|---|---|---|---|
|
{{ user.displayName }}
{{ user.email }}
|
{{ user.uid }}
|
{{ formatLocalTime(user.creationTime) }} | {{ formatLocalTime(user.lastSignInTime) }} | ✅ 已是管理者 (ID: {{ user.partnerDetails.id }}) 👤 一般用戶 (未帶入) |
👑 Plan C (企業)
💎 Plan B (標準)
⚡ Plan A (入門)
🎁 免費試用
⏳ {{ user.partnerDetails.plan || '待定' }}
- 無方案 -
🔒 {{ user.lock_quantity || (user.partnerDetails ? user.partnerDetails.lock_quantity : 1) }} 設備
|
||
| 查無符合條件的 Firebase 帳號 | |||||||
AWS 網站與 API SSL 憑證管理
自動監控與檢測 AWS 伺服器各網域 SSL 憑證到期日、剩餘天數與 Certbot 自動續約狀態。
現有 AWS 網域 SSL 憑證清單
| 網域 (Domain) | 簽發單位 (Issuer) | 生效日期 | 到期日期 | 剩餘天數 | 狀態 | 自動續約機制 |
|---|---|---|---|---|---|---|
| 🔄 正在掃描與握手 AWS SSL 憑證資訊,請稍候... | ||||||
| 查無符合條件的 SSL 憑證紀錄。 | ||||||
|
🔒 {{ cert.domain }}
CN: {{ cert.subject }}
|
{{ cert.issuer }} | {{ cert.validFrom || '-' }} | {{ cert.validTo || '-' }} | {{ cert.daysRemaining }} 天 ⚠️ {{ cert.daysRemaining }} 天 ❌ 已過期 ({{ cert.daysRemaining }} 天) 未知 | 🟢 正常保護中 🟡 即將到期 🔴 無效 / 過期 ⚪ {{ cert.message || '異常' }} |
⚠️
{{ cert.autoRenewMethod }}
⚠️
智邦 FreeSSL (每90天需點擊續約)
🔗 前往智邦後台續約
✓
{{ cert.autoRenewMethod || "AWS Certbot 90天自動續約" }}
|
🔍 即時單一網域 SSL 憑證檢測工具
輸入任何網域(例如 example.com),系統將即時發起 HTTPS TLS 握手檢測其憑證狀態。
🛡️ AWS Certbot 自動更新與提醒機制
- 全自動續約 (Auto-Renew):AWS EC2 伺服器已佈署 Certbot systemd timer,每天將自動輪詢檢查。憑證剩餘 < 30 天時會自動向 Let's Encrypt 完成續約。
- Nginx 無感載入:證書更新成功後會自動觸發
systemctl reload nginx,無需重啟主機即可生效。 - 預防性警報提醒:配合 API Manager 系統的 LINE Notify 警報模組,可在 SSL 剩餘天數過低時自動推播警報通知團隊。
第三方程式串接 (API Key 管理)
配發 API Key 與 Secret 給旅館 PMS 系統,供其換取 JWT Token 以控制硬體。
| 項次 | 合作夥伴名稱 | 國別 | API Key | 訂閱方案 / 設備 | AI 智慧助理 | 狀態 | 建立時間 | 到期時間 | 一鍵同步 | 操作 |
|---|---|---|---|---|---|---|---|---|---|---|
| {{ (partnerPage - 1) * partnerPageSize + index + 1 }} |
{{ formatPartnerId(partner.id) }}
尚未綁定
|
{{ getCountryFlag(partner.country || '台灣') }} {{ partner.country || '台灣' }} |
👑 Plan C (企業)
💎 Plan B (標準)
⚡ Plan A (入門)
🎁 免費試用
⏳ {{ partner.plan || '待定' }}
🔒 {{ partner.lock_quantity !== undefined && partner.lock_quantity !== null ? partner.lock_quantity : (partner.plan === 'C' ? 999 : (partner.plan === 'B' ? 10 : 1)) }} 設備
|
已啟用
未啟用
Token: {{ (partner.ai_tokens_used || 0).toLocaleString() }} / {{ (partner.ai_token_quota || 50000).toLocaleString() }}
|
{{ partner.is_active && !isExpired(partner.expires_at) ? '啟用中' : '已過期/停用' }}
|
{{ getTargetSyncedDate(partner, 'cellbedell') || new Date(partner.created_at).toLocaleString('zh-TW', { year: 'numeric', month: 'numeric', day: 'numeric' }) }}
{{ getTargetSyncedDate(partner, 'vistor') || '--' }}
{{ getTargetSyncedDate(partner, 'meeting') || '--' }}
{{ getTargetSyncedDate(partner, 'member') || '--' }}
{{ getTargetSyncedDate(partner, 'pms') || '--' }}
|
{{ partner.expires_at ? new Date(partner.expires_at).toLocaleString('zh-TW', { year: 'numeric', month: 'numeric', day: 'numeric' }) : '--' }}
{{ partner.vistor_expires_at ? new Date(partner.vistor_expires_at).toLocaleString('zh-TW', { year: 'numeric', month: 'numeric', day: 'numeric' }) : '--' }}
--
--
--
|
|
|
👥 管理員帳號管理
新增、停用或管理系統管理員及員工的登入帳密與角色權限。
| ID | 帳號 (Username) | 顯示名稱 (Display Name) | 角色 (Role) | 狀態 | 建立時間 | 最後登入時間 | 操作 |
|---|---|---|---|---|---|---|---|
| {{ user.id }} | {{ user.username }} | {{ user.display_name || '-' }} | {{ user.role === 'super_admin' ? '超級管理員' : (user.role === 'admin' ? '管理者' : '一般員工') }} | {{ user.is_active === 1 ? '已啟用' : '已停用' }} | {{ formatLocalTime(user.created_at) }} | {{ formatLocalTime(user.last_login_at) }} |
|
| 目前沒有其他管理員帳號。 | |||||||
📋 操作稽核紀錄
完整記錄各個管理員與員工在控制台內執行的登入、編輯、更新、同步與系統參數修改行為。
| 時間 | 操作者 | 動作 (Action) | 操作目標 (Target) | 詳細內容 | 來源 IP |
|---|---|---|---|---|---|
| {{ formatLocalTime(log.created_at) }} | {{ log.username }} | {{ log.action }} | {{ maskApiKeys(log.target) || '-' }} |
{{ log.ip_address || '-' }} |
|
| 目前沒有操作稽核紀錄。 | |||||
📊 API 呼叫統計分析
即時監控合作夥伴與系統 API 呼叫的健全度、頻率與異常統計
{{ statsData.kpis?.totalCalls?.toLocaleString() || 0 }}
{{ statsData.kpis?.successRate || '0.00' }}%
{{ statsData.kpis?.errorCalls?.toLocaleString() || 0 }}
{{ statsData.kpis?.topEndpoint || 'N/A' }}
📈 呼叫量時序趨勢
呈現統計區間內的總調用次數與成功率波動🍩 響應狀態碼分佈
分析請求回傳 HTTP 狀態碼之健康分佈比例🔥 熱門 API 呼叫排行 (Top 5)
| 方法 | API 端點 | 調用次數 |
|---|---|---|
| {{ ep.method }} | {{ ep.endpoint }} | {{ ep.count.toLocaleString() }} 次 |
| 無調用數據 | ||
📅 數據明細列表
| 時間區間 | 總呼叫 | 成功 | 錯誤 | 成功率 |
|---|---|---|---|---|
| {{ row.label }} | {{ row.total.toLocaleString() }} | {{ row.success.toLocaleString() }} | {{ row.error.toLocaleString() }} | {{ row.total > 0 ? ((row.success / row.total) * 100).toFixed(2) : '0.00' }}% |
| 無調用數據 | ||||
| 時間 | 合作夥伴 | 方法 | 端點 | 狀態 | 操作 |
|---|---|---|---|---|---|
| {{ formatLogTime(log.called_at) }} | {{ log.partner_name }} | {{ log.method }} | {{ log.status_code }} | ||
| 無詳細呼叫日誌數據 | |||||
🌿 碳盤查儀表板
每一張虛擬票券,都是一張減少的塑膠卡片。追蹤累計的碳足跡節省量。
{{ (carbonStats.total_cards_replaced || 0).toLocaleString() }}
張{{ formatCarbonKg(carbonStats.total_carbon_saved_g) }}
{{ carbonStats.total_carbon_saved_g >= 1000 ? 'kg' : 'g' }}{{ (carbonStats.equivalent?.trees_planted_year || 0).toLocaleString() }}
棵(一年吸碳量){{ (carbonStats.equivalent?.km_not_driven || 0).toLocaleString() }}
公里🍩 Apple / Google 比例
虛擬票券類型分佈📈 每月節省趨勢
按月累計的虛擬票券與碳節省量🏆 廠商碳貢獻排行
| 名次 | 合作夥伴 | 虛擬票券數 | 節省 CO₂e |
|---|---|---|---|
| {{ idx === 0 ? '🥇' : idx === 1 ? '🥈' : idx === 2 ? '🥉' : '#' + (idx + 1) }} | {{ p.partner_name || '未知廠商' }} | {{ p.cards.toLocaleString() }} 張 | {{ formatCarbonG(p.carbon_g) }} |
| 尚無碳盤查記錄 | |||
📅 月度碳節省明細
| 月份 | 票券數 | 節省 CO₂e |
|---|---|---|
| {{ m.month }} | {{ m.cards.toLocaleString() }} | {{ formatCarbonG(m.carbon_g) }} |
| 尚無碳盤查記錄 | ||
參數設定
🔗 左右帳號一鍵自動綁定分析說明
詳細解析 Cell API Manager (左側後台) 與 Cellbedell 用戶前台 (右側 Firebase) 之間的安全綁定與一鍵同步機制。
🔗 左右系統一鍵自動帳號綁定技術白皮書
🛡️ 100% 既有系統相容與安全保障 (Backward Compatibility)
- 零破壞性更新:資料庫新增之
firebase_uid與user_email欄位皆為Nullable欄位,現有廠商資料庫結構不受影響,既有授權資料依然為空,完美相容。 - 既有 API Key 驗證無感:原先所有廠商配發的 API Key、手機 App 以及硬體設備的 API 呼叫均不受干擾,100% 保持原本功能運行。
- 優雅的斷網與無金鑰降級機制:若系統未於「參數管理」配置 Firebase 私鑰,一鍵同步按鈕點擊後將會彈出溫馨引導,絕對不會引發後端服務 crash 崩潰。
🏗️ 一鍵綁定即時資料流架構 (Realtime Data Flow)
下圖展示了管理員在左側管理系統點擊「⚡ 一鍵同步」時,API Key 在左側 Node.js 後端、Firebase 實時資料庫與右側前台系統之間的實時流向:
graph TD
A["PMS 管理後台
左側系統"] -->|1. 填入 Firebase UID| B("點擊 ⚡ 一鍵同步")
B -->|2. 發送安全 POST 請求| C["Node.js 後端伺服器"]
C -->|3. 讀取廠商 API Key
pk_xxxxxxxx| D["Firebase Admin SDK"]
D -->|4. 使用私鑰建立連線| E[("Firebase RTDB
雲端資料庫")]
E -->|5. 寫入路徑| F["UID/host_user_account
/api_token"]
F -->|6. 即時資料監聽| G["Cellbedell 費用前台
右側系統"]
G -->|7. 讀取 API Key 呼叫 API| H["完美呈現 🔗 左右資料綁定"]
style A fill:#e0f2fe,stroke:#0ea5e9,stroke-width:2px
style C fill:#f3e8ff,stroke:#a855f7,stroke-width:2px
style E fill:#fff1f2,stroke:#f43f5e,stroke-width:2px
style G fill:#f0fdf4,stroke:#22c55e,stroke-width:2px
⚙️ 核心技術機制與安全性 (Security & Core Design)
🔑 API Key 直接同步設計
一鍵同步會將廠商的 API Key (pk_xxxxxxxx) 直接寫入到 Firebase RTDB。前端取得此 API Key 後可直接用於呼叫後端 API,無需額外簽發或轉換,簡單直覺且永不過期(除非管理員手動停用)。
🔑 憑證安全隔離 (Private Key Isolation)
Firebase Admin SDK 私鑰安全地保存在 Cell API Manager 的後端設定檔 wallet_config.json 中,完全對前台以及瀏覽器端隔離。只有在管理員手動發起「⚡ 一鍵同步」時,後端才會使用此憑證透過安全通道寫入 Firebase,極高安全性。
💻 實時同步監聽代碼範例 (Client-side Integration Example)
右側 Cellbedell 網頁前台使用 Firebase Web SDK 監聽該 UID 的 host_user_account/api_token 節點。一旦左側管理後台點擊同步寫入,前台即可實時零延遲觸發監聽並完成綁定與 API Key 帶入:
// 1. 在 Vue / React 中動態訂閱 Firebase RTDB 中該登入用戶的 API Key 節點
const userUid = firebase.auth().currentUser.uid;
const tokenRef = firebase.database().ref(`${userUid}/host_user_account/api_token`);
tokenRef.on('value', async (snapshot) => {
const apiKey = snapshot.val();
if (apiKey) {
console.log("⚡ 偵測到一鍵綁定 API Key 變更:", apiKey);
// 2. 將 API Key 設定至本機儲存空間或狀態管理中
localStorage.setItem('api_key', apiKey);
// 3. 使用 API Key 呼叫左側後台 API,帶入廠商即時授權合約與剩餘天數!
try {
const profileResponse = await fetch('https://pms-api.cellbedell.com/api/partner/profile', {
headers: {
'X-API-Key': apiKey
}
});
const profileData = await profileResponse.json();
// 4. 即時更新畫面狀態!
this.partnerProfile = profileData;
this.isLinked = true;
this.showSuccessToast("🎉 帳號已自動同步綁定!已帶入您的真實授權合約。");
} catch (err) {
console.error("資料帶入失敗:", err);
}
} else {
// 未綁定時,優雅降級為本置 Mock 模擬數據模式
this.isLinked = false;
console.log("📌 尚未綁定帳號,啟用本地端模擬合約資料。");
}
});
API 串接測試文件 - PMS 發卡
提供給第三方廠商的發卡硬體控制標準介接說明。
PMS MQTT 橋接 API 文件
📌 串接前置說明 (Integration Guide)
範例:
https://您的主機網域.com
👉 以「取得存取權杖」為例,完整網址為:
https://您的主機網域.com/api/auth/token
- 取得金鑰: 請先於合作夥伴管理列表,由管理員建立並配發一組專屬的
API Key與API Secret。 - 換取 Token: 依照下方【第 1 步】,使用這組金鑰換取 1 小時效期的
Access Token。 - 發送指令: 依照下方【第 2 步】,在 Request Header 中帶入
Bearer <Token>即可成功傳遞硬體控制資料。
1. 取得存取權杖 (Get Access Token)
在呼叫任何硬體控制 API 之前,必須先使用您的
API Key 與 API Secret 換取 1 小時效期的 JWT Token。
Request Body (application/json)
{
"api_key": "pk_160035...",
"api_secret": "sk_9f1c8a..."
}
Response
{
"access_token": "eyJhbGciOiJIUzI1NiIsIn...",
"token_type": "Bearer",
"expires_in": 3600
}
2. 發送硬體指令 (Publish Command)
使用取得的 Token 來發送控制指令給指定硬體設備。
Headers
Authorization: Bearer <您的_ACCESS_TOKEN>
Content-Type: application/json
Request Body (application/json)
{
"data": "置入取得的虛擬金鑰Vkey"
}
Response (成功)
{
"status": "success"
}
系統架構說明
PMS MQTT 橋接系統的完整資料流與元件架構圖。
PMS MQTT 橋接系統架構
📋 架構總覽
本系統透過 AWS 雲端服務實現 雙向 MQTT 通訊,讓第三方 PMS 廠商能安全地控制旅館硬體設備(如門鎖、發卡機)。
系統包含 下行控制(雲端→設備)與 上行回報(設備→雲端)兩條資料流路徑。
🧩 系統元件說明
| 元件 | 技術 | 說明 |
|---|---|---|
| PMS_MQTT 前端 | Vue 3 + Firebase |
環境監控儀表板,提供即時數據顯示、MQTT 指令發佈、系統日誌 |
| Cell API Manager | Express + SQLite + JWT |
廠商金鑰管理、JWT 認證、API 文件入口 (本系統) |
| AWS API Gateway | HTTP API |
接收前端 HTTP POST 請求,觸發 Lambda 函數 |
| PublishToMQTT | Lambda (Node.js 24.x) |
將 HTTP 請求轉換為 MQTT 訊息,發佈至 AWS IoT Core |
| AWS IoT Core | MQTT Broker |
雲端 MQTT 中樞,負責訊息路由與設備通訊 |
| IoT-To-Firestore | Lambda (Node.js 20.x) |
接收設備 MQTT 回報,寫入 Firebase Firestore 供前端即時更新 |
| Firebase Firestore | NoSQL 即時資料庫 |
儲存設備狀態與歷史紀錄,透過 onSnapshot 推播即時更新 |
📊 資料流架構圖
app.js
POST JSON
us-east-1
觸發
PublishToMQTT
MQTT Publish
MQTT Broker
訂閱接收
門鎖/發卡機
狀態回報
MQTT Publish
MQTT Broker
Rule 觸發
IoT-To-Firestore
寫入
即時資料庫
onSnapshot
即時更新 UI
🖥️ 本地服務對照表
| 服務 | Port | 專案 | 說明 |
|---|---|---|---|
| API Manager | localhost:3000 |
PMS_API_Manager | 後端核心 — 廠商管理、JWT 認證、硬體指令轉發 |
| Swagger Docs | localhost:4000 |
PMS_API_Docs | 互動式 API 文件 — 供開發者線上試打 API |
| MQTT Dashboard | localhost:8080 |
PMS_MQTT | 環境監控前端 — 即時數據、指令發佈、日誌 |
🔐 安全認證機制
- 管理員在 合作夥伴管理 頁面建立廠商,系統自動配發
API Key+API Secret - API Secret 經 SHA-256 雜湊 後儲存,原始值僅在建立時顯示一次
- 第三方使用 Key + Secret 呼叫
/api/auth/token換取 JWT Token(效期 1 小時) - 後續所有硬體控制 API 需在 Header 攜帶
Bearer Token,由 verifyToken 中介軟體 驗證 - Token 過期或廠商授權到期,系統自動拒絕存取(
403 Forbidden)
API儲存與效能
針對第三方呼叫所規劃的混合式儲存與高吞吐、低延遲架構優化(AWS DynamoDB 方案 B)。
⚡ API 儲存與效能 (AWS DynamoDB 方案 B)
為確保第三方廠商呼叫 API 反應最快、不塞車,系統針對統計日誌與大數據吞吐量進行了 混合式儲存架構 (Hybrid Architecture) 優化,並已全面完成實作與部署:
🌐 1. 關係型與非關係型雙庫混合 (Hybrid Engine)
- 輕量關係數據(金鑰管理、廠商設定、認證狀態): 存放在 SQLite (本地端) 或 AWS RDS (生產端) 中,便於進行精準管理與複雜交易。
- 海量日誌數據(API 呼叫日誌、JSON Payload、分析指標): 儲存在高吞吐的 AWS DynamoDB,徹底移出 SQL 資料庫。
⚡ 2. 零延遲異步背景日誌寫入 (Fire-and-Forget Logging)
在全域日誌攔截器中,寫入 DynamoDB 採用異步非阻塞方式。廠商在呼叫 API 時會以毫秒級速度 立刻收到結果,日誌寫入隨後於背景默默完成,API 呼叫反應時間增加 0 毫秒。
📊 3. 預聚合原子統計 (Atomic Stats Engine)
後台分析採用預聚合統計表 pms_api_stats。每次呼叫完成,後端自動在背景對該日/月/年份的計數器累加 +1。當管理員查看圖表時,後端無須 Scan 掃描數百萬筆詳細日誌,而是 5ms 瞬間讀取預聚合計數,圖表渲染快如閃電,且完全不塞車!
🛡️ 4. 多重容錯與本地降級機制 (SQLite Fallback)
若因網路波動或 AWS 區域性異常導致無法寫入 DynamoDB 時,系統具備自動容錯機制,會 無縫降級 (Graceful Fallback) 改寫入本地 SQLite 暫存,確保任何情況下服務皆不中斷,並在網路恢復後自動同步。
🔒 5. 雙環境資料隔離與生產安全防呆 (Dual-Environment Isolation & Seeding Guard)
- 本機與雲端物理隔離: 本地開發環境 (
localhost:3000) 的所有測試數據與日誌皆獨立儲存於本機 SQLite,與 AWS 生產環境完全物理隔離,確保本地端 any 開發與測試 100% 不污染線上營運資料。 - 生產環境自動防呆保護: 系統具備主動路徑與特徵識別機制。當於 AWS 生產環境 (
/home/ubuntu/...) 啟動時,系統將 自動且永久停用歷史資料自動填充功能 (Mock Seeding Guard)。這確保了雲端資料庫在被管理員清空後,重開機也絕不會在線上重新生成測試用假資料,保證線上分析數據的 100% 真實與純淨。
⚙️ 6. 系統管理與廠商呼叫徹底分離統計 (Billing-Safe Metric Isolation)
為確保合作廠商的 計費呼叫數據純淨、不可抵賴與具備法律效力,系統建立了獨立的分流計量引擎:
- 系統與管理員呼叫分類: 所有針對
/api/admin/...等管理路徑的請求,日誌自動歸入partner_id = 'system'(系統管理員),從源頭上與合作廠商的 API 呼叫切離。 - 聚合統計完美排除: 全域預聚合引擎 (
pms_api_stats) 與 SQLite 查詢在統計'all'(所有呼叫) 時,會 自動過濾與剔除'system'的任何呼叫記錄。 - 視覺化計費安全警示: 統計分析界面全面配備毛玻璃計費標籤,即時揭示目前統計範圍是否作為計費基底(🛡️ 應計費廠商呼叫 vs ⚠️ 免計費系統管理呼叫),確保營運財務帳單的百分之百乾淨與透明。
金流與擴充架構
未來第三方金流整合與 API Manager 自動化授權架構規劃。
為何金流不該分拆為獨立伺服器?
在商業架構中,強烈建議將「金流串接」與現有的「API Manager」整併在同一個伺服器 (Node.js) 中運行。
由於 API Key 與過期時間 (Expiry Date) 的資料庫 都存放在此 API Manager 內,若將金流系統獨立為另一台伺服器,將會大幅增加兩台伺服器互相通訊失敗的風險(例如客戶已付款,但金流伺服器跨網域通知 API Manager 失敗,導致客戶權限未開通,產生客服爭議)。
🔄 自動化金流運作流程 (SaaS 訂閱模式)
- 廠商發起付款: 廠商登入本儀表板,點擊「續約 / 購買方案」,系統引導至第三方支付 (如 ECPay 綠界, Stripe, 藍新) 刷卡頁面。
- 背景接收回呼 (Webhook): 廠商付款成功後,第三方支付會在背景發送一筆「成功付款通知 (Webhook POST)」給您的 API Manager 伺服器 (
/api/payment/webhook)。 - 自動展延授權: API Manager 接收並驗證 Webhook 的檢查碼後,直接執行資料庫更新:
UPDATE partners SET expiry_date = '+1 year' WHERE id = ? - 無縫恢復連線: 廠商的 API Key 瞬間恢復效力,自動取得全新的 JWT Token,無須人工介入即可繼續發送指令至 AWS。
🏗️ 綠界科技 (ECPay) 金流與 API 自動化展延系統架構圖
本系統已完整設計並實作第三方支付(綠界科技 ECPay)之自動化金流交易與金鑰延展流程。以下為該系統跨專案(費用前台 Checkout UI、API Manager 後端、Firebase 實時資料庫、獨立帳單儀表板)之核心動態資料流與簽章驗證時序圖:
🔑 綠界科技 Sandbox 介接資訊 (已配置於後端)
- 特店代號 (MerchantID):
2000132 - 金鑰 HashKey:
5294y06JbISpM5x9 - 向量 HashIV:
v77hoKGq4kWxNNIS - 付款介接端點 (Stage URL):
https://payment-stage.ecpay.com.tw/Cashier/AioCheckOut/V5
雙平台金流架構對比
B2B SaaS 訂閱系統(Herd)與 B2C 旅客訂房平台(HOTEL_OTA)之金流串接模式對比。
雙平台金流串接模式比較表
為了達到「敏感憑證統一控管」與「商業邏輯解耦」的目的,本系統(Cell API Manager)被設計為集中式金流中台。 以下是 B2B SaaS 訂閱模式(Herd)與 B2C 旅客訂房模式(HOTEL_OTA)在金流架構設計上的主要差異:
| 比較維度 | B2B SaaS 訂閱系統 | B2C 旅客訂房平台 (HOTEL_OTA) |
|---|---|---|
| 業務定位 | SaaS 服務訂閱、硬體授權額度展延與金鑰有效期限計算。 | 消費者特定房源在指定日期的預訂(Transactional Booking)。 |
| 發起者與付費對象 | 系統合作夥伴 (Partner)。 | 平台註冊旅客 (Guest)。 |
| 前端金流 API 呼叫 | 直接呼叫中台 API POST /api/payment/ecpay。 |
呼叫 Firebase Callable Function createBooking,再由 Firebase 後端中轉呼叫金流中台。 |
| 敏感金鑰儲存 | 儲存於 PMS_API_Manager (中台),安全無洩漏風險。 |
儲存於 PMS_API_Manager (中台),HOTEL_OTA 專案不保存任何綠界私鑰,透過雙向 Secret 來互相驗證。 |
| 交易防重疊機制 | 無特殊要求,直接依付款累加訂閱效期。 | 在向中台開單前,必須透過 Firestore 先將房源日曆鎖定為 pending,防止併發重疊預訂。 |
| 付款完成確認流程 | 中台直接更新本地 SQLite 資料庫與同步雲端並完成展延。 | 中台在背景接收到綠界 Webhook 後,使用 Secret 發送 Webhook 請求通知 HOTEL_OTA 的 confirmBooking webhook 接口,將訂單標記為 confirmed。 |
🏗️ 金流架構流程圖 (B2B vs B2C)
1. B2B 系統金鑰訂閱展延流
sequenceDiagram
autonumber
actor Partner as 合作夥伴 (Partner)
participant Vue as 費用前台 Checkout UI
participant Backend as Cell API Manager (中台)
participant ECPay as 綠界金流
Partner->>Vue: 點擊 "Pay via ECPay" 續約方案
Vue->>Backend: POST /api/payment/ecpay (apiKey, plan, months)
Note over Backend: 使用中台內置 ECPay 金鑰進行簽章
生成 CheckMacValue
Backend-->>Vue: 回傳完整簽章參數與 ECPay URL
Vue->>ECPay: Form Submit (以 _blank 另開新分頁)
ECPay-->>Backend: 背景發送 Webhook 成功通知 (ReturnURL)
Backend->>Backend: 更新本地資料庫並延長該 Partner 效期
2. B2C 旅客訂房金流流 (HOTEL_OTA)
sequenceDiagram
autonumber
actor Guest as 旅客 (Guest)
participant Front as HOTEL_OTA 前端
participant Firebase as Cloud Functions (createBooking)
participant Backend as Cell API Manager (中台)
participant ECPay as 綠界金流
Guest->>Front: 選擇房源與日期,點擊「預訂並付款」
Front->>Firebase: 呼叫 Callable 建立預訂
Note over Firebase: 寫入 Firestore 建立 pending 訂單
防併發鎖定房源日曆 (Calendar)
Firebase->>Backend: POST /api/payment/ecpay (帶入 productType="hotel_booking", secret, amount, bookingId)
Note over Backend: 驗證 Secret 安全性,生成綠界交易編號
使用中台 ECPay 金鑰簽章
Backend-->>Firebase: 回傳簽章參數與支付 URL
Firebase-->>Front: 回傳金流參數至前端
Front->>ECPay: Form Submit (在當前視窗轉跳)
ECPay-->>Backend: 付款成功 -> 背景發送 Webhook (ReturnURL)
Note over Backend: 驗證 CheckMacValue 簽章合法性
識別為 hotel_booking 商品
Backend->>Firebase: POST /confirmBooking (帶入 x-payment-secret Header, bookingId)
Note over Firebase: 驗證 Secret,更新 Firestore 該訂單為 confirmed
💡 「集中式金流中台」設計的優勢分析
- 憑證安全隔離 (Security Boundary): 敏感金鑰 (ECPay Key/IV) 僅集中保存在 API Manager 中。子系統 (HOTEL_OTA) 就算被駭也拿不到付費憑證。
- 減少維護成本 (Single Point of Maintenance): 如果未來綠界的規格升級(例如加密演算法變更)或是更換成 Stripe、LinePay 等,只需要在中台更新,前端與子系統不需要重複編寫繁瑣的金流簽章演算法。
- 系統間鬆耦合 (Loose Coupling): 兩個平台共享同一個金流接口,並以標準的商品類型 (
productType) 來決定不同的付款確認邏輯,既保持高複用度,又互不干擾。
Hotel & BnB 收費分析
針對 HOTEL_OTA 平台未來收費策略的商業模式與架構規劃分析建議。
一、兩大主流收費模式深度對比
在訂房平台(OTA)與旅宿管理系統(PMS)市場中,主要有「交易手續費抽成」與「固定訂閱制」兩種營利模式。以下是詳細對比分析:
| 評估維度 | 模式 A:預訂交易抽成 (Airbnb 模式) | 模式 B:固定訂閱制 (SaaS / PMS 模式) |
|---|---|---|
| 運作機制 | 針對每筆預訂付款進行百分比抽成(例如抽 5% - 15%)。 | 房東每月或每年支付固定年/月費,不論成交量多寡都不加收費用。 |
| 房東開發難度 | 極低(零進入門檻) 房東沒有成交就無須付費,上架意願極高。 |
較高(有初期門檻) 在沒有訂單保障前,新房東不願意預先支付月費。 |
| 營收天花板 | 極高 隨著平台總交易金額(GMV)成長,平台獲利呈指數級上升。 |
有上限 僅取決於房東訂閱戶數,無法共享房東生意做大時的紅利。 |
| 雙方利益綁定 | 高度綁定 平台會主動優化 SEO、投放廣告,因為「房東成交 = 平台賺錢」。 |
低綁定 平台偏向純提供軟體工具,不負責為房東導流與推廣。 |
| 跳過交易風險 | 中等至偏高。房東與熟客常試圖私下交易以規避手續費。 | 極低。既然已付固定月費,房東會希望盡量走平台以方便帳務管理。 |
二、Airbnb 實際收費標準參考
Airbnb 主要採用「拆分服務費 (Split-fee)」機制:
- 房東端 (Host Fee): 抽取每筆訂單的 3%(主要用作信用卡金流處理成本)。
- 旅客端 (Guest Fee): 抽取每筆訂單的 14% 左右,這是平台的主要營收來源。
- 特殊模式(單一費率): 針對連鎖飯店或使用軟體系統串接的專業房客,亦提供「僅抽房東 15%,不抽旅客」的模式。
三、 未來收費模式策略建議
針對 HOTEL_OTA 平台,若純收訂閱制會極難開發前期房東;純收抽成制則對高營業額的專業房東缺乏吸引力。 因此,強烈建議採用「混合型階梯收費模式 (Hybrid Tiered Model)」:
免月費,按預訂抽成
- 房東零上架成本
- 有成交平台才抽成
- 適合副業房東、閒置房源者
低月費,低預訂抽成
- 降低高營業額下的抽成負擔
- 3% 僅包含綠界處理成本
- 適合高客單價、包棟民宿
生態系綁定免費方案
- 直接免收 HOTEL_OTA 抽成與月費
- 僅收取基本金流處理代收費 (3%)
- 適合導入自助機/物聯網飯店
部署與更新教學
交接文件:如何更新 AWS EC2 雲端伺服器的程式碼與架構資訊
📦 一鍵自動更新流程 (推薦)
為了方便交接與後續維護,系統已內建自動化部署腳本。未來若您在本地端 (Local) 修改了任何 PMS_API_Manager 的程式碼,只需透過以下步驟即可一鍵將更新推送到 AWS EC2 正式環境:
更新三部曲
- 打開您的 Mac 終端機 (Terminal)。
- 切換目錄到專案資料夾:
cd ~/Desktop/PMS_API_Manager - 執行自動化部署腳本:
./deploy.sh
deploy.sh 會自動透過 rsync 將您本地端的最新程式碼傳送到 EC2,並且 自動避開 data/pms.db 資料庫檔案(避免覆蓋雲端的正式廠商資料)。最後會透過 SSH 自動遠端執行 pm2 restart pms-api,讓新程式碼立即生效。
☁️ 雲端伺服器 (EC2) 規格與連線資訊
- 公網 IP 位址 (BASE URL):
http://3.27.15.192:3000 - SSH 連線使用者:
ubuntu - SSH 金鑰路徑 (本地):
~/AWS_Key/pms-api-key.pem - 專案存放路徑 (EC2):
~/PMS_API_Manager - 背景常駐工具:
PM2(進程名稱為pms-api)
手動連線至主機 (進階)
若需要手動進去主機查看日誌或除錯,請使用以下指令連線:
ssh -i ~/AWS_Key/pms-api-key.pem ubuntu@3.27.15.192
查看 PM2 即時運行日誌:
pm2 logs pms-api
Wallet 憑證 AWS 部署說明 (方案 B)
交接與規劃:在正式生產環境 (AWS EC2) 下使用 Secrets Manager 與 S3 的無硬碟殘留憑證部署方案。
AWS 生產環境憑證安全整合指南
🛡️ 方案 B 設計核心:零磁碟殘留 (Zero Disk Residual)
在生產環境中,將 .p12 簽章私鑰 以實體檔案形式儲存在 EC2 的硬碟中具有潛在風險(若伺服器被攻破,證書即刻外洩)。
方案 B 透過將憑證託管於 Amazon S3 (Private),密碼託管於 AWS Secrets Manager,並結合 EC2 的 IAM Role 角色授權,實現了「發卡瞬間從記憶體載入、簽章完畢即刻銷毀」的高安全性架構。
1. AWS 雲端安全發卡架構流
在 AWS 部署方案下,API Docs 伺服器與 AWS 託管服務的互動關係如下:
graph TD
PMS["1. 第三方 PMS 系統 - 呼叫 API"] -->|POST /api/wallet/generate| API["2. API 發卡伺服器 - AWS EC2"]
subgraph AWS["AWS 安全網路邊界 - IAM Role 授權"]
API -->|3. 動態下載 P12 憑證| S3["Amazon S3 私有加密儲存桶"]
API -->|4. 取得私鑰密碼| SM["AWS Secrets Manager 憑證密鑰服務"]
API -->|5. 記憶體載入簽署| MEM["RAM 記憶體簽章及打包"]
end
API -->|6. 回傳 pkpass 串流| PMS
2. AWS 權限配置 (IAM Policy)
您需要為執行 Node.js 的 AWS EC2 實例綁定一個 IAM Role (EC2 實例描述檔),並附加以下最低權限 Policy,限制其僅能存取特定的儲存桶與密鑰:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowReadP12FromS3",
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::your-pms-wallet-credentials/pass_credential.p12"
},
{
"Sid": "AllowReadPasswordFromSecretsManager",
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:pms/wallet/config-*"
}
]
}
3. AWS SDK 整合實作程式範例
在伺服器端,我們可以使用環境變數 WALLET_STORAGE_MODE=AWS 來動態切換憑證來源。以下為 Node.js 讀取 AWS 憑證的程式範例:
const { S3Client, GetObjectCommand } = require("@aws-sdk/client-s3");
const { SecretsManagerClient, GetSecretValueCommand } = require("@aws-sdk/client-secrets-manager");
const s3Client = new S3Client({ region: "us-east-1" });
const secretsClient = new SecretsManagerClient({ region: "us-east-1" });
/**
* 取得 Wallet 憑證與密碼 (支援本地/AWS雙模式)
*/
async function getWalletCredentials() {
if (process.env.WALLET_STORAGE_MODE === "AWS") {
console.log("正在從 AWS S3 與 Secrets Manager 獲取憑證...");
// 1. 從 S3 讀取 .p12 檔案
const s3Params = { Bucket: "your-pms-wallet-credentials", Key: "pass_credential.p12" };
const s3Response = await s3Client.send(new GetObjectCommand(s3Params));
// 將 Stream 轉為 Buffer
const streamToBuffer = (stream) =>
new Promise((resolve, reject) => {
const chunks = [];
stream.on("data", (chunk) => chunks.push(chunk));
stream.on("error", reject);
stream.on("end", () => resolve(Buffer.concat(chunks)));
});
const p12Buffer = await streamToBuffer(s3Response.Body);
// 2. 從 Secrets Manager 讀取憑證密碼
const secretResponse = await secretsClient.send(
new GetSecretValueCommand({ SecretId: "pms/wallet/config" })
);
const secrets = JSON.parse(secretResponse.SecretString);
const p12Password = secrets.p12Password;
return { p12Buffer, p12Password };
} else {
// 本地模式 (Fallback)
const fs = require('fs');
const path = require('path');
const p12Path = path.resolve(__dirname, '../PMS_API_Manager/data/pass_credential.p12');
const configPath = path.resolve(__dirname, '../PMS_API_Manager/data/wallet_config.json');
let p12Buffer = fs.readFileSync(path.join(__dirname, 'resources/mock_credential.p12'));
let p12Password = 'mockpass';
if (fs.existsSync(p12Path)) {
p12Buffer = fs.readFileSync(p12Path);
if (fs.existsSync(configPath)) {
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
p12Password = config.p12Password || '';
}
}
return { p12Buffer, p12Password };
}
}
4. 本地開發與 AWS 環境無縫切換
在本地測試時,您可以使用極簡的環境變數 .env 設定來使伺服器在 LOCAL 與 AWS 模式間流暢切換:
- 在本地測試時:不設定變數,後端預設自動採用 LOCAL 模式,直接讀取您在管理後台 (localhost:3000) 上傳之憑證,或自動 Fallback 使用
mock_credential.p12。 - 在部署 AWS 時:於 EC2 啟動指令中宣告
WALLET_STORAGE_MODE=AWS,Node.js 即會自動使用 AWS SDK 拉取密鑰,無需改動任何主程式,實現環境無痛轉移!
Wallet 票卡架構與生成流程說明
為 iOS Apple Wallet (.pkpass) 與 Android 提供發卡資料標準與離線/後端打包架構說明。
Wallet 票卡架構與生成流程說明
📌 票卡底層概念 (Basic Concepts)
當我們在 Web3 錢包或 PMS 發卡系統中生成一個票卡安裝檔時,不論是 iOS 還是 Android,都需要將虛擬金鑰 (Vkey) 或 ERC20 Presets 等核心資料透過條碼 (Barcode) 或 NFC 的方式嵌入至數位票卡中,以利硬體掃描讀取。
.pkpass,本質上是一個內含簽章與配置檔案的 ZIP 壓縮檔。iOS 原生系統會嚴格執行 Apple PKCS#7 證書鏈校驗。
.pkpass 包,通常跳過嚴格的簽章校驗)。
1. 票卡基礎資料結構 (.pkpass 包內檔案組成)
一個標準的 .pkpass 票卡解壓縮後,必須包含以下關鍵檔案:
| 檔案名稱 | 類型與必要性 | 說明與核心欄位 |
|---|---|---|
pass.json |
必要 (JSON) | 定義票卡類型 (如 generic)、外觀顏色、欄位文字與條碼編碼內容 (將 Vkey 寫入 barcodes.message 中)。 |
manifest.json |
必要 (JSON) | 清單檔。列出包內所有檔案(如圖檔、pass.json)及其對應的 SHA-1 Hash 值,用以防止竄改。 |
signature |
必要 (Binary) |
PKCS#7 二進位簽章。使用 Apple 簽發的 Pass Type ID 私鑰與證書對 manifest.json 進行雜湊簽章的結果。
|
icon.pnglogo.png |
非必要但建議 (PNG) | 票卡的視覺素材。包含 1x 圖片與高解析度的 @2x, @3x 版本(例如通知中心圖示、卡片左上角商標等)。 |
pass.json 範例內容:
{
"formatVersion": 1,
"passTypeIdentifier": "pass.com.pms.wallet.vkey",
"teamIdentifier": "TEAMID1234",
"organizationName": "PMS Group",
"serialNumber": "pms_vkey_888888",
"description": "PMS Web3 Hardware Access Key",
"generic": {
"primaryFields": [
{
"key": "vkey_name",
"label": "金鑰名稱",
"value": "Web3 開門晶片"
}
],
"secondaryFields": [
{
"key": "expire",
"label": "效期截止時間",
"value": "2026-12-31 23:59:59"
}
]
},
"barcodes": [
{
"format": "PKBarcodeFormatQR",
"message": "pms_vkey_data_payload_here_0x127391...",
"messageEncoding": "iso-8859-1",
"altText": "掃描以進行硬體開門驗證"
}
],
"backgroundColor": "rgb(15, 23, 42)",
"foregroundColor": "rgb(255, 255, 255)",
"labelColor": "rgb(148, 163, 184)"
}
2. iOS Wallet (.pkpass) 安裝檔製作流程
因為 iOS 系統原生對 Pass 的安全性校驗極高,所以在發卡伺服器上必須有一套標準的簽署流程來生成封裝包:
📊 iOS 票卡簽章與生成資料流
graph TD
A[1. 準備原始檔素材與 pass.json] --> B[2. 計算各檔案 SHA-1 生成 manifest.json]
B --> C[3. 讀取 Apple Pass 憑證與私鑰 .p12]
C --> D[4. 使用 OpenSSL 進行 PKCS#7 簽章生成 signature]
D --> E[5. 將所有檔案打包為 ZIP 並重新命名為 .pkpass]
E --> F[6. 使用者透過 iOS Safari / Mail / 簡訊下載安裝]
F --> G{iOS 內建 Wallet 校驗簽章}
G -- 驗證通過 --> H[成功匯入錢包並顯示卡片]
G -- 驗證失敗 --> I[提示「無法讀取此票卡/憑證無效」]
iOS 原生 Wallet App 對此為強校驗,若
signature 檔為空,或者簽章所使用的證書鏈不被 Apple Trust Store 信任,iOS 下載後會直接跳出「無法加入票卡」/「票卡無效」。
因此,若要在正式 iOS 裝置上部署,發卡方必須在 Apple Developer Account 註冊一個 Pass Type ID 並下載憑證。
👨💻 後端 (macOS / Linux) 使用 OpenSSL 自動簽署指令參考
在後端,我們可以用 Node.js 結合系統 native 的 openssl 快速抽離憑證私鑰並進行 manifest 簽章,免除使用笨重的第三方庫:
# 1. 從發卡方憑證 p12 中提取憑證 (Cert)
openssl pkcs12 -in pass_credential.p12 -clcerts -nokeys -out certificate.pem -passin pass:憑證密碼
# 2. 從 p12 中提取私鑰 (Private Key)
openssl pkcs12 -in pass_credential.p12 -nocerts -out privatekey.pem -passin pass:憑證密碼 -passout pass:私鑰本機密碼
# 3. 使用憑證與私鑰,對 manifest.json 進行 PKCS#7 簽章,輸出二進位 signature
openssl smime -binary -sign -certfile certificate.pem -signer certificate.pem -inkey privatekey.pem -in manifest.json -out signature -outform DER -passin pass:私鑰本機密碼
完成後,將 pass.json、圖片、manifest.json 與 signature 通通用 ZIP 打包並重新命名為 *.pkpass 即是一組合格的安裝檔。
3. Android Wallet 安裝檔製作流程
相較於 iOS,Android 在數位票卡的支援上更為多元與開放,可以分為兩種主流發卡途徑:
🛠️ 途徑 A:直接沿用 .pkpass 格式(相容第三方 Wallet App)
Android 系統原生沒有內建 PKPass 解析引擎,但使用者只需在 Google Play 安裝如 PassWallet 或 PassAndroid 等大牌軟體,便能直接開啟 .pkpass 檔案。
也就是說,只要您將
pass.json 的結構與靜態素材打包正確,即使 signature 檔是空的,或者使用自簽/Mock 的簽署,依然可以在 Android 手機上 100% 成功解析、成功渲染 QR Code Vkey 並正常安裝! 這對於開發初期與免付費憑證的使用場景極為友善。
🌐 途徑 B:Google Wallet 官方 REST API(整合 Google 帳戶)
這是最尊榮的官方整合方式。使用者不需安裝任何第三方 App,點擊網頁上的 「Add to Google Wallet」 按鈕,卡片便會同步儲存至使用者的 Google 帳戶並常駐於 Android 系統的 Google Wallet 中。
📊 Google Wallet 官方發卡資料流
graph TD
A[1. Google Wallet Console 建立帳號] --> B[2. 建立 Service Account 下載 JSON 金鑰]
B --> C[3. 於後端定義 PassClass 範本並發布至雲端]
C --> D[4. 後端依使用者資料/Vkey 生成動態 PassObject 並組裝為 JWT]
D --> E[5. 前端呈現 'Add to Google Wallet' 憑證超連結]
E --> F[6. 使用者點擊將卡片保存至 Google Wallet]
{
"iss": "pms-service-account@pms-iot-project.iam.gserviceaccount.com",
"aud": "google",
"typ": "savetowallet",
"origins": [],
"payload": {
"genericObjects": [
{
"id": "1234567890123456789.pms_vkey_888888",
"classId": "1234567890123456789.pms_vkey_class",
"genericType": "GENERIC_OTHER",
"cardTitle": {
"defaultValue": {
"language": "zh-TW",
"value": "PMS 門禁金鑰"
}
},
"header": {
"defaultValue": {
"language": "zh-TW",
"value": "已啟用"
}
},
"barcode": {
"type": "QR_CODE",
"value": "pms_vkey_data_payload_here_0x127391...",
"alternateText": "門禁專用 Vkey"
},
"hexBackgroundColor": "#0f172a"
}
]
}
}
🌿 碳盤查與計算方法說明
詳細說明以數位票卡 (Apple & Google Wallet) 替代傳統 PVC 實體卡片的減碳計算邏輯與換算標準。
碳盤查計算與生命週期評估 (LCA) 說明文件
♻️ 減碳核心理念
每一次成功的 Wallet Pass API 呼叫,代表產生一張虛擬票卡,並成功替代了一張實體塑膠卡片(如會員卡、識別證或門禁卡)的製造、印刷、寄送與廢棄過程。透過對這些 API 進行自動監控統計,本平台提供可被稽核的碳足跡減量統計數據,助力企業綠色轉型與 ESG 指標申報。
1. 實體卡片碳足跡標準(ISO 14064 LCA 評估)
根據國際 ISO 14064/14067 的生命週期評估 (LCA) 標準研究,一張標準 ISO 7810 規格的 PVC 塑膠卡片,在其生命週期中各階段所產生的碳足跡平均如下:
| 生命週期階段 | 碳排放量 (CO₂e) | 排放來源與說明 |
|---|---|---|
| 原料與製造 (Raw Material & Mfg) | 約 12g | 包含 PVC 顆粒提煉、卡片基材壓延與晶片埋設。 |
| 個人化與印刷 (Personalization) | 約 4g | 卡面熱昇華彩印、條碼噴印及晶片寫入。 |
| 運輸配送 (Logistics) | 約 7g | 卡片自工廠運送至發卡點,及郵寄至使用者手中的運輸碳排。 |
| 廢棄處置 (End of Life) | 約 3g | 因 PVC 不可自然分解,後續進入焚化爐或垃圾掩埋場所產生的溫室氣體。 |
| 每卡累計節量 | 26g CO₂e / 張 | 系統預設採用的基準值(管理員可於後台自訂調整)。 |
2. 等效環境貢獻轉換公式
為了將抽象的「碳公克數 (g CO₂e)」轉化為直觀易懂的綠色成效,系統使用以下經過科學驗證的換算基準:
總碳節省量 (g) ÷ 1,000 ÷ 20
基準:一棵健康成年樹木每年平均吸收約 20 kg (20,000g) 的 CO₂。
總碳節省量 (g) ÷ 1,000 ÷ 0.21
基準:中型汽油乘用車行駛每公里平均排放約 0.21 kg (210g) 的 CO₂。
總簽發票卡張數 × 5
基準:一張符合 ISO 標準之實體 PVC 卡片重量約為 5 公克。
3. 計量統計機制與 API 觸發
系統透過中介軟體 (Middleware) 即時捕捉並篩選代表「成功簽發虛擬票卡」的 API 調用,排除無效或一般管理請求:
- 計入之 API 端點:
POST /api/wallet/sign-pass— Apple Wallet 票卡簽署與發佈POST /api/wallet/sign-google-pass— Google Wallet 票卡簽署與發佈
- 統計判定條件: API 回傳狀態碼必須小於 400 (意即 HTTP 2xx 成功)。所有 HTTP 4xx (參數錯誤) 或 5xx (伺服器錯誤) 均不予計入。
- 儲存與防重機制: 每次觸發皆會在 SQLite / DynamoDB 雙軌資料庫中寫入以下結構:
{ partner_id: "apple_store_01", partner_name: "Apple Store", wallet_type: "apple", // "apple" 或 "google" endpoint: "/api/wallet/sign-pass", carbon_g: 26.0, // 寫入當下系統設定之碳係數 recorded_at: "2026-06-17 18:00:00" }
4. 歷史回補與自訂係數
系統考量到「事後調整碳係數」及「部署前歷史資料匯入」的需求,設計了以下彈性機制:
wallet_config.json),後續新發行票卡之計量將自動套用新係數。
api_logs 歷史 API 日誌,過濾出符合條件的成功簽發記錄,以「目前的碳係數」重新批量計算,補登回 carbon_stats 中,確保數據完整性。
🗄️ Firebase 雲端主庫 + 本機 SQLite 高效快取 雙層架構
詳細解析系統為何採用「Firebase 雲端主庫 (Master)」與「本機 SQLite (Cache)」雙層架構,兼顧極速 API 回應、成本最佳化與 24/7 不間斷高可用性。
雙層資料庫 (Dual-Layer Database) 技術架構說明
1. 雙層資料庫架構示意圖 (Architecture Diagram)
下圖展示管理端(Web Admin Dashboard)進行鎖頭服務切換時的 雙寫機制 (Dual-Write),以及第三方與住客呼叫 API 門鎖驗證時,如何透過 本機 SQLite 提供 0.1ms 極速回應。
如圖所示,系統採用 Firebase 雲端主庫 (Master) + 本機 SQLite 高效快取 (Cache) 雙層分工。管理端在 Web 介面上切換服務鎖頭時,
PMS_API_Manager 會實施 雙寫 (Dual-Write);而 API 閘道 PMS_API_Docs 在處理門鎖金鑰產生時,直接讀取本機 SQLite,達到 0.1 毫秒極速驗證。
2. 雙層架構四大核心優勢 (Key Advantages)
⚡ 1. 超低延遲極速回應 (0.1ms Auth)
門鎖 API (Port 4000) 屬於高並發、高頻率之請求。若每次呼叫均往返 Firebase 雲端,會產生 100ms~300ms 網路延遲。直接讀取 EC2 本機 SQLite 僅需 0.1ms,極速回應開鎖與金鑰生成。
💰 2. 節省 90%+ Firebase 費用
Firebase Firestore 依據「讀取次數 (Document Reads)」計費。將高頻 API 驗證下沉至本機 SQLite 快取層,可大幅降低打向 Firebase 的讀取流量,大幅省下雲端資料庫維運成本。
🛡️ 3. 雲端不斷線容錯 (High Availability)
若外部網路短暫波動或 Firebase 進行微服務升級時,EC2 本機的 API 伺服器依然可憑藉本機 SQLite 快取維持正常 API 驗證與開鎖功能,確保智慧旅館門鎖運作不間斷。
☁️ 4. 24/7 AWS EC2 獨立全天候運作
EC2 上的 SQLite 檔案獨立存儲於 AWS 雲端硬碟 (/home/ubuntu/PMS_API_Manager/data/pms.db),與工程師本機電腦完全解耦。本機電腦關機絕不影響線上 AWS 24小時服務與權限運作。
3. 資料庫職責對照與雙寫 (Dual-Write) 流程
| 資料庫種類 | 架構角色 (Role) | 主要資料職責 (Responsibilities) | 存取速度 |
|---|---|---|---|
| 🔥 Firebase Firestore | Master (雲端主庫) | 全局合作夥伴、管理員帳號、審計日誌、跨伺服器即時同步與雲端備份。 | 100ms - 300ms |
| 💾 EC2 本機 SQLite | Cache (高效快取) | API 閘道 (Port 4000) 權限查核、Vkey 計算鎖頭狀態驗證、快速驗證 Token。 | ⚡ < 0.1ms |
- 狀態開關寫入 (Dual-Write):當管理員於 Web 後端點擊鎖頭解鎖(例如將
Cellbedell解鎖),PMS_API_Manager在處理/toggle-active時,會同步更新 SQLite 與 Firestore 兩端欄位。 - 啟動/讀取 Upsert 同步:當伺服器啟動或呼叫
getAllPartners時,自動將 Firestore 最新的夥伴資料與鎖頭狀態 Upsert 寫入本機 SQLite,解決地端與雲端資料不一致之問題。
🖼️ 功能架構圖總覽
Cellbedell 系統、虛擬金鑰(VKEY)與行動錢包(Wallet)整合設計的完整功能架構圖與說明。
Cellbedell 功能與技術架構圖集
1. 智慧旅館鎖系統整體架構 (Vkey 算法與錢包整合)
展示了智慧旅館鑰匙系統的雙核心流程:左側為基於 TOTP 概念的 虛擬金鑰 (Vkey) 生成與加密算法流程,右側為將生成之加密指令整合入 Apple & Google 行動錢包 (Wallet Pass) 並派發至住客手機的發卡工作流。
- VKEY 運算流:由 Master Code、Lock ID 及時間參數組合成輸入包,利用 AES-128-CBC 與預設加密金鑰 (Cryptographic Key) 算出專屬的 Payload 加密字串。此字串可用於寫入實體 NFC 卡,或作為藍牙開鎖控制指令。
- Wallet 封裝流:後端取得加密 Payload 後,封裝成 Google 錢包的 JWT 憑證,或透過 Apple 簽章憑證 (Apple Certificate) 打包為
.pkpass票卡檔案,交付到住客裝置,實現「開鎖鑰匙即是錢包票卡」的無縫體驗。
2. 第三方系統 API 整合資料流 (Third-Party Integration)
展示第三方 PMS 旅館管理系統(如 Opera/Starlight 等)如何透過 CAS 3.0 API 閘道整合 Cellbedell 雲端平台與 IoT 硬體設備,涵蓋身份認證、API 路由分流,以及 MQTT 雙向控制鏈路。
- 安全認證:第三方 PMS 系統使用 API Key & Secret 通過驗證取得 Portal JWT Token。
- 閘道路由 (Port 4000):CAS 3.0 API 閘道根據請求將其路由至
/api/vkey(VKEY計算)、/api/wallet/generate(票卡生成) 與/api/mqtt/publish(硬體控制)。 - 硬體控制:MQTT 控制請求發布到指定的 MQTT Broker 主題,本地物聯網橋接器訂閱並解析指令後,對硬體(如門鎖、藍牙裝置)實行現場無線控制,並將設備狀態回傳。
3. VKEY Lambda API 無伺服器設計 (Serverless Architecture)
介紹在 AWS Lambda 無伺服器環境中部署 Vkey 算法 API 的技術架構。此架構具有高度彈性、高可用性與極佳的成本效益(零閒置成本)。
- HTTPS 請求:客戶端攜帶 Token 與計算參數向 AWS 終端發送請求。
- API 路由:AWS API Gateway 接收並過濾請求,路由至專屬的 AWS Lambda 函數執行環境。
- Lambda 計算與響應:Lambda 函數被冷啟動或暖啟動,執行核心 Vkey 加密演算法,計算完成後輸出包含開鎖指令 Hex String 的 JSON Payload 回傳給客戶端。
4. Wallet Lambda API 無伺服器設計 (Serverless Wallet API)
展示利用 AWS API Gateway 和 AWS Lambda 來線上簽署、封裝並派發 Apple Wallet 和 Google Wallet 票卡的無伺服器架構。
- 發卡請求:客戶端傳送帶有開鎖 Payload 和圖片資訊的請求。
- AWS Lambda 封裝簽章:Lambda 載入 Apple 簽發證書、結合模板結構進行二進位打包(Apple pkpass)或是利用服務帳號憑證(Service Account)向 Google 錢包 API 換取 JWT 票券。
- 回傳下載連結:回傳 Apple Wallet 票券原始檔案或 Google Wallet 快捷安裝連結,供前端一鍵安裝金鑰票券。
5. 線上 API 測試平台運行流程 (Sandbox UI & Mock Gateway)
介紹本系統提供給第三方工程師串接時使用的線上 API 測試平台(Sandbox)與內部微服務之間的數據調用鏈路。
- 前端沙盒互動:工程師在 Swagger UI 或測試面板輸入 Lock ID 與時段並點選「Execute」。
- 網關轉發與微服務:模擬 API Gateway(CAS 3.0)校驗憑證與限制,隨即交由後端微服務執行核心運算,完成 Vkey 加密指令包生成或 Wallet 派發。
- 即時可視化:前端在幾毫秒內以 JSON 樹狀高亮組件即時渲染返回數據,極大地方便了開發調試與參數對比。
📝 系統開發報告
Cellbedell PMS API Manager 系統架構、核心設計及查核點完成報告。
查核點:後端管理權限與參數設定開發報告
📋 報告概述
本報告針對 查核點(完成日:115年06月30日) 之開發內容進行說明。本系統已 100% 完成「第三方管理權限開通模組」後台架構開發,涵蓋 **A. 後端 - 廠商管理** 與 **B. 後端 - 參數設定** 兩大模組。
📊 查核點開發項目對照表
| 模組名稱 | 查核細項 | 系統功能說明 | 狀態 |
|---|---|---|---|
| A. 廠商管理 | a. 帳號開通 | 管理端可建立合作夥伴檔案,手動開通/停用其 API 存取權限。 | ✅ 已完成 |
| A. 廠商管理 | b. 登入 Token 生成 | 基於 HMAC-SHA256 生成 API Key & Secret,以 JWT 進行安全憑證簽章。 | ✅ 已完成 |
| A. 廠商管理 | c. 使用時間限制 | 可指定合約到期日,中介軟體 (Middleware) 即時進行到期校驗攔截。 | ✅ 已完成 |
| A. 廠商管理 | d. Vkey 生成紀錄 | 詳細儲存 Vkey 生產所用的 Lock ID 與參數 JSON,支援一鍵檢視 Payload。 | ✅ 已完成 |
| A. 廠商管理 | e. Wallet 生成紀錄 | 即時追蹤 Apple/Google Wallet 簽發紀錄與 ESG 減碳克數。 | ✅ 已完成 |
| B. 參數設定 | a. Wallet-iOS 憑證管理 | 支援上傳 `.p12` 發卡私鑰憑證與配置密碼,供 iOS 票卡簽署模組使用。 | ✅ 已完成 |
| B. 參數設定 | b. Wallet-android 憑證管理 | 管理 Google Wallet 的 Issuer ID 與服務帳戶金鑰 (Credentials JSON)。 | ✅ 已完成 |
| B. 參數設定 | c. Google server 串接路徑管理 | 管理對 Google OAuth 伺服器傳輸金鑰、JWT 組裝與路由代理節點。 | ✅ 已完成 |
💡 初始設想與設計理念
在智慧旅館鎖與電子票卡的應用情境中,傳統對接模式往往面臨「第三方系統直接存取 AWS 物聯網平台,導致憑證管理混亂且無法控管租期」的風險。本後端中介平台 (CAS 3.0) 的初始設計理念旨在:
🗺️ 統一安全閘道概念架構流程圖
如下圖所示,CAS 3.0 中介管理平台作為核心防禦與控制層,將外部廠商(PMS)與底層 AWS IoT Core、機密演算法(Lambda)及電子錢包憑證安全隔離,保障多租戶安全性與租期管控:
🗺️ 後端管理權限與參數設定開發流程圖
如下圖所示,詳細展示了「系統管理員配置流程(租期、憑證、JSON 配置)」與「合作夥伴 API 呼叫流程(中介軟體驗證、憑證簽章、稽核日誌)」的完整邏輯:
🔧 模組 A. 廠商管理:核心實作邏輯
後端生成 API Key 後,將 Secret 使用 crypto 進行 SHA256 單向雜湊儲存。呼叫時採用 HMAC 加密比對,確認身分後發放帶有加密 Payload 的 JWT 作為 Session 憑證。
所有 Vkey、Wallet 生成的 API 路徑皆掛載了身分與到期驗證中介軟體。中介軟體在接收請求後:
1. 解析 Token ➡️ 2. 從 SQLite / Firestore 獲取過期日 ➡️ 3. 判斷 Now > Expiry ➡️ 4. 是則阻斷回傳 403。
每一次 API 呼叫均會被自動記錄於 api_logs。日誌包含完整的 JSON Payload,後台提供「廠商分類」與「日期區間條件」快速篩選,大幅縮短了跨系統聯調時排查參數錯誤的耗時。
🔧 模組 B. 參數設定:憑證管理與串接路徑
為了解決電子票卡跨平台(Apple / Google Wallet)繁雜的憑證與握手流程,參數設定模組實作了動態載入:
-
Apple iOS 憑證管理 (a):
後台支援直接上傳簽署用的
.p12發卡憑證檔案並設定密碼。後端將檔案妥善儲存,在執行 Apple Pass 生成時利用openssl進行動態憑證簽章,毋需手動重啟 Node.js 服務即可即時生效。 -
Android Google Wallet 憑證管理 (b):
支援配置
Issuer ID與直接貼上 Google Cloud Service Account 的憑證 JSON 檔案,以動態載入方式在請求時獲取 Google Auth Token,免除硬編碼風險。 - Google Server 串接路徑代理 (c): 設定並映射 Google API 請求的轉發路徑與 JWT 生成路由,透過 Nginx 節點進行反向代理與負載,以確保高頻發卡時的網路連線健全度。
📋 API 測試開發規劃書
PMS API 串接與線上測試平台 (Swagger) 建設前期設計與沙盒流程規劃。
PMS API 串接與線上測試平台開發規劃
💡 專案背景與目標
為因應智慧旅館鎖(Vkey)及電子票卡(Wallet)串接整合需求,降低第三方系統(如 Opera、Starlight 等 PMS)對接難度與系統營運商之技術聯調成本。本規劃書定義於系統建設初期,如何搭建一套結合 「API 串接規格」 與 「線上沙盒測試(Swagger UI)」 的中介聯調平台。
📋 查核點開發項目對照表
| 模組名稱 | 查核細項 | 系統功能說明 | 狀態 |
|---|---|---|---|
| A. 串接口開發 | a. Vkey api 串接口設計 | 設計智慧門禁開鎖金鑰(Vkey)之動態生成計算接口,供外部 PMS 發送房號及效期取得加密 Token。 | ✅ 已完成 |
| A. 串接口開發 | b. Wallet 串接口設計 | 開發電子票卡(Apple Wallet / Google Wallet)封裝及簽發接口,串聯後台私鑰憑證進行即時動態發卡。 | ✅ 已完成 |
| B. Api 串接測試平台 | a. Vkey api 線上平台測試串接口 | 於 Swagger UI 沙盒環境整合 Vkey API,允許合作夥伴工程師傳入自訂參數並即時計算測試金鑰。 | ✅ 已完成 |
| B. Api 串接測試平台 | b. Wallet api 線上平台測試串接口 | 提供 Apple Wallet 票卡動態發卡測試功能,開發者調用後可在前端直接下載 `.pkpass` 檔案以進行手機模擬驗證。 | ✅ 已完成 |
| C. 架構與開發流程規劃 | 1. 開發流程,架構設計圖一份 | 繪製清晰的 Swagger Sandbox 測試時序與安全閘道流程圖,明確呈現開發者與後端 Lambda 微服務的隔離驗證架構。 | ✅ 已完成 |
📊 功能開發範疇與項目 (按合約對照)
- Vkey API 串接口設計: 負責計算與派發智慧門禁開鎖金鑰(Vkey)。
- Wallet 串接口設計: 負責簽署與派發 Apple Wallet (iOS)
.pkpass檔案與 Google Wallet (Android) JSON 票卡。
- Vkey API 線上平台測試: 提供 Swagger Sandbox 介面,供第三方開發者傳入測試參數即時計算開鎖 Key。
- Wallet API 線上平台測試: 提供 Wallet 發卡功能之沙盒模擬與即時下載校驗。
🗺️ 測試平台 (Swagger UI / Sandbox) 運行流程圖
本流程展示了開發者如何透過 Swagger 測試介面,透過安全閘道(CAS 3.0 Sandbox)向後端服務(AWS Lambda/NFC 機密服務)進行安全的沙盒聯調與即時驗證:
📋 測試 API 規格規劃表
| API 端點 (Route) | 方法 | 功能描述 | 測試輸入參數 (Test Inputs) | 預期回傳成果 (Test Outputs) |
|---|---|---|---|---|
| /api/auth/token | POST | 取得 JWT 存取權杖 | apiKey, apiSecret | JWT Access Token, Expiry Date |
| /api/hardware/publish | POST | 發送硬體控制指令 (MQTT) | lockId, action | status: "delivered", messageId |
| /api/calculate | POST | 產生虛擬金鑰 (Vkey) | roomId, expiry, partnerId | vkeyValue, CheckMacValue |
| /api/wallet/generate/ios | POST | 簽發 iOS Wallet 票卡 | holderName, bookingId, roomNo | .pkpass 二進位下載串流 |
| /api/wallet/generate/android | POST | 簽發 Android Wallet 設定檔 | holderName, bookingId, issuerId | Google Wallet JWT 授權連結 |
🛡️ 安全防護與頻寬控制 (SaaS Sandbox 規範)
- 速率限制 (Rate Limiting):限制每個 API Key 於測試沙盒環境中最大頻率為
10 requests / min,防止資源濫用。 - 沙盒數據安全隔離:所有透過
/api/calculate生成的 Vkey 金鑰指向均受限於測試用硬體 Lock ID,防止影響實體鎖數據。 - 防篡改簽章:發卡與控制參數均採用與綠界相同的
HMAC-SHA256算法計算CheckMacValue,保障測試階段之數據完整性。
🤖 Firebase 專案與桌面應用對照庫
彙整此 Google 帳號下 14 個 Firebase 專案對應 Mac 桌面(~/Desktop)應用程式之映射、系統架構角色與 AI Agent 職能。
{{ proj.name }}
projectId: {{ proj.id }} 🤖 {{ proj.agentName }} {{ proj.categoryName }}{{ proj.desc }}
🧩 AI Agent 系統架構與職能定位規劃
打造 Multi-Agent 協同架構,以 PMS_API_Manager 為調度中心,連結跨 Firebase 專案與智慧硬體生態系。
🌐 全系統 14 專案獨立 AI Agent 分佈拓撲架構圖 (Topology Map)
以 MasterBrainAgent 為控制中樞,下轄 13 個獨立分域專屬 Agent,實時監控各專案 Telegram / MQTT 與 API 數據流。
cell-visit (Vsitor)cell-meeting-14030hotelpms-78ab7hotelota-433a8cellstore-11e21membersystem-fa909cellble-b3958dppblockchaincellbedell-onlineshoppingcart-152101. 中央中樞 Agent
- 自然語言指令解析(LLM Function Calling)
- 跨 Firebase 專案 UID / Token 查詢與同步
- API Partner 存取額度與權限審核驗證
- 維護全系統調度路由與任務鏈分發
2. 數據與 Log 監控 Agent
- MQTT 通訊封包流速監控與異常警告
- BLE 藍牙鎖與 ESP32 設備離線狀態預測
- LINE Notify 綠色健康度訊息自動卡片發送
- API 呼叫失敗率警示與自動重試控制
3. 空間通行與服務 Agent
- 訪客核銷、門禁加密通行碼 (Vkey) 自動派發
- 飯店自助入住 (Check-in) 流程陪伴輔導
- Apple / Google Wallet 票卡自動產出與下載
- 會議室預約時段交疊自動檢測與釋出
📡 Agent API 介接與資料流規範
https://firestore.googleapis.com/v1/projects/{projectId}/databases/(default)/documents/{collectionId}/{uid}
cellbedell-api-auth 取得有效 JWT 權杖,並在 Header 夾帶 x-api-key 與 CheckMacValue。
🔔 單專案獨立 AI Agent 主動監控、修復規劃與 LINE 人機審核機制
以獨立 Agent 實時守護每個 Firebase / 桌面專案,發生異常時主動診斷、規劃 Patch,並透過 LINE 進行 Human-in-the-Loop 確認與 Log 歸檔。
📄 1. 獨立 Agent `.md` 記憶檔案機制
每個 Agent 各自擁有獨立知識檔,包含該專案 Schema 規範、業務邏輯與歷次修復紀錄:
HOTEL_PMS_AGENT.md (住房與排房規範)📄
MEET_AGENT.md (會議室門禁與時段規範)📄
VISIT_AGENT.md (訪客登記與Vkey發卡規範)📄
STORE_AGENT.md (電商商品與自動結帳規範)
🔐 2. 負責權限與安全邊界 (Scoped Role)
貫徹最小權限原則 (Least Privilege),防止 Agent 越權誤動其他專案資料:
HotelPMSAgent僅具備hotelpms-78ab7寫入權,無權動用會員點數。ChainProofAgent僅處理區塊鏈存證,無權存取飯店訂單。- 所有 API 呼叫均由
AuthGuardAgent二次核驗 JWT Token 權限邊界。
🤝 3. 跨專案任務協同演練實例 (Task Delegation Scenario)
HOTEL_PMS_AGENT.md,執行 301 房排房與 Check-in。
MEET_AGENT.md,鎖定明日 14:00 會議室開鎖權限。
VISIT_AGENT.md,產出 Vkey 密碼與 Wallet 票卡。
🔄 AI Agent 雙向互動 (Two-Way Interaction) 維運模式與價值
涵蓋由您主動交辦任務(被動執行)與 Agent 主動偵測異常並擬定 Patch(主動告警)之完整機制與範例。
「幫王小明預約明日 14:00 入住 301 號房並發送 Wallet 票卡。」「幫我統計這個月各 Hotel 的 API 呼叫量與碳排放報告。」
MasterBrainAgent (中央大腦) 解析需求,自動分發至對應子 Agent (如 HotelPMSAgent、VisitAgent) 精確執行並回報結果。
hotelpms-78ab7 發生 API 500 錯誤,或藍牙鎖連線超時。
- 專屬 Agent 第一時間主動捕捉異常。
- 透過 LLM 自動分析 Log 找出根本原因,並寫好擬定的修復程式碼 (Patch)。
- 主動發送 LINE Flex Message 告警卡片給您(附帶同意/暫緩按鈕)。
- 您只需在 LINE 點擊確認,Agent 即自動完成部署修復並歸檔日誌。
💡 總結這個架構為您帶來的價值 (Value Comparison Table)
| 維運模式 | 誰發起 | 運作情境 | 帶給您的好處 |
|---|---|---|---|
| 指示任務 (Demand-Driven) | 您 (User) | 辦理入住、釋放門禁權限、產生統計報表、調整跨渠道房價 | ⚡ 高效率的執行秘書 (免去繁瑣手動操作) |
| 主動告警 (Proactive Incident) | AI Agent | 系統報錯、設備斷線、API 異常500、資料庫掛載失敗與自動診斷 | 🛡️ 24/7 不間斷的自動化維運工程師 (不需盯後台,有問題 LINE 會主動推播) |
🚀 AI Agent 實際部署分析(虛擬團隊)
對照「架構與定位規劃」拓撲圖的 14 個 Agent,盤點目前真實在執行的項目與 MD 工作紀錄。
部署現況總覽(2026-08-08 更新)
每位成員都有一份 MD 人事卡(規劃職能 / 目前真實執行項目 / 尚未落地 / 工作日誌),存於 public/agents/,點下方「📄 MD」即可開啟。
團隊總名冊:agents/README.md
| Agent / 職稱 | 狀態 | 目前真實在執行的項目 | MD 紀錄 |
|---|---|---|---|
| 🧠 MasterBrainAgent 系統大腦/總調度 |
🟢 部分落地 | 每 5 分鐘系統健康監測與 danger 告警、OOM 開機偵測、每日 09:00 摘要、AWS 費用每日分析快取、五分項跨專案同步調度。🧠 LLM 根因分析常駐(Gemini):告警自動附上判讀與建議動作(2026-08-07 上線)。📱 Agent in LINE(2026-08-08 上線):自然語言交辦——查詢軌六個唯讀工具即問即答(廠商/系統/費用/SSL/IoT/碳統計);變更軌 v1(設備額度/到期日)LLM 抽參數發提案卡,經核准+六格 PIN 確認碼才由白名單執行器落地,全程稽核。 |
📄 MD |
| 🛡️ AuthGuardAgent API 安全守門員 |
🟢 部分落地 | JWT/角色權限驗證、登入失敗稽核與 IP 紀錄、API Key 生命週期與到期檢查、稽核金鑰遮罩、AWS IAM 最小權限治理。 |
📄 MD |
| 📣 PushBroadcasterAgent 推播官 |
🟢 部分落地 | 五類 LINE Flex 推播:API 失敗(冷卻聚合)、新訂單、SSL 到期、系統健康告警/恢復/OOM、每日摘要含費用。 |
📄 MD |
| 📡 MQTTLogAgent MQTT 通訊監察 |
🟢 部分落地 | 每 30 分鐘監測 AWS IoT 訊息量(CloudWatch),暴衝雙門檻告警 + 🧠 LLM 分析推播 LINE;每日摘要附 IoT 用量與費用估算(2026-08-07 上線)。直接看守佔帳單 76% 的 IoT 費用。 |
📄 MD |
| 🛰️ VisitAgent 訪客管理專員 |
🟡 設施已備 | 付款自動開通(建帳號+Token+解鎖)、到期自動上鎖 cron、SI 開通開關。 |
📄 MD |
| 🗓️ MeetAgent 會議室專員 |
🟡 設施已備 | 一鍵同步自動建 Meeting Auth 帳號與 owner 權限。 |
📄 MD |
| 🏨 HotelPMSAgent 旅宿系統專員 |
🟡 設施已備 | 一鍵同步以信箱比對 hotels/groups 寫入 vkey。 |
📄 MD |
| 💳 MemberWalletAgent 會員錢包專員 |
🟡 設施已備 | 一鍵同步 walletApi、Apple/Google Wallet 票卡簽發端點與憑證管理。 |
📄 MD |
| 🗄️ LegacyDataAgent 歷史資料管理員 |
🟡 設施已備 | Cellbedell RTDB 同步通道(host_user_account/Lockquantity)、SQLite↔Firestore 雙層互備。 |
📄 MD |
| 🌐 OTABridgeAgent OTA 通路專員 |
⚪ 未建置 | 僅 hotel_booking 金流代簽通道;房價同步在 HOTEL_OTA 專案。 |
📄 MD |
| 🛒 StoreAgent 商城導覽員 |
⚪ 未建置 | 本專案無 CellStore 串接程式。 |
📄 MD |
| 📶 BLEBeansAgent 藍牙設備巡檢員 |
⚪ 未建置 | 無 BLE 遙測串接;設備數僅作方案額度同步。 |
📄 MD |
| ⛓️ ChainProofAgent 區塊鏈存證員 |
⚪ 未建置 | 僅測試資料夾,稽核紀錄現存 audit_logs。 |
📄 MD |
| 📦 CartArchiveAgent 舊系統備份員 |
⚪ 未建置 | 本專案無串接。 |
📄 MD |
✅ MasterBrainAgent 常駐分析已上線(2026-08-07)
系統偵測到異常(danger/OOM)時,MasterBrainAgent(masterBrainAgent.js)自動彙整 system-status 快照 + pms-api 錯誤日誌尾段,交給 Gemini(gemini-2.5-flash,沿用參數管理的全域金鑰)生成「根因判讀 + 2~3 條建議動作」,附在 LINE 告警的「🧠 MasterBrain 分析」區塊推播。
- 防護設計:20 秒逾時、每小時最多 4 次 LLM 呼叫;分析失敗時告警照發不受影響。
- 費用:告警屬低頻事件(danger 轉態 + 每小時提醒),Gemini Flash 單次分析成本近乎為零。
- 下一步候選:MQTTLogAgent 訊息量門檻告警(對接 IoT 佔 76% 的帳單)、每日摘要加入 LLM 趨勢短評、自然語言指令解析。
📱 Agent in LINE(人機審核執行)
LINE 告警卡加設「執行優化」按鈕,管理者一鍵授權後由 Agent 執行白名單優化動作。狀態:📋 規劃定稿,待動工。
人機審核執行迴圈(Human-in-the-Loop)
可行性:現有元件對照(地基已就位一半)
LINE Flex Message 按鈕支援 postback:管理者按下後,LINE 把預埋資料(動作 id、事件編號、token)回拋到我方 webhook——與「一鍵開通」等既有互動同一套官方機制,無需額外服務。
| 迴圈環節 | 現有元件 | 缺口 |
|---|---|---|
| 1. 偵測 | MasterBrain / MQTTLog 排程 | 無,已上線 |
| 2. 診斷 | masterBrainAgent.js(Gemini) | 改輸出「結構化動作建議」而非純文字 |
| 3. 推播 | lineNotifier.js Flex 卡片 | 加 postback 按鈕 + 一次性 token |
| 4. 安全閘 | webhook 簽章驗證已寫好(verifySignature) | 擴充處理 postback 事件 |
| 5. 執行 | — | 新增 actionExecutor.js(白名單動作表) |
| 6. 歸檔 | audit_logs 稽核系統 | 加 AGENT_ACTION 動作類型 |
安全設計:白名單,不是自由執行
白名單動作表(第一版草案)
flush_logs(清 PM2 日誌)——低風險,一鍵執行restart_service(重啟指定 PM2 服務)——低風險,一鍵執行rebuild_carbon(碳盤查資料重建)——低風險,一鍵執行expand_ebs/resize_instance——高風險,按鈕僅預約,需在 LINE 回覆確認碼二次確認
按鈕防偽三重驗證
- ① LINE 簽章:確認請求真的來自 LINE 平台(verifySignature 已實作)
- ② 管理員身分:postback 的 userId 必須是設定檔綁定的管理員
- ③ 一次性 token:推播時產生隨機碼存 data/,30 分鐘有效、用過即廢——防舊卡重按、防截圖轉傳代按
三關全過才進執行器;執行器再帶並發鎖(同動作執行中不重複觸發)與逾時保護。結果無論成敗都推回報卡 + 寫入稽核(誰、何時、批准了什麼、結果)。
💬 自然語言交辦(查詢/變更雙軌,2026-08-08 增訂)
管理者可直接在 LINE 用白話交辦事項(例:「給我目前測試廠商設備數量」)。Webhook 驗證身分後交給 MasterBrain(Gemini function calling)從唯讀工具白名單選擇工具查詢,組成白話回覆推回 LINE。聊天入口只有讀取權——這是與白名單執行器一脈相承的權限收斂。
| 軌道 | 行為 | 範例 | 狀態 |
|---|---|---|---|
| 查詢(唯讀) | 直接回答,不需核准 | 廠商資訊/設備額度、系統健康、AWS 費用、SSL 狀態、IoT 訊息量、碳統計(v1 六個工具) | 🟢 已上線 |
| 變更(會動系統) | LLM 抽取參數 → 產生帶參數的變更提案卡 → 核准 + PIN → 執行 → 結果卡 + 稽核 | 「把測試廠商設備數改成 5」→ 提案卡顯示「設備額度 1 → 5」;「聯騏到期日延到 2028-12-31」同理(v1 支援:設備額度、到期日) | 🟢 已上線 |
落地規劃
- 工程量:約一天——動作表與執行器半天、webhook postback 與 token 機制半天、MasterBrain 結構化輸出與卡片按鈕穿插其中。
- 推進策略:第一版只放三個低風險動作,跑順再開高風險類(二次確認機制)。
- 對應拓撲圖:此機制即規劃文件「單專案獨立 AI Agent 主動監控、修復規劃與 LINE 人機審核機制」的階段 3(LINE 推播與確認)→ 階段 4(授權執行)落地;完成後 MasterBrainAgent 由「會分析」升級為「能出手」。
🔌 MCP 與 AI Agent 升級規劃
將現有「單次呼叫」的 Gemini 語意解析器,升級為具 Tool Calling 能力的 AI Agent,並以 MCP (Model Context Protocol) 開放 Cellbedell API 給外部 AI 客戶端安全操作。
✅ 現況盤點:已具備的基礎
ai-parser.js:Gemini 2.5 Flash 單次解析自然語言 → Vkey 欄位,額度不足時退回本地 NEXUS 正規解析。前端為 AIChatVkey 聊天介面。ai_token_quota 50,000 / ai_tokens_used 用量計數。📖 MCP (Model Context Protocol) 是什麼?
MCP 是 AI 客戶端與外部系統之間的開放標準協定:我們只要架設一個 MCP Server,把 Cellbedell 既有 REST API 包裝成一組帶權限控管的 Tools(工具),任何支援 MCP 的 AI(Claude Desktop、Claude Code、其他 Agent 平台)都能直接、安全地查詢訂單、發 Vkey、看設備狀態 — 而不需要為每一家 AI 各寫一次整合。一次包裝,所有 AI 客戶端通用。
🏗️ 目標架構分層圖
🧰 MCP Tools 規劃清單
| Tool 名稱 | 對應既有 API | 讀/寫 | 風險 | 風險來源與前置條件 | 階段 |
|---|---|---|---|---|---|
query_partner_profile | GET /api/partner/profile | 讀 | 低 | 僅回傳自身廠商資料,api_key / secret_hash 已遮罩。 | P1 |
list_orders | GET /api/payment/all-orders | 讀 | 中 | 現行 API 回傳全部廠商訂單,直接開放會跨租戶外洩金流資料。前置:先加 partner 範疇過濾。 | P1 |
query_api_logs | GET /api/admin/stats/raw-logs | 讀 | 高 | 唯讀卻是全表最高風險:request_body 內含 master_code / lock_id 明文,等於把金鑰推導輸入送進模型上下文與第三方 AI 客戶端。前置:日誌遮罩完成前不得開放。 | P2 |
get_device_status | GET /api/mqtt/device/:id/status | 讀 | 低 | 唯讀、不改變硬體狀態;惟會透露場域是否有人,限縮於自家設備即可。 | P1 |
create_vkey | Vkey 發卡 API | 寫 | 高 | 風險在於核發實體通行權(非演算法本身:Vkey 經 CreateVkey 推導後 AES 加密,master_code 為建鎖時隨機生成)。前置:Tool 只收 lock_id + 時段,master_code 由伺服器內部查表,永不進入模型上下文。 | P2(需 LINE 人工確認) |
remote_unlock | MQTT 遠端開鎖 | 最高 | 唯一「立即改變實體世界且不可撤回」的動作 —— 門開了就是開了。前置:一律 LINE 人工確認,AI 不得自主完成。 | P2(需 LINE 人工確認) | |
renew_subscription | 產生 ECPay 付款連結 | 寫 | 低 | 僅產生連結,不動用任何已存付款方式;實際扣款仍需人到綠界頁面完成。 | P3 |
資料敏感度:回傳內容一旦進入模型上下文或外部 AI 客戶端,等同外流什麼?
⚠️ 兩軸須分開看 ——
query_api_logs 動作影響為零,卻因回傳內容含金鑰推導輸入而評為高風險;「唯讀 ≠ 安全」。
🗺️ 三階段實施 Roadmap
- 以
@modelcontextprotocol/sdk建立獨立 MCP Server(EC2 新 PM2 程序) - 先開放 3 個唯讀 Tools(查詢廠商、訂單、設備狀態)— 日誌查詢改列 P2
- 沿用既有 API Key 驗證:AI 只能查到該 Key 所屬廠商的資料
- 前置工項:
/api/payment/all-orders加上 partner 範疇過濾(現行回傳全部廠商訂單) - 用量計入
ai_tokens_used,超過額度即拒絕
- 前置工項:日誌 request_body 遮罩 master_code,並清洗既有紀錄 — 完成後才開放
query_api_logs - 開放高風險 Tools(發 Vkey、遠端開鎖);
create_vkey不收 master_code,改由伺服器內部查表 - 沿用 lineNotifier:高風險操作先推 LINE Flex 給管理者按「同意/拒絕」才執行 (Human-in-the-Loop)
- 每筆寫入操作落 audit_logs(操作者 = AI + 來源客戶端)
- AIChatVkey 從「單次解析」升級為 Function Calling 迴圈(Gemini 或 Claude API)
- 支援多步驟任務:「幫 302 房客展延兩天並重發房卡」→ 查訂單 → 展延 → 發卡 → 回報
- 與 MCP Tools 共用同一套工具定義,一份邏輯兩邊用
🛡️ 安全設計原則
- 最小權限:Tool 的資料範疇 = API Key 所屬廠商;到期或停用的 Key 一律拒絕(沿用 verifyToken 既有檢查)。
- 高風險必經人工:開鎖、發卡等實體世界操作,一律 LINE 確認後才執行,AI 不可自主完成。
- 金鑰不經過模型:api_secret_hash、gemini_api_key 等機敏欄位不出現在任何 Tool 回應(profile API 已完成遮罩)。
- 全程可稽核:每次 Tool 呼叫寫入 audit_logs 與 api_logs,異常走既有 LINE 告警。
- 用量可控:沿用每廠商 ai_token_quota 計量,防止濫用與成本失控。
🛰️ Visitor 第三方串接風險分析
分析對象:Vsitor/Vsitth(Firebase 專案 cell-visit)—— 模擬第三方系統向 Cellbedell 取得金鑰與匯入硬體資訊之完整串接鏈。
📌 結論摘要
tesseract.js 為本機 WASM 光學辨識(證件掃描),非 AI 服務;parse_gemini.py 僅為抓取 Gemini 分享頁的開發用暫存腳本,未納入應用程式。vite / qrcode / tesseract.js,無 MCP SDK 或協定實作。🔗 實際串接鏈路(修復後)
pk_ partner API Key 同步至 cell-visit 之 admins/{uid}/private/credentials(新:匿名不可讀);根文件僅留 hasToken 旗標與非機敏欄位。② 匯入硬體:瀏覽器讀出 token →
POST /cbd_system/api/vistor/hardware-info → 後端驗證 email 隸屬於持 token 之 partner 或其子帳號(新)→ 回傳該帳號 Locks 之 lockid 與 mastercode。③ 取得金鑰:瀏覽器帶同一 token →
POST /cbd_docs/api/vkey → 回傳加密 Vkey → 產生 QRCode 與 Wallet 票卡。④ 子帳號:sub_admin 依
ownerUid 繼承主帳號憑證,Firestore 規則以 isSubAdminOf() 授權讀取。
🚨 風險清單與處理結果
| # | 風險項目 | 原等級 | 狀態 | 實際修復內容 |
|---|---|---|---|---|
| 1 | Firestore 規則全面開放firestore.rules |
極高 | ✅ 已修復 | 憑證移至 private/credentials(匿名不可讀);settings(含 master_code)改為僅本人/子帳號可讀;刪除權限收歸 super;新增 noCredentialInResult() 防止 token 被寫回公開文件。已部署至 cell-visit 並實測驗證。 |
| 2 | Partner API Token 由前端持有admin.js |
高 | ✅ 已根治 | 已改為伺服器對伺服器架構(2026-08-03):前端改帶 Firebase ID Token 呼叫 PMS 代理端點 /api/vistor/issue-vkey、/issue-wallet/:type、/hardware-info-secure;PMS 以 cell-visit Admin SDK 驗證身分後,於伺服器端注入 partner 金鑰。partner 級 API Key 全程不再下發瀏覽器,前端亦不再讀取 private/credentials。 |
| 3 | 正式憑證進入 Git 版控test_api.js 等 4 檔 |
高 | ✅ 已修復 | test_api.js、test_wallet.js/.cjs、test_wallet_full.cjs 之硬編碼 token 與 master_code 全數改為讀取環境變數。⚠️ Git 歷史仍留存,該 token 與 master_code 須另行輪替。 |
| 4 | hardware-info 之 email 未綁定 tokenserver.js |
中高 | ✅ 已修復 | 新增歸屬檢查:email 須為 partner 本人,或其 ownerUid 指向該 partner 的子帳號,否則 403 並寫入警告日誌。已以三組不同 partner token 實測:正常與子帳號皆通過、跨租戶皆被拒。 |
| 5 | mastercode 寫入 DOM 屬性admin.js |
中 | ✅ 已修復 | 選鎖清單改以 data-idx 索引對應 JS 閉包內的資料陣列,mastercode 完全不再輸出至 HTML。 |
| 6 | lockname 未跳脫致儲存型 XSSadmin.js |
中 | ✅ 已修復 | 新增 escapeHtml(),所有進入 innerHTML 的 RTDB 外部資料(lockname、lockid)一律先行跳脫。 |
⛓️ 原攻擊鏈:已於兩處阻斷
仍可讀,但已無 token
private 匿名不可讀
歸屬檢查 403
已無法達成
private/credentials → PERMISSION_DENIED;匿名讀 settings/config → PERMISSION_DENIED;匿名試圖將 token 寫回公開文件 → PERMISSION_DENIED;匿名刪除管理員 → PERMISSION_DENIED。同時 PMS 同步寫入與訪客頁公開讀取皆維持正常。
⚠️ 殘留風險與後續建議
admins 回 PERMISSION_DENIED)。
- Git 歷史殘留憑證:檔案已清理,但歷史紀錄仍可還原,該 token 與對應 master_code 應視同已洩漏並輪替。← 目前唯一待辦的高優先事項
- 服務帳戶金鑰保管:
data/visitor_service_account.json權限已設為 600 且不隨deploy.sh同步(腳本排除data/)。此金鑰權限極大,請勿進版控;原始下載檔建議自 Downloads 移除。 - 訪客申請單為公開讀寫:因訪客未登入,
requests仍須開放讀寫(僅刪除已收歸管理員)。若申請單含個資,建議後續改以後端代理或簽章連結存取。 - admins 根文件仍公開可讀:供訪客頁取 logo/大樓名稱,內含 email 等非機敏欄位(憑證已完全移除)。如需杜絕 email 列舉,可再將品牌資訊移至獨立公開子文件。
- PMS 自動開通帳號使用固定密碼
123456(server.jsIdentity Toolkit 建立流程)。此為既有開通流程設計,未逕行變更以免影響現行導入作業;建議改為隨機密碼並強制首次登入變更。
📝 門禁智慧管理 — AI Agent 與 MCP 架構討論注記
2026-08-03 討論紀錄:門禁智慧管理上 AI Agent 與 MCP 的可行方向、落地順序與關鍵設計決策。核心框架:MCP 負責接系統、Agent 負責做事。
🎯 討論結論摘要
最值得先做的是把門禁主機/管理平台的 API 包成一套 MCP Server,因為所有 Agent 應用都建立在這層之上;接著再挑 2~3 個高價值 Agent 場景落地。Tools 依風險分三級(唯讀/寫入/控制),寫入與控制類一律走審批流,實體控制永遠保留人工確認。
🔌 一、MCP Server 層(基礎建設,先做)
把既有門禁系統的能力包成標準化 Tools,讓任何 AI(Claude、自建 Agent、客服 Bot)都能呼叫。依風險分三級:
query_access_logs— 查刷卡/進出紀錄(人、門、時間區間、結果)get_person_permissions— 查某人有哪些門的權限、效期get_door_status— 門的即時狀態(開/關/離線/異常)get_device_health— 讀卡機、控制器在線與故障狀態list_visitors— 訪客預約與到訪紀錄
grant_access/revoke_access— 開通、停用權限create_visitor_pass— 建立訪客 QR code / 臨時卡set_access_schedule— 設定時段規則
remote_open_door— 遠端開門lockdown/release_lockdown— 封鎖模式
另可再包兩個周邊 MCP:影像系統(調閱某門某時段的監視器截圖/片段供 Agent 比對)與 HR 系統(員工到離職名單,權限治理的資料源頭)。
🤖 二、AI Agent 應用方向(按價值排序)
| # | Agent 方向 | 說明 |
|---|---|---|
| 1 | 💬 自然語言查詢/報表助理 | 最容易落地、立即有感。管理員直接問「上週六有誰進過機房?」「哪些門今天有異常刷卡失敗?」Agent 呼叫唯讀 Tools 組合出答案、產表格或圖表。可直接嵌進現有 Vue 管理後台當對話面板。 |
| 2 | 🔑 權限治理/稽核 Agent | 價值最高的隱形需求。定期排程盤點:離職員工卡未停用(比對 HR 名單)、90 天未使用但仍有效的權限(最小權限原則建議回收)、權限異常集中者;自動產出稽核報告,ISO 27001/客戶稽核直接使用。 |
| 3 | 🚨 異常偵測與告警 Agent | 即時/準即時分析進出事件流:非上班時段進入敏感區、同卡短時間內在距離很遠的兩門刷卡(clone 卡嫌疑)、連續刷卡失敗(試探行為)、門被撐開超時、控制器離線。偵測後 Agent 先做初步調查(調監視器截圖、查行為模式),把「事件+脈絡+建議處置」一起推給管理員,而非冷冰冰的 alert。 |
| 4 | 🛎️ 訪客管理 Agent | 員工自然語言申請:「明天下午三點有兩位廠商來 5 樓開會」→ Agent 建立訪客單、產生 QR code、寄邀請信、到訪時通知接待人,逾時未離場自動提醒。是寫入類最好的第一個場景(臨時權限、影響範圍小)。 |
| 5 | 🔧 維運助理 Agent | 「B2 讀卡機離線了」→ Agent 查設備 log、判斷網路或硬體問題、比對過去故障紀錄、開工單並附上診斷結論。 |
🗺️ 三、建議落地順序
- MCP Server 唯讀 Tools + 查詢助理 — 風險最低,一兩週能做出 Demo,馬上展示價值
- 權限治理排程 Agent — 用同一套唯讀 Tools,加 HR 資料比對
- 寫入類 Tools + 審批流 — 以訪客管理為第一個寫入場景
- 即時異常偵測 — 需要事件流架構(webhook / queue),放後面
- 遠端控制類 — 最後做,且永遠保留人工確認
🛡️ 四、關鍵設計決策(要先想清楚)
- Agent 的權限 = 呼叫者的權限:MCP Tool 執行時帶上使用者身分,樓管與 CEO 問同一題,能看到的範圍應不同。不給 Agent 一把萬能 API Key。
- 實體安全的不可逆性:開門、停權出錯的代價是實體的,confirm-before-act 不是 UX 選項,是硬性規則。
- 個資問題:進出紀錄屬個資(台灣個資法),Agent 查詢範圍、log 保存、雲端 LLM 資料出境問題要先定調 — 也影響是否考慮地端模型。
❓ 五、待確認/後續討論事項
- 串接的門禁主機廠牌(SOYAL / Hundure / HID / 自建系統?)與是否有現成 API
- 確定後可進一步設計實際的 MCP Tool Schema 與審批流程的資料模型
- 與既有 Cellbedell「MCP 與 AI Agent 升級規劃」的 Tools/審批機制(LINE Flex 確認)如何共用同一套設計
AWS EC2 多應用部署架構
單一主機透過 Nginx 反向代理,以路徑節點掛載多個獨立應用服務。
架構設計理念
💡 為什麼用一台 EC2?
使用一台 EC2 搭配 Nginx 反向代理是目前最經濟且靈活的方案。
一個固定 IP (3.27.15.192),
可以透過「路徑節點」掛載無限多個應用,各應用之間完全獨立、互不干擾。
未來若流量增長,可隨時拆分為獨立主機或升級為 Load Balancer 架構。
📊 流量分流架構圖
PM2 → Port 3000靜態檔案服務PM2 → Port 8899靜態檔案服務📋 應用服務對照表
| 專案名稱 | 類型 | 部署方式 | URL 路徑 | 狀態 |
|---|---|---|---|---|
| Cell API Manager | Node.js API | PM2 (Port 3000) |
/pms/ |
運行中 |
| Vsitth 訪客管理 | 靜態前端 + Firebase | Nginx 靜態服務 |
/vsitth/ |
運行中 |
| Meeting System | 靜態前端 + Firebase | Nginx 靜態服務 |
/meeting/ |
運行中 |
| AI Cube 健康監測 | 靜態前端 | Nginx 靜態服務 |
/aicube/ |
運行中 |
| Blockchain Test | 靜態前端 | Nginx 靜態服務 |
/blockchain/ |
運行中 |
| 採購分析物料成本 | Node.js + SQLite | PM2 (Port 8899) |
/bom/ |
規劃中 |
🖥️ EC2 主機資訊
🧭 架構決策:一台 EC2 還是多台?
目前開發方向分為兩大類,性質不同但共用同一台 EC2:
| 🔌 API 串接管理 | 🖥️ 前後端應用開發 | |
|---|---|---|
| 代表專案 | Cell API Manager | Vsitth、BOM 採購分析、Meeting System |
| 性質 | 對外開放的 API 閘道,第三方廠商會打進來 | 內部/自用工具,瀏覽器直接操作 |
| 安全等級 | 🔴 較高 (JWT、API Key、廠商機密) | 🟢 一般 (Firebase Auth 驗證) |
| 流量來源 | 機器對機器 (M2M),24/7 自動化 | 人為操作,上班時間為主 |
✅ 現階段結論:使用一台 EC2 + Nginx 子路徑
- 成本最優:一台 EC2 (t3.micro) 約 $8-10 USD/月,兩台則翻倍
- 維護集中:一個地方做安全更新、看 Log、管理 SSH Key
- 隔離足夠:各應用跑在獨立 PM2 進程,互不影響。Nginx 路徑分流本身即邏輯隔離
- 天然支持擴展:未來若要拆分,只需把 Nginx 的 proxy_pass 指向新 IP,零改動
⚡ 什麼時候該拆成兩台 EC2?
| 觸發條件 | 說明 | ||
|---|---|---|---|
| 合作廠商數量 > 10+ | API 流量開始影響前端應用的回應速度 | ||
| 客戶要求安全合規 | 例如 ISO 27001 要求生產 API 與內部工具實體隔離 | ||
| 團隊分工需求 | 不同人負責不同系統,需要獨立部署權限與 SSH Key | ||
| 服務可用性 SLA | API 需保證 99.9% 不中斷,不能因為前端部署而 reload |
| 對比維度 | SDK 背景自動 PINGREQ (Keep-Alive) | 韌體主動定時 PUBLISH JSON 心跳 |
|---|---|---|
| 封包大小 | 極小 (僅 2 位元組) 標頭 0xC0 0x00,無 Payload |
較大 (約 150~500 位元組) 包含 TCP 標頭、MQTT 標頭與 JSON 內容 |
| 韌體程式碼工作量 | 零 (完全免寫代碼) 由 SDK 在背景執行緒/任務中全自動維護 |
中等 需維護硬體定時器、JSON 序列化與 Publish 狀態重試 |
| 硬體晶片功耗 | 極低 天線僅需發送 2 Byte,耗時極短,隨即進入深休眠 |
較高 天線發射資料時間長,需消耗更多 CPU 算力進行編譯 |
| AWS 與資料庫計費 | 零訊息費 / 極低 DB 費用 AWS 規定 Ping 包不收費。配合生命週期事件,僅於斷連線時寫入 DB |
正常收費 每次發送計入 AWS 訊息費,且每 60 秒強行觸發 Lambda 與寫入 DB |
| 適用場景 | 「在線狀態 (Online/Offline)」維護 不需回報具體硬體數據的純心跳判定 |
「設備狀態監控 (Telemetry)」 需要定時上報電量、訊號強度、溫濕度等真實數據 |
💡 物聯網混和架構最佳實踐 (Hybrid Strategy)
- 連線狀態:完全交給 MQTT SDK 底層 Keep-Alive (2-Byte PINGREQ) 處理,雲端配合 AWS IoT Lifecycle Events,達成零程式碼在線維護與極致省電。
- 硬體數據 (電量/訊號強弱):不要每 60 秒定時發送 JSON。改採「事件驅動上報」(如電量每降 5% 才發送一筆,或 WiFi 斷開重連時發送一筆)或「超長週期定期上報」(如每 12 或 24 小時發送一筆作為底線備份)。
5. 設備端 MQTT SDK 的獲取與配置指引
若要實現上述 Keep-Alive 長連接心跳,硬體研發團隊可以根據晶片與開發平台,透過以下方式獲取並配置 MQTT SDK:
☁️ AWS 官方物聯網 SDK (AWS IoT Device SDK v2)
官方針對微控制器、嵌入式 Linux 與各種語言有深度優化,內建完整的 mTLS(雙向證書加密)、自動重連與 Keep-Alive 機制。
- C / Embedded C SDK (最推薦微控制器):GitHub 官方庫 (適用資源受限的單晶片門禁機)。
- Python SDK (閘道器適用):安裝指令
pip install awsiotsdk。 - Node.js / JS SDK:安裝指令
npm install aws-iot-device-sdk-v2。
🔌 晶片廠商原生 SDK 與開源標準 Client
AWS IoT Core 完全相容標準 MQTT 3.1.1 及 5.0,因此所有支援 TLS 安全加密傳輸的標準 MQTT SDK 皆可開箱即用。
- ESP32 (ESP-IDF 官方框架):自帶標準
esp_mqtt,只需在配置結構體esp_mqtt_client_config_t中指明keepalive = 60;即可啟動底層背景自動 Ping 運作。 - Arduino IDE 生態:可直接於庫管理器搜尋安裝 PubSubClient 或 arduino-mqtt,並使用
setKeepAlive(60)設定。 - 工業開源標準 (Eclipse Paho):相容 C, C++, Java, Go 等,下載自 Eclipse Paho 官網。
🌡️ MQTT/溫濕度 數據對接
深度探討第三方廠商獲取設備溫濕度資料的三大核心對接架構與最佳實踐
1. 溫濕度數據對接系統架構 (System Architecture)
當硬體端(門禁機/環境監控器)採集到溫濕度數據後,會透過安全 MQTT 通道發送至 AWS IoT Core。以下是將這些溫濕度數據安全、高效地分享給第三方(如 PMS、物業管理軟體)的完整架構路徑:
graph TD
%% Base Nodes
subgraph "🔒 內部安全網絡 (Private Internal Network)"
Dev[硬體設備 / 溫濕度傳感器] -- "1. MQTT Publish (溫濕度 JSON)" --> AWS[AWS IoT Core]
AWS -- "2. Rules Engine (直寫 / 無 Lambda)" --> DB[(Firebase / DynamoDB)]
DB -.-> API[Cell API Manager (Nest/Express)]
end
subgraph "🏢 第三方介接網絡 (Third-Party Integration Network)"
API -- "方案一: REST API (GET)" --> REST[第三方 PMS / 物業管理伺服器]
AWS -- "方案三: 專屬 IAM 受限訂閱" --> MQTT[第三方 IoT 監控中心]
%% Webhook Path
AWS --> Lambda[AWS Lambda / Webhook Worker]
Lambda -- "方案二: Webhook POST (主動推播)" --> REST
end
classDef aws fill:#FF9900,stroke:#232F3E,stroke-width:2px,color:#000000;
classDef device fill:#10B981,stroke:#047857,stroke-width:2px,color:#000000;
classDef firebase fill:#FFCA28,stroke:#F57C00,stroke-width:2px,color:#000000;
classDef app fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#000000;
class Dev device;
class AWS,Lambda aws;
class DB firebase;
class REST,MQTT,API app;
2. 三大數據對接方案深度對比
針對不同的業務場景與即時性需求,我們為第三方提供了三種不同的數據對接路徑:
方案一:被動拉取式 (REST API GET)
運作方式: 第三方伺服器在需要顯示環境數據時(例如:房務點開房間詳情頁),主動發送 GET /api/device/{id}/telemetry 請求。您的 API Manager 從 Firebase 讀取最新狀態快照並返回。
- 安全級別: 極高(受 API Gateway 與 JWT Token 嚴格保護)
- 即時性: 中等(取決於第三方查詢頻率)
- 適用場景: 常規儀表板顯示、每日環控報表統計
方案二:主動推播式 (Webhook POST)
運作方式: 第三方在您的平台註冊一個 Callback URL。當溫濕度數據發生顯著變化時(例如:溫度增減超過 ±0.5°C),您的 Webhook Worker 主動發送 HTTP POST 請求將最新 JSON 數據推給廠商。
- 安全級別: 高(透過網址簽章 HMAC SHA256 驗證)
- 即時性: 極高(毫秒級變更推播)
- 適用場景: 機房高溫警報、異常濕度即時通知
方案三:直連訂閱式 (AWS MQTT Subscription)
運作方式: 您在 AWS IoT Core 內為第三方簽發受限的憑證與安全策略(Policy)。廠商伺服器透過 MQTT 長連接訂閱限定的 Topic 路徑(如 partner/{partner_id}/device/{device_id}/telemetry)即時監聽。
- 安全級別: 中等(需精準配置 AWS IoT Policy,否則易有越權風險)
- 即時性: 極致即時(Sub-second 級別物聯網直連)
- 適用場景: 專業物聯網中控大屏、高頻率數據串流分析
| 對接指標 | 方案一:REST API (GET) | 方案二:Webhook (POST) | 方案三:MQTT 訂閱 (SUB) |
|---|---|---|---|
| 即時性 (Latency) | 低(依賴輪詢,有時間差) | 極高(事件變更立即推送) | 極致(亞秒級網路串流) |
| 安全維護難度 | 極低(標準 JWT 驗證) | 中等(需維護 Webhook 驗簽機制) | 極高(需維護 AWS IAM 與證書策略) |
| 伺服器頻寬開銷 | 高(廠商頻繁輪詢時會造成壓力) | 極低(僅變更時發送一次) | 中等(需維持 TCP 長連接維持線路) |
| 廠商對接門檻 | 極低(會寫 HTTP GET 即可) | 低(廠商僅需提供一個接收端點) | 高(廠商需實作 MQTT 客戶端與密鑰管理) |
⚠️ 平台多租戶安全防線(Security Warning)
- 絕對禁止將 Firebase 讀寫權限直接開放給第三方: Firebase 為內部業務微服務與私有 App 的直連通道。直接洩露 Firebase 憑證將導致多租戶資料隔離完全破產,屬於重大安全性漏洞!
- API 統一閘道原則: 第三方獲取任何硬體數據(溫濕度、開門日誌、連線狀態),必須統一經過您的 API Manager,利用 JWT 與設備授權關係表(Device Ownership Map)進行嚴格的物理性權限隔離。
- 數據節流控制: 在開放溫濕度對接時,需在 API Manager 層級限制查詢頻率(例如同一廠商限制每分鐘最多 30 次請求),避免惡意或不當編寫的第三方腳本癱瘓資料庫。
Nginx 反向代理設定
EC2 上的 Nginx 設定檔範本與部署指令備忘錄。
Nginx 設定檔範本
📄 /etc/nginx/sites-available/multi-app
server {
listen 80;
server_name 3.27.15.192;
# ─── Cell API Manager (Node.js via PM2) ───
location /pms/ {
proxy_pass http://127.0.0.1:3000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# ─── Vsitth 訪客管理系統 (靜態前端) ───
location /vsitth/ {
alias /var/www/vsitth/;
try_files $uri $uri/ /vsitth/index.html;
}
# ─── 未來: 採購分析系統 (Node.js via PM2) ───
# location /bom/ {
# proxy_pass http://127.0.0.1:8899/;
# }
# ─── 預設首頁 ───
location / {
return 301 /pms/;
}
}
🔧 部署指令備忘
🚀 Vsitth 部署腳本 (本機端執行)
testVsit/Vsitth/ 專案目錄中,執行 vite build 後,
使用 rsync 將 dist/ 資料夾同步至 EC2 的 /var/www/vsitth/。
#!/bin/bash
# deploy-vsitth.sh
echo "=========================================="
echo "🚀 部署 Vsitth 訪客管理系統至 AWS EC2"
echo "=========================================="
# 1. Build
echo "📦 正在執行 Vite Build..."
npm run build
# 2. Upload
echo "📤 正在同步至 EC2..."
rsync -avz --delete \
-e "ssh -i ~/AWS_Key/pms-api-key.pem" \
dist/ ubuntu@3.27.15.192:/var/www/vsitth/
# 3. Reload Nginx
echo "🔄 重新載入 Nginx..."
ssh -i ~/AWS_Key/pms-api-key.pem ubuntu@3.27.15.192 \
"sudo systemctl reload nginx"
echo "=========================================="
echo "✅ 部署完成!"
echo "🌐 https://3.27.15.192/vsitth/"
echo "=========================================="
⚠️ 重要注意事項
部署至 EC2 後,必須在 Firebase Console → Authentication → Settings → Authorized domains 中, 將
3.27.15.192 加入授權清單,否則 Firebase Auth 登入功能會被阻擋。
若購買了域名 (例如
vsitth.thinkpos.com),可改用子域名搭配
Let's Encrypt 免費 SSL 憑證,輕鬆升級為 HTTPS 安全連線。
💰 費用暴增原因分析
深入解析 AWS IoT Core 的計費方式與異常飆高的真兇
為何帳單會倍數成長?
🧮 費用試算 (以 20 台設備為例)
- 發送頻率: 每台設備每 5 秒發送 1 筆 → 每分鐘 12 筆 → 每天 17,280 筆。
- 總發布量: 20 台設備每天產生 345,600 筆,一個月約產生 1,036 萬筆 寫入。
- 訂閱乘數: AWS IoT 的計費為「發佈」與「訂閱」分別計費。若您的後端伺服器 (Firebase/Node) 訂閱了這些資料,就會產生同樣 1,036 萬筆的「傳出訊息」費用。如果有 2 個後端或網頁開著,量就翻倍。
- 結論: 光是基礎傳輸,每個月就會產生近 2000~3000 萬筆計費訊息,這完全符合帳單呈指數上升的軌跡。
🚨 主機記憶體/磁碟事故
2026-08-07 連線異常事故紀錄、根本原因、處置與日後快速診斷手冊
事故紀錄:網站間歇性斷線 (ERR_TIMED_OUT)
當時的症狀
- cell-nexus.com 出現 ERR_TIMED_OUT,cell-assistant.com 回應慢到 13 秒,時好時壞。
- SSH 連線在 banner exchange 階段逾時(主機忙到連登入都排不上)。
- pms-api 的 PM2 重啟次數快速增加(318 → 323),uptime 永遠只有幾十秒。
- 錯誤日誌大量出現 RTDB Timeout 與 ERR_HTTP_HEADERS_SENT。
根本原因(三層疊加)
- 記憶體太小又無 Swap:主機僅 908MB RAM,跑三個 node 程序 + nginx;pms-api 啟動基線約 200MB(初始化多個 Firebase 專案連線),操作後台儀表板時尖峰衝到約 350MB,kernel 便 OOM 強殺(dmesg 內累積 26 次紀錄,87 天共重啟 323 次,平均一天 3~4 次)。
- 磁碟被日誌塞到 97% 滿:PM2 日誌無輪替,堆了 1.2GB(大多是崩潰時噴的錯誤堆疊),磁碟只剩 238MB。
- 程式小蟲放大日誌量:信件預覽 API 重複呼叫 res.send,每次都往日誌噴一條 ERR_HTTP_HEADERS_SENT 堆疊(已修復)。
已完成的處置(2026-08-07)
- ✅ 清除 1.2GB PM2 舊日誌,磁碟從 97% 降回 74%。
- ✅ 安裝 pm2-logrotate:單檔上限 10M、保留 7 天、自動壓縮,日誌不會再無限膨脹。
- ✅ 建立 1GB swapfile(開機自動掛載,vm.swappiness=10):記憶體尖峰改為換頁變慢,而不是殺程序斷線。磁碟僅 6.7GB,放 2GB swap 需先擴充 EBS。
- ✅ 修復信件預覽 API 重複 res.send 的程式錯誤。
- ✅ 合作夥伴管理頁頂端新增「系統健康狀態卡」,每 60 秒自動更新。
日後如何及時知道原因(診斷手冊)
先看合作夥伴管理頁頂端的系統健康狀態卡:🔴 代表已達危險(記憶體 < 150MB 或磁碟 < 500MB);「API 服務剛啟動」的警示若非人工部署所致,就代表剛發生過 OOM 重啟。要進一步確認時 SSH 進主機執行:
sudo dmesg -T | grep -i 'out of memory' # 有輸出 = 發生過 OOM 強殺
free -m && df -h / # 看記憶體/Swap/磁碟現況
pm2 list # ↺ 欄位暴增 + uptime 極短 = 崩潰循環中
後續處置進度
- ✅ 已根治(2026-08-07 晚):升級 t3.small——RAM 908MB → 2GB(可用記憶體約 1.2GB),同時完成:PM2 記憶體上限 320M(超標優雅重啟取代 OOM 硬殺)、PM2 開機自動復原(systemd)、配發 Elastic IP
52.65.169.17(日後停機重開 IP 不再變動、DNS 同步更新)。月費約 +US$10。 - ✅ 已處理(2026-08-07 晚):EBS 擴充 8GB → 15GB(線上擴容不停機,+約 US$0.67/月),磁碟使用率降至約 52%,Swap 同步加大至 2GB。
- Firebase 連線數(未處理):pms-api 同時初始化多個 Firebase 專案是 200MB 基線的主因,長期可考慮按需初始化。
💰 費用分析與建議(2026-08-07 Cost Explorer 實查)
- 上月(2026-07)實績:US$100.06;本月至今(8/1–8/7)US$19.27,月底預估約 US$116。
- 服務別拆分(本月至今):AWS IoT US$14.63(76%)> EC2 主機 US$1.84(換算約 US$8/月)> Route 53 US$1.00 > VPC US$0.71。
- 建議優先序:① 優化 IoT MQTT 訊息量(見「費用暴增原因 / 處理的方式」的 Lifecycle Events 方案),這裡才有每月數十美元的空間;② 升級 t3.small 根治 OOM(+約 US$10/月);③ EBS 擴充視磁碟成長再說(+US$0.77/月)。
- 費用資料來源:合作夥伴管理頁頂端的「💰 AWS 費用」卡片每日自動更新(Cost Explorer API 每日 3 次請求、約 US$0.9/月),並隨每日 09:00 LINE 摘要一併推播。
🔐 同日完成的資安優化
- EC2 IAM Role「pms-ec2-cost-reader」:主機查費用改走 IAM Role(僅 ce:GetCostAndUsage / ce:GetCostForecast 兩個唯讀權限),AWS 金鑰不落地到主機。
- Root 金鑰已停用:本機 CLI 原使用 root 帳號 Access Key(外洩等於整個帳號淪陷),已改用 IAM 使用者 bryan-admin(可稽核、可撤銷),root 舊金鑰已設為 Inactive(可於 Console 反悔重啟)。
- JWT 簽章密鑰已脫離原始碼(同日晚間):原本寫死在 server.js 的密鑰等於看過程式碼即可偽造管理員登入,已改為 data/jwt_secret.key 隨機密鑰(0600 權限、不隨部署同步),並實測舊密鑰簽發的 token 已被拒絕。
- ✅ root 金鑰已徹底刪除、MFA 已確認啟用(實體安全金鑰):AccountAccessKeysPresent = 0,root 帳號已無任何 API 金鑰,本機備份檔一併銷毀。資安待辦全數完成。
🛠️ 架構處理與優化方式
如何停止無效的頻繁發送,改用官方最佳實踐
導入 AWS IoT 生命週期事件 (Lifecycle Events)
在物聯網架構中,如果單純為了「確認設備存活」而頻繁發送資料,是非常昂貴且沒效率的。我們應改用底層的 Keep-Alive 機制。
1. 底層的 Keep-Alive 機制 (免收訊息費)
ESP32 與 AWS IoT 連線時,會約定一個 Keep-Alive 時間(如 60 秒)。若這段時間沒傳資料,ESP32 會自動發送超小的 PINGREQ 封包。AWS 不會對這種 PING 收取訊息費!
2. AWS 自動發佈斷線事件
一旦 AWS 偵測到 ESP32 沒發 PING (超時) 或正常斷線,系統內部會自動發一筆事件到隱藏頻道:
連線: $aws/events/presence/connected/{clientId}
斷線: $aws/events/presence/disconnected/{clientId}
3. 設定 IoT Rule 寫入 Firebase
- 到 AWS IoT 建立一個 Rule,語法:
SELECT * FROM '$aws/events/presence/#' - 觸發動作設定為 AWS Lambda
- Lambda 內將事件寫入 Firebase (例如
status: 'offline') - 效益: 一天一台設備大概只會觸發幾次事件,完全省下每天上萬次的浪費!
📊 高效率低成本架構圖
視覺化呈現 AWS IoT 與 Firebase 的完美整合
1. 系統元件架構圖 (Architecture Flow)
graph TD
subgraph 邊緣設備
ESP32[ESP32 硬體設備\n- 維持底層 PING\n- 僅在數值變化時發送資料]
end
subgraph AWS 雲端服務
IoT_Core[AWS IoT Core\n- 負責管理 MQTT 連線\n- 監控 Keep-Alive 超時]
Topic_Presence[內部隱藏主題\n$aws/events/presence/#]
IoT_Rule[AWS IoT Rule\n監聽連線與斷線事件]
Lambda[AWS Lambda\n處理狀態更新程式]
ESP32 -- "建立 / 中斷連線" --> IoT_Core
ESP32 -. "底層 MQTT PINGREQ\n(免收訊息費)" .- IoT_Core
IoT_Core -- "自動產生連線/斷線事件" --> Topic_Presence
Topic_Presence -- "觸發規則" --> IoT_Rule
IoT_Rule -- "呼叫" --> Lambda
end
subgraph Firebase 雲端資料庫
DB[(Firebase Database\n儲存設備最新狀態\nstatus: online/offline)]
Lambda -- "API 寫入/更新連線狀態" --> DB
end
subgraph 使用者端
APP[手機 App / 網頁儀表板\n- 隨時開啟隨時查看狀態\n- 無須喚醒硬體]
DB -- "即時狀態同步 (Listener)" --> APP
end
classDef aws fill:#FF9900,stroke:#232F3E,stroke-width:2px,color:#000000;
classDef device fill:#10B981,stroke:#047857,stroke-width:2px,color:#000000;
classDef firebase fill:#FFCA28,stroke:#F57C00,stroke-width:2px,color:#000000;
classDef app fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#000000;
class ESP32 device;
class IoT_Core,Topic_Presence,IoT_Rule,Lambda aws;
class DB firebase;
class APP app;
2. 事件觸發時序圖 (Sequence Diagram)
sequenceDiagram
autonumber
participant ESP32 as ESP32 設備
participant AWS_IoT as AWS IoT Core
participant AWS_Rule as IoT 規則 (Rule)
participant Lambda as AWS Lambda
participant Firebase as Firebase DB
participant App as 手機 App
Note over ESP32, AWS_IoT: 平常待機狀態 (省錢模式)
loop 每 60 秒 (Keep-Alive)
ESP32->>AWS_IoT: 發送 MQTT PINGREQ (維持連線)
AWS_IoT-->>ESP32: 回傳 MQTT PINGRESP
end
Note over ESP32, App: 情境 A:設備異常斷線
ESP32-xAWS_IoT: 網路斷線 / 斷電 (無 PING 訊號)
AWS_IoT->>AWS_IoT: 偵測到 Keep-Alive 超時!
AWS_IoT->>AWS_Rule: 發佈至 $aws/events/presence/disconnected/
AWS_Rule->>Lambda: 攔截事件,觸發 Lambda
Lambda->>Firebase: 更新資料庫: status = "offline"
Firebase-->>App: 手機 App 即時推播 "設備已離線"
Note over ESP32, App: 情境 B:設備重新上線
ESP32->>AWS_IoT: 網路恢復,重新建立 MQTT 連線
AWS_IoT->>AWS_Rule: 發佈至 $aws/events/presence/connected/
AWS_Rule->>Lambda: 攔截事件,觸發 Lambda
Lambda->>Firebase: 更新資料庫: status = "online"
Firebase-->>App: 手機 App 即時推播 "設備已上線"
⚡ AWS IoT Core 運作與監控機制
EC2 系統架構、HTTP 轉 MQTT 控制 API、CloudWatch 指標監控與實體報文規格解析
1. EC2 與 AWS IoT Core 雙向架構概述
本系統於 AWS EC2 雲端伺服器上部署了 PMS API Manager 中樞與 pms-mqtt-bridge 常駐轉發服務。透過整合 AWS IoT Core(區域:ap-southeast-2 雪梨區),實現安全、低延遲的雙向 MQTT 硬體設備控制、雲端紀錄落庫及費用流量即時監控。
POST /api/hardware/publish 將 HTTP 控制請求轉發至 AWS API Gateway Lambda (PublishToMQTT),再發佈給 MQTT Broker。pms-ec2-cost-reader) 自動拉取 CloudWatch 數據,比對雙門檻並交由 Gemini LLM 診斷推播。api_logs,支援 LINE 安全白名單遙控重啟。2. 硬體指令 API 轉發流程 (HTTPS ➔ AWS Lambda ➔ MQTT)
第三方 PMS 或前端透過 API Manager 喚醒硬體設備的標準傳輸鏈結:
3. MQTTLogAgent — 訊息暴衝與費用 AI 監控機制
AWS IoT Core 費用占總帳單約 76%。系統內建 mqttLogAgent.js 自動進行雲端費用監控:
⚡ 告警觸發雙門檻 (Double Thresholds)
- 動態倍率門檻:最近一小時總訊息數 > 前 24 小時平均值的 2 倍 (且 > 10,000 則)。
- 絕對上限門檻:最近一小時總訊息數 > 200,000 則/小時。
- 冷卻機制:觸發告警後開啟 2 小時冷卻,避免訊息轟炸。
🧠 AI 診斷與 LINE 警報連動
- 指標選取:抓取 Namespace
AWS/IoTProtocolMQTT之PublishIn.Success、PublishOut.Success、Connect.Success。 - LLM 診斷:交由 Gemini (MasterBrain) 分析封包暴衝原因(如韌體迴圈發送、重複訂閱)。
- LINE 推播:輸出 Flex Message 視覺卡片至管理人員頻道。
4. MQTT 報文結構與真實 Payload 範例 (Topic: bridge/+)
從 bridge/Cellbedell_IB_hyg67 主題截獲的真實事件 Payload 結構說明:
{
"CreatCardReturn": "CreateSuccess",
"blename": "Cellbedell_IB_hyg67",
"type": "R",
"userid": "5GmerWorwibgj8DnXYGzsrYcry93",
"time": "1786424277"
}
CreateSuccess / CreateCard...)、設備名稱 (blename)、操作類型 (type)、使用者 UID 與時間戳記。
{
"data": ",nestech00r9A10NSnaGAhzGW/hLYj1sgw31CQkGlW3Qo..."
}
pms-mqtt-bridge 接收後解密並執行與門鎖的指令交換。
5. EC2 MQTT 完整通訊與 AI 監控架構時序圖
sequenceDiagram
autonumber
participant Client as 前端 App / 第三方 PMS
participant EC2_API as EC2 (PMS API Manager)
participant AWS_GW as AWS API Gateway (Lambda)
participant AWS_IoT as AWS IoT Core (MQTT Broker)
participant Device as 實體硬體 (門鎖/發卡機)
participant Bridge as EC2 (pms-mqtt-bridge)
participant CW as AWS CloudWatch
participant Agent as MQTTLogAgent + Gemini LLM
participant LINE as LINE 推播通知
Note over Client, Device: 1. 控制指令發佈流程
Client->>EC2_API: POST /api/hardware/publish (帶 Token & data)
EC2_API->>AWS_GW: HTTPS 轉發至 PublishToMQTT Lambda
AWS_GW->>AWS_IoT: 發佈至 MQTT Topic: bridge/${device_serial}
AWS_IoT->>Device: MQTT 訊息推送至硬體設備
Note over Device, Bridge: 2. 設備響應與數據落庫
Device-->>AWS_IoT: 回傳 MQTT 狀態報文 (bridge/Cellbedell_...)
AWS_IoT-->>Bridge: pms-mqtt-bridge 接收報文
Bridge->>Bridge: 解析 JSON/密文數據並寫入 api_logs
Note over EC2_API, LINE: 3. 流量異常監控與 AI 警報 (每 30 分鐘)
Agent->>CW: 抓取 AWS/IoT PublishIn/Out, Connect 指標
CW-->>Agent: 回傳流量數據
alt 觸發倍率門檻 (>2x 均值) 或 絕對門檻 (>200k/時)
Agent->>Agent: 進行 Gemini LLM 事件原因分析
Agent->>LINE: 發送 LINE Flex Message 異常告警
end
💡 建議實作做法與策略
給硬體與軟體團隊的最佳實踐指南
硬體端的降載策略
1. 延長傳輸週期
一般環境數據(溫濕度、空氣品質)不會在 5 秒內有劇烈變化。建議將一般待機時的資料傳送頻率從 5 秒改為 3~5 分鐘,如此可瞬間減少 95% 以上的通訊量。
2. 變化時才傳送 (Report on Exception)
在 ESP32 韌體加入邏輯:只有當感測器數值變化超過特定門檻(例如溫度差 0.5度、有人員進入),或者超過 5 分鐘沒發送時,才發佈訊息。兼具即時性與經濟性。
3. 打包資料 (Batching)
如果系統真的需要高頻率的數據點,可讓設備在內部記憶體收集 1 分鐘的資料後,打包成一個 JSON Array 一次發送。只要單筆 Payload 不超過 5KB,AWS IoT 均以 1 筆計費。
4. 手機 App 喚醒「即時模式」
- 當使用者打開手機 App 時,App 寫入一個 Flag (例如
mode: 'realtime') 到 Firebase。 - ESP32 訂閱該狀態,並將傳輸頻率暫時提高到 2 秒 1 次。
- 使用者關閉 App 後,將狀態復原,設備也切回 5 分鐘 1 次的省錢模式。
🛡️ 系統登入安全防護與規劃
為 PMS API 控制台提供全方位的資安防禦,抵禦暴力破解、會話劫持及常見的 Web 安全漏洞。
資安防護與升級策略
🛡️ 主動防禦核心理念
本平台的資安升級以「最小特權」、「主動防禦」與「縱深防禦」為原則。登入系統的資安防護著重於限制惡意請求速率、防止帳號猜測、加強傳輸管道加密以及收斂跨域授權,從而確保 API 管理後台免受未授權存取與滲透風險。
1. 速率限制 (Rate Limiting) — 防止暴力破解
為了防範惡意機器人使用自動化工具或字典攻擊爆破管理員密碼,系統針對登入端點部署了速率限制限制器:
- 限制規則: 限制同一個 IP 在 15 分鐘內最多僅能嘗試登入 5 次。
- 超載響應: 超過限制次數的 IP,伺服器將拒絕後續請求並回傳
HTTP 429 Too Many Requests。 - 實現細節: 基於記憶體計數器,快速比對請求來源 IP。
2. 帳號鎖定機制 (Account Lockout)
為防止針對單一特定帳號(例如管理員帳號)進行持續性的密碼猜測,系統實施了帳號自動暫時性鎖定:
- 觸發條件: 當特定帳號連續密碼輸入錯誤達 5 次 後,系統會自動在資料庫中記錄鎖定狀態。
- 鎖定懲罰: 該帳號將會被鎖定 15 分鐘,在此期間內即使輸入了正確密碼,伺服器亦會拒絕登入。
- 安全提示: 登入回應會使用模糊化的提示語(“帳號或密碼錯誤,或帳號已被停用”),避免暴露帳號是否存在或是否已被鎖定。
3. 安全標頭與 CORS 存取收斂
加固伺服器 Response Headers,減少被探測敏感資訊或遭受第三方惡意網頁攻擊的機會:
Content-Security-Policy、X-Frame-Options(防範點擊劫持)與 Strict-Transport-Security 等 HTTP 安全標頭,強迫瀏覽器實施最嚴格的網路安全性限制。
Access-Control-Allow-Origin: * 通配符進行收斂,設定僅能允許信任的指定後台網域、測試網域發起 API 呼叫,阻絕外部惡意網站透過跨站腳本探測後端 API。
4. 安全傳輸與儲存 (HttpOnly Cookie)
防範常見的 XSS (Cross-Site Scripting) 跨站腳本攻擊所導致的憑證竊取:
localStorage 中的 Token 可以輕易地被任何執行的 JS 腳本讀取,若網頁中使用了有漏洞的第三方套件,將面臨 Token 遭外洩的重大風險。
安全升級方案:
- 將 JWT 改以
HttpOnly Cookie的方式傳輸與儲存。 - 開啟
Secure標記(僅允許 HTTPS 傳輸)與SameSite=Strict(避免 CSRF 跨站請求偽造攻擊)。 - 如此一來,任何前端 JavaScript 腳本都無法讀取此 Token,能達到極高的會話防盜安全等級。
5. 登入防護與驗證流程圖
回傳 HTTP 429
回傳 HTTP 423
若滿 5 次鎖定 15 分鐘
回傳 HTTP 401
🔒 Cellbedell 系統資安防護與規劃
為 Cellbedell 專案引入 PHP 伺服器端會話 (Session) 驗證,並藉由 Firebase Admin SDK 進行安全憑證驗證。
Cellbedell 系統與 PMS API Manager 資安對比
兩個系統的開發語言與架構模式截然不同,因此防禦重點與手段亦有所區別:
| 比較項目 | 🔑 PMS API Manager (Node.js) | 📦 Cellbedell 系統 (PHP) |
|---|---|---|
| 驗證模式 | 本地 Node 伺服器 API 自行認證 | 前端對接 Firebase Auth (第三方認證) |
| 主要資安風險 | 暴力密碼破解、XSS 竊取憑證等 | 前端跳轉可遭繞過、DOM 結構外洩 |
| 核心防禦手段 | 速率限制、失敗鎖定、HttpOnly Cookie | PHP 伺服器端 Session 阻斷、Token 交換驗證 |
🛡️ Cellbedell 安全補強作法
1. 伺服器端 PHP Session 阻斷防護
為了解決「禁用 JavaScript 即可繞過登入頁面」的致命漏洞,我們在 Cellbedell 系統所有頁面共同引用的核心檔案 layouts/helper.php 最頂部,加入 PHP 原生 Session 阻斷邏輯。
若未通過伺服器端 Session 驗證,伺服器將直接下達 header('Location: login.php') 指令重定向,拒絕輸出任何後台 HTML 結構,從根本上防範 DOM 洩露。
2. Firebase ID Token 後端雙軌驗證機制 (Token Exchange)
為確保伺服器端 Session 不能被客戶端輕易偽造,登入流程採用了**安全權杖交換模式 (Token Exchange)**:
- 使用者在前端登入成功後,取得 Firebase 發行的 ID Token (JWT)。
- 前端將該 Token 傳送給 PHP 寫入 API
set_session.php。 set_session.php在伺服器後端將 Token 發送至PMS_API_Manager的/api/auth/verify-firebase-token。- Node 端使用具備完整金鑰與憑證的 **Firebase Admin SDK** 進行驗證,確認其為合法簽發的 Firebase 使用者憑證。
- 驗證成功後,PHP 端才會寫入
$_SESSION['cbd_logged_in'] = true,安全授權登入狀態。
3. 安全登出銷毀機制
建立專門的 logout.php 檔案。當使用者點擊登出時,前端會引導至該檔案。它會在伺服器端徹底執行 session_destroy() 銷毀會話,並清除 Cookie 及 LocalStorage 緩存,確保會話無法再被重複使用。