feat(health): BLE 网关后端接入 — 网关管理 + API Key 认证 + 多患者批量上报
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

- 新增 ble_gateways + gateway_patient_bindings 表迁移 (000113)
- 网关 CRUD:注册/编辑/删除/重生成 API Key,含患者绑定管理
- API Key 认证中间件(SHA-256 hash + prefix 快速查找)
- 网关数据上报端点:多患者批量读数,复用 device_reading_service 管道
- 网关心跳端点:固件版本/IP 更新 + last_heartbeat_at
- 10 个管理端路由(JWT)+ 2 个网关端路由(API Key)
- health.ble-gateways.list/manage 权限声明
- 修复 000112 迁移 ForeignKey 借用错误
This commit is contained in:
iven
2026-05-04 20:28:26 +08:00
parent 7b17f94bc0
commit 7e57565ecd
16 changed files with 1379 additions and 4 deletions

View File

@@ -112,6 +112,7 @@ mod m20260504_000109_add_missing_fk_constraints;
mod m20260504_000110_alter_critical_alerts_version_i32;
mod m20260505_000111_create_care_plan;
mod m20260505_000112_create_shift_management;
mod m20260505_000113_create_ble_gateways;
pub struct Migrator;
@@ -231,6 +232,7 @@ impl MigratorTrait for Migrator {
Box::new(m20260504_000110_alter_critical_alerts_version_i32::Migration),
Box::new(m20260505_000111_create_care_plan::Migration),
Box::new(m20260505_000112_create_shift_management::Migration),
Box::new(m20260505_000113_create_ble_gateways::Migration),
]
}
}

View File

@@ -85,7 +85,7 @@ impl MigrationTrait for Migration {
manager
.create_foreign_key(
&mut ForeignKey::create()
ForeignKey::create()
.name("fk_patient_assignments_shift")
.from(PatientAssignment::Table, PatientAssignment::ShiftId)
.to(Shift::Table, Shift::Id)
@@ -147,7 +147,7 @@ impl MigrationTrait for Migration {
manager
.create_foreign_key(
&mut ForeignKey::create()
ForeignKey::create()
.name("fk_handoff_log_from_shift")
.from(HandoffLog::Table, HandoffLog::FromShiftId)
.to(Shift::Table, Shift::Id)
@@ -158,7 +158,7 @@ impl MigrationTrait for Migration {
manager
.create_foreign_key(
&mut ForeignKey::create()
ForeignKey::create()
.name("fk_handoff_log_to_shift")
.from(HandoffLog::Table, HandoffLog::ToShiftId)
.to(Shift::Table, Shift::Id)

View File

@@ -0,0 +1,131 @@
use sea_orm_migration::{prelude::*, schema::*};
#[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("ble_gateways"))
.col(uuid("id").primary_key())
.col(uuid("tenant_id").not_null())
.col(string("gateway_id").unique_key().not_null())
.col(string("name").not_null())
.col(string("api_key_hash").not_null())
.col(string("api_key_prefix").not_null())
.col(string("status").default("active").not_null())
.col(string("firmware_version").null())
.col(string("ip_address").null())
.col(timestamp_with_time_zone("last_heartbeat_at").null())
.col(json("metadata").null())
.col(timestamp_with_time_zone("created_at").default(Expr::current_timestamp()).not_null())
.col(timestamp_with_time_zone("updated_at").default(Expr::current_timestamp()).not_null())
.col(uuid("created_by").null())
.col(uuid("updated_by").null())
.col(timestamp_with_time_zone("deleted_at").null())
.col(integer("version").default(1).not_null())
.to_owned(),
)
.await?;
manager
.create_table(
Table::create()
.table(Alias::new("gateway_patient_bindings"))
.col(uuid("id").primary_key())
.col(uuid("tenant_id").not_null())
.col(uuid("gateway_id_fk").not_null())
.col(uuid("patient_id").not_null())
.col(string("peripheral_mac").null())
.col(string("device_type").null())
.col(string("status").default("active").not_null())
.col(timestamp_with_time_zone("created_at").default(Expr::current_timestamp()).not_null())
.col(timestamp_with_time_zone("updated_at").default(Expr::current_timestamp()).not_null())
.col(uuid("created_by").null())
.col(uuid("updated_by").null())
.col(timestamp_with_time_zone("deleted_at").null())
.col(integer("version").default(1).not_null())
.to_owned(),
)
.await?;
// 索引
manager
.create_index(
Index::create()
.name("idx_ble_gateways_tenant_id")
.table(Alias::new("ble_gateways"))
.col(Alias::new("tenant_id"))
.to_owned(),
)
.await?;
manager
.create_index(
Index::create()
.name("idx_ble_gateways_api_key_prefix")
.table(Alias::new("ble_gateways"))
.col(Alias::new("api_key_prefix"))
.to_owned(),
)
.await?;
manager
.create_index(
Index::create()
.name("idx_gateway_patient_bindings_gateway")
.table(Alias::new("gateway_patient_bindings"))
.col(Alias::new("gateway_id_fk"))
.to_owned(),
)
.await?;
manager
.create_index(
Index::create()
.name("idx_gateway_patient_bindings_patient")
.table(Alias::new("gateway_patient_bindings"))
.col(Alias::new("patient_id"))
.to_owned(),
)
.await?;
// 外键约束
manager
.create_foreign_key(
ForeignKey::create()
.name("fk_gpb_gateway")
.from(Alias::new("gateway_patient_bindings"), Alias::new("gateway_id_fk"))
.to(Alias::new("ble_gateways"), Alias::new("id"))
.on_delete(ForeignKeyAction::Cascade)
.to_owned(),
)
.await?;
manager
.create_foreign_key(
ForeignKey::create()
.name("fk_gpb_patient")
.from(Alias::new("gateway_patient_bindings"), Alias::new("patient_id"))
.to(Alias::new("patients"), Alias::new("id"))
.on_delete(ForeignKeyAction::Cascade)
.to_owned(),
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(Alias::new("gateway_patient_bindings")).to_owned())
.await?;
manager
.drop_table(Table::drop().table(Alias::new("ble_gateways")).to_owned())
.await?;
Ok(())
}
}