post services integrations
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
---
|
||||
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
|
||||
```mermaid
|
||||
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.
|
||||
Reference in New Issue
Block a user