Penny Lens Serverless 技术架构

2025年1月27日
11 分钟阅读
作者:Penny Lens Team

技术架构

🏗️ 系统架构

Penny Lens Serverless 采用云原生架构,基于支付宝小程序云 Serverless + TypeScript + MongoDB 构建,提供高可用性、自动扩缩容和低成本的后端解决方案。

🛠️ 技术栈

核心框架

数据库与存储

开发工具

📁 项目结构

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 - 统计类型定义

🔄 数据流架构

请求处理流程

用户请求 → 路由分发 → 权限验证 → 控制器处理 → 服务层业务逻辑 → 数据库操作 → 响应返回
↓ ↓ ↓ ↓ ↓ ↓ ↓
路由匹配 身份验证 参数验证 业务处理 数据查询 结果处理 状态返回

开发规约流程:

  1. 路由分发: 使用 buildRoutes 函数批量构建路由配置
  2. 权限验证: 根据 requireAuth 属性进行身份验证
  3. 控制器处理: 使用 wrapAsync 包装业务逻辑,自动处理异常
  4. 服务层业务逻辑: 继承 BaseService,使用工具方法进行数据库操作
  5. 数据库操作: 使用统一的查询条件和分页查询
  6. 异常处理: 使用具体的业务异常类,提供清晰的错误信息

数据同步机制

实时同步

  • 用户操作: 用户操作实时同步到数据库
  • 状态更新: 服务状态实时更新
  • 数据一致性: 保证数据一致性

批量同步

  • 定时任务: 定时同步数据
  • 数据备份: 定期数据备份
  • 统计分析: 定期统计分析

开发规约数据流

// 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 和机器学习集成

📋 开发规约总结

核心规约要点

  1. Service 层规范:

    • 继承 BaseService 基类
    • 使用 buildBaseQueryCondition 构建查询条件
    • 使用 paginateQuery 进行分页查询
    • 使用 validateRecordExists 验证记录存在性
    • 使用 validateUserAccess 验证用户权限
    • 抛出具体的业务异常类
  2. Controller 层规范:

    • 继承 BaseController 基类
    • 使用 wrapAsync 包装业务逻辑
    • 不使用 public 关键字
    • 使用 async () => { return ... } 格式
    • 未使用的参数使用下划线前缀
  3. 路由配置规范:

    • 使用 buildRoutes 函数批量构建路由
    • 明确指定 requireAuth 属性
    • 使用 METHOD_MAPPINGS 处理特殊方法映射
  4. 异常处理规范:

    • 使用统一的异常处理机制
    • 抛出具体的业务异常类
    • 提供清晰的错误信息
  5. 数据库操作规范:

    • 统一在文件顶部定义数据库连接和集合
    • 使用 cloud.database() 获取数据库实例
    • 集合名称使用小写复数形式
    • 避免链式 where 调用

开发检查清单

在开发新功能时,请确保:

  • Service 类继承 BaseService
  • Controller 类继承 BaseController
  • 使用 wrapAsync 包装业务逻辑
  • 不使用 public 关键字
  • 使用 buildBaseQueryCondition 构建查询条件
  • 使用 paginateQuery 进行分页查询
  • 使用具体的业务异常类
  • routes.ts 中注册路由
  • 遵循统一的命名规范
  • 添加完整的 JSDoc 注释

重要提醒:

  1. 始终遵循技术架构规范和开发规约
  2. 确保云原生架构兼容性
  3. 保持代码质量和性能
  4. 优化安全性和可维护性
  5. 遵循最佳实践和设计模式
  6. 严格按照开发规约实现 Service 和 Controller 层