Guía de Contribución
Gracias por tu interés en contribuir a NoxPanel. Esta guía establece las convenciones y procesos para colaborar en el desarrollo del proyecto.
Requisitos de Desarrollo
Para contribuir necesitas:
Python 3.10+
Docker y Docker Compose (v2+)
Git
Node.js (opcional, para assets frontend)
Un editor con soporte para Python (recomendado: VS Code / Cursor)
Configurar el Entorno
# Clonar el repositorio
git clone https://github.com/ocentelles/NoxPanel.git
cd NoxPanel
# Copiar archivo de configuración
cp env.example .env
# Editar .env con tus credenciales de desarrollo
# Levantar servicios
docker-compose up -d
# Verificar que todo funciona
docker-compose ps
docker-compose logs web
Estilo de Código
Python
Seguimos las convenciones de PEP 8 con las siguientes especificaciones:
Indentación: 4 espacios (nunca tabs)
Longitud de línea: máximo 120 caracteres
Imports: Agrupados en 3 bloques (stdlib, terceros, locales) separados por línea en blanco
Docstrings: Formato Google style o reStructuredText
Nombres de variables:
snake_caseNombres de clases:
PascalCaseConstantes:
UPPER_SNAKE_CASE
Ejemplo de estilo:
"""
Módulo de ejemplo siguiendo las convenciones de NoxPanel.
"""
import logging
from typing import Optional
from django.db import models
from rest_framework import serializers
from .models import HostingSite
logger = logging.getLogger(__name__)
class SiteService:
"""Servicio de gestión de sitios web."""
def create_site(
self,
tenant: 'HostingTenant',
domain: str,
ip_address: str = '*',
) -> Optional[HostingSite]:
"""
Crear un nuevo sitio web.
Args:
tenant: Tenant propietario del sitio.
domain: Dominio del sitio web.
ip_address: Dirección IP (usar '*' para todas).
Returns:
El sitio creado o None si falla.
Raises:
ValidationError: Si el dominio ya existe.
"""
...
Templates HTML
Indentación: 2 espacios
Usar clases CSS de Bootstrap 5
Mantener la lógica de template al mínimo
Usar
{% block %}y{% include %}para reutilización
JavaScript
Indentación: 2 espacios
Usar
const/leten lugar devarPreferir
fetch()sobre jQuery AJAXDocumentar funciones con JSDoc
Branching Model
Usamos un modelo simplificado basado en Git Flow:
Rama |
Propósito |
|---|---|
|
Código estable en producción |
|
Rama de desarrollo / integración |
|
Nuevas funcionalidades |
|
Corrección de bugs |
|
Correcciones urgentes en producción |
|
Preparación de releases |
Flujo de trabajo
Crear una rama desde
develop:git checkout develop git pull origin develop git checkout -b feature/nombre-descriptivo
Desarrollar y hacer commits
Abrir Pull Request hacia
developEsperar revisión y aprobación
Merge tras aprobación
Commits
Formato de Mensajes
Seguimos el formato de Conventional Commits:
<tipo>(<ámbito>): <descripción>
[cuerpo opcional]
[notas de pie opcionales]
Tipos permitidos
Tipo |
Descripción |
|---|---|
|
Nueva funcionalidad |
|
Corrección de bug |
|
Cambios en documentación |
|
Formato, espacios, puntos y coma (sin cambio de lógica) |
|
Refactorización sin cambio de funcionalidad |
|
Mejora de rendimiento |
|
Añadir o corregir tests |
|
Tareas de mantenimiento (deps, CI, config) |
Ejemplos:
feat(hosting): add DNS zone import from hosting engine
fix(billing): correct tax calculation for EUR invoices
docs(api): add curl examples to authentication guide
refactor(ticketing): extract email fetcher to separate service
chore(deps): upgrade Django to 5.2
Testing
Ejecutar tests
# Todos los tests
docker-compose exec web python manage.py test
# Tests de un módulo específico
docker-compose exec web python manage.py test hosting
docker-compose exec web python manage.py test billing
docker-compose exec web python manage.py test ticketing
# Test con verbose
docker-compose exec web python manage.py test --verbosity=2
Escribir tests
Cada módulo tiene su archivo
tests.pyo directoriotests/Usar
django.test.TestCasepara tests con BDUsar
rest_framework.test.APITestCasepara tests de APINombrar tests descriptivamente:
test_create_site_exceeds_quota_returns_400
Ejemplo:
from rest_framework.test import APITestCase
from rest_framework import status
from accounts.models import User
from hosting.models import HostingTenant
class SiteAPITest(APITestCase):
def setUp(self):
self.user = User.objects.create_user(
username='test', password='test123',
can_access_hosting=True,
)
self.tenant = HostingTenant.objects.create(
name='Test Corp', slug='test-corp',
contact_email='test@example.com',
)
self.client.force_authenticate(user=self.user)
def test_list_sites_returns_200(self):
response = self.client.get('/hosting/api/rest/sites/')
self.assertEqual(response.status_code, status.HTTP_200_OK)
Pull Requests
Checklist para PRs
Antes de abrir un PR, verifica que:
[ ] Los tests pasan (
python manage.py test)[ ] No hay errores de linting
[ ] Los commits siguen el formato Conventional Commits
[ ] La documentación se ha actualizado si es necesario
[ ] Se han añadido migraciones si se cambiaron modelos
[ ] El PR tiene una descripción clara del cambio
Descripción del PR
Usa la siguiente plantilla:
## Descripción
Breve descripción del cambio y motivación.
## Cambios
- Cambio 1
- Cambio 2
## Testing
Cómo se ha probado el cambio.
## Screenshots (si aplica)
Capturas de pantalla del cambio visual.
Documentación
La documentación se genera con Sphinx y usa el tema Read the Docs:
# Generar documentación
cd app/docs
make html
# Visualizar
open _build/html/index.html
Al añadir nueva funcionalidad:
Actualizar la documentación RST correspondiente
Añadir ejemplos de uso
Incluir en el
toctreedeindex.rstsi es una sección nueva