# i3 FM 混合式平台 — 架構需求文件（ARD）

## 1. 文件資訊與目的

| 項目 | 內容 |
| --- | --- |
| 文件名稱 | i3 FM 混合式平台 架構需求文件（Architecture Requirements Document, ARD） |
| 版本 | v1.0 |
| 日期 | 2026-09-03 |
| 作者 | i3 FM 設計團隊 |
| 適用專案 | i3-fm-platform-hybrid.design（設施管理平台） |
| 相關文件 | docs/PRD.md（產品需求文件）、pages/architecture.html（系統架構圖）、pages/access-control.html（角色與權限架構） |

**目的**：本文件將 PRD 嘅功能需求轉化為可實施嘅架構需求，涵蓋系統上下文、組件架構、數據模型、整合介面（MQTT／BACnet／SOAP）、API 與 RLS 策略、保安合規、部署監控，並提供「PRD 20 個 Session ↔ ARD 章節」對照表，作為開發、測試與部署嘅技術基準。

**Ground truth 聲明**：以專案內 `pages/architecture.html`（系統架構圖與數據流說明）及 `pages/access-control.html`（角色階層與權限矩陣）為既定事實；凡屬設計假設均以「（假設：…）」標示。

---

## 2. 架構原則與非功能需求

### 2.1 架構原則

1. **單一中央數據平面（Single Instance）**：所有站點共用一個中央 Supabase／Postgres 實例；**唔做 per-site 資料庫部署**。多租戶隔離以 `site_id` 邏輯隔離＋RLS 實現，而非實體分庫。
2. **現場分離（Hybrid）**：現場層每 site 獨立部署 Site Gateway 與前端 Web App（頁面亦標示「離線優先 · 本地實例」），就地收斂現場數據；雲端層單一中央數據平面與 Root Console。
3. **資料統一（Normalize Once）**：MQTT（感應器）、BACnet/IP（BMS）、SOAP（供應商系統）三種來源喺 Site Gateway 統一為 canonical JSON（補 `site_id`＋`timestamp`）先寫入數據平面；後端與報表永遠只面對一種格式。
4. **授權分層（Defense in Depth）**：前端 route guard（UX 輔助）＋後端 API 角色檢查（保安邊界）＋資料庫 RLS（最後防線）三層配合；Gateway 以 service role 寫入，前端用戶絕不直接寫 telemetry。
5. **權限階層可管理（Manage Downward Only）**：每一層級只能 handle 其下層級嘅 account；site_owner 可 invite owner（同級）／admin／staff／contractor；site_admin 只可派 staff／field（防自升權限）；support 全系統唯讀。
6. **可配置而非硬編碼**：SLA 規則、警報規則、評分規則、碳排係數、審計保留期全部參數化（settings／rules 表）。

### 2.2 非功能需求（技術視角）

| 類別 | 需求 | 技術含義 |
| --- | --- | --- |
| 保安 | 一切傳輸 TLS；RBAC＋RLS 雙重隔離；密碼雜湊；append-only audit | TLS 終止喺 API 層與 Gateway；Supabase RLS policy 版本管理 |
| 效能 | 感應器→DB 可見端到端延遲 ≤ 10 秒；常用聚合查詢 P95 ≤ 2 秒；首屏 LCP ≤ 2.5 秒 | telemetry 寫入用 batch insert；儀表板／能源查詢用 materialized view 或排程預聚合 |
| 可用性 | 繁中／EN 雙語；現場報到流動友善；狀態色滿足 AA 對比 | i18n 資源表；響應式元件；設計 token 管顏色 |
| 可擴展 | 新站點＝新增 site 記錄＋部署 Gateway，毋須新資料庫；單一 DS 以連線池／讀寫分離應對 | site_members 一對多；Gateway 每 site 獨立部署天然水平攤分連線 |
| 可維護 | migration 向前兼容；版本號（如 v1.4.2）顯示；immutable build | Sequelize／Prisma migration 流程；CI build artifact 版本化 |
| 數據保留 | audit 180 日；telemetry 原始數據保留 13 個月後聚合歸檔；（假設）報表永久 | 排程封存 job；冷儲存策略 |

---

## 3. 系統上下文圖（文字描述）

```
┌─────────────────────────── 現場層（每一個 Site 一套） ───────────────────────────┐
│                                                                              │
│   BMS / 物聯網設備                                                           │
│   ├── 感應器（溫濕度・能耗・設備狀態）───────────────────┐                    │
│   ├── BMS（BACnet/IP Points）───────────────────────────┤                    │
│   └── 供應商系統（SOAP Web Service）────────────────────┤                    │
│                                                        ▼                    │
│                                          ┌─────────────────────┐            │
│                                          │  Site Gateway        │            │
│                                          │  · MQTT Broker       │            │
│                                          │  · BACnet Adapter    │            │
│                                          │  · SOAP Adapter      │            │
│                                          │  · Normalize（canonical JSON）     │
│                                          └──────────┬──────────┘            │
│                                                     │ TLS（service role）     │
│   Site Web App（前端・每 site 獨立部署）             │                         │
│   （離線優先 · 本地實例 v1.4.2）                     ▼                         │
└──────────────────────────────────────────────────────────────────────────────┘
                                        │
                                        ▼
                    ┌─────────────────────────────────────────┐
                    │  平台核心（雲端・單一 instance）          │
                    │  Supabase / Postgres                     │
                    │  · RLS 按 site_id 隔離                   │
                    │  · API（REST・RBAC 檢查）                 │
                    │  · Auth（JWT・session・refresh）         │
                    │  · 排程 jobs（expiry・月報・封存）        │
                    └─────────────────────────────────────────┘
                                        │
                                        ▼
                    ┌─────────────────────────────────────────┐
                    │  Root Console（中央控制台・跨站唯讀總覽）  │
                    │  developer（全系統）／support（全系統唯讀）│
                    │  （例外：site_sites 管理、稽核查閱）       │
                    └─────────────────────────────────────────┘

用戶角色（經 Site Web App 或 Root Console 存取）：
developer（最高權限）→ support（唯讀）→ site_owner → site_admin → site_staff
→ field：technician（無 expiry）／contractor（有 expiry）
```

**數據流摘要**：現場設備 → 三種 adapter → Normalize（canonical JSON，補 `site_id`＋`timestamp`）→ Gateway 以 service role 寫入中央 Supabase telemetry 表 → API 層按用戶角色／site membership 過濾 → 前端渲染。緊急應變「上報中央」以快照同步方式推送至 Root Console（唯讀）。

---

## 4. 組件架構

### 4.1 Presentation（前端 Web App）

- **Site Web App**：每 site 獨立部署一套（含登入頁站點選擇、儀表板、票務池、警報中心、緊急應變、維修工單、保養計劃、能源分析、承辦商評分、合規、日結、月報、稽核日誌、用戶與角色、站點管理（中央用）等 18 個頁面設計）；以登入頁下方「離線優先 · 本地實例 v1.4.2」標示版本；支援繁中／EN 切換與主題切換。
- **Root Console**：中央控制台（developer／support 登入），跨站唯讀總覽；站點管理（sites）為例外嘅中央寫入功能。
- 共用設計系統：design token CSS（brand／background／text／state 色階、light/dark semantic mapping）、共用元件庫（Button、Badge、Card、Table、Select、Input、Field、Modal、Tabs、Toast）。

### 4.2 Application／API（平台核心）

- REST API（Supabase PostgREST／Edge Functions 或同等層）：每模組一組 endpoint（見第 7 節）。
- Auth 服務：登入（站點＋密碼／Root 登入）、JWT 簽發與 refresh、session 管理、登出。
- RBAC middleware：按 JWT claims（user_id、角色經 site_members 解析）做權限檢查；角色階層與 8 項權限能力對應 access-control.html 矩陣。
- 排程 jobs：contractor expiry 自動停權（每日）、月報自動生成（每月 1 日）、audit 封存（180 日）、telemetry 聚合歸檔（13 個月）、合規到期提醒。

### 4.3 Data（Postgres schema）

- 單一中央 Supabase／Postgres 實例；schema 詳見第 5 節。
- 多租戶：所有 site 相關表含 `site_id`；RLS 按 `site_id`＋角色範圍強制隔離。
- 寫入策略：用戶前端只經 API（RLS 用戶身份）；Gateway 用 service role（bypass RLS）寫 telemetry／對應設備表；audit_log 為 append-only。

### 4.4 Integration（Site Gateway）

- **MQTT Broker**：訂閱感應器 topics；QoS≥1、retained 狀態 topic、斷線自動重連、本地 buffer。
- **BACnet Adapter**：輪詢 BMS Points；點表映射（Object/Property → canonical metric name）配置化。
- **SOAP Adapter**：呼叫供應商 Web Service；endpoint 認證（假設：HTTP Basic／WS-Security）；超時與重試（3 次、指數退避）。
- **Normalize 層**：三路輸入統一為 canonical JSON（`site_id`、`timestamp`、`source`、`metric`、`value`、`unit`、raw metadata）；單位／範圍驗證；錯誤寫入 error 日誌。
- Gateway 每 site 獨立部署（container），連線失敗時本地暫存、恢復後補送。

### 4.5 Auth／RBAC

- users（全域身份）＋ site_members（site 內角色、status、expiry）組合決定權限。
- 角色階層（7 角色）：developer → support（唯讀）→ site_owner → site_admin → site_staff → field（technician／contractor）。
- 管理鏈：每一層級可 handle 其下所有層級；site_owner 可 invite owner（同級）／admin／staff／contractor；site_admin 只可派 staff／field（防自升權限）；support 冇 invite、冇 expiry 管理權。
- Invite link 一次性、7 日 expiry、鎖定 role／site。

---

## 5. 數據模型（核心 Table）

以下為核心資料表建議。所有 site 相關表均含 `site_id` 並受 RLS 控制；每表附訪問角色備註（對照 access-control.html 權限矩陣）。

### 5.1 users（用戶主檔）

- 欄位：`id`、`email`（唯一）、`password_hash`、`display_name`、`phone`、`locale`（zh-Hant／en）、`status`（active／disabled）、`created_at`、`updated_at`。
- 訪問備註：developer 可管理全部；support 可讀（人事資料唯讀）；site_owner／site_admin 只能經 site_members 了解自己 site 嘅成員用戶（password_hash 任何角色都唔可讀）。

### 5.2 roles（角色定義）

- 欄位：`id`、`key`（developer／support／site_owner／site_admin／site_staff／technician／contractor）、`name`、`level`（階層次序）、`description`。
- 内建 7 列；`level` 用於「每一層級 handle 其下層級」嘅管理鏈推論。訪問：developer 可編輯定義（角色定義／系統設定係 developer 專屬權限）；其餘角色唯讀。

### 5.3 permissions（權限能力）

- 欄位：`id`、`key`、`name`、`description`。内建 8 項能力：Account 管理、人事資料存取、設備／資產 CRUD、數據讀取、Invite link 發出、Contractor expiry 管理、現場報到、角色定義／系統設定。
- 訪問：developer 全權；其餘按矩陣（見 access-control.html）。

### 5.4 site_members（用戶↔站點・一對多）

- 欄位：`id`、`user_id`、`site_id`、`role_key`、`status`（active／invited／disabled／expired）、`expires_at`（nullable；contractor 必填）、`invited_by`、`joined_at`、`created_at`、`updated_at`。
- **一對多**：同一 user 可喺多個 site 有唔同 membership，各自記錄 role／status／expiry；跨 site 唔互撞（PRD Session 4 驗收項）。
- 訪問備註：僅該 site 嘅 owner／admin（同 jQuery級別與下級）可管理；developer 可跨站管理全部；support 唯讀；staff／field 只可以睇到自己嘅 membership。
- **Contractor expiry**：`expires_at` 由 site owner／admin 設定或延長；到期由排程 job 將 status 轉 expired；expired 無法報到（field_attendance 寫入前檢查）。

### 5.5 sites（站點主檔）

- 欄位：`id`、`name`、`region`、`type`（寫字樓／工廈／商場等）、`timezone`、`address`、`status`（provisioned／online／pending_sync）、`gateway_config`（JSON）、`version`、`created_at`、`updated_at`。
- 訪問：developer 可 CRUD（站點管理屬中央控制台）；site_owner 只可編輯自己 site 嘅非金鑰設定；其餘站點角色只讀自己 site；support 唯讀。

### 5.6 tickets（票單）

