init projectmycelium
This commit is contained in:
@@ -0,0 +1,818 @@
|
||||
# Project Mycelium - Builder Pattern Maximization Roadmap
|
||||
|
||||
**Document Purpose**: Comprehensive roadmap for achieving maximum builder pattern consolidation across the entire Project Mycelium codebase, targeting industry-standard single-source-of-truth architecture with minimal code duplication.
|
||||
|
||||
**Last Updated**: 2025-08-06
|
||||
**Status**: Phase 2 Planning - Ready for Implementation
|
||||
**Target**: Additional 70% code reduction (~1,430 total lines eliminated)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Executive Summary
|
||||
|
||||
Building on the successful **Phase 1 achievement** (95.8% compilation error reduction, ~800 lines eliminated), this roadmap outlines **Phase 2 consolidation opportunities** that will achieve an additional **70% code reduction** while maintaining all existing features and enhancing maintainability through industry-standard builder patterns.
|
||||
|
||||
**Phase 1 Success Metrics:**
|
||||
- ✅ **24 → 0 compilation errors** (100% resolution)
|
||||
- ✅ **~800 lines eliminated** through SessionDataBuilder consolidation
|
||||
- ✅ **Single-source-of-truth** for all UserPersistentData construction
|
||||
- ✅ **Zero feature regression** - all functionality preserved
|
||||
|
||||
**Phase 2 Target Metrics:**
|
||||
- 🎯 **Additional ~630 lines reduction** (70% of remaining opportunities)
|
||||
- 🎯 **4 major builder consolidations** (Configuration, Service, Response, Mock)
|
||||
- 🎯 **Industry-standard patterns** throughout entire codebase
|
||||
- 🎯 **Enhanced maintainability** and developer experience
|
||||
|
||||
---
|
||||
|
||||
## 📊 Consolidation Opportunity Analysis
|
||||
|
||||
### Current Codebase Analysis Results
|
||||
|
||||
Based on comprehensive codebase analysis, the following patterns have been identified for consolidation:
|
||||
|
||||
| Pattern Type | Current Instances | Lines per Instance | Total Lines | Consolidation Potential |
|
||||
|--------------|-------------------|-------------------|-------------|------------------------|
|
||||
| **Configuration Creation** | 15+ instances | ~10 lines | ~150 lines | **ConfigurationBuilder** |
|
||||
| **Service Instantiation** | 25+ instances | ~6 lines | ~150 lines | **ServiceFactory** |
|
||||
| **API Response Construction** | 50+ instances | ~6 lines | ~300 lines | **ResponseBuilder** |
|
||||
| **Mock Data Elimination** | 20+ instances | ~12 lines | ~240 lines | **DataAggregator** |
|
||||
| **Error Handling** | 30+ instances | ~4 lines | ~120 lines | **ErrorBuilder** |
|
||||
| **Context Building** | 10+ instances | ~8 lines | ~80 lines | **ContextBuilder** |
|
||||
| **Validation Logic** | 15+ instances | ~5 lines | ~75 lines | **ValidationBuilder** |
|
||||
| **Total Opportunity** | **165+ instances** | **~8 avg** | **~1,115 lines** | **~780 lines reduction** |
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Phase 2 Implementation Roadmap
|
||||
|
||||
### **Priority 1: ConfigurationBuilder** (~150 line reduction)
|
||||
|
||||
**Current Problem:**
|
||||
```rust
|
||||
// ❌ Scattered configuration creation in multiple files
|
||||
let config = Config::builder()
|
||||
.set_default("server.host", "127.0.0.1")?
|
||||
.set_default("server.port", 9999)?
|
||||
.set_default("server.workers", None::<u32>)?
|
||||
.set_default("templates.dir", "./src/views")?
|
||||
.add_source(File::with_name("config/default").required(false))
|
||||
.add_source(File::with_name("config/local").required(false))
|
||||
.add_source(config::Environment::with_prefix("APP").separator("__"))
|
||||
.build()?;
|
||||
```
|
||||
|
||||
**Solution: Centralized ConfigurationBuilder**
|
||||
```rust
|
||||
// ✅ Single-source-of-truth configuration
|
||||
pub struct ConfigurationBuilder;
|
||||
|
||||
impl ConfigurationBuilder {
|
||||
pub fn development() -> AppConfig {
|
||||
AppConfig {
|
||||
server: ServerConfig {
|
||||
host: "127.0.0.1".to_string(),
|
||||
port: 9999,
|
||||
workers: Some(4),
|
||||
},
|
||||
templates: TemplateConfig {
|
||||
dir: "./src/views".to_string(),
|
||||
},
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn production() -> AppConfig {
|
||||
AppConfig {
|
||||
server: ServerConfig {
|
||||
host: "0.0.0.0".to_string(),
|
||||
port: 8080,
|
||||
workers: Some(num_cpus::get() as u32),
|
||||
},
|
||||
templates: TemplateConfig {
|
||||
dir: "/app/templates".to_string(),
|
||||
},
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn testing() -> AppConfig {
|
||||
AppConfig {
|
||||
server: ServerConfig {
|
||||
host: "127.0.0.1".to_string(),
|
||||
port: 0, // Random port
|
||||
workers: Some(1),
|
||||
},
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_env() -> Result<AppConfig, ConfigError> {
|
||||
match env::var("APP_ENV").unwrap_or_else(|_| "development".to_string()).as_str() {
|
||||
"production" => Ok(Self::production()),
|
||||
"testing" => Ok(Self::testing()),
|
||||
_ => Ok(Self::development()),
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Pattern:**
|
||||
```rust
|
||||
// ✅ Clean, readable configuration
|
||||
let config = ConfigurationBuilder::from_env()?;
|
||||
let dev_config = ConfigurationBuilder::development();
|
||||
let prod_config = ConfigurationBuilder::production();
|
||||
```
|
||||
|
||||
### **Priority 2: ServiceFactory** (~100 line reduction)
|
||||
|
||||
**Current Problem:**
|
||||
```rust
|
||||
// ❌ Repeated service instantiation throughout codebase
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
log::error!("Failed to build farmer service: {}", e);
|
||||
return Ok(HttpResponse::InternalServerError().json(serde_json::json!({
|
||||
"error": "Service initialization failed"
|
||||
})));
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**Solution: Centralized ServiceFactory**
|
||||
```rust
|
||||
// ✅ Single-source-of-truth service creation
|
||||
pub struct ServiceFactory;
|
||||
|
||||
impl ServiceFactory {
|
||||
pub fn create_farmer_service() -> Result<FarmerService, String> {
|
||||
FarmerService::builder()
|
||||
.auto_sync_enabled(true)
|
||||
.metrics_collection(true)
|
||||
.build()
|
||||
}
|
||||
|
||||
pub fn create_order_service() -> Result<OrderService, String> {
|
||||
let currency_service = Self::create_currency_service()?;
|
||||
let product_service = Self::create_product_service()?;
|
||||
|
||||
OrderService::builder()
|
||||
.currency_service(currency_service)
|
||||
.product_service(product_service)
|
||||
.auto_save(true)
|
||||
.build()
|
||||
}
|
||||
|
||||
pub fn create_user_service() -> Result<UserService, String> {
|
||||
UserService::builder()
|
||||
.include_metrics(true)
|
||||
.cache_enabled(true)
|
||||
.real_time_updates(true)
|
||||
.build()
|
||||
}
|
||||
|
||||
pub fn create_currency_service() -> Result<CurrencyService, String> {
|
||||
CurrencyServiceBuilder::new()
|
||||
.base_currency("USD")
|
||||
.cache_duration(60)
|
||||
.auto_update(true)
|
||||
.build()
|
||||
}
|
||||
|
||||
pub fn create_product_service() -> Result<ProductService, String> {
|
||||
let currency_service = Self::create_currency_service()?;
|
||||
|
||||
ProductServiceBuilder::new()
|
||||
.currency_service(currency_service)
|
||||
.cache_enabled(true)
|
||||
.include_slice_products(true)
|
||||
.build()
|
||||
}
|
||||
|
||||
// Convenience method for controllers
|
||||
pub fn create_all_services() -> Result<ServiceBundle, String> {
|
||||
Ok(ServiceBundle {
|
||||
farmer: Self::create_farmer_service()?,
|
||||
order: Self::create_order_service()?,
|
||||
user: Self::create_user_service()?,
|
||||
currency: Self::create_currency_service()?,
|
||||
product: Self::create_product_service()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ServiceBundle {
|
||||
pub farmer: FarmerService,
|
||||
pub order: OrderService,
|
||||
pub user: UserService,
|
||||
pub currency: CurrencyService,
|
||||
pub product: ProductService,
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Pattern:**
|
||||
```rust
|
||||
// ✅ Clean, error-handled service creation
|
||||
let farmer_service = ServiceFactory::create_farmer_service()
|
||||
.map_err(|e| actix_web::error::ErrorInternalServerError(e))?;
|
||||
|
||||
// ✅ Or get all services at once
|
||||
let services = ServiceFactory::create_all_services()
|
||||
.map_err(|e| actix_web::error::ErrorInternalServerError(e))?;
|
||||
```
|
||||
|
||||
### **Priority 3: ResponseBuilder** (~200 line reduction)
|
||||
|
||||
**Current Problem:**
|
||||
```rust
|
||||
// ❌ Repeated JSON response construction
|
||||
Ok(HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
"message": "Operation completed successfully",
|
||||
"data": result_data
|
||||
})))
|
||||
|
||||
Ok(HttpResponse::InternalServerError().json(serde_json::json!({
|
||||
"success": false,
|
||||
"error": "Service initialization failed",
|
||||
"details": error_message
|
||||
})))
|
||||
```
|
||||
|
||||
**Solution: Centralized ResponseBuilder**
|
||||
```rust
|
||||
// ✅ Single-source-of-truth API responses
|
||||
pub struct ApiResponseBuilder;
|
||||
|
||||
impl ApiResponseBuilder {
|
||||
pub fn success<T: Serialize>(data: T) -> HttpResponse {
|
||||
HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
"data": data,
|
||||
"timestamp": Utc::now().to_rfc3339()
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn success_with_message<T: Serialize>(data: T, message: &str) -> HttpResponse {
|
||||
HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
"message": message,
|
||||
"data": data,
|
||||
"timestamp": Utc::now().to_rfc3339()
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn error(message: &str) -> HttpResponse {
|
||||
HttpResponse::InternalServerError().json(serde_json::json!({
|
||||
"success": false,
|
||||
"error": message,
|
||||
"timestamp": Utc::now().to_rfc3339()
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn error_with_details(message: &str, details: &str) -> HttpResponse {
|
||||
HttpResponse::InternalServerError().json(serde_json::json!({
|
||||
"success": false,
|
||||
"error": message,
|
||||
"details": details,
|
||||
"timestamp": Utc::now().to_rfc3339()
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn unauthorized(message: &str) -> HttpResponse {
|
||||
HttpResponse::Unauthorized().json(serde_json::json!({
|
||||
"success": false,
|
||||
"error": message,
|
||||
"code": "UNAUTHORIZED",
|
||||
"timestamp": Utc::now().to_rfc3339()
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn not_found(resource: &str) -> HttpResponse {
|
||||
HttpResponse::NotFound().json(serde_json::json!({
|
||||
"success": false,
|
||||
"error": format!("{} not found", resource),
|
||||
"code": "NOT_FOUND",
|
||||
"timestamp": Utc::now().to_rfc3339()
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn paginated<T: Serialize>(
|
||||
data: Vec<T>,
|
||||
page: u32,
|
||||
per_page: u32,
|
||||
total: u32
|
||||
) -> HttpResponse {
|
||||
HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
"data": data,
|
||||
"pagination": {
|
||||
"page": page,
|
||||
"per_page": per_page,
|
||||
"total": total,
|
||||
"total_pages": (total + per_page - 1) / per_page
|
||||
},
|
||||
"timestamp": Utc::now().to_rfc3339()
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn validation_error(errors: Vec<&str>) -> HttpResponse {
|
||||
HttpResponse::BadRequest().json(serde_json::json!({
|
||||
"success": false,
|
||||
"error": "Validation failed",
|
||||
"validation_errors": errors,
|
||||
"code": "VALIDATION_ERROR",
|
||||
"timestamp": Utc::now().to_rfc3339()
|
||||
}))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Pattern:**
|
||||
```rust
|
||||
// ✅ Clean, consistent API responses
|
||||
return Ok(ApiResponseBuilder::success(farmer_data));
|
||||
return Ok(ApiResponseBuilder::error("Service initialization failed"));
|
||||
return Ok(ApiResponseBuilder::unauthorized("User not authenticated"));
|
||||
return Ok(ApiResponseBuilder::not_found("Node"));
|
||||
return Ok(ApiResponseBuilder::paginated(nodes, page, per_page, total));
|
||||
```
|
||||
|
||||
### **Priority 4: Persistent Data Integration** (~180 line reduction + Mock Elimination)
|
||||
|
||||
**Current Problem:**
|
||||
```rust
|
||||
// ❌ Scattered mock data creation throughout codebase
|
||||
let mock_products = vec![
|
||||
Product { name: "Mock VM".to_string(), /* ... */ },
|
||||
Product { name: "Mock Storage".to_string(), /* ... */ },
|
||||
];
|
||||
|
||||
// ❌ Hardcoded mock services, apps, nodes
|
||||
let mock_services = get_hardcoded_services();
|
||||
let mock_apps = get_hardcoded_apps();
|
||||
```
|
||||
|
||||
**Solution: Persistent Data Integration with DataAggregator**
|
||||
|
||||
**🏭 Industry Standard Architecture: Real Data Only**
|
||||
|
||||
This approach eliminates all mock data and uses only persistent user data from `user_data/` directory, which is the industry-standard production approach:
|
||||
|
||||
```rust
|
||||
// ✅ Real data aggregation from persistent storage
|
||||
pub struct DataAggregator;
|
||||
|
||||
impl DataAggregator {
|
||||
/// Aggregate all marketplace products from real user data
|
||||
pub fn get_marketplace_products() -> Vec<Product> {
|
||||
let mut products = Vec::new();
|
||||
|
||||
// Load all user data files from user_data/ directory
|
||||
if let Ok(entries) = std::fs::read_dir("user_data/") {
|
||||
for entry in entries.flatten() {
|
||||
if let Some(file_name) = entry.file_name().to_str() {
|
||||
if file_name.ends_with(".json") && !file_name.ends_with("_cart.json") {
|
||||
if let Ok(user_data) = UserPersistence::load_user_data_from_file(&entry.path()) {
|
||||
// Aggregate products from user's services
|
||||
products.extend(Self::services_to_products(&user_data.services));
|
||||
|
||||
// Aggregate products from user's apps
|
||||
products.extend(Self::apps_to_products(&user_data.apps));
|
||||
|
||||
// Aggregate products from user's slice products
|
||||
products.extend(Self::slice_products_to_products(&user_data.slice_products));
|
||||
|
||||
// Aggregate products from user's nodes (for rental)
|
||||
products.extend(Self::nodes_to_products(&user_data.nodes));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
products
|
||||
}
|
||||
|
||||
/// Aggregate all marketplace services from real user data
|
||||
pub fn get_marketplace_services() -> Vec<Service> {
|
||||
let mut services = Vec::new();
|
||||
|
||||
if let Ok(entries) = std::fs::read_dir("user_data/") {
|
||||
for entry in entries.flatten() {
|
||||
if let Some(file_name) = entry.file_name().to_str() {
|
||||
if file_name.ends_with(".json") && !file_name.ends_with("_cart.json") {
|
||||
if let Ok(user_data) = UserPersistence::load_user_data_from_file(&entry.path()) {
|
||||
services.extend(user_data.services.into_iter().filter(|s| s.status == "Active"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
services
|
||||
}
|
||||
|
||||
/// Aggregate all marketplace apps from real user data
|
||||
pub fn get_marketplace_apps() -> Vec<PublishedApp> {
|
||||
let mut apps = Vec::new();
|
||||
|
||||
if let Ok(entries) = std::fs::read_dir("user_data/") {
|
||||
for entry in entries.flatten() {
|
||||
if let Some(file_name) = entry.file_name().to_str() {
|
||||
if file_name.ends_with(".json") && !file_name.ends_with("_cart.json") {
|
||||
if let Ok(user_data) = UserPersistence::load_user_data_from_file(&entry.path()) {
|
||||
apps.extend(user_data.apps.into_iter().filter(|a| a.status == "Active"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apps
|
||||
}
|
||||
|
||||
/// Aggregate all available nodes for rental from real user data
|
||||
pub fn get_marketplace_nodes() -> Vec<Node> {
|
||||
let mut nodes = Vec::new();
|
||||
|
||||
if let Ok(entries) = std::fs::read_dir("user_data/") {
|
||||
for entry in entries.flatten() {
|
||||
if let Some(file_name) = entry.file_name().to_str() {
|
||||
if file_name.ends_with(".json") && !file_name.ends_with("_cart.json") {
|
||||
if let Ok(user_data) = UserPersistence::load_user_data_from_file(&entry.path()) {
|
||||
nodes.extend(user_data.nodes.into_iter().filter(|n| n.status == NodeStatus::Online));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nodes
|
||||
}
|
||||
|
||||
/// Get marketplace statistics from real user data
|
||||
pub fn get_marketplace_stats() -> MarketplaceStats {
|
||||
let products = Self::get_marketplace_products();
|
||||
let services = Self::get_marketplace_services();
|
||||
let apps = Self::get_marketplace_apps();
|
||||
let nodes = Self::get_marketplace_nodes();
|
||||
|
||||
MarketplaceStats {
|
||||
total_products: products.len(),
|
||||
total_services: services.len(),
|
||||
total_apps: apps.len(),
|
||||
total_nodes: nodes.len(),
|
||||
active_providers: Self::count_active_providers(),
|
||||
total_transactions: Self::count_total_transactions(),
|
||||
}
|
||||
}
|
||||
|
||||
// Private helper methods for data conversion
|
||||
fn services_to_products(services: &[Service]) -> Vec<Product> {
|
||||
services.iter()
|
||||
.filter(|s| s.status == "Active")
|
||||
.map(|service| {
|
||||
ProductBuilder::new()
|
||||
.name(&service.name)
|
||||
.category_id(&service.category)
|
||||
.description(&service.description)
|
||||
.base_price(Decimal::from(service.price_per_hour))
|
||||
.base_currency("USD")
|
||||
.provider_id(&service.provider_email)
|
||||
.provider_name(&service.provider_name)
|
||||
.build()
|
||||
.expect("Failed to convert service to product")
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn apps_to_products(apps: &[PublishedApp]) -> Vec<Product> {
|
||||
apps.iter()
|
||||
.filter(|a| a.status == "Active")
|
||||
.map(|app| {
|
||||
ProductBuilder::new()
|
||||
.name(&app.name)
|
||||
.category_id(&app.category)
|
||||
.description(&format!("Published app: {}", app.name))
|
||||
.base_price(Decimal::from(app.monthly_revenue_usd))
|
||||
.base_currency("USD")
|
||||
.provider_id(&format!("app-provider-{}", app.id))
|
||||
.provider_name("App Provider")
|
||||
.build()
|
||||
.expect("Failed to convert app to product")
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn slice_products_to_products(slice_products: &[SliceProduct]) -> Vec<Product> {
|
||||
slice_products.iter()
|
||||
.map(|slice| {
|
||||
ProductBuilder::new()
|
||||
.name(&slice.name)
|
||||
.category_id("slice")
|
||||
.description(&slice.description)
|
||||
.base_price(slice.base_price_per_hour)
|
||||
.base_currency("USD")
|
||||
.provider_id(&slice.provider_email)
|
||||
.provider_name("Slice Provider")
|
||||
.build()
|
||||
.expect("Failed to convert slice to product")
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn nodes_to_products(nodes: &[Node]) -> Vec<Product> {
|
||||
nodes.iter()
|
||||
.filter(|n| n.status == NodeStatus::Online && n.rental_options.is_some())
|
||||
.map(|node| {
|
||||
ProductBuilder::new()
|
||||
.name(&format!("Node Rental: {}", node.id))
|
||||
.category_id("node-rental")
|
||||
.description(&format!("Rent computing resources from node {}", node.id))
|
||||
.base_price(node.rental_options.as_ref().unwrap().base_price_per_hour)
|
||||
.base_currency("USD")
|
||||
.provider_id(&node.farmer_email)
|
||||
.provider_name("Node Farmer")
|
||||
.build()
|
||||
.expect("Failed to convert node to product")
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn count_active_providers() -> usize {
|
||||
// Count unique provider emails across all user data
|
||||
let mut providers = std::collections::HashSet::new();
|
||||
|
||||
if let Ok(entries) = std::fs::read_dir("user_data/") {
|
||||
for entry in entries.flatten() {
|
||||
if let Some(file_name) = entry.file_name().to_str() {
|
||||
if file_name.ends_with(".json") && !file_name.ends_with("_cart.json") {
|
||||
if let Ok(user_data) = UserPersistence::load_user_data_from_file(&entry.path()) {
|
||||
if !user_data.services.is_empty() || !user_data.apps.is_empty() || !user_data.nodes.is_empty() {
|
||||
providers.insert(user_data.user_email);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
providers.len()
|
||||
}
|
||||
|
||||
fn count_total_transactions() -> usize {
|
||||
let mut total = 0;
|
||||
|
||||
if let Ok(entries) = std::fs::read_dir("user_data/") {
|
||||
for entry in entries.flatten() {
|
||||
if let Some(file_name) = entry.file_name().to_str() {
|
||||
if file_name.ends_with(".json") && !file_name.ends_with("_cart.json") {
|
||||
if let Ok(user_data) = UserPersistence::load_user_data_from_file(&entry.path()) {
|
||||
total += user_data.transactions.len();
|
||||
total += user_data.orders.len();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
total
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MarketplaceStats {
|
||||
pub total_products: usize,
|
||||
pub total_services: usize,
|
||||
pub total_apps: usize,
|
||||
pub total_nodes: usize,
|
||||
pub active_providers: usize,
|
||||
pub total_transactions: usize,
|
||||
}
|
||||
|
||||
pub struct TestEnvironment {
|
||||
pub users: Vec<UserPersistentData>,
|
||||
pub products: Vec<Product>,
|
||||
pub orders: Vec<Order>,
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Pattern:**
|
||||
```rust
|
||||
// ✅ Real marketplace data from persistent storage
|
||||
let marketplace_products = DataAggregator::get_marketplace_products();
|
||||
let marketplace_services = DataAggregator::get_marketplace_services();
|
||||
let marketplace_apps = DataAggregator::get_marketplace_apps();
|
||||
let marketplace_nodes = DataAggregator::get_marketplace_nodes();
|
||||
let marketplace_stats = DataAggregator::get_marketplace_stats();
|
||||
```
|
||||
|
||||
**🏭 Industry Standard Benefits:**
|
||||
- **Real Data Only**: No mock data, all products/services come from actual users in `user_data/`
|
||||
- **Dynamic Marketplace**: Marketplace content grows organically as users add services, apps, nodes
|
||||
- **Authentic Experience**: Users see real offerings from real providers
|
||||
- **Production Ready**: No mock-to-real data migration needed
|
||||
- **Scalable Architecture**: Handles any number of users and their offerings
|
||||
- **Data Integrity**: All marketplace data backed by persistent user storage
|
||||
|
||||
### **Priority 5: ErrorBuilder** (~120 line reduction)
|
||||
|
||||
**Solution: Centralized Error Handling**
|
||||
```rust
|
||||
pub struct ErrorBuilder;
|
||||
|
||||
impl ErrorBuilder {
|
||||
pub fn service_error(service: &str, operation: &str, details: &str) -> String {
|
||||
format!("Failed to {} in {}: {}", operation, service, details)
|
||||
}
|
||||
|
||||
pub fn validation_error(field: &str, reason: &str) -> String {
|
||||
format!("Validation failed for {}: {}", field, reason)
|
||||
}
|
||||
|
||||
pub fn authentication_error(reason: &str) -> String {
|
||||
format!("Authentication failed: {}", reason)
|
||||
}
|
||||
|
||||
pub fn not_found_error(resource: &str, id: &str) -> String {
|
||||
format!("{} with ID '{}' not found", resource, id)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **Priority 6: ContextBuilder Enhancement** (~80 line reduction)
|
||||
|
||||
**Solution: Enhanced Template Context Building**
|
||||
```rust
|
||||
pub struct ContextBuilder {
|
||||
context: tera::Context,
|
||||
}
|
||||
|
||||
impl ContextBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
context: tera::Context::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_user(mut self, user: &User) -> Self {
|
||||
self.context.insert("user", user);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_dashboard_data(mut self, section: &str) -> Self {
|
||||
self.context.insert("active_page", "dashboard");
|
||||
self.context.insert("active_section", section);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_marketplace_data(mut self, products: &[Product]) -> Self {
|
||||
self.context.insert("products", products);
|
||||
self.context.insert("active_page", "marketplace");
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> tera::Context {
|
||||
self.context
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 Implementation Timeline
|
||||
|
||||
### **Phase 2A: Foundation (Week 1-2)**
|
||||
- [ ] **ConfigurationBuilder** implementation
|
||||
- [ ] **ServiceFactory** implementation
|
||||
- [ ] **ResponseBuilder** implementation
|
||||
- [ ] Core infrastructure and testing
|
||||
|
||||
### **Phase 2B: Enhancement (Week 3-4)**
|
||||
- [ ] **MockDataBuilder** implementation
|
||||
- [ ] **ErrorBuilder** implementation
|
||||
- [ ] **ContextBuilder** enhancement
|
||||
- [ ] Integration testing and validation
|
||||
|
||||
### **Phase 2C: Migration (Week 5-6)**
|
||||
- [ ] Systematic migration of all instances
|
||||
- [ ] Comprehensive testing
|
||||
- [ ] Performance optimization
|
||||
- [ ] Documentation updates
|
||||
|
||||
### **Phase 2D: Validation (Week 7-8)**
|
||||
- [ ] Full regression testing
|
||||
- [ ] Performance benchmarking
|
||||
- [ ] Code review and refinement
|
||||
- [ ] Final documentation
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Success Metrics & Validation
|
||||
|
||||
### **Quantitative Metrics**
|
||||
- **Lines of Code Reduction**: Target 630+ lines (70% of identified opportunities)
|
||||
- **Compilation Time**: Maintain or improve current build times
|
||||
- **Test Coverage**: Maintain 100% test coverage for all builders
|
||||
- **Performance**: No regression in API response times
|
||||
|
||||
### **Qualitative Metrics**
|
||||
- **Developer Experience**: Reduced boilerplate, clearer patterns
|
||||
- **Maintainability**: Single-source-of-truth for all patterns
|
||||
- **Consistency**: Uniform patterns across entire codebase
|
||||
- **Documentation**: Comprehensive guides for all builders
|
||||
|
||||
### **Validation Checklist**
|
||||
- [ ] All existing functionality preserved
|
||||
- [ ] Zero compilation errors
|
||||
- [ ] All tests passing
|
||||
- [ ] Performance benchmarks met
|
||||
- [ ] Code review approved
|
||||
- [ ] Documentation complete
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Advanced Optimization Opportunities
|
||||
|
||||
### **Phase 3: Advanced Patterns** (Future Consideration)
|
||||
|
||||
1. **Macro-Based Builder Generation**
|
||||
```rust
|
||||
#[derive(Builder)]
|
||||
#[builder(pattern = "owned")]
|
||||
struct AutoGeneratedBuilder {
|
||||
// Automatic builder generation
|
||||
}
|
||||
```
|
||||
|
||||
2. **Compile-Time Validation**
|
||||
```rust
|
||||
const_assert!(builder_fields_complete());
|
||||
```
|
||||
|
||||
3. **Builder Trait Abstractions**
|
||||
```rust
|
||||
trait BuilderPattern<T> {
|
||||
fn build(self) -> Result<T, String>;
|
||||
}
|
||||
```
|
||||
|
||||
4. **Performance Optimizations**
|
||||
- Zero-cost abstractions
|
||||
- Compile-time optimizations
|
||||
- Memory pool allocations
|
||||
|
||||
---
|
||||
|
||||
## 📚 Implementation Guidelines
|
||||
|
||||
### **For AI Assistance**
|
||||
|
||||
When implementing Phase 2 consolidation:
|
||||
|
||||
1. **Always use existing patterns** from Phase 1 as templates
|
||||
2. **Maintain backward compatibility** during migration
|
||||
3. **Follow single-source-of-truth principle** for all builders
|
||||
4. **Use `..Default::default()`** for extensibility
|
||||
5. **Include comprehensive error handling** in all builders
|
||||
6. **Add builder methods to existing structs** via `impl` blocks
|
||||
7. **Create template methods** for common use cases
|
||||
8. **Validate all builders** with comprehensive tests
|
||||
|
||||
### **Migration Strategy**
|
||||
|
||||
1. **Implement builder** in `src/models/builders.rs`
|
||||
2. **Add convenience methods** to existing structs
|
||||
3. **Create migration script** to identify all instances
|
||||
4. **Replace instances systematically** one module at a time
|
||||
5. **Test thoroughly** after each module migration
|
||||
6. **Update documentation** for each completed builder
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Expected Final State
|
||||
|
||||
After Phase 2 completion, the Project Mycelium will achieve:
|
||||
|
||||
### **Code Quality**
|
||||
- **~1,430 total lines eliminated** (Phase 1 + Phase 2)
|
||||
- **Industry-standard builder patterns** throughout entire codebase
|
||||
- **Single-source-of-truth architecture** for all major patterns
|
||||
- **Zero code duplication** in construction patterns
|
||||
|
||||
### **Developer Experience**
|
||||
- **Consistent patterns** across all modules
|
||||
- **Self-documenting code** through builder methods
|
||||
- **Reduced cognitive load** for new developers
|
||||
- **Enhanced maintainability** for future features
|
||||
|
||||
### **Architecture Benefits**
|
||||
- **Future-proof foundation** for continued development
|
||||
- **Easy extensibility** for new features
|
||||
- **Simplified testing** through mock builders
|
||||
- **Performance optimizations** through centralized patterns
|
||||
|
||||
This roadmap provides a clear path to achieving maximum builder pattern consolidation while maintaining all existing features and dramatically improving code quality and maintainability.
|
Reference in New Issue
Block a user