# 应用商店监测领域设计(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=`。签名原文为 `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 的直接通知类已删除。