Tienda online de bisutería y accesorios (aretes, collares, pulseras, anillos y más) enfocada al mercado colombiano. Construida sobre el stack más reciente del ecosistema React/Next para entregar una experiencia rápida, segura y escalable.
- Framework: Next.js 16 (App Router) + React 19 + TypeScript estricto
- Base de datos: Supabase (PostgreSQL) + Drizzle ORM
- Autenticación: Supabase Auth (
@supabase/ssr) con Edge Middleware - Estado global (carrito): Zustand con persistencia en
localStorage - UI: Tailwind CSS + shadcn/ui (Radix) — fonts DM Sans / Playfair Display
- Validación: Zod + react-hook-form
- Pasarela de pago: Wompi (Web Checkout + webhook firmado)
- Transportadora: Coordinadora (cotización + generación de guía, con fallback a tarifa plana)
- Emails transaccionales: Resend + React Email
- Iconografía: Lucide React
- Hosting: Netlify
- Catálogo dinámico (SSR) con filtros por material y precio.
- Detalle de producto rico: galería, breadcrumb, selector de variantes con stock por opción, cantidad, wishlist, compartir, pills de confianza (envío gratis / devoluciones / garantía / pago seguro), tabs de descripción/especificaciones/cuidados/envíos, sección de reseñas con calificación promedio, distribución por estrellas y formulario para clientes autenticados, y productos relacionados de la misma categoría.
- Carrito persistente con validación de stock en tiempo real, soporte de variantes (Oro 18k, Plata 925, etc.) y drawer lateral.
- ProductCard enriquecida: precio en COP, badge de descuento automático, stock bajo (
¡Solo quedan 3!), pill de envío gratis, conteo de variantes y estado "Agotado".
- Registro / login con Supabase Auth.
- Perfil con configuración personal.
- Mis pedidos — listado e historial completo con detalle por pedido y tracking.
- Formulario de envío con selector de direcciones guardadas + opción de nueva dirección.
- Snapshot inmutable de dirección y precios al momento del pedido.
- Reserva transaccional de stock al crear el pedido (
PENDING). - Redirección a Wompi Web Checkout para tarjetas, PSE, Nequi y Bancolombia.
- Webhook firmado (HMAC SHA256) que actualiza el estado del pedido y restaura stock si el pago falla.
- Cotización dinámica por ciudad/peso/dimensiones.
- Generación automática de guía desde el panel admin.
- Fallback a tarifa plana cuando las credenciales no están configuradas (no bloquea el checkout durante el onboarding comercial).
- Bienvenida al registrarse.
- Confirmación de pago con resumen del pedido.
- Notificación de envío con número de guía.
- Dashboard con métricas básicas.
- CRUD completo de productos, variantes, categorías y clientes.
- Gestión de pedidos: cambio de estado, registro manual de tracking, generación de guía Coordinadora, reenvío de emails.
- Roles
ADMIN/CUSTOMERcon doble guard (middleware + layout).
git clone <repository-url>
cd bloomrose-ecommerce
pnpm installcp .env.local.example .env.localVariables mínimas para correr el catálogo (ver .env.local.example para todas):
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
DATABASE_URL= # Session Pooler de Supabase, puerto 6543
NEXT_PUBLIC_SITE_URL=http://localhost:3000
Para activar pagos, envíos y emails se requieren además:
- Wompi:
WOMPI_PUBLIC_KEY,WOMPI_PRIVATE_KEY,WOMPI_INTEGRITY_SECRET,WOMPI_EVENTS_SECRET - Coordinadora (opcional):
COORDINADORA_API_KEY,COORDINADORA_NIT,COORDINADORA_ID_CLIENTE - Resend:
RESEND_API_KEY,EMAIL_FROM
Aplicar migraciones a Supabase:
pnpm exec tsx scripts/apply-migration.ts supabase/migrations/<archivo>.sqlSembrar 14 productos / 29 variantes con datos completos (precios COP, peso, dimensiones, descuentos):
pnpm exec tsx lib/db/seed.tspnpm devDisponible en http://localhost:3000.
Para probar el webhook de Wompi (/api/wompi/webhook) desde localhost necesitas exponer el puerto con HTTPS:
# con cloudflared
cloudflared tunnel --url http://localhost:3000
# o con ngrok
ngrok http 3000Registra la URL pública resultante en el panel de Wompi para el evento transaction.updated.
app/
page.tsx Home
productos/ Catálogo + detalle
checkout/ Checkout + página de pago Wompi
api/wompi/webhook/ Webhook de pagos
perfil/ Área de usuario (config + pedidos)
admin/ Panel administrativo (productos, categorías, pedidos, clientes)
auth/ Login / signup
components/
ProductCard.tsx Card enriquecida (descuento, stock, variantes, envío gratis)
CartSheet.tsx Drawer del carrito
StoreHeader[Client].tsx Header con split server/client (anti auth-locks)
OrderStatusBadge.tsx Badge de estado de pedido
ui/ shadcn/ui (Radix)
lib/
db/ Drizzle: schema, cliente, seed
store/cart.ts Zustand
supabase/ Clientes server/client
wompi/ Firma de integridad + verificación de webhook
coordinadora/ Cotización + creación de guía + fallback
shipping/ Tarifa plana de respaldo
email/ Resend + plantillas React Email
scripts/
apply-migration.ts Aplicador de migraciones idempotente
verify-schema.ts Verifica columnas en la DB
supabase/
migrations/ SQL generado por drizzle-kit
middleware.ts Edge — protege /admin, /perfil, /checkout
- Server / Client split del header: la sesión se lee en
StoreHeader(Server) y se pasa por props aStoreHeaderClient. Nunca llamar aauth.getUser()desde un Client Component del header — produce auth locks. - Anti-hydration: componentes con
localStorage(carrito) o portales Radix usan el patrónmountedconuseEffectantes de renderizar. - Snapshot inmutable en pedidos: dirección de envío y precios se copian al
orderpara que el historial sobreviva si el cliente borra direcciones o cambian precios. - Validación servidor-side: stocks, precios y descuentos siempre se re-validan en el Server Action — el carrito del cliente no es fuente de verdad.
- Idioma: UI 100% en español (mercado Colombia).
CLAUDE.md— guía de arquitectura y convenciones del repo.PLAN.md— diagnóstico y hoja de ruta priorizada.