Skip to main content

backbone_pos/
lib.rs

1//! Pos 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;
26// <<< CUSTOM
27/// Stable integration surface for composing services (the deliberate public API consumers depend on).
28pub mod integration;
29// END CUSTOM
30pub mod exports;
31
32// Re-exports for convenience - Domain entities
33pub use domain::entity::*;
34
35// Re-exports - Infrastructure
36pub use infrastructure::persistence::*;
37
38// Re-exports - Application services
39pub use application::service::PosClosingEntryService;
40pub use application::service::PosInvoiceService;
41pub use application::service::PosInvoiceItemService;
42pub use application::service::PosPaymentService;
43pub use application::service::PosProfileService;
44pub use application::service::PosOpeningEntryService;
45pub use application::service::PosCashMovementService;
46pub use application::service::PosDiscountService;
47pub use application::service::PosManagerPinService;
48pub use application::service::PosFloorPlanService;
49pub use application::service::PosTableService;
50
51// Re-exports - Validation
52pub use application::validator::{ValidationError, ValidationResult};
53
54use std::sync::Arc;
55use axum::Router;
56use sqlx::PgPool;
57
58/// Pos module configuration
59///
60/// Use the builder pattern to configure and register this module:
61///
62/// ```text
63/// let pos = PosModule::builder()
64///     .with_database(pool.clone())
65///     .build()?;
66///
67/// // Unguarded full CRUD (trusted/admin); compose a guarded router for production.
68/// let router = pos.all_crud_routes();
69/// ```
70pub struct PosModule {
71    pub(crate) pos_closing_entry_service: Arc<PosClosingEntryService>,
72    pub(crate) pos_invoice_service: Arc<PosInvoiceService>,
73    pub(crate) pos_invoice_item_service: Arc<PosInvoiceItemService>,
74    pub(crate) pos_payment_service: Arc<PosPaymentService>,
75    pub(crate) pos_profile_service: Arc<PosProfileService>,
76    pub(crate) pos_opening_entry_service: Arc<PosOpeningEntryService>,
77    pub(crate) pos_cash_movement_service: Arc<PosCashMovementService>,
78    pub(crate) pos_discount_service: Arc<PosDiscountService>,
79    pub(crate) pos_manager_pin_service: Arc<PosManagerPinService>,
80    pub(crate) pos_floor_plan_service: Arc<PosFloorPlanService>,
81    pub(crate) pos_table_service: Arc<PosTableService>,
82    // <<< CUSTOM FIELDS
83    // END CUSTOM
84}
85
86impl PosModule {
87    /// Create a new module builder
88    pub fn builder() -> PosModuleBuilder {
89        PosModuleBuilder::new()
90    }
91
92    /// Mount ALL generated CRUD endpoints (12 per entity) with NO domain
93    /// validation — the fully **unguarded** surface. A well-formed request can
94    /// create invalid rows or soft-delete a referenced master out from under its
95    /// dependents. Prefer a guarded composition (read + validated writes) for any
96    /// real deployment; use this only in trusted/admin/seeding contexts.
97    pub fn all_crud_routes(&self) -> Router {
98        use presentation::http::{
99            create_pos_closing_entry_routes,
100            create_pos_invoice_routes,
101            create_pos_invoice_item_routes,
102            create_pos_payment_routes,
103            create_pos_profile_routes,
104            create_pos_opening_entry_routes,
105            create_pos_cash_movement_routes,
106            create_pos_discount_routes,
107            create_pos_manager_pin_routes,
108            create_pos_floor_plan_routes,
109            create_pos_table_routes,
110        };
111
112        Router::new()
113            .merge(create_pos_closing_entry_routes(self.pos_closing_entry_service.clone()))
114            .merge(create_pos_invoice_routes(self.pos_invoice_service.clone()))
115            .merge(create_pos_invoice_item_routes(self.pos_invoice_item_service.clone()))
116            .merge(create_pos_payment_routes(self.pos_payment_service.clone()))
117            .merge(create_pos_profile_routes(self.pos_profile_service.clone()))
118            .merge(create_pos_opening_entry_routes(self.pos_opening_entry_service.clone()))
119            .merge(create_pos_cash_movement_routes(self.pos_cash_movement_service.clone()))
120            .merge(create_pos_discount_routes(self.pos_discount_service.clone()))
121            .merge(create_pos_manager_pin_routes(self.pos_manager_pin_service.clone()))
122            .merge(create_pos_floor_plan_routes(self.pos_floor_plan_service.clone()))
123            .merge(create_pos_table_routes(self.pos_table_service.clone()))
124    }
125
126    /// Deprecated alias for [`Self::all_crud_routes`]. `routes()` reads like
127    /// "the routes" but mounts UNVALIDATED generic CRUD on every entity — a naive
128    /// mount exposes unguarded writes. Compose a guarded router (read + validated
129    /// writes) for production, or call `all_crud_routes()` to opt into the full
130    /// unguarded surface explicitly.
131    #[deprecated(note = "mounts unvalidated generic CRUD; prefer readonly_routes() + validated writes, or all_crud_routes() for the full/unguarded surface")]
132    pub fn routes(&self) -> Router {
133        self.all_crud_routes()
134    }
135
136    /// Read-only routes for every entity (GET endpoints only) — the safe base.
137    ///
138    /// Generic mutation can't reach here, so this surface cannot bypass a
139    /// validated write service's invariants. Use this as the production base and
140    /// merge validated write routes (or a write service's HTTP layer) onto it.
141    pub fn readonly_routes(&self) -> Router {
142        use presentation::http::{
143            create_pos_closing_entry_read_routes,
144            create_pos_invoice_read_routes,
145            create_pos_invoice_item_read_routes,
146            create_pos_payment_read_routes,
147            create_pos_profile_read_routes,
148            create_pos_opening_entry_read_routes,
149            create_pos_cash_movement_read_routes,
150            create_pos_discount_read_routes,
151            create_pos_manager_pin_read_routes,
152            create_pos_floor_plan_read_routes,
153            create_pos_table_read_routes,
154        };
155
156        Router::new()
157            .merge(create_pos_closing_entry_read_routes(self.pos_closing_entry_service.clone()))
158            .merge(create_pos_invoice_read_routes(self.pos_invoice_service.clone()))
159            .merge(create_pos_invoice_item_read_routes(self.pos_invoice_item_service.clone()))
160            .merge(create_pos_payment_read_routes(self.pos_payment_service.clone()))
161            .merge(create_pos_profile_read_routes(self.pos_profile_service.clone()))
162            .merge(create_pos_opening_entry_read_routes(self.pos_opening_entry_service.clone()))
163            .merge(create_pos_cash_movement_read_routes(self.pos_cash_movement_service.clone()))
164            .merge(create_pos_discount_read_routes(self.pos_discount_service.clone()))
165            .merge(create_pos_manager_pin_read_routes(self.pos_manager_pin_service.clone()))
166            .merge(create_pos_floor_plan_read_routes(self.pos_floor_plan_service.clone()))
167            .merge(create_pos_table_read_routes(self.pos_table_service.clone()))
168    }
169
170    // <<< CUSTOM METHODS
171    // END CUSTOM
172}
173
174/// Builder for PosModule
175pub struct PosModuleBuilder {
176    db_pool: Option<PgPool>,
177}
178
179impl PosModuleBuilder {
180    /// Create a new builder
181    pub fn new() -> Self {
182        Self {
183            db_pool: None,
184        }
185    }
186
187    /// Set the database connection pool
188    pub fn with_database(mut self, pool: PgPool) -> Self {
189        self.db_pool = Some(pool);
190        self
191    }
192
193    // <<< CUSTOM - custom builder methods
194    // END CUSTOM
195
196    /// Build the module with configured dependencies
197    pub fn build(self) -> anyhow::Result<PosModule> {
198        let db_pool = self.db_pool
199            .ok_or_else(|| anyhow::anyhow!("Database pool not configured"))?;
200
201        // PosClosingEntry service
202        let pos_closing_entry_repository = Arc::new(PosClosingEntryRepository::new(db_pool.clone()));
203        let pos_closing_entry_service = Arc::new(PosClosingEntryService::with_repository(pos_closing_entry_repository.clone()));
204
205        // PosInvoice service
206        let pos_invoice_repository = Arc::new(PosInvoiceRepository::new(db_pool.clone()));
207        let pos_invoice_service = Arc::new(PosInvoiceService::with_repository(pos_invoice_repository.clone()));
208
209        // PosInvoiceItem service
210        let pos_invoice_item_repository = Arc::new(PosInvoiceItemRepository::new(db_pool.clone()));
211        let pos_invoice_item_service = Arc::new(PosInvoiceItemService::with_repository(pos_invoice_item_repository.clone()));
212
213        // PosPayment service
214        let pos_payment_repository = Arc::new(PosPaymentRepository::new(db_pool.clone()));
215        let pos_payment_service = Arc::new(PosPaymentService::with_repository(pos_payment_repository.clone()));
216
217        // PosProfile service
218        let pos_profile_repository = Arc::new(PosProfileRepository::new(db_pool.clone()));
219        let pos_profile_service = Arc::new(PosProfileService::with_repository(pos_profile_repository.clone()));
220
221        // PosOpeningEntry service
222        let pos_opening_entry_repository = Arc::new(PosOpeningEntryRepository::new(db_pool.clone()));
223        let pos_opening_entry_service = Arc::new(PosOpeningEntryService::with_repository(pos_opening_entry_repository.clone()));
224
225        // PosCashMovement service
226        let pos_cash_movement_repository = Arc::new(PosCashMovementRepository::new(db_pool.clone()));
227        let pos_cash_movement_service = Arc::new(PosCashMovementService::with_repository(pos_cash_movement_repository.clone()));
228
229        // PosDiscount service
230        let pos_discount_repository = Arc::new(PosDiscountRepository::new(db_pool.clone()));
231        let pos_discount_service = Arc::new(PosDiscountService::with_repository(pos_discount_repository.clone()));
232
233        // PosManagerPin service
234        let pos_manager_pin_repository = Arc::new(PosManagerPinRepository::new(db_pool.clone()));
235        let pos_manager_pin_service = Arc::new(PosManagerPinService::with_repository(pos_manager_pin_repository.clone()));
236
237        // PosFloorPlan service
238        let pos_floor_plan_repository = Arc::new(PosFloorPlanRepository::new(db_pool.clone()));
239        let pos_floor_plan_service = Arc::new(PosFloorPlanService::with_repository(pos_floor_plan_repository.clone()));
240
241        // PosTable service
242        let pos_table_repository = Arc::new(PosTableRepository::new(db_pool.clone()));
243        let pos_table_service = Arc::new(PosTableService::with_repository(pos_table_repository.clone()));
244
245        // <<< CUSTOM
246        // END CUSTOM
247
248        Ok(PosModule {
249            pos_closing_entry_service,
250            pos_invoice_service,
251            pos_invoice_item_service,
252            pos_payment_service,
253            pos_profile_service,
254            pos_opening_entry_service,
255            pos_cash_movement_service,
256            pos_discount_service,
257            pos_manager_pin_service,
258            pos_floor_plan_service,
259            pos_table_service,
260            // <<< CUSTOM
261            // END CUSTOM
262        })
263    }
264}
265
266impl Default for PosModuleBuilder {
267    fn default() -> Self {
268        Self::new()
269    }
270}