Skip to content

Salta-Dev/saltadev-website

Repository files navigation

SaltaDev Logo

SaltaDev Website

Plataforma web oficial de la comunidad de desarrolladores de Salta, Argentina

Python 3.12 Django 5.2 Ruff Biome pre-commit mypy CI

CaracterísticasTech StackInstalaciónConfiguraciónArquitecturaDespliegueCI/CDMonitoreoImágenesSeguridadSEODesarrollo


Características

  • Autenticación completa - Login, registro con verificación de email y recuperación de contraseña
  • Dashboard de usuario - Panel personalizado con perfil, credencial digital y gestión de datos
  • Credencial digital - Credencial verificable con QR code, descargable como PNG
  • Sistema de roles - Miembro, Colaborador, Moderador y Administrador
  • Eventos - Listado y gestión de eventos con workflow de aprobación
  • Notificaciones - Sistema de notificaciones in-app para usuarios
  • Colaboradores - Showcase de empresas y organizaciones aliadas
  • Staff - Perfiles del equipo organizador
  • Código de conducta - Reglamento de la comunidad

Tech Stack

Backend

Tecnología Versión Descripción
Python 3.12 Lenguaje principal
Django 5.2 Framework web
PostgreSQL 15+ Base de datos
Redis 7+ Cache y rate limiting
Gunicorn 23.0 WSGI Server
Cloudinary - CDN de imágenes

Frontend

Tecnología Versión Descripción
TailwindCSS 4.x CSS compilado via django-tailwind-cli
JavaScript ES6+ Interactividad
HTML5 - Templates Django

DevOps & Herramientas

Tecnología Descripción
Render Cloud hosting
Docker Containerización
Nginx Reverse proxy
GitHub Actions CI/CD
uv Package manager

Estructura del Proyecto

saltadev-website/
├── saltadev/                   # Django project root
│   ├── manage.py
│   ├── tailwind.config.js      # Configuración Tailwind CSS
│   ├── saltadev/               # Django settings package
│   │   ├── settings/
│   │   │   ├── base.py         # Configuración base
│   │   │   ├── local.py        # Desarrollo local
│   │   │   ├── development.py  # Desarrollo
│   │   │   ├── staging.py      # Staging
│   │   │   └── production.py   # Producción
│   │   ├── urls.py
│   │   └── wsgi.py
│   │
│   ├── home/                   # Landing page
│   ├── auth_login/             # Login
│   ├── auth_register/          # Registro + verificación email
│   ├── password_reset/         # Recuperación de contraseña
│   ├── users/                  # Modelo de usuario y perfil
│   ├── dashboard/              # Panel de usuario
│   ├── events/                 # Eventos
│   ├── benefits/               # Beneficios para miembros
│   ├── locations/              # Países y provincias
│   ├── content/                # Contenido (colaboradores, etc)
│   ├── code_of_conduct/        # Código de conducta
│   ├── user_notifications/     # Sistema de notificaciones
│   │
│   ├── static/                 # Archivos estáticos
│   │   └── css/
│   │       └── source.css      # CSS fuente para Tailwind
│   └── templates/              # Templates HTML
│
├── deploy/                     # Configuración de despliegue
│   └── render.yaml             # IaC para Render.com
├── build.sh                    # Script de build para Render
├── tests/                      # Tests con pytest
├── docker/                     # Configuración Docker
├── nginx/                      # Configuración Nginx
├── scripts/                    # Scripts de utilidad
│
├── pyproject.toml              # Dependencias y configuración
├── uv.lock                     # Lockfile
├── pytest.ini                  # Configuración pytest
├── mypy.ini                    # Configuración mypy
├── biome.json                  # Configuración Biome
└── .pre-commit-config.yaml     # Pre-commit hooks

Instalación

Requisitos

  • Python 3.12+
  • uv (package manager)
  • PostgreSQL 15+ (producción) o SQLite (desarrollo)
  • Redis 7+ (opcional, para rate limiting)

Setup Local

