Commit Graph

106 Commits

Author SHA1 Message Date
hailin d083008001 fix(conversations): implement soft-delete for conversation deletion
The delete conversation endpoint was a no-op — it verified ownership but
never actually modified the record. Users saw conversations disappear
(frontend optimistic removal) but they reappeared on refresh.

Changes:
- conversation.entity.ts: Add DELETED status, softDelete() and isDeleted()
- conversation.service.ts: Call softDelete() + update instead of no-op
- conversation-postgres.repository.ts: Exclude DELETED conversations
  from findByUserId() queries so they don't appear in user's list

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 20:49:03 -08:00
hailin b75d607e2b fix(agents): resolve NestJS route collision for evaluation-rules endpoints
AdminConversationController's GET /:id was intercepting requests to
AdminEvaluationRuleController (matching "evaluation-rules" as an id param).
Similarly, DELETE /:id was matching "cache" as an id.

Changes:
- conversation.module.ts: Register AdminMcpController and
  AdminEvaluationRuleController before AdminConversationController
  (more specific prefixes must come first in NestJS)
- admin-evaluation-rule.controller.ts: Move static routes (POST /test,
  DELETE /cache) before dynamic routes (GET/:id, DELETE/:id)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 20:37:40 -08:00
hailin 51a7589fbf fix(agents): export EVALUATION_RULE_REPOSITORY from AgentsModule
The AdminEvaluationRuleController in ConversationModule needs the
EVALUATION_RULE_REPOSITORY token. Even though AgentsModule is @Global(),
Symbol-based providers must be explicitly exported to be available
in other modules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 19:45:38 -08:00
hailin 00a0ac3820 feat(agents): add admin-configurable evaluation gate for agent loop quality control
Add a configurable evaluation gate system that allows administrators to
define quality rules per consulting stage. The gate checks are executed
programmatically before the agent loop returns a response to the user.

## Architecture

- **Zero-config safe**: Empty rules table = no checks = current behavior preserved
- **Callback-based decoupling**: agent-loop.ts receives an optional callback,
  stays decoupled from database layer
- **Max 1 retry**: On RETRY/SUPPLEMENT failure, recurse once without gate to
  prevent infinite loops
- **Error-tolerant**: Gate exceptions are caught and logged, never block responses

## New files

- `database/migrations/20260206_add_evaluation_rules.sql` — DB migration
- `domain/entities/evaluation-rule.entity.ts` — Domain entity with 6 rule types
  (FIELD_COMPLETENESS, ASSESSMENT_QUALITY, RESPONSE_LENGTH, MUST_CONTAIN,
  STAGE_MIN_TURNS, CONVERSION_SIGNAL) and 4 failure actions (RETRY, SUPPLEMENT,
  WARN_AND_PASS, ESCALATE)
- `domain/repositories/evaluation-rule.repository.interface.ts` — Repository contract
- `infrastructure/database/postgres/entities/evaluation-rule.orm.ts` — TypeORM ORM entity
- `infrastructure/database/postgres/repositories/evaluation-rule.repository.ts` — Repository impl
- `infrastructure/agents/coordinator/evaluation-gate.service.ts` — Core evaluation engine
  with 5-minute rule cache, per-rule-type evaluators, severity-based action resolution,
  and feedback message builder for model retry
- `application/dtos/evaluation-rule.dto.ts` — Create/Update/Test DTOs
- `adapters/inbound/admin-evaluation-rule.controller.ts` — Admin CRUD API with 8 endpoints:
  list, get, create, update, delete, toggle, test (dry-run), clear cache

## Modified files

- `agent.types.ts` — Add optional `evaluationGate` callback to `AgentLoopParams`
- `stream.types.ts` — Add `EvaluationWarningEvent`, `'evaluating'` phase
- `agent-loop.ts` — Insert gate check at termination point (line 315)
- `coordinator-agent.service.ts` — Inject EvaluationGateService, build callback,
  handle `evaluation_warning` event in StreamChunk mapping
- `agents.module.ts` — Register EvaluationRuleORM, repository, EvaluationGateService
- `conversation.module.ts` — Register AdminEvaluationRuleController

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 18:56:52 -08:00
hailin 714a674818 feat(mcp): add MCP Server management — backend API + admin UI
实现完整的 MCP (Model Context Protocol) 服务器管理功能,包括后端 API 和管理界面。

## 后端 (conversation-service)

### MCP 混合架构核心 (新增)
- mcp.types.ts: MCP 类型定义 (McpServerConfig, McpToolDefinition, McpConnectionState 等)
- mcp-config.service.ts: 配置解析 — 支持环境变量 MCP_SERVERS 和租户级配置
- mcp-client.service.ts: MCP 客户端 — 连接管理、工具发现、工具执行、运行时增删改
- mcp.module.ts: @Global NestJS 模块,注册 MCP 服务 + TypeORM 实体 + Repository

### 数据持久化 (新增)
- 20260206_add_mcp_server_configs.sql: 数据库迁移 — mcp_server_configs 表
- mcp-server-config.orm.ts: TypeORM 实体 (tenant_id 支持多租户)
- mcp-server-config.repository.ts: Repository 层 (CRUD + ORM→McpServerConfig 转换)

### Admin API (新增)
- admin-mcp.controller.ts: 11 个管理端点,路由前缀 conversations/admin/mcp
  - GET /overview — 统计信息 (服务器总数、已连接、错误、工具总数)
  - GET/POST /servers — 列表 + 创建
  - GET/PUT/DELETE /servers/:id — 详情 + 更新 + 删除
  - POST /servers/:id/connect — 手动连接
  - POST /servers/:id/disconnect — 手动断开
  - GET /servers/:id/tools — 查看已发现工具
  - POST /servers/:id/test — 测试连接
  - POST /test-config — 测试未保存的配置

### 已有文件修改
- coordinator-tools.ts: getToolsForClaudeAPI() 支持 additionalTools 可选参数
- agent-loop.ts: 支持 additionalTools + additionalConcurrencyMap 透传
- coordinator-agent.service.ts: 注入 McpClientService,工具路由加 MCP 分支
- agents.module.ts: 导入 McpModule
- conversation.module.ts: 注册 AdminMcpController

## 前端 (admin-client)

### API + Hooks (新增)
- mcp.api.ts: Axios API 客户端 + 完整 TypeScript 类型定义
- useMcp.ts: 10 个 React Query hooks (queries + mutations)

### UI 页面 (新增)
- McpPage.tsx: 主页面 — 统计卡片 + 服务器表格 + 操作按钮
- ServerFormDrawer.tsx: 创建/编辑表单 — 基本信息、传输配置、高级设置、连接测试
- ServerDetailDrawer.tsx: 详情抽屉 — 配置展示、工具浏览 (Collapse + JSON Schema)

### 路由 + 导航
- App.tsx: 添加 /mcp 路由
- MainLayout.tsx: 侧边栏添加 "MCP 服务器" 菜单项 (ApiOutlined 图标)

## 依赖
- @modelcontextprotocol/sdk: ^1.0.0 (MCP 协议 SDK)

## 架构设计
- 混合架构: 16 个内置工具保持不变 + MCP 工具动态发现/热插拔
- 工具名前缀 mcp__{serverId}__{toolName} 确保零冲突
- 优雅降级: MCP 连接失败不影响内置工具,仅 log 记录
- 启动加载: 先连接环境变量配置,再连接数据库配置
- 运行时管理: 支持不重启服务即可增删改 MCP Server

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 18:29:02 -08:00
hailin dc6311f050 fix(db): add multi-tenancy migration for knowledge-service tables
Adds tenant_id UUID column to user_memories, system_experiences,
knowledge_articles, and knowledge_chunks tables with default tenant
backfill and indexes. Migration already applied to production DB.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 09:23:13 -08:00
hailin 20001277ff fix(agents): update Haiku model ID from 3.5 to 4.5
claude-haiku-3-5-20241022 returns 404 on the proxy. Updated to
claude-haiku-4-5-20251001 in agent configs and context injector.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 08:59:58 -08:00
hailin fb811c7cf4 fix(agents): prevent usage events from emitting stream_end to frontend
The mapEventToStreamChunk was mapping both 'usage' (per-turn) and 'end'
(final) events to type 'end', causing the gateway to emit multiple
stream_end events. This made the frontend create a separate message
bubble (with its own bot avatar) for each agent loop turn.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 08:58:11 -08:00
hailin d1907636fe fix(ws): set tenant context for WebSocket message handling
WebSocket gateway was missing AsyncLocalStorage tenant context setup,
causing 'Tenant context not set' error on every message. Now extracts
tenantId from handshake and wraps handleMessage in tenantContext.runAsync().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 08:49:56 -08:00
hailin 4ac1fc4f88 fix(db): add multi-tenancy migration for conversation-service tables
- Add tenant_id column to conversations, messages, token_usages tables
- Create standalone migration SQL script for production deployment
- Add agent_executions table to init-db.sql for new installations
- Fix MessageORM created_at nullable mismatch with database schema
- Backfill existing data with default tenant ID

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 08:39:10 -08:00
hailin 51c05f98ee fix(agents): resolve ContextInjectorService DI error by replacing interface with concrete class
- Replace IKnowledgeClient TypeScript interface (erased at runtime) with KnowledgeClientService concrete class injection
- Fix method signatures to match KnowledgeClientService API:
  - getUserMemories() → getUserTopMemories(), field type → memoryType
  - retrieveForPrompt(query, userId) → retrieveForPrompt({ query, userId })
  - getRelevantExperiences(query, n) → searchExperiences({ query, limit: n }), field type → experienceType
- Remove unused ContextData import

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 08:10:40 -08:00
hailin 691a3523e8 feat(analytics): add Agent usage analytics to admin panel
Add full-stack Agent execution tracking and analytics:

**Database (conversation-service)**
- New `agent_executions` table: tracks each specialist Agent invocation
  with agentType, agentName, durationMs, success, tenantId
- Migration: AddAgentExecutionsTable1738800000000
- ORM entity: AgentExecutionORM with indexes on tenant, conversation,
  agentType, createdAt, and (tenant+date) composite

