# VM 管理、帳務與經銷平台整合規格

版本：v3.0｜日期：2026-09-21｜狀態：SaaS 商業模式已納入；控制平面與收款介接開發中，尚未正式收費營運。

本文件整合既有 VM 規格與集中主控商業模式。`/control` 為真實控制平面工作台；原 `/` 為介面原型。實作與未完成項目以 [實作進度](../docs/implementation-status.md) 為準。

v2.1 明確固定重裝模式：**管理員匯入一次官方 ISO，集中製作並發布 QCOW2 母映像；客戶之後開通或重裝，直接套用已發布母映像，不再跑 ISO 安裝流程。** 更新 OS、修補或安裝設定時製作新映像版本，不原地修改已發布母映像。

## 0. 集中主控與 HOST 訂閱（v3.0）

本產品對外提供集中託管 SaaS：平台營運者維護控制平面，VPS 業者接入自己的 KVM HOST、RouterOS、線路與 IPPOOL。每台受管運算 HOST 訂閱，月繳或年繳，不以 VM 數量限制軟體資格；資源配額、硬體容量與終端客戶付款資格仍須符合。純映像建置節點不計費，首版不提供永久託管方案或 VPS 成交抽成。

- 四層角色：平台營運者 → VPS 業者 → 經銷商 → 終端客戶。`tenant_id` 固定代表業者，不與經銷商／終端客戶共用身份層級。既有區域及 HOST UUID 保留。
- 平台管理員管理業者、HOST 價格及訂閱；業者自行管理所屬資源、人員與零售帳務。跨業者支援需由業者授予最多 60 分鐘的唯讀診斷授權，存取留稽核；不授予永久帳戶或任意寫入。
- 平台帳務只收 HOST 軟體服務費；業者帳務收取 VPS、流量及儲值款。兩套收款範圍、憑證、回調與帳本分離。未配置有效 USD 月／年價格，不上架收款；可設定業者協議價格。
- Stripe 採 Connect 業者直接收款，不以平台代收作備援。平台 HOST 訂閱使用平台帳戶。TRC20 僅接收及核對鏈上付款，不持有提款金鑰，不假定 USDT 永遠等於 USD。
- HOST 以單次業者註冊憑證、穩定 UUID 與 Agent 金鑰識別；動態公網 IP、重連、離線及 VM 數量改變均不自動增減授權。雙向 SSH 連線模式仍適用。
- 已付款名額原子綁定 HOST；新增數量先報價／收款，未知付款結果不增額。減量、取消及月年切換於期末生效。名額轉移不可同時綁定兩台 HOST，不刪除舊 HOST 的 VM 或網路。
- 續費失敗寬限七天，之後限制新建 VM、擴容與新綁定。既有 VM 管理、重裝、換密碼、換 IP、救援及匯出保持可用；HOST 軟體訂閱欠費不觸發 VM 關機、刪除或 NAT 修改。客戶 VPS 欠費另依第 10 節規則。
- 業者自有 WHMCS 渠道不扣經銷批發餘額；下游經銷商 WHMCS 仍須足額預付，預設倍率 1.00。服務固定渠道，避免內建帳單和 WHMCS 雙重收款。
- 業者與經銷商 CNAME 指向集中入口，由各自所屬業者收款與結算。DNS 所有權、CNAME、TLS、品牌與憑證租戶一致後才啟用；網站域名不等於寄信域名驗證。

下文「平台」若涉及 VM 零售、經銷批發或客戶餘額，指該 VPS 業者的服務範圍；HOST SaaS 平台帳務不使用這些客戶資金。此節優先於早期單業者措辭。

## 1. 產品定位與範圍

建立多區域、多 HOST、多租戶的 VM 平台，整合 Linux KVM、RouterOS、NetPanel、帳務、收款、經銷商及 CNAME 白標網站。

- 本版專注新系統，不包含舊 VM 搬遷工程。
- 已建立、已開通或已納管的 VM，都提供符合資格的換 IP、修改 root／Administrator 密碼、重裝及一般管理功能，不限新建當下。
- 介面參考 Nube 已觀察的總覽、VM 列表、區域切換及帳務導覽；網路操作以現有 NetPanel 為基準。不將未觀察的功能宣稱為 Nube 現有能力。
- 納管現有服務不重建 VM、不搬移磁碟、不重新收取開通費。每台 VM 登錄唯一控制 backend；既有環境的相容 adapter 不得與 Host Agent 同時控制同一資源。
- 早期原型中的價格、圖表、角色、IP 及餘額均為範例，不作正式產品預設或服務承諾。

### 1.1 角色與面板

| 角色 | 權限與主要功能 |
|---|---|
| SaaS 平台管理員 | 業者、HOST 授權價格、訂閱與限時支援 |
| 業者管理員 | 所屬區域、HOST、IPPOOL、ROS、線路、產品、映像、客戶、經銷商、工作與告警 |
| 維運人員 | 依權限處理 VM、網路、映像與故障，不預設具有財務權限 |
| 財務人員 | 收款、錢包、欠款、退款、對帳及經銷結算 |
| 經銷商 | 自有客戶、產品、批發餘額、WHMCS、白標站與收益 |
| 終端用戶 | 自己的 VM、網路、密碼、重裝、用量、帳單、儲值、驗證及 API Token |

用戶面板包含總覽、VM、網路、帳務、帳戶驗證、API Token 與操作紀錄。管理員可見 HOST 管理網路；客戶只可見自己 VM 的網路資訊，不可取得 ROS 帳密或其他租戶資料。

## 2. 技術架構

| 層級 | 選型與責任 |
|---|---|
| 前端 | React、TypeScript，沿用現有介面基底 |
| 控制平面 | Python、FastAPI；統一權限、產品資格、資源及工作 API |
| 身分驗證 | OIDC／Keycloak；管理員強制 MFA，SMS OTP 不作登入 MFA |
| 主資料庫 | PostgreSQL；資源、帳務、操作、事件及稽核 |
| 背景工作 | Celery、RabbitMQ；工作狀態以 PostgreSQL 為準 |
| 快取 | Redis；不作唯一帳本、唯一操作鎖或唯一工作紀錄 |
| 虛擬化 | Linux KVM、QEMU、libvirt、Host Agent |
| 網路 | NetPanel 網路服務、RouterOS API／SSH adapter |
| 映像儲存 | S3 相容物件儲存；不可變映像版本、可信清單與校驗碼 |
| 密鑰 | Vault；業務資料庫保存密鑰引用 |
| 網站入口 | Caddy、HTTPS、自訂網域路由 |
| 監控 | Prometheus、Grafana、結構化日誌與操作追蹤 |

