BeYourMotorbike

Plataforma de Alquiler de Motos en Tenerife

El Desafío

Desarrollé una plataforma completa de alquiler de motocicletas desde cero utilizando Next.js 15 con TypeScript, PostgreSQL y Prisma ORM. El proyecto incluye un sistema de autenticación robusto con NextAuth.js, procesamiento de pagos con Stripe (incluyendo depósitos, comisiones automáticas y reembolsos), y un panel administrativo completo para gestión de usuarios, reservas y analytics.

Stack Tecnológico

Frontend

Next.js 15
TypeScript
Tailwind CSS
Framer Motion
Leaflet

Backend

Prisma ORM
NextAuth.js
Stripe
Zod

Database

PostgreSQL

Tools

Cloudinary
next-intl

Desafíos Técnicos Superados

Diseño de Base de Datos desde Cero

Desafío:

Primera vez diseñando un esquema relacional completo para un marketplace con múltiples entidades interconectadas.

Solución:

Creé 8+ tablas interconectadas con relaciones complejas entre usuarios, motos, reservas y pagos. Implementé roles granulares (CLIENT, PROVIDER, ADMIN) y un sistema de documentos escalable.

Resultado:

Sistema escalable que maneja eficientemente todas las operaciones del marketplace con integridad referencial completa.

Sistema de Pagos Complejo

Desafío:

Integrar Stripe con cálculos automáticos de comisiones, depósitos, descuentos y reembolsos.

Solución:

Implementé webhooks para procesar pagos en tiempo real, calcular comisiones automáticas, manejar depósitos del 15% inicial y un sistema de reembolsos con tracking completo.

Resultado:

Sistema automático de pagos que procesa transacciones de forma segura con cálculos financieros precisos.

Internacionalización Empresarial

Desafío:

Crear una plataforma multiidioma con SEO optimizado para tres mercados diferentes.

Solución:

Implementé next-intl con soporte completo para ES/EN/DE, configuré hreflang para SEO, y creé middleware inteligente para redirección automática según el idioma del navegador.

Resultado:

Plataforma completamente internacionalizada con SEO optimizado para tres idiomas y UX fluida.

Funcionalidades Destacadas

Sistema de Documentos Avanzado

Permite escanear documentos con la cámara del móvil, recortarlos con CropperJS y subirlos organizadamente a Cloudinary. Incluye validación de ITV, seguros y licencias con tokens de acceso para visualización segura.

Panel Administrativo Completo

Panel con gestión de usuarios, motos, reservas y analytics en tiempo real. Incluye sistema de marketing con exportación de datos y gestión de reembolsos con estados.

Procesamiento de Pagos Automático

Integración completa con Stripe que maneja depósitos (15% inicial), cálculo automático de comisiones, códigos de descuento y reembolsos con tracking completo.

Sistema de Reservas Inteligente

Calendarios dinámicos con disponibilidad en tiempo real, cálculo automático de precios según duración, aplicación de descuentos y gestión de extras (cascos, chaquetas, etc.).

Resultados del Proyecto

2 meses
Tiempo de Desarrollo
8+
Tablas de Base de Datos
3
Idiomas Implementados
15+
Endpoints de API
100%
Type Safety
6
Secciones del Panel Admin

Código Destacado

JWT con Renovación Automática y Validación de Usuario

Sistema JWT avanzado con verificación automática de usuarios en base de datos y renovación proactiva de tokens para mantener sesiones seguras.

// JWT con renovación automática y validación de usuario
async jwt({ token, user }) {
  if (user) {
    token.id = user.id;
    token.role = user.role;
    token.iat = Math.floor(Date.now() / 1000);
    token.exp = Math.floor(Date.now() / 1000) + 24 * 60 * 60;
  }

  // Verificar que el usuario existe en la base de datos
  if (token.id) {
    try {
      const userExists = await prisma.user.findUnique({
        where: { id: token.id as string },
        select: { id: true, role: true },
      });

      if (!userExists) {
        return { ...token, error: "UserNotFound" };
      }

      token.role = userExists.role;
    } catch (error) {
      console.error("Error verifying user existence:", error);
      return { ...token, error: "UserVerificationFailed" };
    }
  }

  // Renovar el token si está próximo a expirar (2 horas antes)
  if (
    token.exp &&
    typeof token.exp === "number" &&
    token.exp < Math.floor(Date.now() / 1000) + 2 * 60 * 60
  ) {
    token.exp = Math.floor(Date.now() / 1000) + 24 * 60 * 60;
  }

  return token;
}

Sistema de Documentos con Validación

Validación robusta de documentos con Zod para garantizar la integridad de los datos antes de la subida.

// Sistema de documentos con validación
const documentSchema = z.object({
  documentType: z.enum(['id', 'license', 'itv', 'insurance']),
  side: z.enum(['front', 'back']),
  file: z.instanceof(File),
  expiryDate: z.date().optional()
});
Cristian Perdomo - Desarrollador Full Stack