hailin
6bdd8d1e19
fix(admin-service): 增加 multer fileSize 限制 500MB,支持 APK/IPA 上传
...
FileInterceptor upload/parse 均未设置文件大小限制,可能导致 multer 默认
内存保护触发。与 Nginx client_max_body_size 500m 保持一致。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 21:57:50 -08:00
hailin
0f07698262
fix(issuer-service): 修复 LifecyclePipeline 接口字段与 Coupon.couponType 类型错误
...
- LifecyclePipeline 接口字段与实际返回值对齐 (minted/listed/sold/inCirculation/redeemed/recalled)
- coupon.type → coupon.couponType (Coupon entity 字段名修正)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 21:20:36 -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
91f06890a5
docs(auth): 完善三方登录模块注释 — 含申请步骤与算法说明
...
AlipayProvider:
- callGateway: 补充完整请求参数结构说明
- sign: 详细说明 RSA2 签名5步骤(字典序→拼接→SHA256WithRSA→Base64)
- chunkBase64: 说明 PEM 格式每64字符换行要求
AppleProvider:
- verifyIdentityToken: 详细说明 claims 验证逻辑和签名验证原理
- getAppleJWKS: 说明 JWKS 缓存策略和 Apple 密钥轮换机制
- jwkToPublicKeyPem: 说明 JWK→SPKI PEM 转换过程
- base64urlDecode: 说明 Base64URL 与标准 Base64 的区别
GoogleProvider:
- verifyIdToken: 说明 tokeninfo vs JWKS 本地验证的权衡,补充响应字段说明
welcome_page.dart:
- 类头注释: 补充平台配置要求和各登录方式申请前提
- _onAlipayTap: 补充 tobias v3 API 结构、result 格式解析、scope 含义、iOS/Android 配置要求
- _parseParam: 说明 URI query 解析的原因
- _onGoogleTap: 补充 signIn 返回 null 的含义、idToken 说明、Android 配置
- _onAppleTap: 补充 Apple 3 项重要限制(姓名/邮箱只在首次授权时返回)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 04:56:11 -08:00
hailin
e8e2a44fef
fix(auth-service): 修复 AlipayProvider TypeScript 类型错误 (unknown 类型断言)
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 04:47:01 -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
44de21a733
docs(auth): 完善微信登录模块注释 — 含申请移动应用完整步骤
...
wechat.provider.ts:
- 补充微信开放平台申请移动应用的完整流程(企业资质、创建应用、
获取 AppID/AppSecret、启用 unionid、获取 Android 签名 MD5)
- 说明常见 errcode 含义(40029/42003/40163)
- 安全注意事项(AppSecret 保密、服务端换 token、防重放建议)
wechat.service.ts:
- 完整业务流程注释(6步,含新老用户分支逻辑)
- unionid 优先策略原理(跨 App 唯一性,防重复注册)
- 每次登录同步微信信息说明
- 自动生成账号字段说明(nickname/email/phone/password/kycLevel)
.env.example:
- 微信开放平台申请步骤(注册/认证/创建/获取/启用 unionid)
- Android 签名 MD5 获取命令
- Flutter --dart-define 构建参数说明
- Universal Links 说明
WXEntryActivity.kt:
- 包名路径规范说明(applicationId vs namespace 区别)
- AndroidManifest 配置要求
- 回调未触发的排查步骤(签名/包名/debug包名)
- 获取 Android 签名 MD5 命令
main.dart:
- registerWxApi 传参说明(--dart-define 用法)
- 未配置 WECHAT_APP_ID 时的降级行为
- Universal Links 配置说明
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 04:04:26 -08:00
hailin
c9100d3262
fix(auth): 移除 wechat.service.ts 中对 bcrypt 的直接依赖
...
改用 Password VO 生成随机密码哈希,避免 TypeScript 找不到
bcrypt 类型声明的编译错误。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 03:52:17 -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
ff558ab77f
docs(auth): 完善邮件注册模块注释与说明
...
为以下新增文件补充详细的文件头注释:
- EmailVerification entity: 验证流程、字段说明、清理策略
- EmailLog entity: 审计日志、状态枚举、provider 说明
- EmailCodeService: Redis 缓存层职责、Key 模式、降级机制
- IEmailProvider: 已实现 Provider 列表、切换逻辑、扩展说明
- IEmailVerificationRepository: 关键方法说明
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 03:20:42 -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
3ae5e2f982
feat(kong): 添加 referral-service 路由 /api/v1/referral
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 01:03:32 -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
ec0af6c47e
fix(auth-service): 密码登录时对手机号做 E.164 归一化
...
注册时手机号存储为 +8618926762721,但密码登录用原始输入
18926762721 查库,导致找不到用户。在 login() 中先尝试
Phone.create() 归一化,如果不是合法手机号则作为邮箱使用。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 00:23:04 -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
2cf90db0b1
fix(admin-service): 移除全局前缀排除规则 — 让 app/version 路由正确响应 /api/v1 前缀
...
Kong 以 strip_path=false 转发 /api/v1/app/version/check,但服务排除了该路径的
全局前缀,导致 404。去掉 exclude 后所有路由统一挂载在 /api/v1 下。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 21:39:32 -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
04a55e3e12
fix(ui): 修复登录页中英混用 + 搜索栏溢出,更新品牌口号并支持后台配置
...
- admin-web 登录页底部 "Genex 券金融平台" → "Genex 管理后台",风格统一
- admin-web 顶部搜索栏改为弹性宽度(width:100%/maxWidth:320),修复窄屏溢出
- 全平台品牌口号统一更新为"让每一张券,自由流动"
覆盖:genex-mobile(4语言) / miniapp(3语言) / portal(zh-CN/en-US)
- backend admin-system.service: getConfig() 新增 brandConfig 字段(4语言口号)
- admin-web 系统配置页新增品牌配置卡片:支持4语言口号在线编辑并保存
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 20:41:37 -08:00
hailin
fcf49b5257
fix(admin-service): 注册 JwtStrategy 解决 "Unknown authentication strategy" 错误
...
admin-service 使用了 @genex/common 的 JwtAuthGuard 保护管理端接口,
但缺少对应的 Passport JWT Strategy 注册。新增轻量级 JwtStrategy,
仅验证 token 签名和提取 payload,不依赖 UserRepository。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 08:16:38 -08:00
hailin
6f87be4454
fix(admin-service): 修复公开 API 路由前缀排除规则
...
setGlobalPrefix exclude 应匹配 controller 路径而非完整 URL。
修复前: exclude: ['api/app/version/(.*)']
→ 不生效,公开 API 被加上 /api/v1 前缀
→ 移动端需访问 /api/v1/app/version/check (错误)
修复后: exclude: ['app/version/(.*)']
→ 正确排除 AppVersionController 的路由
→ 移动端访问 /api/app/version/check (无 /api/v1 前缀)
→ 管理端继续使用 /api/v1/admin/versions (不受影响)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 07:37:44 -08:00
hailin
c1681085b8
feat(admin): App 版本管理 — 多应用支持 + 管理后台页面
...
为 admin-service 添加 appType 维度,支持管理 genex-mobile (用户端)
和 admin-app (发行方管理端) 两个 Flutter 应用的版本发布。
同时在 admin-web 新增完整的版本管理页面。
### 后端改动 (admin-service)
数据模型:
- 新增 AppType 枚举: GENEX_MOBILE | ADMIN_APP
- app_versions 表添加 app_type 列 (VARCHAR(20), 默认 GENEX_MOBILE)
- 重建唯一索引: (app_type, platform, version_code)
- Migration 046: ALTER TABLE + 索引重建
DDD 各层更新:
- Repository 接口/实现: 所有查询方法增加 appType 参数
- Service: checkUpdate/listVersions/createVersion 支持按 appType 过滤
重复检测范围: 同一 appType + platform 内的 versionCode 唯一
- AdminVersionController:
- GET /admin/versions 增加 ?appType= 查询参数
- POST /admin/versions body 增加 appType 字段
- POST /admin/versions/upload body 增加 appType 字段
- AppVersionController (移动端):
- GET /app/version/check 增加 ?app_type= 参数 (默认 GENEX_MOBILE)
### 前端改动 (admin-web)
新增页面 /app-versions:
- App 选择器 Tab: Genex 用户端 / 发行方管理端
- 平台过滤器: 全部 / Android / iOS
- 版本列表表格: 版本号、代码、平台、构建号、文件大小、强制更新、状态、发布日期
- 操作列: 编辑 / 启用|禁用 / 删除
- 上传对话框: 文件选择 → 自动解析包信息 → 填写表单 → 上传到 MinIO
- 编辑对话框: 更新日志、最低系统版本、强制更新、启用状态
- i18n: zh-CN / en-US / ja-JP 各 28 个新翻译键
- 侧边栏: 在「系统管理」前增加「📱 应用版本」菜单项
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 06:09:55 -08:00
hailin
41b8a8fcfb
feat(auth): SMS 模板按类型分发 + 阿里云 8 模板配置
...
重构 auth-service 短信发送逻辑,从单一模板改为按验证类型分发不同模板。
变更:
- SmsVerificationType 枚举新增 3 类型: IDENTITY_VERIFY, TRANSACTION_CONFIRM, PAYMENT_VERIFY
- AliyunSmsProvider.getTemplateCode() 通过 TEMPLATE_ENV_MAP 按类型查找环境变量
优先使用类型专属模板,fallback 到通用 ALIYUN_SMS_TEMPLATE_CODE
- 无模板配置时返回错误而非发送空模板
- 日志增加类型和模板代码,便于排查
阿里云已创建 8 个 Genex 短信模板:
- SMS_501745796 注册验证码 (已通过)
- SMS_501720822 登录验证码
- SMS_501735781 重置密码
- SMS_501925825 身份验证 (已通过)
- SMS_501820752 交易确认 (已通过)
- SMS_501855782 支付验证 (已通过)
- SMS_501780799 异常登录提醒 (已通过)
- SMS_501810819 账户变更通知
环境变量:
- .env.example / docker-compose.yml 新增 ALIYUN_SMS_TPL_* 共 7 项
- aliyun_sms_manager.py 迁移到 CreateSmsTemplate 新 API (旧 AddSmsTemplate 已下线)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 05:13:16 -08:00
hailin
6e6723a664
fix(auth): 参照rwdurian实现重写AliyunSmsProvider
...
使用 sendSmsWithOptions + RuntimeOptions 替代 sendSms,
与 rwdurian identity-service 已验证的实现保持一致。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 01:00:30 -08:00
hailin
9c2e8b8024
fix(auth): AliyunSmsProvider 使用 SendSmsRequest 构造请求对象
...
修复 request.validate is not a function 错误,
dysmsapi v3 SDK 的 sendSms() 需要 SendSmsRequest 实例而非 plain object。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 00:55:54 -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
e8f67527c7
fix(auth): LoginDto.deviceInfo/ipAddress 添加 @IsOptional
...
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:18:21 -08:00
hailin
6d3d45a4fb
fix(auth): Aliyun SMS 用 require() 替代 import() 避免 TS2307
...
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:11:14 -08:00
hailin
9eb35e5f1e
fix(auth): 修复 TypeScript 编译错误 — RegisterDto.password 可选 + Aliyun import 类型
...
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:10:28 -08:00
hailin
8a12bc225d
fix(seed): 修复 address_mappings 种子数据匹配实际 schema
...
- address_mappings: 添加 internal_address + chain_type, 移除不存在的 signature 列
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:06:26 -08:00
hailin
4651edae35
fix(seed): 更新 disputes + audit_logs 种子数据匹配新 schema
...
- disputes: buyer_id/seller_id → plaintiff_id/defendant_id, 移除已删除列
- audit_logs: actor_id/actor_role/resource_type → admin_id/admin_name/resource
- 枚举值对齐: buyer_complaint → buyer_claim, evidence_collection → processing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:04:31 -08:00
hailin
686bf6c395
fix(schema): 统一 disputes + audit_logs 迁移与实体定义
...
- 新增 045_align_disputes_audit_logs.sql: ALTER迁移对齐021/022旧schema到实体期望schema
- disputes: buyer_id→plaintiff_id, seller_id→defendant_id, 添加amount+version列
- audit_logs: actor_id→admin_id, resource_type→resource, 添加admin_name+result+updated_at+version列
- 将028/029改为no-op (已被045取代)
- Dispute entity: enum类型改为varchar (匹配CHECK约束而非PostgreSQL原生enum)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:01:20 -08:00
hailin
7fc3123b5a
fix(auth): 补全部署前置条件 — version列迁移 + docker-compose优化
...
- 新增 044_add_users_version_column.sql 迁移 (TypeORM @VersionColumn 需要)
- auth-service 移除 Kafka 硬依赖 (EventPublisher 已有 graceful no-op)
- docker-compose 添加 SMS_ENABLED/SMS_CODE_EXPIRE_SECONDS/SMS_DAILY_LIMIT 环境变量
- 新增 auth-service/.env.example 文档化所有必需环境变量
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 21:49:31 -08:00
hailin
e8d9bdc2fb
fix(api): 修复前后端 API 对接 — 响应结构+字段名对齐
...
端到端审查发现并修复 4 类前后端不匹配问题:
## 1. 响应结构嵌套不匹配
后端返回 `{ data: { user, tokens: { accessToken, refreshToken } } }`
但 miniapp/admin-app/admin-web 均按扁平结构解析
- miniapp services/auth.ts: 新增 AuthResponse→LoginResult 映射层
- miniapp store/auth.ts: 从 `resp.tokens.accessToken` 取 token
- admin-app auth_service.dart: LoginResult.fromJson 优先从 tokens 子对象取
- admin-web auth-context.tsx: 从 `result.tokens.accessToken` 取 token
## 2. 密码登录字段名不匹配
后端 LoginDto 字段为 `identifier`, 但 admin-app 发 `email`, admin-web 发 `email`
- admin-app: `'email' → 'identifier'`
- admin-web: `{ email, password } → { identifier: email, password }`
## 3. 注册 password 字段必填 vs 前端可选
miniapp h5-register 只收集手机+验证码, 不传 password, 会触发 400 校验
- backend RegisterDto: password 改为 @IsOptional
- auth.service.ts: 未传 password 时自动生成随机密码
## 4. miniapp LoginResult 类型导出
- 导出 LoginResult 接口供外部使用
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 21:39:26 -08:00
hailin
e59c0d0527
feat(admin): SMS 管理后台 — admin 端点 + 用户管理增强 + SMS 日志页
...
Phase 8: admin-web 后台管理增强
## 后端 (auth-service)
- 新增 AdminSmsController (JWT 保护):
· GET /admin/sms/logs — 按手机号查询 SMS 发送日志
· GET /admin/sms/logs/user/:id — 按用户 ID 查询其 SMS 日志
· POST /admin/sms/unlock/:id — 手动解锁账号(清除 loginFailCount + lockedUntil)
· 手机号脱敏: 138****5678 格式
- auth.module.ts 注册 AdminSmsController
## 前端 (admin-web)
- UserManagementPage 增强:
· 新增状态列: 正常(绿) / 已冻结(红) / 已锁定(黄)
· 手机号自动掩码显示
· 冻结/解冻按钮根据状态切换
· 锁定用户显示"解锁"按钮
- 新增 SMS 日志查看页面 (SmsLogPage):
· 按手机号搜索 SMS 发送记录
· 类型、状态 badge 展示
· 路由: /users/sms-logs
- AdminLayout 侧边栏新增 "SMS 日志" 导航项
- i18n 补充 (zh-CN/en-US/ja-JP):
· 用户状态: user_active, user_frozen, user_locked, user_unlock
· SMS 日志: 17 个新 key (sms_log_*, sms_type_*, sms_status_*, nav_users_sms_logs)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 20:34:15 -08:00
hailin
e89ec82406
feat(auth): 完整实现 SMS 手机注册/登录/验证系统
...
参考 rwadurian 项目的成熟实现,在 Genex auth-service 上全面增强短信验证体系。
## 新增功能
### Domain 层
- Phone Value Object: E.164 标准化、中国大陆格式自动补+86、掩码显示(138****8000)
- SmsCode Value Object: crypto 安全随机6位生成、格式验证
- SmsVerification Entity: 验证码记录持久化,支持4种类型(REGISTER/LOGIN/RESET_PASSWORD/CHANGE_PHONE)
- SmsLog Entity: SMS发送日志审计追踪(provider/status/error)
- User Entity 增强: loginFailCount + lockedUntil 字段,指数退避锁定策略(1→2→4→8...→1440分钟)
- 5个新 Domain Events: SmsCodeSent, SmsCodeVerified, AccountLocked, PhoneChanged, PasswordReset
### Infrastructure 层
- 3个 SQL 迁移: users表锁定字段(041), sms_verifications表(042), sms_logs表(043)
- SmsVerification/SmsLog TypeORM Repository 实现
- SMS Provider 抽象层: ISmsProvider 接口 + ConsoleSmsProvider(开发) + AliyunSmsProvider(生产)
- Redis SmsCodeService 增强: 类型前缀 auth:sms:{type}:{phone},保留向后兼容
### Application 层
- 独立 SmsService: 发送验证码(日限额10条+业务规则校验) + 验证验证码(尝试限制5次)
- AuthService 重构: 注册需SMS验证、密码登录带锁定检查、+resetPassword/changePhone
### Interface 层
- 新端点: POST /auth/sms/send, POST /auth/reset-password, POST /auth/change-phone
- DTO 更新: RegisterDto 增加 smsCode 必填, SendSmsCodeDto 增加 type 枚举
- 全部端点 Swagger 文档
### 配置
- .env.example: SMS_ENABLED, ALIYUN_SMS_*, SMS_DAILY_LIMIT, LOGIN_MAX_FAIL_ATTEMPTS
- auth.module: SMS_PROVIDER 按 SMS_ENABLED 环境变量自动切换
## API 端点一览
- POST /api/v1/auth/sms/send — 发送验证码(4种类型)
- POST /api/v1/auth/register — 手机注册(phone+smsCode+password)
- POST /api/v1/auth/login — 密码登录(带锁定检查)
- POST /api/v1/auth/login-phone — 短信验证码登录
- POST /api/v1/auth/reset-password — 重置密码
- POST /api/v1/auth/change-phone — 换绑手机(需登录)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 19:12:57 -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
e8e2d14fbc
fix(health): 修正NestJS服务健康检查URL路径 /health → /api/v1/health
...
NestJS服务注册了全局路由前缀 api/v1,HealthController 实际挂载在
/api/v1/health 而非 /health,导致 Docker HEALTHCHECK 返回 404。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 05:50:26 -08:00
hailin
c5787020d2
feat(health): 为全部12个微服务添加Docker健康检查
...
## 变更概要
所有后端微服务均增加 Docker HEALTHCHECK 指令,统一通过 GET /health
端点检测服务存活状态。解决 `docker ps` 中13个容器无 (healthy) 状态的问题。
## NestJS 服务 (9个)
- auth-service (:3010), user-service (:3001), issuer-service (:3002),
clearing-service (:3004), compliance-service (:3005), ai-service (:3006),
notification-service (:3008), telemetry-service (:3011), admin-service (:3012)
- 7个服务的 app.module.ts 新增 `import { HealthModule } from '@genex/common'`
注册标准健康检查控制器 (GET /health, /health/ready, /health/live)
- telemetry-service 和 admin-service 已有自建 HealthController,无需导入
- Dockerfile: HEALTHCHECK --interval=30s --start-period=15s --retries=3
## Go 服务 (3个)
- trading-service (:3003), translate-service (:3007), chain-indexer (:3009)
- 已有 /health 端点 (Gin 路由),仅 Dockerfile 添加 HEALTHCHECK
- Dockerfile: HEALTHCHECK --interval=30s --start-period=10s --retries=3
## Kafka Connect
- docker-compose.yml 添加 healthcheck (curl http://localhost:8083/ )
## 健康检查方式
- 所有服务统一使用 `wget --spider http://localhost:PORT/health `
(node:20-alpine 和 alpine:3.19 均自带 BusyBox wget)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 05:39:25 -08:00
hailin
0b1de382b0
fix(deploy): 服务器部署修复 — 全栈编译运行通过
...
在内网服务器 (192.168.1.222) 首次部署时发现并修复的所有问题,
涉及 backend (12微服务)、blockchain (Cosmos SDK节点)、前端 (admin-web)。
## Backend 修复
### docker-compose.yml
- DB_PASSWORD: 从硬编码 `genex_dev_password` 改为 `${DB_PASSWORD}` 环境变量插值,
所有13个服务统一从 .env 读取,避免密码不一致导致连接失败
- Kong 镜像: `kong:3.5-alpine` → `kong:3.5`,alpine 版本在 amd64 上缺少依赖
- chain-indexer: 环境变量名 `CHAIN_RPC_URL` → `RPC_URL` (与 Go 代码 getEnv 一致)
- chain-indexer: RPC 地址改为 `http://172.17.0.1:8545 ` (Docker bridge gateway,
跨 docker-compose network 访问 blockchain 节点的 EVM JSON-RPC)
- chain-indexer: 补全缺失的 DB_HOST/DB_PORT/DB_USERNAME/DB_PASSWORD/DB_NAME
### ai-service
- ai.module.ts: 移除重复的 TypeOrmModule.forRootAsync — 该模块错误地使用了
DB_USER/DB_PASS (默认 'genex'/'genex') 和独立数据库 genex_ai,与 app.module.ts
中已有的 TypeOrmModule.forRoot 冲突,导致密码认证失败
- app.module.ts: 添加 ConfigModule.forRoot({ isGlobal: true }),因为
JwtModule.registerAsync 依赖 ConfigService 注入
### 依赖补全
- user-service/package.json: 添加 kafkajs ^2.2.4 (Kafka 事件消费)
- admin-service/package.json: 添加 kafkajs ^2.2.4 (Kafka 事件消费)
## Blockchain 修复
### genex-chain/app.go — 修复 chainConfig panic
- 问题: NewGenexApp 被调用两次 (tempApp 注册编码 + 实际启动),cosmos/evm 的
SetChainConfig 在第二次调用时 panic: "chainConfig already set"
- 原因: 原代码 `if evmChainID == 0 { evmChainID = GenexEVMChainID }` 导致
tempApp 也使用 8888,SetChainConfig 设置后,实际 app 再次设置时触发 panic
- 修复: 移除默认值回退,让 tempApp 使用 evmChainID=0 → DefaultEVMChainID(262144),
实际 app 从 app.toml 读取 8888 后可正常覆盖
### genex-chain/cmd/genexd/cmd/root.go
- 移除未使用的 banktypes import (编译错误)
### docker-compose.yml
- 添加 `command: ["start", "--chain-id", "genex-testnet-1"]` 到 x-genex-node 默认配置,
否则 InitChain 时 chain-id 为空导致校验失败
### init-genesis.sh (新增)
- 创世初始化脚本: init → 补丁 genesis.json → 创建验证者 → gentx → collect-gentxs
- 将所有默认 denom (aatom) 替换为 agnx (GNX, 18 decimals EVM 兼容)
- 配置: evm_denom, bond_denom, mint_denom, gov min_deposit, bank denom_metadata
- 启用 JSON-RPC (0.0.0.0:8545/8546)、REST API、CORS
- 设置 evm-chain-id=8888
## 部署结果
- 20 个 Docker 容器全部运行 (4 基础设施 + 12 后端 + 1 区块链节点 + 1 前端 + 2 辅助)
- 区块链稳定出块 (height 80+),EVM JSON-RPC 正常
- chain-indexer 实时索引区块 (lag=0)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 05:29:33 -08:00
hailin
8e9ee1d38b
fix(docker): 端口避让 + admin-service依赖修复
...
- 所有端口改为不冲突范围: 基础设施4xxxx, 服务4xxx
- admin-service添加adbkit-apkreader/unzipper/bplist-parser依赖
- 修复Platform类型推断
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:34:24 -08:00
hailin
2f583a0a24
fix(admin-service): 添加APK/IPA解析依赖 + 修复Platform类型推断
...
- 添加adbkit-apkreader, unzipper, bplist-parser
- 修复platform变量类型为Platform枚举
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 19:58:12 -08:00
hailin
c42827c6c1
fix(backend): 修复所有服务编译问题 — tsconfig宽松化 + 补全缺失依赖
...
- 所有tsconfig.json: strict改为false, 移除paths映射(改用node_modules解析)
- compliance/clearing/ai/notification: 添加缺失的@nestjs/passport和@nestjs/jwt
- ai-service: 添加缺失的@nestjs/config
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 19:20:48 -08:00
hailin
a31c1aa478
fix(common): 修复@genex/common包TypeScript编译错误
...
- current-user.decorator: 移除显式返回类型以兼容undefined字段访问
- http-exception.filter: 为message变量提供默认值避免TS2454
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 19:04:21 -08:00
hailin
d48bd3acb9
feat(docker): 重构Monorepo构建 — 支持@genex/common共享包
...
- docker-compose.yml build context从service目录改为backend根目录
- 所有NestJS Dockerfile改为先构建共享@genex/common包
- 共享包编译后复制到service的node_modules供运行时解析
- 新增backend/.dockerignore减少构建上下文体积
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 19:00:27 -08:00
hailin
d146bf0a1f
fix(tsconfig): 关闭strictPropertyInitialization以兼容TypeORM实体
...
TypeORM实体使用装饰器定义属性,不在构造函数中初始化。
strict:true隐式启用strictPropertyInitialization导致TS2564编译错误。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 17:48:48 -08:00
hailin
12bb31ede1
fix(docker): 所有NestJS服务Dockerfile使用npm install替代npm ci
...
项目未包含package-lock.json,npm ci要求该文件存在才能运行。
改用npm install确保Docker构建正常完成。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 17:33:31 -08:00
hailin
c11d009ae7
fix: admin-service/telemetry-service Dockerfile 改为多阶段构建
...
修复缺少 builder 阶段导致 COPY dist/ 找不到目录的问题
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 17:29:56 -08:00
hailin
bc0d1e0876
feat: 新增 deploy.sh 部署管理脚本体系 — 后端主控+12服务独立+区块链
...
参照 rwadurian 项目模式,为全栈系统创建统一的 deploy.sh 管理体系:
- backend/deploy.sh: 主控脚本 (up/down/restart/build/build-no-cache/health/infra-*/单服务操作)
- 12个服务独立 deploy.sh (build/rebuild/start/stop/restart/logs/health/shell/test)
- blockchain/deploy.sh: 节点+生态+合约+浏览器+监控全覆盖
- 更新 09-编译部署指南.md 新增第9章 deploy.sh 使用文档
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 17:13:09 -08:00
hailin
be3555f338
fix(chain-indexer): 替换Mock为真实区块链RPC索引 — 接入Genex Chain EVM节点
...
## 背景
chain-indexer(:3009)此前使用Mock模式,每10秒生成假区块数据(hash为纯数字填充,
txCount固定为0),未连接任何真实区块链节点。这是整个区块链架构中唯一的功能缺口
(8大核心服务中TX Indexer完成度仅85%)。
## 改动内容
### 新增文件
- internal/domain/repository/chain_client.go
DDD领域接口ChainClient,定义GetLatestBlockNumber/GetBlockByNumber/Close三个方法,
遵循依赖倒置原则,应用层不依赖具体RPC实现
- internal/infrastructure/rpc/eth_client.go
EthChainClient实现,基于go-ethereum/ethclient:
· ethclient.Dial()连接EVM JSON-RPC节点
· BlockByNumber()获取完整区块(hash/timestamp/txCount)
· types.LatestSignerForChainID()恢复交易发送方地址
· TransactionReceipt()获取交易执行状态(confirmed/failed)
### 修改文件
- go.mod: 新增github.com/ethereum/go-ethereum v1.14.8依赖
- internal/application/service/indexer_service.go
· 注入ChainClient依赖,移除所有Mock逻辑
· 轮询间隔10s→2s(匹配链~1s出块时间)
· 批量追赶:每周期最多索引50个区块,快速消化落后高度
· 新增GetChainHeight()/IsSynced()方法供API层使用
· 区块+交易分别持久化,每条交易独立发布Kafka事件
- cmd/server/main.go
· 新增RPC_URL环境变量(默认http://localhost:8545 )
· 初始化EthChainClient并注入IndexerService
· /api/v1/chain/status返回真实chainHeight和syncing状态
- internal/interface/http/handler/admin_chain_handler.go
· GetContracts: 合约列表更新为真实11个已部署合约(与genex-contracts对齐)
· GetGasMonitor: Gas数据全部归零(Genex Chain min_gas_price=0平台补贴)
· GetChainStats: 使用真实chainHeight计算indexerLag/tps/indexerStatus
· chainId修正88888→8888,consensusType修正PoA→CometBFT
## 环境变量
RPC_URL=http://localhost:8545 (Docker内使用 http://genex-node-1:8545 )
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 18:04:18 -08:00
hailin
9e0152ca0d
fix: RegexRouter 精确匹配 outbox 表,防止 heartbeat 事件污染消费者
...
问题根因 (rwadurian 生产环境发现):
- transforms.route.regex=".*" 将所有 CDC 变更事件(包括 heartbeat 表)
统一路由到 outbox topic,导致消费者收到非 outbox 格式的消息
- 消费者无法解析 heartbeat 消息 → prisma:error + "Unknown event format" 告警
- 每 10 秒一次 heartbeat × 5 个 connector = 持续的日志噪音
修复方案:
- transforms.route.regex 从 ".*" 改为 ".*outbox"
- 只有匹配 *outbox 的 topic(即真正的 outbox 表变更)才被路由到目标 topic
- heartbeat/signal 表的变更走默认 topic 命名(无消费者监听,自动过期)
- heartbeat 仍在 table.include.list 中,确保 Kafka offset 正常推进
→ confirmed_flush_lsn 持续前进 → WAL 不积压
验证 (rwadurian 生产环境):
- 修复后 mining-admin-service "Unknown event format" 告警清零
- WAL lag 从 540MB 降至 30-97MB 正常波动
- 5 个 connector 全部 RUNNING,heartbeat 正常(5s 内更新)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 07:04:17 -08:00