**Data Capture (conversation-service)**
- conversation.service.ts: captures `agent_start` and `agent_complete`
  StreamChunk events in the sendMessage() async generator loop
- Persists agent execution records to DB after each message completes
- Non-blocking: agent persistence failures are logged but don't break
  the main conversation flow

**Admin API (conversation-service)**
- GET /conversations/admin/statistics/agents?days=30
  Aggregated stats per agent type: totalCalls, successCount, failureCount,
  successRate, avgDurationMs, min/max duration
- GET /conversations/admin/statistics/agents/trend?days=7&agentType=
  Daily trend data: date, agentType, calls, avgDurationMs, successRate
- GET /conversations/admin/:id/agent-executions
  Per-conversation agent execution records ordered by createdAt

**Admin Client - Analytics Page**
- New AgentAnalyticsTab component with:
  - 4 summary cards (total calls, success rate, avg duration, top agent)
  - Agent statistics table (Ant Design Table with sortable columns,
    color-coded Tags, Progress bar for success rate)
  - Stacked bar trend chart (Recharts BarChart, color per agent type)
  - Time range selectors (7/14/30/90 days)
- Added as third tab "Agent 使用分析" in AnalyticsPage dimension tabs

**Admin Client - Conversations Page**
- Added "Agent 使用详情" section to conversation detail drawer
  (between Token Usage and Messages sections)
- Shows per-conversation agent execution table with agent name (color Tag),
  duration, success/failure status, and timestamp
- Empty state: "暂无 Agent 使用记录"

Agent color mapping: policy_expert=#1890ff, assessment_expert=#52c41a,
strategist=#722ed1, objection_handler=#eb2f96, case_analyst=#faad14,
memory_manager=#13c2c2

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 08:00:55 -08:00
hailin 16cc0e4c08 feat(agents): implement multi-agent collaboration architecture
借鉴 Claude Code 的架构模式,将单一 Agent 重构为 Coordinator + 6 Specialist 多 Agent 协作系统。

## 新增文件 (36个)

### 架构设计文档 (docs/architecture/, 12个)
- 00-overview.md ~ 11-prompt-templates.md: 完整架构设计,覆盖所有 Agent 的详细设计、
  Prompt 模板、协作流程、工具并发系统、动态上下文注入

### 多 Agent 系统 (infrastructure/agents/, 23个)
- coordinator/coordinator-agent.service.ts: 主协调器,替代 ClaudeAgentServiceV2
- coordinator/agent-loop.ts: 核心递归 async generator 循环(参考 Claude Code aM())
- coordinator/context-injector.service.ts: 动态上下文注入(8种上下文类型按优先级注入)
- specialists/base-specialist.service.ts: Agent 基类(封装 Claude API 调用 + prompt 缓存)
- specialists/policy-expert.service.ts: 政策专家 (Sonnet 4, temp=0)
- specialists/assessment-expert.service.ts: 评估专家 (Sonnet 4, temp=0)
- specialists/strategist.service.ts: 策略顾问 (Sonnet 4, temp=0.3)
- specialists/objection-handler.service.ts: 异议处理 (Sonnet 4, temp=0.2)
- specialists/case-analyst.service.ts: 案例分析 (Haiku, temp=0)
- specialists/memory-manager.service.ts: 记忆管理 (Haiku, temp=0)
- prompts/coordinator-system-prompt.ts: 协调器 Prompt(1095行,13章)
- prompts/{policy,assessment,strategist,objection,case,memory}-*-prompt.ts: 各专家 Prompt
- tools/coordinator-tools.ts: 16个工具定义(6 Agent 调用 + 10 直接工具)
- tools/tool-execution-queue.ts: 并发执行队列(isConcurrencySafe 控制并行/串行)
- types/agent.types.ts: Agent 配置、输入/输出类型定义
- types/stream.types.ts: 流式事件类型(含 agent_start/complete/coordinator_thinking)
- types/context.types.ts: 上下文注入类型
- agents.module.ts: NestJS 模块注册

### 前端 Agent 状态展示 (1个)
- AgentStatusIndicator.tsx: 多 Agent 工作状态组件(含动画)

## 修改文件 (15个)

### 后端集成
- conversation.service.ts: 切换到 CoordinatorAgentService
- conversation.gateway.ts: 新增 agent_start/agent_complete/coordinator_thinking 事件
- claude.module.ts: 引入 AgentsModule
- agents.module.ts: 注册 ImmigrationToolsService(复用旧版生产测试的工具实现)
- knowledge-client.service.ts: 新增 search()/getUserContext() 便捷方法

### 旧代码标记 @deprecated
- claude-agent.service.ts, claude-agent-v2.service.ts
- strategy-engine.service.ts, intent-classifier.ts, response-gate.ts

### 前端适配
- chatStore.ts: 新增 ActiveAgent/CompletedAgent/CoordinatorPhase 状态
- useChat.ts: 新增 WebSocket 事件处理
- ChatWindow.tsx: 集成 AgentStatusIndicator
- globals.css: 新增 agentPulse/agentSlideIn 动画

