API REST para gestão de seguros: segurados, apólices e o ciclo de vida completo de sinistros.
Sobre • Funcionalidades • Arquitetura • Tecnologias • Como executar • Endpoints • Testes • Licença
O PolicyDesk é uma API backend que modela o núcleo operacional de uma seguradora: o cadastro de segurados, a emissão e o cancelamento de apólices e o fluxo de sinistros, da abertura ao pagamento.
O projeto foi construído como peça de portfólio, com foco em qualidade de engenharia: regras de negócio protegidas no domínio, separação clara de responsabilidades, tratamento de erros padronizado, controle de concorrência, observabilidade de ponta a ponta e uma suíte de testes que cobre do domínio ao banco de dados real.
- Cadastro com validação de CPF, e-mail, telefone e data de nascimento
- Unicidade de CPF e e-mail entre segurados ativos
- Atualização de dados cadastrais
- Inativação (soft delete), bloqueada enquanto houver apólice vigente ou futura
- Emissão vinculada a um segurado ativo, com valor de cobertura, prêmio e período de vigência
- Listagem com filtros por segurado e status
- Cancelamento com registro da data
- Abertura validada contra a apólice: ela precisa estar ativa, a data da ocorrência precisa estar dentro da vigência e o valor não pode exceder a cobertura
- Fluxo de status controlado por uma máquina de estados no domínio:
stateDiagram-v2
direction LR
[*] --> Pendente: registrar
Pendente --> EmAnálise: iniciar análise
EmAnálise --> Aprovado: aprovar
EmAnálise --> Negado: negar (com motivo)
Aprovado --> Pago: registrar pagamento
Negado --> [*]
Pago --> [*]
Qualquer transição fora desse fluxo é recusada com uma mensagem de regra de negócio.
A solução segue os princípios da Clean Architecture: o domínio fica no centro, sem depender de frameworks, e as camadas externas dependem das internas.
flowchart TB
API["<b>PolicyDesk.Api</b><br/>Controllers · Filtros · Observabilidade"]
APP["<b>PolicyDesk.Application</b><br/>Casos de uso · Validações"]
DOM["<b>PolicyDesk.Domain</b><br/>Entidades · Regras · Contratos de repositório"]
INF["<b>PolicyDesk.Infrastructure</b><br/>EF Core · PostgreSQL · Migrations"]
COM["<b>PolicyDesk.Communication</b><br/>Requests · Responses"]
EXC["<b>PolicyDesk.Exception</b><br/>Exceções · Mensagens localizadas"]
API --> APP
API --> INF
APP --> DOM
INF --> DOM
API -.-> COM
APP -.-> COM
COM -.-> DOM
DOM -.-> EXC
PolicyDesk
├── src
│ ├── Backend
│ │ ├── PolicyDesk.Api # Camada HTTP: controllers, filtros, ProblemDetails, OpenTelemetry
│ │ ├── PolicyDesk.Application # Um caso de uso por operação (Register, Listing, Approve...)
│ │ ├── PolicyDesk.Domain # Entidades ricas, enums, validadores e interfaces de repositório
│ │ └── PolicyDesk.Infrastructure # DbContext, mapeamentos, repositórios, Unit of Work, migrations
│ └── Shared
│ ├── PolicyDesk.Communication # Contratos de entrada e saída da API
│ └── PolicyDesk.Exception # Hierarquia de exceções e mensagens (.resx)
└── tests
└── src
├── CommonTestUtilities # Builders de entidades, requests e mocks
├── PolicyDesk.Domain.Tests
├── PolicyDesk.Application.Tests
├── PolicyDesk.Infrastructure.Tests
└── PolicyDesk.Api.IntegrationTests
| Tema | Abordagem |
|---|---|
| Domínio rico | Entidades com setters privados validam as próprias invariantes no construtor e nos métodos de transição de estado. |
| Casos de uso | Cada operação é uma classe com interface própria, o que mantém responsabilidades pequenas e testáveis isoladamente. |
| Repositórios segregados | Interfaces separadas para leitura (ReadOnly, sem rastreamento), escrita (WriteOnly) e alteração (UpdateOnly). |
| Unit of Work | A persistência é confirmada em um único ponto, ao final de cada caso de uso. |
| Concorrência otimista | Uso da coluna de sistema xmin do PostgreSQL como token de concorrência; conflitos retornam 409 Conflict. |
| Erros padronizados | Todas as respostas de erro seguem o ProblemDetails (RFC 9457), com a lista errors e o traceId da requisição. |
| Mensagens centralizadas | Textos de erro em arquivo de recursos (.resx), com localização por Accept-Language já configurada no pipeline. |
| Cancelamento | O CancellationToken é propagado dos controllers até o banco; requisições abortadas pelo cliente retornam 499. |
| Higiene do código | Analisadores do .NET ativos no build, TreatWarningsAsErrors e versões de pacotes centralizadas (Directory.Packages.props). |
| Categoria | Ferramentas |
|---|---|
| Plataforma | .NET 10, ASP.NET Core, C# |
| Persistência | Entity Framework Core 10, PostgreSQL 17 (Npgsql) |
| Documentação da API | OpenAPI nativo + Swagger UI |
| Observabilidade | OpenTelemetry (logs, traces e métricas), exportação OTLP, .NET Aspire Dashboard, health checks |
| Testes | xUnit, Shouldly, Moq, Bogus, Testcontainers, WebApplicationFactory, Coverlet |
| Infraestrutura | Docker (build multi-stage, usuário não-root), Docker Compose |
- Docker e Docker Compose
- .NET SDK 10 (apenas para executar fora do Docker ou rodar os testes)
Sobe a API, o PostgreSQL e o Aspire Dashboard com um único comando:
git clone https://github.com/Rodrigosdk/PolicyDesk.git
cd PolicyDesk
docker compose up --build| Serviço | Endereço |
|---|---|
| API | http://localhost:8080 |
| Swagger UI | http://localhost:8080/swagger |
| Health check | http://localhost:8080/health |
| Aspire Dashboard (logs, traces e métricas) | http://localhost:18888 |
As migrations são aplicadas automaticamente na inicialização, fora do ambiente de produção.
A senha do banco pode ser definida pela variável
POSTGRES_PASSWORD. Sem ela, é usado um valor padrão para desenvolvimento local.
# 1. Suba apenas o banco e o dashboard
docker compose up -d db dashboard
# 2. Configure a connection string via User Secrets
dotnet user-secrets set "ConnectionStrings:DbConnection" \
"Host=localhost;Port=5432;Database=PolicyDesk;Username=admin;Password=policy-desk-local" \
--project src/Backend/PolicyDesk.Api
# 3. Execute a API
dotnet run --project src/Backend/PolicyDesk.ApiA API ficará disponível em http://localhost:5045, com o Swagger em http://localhost:5045/swagger.
| Método | Rota | Descrição |
|---|---|---|
GET |
/api/segurados |
Lista os segurados ativos |
GET |
/api/segurados/{id} |
Busca um segurado |
POST |
/api/segurados |
Cadastra um segurado |
PUT |
/api/segurados/{id} |
Atualiza os dados de um segurado |
DELETE |
/api/segurados/{id} |
Inativa um segurado |
| Método | Rota | Descrição |
|---|---|---|
GET |
/api/apolices?seguradoId=&status= |
Lista apólices, com filtros opcionais |
GET |
/api/apolices/{id} |
Busca uma apólice |
POST |
/api/apolices |
Emite uma apólice |
POST |
/api/apolices/{id}/cancelamento |
Cancela uma apólice |
| Método | Rota | Descrição |
|---|---|---|
POST |
/api/apolices/{id}/sinistros |
Registra um sinistro na apólice |
GET |
/api/apolices/{id}/sinistros |
Lista os sinistros de uma apólice |
GET |
/api/sinistros/{id} |
Busca um sinistro |
POST |
/api/sinistros/{id}/analise |
Inicia a análise |
POST |
/api/sinistros/{id}/aprovacao |
Aprova o sinistro |
POST |
/api/sinistros/{id}/negacao |
Nega o sinistro, informando o motivo |
POST |
/api/sinistros/{id}/pagamento |
Registra o pagamento |
curl -X POST http://localhost:8080/api/apolices \
-H "Content-Type: application/json" \
-d '{
"policyholderId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"description": "Seguro residencial",
"coverageAmount": 250000.00,
"premiumAmount": 1200.00,
"startDate": "2026-01-01",
"endDate": "2026-12-31"
}'Todas as falhas seguem o mesmo contrato, com status HTTP coerente (400, 404, 409, 500):
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"instance": "/api/apolices/3fa85f64-5717-4562-b3fc-2c963f66afa6/sinistros",
"errors": [
"O valor do sinistro excede a cobertura da apólice."
],
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736"
}O mesmo traceId volta no cabeçalho X-Trace-Id de toda resposta e aparece nos logs e traces, o que permite rastrear qualquer requisição de ponta a ponta.
- Traces distribuídos do ASP.NET Core, de chamadas HTTP de saída e de consultas ao PostgreSQL (Npgsql)
- Métricas de requisições, runtime do .NET, EF Core e Npgsql
- Logs estruturados (JSON em produção) com uma linha por requisição, sem corpo nem query string, para não expor dados pessoais (LGPD)
- Health check em
/health, incluindo a verificação de conectividade com o banco
A exportação OTLP só é ativada quando OTEL_EXPORTER_OTLP_ENDPOINT está definida. No Docker Compose, os dados chegam automaticamente ao Aspire Dashboard.
A suíte conta com mais de 240 testes, organizados em quatro níveis:
| Projeto | Escopo |
|---|---|
PolicyDesk.Domain.Tests |
Invariantes das entidades, transições de estado e validadores (CPF, e-mail, telefone) |
PolicyDesk.Application.Tests |
Casos de uso isolados com repositórios simulados (Moq) |
PolicyDesk.Infrastructure.Tests |
Repositórios e Unit of Work contra um PostgreSQL real via Testcontainers |
PolicyDesk.Api.IntegrationTests |
Requisições HTTP de ponta a ponta, contratos de erro, concorrência e health check |
# Requer Docker em execução para os testes com Testcontainers
dotnet test
# Com cobertura de código
dotnet test --collect:"XPlat Code Coverage"Distribuído sob a licença MIT. Consulte o arquivo LICENSE para mais detalhes.