feat: 初始化ERP平台底座项目结构
- 添加基础crate结构(erp-core, erp-common) - 实现核心模块trait和事件总线 - 配置Docker开发环境(PostgreSQL+Redis) - 添加Tauri桌面端基础框架 - 设置CI/CD工作流 - 编写项目协作规范文档(CLAUDE.md)
This commit is contained in:
25
crates/erp-server/Cargo.toml
Normal file
25
crates/erp-server/Cargo.toml
Normal file
@@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "erp-server"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[[bin]]
|
||||
name = "erp-server"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
erp-core.workspace = true
|
||||
erp-common.workspace = true
|
||||
tokio.workspace = true
|
||||
axum.workspace = true
|
||||
tower.workspace = true
|
||||
tower-http.workspace = true
|
||||
tracing.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
config.workspace = true
|
||||
sea-orm.workspace = true
|
||||
redis.workspace = true
|
||||
utoipa.workspace = true
|
||||
utoipa-swagger-ui.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde.workspace = true
|
||||
19
crates/erp-server/config/default.toml
Normal file
19
crates/erp-server/config/default.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[server]
|
||||
host = "0.0.0.0"
|
||||
port = 3000
|
||||
|
||||
[database]
|
||||
url = "postgres://erp:erp_dev_2024@localhost:5432/erp"
|
||||
max_connections = 20
|
||||
min_connections = 5
|
||||
|
||||
[redis]
|
||||
url = "redis://localhost:6379"
|
||||
|
||||
[jwt]
|
||||
secret = "change-me-in-production"
|
||||
access_token_ttl = "15m"
|
||||
refresh_token_ttl = "7d"
|
||||
|
||||
[log]
|
||||
level = "info"
|
||||
50
crates/erp-server/src/config.rs
Normal file
50
crates/erp-server/src/config.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct AppConfig {
|
||||
pub server: ServerConfig,
|
||||
pub database: DatabaseConfig,
|
||||
pub redis: RedisConfig,
|
||||
pub jwt: JwtConfig,
|
||||
pub log: LogConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ServerConfig {
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct DatabaseConfig {
|
||||
pub url: String,
|
||||
pub max_connections: u32,
|
||||
pub min_connections: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct RedisConfig {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct JwtConfig {
|
||||
pub secret: String,
|
||||
pub access_token_ttl: String,
|
||||
pub refresh_token_ttl: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct LogConfig {
|
||||
pub level: String,
|
||||
}
|
||||
|
||||
impl AppConfig {
|
||||
pub fn load() -> anyhow::Result<Self> {
|
||||
let config = config::Config::builder()
|
||||
.add_source(config::File::with_name("config/default"))
|
||||
.add_source(config::Environment::with_prefix("ERP").separator("__"))
|
||||
.build()?;
|
||||
Ok(config.try_deserialize()?)
|
||||
}
|
||||
}
|
||||
16
crates/erp-server/src/db.rs
Normal file
16
crates/erp-server/src/db.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use sea_orm::{ConnectOptions, Database, DatabaseConnection};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::config::DatabaseConfig;
|
||||
|
||||
pub async fn connect(config: &DatabaseConfig) -> anyhow::Result<DatabaseConnection> {
|
||||
let mut opt = ConnectOptions::new(&config.url);
|
||||
opt.max_connections(config.max_connections)
|
||||
.min_connections(config.min_connections)
|
||||
.connect_timeout(Duration::from_secs(10))
|
||||
.idle_timeout(Duration::from_secs(600));
|
||||
|
||||
let db = Database::connect(opt).await?;
|
||||
tracing::info!("Database connected successfully");
|
||||
Ok(db)
|
||||
}
|
||||
41
crates/erp-server/src/main.rs
Normal file
41
crates/erp-server/src/main.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
mod config;
|
||||
mod db;
|
||||
|
||||
use axum::Router;
|
||||
use config::AppConfig;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
// Load config
|
||||
let config = AppConfig::load()?;
|
||||
|
||||
// Initialize tracing
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| EnvFilter::new(&config.log.level)),
|
||||
)
|
||||
.json()
|
||||
.init();
|
||||
|
||||
tracing::info!("ERP Server starting...");
|
||||
|
||||
// Connect to database
|
||||
let db = db::connect(&config.database).await?;
|
||||
|
||||
// Connect to Redis
|
||||
let _redis_client = redis::Client::open(&config.redis.url[..])?;
|
||||
tracing::info!("Redis client created");
|
||||
|
||||
// Build app
|
||||
let app = Router::new()
|
||||
.fallback(|| async { axum::Json(serde_json::json!({"error": "Not found"})) });
|
||||
|
||||
let addr = format!("{}:{}", config.server.host, config.server.port);
|
||||
let listener = tokio::net::TcpListener::bind(&addr).await?;
|
||||
tracing::info!("Server listening on {}", addr);
|
||||
axum::serve(listener, app).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user