新 HOST 基準採 Debian 13 及受支援的 QEMU／libvirt 套件。libvirt 11.x 作 VLAN bridge 整合基線；上線前固定並驗證實際套件組合。HOST 系統、管理網、儲存網與客戶網分離。

```mermaid
flowchart TD
    UI[管理員／用戶／經銷商／白標面板] --> API[控制平面 API]
    WHMCS[經銷商 WHMCS] --> API
    API --> DB[(PostgreSQL：資源、帳本、工作)]
    DB --> JOB[Outbox／背景工作]
    JOB --> COMPUTE[Compute Worker]
    COMPUTE --> GW[SSH Connection Gateway]
    GW --> AGENT[Host Agent]
    AGENT --> KVM[libvirt／KVM]
    JOB --> NET[NetPanel／Network Worker]
    NET --> ROS[RouterOS／PPPoE／NAT]
    JOB --> BUILD[隔離的 Image Builder]
    BUILD --> IMAGE[(QCOW2 母映像庫)]
    IMAGE --> AGENT
    PAY[Stripe／TRON] --> EVENT[付款事件與對帳]
    EVENT --> DB
    METER[流量計量與預付授權] --> DB
    JOB --> NOTIFY[Postal／SMS]
```

長時間操作一律背景執行。HTTP 受理不等待 VM 啟動、重撥、重裝或映像製作完成；worker 重送採持久化操作 ID 與資源版本核對。

## 3. 區域、HOST 與專屬 IPPOOL

**資源歸屬：區域 → HOST → 該 HOST 擁有的 IPPOOL。**

IPPOOL 記錄 region、host、fabric、類型、CIDR／地址清單、閘道、DNS、VLAN、可用與保留範圍、可達 ROS／路由表／出口，以及可用、預留、已分配、隔離、待回收狀態。

- 池類型包含私有 IP、靜態公網 IP、PPPoE 出口資源。動態 PPPoE 池保存可分配 session／名額，公網 IP 由實際撥號觀測，不是固定地址清單。
- 用戶選區域與方案；排程器聯合選擇 HOST、該 HOST 的 IPPOOL、可達出口及空閒 session。
- 在一致的資源預留流程內保留 CPU、RAM、儲存、私有 IP 與出口。禁止自動跨 HOST／區域借用 IP。
- 有運算容量但沒有合適 IPPOOL／出口，仍不可開通。CPU／RAM 初版預設不超賣，系統保留量先從可售容量扣除。
- 私有地址在同一 routing domain 內唯一；不同 HOST 的池不能造成同一 routing domain 地址重疊。公網地址不可重複分配。
- VLAN 在 fabric 內唯一；管理及儲存 VLAN 不分配給客戶。MAC／IP／VLAN 防偽冒與同 VLAN 隔離在 HOST 或交換層執行。
- 每個專屬 PPPoE session 同時只屬於一個有效網路配置，不得供不同 VM 共用完整 1:1 NAT。
- 只有確認 VM、網卡、NAT、路由已清理，才回收地址／session；結果未知不可逕自釋放。

## 4. HOST 與主控連線

| 模式 | 連線建立方式 |
|---|---|
| HOST 主動回連 | HOST SSH 連向 Connection Gateway，建立反向隧道 |
| 主控主動連入 | Gateway SSH 連向 HOST，建立本地轉送 |

兩者控制方向均為「控制平面 → Host Agent → 本機 libvirt」。每台 HOST 可設定主、備模式，但只有一個有效控制租約及 generation。

- Agent 只監聽 loopback HTTPS，預設 8443；Agent mTLS 憑證綁定 host_id。
- SSH 使用每 HOST 個別身分、可信主機金鑰／CA、受限轉送帳號，不提供一般 shell 或任意 sudo。
- 反向 listener 只綁 Gateway loopback，使用受限 PermitListen；正向轉送只允許 Agent 目標，使用 PermitOpen。
- Gateway 維護 host_id、listener、有效租約的關係；其他控制節點不能把自己的 127.0.0.1 誤當遠端 Gateway。
- 隧道恢復先查回既有操作，不盲目重跑重裝、刪除或改密碼。SSH 可連不代表 Agent／libvirt 健康。
- HOST 管理出口不依賴客戶可重撥的 PPPoE；映像傳輸走獨立限速連線，避免阻塞控制。
- 隧道失聯不直接判定 VM 已停止；本地預付期限與流量上限仍須執行。

## 5. VM 生命週期與已開通機器操作

建立流程：

`資格檢查 → 金額與資源預留 → 網路準備 → 從已發布母映像建立系統碟 → VM 定義 → 開機初始化 → 驗證 → 正式開通`

正式開通前驗證實際 CPU／RAM／容量、私有 IP／MAC／VLAN／閘道／DNS、指定出口與 NAT、安全群組、QGA、初始化完成狀態。只有 running 或 guest-ping 成功不足以判定完成。

- 用戶可建立、啟動、關機、重啟、開主控台、重裝、改密碼與刪除，均受產品資格與權限限制。
- 已開通或已納管 VM 與新 VM 使用相同操作入口。接管時核對 backend 身分、磁碟、網卡、IPPOOL 與出口，不能用陳舊 IP 猜測 VM。
- 重裝、刪除、改密碼及換 IP 使用互斥工作。重裝／刪除顯示資料影響；離線改密碼顯示停機需求。
- desired state、observed state、停權原因及服務已付期限分開記錄。付款恢復不能解除其他停權。
- 補償只處理該次工作建立的資源；回收不明保留預留並進 recovery_required。

## 6. ISO → QCOW2 母映像 → 重裝

### 6.1 管理後台集中建置

