# Launch 購買期限與帳號 SDK 邊界

本次變更僅在本地開發、驗證；未部署 Launch，未發布 SDK 包。當前源碼依賴 Licentivo 的帳號授權協議和配套官方 SDK 更新，不能與僅支持長期許可證密鑰的舊服務端混用。

## 職責

| 能力 | 負責方 |
| --- | --- |
| 注冊、登錄、帳號安全、商品、訂單、支付、退款 | Launch |
| 續費/升級報價、購買周期和絕對起止時間計算 | Launch |
| 套餐引用到授權產品/策略的映射執行與策略校驗 | Licentivo；Launch 提供選擇和登記入口 |
| 許可證、功能權限、設備名額、授權會話、離線許可 | Licentivo 與官方 SDK |
| 設備列表和遠程解綁 | Licentivo；Launch 代理當前帳號的請求并展示結果 |
| 登錄憑據的保存、帳號恢復、退出入口 | Launch SDK |

Launch 的訂單、購買期限、同步完成標記都不能放行受保護功能。客戶端必須通過官方 SDK 的 `RunFeature` 等運行接口執行受保護業務。

每個 Launch 產品保存一個穩定的公開 Licentivo 產品路由。同一產品的套餐可選擇不同策略，但不能切換到另一個遠端產品；映射保存通過共同產品的資料庫行鎖串行校驗。客戶身份、套餐發布與 SDK 接入配置讀取同一綁定，草稿不能改變已購客戶的產品上下文。這只校驗接入配置的一致性，不決定功能或設備授權。舊庫缺少穩定字段時優先參考購買及發布歷史，無法唯一確認時返回 `PRODUCT_MAPPING_CONFLICT`，詳見 [映射并發修復](/zh-hant/launch-documents/product-mapping-fix-2026-10-24/)。

## 購買期限同步

復用現有接口，不新增付款事實、退款事實或報價服務：

- `POST /api/v1/launch/connections`、`PUT /connections/{id}`：登記身份簽名公鑰，正式與測試環境分別建立連接。
- `PUT /api/v1/launch/connections/{id}/plans/{plan}`：登記不可重復的 Launch 套餐版本引用及遠端產品、策略版本。
- `POST /api/v1/launch/connections/{id}/events`：提交完整的版本化購買快照。
- `GET /api/v1/launch/connections/{id}/events/{event}`：確認處理結果。
- `POST /api/v1/launch/connections/{id}/events/{event}/retry`：核對后重試原事件。

快照只含事件編號、環境、事件類型、購買引用、匿名帳號引用、Launch 產品、套餐版本引用、遞增版本和絕對 `valid_from` / `valid_until`；遷移時附舊許可證 ID。不發送支付密鑰、價格、客戶郵箱或長期許可證密鑰。永久購買的 `valid_until` 為 `null`，由 Licentivo 校驗是否與策略匹配。

Launch 在同一資料庫事務內確認付款、記錄不可變的購買覆蓋區間并保存同步任務。按日/月/年的日歷周期計算截止時間；續費沿用原購買錨點，已過期后才付款則從實際付款時間開始。升級報價和期限仍在 Launch 計算。

每次變化發送完整絕對值，重試使用同一個事件 ID 和相同正文，不發送“再加 N 天”。任務持久化請求、遠端連接和處理進度；響應丟失、進程重啟和并發工作進程均不會重復疊加期限。

HTTP 202 只代表 Licentivo 已接收。僅收到 `applied` 才標記同步完成；`pending` 繼續查詢，`manual_review` 和無法確認的 `stale` 保留待核對狀態。網路錯誤退避重試，連續失敗達到上限后進入人工核對。

退款只移除對應訂單的覆蓋區間：退升級訂單恢復基礎套餐；退續費訂單移除對應延長部分；仍有未退款購買時同步重算結果，不撤銷全部購買。全部購買均退款后發送 `entitlement.refunded`。以后重新購買使用新的購買引用，防止復活已撤銷的遠端許可證。

渠道確認的敗訴拒付或撤款也只移除對應訂單的購買覆蓋，訂單顯示為 `reversed`，實際授權變化仍由 Licentivo 應用購買快照后處理。未決爭議不改變購買記錄。歷史待核對撤款通知可通過原渠道重新驗簽重發恢復。

未知退款進入人工核對后，可由管理員通過 `POST /api/v1/admin/refunds/{id}/reconcile` 恢復原操作。回執需匹配原交易、幣種和金額；不得變更原操作編號及審批時間，超出安全重試窗口后不得盲目重新提交資金請求。

## 帳號與客戶端

1. 客戶端使用 `POST /api/v1/auth/login` 建立真實桌面登錄會話。
2. Launch SDK 請求 `POST /api/v1/software/products/{id}/identity`，指定 `sandbox` 或 `live`。
3. Launch 簽發最長 120 秒、指定接收方及產品/購買上下文的身份斷言，包含真實登錄 `sid` 和登錄到期。斷言不含功能、設備額度或離線權限。
4. Launch SDK 僅在內存中把 `identity_token`、`launch_connection_id`、`environment` 傳給官方 SDK，`license_key` 為空。
5. 官方 SDK 調用 Licentivo `/api/v1/launch/exchange`，由 Licentivo 決定授權并下發設備憑據和簽名許可。

