Skip to main content

backbone_integrations/
lib.rs

1//! Integrations 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// The module's extension (hand-written; ADR-0031).
29#[path = "lib.ext.rs"]
30mod lib_ext;
31pub use lib_ext::*;
32/// This crate's module and builder under fixed names, for the extension's `impl` blocks.
33#[allow(dead_code)]
34pub(crate) type ThisModule = IntegrationsModule;
35#[allow(dead_code)]
36pub(crate) type ThisModuleBuilder = IntegrationsModuleBuilder;
37
38// Re-exports - Infrastructure
39pub use infrastructure::persistence::*;
40
41// Re-exports - Application services
42pub use application::service::IntegrationConnectorService;
43pub use application::service::IntegrationAccountService;
44pub use application::service::IntegrationEventService;
45
46// Re-exports - Workflows
47pub use application::workflows::*;
48
49use std::sync::Arc;
50use axum::Router;
51use sqlx::PgPool;
52
53/// Integrations module configuration
54///
55/// Use the builder pattern to configure and register this module:
56///
57/// ```text
58/// let integrations = IntegrationsModule::builder()
59///     .with_database(pool.clone())
60///     .build()?;
61///
62/// // Unguarded full CRUD (trusted/admin); compose a guarded router for production.
63/// let router = integrations.all_crud_routes();
64/// ```
65pub struct IntegrationsModule {
66    pub(crate) integration_connector_service: Arc<IntegrationConnectorService>,
67    #[allow(dead_code)]
68    pub(crate) integration_account_service: Arc<IntegrationAccountService>,
69    pub(crate) integration_event_service: Arc<IntegrationEventService>,
70    /// The module's extension state (`lib.ext.rs`); its fields read through `Deref`.
71    pub(crate) ext: ModuleExt,
72}
73
74impl std::ops::Deref for IntegrationsModule {
75    type Target = ModuleExt;
76    fn deref(&self) -> &Self::Target {
77        &self.ext
78    }
79}
80
81impl std::ops::DerefMut for IntegrationsModule {
82    fn deref_mut(&mut self) -> &mut Self::Target {
83        &mut self.ext
84    }
85}
86
87/// What the extension's `build` hook receives from the generated build (ADR-0031).
88#[allow(dead_code)]
89pub(crate) struct ModuleParts<'a> {
90    pub(crate) db_pool: &'a PgPool,
91    pub(crate) integration_connector_service: &'a Arc<IntegrationConnectorService>,
92    pub(crate) integration_connector_repository: &'a Arc<IntegrationConnectorRepository>,
93    pub(crate) integration_account_service: &'a Arc<IntegrationAccountService>,
94    pub(crate) integration_account_repository: &'a Arc<IntegrationAccountRepository>,
95    pub(crate) integration_event_service: &'a Arc<IntegrationEventService>,
96    pub(crate) integration_event_repository: &'a Arc<IntegrationEventRepository>,
97}
98
99impl IntegrationsModule {
100    /// Create a new module builder
101    pub fn builder() -> IntegrationsModuleBuilder {
102        IntegrationsModuleBuilder::new()
103    }
104
105    /// Mount ALL generated CRUD endpoints (12 per entity) with NO domain
106    /// validation — the fully **unguarded** surface. A well-formed request can
107    /// create invalid rows or soft-delete a referenced master out from under its
108    /// dependents. Prefer a guarded composition (read + validated writes) for any
109    /// real deployment; use this only in trusted/admin/seeding contexts.
110    pub fn all_crud_routes(&self) -> Router {
111        use presentation::http::{
112            create_integration_connector_routes,
113            create_integration_event_routes,
114        };
115
116        Router::new()
117            .merge(create_integration_connector_routes(self.integration_connector_service.clone()))
118            .merge(create_integration_event_routes(self.integration_event_service.clone()))
119    }
120
121    /// Deprecated alias for [`Self::all_crud_routes`]. `routes()` reads like
122    /// "the routes" but mounts UNVALIDATED generic CRUD on every entity — a naive
123    /// mount exposes unguarded writes. Compose a guarded router (read + validated
124    /// writes) for production, or call `all_crud_routes()` to opt into the full
125    /// unguarded surface explicitly.
126    #[deprecated(note = "mounts unvalidated generic CRUD; prefer readonly_routes() + validated writes, or all_crud_routes() for the full/unguarded surface")]
127    pub fn routes(&self) -> Router {
128        self.all_crud_routes()
129    }
130
131    /// Read-only routes for every entity (GET endpoints only) — the safe base.
132    ///
133    /// Generic mutation can't reach here, so this surface cannot bypass a
134    /// validated write service's invariants. Use this as the production base and
135    /// merge validated write routes (or a write service's HTTP layer) onto it.
136    pub fn readonly_routes(&self) -> Router {
137        use presentation::http::{
138            create_integration_connector_read_routes,
139            create_integration_event_read_routes,
140        };
141
142        Router::new()
143            .merge(create_integration_connector_read_routes(self.integration_connector_service.clone()))
144            .merge(create_integration_event_read_routes(self.integration_event_service.clone()))
145    }
146
147}
148
149/// Builder for IntegrationsModule
150pub struct IntegrationsModuleBuilder {
151    db_pool: Option<PgPool>,
152    /// The builder's extension state (`lib.ext.rs`); its fields read through `Deref`.
153    ext: ModuleBuilderExt,
154}
155
156impl std::ops::Deref for IntegrationsModuleBuilder {
157    type Target = ModuleBuilderExt;
158    fn deref(&self) -> &Self::Target {
159        &self.ext
160    }
161}
162
163impl std::ops::DerefMut for IntegrationsModuleBuilder {
164    fn deref_mut(&mut self) -> &mut Self::Target {
165        &mut self.ext
166    }
167}
168
169impl IntegrationsModuleBuilder {
170    /// Create a new builder
171    pub fn new() -> Self {
172        Self {
173            db_pool: None,
174            ext: Default::default(),
175        }
176    }
177
178    /// Set the database connection pool
179    pub fn with_database(mut self, pool: PgPool) -> Self {
180        self.db_pool = Some(pool);
181        self
182    }
183
184
185    /// Build the module with configured dependencies
186    pub fn build(self) -> anyhow::Result<IntegrationsModule> {
187        let db_pool = self.db_pool
188            .ok_or_else(|| anyhow::anyhow!("Database pool not configured"))?;
189
190        // IntegrationConnector service
191        let integration_connector_repository = Arc::new(IntegrationConnectorRepository::new(db_pool.clone()));
192        let integration_connector_service = Arc::new(IntegrationConnectorService::with_repository(integration_connector_repository.clone()).with_guard(Arc::new(crate::application::service::IntegrationConnectorRowRules)));
193
194        // IntegrationAccount service
195        let integration_account_repository = Arc::new(IntegrationAccountRepository::new(db_pool.clone()));
196        let integration_account_service = Arc::new(IntegrationAccountService::with_repository(integration_account_repository.clone()).with_guard(Arc::new(crate::application::service::IntegrationAccountRowRules)));
197
198        // IntegrationEvent service
199        let integration_event_repository = Arc::new(IntegrationEventRepository::new(db_pool.clone()));
200        let integration_event_service = Arc::new(IntegrationEventService::with_repository(integration_event_repository.clone()).with_guard(Arc::new(crate::application::service::IntegrationEventRowRules)));
201
202
203        // The extension builds its own state from what the generated build made.
204        let ext = self.ext.build(&ModuleParts {
205            db_pool: &db_pool,
206            integration_connector_service: &integration_connector_service,
207            integration_connector_repository: &integration_connector_repository,
208            integration_account_service: &integration_account_service,
209            integration_account_repository: &integration_account_repository,
210            integration_event_service: &integration_event_service,
211            integration_event_repository: &integration_event_repository,
212        })?;
213
214        Ok(IntegrationsModule {
215            integration_connector_service,
216            integration_account_service,
217            integration_event_service,
218            ext,
219        })
220    }
221}
222
223impl Default for IntegrationsModuleBuilder {
224    fn default() -> Self {
225        Self::new()
226    }
227}
228
229// This directory's extension (hand-written; ADR-0031).
230include!("mod.ext.rs");