refactor: migrate to clean architecture with trait-based DI (v0.2.0)

Complete architectural overhaul across all 12 crates:

- Replace validator crate with zod-rs for all DTO validation
- Replace manual pagination with paginator-rs/paginator-sea-orm
- Migrate all modules (iam, cms, gacha, dimentorin) to clean architecture:
  domain → application → infrastructure layers
- Introduce trait-based DI (Arc<dyn Trait>) at every layer for repositories and services
- Delete all v1/ legacy SurrealDB-era code across every crate
- Replace opaque response helpers with typed IntoResponse structs (ApiSuccess, ApiCreated, ApiPaginated, ApiMessage)
- Remove dual_mode_repository, migration_validation_errors, validator.rs dead code
- Zero cargo clippy warnings; release build clean

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
maulanasdqn
2026-04-02 13:39:52 +07:00
co-authored by Claude Sonnet 4.6
parent 1b3366d735
commit e432a1a743
379 changed files with 9013 additions and 30532 deletions
+27 -28
View File
@@ -1,28 +1,27 @@
[package]
name = "imphnen-gateway"
version = "0.1.0"
edition = "2024"
[dependencies]
imphnen-iam.workspace = true
imphnen-libs.workspace = true
imphnen-utils.workspace = true
imphnen-gacha.workspace = true
imphnen-entities.workspace = true
imphnen-middleware.workspace = true
imphnen-cms.workspace = true
imphnen-dimentorin.workspace = true
axum.workspace = true
serde.workspace = true
serde_json.workspace = true
utoipa.workspace = true
lazy_static.workspace = true
regex.workspace = true
validator.workspace = true
axum-test.workspace = true
rand.workspace = true
tokio.workspace = true
chrono.workspace = true
anyhow.workspace = true
tower-http.workspace = true
utoipa-swagger-ui.workspace = true
[package]
name = "imphnen-gateway"
version = "0.2.0"
edition = "2024"
[dependencies]
imphnen-iam.workspace = true
imphnen-libs.workspace = true
imphnen-utils.workspace = true
imphnen-gacha.workspace = true
imphnen-entities.workspace = true
imphnen-middleware.workspace = true
imphnen-cms.workspace = true
imphnen-dimentorin.workspace = true
axum.workspace = true
serde.workspace = true
serde_json.workspace = true
utoipa.workspace = true
lazy_static.workspace = true
regex.workspace = true
axum-test.workspace = true
rand.workspace = true
tokio.workspace = true
chrono.workspace = true
anyhow.workspace = true
tower-http.workspace = true
utoipa-swagger-ui.workspace = true
+66 -68
View File
@@ -1,41 +1,39 @@
use imphnen_cms::v1::landing::events::events_controller;
use imphnen_cms::v1::landing::events::events_dto::{EventsDetailItemDto, EventsListItemDto};
use imphnen_cms::v1::landing::testimonials::testimonials_controller;
use imphnen_cms::v1::landing::testimonials::testimonials_dto::{
use imphnen_cms::events::infrastructure::http::handlers as events_controller;
use imphnen_cms::events::infrastructure::http::dto::{EventsDetailItemDto, EventsListItemDto};
use imphnen_cms::testimonials::infrastructure::http::handlers as testimonials_controller;
use imphnen_cms::testimonials::infrastructure::http::dto::{
TestimonialsCreateRequestDto, TestimonialsDetailItemDto,
TestimonialsListItemDto, TestimonialsUpdateRequestDto,
};
use imphnen_dimentorin::v1::mentors::{
mentors_controller,
mentors_dto::{
IdentityAndVerification, MentorDetailResponseDto, MentorListResponseDto,
MentorRegisterFromTokenRequestDto, MentorRegisterResponseDto,
MentorUpdateRequestDto, MentorUserRegisterRequestDto, MentorVerifyRequestDto,
MentoringLogistics, MentoringRate, ProfessionalProfile,
},
use imphnen_dimentorin::mentors::infrastructure::http::handlers as mentors_controller;
use imphnen_dimentorin::mentors::infrastructure::http::dto::{
IdentityAndVerification, MentorDetailResponseDto, MentorListResponseDto,
MentorRegisterFromTokenRequestDto, MentorRegisterResponseDto,
MentorUpdateRequestDto, MentorUserRegisterRequestDto, MentorVerifyRequestDto,
MentoringLogistics, MentoringRate, ProfessionalProfile,
};
use imphnen_dimentorin::v1::sessions::{
sessions_controller,
use imphnen_dimentorin::sessions::infrastructure::http::handlers as sessions_controller;
use imphnen_dimentorin::sessions::infrastructure::http::dto::{
BookSessionRequestDto, BookSessionResponseDto, MentorAvailabilityDto,
SessionFeedbackRequestDto, SessionFeedbackResponseDto, SessionListItemDto,
SessionListResponseDto, UpdateSessionStatusRequestDto, UpdateSessionStatusResponseDto,
AvailabilitySlotDto,
};
use imphnen_gacha::v1::gacha_claims::{gacha_claims_controller, GachaClaimItemDto, GachaClaimRequestDto};
use imphnen_gacha::v1::gacha_items::{gacha_items_controller, GachaItemDto};
use imphnen_gacha::v1::gacha_items::gacha_items_dto::GachaItemRequestDto;
use imphnen_gacha::v1::gacha_rolls::{gacha_rolls_controller, GachaRollItemDto};
use imphnen_gacha::v1::gacha_rolls::gacha_rolls_dto::GachaRollRequestDto;
use imphnen_entities::{PermissionsItemDto, RolesDetailItemDto};
use imphnen_entities::{MessageResponseDto, MetaRequestDto, MetaResponseDto, ResponseListSuccessDto, ResponseSuccessDto};
use imphnen_iam::v1::auth::auth_dto::{AuthLoginRequestDto, AuthLoginResponsetDto, AuthNewPasswordRequestDto, AuthRefreshTokenRequestDto, AuthResendOtpRequestDto, AuthVerifyEmailRequestDto, TokenDto};
use imphnen_iam::v1::permissions::permissions_dto::PermissionsRequestDto;
use imphnen_iam::v1::roles::RolesListItemDto;
use imphnen_iam::v1::roles::roles_dto::{RolesRequestCreateDto, RolesRequestUpdateDto};
use imphnen_iam::v1::users::UsersDetailItemDto;
use imphnen_iam::v1::users::users_dto::{UsersCreateRequestDto, UsersListItemDto, UsersUpdateRequestDto};
use imphnen_iam::v1::{auth, permissions, roles, users};
use imphnen_iam::v1::users::users_controller::FileUploadSchema;
use imphnen_gacha::gacha_claims::infrastructure::http::handlers as gacha_claims_controller;
use imphnen_gacha::gacha_claims::infrastructure::http::dto::{GachaClaimDetailDto, GachaClaimCreateRequestDto};
use imphnen_gacha::gacha_items::infrastructure::http::handlers as gacha_items_controller;
use imphnen_gacha::gacha_items::infrastructure::http::dto::{GachaItemDto, GachaItemCreateRequestDto};
use imphnen_gacha::gacha_rolls::infrastructure::http::handlers as gacha_rolls_controller;
use imphnen_gacha::gacha_rolls::infrastructure::http::dto::{GachaRollItemDto, GachaRollCreateRequestDto};
use imphnen_entities::{MessageResponseDto, ResponseListSuccessDto, ResponseSuccessDto};
use imphnen_iam::auth::infrastructure::http::dto::{AuthLoginRequestDto, AuthLoginResponsetDto, AuthNewPasswordRequestDto, AuthRefreshTokenRequestDto, AuthResendOtpRequestDto, AuthVerifyEmailRequestDto, TokenDto};
use imphnen_iam::permissions::infrastructure::http::handlers as permissions_controller;
use imphnen_iam::permissions::infrastructure::http::dto::{PermissionsCreateRequestDto, PermissionsItemDto};
use imphnen_iam::roles::infrastructure::http::handlers as roles_controller;
use imphnen_iam::roles::infrastructure::http::dto::{RolesDetailItemDto, RolesListItemDto, RolesCreateRequestDto, RolesUpdateRequestDto};
use imphnen_iam::users::infrastructure::http::handlers as users_controller;
use imphnen_iam::users::infrastructure::http::dto::{UsersDetailItemDto, UsersCreateRequestDto, UsersListItemDto, UsersUpdateRequestDto, FileUploadSchema};
use imphnen_iam::auth::infrastructure::http::handlers as auth_controller;
use utoipa::{
Modify, OpenApi,
openapi::security::{Http, HttpAuthScheme, SecurityScheme, SecurityRequirement},
@@ -44,43 +42,44 @@ use utoipa::{
#[derive(OpenApi)]
#[openapi(
paths(
auth::auth_controller::post_login,
auth::auth_controller::post_login_mentor,
auth::auth_controller::post_register,
auth::auth_controller::post_verify_email,
auth::auth_controller::post_resend_otp,
auth::auth_controller::post_refresh_token,
auth::auth_controller::post_forgot_password,
auth::auth_controller::post_new_password,
users::users_controller::post_create_user,
users::users_controller::put_update_user,
users::users_controller::put_update_user_me,
users::users_controller::patch_user_active_status,
users::users_controller::delete_user,
users::users_controller::get_user_by_id,
users::users_controller::get_user_me,
users::users_controller::get_user_list,
users::users_controller::upload_file,
roles::roles_controller::get_role_list,
roles::roles_controller::get_role_by_id,
roles::roles_controller::post_create_role,
roles::roles_controller::put_update_role,
roles::roles_controller::delete_role,
permissions::permissions_controller::get_permission_list,
permissions::permissions_controller::get_permission_by_id,
permissions::permissions_controller::post_create_permission,
permissions::permissions_controller::put_update_permission,
permissions::permissions_controller::delete_permission,
gacha_claims_controller::get_detail_gacha_claim,
auth_controller::post_login,
auth_controller::post_login_mentor,
auth_controller::post_register,
auth_controller::post_verify_email,
auth_controller::post_resend_otp,
auth_controller::post_refresh_token,
auth_controller::post_forgot_password,
auth_controller::post_new_password,
users_controller::post_create_user,
users_controller::put_update_user,
users_controller::put_update_user_me,
users_controller::patch_user_active_status,
users_controller::delete_user,
users_controller::get_user_by_id,
users_controller::get_user_me,
users_controller::get_user_list,
users_controller::upload_file,
roles_controller::get_role_list,
roles_controller::get_role_by_id,
roles_controller::post_create_role,
roles_controller::put_update_role,
roles_controller::delete_role,
permissions_controller::get_permission_list,
permissions_controller::get_permission_by_id,
permissions_controller::post_create_permission,
permissions_controller::put_update_permission,
permissions_controller::delete_permission,
gacha_claims_controller::get_gacha_claim_by_id,
gacha_claims_controller::post_create_gacha_claim,
gacha_items_controller::get_gacha_item_list,
gacha_items_controller::get_gacha_item_by_id,
gacha_items_controller::post_create_gacha_item,
gacha_items_controller::put_update_gacha_item,
gacha_items_controller::delete_gacha_item,
gacha_rolls_controller::get_detail_gacha_roll,
gacha_rolls_controller::get_gacha_roll_by_id,
gacha_rolls_controller::post_create_gacha_roll,
gacha_rolls_controller::post_execute_gacha_roll,
gacha_rolls_controller::delete_gacha_roll,
events_controller::get_event_list,
events_controller::get_event_by_id,
events_controller::post_create_event,
@@ -109,8 +108,6 @@ use utoipa::{
),
components(
schemas(
MetaRequestDto,
MetaResponseDto,
MessageResponseDto,
AuthLoginRequestDto,
AuthLoginResponsetDto,
@@ -120,25 +117,26 @@ use utoipa::{
AuthRefreshTokenRequestDto,
ResponseSuccessDto<TokenDto>,
RolesListItemDto,
RolesRequestCreateDto,
RolesRequestUpdateDto,
PermissionsRequestDto,
RolesDetailItemDto,
RolesCreateRequestDto,
RolesUpdateRequestDto,
PermissionsCreateRequestDto,
PermissionsItemDto,
UsersDetailItemDto,
UsersListItemDto,
UsersUpdateRequestDto,
UsersCreateRequestDto,
FileUploadSchema,
GachaClaimItemDto,
GachaClaimRequestDto,
GachaClaimDetailDto,
GachaClaimCreateRequestDto,
GachaItemDto,
GachaItemRequestDto,
GachaItemCreateRequestDto,
GachaRollItemDto,
GachaRollRequestDto,
GachaRollCreateRequestDto,
ResponseListSuccessDto<Vec<GachaItemDto>>,
ResponseSuccessDto<GachaRollItemDto>,
ResponseSuccessDto<GachaItemDto>,
ResponseSuccessDto<GachaClaimItemDto>,
ResponseSuccessDto<GachaClaimDetailDto>,
ResponseSuccessDto<AuthLoginResponsetDto>,
ResponseListSuccessDto<Vec<RolesListItemDto>>,
ResponseSuccessDto<RolesDetailItemDto>,
+72 -59
View File
@@ -1,59 +1,72 @@
use axum::{
Extension,
Router,
middleware::from_fn,
response::Redirect,
routing::get,
};
use imphnen_cms::{
events_protected_routes,
events_public_routes,
testimonials_protected_routes,
testimonials_public_routes,
};
use imphnen_dimentorin::dimentorin_router;
use imphnen_gacha::gacha_router;
use imphnen_iam::{
iam_protected_routes,
iam_public_routes,
v1::auth::auth_repository::AuthRepoImpl,
};
use imphnen_libs::PostgresUserLookupService;
use imphnen_libs::{AppState, axum::PostgresClients};
use imphnen_middleware::{auth_middleware, cors_middleware, rate_limiting_middleware, security_headers_middleware};
use std::sync::Arc;
use utoipa_swagger_ui::SwaggerUi;
pub mod docs;
pub use docs::{ApiDoc, SecurityAddon, docs_router};
pub async fn gateway_service(
postgres_clients: PostgresClients,
) -> Router {
let state = AppState {
postgres_connection: postgres_clients.main.clone(),
user_lookup_service: Arc::new(PostgresUserLookupService::new()),
auth_repository: Arc::new(AuthRepoImpl::new()),
};
let public_routes = Router::new()
.merge(iam_public_routes().layer(from_fn(rate_limiting_middleware)))
.merge(testimonials_public_routes())
.merge(events_public_routes());
let protected_routes = Router::new()
.merge(iam_protected_routes())
.merge(events_protected_routes())
.merge(testimonials_protected_routes())
.merge(dimentorin_router())
.nest("/gacha", gacha_router())
.layer(from_fn(auth_middleware));
Router::new()
.route("/", get(Redirect::to("/docs")))
.nest("/v1", public_routes.merge(protected_routes))
.merge(SwaggerUi::new("/docs").url("/openapi.json", docs_router()))
.layer(cors_middleware())
.layer(from_fn(security_headers_middleware))
.layer(Extension(state))
}
use axum::{
Extension,
Router,
middleware::from_fn,
response::Redirect,
routing::get,
};
use imphnen_cms::{
events_protected_routes,
events_public_routes,
testimonials_protected_routes,
testimonials_public_routes,
};
use imphnen_dimentorin::{
mentors_public_routes, mentors_protected_routes,
sessions_public_routes, sessions_protected_routes,
};
use imphnen_gacha::gacha_router;
use imphnen_iam::{
auth_public_routes,
permissions_protected_routes,
roles_protected_routes,
users_protected_routes,
};
use imphnen_libs::services::PostgresAuthRepository as AuthRepoImpl;
use imphnen_libs::PostgresUserLookupService;
use imphnen_libs::{AppState, axum::PostgresClients};
use imphnen_middleware::{auth_middleware, cors_middleware, rate_limiting_middleware, security_headers_middleware};
use std::sync::Arc;
use utoipa_swagger_ui::SwaggerUi;
pub mod docs;
pub use docs::{ApiDoc, SecurityAddon, docs_router};
pub async fn gateway_service(
postgres_clients: PostgresClients,
) -> Router {
let state = AppState {
postgres_connection: postgres_clients.main.clone(),
user_lookup_service: Arc::new(PostgresUserLookupService::new()),
auth_repository: Arc::new(AuthRepoImpl::new()),
};
let db = state.postgres_connection.conn.clone();
let state_arc = Arc::new(state.clone());
let public_routes = Router::new()
.merge(auth_public_routes(db.clone(), Arc::clone(&state_arc)).layer(from_fn(rate_limiting_middleware)))
.merge(testimonials_public_routes(db.clone()))
.merge(events_public_routes(db.clone()))
.merge(mentors_public_routes(db.clone(), Arc::clone(&state_arc)))
.merge(sessions_public_routes(db.clone()));
let protected_routes = Router::new()
.merge(users_protected_routes(db.clone(), Arc::clone(&state_arc)))
.merge(roles_protected_routes(db.clone(), Arc::clone(&state_arc)))
.merge(permissions_protected_routes(db.clone(), Arc::clone(&state_arc)))
.merge(events_protected_routes(db.clone()))
.merge(testimonials_protected_routes(db.clone()))
.merge(mentors_protected_routes(db.clone(), Arc::clone(&state_arc)))
.merge(sessions_protected_routes(db.clone(), Arc::clone(&state_arc)))
.nest("/gacha", gacha_router(db.clone(), Arc::clone(&state_arc)))
.layer(from_fn(auth_middleware));
Router::new()
.route("/", get(Redirect::to("/docs")))
.nest("/v1", public_routes.merge(protected_routes))
.merge(SwaggerUi::new("/docs").url("/openapi.json", docs_router()))
.layer(cors_middleware())
.layer(from_fn(security_headers_middleware))
.layer(Extension(state))
}