Project.Fengling.QoderVersion/docs/backend/后端功能概览.md
sam 056eb9b6f9 feat: 实现完整的前后端功能
- 后端新增管理员、商品、分类聚合模型
- 实现积分规则、礼品、订单、会员等完整功能
- 添加管理员认证和权限管理
- 完善数据库迁移和实体配置
- 前端管理后台实现登录、仪表盘、积分规则、礼品、订单、会员等页面
- 集成shadcn-vue UI组件库
- 添加前后端功能文档和截图
2026-02-11 21:36:37 +08:00

508 lines
18 KiB
Markdown
Raw Permalink 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.

## 后端功能概览
> 本文档说明当前后端(Backend)已完成的主要功能与技术实现,便于后续开发和前后端联调。
> 最后更新时间2026-02-11
---
## 一、整体技术栈与架构
### 1.1 技术栈
- **.NET 10** - 最新的 .NET 运行时
- **EF Core + SQLite** - 数据持久化(已从 PostgreSQL 迁移到 SQLite
- **CAP + NetCorePal** - 分布式事务与集成事件框架
- **FastEndpoints** - 高性能 API 端点框架
- **Hangfire** - 后台任务调度
- **Redis** - 分布式缓存与 CAP 消息存储
- **MediatR** - CQRS 模式实现
- **Swashbuckle/Swagger** - API 文档
### 1.2 架构风格
- **CleanDDD 分层结构**Domain / Infrastructure / Web
- **聚合根**:统一继承 `Entity<TId>, IAggregateRoot`
- **强类型 ID**:所有实体 ID 使用 `xxxId : IGuidStronglyTypedId`
- **领域事件 + 集成事件**:解耦跨聚合、跨事务操作
- **CQRS**:命令(Command)与查询(Query)分离,命令处理器操作仓储,查询直接访问 DbContext
- **最终一致性**:通过领域事件 → 集成事件 → 事件处理器实现
---
## 二、已完成的核心聚合与领域模型
### 2.1 会员聚合 (MemberAggregate)
- **实体**`Member`
- **核心字段**
- 手机号、密码(加密)、昵称
- 累计总积分 `TotalPoints`
- 可用积分 `AvailablePoints`
- 状态(正常/禁用)、注册时间
- **值对象**
- `MemberLevel`:等级编码、名称、所需积分、积分倍率
- **领域行为**
- `AddPoints(amount, source, reason, relatedId, expiryDate)` - 增加积分
- `ConsumePoints(amount, reason, orderId)` - 消费积分
- `RefundPoints(amount, reason, orderId)` - 退还积分
- **领域事件**
- `PointsAddedDomainEvent`
- `PointsConsumedDomainEvent`
- `PointsRefundedDomainEvent`
### 2.2 营销码聚合 (MarketingCodeAggregate)
- **实体**`MarketingCode`
- **核心字段**
- 营销码 `Code`(唯一)
- 批次号 `BatchNo`
- 是否已使用 `IsUsed`
- 使用者会员ID、使用时间
- 过期时间
- **值对象**
- `ProductInfo`产品ID、产品名称、品类ID、品类名称
- **领域行为**
- `Use(memberId)` - 使用营销码
- **领域事件**
- `MarketingCodeUsedDomainEvent`
### 2.3 积分规则聚合 (PointsRuleAggregate)
- **实体**`PointsRule`
- **核心字段**
- 规则名称、规则类型(产品/时间/会员等级)
- 积分值、奖励倍数
- 产品ID、品类ID、会员等级编码
- 生效时间范围(开始/结束)
- 是否激活
- **领域行为**
- `CalculatePoints(memberBonusRate)` - 计算应得积分
### 2.4 积分交易聚合 (PointsTransactionAggregate)
- **实体**`PointsTransaction`
- **核心字段**
- 会员ID、交易类型(获取/消费/退还/过期)
- 积分数量、来源、原因描述
- 关联ID(营销码ID/订单ID等)
- 过期时间(仅获取类型有效)
- 创建时间
- **静态工厂方法**
- `CreateEarnTransaction(...)` - 创建获取积分记录
- `CreateConsumeTransaction(...)` - 创建消费积分记录
- `CreateRefundTransaction(...)` - 创建退还积分记录
- `CreateExpireTransaction(...)` - 创建过期积分记录
- **说明**:通过集成事件异步创建,与会员聚合解耦
### 2.5 礼品聚合 (GiftAggregate)
- **实体**`Gift`
- **核心字段**
- 礼品名称、类型(实物/虚拟/自有产品)
- 描述、图片URL
- 所需积分、总库存、可用库存
- 每人限兑数量、是否上架、排序
- 创建/更新时间
- **领域行为**
- `Update(...)` - 更新礼品信息
- `AddStock(quantity)` - 增加库存
- `ReserveStock(quantity)` - 预留库存(下单时)
- `DeductStock(quantity)` - 扣减总库存(发货时)
- `ReleaseStock(quantity)` - 释放库存(订单取消时)
- `PutOnShelf()` / `PutOffShelf()` - 上架/下架
- **领域事件**
- `GiftCreatedDomainEvent`
- `GiftUpdatedDomainEvent`
- `GiftStockChangedDomainEvent`
### 2.6 兑换订单聚合 (RedemptionOrderAggregate)
- **实体**`RedemptionOrder`
- **核心字段**
- 订单号、会员ID、礼品ID/名称/类型
- 数量、消耗积分
- 物流单号、取消原因
- 状态(待处理/已发货/已送达/已完成/已取消)
- 创建/更新时间
- **值对象**
- `Address`:收货人姓名、电话、省市区、详细地址(实物礼品必填)
- **领域行为**
- `MarkAsDispatched(trackingNo)` - 标记为已发货
- `MarkAsDelivered()` - 标记为已送达
- `Complete()` - 完成订单
- `Cancel(reason)` - 取消订单
- **领域事件**
- `RedemptionOrderCreatedDomainEvent`
- `RedemptionOrderDispatchedDomainEvent`
- `RedemptionOrderDeliveredDomainEvent`
- `RedemptionOrderCompletedDomainEvent`
- `RedemptionOrderCancelledDomainEvent`
---
## 三、核心业务流程
### 3.1 会员注册与登录
#### 会员注册
- **端点**`POST /api/members/register`
- **请求**`RegisterMemberRequest { Phone, Password, Nickname? }`
- **命令**`RegisterMemberCommand`
- **流程**
1. 校验手机号唯一性
2. 密码加密存储
3. 创建会员并设置初始等级
4. 返回会员ID
#### 会员登录
- **端点**`POST /api/members/login`
- **请求**`LoginMemberRequest { Phone, Password }`
- **命令**`LoginMemberCommand`
- **流程**
1. 验证手机号和密码
2. 返回会员信息和 TokenTODO: 完善 JWT 认证)
### 3.2 扫码获取积分流程
#### 使用营销码
- **端点**`POST /api/marketing-codes/scan`
- **请求**`UseMarketingCodeRequest { Code, MemberId }`
- **命令**`UseMarketingCodeCommand`
#### 完整流程
```
1. UseMarketingCodeCommand
├─ 校验营销码存在且未使用
├─ 校验未过期
├─ 关联会员并标记为已使用
└─ 发布 MarketingCodeUsedDomainEvent
2. MarketingCodeUsedDomainEvent
└─ MarketingCodeUsedDomainEventHandlerForEarnPoints
├─ 加载会员聚合
├─ 匹配积分规则(IPointsRuleRepository.GetEffectiveRulesAsync)
├─ 计算应得积分和过期时间
├─ 调用 Member.AddPoints(...)
├─ 更新会员聚合
└─ 发布 PointsAddedDomainEvent
3. PointsAddedDomainEvent
└─ PointsAddedToPointsEarnedConverter (集成事件转换器)
└─ 发布 PointsEarnedIntegrationEvent
4. PointsEarnedIntegrationEvent
└─ PointsEarnedIntegrationEventHandler
├─ 幂等性检查(基于 RelatedId)
├─ 创建 PointsTransaction.CreateEarnTransaction(...)
└─ 保存到积分交易表
```
### 3.3 礼品兑换流程
#### 创建兑换订单
- **端点**`POST /api/gifts/redeem`
- **请求**`CreateRedemptionOrderCommand { MemberId, GiftId, Quantity, ShippingAddress? }`
#### 完整流程
```
1. CreateRedemptionOrderCommand
├─ 校验礼品存在且已上架
├─ 校验库存充足
├─ 校验限兑数量(IRedemptionOrderRepository.GetMemberRedemptionCountAsync)
├─ 校验会员积分充足
├─ 调用 Member.ConsumePoints(...) 扣减积分
├─ 更新会员聚合 → 发布 PointsConsumedDomainEvent
├─ 构造收货地址(实物礼品必填)
├─ 创建 RedemptionOrder 聚合
└─ 发布 RedemptionOrderCreatedDomainEvent
2. PointsConsumedDomainEvent
└─ PointsConsumedToPointsConsumedIntegrationEventConverter
└─ 发布 PointsConsumedIntegrationEvent
└─ 创建消费积分交易记录
3. RedemptionOrderCreatedDomainEvent
└─ RedemptionOrderCreatedDomainEventHandler
├─ 加载礼品聚合
├─ 调用 Gift.ReserveStock(quantity)
└─ 更新礼品聚合(预留库存)
```
#### 订单状态流转
```
订单发货: POST /api/admin/redemption-orders/{OrderId}/dispatch
├─ MarkOrderAsDispatchedCommand
├─ Order.MarkAsDispatched(trackingNo)
├─ 发布 RedemptionOrderDispatchedDomainEvent
└─ RedemptionOrderDispatchedDomainEventHandler
└─ Gift.DeductStock(quantity) 扣减总库存
订单取消: POST /api/admin/redemption-orders/{OrderId}/cancel
├─ CancelOrderCommand
├─ Order.Cancel(reason)
├─ 发布 RedemptionOrderCancelledDomainEvent
├─ RedemptionOrderCancelledDomainEventHandler
│ └─ Gift.ReleaseStock(quantity) 释放库存
└─ 退还积分(TODO: 待实现)
```
---
## 四、积分交易与集成事件架构
### 4.1 领域事件与集成事件流转
#### 领域事件 (Domain Events)
在会员聚合中发布,用于触发同一事务内或跨事务的业务逻辑:
- `PointsAddedDomainEvent` - 会员增加积分时
- `PointsConsumedDomainEvent` - 会员消费积分时
- `PointsRefundedDomainEvent` - 积分退还时
- `PointsExpiredDomainEvent` - 积分过期时
#### 集成事件 (Integration Events)
实现 `IIntegrationEvent` 接口,通过 CAP 框架发布和消费:
- `PointsEarnedIntegrationEvent` - 对应 Earn 交易
- `PointsConsumedIntegrationEvent` - 对应 Consume 交易
- `PointsRefundedIntegrationEvent` - 对应 Refund 交易
- `PointsExpiredIntegrationEvent` - 对应 Expire 交易
#### 集成事件转换器 (IIntegrationEventConverter)
将领域事件转换为集成事件:
- `PointsAddedToPointsEarnedConverter`
- `PointsConsumedToPointsConsumedIntegrationEventConverter`
- `PointsRefundedToPointsRefundedIntegrationEventConverter`
- `PointsExpiredToPointsExpiredIntegrationEventConverter`
### 4.2 集成事件处理器
位于 Web 层,通过 `ApplicationDbContext` 操作积分交易表:
```csharp
// 示例:处理获取积分集成事件
public class PointsEarnedIntegrationEventHandler : IIntegrationEventHandler<PointsEarnedIntegrationEvent>
{
public async Task Handle(PointsEarnedIntegrationEvent @event, CancellationToken cancellationToken)
{
// 1. 幂等性检查:基于 RelatedId 查询是否已存在
var exists = await dbContext.PointsTransactions
.AnyAsync(x => x.RelatedId == @event.RelatedId, cancellationToken);
if (exists) return; // 已处理过,跳过
// 2. 创建积分交易记录
var transaction = PointsTransaction.CreateEarnTransaction(
memberId: new MemberId(@event.MemberId),
amount: @event.Amount,
source: @event.Source,
reason: @event.Reason,
relatedId: @event.RelatedId,
expiryDate: @event.ExpiryDate
);
// 3. 保存到数据库
await dbContext.PointsTransactions.AddAsync(transaction, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
}
}
```
### 4.3 事务与一致性保证
#### 最终一致性
- **会员积分变更**(会员聚合)和 **积分交易记录**PointsTransaction 聚合)处于**不同事务**
- 通过 **领域事件 → 集成事件 → 事件处理器** 链路实现最终一致性
- CAP 框架保证集成事件至少一次送达
#### 幂等性保证
- 基于 `RelatedId`营销码ID、订单ID等进行幂等性检查
- 防止重复消费导致的数据不一致
---
## 五、API 端点一览
### 5.1 会员模块 (Members)
| 端点 | 方法 | 说明 | 认证 |
|------|------|------|------|
| `/api/members/register` | POST | 会员注册 | 匿名 |
| `/api/members/login` | POST | 会员登录 | 匿名 |
| `/api/members/{MemberId}` | GET | 获取会员信息 | 需要 |
### 5.2 营销码模块 (MarketingCodes)
| 端点 | 方法 | 说明 | 认证 |
|------|------|------|------|
| `/api/marketing-codes/scan` | POST | 扫码使用营销码 | 匿名 |
| `/api/admin/marketing-codes/generate` | POST | 批量生成营销码(管理端) | 需要 |
### 5.3 礼品模块 (Gifts)
#### 会员端
| 端点 | 方法 | 说明 | 认证 |
|------|------|------|------|
| `/api/gifts` | GET | 获取上架礼品列表 | 匿名 |
| `/api/gifts/{GiftId}` | GET | 获取礼品详情 | 匿名 |
| `/api/gifts/redeem` | POST | 兑换礼品 | 需要 |
#### 管理端
| 端点 | 方法 | 说明 | 认证 |
|------|------|------|------|
| `/api/admin/gifts` | POST | 创建礼品 | 需要 |
| `/api/admin/gifts/{GiftId}` | PUT | 更新礼品信息 | 需要 |
| `/api/admin/gifts/{GiftId}/putonshelf` | POST | 上架礼品 | 需要 |
| `/api/admin/gifts/{GiftId}/putoffshelf` | POST | 下架礼品 | 需要 |
| `/api/admin/gifts/{GiftId}/addstock` | POST | 增加库存 | 需要 |
| `/api/admin/gifts` | GET | 获取礼品列表(支持筛选) | 需要 |
| `/api/admin/gifts/{GiftId}` | GET | 获取礼品详情 | 需要 |
### 5.4 兑换订单模块 (RedemptionOrders)
#### 会员端
| 端点 | 方法 | 说明 | 认证 |
|------|------|------|------|
| `/api/redemption-orders/my` | GET | 获取我的兑换订单列表 | 需要 |
| `/api/redemption-orders/{OrderId}` | GET | 获取订单详情 | 需要 |
#### 管理端
| 端点 | 方法 | 说明 | 认证 |
|------|------|------|------|
| `/api/admin/redemption-orders` | GET | 获取兑换订单列表 | 需要 |
| `/api/admin/redemption-orders/{OrderId}` | GET | 获取订单详情 | 需要 |
| `/api/admin/redemption-orders/{OrderId}/dispatch` | POST | 标记为已发货 | 需要 |
| `/api/admin/redemption-orders/{OrderId}/complete` | POST | 完成订单 | 需要 |
| `/api/admin/redemption-orders/{OrderId}/cancel` | POST | 取消订单 | 需要 |
### 5.5 积分规则模块 (PointsRules)
| 端点 | 方法 | 说明 | 认证 |
|------|------|------|------|
| `/api/admin/points-rules` | POST | 创建积分规则(管理端) | 需要 |
### 5.6 通用端点
| 端点 | 方法 | 说明 | 认证 |
|------|------|------|------|
| `/api/hello` | GET | 健康检查 | 匿名 |
| `/swagger` | GET | API 文档 | 匿名 |
**注意**
- 所有端点返回统一的 `ResponseData<T>` 格式
- 强类型ID`MemberId`, `GiftId`)在 Swagger 中映射为字符串类型
- 当前 JWT 认证尚未完全实现,部分端点暂时从请求参数获取 MemberId
---
## 六、数据库设计
### 6.1 数据库信息
- **数据库类型**SQLite
- **数据库文件**`app.db`(开发环境)
- **迁移工具**EF Core Migrations
- **最新迁移**`20260211044819_Init`
### 6.2 核心数据表
#### Members - 会员表
主要字段Id, Phone(唯一), Password, Nickname, Status, TotalPoints, AvailablePoints, LevelCode, LevelName, BonusRate, RequiredPoints, RegisteredAt
#### MarketingCodes - 营销码表
主要字段Id, Code(唯一), BatchNo, IsUsed, UsedByMemberId, UsedAt, ExpiryDate, ProductId, ProductName, CategoryId, CategoryName
#### PointsRules - 积分规则表
主要字段Id, RuleName, RuleType, PointsValue, BonusMultiplier, ProductId, CategoryId, MemberLevelCode, StartDate, EndDate, IsActive
#### PointsTransactions - 积分交易表
主要字段Id, MemberId, Type, Amount, Source, Reason, RelatedId, ExpiryDate, CreatedAt
**重要索引**
- `IX_PointsTransactions_MemberId` - 会员积分查询
- `IX_PointsTransactions_RelatedId` - 幂等性检查(非唯一)
- `IX_PointsTransactions_Type` - 按类型筛选
- `IX_PointsTransactions_CreatedAt` - 时间排序
#### Gifts - 礼品表
主要字段Id, Name, Type, Description, ImageUrl, RequiredPoints, TotalStock, AvailableStock, LimitPerMember, IsOnShelf, SortOrder, CreatedAt, UpdatedAt
#### RedemptionOrders - 兑换订单表
主要字段Id, OrderNo(唯一), MemberId, GiftId, GiftName, GiftType, Quantity, ConsumedPoints, Status, TrackingNo, CancelReason, ReceiverName, ReceiverPhone, Province, City, District, DetailAddress, CreatedAt, UpdatedAt
### 6.3 数据表关系说明
- 所有表使用 GUIDVersion 7作为主键
- 使用软删除(`Deleted` 字段)
- 使用行版本(`RowVersion`)实现乐观并发控制
- 积分交易表与会员表通过 MemberId 关联,但不设置外键(最终一致性)
- 兑换订单表包含礼品快照信息,减少关联查询
---
## 七、当前状态与后续建议
### 7.1 当前状态
**已完成功能**
- 后端项目成功编译和运行(`dotnet build` & `dotnet run`
- 数据库迁移已修复SQLite 切换完成EF Core 模型与迁移一致)
- Swagger API 文档正常生成Schema 冲突已解决)
- 会员、营销码、积分规则、积分交易、礼品、兑换订单等核心领域模型完整
- 扫码获取积分、礼品兑换等主要业务流程已打通
- 集成事件架构实现(领域事件 → 集成事件 → 事件处理器)
⚠️ **已知问题**
- 存在若干 Sonar 质量规则警告TODO 注释、异常处理建议等),不影响运行
- JWT 认证尚未完全实现,部分端点暂时从请求参数获取 MemberId
- 订单取消后的积分退还逻辑待完善
### 7.2 后续建议
#### 短期优化
1. **完善认证鉴权**
- 实现完整的 JWT Token 认证流程
- 从 Token 中获取当前登录会员ID
- 添加基于角色的权限控制(会员端/管理端)
2. **补充查询功能**
- 会员积分流水查询(分页、筛选)
- 礼品库存统计和销售报表
- 订单统计和数据分析
3. **完善业务逻辑**
- 实现订单取消后的积分退还
- 添加积分过期处理定时任务
- 完善会员等级自动升级逻辑
#### 长期规划
- 根据前端实际需求调整 API 结构和 DTO 字段
- 增加单元测试和集成测试覆盖率
- 性能优化和缓存策略
- 监控和日志完善
---
## 八、开发与部署
### 8.1 本地开发
```bash
# 启动基础设施Redis
cd Backend/scripts
./init-infrastructure.sh # Linux/Mac
./init-infrastructure.ps1 # Windows
# 运行后端
cd Backend/src/Fengling.Backend.Web
dotnet run
# 访问 Swagger 文档
http://localhost:5511/swagger
```
### 8.2 数据库迁移
```bash
# 添加新迁移
cd Backend/src/Fengling.Backend.Infrastructure
dotnet ef migrations add MigrationName
# 应用迁移(自动在启动时执行)
dotnet ef database update
```
### 8.3 项目结构
```
Backend/
├── src/
│ ├── Fengling.Backend.Domain/ # 领域层:聚合、实体、值对象、领域事件
│ ├── Fengling.Backend.Infrastructure/ # 基础设施层:数据库、仓储实现
│ └── Fengling.Backend.Web/ # 应用层API端点、命令查询、事件处理器
├── test/ # 测试项目
└── scripts/ # 基础设施脚本