02 — Landings & Pages
Índice de la página
- 01Cliente: Martín Rieznik / LevantArte
- Área: Frontend / Quick Funnel + Sales Pages
- 020. Definición de "done" para esta checklist
- 031. Pre-requisitos
- 042. Tareas
- 2.1 Routing y layout multi-tenant
- 2.2 Quick Funnel — /martin/ (quiz + form + bifurcación)
- 2.3 Páginas de gracias
- 2.4 Sales page taller — /martin/taller
- 2.5 Sales page membresía — /martin/membresia
- 2.6 Páginas auxiliares
- 2.7 Tracking + APIs internas
- 2.8 Performance + QA
- 053. Variables y posibilidades a anticipar
- 064. Multi-tenant: cómo se replica al cliente #2
- 075. Recursos y archivos relacionados
- 086. Notas y aprendizajes (post-mortem)
- 09CHANGELOG
Cliente: Martín Rieznik / LevantArte
Área: Frontend / Quick Funnel + Sales Pages
Construir el embudo completo en
deacademia.com/martin/...: Quick Funnel clone (quiz 5 preguntas + calculating teatral + form 4 pasos + score + bifurcación calificado/no), sales pages del taller (precio dinámico) y membresía (3 precios), replay page gated, gracias-calificado/no-calificado, transferencia, admisión, post-compra. Todo parametrizado para que cliente #2 herede sin tocar código.
Última actualización: 2026-05-05
Responsable principal (R): Eric (build) + Cortex (copy)
Aprobador (A): Jesús
Deadline: 2026-05-31
Depende de: 01 (infra), 03 (copies de páginas), 08 (oferta cerrada para precios y stack), 13 (pixel IDs cargados)
Bloquea a: 14 (ads necesitan landings vivas), 19 (go-live)
0. Definición de "done" para esta checklist
- Las 11 URLs
/martin/*listadas en plan interno § 1.6 funcionan end-to-end en produccióndeacademia.com/martin/...desde dispositivo limpio (mobile + desktop, sin glitches). - Quiz completo dispara
Leadevento, redirige a WhatsApp con mensaje pre-llenado y guarda fila en Supabase con UTMs persistidas. - Precio dinámico del taller cambia automáticamente por reloj de servidor (ART) en lunes/martes/mié-vie sin necesidad de deploy.
- Lighthouse score ≥ 85 en
/martin/(mobile) y todas las pages cargan en < 2.5s LCP. - Headlines de sales pages aprobadas con score Promise Engineer ≥ 40/50.
1. Pre-requisitos
| # | Pre-requisito | Provisto por | Estado |
|---|---|---|---|
| 1 | Infra técnica done (DNS verde, repo creado, Supabase + Railway corriendo) | Eric (checklist 01) | ⚠️ |
| 2 | Pixel IDs Meta + TikTok + Google Ads cargados en clients.config_json |
Eric + Martín | ⚠️ |
| 3 | Copy de quiz (5 preguntas), CTA WhatsApp, FAQs de objeciones | Cortex (checklist 03) | ⚠️ |
| 4 | Headline + body + bonus + stack del taller cerrados | Martín + Cortex (checklist 08) | ⚠️ |
| 5 | Headline + body + stack de membresía cerrados | Martín + Cortex (checklist 08) | ⚠️ |
| 6 | Datos de transferencia (alias / CBU / titular) para /martin/transferencia |
Martín (checklist 17) | ⚠️ |
| 7 | Logo + paleta de colores LevantArte (al menos primary + secondary) | Cortex (R/Brand assets) | ⚠️ |
| 8 | Links de las 5 pasarelas por SKU (5 × 6 = 30 URLs) | Martín + Cortex (checklist 16) | ⚠️ |
2. Tareas
2.1 Routing y layout multi-tenant
- Crear
src/app/[client_slug]/layout.tsxque leeclients.config_jsondesde Supabase server-side y pasa branding (colores, logo, voz) via context al árbol. R: Eric. Done cuando: import en cualquier page accede auseClientConfig()con tipos. - Crear
src/app/[client_slug]/middleware.ts(o middleware global) que valida slug existe en DB; si no, retorna 404 amigable. R: Eric. Done cuando:/cliente-inexistente/retorna 404 con mensaje claro. - Definir paleta de colores LevantArte en
clients.config_json(primary, secondary, accent, bg, text) y aplicar via CSS vars al layout para que Tailwind las use. R: Eric + Cortex. Done cuando: cambiar el config refresca el branding sin tocar código. - Configurar
metadataSEO dinámica por cliente (title, description, OG image). R: Eric. Done cuando:<head>de cada page muestra metadata correcta + preview en redes muestra OG image de Martín. - Configurar favicon dinámico por cliente desde
public/clients/[slug]/favicon.ico. R: Eric. Done cuando: tab del navegador muestra favicon LevantArte en URLs/martin/*.
2.2 Quick Funnel — /martin/ (quiz + form + bifurcación)
- Página
/martin/page.tsx: hero con headline + sub + CTA "Empezá el test" + indicador de progreso 0/5. R: Cortex (copy) + Eric (build). Done cuando: hero responsive + CTA scrollea suave a quiz. - Quiz de 5 preguntas con UI tipo cards selectables (1 pregunta a la vez, transición animada). R: Eric. Done cuando: usuario navega 5 preguntas, cada respuesta dispara evento
quiz_started(primera) y avanza el step. - Pantalla "calculating" teatral entre quiz y form (3-5s con animación tipo loading bar + texto cambiante "Analizando tu perfil..."). R: Eric. Done cuando: animación se ve fluida en mobile + no se puede skipear.
- Form de 4 pasos: (1) email + nombre, (2) WhatsApp con país, (3) edad + estado civil, (4) "qué buscás resolver" (textarea). R: Eric. Done cuando: validaciones por step (zod), persistencia entre pasos (no se pierde al hacer back), submit final dispara
quiz_completed. - Score de calificación 96-99: lógica simple (combinación de respuestas pondera score). Mostrar en pantalla con efecto wow ("Tu compatibilidad es 97/100"). R: Eric + Cortex (lógica). Done cuando: score se calcula consistente + se muestra grande tras submit.
- Bifurcación calificado (>= 96 + edad >= 25 + país soportado) → redirect a
/martin/gracias-calificadoconlead_iden query. R: Eric. Done cuando: caso calificado redirige correctamente + eventoregistered_calificadoen Supabase. - Bifurcación no calificado → redirect a
/martin/gracias-no-calificado. R: Eric. Done cuando: caso no calificado redirige + eventoregistered_no_calificado. - Persistir UTMs (utm_source, medium, campaign, content) desde query string al cookie
ta_utms(90 días) y guardar enleads.utm_*. R: Eric. Done cuando: lead que viene de?utm_source=meta&utm_campaign=testaparece con esos valores en Supabase. - Generar
ta_uid(UUID v4) por sesión, persistir en cookie 1 año, usar como key cross-page. R: Eric. Done cuando: mismo dispositivo siempre tiene mismota_uid, visible en Supabase. - A/B variant: cookie
ab_variant+ab_sourceasignados via/api/redirect, log enleads.ab_variant. R: Eric. Done cuando: 50/50 split observable en Supabase tras 100 leads de prueba.
2.3 Páginas de gracias
-
/martin/gracias-calificado/page.tsx: mensaje cálido "Sos uno de los nuestros" + botón grande "Hablar con Martín por WhatsApp" con linkwa.me/<number>?text=...pre-llenado. R: Eric + Cortex (copy + mensaje pre-llenado). Done cuando: click abre WA con mensaje "Hola Martín, terminé el test, soy {nombre}". - Disparar pixel
CompleteRegistrationMeta (browser-side) +Leadserver-side via CAPI + TikTokCompleteRegistrationengracias-calificado. R: Eric (coord con checklist 13). Done cuando: events manager Meta + TikTok muestran eventos. -
/martin/gracias-no-calificado/page.tsx: mensaje educado + opción soft de WhatsApp (no botón gigante) + sugerencia de seguir Instagram. R: Cortex (copy) + Eric. Done cuando: tono no rechaza al usuario pero no le da el mismo trato VIP. - Pixel más débil en no-calificado:
Leadevent convalue=0(para que Meta no lo optimice como lead caliente). R: Eric. Done cuando: event aparece en pixel con value 0.
2.4 Sales page taller — /martin/taller
-
src/lib/precio_dinamico.ts: funcióngetPrecioTaller(now: Date, tz='America/Argentina/Buenos_Aires')retorna 5/10/15 según día (lunes 5, martes 10, mié-vie 15). R: Eric. Done cuando: tests unitarios cubren los 7 días + edge case medianoche ART. - Página
/martin/taller/page.tsxserver-rendered con precio dinámico calculado a request time (no cliente). R: Eric. Done cuando: refresh en horarios distintos cambia el precio sin deploy. - Estructura de la sales page (9 Pasos Carta de Venta + Stack Slides + 4-Legged Stool): Hero → Promesa → Mecanismo → Stack visual → Bonus → Garantía → Urgencia → CTA → FAQs. R: Cortex (copy) + Eric (build). Done cuando: cada bloque presente + scroll fluido en mobile.
- Headline auditada por Promise Engineer con score ≥ 40/50. R: Cortex. Done cuando: PDF de scorecard archivado + headline aprobada por Jesús.
- Stack de valor visual (cards con valores percibidos + valor total tachado + precio actual). R: Cortex (diseño) + Eric (build). Done cuando: stack legible mobile + suma matemática correcta.
- 5 botones de pasarela (dLocal / Shopify / Hotmart / Skool / Transferencia) más botón "Hablar con asesor" →
/martin/admision. R: Eric. Done cuando: 6 botones presentes + cada uno con link correcto leído declients.config_json.checkouts.taller. - Cada click en botón de pasarela dispara evento
checkout_clickedconpasarela+sku+precio_actual. R: Eric. Done cuando: evento en Supabase + pixelInitiateCheckoutMeta + TikTok. - Bloque FAQs con 8-12 objeciones rotas (extraídas del análisis de contenido de Martín). R: Cortex. Done cuando: FAQs con accordion + ninguna pregunta queda sin respuesta sólida.
- Countdown visual al cambio de precio ("$5 hasta hoy 23:59 ARG"), updated server-side. R: Eric. Done cuando: countdown se ve correcto + al pasar la hora cambia precio + mensaje.
2.5 Sales page membresía — /martin/membresia
- Página
/martin/membresia/page.tsxcon lógica de mostrar precios según día actual (jueves: solo $97; viernes y posteriores: $97 + $17/mes + $67×6). R: Eric. Done cuando: helper similar agetPrecioTallerpero para membresía + tests. - Estructura: Hero (pitch membresía) + Stack del año (qué incluye) + Bonus + Comparación contra Mentoría 90 días + Garantía + 3 cards de precio + 5 pasarelas por precio + admisión. R: Cortex (copy) + Eric (build). Done cuando: bloques presentes + tabla comparativa clara.
- Embed del video de pitch de Martín (grabado en Sesión 4 — checklist 09). R: Eric. Done cuando: video reproduce inline + autoplay muted + controles visibles.
- 3 cards de precio con badges ("Mejor valor", "Más popular", "Acceso flexible"). R: Cortex (textos) + Eric. Done cuando: cards visualmente diferenciadas + badges legibles mobile.
- 5 pasarelas × 3 precios = 15 botones (no abrumar UI: usar dropdown o tabs por pasarela). R: Eric + Cortex (UX). Done cuando: usuario elige precio → ve 5 opciones de pago + botón admisión visible siempre.
- Headline auditada Promise Engineer score ≥ 40/50. R: Cortex. Done cuando: aprobado por Jesús.
2.6 Páginas auxiliares
-
/martin/replay/page.tsx: gated por email (formulario "Recibí mi link" → email verifica + redirect a página con video privado). R: Eric + Cortex (copy). Done cuando: solo emails registrados comoattended_webinarodropped_webinaracceden + el resto ve form de registro. -
/martin/transferencia/page.tsx: instructivo bancario claro (alias, CBU, titular, monto a transferir según SKU) + form "Ya transferí" con upload de comprobante. R: Cortex (instructivo + copy) + Eric (build + upload). Done cuando: comprobante se sube a Supabase storage + notificación a Jesús +comprasrow con status pending. -
/martin/admision/page.tsx: form pre-handoff a closer (nombre, WhatsApp, qué te interesa, presupuesto). Output: link a WhatsApp del closer + lead marcado en Supabase. R: Cortex (copy) + Eric. Done cuando: form 4 campos + redirect WA closer + leadtipo=admisionen eventos. -
/martin/checkout/[sku]/page.tsx: selector visual de pasarela (5 opciones grandes con logos), redirect tras click. R: Eric. Done cuando: navegando a/martin/checkout/TALLER_LUNESse ven 5 botones que llevan al checkout correcto. -
/martin/taller/gracias/page.tsx: post-compra. "Bienvenido al taller. Te agregamos al grupo. Acá tu acceso." + dispara eventopurchase_completed. R: Cortex (copy) + Eric. Done cuando: page muestra info de acceso + PixelPurchaseserver-side disparado + bot WA agrega al grupo compradores. -
/martin/membresia/gracias/page.tsx: post-compra membresía. Bienvenida + acceso + agregar a grupo miembros. R: Cortex (copy) + Eric. Done cuando: análogo a/taller/graciaspero para membresía.
2.7 Tracking + APIs internas
- API route
/api/trackPOST: recibe{lead_id, evento, data}y escribe en Supabaseeventos. R: Eric. Done cuando: cualquier page puede loguear eventos custom + rate limit 100 req/min por IP. - API route
/api/redirect: asigna A/B variant + setea cookie + redirige a destino. R: Eric. Done cuando: ads pueden apuntar a/api/redirect?to=/martin/&variant=autoy distribuye 50/50. - API route
/api/lead: crea/upserta lead en Supabase + retornalead_idpara que frontend siga track. R: Eric. Done cuando: form del quiz llama/api/leady recibe ID. - API route
/api/precio-taller: retorna{precio, dia, prox_cambio}para UI countdown. R: Eric. Done cuando: endpoint público + cacheable 60s.
2.8 Performance + QA
- Lighthouse mobile ≥ 85 en
/martin/,/martin/taller,/martin/membresia. R: Eric. Done cuando: 3 reportes archivados con score ≥ 85 cada uno. - Imágenes optimizadas con
next/image+ AVIF/WebP automatic. R: Eric. Done cuando: ningún PNG > 200KB sirviéndose. - Test cross-browser: Chrome, Safari (iOS), Firefox, Samsung Internet. R: Eric. Done cuando: 4 browsers OK + screenshots archivados.
- Test cross-device: iPhone SE (small), iPhone 14, Android medio (Pixel 5), iPad, desktop 1440px. R: Eric. Done cuando: 5 dispositivos OK + screenshots.
- End-to-end test: dispositivo limpio + IP nueva → quiz → calificado → WhatsApp → todo trackeado en Supabase. R: Eric + Jesús. Done cuando: log completo en Supabase + match con expected events.
3. Variables y posibilidades a anticipar
| Escenario | Plan B |
|---|---|
| Cambio de precio del taller falla en medianoche ART (timezone bug) | Cron job de Railway 00:01 ART verifica precio actual + dispara warning si discrepa con día. Tests unitarios con mocks de fechas. |
| Form del quiz se rompe en Safari iOS (autofill o input zoom) | Disable autofill en campos no necesarios + meta viewport user-scalable=no + font-size mínimo 16px en inputs. |
| Lead duplica registros si refresca la página | Constraint unique (client_id, email) en leads + handle 23505 con upsert. |
WhatsApp link wa.me no funciona en algunos navegadores in-app (Instagram, TikTok) |
Detectar UA in-app + mostrar instrucción "Abrí en navegador" + botón copy número. |
| Precio dinámico se desincroniza entre páginas (cliente cachea) | Server-render todo + Cache-Control: no-store en pages con precio + revalidate 60s en API. |
| Headlines de Promise Engineer no llegan a 40/50 | Iteración: 3 rondas con feedback de Jesús + Martín. Si tras 3 rondas no llega, escalar a Jesús para decisión. |
| Stack visual no se ve bien en mobile (cards muy grandes) | Layout vertical mobile-first + cards apiladas + max 1 col mobile, 3 col desktop. |
| Replay page accede usuarios no registrados (link compartido) | Token único por email + expiración 7 días + log de IPs accediendo cada token (alerta si > 3 IPs). |
| Comprobante de transferencia upload pesa > 10MB (PDF escaneado mal) | Limite 5MB en frontend + compresión client-side + msj de error claro + alternativa "envianos por WA". |
Closer no recibe handoff de /martin/admision (notificación se pierde) |
Doble notificación: WA + email + log en Supabase con tag pending_handoff. Cron 1h chequea pending. |
| Botones de pasarela rotos (links incorrectos cargados en config) | Test smoke automático cada hora: GET HEAD a cada link de checkout + alert si 404. |
| OG image no se renderiza en preview Meta/WA | Validar con https://developers.facebook.com/tools/debug/ + cache buster en URL. |
4. Multi-tenant: cómo se replica al cliente #2
Esta sección alimenta
sop/lanzar-cliente/02_LANDINGS_NEW_CLIENT.md.
- Variables a externalizar (todo en
clients.config_jsondel cliente): quiz.preguntas[]— array de 5 preguntas con opciones + scoringquiz.umbral_calificado— score mínimo para bifurcar a calificadoquiz.umbral_edad— edad mínimaquiz.paises_soportados[]oferta.taller.precios_por_dia[]—[{dia: 'lunes', precio: 5}, ...]oferta.taller.headline,subhead,bonus[],stack[],garantia,faqs[]oferta.membresia.precios[]— array con tipo + monto + cuotasoferta.membresia.headline,stack[],comparacion,bonus[]pasarelas.taller—{dlocal: url, shopify: url, hotmart: url, skool: url, transferencia: '/transferencia'}pasarelas.membresia— análogowhatsapp.numero_principal,whatsapp.mensaje_pre_llenado_templatewhatsapp.numero_closertransferencia.alias,cbu,titular,cuitvoz.tono,voz.no_decir[],voz.frases_clave[]— para copies-
branding.colores,branding.logo,branding.favicon,branding.og_image -
Templates a guardar en
sop/lanzar-cliente/templates/landings/: app-client-slug-template/— todas las páginas con placeholders{{CLIENT_*}}quiz-config.template.json— esqueleto del quizsales-page-taller.template.tsx— estructura genérica con slotssales-page-membresia.template.tsx— análogogracias-calificado.template.tsxgracias-no-calificado.template.tsxreplay.template.tsxadmision.template.tsxtransferencia.template.tsx-
checkout-sku.template.tsx -
Sustituciones automáticas (
clone_client.pyextiende): - Copia carpeta
app/martin/→app/[nuevo_slug]/ - Reemplaza placeholders en imports + textos visibles que sean de marca
- Genera nuevo
clients.config_jsondesde template + datos del nuevo cliente - Asigna pixel IDs nuevos en config
-
Vercel re-deploy automático tras commit
-
Tiempo objetivo cliente #2 para landings: < 4 días desde infra-listo a landings-vivas (asume copy + oferta del cliente #2 ya cerrados).
5. Recursos y archivos relacionados
01_INFRA_TECNICA.md— base sobre la que corren las pages03_COPIES.md— fuente de copies del quiz, sales pages, FAQs08_OFERTA_Y_STACK.md— oferta + bonus + precios necesarios para sales pages13_PIXEL_TRACKING.md— pixels que se disparan en cada page16_PASARELAS_PAGO.md— links de checkout17_TRANSFERENCIA.md— datos para/martin/transferencia../02_PLAN_INTERNO_EQUIPO.md— § 1.6 routing técnico + § 6 estructura sales pages- Quick Funnel ADP de referencia (clon parametrizable origen)
- Promise Engineer scorecard:
agents/promise-engineer/scripts/score_promise.py
6. Notas y aprendizajes (post-mortem)
Llenar después del primer ciclo. Estos aprendizajes son los que se llevan al SOP.
- (vacío hasta primera ejecución)
CHANGELOG
- 2026-05-05 — Cortex (agente A) — Creación inicial con base en plan interno § 1.6 + § 6.