提交图

163 次代码提交

作者 SHA1 备注 提交日期
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
XuqmGroup
8de0338b93 fix: withdraw previously-approved store reviews before re-submitting same version
When re-submitting a version to stores where the previous review was APPROVED:

1. markSubmitted now sets those stores to WITHDRAWN (not PENDING), preserving
   the old batchId/submittedAt for traceability. This signals to executeSubmitAsync
   that the store cancel API must be called before a new submission is attempted.

2. executeSubmitAsync detects the WITHDRAWN state and calls cancelAtStore first,
   then falls through to the normal submission path. This revokes the old approval
   on the store's side so no stale webhook or poll cycle can fire APPROVED for the
   old review after re-submission.

3. updateStoreReview now rejects APPROVED transitions from PENDING or WITHDRAWN
   states (stale webhook guard). A valid approval can only arrive after the store
   has seen the new submission (i.e. current state must be SUBMITTING or UNDER_REVIEW).
   This prevents autoPublishAfterReview from triggering before the new review cycle.

Operation log includes `approvedWithdrawn` list when any store was withdrawn on re-submit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 17:09:31 +08:00
XuqmGroup
ab7f029960 feat(update-service): add PATCH /app/{id}/changelog with audit log
Allows editors to update release notes at any time. Every change is
recorded in update_operation_log with action CHANGELOG_UPDATE and
before/after values in detailJson, satisfying the audit requirement.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 16:47:36 +08:00
XuqmGroup
1ec7f2e35d fix(file-service): stream upload to disk to fix OOM on large files
file.getBytes() loaded the entire APK into JVM heap, causing
OutOfMemoryError on files >~50MB. Now streams to a temp file while
computing SHA-256 via DigestInputStream, then atomically moves to the
final path. Zero heap cost regardless of file size.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 16:31:15 +08:00
XuqmGroup
9c51e666f8 fix(file-service): permit /error endpoint to avoid 401 on server errors
Spring Boot's /error handler was secured, causing any server-side exception
during upload/serve to redirect clients to login instead of returning an
error message. Permitting /error ensures errors are returned as proper
JSON responses rather than auth challenges.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 16:10:49 +08:00
XuqmGroup
8bc9b1ebda fix(file-service): use AntPathRequestMatcher to bypass Spring MVC matching
Spring Security 6 with MVC on classpath resolves requestMatchers(HttpMethod, String)
to MvcRequestMatcher, which fails to match the actual servlet paths for this service.
Switching to explicit AntPathRequestMatcher instances bypasses MVC introspection and
forces pure Ant pattern evaluation, fixing persistent 401 on public upload/serve endpoints.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 15:40:11 +08:00
XuqmGroup
b49b67bb1e fix(file-service): use explicit HttpMethod on all requestMatchers to force AntRequestMatcher
Spring Security 6 MvcRequestMatcher (used when no HttpMethod is specified
and Spring MVC is on the classpath) fails to match the upload endpoint,
falling through to anyRequest().authenticated() and returning 401.
Specifying HttpMethod forces AntRequestMatcher which matches reliably.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 15:11:13 +08:00
XuqmGroup
61b79465cd fix(file-service): restore public upload by explicitly allowing POST /api/file/upload
The previous commit (GET-only permitAll) inadvertently broke upload by
requiring auth. The original design intentionally allows unauthenticated
upload — explicitly permit POST /api/file/upload to make this clear.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 14:49:37 +08:00
XuqmGroup
623656648e fix(file-service): restrict file-serving permitAll to GET requests only
Upload endpoint (POST) was inadvertently matched by the method-less
requestMatchers("/api/file/*") rule. Making it GET-only makes the intent
explicit and ensures upload correctly requires a valid JWT.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 14:11:56 +08:00
XuqmGroup
4e54737e72 feat: webhook shows app name; auto-withdraw superseded approved stores
- Webhook notification body shows app display name (resolved from
  tenant-service via internal API with in-memory cache) instead of appKey
- When re-uploading a package with the same versionCode, automatically
  withdraw APPROVED store entries from the older entity before submitting
  the new entity, preventing duplicate active submissions
