Vicente Jorquera
Vicente Jorquera

Publicado el 15/06/2025

Finanzas Personales

Dashboard de Finanzas Personales

Enlaces

El Vistazo General

Este proyecto nace como un “side project” de fin de semana con un objetivo simple: crear una plataforma para registrar y visualizar mis finanzas personales —ingresos, gastos, ahorros— de manera intuitiva. Sin embargo, el desafío fue construirla con una arquitectura full-stack escalable, segura y moderna.

Una de las características centrales de la aplicación es ayudar a los usuarios a gestionar sus ingresos mensuales de forma eficiente. Para ello, se ha implementado una recomendación de gastos basada en la popular regla 50/30/20. Como se puede ver en el dashboard, la aplicación desglosa automáticamente el total de ingresos mensuales en tres categorías:

Esta guía visual e intuitiva, representada con un gráfico circular, permite a los usuarios entender rápidamente cómo se distribuyen sus ingresos y tomar decisiones financieras más informadas para alcanzar sus metas.

Este artículo ofrece un análisis técnico de la aplicación, detallando las decisiones de diseño y las tecnologías implementadas, desde el modelo de datos hasta la autenticación y la gestión del estado.

Tecnologías Clave

Despliegue: Vercel y Supabase

Para un “side project”, la facilidad y rapidez de despliegue son cruciales. Por ello, opté por una combinación de servicios que ofrecen generosos planes gratuitos y una experiencia de desarrollador excepcional:

Modelo de Datos en Prisma

Todo proyecto sólido comienza con un buen modelo de datos. Para este proyecto, utilicé Prisma por su simplicidad y seguridad de tipos. El diseño se centra en un modelo principal llamado FinanzasPersonales, que actúa como el contenedor de toda la información financiera de un usuario.

A continuación, un diagrama que ilustra las relaciones principales del modelo de datos:

Modelo de datos

Consideraciones Multi-Tenant: finanzasId

Desde el inicio, quise que la aplicación fuera capaz de manejar múltiples usuarios de forma segura, aislando completamente sus datos. Esto se conoce como arquitectura multi-tenant.

La solución fue el modelo FinanzasPersonales. Cada User tiene una única instancia de FinanzasPersonales. Luego, cada transacción (como un Gasto o un Ingreso) no se relaciona directamente con el User, sino con su FinanzasPersonales a través de un campo finanzasId.

Esto ofrece dos ventajas clave:

  1. Seguridad: Asegura que las consultas a la base de datos siempre puedan ser filtradas por finanzasId, evitando que un usuario pueda acceder accidentalmente a datos de otro.
  2. Flexibilidad a Futuro: Este diseño abre la puerta a funcionalidades colaborativas. En el futuro, podría permitir que un usuario “invite” a otros a su FinanzasPersonales, creando un espacio compartido para gestionar las finanzas en pareja o en grupo, sin tener que reestructurar la base de datos.

Seguridad: Autenticación con Auth.js y Rutas Protegidas

Para la autenticación, me decanté por Auth.js (anteriormente NextAuth.js) por su increíble flexibilidad y su integración nativa con Next.js.

Configuración de Auth.js

La configuración es sorprendentemente sencilla. Utilicé el PrismaAdapter, que se encarga de gestionar automáticamente los modelos User, Account y Session en la base de datos. Como proveedor de autenticación, elegí Google, ya que ofrece un buen balance entre seguridad y facilidad de uso para el usuario final.

El archivo src/auth.ts centraliza toda esta lógica. Uno de los puntos más interesantes es el uso de los events y callbacks:

// src/auth.ts (extracto)
callbacks: {
    async session({ session, user }) {
      if (session.user) {
        const finanzas = await prisma.finanzasPersonales.findUnique({
          where: { userId: user.id },
        });
        // Agregar el ID de FinanzasPersonales a la sesión
        (session.user as any).finanzasId = finanzas?.id || null;
      }
      return session;
    }
}

Protección de Rutas

Con el finanzasId disponible en la sesión, proteger las rutas y asegurar el acceso a los datos es mucho más sencillo. Aunque no hay un archivo middleware.ts global, la protección se realiza a nivel de página o layout en el servidor.

Usando la función auth() de Auth.js, puedo obtener la sesión del usuario en cualquier Server Component. Si la sesión no existe o no es válida, puedo redirigir al usuario a la página de login. Para las llamadas a la base de datos, siempre uso el finanzasId de la sesión para filtrar los resultados.

Gestión de Estado en el Cliente con Redux Toolkit

Si bien Next.js fomenta el uso de Server Components, una aplicación interactiva como esta necesita una gestión de estado robusta en el cliente. Para esto, elegí Redux Toolkit.

Redux me permite tener un “store” centralizado que actúa como la única fuente de verdad para los datos que se muestran en la UI. Esto evita tener que pasar props a través de múltiples niveles de componentes (prop drilling) y simplifica la lógica de carga y actualización de datos.

La estructura en src/store/ es la estándar de Redux Toolkit, con slices para cada tipo de dato principal:

Cada slice gestiona su propio estado (los datos, el estado de carga, errores, etc.) y define los reducers y thunks asíncronos para interactuar con la API del backend. Esto mantiene el código organizado, predecible y fácil de depurar con las herramientas de desarrollo de Redux.

Conclusiones y Próximos Pasos

Lo que empezó como un proyecto de fin de semana se ha convertido en una base sólida y escalable para una aplicación de finanzas personales. La combinación de Next.js, Prisma, Auth.js y Redux Toolkit demostró ser extremadamente poderosa y eficiente para desarrollar rápidamente una aplicación full-stack.

Este proyecto no solo me ayudó a afianzar mis conocimientos en estas tecnologías, sino que también me dejó con una herramienta útil y con un gran potencial para seguir creciendo.

Próximos pasos que tengo en mente: