XuqmGroup-Server/docs/STORE_MONITORING_V3.md

163 行
7.4 KiB
Markdown

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

# 应用商店监测领域设计V3
## 1. 文档状态
- 文档类型:服务端对内设计与实施交接
- 当前迭代Android 全链路;租户平台 iOS/HarmonyOS 只读商店监测
- 目标地区:中国大陆(`CHN`
- 更新时间2026-07-28
- 实施状态:进行中
本文件是 `update-service` 应用商店监测领域的权威设计。历史
`storeReviewStatus` JSON、`APPROVED/liveOnStore` 混合状态以及
`StoreReviewImNotifier` 只能作为迁移线索,不是新实现契约。
## 2. 当前迭代边界
### 2.1 必须实现
1. 绑定 App Store Connect 与华为 AppGallery Connect 的只读监测凭据。
2. 拉取当前在线、审核中、审核通过待发布、拒绝等官方版本。
3. 分别保存官方版本 ID、展示版本号和平台原生构建号。
4. 以中国大陆实际可下载作为 `AVAILABLE` 的唯一条件。
5. 官方事件优先、定时轮询最终对账;相同状态不得重复产生通知事件。
6. 已上架外部版本允许由管理员创建“跳转应用商店”型 Xuqm 更新草稿。
7. 通知仅支持邮件和 Webhook,默认全部关闭。
8. 所有商店状态、人工操作和投递结果必须可审计。
### 2.2 本期禁止伪实现
1. 上传 IPA/HAP。
2. 提交 iOS/HarmonyOS 审核。
3. 对 iOS/HarmonyOS 执行立即发布、定时发布或撤回审核。
4. 在页面保留能够点击但后端只写日志的按钮。
上述写操作只在设计文档中保留扩展边界,不进入当前可用能力。
## 3. 核心不变量
1. 官方商店版本与 Xuqm 客户端更新版本是两个聚合,通过
`update_store_update_link` 显式关联。
2. 官方资源 ID 是商店版本唯一标识;展示版本号不能代替资源 ID。
3. iOS `CFBundleVersion` 是原始字符串,禁止强转为 Android `int versionCode`
4. `APPROVED_PENDING_RELEASE` 不等于 `AVAILABLE`
5. 调用官方发布接口成功也不能直接标记上架,必须由监测确认中国大陆可下载。
6. 未识别的官方状态统一映射为 `UNKNOWN`,不得猜测成审核中或已上架。
7. 凭据正文只能由 `StoreSecretProvider` 解析,控制器、实体视图和日志不得返回。
8. 监测失败只更新同步健康状态,不覆盖最后一个已验证的商店版本状态。
## 4. 统一状态机
| 状态 | 含义 | 是否允许配置客户端更新 |
| --- | --- | --- |
| `DISCOVERED` | 首次发现 | 否 |
| `PREPARING` | 商店后台准备中 | 否 |
| `SUBMITTED` | 已提交 | 否 |
| `WAITING_FOR_REVIEW` | 等待审核 | 否 |
| `IN_REVIEW` | 审核中 | 否 |
| `REJECTED` | 审核拒绝 | 否 |
| `APPROVED_PENDING_RELEASE` | 审核通过,尚未发布 | 否 |
| `RELEASE_SCHEDULED` | 已配置官方发布计划(后续版本) | 否 |
| `RELEASE_REQUESTED` | 已请求官方发布(后续版本) | 否 |
| `PROCESSING_DISTRIBUTION` | 商店分发处理中 | 否 |
| `PARTIALLY_AVAILABLE` | 非全部目标地区可用 | 否 |
| `AVAILABLE` | 中国大陆实际可下载 | 是 |
| `WITHDRAWN` | 已撤回 | 否 |
| `REMOVED` | 已下架或被替代 | 否 |
| `UNKNOWN` | 未识别官方状态 | 否 |
| `SYNC_FAILED` | 应用级同步失败视图 | 否 |
官方原始状态必须与统一状态同时保存。
## 5. 数据模型
### 5.1 商店与版本
- `update_store_application`Xuqm 应用与官方商店应用绑定。
- `update_store_version`:官方版本库存。
- `update_store_region_availability`:目标地区可用性。
- `update_store_state_event`:状态变化的不可变事件历史。
- `update_store_update_link`:官方版本与 Xuqm 更新版本的唯一有效关联。
### 5.2 凭据与通知
- `update_store_credential_profile`:非敏感凭据元数据和 Secrets 引用。
- `update_store_secret`:私有化默认 Secrets 后端的 AES-256-GCM 密文。
- `update_store_notification_policy`:应用级邮件/Webhook 策略,默认关闭。
- `update_store_notification_outbox`:异步投递、重试和最终结果。
公有化部署后续可替换 `StoreSecretProvider` 为 KMS/Vault 适配器;业务层不得感知后端类型。
公有化与私有化不允许自动回退到另一套 Secrets 服务。
## 6. API当前迭代
基础路径:`/api/v1/updates/store-monitoring`
| 方法 | 路径 | 用途 |
| --- | --- | --- |
| GET | `/bindings?appKey=...` | 查询已配置的只读绑定 |
| PUT | `/bindings/{APP_STORE\|HARMONY_APP}?appKey=...` | 保存绑定或替换监测凭据 |
| POST | `/bindings/{storeType}/sync?appKey=...` | 人工立即同步 |
| GET | `/bindings/{bindingId}/versions?appKey=...` | 查询官方版本库存 |
| GET | `/bindings/{bindingId}/events?appKey=...` | 查询最近 100 条状态事件 |
| POST | `/bindings/{bindingId}/versions/{storeVersionId}/update-draft?appKey=...` | 由 CHN 已上架版本创建 Xuqm 更新草稿 |
| GET | `/notification-policy?appKey=...` | 查询通知策略;默认全部关闭 |
| PUT | `/notification-policy?appKey=...` | 保存邮件/Webhook 通知策略 |
所有接口执行应用归属校验。凭据只在保存请求中出现一次,响应永不返回正文。
Webhook 请求包含 `X-Xuqm-Event-Id`、`X-Xuqm-Timestamp` 和
`X-Xuqm-Signature: sha256=<hex>`。签名原文为
`timestamp + "." + rawBody`,使用租户保存的 Webhook 密钥执行 HMAC-SHA256。
同一商店事件、同一渠道只产生一条 Outbox;失败采用退避重试,达到 6 次后进入
`DEAD` 并保留审计记录,不影响商店状态和平台主流程。
创建更新草稿要求商店统一状态为 `AVAILABLE``CHN` 可用性为
`AVAILABLE`。该操作只生成 `DRAFT`,不会自动发布或强制更新。重复请求返回同一条
有效关联,不重复创建版本。App 更新版本使用以下统一标识:
- Android`versionCode`;
- iOS/Harmony平台原生字符串 `buildVersion`,`versionCode` 必须为空;
- 所有平台:数据库原子分配 `releaseSequence` 负责服务端排序;
- 外部商店草稿:`updateSource=EXTERNAL_STORE`、
`installMode=STORE_REDIRECT`
## 7. 配置与部署
必须通过运行环境提供:
- `SPRING_DATASOURCE_URL`
- `SPRING_DATASOURCE_USERNAME`
- `SPRING_DATASOURCE_PASSWORD`
- `XUQM_JWT_SECRET`
- `XUQM_STORE_SECRET_MASTER_KEY`32 字节随机值的 Base64
可选配置:
- `XUQM_STORE_SECRET_KEY_VERSION`,默认 `v1`
- `XUQM_STORE_MONITORING_POLL_DELAY_MS`,默认 `600000`
- `XUQM_STORE_NOTIFICATION_DELAY_MS`,默认 `5000`
- `SMTP_HOST`、`SMTP_PORT`、`SMTP_USERNAME`、`SMTP_PASSWORD`、`SMTP_TLS`、
`SMTP_SSL`:仅启用邮件通知时需要
禁止在 Git、普通文档、日志或容器镜像中写入真实值。
## 8. 当前验证记录
2026-07-28
- `./mvnw -pl update-service -am test -DskipITs`
- 结果35 个测试通过,0 失败。
- 已覆盖统一状态映射、iOS 在线/待发布分离、HarmonyOS 在线/审核中分离、
通知默认关闭、邮件/Webhook 独立入队、CHN 上架门禁、商店草稿不伪造
Android versionCode、现有 RN release-set 与鉴权回归。
- 未验证:真实 App Store Connect、AppGallery Connect 账号联调;Flyway 对真实
MySQL 的 V5 迁移;真实 SMTP/Webhook 投递;租户平台 UI。
## 9. 下一实施顺序
1. 租户平台接入绑定、同步、版本库存、事件时间线、更新草稿和通知配置。
2. 增加真实 MySQL Flyway 集成测试与官方沙箱/测试账号联调。
3. 完成旧 `storeReviewStatus` 数据一次性迁移并删除旧读写路径及旧直发
Webhook;Update 对 IM 的直接通知类已删除。