提交图

90 次代码提交

作者 SHA1 备注 提交日期
XuqmGroup
f24e0356a7 fix(api): return forbidden for ownership denials 2026-07-29 00:55:51 +08:00
XuqmGroup
63cc21d812 fix(update): repair baselined plugin schema 2026-07-29 00:40:25 +08:00
XuqmGroup
b7980ade1c fix(update): decouple optional mail health 2026-07-28 22:04:30 +08:00
XuqmGroup
a86b753508 fix(update): make store migration production-safe 2026-07-28 21:50:28 +08:00
XuqmGroup
228c87f5da refactor(security): remove client-embedded app secret 2026-07-28 20:12:27 +08:00
XuqmGroup
f96a27facc feat(update): add official store monitoring domain 2026-07-28 19:53:15 +08:00
XuqmGroup
061b9a53e7 feat(update): implement signed RN release sets 2026-07-27 09:58:25 +08:00
XuqmGroup
c51cdd46f4 feat(platform): implement signed sdk config and artifacts 2026-07-27 09:58:25 +08:00
XuqmGroup
e34ef26d73 feat(update-service,file-service): 下载页对已丢失的历史APK显示"无法下载"
新增 file-service GET /api/file/{hash}/exists 轻量存在性检查(不读取文件内容),
下载页为每个历史版本调用该接口确认文件是否真实存在;若已丢失(如本次修复之前
就已被 30 天回收任务误删),不再展示会 404 的下载按钮,改为显示"无法下载"提示。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04 02:47:50 +08:00
XuqmGroup
9be2e71b82 feat(update-service,file-service): 按占用空间阈值清理历史APK,下载页兼容"从未点击发布"的真实数据
- 下载页/公开接口重新定义"曾上架":不再要求内部 PublishStatus=PUBLISHED,
  实际生产数据显示大多数租户只提交应用商店从不点击"发布",现改为
  PublishStatus 已发布 或 任一厂商 storeReviewStatus 显示 liveOnStore
- 新增 file-service DELETE /api/file/{hash}(X-Internal-Token 保护,销毁性操作不能像
  pin/GET 一样完全公开)
- 新增 ApkRetentionService:按 appKey 分组,从最新版本往回累加安装包大小,
  超过阈值(默认 5GB,可通过发布配置 JSON 里 apkRetentionMaxTotalSizeMb 按应用覆盖)
  即清理更旧版本的安装包,但永远保留最新版本
- AppVersionEntity 新增 fileSize 字段,上传时记录(本地存储路径直接取
  MultipartFile.getSize(),file-service 路径由前端一并上传时的 size 回传)
- 新增每日 02:00 自动重新 pin 所有历史 APK 的兜底任务,保护本次修复之前已上传、
  尚未被 pin 保护的历史版本

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04 02:38:35 +08:00
XuqmGroup
eb0e3a1877 fix(file-service,update-service): APK 下载 500、文件被误回收;下载页支持历史版本
file-service:
- 新增 GlobalExceptionHandler(此前完全缺失,任何异常都变成裸 500,包括文件不存在)
- 修复 Content-Disposition 文件名未按 RFC 5987 编码,中文应用名会导致下载响应异常
- 新增 pinned 标记 + POST /api/file/{hash}/pin,30 天未访问自动回收任务不再误删仍被引用的文件

update-service:
- 上传 APK 到 file-service 后自动调用 pin,防止已发布版本的安装包被回收站清理
- PublicDownloadController 返回 Android 全部曾发布版本(PUBLISHED+DEPRECATED)历史列表,而非仅最新版本

tenant-platform:
- 下载页展示历史版本列表,支持下载任意历史 APK
- 版本管理页新增"复制对外下载页链接"入口,便于管理员查找/分享

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04 02:12:55 +08:00
XuqmGroup
7db07cc5fc fix(update-service): OPPO 商店状态字段读取修复、避免重复审核通知,新增默认更新说明与公开下载接口
- 修复 OPPO 状态查询读取 snake_case 字段名(version_code/version_name),解决版本已上线仍显示"审核中"
- 手动刷新厂商状态时若已是干净的 APPROVED+live 状态则跳过重复通知,避免重复发送【应用审核通知】
- 各厂商提交分支统一走 effectiveChangeLog(),更新说明为空时兜底默认文案
- 新增 GET /api/v1/updates/public/download-info 公开接口,支撑新的应用下载页

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04 01:50:42 +08:00
XuqmGroup
8c0bcef237 fix: update store state to APPROVED when app is live even if version code doesn't match exactly
- When polled state is ONLINE but version codes don't match, still mark as APPROVED with nonCurrentRelease=true
- Prevents state getting stuck at UNDER_REVIEW when Huawei shows the app is already live
- Fixes issue where Huawei app is live but system still shows '审核中'

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-02 19:34:28 +08:00
XuqmGroup
a6da4f3560 fix: prevent duplicate store submissions by adding SUBMITTING state guard
- Add SUBMITTING to skip guard in executeSubmitAsync to prevent concurrent uploads
- Add getSubmittingStores() public method to check SUBMITTING state
- Add controller-level check to reject submissions when stores are already uploading
- Prevents VIVO/Honor 'app is under review' errors from duplicate uploads

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-02 18:56:33 +08:00
XuqmGroup
5b1e04b6d1 feat: update-service 签名验证 + bugcollect 统计图表 API + 修复字段映射
- update-service: 集成 AppSignatureAuthFilter 签名验证
- update-service: 添加 TenantAppSecretResolver
- bugcollect: 新增 /statistics 统计 API 端点
- bugcollect: 修复 OverviewResponse 字段名(crashRateTrend/topIssues/crashRate)
- bugcollect: 修复 IssueResponse 添加 type 字段
- bugcollect: 修复 affectedUsers 语义(从 openIssues 改为真正的受影响用户数)
- bugcollect: 新增 StatisticsResponse DTO
- bugcollect: LogIssueRepository 新增统计查询方法

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-19 01:26:36 +08:00
XuqmGroup
8ac2a37e7f fix: bugcollect controller 路径从 /bugcollect/v1 改为 /api/bugcollect/v1,匹配 nginx 路由 2026-06-19 00:41:07 +08:00
XuqmGroup
92f2c7c88b feat(update-service): 添加更新服务配置文件
- 配置服务器端口为8084
- 设置MySQL数据库连接参数包括URL、用户名、密码和驱动
- 配置HikariCP连接池参数如最小空闲连接、最大池大小等
- 启用Flyway数据库迁移并配置基线版本和历史表
- 设置JWT密钥和过期时间
- 配置文件上传目录和基础URL
- 添加租户服务URL和内部令牌配置
- 启用健康检查和信息端点监控
2026-06-17 13:55:55 +08:00
XuqmGroup
d127ce785f fix(update-service): 服务开通检查改为查 t_feature_service.enabled,而非 existsByAppKey
existsByAppKey 在服务关闭但历史版本仍存在时会误判为已开通。
改为调 tenant-service 内部接口 /services/{platform}/UPDATE 查 enabled 字段。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 13:02:28 +08:00
XuqmGroup
3cf5e294aa feat(update-service): 更新服务未开通时返回 error 40404,修复多处编译错误
- AppVersionController: appKey 无任何版本记录时返回 ApiResponse.error(40404, "更新服务未开通")
- AppVersionRepository: 新增 existsByAppKey() 方法
- SchemaMigrationRunner: BeanFactoryPostProcessor → ApplicationRunner,修复 DataSource 启动时序问题
- pom.xml: 补全 spring-boot-starter-websocket 依赖
- 修复编译错误: GrayMemberService JsonNode import、StoreSubmissionService objectMapper→mapper、PublishConfigService groupName 方法不存在、RnBundleController memberCount 未定义、UnifiedReleaseController StoreResult 类型不匹配、UpdateAssetService NoSuchAlgorithmException 未捕获
- application.yml: 关闭 Flyway(原始配置),ddl-auto 改回 update

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 12:21:54 +08:00
XuqmGroup
ffdb7c56fe fix(flyway): 各服务配置独立历史表名,解决共享数据库冲突
私有化部署所有服务共用同一 MySQL 库,Flyway 默认都写
flyway_schema_history,导致不同服务的 V1 checksum 互相
覆盖/冲突。改为每个服务使用独立的表名:
flyway_history_{tenant|im|file|update|license|push|demo}

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 00:05:31 +08:00
XuqmGroup
200f8ae54a feat: 引入 Flyway 数据库版本管理,替换 ddl-auto: update
所有服务(tenant/im/file/update/license/push/demo)统一:
- 添加 flyway-core + flyway-mysql 依赖
- ddl-auto 从 update 改为 validate
- 添加 V1__init.sql 基线(CREATE TABLE IF NOT EXISTS,幂等)
- baseline-on-migrate=true 兼容已有部署,存量库不重跑 V1

