Variables de entorno
Qué hace cada ajuste de los archivos .env de la API y de los frontends, y cuáles necesitas.
Para el paquete Full Stack
Dónde están los ajustes
| Archivo | Lo lee | Contiene secretos |
|---|---|---|
back-end/.env | La API, con yarn dev y dentro de Docker | Sí. Nunca lo incluyas en un commit. |
frontend/.env | El sitio para estudiantes, durante la construcción | No. Todos los valores son públicos. |
admin-dashboard/.env | El panel de administración, durante la construcción | No. Todos los valores son públicos. |
.env junto a docker-compose.yml | Docker Compose, para el paquete Full Stack | No |
Crea cada archivo a partir del .env.example que tiene al lado, que documenta todas las variables: cp .env.example .env. Los ejemplos funcionan tal cual para una ejecución local.
Dónde están los ajustes
Un solo archivo, frontend/.env, que se lee al construir el sitio. Todos sus valores son públicos, así que nunca contiene un secreto. Créalo a partir de .env.example, que documenta cada variable: cp .env.example .env.
Dónde están los ajustes
Un solo archivo, admin-dashboard/.env, que se lee al construir el panel. Todos sus valores son públicos, así que nunca contiene un secreto. Omítelo para usar la simulación; créalo a partir de .env.example cuando conectes una API: cp .env.example .env.
Dónde están los ajustes
Un solo archivo, back-end/.env, que la API lee con yarn dev y dentro de Docker. Contiene secretos: nunca lo incluyas en un commit. Créalo a partir de .env.example, que documenta cada variable y funciona tal cual para una ejecución local: cp .env.example .env.
Lo esencial de la API
La API comprueba estas variables antes de iniciarse. Si falta alguna o no es válida, se detiene con una lista breve de lo que hay que corregir.
| Variable | Qué hace |
|---|---|
NODE_ENV | development en local, production en un servidor en producción. |
PORT | El puerto de la API, 8000. Ambos frontends apuntan a él. |
DB_TYPE | sqlite (el predeterminado) o mysql. |
SQLITE_DATABASE | Ruta del archivo SQLite, ./database.sqlite por defecto. |
JWT_SECRET | Firma cada inicio de sesión. Obligatorio. El valor de ejemplo solo se acepta en desarrollo. |
JWT_EXPIRATION | Cuánto dura un inicio de sesión, 7d por defecto. |
CORS_ORIGIN | Las direcciones del sitio para estudiantes y del panel de administración, separadas por comas. Obligatorio en producción. |
FRONTEND_URL | La dirección del sitio para estudiantes, usada en los enlaces que envía la API. |
Genera tu propio JWT_SECRET con:
node -e "console.log(require('crypto').randomBytes(48).toString('hex'))"Usa MySQL en lugar de SQLite
Crea una base de datos vacía y luego configura el controlador y la conexión en back-end/.env:
DB_TYPE=mysql
DB_HOST=your-mysql-host
DB_PORT=3306
DB_USERNAME=your-mysql-username
DB_PASSWORD=your-mysql-password
DB_DATABASE=your-database-nameDespués ejecuta yarn seed para los datos de demostración, o yarn db:sync en un sitio en producción, que crea las tablas sin escribir ninguna fila. La API en ejecución solo actualiza el esquema por sí misma cuando NODE_ENV=development.
Sitio para estudiantes y panel de administración
Todos los valores de aquí son NEXT_PUBLIC_* y se compilan en el JavaScript que carga el navegador. Nunca pongas un secreto en estos archivos, y vuelve a construir la aplicación después de cambiar uno.
| Variable | Aplicación | Qué hace |
|---|---|---|
NEXT_PUBLIC_API_BASE_URL | Ambos | La dirección de la API incluyendo /api, por ejemplo http://localhost:8000/api. Si se deja vacía, la aplicación usa sus datos de ejemplo. |
NEXT_PUBLIC_SITE_URL | Ambos | La dirección pública del sitio para estudiantes, usada para los enlaces canónicos, las vistas previas al compartir y el mapa del sitio. En producción, pon tu dominio real. |
NEXT_PUBLIC_MEDIA_HOSTNAME | Ambos | El host público de tu bucket de archivos multimedia, sin https://. Déjalo vacío hasta que tengas un bucket. |
NEXT_PUBLIC_WEBSOCKET_BASE_URL | Panel de administración | La dirección de la API sin /api, para las notificaciones en tiempo real. |
NEXT_PUBLIC_SAMPLE_DATA_NOTICE | Ambos | Opcional. always muestra el aviso "Sample data" también en una versión de producción cuando la API deja de responder. El docker-compose.yml de la raíz lo define; un sitio en producción normalmente lo deja sin definir. |
API_INTERNAL_URL | Sitio para estudiantes | Opcional, solo en el servidor. La dirección por la que el propio servidor del sitio llega a la API cuando difiere de la del navegador, como dentro de Docker Compose. |
Opciones de Docker Compose
No hay que configurar nada para una ejecución local. Para cambiar algo, ponlo en un archivo .env junto a docker-compose.yml y vuelve a ejecutar docker compose up --build: los frontends compilan estos valores en su código.
| Variable | Qué hace |
|---|---|
SITE_PORT, ADMIN_PORT, API_PORT | Los puertos de tu ordenador: 3030, 3031 y 8000 por defecto. Pon uno cuando otro programa ya use ese puerto, por ejemplo ADMIN_PORT=3041. Las direcciones de abajo, CORS_ORIGIN y FRONTEND_URL los siguen. |
SITE_URL, ADMIN_URL, API_URL | Dónde llega el navegador a cada aplicación. Configura las tres cuando sirvas el conjunto en tus propios dominios. |
MEDIA_HOSTNAME | El host público de tu bucket, junto con las variables R2_* en back-end/.env. |
SEED_DEMO_DATA | false empieza con las tablas vacías en lugar de los datos de demostración. |
El contenedor de la API también lee back-end/.env cuando existe, así que las claves de correo, pagos, archivos multimedia e IA se configuran en un solo lugar tanto para yarn dev como para Docker.
Almacenamiento multimedia
Las imágenes de los cursos, los avatares, las imágenes del blog, los videos de las lecciones y los materiales se suben a un bucket de Cloudflare R2, o a cualquiera compatible con S3. Configura las cinco variables en back-end/.env y da a ambos frontends el host público del bucket mediante NEXT_PUBLIC_MEDIA_HOSTNAME.
R2_ACCESS_KEY_ID=
R2_SECRET_ACCESS_KEY=
R2_ENDPOINT=
R2_BUCKET_NAME=
R2_PUBLIC_URL=Sin un bucket, el script de carga de datos guarda rutas a archivos de ejemplo que incluyen los propios frontends, así que todas las imágenes y los videos de las lecciones funcionan en local. Solo deja de funcionar la subida de nuevos archivos multimedia.
Correo electrónico
Las confirmaciones de email, los restablecimientos de contraseña, los recibos y las confirmaciones de inscripción se envían a través de Resend. Sin RESEND_API_KEY, la aplicación sigue funcionando y escribe cada mensaje en su registro.
RESEND_API_KEY=
MAIL_FROM=Learnio <noreply@example.com>
MAIL_MAX_PER_ADDRESS_PER_DAY=5
MAIL_MAX_PER_SENDER_PER_DAY=20- Usa una clave con acceso solo de envío, no una con acceso completo.
MAIL_FROMdebe pertenecer a un dominio que hayas verificado en Resend; de lo contrario, se rechaza cada envío.- Los dos límites fijan cuántos mensajes al día puede recibir una dirección y cuántos puede provocar un mismo remitente.
- El nombre del producto dentro de cada mensaje y su dirección de respuesta no son variables: son los ajustes
site_nameysupport_emailde la pestaña App Settings de Settings, en el panel de administración, y se leen para cada mensaje que se envía.
Pagos
De serie, el pago funciona con un simulador integrado: no se contacta con ningún procesador y no se cobra nada. Un número de tarjeta que termina en 0 se rechaza, para que puedas probar el caso de fallo.
Rellena las claves de un procesador y ese método de pago pasa al procesador real. Configura tanto Stripe como PayPal antes de aceptar pedidos reales: el pago siempre ofrece tarjeta y PayPal, y un pedido pagado con el simulador se completa sin que se cobre a nadie.
Los cursos gratuitos (precio 0) no necesitan ningún procesador: su pago se completa en la API sin él, sean cuales sean las claves definidas.
| Procesador | Variables | Endpoint del webhook |
|---|---|---|
| Stripe | STRIPE_SECRET_KEY, STRIPE_PUBLISHABLE_KEY, STRIPE_WEBHOOK_SECRET | POST <api>/api/webhooks/payments/stripe |
| PayPal | PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PAYPAL_WEBHOOK_ID, PAYPAL_ENV | POST <api>/api/webhooks/payments/paypal |
El webhook concede la plaza
Un estudiante queda inscrito cuando el procesador confirma el pago a través del webhook, no cuando vuelve de la página de pago. Sin la suscripción al webhook, los pedidos se quedan pendientes.
- Suscribe Stripe a
checkout.session.completed,payment_intent.payment_failedycharge.refunded. - Suscribe PayPal a
PAYMENT.CAPTURE.COMPLETED,PAYMENT.CAPTURE.DENIED,PAYMENT.CAPTURE.REFUNDEDyPAYMENT.CAPTURE.REVERSED. PAYPAL_ENVessandboxpor defecto, que no cobra dinero real. Las credenciales de producción pertenecen a otra app de PayPal, así que pasar a producción requiere claves nuevas además dePAYPAL_ENV=live.
Asistente de IA
Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.
Activar el asistente de IA: las claves de los proveedores, cómo se ofrece cada modelo y qué ve el administrador sin clave.
Clases en vivo
Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.
Configurar las clases en directo: conectar un servidor Jitsi Meet, los tokens de acceso seguros y los controles del anfitrión.
Datos de ejemplo en los frontends
Ambos frontends siguen funcionando cuando no se puede acceder a la API: sirven los datos de ejemplo incluidos y muestran un aviso "Sample data" al pie de la página. En una versión de producción solo aparece cuando no hay ninguna API configurada, salvo que la app se haya compilado con NEXT_PUBLIC_SAMPLE_DATA_NOTICE=always, como hace el docker-compose.yml de la raíz.
- Los datos de ejemplo del panel de administración cubren el inicio de sesión, los estudiantes, el personal, los roles, las categorías, los ajustes, las notificaciones, la búsqueda y el historial de chats del asistente. Sus demás pantallas (las cifras del resumen, cursos, instructores, inscripciones, pedidos, reseñas, blog, agenda, cuestionarios y mensajes) necesitan la API.
- Con los datos de ejemplo, el inicio de sesión del panel de administración acepta cualquier correo y contraseña, y guarda tus cambios en el navegador. Para empezar de cero, ejecuta
localStorage.removeItem("mock_db_v1"); location.reload();en la consola del navegador. - El asistente de IA no está disponible con los datos de ejemplo, porque necesita las claves de la API.
- Cuando tu API esté en producción,
yarn remove:mocken cualquiera de las dos aplicaciones elimina la capa de datos de ejemplo.
Cómo funciona la capa de datos de ejemplo
Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.
Cómo se dirigen las solicitudes a los datos incluidos, y cómo cambiarlos o ampliarlos.
Modo demostración
Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.
Publicar una demo: el interruptor de la demo, las cuentas por visitante, el límite de mensajes y cómo quitarlo todo.