Ir al contenido

Stack y arquitectura

El sistema tiene 6 capas. El usuario entra por el browser, todo pasa por Cloudflare, y desde ahí se reparte entre el frontend (Vercel) y el backend (Cloud Run).

┌───────────────────┐
│ Usuario │
│ (en tcgcards.cl) │
└─────────┬─────────┘
┌───────────────────┐
│ Cloudflare │
│ DNS · CDN · WAF │
└─┬─────────────┬───┘
│ │
páginas │ │ /api/v1/*
▼ ▼
┌──────────────┐ ┌──────────────────┐
│ Vercel │ │ GCP Cloud Run │
│ tcgcards-web │◄─┤ tcgcards-api │
│ Next.js 16 │ │ Express + Node20 │
└──────────────┘ └────────┬─────────┘
┌──────────────────┐
│ MongoDB Atlas │
└──────────────────┘
│ usa
┌────────────┬─────────────┬────────────┬────────────┐
▼ ▼ ▼ ▼ ▼
┌────────┐ ┌──────────┐ ┌─────────┐ ┌────────┐ ┌─────────┐
│ MP │ │Cloudinary│ │ Resend │ │ Sentry │ │ PostHog │
│ (pagos)│ │(imágenes)│ │(emails) │ │(errors)│ │(eventos)│
└────────┘ └──────────┘ └─────────┘ └────────┘ └─────────┘
┌──────────────────┐
│ Cloud Scheduler │ ── HTTP POST cada N minutos ──► tcgcards-api
│ (5 cron jobs) │ (endpoints /internal/cron/*)
└──────────────────┘
  1. Usuario — un browser entrando a tcgcards.cl.
  2. Cloudflare — primera capa que recibe el tráfico. Hace DNS, CDN (cachea estáticos), firewall y bloquea bots. También sirve los docs internos via Cloudflare Access.
  3. Frontend (Vercel)tcgcards-web, Next.js 16 con App Router. Renderiza páginas server-side y maneja todo el JS del cliente. Deploya automático en cada push a main.
  4. Backend (Cloud Run, GCP)tcgcards-api, servidor Express en Node 20. Expone /api/v1/*. Cloud Run escala automático y cobra solo cuando hay tráfico. Deploy manual con gcloud run deploy.
  5. MongoDB Atlas — base de datos. La única fuente de verdad de listings, órdenes, usuarios, etc.
  6. Servicios externos:
    • Mercado Pago — procesa pagos y devoluciones.
    • Cloudinary — guarda fotos de listings y banners.
    • Resend — envía emails transaccionales (confirmaciones, disputas, etc.).
    • Sentry — captura errores del web y el api.
    • PostHog — registra eventos de producto (clicks, conversión).
  7. Cloud Scheduler — 5 jobs que llaman al backend cada cierto tiempo (backups, expiración de órdenes, reconciliación de wallet). Ver crons.

Detalle de cada servicio externo (URLs de paneles, dónde están las credenciales): infraestructura.

TecnologíaVersiónPara qué
Next.js16.2.4Framework. App Router con server components + server actions.
React19.2.4UI
TypeScriptstrictTipado
Tailwind CSSv4Estilos
shadcn4.6Componentes base (Radix + Tailwind)
Auth.jsv5 betaOAuth con Google, sesión via cookies cifradas
next-themes0.4Dark/light mode
Zod4.4Validación de schemas
Sentry10.52Errores client + server
PostHog1.372Eventos de producto
Sonner2.0Toasts
dnd-kit6.3Drag-and-drop (reordenar fotos)
embla-carousel8.6Carruseles
browser-image-compression2.0Compresión de imágenes antes de subir
TecnologíaVersiónPara qué
Node20+Runtime
Express4.21HTTP server
TypeScriptstrict, ESMTipado, módulos
Mongoose8.7ODM para Mongo
Zod3.23Validación de body / config
jsonwebtoken9JWT HS256
Mercado Pago SDK2.12Cobros y reembolsos
Cloudinary SDK2.10Uploads firmados
Resend6.12Email outbound
Pino9.4Logger estructurado
Sentry10.52 (node)Errores
express-rate-limit8.4Rate limiting
dotenv16.4Carga de envs
WebAPI
RunnerVitestVitest
Coberturaunitunit + integration (mongo en memoria)
UI@testing-library/reactsupertest
Comandonpm testnpm test
  1. Usuario abre tcgcards.cl/cartas/... en su browser.
  2. Cloudflare sirve el sitio (CDN + DNS).
  3. Next.js (Vercel) renderiza en servidor; hace fetch a tcgcards-api para data.
  4. Usuario agrega al carrito → server action de Next.js → POST a tcgcards-api (con cookie + JWT interno).
  5. Usuario va a checkout → tcgcards-api crea orden + payment en Mercado Pago.
  6. Usuario es redirigido a Mercado Pago, paga.
  7. Mercado Pago notifica a tcgcards-api por webhook → marca orden como awaiting_paymentpending.
  8. Cron orders-awaiting-payment-cleanup (cada 5 min) cancela órdenes sin pago confirmado.
  9. Cron orders-tick (cada hora) maneja transiciones automáticas posteriores (auto-cancel si vendedor no envía, auto-complete si comprador no confirma recepción).

Estas conviven en CLAUDE.md de cada repo. Acá las resumo para que no se pierdan:

  • Precios en CLP cents (entero) en backend. formatPriceCents() para mostrar.
  • Multi-TCG sin defaults a ‘pokemon’: server components fetchean getTcgs() y propagan availableTcgs a clientes.
  • Stock-dependent reads usan cache: 'no-store'. Solo sets/rarities cachean 5 min.
  • Server-only guards: import 'server-only' en archivos sensibles para que leaks fallen en build.
  • SessionProvider pattern: leer sesión en Header server-side rompe UI con páginas mixtas; usar SessionProvider + useSession().
  • Theme toggle SSR: UIs que leen prefs del usuario requieren mounted flag para evitar hydration mismatch.
  • Cero hex hardcoded fuera de emails. Solo tokens shadcn. Dark/light desde el primer commit.
  • Copy en tú-form español neutro/chileno, sin voseo (querés/podés/tenés/iniciá/usá).
  • Discriminated unions exhaustivas: default: const _exhaustive: never en cada switch.
  • Schemas Mongoose alineados con TS: default: null no required: true cuando TS permite null.

Más detalle en decisiones técnicas.