feat(server): integrate AppState, ModuleRegistry, health check, and graceful shutdown

- Add AppState with DB, Config, EventBus, ModuleRegistry via Axum State
- ModuleRegistry now uses Arc for Clone support, builder-pattern register()
- Add /api/v1/health endpoint returning status, version, registered modules
- Add graceful shutdown on CTRL+C / SIGTERM
- erp-common utils: ID generation, timestamp helpers, code generator with tests
- Config structs now derive Clone for state sharing
- Update wiki to reflect Phase 1 completion
This commit is contained in:
iven
2026-04-11 01:19:30 +08:00
parent 5901ee82f0
commit 810eef769f
9 changed files with 216 additions and 30 deletions

View File

@@ -1,3 +1,55 @@
/// Shared utility functions for the ERP platform.
#[allow(dead_code)]
pub fn noop() {}
use chrono::{DateTime, Utc};
use uuid::Uuid;
/// 生成 UUID v7时间排序 + 唯一性)
pub fn generate_id() -> Uuid {
Uuid::now_v7()
}
/// 获取当前 UTC 时间
pub fn now() -> DateTime<Utc> {
Utc::now()
}
/// 软删除时间戳 — 返回 None 表示未删除
pub const fn not_deleted() -> Option<DateTime<Utc>> {
None
}
/// 生成租户级别的编号前缀
/// 格式: {prefix}-{timestamp_seconds}-{random_4hex}
pub fn generate_code(prefix: &str) -> String {
let ts = Utc::now().timestamp() as u32;
let random = (Uuid::now_v7().as_u128() & 0xFFFF) as u16;
format!("{}-{:08x}-{:04x}", prefix, ts, random)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_generate_id_returns_valid_uuid() {
let id = generate_id();
assert!(!id.is_nil());
}
#[test]
fn test_generate_code_format() {
let code = generate_code("USR");
assert!(code.starts_with("USR-"));
assert_eq!(code.len(), "USR-".len() + 8 + 1 + 4);
}
#[test]
fn test_not_deleted_returns_none() {
assert!(not_deleted().is_none());
}
#[test]
fn test_generate_ids_are_unique() {
let ids: std::collections::HashSet<Uuid> =
(0..100).map(|_| generate_id()).collect();
assert_eq!(ids.len(), 100);
}
}