管理員選擇 OS、Edition、版本、架構及對應安裝設定檔，匯入官方 ISO 或受控官方下載來源。驗證來源、校驗碼後，在隔離的 Image Builder 內自動安裝。

```mermaid
flowchart TD
    ISO[管理員匯入官方 ISO] --> PROFILE[已核准的自動安裝設定檔]
    PROFILE --> BUILD[隔離建置 VM]
    BUILD --> TOOLS[系統更新／驅動／QGA／初始化工具]
    TOOLS --> CLEAN[清除建置秘密與機器識別／一般化]
    CLEAN --> QCOW[輸出自含式 QCOW2 母映像]
    QCOW --> QA[以獨立副本驗收開機、容量、網路、帳密、Agent]
    QA --> PUBLISH[發布不可變 image_version_id]
    PUBLISH --> CACHE[HOST 下載並校驗母映像快取]
    CACHE --> DISK[複製成各 VM 獨立系統碟]
    DISK --> INIT[本次 installation_id 初始化]
    INIT --> READY[開通／重裝驗證完成]
```

**同一組 OS／Edition／架構／安裝設定版本集中建置並驗收母映像，供後續多次開通及重裝使用。客戶重裝不再掛載原始 ISO、不再執行完整 ISO 安裝、不為每位客戶重做母映像。**

OS 修補、驅動或設定更新須另建新版本。只能處理已核准的 ISO 與設定檔，不承諾任意 ISO 都可無人值守轉換。

| 系統 | 建置方式與預裝元件 |
|---|---|
| Ubuntu Server | Autoinstall、cloud-init、QGA |
| Debian | 版本對應 unattended 安裝、cloud-init、QGA |
| AlmaLinux／Rocky Linux | Kickstart、cloud-init、QGA |
| Windows Server | Unattend、VirtIO 驅動、QGA、Cloudbase-Init、Sysprep |

Builder 不可接觸客戶生產磁碟或管理憑證。母映像內清除建置帳密、SSH host keys、machine-id／初始化狀態等應逐機產生的資料；Windows 在捕獲前完成一般化。這些清理不套用到普通已開通 VM。

**開機驗收一律使用候選母映像的獨立副本。** 候選母映像保持清理／一般化後、尚未執行客戶初始化的狀態，不直接開機寫入；驗收帳密、網路配置及首次啟動狀態不得回寫或重新捕獲成發布母映像。發布前再次核對母映像雜湊未變。

### 6.2 母映像發布與 HOST 快取

每個發布版本保存 image_version_id、OS／Edition／架構、來源 ISO 校驗碼、設定檔版本、SHA-256、檔案大小、虛擬磁碟容量、最低 CPU／RAM／系統碟、開機模式、QGA 及初始化工具版本、測試結果與發布狀態。

- 母映像發布後不可變、唯讀保存，不用顯示名稱或可變檔案路徑作唯一選擇依據。
- **首版固定採完整獨立複製：發布母映像為自含式 QCOW2，建立的客戶系統碟也不得依賴外部 backing file。** 不採永久共享 backing chain；客戶寫入不影響母映像或其他 VM。
- HOST 先下載到暫存位置，依可信版本清單驗證雜湊、大小、格式及無非預期 backing 依賴，再原子發布到本地快取。
- 同 HOST 同版本同時只下載一次；未完成或損壞檔案不得用來開機。快取是可重建副本，只有未被建置／複製工作使用時才可淘汰。
- 以 image_version_id 固定工作輸入。預設映像改版不會把正在執行的工作換成另一版本。
- 停用舊版本禁止新建／重裝使用，不修改已運行 VM 的系統碟。清理映像物件前檢查工作與保留政策。

### 6.3 客戶開通／重裝套用流程

1. 檢查服務所有權、狀態、有效且已付款／預付方案、OS／Edition 資格與映像最低資源。
2. 鎖定 VM、網路配置及系統碟，固定 image_version_id；確認暫存新碟及回復點容量足夠。
3. 重裝時確認資料影響，正常關機並驗證已停止；以磁碟 ID／用途辨識原系統碟，保留回復來源。
4. 從已校驗 QCOW2 母映像完整複製出該 VM 專屬新系統碟。按已購容量擴大虛擬碟，初始化時擴充分割區／檔案系統。
5. 產生新的 installation_id，配置本次帳號、密碼／SSH Key、hostname、系統卷、私有 IP／prefix／gateway／DNS／MTU，並確認 QGA。
6. 沿用服務、VM、網卡身分／MAC、私有 IP、VLAN、PPPoE session 與 NAT 綁定。公網 IP 由 ROS 管理，不填成 guest 私有網卡位址；重裝不順便重撥或重新選線。
7. 只替換指定系統碟並啟動驗證；附加資料碟不格式化、不重新分割、不自動擴充，guest 初始化亦只處理系統卷。
8. 驗證初始化完成、帳戶建立／密碼操作結果、容量、網路、QGA 及開機狀態後才回報成功。失敗保留可回復原系統碟，不把部分完成的新碟視為成功。
9. 成功後回復來源預設保留 24 小時，再由受控清理工作刪除；失敗／結果不明時不得按此期限自動刪除。暫存與回復容量需事前預留。
10. 移除敏感 seed／一次性秘密，但保留初始化完成標記。普通重開機或 Agent 重連不得重新產生 installation_id 或套回初始密碼。

服務、帳單、流量計量身分持續沿用；重裝不重收開通費、不清空已用流量、不重設服務期限。不得低於映像最低虛擬容量，也不能用壓縮檔案大小推斷系統碟最低需求。

### 6.4 最小化安裝與購買資格

| 映像類別 | 系統碟建置起始目標 |
|---|---:|
| Linux 無桌面 | 10 GiB |
| Windows Server Core | 40 GiB |
| Windows Server Desktop Experience | 64 GiB |

以上是工程驗證起點，不是已量測結果或通用官方最低需求。首批 Windows 映像以 Server 2022／2025 的核准版本設定檔驗收；Linux 各發行版也逐版本驗證。正式最低容量以安裝、更新、重啟及剩餘空間測試結果發布。

