Skip to main content

backbone_support/
lib.rs

1//! Support 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::IssueService;
36pub use application::service::ServiceLevelAgreementService;
37pub use application::service::ServiceLevelPriorityService;
38pub use application::service::WarrantyClaimService;
39
40use std::sync::Arc;
41use axum::Router;
42use sqlx::PgPool;
43
44/// Support module configuration
45///
46/// Use the builder pattern to configure and register this module:
47///
48/// ```text
49/// let support = SupportModule::builder()
50///     .with_database(pool.clone())
51///     .build()?;
52///
53/// // Unguarded full CRUD (trusted/admin); compose a guarded router for production.
54/// let router = support.all_crud_routes();
55/// ```
56pub struct SupportModule {
57    pub(crate) issue_service: Arc<IssueService>,
58    pub(crate) service_level_agreement_service: Arc<ServiceLevelAgreementService>,
59    pub(crate) service_level_priority_service: Arc<ServiceLevelPriorityService>,
60    pub(crate) warranty_claim_service: Arc<WarrantyClaimService>,
61}
62
63impl SupportModule {
64    /// Create a new module builder
65    pub fn builder() -> SupportModuleBuilder {
66        SupportModuleBuilder::new()
67    }
68
69    /// Mount ALL generated CRUD endpoints (12 per entity) with NO domain
70    /// validation — the fully **unguarded** surface. A well-formed request can
71    /// create invalid rows or soft-delete a referenced master out from under its
72    /// dependents. Prefer a guarded composition (read + validated writes) for any
73    /// real deployment; use this only in trusted/admin/seeding contexts.
74    pub fn all_crud_routes(&self) -> Router {
75        use presentation::http::{
76            create_issue_routes,
77            create_service_level_agreement_routes,
78            create_service_level_priority_routes,
79            create_warranty_claim_routes,
80        };
81
82        Router::new()
83            .merge(create_issue_routes(self.issue_service.clone()))
84            .merge(create_service_level_agreement_routes(self.service_level_agreement_service.clone()))
85            .merge(create_service_level_priority_routes(self.service_level_priority_service.clone()))
86            .merge(create_warranty_claim_routes(self.warranty_claim_service.clone()))
87    }
88
89    /// Deprecated alias for [`Self::all_crud_routes`]. `routes()` reads like
90    /// "the routes" but mounts UNVALIDATED generic CRUD on every entity — a naive
91    /// mount exposes unguarded writes. Compose a guarded router (read + validated
92    /// writes) for production, or call `all_crud_routes()` to opt into the full
93    /// unguarded surface explicitly.
94    #[deprecated(note = "mounts unvalidated generic CRUD; prefer readonly_routes() + validated writes, or all_crud_routes() for the full/unguarded surface")]
95    pub fn routes(&self) -> Router {
96        self.all_crud_routes()
97    }
98
99    /// Read-only routes for every entity (GET endpoints only) — the safe base.
100    ///
101    /// Generic mutation can't reach here, so this surface cannot bypass a
102    /// validated write service's invariants. Use this as the production base and
103    /// merge validated write routes (or a write service's HTTP layer) onto it.
104    pub fn readonly_routes(&self) -> Router {
105        use presentation::http::{
106            create_issue_read_routes,
107            create_service_level_agreement_read_routes,
108            create_service_level_priority_read_routes,
109            create_warranty_claim_read_routes,
110        };
111
112        Router::new()
113            .merge(create_issue_read_routes(self.issue_service.clone()))
114            .merge(create_service_level_agreement_read_routes(self.service_level_agreement_service.clone()))
115            .merge(create_service_level_priority_read_routes(self.service_level_priority_service.clone()))
116            .merge(create_warranty_claim_read_routes(self.warranty_claim_service.clone()))
117    }
118
119}
120
121/// Builder for SupportModule
122pub struct SupportModuleBuilder {
123    db_pool: Option<PgPool>,
124}
125
126impl SupportModuleBuilder {
127    /// Create a new builder
128    pub fn new() -> Self {
129        Self {
130            db_pool: None,
131        }
132    }
133
134    /// Set the database connection pool
135    pub fn with_database(mut self, pool: PgPool) -> Self {
136        self.db_pool = Some(pool);
137        self
138    }
139
140
141    /// Build the module with configured dependencies
142    pub fn build(self) -> anyhow::Result<SupportModule> {
143        let db_pool = self.db_pool
144            .ok_or_else(|| anyhow::anyhow!("Database pool not configured"))?;
145
146        // Issue service
147        let issue_repository = Arc::new(IssueRepository::new(db_pool.clone()));
148        let issue_service = Arc::new(IssueService::with_repository(issue_repository.clone()).with_guard(Arc::new(crate::application::service::IssueRowRules)));
149
150        // ServiceLevelAgreement service
151        let service_level_agreement_repository = Arc::new(ServiceLevelAgreementRepository::new(db_pool.clone()));
152        let service_level_agreement_service = Arc::new(ServiceLevelAgreementService::with_repository(service_level_agreement_repository.clone()).with_guard(Arc::new(crate::application::service::ServiceLevelAgreementRowRules)));
153
154        // ServiceLevelPriority service
155        let service_level_priority_repository = Arc::new(ServiceLevelPriorityRepository::new(db_pool.clone()));
156        let service_level_priority_service = Arc::new(ServiceLevelPriorityService::with_repository(service_level_priority_repository.clone()).with_guard(Arc::new(crate::application::service::ServiceLevelPriorityRowRules)));
157
158        // WarrantyClaim service
159        let warranty_claim_repository = Arc::new(WarrantyClaimRepository::new(db_pool.clone()));
160        let warranty_claim_service = Arc::new(WarrantyClaimService::with_repository(warranty_claim_repository.clone()).with_guard(Arc::new(crate::application::service::WarrantyClaimRowRules)));
161
162
163        Ok(SupportModule {
164            issue_service,
165            service_level_agreement_service,
166            service_level_priority_service,
167            warranty_claim_service,
168        })
169    }
170}
171
172impl Default for SupportModuleBuilder {
173    fn default() -> Self {
174        Self::new()
175    }
176}