Files
EmailBill/openspec/specs/budget-stats/spec.md

49 lines
3.0 KiB
Markdown
Raw Normal View History

2026-02-18 21:16:45 +08:00
## MODIFIED Requirements
### Requirement: Budget statistics API response includes complete data
预算统计 API (`GET /api/budget/stats/{category}`) SHALL 返回完整的统计数据,包括用于前端图表渲染的 `Trend` 数组和用于明细弹窗的 `Description` HTML 内容。
响应结构中的 `Month``Year` 对象 MUST 包含以下字段:
- `Limit`: 预算限额
- `Current`: 当前实际金额
- `Remaining`: 剩余金额
- `UsagePercentage`: 使用百分比
- `Trend`: 每日/每月累计金额数组 (`List<decimal?>`)
- `Description`: HTML 格式的详细说明,包含计算公式和数据表格 (`string`)
#### Scenario: Monthly stats with trend data
- **WHEN** 客户端请求月度预算统计 `GET /api/budget/stats/food?date=2026-02`
- **THEN** 响应的 `month` 对象包含 `trend` 数组长度等于该月天数如28/29/30/31
- **AND** `trend` 数组每个元素表示截至该天的累计金额(支出类为递减,收入类为递增)
- **AND** `trend` 数组中未到达的日期对应的元素为 `null`
#### Scenario: Monthly stats with description
- **WHEN** 客户端请求月度预算统计 `GET /api/budget/stats/food?date=2026-02`
- **THEN** 响应的 `month` 对象包含 `description` 字段
- **AND** `description` 是 HTML 格式字符串,包含 `<table>` 标签展示明细数据
- **AND** `description` 包含计算公式说明(如"剩余 = 限额 - 已用"
#### Scenario: Yearly stats with trend data
- **WHEN** 客户端请求年度预算统计 `GET /api/budget/stats/salary?date=2026`
- **THEN** 响应的 `year` 对象包含 `trend` 数组长度为12代表12个月
- **AND** `trend` 数组每个元素表示截至该月的累计金额
- **AND** `trend` 数组中未到达的月份对应的元素为 `null`
#### Scenario: Yearly stats with description
- **WHEN** 客户端请求年度预算统计 `GET /api/budget/stats/salary?date=2026`
- **THEN** 响应的 `year` 对象包含 `description` 字段
- **AND** `description` 是 HTML 格式字符串,包含年度统计明细
### Requirement: DTO mapping preserves all Service layer data
Application 层的 `BudgetApplication.GetCategoryStatsAsync` 方法在将 Service 层的 `BudgetStatsDto` 映射到 API 响应 DTO 时MUST 保留所有数据字段,不得丢失 `Trend``Description`
#### Scenario: Mapping from Service DTO to API DTO
- **WHEN** `BudgetApplication.GetCategoryStatsAsync` 接收到 Service 层返回的 `BudgetStatsDto`
- **THEN** 映射后的 `BudgetStatsDetail` 对象包含 `Trend` 字段,其值等于 `BudgetStatsDto.Month.Trend``BudgetStatsDto.Year.Trend`
- **AND** 映射后的 `BudgetStatsDetail` 对象包含 `Description` 字段,其值等于 `BudgetStatsDto.Month.Description``BudgetStatsDto.Year.Description`
#### Scenario: API response schema validation
- **WHEN** 前端调用 `/api/budget/stats/{category}` 并解析 JSON 响应
- **THEN** TypeScript 类型检查不报错,响应对象符合 `BudgetStatsResponse` 接口定义
- **AND** `month.trend``month.description` 字段存在且非 `undefined`