可裝系統＝有效已付款／預付方案＋OS／Edition 權限＋授權配置＋最低硬體需求。只買到磁碟或錢包有餘額，不自動取得較高階 OS；經銷折扣不改變產品權限。升級必須已付款且生效後才能重裝相應系統。Windows 授權／啟用設定隨產品配置，不共用不適用的客戶密鑰。

## 7. 修改已開通 VM 密碼

| 狀況 | 處理方式 |
|---|---|
| Linux／Windows 有可用 QGA | 經受控 API 修改指定本機帳戶 |
| Linux 無 QGA | 維護鎖、關機、回復點，離線修改本機密碼，再開機驗證 |
| Windows 無 QGA | 離線注入相符驅動與 QGA firstboot 安裝服務；啟動完成後再透過 QGA 改本機密碼 |
| 加密磁碟或特殊／不支援系統 | 受控救援及必要解鎖條件，不自動重裝 |

- 不把 Linux 的 virt-customize root-password 操作當成 Windows Administrator 重設方法。
- Windows 帳戶使用實際本機身分，支援 Administrator 被改名；AD／LAPS 管理帳戶不走通用重設。
- 加密磁碟需可用解鎖方式；Windows 強制重設提示 EFS／DPAPI 使用者加密資料可能受影響。
- 不附帶開啟 root SSH、解除帳戶停用、加入管理員群組或改防火牆。
- 密碼以短效加密秘密傳遞，不放母映像、firstboot 命令列、郵件、一般工作紀錄或日誌，操作完成後清除。
- 作業結果不明先核對原工作。普通重啟不再次套用密碼；重設失敗不以重裝替代。

## 8. NetPanel、ROS 與 IP 顯示

沿用 NetPanel 的「VM 私有 IP／網路配置 → 對應 ROS → NAT／PPPoE → 公網 IP」操作方式。正式綁定以穩定 network_allocation_id、router_id、session_id 與資源版本為準；掃描 NAT／comment 只作發現與核對，多義、共享或不明綁定不執行破壞性操作。

### 8.1 出口與 NAT

- 支援靜態公網 1:1 NAT、固定 PPPoE、專屬動態 PPPoE及僅私網；本版換 IP 僅針對專屬動態 PPPoE。
- HiNet 帳號 trim、網域不分大小寫後，endsWith(@ip.hinet.net) 判固定，其餘依用戶指定慣例判動態。後綴不等於實際公網入站能力，仍須核對協商位址與線路條件。
- 1:1 NAT 需要專屬可路由公網位址。NAT 不代表防火牆放行，安全群組預設拒絕未明示入站，回程使用指定 WAN／路由表。
- 規則帶平台資源 UUID／revision；不接管無標記人工規則。每個 binding 只有一個規則定義與寫入協調責任。
- 歷史 NetPanel 所用 autoUpdate on-up 依 PPP 介面更新 SNAT；部分 DNAT 以 in-interface 匹配，換公網 IP 不須改其地址條件。新 adapter 必須按實際規則型態逐條核對。
- 受管 ROS hook 處理快速收斂，中央 reconciler 在重連、啟動及定期巡查補核；兩者使用一致配置，不能互相覆寫。第一條 SNAT 正確不代表其餘規則正確。
- 只清理能確定屬於該 VM 的舊 conntrack，禁止全表清除。管理路徑與可重撥客戶出口分離。

### 8.2 公私 IP 顯示

| 對象 | 私有 IP | 公網資訊 |
|---|---|---|
| HOST | Agent 管理網卡位址 | 經指定管理出口偵測的公網出口 |
| VM | IPPOOL 分配值與 QGA 實際值核對 | 靜態配置／PPPoE 協商值，加 NAT／指定出口驗證 |

- 分別保存配置的對外 IP、實測出口 IP、來源、最後確認時間、連線狀態及 stale 標記。
- 上線、重裝、網路異動與重撥後立即更新，另預設每 60 秒核對。
- 不能拿 HOST 公網 IP 套用到所有 VM；多網卡／多 IP 顯示各自對應配置。
- 查詢失敗保留最後確認值並標示過期，不刷新時間假裝已確認；分配值與實際值不同要顯示異常。
- CGNAT／雙重 NAT 分別標示出口與分配地址；公網出口不等於能從外部連入。
- HOST 偵測公網 IP 不自動取代已驗證 SSH 目標。客戶不見 HOST 管理位址。

### 8.3 換 IP 與 DDNS

面板、API、WHMCS 共用：資格與所有權檢查 → VM／配置／session 互斥 → 重新核對綁定與舊 IP → 單次重撥 → session／位址／NAT／出口驗證 → 更新顯示、DDNS及操作紀錄。

| 結果 | 狀態 |
|---|---|
| 位址不同且全部驗證完成 | succeeded／changed |
| 重連正常但 ISP 配回同一 IP | failed／IP_UNCHANGED，connectivity 可為 connected |
| 無法確認結果 | recovery_required，保留互斥並核對原作業 |
| 重連或 NAT 驗證失敗 | 明確錯誤及實際連線狀態，不把舊 IP 當目前有效 |

預設完成後冷卻 60 秒；不自動無限重撥，不保證取得不同 IP 或取回舊 IP。重撥中斷既有連線，但不重設私有 IP、VLAN、計費週期、流量或餘額。DDNS 只在位址及入站資格確認後更新；DDNS 與白標網站網域是不同功能。

## 9. 流量產品線路優選

實體線路與 session 分開建模。一條線可配置八個撥號名額，實際上限按 ISP 配置；八撥不是八倍頻寬。

先篩選區域、HOST／IPPOOL、可達出口、容量與專屬空閒 session，再依以下順序挑選組合：

1. 最近五分鐘出站使用率，加上尚未反映到監控的待開通預留負載。
2. 頻寬餘裕、入口壅塞與線路健康。
3. 空閒 session 數與 HOST 剩餘容量。

所有可用線路都高負載時仍選最好的開通；只有實際容量、IP／session 不足或不可用才拒絕。跨 HOST 共用實體線時，負載及撥號上限仍按整條線匯總。只在 HOST 合法的池內分配，不為了挑線跨池借 IP；初版不自動搬動既有 VM 出口。

## 10. 帳本、預付、欠費與計量

### 10.1 費用與帳本

