Stack técnico · deploy · escalabilidad · event-driven · monorepo modular.
Diagrama vivo de la arquitectura Marketplace SMC. Click en cualquier bloque para ver detalle · descripción · stack · owner · canales · docs relacionados. Filtros arriba para aislar el flujo de un canal específico (MeLi · D2C · MP · B2B). Hover destaca la ruta end-to-end que toca ese componente. Zoom con la rueda + ⌘/Ctrl o con los botones · arrastrá para hacer pan.
Tip: click en un bloque para ver detalle · Esc cierra · arrastra el canvas para hacer pan · ⌘/Ctrl + scroll para zoom.
Análogo al Channel Adapter del HLA principal · existe un Supplier Adapter Pattern para integrarse con proveedores externos que despachan directamente al cliente final (modo dropshipping · Doc 02 BBP P13).
Interfaz uniforme: SupplierAdapter con métodos syncCatalog() · checkStock(sku) · createPurchaseOrder(items, shipTo) · trackShipment(po_id) · handleReturn(order_id). Cada proveedor implementa según su API.
Beneficio: agregar proveedor nuevo = 1 archivo nuevo + entry en registry. NO refactor del core.
Implementación en repo: lib/adapters/suppliers/{supplier-x}.ts.
Tests en __tests__/adapters/suppliers-registry.test.ts.
Trigger migración a stock local: SQL materialized view mkt_dropship_migration_candidates
detecta SKUs con revenue >$10M CLP en 60 días · sugiere comprar stock para subir margen 15-25pp.
Ver Doc 05 §12 schema completo + Doc 21 §03c estrategia migración.
Cómo recorre el sistema un caso real paso a paso. Seleccioná un escenario (A · B · C · D · E) para ver su pipeline horizontal con etapas y pasos integración (INT-XXX). Click en un paso para ver descripción · stack · sample payload · errores comunes · docs relacionados.
Tip: cambiar escenario re-renderiza el pipeline · click en cualquier INT-XXX abre detalle del paso · Esc cierra.
| # | Señal | Cómo se mide | Peso |
|---|---|---|---|
| 1 | Multistore presence | # stores con mismo SKU canónico | 25% |
| 2 | Price spread | (max - min) / min · >15% = oportunidad | 25% |
| 3 | Availability rate | # stores con is_available / total | 15% |
| 4 | Price stability | baja varianza precio 7d (demanda sostenida) | 15% |
| 5 | Category premium | tabla fija mkt_category_premium | 10% |
| 6 | MeLi presence | producto también en store MeLi (id=260)? | 10% |
| Capa | Tecnología | Razón decisión |
|---|---|---|
| Frontend | Next.js 16 + React 19 + TypeScript | Stack SMC actual · SSR · App Router |
| UI library | @smc/ui (Radix + Tailwind v4 + tv) | Estándar interno SMC |
| Backend | Next.js API Routes + Server Actions | Monorepo simple · 1 deploy |
| BD | Supabase Postgres (pgvector + pg_cron) | Multi-tenant RLS nativo · escala |
| Auth | Supabase Auth | JWT + roles · email + OAuth |
| Storage | Supabase Storage | CDN incluido · XML DTE · imágenes |
| Event Bus | PostgreSQL NOTIFY + pg_cron + Inngest (opcional) | Sin Kafka/Redis al inicio · simple |
| IA principal | Groq Llama 3.3 70B | Velocidad + costo · función calling |
| IA fallback | OpenRouter (Llama 4 Scout · Gemini Flash · DeepSeek) | Regla SMC: nunca Claude como fallback |
| DTE | Open Factura API | Compliance SII turnkey |
| Pasarela pago | MercadoPago Empresa + WebPay Plus | Coverage máximo Chile |
| Couriers | Chilexpress · Starken · Bluexpress APIs | Nacional |
| Deploy | AWS Amplify (Next.js auto-build) | Stack SMC actual · push-to-deploy |
| Observabilidad | Sentry + Supabase Logs + custom mk_api_logs | Errors + perf + LLMOps |
| Testing | Vitest (unit/integration) + Playwright (e2e) | Estándar SMC |
| CI/CD | GitHub Actions | Lint · TSC · test · build · deploy |
| Resend o Postmark | Transactional · DTE PDFs |
smc-marketplace-hub/ ├── apps/ │ ├── web/ # Next.js app (frontend + API) │ │ ├── app/ │ │ │ ├── (auth)/ # login · signup │ │ │ ├── (dashboard)/ # cockpit operador │ │ │ │ ├── inventory/ │ │ │ │ ├── channels/ │ │ │ │ │ ├── meli/ │ │ │ │ │ ├── mp/ │ │ │ │ │ ├── d2c/ │ │ │ │ │ └── b2b/ │ │ │ │ ├── orders/ │ │ │ │ ├── finance/ │ │ │ │ ├── cerebro/ │ │ │ │ └── analytics/ │ │ │ └── api/ │ │ │ ├── webhooks/ # meli · mp · webpay · etc. │ │ │ ├── cron/ # refresh-tokens · mp-tenders │ │ │ └── v1/ # APIs internas REST │ │ └── package.json │ └── storefronts/ # marcas propias futuras │ └── marca-1/ # primera marca migrada al Hub │ ├── packages/ │ ├── core/ # @smc/core · dominio puro │ │ ├── inventory/ │ │ ├── orders/ │ │ ├── finance/ │ │ ├── events/ # Event bus interno │ │ └── tenants/ │ ├── channels/ # @smc/channels · adapters │ │ ├── _interface.ts # interfaz ChannelAdapter │ │ ├── meli/ │ │ ├── mp/ │ │ ├── d2c/ │ │ ├── b2b/ │ │ └── falabella/ │ ├── ui/ # @smc/ui (existente) │ ├── shared/ # @smc/shared · types · utils │ ├── ai/ # @smc/ai · Cerebro · Groq client · prompts │ └── billing/ # @smc/billing · DTE · Open Factura │ ├── supabase/ │ ├── migrations/ # SQL versionado │ ├── seed/ # data fixtures dev │ └── functions/ # Edge Functions opcional │ ├── .github/ │ └── workflows/ # CI/CD │ └── docs/ # blueprint + ADRs (estos docs)
Compartir tipos TS entre frontend y backend · 1 deploy · 1 versión de toda la app. Si futuro necesita microservicios · cada package se extrae a su propio repo sin refactor.
Cada operación significativa emite un evento. Los módulos suscritos reaccionan automático. Esto evita acoplamiento (módulo finance no llama a inventory · escucha eventos).
No usar Kafka/Redis al inicio · es overkill. Usar Postgres NOTIFY + tabla mk_evt_operations como event store + pg_cron para retries. Cuando volumen pase 10K eventos/día evaluar Inngest o Trigger.dev.
-- En cada query, el server setea el tenant context
SET app.current_tenant = '<tenant-uuid>';
-- Policy aplicada a TODAS las tablas (excepto mk_tenants y mk_users)
CREATE POLICY tenant_isolation ON mk_products
USING (tenant_id = current_setting('app.current_tenant')::uuid)
WITH CHECK (tenant_id = current_setting('app.current_tenant')::uuid);
ALTER TABLE mk_products ENABLE ROW LEVEL SECURITY;
ALTER TABLE mk_products FORCE ROW LEVEL SECURITY;
tenant_idX-Tenant-IdSET app.current_tenant = ? en conexión PostgresAunque un dev olvide filtrar WHERE tenant_id = ? · RLS Postgres bloquea. Defensa de último nivel.
| Ambiente | Branch | URL | Auto-deploy |
|---|---|---|---|
| Local | (working tree) | localhost:3000 | npm run dev |
| QAS | develop | qas.marketplace.smconnection.cl | push develop → AWS Amplify |
| PRD | main | marketplace.smconnection.cl | push main → AWS Amplify |
push branch → GitHub Actions: 1. install (cache pnpm) 2. lint (eslint) 3. type-check (tsc --noEmit) 4. unit tests (vitest run) 5. build (next build) 6. integration tests (vitest --integration) 7. e2e smoke (playwright · solo en main) 8. deploy (auto vía Amplify webhook) 9. health check post-deploy (curl /api/health) 10. rollback automático si health falla
supabase/migrations/YYYY-MM-DD-name.sql| Tipo | Herramienta | Qué se mide |
|---|---|---|
| Errores producción | Sentry | Excepciones JS · stack traces · usuarios afectados |
| Performance APIs | Sentry Performance + Supabase Logs | Latencia p50/p95/p99 por endpoint |
| API externa llamadas | mk_api_logs (custom) | Endpoint · status · latencia · payload · source |
| Eventos operativos | mk_evt_operations | Todo evento dominio (audit + IA contexto) |
| LLMOps | Custom log Groq calls | Tokens · costo · latencia · prompt version · score |
| Uptime | UptimeRobot o BetterStack | /api/health ping cada 1 min |
| BD performance | Supabase dashboard | Queries lentas · index usage · pool conexiones |
mk_channels.credentialsmk_audit_changes en cada UPDATE/DELETE de tablas financieras| Métrica | Threshold | Acción |
|---|---|---|
| Órdenes/hora por tenant | > 500 | Mover sync canales a workers async (Inngest) |
| Tamaño BD | > 50 GB | Plan Supabase Team · evaluar particionado tablas hot |
| p95 API latency | > 800ms sostenido | Cache Redis · query optimization · índices |
| Concurrentes activos | > 100 | Pool conexiones PG · escalar app server |
| Tenants activos | > 50 | Considerar BD por tier (free/pro/enterprise) |
| Build time | > 5 min | Turborepo cache · split apps |
| Costo Groq mensual | > $100K CLP | Caching IA · prompt optimization · evaluar modelo más chico |
No premature optimization · Supabase + Next.js + Amplify aguanta cómodo hasta 500K órdenes/mes. Cuando llegue · refactorizar con data real, no asunciones.
Architectural Decision Records · cada decisión clave queda en docs/adrs/NNNN-titulo.md
| # | Decisión | Status |
|---|---|---|
| ADR-001 | Single source of truth: 1 BD Postgres con tenant_id | Aceptado |
| ADR-002 | Channel Adapter Pattern para canales externos | Aceptado |
| ADR-003 | Event-driven con PG NOTIFY (no Kafka/Redis MVP) | Aceptado |
| ADR-004 | Monorepo (no microservicios) hasta >500 órdenes/h | Aceptado |
| ADR-005 | Asientos contables auto · NO entrada manual | Aceptado |
| ADR-006 | Nexport como proveedor importador (no comex propio) | Aceptado |
| ADR-007 | Open Factura para DTE (no SII directo) | Aceptado |
| ADR-008 | Groq como IA primaria · OpenRouter fallback | Aceptado |
| ADR-009 | RLS Postgres como defensa de aislamiento multi-tenant | Aceptado |
| ADR-010 | Primera marca propia migra back-office al Hub · storefront sigue separado | Propuesto |