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