Skip to content

SamuelScar/BlogSharp

Repository files navigation

BlogSharp

BlogSharp é uma API backend para um Blog Pessoal, desenvolvida em ASP.NET Core 8, PostgreSQL, Docker, JWT, integração com IA e análise de qualidade com SonarQube.

Eu mantive este README focado em duas coisas: como rodar o projeto e quais decisões técnicas foram tomadas. Endpoints e contratos detalhados ficam no Swagger, porque ele reflete a API executável.

Sumário

1. Pré-requisitos

2. Configuração do ambiente

Crie o arquivo .env na raiz do projeto usando o .env.example como base:

cp .env.example .env

Configuração mínima para desenvolvimento local:

POSTGRES_DB=blogsharp
POSTGRES_USER=blogsharp
POSTGRES_PASSWORD=blogsharp_password
JWT_SECRET_KEY=troque_por_uma_chave_segura_com_pelo_menos_32_caracteres

IA_ENABLED=false
IA_PROVIDER=OpenRouter
IA_BASE_URL=https://openrouter.ai
IA_API_KEY=
IA_MODEL=
IA_SITE_URL=
IA_APP_NAME=BlogSharp

HOST_UID=1000
HOST_GID=1000

SONAR_TOKEN=

HOST_UID e HOST_GID são usados apenas para evitar problema de permissão em arquivos gerados pelo container no Linux. Na maioria das instalações Linux o valor 1000 já funciona; se der problema de permissão em bin/, obj/ ou arquivos gerados pelo Docker, confira os valores com:

id -u
id -g

Sempre que alterar variáveis do .env, recrie o container da API para que o Docker Compose injete os novos valores:

docker compose up -d --force-recreate api

3. Executando a aplicação

Na raiz do projeto, suba a API e o PostgreSQL:

docker compose up --build

API: http://localhost:5000

PostgreSQL: localhost:5432

Para parar os containers:

docker compose down

Para parar e remover também os volumes locais:

docker compose down -v

Use down -v apenas quando quiser apagar os dados locais do PostgreSQL.

4. Swagger e autenticação

O Swagger pode ser acessado em http://localhost:5000/swagger/index.html.

Para testar rotas protegidas:

  1. Faça login no endpoint POST /api/usuarios/login.
  2. Copie o valor retornado no campo token.
  3. Clique em Authorize no Swagger.
  4. Cole apenas o token e confirme.

5. Banco de dados e migrations

O projeto usa PostgreSQL como banco relacional. Dentro da rede do Docker Compose, a API acessa o banco pelo host database.

Os dados ficam no volume Docker blogsharp_postgres_data.

No fluxo normal com Docker, não é necessário rodar migrations manualmente. Ao iniciar em ambiente de desenvolvimento, os seeders aplicam migrations pendentes antes de inserir os dados iniciais.

Se eu quiser aplicar migrations fora desse fluxo automático, com o PostgreSQL já rodando, uso:

ASPNETCORE_ENVIRONMENT=Development dotnet ef database update --project src/BlogSharp.Api/BlogSharp.Api.csproj

6. Seeders

Eu mantive dois modos de seed: um automático para dados mínimos de desenvolvimento e outro manual para criar massa de dados quando for necessário testar melhor a aplicação.

6.1. Seed automático

Quando a API inicia em ambiente Development, os seeders fixos executam:

  • aplicam migrations pendentes;
  • criam usuários fixos se os emails ainda não existirem;
  • criam um tema inicial se ele ainda não existir;
  • criam uma postagem inicial se ela ainda não existir.

Usuários disponíveis para testes:

Perfil Email Senha
Admin admin@blogsharp.com Admin@123
Usuario usuario@blogsharp.com Usuario@123

6.2. Seed manual

Para criar dados aleatórios, use os comandos abaixo com a API em execução:

docker compose exec api dotnet run -- seed usuarios 10
docker compose exec api dotnet run -- seed temas 5
docker compose exec api dotnet run -- seed postagens 20

O número final define a quantidade de registros que será criada.

Usuários aleatórios usam emails únicos no domínio seed.blogsharp.local e senha padrão:

Senha@123

As postagens aleatórias são vinculadas a usuários e temas já cadastrados. Se os dados fixos ainda não existirem, o seeder manual de postagens cria antes os usuários e o tema inicial.

7. Integração com IA

Quando a integração está habilitada, ao cadastrar uma postagem a API envia o conteúdo para um provedor externo de IA e salva na postagem:

  • resumo;
  • tags;
  • categoria.

A integração fica desabilitada por padrão:

IA_ENABLED=false

Com a IA desabilitada, o cadastro de postagens continua funcionando e os campos ResumoIA, TagsIA e CategoriaIA ficam vazios.

Para habilitar:

IA_ENABLED=true
IA_PROVIDER=OpenRouter
IA_BASE_URL=https://openrouter.ai
IA_API_KEY=sua_chave_da_openrouter
IA_MODEL=openai/gpt-5.2
IA_SITE_URL=http://localhost:5000
IA_APP_NAME=BlogSharp

Depois de alterar o .env, recrie o container da API:

docker compose up -d --force-recreate api

Também existe a rota protegida POST /api/ia/resumir, usada para gerar resumo, categoria e tags a partir de um texto sem criar uma postagem.

8. Testes

Os testes ficam em tests/BlogSharp.Api.Tests.

Para executar todos os testes:

dotnet test BlogSharp.sln

Para executar apenas os testes de integração:

dotnet test BlogSharp.sln --filter FullyQualifiedName~Integration

Os testes unitários cobrem regras de service e provider de IA com fakes simples. Os testes de integração sobem a API em memória e validam fluxos HTTP principais.

9. SonarQube

O projeto possui um serviço Docker para rodar o SonarQube localmente. Ele fica no profile quality para não subir junto com API e banco quando eu só quero desenvolver ou testar a aplicação.

9.1. Subir o SonarQube

docker compose --profile quality up -d sonarqube

Painel: http://localhost:9000

No primeiro acesso, use:

Login: admin
Senha: admin

O SonarQube irá solicitar a troca da senha.

9.2. Configurar token

Crie um token no SonarQube e adicione no .env:

SONAR_TOKEN=seu_token_do_sonarqube

9.3. Instalar scanner

A análise é executada pela máquina local, não dentro do container do SonarQube.

dotnet tool install --global dotnet-sonarscanner

9.4. Rodar análise

O projeto usa o script scripts/sonar.sh para evitar repetir manualmente o fluxo begin, build, test e end do scanner .NET.

./scripts/sonar.sh

Ao final, o relatório fica em http://localhost:9000/dashboard?id=BlogSharp.

10. Decisões do projeto

10.1. DTOs e contratos mínimos

Eu optei por respostas com apenas os campos necessários para cada endpoint. No caso de PostagemResponse, o PDF pede que a postagem esteja vinculada a usuário e tema, mas não exige retornar os objetos completos. Por isso, a resposta retorna UsuarioId e TemaId, sem expandir UsuarioResponse ou TemaResponse.

Essa escolha evita carregar e trafegar dados que o contrato não pediu.

10.2. Data Annotations

Eu usei Data Annotations para validações simples, como campos obrigatórios, email e tamanho de texto. Isso deixa regras básicas visíveis nos DTOs e models sem criar uma camada extra só para validações simples.

10.3. Operações assíncronas

Services e repositories usam Task e o sufixo Async porque acessam o banco com Entity Framework Core. Como acesso ao banco é uma operação de I/O, o async/await evita bloquear a thread do ASP.NET Core enquanto o PostgreSQL responde.

10.4. Regras de acesso

O PDF define autenticação e controle por tipo de usuário, mas não detalha todas as regras finas. Eu defini regras explícitas para evitar comportamento ambíguo:

  • cadastro público sempre cria usuário comum;
  • usuário pode atualizar e excluir o próprio cadastro;
  • administrador pode excluir usuários;
  • alteração de privilégio fica em rota administrativa separada;
  • dono pode criar e atualizar a própria postagem;
  • administrador pode excluir postagens para moderação;
  • temas são administrados apenas por administradores.

10.5. Integração com IA

O PDF sugere OpenAI API, Gemini API ou Azure AI Services. Eu usei OpenRouter com um modelo da OpenAI por uma questão prática: durante os testes, o Gemini retornou erro 403 de chave inválida mesmo com contas e chaves diferentes; a API direta da OpenAI exige créditos pagos; e o Azure ficou burocrático demais para este escopo, porque exige várias etapas de cadastro e configuração só para conseguir uma chave de API.

Com OpenRouter, o projeto mantém o objetivo do desafio: consumir uma API externa de IA, tratar resposta JSON e enriquecer postagens com resumo, tags e categoria. Também deixei IA_ENABLED=false por padrão para a API continuar funcionando mesmo sem chave de IA configurada.

10.6. Segredos fora do código

Chave JWT, token do SonarQube e chave da IA ficam no .env local. O repositório versiona apenas .env.example, sem valores sensíveis.

10.7. SonarQube como ferramenta de inspeção

O PDF pede SonarQube, integração com build, métricas e relatórios, mas não define meta mínima de cobertura nem exige aprovação obrigatória no Quality Gate padrão. Por isso, eu uso o SonarQube como ferramenta de inspeção: corrigir bugs, vulnerabilidades, hotspots relevantes e más práticas, sem criar testes artificiais apenas para subir porcentagem.

10.8. Hotspot do Dockerfile

O SonarQube aponta hotspot no Dockerfile porque a imagem base do SDK .NET pode executar como root quando usada isoladamente.

No fluxo atual, considerei esse risco aceitável para ambiente local porque a API roda pelo Docker Compose com o usuário do host:

user: "${HOST_UID:-1000}:${HOST_GID:-1000}"

Se o projeto ganhar um Dockerfile de produção, a imagem deve definir um usuário não-root diretamente.

11. Licença

Este projeto está licenciado conforme o arquivo LICENSE.

About

API backend para um Blog Pessoal desenvolvida em ASP.NET Core, com autenticação, persistência de dados, arquitetura em camadas e integração com recursos de IA.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages