- Add docker-compose.staging.yml with PostgreSQL and Django - Add .env.staging.example with staging-specific environment variables - Configure staging settings (DEBUG=False, no SSL redirect for localhost) - Update settings/__init__.py to support staging environment detection - Update AGENTS.md with staging environment documentation - Update .gitignore to exclude .env.staging - Optimize docker-compose.prod.yml configuration Staging environment simulates production configuration locally: - PostgreSQL database (port 5433 to avoid conflicts) - Gunicorn with 4 workers - DEBUG=False but HTTP allowed for easier testing - Separate volumes for static files, media, and logs Usage: cp .env.staging.example .env.staging docker compose -f docker-compose.staging.yml up -d
434 lines
16 KiB
Markdown
434 lines
16 KiB
Markdown
# Don Confiao Backend - Contexto del Proyecto
|
|
|
|
## Tipo de Proyecto
|
|
Backend Django con Django REST Framework
|
|
|
|
## Estructura del Proyecto
|
|
```
|
|
don_confiao_backend/
|
|
├── requirements.txt # Dependencias Python
|
|
├── docker-compose.dev.yml # Docker Compose para desarrollo
|
|
├── docker-compose.staging.yml # Docker Compose para staging (testing producción local)
|
|
├── docker-compose.prod.yml # Docker Compose para producción
|
|
├── django.Dockerfile # Dockerfile Django
|
|
├── .env.development # Variables de entorno desarrollo
|
|
├── .env.staging # Variables de entorno staging
|
|
├── .env.production.example # Ejemplo variables de entorno producción
|
|
├── .env_example # Ejemplo de variables de entorno
|
|
├── README.rst # Documentación básica
|
|
├── Rakefile # Tareas rake
|
|
├── doc/ # Documentación adicional
|
|
│ └── requests.org
|
|
└── tienda_ilusion/ # Proyecto Django
|
|
├── manage.py
|
|
├── db.sqlite3 # Base de datos SQLite (desarrollo)
|
|
├── don_confiao/ # App principal
|
|
│ ├── models.py # Modelos: Customer, Product, Sale, SaleLine, Payment, ReconciliationJar, AdminCode
|
|
│ ├── views.py
|
|
│ ├── api_views.py
|
|
│ ├── serializers.py
|
|
│ ├── forms.py
|
|
│ ├── admin.py
|
|
│ ├── urls.py
|
|
│ ├── export_csv.py
|
|
│ ├── tests/ # Tests
|
|
│ └── migrations/
|
|
├── users/ # App de usuarios
|
|
│ ├── models.py
|
|
│ ├── views.py
|
|
│ ├── serializers.py
|
|
│ ├── urls.py
|
|
│ └── tests/
|
|
└── config/ # Configuración Django
|
|
├── settings/ # Settings por ambiente
|
|
│ ├── __init__.py # Detección automática de ambiente
|
|
│ ├── base.py # Configuración compartida
|
|
│ ├── development.py # Configuración desarrollo
|
|
│ ├── staging.py # Configuración staging
|
|
│ └── production.py # Configuración producción
|
|
├── urls.py
|
|
├── wsgi.py
|
|
└── asgi.py
|
|
```
|
|
|
|
## Dependencias Principales
|
|
- Django==5.0.6
|
|
- djangorestframework
|
|
- django-cors-headers
|
|
- djangorestframework-simplejwt
|
|
- sabatron-tryton-rpc-client==7.4.0 (integración con Tryton ERP)
|
|
- psycopg2-binary (driver PostgreSQL para producción)
|
|
- gunicorn (servidor WSGI para producción)
|
|
- python-decouple (gestión de variables de entorno)
|
|
|
|
## Modelos Principales (don_confiao/models.py)
|
|
- **Customer**: Clientes (name, address, email, phone, external_id)
|
|
- **Product**: Productos (name, price, measuring_unit, categories)
|
|
- **ProductCategory**: Categorías de productos
|
|
- **Sale**: Ventas (customer, date, phone, description, payment_method, reconciliation)
|
|
- **SaleLine**: Líneas de venta (sale, product, quantity, unit_price, description)
|
|
- **Payment**: Pagos (date_time, type_payment, amount, reconciliation_jar)
|
|
- **PaymentSale**: Relación muchos a muchos entre Payment y Sale
|
|
- **ReconciliationJar**: Arqueo de caja (is_valid, date_time, reconcilier, cash_taken, cash_discrepancy)
|
|
- **AdminCode**: Códigos de administrador
|
|
|
|
## Autenticación
|
|
- JWT con djangorestframework-simplejwt
|
|
- ACCESS_TOKEN_LIFETIME: 30 minutos
|
|
- REFRESH_TOKEN_LIFETIME: 1 día
|
|
|
|
## API Endpoints
|
|
- REST API en don_confiao/api_views.py y users/
|
|
- URLs en don_confiao/urls.py y users/urls.py
|
|
|
|
## Ejecución con Docker Compose
|
|
|
|
El proyecto se ejecuta con docker-compose. Todos los comandos `manage.py` deben ejecutarse dentro del contenedor:
|
|
|
|
### Desarrollo (Development)
|
|
|
|
```bash
|
|
# Ejecutar tests
|
|
docker compose -f docker-compose.dev.yml run --rm django python manage.py test
|
|
|
|
# Migraciones
|
|
docker compose -f docker-compose.dev.yml run --rm django python manage.py makemigrations
|
|
docker compose -f docker-compose.dev.yml run --rm django python manage.py migrate
|
|
|
|
# Servidor desarrollo
|
|
docker compose -f docker-compose.dev.yml up
|
|
|
|
# Shell Django
|
|
docker compose -f docker-compose.dev.yml run --rm django python manage.py shell
|
|
|
|
# Crear superuser
|
|
docker compose -f docker-compose.dev.yml run --rm django python manage.py createsuperuser
|
|
```
|
|
|
|
### Staging (Testing Producción Local)
|
|
|
|
```bash
|
|
# Iniciar servicios (PostgreSQL + Django con Gunicorn)
|
|
# Ya incluye el archivo .env.staging, listo para usar
|
|
docker compose -f docker-compose.staging.yml up -d
|
|
|
|
# Migraciones
|
|
docker compose -f docker-compose.staging.yml run --rm django python manage.py migrate
|
|
|
|
# Colectar archivos estáticos
|
|
docker compose -f docker-compose.staging.yml run --rm django python manage.py collectstatic --noinput
|
|
|
|
# Crear superuser
|
|
docker compose -f docker-compose.staging.yml run --rm django python manage.py createsuperuser
|
|
|
|
# Ver logs
|
|
docker compose -f docker-compose.staging.yml logs -f django
|
|
|
|
# Detener servicios
|
|
docker compose -f docker-compose.staging.yml down
|
|
```
|
|
|
|
### Producción (Production)
|
|
|
|
```bash
|
|
# Primero, copiar .env.production.example a .env.production y configurar variables
|
|
cp .env.production.example .env.production
|
|
# Editar .env.production con valores reales
|
|
|
|
# Iniciar servicios (PostgreSQL + Django con Gunicorn)
|
|
docker compose -f docker-compose.prod.yml up -d
|
|
|
|
# Migraciones
|
|
docker compose -f docker-compose.prod.yml run --rm django python manage.py migrate
|
|
|
|
# Colectar archivos estáticos
|
|
docker compose -f docker-compose.prod.yml run --rm django python manage.py collectstatic --noinput
|
|
|
|
# Crear superuser
|
|
docker compose -f docker-compose.prod.yml run --rm django python manage.py createsuperuser
|
|
|
|
# Ver logs
|
|
docker compose -f docker-compose.prod.yml logs -f django
|
|
|
|
# Detener servicios
|
|
docker compose -f docker-compose.prod.yml down
|
|
```
|
|
|
|
Nota: El volumen monta `tienda_ilusion/` en `/app/`, por lo que el path correcto es `python manage.py` (no `python tienda_ilusion/manage.py`).
|
|
|
|
## Tests
|
|
- Framework: Django unittest
|
|
- Directorio: don_confiao/tests/
|
|
- Ejecutar: `docker-compose -f docker-compose.dev.yml run --rm django python manage.py test`
|
|
|
|
## Comandos Útiles (dentro del contenedor)
|
|
- Migraciones: `docker-compose -f docker-compose.dev.yml run --rm django python manage.py makemigrations && docker-compose -f docker-compose.dev.yml run --rm django python manage.py migrate`
|
|
- Servidor desarrollo: `docker-compose -f docker-compose.dev.yml up`
|
|
- Shell Django: `docker-compose -f docker-compose.dev.yml run --rm django python manage.py shell`
|
|
- Superuser: `docker-compose -f docker-compose.dev.yml run --rm django python manage.py createsuperuser`
|
|
|
|
## Configuración de Ambientes
|
|
|
|
El proyecto soporta tres ambientes diferentes mediante la variable `DJANGO_ENV`:
|
|
|
|
### Development (desarrollo local)
|
|
- **Variable de ambiente**: `DJANGO_ENV=development`
|
|
- **Archivo de configuración**: `.env.development`
|
|
- **Base de datos**: SQLite (db.sqlite3)
|
|
- **DEBUG**: True
|
|
- **CORS**: Permisivo para desarrollo local
|
|
- **Docker Compose**: `docker-compose.dev.yml`
|
|
|
|
### Staging (testing de producción local)
|
|
- **Variable de ambiente**: `DJANGO_ENV=staging`
|
|
- **Archivo de configuración**: `.env.staging`
|
|
- **Base de datos**: PostgreSQL (tienda_ilusion_staging)
|
|
- **DEBUG**: False (simula producción)
|
|
- **CORS**: Permisivo para localhost (sin SSL redirect)
|
|
- **Docker Compose**: `docker-compose.staging.yml`
|
|
- **Servidor**: Gunicorn con 4 workers
|
|
- **Puerto PostgreSQL**: 5433 (para no conflictuar con producción)
|
|
|
|
### Production (producción)
|
|
- **Variable de ambiente**: `DJANGO_ENV=production`
|
|
- **Archivo de configuración**: `.env.production` (crear desde `.env.production.example`)
|
|
- **Base de datos**: PostgreSQL
|
|
- **DEBUG**: False
|
|
- **Seguridad**: HTTPS, HSTS, secure cookies, CSRF protections
|
|
- **Docker Compose**: `docker-compose.prod.yml`
|
|
- **Servidor**: Gunicorn con 4 workers
|
|
|
|
### Cambiar entre ambientes
|
|
|
|
La detección de ambiente es automática mediante la variable `DJANGO_ENV`. Docker Compose configura esta variable automáticamente según el archivo usado:
|
|
|
|
- `docker-compose.dev.yml` → usa `.env.development` → carga `settings/development.py`
|
|
- `docker-compose.staging.yml` → usa `.env.staging` → carga `settings/staging.py`
|
|
- `docker-compose.prod.yml` → usa `.env.production` → carga `settings/production.py`
|
|
|
|
### Variables de entorno requeridas
|
|
|
|
**Desarrollo** (`.env.development`):
|
|
- `DJANGO_ENV=development`
|
|
- `DEBUG=True`
|
|
- `TRYTON_HOST`, `TRYTON_DATABASE`, `TRYTON_USERNAME`, `TRYTON_PASSWORD`
|
|
|
|
**Staging** (`.env.staging`):
|
|
- `DJANGO_ENV=staging`
|
|
- `DEBUG=False`
|
|
- `SECRET_KEY` (para staging local, puede ser una key fija)
|
|
- `ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0`
|
|
- `CORS_ALLOWED_ORIGINS` (URLs localhost separadas por comas)
|
|
- `DB_NAME=tienda_ilusion_staging`, `DB_USER`, `DB_PASSWORD`, `DB_HOST=postgres`, `DB_PORT=5432`
|
|
- `TRYTON_HOST`, `TRYTON_DATABASE`, `TRYTON_USERNAME`, `TRYTON_PASSWORD`
|
|
|
|
**Producción** (`.env.production`):
|
|
- `DJANGO_ENV=production`
|
|
- `DEBUG=False`
|
|
- `SECRET_KEY` (generar una nueva y segura)
|
|
- `ALLOWED_HOSTS` (dominios separados por comas)
|
|
- `CORS_ALLOWED_ORIGINS` (URLs separadas por comas)
|
|
- `CSRF_TRUSTED_ORIGINS` (URLs separadas por comas)
|
|
- `DB_NAME`, `DB_USER`, `DB_PASSWORD`, `DB_HOST`, `DB_PORT`
|
|
- `EMAIL_HOST`, `EMAIL_PORT`, `EMAIL_HOST_USER`, `EMAIL_HOST_PASSWORD`
|
|
- `TRYTON_HOST`, `TRYTON_DATABASE`, `TRYTON_USERNAME`, `TRYTON_PASSWORD`
|
|
|
|
Ver `.env.production.example` para todos los detalles.
|
|
|
|
## Scripts Útiles
|
|
|
|
El proyecto incluye scripts para facilitar operaciones comunes:
|
|
|
|
### Health Check
|
|
Verifica el estado de todos los servicios:
|
|
```bash
|
|
# Verificar ambiente de desarrollo
|
|
./scripts/health-check.sh dev
|
|
|
|
# Verificar ambiente de producción
|
|
./scripts/health-check.sh prod
|
|
```
|
|
|
|
### Backup de Base de Datos (Producción)
|
|
Crea un backup comprimido de la base de datos PostgreSQL:
|
|
```bash
|
|
./scripts/backup-db.sh
|
|
```
|
|
|
|
Los backups se guardan en `backups/` y se mantienen por 7 días automáticamente.
|
|
|
|
### Restore de Base de Datos (Producción)
|
|
Restaura un backup de la base de datos:
|
|
```bash
|
|
./scripts/restore-backup.sh <archivo_backup.sql.gz>
|
|
```
|
|
|
|
**ADVERTENCIA**: Esto reemplazará la base de datos actual. Se crea un backup de seguridad antes de restaurar.
|
|
|
|
## Troubleshooting
|
|
|
|
### Errores Comunes
|
|
|
|
#### 1. Error: "database 'tienda_ilusion_user' does not exist"
|
|
**Síntoma**: Aparece en los logs de PostgreSQL
|
|
```
|
|
FATAL: database "tienda_ilusion_user" does not exist
|
|
```
|
|
|
|
**Causa**: Este es un comportamiento normal de PostgreSQL. Cuando te conectas sin especificar una base de datos, PostgreSQL intenta conectarse a una base con el mismo nombre del usuario.
|
|
|
|
**Solución**: Este error NO afecta el funcionamiento de Django. Para verificar que la base de datos correcta existe:
|
|
```bash
|
|
docker exec tienda_ilusion_postgres_prod psql -U tienda_ilusion_user -d tienda_ilusion_prod -c '\l'
|
|
```
|
|
|
|
#### 2. Error: "required variable DB_PASSWORD is missing a value"
|
|
**Síntoma**: Docker Compose falla al iniciar con error de variable faltante
|
|
|
|
**Causa**: El archivo `.env.production` no existe o tiene valores placeholder
|
|
|
|
**Solución**:
|
|
1. Copiar el archivo de ejemplo: `cp .env.production.example .env.production`
|
|
2. Editar `.env.production` y reemplazar todos los valores `CHANGE-ME-...` con valores reales
|
|
3. Generar SECRET_KEY segura:
|
|
```bash
|
|
python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'
|
|
```
|
|
|
|
#### 3. Error: "ModuleNotFoundError" o importación fallida
|
|
**Síntoma**: Django no puede importar módulos después de cambiar configuración
|
|
|
|
**Causa**: Dependencias no instaladas o contenedor con caché viejo
|
|
|
|
**Solución**:
|
|
```bash
|
|
# Reconstruir contenedores
|
|
docker-compose -f docker-compose.dev.yml build --no-cache
|
|
docker-compose -f docker-compose.dev.yml up
|
|
|
|
# Para producción
|
|
docker-compose -f docker-compose.prod.yml build --no-cache
|
|
docker-compose -f docker-compose.prod.yml up -d
|
|
```
|
|
|
|
#### 4. Error: "django.db.utils.OperationalError: could not connect to server"
|
|
**Síntoma**: Django no puede conectarse a PostgreSQL
|
|
|
|
**Causa**: PostgreSQL aún no está listo cuando Django intenta conectar
|
|
|
|
**Solución**: El healthcheck en `docker-compose.prod.yml` maneja esto automáticamente. Si el problema persiste:
|
|
```bash
|
|
# Verificar que PostgreSQL esté corriendo
|
|
docker ps | grep postgres
|
|
|
|
# Ver logs de PostgreSQL
|
|
docker logs tienda_ilusion_postgres_prod
|
|
|
|
# Reiniciar servicios en orden
|
|
docker-compose -f docker-compose.prod.yml restart postgres
|
|
docker-compose -f docker-compose.prod.yml restart django
|
|
```
|
|
|
|
#### 5. Error: "CSRF verification failed"
|
|
**Síntoma**: Errores CSRF en producción
|
|
|
|
**Causa**: `CSRF_TRUSTED_ORIGINS` no configurado correctamente
|
|
|
|
**Solución**: En `.env.production`, asegurar que `CSRF_TRUSTED_ORIGINS` incluya el protocolo:
|
|
```bash
|
|
CSRF_TRUSTED_ORIGINS=https://tudominio.com,https://www.tudominio.com
|
|
```
|
|
|
|
#### 6. Static files no se sirven en producción
|
|
**Síntoma**: CSS/JS no cargan, errores 404 para archivos estáticos
|
|
|
|
**Causa**: `collectstatic` no ejecutado o configuración de nginx incorrecta
|
|
|
|
**Solución**:
|
|
```bash
|
|
# Ejecutar collectstatic
|
|
docker-compose -f docker-compose.prod.yml exec django python manage.py collectstatic --noinput
|
|
|
|
# Verificar que los archivos existen
|
|
docker exec tienda_ilusion_django_prod ls -la /app/staticfiles
|
|
```
|
|
|
|
#### 7. Migraciones pendientes después de deployment
|
|
**Síntoma**: Errores de base de datos o tablas faltantes
|
|
|
|
**Causa**: Migraciones no aplicadas en producción
|
|
|
|
**Solución**:
|
|
```bash
|
|
# Ver estado de migraciones
|
|
docker-compose -f docker-compose.prod.yml exec django python manage.py showmigrations
|
|
|
|
# Aplicar migraciones pendientes
|
|
docker-compose -f docker-compose.prod.yml exec django python manage.py migrate
|
|
```
|
|
|
|
### Comandos de Diagnóstico
|
|
|
|
```bash
|
|
# Ver todos los contenedores
|
|
docker ps -a
|
|
|
|
# Ver logs en tiempo real
|
|
docker-compose -f docker-compose.prod.yml logs -f
|
|
|
|
# Ver logs solo de Django
|
|
docker logs -f tienda_ilusion_django_prod
|
|
|
|
# Ver logs solo de PostgreSQL
|
|
docker logs -f tienda_ilusion_postgres_prod
|
|
|
|
# Ejecutar shell en contenedor Django
|
|
docker-compose -f docker-compose.prod.yml exec django bash
|
|
|
|
# Ejecutar Django shell
|
|
docker-compose -f docker-compose.prod.yml exec django python manage.py shell
|
|
|
|
# Conectar a PostgreSQL
|
|
docker exec -it tienda_ilusion_postgres_prod psql -U tienda_ilusion_user -d tienda_ilusion_prod
|
|
|
|
# Verificar variables de entorno en contenedor
|
|
docker-compose -f docker-compose.prod.yml exec django env | grep DJANGO
|
|
```
|
|
|
|
### Performance y Optimización
|
|
|
|
Si experimentas problemas de rendimiento:
|
|
|
|
1. **Verificar recursos del contenedor**:
|
|
```bash
|
|
docker stats
|
|
```
|
|
|
|
2. **Ajustar workers de Gunicorn** (editar `docker-compose.prod.yml`):
|
|
```yaml
|
|
command: gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 8 --timeout 120
|
|
```
|
|
Regla general: `workers = (2 x CPU cores) + 1`
|
|
|
|
3. **Habilitar persistent connections**: Ya configurado en `settings/production.py` con `CONN_MAX_AGE = 600`
|
|
|
|
4. **Considerar agregar Redis para caché**: Descomentar sección de Redis en `settings/production.py`
|
|
|
|
### Seguridad
|
|
|
|
Antes de ir a producción, verificar:
|
|
|
|
- [ ] `DEBUG=False` en `.env.production`
|
|
- [ ] `SECRET_KEY` único y seguro generado
|
|
- [ ] `ALLOWED_HOSTS` configurado con dominios reales
|
|
- [ ] `CORS_ALLOWED_ORIGINS` limitado a orígenes confiables
|
|
- [ ] `CSRF_TRUSTED_ORIGINS` configurado correctamente
|
|
- [ ] Contraseñas de base de datos seguras
|
|
- [ ] `.env.production` NO commiteado a git
|
|
- [ ] HTTPS habilitado (certificados SSL/TLS configurados)
|
|
- [ ] Firewall configurado (solo puertos necesarios abiertos)
|
|
- [ ] Backups automáticos configurados
|
|
|
|
## Integraciones
|
|
- **Tryton ERP**: Integración mediante sabatron-tryton-rpc-client para sincronización de clientes, productos y ventas
|