bindbox-game/.planning/REQUIREMENTS.md
2026-03-21 16:37:24 +08:00

109 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Requirements: Bindbox Game 盈亏统计函数
**Defined:** 2026-03-21
**Core Value:** 提供可复用的盈亏统计方法,使平台运营能从用户和活动两个维度快速了解各类资产的收支状况
## v1 Requirements
Requirements for initial release. Each maps to roadmap phases.
### Core P&L Functions
- [ ] **PNL-01**: 函数接收 ProfitLossParams 参数结构体所有字段可选资产类型、维度ID、时间范围
- [ ] **PNL-02**: Revenue 计算口径为 actual_amount + discount_amount排除已退款/取消订单status=3,4
- [ ] **PNL-03**: Game-pass 订单通过 finance.IsGamePassOrder 三条件检测source_type=4、order_no LIKE 'GP%'、remark含use_game_pass与现金收入严格互斥
- [ ] **PNL-04**: Game-pass 订单收入通过 finance.ComputeGamePassValue 计算draw_count × activity_price
- [ ] **PNL-05**: Prize cost 通过 finance.ComputePrizeCostWithMultiplier 计算,包含道具卡倍率
- [ ] **PNL-06**: Profit 通过 finance.ComputeProfit 计算,返回 int64 分 + float64 利润率
- [ ] **PNL-07**: 排除已作废库存remark LIKE '%void%' 或 status=2不计入成本
- [ ] **PNL-08**: 兼容 order_id=0 或 NULL 的历史数据(不受订单状态过滤影响)
### Query Dimensions
- [ ] **DIM-01**: QueryUserProfitLoss 接收 []int64 用户ID空切片=统计全部用户
- [ ] **DIM-02**: QueryActivityProfitLoss 接收 []int64 活动ID空切片=统计全部活动
- [ ] **DIM-03**: 时间范围过滤使用 *time.Timenil=不限),不使用零值作哨兵
- [ ] **DIM-04**: AssetType 可选过滤nil/All(0)=统计全部资产类型
### Return Structure
- [ ] **RET-01**: ProfitLossResult 包含汇总数据:总收入、总成本、净盈亏、利润率
- [ ] **RET-02**: ProfitLossResult 包含 []ProfitLossBreakdown 按资产类型拆分明细
- [ ] **RET-03**: 所有金额以 int64 分为单位,不使用 float64 存储金额
### Asset Types
- [ ] **AST-01**: 定义 AssetType 枚举Points(1)、Coupon(2)、ItemCard(3)、Product(4)、Fragment(5)、All(0)
- [ ] **AST-02**: 每种资产类型对应不同的数据源表和 JOIN 路径
- [ ] **AST-03**: Fragment 成本从 fragment_synthesis_logs 表获取
### Code Quality
- [ ] **QUA-01**: 新函数放在 internal/service/finance/ 包下
- [ ] **QUA-02**: Service 构造器仅注入 DbR读库包内不出现 GetDbW() 调用
- [ ] **QUA-03**: 每个 Scan() 调用必须检查 .Error 并返回错误,不静默吞掉
- [ ] **QUA-04**: 复用现有 finance.* 工具函数ClassifyOrderSpending、IsGamePassOrder 等),不重复实现
- [ ] **QUA-05**: 使用 fan-out + in-memory merge 查询模式(多次独立 ScanGo 层合并)
## v2 Requirements
Deferred to future release.
### Performance & Caching
- **PERF-01**: Redis TTL 缓存包装(查询延迟超过 2s 时启用)
- **PERF-02**: 增量/时间桶聚合 + 物化统计表
### Integration
- **INT-01**: 抖音/直播间订单纳入用户维度盈亏统计
- **INT-02**: 新增对应 Admin API endpoint 供前端调用
## Out of Scope
| Feature | Reason |
|---------|--------|
| 复用现有 Dashboard 盈亏逻辑 | 现有逻辑耦合 HTTP 上下文,计算口径不一致 |
| Service 层内置缓存 | 缓存属于调用层责任,不应在 Service 函数内实现 |
| 分页 | 聚合函数返回完整结果集,分页由 API 层处理 |
| 返回格式化金额字符串 | 格式化属于展示层Service 返回 int64 分 |
| 物化表预计算 | 需要 schema 变更和写权限v1 直接查询 |
| 实时推送盈亏变化 | 需要事件基础设施,超出 v1 范围 |
## Traceability
| Requirement | Phase | Status |
|-------------|-------|--------|
| PNL-01 | Phase 1 | Pending |
| PNL-02 | Phase 1 | Pending |
| PNL-03 | Phase 1 | Pending |
| PNL-04 | Phase 1 | Pending |
| PNL-05 | Phase 1 | Pending |
| PNL-06 | Phase 1 | Pending |
| PNL-07 | Phase 1 | Pending |
| PNL-08 | Phase 1 | Pending |
| DIM-01 | Phase 1 | Pending |
| DIM-02 | Phase 1 | Pending |
| DIM-03 | Phase 1 | Pending |
| DIM-04 | Phase 1 | Pending |
| RET-01 | Phase 1 | Pending |
| RET-02 | Phase 2 | Pending |
| RET-03 | Phase 1 | Pending |
| AST-01 | Phase 1 | Pending |
| AST-02 | Phase 2 | Pending |
| AST-03 | Phase 2 | Pending |
| QUA-01 | Phase 1 | Pending |
| QUA-02 | Phase 1 | Pending |
| QUA-03 | Phase 1 | Pending |
| QUA-04 | Phase 1 | Pending |
| QUA-05 | Phase 1 | Pending |
**Coverage:**
- v1 requirements: 23 total
- Mapped to phases: 23
- Unmapped: 0 ✓
---
*Requirements defined: 2026-03-21*
*Last updated: 2026-03-21 after roadmap creation*