Compare commits
2 Commits
294dbdee91
...
bf69fe88d9
| Author | SHA1 | Date | |
|---|---|---|---|
| bf69fe88d9 | |||
| 8818246870 |
51
.env.staging.example
Normal file
51
.env.staging.example
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# Staging Environment Variables
|
||||||
|
# Testing de producción en localhost sin SSL
|
||||||
|
# Este ambiente simula producción pero permite HTTP en localhost
|
||||||
|
|
||||||
|
# Django Environment
|
||||||
|
DJANGO_ENV=staging
|
||||||
|
|
||||||
|
# Debug mode (False para simular producción)
|
||||||
|
DEBUG=False
|
||||||
|
|
||||||
|
# Django Secret Key
|
||||||
|
# Para staging local, puedes usar una key fija (NO usar en producción real)
|
||||||
|
SECRET_KEY=staging-local-key-zh6rinl@8y7g(cf781snisx2j%p^c#d&b2@@9cqe!v@4yv8x=v
|
||||||
|
|
||||||
|
# Allowed hosts (localhost para testing)
|
||||||
|
ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0
|
||||||
|
|
||||||
|
# CORS allowed origins (permite acceso desde navegador local)
|
||||||
|
# Incluye común puertos de desarrollo de frontend y acceso directo
|
||||||
|
CORS_ALLOWED_ORIGINS=http://localhost:8000,http://localhost:3000,http://localhost:5173,http://localhost:7001,http://127.0.0.1:8000
|
||||||
|
|
||||||
|
# CSRF Trusted Origins (localhost HTTP para staging)
|
||||||
|
CSRF_TRUSTED_ORIGINS=http://localhost:8000,http://127.0.0.1:8000
|
||||||
|
|
||||||
|
# PostgreSQL Database Configuration (staging local)
|
||||||
|
DB_NAME=tienda_ilusion_staging
|
||||||
|
DB_USER=tienda_ilusion_user
|
||||||
|
DB_PASSWORD=staging_local_password
|
||||||
|
DB_HOST=postgres
|
||||||
|
DB_PORT=5432
|
||||||
|
|
||||||
|
# Email Configuration (console backend para staging)
|
||||||
|
EMAIL_HOST=smtp.gmail.com
|
||||||
|
EMAIL_PORT=587
|
||||||
|
EMAIL_USE_TLS=True
|
||||||
|
EMAIL_HOST_USER=staging@tiendailusion.local
|
||||||
|
EMAIL_HOST_PASSWORD=staging_password
|
||||||
|
DEFAULT_FROM_EMAIL=staging@tiendailusion.local
|
||||||
|
|
||||||
|
# Admin notifications
|
||||||
|
ADMIN_EMAIL=admin@tiendailusion.local
|
||||||
|
|
||||||
|
# Tryton ERP Configuration (Staging)
|
||||||
|
# Ajusta estos valores según tu entorno de staging de Tryton
|
||||||
|
TRYTON_HOST=localhost
|
||||||
|
TRYTON_DATABASE=tryton_staging
|
||||||
|
TRYTON_USERNAME=admin
|
||||||
|
TRYTON_PASSWORD=admin
|
||||||
|
|
||||||
|
# Staging specific: Disable SSL redirect for localhost testing
|
||||||
|
STAGING_DISABLE_SSL=True
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -363,3 +363,4 @@ pgdata/
|
|||||||
# IDE-specific
|
# IDE-specific
|
||||||
.vscode/
|
.vscode/
|
||||||
.idea/
|
.idea/
|
||||||
|
.env.staging
|
||||||
|
|||||||
72
AGENTS.md
72
AGENTS.md
@@ -8,9 +8,11 @@ Backend Django con Django REST Framework
|
|||||||
don_confiao_backend/
|
don_confiao_backend/
|
||||||
├── requirements.txt # Dependencias Python
|
├── requirements.txt # Dependencias Python
|
||||||
├── docker-compose.dev.yml # Docker Compose para desarrollo
|
├── 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
|
├── docker-compose.prod.yml # Docker Compose para producción
|
||||||
├── django.Dockerfile # Dockerfile Django
|
├── django.Dockerfile # Dockerfile Django
|
||||||
├── .env.development # Variables de entorno desarrollo
|
├── .env.development # Variables de entorno desarrollo
|
||||||
|
├── .env.staging # Variables de entorno staging
|
||||||
├── .env.production.example # Ejemplo variables de entorno producción
|
├── .env.production.example # Ejemplo variables de entorno producción
|
||||||
├── .env_example # Ejemplo de variables de entorno
|
├── .env_example # Ejemplo de variables de entorno
|
||||||
├── README.rst # Documentación básica
|
├── README.rst # Documentación básica
|
||||||
@@ -42,6 +44,7 @@ don_confiao_backend/
|
|||||||
│ ├── __init__.py # Detección automática de ambiente
|
│ ├── __init__.py # Detección automática de ambiente
|
||||||
│ ├── base.py # Configuración compartida
|
│ ├── base.py # Configuración compartida
|
||||||
│ ├── development.py # Configuración desarrollo
|
│ ├── development.py # Configuración desarrollo
|
||||||
|
│ ├── staging.py # Configuración staging
|
||||||
│ └── production.py # Configuración producción
|
│ └── production.py # Configuración producción
|
||||||
├── urls.py
|
├── urls.py
|
||||||
├── wsgi.py
|
├── wsgi.py
|
||||||
@@ -86,20 +89,43 @@ El proyecto se ejecuta con docker-compose. Todos los comandos `manage.py` deben
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Ejecutar tests
|
# Ejecutar tests
|
||||||
docker-compose -f docker-compose.dev.yml run --rm django python manage.py test
|
docker compose -f docker-compose.dev.yml run --rm django python manage.py test
|
||||||
|
|
||||||
# Migraciones
|
# 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 makemigrations
|
||||||
docker-compose -f docker-compose.dev.yml run --rm django python manage.py migrate
|
docker compose -f docker-compose.dev.yml run --rm django python manage.py migrate
|
||||||
|
|
||||||
# Servidor desarrollo
|
# Servidor desarrollo
|
||||||
docker-compose -f docker-compose.dev.yml up
|
docker compose -f docker-compose.dev.yml up
|
||||||
|
|
||||||
# Shell Django
|
# Shell Django
|
||||||
docker-compose -f docker-compose.dev.yml run --rm django python manage.py shell
|
docker compose -f docker-compose.dev.yml run --rm django python manage.py shell
|
||||||
|
|
||||||
# Crear superuser
|
# Crear superuser
|
||||||
docker-compose -f docker-compose.dev.yml run --rm django python manage.py createsuperuser
|
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)
|
### Producción (Production)
|
||||||
@@ -110,22 +136,22 @@ cp .env.production.example .env.production
|
|||||||
# Editar .env.production con valores reales
|
# Editar .env.production con valores reales
|
||||||
|
|
||||||
# Iniciar servicios (PostgreSQL + Django con Gunicorn)
|
# Iniciar servicios (PostgreSQL + Django con Gunicorn)
|
||||||
docker-compose -f docker-compose.prod.yml up -d
|
docker compose -f docker-compose.prod.yml up -d
|
||||||
|
|
||||||
# Migraciones
|
# Migraciones
|
||||||
docker-compose -f docker-compose.prod.yml run --rm django python manage.py migrate
|
docker compose -f docker-compose.prod.yml run --rm django python manage.py migrate
|
||||||
|
|
||||||
# Colectar archivos estáticos
|
# Colectar archivos estáticos
|
||||||
docker-compose -f docker-compose.prod.yml run --rm django python manage.py collectstatic --noinput
|
docker compose -f docker-compose.prod.yml run --rm django python manage.py collectstatic --noinput
|
||||||
|
|
||||||
# Crear superuser
|
# Crear superuser
|
||||||
docker-compose -f docker-compose.prod.yml run --rm django python manage.py createsuperuser
|
docker compose -f docker-compose.prod.yml run --rm django python manage.py createsuperuser
|
||||||
|
|
||||||
# Ver logs
|
# Ver logs
|
||||||
docker-compose -f docker-compose.prod.yml logs -f django
|
docker compose -f docker-compose.prod.yml logs -f django
|
||||||
|
|
||||||
# Detener servicios
|
# Detener servicios
|
||||||
docker-compose -f docker-compose.prod.yml down
|
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`).
|
Nota: El volumen monta `tienda_ilusion/` en `/app/`, por lo que el path correcto es `python manage.py` (no `python tienda_ilusion/manage.py`).
|
||||||
@@ -143,7 +169,7 @@ Nota: El volumen monta `tienda_ilusion/` en `/app/`, por lo que el path correcto
|
|||||||
|
|
||||||
## Configuración de Ambientes
|
## Configuración de Ambientes
|
||||||
|
|
||||||
El proyecto soporta dos ambientes diferentes mediante la variable `DJANGO_ENV`:
|
El proyecto soporta tres ambientes diferentes mediante la variable `DJANGO_ENV`:
|
||||||
|
|
||||||
### Development (desarrollo local)
|
### Development (desarrollo local)
|
||||||
- **Variable de ambiente**: `DJANGO_ENV=development`
|
- **Variable de ambiente**: `DJANGO_ENV=development`
|
||||||
@@ -153,6 +179,16 @@ El proyecto soporta dos ambientes diferentes mediante la variable `DJANGO_ENV`:
|
|||||||
- **CORS**: Permisivo para desarrollo local
|
- **CORS**: Permisivo para desarrollo local
|
||||||
- **Docker Compose**: `docker-compose.dev.yml`
|
- **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)
|
### Production (producción)
|
||||||
- **Variable de ambiente**: `DJANGO_ENV=production`
|
- **Variable de ambiente**: `DJANGO_ENV=production`
|
||||||
- **Archivo de configuración**: `.env.production` (crear desde `.env.production.example`)
|
- **Archivo de configuración**: `.env.production` (crear desde `.env.production.example`)
|
||||||
@@ -167,6 +203,7 @@ El proyecto soporta dos ambientes diferentes mediante la variable `DJANGO_ENV`:
|
|||||||
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:
|
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.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`
|
- `docker-compose.prod.yml` → usa `.env.production` → carga `settings/production.py`
|
||||||
|
|
||||||
### Variables de entorno requeridas
|
### Variables de entorno requeridas
|
||||||
@@ -176,6 +213,15 @@ La detección de ambiente es automática mediante la variable `DJANGO_ENV`. Dock
|
|||||||
- `DEBUG=True`
|
- `DEBUG=True`
|
||||||
- `TRYTON_HOST`, `TRYTON_DATABASE`, `TRYTON_USERNAME`, `TRYTON_PASSWORD`
|
- `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`):
|
**Producción** (`.env.production`):
|
||||||
- `DJANGO_ENV=production`
|
- `DJANGO_ENV=production`
|
||||||
- `DEBUG=False`
|
- `DEBUG=False`
|
||||||
|
|||||||
@@ -4,5 +4,3 @@ WORKDIR /app/
|
|||||||
|
|
||||||
COPY requirements.txt ./
|
COPY requirements.txt ./
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
CMD ["python", "manage.py", "runserver", "0.0.0.0:9090"]
|
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ services:
|
|||||||
- tienda_network
|
- tienda_network
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-tienda_ilusion_user}"]
|
test:
|
||||||
|
[
|
||||||
|
"CMD-SHELL",
|
||||||
|
"pg_isready -U ${POSTGRES_USER:-tienda_ilusion_user} -d ${POSTGRES_DB:-tienda_ilusion_prod}",
|
||||||
|
]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
|
|||||||
73
docker-compose.staging.yml
Normal file
73
docker-compose.staging.yml
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
container_name: tienda_ilusion_postgres_staging
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=${DB_USER:-tienda_ilusion_user}
|
||||||
|
- POSTGRES_DB=${DB_NAME:-tienda_ilusion_staging}
|
||||||
|
- POSTGRES_PASSWORD=${DB_PASSWORD:-staging_local_password}
|
||||||
|
env_file:
|
||||||
|
- .env.staging
|
||||||
|
volumes:
|
||||||
|
- postgres_staging_data:/var/lib/postgresql/data
|
||||||
|
ports:
|
||||||
|
- "5433:5432" # Puerto diferente para no conflictuar con prod
|
||||||
|
networks:
|
||||||
|
- tienda_staging_network
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test:
|
||||||
|
[
|
||||||
|
"CMD-SHELL",
|
||||||
|
"pg_isready -U ${DB_USER:-tienda_ilusion_user} -d ${DB_PASSWORD:-tienda_ilusion_staging}",
|
||||||
|
]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
django:
|
||||||
|
build:
|
||||||
|
context: ./
|
||||||
|
dockerfile: django.Dockerfile
|
||||||
|
container_name: tienda_ilusion_django_staging
|
||||||
|
env_file:
|
||||||
|
- .env.staging
|
||||||
|
environment:
|
||||||
|
- DJANGO_ENV=staging
|
||||||
|
- DB_HOST=postgres
|
||||||
|
- DB_USER=${DB_USER:-tienda_ilusion_user}
|
||||||
|
- DB_NAME=${DB_NAME:-tienda_ilusion_staging}
|
||||||
|
- DB_PASSWORD=${DB_PASSWORD:-staging_local_password}
|
||||||
|
volumes:
|
||||||
|
- ./tienda_ilusion:/app/
|
||||||
|
- static_staging_volume:/app/staticfiles
|
||||||
|
- media_staging_volume:/app/media
|
||||||
|
- logs_staging_volume:/app/logs
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- tienda_staging_network
|
||||||
|
restart: unless-stopped
|
||||||
|
command: >
|
||||||
|
sh -c "python manage.py migrate &&
|
||||||
|
python manage.py collectstatic --noinput &&
|
||||||
|
gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 4 --timeout 120 --reload"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_staging_data:
|
||||||
|
driver: local
|
||||||
|
static_staging_volume:
|
||||||
|
driver: local
|
||||||
|
media_staging_volume:
|
||||||
|
driver: local
|
||||||
|
logs_staging_volume:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
tienda_staging_network:
|
||||||
|
driver: bridge
|
||||||
@@ -13,5 +13,5 @@ gunicorn # WSGI HTTP Server for production
|
|||||||
# Environment variable management
|
# Environment variable management
|
||||||
python-decouple # Manage environment variables and settings
|
python-decouple # Manage environment variables and settings
|
||||||
|
|
||||||
# Optional: Static files serving in production
|
# Static files serving in production/staging
|
||||||
# whitenoise # Serve static files efficiently
|
whitenoise==6.6.0 # Serve static files efficiently with compression
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ Settings module for tienda_ilusion project.
|
|||||||
|
|
||||||
This module automatically loads the appropriate settings based on the DJANGO_ENV
|
This module automatically loads the appropriate settings based on the DJANGO_ENV
|
||||||
environment variable. Valid values are:
|
environment variable. Valid values are:
|
||||||
- 'development' (default): Development settings
|
- 'development' (default): Development settings with SQLite
|
||||||
- 'production': Production settings
|
- 'staging': Staging settings for testing production config locally (PostgreSQL, no SSL)
|
||||||
|
- 'production': Production settings with full security (PostgreSQL, SSL, etc.)
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
Set DJANGO_ENV environment variable before running Django:
|
Set DJANGO_ENV environment variable before running Django:
|
||||||
@@ -13,6 +14,10 @@ Usage:
|
|||||||
export DJANGO_ENV=development
|
export DJANGO_ENV=development
|
||||||
python manage.py runserver
|
python manage.py runserver
|
||||||
|
|
||||||
|
Staging (test production locally):
|
||||||
|
export DJANGO_ENV=staging
|
||||||
|
python manage.py runserver
|
||||||
|
|
||||||
Production:
|
Production:
|
||||||
export DJANGO_ENV=production
|
export DJANGO_ENV=production
|
||||||
gunicorn config.wsgi:application
|
gunicorn config.wsgi:application
|
||||||
@@ -25,6 +30,8 @@ DJANGO_ENV = os.environ.get("DJANGO_ENV", "development")
|
|||||||
|
|
||||||
if DJANGO_ENV == "production":
|
if DJANGO_ENV == "production":
|
||||||
from .production import *
|
from .production import *
|
||||||
|
elif DJANGO_ENV == "staging":
|
||||||
|
from .staging import *
|
||||||
elif DJANGO_ENV == "development":
|
elif DJANGO_ENV == "development":
|
||||||
from .development import *
|
from .development import *
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -58,13 +58,14 @@ INSTALLED_APPS = [
|
|||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
"django.middleware.security.SecurityMiddleware",
|
"django.middleware.security.SecurityMiddleware",
|
||||||
|
"whitenoise.middleware.WhiteNoiseMiddleware", # Serve static files (must be after SecurityMiddleware)
|
||||||
|
"corsheaders.middleware.CorsMiddleware", # Must be before CommonMiddleware
|
||||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
"django.middleware.common.CommonMiddleware",
|
"django.middleware.common.CommonMiddleware",
|
||||||
"django.middleware.csrf.CsrfViewMiddleware",
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
"django.contrib.messages.middleware.MessageMiddleware",
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
"corsheaders.middleware.CorsMiddleware",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
ROOT_URLCONF = "config.urls"
|
ROOT_URLCONF = "config.urls"
|
||||||
|
|||||||
@@ -42,6 +42,29 @@ DATABASES = {
|
|||||||
# Email backend for development (prints to console)
|
# Email backend for development (prints to console)
|
||||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||||
|
|
||||||
|
# Static files configuration for development
|
||||||
|
# Note: With DEBUG=True, Django's runserver serves static files automatically
|
||||||
|
# But WhiteNoise can still be used for consistency across environments
|
||||||
|
STATIC_ROOT = BASE_DIR / "staticfiles"
|
||||||
|
STATIC_URL = "/static/"
|
||||||
|
|
||||||
|
# WhiteNoise configuration for development (optional, for consistency)
|
||||||
|
# In development with DEBUG=True, Django serves static files automatically
|
||||||
|
# But this ensures consistent behavior across all environments
|
||||||
|
STORAGES = {
|
||||||
|
"default": {
|
||||||
|
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
||||||
|
},
|
||||||
|
"staticfiles": {
|
||||||
|
"BACKEND": "whitenoise.storage.CompressedStaticFilesStorage", # No manifest in dev
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# WhiteNoise settings for development
|
||||||
|
WHITENOISE_AUTOREFRESH = True # Auto-reload static files
|
||||||
|
WHITENOISE_USE_FINDERS = True # Use Django's staticfiles finders (convenient for dev)
|
||||||
|
WHITENOISE_MANIFEST_STRICT = False # Permissive mode
|
||||||
|
|
||||||
# Enhanced logging for development
|
# Enhanced logging for development
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASSWORD", "")
|
|||||||
DEFAULT_FROM_EMAIL = os.environ.get("DEFAULT_FROM_EMAIL", "noreply@tiendailusion.com")
|
DEFAULT_FROM_EMAIL = os.environ.get("DEFAULT_FROM_EMAIL", "noreply@tiendailusion.com")
|
||||||
|
|
||||||
# Static files configuration for production
|
# Static files configuration for production
|
||||||
# Serve static files using WhiteNoise or CDN
|
|
||||||
STATIC_ROOT = BASE_DIR / "staticfiles"
|
STATIC_ROOT = BASE_DIR / "staticfiles"
|
||||||
STATIC_URL = "/static/"
|
STATIC_URL = "/static/"
|
||||||
|
|
||||||
@@ -83,10 +82,23 @@ STATIC_URL = "/static/"
|
|||||||
MEDIA_ROOT = BASE_DIR / "media"
|
MEDIA_ROOT = BASE_DIR / "media"
|
||||||
MEDIA_URL = "/media/"
|
MEDIA_URL = "/media/"
|
||||||
|
|
||||||
# Optional: WhiteNoise configuration for serving static files
|
# WhiteNoise configuration for serving static files in production
|
||||||
# Uncomment if using WhiteNoise
|
# Django 4.2+ uses STORAGES setting instead of STATICFILES_STORAGE
|
||||||
# MIDDLEWARE.insert(1, 'whitenoise.middleware.WhiteNoiseMiddleware')
|
STORAGES = {
|
||||||
# STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
"default": {
|
||||||
|
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
||||||
|
},
|
||||||
|
"staticfiles": {
|
||||||
|
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# WhiteNoise settings optimized for production
|
||||||
|
WHITENOISE_AUTOREFRESH = False # Disabled in production for better performance
|
||||||
|
WHITENOISE_USE_FINDERS = False # Use collected static files only
|
||||||
|
WHITENOISE_MANIFEST_STRICT = True # Strict mode - fail if referenced file is missing
|
||||||
|
WHITENOISE_MAX_AGE = 31536000 # 1 year cache for files with content hash
|
||||||
|
WHITENOISE_ALLOW_ALL_ORIGINS = False # Security: don't allow CORS for static files
|
||||||
|
|
||||||
# Production logging - log to file and console
|
# Production logging - log to file and console
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
|
|||||||
206
tienda_ilusion/config/settings/staging.py
Normal file
206
tienda_ilusion/config/settings/staging.py
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
"""
|
||||||
|
Staging settings for tienda_ilusion project.
|
||||||
|
|
||||||
|
This file contains settings for staging environment - simulates production
|
||||||
|
configuration but runs on localhost without SSL redirect for easier testing.
|
||||||
|
|
||||||
|
Use this environment to test production-like configuration locally before
|
||||||
|
deploying to real production.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from .base import *
|
||||||
|
|
||||||
|
# SECURITY WARNING: DEBUG is False to simulate production behavior
|
||||||
|
DEBUG = False
|
||||||
|
|
||||||
|
# SECRET_KEY for staging (use a fixed key for local staging, not for real production)
|
||||||
|
SECRET_KEY = os.environ.get(
|
||||||
|
"SECRET_KEY",
|
||||||
|
"staging-local-key-zh6rinl@8y7g(cf781snisx2j%p^c#d&b2@@9cqe!v@4yv8x=v",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Allow localhost for staging
|
||||||
|
ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "localhost,127.0.0.1,0.0.0.0").split(
|
||||||
|
","
|
||||||
|
)
|
||||||
|
|
||||||
|
# CORS settings for staging - permissive for localhost testing
|
||||||
|
CORS_ALLOWED_ORIGINS = os.environ.get(
|
||||||
|
"CORS_ALLOWED_ORIGINS",
|
||||||
|
"http://localhost:8000,http://localhost:3000,http://localhost:5173,http://localhost:7001,http://127.0.0.1:8000",
|
||||||
|
).split(",")
|
||||||
|
|
||||||
|
CORS_ALLOW_CREDENTIALS = True
|
||||||
|
|
||||||
|
# Additional CORS headers for better compatibility
|
||||||
|
CORS_ALLOW_HEADERS = [
|
||||||
|
"accept",
|
||||||
|
"accept-encoding",
|
||||||
|
"authorization",
|
||||||
|
"content-type",
|
||||||
|
"dnt",
|
||||||
|
"origin",
|
||||||
|
"user-agent",
|
||||||
|
"x-csrftoken",
|
||||||
|
"x-requested-with",
|
||||||
|
]
|
||||||
|
|
||||||
|
CORS_EXPOSE_HEADERS = ["Content-Type", "X-CSRFToken"]
|
||||||
|
|
||||||
|
# Database - PostgreSQL for staging (simulates production)
|
||||||
|
DATABASES = {
|
||||||
|
"default": {
|
||||||
|
"ENGINE": "django.db.backends.postgresql",
|
||||||
|
"NAME": os.environ.get("DB_NAME", "tienda_ilusion_staging"),
|
||||||
|
"USER": os.environ.get("DB_USER", "tienda_ilusion_user"),
|
||||||
|
"PASSWORD": os.environ.get("DB_PASSWORD", "staging_local_password"),
|
||||||
|
"HOST": os.environ.get("DB_HOST", "localhost"),
|
||||||
|
"PORT": os.environ.get("DB_PORT", "5432"),
|
||||||
|
"CONN_MAX_AGE": 600, # Persistent connections
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Security settings - DISABLED SSL redirect for localhost testing
|
||||||
|
# This is the key difference from production.py
|
||||||
|
SECURE_SSL_REDIRECT = False # Permite HTTP en localhost
|
||||||
|
SESSION_COOKIE_SECURE = False # Permite cookies sin HTTPS
|
||||||
|
CSRF_COOKIE_SECURE = False # Permite CSRF sin HTTPS
|
||||||
|
|
||||||
|
# Keep other security features enabled
|
||||||
|
SECURE_BROWSER_XSS_FILTER = True
|
||||||
|
SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||||
|
X_FRAME_OPTIONS = "DENY"
|
||||||
|
|
||||||
|
# NO HSTS for staging (only for production with real HTTPS)
|
||||||
|
SECURE_HSTS_SECONDS = 0
|
||||||
|
SECURE_HSTS_INCLUDE_SUBDOMAINS = False
|
||||||
|
SECURE_HSTS_PRELOAD = False
|
||||||
|
|
||||||
|
# Proxy headers - disabled for staging
|
||||||
|
# SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
|
|
||||||
|
# Email configuration for staging - use console backend for easier debugging
|
||||||
|
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||||
|
|
||||||
|
# Optional: Use SMTP for staging if you want to test real emails
|
||||||
|
# EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||||
|
# EMAIL_HOST = os.environ.get("EMAIL_HOST", "smtp.gmail.com")
|
||||||
|
# EMAIL_PORT = int(os.environ.get("EMAIL_PORT", "587"))
|
||||||
|
# EMAIL_USE_TLS = os.environ.get("EMAIL_USE_TLS", "True") == "True"
|
||||||
|
# EMAIL_HOST_USER = os.environ.get("EMAIL_HOST_USER", "")
|
||||||
|
# EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASSWORD", "")
|
||||||
|
# DEFAULT_FROM_EMAIL = os.environ.get("DEFAULT_FROM_EMAIL", "staging@tiendailusion.local")
|
||||||
|
|
||||||
|
# Static files configuration
|
||||||
|
STATIC_ROOT = BASE_DIR / "staticfiles"
|
||||||
|
STATIC_URL = "/static/"
|
||||||
|
|
||||||
|
# Media files configuration
|
||||||
|
MEDIA_ROOT = BASE_DIR / "media"
|
||||||
|
MEDIA_URL = "/media/"
|
||||||
|
|
||||||
|
# WhiteNoise configuration for serving static files in staging
|
||||||
|
# Django 4.2+ uses STORAGES setting instead of STATICFILES_STORAGE
|
||||||
|
STORAGES = {
|
||||||
|
"default": {
|
||||||
|
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
||||||
|
},
|
||||||
|
"staticfiles": {
|
||||||
|
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# WhiteNoise settings for staging
|
||||||
|
WHITENOISE_AUTOREFRESH = (
|
||||||
|
True # Auto-reload static files in staging (convenient for testing)
|
||||||
|
)
|
||||||
|
WHITENOISE_USE_FINDERS = False # Use collected static files only
|
||||||
|
WHITENOISE_MANIFEST_STRICT = False # More permissive in staging
|
||||||
|
WHITENOISE_MAX_AGE = 600 # 10 minutes cache for staging (allows easier testing)
|
||||||
|
|
||||||
|
# Staging logging - similar to production but more verbose
|
||||||
|
LOGGING = {
|
||||||
|
"version": 1,
|
||||||
|
"disable_existing_loggers": False,
|
||||||
|
"formatters": {
|
||||||
|
"verbose": {
|
||||||
|
"format": "[{levelname}] {asctime} {name} {message}",
|
||||||
|
"style": "{",
|
||||||
|
},
|
||||||
|
"simple": {
|
||||||
|
"format": "[{levelname}] {message}",
|
||||||
|
"style": "{",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"handlers": {
|
||||||
|
"console": {
|
||||||
|
"class": "logging.StreamHandler",
|
||||||
|
"formatter": "verbose",
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"class": "logging.handlers.RotatingFileHandler",
|
||||||
|
"filename": BASE_DIR / "logs" / "staging.log",
|
||||||
|
"maxBytes": 1024 * 1024 * 15, # 15MB
|
||||||
|
"backupCount": 10,
|
||||||
|
"formatter": "verbose",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"handlers": ["console", "file"],
|
||||||
|
"level": "INFO",
|
||||||
|
},
|
||||||
|
"loggers": {
|
||||||
|
"django": {
|
||||||
|
"handlers": ["console", "file"],
|
||||||
|
"level": "INFO",
|
||||||
|
"propagate": False,
|
||||||
|
},
|
||||||
|
"django.security": {
|
||||||
|
"handlers": ["console", "file"],
|
||||||
|
"level": "WARNING",
|
||||||
|
"propagate": False,
|
||||||
|
},
|
||||||
|
"django.db.backends": {
|
||||||
|
"handlers": ["console"],
|
||||||
|
"level": "INFO", # Show SQL queries in staging for debugging
|
||||||
|
"propagate": False,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create logs directory if it doesn't exist
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
logs_dir = BASE_DIR / "logs"
|
||||||
|
pathlib.Path(logs_dir).mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Admin email notifications
|
||||||
|
ADMINS = [
|
||||||
|
("Staging Admin", os.environ.get("ADMIN_EMAIL", "admin@tiendailusion.local")),
|
||||||
|
]
|
||||||
|
MANAGERS = ADMINS
|
||||||
|
|
||||||
|
# Cache configuration - local memory cache for staging
|
||||||
|
CACHES = {
|
||||||
|
"default": {
|
||||||
|
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
|
||||||
|
"LOCATION": "staging-cache",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Session configuration
|
||||||
|
SESSION_ENGINE = "django.contrib.sessions.backends.db"
|
||||||
|
SESSION_COOKIE_AGE = 86400 # 24 hours
|
||||||
|
SESSION_COOKIE_HTTPONLY = True
|
||||||
|
SESSION_COOKIE_SAMESITE = "Lax"
|
||||||
|
|
||||||
|
# CSRF configuration
|
||||||
|
CSRF_COOKIE_HTTPONLY = True
|
||||||
|
CSRF_COOKIE_SAMESITE = "Lax"
|
||||||
|
CSRF_TRUSTED_ORIGINS = os.environ.get(
|
||||||
|
"CSRF_TRUSTED_ORIGINS", "http://localhost:8000,http://127.0.0.1:8000"
|
||||||
|
).split(",")
|
||||||
|
|
||||||
|
# Performance optimizations
|
||||||
|
CONN_MAX_AGE = 600 # Database connection pooling
|
||||||
Reference in New Issue
Block a user