技术架构
🏗️ 系统架构
Penny Lens Serverless 采用云原生架构,基于支付宝小程序云 Serverless + TypeScript + MongoDB 构建,提供高可用性、自动扩缩容和低成本的后端解决方案。
🛠️ 技术栈
核心框架
- 支付宝小程序云 - 云原生 Serverless 平台
- TypeScript - 类型安全的 JavaScript 超集
- Node.js - JavaScript 运行时环境
数据库与存储
开发工具
📁 项目结构
src/├── config/ # 配置文件│ └── index.ts # 配置入口├── controllers/ # 控制器层│ ├── UserController.ts│ ├── AssetController.ts│ ├── AccountingController.ts│ ├── BudgetController.ts│ ├── StatisticsController.ts│ ├── SubscriptionController.ts│ ├── SavingsController.ts│ └── ShortLinkController.ts├── services/ # 服务层│ ├── UserService.ts│ ├── AssetService.ts│ ├── AccountingService.ts│ ├── BudgetService.ts│ ├── StatisticsService.ts│ ├── SubscriptionService.ts│ ├── SavingsService.ts│ └── ShortLinkService.ts├── types/ # 类型定义│ ├── BaseService.ts # 基础服务类│ ├── BaseController.ts # 基础控制器类│ ├── appResponse.ts # 统一响应格式│ ├── User.ts│ ├── Asset.ts│ ├── Accounting.ts│ ├── Budget.ts│ ├── Statistics.ts│ ├── Subscription.ts│ ├── Savings.ts│ └── ShortLink.ts├── exceptions/ # 异常处理│ └── AppException.ts├── enums/ # 枚举定义│ └── HttpEnum.ts├── router.ts # 路由配置├── routes.ts # 路由定义└── index.ts # 入口文件🔧 开发规约架构
1. 基础架构层
BaseService - 基础服务类
/**
* 基础服务类
* 提供通用的数据库操作和业务逻辑处理
*/
export abstract class BaseService {
/**
* 构建基础查询条件
*/
protected buildBaseQueryCondition(userInfo: UserResponse): any {
return {
userId: userInfo.id,
delFlag: false
};
}
/**
* 分页查询
*/
protected async paginateQuery<T>(
collection: any,
where: any,
page: number,
pageSize: number,
orderBy: { field: string; order: "asc" | "desc"; }[] = [{ field: "createdAt", order: "desc" }]
): Promise<Page<T>> {
// 分页查询实现
}
/**
* 验证记录是否存在
*/
protected async validateRecordExists(
collection: any,
condition: any,
errorMessage: string
): Promise<any> {
// 记录存在性验证实现
}
/**
* 验证用户访问权限
*/
protected async validateUserAccess(
record: any,
userInfo: UserResponse,
errorMessage: string
): Promise<void> {
// 用户权限验证实现
}
}BaseController - 基础控制器类
/**
* 基础控制器类
* 提供统一的请求处理和响应格式
*/
export abstract class BaseController {
/**
* 包装异步方法,自动处理异常
*/
protected wrapAsync<T>(
asyncFn: () => Promise<T>,
successMessage: string = "操作成功"
): Promise<AppResponse<T>> {
try {
const data = await asyncFn();
return {
code: 200,
message: successMessage,
data
};
} catch (error) {
// 统一异常处理
return this.handleError(error);
}
}
/**
* 统一错误处理
*/
private handleError(error: unknown): AppResponse<null> {
if (error instanceof AppException) {
return {
code: error.code,
message: error.message,
data: null
};
}
const errorMessage = error instanceof Error ? error.message : "未知错误";
return {
code: 500,
message: `服务器错误: ${errorMessage}`,
data: null
};
}
}2. 异常处理架构
/**
* 应用异常基类
*/
export abstract class AppException extends Error {
constructor(
public code: number,
public message: string,
public data?: any
) {
super(message);
this.name = 'AppException';
}
}
/**
* 验证异常
*/
export class ValidationException extends AppException {
constructor(message: string, data?: any) {
super(400, message, data);
}
}
/**
* 认证异常
*/
export class AuthenticationException extends AppException {
constructor(message: string = 'Authentication failed') {
super(401, message);
}
}
/**
* 授权异常
*/
export class AuthorizationException extends AppException {
constructor(message: string = 'Access denied') {
super(403, message);
}
}
/**
* 未找到异常
*/
export class NotFoundException extends AppException {
constructor(message: string = 'Resource not found') {
super(404, message);
}
}
/**
* 数据库异常
*/
export class DatabaseException extends AppException {
constructor(message: string = 'Database operation failed') {
super(500, message);
}
}3. 路由配置架构
/**
* 路由配置接口
*/
export interface RouteConfig {
controller: any;
method: string;
requireAuth: boolean;
}
/**
* 批量构建路由配置
*/
export function buildRoutes(
serviceName: string,
actions: Array<{ action: string; requireAuth: boolean }>,
controller: any
): Record<string, RouteConfig> {
const routes: Record<string, RouteConfig> = {};
actions.forEach(({ action, requireAuth }) => {
const routeKey = `${serviceName}.${action}`;
const methodName = METHOD_MAPPINGS[routeKey] || action;
routes[routeKey] = {
controller,
method: methodName,
requireAuth
};
});
return routes;
}
/**
* 方法映射表(特殊 action 到 service 方法名的映射)
*/
export const METHOD_MAPPINGS: Record<string, string> = {
"asset.record.queryByAssetId": "queryListByAssetId",
"user.generateQrCodeLogin": "generateQrCodeLogin",
"user.confirmQrCodeLogin": "confirmQrCodeLogin",
"user.pollQrCodeLogin": "pollQrCodeLogin",
};🔧 核心功能模块
1. 用户管理模块
功能: 用户注册、登录、信息管理、QR码登录
技术实现:
- JWT Token 认证
- 多平台登录支持(微信、支付宝)
- QR码跨设备登录
- 用户信息加密存储
- 权限控制
开发规约实现:
// Service 层
export class UserService extends BaseService {
public async create(params: UserCreateRequest, userInfo: UserResponse): Promise<{ id: string; }> {
// 使用 buildBaseQueryCondition 构建查询条件
// 使用 validateRecordExists 验证记录存在性
// 抛出具体的业务异常
}
}
// Controller 层
export class UserController extends BaseController {
async create(params: UserCreateRequest, userInfo: UserResponse): Promise<AppResponse<{ id: string; }>> {
return this.wrapAsync(
async () => {
return this.userService.create(params, userInfo);
},
"创建用户成功",
);
}
}相关文件:
controllers/UserController.ts- 用户控制器services/UserService.ts- 用户服务types/User.ts- 用户类型定义
2. 资产管理模块
功能: 资产增删改查、余额管理、转账功能
技术实现:
- 多账户类型支持
- 实时余额计算
- 资产变化记录
- 转账功能
开发规约实现:
// Service 层
export class AssetService extends BaseService {
public async create(params: AssetCreateRequest, userInfo: UserResponse): Promise<{ id: string; }> {
// 参数验证
if (!params.name) {
throw new ValidationException("资产名称不能为空");
}
// 构建基础查询条件
const baseCondition = this.buildBaseQueryCondition(userInfo);
// 检查资产是否已存在
const existingAsset = await assetCollection
.where({
...baseCondition,
name: params.name,
delFlag: false
})
.get();
if (existingAsset.data.length > 0) {
throw new ValidationException("资产名称已存在");
}
// 创建资产记录
const assetData = {
...params,
userId: userInfo.id,
delFlag: false,
createdAt: Date.now(),
updatedAt: Date.now()
};
const result = await assetCollection.add(assetData);
return { id: result._id };
}
}相关文件:
controllers/AssetController.ts- 资产控制器services/AssetService.ts- 资产服务types/Asset.ts- 资产类型定义
3. 记账管理模块
功能: 收入、支出、转账记录管理
技术实现:
- 复式记账法
- 分类管理
- 批量操作
- 数据验证
开发规约实现:
// Service 层
export class AccountingService extends BaseService {
public async create(params: AccountingCreateRequest, userInfo: UserResponse): Promise<{ id: string; }> {
// 使用 validateRecordExists 验证资产存在
const asset = await this.validateRecordExists(
assetCollection,
{ _id: params.assetId, userId: userInfo.id },
"资产不存在"
);
// 使用 validateUserAccess 验证用户权限
await this.validateUserAccess(asset, userInfo, "无权限操作该资产");
// 业务逻辑处理
// ...
}
}相关文件:
controllers/AccountingController.ts- 记账控制器services/AccountingService.ts- 记账服务types/Accounting.ts- 记账类型定义
4. 预算管理模块
功能: 预算设置、执行监控、预警提醒
技术实现:
- 分类预算设置
- 实时执行监控
- 超支预警系统
- 预算分析报告
开发规约实现:
// Service 层
export class BudgetService extends BaseService {
public async query(params: BudgetQueryRequest, userInfo: UserResponse): Promise<Page<Budget>> {
const baseCondition = this.buildBaseQueryCondition(userInfo);
const whereCondition = {
...baseCondition,
...(params.categoryId && { categoryId: params.categoryId }),
...(params.status && { status: params.status })
};
return this.paginateQuery(
budgetCollection,
whereCondition,
params.page || 1,
params.pageSize || 20,
[{ field: "createdAt", order: "desc" }]
);
}
}相关文件:
controllers/BudgetController.ts- 预算控制器services/BudgetService.ts- 预算服务types/Budget.ts- 预算类型定义
5. 统计分析模块
功能: 收支统计、趋势分析、报表生成
技术实现:
- 多维度统计分析
- 实时数据计算
- 报表生成
- 数据导出
开发规约实现:
// Service 层
export class StatisticsService extends BaseService {
public async getIncomeStatistics(params: StatisticsRequest, userInfo: UserResponse): Promise<StatisticsResponse> {
// 使用 buildBaseQueryCondition 构建查询条件
const baseCondition = this.buildBaseQueryCondition(userInfo);
// 复杂的统计查询逻辑
// ...
}
}相关文件:
controllers/StatisticsController.ts- 统计控制器services/StatisticsService.ts- 统计服务types/Statistics.ts- 统计类型定义
🔄 数据流架构
请求处理流程
用户请求 → 路由分发 → 权限验证 → 控制器处理 → 服务层业务逻辑 → 数据库操作 → 响应返回 ↓ ↓ ↓ ↓ ↓ ↓ ↓ 路由匹配 身份验证 参数验证 业务处理 数据查询 结果处理 状态返回开发规约流程:
- 路由分发: 使用
buildRoutes函数批量构建路由配置 - 权限验证: 根据
requireAuth属性进行身份验证 - 控制器处理: 使用
wrapAsync包装业务逻辑,自动处理异常 - 服务层业务逻辑: 继承
BaseService,使用工具方法进行数据库操作 - 数据库操作: 使用统一的查询条件和分页查询
- 异常处理: 使用具体的业务异常类,提供清晰的错误信息
数据同步机制
实时同步
- 用户操作: 用户操作实时同步到数据库
- 状态更新: 服务状态实时更新
- 数据一致性: 保证数据一致性
批量同步
- 定时任务: 定时同步数据
- 数据备份: 定期数据备份
- 统计分析: 定期统计分析
开发规约数据流
// 1. 路由配置
export const routes: Record<string, RouteConfig> = {
...buildRoutes("user", userActions, userController),
...buildRoutes("asset", assetActions, assetController),
};
// 2. 控制器处理
export class UserController extends BaseController {
async create(params: UserCreateRequest, userInfo: UserResponse): Promise<AppResponse<{ id: string; }>> {
return this.wrapAsync(
async () => {
// 简单的参数验证
if (!params.username) {
throw new ValidationException("用户名不能为空");
}
// 调用服务层
return this.userService.create(params, userInfo);
},
"创建用户成功",
);
}
}
// 3. 服务层业务逻辑
export class UserService extends BaseService {
public async create(params: UserCreateRequest, userInfo: UserResponse): Promise<{ id: string; }> {
// 构建基础查询条件
const baseCondition = this.buildBaseQueryCondition(userInfo);
// 检查用户名是否已存在
const existingUser = await userCollection
.where({
...baseCondition,
username: params.username,
delFlag: false
})
.get();
if (existingUser.data.length > 0) {
throw new ValidationException("用户名已存在");
}
// 创建用户记录
const userData = {
...params,
userId: userInfo.id,
delFlag: false,
createdAt: Date.now(),
updatedAt: Date.now()
};
const result = await userCollection.add(userData);
return { id: result._id };
}
}🔐 安全架构
认证机制
// JWT Token 认证
export class AuthService {
generateToken(user: User): string {
return jwt.sign(
{ userId: user._id, username: user.username },
process.env.JWT_SECRET!,
{ expiresIn: '7d' }
);
}
verifyToken(token: string): any {
return jwt.verify(token, process.env.JWT_SECRET!);
}
}权限控制
// 权限中间件
export const requireAuth = (req: Request, res: Response, next: NextFunction) => {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) {
throw new AuthenticationException('Token required');
}
try {
const decoded = authService.verifyToken(token);
req.user = decoded;
next();
} catch (error) {
throw new AuthenticationException('Invalid token');
}
};数据加密
// 数据加密服务
export class EncryptionService {
encrypt(text: string): string {
const cipher = crypto.createCipher('aes-256-cbc', process.env.ENCRYPTION_KEY!);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
}
decrypt(encryptedText: string): string {
const decipher = crypto.createDecipher('aes-256-cbc', process.env.ENCRYPTION_KEY!);
let decrypted = decipher.update(encryptedText, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
}⚡ 性能优化
数据库优化
// 数据库索引
export const createIndexes = async () => {
// 用户索引
await db.collection('users').createIndex({ username: 1 }, { unique: true });
await db.collection('users').createIndex({ email: 1 }, { unique: true });
// 资产索引
await db.collection('assets').createIndex({ userId: 1 });
await db.collection('assets').createIndex({ type: 1 });
// 记账记录索引
await db.collection('accounting').createIndex({ userId: 1, date: -1 });
await db.collection('accounting').createIndex({ categoryId: 1 });
};缓存机制
// 缓存服务
export class CacheService {
private cache = new Map<string, { data: any; timestamp: number; ttl: number }>();
set(key: string, data: any, ttl: number = 300000): void {
this.cache.set(key, {
data,
timestamp: Date.now(),
ttl
});
}
get(key: string): any | null {
const item = this.cache.get(key);
if (!item) return null;
if (Date.now() - item.timestamp > item.ttl) {
this.cache.delete(key);
return null;
}
return item.data;
}
}🧪 测试策略
单元测试
// 用户服务测试
describe('UserService', () => {
let userService: UserService;
beforeEach(() => {
userService = new UserService();
});
it('should create user successfully', async () => {
const userData = {
username: 'testuser',
email: 'test@example.com',
password: 'password123'
};
const result = await userService.createUser(userData);
expect(result).toBeDefined();
expect(result.username).toBe(userData.username);
});
});集成测试
// API 集成测试
describe('User API', () => {
it('should login successfully', async () => {
const response = await request(app)
.post('/api/user/login')
.send({
username: 'testuser',
password: 'password123'
});
expect(response.status).toBe(200);
expect(response.body.code).toBe(200);
expect(response.body.data.token).toBeDefined();
});
});🚀 部署架构
开发环境
- 本地开发: 本地开发环境
- 热重载: 实时代码更新
- 调试工具: 调试工具支持
- 代码检查: ESLint + TypeScript
生产环境
- 云函数部署: 自动部署到云端
- 数据库配置: 生产数据库配置
- 监控告警: 生产环境监控
- 备份恢复: 数据备份和恢复
📊 监控和运维
性能监控
- 服务监控: 服务性能监控
- 数据库监控: 数据库性能监控
- 错误监控: 错误日志监控
- 业务监控: 业务指标监控
日志管理
- 访问日志: 用户访问记录
- 错误日志: 系统错误和异常
- 业务日志: 业务操作记录
- 性能日志: 性能指标记录
🔄 持续集成
代码管理
- 版本控制: Git 版本控制
- 代码审查: Pull Request 代码审查
- 自动化测试: 单元测试、集成测试
- 代码质量: ESLint、TypeScript 检查
部署流程
- 自动化构建: CI/CD 自动化构建
- 环境管理: 开发、测试、生产环境
- 回滚机制: 快速回滚机制
- 灰度发布: 渐进式发布
📈 扩展性
功能扩展
- 模块化设计: 模块化功能设计
- 插件系统: 可扩展的插件系统
- 接口标准化: 标准化接口设计
- 版本兼容: 版本兼容性管理
技术扩展
- 微服务化: 微服务架构演进
- 容器化: 容器化部署
- 云原生: 云原生架构
- 智能化: AI 和机器学习集成
📋 开发规约总结
核心规约要点
-
Service 层规范:
- 继承
BaseService基类 - 使用
buildBaseQueryCondition构建查询条件 - 使用
paginateQuery进行分页查询 - 使用
validateRecordExists验证记录存在性 - 使用
validateUserAccess验证用户权限 - 抛出具体的业务异常类
- 继承
-
Controller 层规范:
- 继承
BaseController基类 - 使用
wrapAsync包装业务逻辑 - 不使用
public关键字 - 使用
async () => { return ... }格式 - 未使用的参数使用下划线前缀
- 继承
-
路由配置规范:
- 使用
buildRoutes函数批量构建路由 - 明确指定
requireAuth属性 - 使用
METHOD_MAPPINGS处理特殊方法映射
- 使用
-
异常处理规范:
- 使用统一的异常处理机制
- 抛出具体的业务异常类
- 提供清晰的错误信息
-
数据库操作规范:
- 统一在文件顶部定义数据库连接和集合
- 使用
cloud.database()获取数据库实例 - 集合名称使用小写复数形式
- 避免链式 where 调用
开发检查清单
在开发新功能时,请确保:
- Service 类继承
BaseService - Controller 类继承
BaseController - 使用
wrapAsync包装业务逻辑 - 不使用
public关键字 - 使用
buildBaseQueryCondition构建查询条件 - 使用
paginateQuery进行分页查询 - 使用具体的业务异常类
- 在
routes.ts中注册路由 - 遵循统一的命名规范
- 添加完整的 JSDoc 注释
重要提醒:
- 始终遵循技术架构规范和开发规约
- 确保云原生架构兼容性
- 保持代码质量和性能
- 优化安全性和可维护性
- 遵循最佳实践和设计模式
- 严格按照开发规约实现 Service 和 Controller 层
