Commit Graph

25 Commits

Author SHA1 Message Date
hailin 9519e29b8f feat(mobile/telemetry): collect real network type via connectivity_plus
- Add connectivity_plus: ^6.0.3 to pubspec.yaml
- DeviceInfoCollector._getNetworkType() calls Connectivity().checkConnectivity()
  and maps ConnectivityResult → wifi / mobile / ethernet / vpn / bluetooth / none / unknown
- networkType field in DeviceContext is now populated on every cold start
- All page_view and session events carry the accurate network type in device props

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 09:43:04 -08:00
hailin 9b760c56ee feat(mobile/telemetry): add comprehensive event tracking for DAU, real-time presence & funnels
## 架构设计(亿级用户规模)
- 客户端:本地队列(500条) + 批量上传(20条/30s) + 10% 采样率
- 心跳:前台每60s发送,后端3分钟滑动窗口 → 实时在线率
- DAU:app_session_start 事件 + installId 去重
- 后端接入:Kafka → ClickHouse 消费落盘

## 新增 TelemetryRouteObserver (NEW FILE)
- 继承 RouteObserver<PageRoute>,注册到 MaterialApp.navigatorObservers
- 自动记录所有页面 page_view(push/pop/replace),零侵入业务页面
- 属性:page_name, previous_page, nav_action
- 覆盖全部 37 个已注册路由,无需逐页埋点

## main.dart
- 接入 TelemetryRouteObserver.instance
- 新增 FlutterError.onError 全局钩子 → logError 上报 Widget build 异常

## auth_service.dart — 认证漏斗
| 事件 | 触发时机 | method 属性 |
|------|---------|------------|
| register_success | 注册成功 | phone_sms / email_code |
| login_success    | 登录成功 | password / phone_sms / email_code / wechat / alipay / google / apple |
| user_logout      | 主动登出 | — |

## self_hosted_updater.dart — 升级漏斗
update_prompted → update_accepted / update_dismissed
→ update_download_started → update_download_completed / update_download_failed / update_download_cancelled
→ update_install_triggered / update_install_failed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 09:39:48 -08:00
hailin d174b74764 debug(mobile): 下载失败诊断日志
添加详细 debugPrint,覆盖:
- URL 检查失败原因
- 实际下载 URL 和保存路径
- HTTP 响应状态码和 content-length/content-range
- DioException 类型、消息、HTTP 状态码
- SHA-256 校验结果(预期值 vs 实际值)
- 文件大小

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 08:53:05 -08:00
hailin 0c3ef3b598 fix(mobile): fix version check API and platform detection in both apps
genex-mobile/lib/core/updater/version_checker.dart
- platform 从写死 'android' 改为运行时检测 Platform.isIOS ? 'IOS' : 'ANDROID'

admin-app/lib/core/updater/version_checker.dart
- API 路径修正: /api/app/version/check → /api/v1/app/version/check
- 新增 app_type: 'ADMIN_APP'(原缺失,后端默认返回 GENEX_MOBILE 版本)
- platform 从写死 'android' 改为运行时检测
- 响应解析修正: 原逻辑把外层 {code,data} 当版本数据用,
  改为正确取 response.data['data'] 内层对象
- 新增 downloadUrl 相对路径修复(向下兼容旧记录)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 00:50:42 -08:00
hailin 4369aecf60 fix: 修复上传版本500错误 + 优化App冷启动通知请求
- fix(admin-service): versionCode 兜底从 Date.now() 改为 1,避免超出 PostgreSQL integer 范围
- fix(genex-mobile): NotificationBadgeManager 加登录检查,未登录跳过API请求
- fix(genex-mobile): 将通知徽章初始化移至首帧后执行,消除冷启动DNS竞争

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 08:48:09 -08:00
hailin ce9cc5b72e feat(telemetry): 完整实现 presence-service 迁移 + Flutter 遥测接入
## 后端 (backend/services/telemetry-service)

### 修复骨架中的关键缺陷
- 创建本地 JwtAuthGuard / AdminGuard,替换不存在的 @genex/common 包
- 修复 req.user.sub → req.user.id(与 JwtStrategy.validate() 返回值对齐)
- 重写 Dockerfile,移除对不存在的 packages/common 目录的引用
- 更新 telemetry.module.ts,将 JwtAuthGuard / AdminGuard 注册为 providers
- admin-telemetry.controller.ts 改用本地 AdminGuard(检查 role === 'admin')

### 新增功能
- GET /api/v1/telemetry/config:公开配置下发接口
  Flutter TelemetryConfig.syncFromRemote() 每小时拉取,返回全局开关、采样率、
  心跳间隔等配置,所有字段支持环境变量覆盖(TELEMETRY_GLOBAL_ENABLED 等)
- 设备字段(deviceBrand/deviceModel/deviceOs/appVersion/locale)提升为顶层列
  BatchEventsDto / TelemetryEvent 实体 / recordEvents() 全链路补齐
  原因:JSONB 内字段无法走 B-tree 索引,千万级数据分组查询需独立列

### DB 迁移
- 050_add_device_fields_to_telemetry_events.sql:为已有 telemetry_events 表
  新增 5 个设备字段列和 device_brand / app_version 索引

### docker-compose 环境变量
- telemetry-service 新增 TELEMETRY_GLOBAL_ENABLED / SAMPLING_RATE /
  HEARTBEAT_INTERVAL / CONFIG_VERSION 环境变量,支持生产环境热调整

## 前端

### genex-mobile (Flutter 消费者端)
- 复制 lib/core/telemetry/ 模块(11个文件):TelemetryService、
  HeartbeatService、SessionManager、TelemetryUploader、TelemetryStorage 等
- 修正 API 路径:presence/heartbeat → telemetry/heartbeat,
  analytics/events → telemetry/events
- pubspec.yaml 新增依赖:uuid ^4.3.3、equatable ^2.0.5、device_info_plus ^10.1.0
- main.dart:initState 首帧回调初始化 TelemetryService(需 BuildContext 采集设备信息)
  已登录时自动注入 accessToken
- auth_service.dart:_setAuth() 登录成功后注入 userId + accessToken;
  _clearAuth() 退出时清除(同时覆盖 Token 过期自动清除场景)

### admin-app (Flutter 发行方控制台)
- 复制 lib/core/telemetry/ 模块(同上)
- pubspec.yaml 新增依赖:uuid、equatable、device_info_plus、shared_preferences
- IssuerLoginPage:initState 首帧初始化 + 登录成功后注入 userId/token
  使用 api.gogenex.cn(与 UpdateService 域名一致)
- settings_page.dart:退出登录时调用 clearUserId() + clearAccessToken()

## 架构说明
- 在线人数:Redis Sorted Set (genex:presence:online),心跳 60s/次,180s 窗口判定在线
- DAU:app_session_start 事件写入 telemetry_events,每天凌晨 1 点聚合到
  daily_active_stats 表,同时每小时滚动更新当日 DAU
- 设备字段采用 Amplitude 风格:前端本地队列存 properties 内,
  toServerJson() 上传时自动提升为顶层字段,后端写入独立索引列
- 心跳需要 JWT 认证(未登录用户自动跳过,不报错)
- 遥测完全异步,任何失败只打 debug 日志,不影响主流程

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 23:33:13 -08:00
hailin 8f3d0f5d17 fix: comprehensive API compatibility fixes across issuer/user/ai services and Flutter
Backend:
- issuer-service: fix credit-metric entity column names to match DB schema
  (breakage_ratio, market_tenure_months, user_satisfaction, computed_score, etc.)
- issuer-service: add page/limit to ListStoresQueryDto and ListEmployeesQueryDto
- issuer-service: add period field to ReconciliationQueryDto
- issuer-service: fix IssuerStatsController to use req.user.id→issuerId lookup
- issuer-service: add analytics stubs (users/demographics/repurchase/ai-insights)
- issuer-service: add issuers/me/coupons endpoint
- user-service: add GET /users/payment-methods stub before /:id route
- ai-service: add GET /ai/sessions/current/messages stub endpoint

Flutter:
- genex-mobile: fix /users/kyc/status → /users/kyc
- genex-mobile: fix announcements offset→page param
- genex-mobile: fix trading paths (/trading/* → /trades/*)
- admin-app: fix announcements offset→page param

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 09:29:44 -08:00
hailin 4957b2ef85 feat(genex-mobile): 重构为 Clean Architecture + Riverpod
- 添加 flutter_riverpod ^2.5.1 依赖
- 搭建 core/error/failures.dart 和 core/usecases/usecase.dart 基础骨架
- auth feature 完整 3 层重构:
  - domain: AuthUser + AuthSession 实体, IAuthRepository 接口, 全套 UseCases
  - data: AuthRepositoryImpl(Strangler Fig,委托给 AuthService 保留 token 刷新逻辑)
  - presentation: AuthNotifier + authProvider + currentUserProvider + isAuthenticatedProvider
- 4 个 auth 页面升级为 ConsumerStatefulWidget,使用 ref.read(authProvider.notifier)
- main.dart: ProviderScope 包裹 GenexConsumerApp,改为 ConsumerStatefulWidget
  - 桥接 AuthService ValueNotifier → Riverpod authProvider(会话过期自动导航)
- 12 个 feature 全部创建 Riverpod providers(FutureProvider/NotifierProvider)
- 修复 my_coupons_page.dart 中 EmptyState/StatusTags 缺少 BuildContext 的预存在错误

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 20:12:50 -08:00
hailin 828770add8 fix(alipay): 适配 tobias 5.x 新 auth API,后端生成签名 authString
tobias 3.x+ 移除了顶层函数 aliPayAuth(appId, scope),
改为需要后端预签名的 Tobias().auth(authString)。

变更:
- alipay.provider.ts: 新增 generateMobileAuthString(scope) 方法,
  用 RSA2 私钥生成符合 Alipay SDK 格式的签名授权字符串
- auth.controller.ts: 新增 GET /auth/alipay/auth-string 接口
- pubspec.yaml: tobias ^3.0.0 → ^5.0.0
- auth_service.dart: 新增 getAlipayAuthString() 方法
- welcome_page.dart: 更新支付宝登录流程,先获取 authString 再调用 tobias

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 09:26:30 -08:00
hailin 1fc0fcb95e feat(auth): 支付宝 + Google + Apple 三方登录
后端 (auth-service):
- 新增 AlipayProvider (RSA2签名) + AlipayService + POST /auth/alipay
- 新增 GoogleProvider (tokeninfo验证) + GoogleService + POST /auth/google
- 新增 AppleProvider (JWKS验证ES256 JWT) + AppleService + POST /auth/apple
- SocialProvider 枚举新增 ALIPAY
- .env.example 补充三方登录申请步骤文档

Flutter (genex-mobile):
- pubspec.yaml: 新增 tobias / google_sign_in / sign_in_with_apple
- auth_service.dart: loginByAlipay / loginByGoogle / loginByApple
- welcome_page.dart: Android=微信+支付宝+Google, iOS=+Apple
- AndroidManifest: 添加支付宝包名查询
- Info.plist: 支付宝 URL Scheme + alipay/alipays queries
- i18n: 4 语言补充失败提示文案

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 04:40:31 -08:00
hailin d68d48cb95 feat(auth): 微信登录 / 注册完整实现 — social_accounts + fluwx 全链路
后端:
- 新增 social_accounts 表 Entity/Repository/Migration (049)
- WechatProvider: code ↔ access_token / 获取用户信息 (native https)
- WechatService: unionid 优先查找 → 自动登录/注册 → 发布事件
- POST /auth/wechat 端点 (WechatLoginDto, referralCode 支持)
- auth.module.ts 注册 SocialAccount、WechatProvider、WechatService

Flutter (genex-mobile):
- pubspec.yaml: 添加 fluwx ^3.10.0
- main.dart: registerWxApi 初始化 (WECHAT_APP_ID via --dart-define)
- AuthService: loginByWechat(code, referralCode?, deviceInfo?)
- WelcomePage: 改为 StatefulWidget,监听 weChatResponseEventHandler
  微信按钮触发 sendWeChatAuth,授权成功后自动登录 → /main
  未安装微信 / 登录失败均有 SnackBar 提示
- 4语言 i18n: wechatNotInstalled / wechatLoginFailed

Android:
- AndroidManifest: WXEntryActivity + queries(com.tencent.mm)
- WXEntryActivity.kt: 继承 fluwx 提供的基类,无额外代码
- proguard-rules.pro: keep WeChat SDK 类

iOS:
- Info.plist: CFBundleURLTypes (wx${WECHAT_APP_ID}) + LSApplicationQueriesSchemes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 03:37:51 -08:00
hailin 9473512530 feat(auth): 邮箱注册完整实现 — Gmail SMTP + 邮件验证码全链路
后端 (auth-service):
- 新增 EmailVerification / EmailLog 实体 + TypeORM 映射
- Email 值对象:格式校验、小写归一化、脱敏展示
- Gmail SMTP Provider (nodemailer) + ConsoleEmailProvider (dev)
- EmailCodeService:Redis 缓存快速路径,与 SmsCodeService 对称
- EmailService:sendCode/verifyCode + 日限额 + 业务规则校验
- 新增端点:POST /auth/email/send / register-email / login-email / reset-password-email
- EMAIL_ENABLED 环境变量切换真实/控制台发送
- 数据库迁移:048_create_email_verifications.sql

前端 (genex-mobile):
- AuthService 新增 sendEmailCode / registerByEmail / loginByEmail / resetPasswordByEmail
- RegisterPage 根据 isEmail 参数自动切换 SMS/Email API 调用
- WelcomePage 邮箱注册按钮传递 isEmail:true 参数
- i18n 新增 register.errorEmailRequired(4语种)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 02:27:43 -08:00
hailin a893dbdb1b feat(genex-mobile): Token 持久化 — 登录状态跨重启保持
## 核心变更

### 新增 SessionStorage (lib/core/storage/session_storage.dart)
- flutter_secure_storage 封装层
- Android: EncryptedSharedPreferences(AES-256,Android Keystore 托管密钥)
- iOS: Keychain(AccessibilityFirstUnlock)
- 存储键: genex_access_token / genex_refresh_token / genex_user_json
- API: save() / load() / updateTokens() / getRefreshToken() / clear()

### 升级 ApiClient (lib/core/network/api_client.dart)
- 新增 Dio 错误拦截器(_buildAuthInterceptor)
- 401 自动触发 Token 静默刷新,成功后无感重试原始请求
- Completer 并发锁:多个 401 同时发生只执行一次刷新,其余等待结果
- 跳过重试的端点:/auth/refresh、/auth/login、/auth/register 等
- configureAuthCallbacks():注册 onTokenRefreshed / onSessionExpired 反向回调

### 升级 AuthService (lib/core/services/auth_service.dart)
- _setAuth():登录/注册后 await 写入 SecureStorage
- _clearAuth():登出/Token 过期后 await 清除 SecureStorage
- restoreSession():App 冷启动时从 SecureStorage 恢复 Token + 注册 ApiClient 回调
- refreshToken():主动刷新(正常由拦截器自动触发,无需手动调用)

### 升级 main.dart
- await AuthService.instance.restoreSession() 在 runApp 前执行
- initialRoute 动态判断:isLoggedIn → '/main',否则 '/'
- 全局 NavigatorKey(_navigatorKey)挂载到 MaterialApp
- 监听 authState ValueNotifier:Token 过期后自动导航回 '/'(pushNamedAndRemoveUntil)

## 用户体验
- 登录后关闭 App 再打开:直接进主界面,无需重新登录
- Access Token 过期:ApiClient 自动静默刷新,用户无感知
- Refresh Token 过期:清除本地会话,跳回欢迎页,提示重新登录
- 主动登出:清除 SecureStorage,跳回欢迎页

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 02:01:27 -08:00
hailin 1c36c849e2 docs(genex-mobile): 完善邀请分享模块注释与说明
SharePage:
  - 文件头注释:完整功能概述、支持的分享场景、数据来源、URL格式、依赖包说明
  - 类注释:生命周期描述、Widget 树结构图(ASCII)
  - 状态变量:详细说明 _info/_loading/_error/_baseInviteUrl
  - _inviteLink:注释已加载/未加载两种输出示例
  - _loadInfo:成功/失败两条路径说明
  - _showCopied:SnackBar 样式描述
  - _copyCode/_copyLink:示例复制内容
  - _shareNative:iOS/Android 行为说明 + 文案模板示例
  - _buildHeroCard:视觉层次注释 + QR 参数说明
  - _buildStatsCard:布局描述 + 数据来源注释
  - _buildShareActions:三项操作的点击行为说明

ReferralService:
  - 文件头:完整端点一览、推荐码格式、推荐链规则
  - ReferralInfo:字段含义 + 后端响应 JSON 示例
  - getMyInfo:登录要求说明
  - validateCode:用途说明 + 返回值降级策略
  - getDirectReferrals:分页参数范围 + 响应 JSON 示例

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 01:42:47 -08:00
hailin 46d2404d19 feat(genex-mobile): 邀请好友 — 分享二维码页面全链路实现
- 新增 SharePage:推荐码 QR 码 + 邀请进度 + 一键复制/原生分享
- ProfilePage 添加「邀请好友」渐变横幅入口
- 新增 ReferralService(getMyInfo / getDirectReferrals)
- pubspec.yaml 引入 qr_flutter ^4.1.0、share_plus ^10.0.2
- 路由 /share 注册
- i18n:4 语言新增 share.* 共 20 个翻译键(zh-CN / zh-TW / en / ja)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 01:28:22 -08:00
hailin 0ecf295c35 feat(referral): 推荐服务全链路实现
Backend:
- referral-service: 全新微服务 (NestJS + DDD + Clean Architecture)
  - ReferralProfile 聚合根 (TypeORM entity)
  - ReferralCode / ReferralChain 值对象
  - 仓储接口 + 实现
  - ReferralService 应用服务: 创建档案/验证码/查询直推
  - UserRegisteredHandler: 订阅 genex.user.registered Kafka 事件
  - REST: GET /referral/my, GET /referral/validate, GET /referral/direct
  - 内网: POST /internal/referral/profiles
  - 端口 3013 (外部 4013)
- auth-service: RegisterDto 增加 referralCode 字段
- auth-service: UserRegisteredEvent 携带 referralCode
- auth-service: EventPublisherService 实际接入 Kafka (之前是 stub)
- migrations: 047_create_referral_profiles.sql
- docker-compose: 新增 referral-service 服务块

Frontend (genex-mobile):
- 注册页添加推荐码输入框 (可选),输入时实时验证推荐码有效性
- AuthService.register() 增加 referralCode 参数
- AuthService.validateReferralCode() 新增方法
- i18n: zh_CN/zh_TW/en/ja 各新增 4 个推荐码相关 key

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 00:58:28 -08:00
hailin abb358100d fix(genex-mobile): 还原 api.gogenex.com + 增加更新检测日志
.cn 域名因未 ICP 备案被 ISP 拦截,继续使用 api.gogenex.com (HK IP)。
增加 [UpdateService] 和 [VersionChecker] 详细日志便于调试。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 23:17:12 -08:00
hailin 286e4d8886 fix(admin-service+mobile): 修复 OTA 下载三处 Bug
1. MinIO 内网 hostname 导致 redirect 失效
   → 改为 admin-service 直接流式代理传输文件(streamFile)
   → MinIO 仅绑 127.0.0.1:49000,不对外暴露

2. version_checker.dart 响应解析错误
   → API 返回 {"code":0,"data":{...}} 但代码误把外层 Map 当 VersionInfo
   → 现在正确提取 responseMap["data"] 内层对象

3. VersionInfo.fromJson 在 releaseDate=null 时崩溃
   → releaseDate 改为 nullable (DateTime?),null-safe 解析
   → 同步修复 version_checker.dart 拼接绝对 downloadUrl

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 22:19:10 -08:00
hailin c6c434a07a fix(update): 修复 app 版本更新检查路径 + 解决 MinIO presigned URL 24h 过期
Mobile 端:
- version_checker.dart: /api/app/... → /api/v1/app/... (与 Kong 路由匹配)

Backend (admin-service):
- AppVersion 实体新增 storage_key 字段(已执行 ALTER TABLE)
- FileStorageService: uploadFile 不再返回 presigned URL,只返回 objectName
- AdminVersionController: upload 后保存 storageKey,downloadUrl 设为
  /api/v1/app/version/download/{id}(稳定 API 地址,不过期)
- AppVersionController.downloadVersion: storageKey 存在时每次请求动态
  生成 presigned URL(1小时有效,只需够下载完成即可)
- AppVersionService.checkUpdate: 有 storageKey 的版本统一返回 API 下载地址

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 21:13:13 -08:00
hailin 535f53041f feat(deploy): Nginx反向代理 + SSL + 前端切换域名
部署架构:
- Nginx (跳板机 14.215.128.96) → Kong (192.168.1.222:48080)
- SSL: Let's Encrypt 证书已为 api.gogenex.com 签发
- HTTP 自动 301 → HTTPS

前端 API 地址:
- genex-mobile: https://api.gogenex.com (ApiClient + UpdateService)
- miniapp: https://api.gogenex.com (development config)
- 备案完成后切回 https://api.gogenex.cn

Namecheap DNS 新增:
- admin.gogenex.com → 154.84.135.121
- ws.gogenex.com → 154.84.135.121

备注:
- gogenex.cn 的 80/443 端口被世纪互联 ISP 拦截,需完成 ICP 备案
- admin/ws 子域名的 SSL 证书待 DNS 传播后申请

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 00:00:58 -08:00
hailin 8ed667bcf4 feat(联调): 前端指向远程API + 启用阿里云SMS
- genex-mobile ApiClient/UpdateService 指向 154.84.135.121:48080
- miniapp dev 环境指向 154.84.135.121:48080
- docker-compose 添加 ALIYUN SMS 环境变量透传
- auth-service 添加 @alicloud/dysmsapi20170525 等 SDK 依赖

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 00:18:05 -08:00
hailin 4b1cdf9fb3 feat(genex-mobile): Flutter 前端对接 SMS 认证 API
Phase 6 — Flutter 前端完整对接后端 SMS 认证系统:

新增组件:
- OtpInput: 6位验证码输入框,支持自动跳转、粘贴、错误状态
- CountdownButton: 短信验证码倒计时按钮(60s),发送失败不启动倒计时

新增服务:
- AuthService: 单例认证服务,封装全部 auth API
  · sendSmsCode (REGISTER/LOGIN/RESET_PASSWORD/CHANGE_PHONE)
  · register / loginByPassword / loginByPhone
  · resetPassword / changePassword / changePhone
  · refreshToken / logout
  · ValueNotifier<AuthResult?> 状态管理

页面重写 (对接真实 API):
- LoginPage: 双 Tab (密码/验证码登录),错误提示 Banner,账户锁定展示
- RegisterPage: 三步注册流程,CountdownButton 集成,密码强度检查
- ForgotPasswordPage: 四步找回密码,验证码重发,密码一致性校验

i18n 补充 (4语言 × 13 新 key):
- login: noAccount, registerNow, networkError, errorPhoneRequired,
         errorPasswordMin, errorCodeInvalid
- register: hasAccount, loginNow, errorPhoneRequired, errorCodeInvalid,
            errorPasswordWeak, errorTermsRequired
- forgot: errorPasswordMismatch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 19:23:25 -08:00
hailin a92f00af25 feat(branding+fix): 中文品牌名、miniapp logo资源、编译错误修复
## 中文品牌名更新
- admin-app: 中文环境下 app_name → "企业券信",login_title/ai_welcome/settings_about 同步更新
- miniapp: 中文环境下 app_name → "券信",6处内联文本(share/activity/register/ai_chat等)同步更新
- genex-mobile: zh_cn + zh_tw 共12处 "Genex" → "券信"(login/register/aiChat/profile/aiFab)
- 英文/日文环境保持 "Genex" 不变

## miniapp logo 资源集成
- 新增 src/assets/images/ 目录:logo.png, logo_icon.png, logo_icon.svg, logo_full.svg
- login 页:CSS模拟logo(.logo-left/.logo-right) → <image src={logoIcon}>
- h5-share 页:💎 emoji → <img src={logoIcon}> (header + RegisterGuidePage)
- h5-activity 页:"G" 文字方块 → <image src={logoIcon}> (footer)
- h5-register 页:"G" 文字方块 → <image src={logoIcon}> (branding section)

## genex-mobile 编译错误修复
- wallet_coupons_page: EmptyState.noCoupons() + StatusTags.active/pending/expired/used() 添加 context 参数
- trading_page: StatusTags.onSale/completed/cancelled() 添加 context 参数
- message_page: EmptyState.noMessages() 添加 context 参数
- coupon_service: inner['total'] 添加 `as int?` 显式类型转换

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 16:57:30 -08:00
hailin 3a57b0fd4d feat: 全平台API对齐 — 4个前端应用55+页面接入真实后端API
跨越 genex-mobile、admin-app、admin-web、miniapp 四个前端应用,
将所有页面从 mock 硬编码数据替换为真实后端 API 调用,
同时补建后端缺失的 27+ 个端点,实现前后端完整联通。

## 后端新增 (4个微服务, 27+端点)

### issuer-service — 5个新Controller, 19个新文件
- IssuerStatsController: GET /issuers/me/stats, /credit (发行商仪表盘统计+信用)
- IssuerFinanceController: GET/POST balance/stats/transactions/withdraw/reconciliation
- IssuerStoreController: CRUD /issuers/me/stores + /employees (门店+员工管理)
- RedemptionController: POST scan/manual/batch, GET history/today-stats (核销)
- CouponBatchController: POST issue/recall/price-adjust, GET operations (批量操作)
- CouponController扩展: GET /search, /:id/nearby-stores, /:id/similar
- 新实体: Employee, Redemption; Store 增加 level/parentId
- 新迁移: 032_create_stores_employees_redemptions.sql

### trading-service (Go)
- GET /api/v1/trades/my/orders — 用户订单列表(分页+状态筛选)
- POST /api/v1/trades/coupons/:id/transfer — 券转赠

### user-service
- GET/PUT /api/v1/users/me/settings — 用户偏好设置(语言/货币/通知)

### auth-service
- POST /api/v1/auth/send-sms-code — 发送短信验证码(Redis存储, 5分钟TTL)
- POST /api/v1/auth/login-phone — 手机号+验证码登录(自动注册)

### Kong 路由
- 新增5条路由: issuers/me, redemptions, coupons/batch, trades/my, trades/coupons

## genex-mobile (Flutter, 2页)
- HomePage: 接入 CouponApiService.getFeaturedCoupons() + getHoldingsSummary()
- WalletCouponsPage: 接入持仓列表API, 支持Tab状态筛选
- 修复 NotificationService/PushService 7+2个路径缺少 /api/v1/ 前缀
- 新增 CouponApiService, CouponModel, HoldingsSummaryModel

## admin-app (Flutter发行商控制台, 11页 + router + i18n)
- 修复 NotificationService 7个路径 + PushService 2个路径前缀
- 新增9个Service: auth, issuer, coupon, finance, credit, store, redemption, analytics, ai_chat
- 11页全部从 StatelessWidget→StatefulWidget, mock→API:
  IssuerLoginPage(SMS登录), Dashboard(统计), CouponList(分页+筛选),
  CreateCoupon(提交审核), CouponDetail(详情), Redemption(扫码/手动/批量核销),
  Finance(余额/流水/对账), Credit(评分), StoreManagement(门店+员工),
  AiAgent(真实AI对话), Settings(资料+登出)
- 所有页面添加 loading/error/pull-to-refresh 状态

## admin-web (Next.js 15管理后台, 24页)
- 新建API基础设施: api-client.ts(axios), auth-context.tsx, use-api.ts(react-query)
- providers.tsx 接入 QueryClientProvider + AuthProvider
- 24页全部替换 useState(mockArray) 为 useApi<T>('/api/v1/admin/...'):
  Dashboard, Users, Issuers, Coupons, Trading, Risk, Finance, System,
  Compliance(SAR/SEC/License/SOX/Tax/IPO), Analytics(User/Coupon/MM/Consumer),
  Disputes, Chain, Reports, Merchant, Agent, Insurance
- 所有页面添加 TypeScript 接口, loading/error 状态, 'use client' 指令
- 状态比较改用原始API字符串(非t()翻译值)

## miniapp (Taro/React小程序, 20页)
- 新建API基础设施: config/index.ts, utils/request.ts(Taro.request封装), store/auth.ts
- 新增8个Service: auth, coupon, my-coupon, user, trading, wallet, notification, ai
- 20页全部替换硬编码数据为Service调用:
  Home, Search, Detail, Purchase, PaymentSuccess,
  MyCoupons, MyCouponDetail, Redeem, Transfer,
  Profile, Orders, Messages, Wallet, Settings, KYC, AIChat,
  Login, H5Share, H5Activity, H5Register
- 统一 useState+useEffect 数据获取模式, 错误处理, 加载状态

## 统计
- 新建文件: ~51个 (后端26 + 前端25)
- 修改文件: ~93个 (后端24 + 前端69)
- 新增后端端点: 27+
- 前端页面接入API: 55+ (genex-mobile 2 + admin-app 11 + admin-web 24 + miniapp 20)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 22:53:07 -08:00
hailin 184a7d16db feat: 三端集成 App升级 + 内部推送 + FCM外部推送框架 (genex-mobile/admin-app/mobile)
从 rwadurian/frontend/mobile-app 移植升级系统和通知系统到 Genex 三个 Flutter 客户端,
适配目标项目轻量架构(ValueNotifier 替代 Riverpod,Dio HTTP 客户端,移除 screenutil)。

## 新增核心模块 (每个 app 13 个 Dart 文件)

### 升级系统 (core/updater/)
- UpdateService: 统一升级服务单例,支持 Google Play + 自建服务器双渠道
- VersionChecker: 版本检测器,调用 GET /api/app/version/check
- DownloadManager: APK 下载管理,支持断点续传 + SHA256 校验
- ApkInstaller: APK 安装器 (Platform Channel)
- AppMarketDetector: 应用市场来源检测
- SelfHostedUpdater: 自建服务器渠道更新对话框 (i18n 化)
- GooglePlayUpdater: Google Play 应用内更新

### 通知系统 (core/services/ + core/providers/)
- NotificationService: 通知 + 公告 API 服务
  - GET /notifications, /notifications/unread-count
  - PUT /notifications/:id/read
  - GET /announcements, /announcements/unread-count
  - PUT /announcements/:id/read, /announcements/read-all
- NotificationBadgeManager: 未读徽章管理器
  - ValueNotifier<int> 驱动 UI
  - 30秒定时自动刷新 + 前后台切换刷新 (WidgetsBindingObserver)

### FCM 推送框架 (core/push/)
- PushService: Firebase 推送服务框架
  - Firebase 代码注释保护,无配置文件时静默跳过
  - 设备 token 注册 POST /device-tokens
  - 待 Firebase 配置文件就绪后取消注释即可启用

### HTTP 客户端 (core/network/)
- ApiClient: Dio 封装单例,baseUrl = https://api.gogenex.cn

## Android 原生配置 (每个 app)
- AndroidManifest.xml: 添加 REQUEST_INSTALL_PACKAGES 权限 + FileProvider
- res/xml/file_paths.xml: FileProvider 路径配置
- MainActivity.kt: APK 安装器 + 应用市场检测 MethodChannel

## UI 层改造 (每个 app)
- main.dart: 异步启动,初始化 UpdateService/PushService/NotificationBadgeManager
- MainShell: 消息 Tab 徽章改为 ValueListenableBuilder 动态未读数,进入后 3 秒检查更新
- SettingsPage: StatefulWidget 化,动态版本号 (PackageInfo),点击版本号手动检查更新
- MessagePage: 移除 mock 数据,接入 NotificationService API,4 Tab 分类 + 下拉刷新 + 标记已读

## i18n 新增 (~35 keys/语言)
- update.*: 25 个升级相关 keys
- notification.*: 9 个通知相关 keys
- genex-mobile: 4 语言 (zh_CN/zh_TW/en/ja) 分文件
- admin-app: 3 语言 (zh_CN/en_US/ja_JP) 内联单文件
- mobile: 4 语言 (zh_CN/zh_TW/en/ja) 分文件

## 三端差异化配置
| App | MethodChannel 前缀 | applicationId |
|-----|-------------------|---------------|
| genex-mobile | cn.gogenex.consumer | cn.gogenex.consumer |
| admin-app | cn.gogenex.issuer | cn.gogenex.issuer |
| mobile | cn.gogenex.mobile | cn.gogenex.mobile |

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 07:02:14 -08:00