fengling-console/OpenCode.md

11 KiB
Raw Blame History

# Fengling Project Rewrite - Conversation Summary ## Project Information Project Name: Fengling (风灵) - QR Code Marketing Management Platform Rewrite Project Locations: - Old Project: /Users/movingsam/Fengling.Refactory/ - Fengling.Backend.Web/ - Old monolithic backend - Yarp.Gateway/ - Old gateway (no longer relevant for reference)
- New Project: /Users/movingsam/Fengling.Refactory.Buiding/ - src/YarpGateway/ - New independent gateway service - src/YarpGateway.Admin/ - Vue3 admin UI ## What We Did ### Phase 1: Initial Gateway Setup 1. Created YARP Gateway backend with: - YARP 2.2.0 (reverse proxy framework) - EF Core 9.0.0 + PostgreSQL (192.168.100.10:5432) - StackExchange.Redis (192.168.100.10:6379) for distributed locks - Serilog for logging 2. Created Vue3 Admin frontend with: - Vue 3 + TypeScript + Vite + Element Plus + Pinia - Running on http://localhost:5173 ### Phase 2: Core Architecture Implementation #### 1. Route Priority Design (99% Global + 1% Tenant-Specific) User's requirement: > "普通情况租户走特定的实例pod只是特殊场景所以是要对 前缀匹配到不同的服务这块的ui呢" Implementation: - Added IsGlobal boolean field to GwTenantRoute table - Route priority: Tenant-specific routes > Global routes - Database migration: 20260201133826_AddIsGlobalToTenantRoute Benefit: - Before: 100 tenants × 10 services = 1000 route configurations - After: 10 global routes + few tenant-specific routes #### 2. In-Memory Route Caching File: src/YarpGateway/Services/RouteCache.cs - Loads routes from database at startup - Priority-based lookup: tenant route → global route → 404 - Hot reload support via ReloadAsync() - Avoids database queries per request #### 3. Redis Distributed Load Balancing File: src/YarpGateway/LoadBalancing/DistributedWeightedRoundRobinPolicy.cs - Implements weighted round-robin algorithm - Uses Redis for distributed locks: lock:{instanceName}:{clusterId} - Stores load balancing state in Redis: lb:{instanceName}:{clusterId}:state - Supports multiple gateway instances #### 4. Dynamic Proxy Configuration File: src/YarpGateway/DynamicProxy/DynamicProxyConfigProvider.cs - Implements IProxyConfigProvider - Loads routes and clusters from database - Provides configuration to YARP #### 5. Tenant Routing Middleware File: src/YarpGateway/Middleware/TenantRoutingMiddleware.cs - Extracts tenant ID from JWT headers (X-Tenant-Id) - Uses RouteCache to get route cluster - Sets context.Items["DynamicClusterId"] for YARP ### Phase 3: Frontend Development Created Vue3 admin pages: 1. Dashboard.vue - Statistics dashboard 2. TenantList.vue - Tenant management 3. TenantRoutes.vue - Tenant-specific routes 4. GlobalRoutes.vue - Global routes management (NEW) 5. ClusterInstances.vue - Service instance management ### Phase 4: Bug Fixes 1. Fixed 4K screen width constraints (removed max-width, added 100% width/height) 2. Fixed route /tenants not displaying until page refresh 3. Fixed CORS configuration (allowed origins: localhost:5173, 127.0.0.1:5173) 4. Fixed multiple compilation errors in DistributedWeightedRoundRobinPolicy.cs: - Missing using statements - JsonSerializer ambiguity (used full namespace) - HashCode.Combine signature errors - Typo: M.achineNameMachineName - Changed await using var to using var ### Phase 5: Database Configuration Applied database migration: bash dotnet ef database update ## Current Status ### Completed 1. Backend compiles successfully 2. Frontend runs on http://localhost:5173 3. Database migrations applied 4. Global routes management UI created 5. Redis distributed load balancing implemented 6. In-memory route caching implemented ### ⚠️ Known Issue: YARP Dynamic Routing Problem: - Accessing /api/product/test returns 404 - Logs show: "Request reached end of middleware pipeline" - DynamicProxyConfigProvider is registered but not being used by YARP User's comment: > "你等下 下游的应用还没建立 肯定404吧" > "你先把网关的ui更新一下功能呀。这个你先别急着测试吧" Conclusion: The 404 is expected because downstream microservices don't exist yet. User wants to focus on UI updates and move to microservices analysis. ## Database Schema ### Tables #### Tenants sql Id: bigint (PK) TenantCode: varchar(50) (unique) TenantName: varchar(100) Status: int (1=enabled, 0=disabled) IsDeleted: boolean CreatedTime, UpdatedTime, Version #### TenantRoutes sql Id: bigint (PK) TenantCode: varchar(50) (empty string = global route) ServiceName: varchar(100) ClusterId: varchar(100) PathPattern: varchar(200) Priority: int (0=global, 10=tenant) Status: int IsGlobal: boolean (NEW) IsDeleted: boolean CreatedTime, UpdatedTime, Version #### ServiceInstances sql Id: bigint (PK) ClusterId: varchar(100) DestinationId: varchar(100) Address: varchar(200) Health: int (1=healthy) Weight: int Status: int IsDeleted: boolean CreatedTime, UpdatedTime, Version ## Configuration ### Backend (appsettings.json) json { "ConnectionStrings": { "DefaultConnection": "Host=192.168.100.10;Port=5432;Database=fengling_gateway;Username=movingsam;Password=sl52788542" }, "Redis": { "ConnectionString": "192.168.100.10:6379", "Database": 0, "InstanceName": "YarpGateway" }, "Cors": { "AllowedOrigins": ["http://localhost:5173", "http://127.0.0.1:5173", "http://localhost:5174"], "AllowAnyOrigin": false }, "ReverseProxy": { "Routes": {}, "Clusters": {} } } ### Ports - Frontend: http://localhost:5173 - Backend: http://0.0.0.0:8080 ## API Endpoints ### Tenant Management - GET /api/gateway/tenants - List tenants - POST /api/gateway/tenants - Create tenant - DELETE /api/gateway/tenants/{id} - Delete tenant ### Tenant Routes - GET /api/gateway/tenants/{tenantCode}/routes - List tenant routes - POST /api/gateway/tenants/{tenantCode}/routes - Create tenant route ### Global Routes - GET /api/gateway/routes/global - List global routes - POST /api/gateway/routes/global - Create global route - DELETE /api/gateway/routes/{id} - Delete route ### Cluster Instances - GET /api/gateway/clusters/{clusterId}/instances - List instances - POST /api/gateway/clusters/{clusterId}/instances - Add instance - DELETE /api/gateway/instances/{id} - Delete instance ### Configuration - POST /api/gateway/reload - Reload configuration ## File Structure /Users/movingsam/Fengling.Refactory.Buiding/src/ ├── YarpGateway/ │ ├── Config/ │ │ ├── DatabaseRouteConfigProvider.cs │ │ ├── DatabaseClusterConfigProvider.cs │ │ ├── JwtConfig.cs │ │ └── RedisConfig.cs │ ├── Controllers/ │ │ └── GatewayConfigController.cs │ ├── Data/ │ │ ├── GatewayDbContext.cs │ │ └── GatewayDbContextFactory.cs │ ├── DynamicProxy/ │ │ └── DynamicProxyConfigProvider.cs │ ├── LoadBalancing/ │ │ └── DistributedWeightedRoundRobinPolicy.cs │ ├── Middleware/ │ │ ├── JwtTransformMiddleware.cs │ │ └── TenantRoutingMiddleware.cs │ ├── Models/ │ │ ├── GwTenant.cs │ │ ├── GwTenantRoute.cs │ │ └── GwServiceInstance.cs │ ├── Services/ │ │ ├── RouteCache.cs │ │ └── RedisConnectionManager.cs │ ├── Migrations/ │ │ ├── 20260201120312_InitialCreate.cs │ │ └── 20260201133826_AddIsGlobalToTenantRoute.cs │ ├── sql/ │ │ └── init.sql │ ├── Program.cs │ └── appsettings.json │ └── YarpGateway.Admin/ ├── src/ │ ├── api/ │ │ └── index.ts │ ├── components/ │ │ └── Layout.vue │ ├── stores/ │ │ └── tenant.ts │ ├── views/ │ │ ├── Dashboard.vue │ │ ├── TenantList.vue │ │ ├── TenantRoutes.vue │ │ ├── GlobalRoutes.vue │ │ └── ClusterInstances.vue │ ├── router/ │ │ └── index.ts │ └── main.ts └── package.json ## What We're Doing Now The user wants to stop working on the gateway routing issue and instead focus on: 1. Updating the gateway UI functionality (COMPLETED - GlobalRoutes.vue added) 2. Analyzing the old backend for microservices split User's exact words: > "你先把网关的ui更新一下功能呀。这个你先别急着测试吧" > "我准备开始分析业务的微服务拆分了" ## Next Steps (For New Conversation) ### Immediate Priority: Microservices Analysis Task: Analyze the old backend (/Users/movingsam/Fengling.Refactory/Fengling.Backend.Web/) to determine how to split it into microservices Known Old Backend Structure: /Users/movingsam/Fengling.Refactory/Fengling.Backend.Web/src/src/ ├── account/ # Account module ├── activityplan/ # Activity planning ├── basis/ # Basic configuration ├── channel/ # Channel management ├── company/ # Company management ├── coupon/ # Coupon management ├── fieldConfig/ # Field configuration ├── flow/ # Workflow ├── gift/ # Gift management ├── integralConfig/ # Points configuration ├── member/ # Member management ├── promoter/ # Promoter management ├── qipei/ # Service matching ├── reports/ # Reports ├── riskManage/ # Risk management └── [many more modules...] ### Analysis Goals 1. Identify business domain boundaries 2. Determine which modules should become independent microservices 3. Design inter-service communication patterns 4. Plan database splitting strategy 5. Consider shared services (auth, configuration, etc.) ### Deferred Tasks (Lower Priority) 1. Fix YARP DynamicProxyConfigProvider to properly integrate with YARP 2. Test dynamic routing with actual downstream services 3. Complete deployment architecture (Docker, Kubernetes) ## Key Technical Decisions ### 1. Why Global Routes + Tenant-Specific Routes? Reason: 99% of tenants share the same services, only 1% need dedicated instances Benefit: Drastically reduces configuration complexity ### 2. Why YARP? - Microsoft official support - High performance (based on Kestrel) - Extensible (custom load balancing policies) - Dynamic configuration support ### 3. Why Redis? - Distributed locks for multi-instance scenarios - Persistent load balancing state - High performance (millisecond response) ## Important Notes for Continuation 1. Database Access: PostgreSQL at 192.168.100.10:5432, Database: fengling_gateway 2. Redis Access: 192.168.100.10:6379 3. Project Location: /Users/movingsam/Fengling.Refactory.Buiding/ 4. User Preference: Manually handles database migrations (user applies SQL manually) 5. Old Gateway: User confirmed the old gateway at /Users/movingsam/Fengling.Refactory/Yarp.Gateway/ is no longer relevant for reference