Skip to content

About

API REST de gestão de seguros: segurados, apólices e o ciclo de vida dos sinistros, com uma máquina de estados no domínio. .NET 10, Clean Architecture, EF Core + PostgreSQL, concorrência otimista, ProblemDetails, OpenTelemetry e testes de integração com Testcontainers

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

🛡️ PolicyDesk

API REST para gestão de seguros: segurados, apólices e o ciclo de vida completo de sinistros.

.NET C# PostgreSQL Docker OpenTelemetry License: MIT

Sobre • Funcionalidades • Arquitetura • Tecnologias • Como executar • Endpoints • Testes • Licença


📖 Sobre

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.


✨ Funcionalidades

👤 Segurados

  • 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

📄 Apólices

  • 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

🚨 Sinistros

  • 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 --> [*]
Loading

Qualquer transição fora desse fluxo é recusada com uma mensagem de regra de negócio.


🏛️ Arquitetura

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
Loading
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

Decisões de design

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).

🧰 Tecnologias

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

🚀 Como executar

Pré-requisitos

  • Docker e Docker Compose
  • .NET SDK 10 (apenas para executar fora do Docker ou rodar os testes)

Opção 1 — Docker Compose (recomendado)

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.

Opção 2 — Execução local com dotnet run

# 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.Api

A API ficará disponível em http://localhost:5045, com o Swagger em http://localhost:5045/swagger.


🔌 Endpoints

Segurados — /api/segurados

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

Apólices — /api/apolices

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

Sinistros

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

Exemplo de uso

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"
      }'

Formato de erro

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.


📊 Observabilidade

  • 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.


🧪 Testes

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"

📝 Licença

Distribuído sob a licença MIT. Consulte o arquivo LICENSE para mais detalhes.


Desenvolvido por Rodrigo Mamede

GitHub

About

API REST de gestão de seguros: segurados, apólices e o ciclo de vida dos sinistros, com uma máquina de estados no domínio. .NET 10, Clean Architecture, EF Core + PostgreSQL, concorrência otimista, ProblemDetails, OpenTelemetry e testes de integração com Testcontainers

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages