Skip to content

Commit feff5ed

Browse files
committed
feat: Ajuste da configuração do Kafka e rotas internas dos serviços
- Inclusão dos fatores de replicação dos tópicos internos do Kafka no docker-compose.yml para funcionar corretamente com um único broker. - Atualização do README.md com as mudanças de arquitetura e responsabilidades dos serviços. - Alteração dos appsettings.json para incluir nova rota interna do serviço de Clientes. - Refatoração dos serviços Admin e Clientes para melhorar tratamento de erros e mensagens de resposta. - Ajuste do serviço MotorCompra para retornar resultados de execução com resíduos. - Atualização dos testes para cobrir os novos cenários e garantir robustez.
1 parent 91ea129 commit feff5ed

File tree

51 files changed

+445
-474
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+445
-474
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ jobs:
8282
--logger "trx;LogFileName=test-results.trx" \
8383
--collect:"XPlat Code Coverage" \
8484
--results-directory ./TestResults \
85-
--settings tests/CompraProgramada.Tests/runsettings
85+
--settings tests/CompraProgramada.Tests/coverlet.runsettings
8686
8787
- name: Install ReportGenerator
8888
run: dotnet tool install -g dotnet-reportgenerator-globaltool

README.md

Lines changed: 31 additions & 214 deletions
Original file line numberDiff line numberDiff line change
@@ -1,250 +1,67 @@
1-
# Sistema de Compra Programada de Ações
1+
# Compra Programada – Itaú Corretora
22

3-
**Itaú Corretora** – Desafio Técnico | Arquitetura **Microsserviços**
3+
Sistema de compra programada (carteira Top Five) em **.NET 9**, **MySQL**, **Kafka**, integração **COTAHIST B3**.
44

5-
---
6-
7-
## Visão Geral
8-
9-
Sistema de compra programada que permite aos clientes aderir a um plano de investimento recorrente na carteira **Top Five** (5 ações recomendadas). Desenvolvido em **.NET 9**, **MySQL**, **Apache Kafka**, com integração ao arquivo **COTAHIST da B3**.
10-
11-
---
12-
13-
## Arquitetura Microsserviços
14-
15-
```
16-
┌─────────────────────────────────────────────────────────┐
17-
│ API GATEWAY (YARP) │
18-
│ http://localhost:5000 │
19-
└───────────────────────────┬─────────────────────────────┘
20-
21-
┌───────────────────┬───────────────────┼───────────────────┬───────────────────┐
22-
│ │ │ │ │
23-
▼ ▼ ▼ ▼ ▼
24-
┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐
25-
│ Clientes │ │ Admin │ │ Cotação │ │ Motor Compra │ │ Rebalanceamento│
26-
│ Service │ │ Service │ │ Service │ │ Service │ │ Service │
27-
│ :5001 │ │ :5002 │ │ :5003 │ │ :5004 │ │ :5005 │
28-
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘
29-
│ │ │ │ │
30-
│ │ │ │ │
31-
▼ ▼ ▼ ▼ ▼
32-
[MySQL] [MySQL] [MySQL] [MySQL] [MySQL]
33-
clientes_db admin_db CotacaoDb motor_db rebalanceamento_db
34-
│ │ │ │ │
35-
└──────────────────┴──────────────────┴──────────────────┴──────────────────┘
36-
37-
38-
┌─────────────┐
39-
│ Kafka │
40-
│ :9092 │
41-
│ ir-dedo-duro│
42-
└─────────────┘
43-
```
44-
45-
### Responsabilidade dos Serviços
46-
47-
| Serviço | Responsabilidade | API Base |
48-
|---------|------------------|----------|
49-
| **ApiGateway** | Roteamento reverso (YARP), único ponto de entrada | `/` |
50-
| **Clientes.Service** | Adesão, saída, alterar valor mensal, consultar carteira, rentabilidade | `/api/clientes` |
51-
| **Admin.Service** | Cesta Top Five (CRUD), histórico, custódia master | `/api/admin` |
52-
| **Cotacao.Service** | Leitura/parse COTAHIST B3, cache de cotações, fechamento por ticker | `/api/cotacoes` |
53-
| **MotorCompra.Service** | Execução da compra programada (dias 5, 15, 25), distribuição, ordens | `/api/motor` |
54-
| **MotorCompra.Worker** | Job em background que dispara a compra nas datas configuradas ||
55-
| **Rebalanceamento.Service** | Rebalanceamento por mudança de cesta ou desvio de proporção | `/api/rebalanceamento` |
56-
57-
### Comunicação
5+
## Arquitetura
586

59-
- **Síncrona:** Cliente → Gateway → Serviços via HTTP/REST.
60-
- **Assíncrona:** MotorCompra e Rebalanceamento publicam eventos de **IR** no **Kafka** (tópico `ir-dedo-duro`).
7+
- **ApiGateway (YARP)**`:5000` – roteamento reverso
8+
- **Clientes.Service**`:5001` – adesão, saída, valor mensal, carteira, rentabilidade
9+
- **Admin.Service**`:5002` – cesta Top Five, histórico, custódia master
10+
- **Cotacao.Service**`:5003` – COTAHIST, fechamento por ticker
11+
- **MotorCompra.Service**`:5004` – execução compra (dias 5, 15, 25), distribuição
12+
- **Rebalanceamento.Service**`:5005` – rebalanceamento por mudança de cesta ou desvio
13+
- **MotorCompra.Worker** – job em background (datas de execução)
14+
- **Kafka**`:9092` – eventos IR (`ir-dedo-duro`, `ir-operacoes`)
6115

62-
### Banco de Dados (MySQL)
63-
64-
Cada microsserviço pode usar um **database próprio** na mesma instância MySQL (ou instâncias separadas):
65-
66-
- `clientes_db` – Clientes, ContasGraficas, Custodias (filhote)
67-
- `admin_db` – CestasRecomendacao, ItensCesta
68-
- `CotacaoDb` – Cache de cotações (COTAHIST)
69-
- `motor_db` – OrdensCompra, Distribuicoes, ContaMaster, CustodiaMaster, ExecucaoCompras
70-
- `rebalanceamento_db` – Rebalanceamentos, eventos de venda
71-
72-
---
16+
Cada serviço pode usar DB próprio no MySQL: `clientes_db`, `admin_db`, `CotacaoDb`, `motor_db`, `rebalanceamento_db`.
7317

74-
## Estrutura do Projeto
18+
## Estrutura
7519

7620
```
77-
/
78-
├── src/
79-
│ ├── ApiGateway/ # YARP reverse proxy :5000
80-
│ ├── Shared/
81-
│ │ ├── Shared.Contracts/ # DTOs, eventos (Adesao, Cesta, EventoIR)
82-
│ │ └── Shared.Kafka/ # IEventoIRPublisher, Kafka producer
83-
│ └── Services/
84-
│ ├── Clientes.Service/ # API clientes :5001
85-
│ ├── Admin.Service/ # API admin :5002
86-
│ ├── Cotacao.Service/ # API cotações + parser COTAHIST :5003
87-
│ ├── MotorCompra.Service/ # API motor + orquestração :5004
88-
│ ├── MotorCompra.Worker/ # Background job dias 5/15/25
89-
│ └── Rebalanceamento.Service/# API rebalanceamento :5005
90-
├── cotacoes/ # Pasta padrão para COTAHIST (configurável no Cotacao.Service)
91-
├── tests/ # Testes unitários e integração
92-
├── Docs/ # Documentação do desafio
93-
├── docker-compose.yml # MySQL + Kafka (+ Zookeeper)
94-
├── CompraProgramada.sln
95-
└── README.md
21+
src/
22+
├── ApiGateway/
23+
├── Shared/ (Shared.Contracts, Shared.Kafka)
24+
└── Services/ (Clientes, Admin, Cotacao, MotorCompra, MotorCompra.Worker, Rebalanceamento)
25+
cotacoes/ → arquivos COTAHIST (configurável)
26+
tests/ → CompraProgramada.Tests
27+
Docs/ → regras, contratos API, layout COTAHIST
9628
```
9729

98-
---
99-
100-
## Pré-requisitos
101-
102-
- .NET 9 SDK
103-
- Docker e Docker Compose (MySQL, Kafka)
104-
- Arquivos COTAHIST na pasta `cotacoes/` (download no site B3)
105-
106-
---
107-
108-
## Como Rodar
109-
110-
### 1. Subir infraestrutura
30+
## Rodar
11131

11232
```bash
11333
docker-compose up -d
114-
```
34+
# Criar DBs no MySQL (clientes_db, admin_db, CotacaoDb, motor_db, rebalanceamento_db)
11535