使用不可變雙式帳本，付款、儲值、預留、消費、退款、保留費欠款及經銷收益分別記錄。

| 項目 | 規則 |
|---|---|
| Stripe 月租訂閱 | 直接扣卡，按已付款服務期間提供資格 |
| 錢包月租 | 預付一個完整計費期間 |
| 小時計價 | 小時價換算每分鐘，預付下一分鐘；正式可用後開始 |
| 流量 | 只計實際公網出站 |
| 客戶手動關機 | 依已揭露資源保留方案繼續計費 |
| 欠費停機 | 停止新的 CPU／RAM 按量費與計費出口，磁碟／IP 繼續累計保留費 |

預設帳本基準幣別 USD；付款原幣別、鏈上資產及匯率另存。使用高精度 Decimal、整數 bytes、明確時間區間及不可變 price_version，不用浮點數，不逐封包進位。磁碟 GiB、流量十進位 GB；儲存 UTC、預設顯示 Asia/Taipei。

可用額＝已入帳餘額－有效預留；開通前原子預留，成功後結算，確認資源回收才釋放。不同事件造成同一業務效果也只能入帳一次，錢包餘額必須可由帳本重建。

### 10.2 欠費、保留費與復機

- 一般用量不能令可用錢包自動變成負數。磁碟／IP 保留費另記應收欠款，不是可消費額度。
- 保留費按資源與計費區間唯一入帳；已付月租／預付期間涵蓋的同一資源不重複計收。
- 延遲月租款涵蓋已計保留費區間時，以沖銷分錄消除重疊；不得直接改歷史分錄。
- 儲值先清到期欠款，剩餘才成可用額。復機須欠款清償、下個預付單位足夠、服務期有效、原合法 HOST 容量足夠且無其他停權。
- 復機完成前不顯示成功、不正式收取新的運算分鐘費；容量不足不得偷偷跨 HOST IPPOOL 搬機。
- 只解除因餘額不足的停權。關機不自動取消 Stripe 訂閱，流量欠費亦不自動刷卡補值。
- 首版不因欠費自動刪資料；長期欠費進管理員處置清單。保留費必須在產品頁、購買確認及欠費通知揭露。

### 10.3 流量口徑與預付授權

只計 VM 經指定 WAN 的公網出站；入站、內網、平台管理、備份與內部 hairpin 不計費。

- ROS 使用受管流量分類及轉送計數，不能用僅首包的 NAT 規則計數作帳單。FastTrack／硬體卸載不得繞過計費口徑。
- HOST TAP 總量只作比對，不直接當作公網用量。換 IP、重裝、歸零與重啟使用 counter_epoch；缺報標記待對帳，不當成零。
- 先原子預留費用，再授予有限 bytes 額度；多 VM 授權總額不得超過資金預留。
- HOST 以本地 tc/eBPF 執行保守出站上限，ROS 依實際分類結果結算。只有已驗證排除流量才可不扣授權，差額經對帳釋放。
- 額度耗盡／過期時本地阻止新增計費流量並觸發停機；控制平面失聯不可無限續用。未確認舊授權不得釋放後重發。
- 未通過分類、限額與故障測試的節點不得販售流量計費產品。

## 11. Stripe、USDT TRC20、退款與對帳

### 11.1 Stripe

- 訂閱與一次性儲值使用不同用途 Checkout。訂閱款不加錢包，儲值不重付已訂閱月租。
- 不自動刷卡補錢包，也不自動用錢包補訂閱扣款失敗。取消預設期末生效。
- raw body 驗簽、持久化 inbox、核對供應商帳戶／模式／訂單／金額／幣別及付款狀態後入帳；不憑成功返回頁。
- event ID 與付款 business key 兩層去重，處理逆序、延遲與重播。建立付款及退款均使用穩定冪等鍵。
- 純續費失敗不提前撤銷有效已付款期限；流量欠費另按用量規則處理。

### 11.2 USDT TRC20

- 首版支援 TRON 主網 USDT，其他鏈／資產透過獨立 adapter 擴充。
- 依指定合約 allowlist、6 位小數與 canonical 地址核對，代幣合約不可當成收款地址。
- 每筆儲值保存受控收款地址、報價來源、匯率、應付數量及期限；不固定假設 USDT 永遠等值 USD。
- 驗成功 receipt、正確 Transfer／to／amount 及 solidified 狀態後入帳；以 network／txid／log_index 去重，checkpoint 重掃與每日對帳。
- 少付累計、溢付、逾期、錯鏈與錯資產分開處理；逾期進對帳，不套過期匯率自動入帳。
- 地址不重派給其他租戶；watcher 無提款權，簽名及歸集獨立處理 TRX／Energy／Bandwidth 與金鑰。
- 退款人工核准並確認地址，不自動退向原 from。

退款先鎖可退額，可退額扣除到期欠款、有效預留及既有退款鎖。已消費費用不自動按比例退款，例外補償人工核准。退款受理不等於完成；拒付缺口記追回款，不抹除消費。財務修正以沖銷／調整分錄處理。

## 12. 經銷商、WHMCS 與白標站

### 12.1 WHMCS 預付批發

經銷商自行收終端零售款；所屬業者向經銷商錢包扣批發月租、分鐘費及流量費。批發價＝產品基準價×協議倍率，預設 1.00；協議明列適用產品及費用項目。

例如餘額 1,000、基準月費 100：倍率 1.00 最多預付十台；倍率 0.80 可預付十二台、餘四十。這是消耗型預付款，不是刪機即可恢復的可循環容量額度。

- WHMCS 模組支援建立、暫停、恢復、終止、資訊、換 IP、重裝與改密碼。
- 以 whmcs_instance_id＋external_service_id 識別服務，並驗證經銷商／客戶歸屬。
- 餘額不足不能開通；預留、扣款與恢復按同一帳本及作業規則。
- 202 只表示受理，WHMCS 保持待處理；核對實際成功才 Active 及發開通信。重試沿用原操作，不重建 VM。
- 折扣只影響價格，不改產品規格與 OS 權限。刪除不自動退已消費額度。

### 12.2 CNAME 白標獨立站

平台託管網站，經銷商用自己的 DNS／網址與品牌，不需自架網站程式。

