Commit Graph

4 Commits

Author SHA1 Message Date
hailin 3bc35bad64 feat(push): add offline push notification system (FCM + HMS + Mi + OPPO + vivo)
## Backend (notification-service)
- Add `device_push_tokens` table (migration 014) — stores per-user tokens per
  platform (FCM/HMS/MI/OPPO/VIVO) with UNIQUE constraint on (user_id, platform, device_id)
- Add `DevicePushTokenRepository` with upsert/delete/targeting queries
  (by userId, tenantId, plan, tags, segment)
- Add push provider interface with `sendBatch(tokens, message): BatchSendResult`
  returning `invalidTokens[]` for automatic DB cleanup
- Add FCM provider — OAuth2 via RS256 JWT, chunked concurrency (max 20 parallel),
  detects UNREGISTERED/404 as invalid tokens
- Add HMS provider — native batch API (1000 tokens/chunk), OAuth2 token cache
  with 5-min buffer, detects code 80100016
- Add Xiaomi provider — `/v3/message/regids` batch endpoint (1000/chunk),
  parses `bad_regids` field
- Add OPPO provider — single-send with Promise-based mutex to prevent concurrent
  auth token refresh races
- Add vivo provider — `/message/pushToList` batch endpoint, mutex same as OPPO,
  parses `invalidMap`
- Add `OfflinePushService` — groups tokens by platform, sends concurrently,
  auto-deletes invalid tokens; fire-and-forget trigger after notification creation
- Add `DevicePushTokenController` — POST/DELETE `/api/v1/notifications/device-token`
- Wire offline push into `NotificationAdminController` and `EventTriggerService`
- Add Kong route for device-token endpoint (JWT required)
- Add all push provider env vars to docker-compose notification-service

## Flutter (it0_app)
- Add `PushService` singleton — detects OEM (Huawei/Xiaomi/OPPO/vivo/FCM),
  initialises correct push SDK, registers token with backend
  - FCM: full init with background handler, foreground local notifications,
    tap stream, iOS APNs support
  - HMS: `HuaweiPush` async token via `onTokenEvent`, no FCM fallback on failure
    (Huawei without GMS cannot use FCM)
  - Mi/OPPO/vivo: MethodChannel bridge to Kotlin receivers; handler set before
    `getToken()` call to avoid race
  - `_initialized` guard prevents double-init on hot-restart
  - `static Stream<void> onNotificationTap` for router navigation
- Add Kotlin OEM bridge classes: `MiPushReceiver`, `OppoPushService`,
  `VivoPushReceiver` — forward token/message/tap events to Flutter via MethodChannel
- Update `MainActivity` — register all three OEM MethodChannels; OEM credentials
  injected from `BuildConfig` (read from `local.properties` at build time)
- Update `build.gradle.kts` — add Google Services + HMS AgConnect plugins,
  BuildConfig fields for OEM credentials, `fileTree("libs")` for OEM AARs
- Update `android/build.gradle.kts` — add buildscript classpath for GMS + HMS,
  Huawei Maven repo
- Update `AndroidManifest.xml` — HMS service, Xiaomi receiver + services,
  vivo receiver; OPPO handled via AAR manifest merge
- Add OEM SDK AARs to `android/app/libs/`:
  MiPush 7.9.2, HeytapPush 3.7.1, vivo Push 4.1.3
- Add `google-services.json` (Firebase project: it0-iagent, package: com.iagent.it0_app)
- Add `firebase_core ^3.6.0`, `firebase_messaging ^15.1.3`, `huawei_push ^6.11.0+300`
  to pubspec.yaml
- Add `ApiEndpoints.notificationDeviceToken` endpoint constant

## Ops
- Add FCM_PROJECT_ID, FCM_CLIENT_EMAIL, FCM_PRIVATE_KEY (+ HMS/Mi/OPPO/vivo placeholders)
  to `.env.example` with comments pointing to each OEM's developer portal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 02:42:34 -07:00
hailin 54e3d442ed feat(it0_app): add auto-increment versionCode on each build
参照 rwadurian mobile-app 的版本自增机制,为 IT0 App 添加相同的逻辑:

- 使用 version.properties 文件持久化存储 VERSION_CODE 计数器
- 每次 gradle build 自动读取当前值 +1 并写回文件
- versionCode 使用自增数字(跨日期持续递增,确保每次构建唯一)
- versionName 格式: ${pubspec版本}.${自增号}(如 1.0.0.42)
- version.properties 已加入 .gitignore,每个构建环境独立维护计数器

这样每次编译 APK 都会自动获得一个比上次更高的版本号,
无需手动修改 pubspec.yaml 中的 version 字段。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 08:52:04 -08:00
hailin 3d9b25391e fix: enable core library desugaring for flutter_local_notifications
flutter_local_notifications 插件依赖 java.time API,需要启用 Android core
library desugaring 才能在低版本设备上运行。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 01:24:38 -08:00
hailin 913267fb9d fix: 提交完整的Android项目配置文件,修复跨机器构建失败
问题描述:
  在其他机器 (C:\Users\ph) 上执行 flutter build apk 时报错:
  "Build failed due to use of deleted Android v1 embedding."
  原因是 Android 项目配置文件未被提交到 Git 仓库。

根本原因:
  之前重新生成 Android 项目(从 speech_to_text 迁移到 record 包)时,
  新生成的 Android 构建文件只在本地存在,未提交到远程仓库。
  其他机器 clone/pull 后缺少这些文件,导致构建失败。

本次提交包含的文件:
  Android 构建配置:
  - android/settings.gradle.kts — Gradle 插件配置 (AGP 8.11.1, Kotlin 2.2.20)
  - android/build.gradle.kts — 根项目 Gradle 配置
  - android/app/build.gradle.kts — 应用模块配置 (namespace: com.iagent.it0_app, Java 17)
  - android/gradle.properties — JVM 参数 (8G heap), AndroidX 启用
  - android/gradle/wrapper/gradle-wrapper.properties — Gradle 8.14

  Android 清单与入口:
  - android/app/src/main/AndroidManifest.xml — 主清单 (v2 embedding, INTERNET+RECORD_AUDIO权限, cleartext允许)
  - android/app/src/debug/AndroidManifest.xml — Debug 清单
  - android/app/src/profile/AndroidManifest.xml — Profile 清单
  - android/app/src/main/kotlin/.../MainActivity.kt — FlutterActivity (v2 embedding)

  Android 资源:
  - res/drawable/ — 启动画面背景
  - res/mipmap-*/ — 应用图标 (hdpi~xxxhdpi)
  - res/values/ — 主题样式 (LaunchTheme + NormalTheme, 含夜间模式)

  Flutter 项目元数据:
  - .gitignore — Flutter 项目忽略规则
  - .metadata — Flutter SDK 版本追踪
  - android/.gitignore — Android 构建产物忽略规则

构建要求:
  - Flutter SDK >= 3.38.0 (pubspec.lock 约束)
  - 其他机器需执行: flutter clean && flutter pub get 后重新构建

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:17:18 -08:00