Casi nadie sabe cuánto paga por mes en suscripciones, y menos cuando están en más de una moneda. TrackMySubs reúne todo en un solo lugar: el usuario registra sus servicios (Netflix, Spotify, YouTube y más), ve cuánto gasta, marca lo que ya pagó este mes y descarga un informe.
El producto en sí se vende como suscripción mensual con tres planes, cobrada con pagos recurrentes reales a través de Mercado Pago. Quién puede hacer qué, cuánto y hasta cuándo se decide y se aplica en el servidor y en la base de datos, no solo en la interfaz.
Por qué importa
Los cobros pequeños y recurrentes son fáciles de olvidar y difíciles de sumar. TrackMySubs lo resuelve, y además está construido como un producto de pago completo y pensado para producción.
- Claro: un dashboard con el total mensual separado por moneda (ARS, USD, EUR...), la próxima fecha de cobro de cada servicio y lo que ya se pagó este mes.
- Práctico: filtra por moneda o categoría, pausa o cancela servicios, marca todo como pagado con un clic y descarga el mes en CSV o PDF.
- Facturación justa: tres planes mensuales, prueba gratis solo la primera vez, mejoras de plan que cobran únicamente la parte restante del mes, bajas de plan que rigen desde el siguiente período y cancelación que mantiene el acceso hasta que termina lo ya pagado.
- Confiable: precios, límites y permisos nunca vienen del navegador. El servidor verifica cada pago con Mercado Pago y la base de datos rechaza todo lo que el plan no permite.
- Aislado: los datos de cada usuario son invisibles para los demás, a nivel de base de datos.
Planes
- Free (ARS 0): hasta 4 servicios activos, con exportación a CSV y PDF.
- Standard (ARS 4.999 por mes): hasta 7 servicios activos, con 30 días gratis solo la primera vez y exportación a CSV y PDF.
- Pro (ARS 9.999 por mes): servicios activos ilimitados, con exportación a CSV y PDF.
Los precios, los límites y la duración de la prueba viven en la base de datos (tabla plans), así que cambiarlos no requiere tocar el código de la aplicación.
Qué hace
Dashboard
- Agrega un servicio con nombre, costo, moneda, ciclo de cobro (mensual o anual), fecha de cobro y categoría. Se puede editar, eliminar y cambiar su estado: activo, pausado o cancelado.
- Marca un servicio, o todos, como pagado en el mes. El estado se reinicia solo cada mes.
- Muestra el total por moneda de los servicios activos (los anuales cuentan como equivalente mensual) y cuánto ya está pagado.
- Calcula la próxima fecha de cobro de cada servicio a partir de su día de facturación.
- Filtros por moneda y categoría, y un contador de uso frente al límite del plan (por ejemplo,
3 / 4 servicios activos). - Descarga del mes completo en CSV o PDF, con totales por moneda.
- Avisos: "Tu plan termina pronto" (plan cancelado, 7 días o menos) y "No recibimos tu último pago" (renovación todavía sin confirmar).
- Las cuentas suspendidas ven una pantalla de renovación en lugar del dashboard, y sus datos permanecen a salvo.
Facturación y gestión del plan
- Página pública de planes que se adapta a quién la mira: visitante, usuario free, de pago, cancelado o suspendido.
- Resumen de compra y redirección a Mercado Pago para autorizar el pago recurrente. Mientras se confirma el pago hay pantallas de éxito (con consulta automática), pendiente y error.
- Mejora (Standard a Pro): el usuario paga solo la diferencia de precio por lo que resta del período, mediante un pago único. Pro empieza apenas se aprueba el pago y el siguiente cobro ya es el de Pro.
- Baja (Pro a Standard): queda programada. Mantiene Pro hasta que termina el período pagado y el siguiente cobro es el de Standard.
- Cancelación: irreversible. Conserva el plan actual hasta que termina el período pagado, sin reembolso, y después se puede volver a suscribir.
- Renovación: cuando el plan termina y la cuenta queda suspendida, el usuario se suscribe de nuevo desde Configuración.
Cómo funciona la facturación
Esta es la parte más delicada del proyecto, porque el dinero no puede depender de lo que diga el navegador.
- El usuario elige un plan. El navegador solo envía el identificador del plan.
- El servidor lee de la base el precio, la prueba gratis y la suscripción del propio usuario, y crea en Mercado Pago una suscripción en estado pendiente.
- Mercado Pago devuelve una URL de autorización y el usuario autoriza el pago allí.
- Mercado Pago avisa al servidor con una notificación firmada que solo trae un identificador.
- El servidor consulta a Mercado Pago el estado real de la suscripción y alinea la base de datos con él: activa el plan y el fin del período.
- Mientras tanto, la página de éxito consulta el estado hasta que el plan queda activo y redirige al dashboard.
El ciclo de vida del plan es: Free → Activo al autorizarse el pago → Cancelado si el usuario cancela → Suspendido cuando termina el período pagado, o si la suscripción se pausa o no se renueva. Desde Suspendido se vuelve a Activo suscribiéndose de nuevo.
Decisiones de diseño
- El servidor es la fuente de verdad del dinero. Precio, moneda, prueba, usuario y email se leen en el servidor. El monto de una mejora se calcula en el servidor y lo vuelve a validar el webhook.
- Los webhooks sincronizan estado, no confían en el contenido. La notificación solo aporta un identificador; el manejador consulta el recurso actual en Mercado Pago, así que notificaciones repetidas o fuera de orden son inofensivas.
- El acceso se deriva, no se guarda como bandera. Una función de la base de datos calcula el plan vigente a partir del plan, el estado y el fin del período, de modo que un plan vencido pierde el acceso solo, sin tareas programadas.
- Las reglas de negocio viven en la base de datos (límites, suspensión, columnas inmutables), así que se cumplen sin importar qué cliente llame a la API.
- Sin librerías de terceros para la lógica de planes: mejoras, bajas y cancelaciones son funciones de servidor pequeñas y explícitas, cada una con sus propias comprobaciones.
Seguridad
Defensa en profundidad: cada operación sensible se verifica en varios niveles independientes.
- Proxy: refresca la sesión en cada petición, protege
/dashboard,/settingsy/checkout, y redirige a los usuarios con sesión fuera de las pantallas de acceso. - Server Actions: vuelven a comprobar la sesión, el email verificado y el estado de la suscripción antes de actuar. Validan los planes contra una lista permitida y toman usuario, precio y moneda del servidor.
- Módulo de Mercado Pago: sus funciones (cancelar, cambiar monto, leer cualquier suscripción por id) no se exponen como Server Actions, porque
"use server"las convertiría en endpoints públicos. Sonserver-onlyy solo las llaman acciones propias y autenticadas, usando el id de suscripción guardado en la fila del propio usuario. - Webhook: verifica la firma HMAC con comparación de tiempo constante, valida el formato del id, registra cada evento para garantizar idempotencia, consulta el estado real a Mercado Pago y actualiza la base. Los fallos reintentables devuelven 500 para que Mercado Pago reenvíe; los permanentes quedan como
failedcon su motivo. - Row Level Security: todas las tablas deniegan por defecto. Cada usuario ve y cambia solo sus filas, y
payment_eventsno tiene ninguna política (solo accesible con la clave de servicio). - Privilegios por columna: en
servicessolo se pueden insertar o actualizar columnas concretas, ysubscriptionsno puede ser escrita por ningún cliente. - Triggers: un bloqueo por usuario más un trigger hacen cumplir el límite de servicios activos del plan y bloquean cambios en cuentas suspendidas, para que peticiones concurrentes no esquiven el límite.
- Funciones auxiliares: sin permiso de ejecución para
anonniauthenticated, y consearch_pathvacío.
Otras protecciones:
- Protección contra redirecciones abiertas: el parámetro
nextsolo acepta rutas internas. - "Olvidé mi contraseña" responde siempre igual, para no revelar qué emails existen, y cambiar la contraseña exige la actual.
- Si se autoriza una segunda suscripción mientras hay una activa, la más nueva se cancela automáticamente en Mercado Pago para no cobrar dos veces.
- Un evento de cancelación tardío de una suscripción vieja nunca pisa a una más nueva.
- Los pagos de mejora los revalida el webhook: quién paga, qué plan, referencia, moneda y que el monto esté dentro del rango permitido de la diferencia de precio.
- Las exportaciones CSV neutralizan fórmulas de hojas de cálculo (
=,+,-,@). - Los secretos (token de Mercado Pago, secreto del webhook y clave de servicio) solo se leen en el servidor.
Casos borde contemplados
- Doble clic y doble checkout: la suscripción duplicada se cancela sola.
- Webhooks entregados dos veces o fuera de orden.
- Un pago confirmado antes o después de que el usuario vuelva al sitio.
- Un usuario que llega a la página de éxito con un id falso: eso solo afecta qué pantalla se muestra, nunca el acceso.
- Un plan que vence con la aplicación abierta: la base de datos rechaza los cambios.
Verificación
Este proyecto todavía no tiene pruebas automatizadas. El comportamiento se verifica con una matriz manual de permisos por estado de cuenta (free, activo, cancelado y suspendido) y con escenarios en el entorno de pruebas de Mercado Pago:
- Compra con prueba gratis, y segunda compra tras cancelar, sin prueba.
- Mejora: se cobra el monto mostrado, el plan pasa a Pro y el siguiente cobro es el de Pro.
- Baja programada: el plan sigue siendo Pro hasta que se procesa el siguiente cobro.
- Cancelación: el acceso se mantiene hasta la fecha de fin y no aparecen botones de cambio ni de compra.
- Repetición de la misma notificación: se registra una sola vez y se omite.
El esquema incluye consultas de comprobación, y la tabla payment_events permite auditar cada pago con su estado y su error.
Stack
- Next.js 16 (App Router, Server Components, Server Actions,
proxy.ts) y React. - TypeScript estricto, Tailwind CSS v4 y shadcn/ui con primitivos de Base UI.
- Supabase: Auth con email y contraseña, verificación de email y recuperación, y PostgreSQL con Row Level Security, privilegios por columna y triggers.
- Mercado Pago: suscripciones (API PreApproval) y Checkout Pro para el pago único de las mejoras, con el SDK oficial.
- jsPDF y jspdf-autotable para los informes PDF, generados en el cliente.
- Autenticación y pagos arrancaron con módulos generados por
@dariomvg/create(basic-authde Supabase ysubscriptionsde Mercado Pago). Después se adaptaron: el webhook se reescribió para ser idempotente y sincronizar estado, y las funciones del módulo de pagos dejaron de ser Server Actions.
Alcance y límites conocidos
- Sin pruebas automatizadas y sin límite de frecuencia de peticiones (haría falta un almacén externo como Redis).
- Los planes se facturan solo en ARS, aunque los servicios registrados pueden estar en cualquier moneda.
- No hay reembolsos al cancelar ni al bajar de plan, y la cancelación es definitiva.
- Los pagos de mejora duplicados quedan registrados como
failedy se reembolsan a mano desde Mercado Pago. - No hay eliminación de cuenta: borrar un usuario directamente en Supabase elimina sus datos, pero no cancela su suscripción en Mercado Pago.
Lo que demuestra este proyecto
- Cobros recurrentes de punta a punta: alta, renovación, mejora prorrateada, baja programada y cancelación.
- Webhooks firmados e idempotentes que sobreviven a entregas duplicadas y desordenadas.
- Un modelo donde el acceso se deriva del estado y la base de datos hace cumplir los límites del plan.
- Criterio de producto: prueba gratis una sola vez, período de gracia en los pagos, y límites y precios editables sin desplegar.
