# 🎯 CQRS Pattern Implementation - PraFrota Frontend

## Overview

This document outlines how the PraFrota frontend implements the Command Query Responsibility Segregation (CQRS) pattern to align with our backend architecture.

## 🏗️ Service Layer Structure

### Query Services

```typescript
@Injectable({
  providedIn: 'root'
})
export class VehicleQueryService {
  constructor(private http: HttpClient) {}

  // Query Methods (Read Operations)
  getVehicles(filters: VehicleFilters): Observable<ResponsePaginated<Vehicle>> {
    return this.http.get<ResponsePaginated<Vehicle>>('/api/vehicle', { params: filters });
  }

  getVehicleById(id: string): Observable<Response<Vehicle>> {
    return this.http.get<Response<Vehicle>>(`/api/vehicle/${id}`);
  }

  searchVehicles(query: string): Observable<Response<Vehicle[]>> {
    return this.http.get<Response<Vehicle[]>>('/api/vehicle/search', { params: { query } });
  }
}
```

### Command Services

```typescript
@Injectable({
  providedIn: 'root'
})
export class VehicleCommandService {
  constructor(private http: HttpClient) {}

  // Command Methods (Write Operations)
  createVehicle(vehicle: CreateVehicleDto): Observable<Response<Vehicle>> {
    return this.http.post<Response<Vehicle>>('/api/vehicle', vehicle);
  }

  updateVehicle(id: string, vehicle: UpdateVehicleDto): Observable<Response<Vehicle>> {
    return this.http.put<Response<Vehicle>>(`/api/vehicle/${id}`, vehicle);
  }

  deleteVehicle(id: string): Observable<Response<void>> {
    return this.http.delete<Response<void>>(`/api/vehicle/${id}`);
  }
}
```

## 📦 Service Adapters

Service adapters bridge between our CQRS services and the BaseDomainComponent:

```typescript
@Injectable({
  providedIn: 'root'
})
export class VehicleServiceAdapter implements IDomainServiceAdapter<Vehicle> {
  constructor(
    private queryService: VehicleQueryService,
    private commandService: VehicleCommandService
  ) {}

  // Query Operations
  getList(filters: any): Observable<ResponsePaginated<Vehicle>> {
    return this.queryService.getVehicles(filters);
  }

  getById(id: string): Observable<Response<Vehicle>> {
    return this.queryService.getVehicleById(id);
  }

  // Command Operations
  create(data: CreateVehicleDto): Observable<Response<Vehicle>> {
    return this.commandService.createVehicle(data);
  }

  update(id: string, data: UpdateVehicleDto): Observable<Response<Vehicle>> {
    return this.commandService.updateVehicle(id, data);
  }

  delete(id: string): Observable<Response<void>> {
    return this.commandService.deleteVehicle(id);
  }
}
```

## 🔄 Component Integration

### BaseDomainComponent Usage

```typescript
@Component({
  selector: 'app-vehicle',
  standalone: true,
  imports: [CommonModule, TabSystemComponent],
  templateUrl: './vehicle.component.html'
})
export class VehicleComponent extends BaseDomainComponent<Vehicle> {
  constructor(
    private queryService: VehicleQueryService,
    private commandService: VehicleCommandService,
    titleService: TitleService,
    headerActionsService: HeaderActionsService,
    cdr: ChangeDetectorRef
  ) {
    super(
      titleService,
      headerActionsService,
      cdr,
      new VehicleServiceAdapter(queryService, commandService)
    );
  }
}
```

## 📊 State Management

### Query State

```typescript
interface QueryState<T> {
  data: T[];
  loading: boolean;
  error: any;
  filters: any;
  pagination: {
    currentPage: number;
    pageSize: number;
    totalCount: number;
  };
}
```

### Command State

```typescript
interface CommandState<T> {
  data: T | null;
  loading: boolean;
  error: any;
  success: boolean;
}
```

## 🔐 Error Handling

### Query Error Handling

```typescript
@Injectable({
  providedIn: 'root'
})
export class QueryErrorHandler {
  handleError(error: HttpErrorResponse): Observable<never> {
    // Handle query-specific errors
    if (error.status === 404) {
      // Handle not found
    }
    return throwError(() => error);
  }
}
```

### Command Error Handling

```typescript
@Injectable({
  providedIn: 'root'
})
export class CommandErrorHandler {
  handleError(error: HttpErrorResponse): Observable<never> {
    // Handle command-specific errors
    if (error.status === 409) {
      // Handle conflicts
    }
    return throwError(() => error);
  }
}
```

## 📝 Best Practices

1. **Service Organization**:
   - Separate query and command services
   - Use service adapters for component integration
   - Implement proper error handling

2. **State Management**:
   - Maintain separate states for queries and commands
   - Use proper loading states
   - Handle errors appropriately

3. **Type Safety**:
   - Use proper TypeScript interfaces
   - Implement proper DTOs
   - Use proper response types

4. **Performance**:
   - Implement proper caching
   - Use proper pagination
   - Optimize queries

## 🔄 Implementation Checklist

When implementing CQRS in a new domain:

1. [ ] Create Query Service
2. [ ] Create Command Service
3. [ ] Create Service Adapter
4. [ ] Implement proper error handling
5. [ ] Add proper loading states
6. [ ] Implement proper caching
7. [ ] Add proper validation
8. [ ] Test all scenarios

## 📚 Additional Resources

- Backend CQRS Documentation: `/docs/mcp/CQRS_PATTERN.md`
- Frontend Architecture: `/docs/ARCHITECTURE.md`
- Service Adapter Pattern: `/docs/SERVICE_ADAPTER_PATTERN.md` 