Files
oxspeak_server/.junie/plans/refactor-write-services-and-read-repositories.md
2026-07-29 18:09:38 +02:00

7.2 KiB

sessionId
sessionId
session-260729-174324-a4dc

Requirements

Overview & Goals

Currently, write operations (mutations) and EventBus emissions take place inside Repositories. This design poses two main challenges:

  1. Lack of Transactional Atomicity: Multi-table writes (e.g., creating a channel while simultaneously inserting its order record into server_item_order) cannot share an atomic database transaction.
  2. Premature / Ghost Events: Events are emitted inside Repositories before confirming whether higher-level multi-step operations or surrounding DB transactions committed successfully.

To solve this, we are refactoring to a lightweight Command/Query separation:

  • Services (Commands / Write Operations): Perform write operations, manage SeaORM database transactions (db.begin()), and emit EventBus events strictly after transaction commits.
  • Repositories (Queries / Read Operations): Focus on complex reads, queries, and filters. Event bus emissions are completely removed from Repositories.

Scope

  • In Scope:
    • Removing events: Arc<EventBus> from RepositoryContext and Repositories::new.
    • Stripping all .events.emit(...) calls from CategoryRepository, ChannelRepository, MessageRepository, RoleRepository, ServerRepository, ServerItemOrderRepository, and UserRepository.
    • Creating/expanding dedicated domain services under src/services/ (ChannelService, ServerService, CategoryService, MessageService, UserService, RoleService) with SeaORM transaction support and post-commit event emissions.
    • Registering all domain services in src/services/mod.rs and Services.
    • Updating Axum HTTP route handlers in src/routes/ to delegate write operations (POST, PUT, DELETE) to state.services while keeping read operations (GET) on state.repositories.
  • Out of Scope:
    • Changing API DTO contracts or client-facing response schemas.
    • Modifying underlying SeaORM database entities or table schemas.

Functional Requirements

  • FR1: Repositories must be strictly read/query-focused and contain zero event emissions or EventBus references.
  • FR2: Write mutations (create, update, delete) and permission management must be executed inside domain Services.
  • FR3: Multi-step writes (such as creating a server/channel and updating server_item_order) must execute within an atomic SeaORM transaction (db.begin().await?).
  • FR4: EventBus events must only be emitted after the database transaction successfully commits.
  • FR5: Axum route handlers must invoke service methods for all state-mutating requests (POST, PUT, DELETE) and repository methods for read requests (GET).

Technical Design

Current Implementation

  • RepositoryContext in src/repositories/mod.rs holds both db: DatabaseConnection and events: Arc<EventBus>.
  • Repositories (ChannelRepository, ServerRepository, CategoryRepository, MessageRepository, UserRepository, RoleRepository, ServerItemOrderRepository) execute active.insert(), active.update(), and delete operations directly and emit events immediately inside repository methods.
  • Axum route handlers in src/routes/*/handlers.rs call repository write methods directly.

Key Decisions

  1. Command / Query Responsibility Segregation:
    • Repositories handle data access, queries, filters, and read models.
    • Services handle business logic, transactional boundaries (db.begin()), and event dispatching.
  2. Post-Commit Event Emission:
    • Events are only emitted after txn.commit().await? succeeds, preventing ghost/premature events on transaction rollback.

Proposed Changes & Affected Files

  1. src/repositories/mod.rs & Repository Modules:
    • Modify RepositoryContext to remove events: Arc<EventBus>.
    • Remove .events.emit(...) calls from:
      • src/repositories/category.rs
      • src/repositories/channel.rs
      • src/repositories/message.rs
      • src/repositories/role.rs
      • src/repositories/server.rs
      • src/repositories/server_item_order.rs
      • src/repositories/user.rs
  2. src/services/ Modules:
    • Expand src/services/ with new service files:
      • channel.rs (ChannelService)
      • server.rs (ServerService)
      • category.rs (CategoryService)
      • message.rs (MessageService)
      • user.rs (UserService)
      • role.rs (RoleService)
  3. src/services/mod.rs:
    • Update Services struct and Services::new to initialize and expose all domain services.
  4. src/routes/ Handlers:
    • Update write handlers across src/routes/{channel,server,category,message,user,role}/handlers.rs to invoke state.services.*.

Architecture Diagram

graph LR
    HTTP[Axum Handlers] -->|Write mutations| Services[Domain Services]
    HTTP[Read requests] -->|Query/Filter| Repositories[Read Repositories]
    Services -->|Transaction & DB mutations| DB[(SeaORM Database)]
    Services -->|Post-commit emit| Events[EventBus]
    Repositories -->|Read query| DB

Delivery Steps

✓ Step 1: Clean up Repositories and Remove Write Event Emissions

Clean up Repositories and RepositoryContext

  • Remove events: Arc<EventBus> from RepositoryContext in src/repositories/mod.rs and update Repositories::new.
  • Strip write event emissions (self.context.events.emit(...)) from all repositories (CategoryRepository, ChannelRepository, MessageRepository, RoleRepository, ServerRepository, ServerItemOrderRepository, UserRepository).
  • Ensure repository write methods operate purely on database connections/ActiveModels without triggering event bus emissions.

✓ Step 2: Create Domain Services with Transactional Atomicity and Post-Commit Events

Create Domain Services for Write Operations

  • Create domain services in src/services/ for channels, servers, categories, messages, users, and roles (e.g., ChannelService, ServerService, CategoryService, MessageService, UserService, RoleService).
  • Implement SeaORM transaction management (db.begin().await?) in service write methods.
  • Ensure EventBus events are emitted strictly after transaction commits.
  • Handle multi-table transactional writes such as creating a channel while inserting into server_item_order.

✓ Step 3: Register Services in Services Container

Register Services in Services Container and Update State/Context

  • Update src/services/mod.rs to include and initialize the new services (channel, server, category, message, user, role) within the Services struct and ServicesContext.
  • Expose the updated Services container via AppState / ServicesContext.

✓ Step 4: Refactor Axum HTTP Route Handlers to Use Services

Refactor Axum HTTP Route Handlers

  • Update write endpoints (POST, PUT, DELETE) across src/routes/ to invoke service methods on state.services instead of repositories directly.
  • Keep read endpoints (GET) using repositories for complex queries, filters, and tree generation.

✓ Step 5: Verification and Testing

Verification and Testing

  • Run cargo build/check to ensure clean compilation across all modules.
  • Verify integration checks: channel creation populates server_item_order, events are only triggered upon successful DB transaction commit.