`新增網域 → 顯示 CNAME／歸屬驗證紀錄 → 驗證 → TLS → 品牌／產品配置 → 開站`

- 支援子網域 CNAME；根網域需供應商相應 ALIAS／flattening 能力。
- 同域名只能屬一個品牌站；只為已驗證且啟用網域簽發 TLS，不接受任意 Host 自動開站。
- 可設定 Logo、名稱、配色、客服、產品與零售價；跨域登入只使用已驗證回呼地址與租戶綁定。
- 白標由所屬業者收款，與 WHMCS 自收零售渠道分開。收益按已賺取零售收入－批發成本－約定費用－退款／拒付計算。
- 儲值不是收益，實際消費後認列。每月結算、人工核准撥付，不再重扣 WHMCS 批發錢包。
- 解除綁定、轉移或停用網域後撤銷原品牌路由權限。網站域名與郵件寄件域名分別驗證。

## 13. Didit、SMS OTP 與 Postal

### 13.1 Didit KYC

- 儲值及首次開通前驗有效 KYC；保存 session 引用、狀態與必要稽核，不預設複製整份證件。
- 依 v3 介接驗簽、去重、核對當前 session；拒絕偽造／過期回調，舊 session 不覆蓋新狀態。
- 通過、審查、拒絕及過期分開，必要時向 Didit 查回 authoritative decision。
- KYC 與手機驗證是獨立條件。過期回調不立即刪既有 VM，但新儲值／開通需重新符合資格。

### 13.2 SMS OTP／sms.1go.to

- 用於註冊手機驗證及換號，不作登入 MFA。平台產生與驗證 OTP，sms.1go.to 負責發送。
- 號碼正規化 E.164：+86 走中國號碼路由，其他支援地區走台灣號碼的國際發送路由，包含台灣、香港、澳門與其他國際號碼。
- 不因備援默默跨越路由政策。既有台灣號碼限定須在 sms.1go.to 的驗證及傳輸各層擴充並驗收。
- 預設六位 OTP、五分鐘有效、最多五次驗證、重送間隔六十秒；另按號碼、帳戶與來源限流。
- OTP 用伺服器秘密保護的雜湊保存；訊息、歷史與日誌不長期保留明文 OTP。
- 發送結果未知先查同一 UUID，不能直接換路由重送；閘道接受不等於送達，無回調時以狀態查詢核對。

### 13.3 Postal 郵件

指定服務：https://email.zcnzc.com/ 。正式 API／回調簽章能力依部署版本接入驗證，尚未宣稱連線成功。

- 優先 HTTPS API，outbox＋背景工作；保存通知業務鍵與供應商 message_id。
- 用於驗證、登入密碼重設連結、KYC、收款、低餘額／欠費、開通／重裝、異常及結算通知。
- 接受、投遞、延遲、退信分開；通知失敗不回滾 VM 或帳務。
- 不寄 VM 密碼、API Token 或其他秘密。發送逾時標記未知並核對，不宣稱恰好投遞一次。
- Postal 回調依實際版本驗證，已查官方主線 RSA 簽章不可套成通用 HMAC；使用可信配置的公鑰來源並去重。
- CNAME 開站不等於郵件域名驗證；需另驗寄件域名與 SPF／DKIM／return path 等。未驗證時使用平台已驗證 From 與品牌顯示名稱；不為發信自動改客戶收信 MX。

## 14. 核心資料模型與一致性

| 群組 | 實體與關鍵資料 |
|---|---|
| 身分 | users、tenants、memberships、roles、api_tokens、kyc_sessions、phone_verifications |
| 主機 | regions、fabrics、hosts、host_connections、capacity_reservations |
| VM | services、vms、vm_interfaces、volumes、installations、provider_bindings |
| 網路 | ip_pools、ip_allocations、routers、physical_lines、pppoe_sessions、nat_bindings、ddns_records |
| 產品 | plans、price_versions、os_entitlements、discount_agreements |
| 映像 | image_sources、build_profiles、image_builds、image_versions、host_image_cache |
| 帳務 | wallets、ledger_transactions／entries、holds、receivables、usage_records、invoices、payments、refunds |
| 渠道 | resellers、whmcs_instances、external_service_bindings、brand_sites、settlements |
| 工作 | operations、operation_steps、event_inbox／outbox、notifications、audit_logs |

- 租戶資源均有 tenant_id 與穩定 UUID，跨表關聯驗證租戶一致性；UUID 不替代權限檢查。
- VM／網卡／network_allocation_id 分離；可變 IP 不作身分識別。
- installations 關聯 installation_id、VM、image_version_id、系統碟及初始化狀態；普通重開不能建立新安裝。
- image_versions 保存來源與產物雜湊、virtual_size、minimum_disk_size、profile 版本、OS 資格與測試結果；host_image_cache 保存主機、版本、校驗與可用狀態。
- volumes 明確記錄 system／data 角色、VM 所有權、映像來源及外部依賴。首版客戶系統碟無母映像 backing 依賴。
- 有效 VLAN、地址分配及專屬 session 使用資料庫唯一約束；資源保留與狀態轉換在交易中執行。
- 付款事件、付款業務鍵、usage event、鏈上事件、資源／期間保留費各有唯一鍵。
- 分錄每幣別借貸平衡、業務效果唯一；已過帳不可 UPDATE／DELETE，使用 reversal。入帳、分配與 outbox 同一交易提交。
- 暫存秘密只保存加密引用，不放在 API 回應、一般 JSON payload 或可查詢日誌。

## 15. API 與操作契約

### 15.1 主要 API

