#
📚 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
npm run db:push
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)
npm i -g vercel
vercel
Configuración necesaria en Vercel:
- Conectar el repositorio de GitHub/GitLab
- Añadir todas las variables de entorno en el panel de Vercel
- Configurar el dominio personalizado (opcional)
- 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