后续 Entity 变更须同步写 V(n+1) 迁移 SQL,Flyway 在容器
启动时自动按版本顺序执行,update.sh 无需任何改动。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 23:28:12 +08:00
XuqmGroup
77553cd105 feat(app): 支持多平台包名配置和应用信息编辑功能
- 后端增加至少填写一个平台包名的验证逻辑
- 前端调整应用数据模型,将包名字段改为可选类型
- 添加应用详情页的编辑功能和表单验证
- 优化应用列表页包名显示逻辑,支持多平台包名展示
- 重构应用配置指引页面,按平台分类展示商店配置指南
- 在版本管理页面增加包名配置检查和相应提示
- 新增应用信息编辑弹窗组件和相关业务逻辑
2026-06-11 13:04:28 +08:00
XuqmGroup
3e2db6441e feat(update): 添加 API Key 管理和 WebSocket 实时通知功能
- 新增 API Key 管理功能,支持外部工具认证调用平台 API
- 实现 WebSocket 实时通知,版本发布时推送轻量通知给客户端
- 添加 APK 文件哈希校验,支持已下载检测和直接安装
- 支持外部 APK 上传使用 API Key 认证
- 优化私有化部署自动注入 nginx WebSocket 代理配置
- 扩展 SDK 功能包括已下载检测、直接安装和实时通知监听
2026-06-11 12:25:16 +08:00
XuqmGroup
73dd4814f2 feat(logs): 添加操作日志功能支持推送和授权模块
- 在JwtAuthFilter中设置认证详情到claims
- 为license-service添加LicenseOperationLog相关实体、仓库和服务
- 为push-service添加PushOperationLog相关实体、仓库和服务
- 在LicenseAdminController中注入并使用操作日志记录授权变更
- 在PushManagementController中注入并使用操作日志记录推送操作
- 更新OperationLogService以支持从JWT claims获取用户信息
- 扩展OperationLogService支持推送和授权操作日志查询
- 在前端OperationLogView中添加推送和授权日志选项卡
- 添加LicenseOperationLog和PushOperationLog接口定义
- 实现推送和授权日志的数据加载和分页功能
- 添加操作类型和资源类型的标签映射支持
2026-05-27 13:36:16 +08:00
XuqmGroup
50da70d580 fix(core): 统一全局异常处理器并添加数据库管理功能
- 在所有服务的GlobalExceptionHandler中添加HttpServletRequest参数以记录请求上下文
- 统一异常响应格式为ResponseEntity<ApiResponse<Void>>并改进错误日志记录
- 添加对多种异常类型的处理包括参数验证、请求方法不支持、权限拒绝等
- 为业务异常添加不同级别的日志记录(warn/error)和状态码映射
- 在前端系统API中新增数据库表管理相关接口定义和实现
- 添加数据库表列表、列信息和数据查询的API调用函数
2026-05-27 11:51:19 +08:00
XuqmGroup
e75aa66747 refactor(update): 移除包名校验逻辑简化版本检查接口
- 移除了 AppVersionController 中的 packageName 参数验证
- 简化了 resolveAndValidate 方法的参数列表
- 删除了包名校验相关的业务逻辑和异常抛出
- 移除了对 tenantClient 平台信息的包名校验调用
- 更新了方法签名以减少参数传递复杂度
2026-05-23 03:48:02 +08:00
XuqmGroup
c6ab1b9244 fix(update): 修复应用版本审核状态轮询逻辑
- 扩展查询条件以包含非当前发布和预存在标记的应用版本
- 更新轮询日志信息以反映新的状态检查范围
- 添加对已批准商店中陈旧非当前发布/预存在标记的清理逻辑
- 实现在线版本码比较来清除错误的状态标记
- 优化轮询流程以处理审核状态和陈旧标记的组合情况
2026-05-22 22:18:50 +08:00
XuqmGroup
362dbcc638 fix: clear stale nonCurrentRelease even when onlineVersionCode is blank
Enhance the universal cleanup in refreshStoreReviewStatus to also clear
stale nonCurrentRelease/preExisting marks when onlineVersionCode is blank
but currentSubmissionLive is false. This handles OPPO and other stores
that may not return a versionCode in their API response.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 19:55:49 +08:00
XuqmGroup
619e822d85 fix: clear stale nonCurrentRelease regardless of polled review state
Previous fix only cleared stale APPROVED+nonCurrentRelease states when
poll returned mappedState==APPROVED. If the store API returned UNDER_REVIEW
(for the newly-submitted version) while the DB still held a stale
APPROVED+nonCurrentRelease from the old online version, the stale state
was never cleared.