| API | 功能 |
|---|---|
| GET /v1/catalog/plans、/v1/images、/v1/regions | 方案、可用發布映像與區域 |
| GET／POST /v1/vms | VM 列表與建立 |
| GET /v1/vms/{id} | 配置、desired／observed state、可用操作 |
| POST /v1/vms/{id}/actions | 啟動、關機、重啟等 |
| POST /v1/vms/{id}/console-sessions | 短效主控台票證 |
| GET /v1/vms/{id}/network | 私網、公網、VLAN、出口與確認時間 |
| POST /v1/vms/{id}/ip-rotations | 指定網路配置重撥 |
| POST /v1/vms/{id}/reinstallations | 套用指定已發布 QCOW2 映像版本 |
| POST /v1/vms/{id}/password-resets | 指定本機帳戶改密碼 |
| GET /v1/operations/{id} | 工作進度與結果 |
| GET /v1/billing/wallet、/v1/billing/usage、/v1/billing/invoices | 可用／預留／欠款、用量與帳單 |
| POST /v1/payments/checkout、/v1/payments/crypto-intents | 訂閱／儲值付款與鏈上報價 |
| GET /v1/payments/{id} | 後端核對的付款狀態 |
| POST /v1/kyc/sessions | Didit 驗證 |
| POST /v1/phone-verifications、/v1/phone-verifications/{id}/verify | SMS OTP |
| /v1/reseller/* | WHMCS 站點、服務、折扣、白標及結算 |
| /v1/admin/* | HOST、IPPOOL、ROS、線路、產品、映像與工作 |
| POST /v1/webhooks/stripe、/v1/webhooks/didit、/v1/webhooks/postal | 供應商各自驗簽的事件入口 |

### 15.2 映像管理與重裝介面

- POST /v1/admin/image-sources：建立 ISO 來源與版本／校驗紀錄。
- POST /v1/admin/image-builds：指定 source_id、build_profile_id 與版本、OS／Edition／架構，建立背景建置工作。
- GET /v1/admin/image-builds/{id}：查詢建置、清理、QCOW2 匯出及測試狀態。
- POST /v1/admin/images/{image_version_id}/publish：僅測試通過且 metadata 完整時發布；已發布內容不可覆寫。
- POST /v1/admin/images/{image_version_id}/deprecate：停止新使用，不更改既有 VM 磁碟。
- 客戶 reinstallations 請求指定 image_version_id、預期 VM revision、初始化設定及資料影響確認。帳密經受控秘密輸入流程傳遞。
- 客戶端不可傳 ISO URL、HOST 檔案路徑、shell 指令或任意映像；不能以重裝 API 啟動母映像建置。
- 服務端依訂單判定容量及 OS 資格，依 volume role 選系統碟，依現有網路綁定配置 IP；不相信客戶任意傳入的磁碟 ID／容量／IP。

### 15.3 非同步、認證與冪等

建立、換 IP、重裝、改密碼及映像建置受理回 HTTP 202：

```json
{
  "operation_id": "op_uuid",
  "status": "queued"
}
```

共同狀態：queued → running → succeeded／failed／recovery_required。記錄資源、租戶、類型、步驟、時間、result、error_code、請求識別、資源 revision、租約及外部引用。未知結果不得當成可立即重做的失敗。

- Browser 用安全 Session 與 CSRF 防護；程式用可撤銷且限定範圍的 Bearer Token。工作查詢也驗資源歸屬。
- 產生資源、費用或破壞性變更的 POST 要求 Idempotency-Key；同租戶同 key／內容回原工作，不同內容回 409。
- 唯一性存在 PostgreSQL，不僅靠快取或供應商短效 key。租約到期接手前先核對設備結果。
- API Token 只存驗證雜湊，主控台用短效單次票證，不公開 HOST VNC 埠。
- 客戶不能指定 ROS 地址、介面或 SSH 指令。列表使用 cursor pagination，錯誤不洩漏秘密或其他租戶資源存在性。
- HTTP：401 未登入、403 權限不足、404 不可見、409 資格／狀態衝突、429 限流、503 尚未啟動且依賴不可用；已受理工作結果未知由 operation 回報。

### 15.4 換 IP API

POST /v1/vms/{id}/ip-rotations，Bearer Token 與 Idempotency-Key 必填。body 使用 network_allocation_id；只有一個可操作配置時可省略，多個時必填。

```json
{
  "operation_id": "op_uuid",
  "status": "succeeded",
  "outcome": "changed",
  "private_ip": "10.20.0.15",
  "previous_public_ip": "192.0.2.10",
  "current_public_ip": "198.51.100.20",
  "connectivity": "connected",
  "nat_status": "converged",
  "verified_at": "2026-09-21T00:00:00Z"
}
```

以上為文件示例 IP。無法確認時 current_public_ip 為 null，last-known 另存。NetPanel 既有 internal/change-ip 的 started 回覆不能直接轉為 succeeded。

## 16. 開發順序、驗收與營運

### 16.1 開發順序

| 階段 | 成果 |
|---|---|
| 1 平台基礎 | 身分、租戶、RBAC、資料模型、持久化工作、事件、稽核及帳本 |
| 2 資源管理 | 區域、HOST、雙向 SSH、Agent、IPPOOL、VM 與已發布映像部署介面 |
| 3 NetPanel | ROS、PPPoE、NAT、公私 IP、換 IP API、DDNS、線路優選 |
| 4 映像與系統維護 | ISO 工廠、唯讀 QCOW2 發布／快取、套用重裝、OS 資格、新舊 VM 改密與救援 |
| 5 收款與計費 | Stripe、TRC20、分鐘費、流量預付授權、保留費欠款、退款及對帳 |
| 6 商業渠道 | WHMCS、折扣、白標、結算、Didit、SMS、Postal 完整串接 |

各階段可內部測試；對客開放前相關身份、帳務、失敗處理全部通過。階段 2 可用工程驗證映像測試，正式客戶映像必須走階段 4 的發布驗收。

### 16.2 驗收矩陣

| 類別 | 必須通過的情境 |
|---|---|
| IPPOOL | 不跨 HOST／區域誤配；並發不重複分配地址、session 或容量 |
| 已開通 VM | 不重建服務即可換 IP／改密；操作資格與新機一致 |
| SSH | 雙方向、斷線與備援；拒錯誤金鑰、不重跑工作 |
| 母映像製作 | 同一 ISO/profile 產生可重用版本；建置與客戶重裝為不同工作 |
| 驗收不污染母映像 | QA 只啟動獨立副本，母映像雜湊及未初始化狀態不變，不含驗收帳密 |
| 重裝不跑 ISO | 發布後即使原 ISO 不可用，仍可用母映像開通／重裝；重裝不觸發 Builder |
| 母映像隔離 | 兩台 VM 套同一版本，各自寫入不互相影響，母映像 hash 不變，無外部 backing 依賴 |
| 快取 | 並發只下載一次；截斷／損壞／錯版本拒用；使用中的快取不淘汰 |
| 系統碟 | 依已購容量擴充分割區與檔案系統；附加資料碟內容及分割不變 |
| 初始化 | 每次新 installation_id；機器識別獨立；普通重開不重新套密碼或重跑初始化 |
| 重裝網路 | 保留 MAC、私有 IP、VLAN、PPPoE／NAT 綁定，不另選池／出口，QGA 與網路驗證通過 |
| 重裝失敗 | 能核對／回復原系統碟；未知工作不重複換碟，不誤刪回復來源 |
| OS 資格 | 面板、API、WHMCS 不能繞過已付款方案、Edition、最低虛擬容量 |
| 改密碼 | Linux／Windows、有／無 QGA、改名帳戶、政策拒絕、加密及中斷重試 |
| 換 IP | 新 IP／同 IP／失敗／未知／NAT 漂移；其他 session 不受影響 |
| NAT | 所有受管規則逐條核對；不以第一條或 stale cache 判成功，不清全站 conntrack |
| 線路優選 | 八撥按實體線匯總；全高負載仍挑最佳可用，不跨 HOST 池借 IP |
| 原子預留 | 餘額 1,000 同時兩筆 600 最多一筆成功；未知開通不先釋放 |
| 付款 | webhook 重播／逆序／延遲只入帳一次，訂閱不加錢包 |
| 流量 | 入站／內網／hairpin 排除；重撥、重裝與計數器歸零不漏算／重算 |
| 授權限額 | 多 VM 合計不超預留；控制失聯、計量缺口、HOST 重啟不無限透支 |
| 欠費 | 正確停機、累保留欠款、與月租不重複；補值不越權或搶先標復機 |
| WHMCS | 餘額不足拒絕；202 不提前 Active；站點 service_id 不撞號，重試不重建 |
| 白標 | DNS 歸屬、TLS、解除／轉移及跨租戶隔離；儲值不先認收益 |
| KYC／OTP | 過期、重播、逆序；+86／+886／+852／+853／其他國際路由，未知不重發 |
| Postal | 接受／投遞／退信、簽章與去重；故障不回滾帳務 |
| 對帳復原 | 工作／資料庫中斷後可與支付、HOST、ROS、映像儲存核對，不產生重複效果 |

### 16.3 營運預設

- 繁體中文主介面，保留英文翻譯結構；新映像不可變，發布／停用行為可稽核。
- 價格、OS 資格、流量與保留費、折扣項目及付款週期必填；缺設定不可上架，不使用原型示例價格補空值。
- 月租異動預設下期生效，新權限生效後才開放；降級不自動縮磁碟。
- 每日對帳付款、帳本、欠款、用量與經銷結算。帳務歷史只沖銷，不直接改寫。
- 監控 HOST／ROS、池容量、實體線負載、工作延遲、未收斂操作、映像失敗、計量缺口、付款差額及通知故障。
- 主資料庫每日備份、持續 WAL 保存、定期還原演練；備份使用不同故障範圍。映像庫及其可信版本清單也必須可恢復。
- 內部測試 → 測試客戶 → 小量開放 → 全面開放。未驗收能力以功能開關關閉，不對外提供模擬成功。
- 本版不包含搬遷工程、不自動切換既有 VM 出口、不因欠費自動刪資料。

## 17. 來源與版本依據

需求以本文件及使用者最新確認為準。現行 NetPanel 參考 joysoapp 的 netpanel-api、joyso_netpanel 模組及 2026-09 的專案查核；ROS autoUpdate 行為參考大網管 2026-09-04 的歷史匯出，並非本次連線正式設備取得。Postal 部署版本及其他供應商能力，仍須在實作接入時按驗收項核對。

- [Debian 13 libvirt 套件](https://packages.debian.org/trixie/libvirt-daemon-system)
- [libvirt Domain API／Guest Agent 密碼操作](https://libvirt.org/html/libvirt-libvirt-domain.html)
- [libvirt VLAN／Domain XML](https://libvirt.org/formatdomain.html)
- [libguestfs virt-customize／QGA 注入](https://libguestfs.org/virt-customize.1.html)
- [QEMU 映像格式與 qemu-img](https://www.qemu.org/docs/master/tools/qemu-img.html)
- [Ubuntu Autoinstall](https://canonical-subiquity.readthedocs-hosted.com/en/latest/reference/autoinstall-reference.html)
- [cloud-init NoCloud](https://docs.cloud-init.io/en/latest/reference/datasources/nocloud.html)
- [Cloudbase-Init plugins](https://cloudbase-init.readthedocs.io/en/latest/plugins.html)
- [Windows Server 硬體需求](https://learn.microsoft.com/en-us/windows-server/get-started/hardware-requirements)
- [Windows Sysprep](https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/sysprep--generalize--a-windows-installation?view=windows-11)
- [RouterOS PPPoE](https://help.mikrotik.com/docs/spaces/ROS/pages/2031625/PPPoE)
- [RouterOS NAT](https://help.mikrotik.com/docs/spaces/ROS/pages/3211299/NAT)
- [RouterOS Connection Tracking](https://help.mikrotik.com/docs/spaces/ROS/pages/130220087/Connection+tracking)
- [OpenSSH sshd_config](https://man.openbsd.org/sshd_config)
- [Stripe 訂閱 webhook](https://docs.stripe.com/billing/subscriptions/webhooks)
- [Stripe 冪等請求](https://docs.stripe.com/api/idempotent_requests)
- [TRON 確認語意](https://developers.tron.network/docs/confirmation-semantics)
- [WHMCS provisioning functions](https://developers.whmcs.com/provisioning-modules/core-module-functions)
- [Didit Webhooks](https://docs.didit.me/integration/webhooks)
- [Caddy 自動 HTTPS](https://caddyserver.com/docs/automatic-https)
- [Postal API](https://docs.postalserver.io/developer/api/)
- [Postal Webhooks](https://docs.postalserver.io/developer/webhooks/)
