feat(ai+db): 知识库 3 表迁移 + Entity — rules/references/guides
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

Phase 3 Task 21:
- ai_knowledge_rules: L1 规则表(条件表达式 + 动作文本)
- ai_knowledge_references: L2 参考表(摘要 + pgvector 嵌入)
- ai_knowledge_guides: L3 指南表(全文 + pgvector 嵌入)
This commit is contained in:
iven
2026-05-05 15:55:20 +08:00
parent 2d2e1e191e
commit 3592b55556
8 changed files with 305 additions and 0 deletions

View File

@@ -119,6 +119,9 @@ mod m20260505_000116_seed_missing_health_menus;
mod m20260505_000117_create_ai_tenant_configs;
mod m20260505_000118_create_ai_analysis_queue;
mod m20260505_000119_enable_pgvector;
mod m20260505_000120_create_ai_knowledge_rules;
mod m20260505_000121_create_ai_knowledge_references;
mod m20260505_000122_create_ai_knowledge_guides;
pub struct Migrator;
@@ -245,6 +248,9 @@ impl MigratorTrait for Migrator {
Box::new(m20260505_000117_create_ai_tenant_configs::Migration),
Box::new(m20260505_000118_create_ai_analysis_queue::Migration),
Box::new(m20260505_000119_enable_pgvector::Migration),
Box::new(m20260505_000120_create_ai_knowledge_rules::Migration),
Box::new(m20260505_000121_create_ai_knowledge_references::Migration),
Box::new(m20260505_000122_create_ai_knowledge_guides::Migration),
]
}
}

View File

@@ -0,0 +1,69 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[derive(Iden)]
enum AiKnowledgeRules {
Table,
Id,
TenantId,
RuleName,
AnalysisType,
ConditionExpr,
ActionText,
Priority,
IsEnabled,
CreatedAt,
UpdatedAt,
CreatedBy,
UpdatedBy,
DeletedAt,
VersionLock,
}
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(AiKnowledgeRules::Table)
.if_not_exists()
.col(ColumnDef::new(AiKnowledgeRules::Id).uuid().not_null().primary_key())
.col(ColumnDef::new(AiKnowledgeRules::TenantId).uuid().not_null())
.col(ColumnDef::new(AiKnowledgeRules::RuleName).string().not_null())
.col(ColumnDef::new(AiKnowledgeRules::AnalysisType).string().not_null())
.col(ColumnDef::new(AiKnowledgeRules::ConditionExpr).string().not_null())
.col(ColumnDef::new(AiKnowledgeRules::ActionText).string().not_null())
.col(ColumnDef::new(AiKnowledgeRules::Priority).integer().not_null().default(0))
.col(ColumnDef::new(AiKnowledgeRules::IsEnabled).boolean().not_null().default(true))
.col(ColumnDef::new(AiKnowledgeRules::CreatedAt).timestamp_with_time_zone().not_null().default(Expr::current_timestamp()))
.col(ColumnDef::new(AiKnowledgeRules::UpdatedAt).timestamp_with_time_zone().not_null().default(Expr::current_timestamp()))
.col(ColumnDef::new(AiKnowledgeRules::CreatedBy).uuid())
.col(ColumnDef::new(AiKnowledgeRules::UpdatedBy).uuid())
.col(ColumnDef::new(AiKnowledgeRules::DeletedAt).timestamp_with_time_zone())
.col(ColumnDef::new(AiKnowledgeRules::VersionLock).integer().not_null().default(1))
.to_owned(),
)
.await?;
manager
.create_index(
Index::create()
.if_not_exists()
.name("idx_ai_knowledge_rules_tenant_type")
.table(AiKnowledgeRules::Table)
.col(AiKnowledgeRules::TenantId)
.col(AiKnowledgeRules::AnalysisType)
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(AiKnowledgeRules::Table).to_owned())
.await
}
}

View File

@@ -0,0 +1,72 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[derive(Iden)]
enum AiKnowledgeReferences {
Table,
Id,
TenantId,
Title,
AnalysisType,
SourceName,
ContentSummary,
Embedding,
Tags,
IsEnabled,
CreatedAt,
UpdatedAt,
CreatedBy,
UpdatedBy,
DeletedAt,
VersionLock,
}
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(AiKnowledgeReferences::Table)
.if_not_exists()
.col(ColumnDef::new(AiKnowledgeReferences::Id).uuid().not_null().primary_key())
.col(ColumnDef::new(AiKnowledgeReferences::TenantId).uuid().not_null())
.col(ColumnDef::new(AiKnowledgeReferences::Title).string().not_null())
.col(ColumnDef::new(AiKnowledgeReferences::AnalysisType).string().not_null())
.col(ColumnDef::new(AiKnowledgeReferences::SourceName).string().not_null())
.col(ColumnDef::new(AiKnowledgeReferences::ContentSummary).text().not_null())
// vector(1536) — 兼容 OpenAI text-embedding-ada-002
.col(ColumnDef::new(AiKnowledgeReferences::Embedding).custom("vector"))
.col(ColumnDef::new(AiKnowledgeReferences::Tags).json())
.col(ColumnDef::new(AiKnowledgeReferences::IsEnabled).boolean().not_null().default(true))
.col(ColumnDef::new(AiKnowledgeReferences::CreatedAt).timestamp_with_time_zone().not_null().default(Expr::current_timestamp()))
.col(ColumnDef::new(AiKnowledgeReferences::UpdatedAt).timestamp_with_time_zone().not_null().default(Expr::current_timestamp()))
.col(ColumnDef::new(AiKnowledgeReferences::CreatedBy).uuid())
.col(ColumnDef::new(AiKnowledgeReferences::UpdatedBy).uuid())
.col(ColumnDef::new(AiKnowledgeReferences::DeletedAt).timestamp_with_time_zone())
.col(ColumnDef::new(AiKnowledgeReferences::VersionLock).integer().not_null().default(1))
.to_owned(),
)
.await?;
manager
.create_index(
Index::create()
.if_not_exists()
.name("idx_ai_knowledge_refs_tenant_type")
.table(AiKnowledgeReferences::Table)
.col(AiKnowledgeReferences::TenantId)
.col(AiKnowledgeReferences::AnalysisType)
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(AiKnowledgeReferences::Table).to_owned())
.await
}
}

View File

@@ -0,0 +1,69 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[derive(Iden)]
enum AiKnowledgeGuides {
Table,
Id,
TenantId,
Title,
AnalysisType,
Content,
Category,
Embedding,
IsEnabled,
CreatedAt,
UpdatedAt,
CreatedBy,
UpdatedBy,
DeletedAt,
VersionLock,
}
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(AiKnowledgeGuides::Table)
.if_not_exists()
.col(ColumnDef::new(AiKnowledgeGuides::Id).uuid().not_null().primary_key())
.col(ColumnDef::new(AiKnowledgeGuides::TenantId).uuid().not_null())
.col(ColumnDef::new(AiKnowledgeGuides::Title).string().not_null())
.col(ColumnDef::new(AiKnowledgeGuides::AnalysisType).string().not_null())
.col(ColumnDef::new(AiKnowledgeGuides::Content).text().not_null())
.col(ColumnDef::new(AiKnowledgeGuides::Category).string())
.col(ColumnDef::new(AiKnowledgeGuides::Embedding).custom("vector"))
.col(ColumnDef::new(AiKnowledgeGuides::IsEnabled).boolean().not_null().default(true))
.col(ColumnDef::new(AiKnowledgeGuides::CreatedAt).timestamp_with_time_zone().not_null().default(Expr::current_timestamp()))
.col(ColumnDef::new(AiKnowledgeGuides::UpdatedAt).timestamp_with_time_zone().not_null().default(Expr::current_timestamp()))
.col(ColumnDef::new(AiKnowledgeGuides::CreatedBy).uuid())
.col(ColumnDef::new(AiKnowledgeGuides::UpdatedBy).uuid())
.col(ColumnDef::new(AiKnowledgeGuides::DeletedAt).timestamp_with_time_zone())
.col(ColumnDef::new(AiKnowledgeGuides::VersionLock).integer().not_null().default(1))
.to_owned(),
)
.await?;
manager
.create_index(
Index::create()
.if_not_exists()
.name("idx_ai_knowledge_guides_tenant_type")
.table(AiKnowledgeGuides::Table)
.col(AiKnowledgeGuides::TenantId)
.col(AiKnowledgeGuides::AnalysisType)
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(AiKnowledgeGuides::Table).to_owned())
.await
}
}