- Descripción
- Arquitectura
- Tech Stack
- Estructura del proyecto
- Quick Start
- Scripts disponibles
- Variables de entorno
- Deployment
- Seguridad y hardening
- Features
- Testing y QA
- Colaboración
RareHunter resuelve dos necesidades en un monorepo:
| Capa | Propósito |
|---|---|
| Storefront | Catálogo público, detalle de carta, carrito, checkout con MercadoPago, pedidos y landing responsive |
| Panel Admin | CRM interno con inventario virtualizado, dashboard operativo, órdenes, merchandising, auditoría y contenido custom |
| Backend API | Express monolith con auth JWT, rate limiting, stock atómico, cache Redis, SSE realtime, BullMQ jobs y webhooks de pago |
La separación frontend/backend garantiza que secretos y lógica de negocio nunca se exponen al navegador. El admin consume la misma API con permisos elevados.
┌─────────────┐ ┌─────────────┐
│ Storefront │ │ Admin Panel │
│ React + Vite│ │ React + Vite │
│ (Vercel) │ │ (Vercel) │
└──────┬──────┘ └──────┬───────┘
│ │
└────────┬─────────┘
│ HTTPS
┌────────▼────────┐
│ Express API │
│ (Render) │
│ │
│ ┌─── Auth ────┐ │ ┌──────────────┐
│ │ JWT + RBAC │ │◄────►│ Redis │
│ └─────────────┘ │ │ (Upstash + │
│ ┌─── Cache ───┐ │ │ IORedis TCP) │
│ │ LRU + Redis │ │ └──────────────┘
│ └─────────────┘ │
│ ┌─── Queue ───┐ │ ┌──────────────┐
│ │ BullMQ │ │ │ Cloudinary │
│ └─────────────┘ │ │ (fetch proxy)│
│ ┌─── SSE ─────┐ │ └──────────────┘
│ │ Realtime │ │
│ └─────────────┘ │
└────────┬─────────┘
│
┌────────▼────────┐
│ PostgreSQL │
│ Supabase │
│ (PgBouncer) │
└─────────────────┘
Flujo principal:
- El storefront consulta la API para catálogo, filtros, carrito y checkout.
- MercadoPago procesa pagos (Checkout Pro + API directa) y notifica via webhook.
- El backend reserva stock atómicamente, gestiona estados de orden y emite eventos SSE.
- BullMQ ejecuta jobs en background (sync de catálogo, actualización de stock).
- Redis cachea respuestas con singleflight y fallback LRU in-memory (500 entries).
- Prisma mantiene el schema sobre Supabase Postgres con connection pooling.
| Categoría | Tecnología |
|---|---|
| Frontend | React 19, Vite 6, Tailwind CSS 3, TanStack Query 5, React Router 7 |
| Backend | Node.js ≥20, Express 4, Prisma ORM |
| Database | PostgreSQL (Supabase PgBouncer, sa-east-1) |
| Cache | Redis dual: Upstash REST (cache) + IORedis TCP (BullMQ/pub-sub) + LRU in-memory fallback |
| Queues | BullMQ (stock sync, catalog sync, scheduled jobs) |
| Realtime | SSE con Redis pub/sub (stock, precios, órdenes) |
| Payments | MercadoPago Checkout Pro + Direct Payment API |
| Images | Cloudinary fetch proxy (q_auto:eco, f_auto, responsive srcset) |
| Auth | JWT access (15min) + refresh tokens (30d), RBAC (admin/staff/client) |
| Deploy | Vercel (frontends) + Render (backend) |
| Monitoring | Health endpoint con DB probe, structured JSON logging, audit trail |
rarehunter/
├── backend/ # API Express principal
│ ├── server.js # Monolith (~7600 LOC) — rutas, middleware, lógica
│ ├── prisma/ # Schema, migraciones y seed
│ └── src/lib/ # Módulos: auth, cache, dollar, events, queues, SSE, redis...
├── frontend-admin/ # Panel admin (workspace npm separado)
│ └── src/ # Views, lib, components del admin
├── src/ # Storefront público
│ ├── api/ # Capa de fetch del storefront
│ ├── components/ # UI components (marketplace, cart, checkout)
│ ├── config/ # env.js — resolución unificada de env vars
│ ├── hooks/ # Custom hooks (realtime, auth, queries)
│ └── lib/ # Utilidades (cardImage, mercadopago, userSession)
├── app/ # Next.js app directory (SSR experimental)
├── scripts/ # Dev stack, QA, sandbox checkout, DB smoke checks
├── docs/ # Runbooks de MercadoPago y deploy
├── api/ # Vercel serverless entry (Express adapter)
└── prisma.config.ts # Prisma config
- Node.js ≥20
- npm ≥9
- PostgreSQL (local o Supabase)
# 1. Clonar e instalar
git clone https://github.com/Franx245/Proyecto-FullStack.git
cd Proyecto-FullStack
npm install
# 2. Configurar variables de entorno
cp .env.example .env.local
# Editar .env.local con tus credenciales (ver sección Variables de Entorno)
# 3. Preparar base de datos y seed
npm run setup
# 4. Levantar el stack completo (store + admin + API)
npm run devEl orquestador imprime las URLs reales:
[boot] Store: http://127.0.0.1:5181
[boot] Admin: http://127.0.0.1:5182
[boot] API: http://127.0.0.1:3001
Notas:
- El backend carga primero
.env.local; usar sólo.envno es el flujo principal del repo. npm run devsobreescribe en runtime las URLs locales del API, store y admin.REDIS_TCP_URLsólo hace falta si querés BullMQ/pub/sub reales o levantar el worker; sin eso el API usa fallback inline.
| Script | Descripción |
|---|---|
npm run dev |
Levanta store + admin + API coordinados |
npm run dev:api |
Solo backend |
npm run dev:api:watch |
Backend con hot-reload |
npm run dev:store |
Solo storefront Vite |
npm run dev:admin |
Solo panel admin |
npm start |
Producción — node backend/server.js |
npm run build |
Build store + admin |
npm run setup |
Prisma generate + db push + seed |
npm run db:push |
Aplicar schema a la base |
npm run db:seed |
Cargar datos iniciales |
npm run lint |
ESLint quiet |
npm run check |
Lint + typecheck |
# ── Database ──
DATABASE_URL=postgresql://postgres.xxx:password@aws-0-sa-east-1.pooler.supabase.com:6543/postgres?pgbouncer=true&connection_limit=10
DIRECT_URL=postgresql://postgres.xxx:password@db.xxx.supabase.co:5432/postgres
# ── Auth (REQUIRED — server crashes on startup without these) ──
ACCESS_TOKEN_SECRET=<random-64-char>
REFRESH_TOKEN_SECRET=<random-64-char>
# ── MercadoPago ──
MP_ACCESS_TOKEN=APP_USR-xxx
MP_WEBHOOK_SECRET=<from-mp-dashboard>
# ── Redis ──
UPSTASH_REDIS_REST_URL=https://xxx.upstash.io
UPSTASH_REDIS_REST_TOKEN=xxx
REDIS_TCP_URL=rediss://default:xxx@xxx.upstash.io:6379 # BullMQ + pub/sub
# ── URLs ──
BACKEND_URL=https://tu-backend.onrender.com
FRONTEND_URL=https://tu-storefront.vercel.app
ADMIN_URL=https://tu-admin.vercel.app
# ── Server ──
PORT=3001
NODE_ENV=production
CRON_SECRET=<random-64-char>
CHECKOUT_EXPIRATION_MINUTES=30
CORS_ALLOWED_ORIGINS=
ALLOW_VERCEL_PREVIEWS=true| Variable | Descripción |
|---|---|
DATABASE_URL |
Supabase pooled connection string (PgBouncer) |
DIRECT_URL |
Supabase direct connection (migrations/schema) |
ACCESS_TOKEN_SECRET |
Firma JWT access tokens — fail-fast si falta |
REFRESH_TOKEN_SECRET |
Firma JWT refresh tokens — fail-fast si falta |
MP_ACCESS_TOKEN |
Token privado MercadoPago (Checkout Pro + pagos directos) |
MP_WEBHOOK_SECRET |
Validación HMAC de webhooks MercadoPago |
UPSTASH_REDIS_REST_URL |
Upstash REST endpoint para cache |
UPSTASH_REDIS_REST_TOKEN |
Token REST de Upstash |
REDIS_TCP_URL |
Redis TCP para BullMQ y pub/sub (IORedis) |
BACKEND_URL |
URL pública del backend (webhooks, notification_url) |
FRONTEND_URL |
Storefront URL (CORS, redirects) |
ADMIN_URL |
Admin URL (CORS) |
CRON_SECRET |
Bearer token para cron de expiración de órdenes |
VITE_APP_NAME=RareHunter
VITE_APP_ENV=production
VITE_API_BASE_URL=https://tu-backend.onrender.com
VITE_API_TIMEOUT=10000
VITE_MP_PUBLIC_KEY=APP_USR-xxx
VITE_CLOUDINARY_CLOUD_NAME=tu-cloud
VITE_ENABLE_CART=true
VITE_ENABLE_ORDERS=trueVITE_API_BASE_URL=https://tu-backend.onrender.com
VITE_STOREFRONT_URL=https://tu-storefront.vercel.app| Config | Valor |
|---|---|
| Build Command | npm install && npx prisma generate |
| Start Command | npm start |
| Health Check | GET /api/health (returns 503 if DB down) |
| Node Version | ≥20 (set en engines) |
| Auto-Deploy | Push to main |
El backend incluye trust proxy, graceful shutdown con server.close() y body limit de 256KB.
| Config | Valor |
|---|---|
| Root Directory | / (raíz del repo) |
| Build Command | npm run build:store |
| Output Directory | dist |
| Config | Valor |
|---|---|
| Root Directory | frontend-admin |
| Build Command | npm run build |
| Output Directory | dist |
# Aplicar schema
npm run db:push
# Cargar datos iniciales (opcional)
npm run db:seedEl backend expira órdenes PENDING_PAYMENT cuando expires_at ya pasó → marca como EXPIRED y libera stock.
GET /api/internal/orders/expire-pending
Authorization: Bearer ${CRON_SECRET}
Configurar como Vercel Cron Job o scheduler externo.
El proyecto pasó por una auditoría de producción completa. Estas son las protecciones activas:
| Medida | Detalle |
|---|---|
| JWT fail-fast | requireEnv() crashes on startup si faltan secrets |
| Access tokens | 15 min TTL, firmados con ACCESS_TOKEN_SECRET |
| Refresh tokens | 30 días, hash almacenado en DB |
| RBAC | Roles ADMIN / STAFF / CLIENT con middleware requireAdminRole() |
| IDOR protection | GET /api/orders filtra por userId del token autenticado |
| Scope | Límite |
|---|---|
Global /api/* |
100 req/min por IP |
| Checkout | 5 req/min por IP |
| Admin login | Rate limit dedicado |
Excluidos del global: /api/health, webhooks MercadoPago, SSE streams.
| Componente | Estrategia |
|---|---|
| Stock | Reserva atómica con updateMany WHERE stock >= quantity (no read-check-write) |
| Exchange rate | 3-tier fallback: APIs externas → cache stale → DB persisted rate → emergency 1250 ARS |
| SSE | Límite 200 conexiones + timeout 5 min + heartbeat 30s |
| Dashboard | Queries scoped a 90 días (previene full table scans) |
| Health | GET /api/health probe SQL con timeout 2s, retorna 503 si DB down |
| Cache | Redis singleflight + LRU in-memory fallback (500 entries) |
| Graceful shutdown | SIGTERM → server.close() → drain connections → exit |
| Body limit | express.json({ limit: "256kb" }) |
| Trust proxy | app.set("trust proxy", 1) para IP real detrás de LB |
- Catálogo paginado con filtros por categoría, rarity, set y búsqueda
- Detalle de carta con variantes y stock real
- Carrito persistente con drawer lateral
- Checkout con MercadoPago (Checkout Pro + Direct Payment API)
- Mis pedidos con tracking y estados
- Imágenes optimizadas via Cloudinary fetch proxy (q_auto:eco, f_auto, responsive srcset)
- CSS crítico inline + code splitting por ruta
- SSE realtime para cambios de stock/precios
- Bootstrap temprano de catálogo para first paint rápido
- Contacto con formulario persistido en DB
- Dashboard operativo con KPIs, alertas y acciones rápidas
- Inventario virtualizado (escala a miles de cartas)
- Gestión de órdenes con estados, tracking y notificaciones
- Edición masiva de stock/precios
- Merchandising de home (destacados, nuevas llegadas)
- Contenido custom y publicaciones
- CRM de usuarios con roles y actividad
- Audit trail de mutaciones administrativas
- Observabilidad integrada (logging estructurado)
- Express monolith con 60+ endpoints
- Auth JWT con access + refresh tokens y RBAC
- MercadoPago Checkout Pro + Direct Payment + webhooks con HMAC
- Redis dual (cache REST + TCP pub/sub/queues)
- BullMQ worker para jobs en background
- SSE realtime bidireccional (public + admin)
- Concurrencia optimista e idempotencia en mutaciones admin
- Exchange rate USD→ARS con 3-tier fallback
- Expiración automática de órdenes + liberación de stock
- Health endpoint con DB probe
- Structured JSON logging + API metrics
| Rol | Password | |
|---|---|---|
| Admin | admin@test.com |
admin123 |
| Staff | staff@test.com |
staff123 |
node scripts/db-smoke-check.mjs # Verificar conexión DB
node scripts/check-production-cache.mjs # Validar cache en producción
node scripts/sandbox-checkout-flow.mjs # Test E2E checkout MercadoPago
node scripts/qa-next-e2e.mjs # E2E del storefront Next.js- docs/mercadopago-db-runbook.md — Preparación segura de DB para MercadoPago
- docs/checkout-api-deploy.md — Deploy del checkout directo
- docs/mercadopago-sandbox-runbook.md — Testing en sandbox
- Usá
npm run devdesde la raíz para levantar todo coordinado - Ejecutá
npm run buildantes de abrir un PR - Mantené secretos fuera del repositorio (
.envestá en.gitignore) - Documentá nuevas variables de entorno en este README
- Los cambios de schema requieren
npm run db:pushantes de levantar
Hecho con React, Express y mucho café ☕