Launch 正常帳號記錄使用 v2，只保存帳號會話及公開路由資訊，不保存斷言、許可證密鑰或授權許可。顯式退出時轉為僅用于撤銷的私有 v3 待辦，不能恢復為登錄；確認 Launch 會話撤銷后再刪除。舊 `/credential` 接口返回 HTTP 410。公鑰和產品 ID 可以隨應用分發，管理密鑰只留在服務端。

## 退出、關閉、遠程解綁

| 操作 | 行為 |
| --- | --- |
| 普通 Close / Dispose / Drop | 停止運行時，保留購買、設備綁定和主動記住的帳號 |
| Logout / ReleaseDevice 兼容入口 | 標記本地帳號退出并調用官方 SDK 退出，再向 Launch 撤銷會話；未確認的帳號退出保留安全待辦 |
| 無法接觸設備時，在 Launch 管理設備 | 代理 Licentivo 的設備列表、解綁請求及處理結果 |

官方 SDK 的退出會立即停止本進程使用授權，清理其運行憑據，使用專用退出票據撤銷遠端綁定。網路失敗必須保留 SDK 的 `.logout.json`，結果應顯示遠端撤銷待完成，不能提示解綁成功。Launch SDK 不刪除、遍歷清理或修改官方 SDK 的快取目錄；待撤銷票據由官方 SDK 在對應快取再次初始化后恢復處理。

Launch 帳號退出也有獨立的待辦狀態：網路失敗、取消或響應丟失時，不刪除重試所需的安全記錄；再次登錄、恢復或退出只補交原會話撤銷，待辦不能用于恢復登錄。成功或 HTTP 401 確認會話失效后刪除。跨進程恢復需要持久化安全 Store，MemoryStore 只在本進程有效。詳見 [退出重試修復與聯調](/zh-hant/launch-documents/logout-retry-fix-2026-10-24/)。

遠程解綁請求攜帶原列表返回的 `activation_id` 和 `expected_generation`，重試沿用 `operation_id`。Launch 不計算解綁次數，不自行審批或執行解綁隊列，也不刷新代次后自動重試舊操作。剩余次數、是否允許釋放、審核及最終結果均來自 Licentivo。

帳號恢復 `Restore` 需要聯網確認帳號并取得新身份斷言；Launch 不在帳號服務故障時自行選擇離線放行。需要離線啟動的應用按官方 SDK 的恢復契約接入；簽名、離線期限和時鐘檢查仍由官方 SDK 完成。

## 服務端身份撤銷

對接 Licentivo V39 的現有接口，無需商業事實或報價接口：

- `POST /api/v1/launch/connections/{id}/session-revocations`：撤銷指定 `sid` 或帳號的舊登錄，返回同步提交的回執。
- `GET /api/v1/launch/connections/{id}/session-revocations/{event_id}`：取回原事件的已提交結果，恢復響應丟失的請求。

普通桌面退出、強制退出指定會話使用 `scope=session`；改密、重置密碼、郵箱變更、停用帳號及網站人員角色變更導致的全部會話失效使用 `scope=account`。網站會話的普通退出不影響客戶軟體。Launch 只通知身份已失效，遠端授權會話、運行憑據和設備釋放均由 Licentivo 完成，不修改購買期限，也不消耗 Launch 維護的解綁額度。

本地會話失效與通知入隊在同一事務內完成。隊列凍結當時已存在的連接和環境，使用同一事件 ID、帳號匿名標識及原請求重試；后來創建的連接不接收歷史帳號撤銷。先查詢原回執，確認不存在時才重新提交；每個環境分別持久化結果，只有全部收到匹配的成功回執才顯示完成。斷網自動重試，憑據/契約沖突進入人工核對。管理員可在同步任務頁查看通知并重試；重試不生成新的撤銷事件。

帳號范圍撤銷以 Licentivo 首次接收的 `revoked_before` 為界。通知待完成期間暫停新的桌面登錄和身份斷言；完成后，真實登錄的 `auth_time` 必須嚴格晚于所有環境回執中的截止秒。同秒登錄可稍后重新認證；刷新 `iat` 或身份斷言不能續用舊登錄。網站登錄仍可用于恢復操作。帳號重新啟用后也必須重新登錄，不恢復舊會話。

## 舊資料遷移

有已確認舊許可證綁定的購買使用 `entitlement.migrated`，只提交舊許可證 ID，不讀取或下發舊密鑰。Licentivo 確認遷移后，再發送獨立的新版本快照同步當前商業期限和狀態。未確認過的舊發放結果及不兼容的授權需要人工核對；舊管理命令不會自動重放。

普通 SDK 退出、遠程設備解綁和服務端身份撤銷均對接現有接口。遠程停用仍受官方 SDK 已簽發離線許可的期限約束，Launch 不承諾離線設備收到即時撤銷。

<!-- account-store-ownership-2026-10-24 -->

帳號退出采用獨立安全待辦、本機會話退出摘要及跨進程協調，舊實例只處理自己的登錄。存儲故障后的恢復先補交帳號撤銷，不取得身份或啟動授權；功能、離線許可、設備代次和解綁額度繼續由 Licentivo 決定。詳見 [修復與兩端聯調記錄](/zh-hant/launch-documents/account-store-fix-2026-10-24/)。