# Clonar repositorio
git clone https://github.com/saltadev/saltadev-website.git
cd saltadev-website

# Crear entorno virtual e instalar dependencias
uv venv
source .venv/bin/activate
uv pip install -e .[dev]

# Configurar variables de entorno
cp .env.example .env.local
# Editar .env.local con tus valores

# Aplicar migraciones
cd saltadev
python manage.py migrate

# Crear superusuario (opcional)
python manage.py createsuperuser

# Ejecutar servidor de desarrollo
python manage.py runserver

Configuración

Variables de Entorno

Crear archivo .env.local en la raíz del proyecto:

# Django
DJANGO_ENV=local
SECRET_KEY=tu-secret-key-muy-segura
DEBUG=True

# Base de datos (opcional para local, usa SQLite por defecto)
DATABASE_URL=postgres://user:pass@localhost:5432/saltadev

# Email - Opción 1: SMTP (Gmail)
EMAIL_HOST_USER=tu_email@gmail.com
EMAIL_HOST_PASSWORD=tu_app_password

# Email - Opción 2: Resend (requerido en Render.com free tier)
RESEND_API_KEY=re_xxx
DEFAULT_FROM_EMAIL=noreply@tudominio.com

# reCAPTCHA v2
RECAPTCHA_V2_SITE_KEY=tu-site-key
RECAPTCHA_V2_SECRET=tu-secret-key

# URL del sitio
SITE_URL=http://localhost:8000

Entornos Disponibles

Entorno Archivo Descripción
local .env.local Desarrollo local con DEBUG=True
development .env.development Servidor de desarrollo
staging .env.staging Pre-producción
production .env.production Producción

Arquitectura

Diagrama de Aplicaciones

flowchart TB
    subgraph Public["Páginas Públicas"]
        home[Home]
        events[Eventos]
        coc[Código de Conducta]
        credential[Credencial Pública]
    end

    subgraph Auth["Autenticación"]
        login[Login]
        register[Registro]
        verify[Verificación Email]
        reset[Password Reset]
    end

    subgraph Private["Área Privada"]
        dashboard[Dashboard]
        profile[Perfil]
    end

    subgraph Core["Core"]
        users[Users Model]
        locations[Locations]
        content[Content]
    end

    home --> login
    home --> register
    register --> verify
    verify --> dashboard
    login --> dashboard
    login --> reset
    reset --> login
    dashboard --> profile
    dashboard --> credential

    users --> locations
    users --> content
Loading

Flujo de Verificación de Email

sequenceDiagram
    participant U as Usuario
    participant R as Registro
    participant US as Users
    participant M as Email

    U->>R: Envía formulario de registro
    R->>US: Crea usuario (email_confirmed=False)
    US->>M: Envía código de verificación (6 dígitos)
    M-->>U: Email con código
    U->>US: Ingresa código
    US->>US: Verifica código y confirma email
    US->>U: Login automático → Dashboard
Loading

Flujo de Recuperación de Contraseña

sequenceDiagram
    participant U as Usuario
    participant PR as Password Reset
    participant M as Email

    U->>PR: Solicita recuperación
    PR->>PR: Genera token (válido 10 min)
    PR->>M: Envía email con link
    M-->>U: Email con link de reset
    U->>PR: Abre link y envía nueva contraseña
    PR->>PR: Valida token y actualiza password
    PR->>U: Redirige a login con mensaje de éxito
Loading

Sistema de Notificaciones

El proyecto usa django-notifications-hq para notificaciones in-app:

from notifications.signals import notify
notify.send(sender, recipient=user, verb="aprobó tu evento", target=event)

Endpoints disponibles:

Endpoint Descripción
/notificaciones/ Lista de notificaciones del usuario
/notificaciones/marcar-leidas/ Marcar todas como leídas
/notificaciones/<id>/marcar-leida/ Marcar una como leída

Gestión de Eventos

Los eventos tienen un workflow de aprobación con tres estados:

