Skip to content

About

DDD tático e Arquitetura Hexagonal numa API de pedidos (Java 25, Spring Boot 4): testes, desenvolvimento seguro (OWASP, SAST, DAST, SBOM) e documentação de arquitetura (C4, ADR, DAS)

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

ddd-hexagonal

Domain-Driven Design (tático) e Arquitetura Hexagonal em uma API de pedidos, com Java 25 e Spring Boot 4.

Lab da Fase 1 da Pós Tech Software Architecture (FIAP): Domain Driven Design, Arquitetura Hexagonal, Qualidade de Software, Desenvolvimento Seguro e Documentação de Arquitetura. O código é original, escrito para praticar os conceitos; não é material do curso. As notas de estudo ficam em pos-tech-software-architecture.

O que o lab mostra

Conceito Onde está no código Nota
Objeto de Valor Money, Quantity, OrderId, CustomerId: records imutáveis, iguais por valor, que se validam na criação Objeto de Valor
Entidade OrderItem (identidade dentro do pedido) e Product Entidade
Agregado Order é a raiz: itens só mudam por ela, e as regras valem sempre Agregado
Serviço de Domínio ProductOrderingService: a regra envolve dois agregados (Product e Order) Serviço de Domínio
Evento de Domínio OrderCreated, OrderPlaced, OrderCancelled, publicados depois de salvar Evento de Domínio
Repositório OrderRepository e ProductRepository são do domínio; a implementação JPA é um adaptador Camadas do DDD
Portas e Adaptadores portas de entrada em application.port.in, de saída em application.port.out e nos repositórios; adaptadores em adapter.in.web e adapter.out Arquitetura Hexagonal
Inversão de Controle domínio e aplicação não usam Spring; config.UseCaseConfig liga as implementações ARQ 05
Contexto Delimitado um contexto (Vendas); Product ficaria num contexto de Catálogo num sistema real Contexto Delimitado

Arquitetura

flowchart LR
    client([Cliente HTTP]) --> web

    subgraph adapter_in [Adaptador de entrada]
        web[OrderController / ProductController]
    end

    subgraph application [Aplicação]
        ports_in{{Portas de entrada<br/>CreateOrder, PlaceOrder...}}
        services[OrderApplicationService<br/>CatalogApplicationService]
        port_events{{DomainEventPublisher}}
    end

    subgraph domain [Domínio]
        order[Order + OrderItem]
        product[Product]
        ordering[ProductOrderingService]
        repos{{OrderRepository<br/>ProductRepository}}
    end

    subgraph adapter_out [Adaptadores de saída]
        jpa[JPA + PostgreSQL]
        events[Eventos do Spring]
    end

    web --> ports_in --> services
    services --> order & product & ordering
    services --> repos
    services --> port_events
    jpa -. implementa .-> repos
    events -. implementa .-> port_events
Loading

Os diagramas C4 (contexto, contêineres, componentes e implantação) estão em docs/c4. As dependências apontam sempre para o centro. O teste HexagonalArchitectureTest (ArchUnit) quebra o build se o domínio ou a aplicação passarem a depender de Spring, JPA ou de um adaptador.

src/main/java/io/github/geancgbr/orders
├── domain
│   ├── shared        Money, Quantity, DomainEvent, DomainException
│   ├── order         Order, OrderItem, eventos, OrderRepository, ProductOrderingService
│   └── product       Product, ProductRepository
├── application
│   ├── port/in       casos de uso
│   ├── port/out      DomainEventPublisher
│   └── service       OrderApplicationService, CatalogApplicationService
├── adapter
│   ├── in/web        REST e tratamento de erros (Problem Details)
│   └── out           persistence (JPA) e events (Spring)
└── config            ligação das portas com as implementações

Regras de negócio

  • Um pedido nasce como rascunho (DRAFT), é fechado (PLACED) ou cancelado (CANCELLED).
  • Só um rascunho aceita itens; no máximo 10 produtos diferentes por pedido.
  • Adicionar o mesmo produto de novo soma a quantidade e mantém o preço do primeiro registro.
  • Quantidade entre 1 e 99; valores monetários não podem ser negativos.
  • Produto inativo não entra no pedido.
  • Pedido sem itens não pode ser fechado; cancelamento exige motivo e acontece uma vez.
  • Cupom: um por pedido, só em rascunho com itens, de 1% a 50% sobre o subtotal, arredondado em centavos. Cupons válidos: BEMVINDO10 e BLACKFRIDAY25.

Violação de regra vira 422 com a mensagem do domínio; recurso inexistente vira 404.

Qualidade de Software

Aula Onde está no projeto
QS 01 – Principais conceitos Caixa branca: OrderAddItemWhiteBoxTest (um teste por caminho do código) e InputValidationWhiteBoxTest, com cobertura de ramos medida pelo JaCoCo; o build exige 90% de ramos cobertos no domínio. Caixa preta: OrderApiBlackBoxTest, só entradas e saídas HTTP, com valores-limite de quantidade (0, 1, 99, 100)
QS 02 – Testes de unidade Testes do domínio em JUnit 5 + AssertJ, isolados e rápidos, no formato Arrange / Act / Assert. A aula usa NUnit, xUnit e MSTest (.NET); @Test equivale a [Test] / [Fact] / [TestMethod]
QS 03 – TDD O cupom de desconto foi feito em três ciclos Red-Green-Refactor. Cada etapa é um commit marcado com [TDD vermelho], [TDD verde] ou [TDD refatoração] no histórico
QS 04 – Testes de integração Ambiente semelhante ao de produção com Testcontainers (PostgreSQL real). Bottom-up: JpaOrderRepositoryAdapterTest testa o adaptador de persistência sozinho; depois a API inteira em OrderApiBlackBoxTest. Os testes de aplicação usam adaptadores falsos em memória (support/InMemoryAdapters)
QS 05 – BDD Cenários em Gherkin em português (src/test/resources/features), executados com Cucumber: especificação viva na linguagem ubíqua. Relatório em target/cucumber/relatorio.html
QS 06 – Testes de carga k6 com o fluxo de compra completo: load-tests/carga.js (uso esperado, p95 < 300 ms e menos de 1% de erros) e load-tests/estresse.js (até 500 usuários virtuais, para achar o ponto de degradação)
make test       # 75 testes + formatação, cobertura e análise estática
make coverage   # abre o relatório de cobertura do JaCoCo
make up         # sobe a aplicação
make load       # teste de carga com k6 (roda em container)
make stress     # teste de estresse com k6

Desenvolvimento Seguro

Aula Onde está no projeto
DS 01 – Security by Design Validação de entrada por lista de caracteres permitidos (InputRules) e limites de tamanho. Menor privilégio: a aplicação usa o usuário orders_app, que só lê e grava dados; quem cria e altera tabelas é orders_owner, só nas migrações (db/init/01-roles.sql, conferido por make privileges); o container roda sem root. Segmentação de rede: o PostgreSQL fica numa rede interna, sem porta exposta. Teste de segurança contínuo: SecurityBlackBoxTest e SpotBugs rodam em todo build
DS 02 – Buffer overflow, XSS e SQL Injection SQL Injection: a busca GET /products?name= usa consulta parametrizada (Spring Data); o teste envia ' OR '1'='1, DROP TABLE e UNION SELECT e confirma que viram texto comum. XSS: HTML e script no nome são recusados com 400 sem devolver o conteúdo enviado; a API só responde JSON, com Content-Security-Policy: default-src 'none' e X-Content-Type-Options: nosniff. Buffer overflow: a JVM checa os limites de memória; os campos ainda têm tamanho máximo
DS 03 – Bibliotecas de software SBOM no formato CycloneDX (make sbom, gera target/bom.json). Vulnerabilidades: make deps varre o SBOM com Trivy e falha se houver HIGH ou CRITICAL (resultado: 0). Licenças: make licenses; das 99 dependências, o Trivy aponta como restritas o Logback (LGPL-2.1) e duas APIs Jakarta (GPL-2.0 com classpath exception). As duas têm licença dupla, com EPL como alternativa, e a exceção de classpath permite usar a biblioteca sem que a GPL alcance o projeto
DS 04 – Análise estática de código SpotBugs + FindSecBugs no make test. Achados tratados: CT_CONSTRUCTOR_THROW (corrigido: classes do domínio final), SPRING_CSRF_PROTECTION_DISABLED e EI_EXPOSE_REP2 (aceitos com justificativa, em spotbugs-exclude.xml). SonarQube com make sonar: Quality Gate aprovado, nota A em segurança, confiabilidade e manutenibilidade, 0 bugs, 0 vulnerabilidades, 0 code smells, 93,5% de cobertura
DS 05 – OWASP e OWASP Top 10 DAST com OWASP ZAP sobre a especificação OpenAPI da API (make dast, relatório em target/zap/zap-relatorio.html). O SBOM do make sbom pode ser importado no OWASP Dependency-Track. Mapa do Top 10 abaixo
DS 06 – Padrões de segurança As normas (ISO 27001/27002, NIST 800-53, PCI DSS, CIS) tratam da organização e da infraestrutura. No código, aparecem os controles que elas pedem: controle de acesso por menor privilégio, gestão de vulnerabilidades em componentes e testes de segurança no ciclo de desenvolvimento

O que o ZAP encontrou na primeira varredura (119 verificações aprovadas, 0 falhas, 2 alertas), todos corrigidos:

Alerta Causa Correção
Erro 500 em GET /products?name=%00 O byte nulo chegava ao PostgreSQL, que rejeita o caractere O parâmetro de busca passou a ser validado com a lista de caracteres permitidos: agora responde 400
Erro 500 em GET /products?= O Tomcat rejeita parâmetro sem nome e o tratamento genérico devolvia 500 InvalidParameterException tratada como 400
Falta o cabeçalho Cross-Origin-Resource-Policy Não estava configurado Cross-Origin-Resource-Policy: same-origin

Nenhum teste automatizado tinha pegado os dois erros 500. É o tipo de achado que justifica o teste dinâmico além do estático. Os casos viraram testes em SecurityBlackBoxTest. Na varredura seguinte, o ZAP aprovou as 120 verificações, com 0 alertas.

Por que o CSRF está desligado: a API é stateless, não usa sessão nem cookie, e o CSRF só explora autenticação feita por cookie do navegador. A decisão está registrada no código (@SuppressWarnings("java:S4502")) e no filtro do SpotBugs.

OWASP Top 10 (2021)

Categoria Situação no lab
A01 Broken Access Control ⚠️ Fora do escopo: a API não tem autenticação. Seria o próximo passo (OAuth2/JWT)
A02 Cryptographic Failures ⚠️ Fora do escopo: não há dado sensível; TLS ficaria no proxy de entrada
A03 Injection ✅ Consulta parametrizada, validação de entrada e testes com payloads de SQL Injection e XSS
A04 Insecure Design ✅ Regras de negócio protegidas no agregado (invariantes) e testadas
A05 Security Misconfiguration ✅ Cabeçalhos de segurança, Actuator só com health e info, sem usuário padrão, erros sem stack trace
A06 Vulnerable and Outdated Components ✅ SBOM, Trivy e versões atuais de todas as dependências
A07 Identification and Authentication Failures ⚠️ Fora do escopo (sem autenticação)
A08 Software and Data Integrity Failures ➖ Parcial: o SBOM lista os componentes; não há assinatura de artefatos
A09 Security Logging and Monitoring Failures ✅ Erros inesperados registrados no log sem expor detalhes ao cliente; eventos de domínio registrados
A10 Server-Side Request Forgery ➖ Não se aplica: a API não busca URLs externas
make privileges   # prova o menor privilégio do usuário da aplicação no banco
make deps         # vulnerabilidades nas dependências (Trivy)
make licenses     # licenças das dependências
make sonar        # SonarQube em http://localhost:9000 (admin/admin)
make dast         # OWASP ZAP contra a API em execução

Documentação de Arquitetura

Aula Onde está no projeto
DOC 01 – Introdução Os tipos de documento da aula, todos presentes em docs/: requisitos, HLD, LLD, C4, diagramas de sequência, de classes e de componentes, modelo de dados, documentação de API, manual de instalação, plano de testes, ADRs e DAS. Automação, como a aula recomenda: o contrato da API é gerado pelo springdoc (Swagger/OpenAPI) e os diagramas C4 são gerados por script
DOC 02 – HLD e LLD HLD: visão geral, diagramas de contexto e de contêineres, componentes e requisitos de alto nível, sem detalhe de implementação. LLD: diagrama de classes, máquina de estados do pedido, assinatura de cada porta, algoritmo dos totais, fluxograma do cupom, diagramas de sequência, mapa de erros e mapeamento para o banco
DOC 03 – C4 Model Modelo C4 em Structurizr DSL: um só arquivo gera Contexto, Contêineres, Componentes, a visão dinâmica de aplicar cupom e a de Implantação. O nível de Código, opcional, é o diagrama de classes do LLD. make c4 valida e regenera as imagens; make c4-local abre o modelo no navegador
DOC 04 – Requisitos 10 requisitos funcionais e 11 não funcionais, com prioridade, métrica e rastreabilidade: cada um aponta para o teste ou a ferramenta que o comprova, e os não funcionais trazem o resultado medido (p95, vulnerabilidades, cobertura). O que ficou fora do escopo também está registrado
DOC 05 – ADRs 10 ADRs com contexto, decisão, alternativas e consequências: arquitetura hexagonal, PostgreSQL com Flyway, eventos em processo, cupons em memória, Testcontainers, menor privilégio, CSRF desligado, documentação como código. A ADR-0009 (OAuth2/JWT) está como Proposta, para mostrar o ciclo de vida
DOC 06 – DAS DAS com os 11 elementos da aula: identificação, contexto, requisitos, diagramas, ADRs, plano de testes e monitoramento, modelo de dados (diagrama ER), documentação de API com exemplos reais, instalação por ambiente, continuidade e backup (make backup / make restore, testados) e segurança e compliance (inclui LGPD). Registra também a aprovação e os riscos aceitos

A documentação também é verificada no build. OpenApiContractTest compara o contrato versionado em docs/api/openapi.json com o que a aplicação publica e falha se houver diferença. Para gerar o contrato com os status certos (201, 204, 400, 404, 422, 500), os endpoints e o tratamento de erros passaram a declarar @ResponseStatus. make docs-check renderiza todos os diagramas Mermaid para pegar erro de sintaxe.

Componentes

make c4           # valida o modelo C4 e regenera os diagramas
make c4-local     # Structurizr em http://localhost:8081
make openapi      # atualiza o contrato OpenAPI versionado
make docs-check   # confere a sintaxe dos diagramas Mermaid
make backup       # pg_dump do banco em backups/
make restore      # restaura o backup mais recente (ou FILE=...)

Como rodar

Pré-requisitos: Docker e JDK 25.

make up      # sobe PostgreSQL e a aplicação em http://localhost:8080
make demo    # roteiro completo: catálogo, pedido, regras violadas e eventos
make down    # derruba tudo e apaga os dados

API

Contrato completo em docs/api/openapi.json e, com a aplicação de pé, em http://localhost:8080/v3/api-docs.

Método Caminho Corpo
POST /products {"name": "Teclado", "price": 349.90}
GET /products?name= busca opcional por nome
POST /products/{id}/deactivate
POST /orders {"customerId": "cliente-42"}
GET /orders/{id}
POST /orders/{id}/items {"productId": "...", "quantity": 2}
POST /orders/{id}/coupon {"code": "BEMVINDO10"}
POST /orders/{id}/place
POST /orders/{id}/cancel {"reason": "cliente desistiu"}

Stack

Java 25 · Spring Boot 4.1 · Spring Data JPA · PostgreSQL 18 · Flyway · JUnit 5 · AssertJ · ArchUnit · Testcontainers · Cucumber · JaCoCo · k6 · Spring Security · SpotBugs + FindSecBugs · SonarQube · OWASP ZAP · CycloneDX · Trivy · springdoc-openapi · Structurizr · Mermaid · Spotless (palantir-java-format) · Docker Compose

About

DDD tático e Arquitetura Hexagonal numa API de pedidos (Java 25, Spring Boot 4): testes, desenvolvimento seguro (OWASP, SAST, DAST, SBOM) e documentação de arquitetura (C4, ADR, DAS)

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages