Commit Graph

13 Commits

Author SHA1 Message Date
hailin 924b826542 fix(flutter): redirect to /home after login (was /dashboard which no longer exists)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 01:32:54 -08:00
hailin 6be84617d2 feat(flutter): i18n体系(zh/zh_TW/en) + 智能体解聘功能
- 建立完整 flutter_localizations i18n 体系:zh/zh_TW/en 三语言
- l10n.yaml + ARB 文件 (app_zh.arb 约120键作模板,zh_TW/en 对应覆盖)
- localeProvider 连接 SharedPreferences language 设置,实时切换语言
- 设置页加入语言选择器(简体中文/繁体中文/English)
- 我的智能体页实现解聘(解聘确认弹窗 + DELETE API)与重命名功能
- 全部页面 (~18个) UI 字符串替换为 AppLocalizations.of(context).xxx

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 00:05:55 -08:00
hailin 38594d6fd4 feat(flutter): rename iAgent→我智能体,创建/删除→招募,拉近人机关系距离
- App title、登录页、导航Tab、通话页等全局将 iAgent 改为 我智能体
- 底部导航 Tab "我的创建" → "我的智能体"
- 智能体语境下 "创建" → "招募":招募你的专属智能体、帮我招募一个...
- tasks_page 空状态文案 "创建" → "新增"(非智能体语境保持语义准确)
- 终端欢迎语、通知渠道描述同步更新

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 23:10:07 -08:00
hailin 8d2fd3335a feat(telemetry): add presence-service + Flutter telemetry module
## Backend — packages/services/presence-service (新微服务)

完整的 DDD + Clean Architecture 实现,移植自 RWADurian presence-service,
针对 IT0 架构做了以下适配:

### 核心功能
- 心跳接口: POST /api/v1/presence/heartbeat(JWT 验证,60s 间隔)
  → Redis Sorted Set `presence:online_users` 记录在线时间戳
  → 默认 5 分钟窗口判断在线(PRESENCE_WINDOW_SECONDS=300)
- 事件上报: POST /api/v1/analytics/events(批量,最多 50 条)
  → 写入 presence_event_log 表 + 更新 presence_device_profile
  → Redis HyperLogLog `presence:dau:{date}` 实时 DAU 估算
- 查询接口(需 AdminGuard):
  - GET /api/v1/analytics/online-count  — 实时在线人数
  - GET /api/v1/analytics/online-history — 历史在线快照
  - GET /api/v1/analytics/dau — DAU 统计

### IT0 适配要点
- JWT payload: `sub` = UUID userId(非 RWADurian 的 userSerialNum)
  → JwtAuthGuard: request.user = { userId: payload.sub, roles, tenantId }
- AdminGuard: 改为检查 `roles.includes('admin')`(非 type==='admin')
- 移除 Kafka EventPublisherService(IT0 无 Kafka)
- 移除 Prometheus MetricsService(IT0 无 Prometheus)
- 表前缀改为 `presence_`(避免与其他服务冲突)
- userId 字段 VarChar(36)(UUID 格式,非原来的 VarChar(20))
- Redis DB=10 隔离(独立 key 空间)

### 数据库表(public schema)
- presence_event_log       — 事件流水(append-only)
- presence_device_profile  — 设备快照(upsert,每台设备一行)
- presence_daily_active_users — DAU 日统计
- presence_online_snapshots   — 在线人数每分钟快照

### 定时任务(@nestjs/schedule)
- 每分钟: 采集在线人数快照 → presence_online_snapshots
- 每天 01:05 (UTC+8): 计算前一天 DAU → presence_daily_active_users

---

## Flutter — it0_app/lib/core/telemetry (新模块)

### 文件结构
- telemetry_service.dart      — 单例入口,统筹所有组件
- models/telemetry_event.dart — 事件模型,toServerJson() 将设备字段提升为顶层列
- models/device_context.dart  — 设备上下文(Android/iOS 信息)
- models/telemetry_config.dart — 远程配置(采样率/开关,支持远端同步)
- collectors/device_info_collector.dart — 采集 device_info_plus 设备信息
- storage/telemetry_storage.dart  — SharedPreferences 队列(最多 500 条)
- uploader/telemetry_uploader.dart — 批量上传到 /api/v1/analytics/events
- session/session_manager.dart    — WidgetsBindingObserver 监听前后台切换
- session/session_events.dart     — 会话事件常量
- presence/heartbeat_service.dart — 定时心跳 POST /api/v1/presence/heartbeat
- presence/presence_config.dart   — 心跳配置(间隔/requiresAuth)
- telemetry.dart                  — barrel 导出

### 集成点
- app_router.dart _tryRestore(): TelemetryService().initialize() 在 auth 之前
- auth_provider.dart login/loginWithOtp: setUserId + setAccessToken + resumeAfterLogin
- auth_provider.dart tryRestoreSession: 恢复 userId + accessToken
- auth_provider.dart logout: pauseForLogout + clearUserId + clearAccessToken

### 新增依赖
- device_info_plus: ^10.1.0
- equatable: ^2.0.5

---

## 基础设施

### Dockerfile.service
- 在 builder 和 production 阶段均添加 presence-service/package.json 的 COPY

### docker-compose.yml
- 新增 presence-service 容器(端口 3011/13011)
  - DATABASE_URL: postgresql://... (Prisma 所需连接串格式)
  - REDIS_HOST/PORT/DB: 10(presence 独立 Redis DB)
  - APP_PORT=3011, JWT_SECRET, PRESENCE_WINDOW_SECONDS=300
- api-gateway depends_on 新增 presence-service

### kong.yml (dbless 声明式)
- 新增 presence-service 服务(http://presence-service:3011)
  - presence-routes: /api/v1/presence
  - analytics-routes: /api/v1/analytics
- 对整个 presence-service 启用 JWT 插件(Kong 层鉴权)

### DB 迁移
- packages/shared/database/src/migrations/010-create-presence-tables.sql
  — 4 张 presence_ 前缀表 + 完整索引(IF NOT EXISTS 幂等)
- run-migrations.ts: runSharedSchema() 中新增执行 010-create-presence-tables.sql

---

## 部署步骤(服务器)

1. git pull
2. 执行 presence 表迁移(首次):
   docker exec it0-postgres psql -U it0 -d it0 \
     -f /path/to/010-create-presence-tables.sql
   或通过 migration runner:
   cd /home/ceshi/it0 && node packages/shared/database/dist/run-migrations.js
3. 重建并启动 presence-service:
   docker compose build presence-service api-gateway
   docker compose up -d presence-service api-gateway

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 17:44:01 -08:00
hailin 71ea80972d feat(auth): add SMS OTP verification for phone registration and login
- auth-service: add SmsService (Aliyun SMS) + RedisProvider for OTP storage
- POST /api/v1/auth/sms/send — send OTP (rate limited 1/min per phone)
- POST /api/v1/auth/sms/verify — verify OTP only
- POST /api/v1/auth/login/otp — passwordless login with phone + OTP
- register endpoint now requires smsCode when registering with phone
- Web Admin register page: add OTP input + 60s countdown button for phone mode
- Flutter login page: add 验证码登录 tab with phone + OTP flow
- SMS enabled via ALIYUN_ACCESS_KEY_ID/SECRET + SMS_ENABLED=true env vars
- Falls back to mock mode (logs code) when env vars not set

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 06:43:27 -08:00
hailin 94652857cd feat: 生产级 API 错误处理 — 重试拦截器、友好错误提示、网络监测、WebSocket 退避
## 问题
用户看到原始 DioException 堆栈(如 "DioException [unknown]: null Error:
HttpException: Connection reset by peer"),且无重试机制,网络抖动即报错。

## 变更

### 1. RetryInterceptor(指数退避自动重试)
- 新增 `core/network/retry_interceptor.dart`
- 自动重试:连接超时、发送超时、Connection reset、502/503/504/429
- 指数退避(800ms → 1.6s → 3.2s)+ 随机抖动防雪崩
- 最多 3 次重试,非瞬态错误(401/403/404)不重试
- 集成到 dio_client,优化超时:connect 8s、send 15s、receive 20s

### 2. ErrorHandler 全面升级(友好中文错误提示)
- 重写 `core/errors/error_handler.dart`,新增 `friendlyMessage()` 静态方法
- 所有 DioExceptionType 映射为具体中文:
  - Connection reset → "连接被服务器重置,请稍后重试"
  - Connection refused → "服务器拒绝连接,请确认服务是否启动"
  - Timeout → "连接超时,服务器无响应"
  - 401 → "登录已过期,请重新登录"
  - 403/404/429/500/502/503 各有独立提示
- 新增 TimeoutFailure 类型
- 所有 Failure.message 默认中文

### 3. 网络连接监测 + 离线 Banner
- 新增 `core/network/connectivity_provider.dart` — 每30秒探测服务器可达性
- 新增 `core/widgets/offline_banner.dart` — 黄色警告横幅 "网络连接不可用"
- 集成到 ScaffoldWithNav,所有页面顶部自动显示离线状态

### 4. 统一错误展示(杜绝 e.toString())
- 新增 `core/widgets/error_view.dart` — 统一错误 UI(图标 + 友好文案 + 重试按钮)
- 替换 6 个页面的内联错误 Column 为 ErrorView:
  tasks_page / servers_page / alerts_page / approvals_page / standing_orders_page
- 替换 dashboard 的 3 处 _SummaryCardError(message: e.toString())
- 替换 4 个 provider 的 e.toString(): chat / auth / settings / approvals
- 全项目零 e.toString() 残留(仅剩 time.minute.toString() 时间格式化)

### 5. WebSocket 重连增强
- 指数退避(1s → 2s → 4s → ... → 60s 上限)+ 随机抖动
- 最多 10 次自动重连,超限后停止
- disconnect() 阻止自动重连
- 新增 reconnect() 手动重连方法

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 04:01:04 -08:00
hailin 15e6fca6c0 fix: translate all remaining English UI strings to Chinese and remove dead code
- Translate approval_action_card (Approve/Reject/Cancel/Expired)
- Translate tool_execution_card status labels (Executing/Completed/Error)
- Translate chat_providers error messages and stream content
- Translate message_bubble "Thinking..." indicator
- Translate terminal page tooltips (Reconnect/Disconnect)
- Translate fallback values (Untitled/Unknown/No message) across all pages
- Translate auth error "Login failed" and stream error messages
- Remove dead voice_providers.dart (used speech_to_text which is not installed)
- Remove dead voice_input_button.dart (not referenced anywhere)
- Fix widget_test.dart (was referencing non-existent MyApp class)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 02:07:57 -08:00
hailin d1993a1175 feat: add auto-login with token restore on app startup
App 启动时从 SecureStorage 读取已存储的 JWT,解析用户信息自动恢复登录状态,
无需每次重新输入密码。Token 过期则自动尝试 refresh,refresh 失败才跳转登录页。

- 新增 tryRestoreSession() 从 JWT payload 解码用户信息
- 新增 _isTokenExpired() 检查 token 是否过期(预留 60s 缓冲)
- refreshToken() 成功后恢复 AuthState + tenant 上下文
- 新增 /splash 启动页,尝试恢复后决定跳转 dashboard 或 login

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 01:47:20 -08:00
hailin 092a561867 feat: 完成 iAgent App 三大功能 + 修复租户上下文
## 功能一:设置页(完整实现)
- 新增浅色主题(lightTheme),支持深色/浅色/跟随系统三种模式
- app.dart 接入 themeMode 动态切换
- 设置页完整重写:个人信息编辑、修改密码、主题切换、通知开关
- 新增 settings_remote_datasource 对接后端 admin/settings API
- settings_providers 新增 AccountProfileNotifier 管理远程个人资料

## 功能二:语音通话(音频集成)
- 添加 flutter_sound 依赖,创建 PcmPlayer 流式 PCM 播放器
- agent_call_page 替换空壳:真实麦克风采集(record + GTCRN 降噪)
- 真实 PCM 16kHz 流式播放,基于 RMS 能量驱动波形动画
- 修复 WebSocket URL 路径:/ws/voice/ → /api/v1/voice/ws/
- voice_repository_impl 支持后端返回相对路径自动拼接

## 功能三:推送通知(WebSocket MVP)
- 添加 flutter_local_notifications + socket_io_client 依赖
- 创建 AppNotification 实体、NotificationService(Socket.IO 连接 comm-service)
- 通知 providers:列表管理 + 未读计数
- 登录后自动连接通知服务,登出断开
- 底部导航 Alerts 标签添加未读角标(Badge)
- AndroidManifest 添加 POST_NOTIFICATIONS 权限
- main.dart 初始化本地通知插件

## 修复:租户上下文未初始化(500错误)
- 根因:登录后未设置 currentTenantIdProvider,导致 X-Tenant-Id 头缺失
- Flutter 端:login() 成功后从 JWT 设置 tenantId,logout 时清除
- 后端:tenant-context.middleware 增加 JWT tenantId 回退逻辑
- AuthUser 模型新增 tenantId 字段解析

新增 5 个文件,修改 16 个文件,添加 3 个依赖包

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 01:10:52 -08:00
hailin 68d0c9d6f7 fix: 移除logo白色背景 + 优化登录页面UI和中文化
Logo修复:
  - 移除 logo.svg 中的白色背景矩形 (fill="#ffffff")
  - Logo 现在为透明背景,在深色主题上正确显示

登录页面优化:
  - 添加 "iAgent" 品牌标题 (28px, bold, 带字间距)
  - 副标题改为中文 "服务器集群运维智能体"
  - 表单中文化: 邮箱/密码/登录
  - 错误提示改为带背景色的卡片样式 (红色图标+文字)
  - 添加邮箱输入框 placeholder (user@example.com)
  - 密码框支持回车提交
  - 底部提示: "账号由管理员在后台创建或通过邀请链接注册"
  - 限制表单最大宽度 360px,外层改用 SingleChildScrollView 防溢出

用户账号说明:
  App 端不提供自助注册功能,用户账号通过以下方式创建:
  1. 管理员在 Web 后台 (用户管理页) 直接创建
  2. 管理员发送邀请链接,用户通过链接注册
  3. 通过 Web 端自助注册 (可选填公司名创建新租户)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:42:42 -08:00
hailin 4e1b75483d fix: 修复 .gitignore 误忽略 Flutter data/models/ 源码导致构建失败
问题描述:
  在其他机器上构建报错:
  "Error when reading 'lib/features/auth/data/models/auth_response.dart': 系统找不到指定的路径"
  导致 AuthUser、AuthResponse 等类型找不到,编译失败。

根本原因:
  根目录 .gitignore 第75行 "models/" 规则本意是忽略 ML 模型大文件,
  但该规则匹配了所有目录名为 models/ 的路径,包括 Flutter 项目中
  DDD 架构的 data/models/ 源码目录(共 11 个 models/ 目录、10 个 .dart 文件)。
  这些文件在本地存在但从未被 Git 追踪,其他机器 pull 后缺失这些文件。

修复内容:
  1. 修改 .gitignore: 将宽泛的 "models/" 替换为精确的规则
     - packages/services/voice-service/models/ — voice-service 下载的 ML 模型
     - *.pt, *.pth, *.safetensors — PyTorch/HuggingFace 模型二进制文件
     - 不再影响 Flutter 的 data/models/ 源码目录

  2. 提交之前被忽略的 10 个 Flutter model 文件:
     - auth/data/models/auth_response.dart — 登录响应 (accessToken, refreshToken, user)
     - chat/data/models/chat_message_model.dart — 聊天消息模型
     - chat/data/models/session_model.dart — 会话模型
     - chat/data/models/stream_event_model.dart — SSE 流事件模型
     - servers/data/models/server_model.dart — 服务器状态模型
     - approvals/data/models/approval_model.dart — 审批请求模型
     - alerts/data/models/alert_event_model.dart — 告警事件模型
     - agent_call/data/models/voice_session_model.dart — 语音会话模型
     - standing_orders/data/models/standing_order_model.dart — 常设指令模型
     - tasks/data/models/task_model.dart — 任务模型

  3. 同时提交:
     - it0_app/test/widget_test.dart — Flutter 默认测试
     - packages/services/voice-service/src/models/__init__.py — Python 模块初始化

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:29:03 -08:00
hailin 2f228e4591 feat: integrate robot logo into web admin and Flutter app
- Add logo.svg (green robot character) to project root
- Web admin: replace text "IT" badge with SVG logo in sidebar
- Web admin: add logo image to login, register, invite pages
- Web admin: add SVG favicon and apple-touch-icon metadata
- Flutter: add flutter_svg dependency, replace text "IT0" with logo on login page

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 06:17:08 -08:00
hailin 00f8801d51 Initial commit: IT0 AI-powered server cluster operations platform
Full-stack monorepo with DDD + Clean Architecture:
- Backend: 7 NestJS microservices + 5 shared libraries (TypeScript)
- Mobile: Flutter app with Riverpod (Dart)
- Web Admin: Next.js dashboard with Zustand + React Query
- Voice: Python voice service (STT/TTS/VAD)
- Infra: Docker Compose, K8s manifests, Turborepo build

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