backbone-banking 0.7.1

Cash & bank — bank/account master, statement import, reconciliation, and clearing postings (5th GL producer)
Documentation
//! Banking Module
//!
//! Generated by metaphor-schema. Enhanced with runtime implementations.
//!
//! This module provides:
//! - Domain entities and repositories
//! - Application services
//! - HTTP and gRPC handlers
//! - Route configuration
//! - State machine enforcement
//! - Validation rules runtime
//! - RBAC middleware
//! - Trigger execution system
//! - Computed fields
//! - Workflow orchestrator

#![recursion_limit = "1024"]
#![allow(unused_imports)]

// Generated modules
pub mod domain;
pub mod infrastructure;
pub mod application;
pub mod presentation;
pub mod seeders;
pub mod exports;
// <<< CUSTOM MODULES
pub mod request_pool;
// END CUSTOM

// Re-exports for convenience - Domain entities
pub use domain::entity::*;

// Re-exports - Infrastructure
pub use infrastructure::persistence::*;

// Re-exports - Application services
pub use application::service::BankService;
pub use application::service::BankAccountService;
pub use application::service::BankClearanceService;
pub use application::service::BankReconciliationService;
pub use application::service::BankStatementImportService;
pub use application::service::BankTransactionService;
pub use application::service::FxGainLossService;
pub use application::service::ReconcilePresetService;

// Re-exports - Workflows
pub use application::workflows::*;

use std::sync::Arc;
use axum::Router;
use sqlx::PgPool;

/// Banking module configuration
///
/// Use the builder pattern to configure and register this module:
///
/// ```text
/// let banking = BankingModule::builder()
///     .with_database(pool.clone())
///     .build()?;
///
/// // Unguarded full CRUD (trusted/admin); compose a guarded router for production.
/// let router = banking.all_crud_routes();
/// ```
pub struct BankingModule {
    pub(crate) bank_service: Arc<BankService>,
    pub(crate) bank_account_service: Arc<BankAccountService>,
    pub(crate) bank_clearance_service: Arc<BankClearanceService>,
    pub(crate) bank_reconciliation_service: Arc<BankReconciliationService>,
    pub(crate) bank_statement_import_service: Arc<BankStatementImportService>,
    pub(crate) bank_transaction_service: Arc<BankTransactionService>,
    pub(crate) fx_gain_loss_service: Arc<FxGainLossService>,
    pub(crate) reconcile_preset_service: Arc<ReconcilePresetService>,
    // <<< CUSTOM FIELDS
    // END CUSTOM
}

impl BankingModule {
    /// Create a new module builder
    pub fn builder() -> BankingModuleBuilder {
        BankingModuleBuilder::new()
    }

    /// Mount ALL generated CRUD endpoints (12 per entity) with NO domain
    /// validation — the fully **unguarded** surface. A well-formed request can
    /// create invalid rows or soft-delete a referenced master out from under its
    /// dependents. Prefer a guarded composition (read + validated writes) for any
    /// real deployment; use this only in trusted/admin/seeding contexts.
    pub fn all_crud_routes(&self) -> Router {
        use presentation::http::{
            create_bank_routes,
            create_bank_account_routes,
            create_bank_clearance_routes,
            create_bank_reconciliation_routes,
            create_bank_statement_import_routes,
            create_bank_transaction_routes,
            create_fx_gain_loss_routes,
            create_reconcile_preset_routes,
        };

        Router::new()
            .merge(create_bank_routes(self.bank_service.clone()))
            .merge(create_bank_account_routes(self.bank_account_service.clone()))
            .merge(create_bank_clearance_routes(self.bank_clearance_service.clone()))
            .merge(create_bank_reconciliation_routes(self.bank_reconciliation_service.clone()))
            .merge(create_bank_statement_import_routes(self.bank_statement_import_service.clone()))
            .merge(create_bank_transaction_routes(self.bank_transaction_service.clone()))
            .merge(create_fx_gain_loss_routes(self.fx_gain_loss_service.clone()))
            .merge(create_reconcile_preset_routes(self.reconcile_preset_service.clone()))
    }

    /// Deprecated alias for [`Self::all_crud_routes`]. `routes()` reads like
    /// "the routes" but mounts UNVALIDATED generic CRUD on every entity — a naive
    /// mount exposes unguarded writes. Compose a guarded router (read + validated
    /// writes) for production, or call `all_crud_routes()` to opt into the full
    /// unguarded surface explicitly.
    #[deprecated(note = "mounts unvalidated generic CRUD; prefer readonly_routes() + validated writes, or all_crud_routes() for the full/unguarded surface")]
    pub fn routes(&self) -> Router {
        self.all_crud_routes()
    }