- 欄位：`id`、`ticket_no`（T-YYYYMMxx）、`site_id`、`subject`、`floor`、`priority`（severe／high／medium／low）、`status`（open／assigned／in_progress／resolved／closed）、`vendor_id`（nullable）、`reported_by`、`assigned_to`、`first_response_at`、`sla_deadline`、`updated_by`、`updated_at`、`created_at`。
- 訪問：site_staff 及上級可 CRUD 自己 site；field 只限被指派單；support／developer（Root）跨站存取。
- SLA：`sla_deadline` 由規則參數（假設：嚴重 30 分鐘／高 60／中 4 小時／低 24 小時首次回應）計算；「SLA 達標率」以此欄位統計。

### 5.7 maintenance_work_orders（維修工單）

- 欄位：`id`、`wo_no`（WO-2409-xxx）、`site_id`、`ticket_id`（nullable，由票單轉來）、`title`、`priority`、`status`（new／in_progress／pending_acceptance／completed／cancelled）、`assigned_to`（technician／contractor user id）、`vendor_id`、`sla_deadline`、`completed_at`、`result`（完工記錄）、`updated_by`、`updated_at`、`created_at`。
- 訪問：staff 及以上 CRUD；field 只限指派畀自己嘅工單（「只限指派」權限）＋到場報到（牽涉 field_attendance）；support 唯讀。

### 5.8 maintenance_plans（保養計劃）

- 欄位：`id`、`site_id`、`task_name`、`frequency`（daily／weekly／monthly／quarterly／yearly）、`equipment_id`、`status`（scheduled／in_progress／completed／overdue）、`last_run_at`、`next_due_at`、`assigned_to`、`updated_by`、`updated_at`。
- 訪問：staff 及以上可管理；technician／contractor 只可睇同回報被指派任務；「本月完成率」＝完成／應完成（目標 90%）。

### 5.9 field_attendance（現場報到）

- 欄位：`id`、`site_id`、`user_id`、`work_order_id`（nullable）、`check_in_at`、`check_out_at`、`expiry_checked`（bool）、`result`（ok／expired／forbidden）、`created_at`。
- **規則**：technician 與 contractor 到場都必須報到（現場報到權限＝「需要報到」）；contractor membership 已過期時報到被拒（PRD Session 10）。
- 訪問：developer／support（檢視）、site_owner／site_admin／site_staff（自己 site 檢視）；field 只可建立自己嘅報到記錄。

### 5.10 contractors（承辦商主檔）

- 欄位：`id`、`company_name`、`service_scope`、`contact_email`、`contact_phone`、`contract_end_date`、`site_id`（或經 membership 多 site）、`status`、`created_at`、`updated_at`。
- 訪問：owner／admin 管理（連 membership expiry 一齊管理）；staff 檢視；developer 全站管理；support 唯讀。
- 與 site_members（role＝contractor）關聯：contractor 帳號嘅有效性由 membership.expires_at 決定；`contract_end_date` 為商務提醒。

### 5.11 vendor_scores（承辦商評分）

- 欄位：`id`、`contractor_id`、`site_id`、`avg_response_time`、`completion_rate`、`quality_score`、`overall_score`（加權）、`trend`、`rated_at`、`updated_at`。
- 訪問：owner／admin 可設定「評分規則」；其餘按矩陣唯讀／檢視（developer 全站、support 唯讀）。

### 5.12 alerts（警報）

- 欄位：`id`、`site_id`、`severity`（critical／warning／info）、`system`（HVAC／lift／fire／water／power／security）、`status`（unhandled／in_progress／resolved）、`source`（auto／manual）、`rule_id`（nullable）、`title`、`detail`、`occurred_at`、`resolved_at`、`created_at`。
- 訪問：staff 及以上處理自己 site；field 只限相關指派；support 唯讀。
- 關聯 alert_rules（條件、等級、目標系統）與通知事件（header 通知鈴）。

### 5.13 telemetry（現場數據・統一格式）

- 欄位：`id`、`site_id`、`timestamp`、`source`（mqtt／bacnet／soap）、`device_id`、`metric`、`value`、`unit`、`raw`（JSON）、`created_at`。
- 寫入：僅 Site Gateway 以 service role 寫入；前端用戶不可直接寫。RLS 對外唯讀（按 site_id）。
- 保留：原始數據 13 個月後聚合歸檔（假設）；能源分析／儀表板以預聚合查詢讀取。

### 5.14 incidents（緊急事故）