### 共享类型
- conversation.types.ts: 新增 AGENT_START/AGENT_COMPLETE/COORDINATOR_THINKING 事件

## 核心设计决策

1. **新旧结合**: Coordinator 的 10 个直接工具委托给旧版 ImmigrationToolsService
   (经过生产测试的 Google Search、汇率 API、新闻 API 等),6 个 Agent 调用工具
   走新的 Specialist Agent 系统
2. **递归 async generator**: agent-loop 支持流式输出 + 工具递归 + 成本/轮次控制
3. **并行 Agent 执行**: ToolExecutionQueue 根据 isConcurrencySafe 自动并行/串行
4. **Prompt 缓存**: 所有 Agent 的 system prompt 使用 cache_control: ephemeral
5. **速率限制重试**: 429/529 指数退避,最多 2 次
6. **向后兼容**: LegacyConversationContext 类型别名,StreamChunk 扩展不破坏现有结构

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 04:26:39 -08:00
hailin 7f03a4d870 fix(admin-client): add x-admin-id header for super admin API requests
- Add x-admin-id header to API interceptor from auth store
- Required for super admin tenant management APIs

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-26 08:53:40 -08:00
hailin dcff831e7d fix(analytics): handle statDate as string from database
- Fix toDto method to handle statDate being string or Date
- Fix getTrendData method to handle statDate being string or Date
- PostgreSQL date type returns string, not Date object

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-26 08:40:09 -08:00
hailin 2df8478d61 fix(evolution): handle super admin login without tenant context
- Update AdminPostgresRepository.findByUsername to support super admin
- Add fallback to find super admin by username and isSuperAdmin flag
- Add is_super_admin column to admins table

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-26 08:20:26 -08:00
hailin 0d2e521d69 fix(nginx): fix admin location try_files path and add multi-tenancy migrations
- Fix nginx admin location try_files to use relative path for alias directive
- Add database migrations for multi-tenancy support in user-service
- Add tenant_id column to users, user_profiles, user_contacts, verification_codes tables
- Create migration rollback scripts and documentation

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-26 07:46:52 -08:00
hailin 481c13b67d feat(admin-client): add tenant management page
- Add tenants feature module with Clean Architecture structure
- Create tenantsApi for super admin endpoints
- Add React Query hooks for tenant CRUD operations
- Implement TenantsPage with statistics, list, and modals
- Add tenant route and sidebar menu item
- Support create/edit tenant, suspend/activate, admin management

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 07:03:14 -08:00
hailin e1e9ba1a77 feat(multi-tenant): add super admin module and user profile pages
- Add SuperAdmin module for tenant management (CRUD, suspend/activate)
- Add tenant management REST API (/super-admin/tenants/*)
- Add user profile menu in ChatSidebar with dropdown
- Add ProfilePage and BindPhonePage for user account management
- Update init-db.sql with tenant_id columns for all 16 tables
- Add database seed script (scripts/seed.ts) with ts-node
- Integrate db:seed into deploy.sh rebuild command

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 06:41:11 -08:00
hailin 1ac183fc0c fix(tenant): simplify evolution-service tenant configuration
- Use SimpleTenantFinder for evolution-service middleware (same as other services)
- Keep TenantFinderService available via TenantModule for super-admin
- Add useExternalFinder option to TenantContextModule
- Remove @Global() decorator from TenantContextModule class

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 05:40:39 -08:00
hailin 7ff701369b fix(tenant): use TenantContextModule.forRoot() for global tenant context
All services were providing TenantContextService directly without
making it global, causing DI resolution failures in child modules.
Now using TenantContextModule.forRoot() which exports TenantContextService
globally so all repositories can access it.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 04:31:56 -08:00
hailin 89d9645c02 fix(docker): fix vips package for Alpine 3.23 in file-service
Alpine 3.23 doesn't have vips-dev, use vips runtime instead.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 03:47:56 -08:00
hailin 6bb47dad85 fix(docker): copy shared module AFTER npm install to prevent wipe
npm install was clearing the @iconsulting/shared folder that was
copied before it. Moving the COPY command after npm install ensures
the shared package remains in node_modules.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 03:41:16 -08:00
hailin 7975982fc3 feat(user): add user profile and contact management
- Add UserProfile entity with immigration-specific fields:
  - Basic info (name, birth date, nationality, current location)
  - Immigration intent (target countries, types, timeline)
  - Education records with WES evaluation flag
  - Work records with NOC codes
  - Language scores (IELTS, TOEFL, etc.)
  - Family members info
  - Financial info for investment immigration
  - Profile completion percentage calculation

- Add UserContact entity for identity binding:
  - Support multiple contact types (EMAIL, WECHAT, WHATSAPP, TELEGRAM, LINE)
  - Verification code flow with expiration
  - Notification settings (paid feature)
  - Notification types: POLICY_UPDATE, DEADLINE_REMINDER, etc.

- Add API endpoints:
  - GET/PUT /users/me/profile/* for profile sections
  - GET/POST/PUT/DELETE /users/me/contacts for contact management
  - POST /users/me/contacts/:type/verification for verification flow
  - POST/PUT/DELETE /users/me/contacts/:type/notifications

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 19:32:17 -08:00
hailin 92ee490a57 feat(multi-tenant): complete repository tenant filtering for remaining services
- knowledge-postgres.repository: add tenant_id to all queries and raw SQL
- memory-postgres.repository: add tenant_id filtering for UserMemory and SystemExperience
- admin-postgres.repository: add tenant_id filtering (direct injection for nullable tenantId)
- All 11 repositories now have proper tenant isolation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 19:12:04 -08:00
hailin 1df5854825 feat(multi-tenant): apply tenant middleware and refactor repositories
- Apply TenantContextMiddleware to all 6 services
- Add SimpleTenantFinder for services without direct tenant DB access
- Add TenantFinderService for evolution-service with database access
- Refactor 8 repositories to extend BaseTenantRepository:
  - user-postgres.repository.ts
  - verification-code-postgres.repository.ts
  - conversation-postgres.repository.ts
  - message-postgres.repository.ts
  - token-usage-postgres.repository.ts
  - file-postgres.repository.ts
  - order-postgres.repository.ts
  - payment-postgres.repository.ts
- Add @iconsulting/shared dependency to evolution-service and knowledge-service
- Configure middleware to exclude health and super-admin paths

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 18:30:31 -08:00
hailin 422069be68 feat: add enterprise multi-tenancy infrastructure
- Add shared tenant module with AsyncLocalStorage-based context management
- Create TenantContextService, TenantContextMiddleware, TenantGuard
- Add @TenantId(), @Tenant(), @RequireFeatures() decorators
- Create BaseTenantRepository for automatic tenant filtering
- Add TenantORM entity for tenants table
- Add tenant_id column to all 16 ORM entities across 6 services
- Create database migration script for multi-tenancy support
- Add tenant-related error codes

This implements row-level isolation for 100% data separation between tenants.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 18:11:12 -08:00
hailin 2d4e6285a4 feat(admin): add global token usage statistics
- Add token aggregation to statistics/overview endpoint
- Include total tokens, cost, and API calls for all time
- Include today's token usage and cost breakdown
- Display token stats in ConversationsPage with 2 rows of cards
- Add formatNumber helper for K/M number formatting
- Export GlobalTokenStats and TodayTokenStats types

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 17:29:59 -08:00
hailin 7acdf78e0c fix(conversation): improve token tracking accuracy
- Add 'error' chunk type to StreamChunk for partial token capture
- Record partial tokens to token_usage table even on API errors
- Capture error chunk tokens in conversation.service.ts
- Save partial response and tokens before re-throwing errors
- Add token aggregation from token_usage table for accurate stats
- Display detailed token info in admin (cache tokens, cost, API calls)
- Export TokenDetails type for frontend consumption

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 17:23:25 -08:00
hailin ae99b78579 fix(conversation): track token usage and message count in conversation entity
Problem:
- Token usage was recorded to token_usage table but not to conversation entity
- Message count was not being incremented
- Dashboard showed 0 tokens for all conversations

Solution:
- Add inputTokens/outputTokens fields to StreamChunk interface
- Return token usage in 'end' chunk from ClaudeAgentServiceV2
- Capture token usage in conversation.service.ts sendMessage
- Call conversation.addTokens() and incrementMessageCount() after each exchange
- Consolidate conversation updates into single repo.update() call

Files changed:
- claude-agent-v2.service.ts: Add token fields to StreamChunk, return in 'end'
- conversation.service.ts: Track tokens and message counts properly

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 17:08:23 -08:00
hailin 931055b51f feat(admin): add conversation management with device tracking display
## Backend (conversation-service)
- Add AdminConversationController with JWT auth for admin API
- Endpoints: list conversations, by user, detail, messages, statistics
- Support filtering by status, userId, date range, conversion
- Add JWT_SECRET environment variable to docker-compose.yml
- Add jsonwebtoken dependency for admin token verification

## Frontend (admin-client)
### New Features:
- Add conversations feature module with:
  - API layer (conversations.api.ts)
  - React Query hooks (useConversations.ts)
  - ConversationsPage with full management UI

### User Management Enhancement:
- Add "最近咨询记录" section in user detail drawer
- Display device info for each conversation:
  - IP address with region
  - User-Agent (parsed to browser/OS)
  - Device fingerprint
- Show conversation status, conversion status, message count

### Navigation:
- Add "对话管理" menu item with MessageOutlined icon
- Add /conversations route

## Files Added:
- admin-conversation.controller.ts (backend admin API)
- conversations feature folder (frontend)
  - infrastructure/conversations.api.ts
  - application/useConversations.ts
  - presentation/pages/ConversationsPage.tsx

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 10:04:17 -08:00
hailin 6a3a2130bf feat(conversation): add device tracking and optimize admin-client build
## Device Tracking (conversation-service)
- Add DeviceInfoDto class for validating device information
- Extract client IP from X-Forwarded-For and X-Real-IP headers
- Capture User-Agent header automatically on conversation creation
- Support optional fingerprint and region from client
- Pass deviceInfo through service layer to entity for persistence

Files changed:
- conversation.controller.ts: Add extractClientIp() method and header capture
- conversation.dto.ts: Add DeviceInfoDto with validation decorators
- conversation.service.ts: Update CreateConversationParams interface

## Build Optimization (admin-client)
- Implement code splitting via Rollup manualChunks
- Separate vendor libraries into cacheable chunks:
  - vendor-react: react, react-dom, react-router-dom (160KB)
  - vendor-antd: antd, @ant-design/icons (1013KB)
  - vendor-charts: recharts (409KB)
  - vendor-data: @tanstack/react-query, axios, zustand (82KB)
- Main bundle reduced from 1732KB to 61KB (96% reduction)
- Set chunkSizeWarningLimit to 1100KB for antd

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 09:45:47 -08:00
hailin 3be42c8224 fix(user-service): add jsonwebtoken dependency for admin auth
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 09:02:30 -08:00
hailin e0c2462017 feat(admin): add user management and system settings pages
Backend (user-service):
- Add admin user management APIs (list, search, statistics, detail)
- Add pagination and filtering support for user queries
- Add JWT token authentication for admin endpoints

Frontend (admin-client):
- Add UsersPage with user list, search, filters and statistics
- Add SettingsPage with admin profile, password change, system info
- Update App.tsx routes to use new pages

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 08:58:35 -08:00
hailin ed5dc49b4a fix(audit): reorder routes to fix NestJS route collision
Move specific routes (logs/actions, logs/entity-types) before
parameterized route (logs/:id) to prevent NestJS from matching
'actions' and 'entity-types' as UUID parameters.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 08:40:56 -08:00
hailin f95bc71254 fix(dashboard): remove failing evolution/health API calls
The useEvolutionStatistics and useSystemHealth hooks call endpoints that
depend on a non-existent knowledge-service internal API. Removed these
calls and the related UI sections to prevent 500 errors.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 08:33:08 -08:00
hailin ccb0648f6c fix(evolution): correct knowledge-service port from 3005 to 3003
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 08:24:57 -08:00
hailin 042d2e1456 feat(analytics): implement statistics, financial reports, and audit logging
Backend (evolution-service):
- Add analytics module with scheduled statistics aggregation
- Implement daily_statistics aggregation (OVERALL, CHANNEL, CATEGORY)
- Add monthly financial report generation and management
- Create audit log service for operation tracking
- Schedule cron jobs for automatic data aggregation

Frontend (admin-client):
- Replace dashboard mock data with real API calls
- Add analytics page with trend charts and dimension breakdown
- Add financial reports page with confirm/lock workflow
- Add audit logs page with filtering and detail view
- Update navigation with analytics submenu

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 08:01:39 -08:00
hailin 65c0bdd17c feat(payment): add transaction reliability and idempotency support
- Add TransactionService for atomic database operations with optimistic lock retry
- Implement pessimistic locking in payment callback handling to prevent race conditions
- Add idempotency check via transactionId unique index to prevent duplicate processing
- Add version columns to PaymentORM and OrderORM for optimistic locking
- Add composite indexes for performance (order_status, transaction_id)
- Optimize connection pool settings for both payment and conversation services
- Update init-db.sql with version columns and new indexes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 07:00:01 -08:00
hailin fe37267c39 fix(orm): add explicit PostgreSQL column types for all ORM entities
- user-service: user.orm.ts (lastActiveAt), verification-code.orm.ts (all fields)
- file-service: file.orm.ts (userId, originalName, storagePath, mimeType)
- conversation-service: token-usage.orm.ts (model, all token/count fields)
- knowledge-service: knowledge-article.orm.ts, knowledge-chunk.orm.ts,
  system-experience.orm.ts, user-memory.orm.ts (all numeric, boolean, date fields)

This fixes DataTypeNotSupportedError where PostgreSQL rejects "Object" type
when @Column decorator lacks explicit type specification.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 02:14:07 -08:00
hailin a1f4f7ba0e fix(orm): add explicit types for all ConversationORM and MessageORM fields
Complete fix for all @Column decorators missing explicit type:

## ConversationORM
- status: varchar(20)
- category: varchar(50)
- messageCount: int
- userMessageCount: int
- assistantMessageCount: int
- totalInputTokens: int
- totalOutputTokens: int
- hasConverted: boolean
- consultingStage: varchar(30)
- conversionPath: varchar(30)

## MessageORM
- role: varchar(20)
- type: varchar(30)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 02:09:04 -08:00
hailin 7c22c173a5 fix(orm): add explicit column types for conversation and order entities
Fixed remaining TypeORM DataTypeNotSupportedError for "Object" type.

## conversation-service/ConversationORM
- title: varchar(255)
- endedAt: timestamptz

## payment-service/OrderORM
- serviceCategory: varchar(100)
- currency: varchar(10)
- paymentMethod: varchar(50)
- paidAt: timestamptz
- completedAt: timestamptz

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 01:57:20 -08:00
hailin eb1cb9c496 fix(orm): add explicit PostgreSQL column types for nullable fields
Fixed TypeORM DataTypeNotSupportedError for "Object" type in PostgreSQL.

## Issues Fixed

1. **user-service/UserORM**
   - fingerprint: varchar(255)
   - phone: varchar(20)
   - nickname: varchar(100)
   - avatar: varchar(500)

2. **payment-service/PaymentORM**
   - transactionId: varchar(255)
   - currency: varchar(10)
   - expiresAt: timestamptz
   - paidAt: timestamptz

3. **conversation-service/MessageORM**
   - inputTokens: int
   - outputTokens: int

## Root Cause
@Column({ nullable: true }) without explicit `type` defaults to Object,
which PostgreSQL doesn't support.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 22:50:54 -08:00
hailin afd707d15f refactor(services): implement 4-layer Clean Architecture for all backend services
Refactored all 6 backend services to 4-layer Clean Architecture pattern
following knowledge-service as reference implementation.

## Architecture Pattern (4-Layer)

```
src/
├── domain/              # Pure business entities and interfaces
│   ├── entities/        # Domain entities (no ORM decorators)
│   ├── repositories/    # Repository interfaces + Symbol tokens
│   └── value-objects/   # Enums and value types
├── application/
│   ├── dtos/            # Data transfer objects
│   └── services/        # Application services (use case orchestration)
├── adapters/
│   ├── inbound/         # Controllers, gateways (API endpoints)
│   └── outbound/
│       ├── persistence/ # Repository implementations
│       ├── clients/     # External service clients
│       └── storage/     # File storage adapters
└── infrastructure/
    └── database/postgres/
        └── entities/    # ORM entities with decorators
```

## Services Refactored

### user-service
- adapters/inbound: AuthController, UserController
- adapters/outbound/persistence: UserPostgresRepository, VerificationCodePostgresRepository
- application/services: AuthService, UserService
- application/dtos: AuthDto, UserDto

### payment-service
- adapters/inbound: OrderController, PaymentController
- adapters/outbound/persistence: OrderPostgresRepository, PaymentPostgresRepository
- adapters/outbound/payment-methods: AlipayAdapter, WechatPayAdapter, StripeAdapter
- application/services: OrderService, PaymentService
- application/dtos: OrderDto, PaymentDto

### file-service
- adapters/inbound: FileController
- adapters/outbound/persistence: FilePostgresRepository
- adapters/outbound/storage: MinioStorageAdapter
- application/services: FileService
- application/dtos: UploadFileDto

### conversation-service
- adapters/inbound: ConversationController, InternalController, ConversationGateway
- adapters/outbound/persistence: ConversationPostgresRepository, MessagePostgresRepository, TokenUsagePostgresRepository
- application/services: ConversationService
- application/dtos: ConversationDto

### knowledge-service
- adapters/inbound: KnowledgeController, MemoryController, InternalMemoryController
- adapters/outbound/persistence: KnowledgePostgresRepository, MemoryPostgresRepository
- application/services: KnowledgeService, MemoryService
- application/dtos: KnowledgeDto, MemoryDto

### evolution-service
- domain/entities: AdminEntity
- domain/repositories: IAdminRepository (Symbol-based DI)
- domain/value-objects: AdminRole enum
- adapters/inbound: AdminController, EvolutionController
- adapters/outbound/persistence: AdminPostgresRepository
- adapters/outbound/clients: ConversationClient, KnowledgeClient
- application/services: AdminService, EvolutionService
- application/dtos: AdminDto, EvolutionDto
- infrastructure/database/postgres/entities: AdminORM

## Key Improvements
- Symbol-based dependency injection for repository interfaces
- ORM entities separated from domain entities
- Consistent 4-layer structure across all services
- DTOs for API contracts
- Clear separation: domain logic vs infrastructure concerns

## Configuration
- Updated turbo.json: renamed "pipeline" to "tasks" for Turbo 2.0+

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 22:18:22 -08:00
hailin 9e1dca25f2 refactor(admin-client): implement 3-layer Clean Architecture for frontend
Refactored admin-client from 1.5-layer to 3-layer architecture using
Feature-Sliced Design pattern with Zustand + TanStack Query.

## Architecture Pattern

Each feature now follows 3-layer structure:
```
features/{feature}/
├── presentation/   # React UI components, pages
├── application/    # Zustand stores, TanStack Query hooks
└── infrastructure/ # API clients (axios calls)
```

## Changes by Feature

### Auth Feature
- infrastructure/auth.api.ts: Login, verify API calls
- application/useAuthStore.ts: Zustand store for auth state
- Updated LoginPage.tsx to use useAuthStore
- shared/hooks/useAuth.ts: Re-exports for backward compatibility

### Knowledge Feature
- infrastructure/knowledge.api.ts: Article CRUD APIs
- application/useKnowledge.ts: TanStack Query hooks
  - useKnowledgeArticles, useCreateArticle, useUpdateArticle
  - useDeleteArticle, usePublishArticle, useUnpublishArticle
- Updated KnowledgePage.tsx to use application hooks

### Experience Feature
- infrastructure/experience.api.ts: Experience management APIs
- application/useExperience.ts: TanStack Query hooks
  - usePendingExperiences, useExperienceStatistics
  - useApproveExperience, useRejectExperience, useRunEvolution
- Updated ExperiencePage.tsx to use application hooks

### Dashboard Feature
- infrastructure/dashboard.api.ts: Statistics APIs
- application/useDashboard.ts: TanStack Query hooks
  - useEvolutionStatistics, useSystemHealth
- Updated DashboardPage.tsx to use application hooks

## Benefits
- Clear separation of concerns (UI / business logic / data access)
- Better testability (each layer can be tested independently)
- Reusable hooks across components
- Type-safe API interfaces
- Centralized API error handling

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 22:17:48 -08:00
hailin 02954f56db refactor(services): implement Clean Architecture across 4 services
## Overview
Refactor user-service, payment-service, file-service, and conversation-service
to follow Clean Architecture pattern based on knowledge-service reference.

## Architecture Pattern Applied

```
src/
├── domain/
│   ├── entities/           # Pure domain entities (no ORM decorators)
│   └── repositories/       # Repository interfaces + Symbol DI tokens
├── infrastructure/
│   └── database/postgres/
│       ├── entities/       # ORM entities with TypeORM decorators
│       └── *-postgres.repository.ts  # Repository implementations
└── {feature}/
    └── {feature}.module.ts # DI configuration with Symbol providers
```

## Changes by Service

### user-service (40% → 100% compliant)
- Created: IUserRepository, IVerificationCodeRepository interfaces
- Created: UserORM, VerificationCodeORM entities
- Created: UserPostgresRepository, VerificationCodePostgresRepository
- Modified: UserEntity, VerificationCodeEntity → pure domain with factory methods
- Updated: user.module.ts, auth.module.ts with Symbol-based DI

### payment-service (50% → 100% compliant)
- Created: IOrderRepository, IPaymentRepository interfaces
- Created: OrderORM, PaymentORM entities
- Created: OrderPostgresRepository, PaymentPostgresRepository
- Modified: OrderEntity, PaymentEntity → pure domain with factory methods
- Updated: order.module.ts, payment.module.ts with Symbol-based DI

### file-service (40% → 100% compliant)
- Created: IFileRepository interface
- Created: FileORM entity
- Created: FilePostgresRepository
- Modified: FileEntity → pure domain with factory methods
- Updated: file.module.ts with Symbol-based DI

### conversation-service (60% → 100% compliant)
- Created: IConversationRepository, IMessageRepository, ITokenUsageRepository
- Created: ConversationORM, MessageORM, TokenUsageORM entities
- Created: ConversationPostgresRepository, MessagePostgresRepository,
          TokenUsagePostgresRepository
- Modified: ConversationEntity, MessageEntity, TokenUsageEntity → pure domain
- Updated: conversation.module.ts with Symbol-based DI
- Updated: app.module.ts, data-source.ts entity patterns

## Key Implementation Details

1. **Symbol-based DI Pattern**:
   ```typescript
   export const USER_REPOSITORY = Symbol('IUserRepository');

   @Module({
     providers: [{ provide: USER_REPOSITORY, useClass: UserPostgresRepository }],
     exports: [UserService, USER_REPOSITORY],
   })
   ```

2. **Pure Domain Entities**: Factory methods `create()` and `fromPersistence()`
   for controlled instantiation without ORM decorators

3. **Repository Implementations**: Include `toORM()` and `toEntity()` conversion
   methods for anti-corruption layer between domain and infrastructure

4. **Entity Discovery**: Changed glob pattern from `*.entity` to `*.orm`
   in app.module.ts and data-source.ts files

## Breaking Changes
- None for API consumers
- Internal architecture restructuring only

## Testing
- All 4 services compile successfully with `pnpm build`
- Database schema compatibility verified (column mappings preserved)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 21:18:25 -08:00
hailin 3b6d178ef7 fix(evolution): add proper TypeScript types for API clients
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 20:22:42 -08:00
hailin c2b4fe19cc refactor(evolution): use knowledge-service API for system_experiences
Follow proper microservices architecture:
- knowledge-service owns system_experiences table
- evolution-service uses KnowledgeClient API to save experiences
- Deleted SystemExperienceORM from evolution-service
- Added internal API endpoints in knowledge-service
- Disabled synchronize in all services for safety

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 20:20:30 -08:00
hailin e1bcd0145e refactor(evolution): use API instead of shared database tables
Breaking change: evolution-service no longer directly accesses
conversations and messages tables.

Changes:
- Add internal API endpoints to conversation-service for service-to-service calls
- Create ConversationClient in evolution-service to call conversation-service API
- Remove ConversationORM and MessageORM from evolution-service
- Update evolution.service to use ConversationClient

This follows microservices best practices:
- Each service owns its data
- Services communicate via API, not shared tables

TODO: Apply same pattern to system_experiences (knowledge-service)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 19:48:09 -08:00
hailin 2c1edc26af fix(conversation): disable synchronize in production
Use init-db.sql for schema management instead of TypeORM auto-sync.
synchronize:true is dangerous in production and causes conflicts
when multiple services share tables.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 19:41:44 -08:00