docs(private): 更新私有化SDK设计文档添加配置管理和错误码规范

- Flutter包名格式从xuqm_private_flutter_*改为xuqm_private_*
- 添加configVersion字段用于追踪配置变更,格式为YYYY.MM.DD-序号
- 添加配置版本管理说明,包含schemaVersion兼容性策略
- 添加配置热更新机制,支持冷加载和热加载两种方式
- 添加多环境配置支持,可通过activeProfile指定生效环境
- 添加统一错误码规范,覆盖配置缺失、格式错误、版本不兼容等场景
- 更新验收标准,包含热更新、多环境切换、错误码一致性要求
- 添加私有化开发计划中的错误码规范、文档同步、数据迁移等任务
- 补充MySQL运维细节、证书自动续期、监控告警、日志收集等部署要求
- 添加性能基准指标,包含HTTP API、WebSocket、文件传输等性能要求
- 修复应用商店审核状态轮询中的逻辑错误,添加小米商店特殊处理
- 更新前端界面显示审核版本信息,优化状态刷新逻辑
这个提交包含在:
XuqmGroup 2026-05-18 19:17:44 +08:00
父节点 93fdb31cdc
当前提交 4d54d2a4a4

查看文件

@ -525,7 +525,7 @@ public class StoreSubmissionService {
boolean hasOnlineVersion = updateVersion || !onlineVersionCode.isBlank();
boolean nonCurrentRelease = hasOnlineVersion && !currentSubmissionLive;
StoreRemoteState.ReviewState reviewState;
if (appStatus == 5) {
if (appStatus == 5 && currentSubmissionLive) {
reviewState = StoreRemoteState.ReviewState.REJECTED;
} else if (currentSubmissionLive) {
reviewState = StoreRemoteState.ReviewState.ONLINE;
@ -715,17 +715,19 @@ public class StoreSubmissionService {
log.debug("Store review poll: {}/{} still UNDER_REVIEW", v.getId(), storeType);
}
} else {
// REJECTED: only transition to APPROVED if the CURRENT submission is now live.
// If a different version is online (nonCurrentRelease), keep REJECTED
// the rejection of the current submission is still valid.
if (polled.getReviewState() == StoreRemoteState.ReviewState.ONLINE && polled.isCurrentSubmissionLive()) {
log.info("Store review poll: {}/{} was REJECTED but current submission is now live",
v.getId(), storeType);
storeService.updateStoreReviewLive(v.getId(), storeType, false,
if (polled.getReviewState() == StoreRemoteState.ReviewState.ONLINE) {
log.info("Store review poll: {}/{} was REJECTED but store has live version currentSubmissionLive={} nonCurrentRelease={} liveVersionName={} liveVersionCode={}",
v.getId(), storeType, polled.isCurrentSubmissionLive(), polled.isNonCurrentRelease(),
polled.getOnlineVersionName(), polled.getOnlineVersionCode());
storeService.updateStoreReviewLive(v.getId(), storeType, !polled.isCurrentSubmissionLive(),
buildLiveReason(polled), buildExtra(polled));
} else if (polled.getReviewState() == StoreRemoteState.ReviewState.ONLINE && polled.isNonCurrentRelease()) {
log.debug("Store review poll: {}/{} was REJECTED and a different version is online — leaving REJECTED",
} else if ("MI".equals(storeType)
&& polled.getReviewState() == StoreRemoteState.ReviewState.UNDER_REVIEW_XIAOMI) {
log.info("Store review poll: {}/{} was REJECTED but Xiaomi has no current-version reject signal — restoring UNDER_REVIEW",
v.getId(), storeType);
storeService.updateStoreReview(v.getId(), storeType,
AppVersionEntity.StoreReviewState.UNDER_REVIEW,
"小米应用商店当前提交版本审核中");
}
// otherwise leave REJECTED as-is
}
@ -755,6 +757,12 @@ public class StoreSubmissionService {
reviewMap = new LinkedHashMap<>();
}
List<String> targets = parseTargets(v.getStoreSubmitTargets());
if (targets.isEmpty() && !reviewMap.isEmpty()) {
targets = new ArrayList<>(reviewMap.keySet());
}
if (targets.isEmpty()) {
targets = storeService.resolveDefaultStoreTargets(v.getAppKey());
}
List<StoreRemoteState> results = new ArrayList<>();
for (String storeType : targets) {
AppStoreConfigEntity cfg;
@ -796,24 +804,26 @@ public class StoreSubmissionService {
boolean isUnderReview = "UNDER_REVIEW".equals(existingState);
boolean isRejected = "REJECTED".equals(existingState);
AppVersionEntity.StoreReviewState mappedState = mapToStoreReviewState(polled.getReviewState());
if (isUnderReview) {
if (mappedState != AppVersionEntity.StoreReviewState.UNDER_REVIEW) {
log.info("Manual refresh: {}/{} status changed from UNDER_REVIEW to {}", v.getId(), storeType, mappedState);
if (mappedState == AppVersionEntity.StoreReviewState.APPROVED) {
log.info("Manual refresh: {}/{} writing live state currentSubmissionLive={} nonCurrentRelease={} liveVersionName={} liveVersionCode={}",
v.getId(), storeType, polled.isCurrentSubmissionLive(), polled.isNonCurrentRelease(),
polled.getOnlineVersionName(), polled.getOnlineVersionCode());
storeService.updateStoreReviewLive(v.getId(), storeType, !polled.isCurrentSubmissionLive(),
buildLiveReason(polled), buildExtra(polled));
} else {
} else if ("MI".equals(storeType)
&& polled.getReviewState() == StoreRemoteState.ReviewState.UNDER_REVIEW_XIAOMI) {
if (!"UNDER_REVIEW".equals(existingState)) {
log.info("Manual refresh: {}/{} restoring Xiaomi UNDER_REVIEW from {}", v.getId(), storeType, existingState);
}
storeService.updateStoreReview(v.getId(), storeType,
AppVersionEntity.StoreReviewState.UNDER_REVIEW,
"小米应用商店当前提交版本审核中");
} else if (isUnderReview || isRejected) {
if (mappedState != AppVersionEntity.StoreReviewState.UNDER_REVIEW
|| !"UNDER_REVIEW".equals(existingState)) {
log.info("Manual refresh: {}/{} writing {} from {}", v.getId(), storeType, mappedState, existingState);
storeService.updateStoreReview(v.getId(), storeType, mappedState, "手动刷新厂商审核状态");
}
}
} else if (isRejected) {
if (polled.getReviewState() == StoreRemoteState.ReviewState.ONLINE && polled.isCurrentSubmissionLive()) {
log.info("Manual refresh: {}/{} was REJECTED but current submission is now live", v.getId(), storeType);
storeService.updateStoreReviewLive(v.getId(), storeType, false,
buildLiveReason(polled), buildExtra(polled));
} else if (polled.getReviewState() == StoreRemoteState.ReviewState.ONLINE && polled.isNonCurrentRelease()) {
log.info("Manual refresh: {}/{} was REJECTED and a different version is online — leaving REJECTED", v.getId(), storeType);
}
} else {
// For other states (PENDING, SUBMITTING, APPROVED, WITHDRAWN),
// just record the polled state without modifying the database.
@ -845,7 +855,9 @@ public class StoreSubmissionService {
if (result.isCurrentSubmissionLive()) {
return "厂商审核状态轮询检测:本次提交版本已上线";
}
String version = firstNonBlank(result.getOnlineVersionName(), result.getOnlineVersionCode());
String name = result.getOnlineVersionName();
String code = result.getOnlineVersionCode();
String version = !name.isBlank() && !code.isBlank() ? name + " · " + code : firstNonBlank(name, code);
if (!version.isBlank()) {
return "应用商店已有线上版本 " + version + ",非本次发布";
}
@ -861,6 +873,12 @@ public class StoreSubmissionService {
if (!result.getOnlineVersionCode().isBlank()) {
extra.put("liveVersionCode", result.getOnlineVersionCode());
}
if (!result.getReviewVersionName().isBlank()) {
extra.put("reviewVersionName", result.getReviewVersionName());
}
if (!result.getReviewVersionCode().isBlank()) {
extra.put("reviewVersionCode", result.getReviewVersionCode());
}
if (result.isNonCurrentRelease()) {
extra.put("nonCurrentRelease", true);
}