116-
Aguarde MySQL e Kafka estarem saudáveis.
117-
118-
### 2. Criar databases (se usar um único MySQL)
119-
120-
```bash
121-
docker exec -it compraprogramada-mysql mysql -uroot -proot -e "
122-
CREATE DATABASE IF NOT EXISTS clientes_db;
123-
CREATE DATABASE IF NOT EXISTS admin_db;
124-
CREATE DATABASE IF NOT EXISTS CotacaoDb;
125-
CREATE DATABASE IF NOT EXISTS motor_db;
126-
CREATE DATABASE IF NOT EXISTS rebalanceamento_db;
127-
"
128-
```
129-
130-
### 3. Restaurar dependências e rodar os serviços
131-
132-
Use a solution **CompraProgramada.sln**:
133-
134-
```bash
13536
dotnet restore CompraProgramada.sln
13637
dotnet build CompraProgramada.sln
13738
```
13839

139-
Em terminais separados (ou via IDE):
40+
Subir cada serviço (ou via IDE):
14041

14142
```bash
142-
# Terminal 1 – Gateway
14343
dotnet run --project src/ApiGateway
144-
145-
# Terminal 2 – Clientes
14644
dotnet run --project src/Services/Clientes.Service
147-
148-
# Terminal 3 – Admin
14945
dotnet run --project src/Services/Admin.Service
150-
151-
# Terminal 4 – Cotação
15246
dotnet run --project src/Services/Cotacao.Service
153-
154-
# Terminal 5 – Motor
15547
dotnet run --project src/Services/MotorCompra.Service
156-
157-
# Terminal 6 – Rebalanceamento
15848
dotnet run --project src/Services/Rebalanceamento.Service
159-
160-
# (Opcional) Worker do motor
161-
dotnet run --project src/Services/MotorCompra.Worker
49+
# opcional: dotnet run --project src/Services/MotorCompra.Worker
16250
```
16351

164-
### 4. Acessar
165-
166-
- **Gateway (todas as APIs):** http://localhost:5000
167-
- **Exemplos:**
168-
- `GET http://localhost:5000/api/clientes/1/carteira`
169-
- `GET http://localhost:5000/api/admin/cesta/atual`
170-
- `POST http://localhost:5000/api/motor/executar-compra`
171-
172-
Swagger/OpenAPI em cada serviço (quando habilitado) em `http://localhost:500X/swagger`.
173-
174-
---
175-
176-
## Decisões Técnicas
177-
178-
- **Gateway:** YARP para roteamento reverso leve e configurável.
179-
- **Microsserviços:** um serviço por bounded context (clientes, cesta, cotação, motor, rebalanceamento).
180-
- **Kafka:** um tópico para eventos de IR (dedo-duro e IR venda), consumível por sistemas fiscais.
181-
- **B3:** integração via arquivo COTAHIST (layout posicional 245 caracteres); parser no **Cotacao.Service**.
182-
- **Database:** MySQL por serviço (ou databases separados na mesma instância) para evolução independente.
183-
184-
---
52+
APIs via Gateway: `http://localhost:5000` (ex.: `GET /api/clientes/1/carteira`, `POST /api/motor/executar-compra`).
18553

18654
## CI/CD
18755

188-
O projeto inclui pipelines **GitHub Actions** para integração e entrega contínuas.
189-
190-
### CI (`.github/workflows/ci.yml`)
191-
192-
- **Trigger:** push e pull requests em `main`, `master`, `develop`.
193-
- **Jobs:**
194-
- **Build:** restore + build em Release.
195-
- **Test:** testes com xUnit, cobertura (Coverlet), relatório TRX e ReportGenerator; artefatos de cobertura e resultados de teste; report de testes em PRs.
196-
- **Format check:** `dotnet format --verify-no-changes`.
197-
- **Security:** listagem de pacotes vulneráveis (`dotnet list package --vulnerable`).
198-
- **Cache:** NuGet em `~/.nuget/packages` por hash dos `.csproj`.
199-
- **Cobertura:** mínimo de 70% (configurável por `MIN_COVERAGE`); relatório em HTML/Summary/Badges.
56+
- **ci.yml** – build, testes (xUnit + Coverlet), format check, segurança; cobertura mínima 70% (coverlet.runsettings).
57+
- **cd.yml** – build e push de imagens Docker para ghcr.io.
58+
- **security.yml** – CodeQL, dependency review.
59+
- **dependabot.yml** – atualizações NuGet e Actions.
20060

201-
### CD (`.github/workflows/cd.yml`)
61+
## Docs
20262

203-
- **Trigger:** push em `main`/`master`, tags `v*`, e `workflow_dispatch`.
204-
- **Jobs:** build e push de imagens Docker para **GitHub Container Registry** (`ghcr.io`):
205-
- `compraprogramada-api-gateway`
206-
- `compraprogramada-clientes`
207-
- `compraprogramada-admin`
208-
- `compraprogramada-cotacao`
209-
- `compraprogramada-motor`
210-
- `compraprogramada-motor-worker`
211-
- `compraprogramada-rebalanceamento`
212-
- **Versão:** tags `v*` ou `sha-<commit>`.
213-
- **Cache:** Docker layer cache (GitHub Actions cache).
214-
215-
### Security (`.github/workflows/security.yml`)
216-
217-
- **CodeQL:** análise estática em C# (push em `main`/`master`, PRs, agendamento semanal).
218-
- **Dependency review:** revisão de dependências em PRs.
219-
220-
### Dependabot (`.github/dependabot.yml`)
221-
222-
- Atualizações semanais (segunda-feira) para NuGet e GitHub Actions.
223-
- Agrupamento de pacotes Microsoft/xunit/coverlet; limite de 5 PRs abertos.
224-
225-
### Rodar localmente (equivalente ao CI)
226-
227-
```bash
228-
dotnet restore CompraProgramada.sln
229-
dotnet build CompraProgramada.sln -c Release
230-
dotnet test CompraProgramada.sln -c Release --collect:"XPlat Code Coverage" --results-directory ./TestResults
231-
```
63+
`Docs/` – desafio técnico, regras de negócio, layout COTAHIST, exemplos de contratos API.
23264

23365
---
23466

235-
## Documentação do Desafio
236-
237-
Regras de negócio, layout COTAHIST, contratos de API e diagramas estão em **Docs/**:
238-
239-
- `desafio-tecnico-compra-programada.md`
240-
- `regras-negocio-detalhadas.md`
241-
- `layout-cotahist-b3.md`
242-
- `exemplos-contratos-api.md`
243-
- `glossario-compra-programada.md`
244-
- Diagramas ER, sequência e negócios (drawio)
245-
246-
---
247-
248-
## Licença
249-
25067
Desafio técnico – Itaú Corretora.

docker-compose.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ services:
4141
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
4242
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
4343
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
44+
# Com apenas 1 broker, tópicos internos (ex.: __consumer_offsets) precisam de replication factor 1
45+
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
46+
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
4447
healthcheck:
4548
test: ["CMD", "kafka-broker-api-versions", "--bootstrap-server", "localhost:9092"]
4649
interval: 10s

src/ApiGateway/appsettings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
"Path": "/api/clientes/{**catch-all}"
1616
}
1717
},
18+
"clientes-internal-route": {
19+
"ClusterId": "clientes-cluster",
20+
"Match": {
21+
"Path": "/api/internal/clientes/{**catch-all}"
22+
}
23+
},
1824
"admin-route": {
1925
"ClusterId": "admin-cluster",
2026
"Match": {
Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
<Project Sdk="Microsoft.NET.Sdk.Web">
2-
3-
<PropertyGroup>
4-
<TargetFramework>net9.0</TargetFramework>
5-
<Nullable>enable</Nullable>
6-
<ImplicitUsings>enable</ImplicitUsings>
7-
<GenerateDocumentationFile>true</GenerateDocumentationFile>
8-
<NoWarn>$(NoWarn);1591</NoWarn>
9-
</PropertyGroup>
10-
11-
<ItemGroup>
12-
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.4" />
13-
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0">
14-
<PrivateAssets>all</PrivateAssets>
15-
</PackageReference>
16-
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="9.0.0" />
17-
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
18-
<ProjectReference Include="..\..\Shared\Shared.Contracts\Shared.Contracts.csproj" />
19-
</ItemGroup>
20-
21-
</Project>
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
8+
<NoWarn>$(NoWarn);1591</NoWarn>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.4" />
13+
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0">
14+
<PrivateAssets>all</PrivateAssets>
15+
</PackageReference>
16+
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="9.0.0" />
17+
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
18+
<ProjectReference Include="..\..\Shared\Shared.Contracts\Shared.Contracts.csproj" />
19+
</ItemGroup>
20+
21+
</Project>

src/Services/Admin.Service/Controllers/AdminController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public async Task<ActionResult<CestaResponseDto>> CadastrarCesta([FromBody] Cest
4646
public async Task<ActionResult<CestaResponseDto>> GetCestaAtual(CancellationToken ct = default)
4747
{
4848
var result = await _cestaService.GetAtualAsync(ct);
49-
if (result is null) return NotFound(new { codigo = "CESTA_NAO_ENCONTRADA", erro = "Nenhuma cesta cadastrada." });
49+
if (result is null) return NotFound(new { codigo = "CESTA_NAO_ENCONTRADA", erro = "Nenhuma cesta ativa encontrada." });
5050
return Ok(result);
5151
}
5252

0 commit comments

Comments
 (0)