    /// Read-only routes for every entity (GET endpoints only) — the safe base.
    ///
    /// Generic mutation can't reach here, so this surface cannot bypass a
    /// validated write service's invariants. Use this as the production base and
    /// merge validated write routes (or a write service's HTTP layer) onto it.
    pub fn readonly_routes(&self) -> Router {
        use presentation::http::{
            create_bank_read_routes,
            create_bank_account_read_routes,
            create_bank_clearance_read_routes,
            create_bank_reconciliation_read_routes,
            create_bank_statement_import_read_routes,
            create_bank_transaction_read_routes,
            create_fx_gain_loss_read_routes,
            create_reconcile_preset_read_routes,
        };

        Router::new()
            .merge(create_bank_read_routes(self.bank_service.clone()))
            .merge(create_bank_account_read_routes(self.bank_account_service.clone()))
            .merge(create_bank_clearance_read_routes(self.bank_clearance_service.clone()))
            .merge(create_bank_reconciliation_read_routes(self.bank_reconciliation_service.clone()))
            .merge(create_bank_statement_import_read_routes(self.bank_statement_import_service.clone()))
            .merge(create_bank_transaction_read_routes(self.bank_transaction_service.clone()))
            .merge(create_fx_gain_loss_read_routes(self.fx_gain_loss_service.clone()))
            .merge(create_reconcile_preset_read_routes(self.reconcile_preset_service.clone()))
    }

    // <<< CUSTOM METHODS
    // END CUSTOM
}

/// Builder for BankingModule
pub struct BankingModuleBuilder {
    db_pool: Option<PgPool>,
    // <<< CUSTOM BUILDER FIELDS
    // END CUSTOM
}

impl BankingModuleBuilder {
    /// Create a new builder
    pub fn new() -> Self {
        Self {
            db_pool: None,
            // <<< CUSTOM BUILDER DEFAULTS
            // END CUSTOM
        }
    }

    /// Set the database connection pool
    pub fn with_database(mut self, pool: PgPool) -> Self {
        self.db_pool = Some(pool);
        self
    }

    // <<< CUSTOM - custom builder methods
    // END CUSTOM

    /// Build the module with configured dependencies
    pub fn build(self) -> anyhow::Result<BankingModule> {
        let db_pool = self.db_pool
            .ok_or_else(|| anyhow::anyhow!("Database pool not configured"))?;

        // Bank service
        let bank_repository = Arc::new(BankRepository::new(db_pool.clone()));
        let bank_service = Arc::new(BankService::with_repository(bank_repository.clone()));

        // BankAccount service
        let bank_account_repository = Arc::new(BankAccountRepository::new(db_pool.clone()));
        let bank_account_service = Arc::new(BankAccountService::with_repository(bank_account_repository.clone()));

        // BankClearance service
        let bank_clearance_repository = Arc::new(BankClearanceRepository::new(db_pool.clone()));
        let bank_clearance_service = Arc::new(BankClearanceService::with_repository(bank_clearance_repository.clone()));

        // BankReconciliation service
        let bank_reconciliation_repository = Arc::new(BankReconciliationRepository::new(db_pool.clone()));
        let bank_reconciliation_service = Arc::new(BankReconciliationService::with_repository(bank_reconciliation_repository.clone()));

        // BankStatementImport service
        let bank_statement_import_repository = Arc::new(BankStatementImportRepository::new(db_pool.clone()));
        let bank_statement_import_service = Arc::new(BankStatementImportService::with_repository(bank_statement_import_repository.clone()));

        // BankTransaction service
        let bank_transaction_repository = Arc::new(BankTransactionRepository::new(db_pool.clone()));
        let bank_transaction_service = Arc::new(BankTransactionService::with_repository(bank_transaction_repository.clone()));

        // FxGainLoss service
        let fx_gain_loss_repository = Arc::new(FxGainLossRepository::new(db_pool.clone()));
        let fx_gain_loss_service = Arc::new(FxGainLossService::with_repository(fx_gain_loss_repository.clone()));

        // ReconcilePreset service
        let reconcile_preset_repository = Arc::new(ReconcilePresetRepository::new(db_pool.clone()));
        let reconcile_preset_service = Arc::new(ReconcilePresetService::with_repository(reconcile_preset_repository.clone()));

        // <<< CUSTOM
        // END CUSTOM

        Ok(BankingModule {
            bank_service,
            bank_account_service,
            bank_clearance_service,
            bank_reconciliation_service,
            bank_statement_import_service,
            bank_transaction_service,
            fx_gain_loss_service,
            reconcile_preset_service,
            // <<< CUSTOM
            // END CUSTOM
        })
    }
}

impl Default for BankingModuleBuilder {
    fn default() -> Self {
        Self::new()
    }
}