Tienda online de chocolates artesanales construida con Flask, PostgreSQL, Nginx y Docker Compose.
Branding actual: Chocolates Patitas de Algodón.
FlaskPostgreSQLSQLAlchemyFlask-MigrateGunicornRedisNginxDocker ComposeTailwind CSS
app/: aplicación Flask, rutas, modelos, templates y assetsdb/: inicialización de base de datosnginx/: configuración del proxydocker-compose.yml: stack local y de despliegue
Usa .env.example como base:
DB_USER=valita_user
DB_PASSWORD=supersecret
SECRET_KEY=flask-secret-muy-larga-cambiar-en-prod
MP_ACCESS_TOKEN=
MP_PUBLIC_KEY=
MP_WEBHOOK_SECRET=
RATELIMIT_STORAGE_URI=redis://redis:6379/0
BASE_URL=http://localhost
APP_TIMEZONE=America/Santiago
RESEND_API_KEY=
RESEND_FROM_EMAIL=
RESEND_FROM_NAME=Chocolates Patitas de Algodón
RESEND_REPLY_TO=admin@chocolatesvalita.cl
ADMIN_EMAIL=admin@chocolatesvalita.cl
ADMIN_PASSWORD=Admin1234!Variables relevantes:
MP_ACCESS_TOKEN: token productivo de Mercado PagoMP_PUBLIC_KEY: public key de Mercado PagoMP_WEBHOOK_SECRET: secreto para validar la firma del webhookBASE_URL: URL pública del sitio, por ejemplohttps://carol.gplace.ioAPP_TIMEZONE: zona horaria de la app, por defectoAmerica/SantiagoRESEND_API_KEY: API key de ResendRESEND_FROM_EMAIL: remitente verificado en ResendRESEND_REPLY_TO: correo de respuesta para los correos transaccionales
- Crear
.enva partir de.env.example. - Instalar dependencias frontend:
npm install- Compilar CSS:
npm run build:css- Levantar el stack:
docker compose up -d --build- Poblar datos iniciales:
docker compose exec app flask seed- Abrir la tienda:
http://localhost:8888
Para desarrollo de estilos:
npm run watch:cssAcceso por defecto:
- Email:
admin@chocolatesvalita.cl - Password:
Admin1234!
Ruta:
http://localhost:8888/admin/login
- Catálogo de productos
- Detalle de producto
- Carrito en sesión
- Checkout con Mercado Pago
Checkout Pro - Seguimiento público de pedidos
- Correo transaccional de confirmación vía Resend cuando el pago queda aprobado
- Panel admin para:
- crear productos
- editar productos
- activar o desactivar productos
- eliminar productos sin historial de pedidos
- gestionar pedidos
- aceptar o rechazar pedidos
- revisar historial de cambios
El comando flask seed:
- crea el usuario admin si no existe
- carga productos base
- carga productos de Pascua
- es idempotente por nombre de producto
La integración usa Checkout Pro.
Flujo actual:
- El checkout crea una preferencia con
back_urls,notification_urlyexternal_reference. - El cliente paga en Mercado Pago.
- La app intenta reconciliar el pago por dos vías:
- webhook en
/mp/webhook - retorno del usuario a
/pago/exito,/pago/pendienteo/pago/fallo
- webhook en
- Cuando el pago queda
approved, se actualiza:payment_statusmp_payment_id- correo de confirmación al cliente
Configuración necesaria:
MP_ACCESS_TOKENMP_PUBLIC_KEYMP_WEBHOOK_SECRETBASE_URL
URLs relevantes:
https://tu-dominio/mp/webhookhttps://tu-dominio/pago/exitohttps://tu-dominio/pago/fallohttps://tu-dominio/pago/pendiente
Notas:
- La app valida firma del webhook cuando
MP_WEBHOOK_SECRETestá configurado. - Si el webhook falla o llega tarde, la reconciliación también puede ocurrir desde las
back_urls.
La app envía correo de confirmación solo cuando el pago queda approved.
Configuración necesaria:
RESEND_API_KEYRESEND_FROM_EMAILRESEND_FROM_NAMERESEND_REPLY_TO
Recomendaciones:
RESEND_FROM_EMAILdebe pertenecer a un dominio verificado en Resend.RESEND_REPLY_TOpuede ser un correo personal o comercial.
Template actual:
app/templates/emails/order_confirmation.html
Lógica de envío:
app/utils/email.py
La app guarda timestamps en UTC y los muestra en la zona definida por APP_TIMEZONE.
Valor recomendado para este proyecto:
APP_TIMEZONE=America/SantiagoEsto afecta:
- fechas mostradas en admin
- tracking público
- numeración de pedidos por fecha
- filtros y métricas del dashboard
El proyecto corre con:
docker compose up -d --buildServicios:
db: PostgreSQLredis: backend de rate limitingapp: Flask + Gunicornnginx: proxy público en puerto8888
Notas de operación:
nginxusa resolución dinámica por127.0.0.11para no quedarse pegado a IPs viejas del contenedorapp.- los uploads viven en el volumen
uploads_data Flask-Limiterusa Redis, no memoria local
Deploy validado en jp-personal:
- Host:
100.80.186.8 - Usuario SSH:
sixmanager
Stack del proyecto:
valita-db-1valita-redis-1valita-app-1valita-nginx-1
No deben tocarse otros contenedores ajenos al proyecto.
.envno se versiona.- Los assets públicos de productos viven en
app/static/uploads/. - Las fuentes del sitio viven en
app/static/fonts/. - Si expones credenciales en conversaciones o logs, rótalas después.