Fluento: Arquitectura y Funcionalidad del MVP

29 de diciembre de 2024

Este artículo forma parte de la serie "Desarrollando Fluento". Aquí tienes el índice completo:

  1. Idea y presentación del proyecto
  2. Arquitectura y Funcionalidad del MVP (Este artículo)
  3. Implementación del backend
  4. Próximamente: Algorítmos e implementación de IA

¡Bienvenidos a la segunda parte de la serie sobre el desarrollo de Fluento! En el artículo anterior presentamos la idea general del proyecto. Hoy vamos a sumergirnos un poco más los detalles técnicos y funcionales que darán vida a esta aplicación.

MVP. Funcionalidades

Empezaremos por las funcionalidades mínimas que hemos definido para el MVP. El objetivo en esta fase inicial es que el usuario pueda usar la aplicación y podamos validar la idea y el negocio lo antes posible. Pero también necesitamos que sea lo suficientemente atractiva como para que pueda ser validada de forma correcta. A continuación vamos a definir el listado de funcionalidades mínimas que hemos definido para este MVP:

Registro/Login

El usuario debe poder crear una nueva cuenta o acceder a una ya existente. Habilitaremos acceso con mail y contraseña, así como con Google y Apple.

Explorar listas

El usuario, una vez identificado, debe poder acceder a un conjunto de listas ya creadas de diferentes temáticas y/o niveles de dificultad. Esto lo haremos a través de la sección que llamamos "Explora", que es la que contiene el conjunto de listas públicas, aquellas que son creadas por la propia plataforma y de libre acceso para cualquier usuario. Este contenido debe tener bastante dinamismo y variedad, intentando que se adapte lo mejor posible a diferentes tipos de usuario y que se actualice periódicamente para que el usuario no pierda interés.

Guardar sus listas

El usuario debe poder guardar aquellas listas que le interese para poder acceder de nuevo a ellas en el futuro y tenerlas siempre a mano. Esta sección la llamamos "Guardado". Del mismo modo, cuando un usuario decide practicar una lista, automáticamente se marcará como guardada para que aparezca en esta sección.

Crear listas

Un usuario Premium debe poder crear sus propias listas para poder practicar con contenido personalizado. Esta sección la llamamos "Mis listas". Las listas que se creen de esta forma, serán privadas y solo accesibles para el usuario que las ha creado. Para crear una lista, el usuario lo hará a través de un formulario en el que tendrá que especificar los parámetros de la misma: temática, nivel de dificultad, estructuras gramaticales, etc. Con esta información, un modelo de IA generará las frases que se incluirán.

Práctica

Esta es la funcionalidad principal de la aplicación. Sea en una lista pública o en una lista privada, el usuario debe poder practicar. Practicar en una lista consistirá en ir iterando por las distintas frases de la misma, de forma que el usuario pueda practicar de forma cíclica y repetitiva. El sistema se encargará de escoger la siguiente frase a practicar, analizando el progreso del usuario y haciendo que las frases que domina menos se repitan más veces y viceversa. Para ello, se implementará un algoritmo similar al de Anki, que ya veremos en más detalle cuando profundicemos en esa parte.

En cada unidad o frase a practicar, se seguirá el siguiente flujo:

  1. El usuario empezará viendo en pantalla y escuchando la frase en español.
  2. El usuario tendrá un tiempo para decir la traducción al inglés. Durante este tiempo, se activará el micrófono y se grabará su respuesta.
  3. Pasado este tiempo, el sistema procesará el audio recogido, pasándolo por un modelo de IA que lo convertirá a texto y luego lo comparará con la traducción correcta de la frase, emitiendo una evaluación entre 1 y 4 puntos.
  4. La aplicación mostrará en pantalla la respuesta correcta (la frase en inglés) y la reproducirá.
  5. En función de la evaluación, se le proporcionará feedback visual y auditivo.
  6. Finalmente, se ejecutará el algoritmo que escoge la siguiente frase para iniciar un nuevo ciclo.

Modelo freemium