Estado Descripción
PENDING Evento creado, esperando aprobación
APPROVED Evento aprobado, visible públicamente
REJECTED Evento rechazado

Flujo:

  1. Usuario crea evento → estado PENDING
  2. Staff/Admin revisa en el admin
  3. Al aprobar/rechazar → se envía notificación automática al creador

Despliegue

Render.com (Recomendado)

El proyecto incluye configuración Infrastructure as Code (IaC) para Render.com en deploy/render.yaml.

Ver deploy/RENDER.md para la guía completa de despliegue.

Servicio Tipo Plan Descripción
saltadev-db PostgreSQL Free Base de datos
saltadev-redis Redis Free Cache y rate limiting
saltadev-website Web Service Free Aplicación Django

Deploy automático

  1. Conectar repositorio en Render Dashboard
  2. Seleccionar "Blueprint" y apuntar a deploy/render.yaml
  3. Configurar variables secretas (Cloudinary, Email, reCAPTCHA)
  4. Deploy!

Variables de entorno

Las siguientes se generan automáticamente:

  • DATABASE_URL - Conexión a PostgreSQL
  • REDIS_URL - Conexión a Redis
  • SECRET_KEY - Generada automáticamente

Las siguientes requieren configuración manual:

  • CLOUDINARY_CLOUD_NAME, CLOUDINARY_API_KEY, CLOUDINARY_API_SECRET
  • RESEND_API_KEY, DEFAULT_FROM_EMAIL
  • RECAPTCHA_V2_SITE_KEY, RECAPTCHA_V2_SECRET
  • SITE_URL

Script de build

El archivo build.sh ejecuta durante el deploy:

pip install -r requirements.txt
python manage.py tailwind build
python manage.py collectstatic --no-input
python manage.py migrate
python manage.py loaddata locations

CI/CD

GitHub Actions

El proyecto incluye un workflow de CI que se ejecuta en cada push y PR a main:

Check Comando Descripción
Tests pytest --cov Tests con coverage
Linting ruff check Verificación de código
Format ruff format --check Verificación de formato
Types mypy Chequeo de tipos
Security bandit Análisis de seguridad

El workflow usa PostgreSQL en un service container para tests de integración.

Ver .github/workflows/ci.yml para la configuración completa.

Monitoreo

Healthcheck Endpoint

GET /health/

Verifica el estado de los servicios críticos:

  • Django: Aplicación web
  • PostgreSQL: Base de datos
  • Redis: Cache

Respuesta exitosa (200 OK):

{
  "status": "healthy",
  "services": {
    "django": "ok",
    "postgres": "ok",
    "redis": "ok"
  }
}

Respuesta con error (503 Service Unavailable):

{
  "status": "unhealthy",
  "services": {
    "django": "ok",
    "postgres": "error",
    "redis": "ok"
  }
}

Este endpoint es utilizado por Render.com para verificar la salud del servicio.

Almacenamiento de Imágenes

Cloudinary CDN

El proyecto usa Cloudinary para almacenar y servir imágenes (avatares, etc.):

Característica Detalle
CDN Global Servido desde edge locations mundiales
Formato automático WebP/AVIF según el navegador
Calidad automática Optimización sin pérdida visible
Transformaciones on-the-fly No consume créditos de transformación

Estrategia de transformaciones

Las imágenes se suben SIN transformación y se procesan on-the-fly via URL:

https://res.cloudinary.com/{cloud}/upload/w_400,h_400,c_fill,g_face,q_auto,f_auto/{path}

Esto evita consumir los 25 créditos/mes del free tier, ya que las transformaciones on-the-fly no consumen créditos de transformación.

Desarrollo local

En desarrollo local, las imágenes usan Django ImageField y se guardan en static/assets/img/:

Tipo Ruta
Colaboradores static/assets/img/partners/
Staff static/assets/img/staff/
Avatares media/avatars/

Cloudinary es opcional en desarrollo. Si no se configuran las credenciales, las imágenes se guardan localmente.

Seguridad

Medidas Implementadas

