refactor(api): split Axum handlers into handler/service/repo modules

Keep the REST contract; move domain logic out of route files so checkout, fulfillment, and identity can be reused across customer, shop, and admin surfaces.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Chengdong Zhang
2026-09-18 14:59:36 +08:00
co-authored by Cursor
parent e457339847
commit 5e866d08f4
68 changed files with 3796 additions and 2304 deletions
+13 -9
View File
@@ -1,4 +1,4 @@
use vmall_api::{build_router, config::Config, seed::ensure_platform_admin, state::build_state};
use vmall_api::{build_router, config::Config, seed::ensure_platform_admin, state};
pub const TEST_DB_URL: &str = "postgres://postgres:postgres@127.0.0.1:5432/vmall_test";
pub const TEST_REDIS_URL: &str = "redis://127.0.0.1:6379/";
@@ -14,9 +14,7 @@ impl TestApp {
}
}
/// Spin up the full app against the test database on an ephemeral port.
/// Migrations run once per process; domain tables are truncated per app.
pub async fn spawn_app() -> TestApp {
pub async fn spawn_state() -> vmall_api::state::AppState {
let config = Config {
database_url: TEST_DB_URL.into(),
redis_url: TEST_REDIS_URL.into(),
@@ -24,11 +22,17 @@ pub async fn spawn_app() -> TestApp {
port: 0,
jwt_ttl_secs: 3600,
};
sqlx::migrate!("./migrations")
.run(&sqlx::PgPool::connect(TEST_DB_URL).await.unwrap())
.await
.unwrap();
let state = build_state(&config).await.unwrap();
let db = sqlx::PgPool::connect(TEST_DB_URL).await.unwrap();
sqlx::migrate!("./migrations").run(&db).await.unwrap();
let state = state::assemble(config, db).await.unwrap();
ensure_platform_admin(&state).await.unwrap();
state
}
/// Spin up the full app against the test database on an ephemeral port.
/// Migrations run once per process; domain tables are truncated per app.
pub async fn spawn_app() -> TestApp {
let state = spawn_state().await;
ensure_platform_admin(&state).await.unwrap();
let app = build_router(state.clone());
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();