- tenant-service /internal/sdk/apps/{appKey}/platform-info now includes
  the app 'name' field

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 13:31:31 +08:00
XuqmGroup
3bc8a39d0f fix: return 401 (not 403) for unauthenticated requests across all services
Spring Security's default Http403ForbiddenEntryPoint was returning 403
for all auth failures. Frontend clients treat 403 as a permission error
(not an auth error), so silent loops occurred instead of proper re-login.
Adding a custom AuthenticationEntryPoint that returns 401 makes clients
handle auth failures correctly (show login page on 401).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 13:31:24 +08:00
XuqmGroup
39367a57e1 fix MI poll: don't mistake old published version as new version approved
The MI /devupload/dev/query API returns the currently-published app's status,
not the pending submission. appStatus=3 means the previous version is still
online, not that the new submission was accepted. Use updateVersion=true as
the approval signal; default updateVersion to false to avoid false positives.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 13:04:18 +08:00
XuqmGroup
81f04ee432 fix MI poll: log full response, fix synchroResult=0 mapped to REJECTED not UNDER_REVIEW
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:39:06 +08:00
XuqmGroup
f7dbce7268 fix HONOR poll endpoint and status mapping; improve all store polling reliability
- HONOR: use get-app-current-release endpoint (correct), auditResult field (0=review,1=approved,2=rejected)
- HONOR: assertHonorSuccess now accepts both "0" and "0000" success codes
- OPPO: add integer status mapping (111=approved, 444=rejected) from reference impl
- All stores: add full response body logging for diagnosing poll issues

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:15:19 +08:00
XuqmGroup
8dea96ef5e fix: skip already-reviewing stores on resubmit; clean up orphaned SUBMITTING states
- StoreSubmissionService: skip UNDER_REVIEW/APPROVED stores in preflight loop to prevent duplicate submissions
- StoreSubmissionService: post-batch sweep marks any still-SUBMITTING stores in same batch as REJECTED
- StoreSubmissionService: @EventListener(ApplicationReadyEvent) clears orphaned SUBMITTING states on startup
- AppVersionRepository: add findAllWithSubmittingStores() native query for startup sweep

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:58:27 +08:00
XuqmGroup
4136cd57b6 feat: add app transfer API, parallel store upload, DingTalk/WeCom/Feishu webhook formats
- OpsController/OpsService: POST /api/ops/apps/{appKey}/transfer to move app between tenants
- StoreSubmissionService: read parallelStoreUpload from publish config; conditional parallel vs sequential submission
- AppStoreService: support DINGTALK/WECOM/FEISHU/CUSTOM notify formats in sendWebhook()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:34:59 +08:00
XuqmGroup
57ad8f7f25 fix: app_key backfill on re-registration + notify after tx commit
- LicenseDeviceService: update app_key on re-registration if blank,
  fixing devices that registered before the app_key column was added
