tangweijie 1460187516 docs: 添加完整技术文档体系
- 系统架构文档 (architecture/README.md)
- 6个领域文档:
  - 账户域 (01-account.md)
  - 账务域 (02-ledger.md)
  - 交易域 (03-transaction.md)
  - 对账域 (04-reconciliation.md)
  - 补偿域 (05-compensation.md)
  - 积分域 (06-points.md)
- API 参考文档 (api/README.md)
- 前后端对接清单 (integration/frontend-backend.md)
2026-01-05 18:12:37 +08:00

11 KiB
Raw Blame History

账户域 (Account Domain)

一、领域概述

账户域负责管理银行账户的完整生命周期,包括实体账户(对应真实银行账户)和虚拟子账户(在实体账户下创建的逻辑账户)。

二、核心实体

2.1 实体账户 (PhysicalAccount)

实体账户对应真实的银行账户,是资金管理的基础单元。

pub struct PhysicalAccount {
    pub id: i64,                           // 账户ID
    pub account_no: String,                // 银行账号
    pub bank_code: String,                 // 银行代码
    pub bank_name: Option<String>,         // 银行名称
    pub consistency_mode: ConsistencyMode, // 一致性模式
    pub outbound_control: OutboundControl, // 出金管控模式
    pub status: AccountStatus,             // 账户状态
    pub created_at: DateTime<Utc>,         // 创建时间
    pub updated_at: DateTime<Utc>,         // 更新时间
}

核心方法

  • is_active() - 检查账户是否可用
  • can_outbound() - 检查是否允许出金

2.2 虚拟子账户 (VirtualSubAccount)

虚拟子账户是在实体账户下创建的逻辑账户,用于资金隔离和管理。

pub struct VirtualSubAccount {
    pub id: i64,                             // 子账户ID
    pub physical_account_id: i64,            // 所属实体账户ID
    pub account_code: String,                // 子账户编号
    pub account_type: SubAccountType,        // 子账户类型
    pub valid_from: Option<DateTime<Utc>>,   // 有效期开始
    pub valid_to: Option<DateTime<Utc>>,     // 有效期结束
    pub status: AccountStatus,               // 账户状态
    pub created_at: DateTime<Utc>,           // 创建时间
    pub updated_at: DateTime<Utc>,           // 更新时间
}

核心方法

  • is_active() - 检查账户是否可用(考虑有效期)
  • is_temporary() - 是否为临时账户
  • is_expired() - 临时账户是否过期

2.3 账户控制 (AccountControl)

账户控制配置,用于设置对账频率和银行对接配置。

pub struct AccountControl {
    pub id: i64,
    pub physical_account_id: i64,
    pub reconciliation_interval: i32,        // 对账频率(分钟)
    pub direct_connect_config: Option<Value>, // 银企直连配置
    pub third_party_config: Option<Value>,    // 第三方支付配置
}

2.4 临时账户池 (SubAccountPool)

管理临时子账户的池,支持批量创建和自动销户。

pub struct SubAccountPool {
    pub id: i64,
    pub physical_account_id: i64,
    pub name: String,
    pub valid_from: DateTime<Utc>,
    pub valid_to: DateTime<Utc>,
    pub auto_close_rule: Option<Value>,  // 自动销户规则
}

三、枚举类型

3.1 账户状态 (AccountStatus)

pub enum AccountStatus {
    Active,  // 正常
    Frozen,  // 冻结
    Closed,  // 已关闭
}

状态转移规则

Active ──► Frozen ──► Active
   │                    │
   └──────► Closed ◄────┘

3.2 一致性模式 (ConsistencyMode)

pub enum ConsistencyMode {
    Strong,   // 强一致性 - 交易需等待银行确认
    Eventual, // 最终一致性 - 先记账后对账
}
模式 特点 适用场景
Strong 实时确认,响应慢 大额转账
Eventual 异步确认,响应快 小额高频

3.3 出金管控模式 (OutboundControl)

pub enum OutboundControl {
    ReceiveOnly, // 只收不付
    OnlineBank,  // 网银控制
    Token,       // 令牌控制
}
模式 说明 使用场景
ReceiveOnly 禁止出金 归集账户
OnlineBank 网银审批出金 常规账户
Token 令牌验证出金 高安全账户

3.4 账户类型 (AccountType)

pub enum AccountType {
    Physical, // 实体账户
    Virtual,  // 虚拟账户
}

3.5 子账户类型 (SubAccountType)

pub enum SubAccountType {
    Settlement,  // 结算子账户
    Management,  // 管理子账户
    Temporary,   // 临时子账户
}
类型 说明 特点
Settlement 结算账户 长期使用,用于日常结算
Management 管理账户 内部管理,资金归集
Temporary 临时账户 有有效期,自动销户

四、领域服务

4.1 AccountService

账户域的核心服务,提供账户管理功能。

impl AccountService {
    // 创建实体账户
    pub async fn create_physical_account(&self, req: CreatePhysicalAccountRequest) -> Result<PhysicalAccount>;
    
    // 获取实体账户
    pub async fn get_physical_account(&self, id: i64) -> Result<PhysicalAccount>;
    
    // 获取实体账户列表(分页)
    pub async fn list_physical_accounts_paginated(
        &self, 
        status: Option<AccountStatus>,
        keyword: Option<String>,
        page: i32,
        page_size: i32
    ) -> Result<(Vec<PhysicalAccount>, i64)>;
    
    // 冻结实体账户
    pub async fn freeze_physical_account(&self, id: i64) -> Result<()>;
    
    // 解冻实体账户
    pub async fn unfreeze_physical_account(&self, id: i64) -> Result<()>;
    
    // 创建虚拟子账户
    pub async fn create_sub_account(&self, req: CreateVirtualSubAccountRequest) -> Result<VirtualSubAccount>;
    
    // 批量创建子账户
    pub async fn batch_create_sub_accounts(&self, req: BatchCreateSubAccountRequest) -> Result<Vec<VirtualSubAccount>>;
    
    // 关闭子账户
    pub async fn close_sub_account(&self, id: i64) -> Result<()>;
    
    // 获取实体账户下的子账户列表
    pub async fn list_sub_accounts(&self, physical_account_id: i64) -> Result<Vec<VirtualSubAccount>>;
}

五、仓储接口

5.1 PhysicalAccountRepository

#[async_trait]
pub trait PhysicalAccountRepository: Send + Sync {
    async fn create(&self, account: &PhysicalAccount) -> Result<i64>;
    async fn find_by_id(&self, id: i64) -> Result<Option<PhysicalAccount>>;
    async fn find_by_account_no(&self, account_no: &str) -> Result<Option<PhysicalAccount>>;
    async fn find_all(&self) -> Result<Vec<PhysicalAccount>>;
    async fn find_paginated(&self, status: Option<AccountStatus>, keyword: Option<String>, offset: i64, limit: i64) -> Result<Vec<PhysicalAccount>>;
    async fn count(&self, status: Option<AccountStatus>, keyword: Option<String>) -> Result<i64>;
    async fn update_status(&self, id: i64, status: AccountStatus) -> Result<()>;
}

5.2 VirtualSubAccountRepository

#[async_trait]
pub trait VirtualSubAccountRepository: Send + Sync {
    async fn create(&self, account: &VirtualSubAccount) -> Result<i64>;
    async fn find_by_id(&self, id: i64) -> Result<Option<VirtualSubAccount>>;
    async fn find_by_physical_account(&self, physical_account_id: i64) -> Result<Vec<VirtualSubAccount>>;
    async fn find_expired_temporary(&self) -> Result<Vec<VirtualSubAccount>>;
    async fn update_status(&self, id: i64, status: AccountStatus) -> Result<()>;
    async fn batch_create(&self, accounts: &[VirtualSubAccount]) -> Result<Vec<i64>>;
}

