Arquitectura#

Arquitectura técnica y patrones de diseño utilizados en Construbot.

Descripción general#

Construbot es un sistema de gestión de construcción basado en Django creado con patrones modernos y mejores prácticas. Esta sección explica las decisiones arquitectónicas, los modelos de datos y el diseño del sistema.

Referencia rápida#

Pila de tecnología#

Servidor:

  • Django 3.2.19 (LTS)

  • Pitón 3.9.17+

  • PostgreSQL 12+

  • Redis 6+

Cola de tareas:

  • Apio 5.2.7

  • corredor de Redis

API:

  • Marco REST de Django 3.13.1

  • SimpleJWT 5.2.0

Bibliotecas clave:

  • django-treebeard 4.5.1 (modelos jerárquicos)

  • django-allauth 0.51.0 (autenticación)

  • django-autocomplete-light 3.9.4 (widgets de autocompletar)

  • reportlab 3.6.12 (generación de PDF)

  • openpyxl 3.0.10 (importación/exportación de Excel)

Componentes del sistema#

Capa de aplicación#

┌──────────────────────────────────────────┐
│         Web Clients / API Clients        │
└────────────────┬─────────────────────────┘
                 │
                 ▼
┌──────────────────────────────────────────┐
│      Nginx (Reverse Proxy / SSL)         │
└────────────────┬─────────────────────────┘
                 │
                 ▼
┌──────────────────────────────────────────┐
│    Gunicorn (WSGI Server)                │
│    ┌──────────────────────────────┐      │
│    │  Django Application          │      │
│    │  ├─ proyectos (core logic)   │      │
│    │  ├─ users (auth & accounts)  │      │
│    │  ├─ api (REST endpoints)     │      │
│    │  └─ core (utilities)         │      │
│    └──────────────────────────────┘      │
└────────────────┬─────────────────────────┘
                 │
       ┌─────────┴──────────┐
       ▼                    ▼
┌──────────────┐    ┌──────────────┐
│  PostgreSQL  │    │    Redis     │
│  (Database)  │    │(Cache/Queue) │
└──────────────┘    └──────┬───────┘
                           │
                           ▼
                    ┌──────────────┐
                    │Celery Workers│
                    │(Background)  │
                    └──────────────┘

Flujo de datos#

Solicitud de usuario:

  1. El usuario accede a la aplicación → Nginx

  2. Nginx representa a Gunicorn

  3. Gunicorn ejecuta el ciclo de solicitud/respuesta de Django

  4. Django consulta PostgreSQL para obtener datos

  5. Django usa Redis para el almacenamiento en caché

  6. Respuesta emitida y devuelta

Tarea en segundo plano:

  1. La acción del usuario desencadena la tarea → Retraso de apio()

  2. Tarea en cola en Redis

  3. El trabajador del apio retoma su tarea

  4. El trabajador ejecuta la tarea (por ejemplo, enviar correo electrónico, generar PDF)

  5. Resultado almacenado en Redis (opcional)

Estructura de la aplicación#

Aplicaciones Django#

construbot.users - Gestión de usuarios

  • Modelo de usuario personalizado (autenticación basada en correo electrónico)

  • Modelos de empresa y cliente

  • Niveles de permisos (NivelAcceso)

  • Motores de autenticación

construbot.proyectos - Lógica empresarial central

  • Gestión de contratos (Contrato)

  • Gestión de contraparte (Contraparte)

  • Seguimiento de estimación (Estimación)

  • Estructuras de datos jerárquicas

  • Cálculos financieros

construbot.api - API REST

  • autenticación JWT

  • Puntos finales API para acceso móvil/externo

  • Serializadores y conjuntos de vistas

  • Puntos finales de migración de datos

construbot.core - Utilidades compartidas

  • Modelos base y mixins.

  • Backend de autenticación personalizada

  • Funciones de utilidad

  • Plantillas compartidas

construbot.account_config - Configuración de cuenta

  • Configuraciones específicas de la empresa

  • Formularios de inicio de sesión personalizados

  • Preferencias de cuenta

construbot.taskapp - Configuración de apio

  • Inicialización de la aplicación de apio

  • Definiciones de tareas

  • Configuración de tareas periódicas

Estructura del directorio#

construbot/
├── construbot/                   # Main Django project
│   ├── config/                   # Project configuration
│   │   ├── settings/             # Environment-specific settings
│   │   │   ├── base.py           # Shared settings
│   │   │   ├── local.py          # Development
│   │   │   ├── test.py           # Testing
│   │   │   └── production.py     # Production
│   │   ├── urls.py               # Root URL configuration
│   │   └── wsgi.py               # WSGI application
│   │
│   ├── users/                    # User management app
│   │   ├── models.py             # User, Company, Customer
│   │   ├── views.py              # User views
│   │   ├── forms.py              # User forms
│   │   └── admin.py              # Admin interface
│   │
│   ├── proyectos/                # Core business app
│   │   ├── models.py             # Business models
│   │   ├── views.py              # Business views
│   │   ├── forms.py              # Business forms
│   │   └── migrations/           # Database migrations
│   │
│   ├── api/                      # REST API app
│   │   ├── views.py              # API viewsets
│   │   ├── serializers.py        # Data serializers
│   │   └── urls.py               # API routes
│   │
│   ├── core/                     # Shared utilities
│   │   ├── models.py             # Base models
│   │   ├── backends.py           # Auth backend
│   │   └── utils.py              # Utility functions
│   │
│   ├── static/                   # Static files
│   │   ├── css/                  # Stylesheets
│   │   ├── js/                   # JavaScript
│   │   └── images/               # Images
│   │
│   ├── templates/                # Django templates
│   │   ├── base.html             # Base template
│   │   └── ...                   # App templates
│   │
│   └── media/                    # User uploads
│
├── requirements/                 # Dependencies
│   ├── base.txt                  # Core dependencies
│   ├── local.txt                 # Development
│   ├── test.txt                  # Testing
│   └── production.txt            # Production
│
├── tests/                        # Test suite
│   └── ...                       # Test files
│
├── docs/                         # Documentation
│   └── ...                       # Documentation files
│
├── compose/                      # Docker configuration
│   ├── local/                    # Local development
│   └── production/               # Production
│
├── manage.py                     # Django management script
├── setup.py                      # Package setup
├── docker-compose.yml            # Docker Compose config
└── Makefile                      # Development commands

Patrones de diseño#

Multi-inquilino#

Jerarquía de tres niveles:

Customer (Top-level account)
└── Company (Business entity)
    └── User (Individual with permissions)

Aislamiento de datos:

  • Todos los datos comerciales enfocados a la empresa

  • Los usuarios pueden pertenecer a varias empresas.

  • Empresa activa rastreada en la sesión

Consulte Multi-inquilino para obtener más detalles.

Modelos Jerárquicos#

Camino materializado de Django-treebeard:

Los contratos (Contrato) forman estructuras de árbol:

Main Contract
├── Subcontract 1
│   ├── Sub-subcontract 1.1
│   └── Sub-subcontract 1.2
└── Subcontract 2

Beneficios:

  • Consultas eficientes entre padres e hijos

  • Agregaciones de árboles (cantidades totales)

  • Operaciones de movimiento

  • Consultas basadas en rutas

Implementación:

from treebeard.mp_tree import MP_Node

class Contrato(MP_Node):
    # Inherits: path, depth, numchild
    # Methods: get_children(), get_ancestors(), etc.

Autenticación personalizada#

Autenticación basada en correo electrónico:

  • Sin campo de nombre de usuario

  • Correo electrónico como identificador único

  • Backend de autenticación personalizada

Soporte multiempresa:

  • El usuario puede acceder a múltiples empresas.

  • Cambio de empresa sin volver a iniciar sesión

  • Permisos por empresa

Consulte autenticación para obtener más detalles.

Sistema de permisos#

Seis niveles de permisos (NIVELES_ACCESO):

  1. Auxiliar (1) - Ver solo

  2. Coordinador (2) - Crear/editar

  3. Director (3) - CRUD completo

  4. Corporativo (4) - Multiempresa

  5. Soporte (5) - Acceso al soporte

  6. Superusuario (6) - Acceso completo al sistema

Consulte Niveles de permiso para obtener más detalles.

Patrones de acceso a datos#

Optimización de consultas#

Seleccione Relacionado (claves externas):

# Avoid N+1 queries
contratos = Contrato.objects.select_related('contraparte', 'company')

Relacionado con la captación previa (muchos a muchos):

# Optimize related objects
users = User.objects.prefetch_related('companies', 'user_companies')

Índices de bases de datos:

class Contrato(models.Model):
    folio = models.CharField(max_length=100, db_index=True)

    class Meta:
        indexes = [
            models.Index(fields=['company', 'fecha_inicio']),
        ]

Estrategia de almacenamiento en caché#

Almacenamiento en caché por vista:

from django.views.decorators.cache import cache_page

@cache_page(60 * 15)  # 15 minutes
def dashboard_view(request):
    ...

Almacenamiento en caché de fragmentos de plantilla:

{% load cache %}
{% cache 600 sidebar request.user.id %}
    ... expensive template code ...
{% endcache %}

Almacenamiento en caché de resultados de consultas:

from django.core.cache import cache

def get_company_stats(company_id):
    key = f'company_stats_{company_id}'
    stats = cache.get(key)
    if stats is None:
        stats = calculate_stats(company_id)
        cache.set(key, stats, 3600)  # 1 hour
    return stats

Transacciones atómicas#

Habilitado de forma predeterminada:

# In settings/base.py
DATABASES = {
    'default': {
        ...
        'ATOMIC_REQUESTS': True,
    }
}

Control manual de transacciones:

from django.db import transaction

@transaction.atomic
def create_contract_with_concepts(contract_data, concepts_data):
    contract = Contrato.objects.create(**contract_data)
    for concept_data in concepts_data:
        Concept.objects.create(contract=contract, **concept_data)
    return contract

Diseño API#

Estructura de la API REST#

URL base: /api/v1/

Autenticación: tokens JWT

Puntos finales:

POST   /api/v1/api-token-auth/        # Obtain token
POST   /api/v1/api-token-refresh/     # Refresh token
GET    /api/v1/contracts/             # List contracts
POST   /api/v1/contracts/             # Create contract
GET    /api/v1/contracts/:id/         # Retrieve contract
PUT    /api/v1/contracts/:id/         # Update contract
DELETE /api/v1/contracts/:id/         # Delete contract

Formato de respuesta:

{
  "count": 100,
  "next": "http://api.example.com/api/v1/contracts/?page=2",
  "previous": null,
  "results": [...]
}

Consulte API para obtener la documentación API completa.

Arquitectura de seguridad#

Flujo de autenticación#

Aplicación web:

  1. El usuario envía correo electrónico/contraseña

  2. El backend se autentica contra el modelo de usuario

  3. Sesión creada con el contexto de la empresa.

  4. Usuario redirigido al panel

API:

  1. El cliente publica credenciales en /api-token-auth/

  2. El servidor valida y devuelve el token JWT

  3. El cliente incluye el token en el encabezado Autorización: Portador <token>

  4. El servidor valida el token en cada solicitud

Capas de autorización#

1. Se requiere autenticación:

from django.contrib.auth.decorators import login_required

@login_required
def view(request):
    ...

2. Comprobación del nivel de permiso:

def director_required(view_func):
    def wrapper(request, *args, **kwargs):
        if request.user.nivel_acceso.nivel < 3:
            return HttpResponseForbidden()
        return view_func(request, *args, **kwargs)
    return wrapper

3. Datos al alcance de la empresa:

# Always filter by active company
contratos = Contrato.objects.filter(company=request.user.active_company)

Consulte Autenticación y Niveles de permiso para obtener más detalles.

Consideraciones de rendimiento#

Base de datos#

  • Agrupación de conexiones (CONN_MAX_AGE)

  • Optimización de consultas (select_ related/prefetch_ related)

  • Índices de bases de datos en campos consultados con frecuencia

  • Solicitudes atómicas para la integridad de los datos

Almacenamiento en caché#

  • Redis para backend de caché

  • Almacenamiento de sesiones en caché

  • Almacenamiento en caché de resultados de consultas

  • Almacenamiento en caché de fragmentos de plantilla

Archivos estáticos#

  • WhiteNoise para un servicio eficiente

  • Compresión Gzip/Brotli

  • Encabezados de caché de futuro lejano

  • CDN para implementaciones de alto tráfico

Tareas en segundo plano#

  • Apio para operaciones asincrónicas

  • Envío de correo electrónico en segundo plano

  • Generación de PDF en segundo plano

  • Tareas programadas con Celery Beat

Escalabilidad#

Escalado vertical#

  • Aumentar la CPU/RAM del servidor

  • Actualizar instancia de base de datos

  • Agregar memoria Redis

Escala horizontal#

  • Múltiples servidores de aplicaciones Django

  • Equilibrador de carga (ALB/Nginx)

  • Base de datos administrada (RDS con réplicas de lectura)

  • Caché externo (ElastiCache)

  • S3 para archivos multimedia

Los servidores de aplicaciones sin estado permiten un fácil escalado horizontal.

Puntos de Monitoreo#

Métricas de aplicación#

  • Tiempos de solicitud/respuesta

  • Tasas de error (4xx, 5xx)

  • Rendimiento de consultas de bases de datos

  • Proporción de aciertos/errores de caché

  • Longitud de la cola de tareas de apio

Métricas de infraestructura#

  • uso de CPU

  • Uso de memoria

  • E/S de disco

  • Tráfico de red

  • Conexiones de bases de datos

Métricas comerciales#

  • Usuarios activos

  • Contratos creados

  • Estimaciones generadas

  • Descargas de PDF

  • Uso de API

Consulte Despliegue para conocer la configuración del monitoreo.

Flujo de trabajo de desarrollo#

Desarrollo Local#

  1. Utilice Docker Compose para un entorno coherente

  2. Ejecute make dev para iniciar los servicios

  3. Recarga automática de cambios de código (servidor de desarrollo Django)

  4. Utilice make shell para Django shell

  5. Ejecute make test antes de confirmar

Consulte Instalación para la configuración.

Estrategia de prueba#

  • Pruebas unitarias para modelos y utilidades.

  • Pruebas de integración para vistas.

  • Pruebas API para puntos finales REST

  • Objetivo de cobertura: >80%

Consulte Pruebas para obtener una guía de prueba.

Proceso de implementación#

  1. Ejecutar pruebas (hacer prueba)

  2. Construir imágenes de Docker

  3. Ejecutar migraciones de bases de datos

  4. Recopilar archivos estáticos

  5. Reiniciar los servidores de aplicaciones

  6. Verificar implementación

Consulte Despliegue para obtener una guía de implementación.

Ver también#