|
|
@@ -0,0 +1,293 @@
|
|
|
+# Story 004.001: 创建多租户信用额度模块
|
|
|
+
|
|
|
+## Status
|
|
|
+Draft
|
|
|
+
|
|
|
+## Story
|
|
|
+**As a** 系统管理员,
|
|
|
+**I want** 能够管理用户的信用额度,
|
|
|
+**so that** 控制用户的支付权限和风险
|
|
|
+
|
|
|
+## Acceptance Criteria
|
|
|
+1. 创建`credit_balance_mt`表,包含租户ID、用户ID、总额度、已用额度、可用额度等字段
|
|
|
+2. 创建`credit_balance_log_mt`表,记录额度变更历史
|
|
|
+3. 实现额度管理服务,包含设置额度、扣减额度、查询余额等方法
|
|
|
+4. 提供额度查询和管理的API接口
|
|
|
+5. 添加数据库迁移脚本
|
|
|
+6. 编写单元测试覆盖核心逻辑
|
|
|
+
|
|
|
+## Tasks / Subtasks
|
|
|
+- [ ] **创建多租户信用额度模块包结构** (AC: 1, 2, 3, 4, 6)
|
|
|
+ - [ ] 创建包目录:`packages/credit-balance-module-mt/`
|
|
|
+ - [ ] 配置package.json,包名:`@d8d/credit-balance-module-mt`
|
|
|
+ - [ ] 配置TypeScript和Vitest配置文件
|
|
|
+ - [ ] 创建核心模块结构:`src/entities/`, `src/services/`, `src/schemas/`, `src/routes/`, `src/types/`
|
|
|
+ - [ ] 创建测试目录结构:`tests/unit/`, `tests/integration/`
|
|
|
+
|
|
|
+- [ ] **实现信用额度实体** (AC: 1)
|
|
|
+ - [ ] 创建`CreditBalanceMt`实体类,对应`credit_balance_mt`表
|
|
|
+ - [ ] 添加字段:`tenant_id`, `user_id`, `total_limit`, `used_amount`, `available_amount`, `is_enabled`
|
|
|
+ - [ ] 添加唯一约束:`uk_tenant_user (tenant_id, user_id)`
|
|
|
+ - [ ] 添加索引:`idx_tenant_id`, `idx_user_id`
|
|
|
+ - [ ] 使用TypeORM装饰器定义实体关系
|
|
|
+
|
|
|
+- [ ] **实现额度变更记录实体** (AC: 2)
|
|
|
+ - [ ] 创建`CreditBalanceLogMt`实体类,对应`credit_balance_log_mt`表
|
|
|
+ - [ ] 添加字段:`tenant_id`, `user_id`, `change_type`, `change_amount`, `before_total`, `after_total`, `before_used`, `after_used`, `reference_id`, `remark`, `operator_id`
|
|
|
+ - [ ] 添加索引:`idx_tenant_user`, `idx_reference`, `idx_created`
|
|
|
+ - [ ] 定义变更类型枚举:`SET_LIMIT`, `PAYMENT`, `CHECKOUT`, `CANCEL_ORDER`, `REFUND`, `ADJUST`
|
|
|
+
|
|
|
+- [ ] **实现额度管理服务** (AC: 3)
|
|
|
+ - [ ] 创建`CreditBalanceService`服务类
|
|
|
+ - [ ] 实现方法:`setLimit()`, `adjustLimit()`, `deductAmount()`, `restoreAmount()`, `getBalance()`, `getBalanceByUserId()`
|
|
|
+ - [ ] 实现额度恢复方法:`restoreBalanceForCancelOrder()`, `restoreBalanceForRefund()`
|
|
|
+ - [ ] 添加事务处理确保数据一致性
|
|
|
+ - [ ] 添加额度检查和验证逻辑
|
|
|
+
|
|
|
+- [ ] **实现API路由** (AC: 4)
|
|
|
+ - [ ] 创建路由文件:`src/routes/index.mt.ts`
|
|
|
+ - [ ] 实现API端点:
|
|
|
+ - [ ] `GET /api/credit-balance/{userId}` - 查询用户额度
|
|
|
+ - [ ] `PUT /api/credit-balance/{userId}` - 设置用户额度
|
|
|
+ - [ ] `POST /api/credit-balance/{userId}/adjust` - 调整用户额度
|
|
|
+ - [ ] `GET /api/credit-balance/{userId}/logs` - 查询额度变更记录
|
|
|
+ - [ ] `POST /api/credit-balance/payment` - 额度支付
|
|
|
+ - [ ] `POST /api/credit-balance/checkout` - 结账恢复额度
|
|
|
+ - [ ] 添加数据验证Schema
|
|
|
+ - [ ] 添加权限控制和认证中间件
|
|
|
+
|
|
|
+
|
|
|
+- [ ] **编写单元测试** (AC: 6)
|
|
|
+ - [ ] 创建实体测试:验证实体定义和关系
|
|
|
+ - [ ] 创建服务测试:测试额度管理逻辑
|
|
|
+ - [ ] 创建API测试:测试端点功能和验证
|
|
|
+ - [ ] 添加边界条件测试:额度不足、重复操作等场景
|
|
|
+ - [ ] 确保测试覆盖率 ≥ 80%
|
|
|
+
|
|
|
+- [ ] **配置包依赖和导出** (AC: 3, 4)
|
|
|
+ - [ ] 配置package.json依赖关系(TypeORM、Hono等)
|
|
|
+ - [ ] 创建主入口文件:`src/index.mt.ts` 导出所有模块接口
|
|
|
+ - [ ] 配置TypeScript编译选项
|
|
|
+ - [ ] 配置Vitest测试环境
|
|
|
+ - [ ] 确保包可以正确导入和使用
|
|
|
+
|
|
|
+## Dev Notes
|
|
|
+
|
|
|
+### 技术栈信息 [Source: architecture/tech-stack.md]
|
|
|
+- **运行时**: Node.js 20.18.3
|
|
|
+- **框架**: Hono 4.8.5 (Web框架和API路由,RPC类型安全)
|
|
|
+- **数据库**: PostgreSQL 17 (通过TypeORM进行数据持久化存储)
|
|
|
+- **ORM**: TypeORM 0.3.25 (数据库操作抽象,实体管理)
|
|
|
+- **测试框架**: Vitest 2.x (单元测试框架,更好的TypeORM支持)
|
|
|
+- **API测试**: hono/testing (内置,API端点测试,更好的类型安全)
|
|
|
+
|
|
|
+### 项目结构信息 [Source: architecture/source-tree.md]
|
|
|
+- **包管理**: 使用pnpm workspace管理多包依赖关系
|
|
|
+- **包架构层次**:
|
|
|
+ - **基础设施层**: shared-types → shared-utils → shared-crud
|
|
|
+ - **测试基础设施**: shared-test-util
|
|
|
+ - **业务模块层**: 多租户模块包(-mt后缀),支持租户数据隔离
|
|
|
+ - **应用层**: server (重构后)
|
|
|
+- **多租户架构**:
|
|
|
+ - **包复制策略**: 基于Epic-007方案,通过复制单租户包创建多租户版本
|
|
|
+ - **租户隔离**: 通过租户ID实现数据隔离,支持多租户部署
|
|
|
+ - **后端包**: 10个多租户模块包,支持租户数据隔离
|
|
|
+- **文件命名**: 保持现有kebab-case命名约定
|
|
|
+- **模块化架构**: 采用分层包结构,支持按需安装和独立开发
|
|
|
+
|
|
|
+### 编码标准 [Source: architecture/coding-standards.md]
|
|
|
+- **代码风格**: TypeScript严格模式,一致的缩进和命名
|
|
|
+- **测试位置**: `__tests__` 文件夹与源码并列(但实际使用`tests/`目录)
|
|
|
+- **覆盖率目标**: 核心业务逻辑 > 80%
|
|
|
+- **测试类型**: 单元测试、集成测试、E2E测试
|
|
|
+- **现有API兼容性**: 确保测试不破坏现有API契约
|
|
|
+- **数据库集成**: 使用测试数据库,避免污染生产数据
|
|
|
+
|
|
|
+### 测试策略 [Source: architecture/testing-strategy.md]
|
|
|
+- **单元测试范围**: 单个函数、类或组件,验证独立单元的正确性
|
|
|
+- **单元测试位置**: `packages/*-module/tests/unit/**/*.test.ts`
|
|
|
+- **集成测试范围**: 多个组件/服务协作,验证模块间集成和交互
|
|
|
+- **集成测试位置**: `packages/*-module/tests/integration/**/*.test.ts`
|
|
|
+- **测试框架**: Vitest + Testing Library + hono/testing + shared-test-util
|
|
|
+- **单元测试覆盖率目标**: ≥ 80%
|
|
|
+- **集成测试覆盖率目标**: ≥ 60%
|
|
|
+- **测试执行频率**: 单元测试每次代码变更,集成测试每次API变更
|
|
|
+
|
|
|
+### 数据模型设计 [Source: docs/prd/epic-004-credit-payment.md#数据库设计]
|
|
|
+**credit_balance_mt表结构**:
|
|
|
+```sql
|
|
|
+CREATE TABLE credit_balance_mt (
|
|
|
+ id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
|
|
+ tenant_id INT UNSIGNED NOT NULL COMMENT '租户ID',
|
|
|
+ user_id INT UNSIGNED NOT NULL COMMENT '用户ID',
|
|
|
+ total_limit DECIMAL(10,2) DEFAULT 0.00 COMMENT '总额度',
|
|
|
+ used_amount DECIMAL(10,2) DEFAULT 0.00 COMMENT '已用额度',
|
|
|
+ available_amount DECIMAL(10,2) GENERATED ALWAYS AS (total_limit - used_amount) STORED COMMENT '可用额度',
|
|
|
+ is_enabled TINYINT DEFAULT 1 COMMENT '是否启用(0:禁用,1:启用)',
|
|
|
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
+ UNIQUE KEY uk_tenant_user (tenant_id, user_id),
|
|
|
+ INDEX idx_tenant_id (tenant_id),
|
|
|
+ INDEX idx_user_id (user_id)
|
|
|
+) COMMENT='用户信用额度表';
|
|
|
+```
|
|
|
+
|
|
|
+**credit_balance_log_mt表结构**:
|
|
|
+```sql
|
|
|
+CREATE TABLE credit_balance_log_mt (
|
|
|
+ id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
|
|
+ tenant_id INT UNSIGNED NOT NULL COMMENT '租户ID',
|
|
|
+ user_id INT UNSIGNED NOT NULL COMMENT '用户ID',
|
|
|
+ change_type VARCHAR(20) NOT NULL COMMENT '变更类型: SET_LIMIT(设置额度), PAYMENT(支付扣减), CHECKOUT(结账恢复), CANCEL_ORDER(取消订单恢复), REFUND(退款恢复), ADJUST(调整额度)',
|
|
|
+ change_amount DECIMAL(10,2) NOT NULL COMMENT '变更金额(正数表示增加额度,负数表示减少额度)',
|
|
|
+ before_total DECIMAL(10,2) COMMENT '变更前总额度',
|
|
|
+ after_total DECIMAL(10,2) COMMENT '变更后总额度',
|
|
|
+ before_used DECIMAL(10,2) COMMENT '变更前已用额度',
|
|
|
+ after_used DECIMAL(10,2) COMMENT '变更后已用额度',
|
|
|
+ reference_id VARCHAR(100) COMMENT '关联ID(订单号等)',
|
|
|
+ remark VARCHAR(500) COMMENT '备注',
|
|
|
+ operator_id INT UNSIGNED COMMENT '操作人ID',
|
|
|
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ INDEX idx_tenant_user (tenant_id, user_id),
|
|
|
+ INDEX idx_reference (reference_id),
|
|
|
+ INDEX idx_created (created_at)
|
|
|
+) COMMENT='额度变更记录表';
|
|
|
+```
|
|
|
+
|
|
|
+### API设计 [Source: docs/prd/epic-004-credit-payment.md#API设计]
|
|
|
+**对外API(供UI调用)**:
|
|
|
+1. `GET /api/credit-balance/{userId}` - 查询用户额度
|
|
|
+2. `PUT /api/credit-balance/{userId}` - 设置用户额度
|
|
|
+3. `POST /api/credit-balance/{userId}/adjust` - 调整用户额度
|
|
|
+4. `GET /api/credit-balance/{userId}/logs` - 查询额度变更记录
|
|
|
+5. `POST /api/credit-balance/payment` - 额度支付
|
|
|
+6. `POST /api/credit-balance/checkout` - 结账恢复额度
|
|
|
+
|
|
|
+**服务接口(供其他模块调用)**:
|
|
|
+1. `CreditBalanceService.restoreBalanceForCancelOrder(orderId, userId, amount)` - 取消订单恢复额度
|
|
|
+2. `CreditBalanceService.restoreBalanceForRefund(orderId, userId, refundAmount)` - 退款恢复额度
|
|
|
+
|
|
|
+**设计说明**:
|
|
|
+- **结账恢复**: 需要人工确认,因此通过信用管理UI手动触发,调用`/api/credit-balance/checkout`接口
|
|
|
+- **取消订单恢复**: 自动触发,订单模块在取消订单时直接调用`CreditBalanceService.restoreBalanceForCancelOrder()`方法
|
|
|
+- **退款恢复**: 自动触发,支付模块在退款处理时直接调用`CreditBalanceService.restoreBalanceForRefund()`方法
|
|
|
+- **模块间调用**: 使用PNPM工作空间,通过`@d8d/credit-balance-module-mt`包名导入服务类进行直接调用
|
|
|
+
|
|
|
+### 模块结构 [Source: docs/prd/epic-004-credit-payment.md#模块结构]
|
|
|
+```
|
|
|
+packages/
|
|
|
+├── @d8d/credit-balance-module-mt/ # 多租户余额模块
|
|
|
+│ ├── src/
|
|
|
+│ │ ├── entities/ # 实体定义
|
|
|
+│ │ │ ├── credit-balance.mt.entity.ts
|
|
|
+│ │ │ └── credit-balance-log.mt.entity.ts
|
|
|
+│ │ │ └── index.ts
|
|
|
+│ │ ├── services/ # 服务层
|
|
|
+│ │ │ ├── credit-balance.service.ts
|
|
|
+│ │ │ └── index.ts
|
|
|
+│ │ ├── schemas/ # 数据验证
|
|
|
+│ │ │ └── index.ts
|
|
|
+│ │ ├── routes/ # API路由
|
|
|
+│ │ │ └── index.ts
|
|
|
+│ │ ├── types/ # 类型定义
|
|
|
+│ │ │ └── index.ts
|
|
|
+│ │ └── index.ts # 主入口文件
|
|
|
+│ ├── tests/ # 测试文件
|
|
|
+│ ├── tsconfig.json # TypeScript配置
|
|
|
+│ ├── vitest.config.ts # 测试配置
|
|
|
+│ └── package.json
|
|
|
+```
|
|
|
+
|
|
|
+### 文件位置和命名约定
|
|
|
+- **实体文件**: `packages/credit-balance-module-mt/src/entities/credit-balance.mt.entity.ts`
|
|
|
+- **服务文件**: `packages/credit-balance-module-mt/src/services/credit-balance.service.mt.ts`
|
|
|
+- **路由文件**: `packages/credit-balance-module-mt/src/routes/index.mt.ts`
|
|
|
+- **Schema文件**: `packages/credit-balance-module-mt/src/schemas/index.mt.ts`
|
|
|
+- **类型文件**: `packages/credit-balance-module-mt/src/types/index.mt.ts`
|
|
|
+- **主入口文件**: `packages/credit-balance-module-mt/src/index.mt.ts` (导出所有模块接口)
|
|
|
+
|
|
|
+### 多租户实体命名模式
|
|
|
+基于现有多租户模块观察:
|
|
|
+- **实体类名**: 以`Mt`结尾(如`CreditBalanceMt`, `CreditBalanceLogMt`)
|
|
|
+- **表名**: 以`_mt`结尾(如`credit_balance_mt`, `credit_balance_log_mt`)
|
|
|
+- **文件命名**: `*.mt.ts` 或 `*.entity.ts`
|
|
|
+- **必须包含**: `tenant_id`字段用于租户隔离
|
|
|
+
|
|
|
+### 技术约束
|
|
|
+- **数据库**: 使用PostgreSQL 17,支持DECIMAL类型存储金额
|
|
|
+- **事务处理**: 额度扣减和恢复必须使用数据库事务确保数据一致性
|
|
|
+- **幂等性**: 额度恢复操作需要实现幂等性检查,防止重复恢复
|
|
|
+- **金额验证**: 恢复金额不能超过原支付金额
|
|
|
+- **状态检查**: 只有特定订单状态才能触发恢复
|
|
|
+- **日志记录**: 每次额度变更都必须记录详细的变更日志
|
|
|
+
|
|
|
+### 集成点
|
|
|
+1. **用户模块集成**: 通过`user_id`关联用户信息
|
|
|
+2. **订单模块集成**: 订单模块导入`@d8d/credit-balance-module-mt`包,直接调用`CreditBalanceService.restoreBalanceForCancelOrder()`方法
|
|
|
+3. **支付模块集成**: 支付模块导入`@d8d/credit-balance-module-mt`包,直接调用`CreditBalanceService.restoreBalanceForRefund()`方法
|
|
|
+
|
|
|
+### 测试要求
|
|
|
+- **单元测试**: 测试额度计算逻辑、额度扣减和恢复、额度验证
|
|
|
+- **集成测试**: 测试额度支付流程、额度恢复流程、与订单模块集成测试
|
|
|
+- **边界条件测试**: 额度不足、重复操作、无效金额等场景
|
|
|
+- **覆盖率**: 核心业务逻辑必须达到80%以上单元测试覆盖率
|
|
|
+
|
|
|
+### 项目结构注意事项
|
|
|
+- 需要遵循现有的多租户包架构模式
|
|
|
+- 模块应该创建为独立的多租户包:`packages/credit-balance-module-mt/`
|
|
|
+- 包名应为:`@d8d/credit-balance-module-mt`
|
|
|
+- 需要正确配置pnpm workspace依赖关系
|
|
|
+- **注意**:TypeORM迁移脚本将在server包中使用此模块时创建,不在模块包中创建
|
|
|
+- 参考现有的多租户模块包(如`advertisements-module-mt`)的结构和配置
|
|
|
+
|
|
|
+### 没有在架构文档中找到的特定指导
|
|
|
+- 具体的TypeORM实体装饰器配置示例
|
|
|
+- 具体的Hono路由实现示例
|
|
|
+- 具体的测试数据工厂模式实现
|
|
|
+- **迁移脚本创建时机**:根据项目架构,TypeORM迁移脚本应在server包中使用模块时创建,而不是在模块包中创建
|
|
|
+
|
|
|
+## Testing
|
|
|
+### 测试标准 [Source: architecture/testing-strategy.md]
|
|
|
+- **测试文件位置**: `packages/credit-balance-module-mt/tests/` 目录下
|
|
|
+- **单元测试位置**: `tests/unit/**/*.test.ts`
|
|
|
+- **集成测试位置**: `tests/integration/**/*.test.ts`
|
|
|
+- **测试框架**: Vitest + hono/testing + shared-test-util
|
|
|
+- **覆盖率要求**: 单元测试 ≥ 80%,集成测试 ≥ 60%
|
|
|
+- **测试模式**: 使用测试数据工厂模式,避免硬编码测试数据
|
|
|
+- **数据库测试**: 使用专用测试数据库,事务回滚机制
|
|
|
+
|
|
|
+### 测试策略要求
|
|
|
+- **单元测试**: 验证单个服务方法、实体定义、Schema验证
|
|
|
+- **集成测试**: 验证API端点功能、模块间协作、数据库操作
|
|
|
+- **边界测试**: 测试额度不足、无效输入、重复操作等边界条件
|
|
|
+- **错误处理测试**: 测试各种错误场景和异常情况
|
|
|
+- **性能测试**: 确保API响应时间 < 100ms (p95)
|
|
|
+
|
|
|
+### 测试数据管理
|
|
|
+- 使用测试数据工厂模式创建测试数据
|
|
|
+- 每个测试后清理测试数据(事务回滚)
|
|
|
+- 使用唯一标识符确保测试数据隔离
|
|
|
+- 模拟外部依赖(如用户模块、订单模块)
|
|
|
+
|
|
|
+## Change Log
|
|
|
+| Date | Version | Description | Author |
|
|
|
+|------|---------|-------------|--------|
|
|
|
+| 2025-12-01 | 1.0 | 初始故事创建 | Bob (Scrum Master) |
|
|
|
+
|
|
|
+## Dev Agent Record
|
|
|
+*此部分由开发代理在实现过程中填写*
|
|
|
+
|
|
|
+### Agent Model Used
|
|
|
+*待开发代理填写*
|
|
|
+
|
|
|
+### Debug Log References
|
|
|
+*待开发代理填写*
|
|
|
+
|
|
|
+### Completion Notes List
|
|
|
+*待开发代理填写*
|
|
|
+
|
|
|
+### File List
|
|
|
+*待开发代理填写*
|
|
|
+
|
|
|
+## QA Results
|
|
|
+*此部分由QA代理在审查完成后填写*
|