Medida Descripción
CSRF Protection Token CSRF en todos los formularios
reCAPTCHA v2 Protección contra bots en login/registro
Rate Limiting Límite de intentos por IP, email y fingerprint
Password Validation Validación de fortaleza de contraseñas
Token Expiration Tokens de recuperación expiran en 10 minutos
Single-use Tokens Tokens de un solo uso para reset de contraseña
Email Verification Verificación obligatoria de email
No User Enumeration Misma respuesta para emails existentes y no existentes
Disposable Email Block Rechaza emails de proveedores temporales (10minutemail, etc.)
CSP Headers Content Security Policy via django-csp (producción)
Secure Headers Headers de seguridad configurados
HTTPS Only Forzado en producción

django-axes

Protección contra ataques de fuerza bruta:

  • Bloqueo después de 5 intentos fallidos
  • Bloqueo por IP y por nombre de usuario
  • Desbloqueo automático después de 1 hora

SEO

Optimizaciones Implementadas

Característica Descripción
robots.txt Control de crawlers con reglas Disallow para áreas privadas
sitemap.xml Sitemap generado dinámicamente con django.contrib.sitemaps
JSON-LD Schema Organization en la homepage para rich snippets
Meta descriptions Descripciones únicas y optimizadas por página
Canonical URLs URLs canónicas en todas las páginas públicas
Open Graph Meta tags para compartir en Facebook y LinkedIn
Twitter Cards Meta tags para compartir en Twitter/X
Redirects 301 Links sociales con redirect permanente para tracking

Archivos Clave

saltadev/
├── saltadev/
│   ├── sitemaps.py              # Configuración de sitemap.xml
│   └── urls.py                  # Rutas de robots.txt y sitemap
│
├── templates/
│   ├── robots.txt               # Template de robots.txt
│   └── includes/
│       ├── head.html            # Meta tags, OG y Twitter Cards
│       └── structured_data/
│           └── organization.html # JSON-LD Organization schema
│
└── content/
    └── redirects.py             # Redirects 301 para redes sociales

Desarrollo

Comandos Útiles

# Activar entorno virtual
source .venv/bin/activate

# Ejecutar servidor
python manage.py runserver

# Ejecutar tests
pytest -q

# Tests con coverage
pytest --cov=saltadev --cov-report=html

# Linting y formato
pre-commit run --all-files

# Solo ruff
ruff check .
ruff format .

# Solo mypy
mypy saltadev/

# Ejecutar checks de CI localmente
uv run pytest --cov=saltadev
uv run ruff check saltadev && uv run ruff format --check saltadev
uv run mypy saltadev
uv run bandit -r saltadev -x "**/tests/**"

# Crear migraciones
python manage.py makemigrations

# Aplicar migraciones
python manage.py migrate

# Limpiar tokens expirados
python manage.py cleanup_expired_tokens

Pre-commit Hooks

El proyecto usa pre-commit con los siguientes hooks:

Hook Descripción
ruff Linting y formato de Python
biome Formato de JS/CSS/HTML y linting
bandit Análisis de seguridad en Python
detect-secrets Detección de secretos en el código
mypy Chequeo de tipos estático
# Instalar hooks
pre-commit install

# Ejecutar manualmente
pre-commit run --all-files

Estructura de Tests

tests/
├── conftest.py                     # Fixtures globales
├── test_password_validation.py     # Validación de contraseñas
├── test_password_reset_validation.py
├── test_users/                     # Tests del módulo users
│   ├── test_models.py
│   └── test_views.py
└── ...

Docker

El proyecto usa un Dockerfile unificado con docker-compose para cada ambiente.

Estructura

docker/
├── Dockerfile                    # Dockerfile unificado (multi-stage)
├── entrypoint.sh                 # Script de entrada (migraciones, collectstatic)
├── docker-compose.local.yml      # Desarrollo local con hot reload
├── docker-compose.dev.yml        # Servidor de desarrollo
├── docker-compose.staging.yml    # Staging con SSL
└── docker-compose.prod.yml       # Producción con SSL

