Despliegue a Producción
Sección titulada «Despliegue a Producción»Esta guía está escrita para alguien que nunca ha desplegado esta aplicación antes. Sigue los pasos en orden.
CI/CD Automatizado
Sección titulada «CI/CD Automatizado»📢 Nuevo: El proyecto ahora incluye CI/CD con GitHub Actions. Ver guía de CI/CD para:
- Build automático en cada PR
- Type checking automático
- Despliegue automático a staging (próximamente)
Esta guía cubre el despliegue manual inicial a producción. Una vez configurado, el CI/CD puede automatizar deployments futuros.
Alternativas de Despliegue
Sección titulada «Alternativas de Despliegue»Esta guía cubre Fly.io, pero también puedes desplegar en:
- Railway.app - Interfaz web más simple, $5/mes fijo
- Vercel/Netlify - Solo frontend (requiere backend separado)
- AWS ECS/Fargate - Más caro pero más control
Recomendación: Fly.io para minimizar costos ($0 en free tier), Railway para simplicidad ($5/mes).
Arquitectura de Producción
Sección titulada «Arquitectura de Producción»Usuarios │ ▼Fly.io (frontend + backend Wasp) │ ├── Neon.tech (PostgreSQL — más barato que Fly Postgres) │ └── AWS S3 + CloudFront ─┐ ├─ (videos de cursos — elige uno) └── Azure Blob Storage ─┘¿Por qué esta combinación?
| Servicio | Uso | Costo estimado |
|---|---|---|
| Fly.io | App Wasp (servidor + cliente) | ~$5-10/mes |
| Neon.tech | Base de datos PostgreSQL | Gratis (hasta 0.5 GB) / $19/mes (10 GB) |
| AWS S3 + CloudFront | Almacenamiento de videos (opción A) | ~$0.023/GB/mes + CDN |
| Azure Blob Storage | Almacenamiento de videos (opción B) | ~$0.018/GB/mes + egress |
Fase 1 — Preparación (Antes de Desplegar)
Sección titulada «Fase 1 — Preparación (Antes de Desplegar)»1.1 Requisitos
Sección titulada «1.1 Requisitos»Antes de empezar, debes tener:
- Cuenta en Fly.io (tarjeta de crédito requerida para apps de producción)
- Cuenta en Neon.tech (plan gratuito disponible)
- Almacenamiento de videos — elige una de estas opciones:
- Cuenta en Stripe con verificación completa
- Cuenta en SendGrid para emails de producción
- Wasp CLI instalado:
curl -sSL https://get.wasp-lang.dev/installer.sh | sh
1.2 Instalar Fly CLI
Sección titulada «1.2 Instalar Fly CLI»# macOSbrew install flyctl
# Linuxcurl -L https://fly.io/install.sh | sh
# Verificar instalaciónflyctl version
# Iniciar sesiónflyctl auth loginFase 2 — Base de Datos con Neon
Sección titulada «Fase 2 — Base de Datos con Neon»Neon es una alternativa más barata que Fly Postgres. El plan gratuito cubre el inicio.
2.1 Crear proyecto en Neon
Sección titulada «2.1 Crear proyecto en Neon»- Ir a neon.tech y crear una cuenta
- Hacer clic en “Create Project”
- Nombre del proyecto:
talentbricksai - Región:
US East (N. Virginia)— cercana a la región de Fly que usarás - PostgreSQL version: 16 (o la más reciente disponible)
2.2 Obtener la Connection String
Sección titulada «2.2 Obtener la Connection String»- En el dashboard de Neon, ir a Connection Details
- Copiar la Connection String — se ve así:
postgresql://username:password@ep-xxx-xxx.us-east-2.aws.neon.tech/neondb?sslmode=require- Guardar esta URL — la necesitarás en Fase 4.
Importante: Neon requiere
?sslmode=requireal final de la URL. Wasp lo necesita también.
Fase 3 — Almacenamiento de Videos
Sección titulada «Fase 3 — Almacenamiento de Videos»La app soporta dos proveedores de almacenamiento. La variable STORAGE_PROVIDER controla cuál se
usa en runtime (aws por defecto si no se configura).
STORAGE_PROVIDER=aws # usa AWS S3 + CloudFrontSTORAGE_PROVIDER=azure # usa Azure Blob StorageElige una de las siguientes opciones:
Opción A — AWS S3 + CloudFront
Sección titulada «Opción A — AWS S3 + CloudFront»3.A.1 Crear bucket S3
Sección titulada «3.A.1 Crear bucket S3»- Ir a AWS Console → S3
- Hacer clic en “Create bucket”
- Configuración:
- Bucket name:
talentbricksai-videos(debe ser único globalmente) - AWS Region:
us-east-1(North Virginia) — buena cobertura global - Block all public access: ✅ Activado (los videos serán privados, accedidos via CloudFront)
- Bucket name:
- Hacer clic en “Create bucket”
3.A.2 Crear usuario IAM para la app
Sección titulada «3.A.2 Crear usuario IAM para la app»- Ir a AWS Console → IAM
- Users → Create user
- Nombre:
talentbricksai-app - En Permissions, elegir “Attach policies directly”
- Buscar y seleccionar AmazonS3FullAccess (o crear una política más restrictiva — ver abajo)
- Crear el usuario y luego ir a Security credentials → Create access key
- Propósito: Application running outside AWS
- Guardar
Access Key IDySecret Access Key— no se pueden ver de nuevo
Política IAM mínima (más segura):
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject", "s3:ListBucket"], "Resource": ["arn:aws:s3:::talentbricksai-videos", "arn:aws:s3:::talentbricksai-videos/*"] } ]}3.A.3 Configurar CloudFront
Sección titulada «3.A.3 Configurar CloudFront»CloudFront es el CDN que entrega los videos rápidamente a cualquier parte del mundo.
- Ir a AWS Console → CloudFront
- Hacer clic en “Create distribution”
- Origin domain: seleccionar el bucket S3 que creaste
- Origin access: elegir “Origin access control settings (recommended)”
- Crear un nuevo OAC con el nombre del bucket
- Viewer protocol policy:
Redirect HTTP to HTTPS - Cache policy:
CachingOptimized(default — buena para videos) - Hacer clic en “Create distribution”
Después de crear:
- Copiar el Distribution domain name (ej.
d1234abc.cloudfront.net) - CloudFront tardará ~10 minutos en desplegarse globalmente
Autorizar CloudFront a acceder al bucket S3:
Después de crear la distribución, CloudFront te pedirá actualizar la política del bucket. Copiar y pegar la política que muestra en el bucket S3 → Permissions → Bucket policy.
3.A.4 Configurar Signed URLs (para videos privados)
Sección titulada «3.A.4 Configurar Signed URLs (para videos privados)»Los videos de cursos deben ser privados — solo accesibles por usuarios con acceso pago. Para esto se usan CloudFront Signed URLs.
- En CloudFront → tu distribución → Key management
- Key groups → Create key group
- Primero crear un Key pair (CloudFront → Key management → Public keys):
Ventana de terminal # Generar key pair localmenteopenssl genrsa -out cloudfront_private_key.pem 2048openssl rsa -pubout -in cloudfront_private_key.pem -out cloudfront_public_key.pem - Subir
cloudfront_public_key.pema CloudFront → Public keys - Copiar el Key ID que asigna CloudFront
- Guardar el contenido de
cloudfront_private_key.pem— necesario como variable de entorno
Opción B — Azure Blob Storage
Sección titulada «Opción B — Azure Blob Storage»Azure Blob Storage es más sencillo de configurar y no requiere un CDN separado. Las URLs de descarga son SAS URLs temporales (firmadas), igual que CloudFront Signed URLs.
3.B.1 Crear Storage Account
Sección titulada «3.B.1 Crear Storage Account»- Ir a Azure Portal → Storage accounts
- Hacer clic en “Create”
- Configuración:
- Storage account name:
talentbricksai(solo minúsculas y números, único globalmente) - Region: elige la más cercana a tus usuarios (ej.
East US) - Performance:
Standard - Redundancy:
LRS(Locally Redundant Storage — suficiente para empezar)
- Storage account name:
- Hacer clic en “Review + Create” → “Create”
3.B.2 Crear Container
Sección titulada «3.B.2 Crear Container»- Dentro de la Storage Account → Containers → + Container
- Nombre:
videos - Public access level:
Private(sin acceso anónimo — la app genera SAS URLs) - Hacer clic en “Create”
3.B.3 Obtener credenciales
Sección titulada «3.B.3 Obtener credenciales»- Dentro de la Storage Account → Security + networking → Access keys
- Copiar el Storage account name y una de las Keys (key1 o key2)
- Guardar ambos valores — son las credenciales de la app
Fase 4 — Despliegue en Fly.io
Sección titulada «Fase 4 — Despliegue en Fly.io»4.1 Despliegue inicial (solo una vez)
Sección titulada «4.1 Despliegue inicial (solo una vez)»Desde el directorio app/:
cd appwasp deploy fly launch talentbricksai miatalentbricksai: nombre de la app (debe ser único en Fly.io)mia: región Miami — cercana a Latinoamérica
Este comando creará dos apps en Fly.io:
talentbricksai(servidor) ytalentbricksai-client(frontend). No creará la base de datos — usaremos Neon en su lugar.
4.2 Configurar Variables de Entorno del Servidor
Sección titulada «4.2 Configurar Variables de Entorno del Servidor»Ejecutar cada comando desde el directorio app/:
# === BASE DE DATOS (Neon) ===wasp deploy fly cmd --context server secrets set \ DATABASE_URL="postgresql://user:pass@ep-xxx.us-east-2.aws.neon.tech/neondb?sslmode=require"
# === JWT (generar uno seguro) ===# Para generar: openssl rand -base64 32wasp deploy fly cmd --context server secrets set \ JWT_SECRET="tu-jwt-secret-generado-con-openssl"
# === STRIPE (modo producción — sk_live_*) ===wasp deploy fly cmd --context server secrets set \ STRIPE_API_KEY="sk_live_..."wasp deploy fly cmd --context server secrets set \ STRIPE_WEBHOOK_SECRET="whsec_..."
# === PLANES DE STRIPE (IDs de producción) ===wasp deploy fly cmd --context server secrets set \ PAYMENTS_MONTHLY_SUBSCRIPTION_PLAN_ID="price_live_..."wasp deploy fly cmd --context server secrets set \ PAYMENTS_ANNUAL_SUBSCRIPTION_PLAN_ID="price_live_..."wasp deploy fly cmd --context server secrets set \ PAYMENTS_CREDITS_10_PLAN_ID="price_live_..."
# === ALMACENAMIENTO DE VIDEOS — elige UNA opción ===
# --- Opción A: AWS S3 + CloudFront ---wasp deploy fly cmd --context server secrets set \ STORAGE_PROVIDER="aws"wasp deploy fly cmd --context server secrets set \ AWS_S3_IAM_ACCESS_KEY="AKIA..."wasp deploy fly cmd --context server secrets set \ AWS_S3_IAM_SECRET_KEY="tu-secret-key"wasp deploy fly cmd --context server secrets set \ AWS_S3_FILES_BUCKET="talentbricksai-videos"wasp deploy fly cmd --context server secrets set \ AWS_S3_REGION="us-east-1"# CloudFront (para videos privados con Signed URLs):wasp deploy fly cmd --context server secrets set \ CLOUDFRONT_DOMAIN="d1234abc.cloudfront.net"wasp deploy fly cmd --context server secrets set \ CLOUDFRONT_KEY_PAIR_ID="K1234..."# El private key va en una línea (reemplazar saltos de línea con \n)wasp deploy fly cmd --context server secrets set \ CLOUDFRONT_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nMIIE...\n-----END RSA PRIVATE KEY-----"
# --- Opción B: Azure Blob Storage ---wasp deploy fly cmd --context server secrets set \ STORAGE_PROVIDER="azure"wasp deploy fly cmd --context server secrets set \ AZURE_STORAGE_ACCOUNT_NAME="talentbricksai"wasp deploy fly cmd --context server secrets set \ AZURE_STORAGE_ACCOUNT_KEY="tu-account-key"wasp deploy fly cmd --context server secrets set \ AZURE_STORAGE_CONTAINER_NAME="videos"
# === SENDGRID (emails de producción) ===wasp deploy fly cmd --context server secrets set \ SENDGRID_API_KEY="SG...."
# === GOOGLE OAUTH (si está habilitado) ===wasp deploy fly cmd --context server secrets set \ GOOGLE_CLIENT_ID="722...apps.googleusercontent.com"wasp deploy fly cmd --context server secrets set \ GOOGLE_CLIENT_SECRET="GOC..."
# === ADMIN EMAILS ===wasp deploy fly cmd --context server secrets set \ ADMIN_EMAILS="tu@email.com"
# === NOTIFICACIONES B2B (opcional) ===wasp deploy fly cmd --context server secrets set \ SALES_NOTIFICATION_EMAIL="ventas@tuempresa.com"
# === URL del cliente ===wasp deploy fly cmd --context server secrets set \ CLIENT_URL="https://talentbricksai-client.fly.dev"
# === OPENAI (opcional — para features de AI) ===wasp deploy fly cmd --context server secrets set \ OPENAI_API_KEY="sk-..."
# === ANALYTICS (opcional) ===wasp deploy fly cmd --context server secrets set \ PLAUSIBLE_API_KEY="..."wasp deploy fly cmd --context server secrets set \ PLAUSIBLE_SITE_ID="talentbricks.ai"4.3 Variables del Cliente (Frontend)
Sección titulada «4.3 Variables del Cliente (Frontend)»wasp deploy fly cmd --context client secrets set \ REACT_APP_GOOGLE_ANALYTICS_ID="G-XXXXXXXXXX"4.4 Ejecutar el Despliegue
Sección titulada «4.4 Ejecutar el Despliegue»cd appwasp deploy fly deployEste comando:
- Construye el servidor Node.js
- Construye el cliente React
- Sube ambos a Fly.io
- Ejecuta las migraciones de base de datos automáticamente
4.5 Verificar el Despliegue
Sección titulada «4.5 Verificar el Despliegue»# Ver logs en tiempo realflyctl logs -a talentbricksai
# Ver estado de la appflyctl status -a talentbricksai
# Ver si las máquinas están corriendoflyctl machines list -a talentbricksaiLa app debería estar disponible en:
- Servidor:
https://talentbricksai.fly.dev - Cliente:
https://talentbricksai-client.fly.dev
Fase 5 — Configurar Stripe para Producción
Sección titulada «Fase 5 — Configurar Stripe para Producción»5.1 Completar Verificación de Cuenta Stripe
Sección titulada «5.1 Completar Verificación de Cuenta Stripe»- Ir a Stripe Dashboard
- Completar la verificación de negocio (puede tomar 1-2 días)
- Cambiar a Live mode (toggle en la esquina superior izquierda)
5.2 Obtener API Keys de Producción
Sección titulada «5.2 Obtener API Keys de Producción»En Live mode:
- Developers → API keys
- Copiar
Secret key(comienza consk_live_) - Copiar
Publishable key(comienza conpk_live_)
5.3 Crear Productos y Precios en Producción
Sección titulada «5.3 Crear Productos y Precios en Producción»Repetir la configuración de productos de test, pero en Live mode:
- Products → Add product
- Crear: Suscripción Mensual ($19), Suscripción Anual ($149), cursos individuales ($29-99)
- Copiar los Price IDs (comienzan con
price_) y actualizar las variables de entorno
5.4 Configurar Webhook de Producción
Sección titulada «5.4 Configurar Webhook de Producción»- Developers → Webhooks → Add endpoint
- Endpoint URL:
https://talentbricksai.fly.dev/payments-webhook - Eventos a escuchar:
checkout.session.completedinvoice.paidcustomer.subscription.updatedcustomer.subscription.deleted
- Copiar el Signing secret y actualizar
STRIPE_WEBHOOK_SECRET
Fase 6 — Dominio Personalizado (Opcional)
Sección titulada «Fase 6 — Dominio Personalizado (Opcional)»6.1 Asignar IP estática
Sección titulada «6.1 Asignar IP estática»flyctl ips allocate-v4 -a talentbricksai-clientflyctl ips list -a talentbricksai-client6.2 Configurar DNS
Sección titulada «6.2 Configurar DNS»En tu proveedor de DNS (Namecheap, Cloudflare, etc.):
| Tipo | Host | Valor |
|---|---|---|
| A | @ | IP del cliente de Fly.io |
| A | www | IP del cliente de Fly.io |
| CNAME | api | talentbricksai.fly.dev |
6.3 Agregar Dominio en Fly
Sección titulada «6.3 Agregar Dominio en Fly»flyctl certs add talentbricks.ai -a talentbricksai-clientflyctl certs add www.talentbricks.ai -a talentbricksai-client6.4 Actualizar Variables de Entorno
Sección titulada «6.4 Actualizar Variables de Entorno»wasp deploy fly cmd --context server secrets set CLIENT_URL="https://talentbricks.ai"Luego redesplegar:
cd app && wasp deploy fly deployDespliegues Subsecuentes
Sección titulada «Despliegues Subsecuentes»⚠️ IMPORTANTE: Usar siempre make deploy
Sección titulada «⚠️ IMPORTANTE: Usar siempre make deploy»NUNCA ejecutar wasp deploy fly deploy directamente. Siempre usar:
cd appmake deploymake deploy hace dos cosas en orden:
-
make deploy-client— construye con Wasp y despliega el cliente usando un Dockerfile basado en nginx (en lugar delgostaticque genera Wasp). Esto es lo que aplica los security headers. ElREACT_APP_API_URLse pasa automáticamente apuntando atalentbricksai.fly.dev. -
make deploy-server— despliega el servidor con--skip-clientpara no sobreescribir el Dockerfile de nginx.
También puedes desplegar cada componente por separado:
make deploy-client # solo frontend (nginx + security headers)make deploy-server # solo backend¿Por qué no usar wasp deploy fly deploy directamente?
- Sin
--skip-client: sobreescribe el Dockerfile del cliente congostatic, que no soporta headers HTTP, eliminando todos los security headers. - Sin
REACT_APP_API_URL: Wasp genera la URL del servidor comotalentbricksai-server.fly.dev, que no existe. Nuestro servidor se llamatalentbricksai(sin-server).
Los archivos clave del cliente:
app/client-Dockerfile+app/client-nginx.conf— fuente de verdad para nginxapp/scripts/deploy-client.sh— script invocado pormake deploy-client
Security headers aplicados por nginx:
Content-Security-Policy(CSP)X-Frame-Options: DENYX-Content-Type-Options: nosniffReferrer-Policy: strict-origin-when-cross-originPermissions-PolicyStrict-Transport-Security(HSTS)
Orden recomendado para deploys
Sección titulada «Orden recomendado para deploys»- Commits de código: Commitear y pushear cambios a git primero
- Variables de entorno: Actualizar secrets de Fly si es necesario
- Deploy:
cd app && make deploy - Verificación: Revisar logs y probar funcionalidad crítica
# Ver logs en tiempo real durante el deployflyctl logs -a talentbricksai
# Verificar estado después del deployflyctl status -a talentbricksaiflyctl status -a talentbricksai-client
# Verificar security headers del clientecurl -I https://talentbricksai-client.fly.dev/# Debe mostrar: X-Frame-Options, X-Content-Type-Options, Content-Security-Policy, etc.
# Verificar que el JS del cliente tiene la URL correctaJS_FILE=$(curl -s https://talentbricksai-client.fly.dev/ | grep -o 'assets/[^"]*\.js' | head -1)curl -s "https://talentbricksai-client.fly.dev/$JS_FILE" | grep -o 'https://talentbricksai[^"]*\.fly\.dev'# Debe mostrar: https://talentbricksai.fly.devMonitoreo
Sección titulada «Monitoreo»Ver Logs
Sección titulada «Ver Logs»# Todos los logsflyctl logs -a talentbricksai
# Solo erroresflyctl logs -a talentbricksai | grep -i error
# Logs del clienteflyctl logs -a talentbricksai-clientDashboard de Fly.io
Sección titulada «Dashboard de Fly.io»Visitar fly.io/dashboard:
- Métricas de CPU/memoria
- Estado de las máquinas
- Historial de deployments
Dashboard de Neon
Sección titulada «Dashboard de Neon»Visitar console.neon.tech:
- Uso de almacenamiento
- Queries activas
- Métricas de rendimiento
Backup de Base de Datos
Sección titulada «Backup de Base de Datos»Desde Neon (automático)
Sección titulada «Desde Neon (automático)»Neon incluye backups automáticos en todos los planes. Para restaurar, usar el Point-in-time restore desde el dashboard.
Backup Manual
Sección titulada «Backup Manual»# Instalar pg_dump si no lo tienes# macOS: brew install postgresql
# Hacer backuppg_dump "postgresql://user:pass@ep-xxx.us-east-2.aws.neon.tech/neondb?sslmode=require" \ > backup-$(date +%Y%m%d).sql
# Restaurarpsql "postgresql://user:pass@ep-xxx.us-east-2.aws.neon.tech/neondb?sslmode=require" \ < backup-20260217.sqlCostos Estimados de Producción
Sección titulada «Costos Estimados de Producción»Inicio (bajo tráfico)
Sección titulada «Inicio (bajo tráfico)»| Servicio | Plan | Costo/mes |
|---|---|---|
| Fly.io — Servidor | shared-cpu-1x, 512MB | ~$6.38 |
| Fly.io — Cliente | shared-cpu-1x, 256MB | ~$3.19 |
| Neon — DB | Free tier (0.5 GB) | $0 |
| AWS S3 | ~50 GB almacenamiento | ~$1.15 |
| AWS CloudFront | ~100 GB transferencia | ~$0.85 |
| Total estimado | ~$12-15/mes |
Crecimiento (medio tráfico)
Sección titulada «Crecimiento (medio tráfico)»| Servicio | Plan | Costo/mes |
|---|---|---|
| Fly.io — Servidor | shared-cpu-2x, 512MB | ~$6.38 |
| Fly.io — Cliente | shared-cpu-1x, 256MB | ~$3.19 |
| Neon — DB | Launch plan (10 GB) | $19 |
| AWS S3 | ~500 GB | ~$11.50 |
| AWS CloudFront | ~1 TB | ~$8.50 |
| Total estimado | ~$50-60/mes |
Troubleshooting
Sección titulada «Troubleshooting»Error: “DATABASE_URL is required”
Sección titulada «Error: “DATABASE_URL is required”»Verificar que la variable fue configurada correctamente:
flyctl ssh console -a talentbricksai -C "env | grep DATABASE"Error: “Connection refused” (base de datos)
Sección titulada «Error: “Connection refused” (base de datos)»- Verificar que la URL de Neon incluye
?sslmode=require - Verificar que Neon permite conexiones desde Fly.io (Neon permite todas por defecto)
Error: “Stripe webhook failed”
Sección titulada «Error: “Stripe webhook failed”»- Verificar que
STRIPE_WEBHOOK_SECRETcorresponde al webhook de producción (no el de test) - Verificar que la URL del webhook es
https://talentbricksai.fly.dev/payments-webhook - Ver logs:
flyctl logs -a talentbricksai | grep -i stripe
Error: “S3 access denied”
Sección titulada «Error: “S3 access denied”»- Verificar
AWS_S3_IAM_ACCESS_KEYyAWS_S3_IAM_SECRET_KEY - Verificar que el usuario IAM tiene los permisos correctos en S3
- Verificar que
AWS_S3_FILES_BUCKETcoincide exactamente con el nombre del bucket
Error: “Azure storage error” / “AuthenticationFailed”
Sección titulada «Error: “Azure storage error” / “AuthenticationFailed”»- Verificar que
AZURE_STORAGE_ACCOUNT_NAMEes el nombre exacto de la Storage Account (sin espacios, minúsculas) - Verificar que
AZURE_STORAGE_ACCOUNT_KEYes la key completa (base64, ~88 caracteres) - Verificar que
AZURE_STORAGE_CONTAINER_NAMEcoincide con el container creado en Azure - Verificar que
STORAGE_PROVIDER=azureestá configurado
App no carga después del deploy
Sección titulada «App no carga después del deploy»# Ver estadoflyctl status -a talentbricksai
# Reiniciar si está en estado incorrectoflyctl apps restart talentbricksai
# Ver máquinasflyctl machines list -a talentbricksaiError: CORS / App crashea constantemente / Health checks fallan
Sección titulada «Error: CORS / App crashea constantemente / Health checks fallan»Síntomas:
- Errores CORS: “No ‘Access-Control-Allow-Origin’ header”
- Health checks fallando repetidamente
- App se reinicia constantemente
- Logs muestran:
Out of memory: Killed process
Causa: Memoria insuficiente (256 MB es muy poco para Node.js + Prisma + Express).
Solución:
- Actualizar
fly-server.toml(configuración permanente):
[[vm]] size = "shared-cpu-1x" memory = "512mb" # Cambiado de 256mb- Aplicar el cambio inmediatamente (sin redesplegar):
flyctl scale memory 512 -a talentbricksai- Verificar que funciona:
flyctl status -a talentbricksai# Debe mostrar: Memory: 512 MBNota importante: Con 256 MB, el servidor crashea antes de poder enviar respuestas (incluidos headers CORS), causando errores engañosos de CORS cuando en realidad es un problema de memoria.
Error: “ERR_NAME_NOT_RESOLVED” al cargar el cliente
Sección titulada «Error: “ERR_NAME_NOT_RESOLVED” al cargar el cliente»Síntoma: El cliente muestra errores de conexión al servidor:
POST https://talentbricksai-server.fly.dev/operations/... net::ERR_NAME_NOT_RESOLVEDCausa: Se ejecutó wasp deploy fly deploy sin --skip-client, lo que reemplaza el Dockerfile
del cliente con la versión de gostatic que no tiene la URL correcta del servidor.
Solución: Redesplegar el cliente usando el script correcto:
cd app./scripts/deploy-client.shEl script construye con Wasp y luego sobreescribe el Dockerfile con la versión nginx que incluye los security headers y la configuración correcta.
Checklist Final de Producción
Sección titulada «Checklist Final de Producción»Base de datos:
- Neon proyecto creado y connection string guardada
-
DATABASE_URLconfigurada en Fly con?sslmode=require - Migraciones ejecutadas (el primer deploy las corre automáticamente)
Pagos:
- Stripe en modo Live (no Test)
- Productos y precios creados en Live mode
-
STRIPE_API_KEYessk_live_*(nosk_test_*) - Webhook configurado con URL de producción
-
STRIPE_WEBHOOK_SECRETdel webhook de producción
Videos (AWS S3 + CloudFront):
-
STORAGE_PROVIDER=awsconfigurado en Fly - Bucket S3 creado con acceso público bloqueado
- CloudFront distribución creada y apuntando al bucket
- Policy del bucket actualizada para CloudFront OAC
- Key pair de CloudFront generado y configurado para Signed URLs
- Variables
AWS_S3_*yCLOUDFRONT_*configuradas en Fly
Videos (Azure Blob Storage — alternativa a AWS):
-
STORAGE_PROVIDER=azureconfigurado en Fly - Storage Account creada en Azure
- Container
videoscreado con acceso privado - Variables
AZURE_STORAGE_ACCOUNT_NAME,AZURE_STORAGE_ACCOUNT_KEY,AZURE_STORAGE_CONTAINER_NAMEconfiguradas en Fly
Email:
- SendGrid cuenta verificada y dominio autenticado
-
SENDGRID_API_KEYconfigurada - Email de “From” verificado en SendGrid
-
SALES_NOTIFICATION_EMAILconfigurada (opcional — para recibir alertas de demos B2B)
App:
-
CLIENT_URLapunta al dominio correcto (con https://) -
ADMIN_EMAILSincluye los emails de los admins -
JWT_SECRETes aleatorio y seguro (mínimo 32 caracteres)
Verificación:
- Login funciona con un usuario real
- Email de verificación llega correctamente
- Pago de prueba con tarjeta real de Stripe completa
- Video de curso carga desde CloudFront
- Panel admin accesible con cuenta admin