Así implementé una feature crítica en 1 hora tras recibir feedback de un usuario

De un «no puedo entrar a Savia» de un usuario a una feature en producción con PRD, desarrollo y auditoría en una sola sesión con 3 roles involucrados.

Sabía que iba a pasar. Cuando lancé Savia, la recuperación de contraseña se quedó fuera del MVP deliberadamente. Prioricé el flujo core — que un mentorizado pudiera encontrar un mentor, solicitar una sesión y coordinarla — y aparqué todo lo que no fuera crítico para validar la propuesta de valor. Recuperar contraseña era importante, sí. Pero no era lo que iba a determinar si Savia despertaba algo de interés o no.

Hasta que llegó el feedback que hace daño. Un usuario real no podía entrar a Savia. Llevaba varios minutos perdidos. Me escribió contándomelo para ayudar y como sugerencia, nada enfadado. Sin embargo, me fui a PostHog y había señales de rage click que delataban una frustración evidente. Normal.

Había olvidado su contraseña y no tenía forma de recuperarla. Dead end total. Una versión del producto que dejaba a un usuario atrapado si no podía recuperar su contraseña. Error básico, vaya. No hay login con Google ni ninguna alternativa. Email y contraseña es el único método de acceso, y si la pierdes, pierdes tu cuenta.

La feature para la que pensé “bueno, ya llegará el momento de dedicarle tiempo” se convirtió en necesaria. Quería demostrar a ese usuario que era capaz de darle lo que necesitaba y convertir su feedback en una mejora de producto de manera muy rápida.

De hecho, podría haberle reseteado la contraseña manualmente. Decidí no hacerlo. Le respondí a su email con un: “Gracias por el feedback. Dame un rato, lo soluciono y lo pruebas para confirmar que funciona”.

Definir primero, codear después

Mi primer instinto fue ir directa a implementar. Tengo Claude Code, conozco el codebase, el flujo es estándar. ¿Cuánto podía costar que la IA se ponga a hacerlo directamente?

Pero frené mi instinto. Pensé que era mejor seguir el proceso natural de desarrollo de una feature pero acelerarlo exponencialmente gracias a la IA. Pero no delegarle el criterio y permitir que se pusiera a picar código con un prompt genérico de “implementa recordatorio de contraseña”.

Empecé activando dos skills que tengo configuradas en Claude — una con el rol de Product Manager y otra con el de UX/UI Designer. Les pedí que analizaran el problema antes de tocar una línea de código.

Estas no son skills genéricas. Las he ido construyendo con contexto específico de Savia: conocen la arquitectura, las decisiones de diseño, el tono de voz, las convenciones del código, los patrones de UX que uso. Son archivos markdown que viven en el repositorio del proyecto y que Claude carga cuando los invoco. Cuando los activo, no parten de cero. Parten del proyecto.Cualquiera puede hacer lo mismo: es un archivo de texto con instrucciones, contexto y protocolos. No tiene nada de mágico, pero marca una diferencia enorme en la calidad del output.

Les pedí algo sencillo: “Hay feedback de usuarios de que no tenemos recuperación de contraseña. Quiero que ambos analicéis qué habría que hacer para solucionarlo y me hagáis una propuesta”.

Y lo que salió de esa interación fue útil. El PM identificó 10 consideraciones estratégicas — impacto en retención, riesgo de email bombing, anti-enumeración de usuarios, métricas a trackear. La UX sumó 14 más — dónde colocar el link en login, copy empático, validación en tiempo real, accesibilidad.

Después invocamos a otra skill que tengo con el rol de Software Engineer. Ahí vino algo que no esperaba: detectó que el 80% de la infraestructura ya existía.

El email template para reset de password estaba creado. La ruta de confirmación ya manejaba tokens de recovery. El servidor de correo estaba configurado. La función resetPasswordForEmail() estaba disponible. Simplemente nunca la había invocado.

Esto fue un hallazgo, pero también una señal de alarma. Significaba que cuando definí las features del MVP al principio, ésta se me había colado parcialmente.

Claude la había considerado en su plan de desarrollo inicial, pero la implementó a medias — montó la infraestructura de soporte sin completar el flujo de usuario. Sin un PRD explícito que la definiera, la IA hizo lo que pudo con lo que entendió. Y yo no detecté en ningún momento que eso se nos estaba quedando fuera.Disclaimer: eso fue porque la primera iteración de Savia la hice pasando de propuesta > código. Y ahora he mejorado el flujo pasando de propuesta > PRD > código.

El PRD y la corrección que solo un humano puede hacer

Con todas las consideraciones sobre la mesa, tocaba estructurar. Tengo un template de PRD que fui construyendo y refinando dentro del skill de PM — no es un template genérico, es uno adaptado a cómo trabajo en Savia: incluye Jobs to Be Done, criterios de aceptación con Given/When/Then, edge cases, y un apartado que para mí era clave en este caso: el “why not” — qué pasa si no hacemos esta feature.

En este caso la respuesta era clara: cada usuario que olvide su contraseña se pierde para siempre. Con 10 usuarios activos que tengo ahora mismo, perder 1 es perder el 10% de la base.

Le pedí a Claude que generara el PRD completo usando ese template y los datos del análisis. 4 minutos después tenía un documento con 14 requisitos, 6 escenarios de aceptación y los edge cases cubiertos.

Y entonces pasó algo que para mí resume cómo funciona esta colaboración entre la propuesta que te hace una IA con el contexto que le has dado y el criterio del humano que la IA no puede reemplazar.

Claude propuso un rate limit de 10 peticiones cada 15 minutos para la recuperación de contraseña — el mismo que tenía en login. Yo lo bajé a 3. Nadie legítimo necesita solicitar más de 3 resets en 15 minutos. La IA propone valores razonables; el humano aplica el contexto que la IA no tiene.

Ajustamos el PRD. Definimos el scope, lo que entraba y lo que se quedaba fuera. Quedó así. Si quieres ver el PRD completo, déjame un comentario y te lo comparto en markdown.

Con el PRD aprobado, la implementación fue directa. 4 archivos nuevos, 7 modificados, 11 en total. Build verde, 435 tests passing. Mensaje genérico siempre, tanto si el email existe como si no — para que nadie pueda usar el formulario de reset para averiguar si un email está registrado. Es seguridad básica que muchas apps se saltan.

Y entonces lo desplegué y las rutas no funcionaban

Me llevó un rato depurar el error y detectar qué estaba pasando (Disclaimer: en otro post te contaré cómo estoy aprendiendo a sacar a Claude del bucle cuando se equivoca más de 2 veces con una cosa y se vuelve incapaz de solucionarla sin buenas instrucciones).

Al final dimos con ello: había puesto ñ en la URL — /recuperar-contraseña. El build compiló perfecto. Los tests pasaban. Pero en producción, el servidor no decodifica bien los caracteres especiales en las rutas. Mi ñ se convertía en %C3%B1 y las comparaciones internas fallaban silenciosamente.

Cuando Claude identificó el problema, propuso un fix técnico: interceptar todas las URLs en el middleware y decodificar los caracteres especiales antes de compararlos. Funcionaría, pero era un parche — añadía complejidad a un sitio crítico del sistema para resolver algo que no tenía por qué existir.

Como no se desarrollar, de manera muy inocente le dije: “¿Y si simplemente quitamos la ñ?” /recuperar-contrasena en vez de /recuperar-contraseña. Nueve archivos renombrados, problema eliminado de raíz.

Es el mismo patrón que con el rate limit. La IA tiende a resolver problemas con más código. A veces la mejor solución es cambiar el planteamiento. No necesitas un parche sofisticado si puedes eliminar la causa. Pero eso requiere dar un paso atrás y preguntar “¿por qué estoy resolviendo esto así?” — algo que, al menos hoy, sigue siendo más fácil para un humano que para una IA.

El patrón que se repite

Feedback ? análisis con roles especializados ? PRD ? implementación ? producción. No es un flujo de IA. Es un flujo de producto. Lo que la IA cambia es la velocidad: lo que habrían sido días de trabajo con un equipo distribuido se comprimió en 1 hora con una sola persona activando roles en secuencia.

Pero la velocidad no es lo importante. Lo importante es que en ningún momento delegué una decisión de producto. Corregí el rate limit. Aprobé el PRD. Decidí quitar la ñ en vez de parchear el servidor. La IA amplificó mi capacidad de ejecutar, pero el criterio siguió siendo mío.

Y esa es la parte del vibe coding de la que menos se habla. No es escribir código con prompts. Es tener un equipo que ejecuta a la velocidad que tú piensas — siempre que sepas qué pensar.

Si te apetece probarlo, Savia está en savia.company. Y sí, ahora puedes recuperar tu contraseña.


Artículos anteriores de la serie:

Cómo cumplir con la regulación para un side project en 2 prompts y con un agente

La parte legal de un proyecto es la tarea que siempre cae al fondo de la lista. Sabes que está ahí. Sabes que es importante. Pero siempre hay algo más interesante: un bug, una feature, un usuario con feedback. Y la revisión legal se queda en “lo tengo que hacer”.

El problema es que yo estaba a punto de empezar a dar visibilidad a Savia como pequeño side project. Hablar del proyecto con algunos conocidos, compartir links, invitar a gente. Y no puedes abrir la puerta de tu casa si la instalación eléctrica no cumple normativa.

Si operas en la UE —y más en España, con la LSSI encima— el cumplimiento no es opcional. Es el tipo de cosa que si la ignoras cuando no eres relevante, se te puede hacer bola.

No cumplir con la regulación de tu país sencillamente no es una opción. Así que me puse a revisar qué tenía que tener Savia en un escenario de mínimos. Lo hice creando un agente de IA que auditase el proyecto y me propusiera un plan para solucionar todo lo que encontrase que fuese relevante.

Paso 1: Crear el agente

Uso Claude Code para desarrollar Savia. Tiene una funcionalidad de “slash commands” que básicamente te permite crear agentes especializados: escribes un prompt en un archivo markdown, y después lo invocas con /nombre-del-comando. El agente tiene acceso al código fuente real, no a una descripción que tú le des.

¿Por qué decidir montar este comando? Porque a medida que Savia gane en funcionalidad, tendré que ir repitiendo esta auditoría legal cada cierto tiempo. De esta forma tengo el prompt a un click de distancia para relanzarlo cuando necesite.

La clave estaba en encontrar un buen prompt de partida. Busqué skills de auditoría legal para plataformas SaaS europeas y agentes. Encontré en https://subagents.cc/ uno que cubría RGPD genérico (legal compliance checker) y me gustaba. Ahora necesitaba adaptarlo a mi contexto específico:

  • Savia opera solo en España ? necesitaba LOPDGDD y LSSI, no solo RGPD genérico

  • Tengo proveedores concretos ? Vercel (US), Resend (US), Supabase (EU), PostHog (EU), Sentry (EU)

Así que lo adapté a mi caso concreto:

El prompt que lanza el agente es este:

Eres un auditor legal especializado en plataformas web SaaS en la Unión Europea. Tu objetivo es revisar el proyecto Savia — un marketplace de mentoría profesional 1:1 para España. Quiero que detectes gaps de cumplimiento normativo que subsanar y mejoras para implementar.

  • Define el rol: auditor legal especializado en SaaS para la UE

  • Contextualiza Savia: qué datos recoge, qué proveedores usa, qué stack tiene

  • Enumera la normativa a considerar y cuyo cumplimiento revisar: RGPD, LOPDGDD, LSSI-CE, ePrivacy — con los artículos específicos relevantes

  • Estructura la auditoría en 4 pasos: inventario de datos ? evaluación de lo existente ? análisis de gaps ? plan de remediación

  • Define niveles de severidad: P0 (riesgo de sanción) hasta P3 (recomendación)

Lo más importante: le dije que leyese el código fuente real, no que se fiase de mi documentación. Porque una cosa es lo que crees que tienes implementado y otra lo que de verdad tienes.

———

Paso 2: Ejecutar la auditoría

Ejecuté /legal-review y le dejé trabajar. El agente leyó archivos reales del proyecto: la política de privacidad, el formulario de signup, la configuración de Sentry, los scripts de borrado, el middleware, el footer… En total revisó unas 15-20 fuentes.

El resultado fue un informe estructurado con un inventario de tratamientos de datos, evaluación de lo que ya cumplía, y una lista de gaps ordenados por severidad.

