# Checklist de producción

52 puntos que reviso antes de subir algo a producción.
13 de ellos no son negociables: van marcados con **(no sale sin esto)**.

Versión completa y con explicaciones: https://diegopartida.dev/produccion
Diego Partida · diegopartida.dev

---

## 01 · Llaves y secretos

Va primero porque es lo único de esta lista que no se puede deshacer. Un bug lo arreglas; una llave que ya salió, ya salió.

- [ ] Ninguna llave con permisos de escritura vive en el cliente. **(no sale sin esto)**
      Por qué: Todo lo que empieza con NEXT_PUBLIC_ viaja dentro del JavaScript que descarga el visitante. Si la encuentras tú buscándola ahí, la encuentra cualquiera.
- [ ] La llave de servicio —service_role, admin, secret key— solo se usa en código que corre en el servidor.
      Por qué: Esa llave se salta tus reglas de permisos por diseño. Es la única del proyecto que vale por todas las demás juntas.
- [ ] El .env está en .gitignore y nunca se ha ido en un commit.
- [ ] Si una llave se subió al repo aunque haya sido una vez, ya la rotaste. **(no sale sin esto)**
      Por qué: Borrarla en el commit siguiente no la borra del historial. Sigue ahí, y los bots que barren GitHub la leyeron en minutos.
- [ ] Producción, preview y tu máquina usan llaves distintas.
      Por qué: Es lo que hace que un experimento en una rama no pueda escribir en la base de datos de tus clientes.
- [ ] Cada llave tiene el permiso mínimo que necesita para su trabajo.
      Por qué: Una llave que solo puede leer no te borra nada el día que se filtre.
- [ ] Los webhooks verifican la firma antes de creerle a quien los llamó. **(no sale sin esto)**
      Por qué: Sin verificar la firma, cualquiera puede pegarle a tu endpoint de pagos y decirte que ya pagó.

## 02 · La puerta: quién entra

Esconder el botón no es autenticación. Si el endpoint contesta, está abierto — y contestar es lo único que un endpoint sabe hacer.

- [ ] Cada endpoint vuelve a preguntar quién eres, aunque la interfaz ya haya escondido el botón. **(no sale sin esto)**
      Por qué: El botón que no se ve se llama igual con curl, y con el mismo resultado.
- [ ] El middleware o proxy es conveniencia, no candado: la autorización está pegada al dato.
      Por qué: Es una capa, y las capas se saltan. En marzo de 2025 una cabecera de más bastó para brincarse el middleware de Next.js en medio mundo.
- [ ] La sesión vive en una cookie httpOnly, secure y con sameSite.
      Por qué: Si el token está en localStorage, cualquier script de terceros que cargues puede leerlo — incluido el de analítica que instalaste sin mirar.
- [ ] Las sesiones caducan y cerrar sesión las invalida del lado del servidor.
- [ ] El link para recuperar contraseña sirve una sola vez y caduca.
- [ ] Login, registro y recuperación tienen límite de intentos. **(no sale sin esto)**
      Por qué: Es el primer lugar donde alguien prueba mil contraseñas, o manda mil correos de verificación que tú pagas.
- [ ] Sabes exactamente qué puede hacer una cuenta recién creada que no ha pagado nada.
      Por qué: Ahí es donde se va el cómputo: registro abierto más una operación cara igual a una factura que nadie pidió.
- [ ] Probaste la app con una cuenta sin permisos, no solo con la tuya de administrador.
      Por qué: Tu cuenta ve todo. Es la única con la que la app siempre funciona.

## 03 · Los datos: qué ve cada quien

El error más caro no truena. Le enseña los datos de un cliente a otro cliente y se queda callado hasta que el otro avisa.

- [ ] Toda consulta filtra por dueño, no solo por id. **(no sale sin esto)**
      Por qué: Cambiar el número en /factura/1042 por 1043 no debe enseñar la factura de alguien más. Pruébalo a mano, hoy.
- [ ] Si usas Supabase o algo parecido: RLS prendido en todas las tablas y probado con la llave pública. **(no sale sin esto)**
      Por qué: Probarlo con la llave de servicio no prueba nada — esa se salta las políticas por diseño.
- [ ] El servidor valida otra vez todo lo que ya validó el formulario.
      Por qué: La validación del navegador es para el usuario distraído. No para el que va en serio.
- [ ] Hay respaldos automáticos y ya restauraste uno completo. **(no sale sin esto)**
      Por qué: Un respaldo que nunca restauraste no es un respaldo: es una carpeta con la que te sientes tranquilo.
- [ ] Las migraciones se corrieron primero contra una copia de la base, no contra la buena.
- [ ] Sabes qué se lleva por delante un borrado antes de que lo descubra un cliente.
      Por qué: Revisa las cascadas. Borrar una empresa no debería borrar tres años de facturas de otra.
- [ ] Ni contraseñas, ni tokens, ni datos personales terminan en los logs.
      Por qué: Un log es una copia de tus datos, en otro servidor, que nadie vigila y que casi nadie borra.
- [ ] El cliente puede sacar su información el día que te la pida.

## 04 · Límites y dinero

Lo que no tiene límite, alguien lo encuentra. Casi nunca por maldad: un bot que no sabe quién eres recorre lo que esté abierto, y lo recorre completo.

- [ ] Hay rate limit en todo lo que cuesta dinero cada vez que corre. **(no sale sin esto)**
      Por qué: Modelos de IA, PDFs, correos, consultas pesadas, búsquedas. Por cuenta y por IP, no solo por IP.
- [ ] Cada servicio que cobra por uso tiene tope de gasto y alerta de presupuesto. **(no sale sin esto)**
      Por qué: La alerta se pone antes de necesitarla. Después ya no es una alerta: es un correo avisándote lo que ya debes.
- [ ] Ninguna ruta genera páginas hasta el infinito. **(no sale sin esto)**
      Por qué: Una URL por partido, por producto o por fecha es una invitación abierta a que un crawler las recorra todas — y cada una es cómputo que tú pagas. Valida los parámetros y cachea el resultado.
- [ ] Lo que se puede servir cacheado, se sirve cacheado.
      Por qué: La respuesta más barata que existe es la que nunca llegó a tu servidor.
- [ ] Decidiste a propósito qué crawlers pueden entrar y a qué.
      Por qué: robots.txt es una petición amable, no un candado. Lo que de verdad no debe recorrerse va detrás de un login o detrás de un límite.
- [ ] Toda llamada a un servicio externo tiene timeout y reintentos con espera creciente.
      Por qué: Sin timeout, un proveedor lento no te vuelve lento: te vuelve caro. Y sin espera creciente, tus reintentos son el ataque.
- [ ] Las subidas de archivos tienen tamaño y tipo limitados, del lado del servidor.
- [ ] Los proyectos que ya no usas están apagados, o detrás de una contraseña.
      Por qué: Si está en internet, ya está público. Una demo que nadie vio también consume, también se cae y también te llega en la factura.

## 05 · Cuando truene

No es si truena. Es si te enteras tú primero o te enteras por el mensaje de un cliente un domingo.

- [ ] Los errores llegan a algún lado que de verdad revisas.
      Por qué: Sentry, Logtail, lo que sea. Un console.log en producción no se lo cuenta a nadie.
- [ ] Algo te avisa al teléfono cuando el sitio se cae o cuando falla un pago.
- [ ] Hay un healthcheck y un monitor que lo pica cada minuto desde fuera.
      Por qué: Desde fuera: la mitad de las caídas reales son de DNS, de certificado o del proveedor, y desde dentro se ven perfectas.
- [ ] Sabes volver a la versión anterior en un minuto, y ya lo hiciste una vez a propósito.
- [ ] La página de error no le enseña el stack trace al visitante. **(no sale sin esto)**
      Por qué: Ahí van tus rutas, tus variables de entorno y a veces la consulta completa.
- [ ] Si cobras: los pagos se concilian solos y los cobros fallidos se ven en algún lado.
- [ ] Sabes si tus correos están llegando o cayéndose en spam.
      Por qué: SPF, DKIM y DMARC configurados. Un correo de verificación en spam es un usuario que se dio de baja sin decírtelo.

## 06 · Lo que el mundo ve

El día que compartes el link ya no puedes ensayar. Esto se revisa antes del primer link, no después del primero que se hizo grande.

- [ ] Los ambientes de preview y de pruebas están protegidos y con noindex. **(no sale sin esto)**
      Por qué: Si no, Google indexa tu staging y tus clientes lo encuentran antes que la versión buena — con datos de prueba y todo.
- [ ] Dominio propio con https, y una sola versión: con www o sin www, y la otra redirige.
- [ ] El link se ve bien cuando alguien lo pega en WhatsApp.
      Por qué: Título, descripción e imagen. Se comparte una vez y así se queda en la conversación para siempre.
- [ ] Si cobras o guardas datos personales: aviso de privacidad y términos, con tu nombre real y una forma de contactarte.
- [ ] Lo abriste en un teléfono de verdad, con datos móviles, no solo en el simulador del navegador.
- [ ] Se puede usar con teclado, y el contraste no depende de que tu monitor sea el bueno.
- [ ] Hay analítica desde el día uno.
      Por qué: El tráfico del primer día no se puede medir retroactivamente, y es el único día que vas a querer volver a ver.

## 07 · El repaso de diez minutos

Lo último, con el deploy ya arriba y el café todavía caliente. Diez minutos, siempre los mismos, en el mismo orden.

- [ ] Abre el sitio en una ventana de incógnito: sin sesión, ¿qué alcanzas a ver?
- [ ] Entra con dos cuentas distintas y cambia en la URL de una el id de la otra.
      Por qué: Los treinta segundos más rentables de toda la lista.
- [ ] Busca tus llaves dentro del JavaScript que tu sitio está sirviendo.
      Por qué: Abre el bundle y pega los primeros caracteres de cada llave. No debe salir ninguna.
- [ ] Corta la red a la mitad de una operación que cobra o que escribe.
      Por qué: Lo que se rompa ahí es lo que vas a estar arreglando a mano el resto del mes.
- [ ] Manda el formulario de contacto y espera a que llegue el correo.
- [ ] Escribe una URL que no existe, y luego una que sí existe pero no es tuya.
- [ ] Si cobras: haz un pago real, del monto más chico que puedas, con tu propia tarjeta.
      Por qué: Modo prueba nunca detecta la llave de prueba olvidada en producción. Un peso sí.

---

Es tuya: úsala, cámbiala y métela a tu repo. Si te sirvió, deja el link.

Si está en internet, ya está público.
