Logo

Guia de Contribuição

Como contribuir para o projeto Sinapse

Obrigado por considerar contribuir para o Sinapse! Este guia ajudará você a entender nosso processo de desenvolvimento e como você pode participar.

Código de Conduta

Ao contribuir, você concorda em respeitar nosso código de conduta:

  • Seja respeitoso e inclusivo
  • Aceite críticas construtivas
  • Foque no que é melhor para a comunidade
  • Mostre empatia com outros contribuidores

Como Contribuir

1. Reportando Bugs

Antes de criar um issue:

  1. Verifique se já não existe um issue similar
  2. Teste com a versão mais recente
  3. Colete informações relevantes:
    • Versão do Sinapse
    • Sistema operacional
    • Logs de erro
    • Passos para reproduzir

Template para bug report:

### Descrição
Breve descrição do problema

### Passos para Reproduzir
1. Fazer login como admin
2. Acessar /api/v1/usuarios
3. Tentar criar usuário sem email

### Comportamento Esperado
Retornar erro 422 com mensagem clara

### Comportamento Atual
Retorna erro 500 sem detalhes

### Logs

[cole os logs relevantes aqui]


### Ambiente
- Sinapse: v1.0.0
- Python: 3.11
- OS: Ubuntu 22.04

2. Sugerindo Melhorias

Para sugerir uma nova funcionalidade:

  1. Verifique o roadmap do projeto
  2. Discuta a ideia em um issue antes de implementar
  3. Descreva o caso de uso e benefícios
  4. Considere possíveis impactos

3. Enviando Pull Requests

Setup Inicial

# Fork o repositório no GitHub

# Clone seu fork
git clone [email protected]:seu-usuario/core_sinapse.git
cd core_sinapse

# Adicione o upstream
git remote add upstream [email protected]:InstitutoTodosPelaSaude/core_sinapse.git

# Configure seu ambiente
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt -r requirements-dev.txt

Fluxo de Trabalho

  1. Crie uma branch:

    # Sincronize com upstream
    git fetch upstream
    git checkout main
    git merge upstream/main
    
    # Crie sua branch
    git checkout -b feature/minha-feature
    # ou
    git checkout -b fix/corrigir-bug
  2. Faça suas alterações:

    • Siga os padrões de código
    • Adicione testes quando aplicável
    • Atualize a documentação
    • Mantenha commits atômicos
  3. Teste suas alterações:

    # Execute os testes
    pytest
    
    # Verifique a formatação
    black . --check
    ruff check .
    
    # Type checking
    mypy .
  4. Commit suas mudanças:

    # Commits semânticos
    git commit -m "feat: adicionar endpoint de busca avançada"
    git commit -m "fix: corrigir validação de CPF"
    git commit -m "docs: atualizar README com novos exemplos"
    git commit -m "test: adicionar testes para módulo de agravos"
    git commit -m "refactor: simplificar lógica de autenticação"
  5. Push e crie o PR:

    git push origin feature/minha-feature

Padrões de Código

Python Style Guide

Seguimos PEP 8 com algumas extensões:

# Imports organizados com isort
from typing import Optional, List, Dict
from datetime import datetime

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession

from core.database import get_db
from core.security import get_current_user
from modules.usuarios.schemas import UsuarioSchema
from modules.usuarios.models import UsuarioModel

# Classes com docstrings
class UsuarioService:
    """
    Serviço para operações relacionadas a usuários.
    
    Este serviço centraliza toda a lógica de negócio
    relacionada ao gerenciamento de usuários.
    """
    
    async def criar_usuario(
        self,
        *,
        db: AsyncSession,
        usuario_data: UsuarioSchema,
        current_user: UsuarioModel
    ) -> UsuarioModel:
        """
        Cria um novo usuário no sistema.
        
        Args:
            db: Sessão assíncrona do banco
            usuario_data: Dados do usuário a ser criado
            current_user: Usuário autenticado fazendo a requisição
            
        Returns:
            UsuarioModel: Usuário criado
            
        Raises:
            HTTPException: Se email já existe ou sem permissão
        """
        # Implementação...

Estrutura de Arquivos

modules/novo_modulo/
├── __init__.py          # Exports do módulo
├── module_config.py     # Configurações
├── endpoints.py         # Rotas FastAPI
├── models.py           # Modelos SQLAlchemy
├── schemas.py          # Schemas Pydantic
├── async_services.py   # Lógica de negócio
├── async_repository.py # Acesso a dados
└── tests/              # Testes do módulo
    ├── __init__.py
    ├── test_endpoints.py
    └── test_services.py

Convenções de Nomenclatura

  • Variáveis e funções: snake_case
  • Classes: PascalCase
  • Constantes: UPPER_SNAKE_CASE
  • Arquivos: snake_case
  • URLs: kebab-case

Type Hints

Sempre use type hints:

from typing import Optional, List, Dict, Union
from datetime import datetime

async def processar_dados(
    dados: List[Dict[str, Union[str, int]]],
    filtro: Optional[str] = None,
    limite: int = 100
) -> Dict[str, List[Dict[str, any]]]:
    """Processa dados com filtro opcional."""
    resultado: Dict[str, List[Dict[str, any]]] = {
        "processados": [],
        "erros": []
    }
    # ...
    return resultado

Testes

Estrutura de Testes

# tests/test_usuarios.py
import pytest
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession

from main import app
from modules.usuarios.models import UsuarioModel

class TestUsuarios:
    """Testes para o módulo de usuários."""
    
    @pytest.mark.asyncio
    async def test_criar_usuario(
        self,
        client: AsyncClient,
        db: AsyncSession,
        admin_token: str
    ):
        """Testa criação de usuário com sucesso."""
        # Arrange
        usuario_data = {
            "email": "[email protected]",
            "nome": "Novo Usuario",
            "senha": "senha123"
        }
        
        # Act
        response = await client.post(
            "/api/v1/usuarios/",
            json=usuario_data,
            headers={"Authorization": f"Bearer {admin_token}"}
        )
        
        # Assert
        assert response.status_code == 201
        data = response.json()
        assert data["email"] == usuario_data["email"]
        assert "senha" not in data

Fixtures Comuns

# conftest.py
import pytest
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession

@pytest.fixture
async def client():
    """Cliente HTTP para testes."""
    async with AsyncClient(app=app, base_url="http://test") as ac:
        yield ac

@pytest.fixture
async def admin_user(db: AsyncSession):
    """Usuário admin para testes."""
    # Criar e retornar usuário admin
    pass

@pytest.fixture
async def admin_token(admin_user):
    """Token JWT de admin."""
    # Gerar e retornar token
    pass

Documentação

Docstrings

Use Google style:

def calcular_estatisticas(
    casos: List[AgravoModel],
    periodo: str = "mensal"
) -> Dict[str, float]:
    """
    Calcula estatísticas de casos de agravos.
    
    Args:
        casos: Lista de casos para análise
        periodo: Tipo de agrupamento (diario, semanal, mensal)
        
    Returns:
        Dict com estatísticas calculadas:
            - total: Total de casos
            - media: Média por período
            - taxa_crescimento: Taxa de crescimento
            
    Raises:
        ValueError: Se período não for válido
        
    Example:
        >>> casos = await get_casos_dengue()
        >>> stats = calcular_estatisticas(casos, "semanal")
        >>> print(f"Total: {stats['total']}")
    """

Documentação de API

Sempre documente endpoints:

@router.post(
    "/",
    response_model=UsuarioResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Criar novo usuário",
    description="Cria um novo usuário no sistema. Requer permissão USUARIOS_CRIAR."
)
async def criar_usuario(
    usuario: UsuarioCreate,
    db: AsyncSession = Depends(get_db),
    current_user: UsuarioModel = Depends(requer_permissao("usuarios.criar"))
):
    """
    Cria um novo usuário com os dados fornecidos.
    
    - **email**: Email único do usuário
    - **nome**: Nome completo
    - **senha**: Senha com mínimo 8 caracteres
    - **grupos**: Lista de IDs de grupos (opcional)
    """

Processo de Review

Checklist do PR

Antes de solicitar review, verifique:

  • Código segue os padrões do projeto
  • Testes foram adicionados/atualizados
  • Documentação foi atualizada
  • Sem warnings do linter
  • Commits com mensagens claras
  • Branch está atualizada com main
  • CI está passando

O que esperamos no review

  1. Código limpo e legível
  2. Testes adequados
  3. Documentação clara
  4. Sem código comentado
  5. Sem prints de debug
  6. Segurança considerada

Template de PR

## Descrição
Breve descrição do que foi alterado e por quê.

## Tipo de mudança
- [ ] Bug fix
- [ ] Nova feature
- [ ] Breaking change
- [ ] Documentação

## Como testar
1. Passo 1
2. Passo 2
3. Verificar resultado

## Checklist
- [ ] Testes adicionados
- [ ] Documentação atualizada
- [ ] Código revisado
- [ ] CI passando

## Screenshots (se aplicável)
[Adicione screenshots aqui]

## Issues relacionados
Closes #123

Versionamento

Seguimos Semantic Versioning:

  • MAJOR: Mudanças incompatíveis na API
  • MINOR: Novas funcionalidades compatíveis
  • PATCH: Correções de bugs

Exemplos:

  • 1.0.02.0.0: Removeu endpoint antigo
  • 1.0.01.1.0: Adicionou novo endpoint
  • 1.0.01.0.1: Corrigiu bug de validação

Comunicação

Canais

Seja claro e específico

Bom: "Endpoint GET /usuarios retorna 500 quando filtro cidade tem acentos"

Ruim: "API não funciona com acentos"

Reconhecimento

Todos os contribuidores são reconhecidos em:

  • README.md
  • Release notes
  • Arquivo CONTRIBUTORS.md

Dúvidas?

Se tiver dúvidas sobre como contribuir:

  1. Verifique a documentação técnica
  2. Abra uma discussion
  3. Entre em contato por email

Obrigado por contribuir para tornar o Sinapse melhor! 🎉

On this page