API de vendas construída para o teste técnico da DeveloperStore, com foco em robustez, DDD, validação semântica, contratos HTTP consistentes e modelagem inspirada em Domain Modeling Made Functional.
Repositório público: https://github.com/JailtonJunior94/DeveloperStore
Foi implementada uma API completa para gerenciamento de vendas, cobrindo:
- criação de venda
- consulta de venda por id
- listagem paginada com filtros e ordenação
- atualização de venda
- cancelamento lógico de venda
- cancelamento de item de venda
- publicação de eventos de domínio via log
Cada venda armazena:
- número da venda
- data da venda
- cliente
- filial
- itens vendidos
- quantidade por item
- preço unitário
- desconto aplicado
- total por item
- total consolidado da venda
- status da venda
O escopo implementado neste repositório é Sales API.
Isso significa que a solução entregue cobre o domínio de vendas e suas evidências técnicas correspondentes:
- domínio de vendas
- endpoints de vendas
- persistência de vendas
- testes de vendas
Arquivos em .doc que descrevem auth, users, products e carts devem ser lidos como documentação de referência mais ampla da plataforma, não como prova automática de que esses módulos existem neste repositório.
Neste projeto, uma afirmação de prontidão só é considerada válida quando existe evidência objetiva executada sobre o estado atual do código.
Na prática, isso significa:
- build limpo
- testes relevantes verdes
- prova em PostgreSQL real para comportamento sensível a persistência
- documentação coerente com o comportamento efetivamente implementado
Teste em memória ajuda, mas não é prova suficiente para consultas, ordenação, filtros, tradução de LINQ, constraints ou migrations.
Este projeto foi desenhado para demonstrar:
- domínio explícito e semântico, evitando obsessão por tipos primitivos no núcleo do negócio
- separação clara entre
Domain,Application,ORM,IoC,CommoneWebApi - validação fail-fast com retorno de lista semântica de erros para o cliente
- regras de desconto implementadas no domínio, não espalhadas em controllers ou infraestrutura
- aderência forte a testes automatizados em múltiplos níveis
- prova real com PostgreSQL, e não apenas testes em memória
.NET 10C# 14ASP.NET Core Web APIMediatRFluentValidationEntity Framework CorePostgreSQLxUnitFluentAssertionsNSubstituteSerilog
graph TD
%% Layers
WebApi["DeveloperStore.WebApi (Presentation)"]
Application["DeveloperStore.Application (Use Cases)"]
Domain["DeveloperStore.Domain (Core Business Rules)"]
ORM["DeveloperStore.ORM (Infrastructure / Persistence)"]
IoC["DeveloperStore.IoC (Dependency Injection Composition)"]
Common["DeveloperStore.Common (Cross-Cutting Concerns)"]
%% Dependency Flow
WebApi --> Application
Application --> Domain
ORM --> Domain
IoC --> WebApi
IoC --> Application
IoC --> ORM
IoC --> Domain
Common -.-> WebApi
Common -.-> Application
Common -.-> ORM
Common -.-> Domain
%% Styling
classDef core fill:#a5d6a7,stroke:#2e7d32,stroke-width:2px;
classDef app fill:#90caf9,stroke:#1565c0,stroke-width:2px;
classDef infra fill:#ffe082,stroke:#ff8f00,stroke-width:2px;
classDef presentation fill:#ef9a9a,stroke:#c62828,stroke-width:2px;
classDef cross fill:#b0bec5,stroke:#37474f,stroke-width:1px,stroke-dasharray: 5 5;
class Domain core;
class Application app;
class ORM,IoC infra;
class WebApi presentation;
class Common cross;
.
├── src
│ ├── DeveloperStore.Domain
│ ├── DeveloperStore.Application
│ ├── DeveloperStore.ORM
│ ├── DeveloperStore.IoC
│ ├── DeveloperStore.Common
│ └── DeveloperStore.WebApi
├── tests
│ ├── DeveloperStore.Unit
│ ├── DeveloperStore.Integration
│ ├── DeveloperStore.Functional
│ └── DeveloperStore.Postgres
├── scripts
└── README.md
DeveloperStore.Domain: regras de negócio, aggregateSale, entidades, value objects, eventos e exceções de domínio.DeveloperStore.Application: comandos, queries, handlers, DTOs e validações de aplicação.DeveloperStore.ORM:DbContext, mappings e implementação do repositório.DeveloperStore.IoC: composição das dependências.DeveloperStore.Common: validação, logging e health checks.DeveloperStore.WebApi: controllers, middleware, contrato HTTP e bootstrap da API.
O agregado principal é Sale.
Conceitos semânticos importantes foram modelados com tipos dedicados, por exemplo:
SaleIdSaleItemIdSaleNumberSoldAtMoneyItemQuantityDiscountRateCustomerReferenceBranchReferenceProductReference
Essa modelagem reduz ambiguidade e concentra invariantes no lugar correto.
- compras com
1a3unidades idênticas recebem0%de desconto - compras com
4a9unidades idênticas recebem10%de desconto - compras com
10a20unidades idênticas recebem20%de desconto - não é permitido vender mais de
20unidades do mesmo produto - vendas canceladas não podem ser alteradas
- cancelamento de venda cancela logicamente todos os itens
- cancelamento de item recalcula o total da venda
Os eventos são publicados in-process e registrados em log:
SaleCreatedSaleModifiedSaleCancelledItemCancelled
POST /api/salesGET /api/sales/{id}GET /api/salesPUT /api/sales/{id}DELETE /api/sales/{id}POST /api/sales/{saleId}/items/{itemId}/cancel
_page: padrão1_size: padrão10
Campos suportados em _order:
saleNumbersoldAtcustomerNamebranchNametotalAmountstatusitemCount
Exemplo:
GET /api/sales?_page=1&_size=10&_order=soldAt desc, saleNumber ascsaleNumbercustomerNamebranchNamestatus_minSoldAt_maxSoldAt
Compatibilidade temporária:
customercontinua aceito como alias legado decustomerNamebranchcontinua aceito como alias legado debranchName
saleNumber=SALE-123: match exatosaleNumber=SALE*: prefixocustomerName=*Silva: sufixobranchName=*Center*: contains
A API retorna erros semânticos com lista de detalhes para facilitar tratamento no cliente.
Exemplo:
{
"type": "validation_failed",
"error": "Request validation failed",
"detail": "One or more request values are invalid.",
"status": 422,
"traceId": "00-...",
"errors": [
{
"code": "sale_number_required",
"field": "SaleNumber",
"message": "saleNumber is required"
}
]
}.NET SDK 10DockerDocker Compose v2GNU Make
| Modo | Quando usar | Comando |
|---|---|---|
| Stack completa no Docker | Demo, CI, revisão técnica | make docker-up-build |
| Somente infra + debug VS Code | Desenvolvimento ativo, breakpoints | make infra-up → F5 no VS Code |
Sobe API + PostgreSQL em containers. Migrations aplicadas automaticamente no startup.
make docker-up-buildAcesse:
- API:
http://localhost:8080 - Swagger:
http://localhost:8080/swagger - Health:
http://localhost:8080/health
Para acompanhar logs:
make docker-logsPara derrubar:
make docker-downPara derrubar e remover o volume do banco:
make docker-down-volumesSobe apenas o PostgreSQL em container e roda a API localmente via debugger.
Passo 1: Suba somente a infra.
make infra-upPasso 2: Abra o projeto no VS Code e pressione F5.
O launch config DeveloperStore.WebApi (.vscode/launch.json) executa automaticamente:
infra:up— garante que o PostgreSQL está no arbuild— compila a solução- Lança a API em modo debug conectada a
localhost:5432
A connection string já está pré-configurada no launch config:
Host=localhost;Port=5432;Database=developerstore;Username=developerstore_app;Password=developerstore_local_only
Alternativa com hot reload (watch):
Selecione a config DeveloperStore.WebApi (watch) no picker do VS Code. Ela sobe a infra e lança a API com recompilação automática a cada mudança, sem rebuildar manualmente.
Tasks disponíveis no VS Code (via Terminal > Run Task...):
| Task | Ação |
|---|---|
infra:up |
Sobe PostgreSQL |
infra:down |
Derruba tudo |
infra:logs |
Acompanha logs do banco |
docker:up |
Sobe stack completa |
docker:down |
Derruba stack completa |
build |
Compila a solução |
migrate |
Aplica migrations |
test:unit |
Testes unitários |
test:integration |
Testes de integração |
test:functional |
Testes funcionais |
test:bdd |
Suíte BDD com Testcontainers |
test:postgres |
Validação em PostgreSQL real |
O Makefile é a forma principal de operar o projeto. Ele centraliza os comandos úteis de build, execução, testes, Docker e migrations.
Instalação e uso por sistema operacional:
macOS: o mais comum é já termakecomXcode Command Line Tools. Se faltar, rodexcode-select --install.Linux: instalemakepelo gerenciador da sua distro, por exemplosudo apt-get install make,sudo dnf install makeousudo pacman -S make.Windows: o fluxo recomendado é executar o projeto emWSLouGit Bash, porque esteMakefileusabash. Em shell nativoPowerShelloucmd.exe, prefira os comandos diretos.NETedocker composese não tivermakecompatível instalado.
Primeiro passo em qualquer ambiente:
make helpFluxo mais comum para trabalhar no projeto:
make restore
make build
make test
make runFluxo completo com Docker:
make docker-up-buildValidação mais forte do repositório:
make verify
make verify-fullmake help: lista todos os alvos disponíveis.make doctor: mostra versões locais dedotnet,dockeredocker compose.make restore: restaura pacotes NuGet e a tool localdotnet-ef.make build: compila a solução.make run: sobe a API localmente.make watch: sobe a API com hot reload.make format: formata a solução.make format-check: valida formatação sem alterar arquivos.make test: rodaUnit,IntegrationeFunctional.make test-bdd: roda a suíte BDD comTestcontainers.make test-postgres: sobe PostgreSQL via Docker Compose e roda a suíte dedicada ao provider real.make coverage: coleta cobertura das suítes locais rápidas.make verify: executaformat-check,buildetest.make verify-full: executaverifye adicionaBDD+PostgreSQL real.make publish: publica a API emartifacts/publish.make docker-up: sobe a stack atual em background.make docker-up-build: reconstrói a imagem e sobe a stack em background.make docker-down: derruba a stack sem apagar volume.make docker-down-volumes: derruba a stack e remove o volume nomeado do PostgreSQL.make docker-logs: acompanha logs da stack.make docker-ps: mostra status dos serviços.make db-up: sobe apenas o PostgreSQL.make db-logs: acompanha logs do PostgreSQL.make db-shell: abrepsqldentro do container do PostgreSQL.make migrate: aplica migrations pendentes no banco configurado.make migrate-list: lista migrations conhecidas pelo EF Core; com banco configurado, também tenta informar status aplicado ou pendente.make migrate-add NAME=NomeDaMigration: cria uma nova migration.make migrate-remove: remove a última migration ainda não aplicada.make migrate-script: gera script SQL idempotente emartifacts/migrations/idempotent.sql.
make docker-up-build- API:
http://localhost:8080 - Swagger:
http://localhost:8080/swagger - Health:
http://localhost:8080/health
make docker-downSe quiser apagar também o volume do PostgreSQL:
make docker-down-volumesNo ambiente Docker, as migrations são aplicadas no startup porque Database__ApplyMigrationsOnStartup=true está configurado no compose.
Você precisa de uma instância acessível localmente.
Exemplo:
export ConnectionStrings__DefaultConnection="Host=localhost;Port=5432;Database=developerstore;Username=developerstore_app;Password=developerstore_local_only"make migratePor padrão, a API não aplica migrations automaticamente.
Para habilitar:
export Database__ApplyMigrationsOnStartup=truemake runSe preferir operar sem make, estes são os equivalentes diretos mais úteis.
docker compose up -d --build
docker compose down --remove-orphans
docker compose down --volumes --remove-orphans
docker compose logs -f
docker compose up -d developerstore.dbdotnet tool restore
dotnet restore DeveloperStore.slnx
dotnet build DeveloperStore.slnx
dotnet run --project src/DeveloperStore.WebApi/DeveloperStore.WebApi.csproj
dotnet watch --project src/DeveloperStore.WebApi/DeveloperStore.WebApi.csproj run
dotnet format DeveloperStore.slnx --verify-no-changesPara migrate-list, migrate e comandos que precisem verificar o estado aplicado no banco, configure uma ConnectionStrings__DefaultConnection válida antes de executar.
dotnet tool run dotnet-ef migrations list \
--project src/DeveloperStore.ORM/DeveloperStore.ORM.csproj \
--startup-project src/DeveloperStore.WebApi/DeveloperStore.WebApi.csproj
dotnet tool run dotnet-ef database update \
--project src/DeveloperStore.ORM/DeveloperStore.ORM.csproj \
--startup-project src/DeveloperStore.WebApi/DeveloperStore.WebApi.csproj
dotnet tool run dotnet-ef migrations add NomeDaMigration \
--project src/DeveloperStore.ORM/DeveloperStore.ORM.csproj \
--startup-project src/DeveloperStore.WebApi/DeveloperStore.WebApi.csprojValidam regras de domínio e handlers isolados.
make test-unitValidam o repositório e consultas em nível de infraestrutura.
make test-integrationValidam o contrato HTTP da API.
make test-functionalmake testSobe um PostgreSQL via Docker, aplica migrations e roda a suíte dedicada ao banco real.
make test-postgresmake test-bddmake format-check- regras de desconto
- limite máximo de
20unidades por produto - cálculo de total por item e total da venda
- validação semântica com payload de erro estruturado
- persistência real em PostgreSQL
- listagem com paginação, ordenação e filtros
- cancelamento de venda e cancelamento de item
As seguintes validações são as evidências principais de que a solução está operacional no escopo de sales:
make build
make test
make test-bdd
make test-postgres
make format-check{
"saleNumber": "SALE-301",
"soldAt": "2026-06-23T12:00:00Z",
"customerExternalId": "customer-1",
"customerName": "Jane Doe",
"branchExternalId": "branch-1",
"branchName": "Central",
"items": [
{
"productExternalId": "product-1",
"productName": "Product 1",
"quantity": 4,
"unitPrice": 10.0
}
]
}GET /health/liveGET /health/readyGET /health
- o projeto foi conduzido com foco em
Sales API - o domínio foi priorizado sobre conveniência de ORM
- há validação semântica em borda e invariantes no núcleo do domínio
- a solução possui evidência automatizada em memória e em banco real
- a documentação foi atualizada para refletir o comportamento efetivamente implementado
- aderência literal a toda a pasta
.docnão deve ser inferida sem confronto específico com cada contrato e com o escopo material deste repositório