🔐 El salto de «prototipo» a «producto seguro»
Una app en tu máquina incluso puede tener la clave pegada en el código sin que nadie la vea. Pero cuando la subes a GitHub y funciona en la nube, cualquier descuido con los secretos se convierte en un problema real: una clave filtrada gasta tu dinero y un dato expuesto se convierte en un incidente. Este módulo reúne los hábitos que mantienen todo bajo control: dónde los secretos se guardan, cómo el código los lee, y quién puede ver qué.
Antes de los ocho temas, mira la idea que los une a todos: el código es público (va a GitHub), pero los secretos quedan fuera de él, en una bóveda separada, y solo se inyectan al momento de ejecutarlo. Una capa más: la base con RLS — garantiza que, incluso con la app en línea, un usuario nunca vea los datos de otro.
Diagrama ilustrativo — seguridad en capas: ningún secreto en el código, claves solo en la bóveda e inyectadas en runtime, y la base de datos aislando los datos con RLS independientemente de los bugs de la app.
🔑 Variables de entorno
Qué es
Una variable de entorno es un valor que queda almacenado fuera del código y se inyecta en el programa solo al ejecutarlo (en runtime). El efecto es simple y poderoso: el código nunca contiene la clave. Donde antes escribirías const key = "sk-ant-abc123...", ahora escribe const key = process.env.ANTHROPIC_API_KEY — el valor real proviene del entorno, no del archivo.
¿Qué es?Runtime — el momento en que el programa está ejecutándose de verdad. Clave de API — una contraseña que le da a tu app acceso a un servicio (Anthropic, Firecrawl, Google). Codificado de forma fija — valor escrito directamente en el código (lo que queremos evitar con los secretos).
Diagrama ilustrativo — el código se convierte en una referencia («dame la clave llamada ANTHROPIC_API_KEY»); el valor real vive en el entorno y nunca aparece en el repositorio.
Por qué aprender
Es el mecanismo que separa «lo que es público» (el código) de «lo que es secreto» (las claves). Sin él, todos los secretos viajan junto con el código, y basta con que un git push para que quede expuesto en GitHub para siempre, aunque lo borres después. Una variable de entorno es la base de todo lo que viene en los siguientes temas: es el fundamento de la gestión de secretos.
Conceptos clave
El secreto no está en el archivo.
Se inyecta solo al momento de ejecutarse.
El código pide la clave por nombre.
La clave nunca se escribe a mano.
🗄️ Local (.env) vs. nube (dashboard)
Qué es
El mismo secreto vive en dos lugares diferentes, según dónde se ejecute el código. En el modelo local, queda en un archivo .env en tu máquina. En el modelo nube, queda en el panel de Environment Variables de la plataforma (Trigger.dev, Vercel), que inyecta los valores en tiempo de ejecución. El detalle que sorprende a todos: el Trigger.dev no puede leer tu .env local — en la nube, solo conoce lo que registraste en el dashboard.
¿Qué es?Environment Variables (dashboard) — la pantalla de la plataforma donde agregas cada secreto como par clave/valor. Entorno de development — para probar; production — lo que realmente se ejecuta para los usuarios.
🎯 Objetivo: guardar todos los secretos del proyecto fuera del código, en un archivo local.
# .env — NUNCA vai para o GitHub (precisa estar no .gitignore) ANTHROPIC_API_KEY=<sua-chave> FIRECRAWL_API_KEY=<sua-chave> # Google (acesso via OAuth — ver tópico 4) GOOGLE_CLIENT_ID=<seu-client-id> GOOGLE_CLIENT_SECRET=<seu-client-secret> GOOGLE_REFRESH_TOKEN=<seu-refresh-token> SHEET_ID=<id-da-sua-planilha>
✅ Cómo verificar: ejecuta cat .gitignore y confirma que haya una línea .env — si el archivo aparece en git status como «por commitear», DETENTE y agrégalo al .gitignore antes de cualquier push.
🎯 Consejo práctico
Al pasar a producción, registra cada clave del .env también en el dashboard de la nube — y marca tanto development cuánto production. Olvidar registrar una clave en production es la causa clásica del error que «solo falla en prod»: en tu equipo todo funciona, pero en la nube la app falla con «key is undefined».
Por qué aprender
Porque «funcionó en mi máquina» no basta: el entorno de la nube es otro, con otro almacén de secretos. Entender que son dos lugares —y que deben estar sincronizados— evita el error más frustrante del deploy. Y refuerza la regla del tema 5: puedes (y a veces debes) usar claves distintas para local y producción.
Conceptos clave
Archivo en tu máquina.
Panel de env vars.
La nube ignora tu archivo local.
Regístralas en ambos entornos.
📄 .env.example y process.env
Qué es
O .env.example es un plantilla segura para hacer commit: enumera los nombres de las claves que el proyecto necesita, pero sin ningún valor. Documenta «lo que este proyecto exige» sin exponer ni un solo secreto. En cambio, el process.env es cómo el código lee estos valores en runtime: nunca los escribe directamente. En la práctica, le pides a Claude Code que cree el .env, confirmar que está en el .gitignore, generar el .env.example y ajustar el código para leer desde process.env.
🎯 Objetivo: documentar qué secretos necesita el proyecto, sin exponer ninguno; este archivo SÍ puede ir a GitHub.
# .env.example — só os NOMES, nenhum valor. Seguro de commitar. # Copie para .env e preencha os valores reais. ANTHROPIC_API_KEY= FIRECRAWL_API_KEY= GOOGLE_CLIENT_ID= GOOGLE_CLIENT_SECRET= GOOGLE_REFRESH_TOKEN= SHEET_ID=
✅ Cómo verificar: abre el archivo; ningún valor después del =. Quien clone el repo entenderá qué debe configurar, pero no recibirá ninguno de tus secretos.
🎯 Objetivo: leer el secreto en tiempo de ejecución, sin escribirlo nunca en el código.
// lê o valor do ambiente — o código fica sem segredo
const key = process.env.ANTHROPIC_API_KEY;
// falha rápido e claro se a chave não foi configurada
if (!key) {
throw new Error("Faltou ANTHROPIC_API_KEY no ambiente (.env ou dashboard).");
}
✅ Cómo verificar: ejecuta el código sin la clave en el entorno; debe fallar con un mensaje claro, no con un error confuso más adelante. Este "fallo rápido" ahorra horas de depuración.
🎯 Objetivo: dejar que Claude Code configure todo el esquema de secretos de una vez.
Configure as variáveis de ambiente do projeto para estas chaves: ANTHROPIC_API_KEY, FIRECRAWL_API_KEY, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REFRESH_TOKEN, SHEET_ID. Faça, nesta ordem: 1. crie o arquivo .env (com placeholders <sua-chave>); 2. garanta que .env está no .gitignore; 3. crie um .env.example com as mesmas chaves SEM valores; 4. ajuste o código para ler tudo de process.env (nada hard-coded). Não cole nenhuma chave real no chat.
✅ Cómo verificar: al final, git status muestra .env.example como archivo nuevo, pero NO muestra .env. Busca «sk-» entre comillas en el código para asegurarte de que ninguna clave haya quedado hard-coded.
Por qué aprender
Porque un proyecto sin .env.example es un rompecabezas: quien clona no sabe qué claves necesita y acaba descubriéndolo mediante prueba y error. El par .env.example + process.env resuelve esto con elegancia: documenta lo necesario y mantiene el código limpio de secretos. Es la práctica estándar de cualquier proyecto profesional.
Conceptos clave
Solo los nombres, sin valor.
El example puede subirse; el .env no.
Lectura en runtime.
Di qué necesita el proyecto.
🔄 OAuth y refresh token
Qué es
OAuth es el protocolo que permite delegar el acceso a un servicio (por ejemplo, Google) sin exponer tu contraseña. En vez de darle tu contraseña a la app, autorizas a la app a actuar en tu nombre y esta recibe tokens. El refresh token es el token de larga duración que renueva el acceso por sí solo cuando expira el acceso temporal — es lo que mantiene funcionando a un agente alojado sin que tengas que volver a iniciar sesión cada vez.
¿Qué es?Client ID / Client secret — la «identidad» de tu app en Google Cloud Console. Access token — acceso breve, caduca rápido. Refresh token — acceso prolongado, genera nuevos access tokens. Cuenta de servicio — una cuenta de robot alternativa (aquí usamos el OAuth del usuario, más sencillo para Sheets/Drive personales).
Por qué aprender
Porque así es como los agentes en la nube acceden a Google Sheets, Drive y Gmail sin que abras el navegador en cada ejecución. El camino concreto: crear credenciales OAuth (client ID + secret) en Google Cloud Console y obtener un refresh token. El flujo estándar por OAuth Playground a veces falla con «access blocked» o «request is invalid»; la alternativa que funciona es un script de terminal que imprime una URL de autorización y, al final, te devuelve el refresh token para que lo pegues en el .env y en las variables de entorno de Trigger.dev.
✓ Acceso delegado (OAuth)
- ✓Autorizar la app sin entregar la contraseña.
- ✓El refresh token renueva el acceso automáticamente.
- ✓Si el Playground falla, genera el token mediante un script en la terminal.
✗ Atajos peligrosos
- ✗Pegar tu contraseña de Google directamente en la app.
- ✗Registrar manualmente cada vez que se ejecuta el agente.
- ✗Hacer commit del refresh token en el repositorio.
🎯 Consejo práctico
Si el OAuth Playground se bloquea con "access blocked / request is invalid", no insistas. Pídele a Claude Code un pequeño script de terminal que use tu GOOGLE_CLIENT_ID e GOOGLE_CLIENT_SECRET, imprime la URL de autorización, recibe el código que devuelve Google y suelta el GOOGLE_REFRESH_TOKEN en la consola; luego solo hay que pegarlo en el .env (y en el dashboard de la nube).
Conceptos clave
Autoriza sin dar la contraseña.
Renueva el acceso automáticamente.
Identidad de la app.
El script genera el token.
🏆 Reglas de oro
Qué es
Tres reglas innegociables para manejar secretos. Un: nunca pegues claves de API en el chat de la IA: el chat no es el lugar para un secreto. Dos: nunca hagas commit del .env en GitHub: una vez en el historial, considera que la clave quedó expuesta. Tres: rota/regenera las claves periódicamente y, de ser posible, usa claves diferentes para local y producción. La imagen mental: trata una clave de API como el acceso a una tarjeta de crédito.
El ciclo de vida de un secreto seguro
Generar la clave en el panel del servicio (Anthropic, Firecrawl) y copiarla directo para el .env — sin pasar por el chat.
Aislar: o .env en el .gitignore; el valor registrado en el dashboard de la nube (dev y prod).
Usar a través de process.env — nunca hard-coded, nunca impreso en un registro.
Rotar: si sospechas que hubo una filtración, regenera la clave en el panel — la anterior deja de funcionar de inmediato. Las claves separadas para dev/prod limitan los daños.
⚠️ Clave = tarjeta de crédito
Una clave filtrada no solo da «acceso»: permite que alguien ejecute llamadas de IA en tu cuenta, acumulando uso y costos a tu nombre. En cuestión de minutos, los bots rastrean GitHub en busca de claves expuestas. Por eso la regla es estricta: si se filtra, rótala de inmediato.
Por qué aprender
Porque la mayoría de los incidentes de seguridad con apps de IA no se deben a un hacker sofisticado: se deben a una clave pegada en el lugar equivocado. Interiorizar estas tres reglas es lo que diferencia un prototipo descuidado de un producto que puedes dejar funcionando con tranquilidad.
Conceptos clave
Clave fuera de la conversación con la IA.
.env siempre en .gitignore.
Regénéralo si tienes dudas.
Si se filtra, alguien gasta por ti.
🛡️ RLS — aislar datos en la base de datos
Qué es
RLS (Row-Level Security) son reglas que viven dentro de la propia base de datos (en Supabase, por ejemplo) e impiden que un usuario vea las filas de otro, incluso si hay un bug en el frontend. Es una capa extra de defensa: la base de datos protege los datos independientemente de la app. Si tu código pide por error "todos los leads", la base de datos, con RLS, devuelve solo los leads de ese usuario.
¿Qué es?Fila (row) — un registro en la tabla (p. ej., un lead). Policy — la regla que dice "quién puede ver o modificar qué filas". Defensa en profundidad — no confiar en una sola capa; si una falla, la otra responde.
Diagrama ilustrativo — con RLS, la regla de aislamiento reside en la base de datos; un error en el frontend ya no puede filtrar los datos de otro usuario.
🎯 Objetivo: aislar los datos por usuario en la propia base, con una política RLS en la tabla de leads.
-- liga o Row-Level Security na tabela alter table leads enable row level security; -- política: cada usuário só enxerga as próprias linhas -- (compara o dono da linha com o usuário autenticado) create policy "cada um vê só os seus leads" on leads for select using ( user_id = auth.uid() );
✅ Cómo verificar: inicia sesión como el usuario A y lista los leads; solo aparecen los suyos. Inicia sesión como B e intenta leer los de A: la base de datos devuelve una lista vacía. El aislamiento está garantizado en la base de datos, no en la app.
🎯 Consejo práctico
Al crear el proyecto en Supabase: define una contraseña bancaria distinta de la contraseña de inicio de sesión de la cuenta, elige la región más cercana a los usuarios, habilita el RLS en las tablas con datos de usuario y ejecuta la migración SQL que crea la tabla. Tener RLS desactivado en una tabla expuesta es la falla de seguridad nº 1 en apps hechas a las apuradas.
Por qué aprender
Porque vas a construir rápido, y el código hecho rápido tiene errores. RLS es el cinturón de seguridad: aunque el frontend falle, la base de datos no permite que un usuario vea los datos de otro. Es la diferencia entre «un error molesto» y «una filtración de datos que se vuelve noticia».
Conceptos clave
La protección está en la base.
Cada uno solo ve lo suyo.
Independiente del frontend.
Si una falla, la otra te respalda.
🔍 Auditoría de seguridad
Qué es
Antes de dejar la app en producción, le pides a la IA que actúa como especialista en seguridad y revisa el proyecto con una lista de cuatro puntos: rutas protegidas, ninguna clave expuesta en el frontend, secretos solo en variables de entorno e RLS habilitado. Una buena práctica es limpiar la conversación antes (el contexto fresco audita mejor) y, después, corregir todo lo que falle.
🎯 Objetivo: hacer una auditoría de seguridad explícita antes del deploy.
Aja como especialista de segurança e audite este app. Verifique, item por item: 1. rotas protegidas (nada sensível acessível sem login); 2. nenhuma chave de API exposta no frontend / no bundle; 3. segredos APENAS em variáveis de ambiente (nada hard-coded); 4. RLS habilitado em todas as tabelas com dados de usuário. Liste o que FALHAR e, para cada falha, diga exatamente como corrigir. Não invente: se não der pra confirmar, diga.
✅ Cómo verificar: recibes una lista de hallazgos que permiten tomar medidas. Corrige cada fallo y vuelve a ejecutar la auditoría hasta que la lista quede vacía; solo entonces haz el deploy a producción.
✓ Auditoría que funciona
- ✓Limpiar el contexto antes para hacer un análisis desde cero.
- ✓Checklist explícito de 4 puntos.
- ✓Corrige lo que falle y vuelve a auditar hasta que no quede nada.
✗ Qué sale mal
- ✗Creer que «compiló» = «es seguro».
- ✗Dejar que la clave de la API llegue al frontend.
- ✗Subir a producción sin revisar nunca la seguridad.
Por qué aprender
Porque con vibe coding construyes rápido y es fácil dejar una puerta abierta sin darte cuenta. Una auditoría explícita, con checklist, cuesta poco (un prompt) y detecta justamente lo que se pasó por alto. Es el «trust but verify» aplicado a la seguridad: no confíes en que quedó seguro; verifícalo.
Conceptos clave
Pídele a la IA el rol.
Rutas, claves, env, RLS.
Audita con una conversación nueva.
Hasta que la lista quede vacía.
⚠️ App abierta = riesgo
Qué es
Un app abierta — sin autenticación, es un riesgo financiero concreto: cualquiera que tenga la URL puede activar tu workflow y consumir tus tokens de IA. Como pagas por el uso, el uso de otras personas se carga a tu cuenta. Por eso, no dejes una app sin inicio de sesión funcionando en producción por mucho tiempo: antes de compartirla, agrega autenticación (Supabase) y límites de uso.
¿Qué es?Autenticación — exigir que inicien sesión antes de usar la app. Límite de uso (rate limit / quota) — un límite de cuántas veces alguien puede llamar a la app. Token de IA — la unidad de consumo que le pagas al proveedor en cada llamada al modelo.
⚠️ La cuenta que llega a fin de mes
Publicas una app interesante, compartes el enlace y te vas a dormir. Un bot encuentra la URL, activa el workflow miles de veces y cada activación llama al modelo de IA. Por la mañana, la factura del proveedor se disparó, con un uso que no fue tuyo. App abierta + llamada de IA paga = riesgo directo para tu bolsillo.
Por qué aprender
Porque es el disparador natural para el siguiente módulo. Agregar inicio de sesión con Supabase y límites de uso no es solo seguridad: es el primer paso de un modelo de negocio: si vas a controlar quién lo usa y cuánto, estás a un paso de cobrar por ello. Este razonamiento motiva el modelo freemium con Stripe que ves en 6.3.
Conceptos clave
Quien tiene el enlace, lo activa.
Los tokens de otros terminan en tu cuenta.
Inicia sesión antes de usarlo (Supabase).
Límite por usuario → freemium.
Fijando: dónde NUNCA ¿se debe agregar una clave de API?
📌 Resumen del módulo
Siguiente módulo:
6.3 — Confiabilidad y monetización