Stack y arquitectura
Diagrama general
Sección titulada «Diagrama general»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/*) └──────────────────┘Las capas explicadas
Sección titulada «Las capas explicadas»- Usuario — un browser entrando a
tcgcards.cl. - 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.
- 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 amain. - 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 congcloud run deploy. - MongoDB Atlas — base de datos. La única fuente de verdad de listings, órdenes, usuarios, etc.
- 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).
- 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.
Stack por capa
Sección titulada «Stack por capa»Frontend — tcgcards-web
Sección titulada «Frontend — tcgcards-web»| Tecnología | Versión | Para qué |
|---|---|---|
| Next.js | 16.2.4 | Framework. App Router con server components + server actions. |
| React | 19.2.4 | UI |
| TypeScript | strict | Tipado |
| Tailwind CSS | v4 | Estilos |
| shadcn | 4.6 | Componentes base (Radix + Tailwind) |
| Auth.js | v5 beta | OAuth con Google, sesión via cookies cifradas |
| next-themes | 0.4 | Dark/light mode |
| Zod | 4.4 | Validación de schemas |
| Sentry | 10.52 | Errores client + server |
| PostHog | 1.372 | Eventos de producto |
| Sonner | 2.0 | Toasts |
| dnd-kit | 6.3 | Drag-and-drop (reordenar fotos) |
| embla-carousel | 8.6 | Carruseles |
| browser-image-compression | 2.0 | Compresión de imágenes antes de subir |
Backend — tcgcards-api
Sección titulada «Backend — tcgcards-api»| Tecnología | Versión | Para qué |
|---|---|---|
| Node | 20+ | Runtime |
| Express | 4.21 | HTTP server |
| TypeScript | strict, ESM | Tipado, módulos |
| Mongoose | 8.7 | ODM para Mongo |
| Zod | 3.23 | Validación de body / config |
| jsonwebtoken | 9 | JWT HS256 |
| Mercado Pago SDK | 2.12 | Cobros y reembolsos |
| Cloudinary SDK | 2.10 | Uploads firmados |
| Resend | 6.12 | Email outbound |
| Pino | 9.4 | Logger estructurado |
| Sentry | 10.52 (node) | Errores |
| express-rate-limit | 8.4 | Rate limiting |
| dotenv | 16.4 | Carga de envs |
| Web | API | |
|---|---|---|
| Runner | Vitest | Vitest |
| Cobertura | unit | unit + integration (mongo en memoria) |
| UI | @testing-library/react | supertest |
| Comando | npm test | npm test |
Flujo de una compra típica
Sección titulada «Flujo de una compra típica»- Usuario abre
tcgcards.cl/cartas/...en su browser. - Cloudflare sirve el sitio (CDN + DNS).
- Next.js (Vercel) renderiza en servidor; hace
fetchatcgcards-apipara data. - Usuario agrega al carrito → server action de Next.js → POST a
tcgcards-api(con cookie + JWT interno). - Usuario va a checkout →
tcgcards-apicrea orden + payment en Mercado Pago. - Usuario es redirigido a Mercado Pago, paga.
- Mercado Pago notifica a
tcgcards-apipor webhook → marca orden comoawaiting_payment→pending. - Cron
orders-awaiting-payment-cleanup(cada 5 min) cancela órdenes sin pago confirmado. - 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).
Convenciones importantes del código
Sección titulada «Convenciones importantes del código»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 propaganavailableTcgsa 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
mountedflag 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: neveren cada switch. - Schemas Mongoose alineados con TS:
default: nullnorequired: truecuando TS permite null.
Más detalle en decisiones técnicas.