diff --git a/crates/bootstrap/src/factory.rs b/crates/bootstrap/src/factory.rs index 6b7bd77..be823bd 100644 --- a/crates/bootstrap/src/factory.rs +++ b/crates/bootstrap/src/factory.rs @@ -7,55 +7,12 @@ use tower_http::{ trace::TraceLayer, }; -use adapters_auth::{BcryptPasswordHasher, JwtTokenIssuer}; - -use adapters_postgres::{ - PostgresAlbumRepository, PostgresAssetMetadataRepository, PostgresAssetRepository, - PostgresDuplicateRepository, PostgresIngestSessionRepository, PostgresJobBatchRepository, - PostgresJobRepository, PostgresLibraryPathRepository, PostgresPipelineRepository, - PostgresPluginRepository, PostgresQuotaRepository, PostgresShareRepository, - PostgresSidecarRepository, PostgresStorageVolumeRepository, PostgresTagRepository, - PostgresUsageLedgerRepository, PostgresUserRepository, PostgresVisibilityFilterRepository, - connect, run_migrations, -}; - +use adapters_postgres::{connect, run_migrations}; use adapters_storage::LocalFileStorage; - -use application::{ - catalog::{ - GetAssetHandler, GetTimelineHandler, ReadAssetFileHandler, RegisterAssetHandler, - UpdateMetadataHandler, - }, - identity::{GetProfileHandler, LoginUserHandler, RegisterUserHandler}, - organization::{ - CreateAlbumHandler, GetAlbumHandler, ManageAlbumEntriesHandler, TagAssetHandler, - }, - processing::{ - CompleteJobHandler, ConfigurePipelineHandler, EnqueueJobHandler, FailJobHandler, - ManagePluginHandler, ReportBatchProgressHandler, StartJobHandler, - }, - sharing::{ - AccessSharedResourceHandler, GenerateShareLinkHandler, RevokeShareHandler, - ShareResourceHandler, - }, - sidecar::{ - DetectExternalChangesHandler, ExportSidecarHandler, FullExportHandler, FullImportHandler, - ImportSidecarHandler, ResolveConflictHandler, - }, - storage::{ - CheckQuotaHandler, IngestAssetHandler, RegisterLibraryPathHandler, RegisterVolumeHandler, - }, -}; -use presentation::{ - routes::app_router, - state::{ - AppState, CatalogHandlers, IdentityHandlers, OrganizationHandlers, ProcessingHandlers, - SharingHandlers, SidecarHandlers, StorageHandlers, - }, -}; +use presentation::{routes::app_router, state::AppState}; use crate::config::Config; -use crate::log_sidecar_writer::LogSidecarWriter; +use crate::services; pub async fn build_app(config: &Config) -> Result { let pool = connect(&config.database_url).await?; @@ -64,222 +21,31 @@ pub async fn build_app(config: &Config) -> Result { let nats_client = async_nats::connect(&config.nats_url).await?; adapters_nats::ensure_stream(&nats_client).await?; - // Identity - let user_repo = Arc::new(PostgresUserRepository::new(pool.clone())); - let hasher = Arc::new(BcryptPasswordHasher); - let issuer = Arc::new(JwtTokenIssuer::new(&config.jwt_secret)); - - let register_handler = Arc::new(RegisterUserHandler::new(user_repo.clone(), hasher.clone())); - let login_handler = Arc::new(LoginUserHandler::new( - user_repo.clone(), - hasher, - issuer.clone(), - )); - let get_profile_handler = Arc::new(GetProfileHandler::new(user_repo)); - - // Repos - let album_repo = Arc::new(PostgresAlbumRepository::new(pool.clone())); - let asset_repo = Arc::new(PostgresAssetRepository::new(pool.clone())); - let metadata_repo = Arc::new(PostgresAssetMetadataRepository::new(pool.clone())); - let volume_repo = Arc::new(PostgresStorageVolumeRepository::new(pool.clone())); - let path_repo = Arc::new(PostgresLibraryPathRepository::new(pool.clone())); - let session_repo = Arc::new(PostgresIngestSessionRepository::new(pool.clone())); - let quota_repo = Arc::new(PostgresQuotaRepository::new(pool.clone())); - let ledger_repo = Arc::new(PostgresUsageLedgerRepository::new(pool.clone())); - let tag_repo = Arc::new(PostgresTagRepository::new(pool.clone())); - let duplicate_repo = Arc::new(PostgresDuplicateRepository::new(pool.clone())); - let sidecar_repo = Arc::new(PostgresSidecarRepository::new(pool.clone())); - let job_repo = Arc::new(PostgresJobRepository::new(pool.clone())); - let batch_repo = Arc::new(PostgresJobBatchRepository::new(pool.clone())); - let plugin_repo = Arc::new(PostgresPluginRepository::new(pool.clone())); - let pipeline_repo = Arc::new(PostgresPipelineRepository::new(pool.clone())); let transport = adapters_nats::NatsTransport::new(nats_client); let event_publisher: Arc = Arc::new(event_transport::EventPublisherAdapter::new(transport)); - let sidecar_writer: Arc = Arc::new(LogSidecarWriter); - // File storage let storage_path = std::env::var("STORAGE_PATH").unwrap_or_else(|_| "./data/media".to_string()); let file_storage: Arc = Arc::new(LocalFileStorage::new(&storage_path)); - // Album handlers - let create_album_handler = Arc::new(CreateAlbumHandler::new(album_repo.clone())); - let get_album_handler = Arc::new(GetAlbumHandler::new(album_repo.clone())); - let manage_album_entries_handler = Arc::new(ManageAlbumEntriesHandler::new(album_repo)); - - // Asset handlers - let ingest_asset_handler = Arc::new(IngestAssetHandler::new( - session_repo, - path_repo.clone(), - quota_repo.clone(), - ledger_repo.clone(), - asset_repo.clone(), - file_storage.clone(), - event_publisher.clone(), - )); - let get_asset_handler = Arc::new(GetAssetHandler::new( - asset_repo.clone(), - metadata_repo.clone(), - )); - let get_timeline_handler = Arc::new(GetTimelineHandler::new( - asset_repo.clone(), - metadata_repo.clone(), - )); - let update_metadata_handler = Arc::new(UpdateMetadataHandler::new( - asset_repo.clone(), - metadata_repo.clone(), - event_publisher.clone(), - )); - let read_asset_file_handler = - Arc::new(ReadAssetFileHandler::new(asset_repo.clone(), file_storage)); - - // Register asset handler - let register_asset_handler = Arc::new(RegisterAssetHandler::new( - asset_repo.clone(), - duplicate_repo, - event_publisher.clone(), - )); - - // Tag handler - let tag_asset_handler = Arc::new(TagAssetHandler::new(asset_repo.clone(), tag_repo)); - - // Check quota handler - let check_quota_handler = Arc::new(CheckQuotaHandler::new(quota_repo, ledger_repo)); - - // Sidecar handlers - let export_sidecar_handler = Arc::new(ExportSidecarHandler::new( - metadata_repo.clone(), - sidecar_repo.clone(), - sidecar_writer.clone(), - )); - let detect_changes_handler = Arc::new(DetectExternalChangesHandler::new( - sidecar_repo.clone(), - sidecar_writer.clone(), - )); - let import_sidecar_handler = Arc::new(ImportSidecarHandler::new( - sidecar_repo.clone(), - sidecar_writer.clone(), - metadata_repo.clone(), - )); - let resolve_conflict_handler = Arc::new(ResolveConflictHandler::new( - sidecar_repo.clone(), - sidecar_writer.clone(), - metadata_repo.clone(), - )); - let full_export_handler = Arc::new(FullExportHandler::new( - asset_repo.clone(), - metadata_repo.clone(), - sidecar_repo.clone(), - sidecar_writer.clone(), - )); - let full_import_handler = Arc::new(FullImportHandler::new( - asset_repo, - metadata_repo, - sidecar_repo, - sidecar_writer, - )); - - // Processing handlers - let enqueue_job_handler = Arc::new(EnqueueJobHandler::new( - job_repo.clone(), - event_publisher.clone(), - )); - let start_job_handler = Arc::new(StartJobHandler::new(job_repo.clone())); - let complete_job_handler = Arc::new(CompleteJobHandler::new( - job_repo.clone(), - batch_repo.clone(), - event_publisher.clone(), - )); - let fail_job_handler = Arc::new(FailJobHandler::new( - job_repo.clone(), - batch_repo.clone(), - event_publisher.clone(), - )); - let batch_progress_handler = Arc::new(ReportBatchProgressHandler::new(batch_repo, job_repo)); - let manage_plugin_handler = Arc::new(ManagePluginHandler::new(plugin_repo.clone())); - let configure_pipeline_handler = - Arc::new(ConfigurePipelineHandler::new(pipeline_repo, plugin_repo)); - - // Sharing repos & handlers - let share_repo = Arc::new(PostgresShareRepository::new(pool.clone())); - let _visibility_filter_repo = Arc::new(PostgresVisibilityFilterRepository::new(pool)); - - let share_resource_handler = Arc::new(ShareResourceHandler::new( - share_repo.clone(), - event_publisher.clone(), - )); - let generate_link_handler = Arc::new(GenerateShareLinkHandler::new(share_repo.clone())); - let revoke_handler = Arc::new(RevokeShareHandler::new(share_repo.clone(), event_publisher)); - let access_handler = Arc::new(AccessSharedResourceHandler::new(share_repo)); - - // Storage handlers - let register_volume_handler = Arc::new(RegisterVolumeHandler::new(volume_repo.clone())); - let register_library_path_handler = - Arc::new(RegisterLibraryPathHandler::new(volume_repo, path_repo)); - - let identity = IdentityHandlers { - register: register_handler, - login: login_handler, - get_profile: get_profile_handler, - }; - - let catalog = CatalogHandlers { - ingest_asset: ingest_asset_handler, - get_asset: get_asset_handler, - get_timeline: get_timeline_handler, - update_metadata: update_metadata_handler, - read_asset_file: read_asset_file_handler, - register_asset: register_asset_handler, - }; - - let organization = OrganizationHandlers { - create_album: create_album_handler, - get_album: get_album_handler, - manage_album_entries: manage_album_entries_handler, - tag_asset: tag_asset_handler, - }; - - let storage_handlers = StorageHandlers { - register_volume: register_volume_handler, - register_library_path: register_library_path_handler, - check_quota: check_quota_handler, - }; - - let sidecar = SidecarHandlers { - export: export_sidecar_handler, - detect_changes: detect_changes_handler, - import: import_sidecar_handler, - resolve: resolve_conflict_handler, - full_export: full_export_handler, - full_import: full_import_handler, - }; - - let processing = ProcessingHandlers { - enqueue_job: enqueue_job_handler, - start_job: start_job_handler, - complete_job: complete_job_handler, - fail_job: fail_job_handler, - batch_progress: batch_progress_handler, - manage_plugin: manage_plugin_handler, - configure_pipeline: configure_pipeline_handler, - }; - - let sharing = SharingHandlers { - share_resource: share_resource_handler, - generate_link: generate_link_handler, - revoke: revoke_handler, - access: access_handler, - }; + // Build per-context services + let identity = services::identity::build(&pool, &config.jwt_secret); + let (storage_repos, storage) = services::storage::build(&pool); + let catalog = services::catalog::build(&pool, &storage_repos, file_storage, event_publisher.clone()); + let organization = services::organization::build(&pool); + let sidecar = services::sidecar::build(&pool); + let processing = services::processing::build(&pool, event_publisher.clone()); + let sharing = services::sharing::build(&pool, event_publisher); let state = AppState { - identity, + identity: identity.handlers, catalog, organization, - storage: storage_handlers, + storage, sharing, sidecar, processing, - token_issuer: issuer, + token_issuer: identity.token_issuer, }; let cors = CorsLayer::new() diff --git a/crates/bootstrap/src/lib.rs b/crates/bootstrap/src/lib.rs index d971a4f..70319fb 100644 --- a/crates/bootstrap/src/lib.rs +++ b/crates/bootstrap/src/lib.rs @@ -1,3 +1,4 @@ pub mod config; pub mod factory; pub mod log_sidecar_writer; +pub mod services; diff --git a/crates/bootstrap/src/main.rs b/crates/bootstrap/src/main.rs index fe930a1..ef5dbcb 100644 --- a/crates/bootstrap/src/main.rs +++ b/crates/bootstrap/src/main.rs @@ -4,6 +4,7 @@ use tracing::info; mod config; mod factory; mod log_sidecar_writer; +mod services; #[tokio::main] async fn main() -> anyhow::Result<()> { diff --git a/crates/bootstrap/src/services/catalog.rs b/crates/bootstrap/src/services/catalog.rs new file mode 100644 index 0000000..f9c282b --- /dev/null +++ b/crates/bootstrap/src/services/catalog.rs @@ -0,0 +1,70 @@ +use std::sync::Arc; + +use adapters_postgres::{ + PgPool, PostgresAssetMetadataRepository, PostgresAssetRepository, + PostgresDuplicateRepository, +}; +use adapters_storage::LocalFileStorage; +use application::catalog::{ + GetAssetHandler, GetTimelineHandler, ReadAssetFileHandler, RegisterAssetHandler, + UpdateMetadataHandler, +}; +use application::storage::IngestAssetHandler; +use domain::ports::EventPublisher; +use presentation::state::CatalogHandlers; + +use super::storage::StorageRepos; + +pub fn build( + pool: &PgPool, + storage_repos: &StorageRepos, + file_storage: Arc, + event_publisher: Arc, +) -> CatalogHandlers { + let asset_repo = Arc::new(PostgresAssetRepository::new(pool.clone())); + let metadata_repo = Arc::new(PostgresAssetMetadataRepository::new(pool.clone())); + let duplicate_repo = Arc::new(PostgresDuplicateRepository::new(pool.clone())); + + let ingest_asset = Arc::new(IngestAssetHandler::new( + storage_repos.session_repo.clone(), + storage_repos.path_repo.clone(), + storage_repos.quota_repo.clone(), + storage_repos.ledger_repo.clone(), + asset_repo.clone(), + file_storage.clone(), + event_publisher.clone(), + )); + + let get_asset = Arc::new(GetAssetHandler::new( + asset_repo.clone(), + metadata_repo.clone(), + )); + + let get_timeline = Arc::new(GetTimelineHandler::new( + asset_repo.clone(), + metadata_repo.clone(), + )); + + let update_metadata = Arc::new(UpdateMetadataHandler::new( + asset_repo.clone(), + metadata_repo.clone(), + event_publisher.clone(), + )); + + let read_asset_file = Arc::new(ReadAssetFileHandler::new(asset_repo.clone(), file_storage)); + + let register_asset = Arc::new(RegisterAssetHandler::new( + asset_repo, + duplicate_repo, + event_publisher, + )); + + CatalogHandlers { + ingest_asset, + get_asset, + get_timeline, + update_metadata, + read_asset_file, + register_asset, + } +} diff --git a/crates/bootstrap/src/services/identity.rs b/crates/bootstrap/src/services/identity.rs new file mode 100644 index 0000000..2bc38c8 --- /dev/null +++ b/crates/bootstrap/src/services/identity.rs @@ -0,0 +1,35 @@ +use std::sync::Arc; + +use adapters_auth::{BcryptPasswordHasher, JwtTokenIssuer}; +use adapters_postgres::{PgPool, PostgresUserRepository}; +use application::identity::{GetProfileHandler, LoginUserHandler, RegisterUserHandler}; +use domain::ports::TokenIssuer; +use presentation::state::IdentityHandlers; + +pub struct IdentityServices { + pub handlers: IdentityHandlers, + pub token_issuer: Arc, +} + +pub fn build(pool: &PgPool, jwt_secret: &str) -> IdentityServices { + let user_repo = Arc::new(PostgresUserRepository::new(pool.clone())); + let hasher = Arc::new(BcryptPasswordHasher); + let issuer: Arc = Arc::new(JwtTokenIssuer::new(jwt_secret)); + + let register = Arc::new(RegisterUserHandler::new(user_repo.clone(), hasher.clone())); + let login = Arc::new(LoginUserHandler::new( + user_repo.clone(), + hasher, + issuer.clone(), + )); + let get_profile = Arc::new(GetProfileHandler::new(user_repo)); + + IdentityServices { + handlers: IdentityHandlers { + register, + login, + get_profile, + }, + token_issuer: issuer, + } +} diff --git a/crates/bootstrap/src/services/mod.rs b/crates/bootstrap/src/services/mod.rs new file mode 100644 index 0000000..652e290 --- /dev/null +++ b/crates/bootstrap/src/services/mod.rs @@ -0,0 +1,7 @@ +pub mod catalog; +pub mod identity; +pub mod organization; +pub mod processing; +pub mod sharing; +pub mod sidecar; +pub mod storage; diff --git a/crates/bootstrap/src/services/organization.rs b/crates/bootstrap/src/services/organization.rs new file mode 100644 index 0000000..3d2b641 --- /dev/null +++ b/crates/bootstrap/src/services/organization.rs @@ -0,0 +1,27 @@ +use std::sync::Arc; + +use adapters_postgres::{ + PgPool, PostgresAlbumRepository, PostgresAssetRepository, PostgresTagRepository, +}; +use application::organization::{ + CreateAlbumHandler, GetAlbumHandler, ManageAlbumEntriesHandler, TagAssetHandler, +}; +use presentation::state::OrganizationHandlers; + +pub fn build(pool: &PgPool) -> OrganizationHandlers { + let album_repo = Arc::new(PostgresAlbumRepository::new(pool.clone())); + let asset_repo = Arc::new(PostgresAssetRepository::new(pool.clone())); + let tag_repo = Arc::new(PostgresTagRepository::new(pool.clone())); + + let create_album = Arc::new(CreateAlbumHandler::new(album_repo.clone())); + let get_album = Arc::new(GetAlbumHandler::new(album_repo.clone())); + let manage_album_entries = Arc::new(ManageAlbumEntriesHandler::new(album_repo)); + let tag_asset = Arc::new(TagAssetHandler::new(asset_repo, tag_repo)); + + OrganizationHandlers { + create_album, + get_album, + manage_album_entries, + tag_asset, + } +} diff --git a/crates/bootstrap/src/services/processing.rs b/crates/bootstrap/src/services/processing.rs new file mode 100644 index 0000000..e941798 --- /dev/null +++ b/crates/bootstrap/src/services/processing.rs @@ -0,0 +1,48 @@ +use std::sync::Arc; + +use adapters_postgres::{ + PgPool, PostgresJobBatchRepository, PostgresJobRepository, PostgresPipelineRepository, + PostgresPluginRepository, +}; +use application::processing::{ + CompleteJobHandler, ConfigurePipelineHandler, EnqueueJobHandler, FailJobHandler, + ManagePluginHandler, ReportBatchProgressHandler, StartJobHandler, +}; +use domain::ports::EventPublisher; +use presentation::state::ProcessingHandlers; + +pub fn build(pool: &PgPool, event_publisher: Arc) -> ProcessingHandlers { + let job_repo = Arc::new(PostgresJobRepository::new(pool.clone())); + let batch_repo = Arc::new(PostgresJobBatchRepository::new(pool.clone())); + let plugin_repo = Arc::new(PostgresPluginRepository::new(pool.clone())); + let pipeline_repo = Arc::new(PostgresPipelineRepository::new(pool.clone())); + + let enqueue_job = Arc::new(EnqueueJobHandler::new( + job_repo.clone(), + event_publisher.clone(), + )); + let start_job = Arc::new(StartJobHandler::new(job_repo.clone())); + let complete_job = Arc::new(CompleteJobHandler::new( + job_repo.clone(), + batch_repo.clone(), + event_publisher.clone(), + )); + let fail_job = Arc::new(FailJobHandler::new( + job_repo.clone(), + batch_repo.clone(), + event_publisher, + )); + let batch_progress = Arc::new(ReportBatchProgressHandler::new(batch_repo, job_repo)); + let manage_plugin = Arc::new(ManagePluginHandler::new(plugin_repo.clone())); + let configure_pipeline = Arc::new(ConfigurePipelineHandler::new(pipeline_repo, plugin_repo)); + + ProcessingHandlers { + enqueue_job, + start_job, + complete_job, + fail_job, + batch_progress, + manage_plugin, + configure_pipeline, + } +} diff --git a/crates/bootstrap/src/services/sharing.rs b/crates/bootstrap/src/services/sharing.rs new file mode 100644 index 0000000..9a45cad --- /dev/null +++ b/crates/bootstrap/src/services/sharing.rs @@ -0,0 +1,31 @@ +use std::sync::Arc; + +use adapters_postgres::{ + PgPool, PostgresShareRepository, PostgresVisibilityFilterRepository, +}; +use application::sharing::{ + AccessSharedResourceHandler, GenerateShareLinkHandler, RevokeShareHandler, + ShareResourceHandler, +}; +use domain::ports::EventPublisher; +use presentation::state::SharingHandlers; + +pub fn build(pool: &PgPool, event_publisher: Arc) -> SharingHandlers { + let share_repo = Arc::new(PostgresShareRepository::new(pool.clone())); + let _visibility_filter_repo = Arc::new(PostgresVisibilityFilterRepository::new(pool.clone())); + + let share_resource = Arc::new(ShareResourceHandler::new( + share_repo.clone(), + event_publisher.clone(), + )); + let generate_link = Arc::new(GenerateShareLinkHandler::new(share_repo.clone())); + let revoke = Arc::new(RevokeShareHandler::new(share_repo.clone(), event_publisher)); + let access = Arc::new(AccessSharedResourceHandler::new(share_repo)); + + SharingHandlers { + share_resource, + generate_link, + revoke, + access, + } +} diff --git a/crates/bootstrap/src/services/sidecar.rs b/crates/bootstrap/src/services/sidecar.rs new file mode 100644 index 0000000..7d40520 --- /dev/null +++ b/crates/bootstrap/src/services/sidecar.rs @@ -0,0 +1,65 @@ +use std::sync::Arc; + +use adapters_postgres::{ + PgPool, PostgresAssetMetadataRepository, PostgresAssetRepository, PostgresSidecarRepository, +}; +use application::sidecar::{ + DetectExternalChangesHandler, ExportSidecarHandler, FullExportHandler, FullImportHandler, + ImportSidecarHandler, ResolveConflictHandler, +}; +use presentation::state::SidecarHandlers; + +use crate::log_sidecar_writer::LogSidecarWriter; + +pub fn build(pool: &PgPool) -> SidecarHandlers { + let metadata_repo = Arc::new(PostgresAssetMetadataRepository::new(pool.clone())); + let asset_repo = Arc::new(PostgresAssetRepository::new(pool.clone())); + let sidecar_repo = Arc::new(PostgresSidecarRepository::new(pool.clone())); + let sidecar_writer: Arc = Arc::new(LogSidecarWriter); + + let export = Arc::new(ExportSidecarHandler::new( + metadata_repo.clone(), + sidecar_repo.clone(), + sidecar_writer.clone(), + )); + + let detect_changes = Arc::new(DetectExternalChangesHandler::new( + sidecar_repo.clone(), + sidecar_writer.clone(), + )); + + let import = Arc::new(ImportSidecarHandler::new( + sidecar_repo.clone(), + sidecar_writer.clone(), + metadata_repo.clone(), + )); + + let resolve = Arc::new(ResolveConflictHandler::new( + sidecar_repo.clone(), + sidecar_writer.clone(), + metadata_repo.clone(), + )); + + let full_export = Arc::new(FullExportHandler::new( + asset_repo.clone(), + metadata_repo.clone(), + sidecar_repo.clone(), + sidecar_writer.clone(), + )); + + let full_import = Arc::new(FullImportHandler::new( + asset_repo, + metadata_repo, + sidecar_repo, + sidecar_writer, + )); + + SidecarHandlers { + export, + detect_changes, + import, + resolve, + full_export, + full_import, + } +} diff --git a/crates/bootstrap/src/services/storage.rs b/crates/bootstrap/src/services/storage.rs new file mode 100644 index 0000000..54724a5 --- /dev/null +++ b/crates/bootstrap/src/services/storage.rs @@ -0,0 +1,46 @@ +use std::sync::Arc; + +use adapters_postgres::{ + PgPool, PostgresIngestSessionRepository, PostgresLibraryPathRepository, + PostgresQuotaRepository, PostgresStorageVolumeRepository, PostgresUsageLedgerRepository, +}; +use application::storage::{CheckQuotaHandler, RegisterLibraryPathHandler, RegisterVolumeHandler}; +use presentation::state::StorageHandlers; + +/// Shared storage repos needed by other bounded contexts (catalog ingest, etc.). +pub struct StorageRepos { + pub volume_repo: Arc, + pub path_repo: Arc, + pub session_repo: Arc, + pub quota_repo: Arc, + pub ledger_repo: Arc, +} + +pub fn build(pool: &PgPool) -> (StorageRepos, StorageHandlers) { + let volume_repo = Arc::new(PostgresStorageVolumeRepository::new(pool.clone())); + let path_repo = Arc::new(PostgresLibraryPathRepository::new(pool.clone())); + let session_repo = Arc::new(PostgresIngestSessionRepository::new(pool.clone())); + let quota_repo = Arc::new(PostgresQuotaRepository::new(pool.clone())); + let ledger_repo = Arc::new(PostgresUsageLedgerRepository::new(pool.clone())); + + let register_volume = Arc::new(RegisterVolumeHandler::new(volume_repo.clone())); + let register_library_path = + Arc::new(RegisterLibraryPathHandler::new(volume_repo.clone(), path_repo.clone())); + let check_quota = Arc::new(CheckQuotaHandler::new(quota_repo.clone(), ledger_repo.clone())); + + let handlers = StorageHandlers { + register_volume, + register_library_path, + check_quota, + }; + + let repos = StorageRepos { + volume_repo, + path_repo, + session_repo, + quota_repo, + ledger_repo, + }; + + (repos, handlers) +}