feat(db): 迁移 000148 — AI 聊天会话/消息/工具日志/用户画像 4 张表
This commit is contained in:
@@ -149,6 +149,7 @@ mod m20260513_000144_enforce_version_optimistic_lock;
|
|||||||
mod m20260513_000145_seed_missing_permissions;
|
mod m20260513_000145_seed_missing_permissions;
|
||||||
mod m20260515_000146_seed_menu_permissions_phase2;
|
mod m20260515_000146_seed_menu_permissions_phase2;
|
||||||
mod m20260516_000147_seed_ai_chat_permission;
|
mod m20260516_000147_seed_ai_chat_permission;
|
||||||
|
mod m20260518_000148_create_ai_chat_tables;
|
||||||
|
|
||||||
pub struct Migrator;
|
pub struct Migrator;
|
||||||
|
|
||||||
@@ -305,6 +306,7 @@ impl MigratorTrait for Migrator {
|
|||||||
Box::new(m20260513_000145_seed_missing_permissions::Migration),
|
Box::new(m20260513_000145_seed_missing_permissions::Migration),
|
||||||
Box::new(m20260515_000146_seed_menu_permissions_phase2::Migration),
|
Box::new(m20260515_000146_seed_menu_permissions_phase2::Migration),
|
||||||
Box::new(m20260516_000147_seed_ai_chat_permission::Migration),
|
Box::new(m20260516_000147_seed_ai_chat_permission::Migration),
|
||||||
|
Box::new(m20260518_000148_create_ai_chat_tables::Migration),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,335 @@
|
|||||||
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
#[derive(DeriveMigrationName)]
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
// ai_chat_sessions — AI 会话表
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(AiChatSessions::Table)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiChatSessions::Id)
|
||||||
|
.uuid()
|
||||||
|
.not_null()
|
||||||
|
.primary_key(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(AiChatSessions::TenantId).uuid().not_null())
|
||||||
|
.col(ColumnDef::new(AiChatSessions::UserId).uuid().not_null())
|
||||||
|
.col(ColumnDef::new(AiChatSessions::PatientId).uuid().null())
|
||||||
|
.col(ColumnDef::new(AiChatSessions::Title).string_len(255).null())
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiChatSessions::Status)
|
||||||
|
.string_len(20)
|
||||||
|
.not_null()
|
||||||
|
.default("active"),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(AiChatSessions::Metadata).json().null())
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiChatSessions::CreatedAt)
|
||||||
|
.timestamp_with_time_zone()
|
||||||
|
.not_null()
|
||||||
|
.default(Expr::current_timestamp()),
|
||||||
|
)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiChatSessions::UpdatedAt)
|
||||||
|
.timestamp_with_time_zone()
|
||||||
|
.not_null()
|
||||||
|
.default(Expr::current_timestamp()),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(AiChatSessions::CreatedBy).uuid().null())
|
||||||
|
.col(ColumnDef::new(AiChatSessions::UpdatedBy).uuid().null())
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiChatSessions::DeletedAt)
|
||||||
|
.timestamp_with_time_zone()
|
||||||
|
.null(),
|
||||||
|
)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiChatSessions::VersionLock)
|
||||||
|
.integer()
|
||||||
|
.not_null()
|
||||||
|
.default(1),
|
||||||
|
)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
manager
|
||||||
|
.create_index(
|
||||||
|
Index::create()
|
||||||
|
.name("idx_ai_chat_sessions_tenant_user")
|
||||||
|
.table(AiChatSessions::Table)
|
||||||
|
.col(AiChatSessions::TenantId)
|
||||||
|
.col(AiChatSessions::UserId)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// ai_chat_messages — AI 聊天消息表
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(AiChatMessages::Table)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiChatMessages::Id)
|
||||||
|
.uuid()
|
||||||
|
.not_null()
|
||||||
|
.primary_key(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(AiChatMessages::TenantId).uuid().not_null())
|
||||||
|
.col(ColumnDef::new(AiChatMessages::SessionId).uuid().not_null())
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiChatMessages::Role)
|
||||||
|
.string_len(20)
|
||||||
|
.not_null(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(AiChatMessages::Content).text().null())
|
||||||
|
.col(ColumnDef::new(AiChatMessages::ToolCalls).json().null())
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiChatMessages::ToolCallId)
|
||||||
|
.string_len(100)
|
||||||
|
.null(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(AiChatMessages::TokenCount).integer().null())
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiChatMessages::CreatedAt)
|
||||||
|
.timestamp_with_time_zone()
|
||||||
|
.not_null()
|
||||||
|
.default(Expr::current_timestamp()),
|
||||||
|
)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiChatMessages::UpdatedAt)
|
||||||
|
.timestamp_with_time_zone()
|
||||||
|
.not_null()
|
||||||
|
.default(Expr::current_timestamp()),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(AiChatMessages::CreatedBy).uuid().null())
|
||||||
|
.col(ColumnDef::new(AiChatMessages::UpdatedBy).uuid().null())
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiChatMessages::DeletedAt)
|
||||||
|
.timestamp_with_time_zone()
|
||||||
|
.null(),
|
||||||
|
)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiChatMessages::VersionLock)
|
||||||
|
.integer()
|
||||||
|
.not_null()
|
||||||
|
.default(1),
|
||||||
|
)
|
||||||
|
.foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.name("fk_ai_chat_messages_session")
|
||||||
|
.from(AiChatMessages::Table, AiChatMessages::SessionId)
|
||||||
|
.to(AiChatSessions::Table, AiChatSessions::Id)
|
||||||
|
.on_delete(ForeignKeyAction::Cascade),
|
||||||
|
)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
manager
|
||||||
|
.create_index(
|
||||||
|
Index::create()
|
||||||
|
.name("idx_ai_chat_messages_session")
|
||||||
|
.table(AiChatMessages::Table)
|
||||||
|
.col(AiChatMessages::TenantId)
|
||||||
|
.col(AiChatMessages::SessionId)
|
||||||
|
.col(AiChatMessages::CreatedAt)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// ai_tool_call_logs — AI 工具调用日志(append-only)
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(AiToolCallLogs::Table)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiToolCallLogs::Id)
|
||||||
|
.uuid()
|
||||||
|
.not_null()
|
||||||
|
.primary_key(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(AiToolCallLogs::TenantId).uuid().not_null())
|
||||||
|
.col(ColumnDef::new(AiToolCallLogs::SessionId).uuid().not_null())
|
||||||
|
.col(ColumnDef::new(AiToolCallLogs::MessageId).uuid().not_null())
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiToolCallLogs::ToolName)
|
||||||
|
.string_len(100)
|
||||||
|
.not_null(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(AiToolCallLogs::Parameters).json().null())
|
||||||
|
.col(ColumnDef::new(AiToolCallLogs::ResultSummary).text().null())
|
||||||
|
.col(ColumnDef::new(AiToolCallLogs::ExecutionMs).integer().null())
|
||||||
|
.col(ColumnDef::new(AiToolCallLogs::Success).boolean().not_null())
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiToolCallLogs::CreatedAt)
|
||||||
|
.timestamp_with_time_zone()
|
||||||
|
.not_null()
|
||||||
|
.default(Expr::current_timestamp()),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(AiToolCallLogs::CreatedBy).uuid().null())
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
manager
|
||||||
|
.create_index(
|
||||||
|
Index::create()
|
||||||
|
.name("idx_ai_tool_call_logs_session")
|
||||||
|
.table(AiToolCallLogs::Table)
|
||||||
|
.col(AiToolCallLogs::TenantId)
|
||||||
|
.col(AiToolCallLogs::SessionId)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// ai_user_profiles — 用户长期画像
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(AiUserProfiles::Table)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiUserProfiles::Id)
|
||||||
|
.uuid()
|
||||||
|
.not_null()
|
||||||
|
.primary_key(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(AiUserProfiles::TenantId).uuid().not_null())
|
||||||
|
.col(ColumnDef::new(AiUserProfiles::UserId).uuid().not_null())
|
||||||
|
.col(ColumnDef::new(AiUserProfiles::Preferences).json().null())
|
||||||
|
.col(ColumnDef::new(AiUserProfiles::HealthInterests).array(ColumnType::Text))
|
||||||
|
.col(ColumnDef::new(AiUserProfiles::FrequentTopics).array(ColumnType::Text))
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiUserProfiles::PersonalitySummary)
|
||||||
|
.text()
|
||||||
|
.null(),
|
||||||
|
)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiUserProfiles::LastUpdatedAt)
|
||||||
|
.timestamp_with_time_zone()
|
||||||
|
.null(),
|
||||||
|
)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiUserProfiles::CreatedAt)
|
||||||
|
.timestamp_with_time_zone()
|
||||||
|
.not_null()
|
||||||
|
.default(Expr::current_timestamp()),
|
||||||
|
)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiUserProfiles::UpdatedAt)
|
||||||
|
.timestamp_with_time_zone()
|
||||||
|
.not_null()
|
||||||
|
.default(Expr::current_timestamp()),
|
||||||
|
)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiUserProfiles::DeletedAt)
|
||||||
|
.timestamp_with_time_zone()
|
||||||
|
.null(),
|
||||||
|
)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(AiUserProfiles::VersionLock)
|
||||||
|
.integer()
|
||||||
|
.not_null()
|
||||||
|
.default(1),
|
||||||
|
)
|
||||||
|
.index(
|
||||||
|
Index::create()
|
||||||
|
.name("uq_ai_user_profiles_tenant_user")
|
||||||
|
.col(AiUserProfiles::TenantId)
|
||||||
|
.col(AiUserProfiles::UserId)
|
||||||
|
.unique(),
|
||||||
|
)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(AiUserProfiles::Table).to_owned())
|
||||||
|
.await?;
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(AiToolCallLogs::Table).to_owned())
|
||||||
|
.await?;
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(AiChatMessages::Table).to_owned())
|
||||||
|
.await?;
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(AiChatSessions::Table).to_owned())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(DeriveIden)]
|
||||||
|
enum AiChatSessions {
|
||||||
|
Table,
|
||||||
|
Id,
|
||||||
|
TenantId,
|
||||||
|
UserId,
|
||||||
|
PatientId,
|
||||||
|
Title,
|
||||||
|
Status,
|
||||||
|
Metadata,
|
||||||
|
CreatedAt,
|
||||||
|
UpdatedAt,
|
||||||
|
CreatedBy,
|
||||||
|
UpdatedBy,
|
||||||
|
DeletedAt,
|
||||||
|
VersionLock,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(DeriveIden)]
|
||||||
|
enum AiChatMessages {
|
||||||
|
Table,
|
||||||
|
Id,
|
||||||
|
TenantId,
|
||||||
|
SessionId,
|
||||||
|
Role,
|
||||||
|
Content,
|
||||||
|
ToolCalls,
|
||||||
|
ToolCallId,
|
||||||
|
TokenCount,
|
||||||
|
CreatedAt,
|
||||||
|
UpdatedAt,
|
||||||
|
CreatedBy,
|
||||||
|
UpdatedBy,
|
||||||
|
DeletedAt,
|
||||||
|
VersionLock,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(DeriveIden)]
|
||||||
|
enum AiToolCallLogs {
|
||||||
|
Table,
|
||||||
|
Id,
|
||||||
|
TenantId,
|
||||||
|
SessionId,
|
||||||
|
MessageId,
|
||||||
|
ToolName,
|
||||||
|
Parameters,
|
||||||
|
ResultSummary,
|
||||||
|
ExecutionMs,
|
||||||
|
Success,
|
||||||
|
CreatedAt,
|
||||||
|
CreatedBy,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(DeriveIden)]
|
||||||
|
enum AiUserProfiles {
|
||||||
|
Table,
|
||||||
|
Id,
|
||||||
|
TenantId,
|
||||||
|
UserId,
|
||||||
|
Preferences,
|
||||||
|
HealthInterests,
|
||||||
|
FrequentTopics,
|
||||||
|
PersonalitySummary,
|
||||||
|
LastUpdatedAt,
|
||||||
|
CreatedAt,
|
||||||
|
UpdatedAt,
|
||||||
|
DeletedAt,
|
||||||
|
VersionLock,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user