fengling-console/OpenCode.md

288 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
# 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.achineName``MachineName`
- 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
---