diff --git a/crates/erp-server/migration/src/lib.rs b/crates/erp-server/migration/src/lib.rs index 12fe4aa..7e1fd2b 100644 --- a/crates/erp-server/migration/src/lib.rs +++ b/crates/erp-server/migration/src/lib.rs @@ -97,6 +97,8 @@ mod m20260429_000094_device_readings_unique_constraint; mod m20260429_000095_seed_alert_device_menus; mod m20260430_000096_create_medication_reminder; mod m20260501_000097_seed_menu_permissions; +mod m20260501_000098_create_ai_suggestion; +mod m20260501_000099_create_ai_risk_threshold; pub struct Migrator; @@ -201,6 +203,8 @@ impl MigratorTrait for Migrator { Box::new(m20260429_000095_seed_alert_device_menus::Migration), Box::new(m20260430_000096_create_medication_reminder::Migration), Box::new(m20260501_000097_seed_menu_permissions::Migration), + Box::new(m20260501_000098_create_ai_suggestion::Migration), + Box::new(m20260501_000099_create_ai_risk_threshold::Migration), ] } } diff --git a/crates/erp-server/migration/src/m20260501_000098_create_ai_suggestion.rs b/crates/erp-server/migration/src/m20260501_000098_create_ai_suggestion.rs new file mode 100644 index 0000000..d0a3880 --- /dev/null +++ b/crates/erp-server/migration/src/m20260501_000098_create_ai_suggestion.rs @@ -0,0 +1,98 @@ +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> { + manager + .create_table( + Table::create() + .table(Alias::new("ai_suggestion")) + .col( + ColumnDef::new(Alias::new("id")) + .uuid() + .not_null() + .primary_key() + .default(Expr::cust("gen_random_uuid()")), + ) + .col(ColumnDef::new(Alias::new("tenant_id")).uuid().not_null()) + .col(ColumnDef::new(Alias::new("analysis_id")).uuid().not_null()) + .col( + ColumnDef::new(Alias::new("suggestion_type")) + .string_len(20) + .not_null(), + ) + .col( + ColumnDef::new(Alias::new("risk_level")) + .string_len(10) + .not_null(), + ) + .col(ColumnDef::new(Alias::new("params")).json_binary().not_null()) + .col( + ColumnDef::new(Alias::new("status")) + .string_len(20) + .not_null() + .default("pending"), + ) + .col(ColumnDef::new(Alias::new("workflow_instance_id")).uuid()) + .col(ColumnDef::new(Alias::new("action_result")).json_binary()) + .col(ColumnDef::new(Alias::new("baseline_snapshot")).json_binary()) + .col(ColumnDef::new(Alias::new("reanalysis_id")).uuid()) + .col( + ColumnDef::new(Alias::new("created_at")) + .timestamp_with_time_zone() + .default(Expr::cust("NOW()")), + ) + .col( + ColumnDef::new(Alias::new("updated_at")) + .timestamp_with_time_zone() + .default(Expr::cust("NOW()")), + ) + .col(ColumnDef::new(Alias::new("created_by")).uuid()) + .col(ColumnDef::new(Alias::new("updated_by")).uuid()) + .col( + ColumnDef::new(Alias::new("deleted_at")).timestamp_with_time_zone(), + ) + .col( + ColumnDef::new(Alias::new("version_lock")) + .integer() + .not_null() + .default(1), + ) + .to_owned(), + ) + .await?; + + manager + .create_index( + Index::create() + .name("idx_ai_suggestion_tenant_analysis") + .table(Alias::new("ai_suggestion")) + .col(Alias::new("tenant_id")) + .col(Alias::new("analysis_id")) + .to_owned(), + ) + .await?; + + manager + .create_index( + Index::create() + .name("idx_ai_suggestion_tenant_status") + .table(Alias::new("ai_suggestion")) + .col(Alias::new("tenant_id")) + .col(Alias::new("status")) + .to_owned(), + ) + .await?; + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(Alias::new("ai_suggestion")).to_owned()) + .await + } +} diff --git a/crates/erp-server/migration/src/m20260501_000099_create_ai_risk_threshold.rs b/crates/erp-server/migration/src/m20260501_000099_create_ai_risk_threshold.rs new file mode 100644 index 0000000..99e2057 --- /dev/null +++ b/crates/erp-server/migration/src/m20260501_000099_create_ai_risk_threshold.rs @@ -0,0 +1,74 @@ +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> { + manager + .create_table( + Table::create() + .table(Alias::new("ai_risk_threshold")) + .col( + ColumnDef::new(Alias::new("id")) + .uuid() + .not_null() + .primary_key() + .default(Expr::cust("gen_random_uuid()")), + ) + .col(ColumnDef::new(Alias::new("tenant_id")).uuid().not_null()) + .col( + ColumnDef::new(Alias::new("metric_name")) + .string_len(50) + .not_null(), + ) + .col(ColumnDef::new(Alias::new("low_threshold")).json_binary()) + .col(ColumnDef::new(Alias::new("medium_threshold")).json_binary()) + .col(ColumnDef::new(Alias::new("high_threshold")).json_binary()) + .col( + ColumnDef::new(Alias::new("created_at")) + .timestamp_with_time_zone() + .default(Expr::cust("NOW()")), + ) + .col( + ColumnDef::new(Alias::new("updated_at")) + .timestamp_with_time_zone() + .default(Expr::cust("NOW()")), + ) + .col(ColumnDef::new(Alias::new("created_by")).uuid()) + .col(ColumnDef::new(Alias::new("updated_by")).uuid()) + .col( + ColumnDef::new(Alias::new("deleted_at")).timestamp_with_time_zone(), + ) + .col( + ColumnDef::new(Alias::new("version_lock")) + .integer() + .not_null() + .default(1), + ) + .to_owned(), + ) + .await?; + + manager + .create_index( + Index::create() + .name("idx_ai_risk_threshold_tenant_metric") + .table(Alias::new("ai_risk_threshold")) + .col(Alias::new("tenant_id")) + .col(Alias::new("metric_name")) + .unique() + .to_owned(), + ) + .await?; + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(Alias::new("ai_risk_threshold")).to_owned()) + .await + } +}