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