Commit Graph

15 Commits

Author SHA1 Message Date
hailin 13f2d68754 feat(ux): agent list refresh + OAuth keep-alive + deploy token fix
Flutter:
- my_agents_page: refresh agent list on every My Agents tab tap
  (ref.invalidate in ScaffoldWithNav.onDestinationSelected)
- chat_page + my_agents_page: activate AudioSession before launching OAuth
  browser so iOS keeps network connections alive in background; deactivate
  when app resumes or binding polling completes

agent-service deploy:
- Write openclaw.json with correct gateway token and auth-profiles.json
  with API key BEFORE starting the container, so OpenClaw and bridge
  always agree on the auth token (fixes token_mismatch on new deployments)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 13:26:05 -07: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 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
hailin 2f17266455 feat(referral): implement full referral system across all layers
## Overview
完整实现 IT0 推荐裂变系统,涵盖后端微服务、基础设施、Flutter 移动端、Next.js Web Admin。

## Backend — referral-service (packages/services/referral-service/)

### 架构设计
- 遵循 billing-service 模式:DataSource 直接访问 public schema(非 TenantAwareRepository)
- 推荐单元为租户级别(tenant-level),不区分租户内用户
- 最大 2 层推荐深度(L1 直接推荐 / L2 间接推荐)
- 推荐码格式:`IT0-{tenantPrefix3}-{random4}` 例:`IT0-ACM-X9K2`

### 领域实体(5个,均在 public schema)
- `referral_codes`:每个租户唯一推荐码,记录点击量
- `referral_relationships`:推荐关系,状态流转 PENDING→ACTIVE→REWARDED→EXPIRED
- `referral_rewards`:积分奖励记录,支持 PENDING/APPLIED/EXPIRED
- `referral_stats`:每租户聚合统计(直推数、积分总量等)
- `referral_processed_events`:Redis Stream 幂等性去重表

### 奖励规则
- Pro 套餐首次付款:推荐人 $15(1500分)/ 被推荐人 $5(500分)
- Enterprise 套餐首次付款:推荐人 $50(5000分)/ 被推荐人 $20(2000分)
- 续订奖励:付款金额 10%,最多持续 12 个月
- 奖励触发:监听 Redis Stream `events:payment.received`,消费者组 `referral-service`

### Use Cases(6个)
- `GetMyReferralInfoUseCase`:获取/自动创建推荐码,返回分享链接
- `ValidateReferralCodeUseCase`:验证码格式 + 存在性(公开接口,注册前使用)
- `RegisterWithCodeUseCase`:注册时绑定推荐关系,防止自推荐/重复注册
- `ConsumePaymentReceivedUseCase`:消费支付事件,发放首次/续订奖励,含幂等保护
- `GetReferralListUseCase`:分页查询推荐列表和奖励记录
- `GetPendingCreditsUseCase`:供 billing-service 查询待抵扣积分并标记已使用

### REST Controllers(3个)
- `ReferralController` (/api/v1/referral):用户端,JWT 验证
  - GET /me — 我的推荐码与统计
  - GET /me/referrals — 我的推荐列表(分页)
  - GET /me/rewards — 我的奖励记录(分页)
  - GET /validate?code=xxx — 公开验证推荐码(注册页使用)
- `ReferralInternalController` (/api/v1/referral/internal):服务间调用,X-Internal-Api-Key 验证
  - POST /register — auth-service 注册后回调,绑定推荐关系
  - GET /:tenantId/pending-credits — billing-service 查询待抵扣金额
  - POST /:tenantId/apply-credits — billing-service 账单生成后标记积分已使用
- `ReferralAdminController` (/api/v1/referral/admin):管理员端,JWT + platform_admin 角色
  - GET /relationships — 全量推荐关系(可按状态过滤,分页)
  - GET /rewards — 全量奖励记录(可按状态过滤,分页)
  - GET /stats — 平台汇总统计

## Infrastructure

### database migration (packages/shared/database/migrations/006-create-referral-tables.sql)
创建 5 张表,含必要索引(tenantId、code、status、createdAt)