- FeatureServiceManager: send activation IM notification in afterCommit()
  hook so the frontend refresh sees the committed DB state

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:04:57 +08:00
XuqmGroup
8443af4818 fix: add --http1.1 to MI curl upload to prevent HTTP/2 stream error (exit 92) 2026-05-16 13:28:50 +08:00
XuqmGroup
f977934f5a feat: remove Update methods from Java SDK, keep only IM and Push 2026-05-16 12:10:07 +08:00
Dev
316ecfcd38 perf: Maven BuildKit cache mount + pom-first layering + Alpine JRE; ci: Jenkinsfile固定main分支 2026-05-16 11:33:25 +08:00
XuqmGroup
e7dbdc2ef3 fix(update): use curl for Xiaomi APK upload to bypass server-side body timeout
RestTemplate drops large multipart payloads on the MI API server; switching to
ProcessBuilder curl with Expect:100-continue headers and a 130-minute timeout resolves
upload failures for large APKs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 02:24:04 +08:00
XuqmGroup
afb57a5d5f feat: ops应用列表支持租户筛选 + 返回租户名称 + 服务按类型展示
- AppRepository: 新增 JOIN 查询,返回应用+租户名称
- OpsService: listApps 支持 tenantId 筛选,getAppDetail 按 serviceType 去重
- OpsController: listApps 新增 tenantId 可选参数

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 00:24:10 +08:00
XuqmGroup
805ef3900b fix: Jenkins checkout 使用 BRANCH 参数而非 scm 默认分支
checkout scm 忽略 BRANCH 参数,使用 Jenkins 任务配置的 SCM 分支。
改为显式 checkout 并引用 params.BRANCH,确保构建最新代码。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 23:56:34 +08:00
XuqmGroup
10f0043f15 License服务改造:平台无关、ops管理最大设备数、有效期不可变
- LICENSE审批只创建1条FeatureServiceEntity记录(不分平台)
- FeatureServiceManager扩展平台无关查询到LICENSE
- LicenseServiceClient新增getAppLicenseStatus/updateMaxDevices方法
- OpsController新增license管理接口(GET状态、PUT最大设备数)
- AppLicenseService.update中expiresAt一旦设置不可修改
- 审批流程支持传入expiresAt参数

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 22:38:46 +08:00
XuqmGroup
0ed09a8229 一大波改动 2026-05-15 22:11:03 +08:00
XuqmGroup
bc1165d22e Align license service with app model 2026-05-15 21:42:10 +08:00
XuqmGroup
4f59fead0a Store license check user info 2026-05-15 21:29:48 +08:00
XuqmGroup
d5b8f03996 Fix license service activation visibility 2026-05-15 21:25:58 +08:00
XuqmGroup
7ce4d728cc Use auth domain for license files 2026-05-15 21:09:24 +08:00
XuqmGroup
acfc2cbfbe Add license service and tenant integration 2026-05-15 21:00:24 +08:00
XuqmGroup
b24e3669cb 一大波改动 2026-05-15 16:47:22 +08:00
XuqmGroup
fb8a9d453d fix(update): 修复华为上传URL响应格式 urlInfo 单对象处理
华为实际返回格式为 urlInfo (单对象) 而非 urlList (列表),
代码需同时支持两种格式:
- urlList: 列表形式(旧版API)
- urlInfo: 单对象形式(当前API,含 url/objectId/headers/method)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 00:16:19 +08:00
XuqmGroup
2b975c990a fix(docker): 移除 BuildKit cache mount,兼容无 buildx 的标准 Docker
--mount=type=cache 语法需要 BuildKit/buildx 支持,
生产服务器无 buildx 插件导致每次构建实际使用旧缓存层。
移除该指令后可用标准 docker build 正常编译。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 00:06:36 +08:00
XuqmGroup
ac35f7e2fb fix(update): 修复华为上传URL NPE及提交批次超时限制
- submitToHuawei: urlList 字段做防御性处理,找不到时降级到 data,
  同时输出实际响应内容方便排查
- executeSubmitAsync: allOf.join() 改为 get(20, MINUTES),
  防止大文件上传卡住时批次线程永久阻塞

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 23:58:10 +08:00
XuqmGroup
1a18925034 feat: 厂商应用商店提交功能完善及push用户管理
update-service:
- 修复华为 appId 解析 NPE(支持直接从响应体顶层读取 value 字段)
- 修复 OPPO 更新描述不足5字符时自动补空格
- 修复 VIVO 签名中文字符需 URL 编码
- 修复 RestTemplate 无超时(30s连接/5min读取)
- AppVersionEntity 添加 grayCallbackUrl 字段

tenant-service:
- FeatureServiceController switch 添加 FILE 分支(修复编译错误)
- FeatureServiceManager 添加 buildFileConfig 方法
- AppController 添加应用用户列表代理端点
- AppUserClient 新增 IM/Push 用户列表客户端

push-service:
- 新增 PushUserEntity/PushUserRepository/PushAccountService
- 新增 PushAuthController(内部鉴权接口)
- PushManagementController 添加用户管理接口
- PushAppSecretClient 对接 tenant-service 鉴权

im-service:
- ImAccountRepository/ImAccountService 添加用户搜索接口
- ImAdminController 添加管理端用户列表
- InternalPresenceController 完善在线状态接口

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 23:40:35 +08:00
XuqmGroup
340a54623b fix: add --platform to docker pull and handle pull failure 2026-05-14 15:37:19 +08:00
XuqmGroup
11092165b5 fix: add --platform=linux/amd64 to Jenkinsfile for cross-platform build 2026-05-14 15:29:19 +08:00
XuqmGroup
0a245d21bf fix: add --platform=linux/amd64 to Dockerfile for cross-platform build 2026-05-14 15:22:18 +08:00
XuqmGroup
780f7310a8 fix: add im-sdk module to parent pom.xml to fix Maven build 2026-05-14 14:39:08 +08:00
XuqmGroup
71929fef67 docs(deploy): 添加完整的部署文档和配置示例
- 新增 compose.production.yaml 和 compose.production.server.yaml 部署配置
- 添加 nginx.dev.xuqinmin.com.conf 和 nginx.sentry.xuqinmin.com.conf 反向代理配置
- 创建详细的部署指南文档 deploy/README.md,涵盖架构设计和部署步骤
- 添加前端访问文档 web/README.md,包含线上地址和接口说明
- 补充平台文档总览 README.md,整合各模块文档入口
- 配置多服务容器化部署,包括 tenant-service、im-service、push-service 等
- 设置外部数据库和 Redis 连接配置,确保服务间正确通信
- 配置 WebSocket 和 API 路由转发规则,支持实时通信和版本更新服务
2026-05-09 14:53:42 +08:00
Jenkins CI
d54bfe25f1 ci(jenkins): optimize Jenkinsfile for Windows node 2026-05-08 18:47:01 +08:00
XuqmGroup
cf2013a52d feat(im): 添加平台事件通知功能支持应用审核状态实时更新
- 新增 ImPlatformEventController 提供令牌获取接口
- 新增 InternalImPlatformEventController 处理内部通知请求
- 实现 ImPlatformEventService 核心服务逻辑包括令牌签发和消息推送
- 添加 StoreReviewImNotifier 在更新服务中触发审核状态变更通知
- 在前端平台中集成实时审核状态更新功能
- 配置各项目环境版本管理文件 (.java-version, .nvmrc)
- 更新 Docker 忽略文件和 Maven 配置以优化构建流程
2026-05-08 18:32:46 +08:00
XuqmGroup
dc1ada94ea docs(deploy): 添加部署文档和安全设计规范
- 新增 XuqmGroup 部署文档,包含部署方案、架构建议和部署步骤
- 添加安全设计规范,涵盖密码安全、AppSecret验证和服务端API认证
- 补充平台REST API规范,定义Server-to-Server调用接口和错误码
- 创建Java IM服务端SDK计划文档,规划Maven包发布和接口实现
2026-05-08 18:32:00 +08:00
XuqmGroup
0385b2010a feat(update): 添加应用更新检查功能支持用户ID参数
- 在UpdateApi接口中新增可选的userId查询参数
- 新增UpdateSDK对象用于统一管理应用更新逻辑
- 实现应用版本检查、下载安装和APK文件处理功能
- 添加下载URL规范化处理逻辑
- 在Flutter SDK中新增update模块实现跨平台更新功能
- 在iOS SDK中新增UpdateSDK类提供应用更新检查接口
- 支持Android和iOS平台的应用商店跳转功能
- 添加React Native SDK的更新检查和插件注册功能
- 实现RN Bundle的检查、下载和缓存机制
2026-05-08 12:00:33 +08:00
XuqmGroup
3e55e9d9b6 fix: expose appKey on service activation requests 2026-05-08 10:22:39 +08:00
XuqmGroup
9bb9868d31 docs: align api guide with appKey identity 2026-05-08 10:18:20 +08:00
XuqmGroup
493bb73f5a feat: use appKey as app identifier in tenant service 2026-05-08 10:09:22 +08:00
XuqmGroup
77dafd76bf chore: sync local changes 2026-05-07 19:39:42 +08:00
XuqmGroup
9cb352bb99 fix(push): 修复小米推送 restricted_package_name 硬编码问题
从推送配置中读取 Android 包名,配置缺失时记录警告并跳过推送,
不再使用 com.example.app 占位值导致推送无法送达。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 08:22:57 +08:00