Package name matching is now entirely the SDK's responsibility.
- DeviceService: drop packageName param from register/verify, delete validatePackageName()
- LicensePublicController: remove matchesPackageName check in resolveAppKey(),
remove packageName from service calls, add GET /api/license/app-info for
SDK appKey-only flow to fetch configured package names for local comparison
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add composite unique constraint (app_key, device_id) on DeviceEntity
- Remove global unique constraint from device_id column
- Update DeviceRepository: findByAppKeyAndDeviceId returns Optional,
findByDeviceId returns List for multi-app lookups
- Update DeviceService.register/verify to scope lookups by appKey
so same physical device can register independently for each app
- Update LicenseInternalController.getDevice to return list
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- DeviceService.register(): update appKey when device switches to a different app
and adjust registered device counters for old/new appKey
- LicenseAdminController: fix updateAppLicense parameter count mismatch
- AppController: add POST /api/apps/license/parse endpoint for license file decryption
- SecurityCenterView: add License file parser UI with upload and paste support
- appApi: add parseLicenseFile() method
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
SdkConfigController: require packageName param; reject with 403 if it doesn't
match the platform-specific name registered for the app (skipped when app has
no name configured yet).
LicensePublicController: add required packageName to register/verify requests.
DeviceService: validatePackageName() checks against android/ios/harmony names
stored on AppLicenseEntity; rejects if any are configured and none match.
AppLicenseEntity: add android_package_name, ios_bundle_id, harmony_bundle_name
columns (auto-migrated via ddl-auto=update).
LicenseInternalController/AppLicenseService: accept and persist package names
via upsert endpoint.
LicenseServiceClient/FeatureServiceManager: pass app package names when syncing
license records to license-service.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
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>
- 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>