- 欄位：`id`、`incident_no`（INC-xxx）、`site_id`、`title`、`severity_level`、`status`（not_started／active／closed）、`mobilized_count`、`avg_response_minutes`、`target_minutes`、`central_report_snapshot_no`、`timeline`（JSON 事件鏈）、`closed_at`、`created_at`。
- 訪問：site_staff 及以上處理；「上報中央」快照經特殊管道入 Root Console（支援 developer／support 唯讀查閱）。

### 5.15 compliance_items（合規事項）

- 欄位：`id`、`site_id`、`item_name`、`category`（電力裝置檢查／水質／升降機註冊／消防器材／緊急照明／外牆等）、`status`（passed／failed／pending_review／expired）、`risk_level`、`next_check_date`、`responsible_user`、`updated_by`、`updated_at`。
- 訪問：owner／admin 可改狀態；staff 檢視；support 唯讀；到期自動標記 expired＋通知。

### 5.16 audit_log（稽核日誌・append-only）

- 欄位：`id`、`site_id`（nullable，中央操作可空）、`user_id`、`role_key`、`action`（login／logout／create_ticket／update_settings／delete_record／report_to_central／export_report 等）、`target_type`、`target_id`、`result`、`source`（central_console／local_site）、`ip`、`created_at`。
- **append-only**：無 update／delete 入口；DB trigger 禁止修改；RLS 唔授任何角色 UPDATE／DELETE。保留 180 日，之後封存（假設：冷儲存）。
- 訪問：developer 全量；support 唯讀全量（人事查詢）；site_owner／site_admin 只可查自己 site 嘅記錄。

### 5.17 daily_close（日結）

- 欄位：`id`、`site_id`、`close_date`、`checklist`（JSON：8 項＋逐項狀態／完成時間／操作者）、`progress_pct`、`signed_by`、`signed_at`、`frozen`（bool）、`created_at`。
- 訪問：staff 完成檢查、owner／admin 簽署；簽署後凍結並寫 audit。

### 5.18 monthly_reports（月報）

- 欄位：`id`、`site_id`、`report_month`、`summary`（JSON：營運率、工單、警報同比、能耗同比、分類占比）、`generated_at`、`generated_by`（system／user）、`export_path`。
- 訪問：staff 及以上自己 site；developer 跨站；support 唯讀。每月 1 日排程生成。

### 5.19 invites（邀請連結）

- 欄位：`id`、`site_id`、`role_key`（鎖定）、`email`（nullable）、`token_hash`、`expires_at`（7 日）、`used_at`（用後即棄）、`invited_by`、`status`（pending／used／expired）、`created_at`。
- 訪問：owner（可 invite 同級＋下級）／admin（只可下級）可建立；使用時驗證 token 未過期、未使用、role 未被竄改。

---

## 6. 整合介面需求

### 6.1 MQTT（感應器數據）

- **角色**：Site Gateway 內建 MQTT Broker／Client，訂閱現場感應器 topics。
- **Topic 格式**：（假設）`i3fm/{site_id}/{device_id}/{metric}`；payload 為 JSON（含 value、unit、讀數時間）。狀態類（device online/offline）用 retained message（QoS 1）確保新訂閱者即時拎到最新狀態。
- **QoS 與保留**：數據訊息 QoS≥1；重連機制（exponential backoff）；連線中斷期間訊息本地 buffer，恢復後補送（或按 topic 保留策略決定取捨）。
- **數據格式**：進入 Normalize 後一律為 canonical JSON：`{ site_id, timestamp, source: "mqtt", device_id, metric, value, unit, raw }`。
- **保安**：（假設：MQTT over TLS 8443；client certificate 或 username/password 認證）；topic 權限只讀現場用，唔開放公開 publish。

### 6.2 SOAP（供應商系統）

- **角色**：Site Gateway 嘅 SOAP Adapter 定時／事件觸發呼叫供應商 Web Service（例如合約承辦商報表、第三方系統查詢）。
- **Endpoint 認證**：（假設：HTTP Basic 或 WS-Security UsernameToken——以供應商實際提供為準；credentials 存於 Gateway 加密配置）。
- **輪詢／推送**：優先支援供應商推送；若只支援輪詢，Adapter 以可配置間隔拉取；（假設：預設每 15 分鐘，可按 site／vendor 調整）。
- **錯誤處理**：超時（假設：30 秒）＋重試 3 次、指數退避（1s／4s／16s）；連續失敗寫入 error 日誌並產生 gateway_health 訊號；唔好令單一 vendor 故障拖垮成個 Gateway。
- **數據格式**：SOAP XML response 喺 Adapter 內 deserialize，轉 canonical JSON 先入 Normalize。

### 6.3 BACnet/IP（BMS）

- **角色**：BACnet Adapter 輪詢 BMS Points（例如冷凍機組高壓跳掣、供水泵狀態）。
- **點表映射**：BACnet Object/Property → canonical metric name 嘅映射表配置化（每個 site 可唔同）；支援 WhoIs／ReadProperty 基礎輪詢。
- **頻率**：輪詢間隔按 site／point 類別可配置（假設：關鍵點 30 秒、一般點 5 分鐘）。
- **錯誤處理**：不可達設備重試＋標記該設備離線；原始值單位轉換喺映射層完成。

### 6.4 寫入規則（Gateway → 中央）

- 單一寫入管道：Gateway 使用 service role（bypass RLS），經 API／SQL 邊界寫入 telemetry 與設備健康表；所有寫入都帶 `site_id＋timestamp`。
- 斷網緩衝：Gateway 本地 queue，恢復連線後按序補送（保留原始 timestamp，避免時間錯位）。

---

## 7. API 需求與 RLS 策略

### 7.1 API 分類（按模組）

| 模組 | 主要 API 類別 | 寫入權限要求（對照權限矩陣） |
| --- | --- | --- |
| Auth | POST /auth/login（站點）・POST /auth/login-root・POST /auth/refresh・POST /auth/logout | 公開（登入）；refresh 需有效 token |
| Users | GET/POST/PATCH /users、GET /users/{id} | developer 全量 CRUD；owner/admin 僅限自己 site membership 相關（invite 流程走 invites）；support 唯讀 |
| Invites | POST /invites（帶 role+site）、POST /invites/{token}/accept、GET /invites | owner（同級＋下級）／admin（下級）可建；support 無權 |
| Sites | GET/POST/PATCH /sites、GET /sites/{id}/stats | developer CRUD；其餘角色 GET 僅限自己 site |
| Tickets | GET/POST/PATCH /tickets、GET /tickets/stats | staff＋上級 CRUD 自己 site；field 只限指派 |
| Work Orders | GET/POST/PATCH /work-orders、POST /work-orders/{id}/assign | staff＋上級；field 只限指派（完工更新） |
| Maintenance | GET/POST/PATCH /maintenance-plans、POST /{id}/complete | staff＋上級管理；field 只限指派任務回報 |
| Attendance | POST /attendance/check-in・check-out、GET /attendance | 只有 technician／contractor 可建立自己；開發者／owner／admin／staff 檢視 |
| Contractors | GET/POST/PATCH /contractors、PATCH /{id}/expiry | owner／admin 管理 expiry；developer 全站；support 唯讀 |
| Vendor scores | GET/POST/PATCH /vendor-scores、PATCH /scoring-rules | owner／admin 設定規則；檢視按矩陣 |
| Alerts | GET /alerts、POST /alerts（手動）、PATCH /alerts/{id}/status、POST /alert-rules | staff＋上級；自動警報由警報引擎（service）產生 |
| Telemetry | GET /telemetry（聚合）、POST 僅 Gateway | 讀取按 site RLS；寫入僅 service role |
| Energy | GET /energy/summary・/energy/curve・/energy/breakdown、GET /energy/export | 讀取按 site RLS |
| Incidents | POST /incidents/start、PATCH /incidents/{id}、POST /incidents/{id}/report-central | staff＋上級；report-central 產生 snapshot 供中央唯讀 |
| Compliance | GET/POST/PATCH /compliance-items | owner／admin 改狀態；staff 檢視 |
| Audit | GET /audit-log、GET /audit-log/export | developer／support 全量；owner／admin 限自己 site |
| Daily close | GET/POST/PATCH /daily-close、POST /{date}/sign | staff 填寫；owner／admin 簽署 |
| Monthly report | GET /monthly-reports、POST /{month}/generate | staff＋上級；system job 自動生成 |

### 7.2 RLS（Row Level Security）策略建議

