163 行
7.4 KiB
Markdown
163 行
7.4 KiB
Markdown
# 应用商店监测领域设计(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 的直接通知类已删除。
|