### docker-compose.yml
新增 referral-service 服务定义(port 13012:3012),healthcheck 基于 HTTP 200,
api-gateway depends_on 中添加 referral-service healthy 条件

### kong.yml (packages/gateway/config/kong.yml)
新增 3 组路由:
- `referral-routes`:/api/v1/referral(JWT 插件,转发用户请求)
- `referral-admin-routes`:/api/v1/referral/admin(JWT 插件,管理员)
- `referral-validate-public`:/api/v1/referral/validate(无 JWT,注册页调用)
注:internal 路由不暴露到 Kong,仅服务间直接调用

## auth-service 集成 (packages/services/auth-service/src/application/services/auth.service.ts)
注册成功后(register + registerWithNewTenant 两个路径)fire-and-forget 调用
referral-service 内部接口 POST /api/v1/referral/internal/register,
传入 tenantId + referralCode(可选),使用 Node.js 内置 http 模块(无新依赖)

## Flutter 移动端 (it0_app/lib/features/referral/)

### 数据层
- `referral_info.dart`:ReferralInfo / ReferralItem / RewardItem 模型,含格式化 getter
- `referral_repository.dart`:Dio HTTP 请求 + Riverpod referralRepositoryProvider

### 状态管理(Riverpod FutureProvider)
- referralInfoProvider — 推荐码信息
- referralListProvider — 直推列表首页
- pendingRewardsProvider — 待抵扣奖励
- allRewardsProvider — 完整奖励历史

### UI(referral_screen.dart,630行)
- _ReferralCodeCard:推荐码展示 + 一键复制 + 系统分享(Share.share)
- _StatsRow:3格统计卡(直推数 / 已激活 / 待抵扣积分)
- _RewardRulesCard:奖励规则说明卡片
- _ReferralPreviewList + _RewardPreviewList:首页预览 + "查看全部"导航
- _ReferralListPage + _RewardListPage:完整分页列表子页面

### 入口集成
- profile_page.dart:Billing 分组新增"邀请有礼"设置行(Gift 图标)
- app_router.dart:ShellRoute 内新增 /referral 路由 → ReferralScreen

## Web Admin (it0-web-admin/)

### 数据层
- `src/domain/entities/referral.ts`:TypeScript 接口定义(ReferralRelationship / ReferralReward / ReferralAdminStats / PaginatedResult<T>)
- `src/infrastructure/repositories/api-referral.repository.ts`:React Query 数据获取函数(getAdminReferralStats / listAdminRelationships / listAdminRewards)

### 管理页面 (src/app/(admin)/referral/page.tsx)
3 Tab 布局(概览 / 推荐关系 / 积分奖励):
- StatsOverview:3张统计卡(总推荐数 / 已激活 / 待领积分记录)
- RelationshipsTable:状态筛选下拉 + 分页表格(推荐人、被推荐人租户ID、推荐码、层级、状态、时间)
- RewardsTable:状态筛选下拉 + 分页表格(受益租户、金额、触发类型、状态、来源账单、时间)
- StatusBadge:彩色状态标签组件(PENDING/ACTIVE/REWARDED/EXPIRED/APPLIED)

### 导航集成
- sidebar.tsx:platformAdminItems 新增"推荐管理"(Gift 图标,/referral 路由)
- i18n/locales/zh/sidebar.json:新增 "referral": "推荐管理"
- i18n/locales/en/sidebar.json:新增 "referral": "Referrals"

## 部署说明
1. 服务器执行数据库迁移:
   psql -U it0 -d it0 -f packages/shared/database/migrations/006-create-referral-tables.sql
2. 重建并启动新服务:
   docker compose build referral-service api-gateway && docker compose up -d
3. 确认 .env 中设置 INTERNAL_API_KEY(服务间认证密钥)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 21:15:27 -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 d5930ff4c8 feat(app): redesign navigation — floating robot FAB + 4-tab layout
- Add animated robot avatar widget (CustomPainter, 5 states: idle/thinking/executing/speaking/alert)
- Add FloatingRobotFab that mirrors chatProvider AgentStatus as robot animation state
- Replace 5-tab nav (dashboard/chat/tasks/alerts/settings) with 4-tab (home/my-agents/billing/profile)
- Chat is now pushed full-screen from the robot FAB with slide-up transition
- HomePage: active agent status card + official agent horizontal scroll + quick tips
- MyAgentsPage: empty state with 3-step guide + template grid; shows list when agents exist
- ProfilePage: merged settings + prominent billing entry (replaces old SettingsPage as tab)
- ChatPage AppBar: robot avatar replaces plain text title, reflects real-time agent state
- Add agentConfigs endpoint to ApiEndpoints

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 09:42:17 -08:00
hailin 0aac693b5d fix(app): re-check connectivity on foreground resume to clear false-offline banner
When backgrounded, the periodic TCP ping times out causing isOnline=false.
On resume, immediately re-check so the banner clears as soon as the app
is foregrounded rather than waiting up to 30s for the next scheduled check.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 08:08:01 -08:00
hailin 9ed80cd0bc feat: implement complete commercial monetization loop (Phases 1-4)
## Phase 1 - Token Metering + Quota Enforcement

### Usage Tracking
- agent-service: add UsageRecord entity (per-tenant schema) tracking
  inputTokens/outputTokens/costUsd per AI task
- Modify all 3 AI engines (claude-api, claude-code-cli, claude-agent-sdk)
  to emit separate input/output token counts in the `completed` event
- claude-api-engine: costUsd = (input*3 + output*15) / 1,000,000
  (claude-sonnet-4-5 pricing: $3/MTok in, $15/MTok out)
- agent.controller: persist UsageRecord and publish `usage.recorded`
  event to Redis Streams on every task completion (non-blocking)
- shared/events: new events UsageRecordedEvent, SubscriptionChangedEvent,
  QuotaExceededEvent, PaymentReceivedEvent

### Quota Enforcement
- TenantInfo: add maxServers, maxUsers, maxStandingOrders,
  maxAgentTokensPerMonth fields
- TenantContextMiddleware: rewritten to query public.tenants table for
  real quota values; 5-min in-memory cache; plan-based fallback on error
- TenantContextService: getTenant() returns null instead of throwing;
  added getTenantOrThrow() for strict callers
- inventory-service/server.controller: 429 when maxServers exceeded
- ops-service/standing-order.controller: 429 when maxStandingOrders exceeded
- auth-service/auth.service: 429 when maxUsers exceeded
- 002-create-tenant-schema-template.sql: add usage_records table

## Phase 2 - billing-service (New Microservice, port 3010)

### Domain Layer (public schema, all UUIDs)
Entities: Plan, Subscription, Invoice, InvoiceItem, Payment, PaymentMethod,
UsageAggregate

Domain services:
- SubscriptionLifecycleService: full state machine (trialing -> active ->
  past_due -> cancelled/expired); upgrades immediate, downgrades at period end
- InvoiceGeneratorService: monthly invoice = base fee + overage charges;
  proration item for mid-cycle upgrades
- OverageCalculatorService: (totalTokens - includedTokens) * overageRate

### Infrastructure (all repos use DataSource directly, NOT TenantAwareRepository)
- PlanRepository, SubscriptionRepository, InvoiceRepository (atomic
  transaction for invoice+items), PaymentRepository (payments + methods),
  UsageAggregateRepository (UPSERT via ON CONFLICT for atomic accumulation)

### Application Use Cases
- CreateSubscriptionUseCase: called on tenant registration
- ChangePlanUseCase: upgrade (immediate + proration) or downgrade (scheduled)
- CancelSubscriptionUseCase: immediate or at-period-end
- GenerateMonthlyInvoiceUseCase: cron target (1st of month 00:05 UTC);
  generates invoices, renews periods, applies scheduled downgrades
- AggregateUsageUseCase: Redis Streams consumer group billing-service,
  upserts monthly usage aggregates from usage.recorded events
- CheckTokenQuotaUseCase: hard limit enforcement per plan
- CreatePaymentSessionUseCase + HandlePaymentWebhookUseCase

### REST API
- GET  /api/v1/billing/plans
- GET/POST /api/v1/billing/subscription (+ /upgrade, /cancel)
- GET  /api/v1/billing/invoices (paginated)
- GET  /api/v1/billing/invoices/:id
- POST /api/v1/billing/invoices/:id/pay
- GET  /api/v1/billing/usage/current + /history
- CRUD /api/v1/billing/payment-methods
- POST /api/v1/billing/webhooks/{stripe,alipay,wechat,crypto}

### Plan Seed (auto on startup via PlanSeedService)
- free:       $0/mo,    100K tokens,  no overage,  hard limit 100%
- pro:        $49.99/mo, 1M tokens,  $8/MTok,  hard limit 150%
- enterprise: $199.99/mo, 10M tokens, $5/MTok, no hard limit

## Phase 3 - Payment Provider Integration

### PaymentProviderRegistry (Strategy Pattern, mirrors EngineRegistry)
All providers use @Optional() injection; unconfigured providers omitted

- StripeProvider: PaymentIntent API; webhook via stripe.webhooks.constructEvent
- AlipayProvider: alipay-sdk; Native QR (precreate); RSA2 signature verify
- WeChatPayProvider: v3 REST; Native Pay code_url; AES-256-GCM decrypt;
  HMAC-SHA256 request signing and webhook verification
- CryptoProvider: Coinbase Commerce; hosted checkout; HMAC-SHA256 verify

### WebhookController
All 4 webhook endpoints are public (no JWT) for payment provider callbacks.
rawBody: true enabled in main.ts for signature verification.

## Infrastructure Changes
- docker-compose.yml: billing-service container (port 13010);
  added as dependency of api-gateway
- kong.yml: /api/v1/billing routes (JWT); /api/v1/billing/webhooks (public)
- 005-create-billing-tables.sql: 7 billing tables + invoice sequence +
  ALTER tenants to add quota columns
- run-migrations.ts: 005 runs as part of shared schema step

## Phase 4 - Frontend

### Web Admin (Next.js)
New pages:
- /billing: subscription card + token usage bar + warning banner + invoices
- /billing/plans: comparison grid with USD/CNY toggle + upgrade/downgrade flow
- /billing/invoices: paginated table with Pay Now button
Sidebar: Billing group (CreditCard icon, 3 sub-items)
i18n: billing keys added to en + zh sidebar translations

### Flutter App
New feature module it0_app/lib/features/billing/:
- BillingOverviewPage: plan card + token LinearProgressIndicator +
  latest invoice + upgrade button
- BillingProvider (FutureProvider): parallel fetch subscription/quota/invoice
Settings page: "订阅与用量" entry card
Router: /settings/billing sub-route

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 21:09:17 -08:00
hailin f5d9b1f04f feat: add app upgrade system with self-hosted APK update support
- Add core/updater module: version checker, download manager (resumable + SHA-256),
  APK installer, app market detector, self-hosted updater with progress dialogs
- Add Android native MethodChannels for APK installation and market detection
- Add FileProvider config and REQUEST_INSTALL_PACKAGES permission
- Wire UpdateService singleton into main.dart initialization
- Add auto-check on home entry with cooldown + app resume detection
- Add manual "检查更新" button and dynamic version display in settings
- Fix chat page: bottom overflow, bash spinner persistence, collapsible results
- Merge standing orders into tasks page as second tab

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 22:35:01 -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 9f44878fea fix: unify all pages to Chinese + fix bottom nav selected state
1. 所有页面英文文本统一替换为中文(仪表盘、对话、任务、告警、
   服务器、常驻指令、审批、终端、设置)
2. 底部导航栏添加 selectedIndex 追踪当前路由,点击后正确高亮
3. 导航图标添加 outlined/filled 选中态区分
4. 设置页重构为大厂风格(圆角图标分组 + 主题底部弹窗选择)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 01:59:09 -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 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