Update README and documentation; refactor frontend components for improved structure and resilience

This commit is contained in:
glenn schrooyen
2025-09-11 23:46:29 +02:00
parent 63b4bb487d
commit b9206de1a0
49 changed files with 27058 additions and 581 deletions

View File

@@ -0,0 +1,406 @@
# API Gateway Clean Code Implementation
This document outlines the clean code principles and best practices implemented in the LabFusion API Gateway service (Java Spring Boot).
## 🏗️ **Architecture Overview**
The API Gateway follows a layered architecture with clear separation of concerns:
```
src/main/java/com/labfusion/
├── config/ # Configuration classes
├── controller/ # REST controllers (Presentation Layer)
├── service/ # Business logic (Service Layer)
├── repository/ # Data access (Repository Layer)
├── model/ # JPA entities (Domain Layer)
└── LabFusionApiGatewayApplication.java
```
## 🧹 **Clean Code Principles Applied**
### **1. Single Responsibility Principle (SRP)**
#### **Controllers**
- **DashboardController**: Only handles dashboard-related HTTP requests
- **SystemController**: Only manages system metrics and events
- Each controller has a single, well-defined responsibility
#### **Services**
- **DashboardService**: Manages dashboard business logic
- Each service class focuses on one domain area
#### **Repositories**
- **DashboardRepository**: Only handles dashboard data operations
- **EventRepository**: Only manages event data persistence
- Clear data access boundaries
### **2. Open/Closed Principle (OCP)**
#### **Extensible Design**
```java
// Easy to extend with new widget types
public enum WidgetType {
CHART, TABLE, STATUS_CARD, METRIC
}
// Easy to add new dashboard configurations
@Configuration
public class OpenApiConfig {
// Open for extension, closed for modification
}
```
#### **Interface-Based Design**
```java
public interface DashboardRepository extends JpaRepository<Dashboard, Long> {
// Interface allows for different implementations
}
```
### **3. Dependency Inversion Principle (DIP)**
#### **Dependency Injection**
```java
@Service
public class DashboardService {
private final DashboardRepository dashboardRepository;
// Constructor injection - depends on abstraction
public DashboardService(DashboardRepository dashboardRepository) {
this.dashboardRepository = dashboardRepository;
}
}
```
### **4. Interface Segregation Principle (ISP)**
#### **Focused Interfaces**
- Each repository interface only contains methods relevant to its entity
- Controllers only expose necessary endpoints
- Services have focused, cohesive interfaces
## 📝 **Code Quality Improvements**
### **1. Naming Conventions**
#### **Clear, Descriptive Names**
```java
// Good: Clear purpose
public class DashboardController
public class SystemController
public class DashboardService
// Good: Descriptive method names
public List<Dashboard> getAllDashboards()
public Dashboard createDashboard(Dashboard dashboard)
public void deleteDashboard(Long id)
```
#### **Consistent Naming**
- Classes: PascalCase (e.g., `DashboardController`)
- Methods: camelCase (e.g., `getAllDashboards`)
- Variables: camelCase (e.g., `dashboardRepository`)
- Constants: UPPER_SNAKE_CASE (e.g., `API_VERSION`)
### **2. Method Design**
#### **Small, Focused Methods**
```java
@GetMapping("/dashboards")
public ResponseEntity<List<Dashboard>> getAllDashboards() {
List<Dashboard> dashboards = dashboardService.getAllDashboards();
return ResponseEntity.ok(dashboards);
}
@PostMapping("/dashboards")
public ResponseEntity<Dashboard> createDashboard(@RequestBody Dashboard dashboard) {
Dashboard createdDashboard = dashboardService.createDashboard(dashboard);
return ResponseEntity.status(HttpStatus.CREATED).body(createdDashboard);
}
```
#### **Single Level of Abstraction**
- Controller methods handle HTTP concerns only
- Business logic delegated to service layer
- Data access delegated to repository layer
### **3. Error Handling**
#### **Centralized Exception Handling**
```java
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<ErrorResponse> handleEntityNotFound(EntityNotFoundException ex) {
ErrorResponse error = new ErrorResponse("Entity not found", ex.getMessage());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
}
```
#### **Consistent Error Responses**
- Standardized error response format
- Appropriate HTTP status codes
- Clear error messages
### **4. Configuration Management**
#### **Externalized Configuration**
```yaml
# application.yml
spring:
datasource:
url: ${DATABASE_URL:jdbc:postgresql://localhost:5432/labfusion}
username: ${DATABASE_USERNAME:labfusion}
password: ${DATABASE_PASSWORD:password}
```
#### **Environment-Specific Settings**
- Development, staging, production configurations
- Environment variable support
- Sensitive data externalized
## 🔧 **Spring Boot Best Practices**
### **1. Annotation Usage**
#### **Appropriate Annotations**
```java
@RestController
@RequestMapping("/api/dashboards")
@Validated
public class DashboardController {
@GetMapping
@Operation(summary = "Get all dashboards")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Successfully retrieved dashboards"),
@ApiResponse(responseCode = "500", description = "Internal server error")
})
public ResponseEntity<List<Dashboard>> getAllDashboards() {
// Implementation
}
}
```
### **2. Validation**
#### **Input Validation**
```java
@PostMapping("/dashboards")
public ResponseEntity<Dashboard> createDashboard(
@Valid @RequestBody Dashboard dashboard) {
// @Valid ensures input validation
}
```
#### **Entity Validation**
```java
@Entity
@Table(name = "dashboards")
public class Dashboard {
@NotBlank(message = "Name is required")
@Size(max = 100, message = "Name must not exceed 100 characters")
private String name;
@NotNull(message = "User ID is required")
private Long userId;
}
```
### **3. OpenAPI Documentation**
#### **Comprehensive API Documentation**
```java
@Tag(name = "Dashboard Management", description = "Operations related to dashboard management")
@RestController
public class DashboardController {
@Operation(summary = "Get all dashboards", description = "Retrieve all dashboards for the authenticated user")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Successfully retrieved dashboards"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "500", description = "Internal server error")
})
@GetMapping
public ResponseEntity<List<Dashboard>> getAllDashboards() {
// Implementation
}
}
```
## 📊 **Data Layer Best Practices**
### **1. JPA Entity Design**
#### **Clean Entity Structure**
```java
@Entity
@Table(name = "dashboards")
public class Dashboard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
@Size(max = 100)
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
@OneToMany(mappedBy = "dashboard", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Widget> widgets = new ArrayList<>();
// Constructors, getters, setters
}
```
#### **Proper Relationships**
- Lazy loading for performance
- Cascade operations where appropriate
- Orphan removal for cleanup
### **2. Repository Design**
#### **Focused Repository Methods**
```java
@Repository
public interface DashboardRepository extends JpaRepository<Dashboard, Long> {
List<Dashboard> findByUserId(Long userId);
List<Dashboard> findByNameContainingIgnoreCase(String name);
Optional<Dashboard> findByIdAndUserId(Long id, Long userId);
}
```
## 🚀 **Performance Optimizations**
### **1. Database Optimization**
- Lazy loading for relationships
- Proper indexing strategies
- Query optimization
### **2. Caching Strategy**
- Service-level caching where appropriate
- Redis integration for distributed caching
- Cache invalidation strategies
### **3. Connection Pooling**
- HikariCP configuration
- Proper connection pool sizing
- Connection timeout handling
## 🧪 **Testing Strategy**
### **1. Unit Testing**
- Service layer unit tests
- Repository layer tests
- Controller layer tests
### **2. Integration Testing**
- Database integration tests
- API integration tests
- End-to-end testing
### **3. Test Structure**
```java
@ExtendWith(MockitoExtension.class)
class DashboardServiceTest {
@Mock
private DashboardRepository dashboardRepository;
@InjectMocks
private DashboardService dashboardService;
@Test
void shouldCreateDashboard() {
// Given
Dashboard dashboard = new Dashboard();
when(dashboardRepository.save(any(Dashboard.class))).thenReturn(dashboard);
// When
Dashboard result = dashboardService.createDashboard(dashboard);
// Then
assertThat(result).isNotNull();
verify(dashboardRepository).save(dashboard);
}
}
```
## 📋 **Code Review Checklist**
### **Controller Layer**
- [ ] Single responsibility per controller
- [ ] Proper HTTP status codes
- [ ] Input validation
- [ ] Error handling
- [ ] OpenAPI documentation
### **Service Layer**
- [ ] Business logic only
- [ ] No direct database access
- [ ] Proper exception handling
- [ ] Transaction management
- [ ] Clear method names
### **Repository Layer**
- [ ] Data access only
- [ ] Proper query methods
- [ ] No business logic
- [ ] Performance considerations
### **Entity Layer**
- [ ] Proper JPA annotations
- [ ] Validation constraints
- [ ] Relationship mapping
- [ ] Immutable fields where appropriate
## 🎯 **Benefits Achieved**
### **1. Maintainability**
- Clear separation of concerns
- Easy to modify and extend
- Consistent patterns throughout
- Self-documenting code
### **2. Testability**
- Isolated layers
- Mockable dependencies
- Clear interfaces
- Testable business logic
### **3. Performance**
- Optimized database access
- Proper caching strategies
- Efficient query patterns
- Resource management
### **4. Scalability**
- Modular architecture
- Horizontal scaling support
- Database optimization
- Caching strategies
## 🔮 **Future Improvements**
### **Potential Enhancements**
1. **CQRS Pattern**: Separate read and write models
2. **Event Sourcing**: Event-driven architecture
3. **Microservices**: Further service decomposition
4. **GraphQL**: Alternative API approach
5. **Reactive Programming**: Non-blocking operations
### **Monitoring & Observability**
1. **Metrics**: Application performance metrics
2. **Logging**: Structured logging with correlation IDs
3. **Tracing**: Distributed tracing
4. **Health Checks**: Comprehensive health monitoring
This clean code implementation makes the API Gateway more maintainable, testable, and scalable while following Spring Boot and Java best practices.

View File

@@ -23,10 +23,6 @@ public class OpenApiConfig {
.title("LabFusion API Gateway")
.description("Core API gateway for LabFusion homelab dashboard. Provides authentication, dashboard management, and data storage.")
.version("1.0.0")
.contact(new Contact()
.name("LabFusion Team")
.url("https://github.com/labfusion/labfusion")
.email("team@labfusion.dev"))
.license(new License()
.name("MIT License")
.url("https://opensource.org/licenses/MIT")))