Skip to main content

backbone_banking/
lib.rs

1//! Banking Module
2//!
3//! Generated by metaphor-schema. Enhanced with runtime implementations.
4//!
5//! This module provides:
6//! - Domain entities and repositories
7//! - Application services
8//! - HTTP and gRPC handlers
9//! - Route configuration
10//! - State machine enforcement
11//! - Validation rules runtime
12//! - RBAC middleware
13//! - Trigger execution system
14//! - Computed fields
15//! - Workflow orchestrator
16
17#![recursion_limit = "1024"]
18#![allow(unused_imports)]
19
20// Generated modules
21pub mod domain;
22pub mod infrastructure;
23pub mod application;
24pub mod presentation;
25pub mod seeders;
26pub mod exports;
27
28// Re-exports for convenience - Domain entities
29pub use domain::entity::*;
30
31// Re-exports - Infrastructure
32pub use infrastructure::persistence::*;
33
34// Re-exports - Application services
35pub use application::service::BankService;
36pub use application::service::BankAccountService;
37pub use application::service::BankClearanceService;
38pub use application::service::BankReconciliationService;
39pub use application::service::BankStatementImportService;
40pub use application::service::BankTransactionService;
41pub use application::service::FxGainLossService;
42pub use application::service::ReconcilePresetService;
43
44use std::sync::Arc;
45use axum::Router;
46use sqlx::PgPool;
47
48/// Banking module configuration
49///
50/// Use the builder pattern to configure and register this module:
51///
52/// ```text
53/// let banking = BankingModule::builder()
54///     .with_database(pool.clone())
55///     .build()?;
56///
57/// // Unguarded full CRUD (trusted/admin); compose a guarded router for production.
58/// let router = banking.all_crud_routes();
59/// ```
60pub struct BankingModule {
61    pub(crate) bank_service: Arc<BankService>,
62    pub(crate) bank_account_service: Arc<BankAccountService>,
63    pub(crate) bank_clearance_service: Arc<BankClearanceService>,
64    pub(crate) bank_reconciliation_service: Arc<BankReconciliationService>,
65    pub(crate) bank_statement_import_service: Arc<BankStatementImportService>,
66    pub(crate) bank_transaction_service: Arc<BankTransactionService>,
67    pub(crate) fx_gain_loss_service: Arc<FxGainLossService>,
68    pub(crate) reconcile_preset_service: Arc<ReconcilePresetService>,
69}
70
71impl BankingModule {
72    /// Create a new module builder
73    pub fn builder() -> BankingModuleBuilder {
74        BankingModuleBuilder::new()
75    }
76
77    /// Mount ALL generated CRUD endpoints (12 per entity) with NO domain
78    /// validation — the fully **unguarded** surface. A well-formed request can
79    /// create invalid rows or soft-delete a referenced master out from under its
80    /// dependents. Prefer a guarded composition (read + validated writes) for any
81    /// real deployment; use this only in trusted/admin/seeding contexts.
82    pub fn all_crud_routes(&self) -> Router {
83        use presentation::http::{
84            create_bank_routes,
85            create_bank_account_routes,
86            create_bank_clearance_routes,
87            create_bank_reconciliation_routes,
88            create_bank_statement_import_routes,
89            create_bank_transaction_routes,
90            create_fx_gain_loss_routes,
91            create_reconcile_preset_routes,
92        };
93
94        Router::new()
95            .merge(create_bank_routes(self.bank_service.clone()))
96            .merge(create_bank_account_routes(self.bank_account_service.clone()))
97            .merge(create_bank_clearance_routes(self.bank_clearance_service.clone()))
98            .merge(create_bank_reconciliation_routes(self.bank_reconciliation_service.clone()))
99            .merge(create_bank_statement_import_routes(self.bank_statement_import_service.clone()))
100            .merge(create_bank_transaction_routes(self.bank_transaction_service.clone()))
101            .merge(create_fx_gain_loss_routes(self.fx_gain_loss_service.clone()))
102            .merge(create_reconcile_preset_routes(self.reconcile_preset_service.clone()))
103    }
104
105    /// Deprecated alias for [`Self::all_crud_routes`]. `routes()` reads like
106    /// "the routes" but mounts UNVALIDATED generic CRUD on every entity — a naive
107    /// mount exposes unguarded writes. Compose a guarded router (read + validated
108    /// writes) for production, or call `all_crud_routes()` to opt into the full
109    /// unguarded surface explicitly.
110    #[deprecated(note = "mounts unvalidated generic CRUD; prefer readonly_routes() + validated writes, or all_crud_routes() for the full/unguarded surface")]
111    pub fn routes(&self) -> Router {
112        self.all_crud_routes()
113    }
114
115    /// Read-only routes for every entity (GET endpoints only) — the safe base.
116    ///
117    /// Generic mutation can't reach here, so this surface cannot bypass a
118    /// validated write service's invariants. Use this as the production base and
119    /// merge validated write routes (or a write service's HTTP layer) onto it.
120    pub fn readonly_routes(&self) -> Router {
121        use presentation::http::{
122            create_bank_read_routes,
123            create_bank_account_read_routes,
124            create_bank_clearance_read_routes,
125            create_bank_reconciliation_read_routes,
126            create_bank_statement_import_read_routes,
127            create_bank_transaction_read_routes,
128            create_fx_gain_loss_read_routes,
129            create_reconcile_preset_read_routes,
130        };
131
132        Router::new()
133            .merge(create_bank_read_routes(self.bank_service.clone()))
134            .merge(create_bank_account_read_routes(self.bank_account_service.clone()))
135            .merge(create_bank_clearance_read_routes(self.bank_clearance_service.clone()))
136            .merge(create_bank_reconciliation_read_routes(self.bank_reconciliation_service.clone()))
137            .merge(create_bank_statement_import_read_routes(self.bank_statement_import_service.clone()))
138            .merge(create_bank_transaction_read_routes(self.bank_transaction_service.clone()))
139            .merge(create_fx_gain_loss_read_routes(self.fx_gain_loss_service.clone()))
140            .merge(create_reconcile_preset_read_routes(self.reconcile_preset_service.clone()))
141    }
142
143}
144
145/// Builder for BankingModule
146pub struct BankingModuleBuilder {
147    db_pool: Option<PgPool>,
148}
149
150impl BankingModuleBuilder {
151    /// Create a new builder
152    pub fn new() -> Self {
153        Self {
154            db_pool: None,
155        }
156    }
157
158    /// Set the database connection pool
159    pub fn with_database(mut self, pool: PgPool) -> Self {
160        self.db_pool = Some(pool);
161        self
162    }
163
164
165    /// Build the module with configured dependencies
166    pub fn build(self) -> anyhow::Result<BankingModule> {
167        let db_pool = self.db_pool
168            .ok_or_else(|| anyhow::anyhow!("Database pool not configured"))?;
169
170        // Bank service
171        let bank_repository = Arc::new(BankRepository::new(db_pool.clone()));
172        let bank_service = Arc::new(BankService::with_repository(bank_repository.clone()).with_guard(Arc::new(crate::application::service::BankRowRules)));
173
174        // BankAccount service
175        let bank_account_repository = Arc::new(BankAccountRepository::new(db_pool.clone()));
176        let bank_account_service = Arc::new(BankAccountService::with_repository(bank_account_repository.clone()).with_guard(Arc::new(crate::application::service::BankAccountRowRules)));
177
178        // BankClearance service
179        let bank_clearance_repository = Arc::new(BankClearanceRepository::new(db_pool.clone()));
180        let bank_clearance_service = Arc::new(BankClearanceService::with_repository(bank_clearance_repository.clone()).with_guard(Arc::new(crate::application::service::BankClearanceRowRules)));
181
182        // BankReconciliation service
183        let bank_reconciliation_repository = Arc::new(BankReconciliationRepository::new(db_pool.clone()));
184        let bank_reconciliation_service = Arc::new(BankReconciliationService::with_repository(bank_reconciliation_repository.clone()).with_guard(Arc::new(crate::application::service::BankReconciliationRowRules)));
185
186        // BankStatementImport service
187        let bank_statement_import_repository = Arc::new(BankStatementImportRepository::new(db_pool.clone()));
188        let bank_statement_import_service = Arc::new(BankStatementImportService::with_repository(bank_statement_import_repository.clone()).with_guard(Arc::new(crate::application::service::BankStatementImportRowRules)));
189
190        // BankTransaction service
191        let bank_transaction_repository = Arc::new(BankTransactionRepository::new(db_pool.clone()));
192        let bank_transaction_service = Arc::new(BankTransactionService::with_repository(bank_transaction_repository.clone()).with_guard(Arc::new(crate::application::service::BankTransactionRowRules)));
193
194        // FxGainLoss service
195        let fx_gain_loss_repository = Arc::new(FxGainLossRepository::new(db_pool.clone()));
196        let fx_gain_loss_service = Arc::new(FxGainLossService::with_repository(fx_gain_loss_repository.clone()).with_guard(Arc::new(crate::application::service::FxGainLossRowRules)));
197
198        // ReconcilePreset service
199        let reconcile_preset_repository = Arc::new(ReconcilePresetRepository::new(db_pool.clone()));
200        let reconcile_preset_service = Arc::new(ReconcilePresetService::with_repository(reconcile_preset_repository.clone()).with_guard(Arc::new(crate::application::service::ReconcilePresetRowRules)));
201
202
203        Ok(BankingModule {
204            bank_service,
205            bank_account_service,
206            bank_clearance_service,
207            bank_reconciliation_service,
208            bank_statement_import_service,
209            bank_transaction_service,
210            fx_gain_loss_service,
211            reconcile_preset_service,
212        })
213    }
214}
215
216impl Default for BankingModuleBuilder {
217    fn default() -> Self {
218        Self::new()
219    }
220}
221
222// This directory's extension (hand-written; ADR-0031).
223include!("mod.ext.rs");