558 lines
18 KiB
Markdown
558 lines
18 KiB
Markdown
# 相宜相亲 - 技术栈与开发规范
|
||
|
||
> 版本:1.1
|
||
> 更新日期:2025-12-28
|
||
|
||
---
|
||
|
||
## 一、项目架构概览
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 客户端层 │
|
||
├──────────────────┬──────────────────┬───────────────────────┤
|
||
│ 微信小程序 │ 后台管理系统 │ 微信服务号 │
|
||
│ (uni-app) │ (Vue3+ElementPlus)│ (消息推送) │
|
||
└────────┬─────────┴────────┬─────────┴───────────┬───────────┘
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ API网关层 │
|
||
├──────────────────────────┬──────────────────────────────────┤
|
||
│ 小程序API (独立部署) │ 后台管理API (独立部署) │
|
||
│ /api/app/* │ /api/admin/* │
|
||
└──────────────────────────┴──────────────────────────────────┘
|
||
│ │
|
||
▼ ▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 业务服务层 (.NET 8) │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ 用户服务 │ 相亲资料服务 │ 会员服务 │ 聊天服务 │ 支付服务 │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 数据层 │
|
||
├──────────────────┬──────────────────┬───────────────────────┤
|
||
│ SQL Server │ Redis │ 文件存储 │
|
||
│ (主数据库) │ (缓存/会话) │ (OSS/本地) │
|
||
└──────────────────┴──────────────────┴───────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 二、技术栈清单
|
||
|
||
### 2.1 后端技术栈
|
||
|
||
| 类别 | 技术选型 | 版本 | 说明 |
|
||
|-----|---------|------|------|
|
||
| **运行时** | .NET | 8.0 LTS | 长期支持版本,性能优秀 |
|
||
| **Web框架** | ASP.NET Core WebAPI | 8.0 | RESTful API |
|
||
| **ORM** | FreeSql | 3.x | 国产ORM,功能强大,支持CodeFirst |
|
||
| **数据库** | SQL Server | 2019+ | 主数据库 |
|
||
| **缓存** | Redis | 7.x | 验证码、Token、热点数据缓存 |
|
||
| **认证** | JWT | - | JSON Web Token 身份认证 |
|
||
| **API文档** | Swagger/OpenAPI | - | 接口文档自动生成 |
|
||
| **日志** | Serilog | 3.x | 结构化日志 |
|
||
| **对象映射** | Mapster | 7.x | 轻量级对象映射(比AutoMapper快) |
|
||
| **验证** | FluentValidation | 11.x | 请求参数验证 |
|
||
| **后台任务** | Hangfire | 1.8.x | 定时任务(每日推荐刷新等) |
|
||
| **实时通信** | SignalR | 8.0 | 聊天消息实时推送 |
|
||
|
||
### 2.2 前端技术栈(后台管理)
|
||
|
||
| 类别 | 技术选型 | 版本 | 说明 |
|
||
|-----|---------|------|------|
|
||
| **框架** | Vue | 3.4+ | 渐进式JavaScript框架 |
|
||
| **构建工具** | Vite | 5.x | 快速构建工具 |
|
||
| **UI组件库** | Element Plus | 2.x | Vue3 UI组件库 |
|
||
| **状态管理** | Pinia | 2.x | Vue3官方状态管理 |
|
||
| **路由** | Vue Router | 4.x | 路由管理 |
|
||
| **HTTP客户端** | Axios | 1.x | HTTP请求 |
|
||
| **图表** | ECharts | 5.x | 数据可视化(统计报表) |
|
||
| **富文本** | WangEditor | 5.x | 富文本编辑器(通知编辑) |
|
||
| **TypeScript** | TypeScript | 5.x | 类型安全 |
|
||
|
||
### 2.3 小程序端
|
||
|
||
| 类别 | 技术选型 | 版本 | 说明 |
|
||
|-----|---------|------|------|
|
||
| **开发框架** | uni-app | 3.x | 基于Vue3,可跨平台 |
|
||
| **UI组件** | uView Plus | 3.x | uni-app专用UI组件库 |
|
||
| **状态管理** | Pinia | 2.x | 全局状态管理 |
|
||
| **请求库** | luch-request | - | uni-app请求封装 |
|
||
|
||
### 2.4 第三方服务(抽象设计,支持多服务商)
|
||
|
||
| 服务 | 默认方案 | 备选方案 | 用途 |
|
||
|-----|---------|---------|------|
|
||
| **文件存储** | 腾讯云COS | 阿里云OSS | 用户头像、照片存储 |
|
||
| **短信服务** | 阿里云SMS | 腾讯云SMS | 手机号验证 |
|
||
| **实名认证** | 腾讯云人脸核身 | 阿里云实名认证 | 身份证验证 |
|
||
| **微信支付** | 微信支付V3 | - | 会员购买、实名认证付费 |
|
||
| **微信服务号** | 微信公众平台 | - | 消息推送通知 |
|
||
| **即时通讯** | SignalR | - | 用户聊天功能(自建) |
|
||
|
||
### 2.5 云服务抽象设计
|
||
|
||
为支持多云服务商切换,所有第三方云服务采用**接口抽象 + 依赖注入**模式:
|
||
|
||
```csharp
|
||
// ============ 文件存储抽象 ============
|
||
public interface IStorageProvider
|
||
{
|
||
Task<string> UploadAsync(Stream stream, string fileName, string folder);
|
||
Task<bool> DeleteAsync(string fileKey);
|
||
string GetAccessUrl(string fileKey, int expireMinutes = 30);
|
||
}
|
||
|
||
// 腾讯云COS实现
|
||
public class TencentCosProvider : IStorageProvider { ... }
|
||
|
||
// 阿里云OSS实现
|
||
public class AliyunOssProvider : IStorageProvider { ... }
|
||
|
||
// ============ 短信服务抽象 ============
|
||
public interface ISmsProvider
|
||
{
|
||
Task<bool> SendVerifyCodeAsync(string phone, string code);
|
||
Task<bool> SendNotificationAsync(string phone, string templateId, Dictionary<string, string> parameters);
|
||
}
|
||
|
||
// 阿里云短信实现
|
||
public class AliyunSmsProvider : ISmsProvider { ... }
|
||
|
||
// 腾讯云短信实现
|
||
public class TencentSmsProvider : ISmsProvider { ... }
|
||
|
||
// ============ 实名认证抽象 ============
|
||
public interface IRealNameProvider
|
||
{
|
||
Task<RealNameResult> VerifyIdCardAsync(string name, string idCard);
|
||
Task<RealNameResult> VerifyIdCardWithPhotoAsync(string name, string idCard, string photoBase64);
|
||
}
|
||
|
||
// 腾讯云实现
|
||
public class TencentRealNameProvider : IRealNameProvider { ... }
|
||
|
||
// 阿里云实现
|
||
public class AliyunRealNameProvider : IRealNameProvider { ... }
|
||
```
|
||
|
||
**配置示例 (appsettings.json):**
|
||
|
||
```json
|
||
{
|
||
"CloudServices": {
|
||
"Storage": {
|
||
"Provider": "TencentCos", // 可切换为 "AliyunOss"
|
||
"TencentCos": {
|
||
"SecretId": "xxx",
|
||
"SecretKey": "xxx",
|
||
"Region": "ap-shanghai",
|
||
"BucketName": "xiangyi-1234567890"
|
||
},
|
||
"AliyunOss": {
|
||
"AccessKeyId": "xxx",
|
||
"AccessKeySecret": "xxx",
|
||
"Endpoint": "oss-cn-shanghai.aliyuncs.com",
|
||
"BucketName": "xiangyi"
|
||
}
|
||
},
|
||
"Sms": {
|
||
"Provider": "AliyunSms", // 可切换为 "TencentSms"
|
||
"AliyunSms": {
|
||
"AccessKeyId": "xxx",
|
||
"AccessKeySecret": "xxx",
|
||
"SignName": "相宜相亲",
|
||
"TemplateCode": "SMS_123456789"
|
||
},
|
||
"TencentSms": {
|
||
"SecretId": "xxx",
|
||
"SecretKey": "xxx",
|
||
"AppId": "1400123456",
|
||
"SignName": "相宜相亲",
|
||
"TemplateId": "123456"
|
||
}
|
||
},
|
||
"RealName": {
|
||
"Provider": "TencentRealName", // 可切换为 "AliyunRealName"
|
||
"TencentRealName": {
|
||
"SecretId": "xxx",
|
||
"SecretKey": "xxx"
|
||
},
|
||
"AliyunRealName": {
|
||
"AccessKeyId": "xxx",
|
||
"AccessKeySecret": "xxx"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**依赖注入注册:**
|
||
|
||
```csharp
|
||
// Program.cs
|
||
public static class CloudServiceExtensions
|
||
{
|
||
public static IServiceCollection AddCloudServices(this IServiceCollection services, IConfiguration config)
|
||
{
|
||
// 文件存储
|
||
var storageProvider = config["CloudServices:Storage:Provider"];
|
||
if (storageProvider == "TencentCos")
|
||
services.AddSingleton<IStorageProvider, TencentCosProvider>();
|
||
else
|
||
services.AddSingleton<IStorageProvider, AliyunOssProvider>();
|
||
|
||
// 短信服务
|
||
var smsProvider = config["CloudServices:Sms:Provider"];
|
||
if (smsProvider == "AliyunSms")
|
||
services.AddSingleton<ISmsProvider, AliyunSmsProvider>();
|
||
else
|
||
services.AddSingleton<ISmsProvider, TencentSmsProvider>();
|
||
|
||
// 实名认证
|
||
var realNameProvider = config["CloudServices:RealName:Provider"];
|
||
if (realNameProvider == "TencentRealName")
|
||
services.AddSingleton<IRealNameProvider, TencentRealNameProvider>();
|
||
else
|
||
services.AddSingleton<IRealNameProvider, AliyunRealNameProvider>();
|
||
|
||
return services;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 三、项目结构规范
|
||
|
||
### 3.1 命名空间规范
|
||
|
||
```csharp
|
||
// 核心层
|
||
XiangYi.Core.Entities
|
||
XiangYi.Core.Enums
|
||
XiangYi.Core.Constants
|
||
|
||
// 应用层
|
||
XiangYi.Application.Services
|
||
XiangYi.Application.DTOs
|
||
XiangYi.Application.Interfaces
|
||
|
||
// 基础设施层
|
||
XiangYi.Infrastructure.Data
|
||
XiangYi.Infrastructure.Cache
|
||
XiangYi.Infrastructure.WeChat
|
||
|
||
// API层
|
||
XiangYi.AppApi.Controllers
|
||
XiangYi.AdminApi.Controllers
|
||
```
|
||
|
||
---
|
||
|
||
## 四、API设计规范
|
||
|
||
### 4.1 URL规范
|
||
|
||
```
|
||
# 小程序API 小程序的api,请求参数尽量不要放在路由里面
|
||
POST /api/app/auth/login # 微信登录
|
||
POST /api/app/auth/bindPhone # 绑定手机号
|
||
GET /api/app/users/recommend # 获取推荐用户列表
|
||
GET /api/app/users/getUserId # 获取用户详情
|
||
POST /api/app/profile # 提交相亲资料
|
||
POST /api/app/updateProfile # 更新相亲资料
|
||
POST /api/app/unlock/getToUser # 解锁联系方式
|
||
GET /api/app/messages # 获取消息列表
|
||
POST /api/app/chat/send # 发送聊天消息
|
||
...
|
||
|
||
# 后台管理API
|
||
POST /api/admin/auth/login # 管理员登录
|
||
GET /api/admin/users # 用户列表
|
||
GET /api/admin/users/{id} # 用户详情
|
||
PUT /api/admin/users/{id}/status # 更新用户状态
|
||
GET /api/admin/members # 会员列表
|
||
GET /api/admin/orders # 订单列表
|
||
POST /api/admin/banners # 添加Banner
|
||
PUT /api/admin/settings/popup # 配置弹窗
|
||
GET /api/admin/statistics/overview # 统计概览
|
||
...
|
||
```
|
||
|
||
### 4.2 统一响应格式
|
||
|
||
```csharp
|
||
// 成功响应
|
||
{
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": { ... }
|
||
}
|
||
|
||
// 错误响应
|
||
{
|
||
"code": 40001,
|
||
"message": "手机号格式不正确",
|
||
"data": ["手机号格式不正确"]
|
||
}
|
||
|
||
// 分页响应
|
||
{
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": {
|
||
"items": [...],
|
||
"total": 100,
|
||
"pageIndex": 1,
|
||
"pageSize": 10
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.3 错误码规范
|
||
|
||
| 错误码范围 | 说明 |
|
||
|-----------|------|
|
||
| 0 | 成功 |
|
||
| 10000-19999 | 系统级错误 |
|
||
| 20000-29999 | 认证授权错误 |
|
||
| 30000-39999 | 参数验证错误 |
|
||
| 40000-49999 | 业务逻辑错误 |
|
||
| 50000-59999 | 第三方服务错误 |
|
||
|
||
```csharp
|
||
// 示例
|
||
public static class ErrorCodes
|
||
{
|
||
// 系统错误
|
||
public const int SystemError = 10001;
|
||
public const int DatabaseError = 10002;
|
||
|
||
// 认证错误
|
||
public const int Unauthorized = 20001;
|
||
public const int TokenExpired = 20002;
|
||
public const int InvalidToken = 20003;
|
||
|
||
// 参数错误
|
||
public const int ValidationFailed = 30001;
|
||
public const int InvalidParameter = 30002;
|
||
|
||
// 业务错误
|
||
public const int UserNotFound = 40001;
|
||
public const int ProfileNotCompleted = 40002;
|
||
public const int InsufficientContactCount = 40003;
|
||
public const int AlreadyUnlocked = 40004;
|
||
public const int MembershipRequired = 40005;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 五、数据库设计规范
|
||
|
||
### 5.1 表命名规范
|
||
|
||
```sql
|
||
-- 使用Pascal命名,单数形式
|
||
User -- 用户表
|
||
UserProfile -- 用户相亲资料表
|
||
Member -- 会员表
|
||
Order -- 订单表
|
||
ChatMessage -- 聊天消息表
|
||
UserView -- 用户浏览记录表
|
||
UserFavorite -- 用户收藏表
|
||
UserUnlock -- 用户解锁记录表
|
||
SystemConfig -- 系统配置表
|
||
Banner -- Banner表
|
||
AdminUser -- 管理员表
|
||
```
|
||
|
||
### 5.2 字段命名规范
|
||
|
||
```sql
|
||
-- 主键:Id
|
||
-- 外键:{表名}Id,如 UserId
|
||
-- 时间字段:CreateTime, UpdateTime, ExpireTime
|
||
-- 状态字段:Status
|
||
-- 布尔字段:Is前缀,如 IsDeleted, IsEnabled
|
||
-- 枚举字段:使用int类型存储
|
||
|
||
CREATE TABLE [User] (
|
||
Id BIGINT PRIMARY KEY IDENTITY,
|
||
OpenId NVARCHAR(64) NOT NULL, -- 微信OpenId
|
||
UnionId NVARCHAR(64), -- 微信UnionId
|
||
Phone NVARCHAR(20), -- 手机号
|
||
Nickname NVARCHAR(50), -- 昵称
|
||
Avatar NVARCHAR(500), -- 头像URL
|
||
XiangQinNo NVARCHAR(10), -- 相亲编号
|
||
Status INT DEFAULT 1, -- 状态:1正常 2禁用
|
||
IsRealName BIT DEFAULT 0, -- 是否实名
|
||
IsMember BIT DEFAULT 0, -- 是否会员
|
||
MemberLevel INT DEFAULT 0, -- 会员等级
|
||
ContactCount INT DEFAULT 2, -- 剩余联系次数
|
||
CreateTime DATETIME2 DEFAULT GETDATE(),
|
||
UpdateTime DATETIME2,
|
||
IsDeleted BIT DEFAULT 0
|
||
);
|
||
```
|
||
|
||
### 5.3 FreeSql CodeFirst配置
|
||
|
||
```csharp
|
||
[Table(Name = "User")]
|
||
public class User
|
||
{
|
||
[Column(IsPrimary = true, IsIdentity = true)]
|
||
public long Id { get; set; }
|
||
|
||
[Column(StringLength = 64, IsNullable = false)]
|
||
public string OpenId { get; set; }
|
||
|
||
[Column(StringLength = 20)]
|
||
public string? Phone { get; set; }
|
||
|
||
[Column(StringLength = 50)]
|
||
public string? Nickname { get; set; }
|
||
|
||
[Column(InsertValueSql = "GETDATE()")]
|
||
public DateTime CreateTime { get; set; }
|
||
|
||
[Column(IsIgnore = true)]
|
||
public UserProfile? Profile { get; set; }
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 六、安全规范
|
||
|
||
### 6.1 认证流程
|
||
|
||
```
|
||
小程序端:
|
||
1. 用户点击登录 → 调用wx.login()获取code (注意用户点击多次)
|
||
2. 前端将code发送到后端 /api/app/auth/login (注意用户点击多次)
|
||
3. 后端用code换取openid/unionid
|
||
4. 后端生成JWT Token返回
|
||
5. 前端存储Token,后续请求携带Authorization头
|
||
|
||
后台管理端:
|
||
1. 管理员输入账号密码
|
||
2. 后端验证成功后生成JWT Token
|
||
3. 前端存储Token,后续请求携带Authorization头
|
||
```
|
||
|
||
### 6.2 JWT配置
|
||
|
||
```csharp
|
||
// appsettings.json
|
||
{
|
||
"Jwt": {
|
||
"Secret": "your-256-bit-secret-key-here",
|
||
"Issuer": "XiangYiXiangQin",
|
||
"Audience": "XiangYiApp",
|
||
"ExpireMinutes": 10080 // 7天
|
||
}
|
||
}
|
||
```
|
||
|
||
### 6.3 敏感数据处理
|
||
|
||
```csharp
|
||
// 手机号脱敏
|
||
public static string MaskPhone(string phone)
|
||
=> phone.Length >= 11 ? $"{phone[..3]}****{phone[^4..]}" : phone;
|
||
|
||
// 身份证脱敏
|
||
public static string MaskIdCard(string idCard)
|
||
=> idCard.Length >= 18 ? $"{idCard[..3]}***********{idCard[^4..]}" : idCard;
|
||
|
||
```
|
||
|
||
---
|
||
|
||
## 七、部署架构
|
||
|
||
### 7.1 推荐部署方案
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ Nginx (反向代理) │
|
||
│ SSL证书、负载均衡、静态资源、跨域 │
|
||
└────────────────┬────────────────────────┘
|
||
│
|
||
┌────────────┼────────────┐
|
||
▼ ▼ ▼
|
||
┌────────┐ ┌──────────┐ ┌──────────┐
|
||
│小程序API│ │后台管理API│ │后台管理前端│
|
||
│ :5001 │ │ :5002 │ │ :80 │
|
||
└────────┘ └──────────┘ └──────────┘
|
||
│ │
|
||
└─────┬──────┘
|
||
▼
|
||
┌──────────┐
|
||
│ SQL Server│ ◄── 主数据库
|
||
│ :1433 │
|
||
└──────────┘
|
||
│
|
||
┌──────────┐
|
||
│ Redis │ ◄── 缓存
|
||
│ :6379 │
|
||
└──────────┘
|
||
```
|
||
|
||
### 7.2 服务器配置建议
|
||
|
||
| 环境 | 配置 | 说明 |
|
||
|-----|------|------|
|
||
| 开发环境 | 2核4G | 本地开发 |
|
||
| 测试环境 | 2核4G | 功能测试 |
|
||
| 生产环境 | 4核8G起 | 根据用户量调整 |
|
||
|
||
---
|
||
|
||
## 八、开发工具
|
||
|
||
| 工具 | 用途 |
|
||
|-----|------|
|
||
| Visual Studio 2022 / Rider | .NET开发 |
|
||
| VS Code | 前端开发 |
|
||
| 微信开发者工具 | 小程序开发调试 |
|
||
| Navicat / SSMS | 数据库管理 |
|
||
| Redis Desktop Manager | Redis管理 |
|
||
| Postman / Apifox | API调试 |
|
||
| Git | 版本控制 |
|
||
|
||
---
|
||
|
||
## 九、待确认事项
|
||
|
||
### 9.1 已确认的技术选型
|
||
|
||
- [x] 小程序开发框架:**uni-app**
|
||
- [x] 即时通讯方案:**SignalR(自建)**
|
||
- [x] 文件存储:**腾讯云COS**(已抽象,可切换阿里云OSS)
|
||
- [x] 短信服务商:**阿里云SMS**(已抽象,可切换腾讯云SMS)
|
||
- [x] 实名认证服务商:**腾讯云**(已抽象,可切换阿里云)
|
||
|
||
### 9.2 需要确认的业务问题
|
||
|
||
- [ ] 是否需要后台审核用户资料?
|
||
- [ ] 聊天消息是否需要敏感词过滤?
|
||
- [ ] 是否需要举报功能?
|
||
- [ ] 数据备份策略?
|
||
|
||
---
|
||
|
||
## 十、版本记录
|
||
|
||
| 版本 | 日期 | 修改内容 |
|
||
|-----|------|---------|
|
||
| 1.0 | 2025-12-28 | 初始版本 |
|
||
| 1.1 | 2025-12-28 | 确认技术选型:uni-app、SignalR;新增云服务抽象设计,支持多服务商切换 |
|