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

13 KiB
Raw Blame History

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_CLOSUREDORMANT_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 会携带异常账户命中计划和账户事实:

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:

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. 新增规则池常量:
ABNORMAL_ACCOUNT_RULE_CODES = [
    "SUDDEN_ACCOUNT_CLOSURE",
    "DORMANT_ACCOUNT_LARGE_ACTIVATION",
]
  1. 扩展 FileRecord 字段:
abnormal_account_hit_rules: List[str] = field(default_factory=list)
abnormal_accounts: List[dict] = field(default_factory=list)
  1. _build_subset_rule_hit_plan(...)_build_all_compatible_rule_hit_plan(...)_apply_rule_hit_plan_to_record(...) 中纳入 abnormal_account_hit_rules
  2. 新增最小账户事实生成方法,并在 fetch_inner_flow(...) / 上传链路创建记录时写入 abnormal_accounts
  • Step 4: Run test to verify it passes

Run:

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

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 中新增两条失败测试,分别锁定两条规则的样本口径:

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:

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. 新增:
def build_sudden_account_closure_samples(...): ...
def build_dormant_account_large_activation_samples(...): ...
  1. 造数要求:
    • SUDDEN_ACCOUNT_CLOSURE 所有流水落在销户前 30 天窗口内
    • DORMANT_ACCOUNT_LARGE_ACTIVATION 首笔流水晚于开户满 6 个月
    • 休眠账户样本同时满足累计金额和单笔最大金额阈值
  • Step 4: Run test to verify it passes

Run:

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

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 中新增失败测试,锁定服务层会按命中计划混入异常账户样本:

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:

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_rulesrecord.abnormal_accounts 传给样本构造入口
  • Step 4: Run targeted test to verify it passes

Run:

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

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:

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:

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:

cd lsfx-mock-server
python3 -m pytest tests/test_statement_service.py -v

Expected:

  • PASS

  • Step 5: Commit

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服务后端实施记录"