Deep-dive de Taskly (task-manager-jwt)
Taskly empezó siendo, literalmente, «Task Manager API»: un backend en Express con autenticación JWT y un CRUD de tareas. Sin landing, sin marca, sin nada que mostrarle a alguien que no supiera ya qué esperar. Este post es sobre las dos capas que le agregué después — la técnica (lo que ya tenía) y la de producto (lo que le faltaba) — y sobre todo, sobre cómo decidí no inflarlo con funciones que no existían de verdad.

Lo que ya funcionaba
Antes de tocar una sola línea de diseño, el backend ya resolvía bien lo difícil:
- Autenticación JWT de dos tokens: access token de vida corta guardado en memoria, refresh token en cookie
HTTP-Onlycon rotación en cada renovación. El interceptor de Axios en el frontend hace fila de las peticiones que llegan mientras se renueva el token, para no disparar múltiples refresh en paralelo. - Rate limiting en los endpoints de autenticación, para no dejar la puerta abierta a fuerza bruta.
- CRUD de tareas con prioridad (Baja/Media/Alta) y estado (Por hacer/En curso/Listo), filtros combinados, exportación a CSV.
- Panel de administración con cambio de roles de usuario.
Es decir: la parte que de verdad es difícil de hacer bien — sesiones seguras, control de acceso — ya estaba resuelta. Lo que faltaba era todo lo que hace que alguien entienda eso en cinco segundos.
El problema de diseño real
Le pedí ayuda a Claude para tomar un handoff de diseño (tokens de color, tipografía, un mockup de referencia hecho en Next.js solo para ver la estética) e implementarlo sobre el frontend real en React + Vite. El riesgo obvio: que «mejorar el diseño» se convirtiera en una excusa para inventar funciones que suenan bien en una landing pero no existen en el backend — login con Google, 2FA, «colabora con tu equipo», planes de pago. Ese patrón es muy fácil de caer en él cuando el objetivo es «que se vea como un SaaS real».
Así que la regla fue explícita desde el principio: el rediseño cambia la presentación, no el alcance. Nada de lo que no tuviera un endpoint real detrás iba a aparecer como si funcionara.
Para no dejar esa regla como una buena intención y ya, el proceso fue spec → decisiones técnicas → plan de arquitectura → tareas atómicas, con dos puntos de aprobación humana en el camino: uno antes de instalar cualquier dependencia nueva (solo se aprobó Vitest + Testing Library, nada de librerías de animación), y otro antes de tocar un solo componente, para revisar la arquitectura completa primero. 42 tareas después, con tests para lo único que realmente necesitaba pruebas automatizadas (el foco del modal, las guardas de ruta, el mapeo de filtros), el resultado es la landing que ves en las capturas: hero, beneficios, cómo funciona, precios, testimonios, FAQ — todo apuntando a rutas reales (/register, /login), sin un solo botón que finja hacer algo que no hace.


Lo que decidí dejar afuera (a propósito)
- Login social con Google, 2FA, Magic Link.
- Checkout de Stripe o cualquier flujo de pago.
- «Invitar a tu equipo» / colaboración con roles por proyecto.
No porque sean malas ideas — están en el roadmap real del producto — sino porque un botón que simula un pago que no procesa nada es peor que no tener el botón. Cuando alguien evalúa tu código, ese tipo de detalle se nota más que cualquier animación.

Stack
React 19 · Redux Toolkit · React Router · Tailwind CSS · Node.js · Express · Prisma · PostgreSQL · Docker.
