feat:用户画像功能

This commit is contained in:
2026-09-14 00:19:31 +08:00
parent cf8fcf63c9
commit a7f9e182a4
17 changed files with 971 additions and 37 deletions
+262 -6
View File
@@ -1,8 +1,9 @@
-- =====================================================================
-- 智能公募基金系统 · MySQL 建表脚本(24 张,见开发计划 §3.1)
-- 智能公募基金系统 · MySQL 建表脚本(36 张,见开发计划 §3.1,与 model/ 目录 ORM 对齐)
-- 执行:mysql --default-character-set=utf8mb4 -u<user> -p <database> < sql/schema.sql
-- 约定:InnoDB / utf8mb4;采用"逻辑外键"(不建物理 FK,便于 Mock 数据灌入),
-- 注释即文档,NL2SQL 以 COMMENT 注入 Schema。
-- 维护:新增/调整 ORM 模型时同步更新本脚本(01-24 基础业务域,25-36 扩展域)。
-- =====================================================================
SET NAMES utf8mb4;
@@ -36,6 +37,18 @@ DROP TABLE IF EXISTS fund_nav_history;
DROP TABLE IF EXISTS fin_product;
DROP TABLE IF EXISTS fin_customer_profile;
DROP TABLE IF EXISTS sys_user;
DROP TABLE IF EXISTS nl2sql_query_history;
DROP TABLE IF EXISTS nl2sql_sensitive_field;
DROP TABLE IF EXISTS nl2sql_role_column_permission;
DROP TABLE IF EXISTS nl2sql_role_table_permission;
DROP TABLE IF EXISTS nl2sql_query_role;
DROP TABLE IF EXISTS event_log;
DROP TABLE IF EXISTS advisor_visit_record;
DROP TABLE IF EXISTS advisor_report;
DROP TABLE IF EXISTS advisor_draft;
DROP TABLE IF EXISTS advisor_todo;
DROP TABLE IF EXISTS sensitive_word;
DROP TABLE IF EXISTS fin_account;
SET FOREIGN_KEY_CHECKS = 1;
-- ---------------------------------------------------------------------
@@ -64,7 +77,7 @@ CREATE TABLE IF NOT EXISTS sys_user (
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS fin_customer_profile (
customer_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID,一对一关联 sys_user.id',
risk_level VARCHAR(16) NULL COMMENT '风险等级:保守/稳健/平衡/进取/激进',
risk_level VARCHAR(16) NULL COMMENT '风险等级:R1-R5(R1 最保守,R5 最激进,与产品 risk_level 对齐)',
risk_score INT NULL COMMENT '风险评分 0-100,越高越激进',
investment_experience VARCHAR(16) NULL COMMENT '投资经验:0-1/1-3/3-5/5-10/10年以上',
annual_income_range VARCHAR(32) NULL COMMENT '年收入区间',
@@ -87,7 +100,7 @@ CREATE TABLE IF NOT EXISTS fin_product (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
product_code VARCHAR(32) NOT NULL COMMENT '基金代码,唯一,如 F000001',
product_name VARCHAR(128) NOT NULL COMMENT '基金名称',
product_type VARCHAR(32) NOT NULL COMMENT '类型:货币/债券/混合/股票基金',
product_type VARCHAR(32) NOT NULL COMMENT '类型:货币型/债券型/混合型/股票型/指数型/QDII',
risk_level VARCHAR(8) NOT NULL COMMENT '风险等级 R1-R5',
expected_return DECIMAL(7,4) NULL COMMENT '预期年化收益率(%)',
nav DECIMAL(12,6) NULL COMMENT '最新单位净值',
@@ -191,7 +204,7 @@ CREATE TABLE IF NOT EXISTS fin_risk_assessment (
assessment_date DATE NOT NULL COMMENT '评估日期',
question_version VARCHAR(16) NULL COMMENT '问卷版本(题目变更后按版本追溯)',
total_score INT NOT NULL COMMENT '总分 0-100',
risk_level VARCHAR(16) NOT NULL COMMENT '评定:保守/稳健/平衡/进取/激进',
risk_level VARCHAR(16) NOT NULL COMMENT '评定:R1-R5(R1 最保守,R5 最激进)',
answers JSON NULL COMMENT '答题详情 [{q:1,a:B,score:10}]',
assessor_type VARCHAR(16) NOT NULL DEFAULT 'AI评估' COMMENT 'AI评估/人工评估',
valid_until DATE NOT NULL COMMENT '有效期至(默认 +1年,监管一年一评)',
@@ -308,7 +321,7 @@ CREATE TABLE IF NOT EXISTS conversation_archive (
KEY idx_agent (agent_type),
UNIQUE KEY uk_session_message (session_id, message_id),
KEY idx_agent_run (agent_run_id)
) COMMENT='会话归档表(审计回溯 + Agent 持续学习素材,归档前脱敏)';
) COMMENT='会话归档表(审计回溯 + Agent 持续学习素材)';
-- ---------------------------------------------------------------------
-- 15 知识元数据表(原文存 MySQL,替代 MinIO)
@@ -492,7 +505,7 @@ CREATE TABLE IF NOT EXISTS fund_performance (
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS portfolio_benchmark (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
risk_level VARCHAR(16) NOT NULL COMMENT '客户风险等级:保守/稳健/平衡/进取/激进',
risk_level VARCHAR(16) NOT NULL COMMENT '客户风险等级:R1-R5(R1 最保守,R5 最激进)',
target_allocation JSON NOT NULL COMMENT '目标配置 {货币:50,债券:40,股票:10}',
drift_threshold DECIMAL(5,2) NOT NULL DEFAULT 5.00 COMMENT '偏离阈值(%),超阈值触发调仓建议',
status VARCHAR(8) NOT NULL DEFAULT '启用' COMMENT '启用/停用',
@@ -500,3 +513,246 @@ CREATE TABLE IF NOT EXISTS portfolio_benchmark (
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_risk_level (risk_level)
) COMMENT='组合基准配置表(投顾Agent 再平衡参照,运营可调整)';
-- =====================================================================
-- 以下为扩展域建表(25-36),与 model/ 目录 ORM 一一对齐
-- =====================================================================
-- ---------------------------------------------------------------------
-- 25 客户资金账户表(现金余额,一人一户)
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS fin_account (
customer_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID,一人一户,关联 sys_user.id',
balance DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '账户总余额(含冻结部分)',
frozen_amount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '冻结金额,可用余额=balance-frozen_amount(不落库)',
currency VARCHAR(8) NOT NULL DEFAULT 'CNY' COMMENT '币种',
status VARCHAR(16) NOT NULL DEFAULT '正常' COMMENT '账户状态,默认正常',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号(并发扣款校验)',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (customer_id)
) COMMENT='客户资金账户表(现金余额,申购扣款/赎回入账的账务载体)';
-- ---------------------------------------------------------------------
-- 26 敏感词库表(合规拦截唯一来源)
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS sensitive_word (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
word VARCHAR(128) NOT NULL COMMENT '敏感词',
category VARCHAR(32) NOT NULL COMMENT '敏感词分类(工作台可配置)',
level VARCHAR(8) NOT NULL DEFAULT '高' COMMENT '级别,默认高',
status VARCHAR(8) NOT NULL DEFAULT '启用' COMMENT '启用/停用',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_word (word)
) COMMENT='敏感词库表(工作台与Agent同源,合规拦截唯一来源)';
-- ---------------------------------------------------------------------
-- 27 投顾待办表(事件/定时/计算三类来源统一承载)
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS advisor_todo (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
todo_type VARCHAR(32) NOT NULL COMMENT '待办类型(事件/定时/计算来源的细分类型)',
customer_id BIGINT UNSIGNED NULL COMMENT '关联客户(可为空)',
advisor_id BIGINT UNSIGNED NOT NULL COMMENT '所属投顾',
source VARCHAR(32) NOT NULL COMMENT '来源:事件/定时/计算',
biz_id VARCHAR(64) NULL COMMENT '关联业务ID(与 todo_type 组合定位业务)',
priority VARCHAR(8) NOT NULL DEFAULT '普通' COMMENT '普通/紧急/特急',
status VARCHAR(16) NOT NULL DEFAULT '待处理' COMMENT '待办状态,默认待处理',
due_at DATETIME NULL COMMENT '截止时间',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
handle_time DATETIME NULL COMMENT '处理时间',
UNIQUE KEY uk_todo (todo_type, customer_id, biz_id),
KEY idx_advisor_status (advisor_id, status)
) COMMENT='投顾待办表(事件/定时/计算三类来源统一承载,uk_todo 幂等防重复建待办)';
-- ---------------------------------------------------------------------
-- 28 投顾 Agent 草稿表(不存 sent,不生成交易指令)
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS advisor_draft (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
draft_id VARCHAR(64) NOT NULL COMMENT '草稿ID,全局唯一',
customer_id BIGINT UNSIGNED NOT NULL COMMENT '目标客户',
advisor_id BIGINT UNSIGNED NOT NULL COMMENT '所属投顾',
intent VARCHAR(32) NOT NULL COMMENT '报告意图,如 调仓建议',
title VARCHAR(128) NOT NULL COMMENT '草稿标题',
content TEXT NOT NULL COMMENT '报告正文',
structured_data JSON NULL COMMENT '结构化数据(调仓明细等)',
status VARCHAR(16) NOT NULL DEFAULT 'draft' COMMENT '草稿状态,默认draft',
deviation DECIMAL(10,4) NULL COMMENT '组合偏离度(%)',
disclaimer_ok TINYINT(1) NOT NULL DEFAULT 0 COMMENT '免责声明确认',
warning VARCHAR(512) NULL COMMENT '合规提示/警告信息',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_draft_id (draft_id),
CONSTRAINT ck_advisor_draft_status CHECK (status IN ('draft', 'discarded')),
KEY idx_customer (customer_id),
KEY idx_advisor (advisor_id),
KEY idx_intent (intent),
KEY idx_status (status),
KEY idx_create_time (create_time)
) COMMENT='投顾 Agent 草稿(不存 sent,不生成交易指令)';
-- ---------------------------------------------------------------------
-- 29 建议报告表(工作台本地镜像:sent 状态 + 编辑/发送留痕)
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS advisor_report (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
report_id VARCHAR(64) NOT NULL COMMENT '报告ID,全局唯一',
draft_id VARCHAR(64) NOT NULL COMMENT '来源草稿ID(advisor_draft.draft_id)',
customer_id BIGINT UNSIGNED NOT NULL COMMENT '目标客户',
advisor_id BIGINT UNSIGNED NOT NULL COMMENT '发送投顾',
intent VARCHAR(32) NOT NULL COMMENT '报告意图(继承草稿)',
title VARCHAR(128) NULL COMMENT '报告标题',
content TEXT NULL COMMENT '报告正文',
edit_history JSON NULL COMMENT '编辑留痕(JSON数组)',
send_status VARCHAR(16) NOT NULL DEFAULT 'draft' COMMENT 'draft/sent/discarded,sent 为工作台本地状态不回写投顾Agent',
send_time DATETIME NULL COMMENT '发送时间',
send_by BIGINT UNSIGNED NULL COMMENT '发送人',
msg_id BIGINT UNSIGNED NULL COMMENT '发送后落 sys_message 的站内信ID',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_report_id (report_id),
KEY idx_customer (customer_id),
KEY idx_advisor (advisor_id),
KEY idx_send_status (send_status)
) COMMENT='建议报告表(工作台本地镜像,承载 sent 状态与发送/编辑留痕)';
-- ---------------------------------------------------------------------
-- 30 投顾回访记录表(人工留痕归档)
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS advisor_visit_record (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
customer_id BIGINT UNSIGNED NOT NULL COMMENT '回访客户',
advisor_id BIGINT UNSIGNED NOT NULL COMMENT '回访投顾',
visit_type VARCHAR(32) NOT NULL COMMENT '回访类型',
visit_time DATETIME NOT NULL COMMENT '回访时间',
summary TEXT NULL COMMENT '回访纪要',
audio_url VARCHAR(512) NULL COMMENT '录音文件地址',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_customer (customer_id),
KEY idx_advisor (advisor_id)
) COMMENT='投顾回访记录表(人工留痕归档,不触发Agent记忆抽取)';
-- ---------------------------------------------------------------------
-- 31 事件日志表(事件双写落库,消费以 event_id 幂等)
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS event_log (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
event_id VARCHAR(64) NOT NULL COMMENT '事件ID,全局唯一,消费幂等键',
event_name VARCHAR(64) NOT NULL COMMENT '事件名',
payload JSON NULL COMMENT '事件负载',
trace_id VARCHAR(64) NULL COMMENT '请求链路追踪ID',
status VARCHAR(16) NOT NULL DEFAULT 'pending' COMMENT '消费状态,默认pending',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
consume_time DATETIME NULL COMMENT '消费完成时间',
UNIQUE KEY uk_event_id (event_id),
KEY idx_event_name (event_name),
KEY idx_status (status)
) COMMENT='事件日志表(事件双写落库,Pub/Sub 仅作实时通知,消费幂等)';
-- ---------------------------------------------------------------------
-- 32 NL2SQL 查询角色(按 sys_user.employee_role 映射)
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS nl2sql_query_role (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
role_code VARCHAR(64) NOT NULL COMMENT '角色编码,全局唯一',
role_name VARCHAR(128) NOT NULL COMMENT '角色名称',
employee_role VARCHAR(32) NOT NULL COMMENT '对应 sys_user.employee_role,一对一映射',
can_query TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否允许 NL2SQL 查询:0/1',
max_rows BIGINT NOT NULL DEFAULT 1000 COMMENT '单次查询最大返回行数',
daily_quota BIGINT NOT NULL DEFAULT 0 COMMENT '每日查询配额',
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT 'active/inactive',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_role_code (role_code),
UNIQUE KEY uk_employee_role (employee_role),
CONSTRAINT ck_nl2sql_role_can_query CHECK (can_query IN (0, 1)),
CONSTRAINT ck_nl2sql_role_status CHECK (status IN ('active', 'inactive')),
KEY idx_status (status)
) COMMENT='NL2SQL 查询角色,按 sys_user.employee_role 映射';
-- ---------------------------------------------------------------------
-- 33 NL2SQL 角色的表级 + 行级权限
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS nl2sql_role_table_permission (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
role_id BIGINT UNSIGNED NOT NULL COMMENT '角色ID(nl2sql_query_role.id)',
table_name VARCHAR(128) NOT NULL COMMENT '授权表名',
permission VARCHAR(16) NOT NULL DEFAULT 'SELECT' COMMENT '授权动作,仅 SELECT',
row_scope_type VARCHAR(32) NOT NULL DEFAULT 'none' COMMENT '行级范围:none/customer_ids/product_ids',
row_scope_column VARCHAR(128) NULL COMMENT '行级过滤列(如 customer_id)',
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT 'active/inactive',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT ck_nl2sql_table_permission CHECK (permission = 'SELECT'),
CONSTRAINT ck_nl2sql_row_scope_type CHECK (row_scope_type IN ('none', 'customer_ids', 'product_ids')),
CONSTRAINT ck_nl2sql_table_status CHECK (status IN ('active', 'inactive')),
KEY idx_role (role_id),
KEY idx_status (status)
) COMMENT='NL2SQL 查询角色的表和行级权限';
-- ---------------------------------------------------------------------
-- 34 NL2SQL 角色的字段权限
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS nl2sql_role_column_permission (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
role_id BIGINT UNSIGNED NOT NULL COMMENT '角色ID(nl2sql_query_role.id)',
table_name VARCHAR(128) NOT NULL COMMENT '表名',
column_name VARCHAR(128) NOT NULL COMMENT '列名',
access_mode VARCHAR(16) NOT NULL DEFAULT 'allow' COMMENT 'allow/deny/mask',
mask_type VARCHAR(32) NULL COMMENT '脱敏类型(access_mode=mask 时生效)',
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT 'active/inactive',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT ck_nl2sql_column_access_mode CHECK (access_mode IN ('allow', 'deny', 'mask')),
CONSTRAINT ck_nl2sql_column_status CHECK (status IN ('active', 'inactive')),
KEY idx_role (role_id),
KEY idx_status (status)
) COMMENT='NL2SQL 查询角色的字段权限';
-- ---------------------------------------------------------------------
-- 35 NL2SQL 全局敏感字段规则
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS nl2sql_sensitive_field (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
table_name VARCHAR(128) NOT NULL COMMENT '表名',
column_name VARCHAR(128) NOT NULL COMMENT '列名',
mask_type VARCHAR(32) NOT NULL DEFAULT 'partial' COMMENT '脱敏方式,如 partial',
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT 'active/inactive',
description VARCHAR(255) NULL COMMENT '规则说明',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT ck_nl2sql_sensitive_status CHECK (status IN ('active', 'inactive')),
KEY idx_table_col (table_name, column_name),
KEY idx_status (status)
) COMMENT='NL2SQL 全局敏感字段规则';
-- ---------------------------------------------------------------------
-- 36 NL2SQL 查询归档(不保存完整结果行)
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS nl2sql_query_history (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
query_id VARCHAR(64) NOT NULL COMMENT '查询ID,全局唯一',
user_id BIGINT UNSIGNED NOT NULL COMMENT '发起用户',
session_id VARCHAR(64) NULL COMMENT '会话ID',
caller_agent VARCHAR(64) NULL COMMENT '调用方Agent标识',
question TEXT NOT NULL COMMENT '自然语言问题',
generated_sql TEXT NULL COMMENT '生成的SQL(未执行则为空)',
access_tables JSON NULL COMMENT '实际访问的表列表',
status VARCHAR(16) NOT NULL COMMENT 'success/failed/blocked/timeout',
error_code VARCHAR(64) NULL COMMENT '错误码',
error_message VARCHAR(512) NULL COMMENT '错误信息',
row_count BIGINT NOT NULL DEFAULT 0 COMMENT '返回行数',
truncated TINYINT(1) NOT NULL DEFAULT 0 COMMENT '结果是否被截断',
elapsed_ms FLOAT NULL COMMENT '耗时(毫秒)',
trace_id VARCHAR(64) NULL COMMENT '请求链路追踪ID',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_query_id (query_id),
CONSTRAINT ck_nl2sql_history_status CHECK (status IN ('success', 'failed', 'blocked', 'timeout')),
KEY idx_user (user_id),
KEY idx_session (session_id),
KEY idx_caller_agent (caller_agent),
KEY idx_status (status),
KEY idx_trace (trace_id),
KEY idx_create_time (create_time)
) COMMENT='NL2SQL 查询归档,不保存完整结果行';