# 🌐 Guia de Integração com API PraFrota

## 📋 **Informações da API**

**URL Base**: `https://prafrota-be-bff-tenant-api.grupopra.tech`  
**Swagger UI**: [https://prafrota-be-bff-tenant-api.grupopra.tech/swagger#/](https://prafrota-be-bff-tenant-api.grupopra.tech/swagger#/)  
**Projeto**: PraFrota - Sistema de Gestão de Frota  
**Empresa**: Grupo PRA  

## 🎯 **Fluxo MCP para Novos Domínios**

### **Passo 1: Consulta ao Swagger**

Quando o MCP precisar implementar um novo domínio:

1. **Acessar o Swagger da API**: [https://prafrota-be-bff-tenant-api.grupopra.tech/swagger#/](https://prafrota-be-bff-tenant-api.grupopra.tech/swagger#/)
2. **Identificar endpoints** do domínio desejado
3. **Analisar schemas** de request/response
4. **Mapear operações CRUD** disponíveis

### **Passo 2: Mapeamento de Endpoints**

#### **Padrão Esperado de Endpoints**
```
GET    /api/{domain}           # Listagem com paginação
POST   /api/{domain}           # Criação de nova entidade
GET    /api/{domain}/{id}      # Detalhes de uma entidade
PUT    /api/{domain}/{id}      # Atualização completa
PATCH  /api/{domain}/{id}      # Atualização parcial
DELETE /api/{domain}/{id}      # Exclusão
```

#### **Exemplos de Domínios Esperados**
- `/api/vehicles` - Gestão de veículos
- `/api/drivers` - Gestão de motoristas  
- `/api/routes` - Gestão de rotas
- `/api/clients` - Gestão de clientes
- `/api/companies` - Gestão de empresas
- `/api/contracts` - Gestão de contratos

### **Passo 3: Implementação do Service**

#### **Template Base para Services**
```typescript
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { DomainService } from '../base-domain/base-domain.component';

@Injectable()
export class {Domain}Service implements DomainService<{Entity}> {
  private readonly apiUrl = 'https://prafrota-be-bff-tenant-api.grupopra.tech/api';
  private readonly endpoint = '{domain}'; // ex: 'vehicles'

  constructor(private http: HttpClient) {}

  // ✅ Método obrigatório para BaseDomainComponent
  getEntities(page: number, pageSize: number, filters: any): Observable<{
    data: {Entity}[];
    totalCount: number;
    pageCount: number;
    currentPage: number;
  }> {
    const params = new HttpParams()
      .set('page', page.toString())
      .set('pageSize', pageSize.toString());
      
    // Adicionar filtros se disponíveis na API
    Object.keys(filters).forEach(key => {
      if (filters[key] !== null && filters[key] !== '') {
        params = params.set(key, filters[key]);
      }
    });

    return this.http.get<any>(`${this.apiUrl}/${this.endpoint}`, { params });
  }

  // ✅ Métodos CRUD para salvamento genérico
  create(entity: Partial<{Entity}>): Observable<{Entity}> {
    return this.http.post<{Entity}>(`${this.apiUrl}/${this.endpoint}`, entity);
  }

  update(id: any, entity: Partial<{Entity}>): Observable<{Entity}> {
    return this.http.put<{Entity}>(`${this.apiUrl}/${this.endpoint}/${id}`, entity);
  }

  delete(id: any): Observable<void> {
    return this.http.delete<void>(`${this.apiUrl}/${this.endpoint}/${id}`);
  }

  getById(id: any): Observable<{Entity}> {
    return this.http.get<{Entity}>(`${this.apiUrl}/${this.endpoint}/${id}`);
  }

  // Métodos adicionais específicos do domínio conforme Swagger
}
```

### **Passo 4: Schema para Interface TypeScript**

#### **Processo de Mapeamento**
1. **Localizar schema** no Swagger (seção "Schemas" ou "Definitions")
2. **Mapear tipos** do OpenAPI para TypeScript:
   - `string` → `string`
   - `integer` → `number`
   - `boolean` → `boolean`
   - `array` → `Array<T>`
   - `object` → `interface`
3. **Considerar campos opcionais** (marked as required: false)
4. **Incluir enums** se definidos na API

#### **Template Base para Interfaces**
```typescript
// {entity}.interface.ts
// ✅ Baseado no schema do Swagger da API PraFrota

export interface {Entity} {
  // Campos obrigatórios (required: true no schema)
  id: string;
  name: string;
  createdAt: string;
  updatedAt: string;

  // Campos opcionais (required: false ou não listados)
  description?: string;
  status?: EntityStatus;

  // Relacionamentos
  {relation}Id?: string;
  {relation}?: {RelatedEntity};
}

export enum EntityStatus {
  ACTIVE = 'ACTIVE',
  INACTIVE = 'INACTIVE',
  PENDING = 'PENDING'
}

// Types auxiliares se necessário
export type {Entity}CreateRequest = Omit<{Entity}, 'id' | 'createdAt' | 'updatedAt'>;
export type {Entity}UpdateRequest = Partial<{Entity}CreateRequest>;
```

### **Passo 5: Configuração de Colunas**

#### **Mapeamento de Campos para Tabela**
```typescript
// Baseado nos campos do schema da API
protected getDomainConfig(): DomainConfig {
  return {
    domain: '{domain}',
    title: '{Plural}',
    entityName: '{singular}',
    subTabs: ['dados', 'endereco', 'documentos'], // Conforme necessário
    columns: [
      // ✅ Campos principais para listagem
      { field: 'id', header: 'ID', sortable: true, visible: false },
      { field: 'name', header: 'Nome', sortable: true, filterable: true },
      { field: 'status', header: 'Status', filterable: true },
      { field: 'createdAt', header: 'Criado em', sortable: true, type: 'date' },
      
      // Campos específicos do domínio baseados no schema
      { field: '{specific_field}', header: '{Header}', sortable: true }
    ]
  };
}
```

## 🔧 **Orientações Específicas para o MCP**

### **Antes de Implementar um Domínio**
1. ✅ **SEMPRE consultar o Swagger primeiro**
2. ✅ **Verificar endpoints disponíveis**
3. ✅ **Analisar schema de dados**
4. ✅ **Identificar campos obrigatórios vs opcionais**
5. ✅ **Verificar relacionamentos entre entidades**

### **Durante a Implementação**
1. ✅ **Usar nomes consistentes** com a API
2. ✅ **Mapear todos os campos** do schema
3. ✅ **Incluir validações** baseadas na API
4. ✅ **Testar endpoints** antes de finalizar
5. ✅ **Documentar diferenças** se houver

### **Validação da Implementação**
1. ✅ **Listar entidades** funciona
2. ✅ **Criar nova entidade** funciona  
3. ✅ **Editar entidade** funciona
4. ✅ **Excluir entidade** funciona
5. ✅ **Filtros e ordenação** funcionam

## 🎮 **Exemplo Completo: Veículos**

### **1. Endpoints Identificados no Swagger**
```
GET    /api/vehicles           # Listagem de veículos
POST   /api/vehicles           # Criar veículo
GET    /api/vehicles/{id}      # Detalhes do veículo
PUT    /api/vehicles/{id}      # Atualizar veículo
DELETE /api/vehicles/{id}      # Excluir veículo
```

### **2. Schema Extraído**
```json
{
  "Vehicle": {
    "type": "object",
    "required": ["plate", "model", "year"],
    "properties": {
      "id": { "type": "string" },
      "plate": { "type": "string" },
      "model": { "type": "string" },
      "year": { "type": "integer" },
      "status": { "type": "string", "enum": ["ACTIVE", "INACTIVE", "MAINTENANCE", "RENTED", "STOLEN", "CRASHED", "FOR_SALE", "SCRAPPED", "RESERVED", "UNDER_REPAIR"] },
      "brand": { "type": "string" },
      "color": { "type": "string" }
    }
  }
}
```

### **3. Interface TypeScript**
```typescript
export interface Vehicle {
  id: string;
  plate: string;      // obrigatório
  model: string;      // obrigatório  
  year: number;       // obrigatório
  status?: VehicleStatus;
  brand?: string;
  color?: string;
  createdAt?: string;
  updatedAt?: string;
}

export enum VehicleStatus {
  ACTIVE = 'ACTIVE',              // ✅ Ativo na frota
  INACTIVE = 'INACTIVE',          // ❌ Inativo 
  MAINTENANCE = 'MAINTENANCE',    // 🔧 Em manutenção
  RENTED = 'RENTED',             // 🏠 Alugado
  STOLEN = 'STOLEN',             // 🚨 Roubado
  CRASHED = 'CRASHED',           // 💥 Sinistrado
  FOR_SALE = 'FOR_SALE',         // 💰 Em venda
  SCRAPPED = 'SCRAPPED',         // ♻️ Sucateado
  RESERVED = 'RESERVED',         // 📋 Reservado
  UNDER_REPAIR = 'UNDER_REPAIR'  // 🔨 Em reparo
}
```

### **4. Service Implementado**
```typescript
@Injectable()
export class VehiclesService implements DomainService<Vehicle> {
  private readonly apiUrl = 'https://prafrota-be-bff-tenant-api.grupopra.tech/api';
  
  // ... implementação conforme template
}
```

### **5. Component Final**
```typescript
export class VehiclesComponent extends BaseDomainComponent<Vehicle> {
  protected getDomainConfig(): DomainConfig {
    return {
      domain: 'vehicle',
      title: 'Veículos',
      entityName: 'veículo',
      subTabs: ['dados', 'documentos', 'manutencao'],
      columns: [
        { field: 'plate', header: 'Placa', sortable: true, filterable: true },
        { field: 'model', header: 'Modelo', sortable: true, filterable: true },
        { field: 'year', header: 'Ano', sortable: true },
        { field: 'status', header: 'Status', filterable: true },
        { field: 'brand', header: 'Marca', sortable: true }
      ]
    };
  }
}
```

## 🚨 **Tratamento de Erros da API**

### **Códigos de Status Esperados**
- `200 OK` - Sucesso
- `201 Created` - Criado com sucesso
- `400 Bad Request` - Dados inválidos
- `401 Unauthorized` - Não autenticado
- `403 Forbidden` - Sem permissão
- `404 Not Found` - Recurso não encontrado
- `409 Conflict` - Conflito (ex: duplicata)
- `500 Internal Server Error` - Erro do servidor

### **Implementação de Error Handling**
```typescript
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';

// No service
create(entity: Partial<Vehicle>): Observable<Vehicle> {
  return this.http.post<Vehicle>(`${this.apiUrl}/vehicles`, entity)
    .pipe(
      catchError(error => {
        console.error('Erro ao criar veículo:', error);
        // Transformar erro da API em mensagem amigável
        return throwError(() => this.handleApiError(error));
      })
    );
}

private handleApiError(error: any): string {
  switch (error.status) {
    case 400: return 'Dados inválidos. Verifique os campos obrigatórios.';
    case 409: return 'Já existe um veículo com esta placa.';
    default: return 'Erro interno. Tente novamente.';
  }
}
```

---

## 🔗 **Links Úteis**

- **Swagger da API**: [https://prafrota-be-bff-tenant-api.grupopra.tech/swagger#/](https://prafrota-be-bff-tenant-api.grupopra.tech/swagger#/)
- **Documentação do Framework**: [../src/app/shared/components/tab-system/README.md](../src/app/shared/components/tab-system/README.md)
- **Base Domain Component**: [../src/app/shared/components/base-domain/base-domain.component.ts](../src/app/shared/components/base-domain/base-domain.component.ts)

---

**💡 Dica para o MCP**: Sempre começar pela consulta ao Swagger para garantir implementação correta e consistente com a API PraFrota! 