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
5ff8bda99e
feat(notification): 完整站内消息推送体系 (Phase 1-4)
...
## Phase 1 — 精准推送基础
- 新增 notification-service 微服务 (port 3013)
- DB迁移 007: notifications, notification_reads, notification_tenant_targets 表
- DB迁移 008: tenant_tags, tenant_tag_assignments, notification_user_targets 表
+ notifications 表新增 target_tag_ids/target_tag_logic/target_plans/target_statuses/channel_key 字段
- auth-service: TenantTagController — 租户标签 CRUD + 批量分配 (9个接口)
- notification-service 支持 7 种推送目标类型:
ALL / SPECIFIC_TENANTS / SPECIFIC_USERS / BY_TENANT_TAG(ANY|ALL) / BY_PLAN / BY_TENANT_STATUS / BY_SEGMENT
- Web Admin: /tenant-tags 标签管理页 + 通知表单全面扩展
## Phase 2 — 通知频道与用户偏好
- DB迁移 009: notification_channels (6个预置频道) + user_notification_preferences
+ notification_segment_members 表 (Phase 4 人群包)
- notification-service: ChannelRepository + NotificationChannelController
(频道 CRUD + 用户偏好 API,强制频道不可关闭)
- Web Admin: /notification-channels 频道管理页
- Flutter: NotificationPreferencesPage — 用户按频道 toggle 订阅,profile页新增入口
## Phase 3 — Campaign 活动与数据分析
- DB迁移 010: notification_campaigns, campaign_execution_log, notification_event_log 表
- notification-service: CampaignRepository + CampaignAdminController
(ONCE/RECURRING调度, 排期/取消/删除, 发送量/阅读率统计)
- Web Admin: /campaigns 推送活动管理页 (状态机 + 数据统计弹窗)
## Phase 4 — 事件触发与人群包
- EventTriggerService: Redis Stream 消费者,监听并自动创建通知:
billing.payment_failed / billing.quota_warning / tenant.registered / alert.fired
- SegmentRepository + SegmentAdminController (全量同步/增量添加/删除)
- Web Admin: /segments 人群包管理页 (成员管理 + ETL全量替换)
## 基础设施
- Kong: 新增 notification-service 服务 + 6条路由 + JWT插件
- Docker Compose: 新增 notification-service 容器 (13013:3013)
- notification-service 新增 ioredis 依赖 (Redis Stream 消费)
## Flutter (APK需手动编译)
- 新增路由: /notifications/inbox, /notifications/preferences
- 新增: NotificationInboxPage, NotificationPreferencesPage
- 新增: ForceReadNotificationDialog (强制阅读拦截弹窗)
- profile页: 站内消息行(未读角标) + 通知偏好设置入口
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 22:33:40 -08:00