post services integrations

This commit is contained in:
2026-07-29 18:09:38 +02:00
parent 6cb9acf98b
commit 759bc1dc15
23 changed files with 956 additions and 95 deletions
@@ -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.