Desarrollo Local

# Crear archivo .env.local (si no existe)
cp saltadev/.env.local.example saltadev/.env.local

# Iniciar todos los servicios (Django + PostgreSQL + Redis)
docker compose -f docker/docker-compose.local.yml up

# Ejecutar en background
docker compose -f docker/docker-compose.local.yml up -d

# Ver logs
docker compose -f docker/docker-compose.local.yml logs -f web

# Detener servicios
docker compose -f docker/docker-compose.local.yml down

# Eliminar volúmenes (reset de base de datos)
docker compose -f docker/docker-compose.local.yml down -v

El ambiente local incluye:

  • Hot reload: los cambios en saltadev/ se reflejan sin rebuild
  • Migraciones automáticas: se ejecutan al iniciar el contenedor
  • Fixtures: se cargan automáticamente (locations)
  • PostgreSQL: puerto 5432 expuesto para acceso directo
  • Redis: puerto 6379 expuesto para acceso directo

Otros Ambientes

# Development (gunicorn + nginx)
docker compose -f docker/docker-compose.dev.yml up

# Staging (gunicorn + nginx + SSL)
docker compose -f docker/docker-compose.staging.yml up

# Production (gunicorn + nginx + SSL + 4 workers)
docker compose -f docker/docker-compose.prod.yml up

Comparación de Ambientes

Ambiente Servidor Workers Hot Reload SSL
local runserver 1 No
development gunicorn 2 No No
staging gunicorn 2 No
production gunicorn 4 No

Tailwind CSS

El proyecto usa django-tailwind-cli para compilar Tailwind CSS sin necesidad de Node.js.

Desarrollo Local

# Compilar CSS una vez
cd saltadev
python manage.py tailwind build

# Watch mode (recompila automáticamente)
python manage.py tailwind watch

Docker

El CSS se compila automáticamente al iniciar los containers via entrypoint.sh.

Configuración

Archivo Descripción
saltadev/tailwind.config.js Colores, fuentes, sombras personalizadas
saltadev/static/css/source.css Directivas @tailwind
saltadev/static/css/tailwind.css Output (gitignored)

API de Credenciales

Credencial Pública

GET /credencial/<public_id>/

Muestra la credencial pública de un usuario. Incluye:

  • Foto de perfil
  • Nombre completo
  • Rol en la comunidad
  • Estado de verificación
  • DNI (si está configurado)
  • ID de miembro
  • Fecha de registro
  • Ubicación
  • Código QR verificable

La credencial se puede descargar como PNG o compartir.

Emails

Proveedores Soportados

Proveedor Backend Cuándo usar
SMTP (Gmail) django.core.mail.backends.smtp.EmailBackend Desarrollo local
Resend anymail.backends.resend.EmailBackend Render.com (SMTP bloqueado)

El sistema detecta automáticamente qué backend usar según RESEND_API_KEY:

  • Si está configurado → usa Resend via HTTP API
  • Si no → usa SMTP tradicional

Templates de Email

Los templates HTML se encuentran en templates/emails/:

Template Uso
verification.html Código de verificación de email
password_reset.html Link de recuperación de contraseña

Los emails incluyen fallback de texto plano y el logo de SaltaDev.

Contribuir

  1. Fork del repositorio
  2. Crear branch para feature (git checkout -b feature/nueva-funcionalidad)
  3. Commit de cambios (git commit -m 'Agrega nueva funcionalidad')
  4. Push al branch (git push origin feature/nueva-funcionalidad)
  5. Crear Pull Request

Guía de Estilo

  • Python: Seguir PEP 8, usar ruff para linting
  • JavaScript: Formato con Biome
  • Commits: Mensajes descriptivos en español o inglés
  • Código: Código en inglés, UI en español

Licencia

Este proyecto es propiedad de la comunidad SaltaDev.


Hecho con ❤️ en Salta, Argentina

salta.dev.arGitHubLinkedInInstagram

About

Sitio web de la comunidad SaltaDev

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors