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>
这个提交包含在:
XuqmGroup 2026-05-19 18:25:50 +08:00
父节点 9771663f00
当前提交 450a44de68
共有 6 个文件被更改,包括 52 次插入30 次删除

查看文件

@ -8,9 +8,9 @@ spring:
virtual: virtual:
enabled: true enabled: true
datasource: datasource:
url: jdbc:mysql://39.107.53.187:3306/xuqm_file?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true url: ${SPRING_DATASOURCE_URL:jdbc:mysql://39.107.53.187:3306/xuqm_file?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true}
username: xuqm username: ${SPRING_DATASOURCE_USERNAME:xuqm}
password: Xuqm@2026 password: ${SPRING_DATASOURCE_PASSWORD:Xuqm@2026}
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
hikari: hikari:
minimum-idle: 2 minimum-idle: 2

查看文件

@ -5,9 +5,9 @@ spring:
application: application:
name: im-service name: im-service
datasource: datasource:
url: jdbc:mysql://39.107.53.187:3306/xuqm_im?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true url: ${SPRING_DATASOURCE_URL:jdbc:mysql://39.107.53.187:3306/xuqm_im?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true}
username: xuqm username: ${SPRING_DATASOURCE_USERNAME:xuqm}
password: Xuqm@2026 password: ${SPRING_DATASOURCE_PASSWORD:Xuqm@2026}
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
hikari: hikari:
minimum-idle: 5 minimum-idle: 5
@ -24,10 +24,10 @@ spring:
dialect: org.hibernate.dialect.MySQLDialect dialect: org.hibernate.dialect.MySQLDialect
data: data:
redis: redis:
host: redisdev.xuqinmin.com host: ${SPRING_DATA_REDIS_HOST:redisdev.xuqinmin.com}
port: 6379 port: ${SPRING_DATA_REDIS_PORT:6379}
password: xuqinmin1022 password: ${SPRING_DATA_REDIS_PASSWORD:xuqinmin1022}
database: 2 database: ${SPRING_DATA_REDIS_DATABASE:2}
timeout: 10s timeout: 10s
lettuce: lettuce:
pool: pool:

查看文件

@ -5,9 +5,9 @@ spring:
application: application:
name: license-service name: license-service
datasource: datasource:
url: jdbc:mysql://39.107.53.187:3306/pad_license?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true url: ${SPRING_DATASOURCE_URL:jdbc:mysql://39.107.53.187:3306/pad_license?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true}
username: xuqm username: ${SPRING_DATASOURCE_USERNAME:xuqm}
password: Xuqm@2026 password: ${SPRING_DATASOURCE_PASSWORD:Xuqm@2026}
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
hikari: hikari:
minimum-idle: 5 minimum-idle: 5

查看文件

@ -5,9 +5,9 @@ spring:
application: application:
name: push-service name: push-service
datasource: datasource:
url: jdbc:mysql://39.107.53.187:3306/xuqm_push?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true url: ${SPRING_DATASOURCE_URL:jdbc:mysql://39.107.53.187:3306/xuqm_push?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true}
username: xuqm username: ${SPRING_DATASOURCE_USERNAME:xuqm}
password: Xuqm@2026 password: ${SPRING_DATASOURCE_PASSWORD:Xuqm@2026}
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
hikari: hikari:
minimum-idle: 5 minimum-idle: 5

查看文件

@ -803,24 +803,46 @@ public class StoreSubmissionService {
} }
boolean isUnderReview = "UNDER_REVIEW".equals(existingState); boolean isUnderReview = "UNDER_REVIEW".equals(existingState);
boolean isRejected = "REJECTED".equals(existingState); boolean isRejected = "REJECTED".equals(existingState);
boolean isApproved = "APPROVED".equals(existingState);
AppVersionEntity.StoreReviewState mappedState = mapToStoreReviewState(polled.getReviewState()); AppVersionEntity.StoreReviewState mappedState = mapToStoreReviewState(polled.getReviewState());
if (mappedState == AppVersionEntity.StoreReviewState.APPROVED) { if (mappedState == AppVersionEntity.StoreReviewState.APPROVED) {
log.info("Manual refresh: {}/{} writing live state currentSubmissionLive={} nonCurrentRelease={} liveVersionName={} liveVersionCode={}", if (polled.isCurrentSubmissionLive()) {
v.getId(), storeType, polled.isCurrentSubmissionLive(), polled.isNonCurrentRelease(), // Submitted version is now live update with currentSubmissionLive=true
polled.getOnlineVersionName(), polled.getOnlineVersionCode()); log.info("Manual refresh: {}/{} submitted version now live — updating", v.getId(), storeType);
storeService.updateStoreReviewLive(v.getId(), storeType, !polled.isCurrentSubmissionLive(), storeService.updateStoreReviewLive(v.getId(), storeType, false,
buildLiveReason(polled), buildExtra(polled)); buildLiveReason(polled), buildExtra(polled));
} else if (!isApproved) {
// Store has a different live version (preExisting) and we didn't have APPROVED yet.
// Mark as pre-existing live so UI shows which version is actually on the store.
log.info("Manual refresh: {}/{} pre-existing live detected currentSubmissionLive={} liveVersionCode={}",
v.getId(), storeType, false, polled.getOnlineVersionCode());
storeService.updateStoreReviewLive(v.getId(), storeType, true,
buildLiveReason(polled), buildExtra(polled));
} else {
// Already APPROVED (from webhook): version approved but pending distribution.
// Do NOT overwrite with nonCurrentRelease=true that would show a misleading
// "已上线(非本次发布)" label when the version is simply awaiting distribution.
log.debug("Manual refresh: {}/{} already APPROVED (webhook), store live version={} — pending distribution, no change",
v.getId(), storeType, polled.getOnlineVersionCode());
}
} else if ("MI".equals(storeType) } else if ("MI".equals(storeType)
&& polled.getReviewState() == StoreRemoteState.ReviewState.UNDER_REVIEW_XIAOMI) { && polled.getReviewState() == StoreRemoteState.ReviewState.UNDER_REVIEW_XIAOMI) {
if (!"UNDER_REVIEW".equals(existingState)) { // MI API cannot distinguish "approved, awaiting distribution" from "under review"
// when the submitted version isn't live yet. Never downgrade an APPROVED state.
if (!isApproved && !"WITHDRAWN".equals(existingState)) {
if (!isUnderReview) {
log.info("Manual refresh: {}/{} restoring Xiaomi UNDER_REVIEW from {}", v.getId(), storeType, existingState); log.info("Manual refresh: {}/{} restoring Xiaomi UNDER_REVIEW from {}", v.getId(), storeType, existingState);
} }
storeService.updateStoreReview(v.getId(), storeType, storeService.updateStoreReview(v.getId(), storeType,
AppVersionEntity.StoreReviewState.UNDER_REVIEW, AppVersionEntity.StoreReviewState.UNDER_REVIEW,
"小米应用商店当前提交版本审核中"); "小米应用商店当前提交版本审核中");
} else {
log.debug("Manual refresh: {}/{} MI UNDER_REVIEW_XIAOMI polled but existing={} — no downgrade",
v.getId(), storeType, existingState);
}
} else if (isUnderReview || isRejected) { } else if (isUnderReview || isRejected) {
if (mappedState != AppVersionEntity.StoreReviewState.UNDER_REVIEW if (mappedState != AppVersionEntity.StoreReviewState.UNDER_REVIEW
|| !"UNDER_REVIEW".equals(existingState)) { || !isUnderReview) {
log.info("Manual refresh: {}/{} writing {} from {}", v.getId(), storeType, mappedState, existingState); log.info("Manual refresh: {}/{} writing {} from {}", v.getId(), storeType, mappedState, existingState);
storeService.updateStoreReview(v.getId(), storeType, mappedState, "手动刷新厂商审核状态"); storeService.updateStoreReview(v.getId(), storeType, mappedState, "手动刷新厂商审核状态");
} }

查看文件

@ -5,9 +5,9 @@ spring:
application: application:
name: update-service name: update-service
datasource: datasource:
url: jdbc:mysql://39.107.53.187:3306/xuqm_update?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true url: ${SPRING_DATASOURCE_URL:jdbc:mysql://39.107.53.187:3306/xuqm_update?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true}
username: xuqm username: ${SPRING_DATASOURCE_USERNAME:xuqm}
password: Xuqm@2026 password: ${SPRING_DATASOURCE_PASSWORD:Xuqm@2026}
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
hikari: hikari:
minimum-idle: 5 minimum-idle: 5