bindbox-game/.planning/ROADMAP.md
win b99bcbd06f docs(01-core-pnl-functions): create phase 1 plans
4 plans across 3 waves:
- 01-01 (wave 1): package scaffold — types.go, service.go, service_test.go
- 01-02 (wave 2): QueryUserProfitLoss — query_user.go + user integration tests
- 01-03 (wave 2, parallel): QueryActivityProfitLoss — query_activity.go + activity tests
- 01-04 (wave 3): phase verification — static checks + full test suite gate

Covers all 20 Phase 1 requirements: PNL-01..08, DIM-01..04, RET-01/03,
AST-01, QUA-01..05.
2026-03-21 17:27:58 +08:00

57 lines
4.3 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.

# Roadmap: Bindbox Game 盈亏统计函数
## Overview
Two reusable service-layer functions — `QueryUserProfitLoss` and `QueryActivityProfitLoss` — are built in a new `internal/service/finance/` package. Phase 1 delivers correct, working functions covering the full P&L computation path. Phase 2 populates the per-asset-type breakdown slice, including Fragment synthesis cost. The result is a clean, testable service that callers can invoke without touching HTTP handler logic.
## Phases
**Phase Numbering:**
- Integer phases (1, 2, 3): Planned milestone work
- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
Decimal phases appear between their surrounding integers in numeric order.
- [ ] **Phase 1: Core P&L Functions** - Scaffold the finance package and deliver working QueryUserProfitLoss / QueryActivityProfitLoss with correct revenue, cost, and profit
- [ ] **Phase 2: Per-Asset-Type Breakdown** - Populate the ProfitLossBreakdown slice for all 5 asset types, including Fragment synthesis cost from its own table
## Phase Details
### Phase 1: Core P&L Functions
**Goal**: Callers can invoke QueryUserProfitLoss and QueryActivityProfitLoss and receive a correct ProfitLossResult with total revenue, cost, profit, and profit rate — with all edge cases handled
**Depends on**: Nothing (first phase)
**Requirements**: PNL-01, PNL-02, PNL-03, PNL-04, PNL-05, PNL-06, PNL-07, PNL-08, DIM-01, DIM-02, DIM-03, DIM-04, RET-01, RET-03, AST-01, QUA-01, QUA-02, QUA-03, QUA-04, QUA-05
**Success Criteria** (what must be TRUE):
1. Calling QueryUserProfitLoss with a list of user IDs returns a ProfitLossResult where Revenue equals actual_amount + discount_amount for non-refunded orders only, and game-pass orders contribute draw_count × activity_price instead of cash revenue
2. Calling QueryActivityProfitLoss with an activity ID returns a ProfitLossResult where Revenue is attributed directly to the order's activity (1:1 per D-01 — no proration subquery)
3. Both functions return an error (not silent zero) when any db.Scan() call fails
4. Passing nil for StartTime/EndTime applies no time filter; passing nil/0 for AssetType returns aggregated totals across all asset types
5. The package contains no call to GetDbW() — all queries route through the injected DbR handle; voided inventory (remark LIKE '%void%' or status=2) and refunded orders (status=3,4) are excluded from cost and revenue respectively
**Plans**: 4 plans
Plans:
- [ ] 01-01-PLAN.md — Package scaffold: types.go (AssetType enum + param/result structs) + service.go (interface + read-only constructor) + service_test.go (SQLite test infrastructure)
- [ ] 01-02-PLAN.md — QueryUserProfitLoss: query_user.go with 4 fan-out scans (revenue, inventory cost, points cost, coupon cost) + integration tests
- [ ] 01-03-PLAN.md — QueryActivityProfitLoss: query_activity.go with 4 fan-out scans attributed to activity dimension + integration tests
- [ ] 01-04-PLAN.md — Phase 1 verification: full test suite + static checks (no GetDbW, fan-out count, finance functions reused, int64 monetary types)
### Phase 2: Per-Asset-Type Breakdown
**Goal**: The ProfitLossBreakdown slice in every ProfitLossResult contains one entry per relevant asset type (Points, Coupon, ItemCard, Product, Fragment), with correct per-type cost including Fragment synthesis cost sourced from fragment_synthesis_logs
**Depends on**: Phase 1
**Requirements**: AST-02, AST-03, RET-02
**Success Criteria** (what must be TRUE):
1. A ProfitLossResult for an activity that awarded Points, Coupons, and Items contains exactly one ProfitLossBreakdown entry per asset type that had non-zero cost, with the correct cost value for each
2. Fragment cost in the breakdown is sourced from fragment_synthesis_logs using the verified join path (not from user_inventory), and matches manual spot-checks against the database
3. Summing all breakdown entries' Cost fields equals the total Cost field in the parent ProfitLossResult (no gaps or double-counting between breakdown and totals)
**Plans**: TBD
## Progress
**Execution Order:**
Phases execute in numeric order: 1 → 2
| Phase | Plans Complete | Status | Completed |
|-------|----------------|--------|-----------|
| 1. Core P&L Functions | 0/4 | Planning complete | - |
| 2. Per-Asset-Type Breakdown | 0/TBD | Not started | - |