📐 Camadas - ecosif-moviments

📋 Visão Geral

O serviço ecosif-moviments segue uma arquitetura em camadas bem definida, seguindo os padrões do Spring Boot.


🏗️ Estrutura de Camadas

┌─────────────────────────────────────────────────────────┐
│              Camada de Apresentação (REST)              │
│                                                         │
│  Controllers                                            │
│  • BatchController                                      │
│  • DocumentController                                   │
│  • EntryController                                      │
│  • ConsolidationController                              │
│  • ... (8 mais)                                         │
│                                                         │
│  Responsabilidades:                                     │
│  • Receber requisições HTTP                             │
│  • Validação básica de entrada                          │
│  • Transformar DTOs ↔ JSON                              │
│  • Retornar respostas HTTP                              │
└────────────────────┬────────────────────────────────────┘
                     │
                     │ usa
                     ▼
┌─────────────────────────────────────────────────────────┐
│            Camada de Aplicação (Services)               │
│                                                         │
│  Services                                               │
│  • BatchService                                         │
│  • DocumentService                                      │
│  • EntryService                                         │
│  • ConsolidationService                                 │
│  • ... (25 mais)                                        │
│                                                         │
│  Responsabilidades:                                     │
│  • Lógica de negócio                                    │
│  • Validações complexas                                 │
│  • Orquestração de operações                            │
│  • Transformação DTO ↔ Entity                           │
│  • Processamento assíncrono                             │
└────────────────────┬────────────────────────────────────┘
                     │
                     │ usa
                     ▼
┌─────────────────────────────────────────────────────────┐
│           Camada de Persistência (Repositories)         │
│                                                         │
│  Repositories                                           │
│  • BatchRepository                                      │
│  • DocumentRepository                                   │
│  • EntryRepository                                      │
│  • ... (29 mais)                                        │
│                                                         │
│  Responsabilidades:                                     │
│  • Acesso a dados                                       │
│  • Queries customizadas                                 │
│  • Operações CRUD                                       │
└────────────────────┬────────────────────────────────────┘
                     │
                     │ persiste
                     ▼
┌─────────────────────────────────────────────────────────┐
│              Camada de Dados (Entities)                 │
│                                                         │
│  ecosif-database (Biblioteca Compartilhada)             │
│  • Batch • Document • Entry                             │
│  • Company • Branch • ChartOfAccounts                   │
│  • ... (52+ entidades)                                  │
│                                                         │
│  Responsabilidades:                                     │
│  • Mapeamento objeto-relacional                         │
│  • Validações JSR-303                                   │
│  • Estrutura de dados                                   │
└────────────────────┬────────────────────────────────────┘
                     │
                     │ conecta
                     ▼
┌─────────────────────────────────────────────────────────┐
│                  PostgreSQL Database                    │
│                                                         │
│  • Tabelas contábeis                                    │
│  • Históricos                                           │
│  • Temporárias                                          │
└─────────────────────────────────────────────────────────┘

📦 Detalhamento das Camadas

Camada 1: Controllers (REST)

Localização: io.ecosif.moviments.company.controller

Responsabilidades: - ✅ Receber requisições HTTP - ✅ Validar entrada básica (@Valid) - ✅ Converter JSON ↔ DTO - ✅ Chamar services apropriados - ✅ Retornar respostas HTTP padronizadas - ✅ Tratamento de exceções (via @ExceptionHandler)

Exemplo:

@RestController
public class EntryController {

    @Autowired
    private EntryService entryService;

    @PostMapping("/entry")
    public ResponseEntity<EntryDTO> createEntry(@Valid @RequestBody EntryDTO dto) {
        EntryDTO created = entryService.create(dto);
        return ResponseEntity.status(HttpStatus.CREATED).body(created);
    }
}

Características: - Anotações: @RestController, @RequestMapping, @PostMapping, etc. - Validação: @Valid para DTOs - Documentação: @ApiOperation, @ApiResponses (Swagger)


Camada 2: Services (Lógica de Negócio)

Localização: io.ecosif.moviments.company.service

Responsabilidades: - ✅ Implementar lógica de negócio - ✅ Validações complexas (regras de negócio) - ✅ Orquestração de múltiplos repositories - ✅ Transformação DTO ↔ Entity (ModelMapper) - ✅ Processamento assíncrono (@Async) - ✅ Transações (@Transactional)

Exemplo:

@Service
@Transactional
public class EntryService {

    @Autowired
    private EntryRepository repository;

    @Autowired
    private DocumentService documentService;

    public EntryDTO create(EntryDTO dto) {
        // Validações de negócio
        validatePartidasDobradas(dto);
        validateContaContabil(dto.getContaId());

        // Transformar DTO em Entity
        Entry entry = modelMapper.map(dto, Entry.class);

        // Persistir
        Entry saved = repository.save(entry);

        // Retornar DTO
        return modelMapper.map(saved, EntryDTO.class);
    }
}

Características: - Interface + Implementação (padrão recomendado) - @Service para identificação - @Transactional para transações - @Async para operações assíncronas


Camada 3: Repositories (Acesso a Dados)

Localização: io.ecosif.moviments.company.repository

Responsabilidades: - ✅ Abstração de acesso a dados - ✅ Operações CRUD (herdadas de JpaRepository) - ✅ Queries customizadas (@Query) - ✅ Especificações complexas (Specification)

Exemplo:

@Repository
public interface EntryRepository extends JpaRepository<Entry, Long> {

    List<Entry> findByDocumentId(Long documentId);

    @Query("SELECT e FROM Entry e WHERE e.contaId = :contaId AND e.debitcredit = :debitcredit")
    List<Entry> findByContaAndType(@Param("contaId") Long contaId, 
                                    @Param("debitcredit") String debitcredit);
}

Características: - Interfaces que estendem JpaRepository - Spring Data JPA implementa automaticamente - Queries via métodos ou @Query


Camada 4: DTOs (Data Transfer Objects)

Localização: io.ecosif.moviments.company.dto

Responsabilidades: - ✅ Transferir dados entre camadas - ✅ Isolar entidades JPA da API - ✅ Validações de entrada (@NotNull, @Size, etc.) - ✅ Serialização JSON

Exemplo:

public class EntryDTO {

    @NotNull
    private Long documentId;

    @NotNull
    @Size(max = 5)
    private String lancamento;

    @NotNull
    private String debcre; // D ou C

    @NotNull
    private Long contaId;

    @NotNull
    private Double valor;

    // Getters e Setters
}

Características: - Classes simples (POJOs) - Validações JSR-303 - Sem anotações JPA - Lombok para reduzir boilerplate


Camada 5: Entities (Modelo de Dados)

Localização: Biblioteca ecosif-database

Responsabilidades: - ✅ Representar tabelas do banco - ✅ Mapeamento objeto-relacional (JPA) - ✅ Validações básicas (JSR-303) - ✅ Estrutura de dados do domínio

Exemplo:

@Entity
@Table(name="ct_lancamento")
@Getter
@Setter
public class Entry {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @NotNull
    private Long documentId;

    // ...
}

Características: - Anotações JPA (@Entity, @Table, @Column) - Validações JSR-303 - Lombok para getters/setters - Sem lógica de negócio


🔄 Fluxo de Dados

Fluxo: Criar Lançamento

Cliente HTTP
    │
    ▼
Controller (EntryController)
    │ Valida entrada (@Valid)
    │ Converte JSON → EntryDTO
    ▼
Service (EntryService)
    │ Valida regras de negócio
    │ Transforma EntryDTO → Entry (Entity)
    │ Valida partidas dobradas
    ▼
Repository (EntryRepository)
    │ Executa SQL via Hibernate
    ▼
PostgreSQL
    │ INSERT INTO ct_lancamento
    │
    ▼
Repository
    │ Retorna Entry (Entity)
    ▼
Service
    │ Transforma Entry → EntryDTO
    │ Processa/Enriquece dados
    ▼
Controller
    │ Converte EntryDTO → JSON
    │ Retorna ResponseEntity
    ▼
Cliente HTTP

🎯 Princípios de Design

1. Separation of Concerns

Cada camada tem responsabilidade única: - Controller: Apresentação HTTP - Service: Lógica de negócio - Repository: Acesso a dados - Entity: Estrutura de dados

2. Dependency Injection

Todas as dependências são injetadas via @Autowired: - Controllers dependem de Services - Services dependem de Repositories - Services podem depender de outros Services

3. Inversion of Control (IoC)

Spring gerencia o ciclo de vida: - Criação de beans - Injeção de dependências - Gerenciamento de transações

4. Don't Repeat Yourself (DRY)


📝 Padrões Utilizados

Repository Pattern

Abstração de acesso a dados através de interfaces.

Service Layer Pattern

Camada intermediária para lógica de negócio.

DTO Pattern

Separação entre entidades JPA e DTOs de API.

Dependency Injection

Injeção de dependências via Spring.

Factory Pattern

Criação de entidades complexas (ex: BatchFactory).


🔒 Transações

Nível de Transação

Por padrão, transações são gerenciadas nos Services:

@Service
@Transactional
public class EntryService {
    // Todos os métodos são transacionais
}

Propagation

Rollback


🔄 Processamento Assíncrono

Operações longas são executadas assincronamente:

@Service
public class ConsolidationService {

    @Async
    public CompletableFuture<Void> processConsolidation(ConsolidationDTO dto) {
        // Processamento longo
        return CompletableFuture.completedFuture(null);
    }
}

Configuração: @EnableAsync na classe Application


📊 Mapeamento DTO ↔ Entity

ModelMapper

Usado para converter entre DTOs e Entities:

@Autowired
private ModelMapper modelMapper;

// DTO → Entity
Entry entry = modelMapper.map(entryDTO, Entry.class);

// Entity → DTO
EntryDTO dto = modelMapper.map(entry, EntryDTO.class);

🎯 Boas Práticas

  1. Controllers devem ser finos - Apenas receber e retornar
  2. Lógica de negócio nos Services - Não no Controller
  3. Validações no Service - Além das validações JSR-303
  4. Repositories apenas para dados - Sem lógica de negócio
  5. DTOs para API - Nunca expor Entities diretamente
  6. Transações nos Services - Não nos Controllers
  7. Exceções tratadas globalmente - @ExceptionHandler

Última Atualização: 2025-11-27