ivanDev
Libro Shop

Libro Shop

Iván Bazaga

Iván Bazaga

Desarrollador Junior

# 📚 LibroShop — Tienda Online de Libros

LibroShop es una plataforma de comercio electrónico para la venta de libros, construida con Next.js 16, PostgreSQL, Stripe y un vibrante sistema de diseño verde/esmeralda con acentos naranjas. Incluye una tienda pública completa y un panel de administración para gestionar el catálogo, las categorías y los pedidos.


# 📑 Tabla de Contenidos


# 🛠️ Stack Tecnologico

# Frontend

Tecnología Versión Propósito
Next.js 16.2.6 Framework React con App Router, Server Components y API Routes
React 19.2.6 Librería de UI con patrones modernos (ref como prop, Server Components)
TypeScript 6.0.3 Tipado estricto en toda la aplicación
Tailwind CSS 4.3.0 Framework CSS utility-first con configuración vía @theme
Zustand 5.0.0 Estado global del carrito con persistencia (zustand/middleware)
SWR 2.4.1 Data fetching y caching en el cliente
Lucide React 0.487.0 Iconografía SVG moderna y consistente
clsx + tailwind-merge 2.1.1 / 3.2.0 Gestión condicional de clases Tailwind

# Backend & Base de Datos

Tecnología Versión Propósito
Next.js API Routes 16.2.6 Backend RESTful integrado en el mismo proyecto
Prisma 6.5.0 ORM tipado para PostgreSQL con migraciones y seed
PostgreSQL Base de datos relacional (servidor remoto)

# Autenticación y Pagos

Tecnología Versión Propósito
NextAuth.js 5.0.0-beta.31 Autenticación del panel admin con Credentials provider
Stripe SDK 18.0.0 Pasarela de pagos con Checkout Session y webhooks

# Herramientas de Desarrollo

Tecnología Propósito
tsx Ejecución directa de TypeScript para scripts (seed, migraciones)
PostCSS + Autoprefixer Procesamiento de CSS

# ✨ Funcionalidades

# Tienda Publica

Ruta Descripción
/ Home: hero con gradiente y badges decorativos, sección de categorías con emojis y hover shine, libros destacados con tarjetas interactivas, newsletter CTA
/productos Catálogo completo con filtros por categoría, búsqueda, ordenación y cuadrícula responsiva
/productos/[slug] Detalle del libro: imagen, precio, descripción, metadatos (ISBN, editorial, páginas, formato) y botón de añadir al carrito
/carrito Carrito de compras con persistencia (Zustand + localStorage), resumen y botón de checkout
/checkout Redirige a Stripe Checkout Session para pago seguro
/success Confirmación de pedido exitoso
/cancel Mensaje de pago cancelado

# Panel de Administracion

Ruta Descripción
/admin/login Inicio de sesión con credenciales (NextAuth.js Credentials provider)
/admin Dashboard con estadísticas: total libros, pedidos, ingresos, pedidos recientes
/admin/libros CRUD de libros: listado, crear, editar, eliminar con formularios completos
/admin/categorias CRUD de categorías: listado, crear, editar, eliminar
/admin/pedidos Gestión de pedidos: listado con estado, detalle de cada pedido

# 📁 Estructura del Proyecto

├── prisma/
│   ├── schema.prisma          # Modelo de datos (Book, Category, Order, OrderItem)
│   └── seed.ts                # Datos de prueba (6 categorías, 12 libros, 5 pedidos)
├── public/                    # Assets estáticos
├── src/
│   ├── app/
│   │   ├── admin/             # Panel de administración
│   │   │   ├── categorias/    # CRUD categorías
│   │   │   ├── libros/        # CRUD libros
│   │   │   ├── login/         # Página de login
│   │   │   ├── pedidos/       # Gestión de pedidos
│   │   │   ├── layout.tsx     # Layout protegido del admin
│   │   │   └── page.tsx       # Dashboard
│   │   ├── api/               # API Routes RESTful
│   │   │   ├── admin/         # Endpoints protegidos del panel
│   │   │   ├── auth/          # NextAuth.js API
│   │   │   ├── books/         # CRUD público de libros
│   │   │   ├── categories/    # Categorías públicas
│   │   │   ├── checkout/      # Creación de Stripe Checkout Session
│   │   │   ├── orders/        # Consulta de pedidos
│   │   │   └── webhook/       # Webhook de Stripe
│   │   ├── cancel/            # Página de pago cancelado
│   │   ├── carrito/           # Página del carrito
│   │   ├── checkout/          # Redirección a Stripe
│   │   ├── productos/         # Catálogo y detalle de libros
│   │   ├── success/           # Página de pago exitoso
│   │   ├── error.tsx          # Error boundary global
│   │   ├── globals.css        # Configuración Tailwind v4 + animaciones
│   │   ├── layout.tsx         # Layout raíz (Header + Footer)
│   │   ├── loading.tsx        # Loading state global
│   │   ├── not-found.tsx      # Página 404 personalizada
│   │   └── page.tsx           # Home page
│   ├── components/
│   │   ├── books/             # Componentes de catálogo
│   │   │   ├── BookCard.tsx   # Tarjeta de libro con gradiente y animaciones
│   │   │   ├── BookFilters.tsx # Filtros (categoría, búsqueda, ordenación)
│   │   │   ├── BookGrid.tsx   # Cuadrícula responsiva de libros
│   │   │   ├── CategoryList.tsx # Tarjetas de categoría con emojis y hover shine
│   │   │   └── FeaturedBooks.tsx # Sección de libros destacados
│   │   ├── cart/              # Componentes del carrito
│   │   ├── layout/            # Layout (Header, Footer)
│   │   └── ui/                # Componentes atómicos reutilizables
│   │       ├── Badge.tsx      # Badge con 6 variantes de color
│   │       ├── Button.tsx     # Botón con 6 variantes + loading spinner
│   │       ├── EmptyState.tsx # Estado vacío con icono y mensaje
│   │       ├── Input.tsx      # Input con label y validación
│   │       └── NewsletterForm.tsx # Formulario de suscripción
│   ├── lib/
│   │   ├── api.ts             # Cliente SWR tipado
│   │   ├── auth.ts            # Configuración NextAuth.js (Credentials provider)
│   │   ├── prisma.ts          # Singleton del cliente Prisma
│   │   ├── sample-data.ts     # Datos de ejemplo para seed
│   │   ├── stripe.ts          # Inicialización de Stripe SDK
│   │   └── utils.ts           # Utilidades (formateo de precios, cn())
│   ├── proxy.ts               # Next.js 16 proxy para auth (reemplaza middleware.ts)
│   └── store/
│       └── cart-store.ts      # Store Zustand 5 del carrito con persistencia
├── .env                       # Variables de entorno (DB, Stripe, admin credentials)
├── next.config.ts             # Configuración de Next.js
├── package.json               # Dependencias y scripts
├── postcss.config.js          # Configuración de PostCSS
└── tsconfig.json              # TypeScript strict configuration

# 🗃️ Modelo de Datos

# Category

Campo Tipo Descripción
id String (cuid) Identificador único
name String Nombre de la categoría
slug String (unique) Slug para URLs
description String? Descripción opcional
imageUrl String? URL de imagen opcional
createdAt DateTime Fecha de creación
updatedAt DateTime Fecha de actualización

# Book

Campo Tipo Descripción
id String (cuid) Identificador único
title String Título del libro
author String Autor
slug String (unique) Slug para URLs
description String Descripción del libro
content String? Contenido extendido opcional
price Float Precio actual
comparePrice Float? Precio original (para mostrar descuento)
imageUrl String URL de portada
imageGallery String[] Galería de imágenes
stock Int Stock disponible
pages Int? Número de páginas
isbn String? Código ISBN
publisher String? Editorial
publishedYear Int? Año de publicación
language String Idioma (default: Español)
format String Formato (default: Tapa blanda)
featured Boolean Destacado en home
categoryId String FK a Category
createdAt DateTime Fecha de creación
updatedAt DateTime Fecha de actualización

# Order

Campo Tipo Descripción
id String (cuid) Identificador único
stripeSessionId String? (unique) ID de sesión de Stripe
customerEmail String Email del cliente
customerName String Nombre del cliente
customerPhone String? Teléfono opcional
customerAddress String? Dirección opcional
total Float Total del pedido
status String Estado (pending, completed, cancelled)
createdAt DateTime Fecha de creación
updatedAt DateTime Fecha de actualización

# OrderItem

Campo Tipo Descripción
id String (cuid) Identificador único
orderId String FK a Order (Cascade on delete)
bookId String FK a Book
quantity Int Cantidad
price Float Precio unitario en el momento de la compra

# 🏗️ Arquitectura

# Principios

  • Single-project: El frontend y backend (API Routes) conviven en un mismo proyecto Next.js — no hay separación física entre cliente y servidor.
  • Server Components: Las páginas públicas usan React Server Components para renderizado en servidor con streaming.
  • NextAuth.js v5 Credentials: El panel admin se protege mediante autenticación por credenciales con sesiones JWT.
  • Next.js 16 Proxy: En lugar del deprecated middleware.ts, se usa proxy.ts con exportación proxy para proteger las rutas /admin/* y /api/admin/*.
  • Stripe Checkout Session: Stripe gestiona la UI de pago, reduciendo la complejidad del frontend.
  • Zustand 5 + Persist: El carrito usa selectores individuales (no desestructuración completa) para evitar re-renderizados innecesarios.

# Flujo de Compra

1. Usuario navega catálogo → añade libros al carrito (Zustand persist)
2. Va al carrito → revisa resumen → hace clic en "Pagar"
3. API Route /api/checkout crea una Stripe Checkout Session
4. Redirige a Stripe → usuario paga en la interfaz de Stripe
5. Stripe redirige a /success o /cancel
6. Webhook de Stripe actualiza Order.status a "completed"

# Flujo de Autenticación Admin

1. Usuario visita /admin/login → introduce credenciales
2. NextAuth.js valida contra credenciales en .env
3. Proxy.ts intercepta /admin/* y /api/admin/* → verifica sesión JWT
4. Si no autenticado → redirige a /admin/login
5. Si autenticado → permite el acceso

# 🎨 Sistema de Diseno

# Paleta de Colores

  • Primary (Verde esmeralda): #059669 (primary-600) — color principal de la marca, usado en botones, enlaces y elementos destacados
    • Escala completa: 50 → 950 (verde vibrante progresivo hasta casi negro)
  • Accent (Naranja): #F97316 (accent-500) — usado para CTAs, ofertas, badges de descuento
    • Escala completa: 50 → 900

# Tipografía

Propósito Fuente Pesos
Títulos y displays Rubik 300, 400, 500, 600, 700, 800
Cuerpo de texto Nunito Sans 300, 400, 600, 700

# Estilos Visuales

  • Esquinas redondeadas: rounded-xl, rounded-2xl, rounded-3xl según el contexto
  • Gradientes: fondos degradados en hero, tarjetas de categoría y libros destacados
  • Efectos hover: hover:-translate-y-1.5 con sombra elevada (shadow-xl, shadow-2xl)
  • Efectos de presión: active:scale-[0.97] en botones, active:scale-95 en iconos
  • Animaciones: animate-fade-in (entrada), animate-float (flotación), animate-pulse-glow (brillo pulsante)
  • Patrón decorativo: bg-grid-pattern (cuadrícula semitransparente) para fondos de hero

# Componentes UI

Componente Variantes Características
Button primary, accent, outline, ghost, danger, link Loading spinner, active:scale-[0.97], rounded-xl, sombras
Badge default, success, warning, danger, accent, outline Colores alineados con la paleta, rounded-full
Input Label + input + mensaje de error, rounded-xl
BookCard Gradiente de fondo dinámico, overlay en hover, badge de categoría, rating con estrellas, botón glossy
CategoryList Gradiente por categoría (mapeo por slug), emoji decorativo, hover shine effect

# 📋 Requisitos Previos

  • Node.js 20+ (recomendado 22 LTS)
  • npm 10+
  • PostgreSQL 14+ (o acceso a una base de datos remota)
  • Cuenta de Stripe (para claves de API en produccion)

# ⚙️ Instalacion y Configuracion

# 1. Clonar e instalar dependencias

git clone <tu-repo>
cd venta-de-libros-online
npm install

# 2. Configurar variables de entorno

Copia el archivo .env incluido y ajústalo con tus valores reales:

# Base de datos PostgreSQL
DATABASE_URL="postgresql://usuario:password@host:5432/nombre_bd"

# Stripe (modo test)
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY="pk_test_..."
STRIPE_SECRET_KEY="sk_test_..."
STRIPE_WEBHOOK_SECRET="whsec_..."

# Admin credentials (NextAuth.js)
ADMIN_EMAIL="admin@ejemplo.com"
ADMIN_PASSWORD="contraseña_segura"

# NextAuth
AUTH_SECRET="tu_secreto_jwt_generado_con_openssl_rand_base64_32"
AUTH_URL="http://localhost:3000"

# 3. Configurar base de datos

# Push del esquema a la base de datos
npm run db:push

# Cargar datos de prueba (6 categorías, 12 libros, 5 pedidos)
npm run db:seed

# 4. Iniciar en desarrollo

npm run dev

Abrir http://localhost:3000.


# 📟 Comandos Disponibles

Comando Descripción
npm run dev Inicia servidor de desarrollo
npm run build Compila para producción
npm start Inicia servidor de producción
npm run lint Ejecuta linter
npm run db:generate Genera cliente Prisma
npm run db:push Push del esquema a la BD
npm run db:seed Carga datos de prueba
npm run db:reset Resetea la base de datos (¡cuidado!)
npm run db:studio Abre Prisma Studio (UI para explorar datos)
npm run setup db:push + db:seed en un solo comando

# 🔐 Variables de Entorno

Variable Obligatoria Descripción
DATABASE_URL URL de conexión PostgreSQL
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY Clave pública de Stripe (pk_)
STRIPE_SECRET_KEY Clave secreta de Stripe (sk_)
STRIPE_WEBHOOK_SECRET ✅* Secreto del webhook de Stripe (whsec_)
ADMIN_EMAIL Email para login del panel admin
ADMIN_PASSWORD Contraseña para login del panel admin
AUTH_SECRET Secreto JWT para NextAuth.js
AUTH_URL URL base de la aplicación

Nota: STRIPE_WEBHOOK_SECRET es obligatorio para el webhook de confirmacion de pagos, pero el checkout funciona sin el (los pedidos quedaran como pending hasta que el webhook los actualice).


# 🌐 API Routes

# Públicas

Endpoint Método Descripción
/api/books GET Lista libros (con filtros: categoría, búsqueda, ordenación, página)
/api/books/[slug] GET Detalle de un libro por slug
/api/categories GET Lista todas las categorías
/api/checkout POST Crea una Stripe Checkout Session
/api/webhook POST Webhook de Stripe (actualiza estado del pedido)
/api/orders GET Consulta pedidos (por email de cliente)

# Protegidas (requieren autenticación admin)

Endpoint Método Descripción
/api/admin/stats GET Estadísticas del dashboard
/api/admin/books GET, POST CRUD de libros
/api/admin/books/[id] GET, PUT, DELETE CRUD de libro individual
/api/admin/categories GET, POST CRUD de categorías
/api/admin/categories/[id] GET, PUT, DELETE CRUD de categoría individual
/api/admin/orders GET Lista todos los pedidos
/api/admin/orders/[id] GET Detalle de pedido
/api/auth/* Rutas de NextAuth.js (signin, signout, session, etc.)

# 🚀 Despliegue

# Vercel (recomendado)

# Instalar Vercel CLI
npm i -g vercel

# Desplegar
vercel

Configuración necesaria en Vercel:

  1. Conectar el repositorio de GitHub/GitLab
  2. Añadir todas las variables de entorno en el panel de Vercel
  3. Configurar el dominio personalizado (opcional)
  4. Para webhooks de Stripe en producción, usar vercel url como endpoint del webhook

# Consideraciones para producción

  • Stripe: Cambiar de modo test a producción y actualizar las claves
  • Base de datos: Usar una BD PostgreSQL gestionada (Neon, Supabase, Railway, etc.)
  • AUTH_SECRET: Generar un secreto fuerte: openssl rand -base64 32
  • Webhook: Configurar el endpoint /api/webhook en el panel de Stripe para recibir eventos checkout.session.completed
  • Imágenes: Usar un servicio de imágenes optimizado (Cloudinary, Vercel Blob, etc.) y configurar remotePatterns en next.config.ts
  • SSL/HTTPS: Asegurar que el despliegue use HTTPS (Vercel lo hace automáticamente)

# 📄 Licencia

Este proyecto es de uso personal/educativo. Todos los derechos reservados.


Construido con ❤️ usando Next.js 16, React 19, PostgreSQL y Tailwind CSS v4