- 通用原則：所有 site 相關表預設 policy 為「用戶必須係該 site 嘅 active member」（`EXISTS (SELECT 1 FROM site_members WHERE site_id = X AND user_id = auth.uid() AND status = 'active')`）。
- **角色範圍收窄**：
  - field（technician／contractor）：SELECT 僅限「指派畀自己」嘅工單／任務／報到；所有寫入僅限建立自己嘅 attendance、更新指派畀自己嘅工單狀態。
  - site_staff：自己 site 全表 SELECT＋非管理類寫入；無 account／invite／expiry 權限。
  - site_admin：自己 site 全表（含人事）但「派角色」僅限 staff／field；禁 create owner/admin membership。
  - site_owner：自己 site 全表＋可 invite 同級（co-owner membership 建立權限）。
  - support：全系統 SELECT（唯讀，含 audit／人事）；所有 INSERT/UPDATE/DELETE 拒絕。
  - developer：全系統 SELECT/INSERT/UPDATE/DELETE（受角色定義／系統設定專屬能力保護嘅表除外）。
- **特殊表**：`audit_log` 冇 UPDATE/DELETE policy（append-only）；`telemetry` INSERT 僅 service role（Gateway），用戶側只 SELECT。
- **身份來源**：JWT／auth.uid 對應 users；site 上下文由 membership 解析（`site_members.role_key` 提供行級角色判斷，避免依賴前端傳 site_id）。
- **測試**：RLS 政策納入 migration 版本管理；UAT 專項測試「跨 site 數據洩漏」（PRD Session 20）。

---

## 8. 保安與合規需求

### 8.1 身份與密碼

- 密碼政策：（假設：最少 12 字元、需大小寫＋數字；禁止常見弱密碼）；bcrypt/argon2 雜湊；登入失敗鎖定（假設：連續 5 次鎖 15 分鐘）。
- Session：access token（假設：2 小時）＋refresh token（假設：7 日）；refresh token 輪換、登出即撤銷。
- Root 登入：僅 developer 可用；登入至 Root Console 嘅 session 帶 `console=root` claim，RLS 同樣作用。

### 8.2 授權

- 後端每 API 檢查角色（middleware）；前端 route guard 只係 UX 輔助。
- 管理鏈強制：site_admin 建立 owner/admin membership 喺 API 與 RLS 雙層拒絕。
- support 全寫操作拒絕（包括 invite、expiry、工單狀態）。

### 8.3 Audit logging

- 所有關鍵動作（login／logout、create_ticket、update_settings、delete_record、report_to_central、export_report、工單狀態變更、attendance、expiry 變更、compliance 狀態、daily_close 簽署、月報生成）寫入 audit_log。
- append-only（DB trigger 禁 update/delete）；保留 180 日（假設：之後封存冷儲存）；支援 CSV 匯出（匯出本身亦記 audit）。

### 8.4 Invite link 安全

- 一次性使用、7 日過期（假設）、鎖定 role＋site；token 以 hash 儲存；使用後置 used；過期自動轉 expired；被拒絕嘅邀請（例如嘗試改 role）記 audit。

### 8.5 Contractor expiry 自動停權

- 每日排程掃描 site_members（role=contractor）到期記錄：status→expired；遠期提醒（假設：到期前 30／7 日）走通知引擎。
- expired 即時生效：field_attendance check-in 前檢查 membership status/expiry；過期拒絕報到（錯誤碼 EXPIRED_MEMBERSHIP）。

### 8.6 合規（法規面向）

- 個人資料（人事、承辦商聯絡）最少權限存取；data retention 對應主檔 180 日 audit 政策；繁中／英文文件可追溯；合規事項（電力裝置檢查、水質檢測、升降機註冊續期等）本身由 compliance_items 管理（營運合規，非僅技術合規）。

---

## 9. 部署與監控需求

### 9.1 部署拓撲

- **雲端**：單一中央 Supabase／Postgres 實例（含 Auth、API、排程 jobs）；隻此一個 database instance，唔做 per-site deploy。
- **現場層**：每 site 部署 Site Gateway（container，內含 MQTT Broker、BACnet Adapter、SOAP Adapter、Normalize）＋ Site Web App（static build，掛 site 專屬登入設定）；部署流程以 immutable build artifact（版本號如 v1.4.2）進行。
- **Root Console**：中央控制台（同雲端托一齊部署或用同一 build），developer／support 專用入口。
- **Migration**：中央 DB 以 migration 工具管理（向前兼容）；RLS policy 隨 migration 一齊管。

### 9.2 配置管理

- 每個 site 嘅 gateway 配置（MQTT credentials、BACnet 點表、SOAP endpoints、輪詢間隔）存於 sites.gateway_config（JSON），Gateway 啟動時下載／或本地 secret 注入。
- 環境變數管理 secrets；唔將 credentials 入版控。

### 9.3 監控

- **中央監控**：API latency、DB 連線使用率、排程 job 執行狀態、audit 寫入量；警報引擎同告警規則即時反映 telemetry 異常。
- **Gateway 健康**：online／offline 心跳（retained MQTT topic）、buffer 深度、重連次數、SOAP 失敗率；站點管理頁顯示「已部署 6／在線 5／待同步 1／緊急警報 2」等真實狀態統計。
- **警報**：未處理警報、SLA 逾期、能源異常納入站點卡片與 Root Console 跨站總覽（唯讀）。

### 9.4 備份與復原

- 中央 DB 自動備份（假設：每日全量＋WAL）；每月還原演練；telemetry 歸檔策略（13 個月後聚合歸檔）減低備份體積。
- Gateway 本地 buffer 提供斷網數據復原；復原補送保留原始 timestamp。

### 9.5 上線檢查清單（配合 PRD Session 20）

- migration＋RLS 政策驗證、備份與監控啟動、audit_log 啟動、contractor expiry 排程、月報自動生成排程、UAT P0/P1 缺陷清零、培訓完成、支援窗口建立。

---

## 10. PRD 20 個 Session ↔ ARD 章節對照表

| PRD Session | Session 標題 | 主要對應 ARD 章節 / 交付 |
| --- | --- | --- |
| 1 | 專案 setup 與設計系統基建 | §4.1（Presentation／設計系統）、§2.2（NFR）、§9.1（部署拓撲初版） |
| 2 | 登入與 Auth 流程 | §4.5（Auth）、§7.1（Auth API）、§8.1（身份與密碼） |
| 3 | RBAC 角色層級與權限矩陣實作 | §4.5（RBAC）、§5.2/5.3（roles/permissions）、§7.2（RLS） |
| 4 | Invite link 與 account 管理（site_members 一對多） | §5.4（site_members）、§5.19（invites）、§8.4（invite 安全） |
| 5 | 站點管理與 onboarding | §5.5（sites）、§9.2（gateway 配置）、§4.4（Gateway 註冊） |
| 6 | 儀表板 | §7.1（KPI 聚合 API）、§7.2（RLS site 隔離）、§4.1（前端） |
| 7 | 票務池 | §5.6（tickets）、§7.1（tickets API）、§7.2（RLS） |
| 8 | 維修工單 | §5.7（maintenance_work_orders）、§7.1（work-orders API） |
| 9 | 保養計劃 | §5.8（maintenance_plans）、排程引擎（§4.2 jobs） |
| 10 | 現場報到（technician／contractor 到場報到） | §5.9（field_attendance）、§8.5（expiry 即時生效） |
| 11 | 承辦商管理與 expiry | §5.10/5.11（contractors／vendor_scores）、§8.5（自動停權排程） |
| 12 | 警報中心與通知引擎 | §5.12（alerts）、§4.2（通知引擎）、§9.3（監控告警） |
| 13 | MQTT／SOAP 數據入口接線 | §6.1-6.4（MQTT/SOAP/BACnet/Normalize 寫入）、§5.13（telemetry） |
| 14 | 能源分析 | §5.13（telemetry 聚合）、§7.1（energy API）、§2.2（效能 NFR） |
| 15 | 緊急應變流程 | §5.14（incidents）、§7.1（report-central 快照） |
| 16 | 合規 | §5.15（compliance_items）、§8.6（合規） |
| 17 | 稽核日誌 | §5.16（audit_log append-only）、§8.3（audit logging） |
| 18 | 日結 | §5.17（daily_close）、§7.1（daily-close API） |
| 19 | 月報 | §5.18（monthly_reports）、§4.2（每月 1 日排程）、§7.1（生成 API） |
| 20 | UAT、部署、培訓同上線 | §9.1-9.5（部署／監控／上線檢查清單）、§7.2（RLS 專項測試） |

---

（文件完）