Files
nj/crates/erp-server/src/state.rs
iven 749ef55b89
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
feat: Week 4 收尾 + 架构治理 — 搜索/家长中心/Feature Flag/Docker/环境配置
架构治理:
- Feature Flag 落地: Cargo.toml [features] default=["diary"] + main.rs cfg 条件编译
- 环境配置统一: AppConfig 类 + --dart-define 注入 + SSE 端口 8080→3000 修复

搜索替代方案 (无 FTS):
- SearchBloc + 标签/心情筛选接入后端 API
- JournalRepository 扩展 mood/tag 筛选参数
- 搜索页 UI 接入实际数据(替换占位文本)

家长中心最小集 (PIPL 合规):
- 后端: parent_service (绑定/查看/导出/删除/解绑) + parent_handler (6 个 API 端点)
- 前端: ParentBloc + ParentPage 功能完整实现
- 绑定孩子、只读查看日记、导出数据、删除数据、解绑

Docker 部署:
- verify.sh 健康检查脚本 (Axum/PG/Redis/OpenAPI 四项检查)

测试修复:
- home_bloc_test / calendar_bloc_test 适配 JournalRepository 新参数

验证: flutter test 84/84 pass, cargo test 76/76 pass, cargo check pass
2026-06-01 23:53:34 +08:00

124 lines
4.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use std::sync::atomic::AtomicU64;
use std::sync::Arc;
use axum::extract::FromRef;
use sea_orm::DatabaseConnection;
use crate::config::AppConfig;
use erp_core::events::EventBus;
use erp_core::module::ModuleRegistry;
/// Axum shared application state.
/// All handlers access database connections, configuration, etc. through `State<AppState>`.
#[derive(Clone)]
pub struct AppState {
pub db: DatabaseConnection,
pub config: AppConfig,
pub event_bus: EventBus,
pub module_registry: ModuleRegistry,
pub redis: redis::Client,
/// 实际的默认租户 ID从数据库种子数据中获取。
pub default_tenant_id: uuid::Uuid,
/// 插件引擎
pub plugin_engine: erp_plugin::engine::PluginEngine,
/// 插件实体缓存
pub plugin_entity_cache: moka::sync::Cache<String, erp_plugin::state::EntityInfo>,
/// PII 加密服务KEK + DEK 管理)
pub pii_crypto: erp_core::crypto::PiiCrypto,
/// 定时任务心跳unix timestamp secs每个 cron tick 更新
pub cron_heartbeat: Arc<AtomicU64>,
}
/// Allow handlers to extract `DatabaseConnection` directly from `State<AppState>`.
impl FromRef<AppState> for DatabaseConnection {
fn from_ref(state: &AppState) -> Self {
state.db.clone()
}
}
/// Allow handlers to extract `EventBus` directly from `State<AppState>`.
impl FromRef<AppState> for EventBus {
fn from_ref(state: &AppState) -> Self {
state.event_bus.clone()
}
}
/// Allow erp-auth handlers to extract their required state without depending on erp-server.
///
/// This bridges the gap: erp-auth defines `AuthState` with the fields it needs,
/// and erp-server fills them from `AppState`.
impl FromRef<AppState> for erp_auth::AuthState {
fn from_ref(state: &AppState) -> Self {
use erp_auth::auth_state::parse_ttl;
Self {
db: state.db.clone(),
event_bus: state.event_bus.clone(),
jwt_secret: state.config.jwt.secret.clone(),
access_ttl_secs: parse_ttl(&state.config.jwt.access_token_ttl),
refresh_ttl_secs: parse_ttl(&state.config.jwt.refresh_token_ttl),
default_tenant_id: state.default_tenant_id,
wechat_appid: state.config.wechat.appid.clone(),
wechat_secret: state.config.wechat.secret.clone(),
wechat_dev_mode: state.config.wechat.dev_mode,
redis: Some(state.redis.clone()),
crypto: state.pii_crypto.clone(),
}
}
}
/// Allow erp-config handlers to extract their required state without depending on erp-server.
impl FromRef<AppState> for erp_config::ConfigState {
fn from_ref(state: &AppState) -> Self {
Self {
db: state.db.clone(),
event_bus: state.event_bus.clone(),
}
}
}
/// Allow erp-workflow handlers to extract their required state without depending on erp-server.
impl FromRef<AppState> for erp_workflow::WorkflowState {
fn from_ref(state: &AppState) -> Self {
Self {
db: state.db.clone(),
event_bus: state.event_bus.clone(),
}
}
}
/// Allow erp-message handlers to extract their required state without depending on erp-server.
impl FromRef<AppState> for erp_message::MessageState {
fn from_ref(state: &AppState) -> Self {
Self {
db: state.db.clone(),
event_bus: state.event_bus.clone(),
}
}
}
/// Allow erp-plugin handlers to extract their required state.
impl FromRef<AppState> for erp_plugin::state::PluginState {
fn from_ref(state: &AppState) -> Self {
Self {
db: state.db.clone(),
event_bus: state.event_bus.clone(),
engine: state.plugin_engine.clone(),
entity_cache: state.plugin_entity_cache.clone(),
}
}
}
/// Allow erp-diary handlers to extract their required state.
#[cfg(feature = "diary")]
impl FromRef<AppState> for erp_diary::DiaryState {
fn from_ref(state: &AppState) -> Self {
Self {
db: state.db.clone(),
event_bus: state.event_bus.clone(),
crypto: state.pii_crypto.clone(),
redis: Some(state.redis.clone()),
}
}
}