La puntuación inicial: 6.5/10. No estaba mal para un MVP lanzado en una semana, pero tenía agujeros que había que tapar.

P0 — Crítico (riesgo de sanción):

  • Sin aviso legal LSSI. La ley española obliga a tener una página con el titular, dirección y contacto. Yo tenía política de privacidad pero no aviso legal. Son cosas distintas.

  • Sin checkbox de consentimiento en el signup. Los usuarios creaban cuenta sin aceptar explícitamente nada. El RGPD requiere consentimiento inequívoco.

P1 — Alto:

  • Sentry recibía el email y rol del usuario en setUser(). PII yendo a un servicio de error tracking sin necesidad.

  • Las notificaciones de Telegram incluían el email del usuario que se registraba. PII en un canal de admin que no lo necesitaba.

  • La política de privacidad estaba incompleta: sin tabla de bases legales, sin lista de procesadores, sin plazos de retención, sin procedimiento ARCO detallado.

  • Faltaban avisos en el onboarding: los mentores no sabían que su perfil sería público, los mentees no sabían que sus datos se compartirían con mentores.

———

Paso 3: Montar el plan y ejecutar

Con la lista de gaps clara, le pedí al agente que generase un plan de remediación ordenado por prioridad. Cada item tenía: qué falta, qué archivo tocar, y cuánto esfuerzo.

Lo ejecutamos en dos tandas:

Primera tanda (P0 + P1):

  • Creamos la página de aviso legal con todos los datos del titular

  • Añadimos un checkbox obligatorio en el signup con links a política de privacidad y aviso legal (validación Zod en servidor por si alguien se salta el frontend)

  • Limpiamos PII de Sentry (setUser({ id }) — solo el ID, nada más)

  • Limpiamos PII de Telegram (quitamos el email de la notificación)

  • Ampliamos la política de privacidad: responsable, 8 finalidades con base legal, 6 procesadores, transferencias internacionales, plazos de retención, procedimiento ARCO completo con plazo de 30 días y referencia a la AEPD

  • Añadimos bloques informativos en el onboarding de ambos roles

Segunda tanda (P2):

  • Documentamos las 12 actividades de tratamiento (Art. 30) en un registro interno

  • Añadimos Google Forms como procesador en la política de privacidad

  • Documentamos la base legal de Sentry (Art. 6.1.f — interés legítimo) directamente en el código

Al final: 16 tests E2E verificando que el checkbox existe, que el botón está deshabilitado sin marcar, que el aviso legal tiene los datos obligatorios, , que la política de privacidad tiene todas las secciones requeridas, y que el PII fue eliminado de Sentry y Telegram.

———

El resultado

De 6.5 a 8.5/10 en cumplimiento. Cero P0 abiertos. Los gaps que quedan son operativos (firmar DPAs en el dashboard de cada proveedor) y de escala (crear un DPIA formal cuando pase de 1.000 usuarios).

Algunos aprendizajes de este proceso:

  • No soy abogada. Y este agente no sustituye a una. Pero me ha dado una radiografía bastante precisa de dónde estaban los problemas reales. Los documentos legales finales deberían pasar por un profesional.

  • El agente leyó mi código, no mi documentación. Encontró que Sentry recibía emails porque leyó lib/sentry.ts, no porque yo se lo dijera. Eso es lo que marca la diferencia respecto a pasarle un checklist genérico a la IA.

  • El 70% del trabajo fue crear un buen prompt. Las 140 líneas del agente, con el contexto específico de Savia, la normativa aplicable, y la estructura de salida esperada — eso fue lo que hizo que el resultado fuese accionable y no genérico.

  • Todo el proceso —agente + auditoría + implementación + tests— fue poco más de 1 hora de trabajo. No digo que sea perfecto. Digo que la alternativa era no hacerlo.

La verdad es que la parte legal no tiene por qué ser el monstruo que parece. Con el contexto correcto y las herramientas adecuadas, puedes pasar de “ya lo miro la semana que viene” a “hecho, testeado y desplegado” en una sesión.

Y tú… ¿has auditado el cumplimiento legal de tu producto? ¿Cómo lo has abordado?


Artículos anteriores de la serie: