forge/lib/README.md
2025-11-26 18:33:09 -06:00

245 lines
7.1 KiB
Markdown

# Forge Library
This directory contains the core business logic and data layers for the Forge framework, organized into modular, reusable crates that follow clean architecture principles.
## Architecture Overview
The library follows a **layered architecture** pattern, ensuring separation of concerns and maintainability:
```mermaid
graph TD
Extension[Extension Layer<br/>#40;ArmA 3 Interface#41;]
Services[Services Layer<br/>#40;Business Logic#41;]
Repositories[Repositories Layer<br/>#40;Data Persistence#41;]
Models[Models Layer<br/>#40;Data Structures#41;]
Extension --> Services
Services --> Repositories
Repositories --> Models
```
## Modules
### Models (`lib/models`)
**Purpose**: Defines strict data structures and validation rules for domain entities.
**Responsibilities**:
- Define entity structures (`Actor`, `Org`)
- Implement validation logic
- Handle serialization/deserialization (JSON, Arma)
- Enforce business rules at the data level
**Key Features**:
- Strong typing with Rust structs
- Built-in validation on creation and updates
- Automatic email generation for actors
- Arma-specific type conversions
**Documentation**: [models/README.md](models/README.md)
### Repositories (`lib/repositories`)
**Purpose**: Manages data persistence and retrieval using Redis.
**Responsibilities**:
- Abstract database operations
- Implement CRUD operations
- Handle data serialization to Redis formats
- Manage Redis keys and data structures
**Key Features**:
- Generic over Redis client implementations
- Hash-based storage for structured data
- Set-based storage for collections (e.g., org members)
- Thread-safe operations (`Send + Sync`)
**Documentation**: [repositories/README.md](repositories/README.md)
### Services (`lib/services`)
**Purpose**: Implements business logic, validation, and orchestration of operations.
**Responsibilities**:
- Coordinate between repositories
- Enforce business rules
- Handle complex workflows
- Provide high-level APIs for the extension layer
**Key Features**:
- Generic over repository implementations
- Stateless service design
- Get-or-create patterns for entities
- Comprehensive error handling
**Documentation**: [services/README.md](services/README.md)
### Shared (`lib/shared`)
**Purpose**: Provides common utilities, traits, and helper functions used across all layers.
**Responsibilities**:
- Define shared traits (`RedisClient`)
- Provide utility functions
- Common type definitions
- Cross-cutting concerns
**Key Features**:
- `RedisClient` trait for repository abstraction
- JSON/Redis value parsing utilities
- Arma value conversion helpers
- Reusable helper functions
## How It All Works Together
### Example: Creating an Actor
Here's how the layers interact when creating a new actor:
1. **Extension Layer** receives SQF command:
```rust
// arma/server/extension/src/actor.rs
pub fn create_actor(key: String, data: String) -> String {
// Parse JSON and call service
ACTOR_SERVICE.create_actor(uid, json_data)
}
```
2. **Service Layer** validates and orchestrates:
```rust
// lib/services/src/actor.rs
impl<R: ActorRepository> ActorService<R> {
pub fn create_actor(&self, uid: String, data: String) -> Result<Actor, String> {
// Create actor model (validates data)
let actor = Actor::new(uid, data)?;
// Persist via repository
self.repository.create(&actor)?;
Ok(actor)
}
}
```
3. **Repository Layer** persists to Redis:
```rust
// lib/repositories/src/actor.rs
impl<C: RedisClient> ActorRepository for RedisActorRepository<C> {
fn create(&self, actor: &Actor) -> Result<(), String> {
// Convert actor to Redis hash
let fields = actor.to_redis_fields();
// Store in Redis
self.client.hash_mset(format!("actor:{}", actor.uid), fields)
}
}
```
4. **Model Layer** ensures data integrity:
```rust
// lib/models/src/actor.rs
impl Actor {
pub fn new(uid: String, data: String) -> Result<Self, String> {
// Validate all fields
Self::validate(&uid, &data)?;
// Create actor with validated data
Ok(Actor { uid, /* ... */ })
}
}
```
## Contributing
We welcome contributions to the Forge library! Follow these guidelines to maintain consistency and quality.
### Adding a New Model
See [models/README.md - Contributing](models/README.md#contributing)
**Summary**:
1. Define struct with validation rules
2. Implement `new` and `validate` methods
3. Add serialization traits (`Serialize`, `Deserialize`)
4. Implement Arma conversions (`FromArma`, `IntoArma`)
### Adding a New Repository
See [repositories/README.md - Contributing](repositories/README.md#contributing)
**Summary**:
1. Define repository trait with `Send + Sync`
2. Implement trait for `RedisXRepository<C: RedisClient>`
3. Use `forge_shared::RedisClient` for operations
4. Register module in `lib.rs`
### Adding a New Service
See [services/README.md - Contributing](services/README.md#contributing)
**Summary**:
1. Create service struct generic over repository
2. Implement constructor and business logic methods
3. Delegate data operations to repository
4. Register module in `lib.rs`
### Best Practices
#### Separation of Concerns
- **Models**: Only data structures and validation
- **Repositories**: Only data persistence logic
- **Services**: Only business logic and orchestration
- **Shared**: Only common utilities and traits
#### Error Handling
- Use `Result<T, String>` for all fallible operations
- Provide descriptive error messages
- Propagate errors up the stack with `?`
#### Testing
- **Models**: Test validation rules
- **Repositories**: Test with mock Redis clients
- **Services**: Test with mock repositories
- **Integration**: Test full stack in extension layer
#### Dependencies
- Models should have minimal dependencies
- Repositories depend on models and shared
- Services depend on repositories and models
- Avoid circular dependencies
#### Thread Safety
- All repository traits require `Send + Sync`
- Services are stateless and thread-safe
- Use appropriate synchronization primitives when needed
## Module Dependencies
```mermaid
graph TD
Shared[Shared<br/>#40;No Dependencies#41;]
Models[Models<br/>#40;Depends on Shared#41;]
Repositories[Repositories<br/>#40;Depends on Models, Shared#41;]
Services[Services<br/>#40;Depends on Repositories, Models#41;]
Extension[Extension<br/>#40;Depends on Services, Repositories, Models, Shared#41;]
Shared --> Services
Services --> Repositories
Repositories --> Models
Models --> Extension
```
## Development Workflow
1. **Define Model**: Start with data structure and validation
2. **Create Repository**: Implement persistence layer
3. **Build Service**: Add business logic
4. **Expose in Extension**: Create SQF-callable commands
5. **Test**: Verify each layer independently and together
## Additional Resources
- [Extension Documentation](../arma/server/extension/README.md)
- [Redis Operations](../arma/server/extension/src/redis/README.md)
- [Adapters](../arma/server/extension/src/adapters/README.md)