Como explicamos en el anterior artículo, la idea de Fluento es aplicar un modelo fremium. El usuario podrá usar la aplicación de forma gratuita pero con limitaciones. Para desbloquear todas las funcionalidades, el usuario deberá suscribirse a un plan de pago mensual (aún por definir el precio). Las limitaciones que contemplamos para el plan gratuito son las siguientes:

  • No se podrá crear listas privadas.
  • Se establecerá un límite en el número de frases que se pueden practicar al día.

Partes que componen la plataforma

Ya hemos visto las funcionalidades mínimas que consideramos necesarias para el MVP. Ahora vamos a ver las partes que necesitamos implementar para dar soporte a estas funcionalidades.

Aplicación móvil

Por un lado y como no podría ser de otra manera, la aplicación móvil que utilizará el usuario final y que le ofrecerá la funcionalidad descrita.

API Rest

Por otro lado, necesitamos una API que pueda ser consumida por la aplicación móvil. Esta debe contar con todos los métodos necesarios para dar soporte a las funcionalidades que hemos descrito: gestión de usuarios, gestión de listas, gestión de sesiones de práctica, ejecución de modelos de IA, etc.

Base de datos

Obviamente, necesitaremos una base de datos que nos permita almacenar toda la información necesaria. Por el tipo de datos que tenemos y las relaciones que existen entre ellos, consideramos necesario usar una base de datos relacional.

Web corporativa

Si queremos llevar a cabo campañas de marketing y que los usuarios puedan entender lo que Fluento ofrece, es vital que contemos con una web corporativa a la que podamos mandar tráfico a través de diferentes acciones. Esta web debe explicar de forma clara y sencilla en que consiste esta plataforma y animar al usuario a que la empiece a utilizar. También debemos contar con una sección de ayuda o con las páginas legales necesarias. Todo esto se podrá encapsular dentro de esta misma web.

Back office

Aunque esto no es algo estrictamente necesario en esta fase MVP, donde lo que prima es que el usuario utilice la aplicación y recojamos feedback sobre ella lo antes posible, sí que consideramos importante contar con un mínimo back office que nos permita gestionar fundamentalmente 2 cosas:

  • Contenido del Explora: Como decíamos el contenido del Explora debe ser dinámico y variado, por lo que necesitaremos un sistema que nos permita llevar a cabo una gestión eficiente de dicho contenido.
  • Revisión de listas privadas: Las listas privadas se crearán de forma automática por el usuario y la idea es que no requiera de intervención humana. Sin embargo, es esperable que se puedan producir errores que necesiten de una intervención manual, como el forzar un reintento de creación de la lista. El back office debe permitir esta funcionalidad.

Arquitectura: Construyendo sobre bases sólidas

La arquitectura de Fluento está diseñada pensando en un equilibrio entre tres pilares fundamentales: escalabilidad, mantenibilidad y agilidad en el desarrollo. Veamos en detalle cada componente del stack tecnológico y por qué lo hemos elegido:

Aplicación móvil: React Native y Expo

Para el desarrollo de la aplicación móvil, hemos elegido React Native como nuestra tecnología principal. Esta decisión nos permite desarrollar tanto para iOS como para Android con un único código base, lo que reduce significativamente los costes de desarrollo y mantenimiento. La capacidad de Hot Reload acelera nuestro ciclo de desarrollo, permitiéndonos ver cambios en tiempo real. Además, Expo nos proporciona un ecosistema maduro que cuenta con una amplia variedad de librerías para gestionar las diferentes funcionalidades que necesitamos.

Sistema de autenticación: Supabase

Supabase es una plataforma de desarrollo que nos proporciona un sistema de autenticación robusto con OAuth listo para usar con múltiples proveedores. Esto nos facilita enormemente la gestión de registro e identificación de usuarios.

Base de datos: PostgreSQL en Supabase

Para la base de datos relacional, hemos optado por usar el PostgreSQL que nos proporciona Supabase. Esta elección nos da una base de datos robusta y escalable, que nos permitirá gestionar las relaciones entre los diferentes tipos de datos que necesitamos. Además Supabase nos ofrece una gestión que nos libera de las preocupaciones de administración de la misma.

Prisma: ORM para PostgreSQL

