Configuración del entorno
Closegram tiene tres lugares separados que necesitan configuración de entorno, cada uno con su propio archivo:
| App | Archivo | Plantilla |
|---|
apps/backend | .env (también .env.dev para Docker, .env.test para el stack de pruebas) | .env.example |
apps/frontend-nextjs | .env.local | .env.local.example |
apps/ios | No es un archivo .env real — las variables se configuran directamente en el scheme de Xcode (ver iOS más abajo) | apps/ios/app/.env.example (solo de referencia) |
Esta página es una referencia completa de cada variable en las tres. Para instrucciones paso a paso sobre cómo obtener los valores reales de claves/secretos (Firebase, Google, Apple, Stripe, AWS, Twilio, etc.), consulta Obtención de claves API. Para cómo difieren estas variables entre local/development/production y qué valores van en el dashboard de Railway por entorno, consulta Entornos de despliegue.
Inicio rápido
# Backend
cd apps/backend
cp .env.example .env
# completa los valores — consulta las tablas de abajo y la guía de claves API
# Frontend
cd apps/frontend-nextjs
cp .env.local.example .env.local
Genera un secreto aleatorio seguro para cualquier valor *_SECRET con:
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
Infraestructura local vía Docker (recomendado)
No necesitas cuentas reales de base de datos, Redis o LiveKit para desarrollar localmente — apps/backend/docker-compose.yml levanta los tres con credenciales de desarrollo integradas:
cd apps/backend
npm run docker:up # postgres + redis + redis-livekit + livekit, usando .env.dev
npm run migrate # ejecuta las migraciones contra el Postgres dockerizado
npm run seed # opcional — datos de siembra
| Servicio | Contenedor | Puerto por defecto | Credenciales por defecto |
|---|
| PostgreSQL | closegram-postgres | 5432 | usuario postgres / contraseña closegram_postgres_pass / bd closegram_dev |
| Redis | closegram-redis | 6382 (host) → 6379 (contenedor) | contraseña closegram_redis_pass |
| Redis (instancia dedicada de LiveKit) | closegram-redis-livekit | 6381 | contraseña livekit_redis_pass |
| Servidor LiveKit | closegram-livekit | 7880 (HTTP), 7881 (TCP), 7882 (UDP) | clave API devkey / secreto dev1234567890abcdef1234567890abcdef (fijo en docker-compose.yml, solo desarrollo) |
| Redis Commander (GUI, opcional) | closegram-redis-commander | vía --profile gui | admin / admin |
Como la clave de desarrollo de LiveKit está integrada en el archivo compose, puedes dejar LIVEKIT_URL, LIVEKIT_API_KEY y LIVEKIT_API_SECRET en tu .env apuntando a ws://localhost:7880 / devkey / dev1234567890abcdef1234567890abcdef para el desarrollo local — no se necesita cuenta de LiveKit Cloud hasta que despliegues. Otros scripts útiles: npm run docker:down, npm run docker:reset (borra los volúmenes), npm run docker:up:test (Postgres/Redis de prueba separado en puertos distintos), npm run redis:cli / redis:cli:livekit.
Qué es realmente necesario
No todas las variables de abajo necesitan un valor real para ejecutar la app localmente. En resumen:
- Necesario para arrancar del todo: Base de datos (
DB_*), secretos JWT (JWT_*). Sin ellos el backend no arranca o la autenticación no funciona.
- Necesario para funcionalidades específicas, de lo contrario esa funcionalidad se degrada silenciosamente: Firebase (verificación de inicio de sesión con Google + push), inicio de sesión con Apple (
APPLE_*), Stripe (pagos — DISABLE_STRIPE=true para omitirlo), AWS S3 (subida de archivos — DISABLE_S3=true usa respuestas simuladas), SMS/Twilio (OTP por teléfono — DISABLE_SMS=true para omitirlo), LiveKit (llamadas/en vivo — ver la sección de Docker más arriba, DISABLE_LIVEKIT=true para omitirlo).
- Opcional / solo observabilidad: Redis se puede omitir con
DISABLE_REDIS=true (aunque varias funcionalidades en tiempo real dependen de él — ver Infraestructura), Sentry/Datadog/New Relic/LogRocket/logger personalizado, analítica de BigQuery (recae en Postgres vía ANALYTICS_DB_TYPE=postgres), PayPal, MessageBird.
- Vestigial — definido en
.env.example pero no leído por ningún código del backend (confirmado buscando en el código fuente, seguro dejarlo en blanco o eliminarlo): DEEPAI_API_KEY, AWS_PINPOINT_PROJECT_ID, GMAIL_USER_NAME / GMAIL_USER_PASSWORD / GMAIL_SERVICE_HOST / GMAIL_SERVICE_PORT (no existe una ruta de envío por Gmail/nodemailer — EMAIL_PROVIDER solo tiene una implementación aws-ses a pesar de ser nominalmente conectable).
Backend — apps/backend/.env
Aplicación
| Variable | Ejemplo | Propósito |
|---|
NODE_ENV | development | Selecciona qué archivo .env.<NODE_ENV> se carga |
APP_NAME | Closegram | Nombre visible usado en correos/logs |
APP_VERSION / BACKEND_VERSION | 1.0.0 | Etiquetas de versión para logging/release de Sentry |
BACKEND_PORT / PORT | 8000 | Puerto del servidor |
API_URL | http://localhost:8000 | URL pública propia del backend |
FRONTEND_URL | http://localhost:3000 | Se usa para construir enlaces en correos, CORS |
TIMEZONE | America/Los_Angeles | Zona horaria por defecto del servidor |
WEBAUTHN_RP_ID | localhost | Passkeys. Solo el dominio registrable — sin esquema/puerto/ruta (p. ej. closegram.com). Debe configurarse en producción, de lo contrario el registro de passkey falla con The RP ID "localhost" is invalid for this domain |
WEBAUTHN_ORIGIN | FRONTEND_URL | Passkeys. Origen(es) completo(s) permitidos para ejecutar la ceremonia, incl. https, sin barra final. Separa con comas para múltiples (p. ej. https://closegram.com,https://www.closegram.com) |
WEBAUTHN_RP_NAME | APP_NAME | Passkeys. Nombre mostrado en el prompt de passkey del sistema operativo |
Base de datos
| Variable | Propósito |
|---|
DB_HOST / DB_PORT / DB_NAME / DB_USER / DB_PASSWORD / DB_DIALECT | Piezas estándar de conexión Sequelize/Postgres |
DEV_DATABASE_URL / DATABASE_URL | Alternativa de cadena de conexión completa (usada por algunas herramientas) |
Redis
| Variable | Propósito |
|---|
REDIS_HOST / REDIS_PORT / REDIS_PASSWORD | Conexión — potencia presencia, caché de chat, caché de OTP, BullMQ, suscripciones pub/sub |
DISABLE_REDIS | Configura true para ejecutar sin Redis (degrada las funcionalidades anteriores) |
REDIS_COMMANDER_USER / REDIS_COMMANDER_PASSWORD | Inicio de sesión para la GUI opcional de Redis Commander |
Traducción de chat (opcional)
Potencia el modo de traducción dentro del chat (message-translation.service.js). Independiente del proveedor: el primer proveedor configurado gana, en este orden — LibreTranslate → DeepL → Google Translate → OpenAI. Si ninguno está configurado, la funcionalidad se desactiva silenciosamente (el botón de traducir se oculta y el chat muestra el texto original), así que estas son totalmente opcionales. Las traducciones se almacenan en caché en Postgres (message_translation) por mensaje + idioma, así que cada proveedor se llama como máximo una vez por mensaje por idioma.
| Variable | Propósito |
|---|
LIBRETRANSLATE_URL | URL base de una instancia de LibreTranslate (p. ej. https://libretranslate.com o la tuya autoalojada). Opción más económica/autoalojable; habilita el proveedor cuando está configurada |
LIBRETRANSLATE_API_KEY | Clave API opcional si tu instancia de LibreTranslate la requiere |
DEEPL_API_KEY | Clave API de DeepL (plan gratuito: 500 mil caracteres/mes). Se usa si LibreTranslate no está configurado |
DEEPL_API_URL | URL base opcional de DeepL — por defecto https://api-free.deepl.com; usa https://api.deepl.com para el plan de pago |
GOOGLE_TRANSLATE_API_KEY | Clave API de Google Cloud Translation v2. Se usa si las anteriores no están configuradas |
OPENAI_API_KEY | Clave de OpenAI — respaldo de traducción basado en LLM si no hay un traductor dedicado configurado |
OPENAI_TRANSLATE_MODEL | Modelo para la traducción con OpenAI (por defecto gpt-4o-mini) |
TRANSLATION_MONTHLY_CHAR_LIMIT | Límite estricto opcional de caracteres traducidos por mes calendario (rastreado en Redis). 0/sin configurar = sin límite. Al alcanzarlo, la traducción se detiene hasta el siguiente mes — una válvula de seguridad de gasto |
TRANSLATION_MAX_CHARS | Límite de caracteres por mensaje enviado a la API (por defecto 5000) |
TRANSLATION_HTTP_TIMEOUT_MS | Tiempo de espera para una llamada HTTP al proveedor (por defecto 8000) |
JWT
| Variable | Propósito |
|---|
JWT_SECRET | Firma los tokens de acceso de usuarios regulares |
JWT_REFRESH_SECRET | Firma los tokens de refresco |
JWT_ADMIN_SECRET | Firma los tokens de sesión del panel de administración |
JWT_TOKEN_EXPIRY | p. ej. 8h |
JWT_TEMP_TOKEN_EXPIRY | p. ej. 10m — tokens de corta duración (desafío 2FA, etc.) |
Passkeys (WebAuthn)
Compartidas tanto por las passkeys de la app principal (services/passkey.service.js) como por las passkeys de administrador (services/admin-passkey.service.js) — no hay una variable separada solo para admin. Ambas usan por defecto localhost/FRONTEND_URL para desarrollo local, pero deben configurarse explícitamente en producción o el registro falla con The RP ID "localhost" is invalid for this domain (o, si solo WEBAUTHN_ORIGIN está mal configurado, con Unexpected registration response origin).
| Variable | Ejemplo | Propósito |
|---|
WEBAUTHN_RP_ID | closegram.com | El dominio registrable solamente — sin esquema, sin puerto, sin ruta. Debe ser el dominio del origen o un padre registrable de este (p. ej. closegram.com también es válido para admin.closegram.com — no se necesita un valor separado para el panel de administración). Por defecto es localhost. |
WEBAUTHN_ORIGIN | https://closegram.com,https://admin.closegram.com | El/los origen(es) completo(s) autorizados para realizar la ceremonia, incluyendo el esquema. Separados por comas para varios — debe incluir tanto el origen de la app cliente como el del panel de administración (son subdominios distintos), o el registro de passkeys de administrador falla. Sin barra final. Por defecto es FRONTEND_URL. |
WEBAUTHN_RP_NAME | Closegram | Nombre para mostrar en el diálogo de passkey del sistema operativo. Por defecto es APP_NAME. |
Consulta el bloque WEBAUTHN_* en apps/backend/.env.example para un ejemplo real de producción, y Cuentas de administrador para el detalle específico del origen en admin.
AWS — S3, SES, SNS
| Variable | Propósito |
|---|
AWS_REGION | p. ej. us-east-1 |
AWS_ACCESS_KEY / AWS_ACCESS_KEY_ID, AWS_SECRET_KEY / AWS_SECRET_ACCESS_KEY | Credenciales de IAM (ambas variantes de nombre se leen en distintos lugares) |
AWS_BUCKET_NAME / AWS_S3_URL | Bucket S3 para subidas |
AWS_API_VERSION / AWS_PROFILE / AWS_TOKEN_KEY | Configuración diversa del SDK de AWS |
STORAGE_PROVIDER | Actualmente solo aws-s3 está implementado |
DISABLE_S3 | true usa respuestas simuladas de subida localmente |
AWS_EMAIL / AWS_EMAIL_NAME | Dirección/nombre "from" de SES |
AWS_S3_EMAIL_TEMPLATES_PATH | Ruta en S3 para las plantillas de correo Pug |
AWS_CONFIGURATION_NAME | Conjunto de configuración de SES (seguimiento de rebotes/quejas) |
AWS_SNS_SENDER_ID | ID de remitente SMS de SNS |
AWS_PINPOINT_PROJECT_ID | No se referencia en ningún lugar del backend — vestigial |
Correo
| Variable | Propósito |
|---|
EMAIL_PROVIDER | Solo aws-ses tiene una implementación a pesar de ser nominalmente conectable |
DISABLE_EMAIL | Omite el envío de correos localmente |
VERIFIED_EMAIL_TIME_WAIT / VERIFIED_EMAIL_LIMIT_TIMES / VERIFIED_EMAIL_TIME_TRANSFORM | Limitación de frecuencia del código de verificación de correo |
GMAIL_USER_NAME / GMAIL_USER_PASSWORD / GMAIL_SERVICE_HOST / GMAIL_SERVICE_PORT | Vestigial — no existe una ruta de envío por Gmail/nodemailer |
SMS / OTP por teléfono
| Variable | Propósito |
|---|
SMS_PROVIDER | twilio (por defecto), aws-sns o messagebird |
SMS_ORIGINATOR_PHONE | Etiqueta del remitente |
DISABLE_SMS | Omite el envío de SMS localmente |
VERIFIED_SMS_TIME_WAIT / VERIFIED_SMS_LIMIT_TIMES / VERIFIED_SMS_TIME_TRANSFORM | Limitación de frecuencia del OTP |
TWILIO_ACCOUNT_SID / TWILIO_AUTH_TOKEN / TWILIO_PHONE_NUMBER / TWILIO_VERIFY_SERVICE_SID | Credenciales de Twilio |
MESSAGEBIRD_API_KEY / MESSAGEBIRD_ORIGINATOR | Credenciales de MessageBird (proveedor alternativo) |
PHONE_LOGIN_PROVIDER | Interruptor de cómo funciona "iniciar sesión / agregar cuenta con número de teléfono": firebase (por defecto — el cliente web usa Firebase Phone Auth, este servidor no envía SMS), twilio (mutations heredadas requestPhoneOtp/loginWithPhone, este servidor envía el OTP él mismo), o disabled (login por teléfono desactivado por completo, incluso vía Firebase). Reflejado en el frontend por NEXT_PUBLIC_PHONE_LOGIN_PROVIDER. |
Stripe / PayPal
| Variable | Propósito |
|---|
STRIPE_API_KEY_PROD_SECRET | Clave secreta de Stripe |
STRIPE_WEBHOOK_SECRET | Verifica las firmas de los webhooks entrantes de Stripe |
PAYMENT_PROVIDER | Actualmente stripe |
DISABLE_STRIPE | Omite el procesamiento de pagos localmente |
PAYPAL_CLIENT_ID / PAYPAL_CLIENT_SECRET | Credenciales de la app de PayPal |
PAYPAL_API_BASE | Por defecto usa la URL de sandbox si no se configura |
Compras dentro de la app (Apple / Google IAP)
Las monedas compradas dentro de las apps nativas iOS/Android se validan del lado del servidor contra cada tienda y luego se acreditan (ver Monedas). Es aparte del flujo web de Stripe/PayPal de arriba. Cómo obtener cada credencial: guía de API keys → Compras en app.
| Variable | Propósito |
|---|
APPLE_IAP_ISSUER_ID | Issuer ID de la API key de App Store Connect (para el App Store Server API) |
APPLE_IAP_KEY_ID | El Key ID (kid) de la API key de App Store Connect |
APPLE_IAP_PRIVATE_KEY | Contenido del .p8 (en línea; \n-escapado está bien) |
APPLE_IAP_BUNDLE_ID | Bundle id de la app iOS (p. ej. com.closegram.app) |
APPLE_IAP_ENVIRONMENT | production o sandbox — opcional; el servicio prueba producción y cae a sandbox |
GOOGLE_IAP_PACKAGE_NAME | applicationId de Android (p. ej. com.closegram.app) |
GOOGLE_IAP_SERVICE_ACCOUNT_KEY | JSON de service account (como string) con acceso a Android Publisher |
Webhooks de reembolso de tiendas — descuentan monedas cuando una tienda reembolsa/revoca una compra. Endpoints: POST /api/webhooks/apple/iap (App Store Server Notifications V2) y POST /api/webhooks/google/rtdn (Google RTDN vía Pub/Sub push). APPLE_IAP_ROOT_CERT es requerido para el webhook de reembolso de Apple — falla en cerrado y rechaza las notificaciones sin un root anclado. Las vars de Google son opcionales (su chequeo de token se salta si no se configuran):
| Variable | Propósito |
|---|
APPLE_IAP_ROOT_CERT | Requerido para el webhook de reembolso de Apple — PEM del Apple Root CA — G3. Sin él, el webhook rechaza toda notificación (fail-closed). |
GOOGLE_RTDN_AUDIENCE | (opcional) Audiencia esperada del token OIDC del push de Pub/Sub — normalmente la URL de tu webhook |
GOOGLE_RTDN_SA_EMAIL | (opcional) Email de la service account del push de Pub/Sub autorizada a llamar al webhook |
Firebase (notificaciones push + verificación de auth de Google/teléfono)
| Variable | Propósito |
|---|
FIREBASE_PROJECT_ID | ID del proyecto de Firebase |
FIREBASE_PRIVATE_KEY_ID / FIREBASE_PRIVATE_KEY / FIREBASE_CLIENT_EMAIL / FIREBASE_CLIENT_ID | Credenciales de cuenta de servicio (de la clave JSON descargada) |
FIREBASE_AUTH_URI / FIREBASE_TOKEN_URI / FIREBASE_AUTH_PROVIDER_CERT_URL / FIREBASE_CLIENT_CERT_URL / FIREBASE_UNIVERSE_DOMAIN | Campos estándar del JSON de cuenta de servicio — copia tal cual |
FIREBASE_DATABASE_URL / FIREBASE_STORAGE_BUCKET | URLs del proyecto |
FIREBASE_SERVICE_ACCOUNT_PATH | Alternativa a las credenciales FIREBASE_* en línea — ruta a un archivo JSON de cuenta de servicio |
DISABLE_PUSH_NOTIFICATIONS | Omite el envío de push localmente |
Inicio de sesión con Apple
| Variable | Propósito |
|---|
APPLE_CLIENT_ID | El Bundle ID de la app iOS nativa (p. ej. com.yourapp.bundle) — el claim aud de los ID tokens que emite Sign in with Apple dentro de la app iOS. No es el Services ID de abajo, pese al nombre. |
APPLE_WEB_CLIENT_ID | El Services ID separado para Sign in with Apple en la web (registrado en Apple Developer, ligado a un dominio verificado + Return URLs) — no es lo mismo que APPLE_CLIENT_ID/Bundle ID de arriba. Debe coincidir con NEXT_PUBLIC_APPLE_CLIENT_ID en frontend-nextjs. Déjalo sin configurar si no tienes montado el Sign in with Apple web. |
APPLE_TEAM_ID | Team ID de Apple Developer |
APPLE_KEY_ID | ID de la clave privada de Sign in with Apple |
APPLE_REDIRECT_URI | URL de redirección de OAuth (flujo web) |
APPLE_PRIVATE_KEY | El contenido de la clave privada .p8 (en línea) |
APPLE_PRIVATE_KEY_PATH | Alternativa a APPLE_PRIVATE_KEY — ruta (relativa a apps/backend) al archivo .p8 (apple-auth.service.js) |
APPLE_KEY_P8 | Nombre del archivo de la clave .p8 dentro de apps/backend/utils/ (estrategia OAuth heredada passport-apple) |
Apple Push Notifications (APNs) — llamadas/VoIP en iOS
| Variable | Propósito |
|---|
APNS_PRIVATE_KEY / APNS_KEY_ID / APNS_TEAM_ID | Clave de autenticación APNs (clave separada de Sign in with Apple) |
APNS_BUNDLE_ID | Bundle ID de la app de iOS |
APNS_PRODUCTION | false para APNs de sandbox, true para producción |
Google Cloud / BigQuery (analítica)
| Variable | Propósito |
|---|
GOOGLE_CLOUD_PROJECT_ID / GCP_PROJECT_ID | Proyecto de GCP |
BIGQUERY_DATASET_ID / BIGQUERY_LOCATION | Configuración del dataset |
BIGQUERY_PRIVATE_KEY_ID / BIGQUERY_PRIVATE_KEY / BIGQUERY_CLIENT_EMAIL / BIGQUERY_CLIENT_ID | Credenciales de cuenta de servicio |
ANALYTICS_DB_TYPE | postgres (por defecto, no necesita GCP) o bigquery |
ANALYTICS_DB_HOST / PORT / NAME / USER / PASSWORD | Solo se usan cuando ANALYTICS_DB_TYPE=postgres y quieres una base de datos de analítica separada |
ANALYTICS_ENABLED | Interruptor maestro de encendido/apagado |
OAuth social
Hay dos mecanismos independientes de OAuth de Google en el código — ambos deben completarse si quieres que el inicio de sesión con Google funcione completamente fuera de la ruta de verificación de Firebase:
| Variable | Propósito |
|---|
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET | Estrategia passport-google-token de Passport |
CLIENT_ID / CLIENT_ID_SECRET / REDIRECT_URIs | Un OAuth2Client de googleapis separado usado en otra parte del servicio de auth |
Nota: el inicio de sesión con Facebook se eliminó por completo (tanto de la documentación orientada al producto de Autenticación como de la estrategia passport-facebook-token del backend) — ya no se ofrece como opción de login. FACEBOOK_APP_ID/FACEBOOK_APP_SECRET todavía existen, pero solo para crossposting (ver abajo).
Crossposting social (opcional) — para publicar contenido cruzado en X / TikTok / Facebook (services/crosspost.service.js):
| Variable | Propósito |
|---|
X_CLIENT_ID / X_CLIENT_SECRET | Credenciales de la app OAuth de X (Twitter) |
TIKTOK_CLIENT_KEY / TIKTOK_CLIENT_SECRET | Credenciales de la app OAuth de TikTok |
FACEBOOK_APP_ID / FACEBOOK_APP_SECRET | Credenciales de la app OAuth de Facebook Graph API (solo crossposting, no login) |
TOKEN_ENCRYPTION_KEY | Cifra los tokens OAuth de terceros almacenados en reposo (utils/crypto.util.js). Si no está configurada, el almacenamiento de tokens es una operación sin efecto en texto plano — configúrala en producción cuando el crossposting esté habilitado. Generar: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" |
Google Ad Manager (opcional) — reporte de ganancias por publicidad de creadores (services/gam-report.service.js):
| Variable | Propósito |
|---|
GAM_NETWORK_CODE | Tu código de red de Ad Manager |
GAM_SERVICE_ACCOUNT_KEY | Ruta a (o JSON crudo de) la clave de cuenta de servicio |
GAM_CREATOR_KEY | Nombre de la clave de segmentación personalizada que identifica al creador (por defecto creator) |
Análisis de imágenes (NSFW / moderación de contenido)
| Variable | Propósito |
|---|
IMAGE_ANALYSIS_PROVIDER | google-vision (el único proveedor implementado) |
IMAGE_ANALYSIS_MIN_LABEL_CONFIDENCE | Umbral de confianza 0–1 |
IMAGE_ANALYSIS_MAX_LABELS_PER_POST | Límite de etiquetas procesadas por subida |
DISABLE_IMAGE_ANALYSIS | Omite el análisis localmente |
DEEPAI_API_KEY | Vestigial — no se referencia en ningún lugar; el proveedor activo es Google Vision, que se autentica mediante las mismas credenciales de cuenta de servicio de Google Cloud de arriba |
LiveKit (llamadas + transmisiones en vivo)
| Variable | Propósito |
|---|
LIVEKIT_URL / LIVEKIT_WS_URL | URL de WebSocket del servidor LiveKit |
LIVEKIT_API_KEY / LIVEKIT_API_SECRET | Credenciales del servidor |
LIVEKIT_PORT / LIVEKIT_RTC_TCP / LIVEKIT_RTC_UDP | Solo relevante si estás ejecutando el servidor LiveKit autoalojado con Docker |
DISABLE_LIVEKIT | Omite llamadas/en vivo localmente |
Localmente estas pueden apuntar al servidor LiveKit provisto por Docker (ver la sección de Docker más arriba) — no se necesita cuenta externa hasta producción.
Logging / observabilidad (todo opcional)
| Variable | Propósito |
|---|
DATADOG_API_KEY | Habilita el transporte de logs de Datadog |
SENTRY_DSN / SENTRY_ENVIRONMENT / SENTRY_RELEASE | Seguimiento de errores |
NEW_RELIC_LICENSE_KEY / NEW_RELIC_APP_NAME / NEW_RELIC_ENABLED | APM — index.js hace require('newrelic') condicionalmente solo si la clave de licencia está configurada |
NEW_RELIC_LOG_LEVEL | Verbosidad propia del log del agente de New Relic: error/warn/info/debug/trace (por defecto info) |
LOGROCKET_APP_ID | Reproducción de sesiones |
CUSTOM_LOGGER_URL / CUSTOM_LOGGER_API_KEY | Envía logs a un endpoint HTTP personalizado |
Panel de administración, seguridad, límite de tasa, notificaciones
Estas generalmente tienen valores por defecto razonables y no necesitan cuentas externas — consulta .env.example para la lista completa: ADMIN_PANEL_URL, ADMIN_SESSION_TIMEOUT_MINUTES, ADMIN_REQUIRE_EMAIL_VERIFICATION, ADMIN_REQUIRE_2FA_SUPER_ADMIN, SESSION_EXPIRY_HOURS, MAX_FAILED_LOGIN_ATTEMPTS, ACCOUNT_LOCK_DURATION_MINUTES, el bloque PASSWORD_* de políticas, el bloque RATE_LIMIT_*, y NOTIFICATION_* / PUSH_NOTIFICATION_PROVIDER.
Frontend — apps/frontend-nextjs/.env.local
| Variable | Propósito |
|---|
NEXT_PUBLIC_GRAPHQL_URL | Endpoint GraphQL de cliente del backend — http://localhost:8000/web/graphql (el cliente usa la ruta dedicada /web/graphql; ya no hay /graphql legacy). Ajusta a tu BACKEND_PORT (por defecto 8000). |
NEXT_PUBLIC_WS_URL | WebSocket de suscripciones GraphQL — ws://localhost:8000/web/graphql |
NEXT_PUBLIC_SITE_URL | URL pública del sitio — se usa para metadatos SEO, enlaces canónicos, robots.txt, sitemap.xml. Debe ser el dominio real de producción en producción. |
NEXT_PUBLIC_FIREBASE_API_KEY / _AUTH_DOMAIN / _PROJECT_ID / _STORAGE_BUCKET / _MESSAGING_SENDER_ID / _APP_ID | Configuración de la app web de Firebase (de la consola de Firebase, distinta de las credenciales de cuenta de servicio del backend) |
NEXT_PUBLIC_FIREBASE_VAPID_KEY | Clave VAPID de Firebase Web Push — habilita las notificaciones push en la web. Opcional. |
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY | Clave pública de Stripe para los Elements del lado del cliente |
NEXT_PUBLIC_PAYPAL_CLIENT_ID | Client id público de la app de PayPal — para los botones de PayPal de "comprar monedas" |
NEXT_PUBLIC_ADSENSE_CLIENT | Id de publicador de Google AdSense (p. ej. ca-pub-…). Activa el loader de verificación/Auto ads a nivel de todo el sitio en app/layout.tsx y el renderizado de AdSense en el espacio de anuncio del perfil — ver Anuncios y Reparto de Ingresos |
NEXT_PUBLIC_GAM_NETWORK_CODE | Código de red de Google Ad Manager — habilita el espacio de anuncio del perfil basado en GPT (la ruta conforme de ingresos por creador, ver Anuncios y Reparto de Ingresos) |
NEXT_PUBLIC_GA_MEASUREMENT_ID | Id de medición de GA4 (p. ej. G-XXXXXXXXXX), de Google Analytics → Admin → Data streams. Opcional — la etiqueta <GoogleAnalytics> en app/layout.tsx solo se renderiza cuando esto está configurado, así el tráfico de desarrollo nunca contamina la analítica de producción. |
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY | Autocompletado de Google Places para el campo de "ubicación" del composer de posts (necesita la Places API + Maps JavaScript API habilitadas en la clave). Opcional — sin ella el campo recae en entrada de texto manual + geolocalización. |
NEXT_PUBLIC_GIPHY_API_KEY | Clave API de GIPHY — potencia el selector de GIFs |
NEXT_PUBLIC_PHONE_LOGIN_PROVIDER | Refleja el PHONE_LOGIN_PROVIDER del backend. Solo disabled tiene efecto aquí — oculta el botón "Continue with phone" en Login.tsx / AddAccountModal.tsx. Déjalo en blanco/sin configurar (o firebase) para mantenerlo visible. |
NEXT_PUBLIC_APPLE_CLIENT_ID | Sign in with Apple en la web — un "Services ID" registrado en Apple Developer (ligado a un dominio verificado + Return URLs), no el Bundle ID de la app iOS nativa. Debe coincidir con APPLE_WEB_CLIENT_ID del backend. Déjalo en blanco para ocultar/desactivar el botón "Continue with Apple" (muestra un mensaje de "no disponible" en vez de fallar silenciosamente). |
NEXT_PUBLIC_APPLE_REDIRECT_URI | URL de retorno registrada para el Services ID de arriba. Requerida por el init() de Apple incluso en modo popup. Por defecto usa el origin actual si no se configura. |
Todas las variables NEXT_PUBLIC_* se exponen al bundle del navegador — nunca pongas un secreto en una de estas.
iOS — apps/ios/app
iOS no carga un archivo .env automáticamente. apps/ios/app/.env.example es solo de referencia; los valores reales deben ingresarse directamente en el scheme de Xcode:
Xcode → Product → Scheme → Edit Scheme → Run → Arguments → Environment Variables
| Variable | Propósito |
|---|
STRIPE_PUBLISHABLE_KEY | Leída por Secrets.swift — recae en una clave de prueba fija en builds DEBUG, pero causa fatalError en Release si no está configurada |
GIPHY_API_KEY | Mismo patrón — respaldo de desarrollo fijo en DEBUG, requerida en Release |
API_HOST | Opcional — por defecto 127.0.0.1. Configúrala con la IP LAN de tu Mac (ipconfig getifaddr en0) al probar en un dispositivo físico. APIConfig.swift construye el endpoint como http://<API_HOST>:8000/web/graphql (la misma ruta /web/graphql que el cliente web). |
Otras dos piezas de configuración de iOS que no son variables de entorno en absoluto:
app/GoogleService-Info.plist — ya está incluido en el repositorio, apuntando a la app iOS de Firebase del proyecto. Si estás levantando un proyecto de Firebase separado, descarga el tuyo propio desde la consola de Firebase y reemplaza este archivo (ver Obtención de claves API).
app/app.entitlements — declara la capacidad com.apple.developer.applesignin (necesaria para Sign in with Apple) y un grupo de apps (group.com.closegram, compartido con la extensión NotificationService para notificaciones push enriquecidas). Si haces un fork de esto bajo tu propio bundle ID, actualiza el identificador del grupo de apps aquí y en tu cuenta de Apple Developer.
Consulta la página técnica de iOS para el resto de la configuración (abrir el proyecto, resolver los paquetes de Swift, ejecutar pruebas).