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>
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>
- 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>
- 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>
- 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>
- 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>
- 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>
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>
## 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>
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>
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>
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>
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>
- 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>
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>
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>
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>
- Add @Index decorators for conversation_id, created_at, role
- Set created_at to timestamptz type to match database
- Set columns nullable to match database schema
This prevents synchronize:true from trying to modify columns
that have dependent indexes.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add input_tokens and output_tokens columns that evolution-service
defines to prevent synchronize:true from trying to drop them.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add columns that evolution-service defines to prevent synchronize:true
from trying to drop them:
- userMessageCount, assistantMessageCount
- totalInputTokens, totalOutputTokens
- rating, feedback, hasConverted
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove migration-based approach which kept failing
- Enable synchronize:true to auto-sync Entity with database
- Schema will always match Entity definition on startup
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add migrations path to TypeORM config
- Set migrationsRun: true to run pending migrations on startup
- This ensures V2 columns are created automatically when app starts
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add data-source.prod.ts for compiled JS migrations
- Add migration:run:prod script to package.json
- Update deploy.sh to try prod migration first, fallback to dev
- Keep SQL fallback in full-reset as safety net with proper indexes
This ensures migrations work in Docker where ts-node may not be available.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Switch ConversationService to use ClaudeAgentServiceV2
- Pass consultingState and deviceInfo from conversation to context
- Handle state_update chunks and save updated state to database
- Move dotenv to dependencies for migration runtime
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add 8-stage consulting workflow (greeting → handoff)
- Create StrategyEngineService for state management and transitions
- Add ClaudeAgentServiceV2 with integrated strategy guidance
- Support old user recognition via get_user_context tool
- Add device info (IP, fingerprint) for new user icebreaking
- Extend ConversationEntity with consulting state fields
- Add database migration for new JSONB columns
Stages: greeting, needs_discovery, info_collection, assessment,
recommendation, objection_handling, conversion, handoff
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix Usage type cast by using unknown intermediate type
- Add PricingTier interface and proper Record type for PRICING
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add TokenUsageEntity to store per-request token consumption
- Add TokenUsageService with cost calculation and statistics APIs
- Record input/output/cache tokens per API call
- Calculate estimated cost based on Claude pricing
- Provide user/conversation/global stats aggregation
- Support daily stats and top users ranking
- Integrate token tracking in ClaudeAgentService
- Track latency, tool calls, response length
- Accumulate tokens across tool loop iterations
- Add token_usages table to init-db.sql with proper indexes
This enables:
- Per-user token consumption tracking
- Cost analysis and optimization
- Future billing/quota features
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Reduce tokensPerChar from 2 to 1.8 for more accurate Chinese token estimation
- Use min() instead of max() to enforce upper limits on token counts
- CHAT: max 200 tokens (was min 256)
- SIMPLE_QUERY: max 600 tokens (was min 512)
- CLARIFICATION: max 300 tokens (was min 256)
- CONFIRMATION: max 400 tokens (was min 384)
- DEEP_CONSULTATION: 800-1600 tokens (was 1024-4096)
- ACTION_NEEDED: 500-1000 tokens (was 768-2048)
This should result in more concise AI responses that better match
the intent classifier's suggested length limits.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
TypeORM doesn't natively support pgvector type. Add custom transformer
to convert between JavaScript arrays and pgvector string format [1,2,3].
Fixes: invalid input syntax for type vector errors
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add OPENAI_BASE_URL configuration to .env.example
- Update EmbeddingService to disable TLS verification for IP-based proxy URLs
- Mirror the same proxy handling pattern used in Anthropic API
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change MessageEntity.role from enum to VARCHAR(20)
- Change MessageEntity.type from enum to VARCHAR(30)
- Change ConversationEntity.status from enum to VARCHAR(20)
- Add nullable: true to userId to match database schema
- Add length constraints to match database schema
- Convert enums to const objects with type exports for type safety
This ensures TypeORM entities match the database schema exactly,
avoiding potential issues with enum type creation in production.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add missing 'type' column to MessageORM entity
- Add 'TEXT_WITH_ATTACHMENTS' to messages.type CHECK constraint
(matches MessageType enum in conversation-service)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The embedding column was declared as float[] but the database uses
VECTOR(1536) from pgvector. TypeORM doesn't natively support pgvector
types, causing 500 errors when querying the system_experiences table.
Fixed by:
- Changed column type to 'text' with select: false
- This prevents TypeORM from trying to select/map the vector column
- The embedding field is only used for similarity searches via raw SQL
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add the following real-time tools to ImmigrationToolsService:
- get_current_datetime: Get current date/time with timezone support
- web_search: Search internet for latest immigration news/policies (Google CSE)
- get_exchange_rate: Query real-time currency exchange rates (for investment immigration)
- fetch_immigration_news: Fetch latest immigration announcements
All tools include graceful degradation with fallback responses when external APIs are unavailable.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>