六、业务规则

6.1 账户创建规则

  1. 银行账号必须唯一
  2. 实体账户必须关联有效的银行代码
  3. 子账户编号在同一实体账户下必须唯一
  4. 临时账户必须设置有效期

6.2 账户状态规则

  1. 只有 Active 状态的账户可以进行交易
  2. Frozen 状态只影响出金,入金正常
  3. Closed 状态不可进行任何交易
  4. 账户关闭前必须余额为零

6.3 出金管控规则

  1. ReceiveOnly 模式禁止任何出金操作
  2. OnlineBank 模式需要通过网银审批
  3. Token 模式需要提供有效令牌

七、API 接口

方法 路径 说明
POST /api/v1/physical-accounts 创建实体账户
GET /api/v1/physical-accounts 获取实体账户列表
GET /api/v1/physical-accounts/:id 获取实体账户详情
POST /api/v1/physical-accounts/:id/freeze 冻结实体账户资金
POST /api/v1/physical-accounts/:id/unfreeze 解冻实体账户资金
POST /api/v1/sub-accounts 创建虚拟子账户
GET /api/v1/sub-accounts/:id 获取子账户详情
GET /api/v1/sub-accounts/:id/balance 获取子账户余额
POST /api/v1/sub-accounts/:id/freeze 冻结子账户资金
POST /api/v1/sub-accounts/:id/unfreeze 解冻子账户资金
POST /api/v1/sub-accounts/:id/close 关闭子账户
GET /api/v1/physical-accounts/:id/sub-accounts 获取实体账户下的子账户列表

八、数据库表结构

8.1 physical_account 表

CREATE TABLE physical_account (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    account_no VARCHAR(64) NOT NULL UNIQUE,
    account_name VARCHAR(128),
    bank_code VARCHAR(32) NOT NULL,
    bank_name VARCHAR(128),
    consistency_mode VARCHAR(32) DEFAULT 'eventual',
    outbound_control VARCHAR(32) DEFAULT 'online_bank',
    status VARCHAR(32) DEFAULT 'active',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_bank_code (bank_code),
    INDEX idx_status (status)
);

8.2 virtual_sub_account 表

CREATE TABLE virtual_sub_account (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    physical_account_id BIGINT NOT NULL,
    account_code VARCHAR(64) NOT NULL,
    account_type VARCHAR(32) DEFAULT 'settlement',
    valid_from TIMESTAMP NULL,
    valid_to TIMESTAMP NULL,
    status VARCHAR(32) DEFAULT 'active',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (physical_account_id) REFERENCES physical_account(id),
    UNIQUE INDEX idx_account_code (physical_account_id, account_code),
    INDEX idx_status (status),
    INDEX idx_valid_to (valid_to)
);

九、使用示例

9.1 创建实体账户

let req = CreatePhysicalAccountRequest {
    account_no: "6222021234567890123".to_string(),
    bank_code: "ICBC".to_string(),
    bank_name: Some("中国工商银行".to_string()),
    consistency_mode: Some(ConsistencyMode::Eventual),
    outbound_control: Some(OutboundControl::OnlineBank),
};

let account = account_service.create_physical_account(req).await?;

9.2 创建子账户

let req = CreateVirtualSubAccountRequest {
    physical_account_id: 1,
    account_code: "SUB001".to_string(),
    account_type: SubAccountType::Settlement,
    valid_from: None,
    valid_to: None,
};

let sub_account = account_service.create_sub_account(req).await?;

9.3 批量创建临时账户

let req = BatchCreateSubAccountRequest {
    physical_account_id: 1,
    account_type: SubAccountType::Temporary,
    prefix: "TEMP".to_string(),
    count: 100,
    valid_from: Some(Utc::now()),
    valid_to: Some(Utc::now() + Duration::days(30)),
};

let accounts = account_service.batch_create_sub_accounts(req).await?;