Aquí hemos tomado una decisión algo inusual y la vamos a justificar. Dado que estamos usando Supabase, lo lógico sería utilizar su propia API para interactuar con la base de datos, que además de ofrecernos una interfaz amigable, nos proporciona cosas muy interesantes como el mecanismos de seguridad Row Level Security.

Sin embargo, veíamos demasiada atadura la dependencia que esto implica. Pensando en el futuro, no sería extraño que queramos migrar a otro tipo de base de datos, como un RDS en AWS. Si esto ocurriera, nos veríamos obligados a cambiar de ORM, lo que nos llevaría tiempo y recursos.

Por ello, hemos optado por usar Prisma como ORM para PostgreSQL. Prisma nos proporciona un sistema de tipos TypeScript que nos permite interactuar con la base de datos de forma segura y sencilla, y nos ofrece una capa de abstracción que nos permite migrar a otra base de datos en el futuro si fuera necesario. Además, la integración entre Prisma y Supabase es totalmente válida y está documentada tanto por Prisma como por Supabase.

Back Office con NextJS y despliegue en Vercel

Para el back office, hemos optado por usar NextJS. Este framework nos permite crear una interfaz de administración altamente eficiente, donde la mayoría del renderizado ocurre en el servidor, resultando en una experiencia más rápida. La integración nativa con React Server Components significa que podemos construir interfaces complejas manteniendo tiempos de carga mínimos.

Además, para el despliegue hemos optado por usar Vercel, que nos proporciona una integración perfecta con NextJS y nos ofrece una solución sencilla y escalable para el despliegue de la aplicación, así como un sistema de CI/CD que nos permite desplegar de forma automática las diferentes versiones de la aplicación.

Consideramos que esta es una buena elección para esta fase inicial del MVP.

API Rest con NextJS

Aquí otra elección atípica. NextJS no es un framework orientado al desarrollo de APIs, y lo natural habría sido elegir un framework como NestJS o Fastify. Sin embargo, hemos optado por usar NextJS para el backend por varias razones:

  • Unificar desarrollo y despliegue de la API y el back office en un único proyecto.
  • El despliegue de los endpoints a Vercel como Edge Functions es perfecto para tareas como la del procesado de audio y texto con baja latencia,
  • La integración directa con Vercel simplifica enormemente el despliegue y el CI/CD.
  • La posibilidad de reutilizar tipos, utilidades y componentes entre el back office y la API, reduciendo la duplicación de código y manteniendo la consistencia en toda la plataforma. Nota: Esto mismo se podría conseguir utilizando una arquitectura de monorepo, donde tengamos las diferentes partes como proyectos independientes pero compartiendo esas funcionalidades comunes. Seguramente a futuro sea interesante explorar esta opción pero para el MVP nos parece suficiente esta solución y mucho más sencillo de implementar.

Web Corporativa con NextJS

Por la misma razón que la API, la web corporativa la desarrollaremos también con NextJS en el mismo proyecto. Dentro de esta web corporativa incluiremos aquellas landing pages o páginas que consideremos necesarias para explicar la plataforma y animar al usuario a que la empiece a utilizar. Además, dentro de esta web corporativa podemos incluir secciones de ayuda y las páginas legales necesarias.

Conclusión

En resumen, a pesar de que la plataforma cuenta con varias partes que funcionan de forma independiente, la estrategia adoptada nos permite tener únicamente 2 proyectos a implementar y mantener:

  • Proyecto app: La aplicación móvil con React Native y Expo.
  • Proyecto next: El proyecto NextJS que albergará la API, el back office y la web corporativa.

Fin

En este artículo hemos visto la arquitectura general de la plataforma y los componentes que la componen. Hemos justificado las decisiones técnicas tomadas y hemos definido la forma en la que abordaremos el proyecto. En los siguientes artículos de la serie, profundizaremos en la implementación de las diferentes partes de la plataforma. Si tienes alguna duda, si te gustaría que profundice más en algún aspecto o si te gustaría de alguna forma colaborar con este proyecto, no dudes en contactarme a través de:


Este es el segundo artículo de la serie "Desarrollando Fluento". Puedes continuar con el siguiente artículo de la serie: Implementación del backend