Add universal cleanup: before any mappedState branching, if onlineVersionCode
< submittedCode and the DB entry has nonCurrentRelease/preExisting flags,
immediately clear the store review state.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 19:44:53 +08:00
XuqmGroup
0c9fd338eb fix: clear stale APPROVED state when online version is older than submitted
- Add AppStoreService.clearStoreReview() to remove a store's review entry
  from storeReviewStatus JSON (used for false-positive cleanup)
- refreshStoreReviewStatus: when existing state is APPROVED but polled
  onlineVersionCode < submittedCode, clear the stale state instead of
  leaving the misleading nonCurrentRelease flag in place

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 19:20:48 +08:00
XuqmGroup
94fda7ad6e fix: allow store submission when online version is older than submitted
- Add compareVersionCodes() helper to compare numeric versionCodes safely
- preflightStoreSubmission: block only when onlineVersionCode >= submittedCode;
  allow submit when online < submitted (normal new release)
- refreshStoreReviewStatus: only write preExisting=true when online >= submitted
- pollStoreReviewStatus: same guard for UNDER_REVIEW/REJECTED → ONLINE transitions
- All per-store query methods (Huawei, Xiaomi, OPPO, VIVO, Honor): only set
  nonCurrentRelease=true when onlineVersionCode > submittedCode
- Fix pre-existing compilation errors: replace findByAppKeyAndStoreType with
  findTopByAppKeyAndStoreTypeOrderByUpdatedAtDesc

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 19:09:20 +08:00
XuqmGroup
8c9bfb6acd feat: license 文件作为通用凭证支持所有服务 SDK 初始化
- LicenseFileCrypto 移至 common 模块并新增 decrypt() 方法
- LicenseFileCrypto.LicensePayload 携带 appKey / packageName / iosBundleId / harmonyBundleName,matchesPackageName() 支持三端包名任一匹配
- tenant-service downloadLicenseFile:去掉"License 服务已开通"限制,app 创建即可下载;payload 新增 iosBundleId / harmonyBundleName
- im / push / update / license 四个服务 SDK 初始化端点均支持双模式:
  · licenseFile 模式:解密文件取 appKey,比对 packageName(无需调 tenant-service)
  · appKey 模式:调 tenant-service 取 platformInfo 比对 packageName(原有逻辑)
- appKey 参数由必填改为可选(与 licenseFile 二选一)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 16:47:30 +08:00
XuqmGroup
0a267c5f70 feat: 校验 SDK 初始化时 packageName 与平台配置的 appKey 是否匹配
- im/push/update 三个服务登录/检查更新接口新增必填参数 packageName
- 调用对应服务的 tenant-service 内部接口获取 platformInfo,与传入包名比对,不匹配返回 403
- update 服务按 platform 字段精确匹配(ANDROID/IOS/HARMONY 各用对应字段)
- im/push 服务对三端包名任一匹配即通过
- ImAppSecretClient / PushAppSecretClient 新增 getPlatformInfo 缓存方法
- 新增 UpdateTenantClient 用于 update-service 调用 tenant-service platformInfo 接口

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 16:41:17 +08:00
XuqmGroup
138360b760 fix(update): rewrite file-service URL to internal address for private deployments
UpdateAssetService: add FILE_BASE_URL / FILE_SERVICE_INTERNAL_URL config; any URL
starting with FILE_BASE_URL is rewritten to the internal file-service address instead
of going through the external domain, fixing APK inspect timeout on private deployments.

SystemUpdateService: add patchDockerComposeUpdateService() to inject FILE_BASE_URL and
FILE_SERVICE_INTERNAL_URL into existing customers' docker-compose.yml on update.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 16:03:09 +08:00
XuqmGroup
9728dbb002 fix: suppress duplicate-result errors and hide system apps from private deployment
update-service:
- AppPublishConfigRepository/AppStoreConfigRepository: change Optional-returning
  findBy methods to findTopBy...OrderByUpdatedAtDesc to tolerate duplicate rows in
  public DB and avoid IncorrectResultSizeDataAccessException
- Revert GlobalExceptionHandler to safe "服务器内部错误" (debug details removed)

tenant-service:
- SdkAppInitializer: skip Demo Chat creation on DEPLOYMENT_MODE=PRIVATE;
  migrate existing system apps (ak_demo_chat, IM platform app) to is_default=true
- SdkAppProvisioningService.ensureApp: mark all platform-provisioned apps as
  is_default=true, deletable=false so they don't appear in user's app list
- PrivateTenantBootstrapInitializer: migrate existing private bootstrap apps to
  is_default=true on upgrade
- AppService.listByTenant: filter out is_default=true system apps from the list

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 14:24:33 +08:00
XuqmGroup
855b17ef0e fix(update): 修复版本列表排序并改进Android包上传功能
- 将版本查询排序从versionCode改为createdAt以正确显示最新版本
- 为Android包上传表单添加已上传文件显示区域
- 实现删除已上传文件的功能以便重新上传
- 添加上传组件引用以支持文件清除操作
- 增加Document和Delete图标导入用于文件管理界面
- 添加已上传文件信息的样式和布局支持
2026-05-21 18:20:06 +08:00
XuqmGroup
24e11794bc refactor(update): 移除版本重复检查并修改发布状态逻辑
- 移除了应用包名和版本号的重复上传检查逻辑
- 修改了发布立即生效时的状态变更机制,改为将其他已发布版本标记为废弃状态
- 新增了按应用键、平台和发布状态查询的方法
- 简化了版本上传时的验证流程,移除了APK文件MD5比较相关代码
2026-05-21 18:08:21 +08:00
XuqmGroup
e5d9e0da0c debug(update-service): 在错误响应中暴露异常信息(临时)
用于排查上传接口 500 错误的根本原因,确认后将恢复。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 17:47:51 +08:00
XuqmGroup
d49d0297cf fix(update-service): 非灰度版本对匿名用户可见
原逻辑在 allowAnonymousCheck=false 且 userId=null 时直接返回
needsUpdate=false,导致无登录流程的应用(如 clinical-android)
永远收不到更新提示。

修正为:只有灰度版本才需要 userId;非灰度已发布版本对所有调用
方可见,allowAnonymousCheck=false 仅在非灰度场景下补充拦截。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 17:22:59 +08:00
XuqmGroup
02ad5aad06 fix(private): 私有化部署 CORS 放开所有 Origin
私有化部署时客户使用自定义域名,原硬编码的 *.xuqinmin.com 白名单
导致 WebSocket 握手和跨域请求被 Spring Security CORS 过滤器拒绝(426/403)。
检测 DEPLOYMENT_MODE=PRIVATE 环境变量,私有化模式下允许所有 Origin。
影响范围:im-service / file-service / license-service / update-service。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 10:44:33 +08:00
XuqmGroup
4432c7dc28 fix(oppo): remap audit_status=5 to UNDER_REVIEW; restore REJECTED→UNDER_REVIEW in poll
OPPO returns audit_status=5 for versions currently under review (审核中);
previously this was mapped to REJECTED causing a state mismatch. Only 444
is now treated as the rejected aggregate code.

Also extend the scheduled poll to restore REJECTED→UNDER_REVIEW for any
store (not just Xiaomi) when the vendor API reports the version is under
review, covering cases where the submission succeeded after our platform
recorded an exception.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 10:59:52 +08:00
XuqmGroup
4d2faa33de fix(oppo): strip empty params from submit body to fix sign mismatch (errno=800004)
OPPO server includes all received body params in server-side signature computation;
sending empty-string optional params while excluding them from the client-side sign
produces a mismatch. Remove empty entries from params map before building both the
api_sign and the POST body so both sides operate on identical param sets.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 10:16:41 +08:00
XuqmGroup
501d7e09ab fix(update): fix OPPO token expiry, sign empty params, and MI already-live detection
- OPPO: re-obtain access token after APK upload (prevents expiry during long uploads)
- OPPO: exclude empty-string params from api_sign computation per OPPO spec
- OPPO: include errno in error message for easier debugging
- MI: detect already-live version via packageInfo.versionCode before upload;
  throw VersionAlreadyLiveException → executor marks state APPROVED instead of REJECTED

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 19:11:13 +08:00
XuqmGroup
450a44de68 fix: isolate private deployment databases and fix store review refresh bugs
application.yml — all services:
- Replace hardcoded jdbc:mysql://39.107.53.187 with ${SPRING_DATASOURCE_URL:fallback}
- Same for SPRING_DATASOURCE_USERNAME/PASSWORD
- im-service: replace hardcoded redisdev.xuqinmin.com with ${SPRING_DATA_REDIS_*}
  This ensures docker-compose environment overrides take effect; without these
  placeholders, Spring Boot's relaxed binding couldn't override the YAML values
  and the private deployment connected to production databases.

StoreSubmissionService.refreshStoreReviewStatus — two bugs fixed:
1. MI/UNDER_REVIEW_XIAOMI branch now guards against downgrading APPROVED state.
   Xiaomi's poll API returns UNDER_REVIEW_XIAOMI when the submitted version is
   not yet the live version, even after the store approves it. Previously this
   caused the manual refresh to overwrite a webhook-confirmed APPROVED with
   UNDER_REVIEW on every click.
2. When the poll returns APPROVED but currentSubmissionLive=false (another version
   is live on the store), no longer overwrite an existing APPROVED (from webhook)
   with nonCurrentRelease=true. The webhook is authoritative; the live version
   difference just means distribution is pending, not that this is a non-current
   release. Only adds nonCurrentRelease when transitioning FROM a non-APPROVED
   state (true pre-existing detection).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 18:25:50 +08:00
XuqmGroup
d007072ea9 fix(update): send webhook on store live detection (Xiaomi 已上架)
updateStoreReviewLive was calling IM notifier but not sendWebhook,
so polling-detected APPROVED events (e.g. Xiaomi going live) never
triggered the tenant's configured webhook URL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 15:57:51 +08:00
XuqmGroup
4d54d2a4a4 docs(private): 更新私有化SDK设计文档添加配置管理和错误码规范
- Flutter包名格式从xuqm_private_flutter_*改为xuqm_private_*
- 添加configVersion字段用于追踪配置变更,格式为YYYY.MM.DD-序号
- 添加配置版本管理说明,包含schemaVersion兼容性策略
- 添加配置热更新机制,支持冷加载和热加载两种方式
- 添加多环境配置支持,可通过activeProfile指定生效环境
- 添加统一错误码规范,覆盖配置缺失、格式错误、版本不兼容等场景
- 更新验收标准,包含热更新、多环境切换、错误码一致性要求
- 添加私有化开发计划中的错误码规范、文档同步、数据迁移等任务
- 补充MySQL运维细节、证书自动续期、监控告警、日志收集等部署要求
- 添加性能基准指标,包含HTTP API、WebSocket、文件传输等性能要求
- 修复应用商店审核状态轮询中的逻辑错误,添加小米商店特殊处理
- 更新前端界面显示审核版本信息,优化状态刷新逻辑
2026-05-18 19:17:44 +08:00
XuqmGroup
93fdb31cdc docs(private): 完善私有化部署开发计划和设计规范
- 增加实时进度和交接规则,定义任务状态枚举和更新格式
- 创建任务进度台账,涵盖P0-P5阶段全部开发任务
- 补充部署仓库交付边界确认和进度审计规范
- 完善MySQL/Redis双模式支持,增加external/managed选项
- 增加离线部署、安全治理、可观测性等完整交付能力
- 更新仓库结构设计,增加secrets.env、observability、data目录
- 补充健康检查、诊断脚本、升级回滚、备份恢复详细要求
- 优化应用商店审核状态查询逻辑,增加手动刷新接口
- 修复小米和VIVO商店状态查询中的版本匹配逻辑错误
- 增加缓存键版本隔离,防止不同版本状态混淆
- 优化厂商API连通性检查和审核状态轮询机制
2026-05-18 19:00:38 +08:00
XuqmGroup
87edb316a5 feat(private-deploy): 支持 MySQL/Redis 外部连接和托管模式部署
- 添加 external 和 managed 两种数据库/缓存模式支持
- 实现 MySQL/Redis 托管安装脚本和配置向导
- 支持客户自备连接或部署脚本新建基础设施
- 更新部署文档说明不同模式的配置和验证要求
- 添加应用版本防重复上传和删除功能
- 实现应用商店预提交检查和发布计划功能
2026-05-18 18:37:10 +08:00
XuqmGroup
b3b33dbb7b fix: remove unreliable post-failure live-check; restrict REJECTED poll to HUAWEI
Post-failure live check called pollStoreSingleReviewState on submission
failure, but for MI/VIVO/OPPO/HONOR the poll returns APPROVED for ANY
live version (not version-specific). This caused false positives: if an
older version was live on Xiaomi, the poll would return APPROVED and
incorrectly mark the new submission as 已上线(直接上传).

Changes:
- Remove post-failure live check from executeSinglePlan and sequential
  failure handler — submission failures are just marked REJECTED
- Restrict the REJECTED-store poll to HUAWEI only, since it is the only
  store where pollStoreSingleReviewState is version-specific
  (compares onShelfVersionCode against v.getVersionCode())
- Log full VIVO data response to capture versionCode field name for
  future version-specific detection

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 17:52:53 +08:00
XuqmGroup
8d46d21726 fix: store resubmission, Xiaomi curl, and live-on-store detection
- Dockerfile: add curl to Alpine runtime image (required by Xiaomi/Vivo
  APK upload which uses ProcessBuilder curl for HTTP/1.1 multipart)
- AppStoreService: mark previously-APPROVED stores as WITHDRAWN on
  resubmission so executeSubmitAsync calls the store cancel API first;
  guard updateStoreReview from stale APPROVED webhooks on PENDING/WITHDRAWN
  stores; add updateStoreReviewLive() to record pre-existing live versions
  with liveOnStore/preExisting metadata
- StoreSubmissionService: call cancelAtStore for WITHDRAWN stores before
  resubmitting; expand poll query to include REJECTED stores and call
  updateStoreReviewLive when a REJECTED store is found live; after any
  submission failure check if the store already has the version live
  (catches Huawei/Vivo pre-existing direct uploads at submission time)
- AppVersionRepository: add findAllWithUnderReviewOrRejectedStores query

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 17:30:26 +08:00