Files
ccdi/docs/plans/backend/2026-03-31-lsfx-mock-server-abnormal-account-backend-implementation-plan.md

384 lines
13 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.
# LSFX Mock Server 异常账户命中流水后端 Implementation Plan
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
>
> 仓库约束:当前仓库明确禁止开启 subagent执行时统一使用 `superpowers:executing-plans`。
**Goal:** 在现有 `lsfx-mock-server` 中补齐异常账户命中计划、最小账户事实和可命中后端 SQL 的流水样本,让同一个 `logId` 下稳定命中 `SUDDEN_ACCOUNT_CLOSURE``DORMANT_ACCOUNT_LARGE_ACTIVATION`
**Architecture:** 复用现有 `FileService -> FileRecord -> StatementService -> build_seed_statements_for_rule_plan(...)` 主链路,不新增独立接口或平行造数模块。异常账户能力拆成三层:`FileRecord` 持有命中计划与账户事实、`statement_rule_samples.py` 生成异常账户样本、`StatementService` 统一混入种子流水并继续补噪声与分页。
**Tech Stack:** Python 3, FastAPI, pytest, dataclasses, Markdown docs
---
## File Structure
- `lsfx-mock-server/services/file_service.py`: 扩展 `FileRecord`,增加异常账户规则池、命中计划和最小账户事实生成逻辑。
- `lsfx-mock-server/services/statement_rule_samples.py`: 定义异常账户事实结构,并新增两类异常账户样本生成器及统一接入点。
- `lsfx-mock-server/services/statement_service.py`: 消费 `FileRecord` 中新增的异常账户计划,让种子流水能混入异常账户命中样本。
- `lsfx-mock-server/tests/test_file_service.py`: 锁定异常账户命中计划与账户事实生成行为。
- `lsfx-mock-server/tests/test_statement_service.py`: 锁定异常账户样本日期窗口、金额阈值与服务层混入行为。
- `docs/reports/implementation/2026-03-31-lsfx-mock-server-abnormal-account-backend-implementation.md`: 记录本次 Mock 服务后端实施结果。
- `docs/tests/records/2026-03-31-lsfx-mock-server-abnormal-account-backend-verification.md`: 记录 pytest 验证命令、结果与进程清理结论。
## Task 1: 扩展 `FileRecord` 并锁定异常账户命中计划
**Files:**
- Modify: `lsfx-mock-server/services/file_service.py`
- Modify: `lsfx-mock-server/tests/test_file_service.py`
- Reference: `docs/design/2026-03-31-lsfx-mock-server-abnormal-account-design.md`
- [ ] **Step 1: Write the failing test**
先在 `lsfx-mock-server/tests/test_file_service.py` 中新增失败用例,锁定 `fetch_inner_flow(...)` 生成的 `FileRecord` 会携带异常账户命中计划和账户事实:
```python
def test_fetch_inner_flow_should_attach_abnormal_account_rule_plan():
service = FileService(staff_identity_repository=FakeStaffIdentityRepository())
response = service.fetch_inner_flow(
{
"groupId": 1001,
"customerNo": "customer_abnormal_account",
"dataChannelCode": "test_code",
"requestDateId": 20240101,
"dataStartDateId": 20240101,
"dataEndDateId": 20240131,
"uploadUserId": 902001,
}
)
log_id = response["data"][0]
record = service.file_records[log_id]
assert hasattr(record, "abnormal_account_hit_rules")
assert hasattr(record, "abnormal_accounts")
assert isinstance(record.abnormal_account_hit_rules, list)
assert isinstance(record.abnormal_accounts, list)
```
- [ ] **Step 2: Run test to verify it fails**
Run:
```bash
cd lsfx-mock-server
python3 -m pytest tests/test_file_service.py::test_fetch_inner_flow_should_attach_abnormal_account_rule_plan -v
```
Expected:
- `FAIL`
- 原因是 `FileRecord` 还没有异常账户相关字段
- [ ] **Step 3: Write minimal implementation**
`lsfx-mock-server/services/file_service.py` 中按最小路径补齐:
1. 新增规则池常量:
```python
ABNORMAL_ACCOUNT_RULE_CODES = [
"SUDDEN_ACCOUNT_CLOSURE",
"DORMANT_ACCOUNT_LARGE_ACTIVATION",
]
```
2. 扩展 `FileRecord` 字段:
```python
abnormal_account_hit_rules: List[str] = field(default_factory=list)
abnormal_accounts: List[dict] = field(default_factory=list)
```
3.`_build_subset_rule_hit_plan(...)``_build_all_compatible_rule_hit_plan(...)``_apply_rule_hit_plan_to_record(...)` 中纳入 `abnormal_account_hit_rules`
4. 新增最小账户事实生成方法,并在 `fetch_inner_flow(...)` / 上传链路创建记录时写入 `abnormal_accounts`
- [ ] **Step 4: Run test to verify it passes**
Run:
```bash
cd lsfx-mock-server
python3 -m pytest tests/test_file_service.py::test_fetch_inner_flow_should_attach_abnormal_account_rule_plan -v
```
Expected:
- `PASS`
- `FileRecord` 已稳定保存异常账户命中计划和账户事实列表
- [ ] **Step 5: Commit**
```bash
git add lsfx-mock-server/services/file_service.py lsfx-mock-server/tests/test_file_service.py
git commit -m "补充异常账户命中计划与账户事实"
```
## Task 2: 先写异常账户样本生成器的失败测试
**Files:**
- Modify: `lsfx-mock-server/services/statement_rule_samples.py`
- Modify: `lsfx-mock-server/tests/test_statement_service.py`
- Reference: `docs/design/2026-03-31-lsfx-mock-server-abnormal-account-design.md`
- [ ] **Step 1: Write the failing tests**
`lsfx-mock-server/tests/test_statement_service.py` 中新增两条失败测试,分别锁定两条规则的样本口径:
```python
def test_sudden_account_closure_samples_should_stay_within_30_days_before_invalid_date():
statements = build_sudden_account_closure_samples(
group_id=1000,
log_id=20001,
account_fact={
"account_no": "6222000000000001",
"owner_id_card": "320101199001010030",
"account_name": "测试员工工资卡",
"status": 2,
"effective_date": "2024-01-01",
"invalid_date": "2026-03-20",
},
le_name="测试主体",
)
assert statements
assert all("6222000000000001" == item["accountMaskNo"] for item in statements)
assert all("2026-02-18" <= item["trxDate"][:10] < "2026-03-20" for item in statements)
def test_dormant_account_large_activation_samples_should_exceed_threshold_after_6_months():
statements = build_dormant_account_large_activation_samples(
group_id=1000,
log_id=20001,
account_fact={
"account_no": "6222000000000002",
"owner_id_card": "320101199001010030",
"account_name": "测试员工工资卡",
"status": 1,
"effective_date": "2025-01-01",
"invalid_date": None,
},
le_name="测试主体",
)
assert statements
assert min(item["trxDate"][:10] for item in statements) >= "2025-07-01"
assert sum(item["drAmount"] + item["crAmount"] for item in statements) >= 500000
assert max(item["drAmount"] + item["crAmount"] for item in statements) >= 100000
```
- [ ] **Step 2: Run test to verify it fails**
Run:
```bash
cd lsfx-mock-server
python3 -m pytest tests/test_statement_service.py -k "sudden_account_closure or dormant_account_large_activation" -v
```
Expected:
- `FAIL`
- 原因是异常账户样本生成器尚不存在
- [ ] **Step 3: Write minimal implementation**
`lsfx-mock-server/services/statement_rule_samples.py` 中补齐最小实现:
1. 定义异常账户事实结构或约定字典字段
2. 新增:
```python
def build_sudden_account_closure_samples(...): ...
def build_dormant_account_large_activation_samples(...): ...
```
3. 造数要求:
- `SUDDEN_ACCOUNT_CLOSURE` 所有流水落在销户前 30 天窗口内
- `DORMANT_ACCOUNT_LARGE_ACTIVATION` 首笔流水晚于开户满 6 个月
- 休眠账户样本同时满足累计金额和单笔最大金额阈值
- [ ] **Step 4: Run test to verify it passes**
Run:
```bash
cd lsfx-mock-server
python3 -m pytest tests/test_statement_service.py -k "sudden_account_closure or dormant_account_large_activation" -v
```
Expected:
- `PASS`
- 两类样本的日期和金额口径与设计一致
- [ ] **Step 5: Commit**
```bash
git add lsfx-mock-server/services/statement_rule_samples.py lsfx-mock-server/tests/test_statement_service.py
git commit -m "补充异常账户规则样本生成器"
```
## Task 3: 将异常账户样本接入统一种子流水构造
**Files:**
- Modify: `lsfx-mock-server/services/statement_rule_samples.py`
- Modify: `lsfx-mock-server/services/statement_service.py`
- Modify: `lsfx-mock-server/tests/test_statement_service.py`
- [ ] **Step 1: Write the failing service-level test**
`lsfx-mock-server/tests/test_statement_service.py` 中新增失败测试,锁定服务层会按命中计划混入异常账户样本:
```python
def test_generate_statements_should_follow_abnormal_account_rule_plan_from_file_record():
file_service = FileService(staff_identity_repository=FakeStaffIdentityRepository())
statement_service = StatementService(file_service=file_service)
response = file_service.fetch_inner_flow(
{
"groupId": 1001,
"customerNo": "customer_abnormal_rule_plan",
"dataChannelCode": "test_code",
"requestDateId": 20240101,
"dataStartDateId": 20240101,
"dataEndDateId": 20240131,
"uploadUserId": 902001,
}
)
log_id = response["data"][0]
record = file_service.file_records[log_id]
record.abnormal_account_hit_rules = ["SUDDEN_ACCOUNT_CLOSURE"]
record.abnormal_accounts = [
{
"account_no": "6222000000000001",
"owner_id_card": record.staff_id_card,
"account_name": "测试员工工资卡",
"status": 2,
"effective_date": "2024-01-01",
"invalid_date": "2026-03-20",
}
]
statements = statement_service._generate_statements(group_id=1001, log_id=log_id, count=80)
assert any(item["accountMaskNo"] == "6222000000000001" for item in statements)
assert any("销户" in item["userMemo"] or "异常账户" in item["userMemo"] for item in statements)
```
- [ ] **Step 2: Run test to verify it fails**
Run:
```bash
cd lsfx-mock-server
python3 -m pytest tests/test_statement_service.py::test_generate_statements_should_follow_abnormal_account_rule_plan_from_file_record -v
```
Expected:
- `FAIL`
- 原因是种子流水构造入口尚未消费异常账户命中计划
- [ ] **Step 3: Write minimal implementation**
实现顺序:
1.`build_seed_statements_for_rule_plan(...)` 中增加 `abnormal_account_hit_rules` 入参消费
2. 根据 `abnormal_accounts` 逐条匹配调用对应样本生成器
3.`StatementService._generate_statements(...)` 中把 `record.abnormal_account_hit_rules``record.abnormal_accounts` 传给样本构造入口
- [ ] **Step 4: Run targeted test to verify it passes**
Run:
```bash
cd lsfx-mock-server
python3 -m pytest tests/test_statement_service.py::test_generate_statements_should_follow_abnormal_account_rule_plan_from_file_record -v
```
Expected:
- `PASS`
- 服务层已能按 `FileRecord` 中的异常账户计划稳定混入命中样本
- [ ] **Step 5: Commit**
```bash
git add lsfx-mock-server/services/statement_rule_samples.py lsfx-mock-server/services/statement_service.py lsfx-mock-server/tests/test_statement_service.py
git commit -m "接入异常账户命中流水主链路"
```
## Task 4: 跑回归测试并补实施记录
**Files:**
- Create: `docs/reports/implementation/2026-03-31-lsfx-mock-server-abnormal-account-backend-implementation.md`
- Create: `docs/tests/records/2026-03-31-lsfx-mock-server-abnormal-account-backend-verification.md`
- Modify: `lsfx-mock-server/README.md`
- [ ] **Step 1: Run focused backend regression**
Run:
```bash
cd lsfx-mock-server
python3 -m pytest tests/test_file_service.py tests/test_statement_service.py -v
```
Expected:
- `PASS`
- 异常账户相关新增测试和既有流水造数测试均通过
- [ ] **Step 2: Run full mock-server regression**
Run:
```bash
cd lsfx-mock-server
python3 -m pytest tests/ -v
```
Expected:
- `PASS`
- 无异常账户改造引入的回归失败
- [ ] **Step 3: Update docs**
在实施记录中至少写明:
- 新增的异常账户命中计划字段
- 两类异常账户样本生成器
- 服务层如何接入现有种子流水主链路
- 验证命令与结果
在验证记录中至少写明:
- 执行过的 pytest 命令
- 结果摘要
- 本轮未启动额外前后端进程,因此无需清理残留进程
如果 README 已描述规则计划结构,同步补充 `abnormal_account_hit_rules` 说明;否则可只补最小联调说明。
- [ ] **Step 4: Re-run docs-relevant verification if README changed**
Run:
```bash
cd lsfx-mock-server
python3 -m pytest tests/test_statement_service.py -v
```
Expected:
- `PASS`
- [ ] **Step 5: Commit**
```bash
git add lsfx-mock-server/README.md docs/reports/implementation/2026-03-31-lsfx-mock-server-abnormal-account-backend-implementation.md docs/tests/records/2026-03-31-lsfx-mock-server-abnormal-account-backend-verification.md
git commit -m "完成异常账户Mock服务后端实施记录"
```