Files
group_xinghuo_jinrong/docs/项目框架设计/表设计/02-mysql-agent专用.sql
T
GaoYiYuan_0626 c5182f1910 feat(convert): 基金转换 T-0/T-0b 门禁 + T-1 数据层 + T-2/T-2b 纯函数与实算回填
T-0 / T-0b(门禁 · 2026-09-10)
- T-0:sqlite 与 MySQL 结构对齐 —— core_holding 统一为 qty/cost_amount/as_of/pnl_pct
  + PK + UNIQUE(customer_id, product_id);补 core_product_nav;新增建库自校验
  _assert_ddl_aligned()(R-g);test_db.py 增 3 条门禁用例(含反向验证门禁失效)
- T-0b:DB 账号分离(D20)—— 新增 scripts/core/00-grant.sql(三账号逐表授权);
  settings.py 增 3 组账号;db.py 改 get_engine(db, role),缓存键改为 (库名, 角色),
  账号未配置回退单账号;core_ro→ro / gateway_repository→rw / risk·session_repository→rw;
  tests/conftest.py 四处显式 role="admin"(R-e)

T-1(数据层)
- scripts/core/01-ddl.sql:新建 core_fee_rule / core_share_lot / core_convert_lot_detail;
  core_trade 加 convert_group_id + idx_convert_group;core_product 加 8 列 + fee_rate 补 COMMENT
- 新增 07-seed-fee-rule.sql(赎回费 5 档 × 14 产品,按 22 号文 §10)/ 08-seed-share-lot.sql
  (58 行持仓 → 61 行批次,Σ remain_qty 恒等于 qty)/ 09-seed-org.sql(管理人 + TA +
  申购费率 + 最低持有余额,v1.1 按「管理人全产品线」重排)
- reset.ps1 追加 07/08/09;02-mysql-agent专用.sql 追加 risk_convert_detail
- tests/_ddl.py 同步 4 表 + 新增 REQUIRED_CONVERT_TABLES 建库门禁
- 新增 scripts/dev/verify_convert_seed.py(pymysql 等价 reset 流程 + 8 条 DoD 断言,
  含断言 ⑧「费率档 ↔ product_type 匹配」,越档即 FAIL)

T-2 / T-2b(纯函数包 + 示例实算回填)
- 新增 app/service/convert/ 7 文件:__init__ / types / calc / fee / nav / lot_bootstrap / errors
  (纯函数,不查库、不碰 SQL;所有量化显式 ROUND_HALF_UP;lot_bootstrap 用 zlib.crc32
   保证 D18 跨进程同源)
- 新增 tests/test_convert_calc.py 93 用例(12 类:HALF_UP 反向自证 / 分档边界 /
  FIFO 含同 confirmed_at 兜底 / 双口径 / 强制全转与强制赎回 / PRD §5.3 全链自证 /
  纯函数零 IO 依赖断言)
- 重写 scripts/dev/calc_convert_demo.py:去掉脚本内公式副本,改为调用生产 calc.py,
  末尾与 PRD §5.3 逐项比对(不一致即退出码 1),兼作一致性门禁

验证
- pytest 609 passed / 3 skipped(516 → +93,零回归)
- verify_convert_seed.py 8/8 PASS;calc_convert_demo.py 15/15 与 PRD §5.3 一致

文档:PRD v0.9.1(费率分类修正)· 架构 §7 签名回填 / §8.3 错误码注 / §15 T-2 完成 ·
开发计划 §1.5 新增 R-h + §4.2·§4.3 执行记录 · AGENTS.md · docs/memory
2026-09-10 14:45:55 +08:00

144 lines
8.2 KiB
SQL
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.
-- =============================================================================
-- 单 Agent 专用 MySQL(6 张)
-- 执行时机:各 Agent 组开发自己的功能时创建(也可一次性全建)
-- 共用底座见 01-mysql-共用底座.sql
-- =============================================================================
USE jinrong_agent;
-- ⚪ 客户财富 Agent
CREATE TABLE customer_threshold_config (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
customer_id VARCHAR(64) NOT NULL,
scope_type ENUM('portfolio','product') NOT NULL DEFAULT 'portfolio',
scope_ref VARCHAR(64) NULL,
loss_threshold_pct DECIMAL(5,2) NOT NULL,
notify_channel SET('app','sms','email') NOT NULL DEFAULT 'app',
is_enabled TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
KEY idx_customer (customer_id, is_enabled)
) ENGINE=InnoDB COMMENT='【客户专用】亏损阈值配置';
CREATE TABLE customer_notify_log (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
customer_id VARCHAR(64) NOT NULL,
trace_id VARCHAR(64) NOT NULL,
notify_type ENUM('loss_threshold','market_volatility') NOT NULL,
threshold_config_id BIGINT UNSIGNED NULL,
payload JSON NOT NULL,
channel VARCHAR(16) NOT NULL,
send_status ENUM('sent','failed') NOT NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
KEY idx_customer_time (customer_id, created_at)
) ENGINE=InnoDB COMMENT='【客户专用】提醒留痕';
-- ⚪ 代理人助手 Agent
CREATE TABLE advisor_draft (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
draft_id VARCHAR(64) NOT NULL,
session_id VARCHAR(64) NOT NULL,
trace_id VARCHAR(64) NOT NULL,
advisor_id VARCHAR(64) NOT NULL,
customer_id VARCHAR(64) NOT NULL,
draft_type ENUM('script','follow_up') NOT NULL,
content MEDIUMTEXT NOT NULL,
review_status ENUM('pending','approved','rejected') NOT NULL DEFAULT 'pending',
reviewer_id VARCHAR(64) NULL,
reviewed_at DATETIME(3) NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
UNIQUE KEY uk_draft_id (draft_id),
KEY idx_advisor_customer (advisor_id, customer_id, created_at),
KEY idx_review (review_status, created_at)
) ENGINE=InnoDB COMMENT='【代理人专用】话术/跟进草稿';
CREATE TABLE compliance_hit_log (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
session_id VARCHAR(64) NOT NULL,
trace_id VARCHAR(64) NOT NULL,
agent_type ENUM('customer','advisor') NOT NULL,
actor_id VARCHAR(64) NOT NULL,
hit_category ENUM('return_promise','principal_guarantee','buy_sell_guide','product_recommend','other') NOT NULL,
matched_terms JSON NOT NULL,
severity ENUM('low','medium','high') NOT NULL,
action_taken ENUM('flagged','blocked','alerted') NOT NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
KEY idx_severity_time (severity, created_at),
KEY idx_session (session_id)
) ENGINE=InnoDB COMMENT='【代理人专用】违规话术命中';
-- ⚪ 数据分析 Agent
CREATE TABLE analytics_query_log (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
session_id VARCHAR(64) NOT NULL,
trace_id VARCHAR(64) NOT NULL,
staff_id VARCHAR(64) NOT NULL,
nl_question TEXT NOT NULL,
generated_sql TEXT NOT NULL,
sql_hash CHAR(64) NOT NULL,
row_count INT UNSIGNED NULL,
exec_status ENUM('success','error','blocked') NOT NULL,
exec_latency_ms INT UNSIGNED NULL,
result_summary JSON NULL,
has_disclaimer TINYINT(1) NOT NULL DEFAULT 0,
error_message VARCHAR(512) NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
KEY idx_staff_time (staff_id, created_at),
KEY idx_trace (trace_id),
KEY idx_sql_hash (sql_hash)
) ENGINE=InnoDB COMMENT='【分析专用】查数 SQL 留痕';
-- ⚪ 风控监测 Agent
CREATE TABLE risk_aml_list (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
list_id VARCHAR(64) NOT NULL,
list_type ENUM('sanction','terror','pep') NOT NULL,
full_name VARCHAR(128) NOT NULL COMMENT '与 core_customer.display_name 同为脱敏展示名口径',
id_no VARCHAR(32) NULL COMMENT '预留:待 Core 提供证件数据后启用匹配',
bank_card_no VARCHAR(32) NULL COMMENT '预留:同上',
match_threshold DECIMAL(3,2) NOT NULL DEFAULT 0.85,
source VARCHAR(64) NOT NULL,
list_version VARCHAR(16) NOT NULL,
effective_date DATE NOT NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
UNIQUE KEY uk_list_id (list_id),
KEY idx_name (full_name),
KEY idx_active (is_active)
) ENGINE=InnoDB COMMENT='【风控专用】AML 名单本地镜像 · 依据 docs/PRD/PRD-风控监测Agent.md §6.2';
-- ============================================================================
-- 基金转换详情(Agent 侧)· T-1 新增(2026-09-10)
-- 依据:docs/PRD/PRD-基金转换交易.md §4.1 DDL 原文 · 架构设计-基金转换交易.md §9
-- 说明:
-- · `status` **建表即含全部 5 值**(pending / completed / failed / cancelled / expired),
-- 二期撤单与占位超时清理**零 ALTER**(评审 S2 / L-5)。
-- · `uk_idem(client_request_id)` 支撑 FR-C17 幂等;值为 NULL 时不触发唯一约束
-- (MySQL 允许多个 NULL),故无幂等键的请求不受影响。
-- · Core 侧的批次计费明细在 `jinrong_core.core_convert_lot_detail`(含 nav/nav_date),
-- 本表只存汇总与流程状态;两库各自 engine,**无法单事务**,补偿路径见 PRD §7。
-- ============================================================================
CREATE TABLE risk_convert_detail (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
convert_group_id VARCHAR(64) NOT NULL,
status ENUM('pending','completed','failed','cancelled','expired') NOT NULL DEFAULT 'pending'
COMMENT 'pending=阶段一前占位;completed=两阶段均成;failed=阶段二失败待补偿;cancelled=二期撤单预留;expired=占位超时清理(S2,建表即含,免 ALTER)',
out_trade_id VARCHAR(64) NULL COMMENT '占位阶段为 NULL',
in_trade_id VARCHAR(64) NULL COMMENT '占位阶段为 NULL',
related_trade_id VARCHAR(64) NULL COMMENT '对端 trade_id',
nav DECIMAL(10,4) NULL COMMENT '成交净值',
nav_date DATE NULL,
fee_amount DECIMAL(18,2) NULL COMMENT '本笔费用',
hold_days_min INT NULL COMMENT '跨批次时最短持有天数',
hold_days_max INT NULL COMMENT '跨批次时最长持有天数',
estimated TINYINT(1) NOT NULL DEFAULT 1 COMMENT '1=模拟折算 0=真实确认',
nav_stale TINYINT(1) NOT NULL DEFAULT 0,
client_request_id VARCHAR(64) NULL COMMENT '幂等键',
cancelled_at DATETIME(3) NULL COMMENT '二期撤单时间预留(一期不写入)',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
UNIQUE KEY uk_group (convert_group_id),
UNIQUE KEY uk_idem (client_request_id),
KEY idx_out (out_trade_id),
KEY idx_in (in_trade_id)
) ENGINE=InnoDB COMMENT='基金转换详情(Agent 侧)';