Communitygithub.com

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Configura notificação via bot do Telegram para pagamentos bem-sucedidos vindos do webhook do Sepay em um projeto Next.js.

O que é MKT.LANDINGPAGE.SKILLS?

Este skill automatiza a integração de notificações em tempo real via Telegram para pagamentos recebidos via Sepay em projetos Next.js. Ele guia o usuário na criação de um bot do Telegram, obtenção do token e chat ID, e na implementação de uma função helper reutilizável `sendTelegramNotification()` em `lib/telegram.ts`. O skill detecta automaticamente a rota existente do webhook do Sepay no projeto e adiciona a chamada ao Telegram em paralelo com outras ações (como envio de e-mail), usando `Promise.allSettled` para garantir que uma falha no Telegram não bloqueie a resposta 200 ao Sepay, evitando retentativas e notificações duplicadas. A mensagem padrão é formatada em vietnamita com emojis, dados do cliente e valor, e as variáveis de ambiente necessárias são adicionadas ao `.env.local`. É útil para proprietários de landing pages de vendas que já possuem integração com Sepay e desejam um alerta rápido e confiável no celular, sem depender de e-mail.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/lexuanthanhhy/MKT.LANDINGPAGE.SKILLS/tree/main/.claude/skills/biz-telegram-payment-notify

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Biz Telegram Payment Notify — Alerta em tempo real quando o Sepay recebe o pagamento

Este skill conecta a notificação do bot do Telegram ao webhook do Sepay já existente no seu projeto Next.js. Sempre que um cliente transfere dinheiro com sucesso para a conta bancária vinculada ao Sepay, o skill faz o bot do Telegram enviar uma mensagem em tempo real para o chat do proprietário (ou grupo da equipe de vendas) — incluindo nome do cliente, telefone, valor, produto e horário.

Filosofia: O auto-responder por e-mail para o cliente (Resend) e o alerta no Telegram para o proprietário atendem a dois atores diferentes. O e-mail é formal para o cliente. O Telegram é um "ping" para o proprietário — você está na rua, abre o Telegram e vê o novo pedido imediatamente, sem precisar abrir o Gmail e procurar entre 100 e-mails. Latência do Telegram < 2 segundos vs. e-mail 30-60 segundos.

Por que Telegram e não Slack/Discord/Zalo: A configuração do bot do Telegram leva 5 minutos (1 token + 1 chat_id), não requer workspace/administrador de servidor, é gratuito com mensagens ilimitadas, tem notificações push mais fortes que e-mail e aplicativo nativo iOS/Android/desktop. O Slack precisa de workspace + convite. O Discord precisa de servidor + configuração de permissão. O Zalo OA precisa de conta empresarial verificada (3-7 dias para aprovação) + taxa mensal por usuário ativo. O Telegram é o caminho de menor resistência para alertas do lado do proprietário.

Saída do skill: patch de código + guia de configuração do bot passo a passo + lista de variáveis de ambiente + plano de teste em 3 níveis. O skill NÃO testa o envio do Telegram automaticamente — ele solicita que o usuário cole o token do bot e o chat_id primeiro, pois essas credenciais são de propriedade do usuário.


Quando usar este skill

  • O usuário acabou de configurar o webhook do Sepay e deseja ser notificado em tempo real no Telegram quando um cliente transferir dinheiro.
  • O usuário já tem /api/payment-success (ou equivalente) para processar e-mail com Resend e deseja adicionar o alerta do Telegram EM PARALELO — sem criar uma nova rota, sem duplicar a lógica.
  • O usuário diz "me avise quando houver um pedido" e o contexto é uma landing page de vendas com integração Sepay.

NÃO use este skill quando:

  • O usuário deseja notificação no Slack/Discord → caso de uso diferente.
  • O usuário deseja um bot do Zalo OA → precisa de conta empresarial verificada + estrutura de custos diferente.
  • O usuário ainda não configurou o webhook do Sepay (ainda não tem conta bancária vinculada ao Sepay, ainda não tem endpoint para receber webhook) → este skill não configura o Sepay do zero, apenas se conecta a um webhook existente.
  • O usuário quer apenas e-mail para o proprietário → biz-email-setup já tem o e-mail B (notificação ao proprietário).

Fluxo de trabalho geral (6 fases)

Fase 0: DETECTAR rota existente do webhook do Sepay (path + framework + formato do handler)
       ↓
Fase 0.5: DETECTAR armazenamento de leads (lib/leads-kv.ts de /biz-setup-sepay-payment)
           → sim: usar consulta KV real
           → não: oferecer 2 opções (modo bruto OU executar /biz-setup-sepay-payment primeiro)
       ↓
Fase 1: GUIAR usuário na criação do bot do Telegram (BotFather → token → chat_id)
       ↓ [BARREIRA — aguardar usuário colar token + chat_id]
       ↓
Fase 2: RASCUNHAR formato da mensagem → mostrar preview ao usuário → confirmar
       ↓
Fase 3: IMPLEMENTAR código (helper lib/telegram.ts + integrar no handler do webhook + variáveis de ambiente)
       ↓
Fase 4: PLANO DE TESTE (curl no bot direto → payload simulado do Sepay → verificação em produção)

As fases 1 e 4 têm barreira de espera pelo usuário porque exigem ação manual do usuário (obter token, verificar em produção). As fases 0/0.5/2/3 são feitas ativamente pelo skill.


Fase 0 — Detectar webhook do Sepay existente

Este skill se conecta a um webhook existente, NÃO cria uma nova rota. Primeiro, localize o handler.

Encontrar rota do webhook — grep por palavras-chave comuns:

# Na raiz do projeto
grep -r "sepay" --include="*.ts" --include="*.js" --include="*.tsx" -l
grep -r "transferAmount\|transferType\|payment-success\|payment-webhook" --include="*.ts" --include="*.js" -l

3 cenários comuns:

CenárioPath existenteAção
Usuário usou pipeline biz-email-setupapp/api/payment-success/route.ts (ou pages/api/payment-success.ts) já tem Resend chamando sendCustomerEmail + sendOwnerEmailConectar sendTelegramNotification no mesmo Promise.allSettled
Usuário tem rota específica do Sepayapp/api/sepay-webhook/route.ts ou app/api/webhook/sepay/route.tsConectar após analisar + validar payload do Sepay (ramo transferType === 'in')
Nenhuma rota encontrada—PARAR. Informar ao usuário: "Não encontrei uma rota de webhook para receber o Sepay. Configure o webhook do Sepay primeiro (vincule o banco ao Sepay → crie a URL do webhook apontando para o domínio) e depois volte para eu conectar o Telegram. Ou, se o webhook estiver em um endpoint com nome diferente, me indique o caminho."

Ler o handler atual para entender o formato:

  • Há autenticação da requisição do Sepay? (cabeçalho Authorization Apikey ou HMAC)
  • Há deduplicação por id ou referenceCode? (Sepay tenta novamente se não receber 200 → precisa de dedup para evitar notificação duplicada)
  • Há consulta de lead por content (mensagem de transferência contendo ID do pedido)?
  • Formato da resposta para o Sepay: { success: true } ou 200 OK simples?

Se o handler atual não tiver dedup — avise o usuário, mas NÃO bloqueie. O skill apenas conecta o Telegram, a deduplicação é uma preocupação da lógica de pagamento. Sugira que o usuário adicione dedup separadamente, se necessário.


Fase 0.5 — Detectar armazenamento de leads (CRÍTICO)

O webhook do Sepay envia apenas content (texto que o cliente colou ao transferir) + transferAmount + referenceCode. O Sepay não sabe quem é o cliente — é necessário consultar o armazenamento local pelo content (que contém o ID do pedido).

O skill verifica 3 coisas:

# 1. Verificar se o helper de armazenamento de leads existe
test -f lib/leads-kv.ts || test -f lib/leads-kv.js && echo "lead store: ✓"

# 2. Verificar variáveis de ambiente do Vercel KV
grep -E "KV_REST_API_URL|KV_REST_API_TOKEN" .env.local && echo "KV env: ✓"

# 3. Verificar se @vercel/kv está instalado
grep '"@vercel/kv"' package.json && echo "KV package: ✓"

3 cenários:

CenárioAção
Todos os 3 ✓ — armazenamento de leads prontoProsseguir para a Fase 1, usar getLeadByOrderId() de lib/leads-kv.ts no handler do webhook
1+ ausente — não configuradoPARAR, perguntar ao usuário sobre 2 opções (veja abaixo)

Se estiver faltando, pergunte ao usuário:

Percebi que você ainda não tem um armazenamento de leads (Vercel KV). O webhook do Sepay não sabe quem é o cliente — ele só tem o conteúdo da transferência + valor. O que você prefere?

Opção 1 — Configurar o armazenamento de leads completo via /biz-setup-sepay-payment primeiro (recomendado):

  • Esse skill configurará o Vercel KV, criará o scaffold de lib/leads-kv.ts e conectará o envio do formulário para salvar o lead quando o usuário se registrar
  • Depois, volte aqui e eu conectarei o Telegram para consultar o nome/telefone/e-mail completo do cliente
  • O alerta do Telegram mostrará: "Nguyễn Văn A — 0901234567 — [email protected] — 499K — Curso de Agente de IA"

Opção 2 — Modo bruto: enviar o payload do Sepay diretamente para o Telegram, sem consultar o lead:

  • O Telegram mostrará apenas: "Vietcombank — 499.000đ — content: DH001 0901234567 — 14:32"
  • O proprietário terá que adivinhar quem é o cliente pelo conteúdo e verificar o log de e-mail do Resend
  • Simples, funciona imediatamente, mas experiência do usuário ruim

Qual você escolhe, 1 ou 2?

Se o usuário escolher 1 → PARE este skill, sugira /biz-setup-sepay-payment. Depois que o usuário concluir a configuração, volte a este skill.

Se o usuário escolher 2 → prossiga para a Fase 1, use o modelo bruto (veja templates/lib-telegram-raw.ts).


Fase 1 — Guiar o usuário na criação do bot do Telegram

Leia references/telegram-bot-setup.md para instruções detalhadas com capturas de tela em texto. Resumo em 3 etapas para o usuário:

Etapa 1 — Criar um novo bot via @BotFather

1. Abra o Telegram (celular/desktop)
2. Pesquise: @BotFather → clique em Iniciar
3. Digite o comando: /newbot
4. O BotFather pergunta o nome do bot — insira o nome de exibição (exemplo: "Pedidos Marca X")
5. O BotFather pergunta o username — insira um username terminado em "_bot" (exemplo: marcx_pedidos_bot) — deve ser único globalmente
6. O BotFather retorna uma mensagem com a linha:
   "Use this token to access the HTTP API: 1234567890:AAxxxxxxxxxxxxxxxxxxxxxx"
7. Copie esse token e cole para mim.

ATENÇÃO À SEGURANÇA: Este token = controle total do bot. Não o comite no Git, não o compartilhe publicamente. Se vazar, volte ao @BotFather → /token → /revoke para criar um novo token.

Etapa 2 — Obter o chat_id

Chat 1-1 (apenas o proprietário recebe) — recomendado para empreendedores individuais:

1. No Telegram, pesquise: @userinfobot → clique em Iniciar
2. O bot retorna uma mensagem com "Id: 123456789" — copie esse número.
3. Esse é o seu chat_id.

Chat em grupo (equipe de vendas recebe junto) — recomendado para equipes:

1. Crie um novo grupo no Telegram (ou use um grupo existente)
2. Clique no nome do grupo → Adicionar membro → pesquise o bot que você acabou de criar (pelo username @marcx_pedidos_bot) → Adicionar
3. No grupo, digite: /start@marcx_pedidos_bot (ou qualquer mensagem)
4. Abra o navegador e acesse:
   https://api.telegram.org/bot<TOKEN>/getUpdates
   (substitua <TOKEN> pelo token da etapa 1)
5. Na resposta JSON, procure por "chat":{"id":-1001234567890,...} — copie esse número (lembre-se de manter o sinal de menos, se houver)
6. Esse é o chat_id do grupo.

Canal (broadcast unidirecional, sem discussão) — chat_id começa com -100. A forma de obter é a mesma do grupo, mas adicione o bot como administrador do canal.

Etapa 3 — Colar para o skill

Aguarde o usuário colar:

TELEGRAM_BOT_TOKEN=1234567890:AAxxxxxxxxxxxxxxxxxxxxxx
TELEGRAM_CHAT_ID=123456789

BARREIRA IMPORTANTE: NÃO prossiga para a Fase 2 até que o usuário cole AMBOS os valores. Se o usuário disser "já tenho, de outro lugar" → ainda aguarde a colagem, pois é necessário injetar no .env.local na Fase 3.


Fase 2 — Rascunhar formato da mensagem

Formato padrão em vietnamita, compatível com dispositivos móveis (o Telegram renderiza HTML):

🎉 <b>NOVO PEDIDO</b>

👤 <b>{{name}}</b>
📞 {{phone}}
📧 {{email}}
💰 <b>{{amount}}</b> — {{product_name}}
🕐 {{time_vn}}

🔗 Código da Trans.: <code>{{reference_code}}</code>

Após injetar as variáveis:

🎉 NOVO PEDIDO

👤 Nguyễn Văn A
📞 0901 234 567
📧 [email protected]
💰 499.000đ — Curso de Agente de IA
🕐 14:32 14/05/2026

🔗 Código da Trans.: FT26134567890

Mostrar preview ao usuário, perguntar:

  1. Este formato está OK? Deseja adicionar/remover algum campo? (exemplo: adicionar origem UTM, número de pedidos do dia, link do Zalo do cliente)
  2. Há muitos emojis? (alguns usuários preferem texto simples)
  3. Deseja adicionar um botão inline (CTA) com link para o CRM/Planilhas? (avançado — o skill pode adicionar teclado inline)

Regras de formatação:

  • Modo HTML (parse_mode: "HTML") — o Telegram suporta <b>, <i>, <u>, <code>, <pre>, <a href>. NÃO suporta <br> — use \n.
  • Formato do valor em VN: 499.000đ (ponto separador de milhar, com đ no final) OU charm 499K / 1.99M para ficar bonito. Leia a configuração voice de offer.json, se disponível.
  • Formato do telefone: 0901 234 567 (separado 3-3-3) — mais fácil de escanear no celular.
  • Horário VN: HH:mm dd/mm/yyyy — defina o horário do Vietnã (UTC+7), não UTC.
  • Evite spam de emojis (>5 emojis/mensagem → reduz a sensação de profissionalismo).

Fase 3 — Implementar o código

3 alterações:

3.1 Criar a função helper lib/telegram.ts

Leia templates/lib-telegram.ts (TypeScript) ou templates/lib-telegram.js (vanilla JS). Conteúdo:

// lib/telegram.ts
type TelegramPayload = {
  name: string;
  phone: string;
  email: string;
  amount: number; // VND, número bruto (ex: 499000)
  productName: string;
  referenceCode?: string;
};

export async function sendTelegramNotification(payload: TelegramPayload): Promise<void> {
  const token = process.env.TELEGRAM_BOT_TOKEN;
  const chatId = process.env.TELEGRAM_CHAT_ID;

  if (!token || !chatId) {
    console.error('[telegram] TELEGRAM_BOT_TOKEN ou TELEGRAM_CHAT_ID ausentes');
    return; // Não lançar erro — falha do Telegram não deve bloquear a resposta de pagamento
  }

  const text = formatMessage(payload);

  try {
    const res = await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        chat_id: chatId,
        text,
        parse_mode: 'HTML',
        disable_web_page_preview: true,
      }),
    });
    if (!res.ok) {
      const errBody = await res.text();
      console.error(`[telegram] Falha no envio: ${res.status} ${errBody}`);
    }
  } catch (err) {
    console.error('[telegram] Erro de rede:', err);
    // Engolir — não deixe a falha do Telegram fazer o Sepay tentar novamente
  }
}

function formatMessage(p: TelegramPayload): string {
  const amountStr = p.amount.toLocaleString('vi-VN') + 'đ';
  const phoneStr = p.phone.replace(/(\d{4})(\d{3})(\d{3})/, '$1 $2 $3');
  const now = new Date().toLocaleString('vi-VN', {
    timeZone: 'Asia/Ho_Chi_Minh',
    day: '2-digit', month: '2-digit', year: 'numeric',
    hour: '2-digit', minute: '2-digit',
  });
  return [
    '🎉 <b>NOVO PEDIDO</b>',
    '',
    `👤 <b>${escapeHtml(p.name)}</b>`,
    `📞 ${phoneStr}`,
    `📧 ${escapeHtml(p.email)}`,
    `💰 <b>${amountStr}</b> — ${escapeHtml(p.productName)}`,
    `🕐 ${now}`,
    p.referenceCode ? `\n🔗 Código da Trans.: <code>${escapeHtml(p.referenceCode)}</code>` : '',
  ].filter(Boolean).join('\n');
}

function escapeHtml(s: string): string {
  return s.replace(/[<>&]/g, c => ({ '<': '&lt;', '>': '&gt;', '&': '&amp;' }[c]!));
}

Por que engolir o erro: O Sepay tenta novamente o webhook se receber um código diferente de 200. Se o Telegram timeout/cair causar uma falha no webhook → Sepay tenta novamente → cada tentativa reenvia o e-mail + registra o pagamento novamente → o usuário recebe 5 e-mails + 5 alertas do Telegram para um único pedido. O Telegram é um canal lateral de melhor esforço, não um caminho crítico.

3.2 Conectar ao handler do webhook do Sepay

Leia o handler atual, localize o local onde o sucesso do pagamento é processado (após analisar o payload do Sepay + validar transferType === 'in'). Adicione:

// app/api/payment-success/route.ts (ou equivalente)
import { sendTelegramNotification } from '@/lib/telegram';
import { sendCustomerEmail, sendOwnerEmail } from '@/lib/resend'; // se já existir

export async function POST(req: Request) {
  const payload = await req.json();

  // [Existente] Validar autenticação do Sepay + analisar payload
  if (payload.transferType !== 'in') {
    return Response.json({ success: true }); // ignorar transferência de saída
  }

  // [Existente] Consultar lead pelo content (contém ID do pedido) ou referenceCode
  const lead = await lookupLeadByTransferContent(payload.content);

  // [NOVO] Distribuir 3 efeitos colaterais em paralelo — falha do Telegram não bloqueia o e-mail
  await Promise.allSettled([
    sendCustomerEmail(lead),
    sendOwnerEmail(lead),
    sendTelegramNotification({
      name: lead.name,
      phone: lead.phone,
      email: lead.email,
      amount: payload.transferAmount,
      productName: lead.productName,
      referenceCode: payload.referenceCode,
    }),
  ]);

  return Response.json({ success: true });
}

Por que usar Promise.allSettled em vez de Promise.all:

  • Promise.all rejeita se QUALQUER promise falhar → o handler lança erro → Sepay recebe 500 → tenta novamente → e-mail duplicado.
  • Promise.allSettled aguarda todas as promises serem concluídas (resolvidas ou rejeitadas) e não lança erro. Mesmo que o Telegram esteja fora do ar, o e-mail ainda é enviado e o Sepay recebe 200.

3.3 Adicionar variáveis de ambiente

# .env.local
TELEGRAM_BOT_TOKEN=1234567890:AAxxxxxxxxxxxxxxxxxxxxxx
TELEGRAM_CHAT_ID=123456789

Instruções para o usuário:

  1. Copie estas 2 variáveis para o arquivo .env.local (substituindo os valores de exemplo pelos seus).
  2. IMPORTANTE: NUNCA comite o .env.local. Verifique se ele está no .gitignore. Se não estiver, adicione-o IMEDIATAMENTE.
  3. Se estiver usando Vercel, adicione as variáveis também no dashboard do Vercel (Settings → Environment Variables) para os ambientes de produção/preview.

Fase 4 — Plano de teste

Nível 1 — Testar o bot do Telegram diretamente (sem o webhook)

Depois que as variáveis de ambiente estiverem configuradas e o servidor de desenvolvimento estiver rodando:

# No terminal, execute um script ou use curl para chamar a função helper
curl -X POST http://localhost:3000/api/test-telegram \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Nguyễn Văn Test",
    "phone": "0901234567",
    "email": "[email protected]",
    "amount": 499000,
    "productName": "Curso de Teste",
    "referenceCode": "TEST001"
  }'

Você pode precisar criar uma rota de teste temporária app/api/test-telegram/route.ts que chame sendTelegramNotification.

Critério de sucesso: Você recebe uma mensagem no Telegram com o formato correto.

Nível 2 — Simular payload do Sepay

Use o payload de exemplo do Sepay para testar a rota real do webhook:

curl -X POST http://localhost:3000/api/sepay-webhook \
  -H "Content-Type: application/json" \
  -d '{
    "id": 12345,
    "referenceCode": "FT26134567890",
    "transferType": "in",
    "transferAmount": 499000,
    "content": "DH001 0901234567",
    "accountNumber": "1234567890",
    "bankName": "Vietcombank",
    "gateway": "sepay"
  }'

Critério de sucesso:

  • Resposta 200 OK ({ "success": true })
  • Você recebe a notificação no Telegram
  • O cliente recebe o e-mail (se configurado)
  • Nenhum erro no console do servidor

Nível 3 — Teste em produção

  1. Faça o deploy da alteração.
  2. Peça a um amigo ou use um pagamento de teste real (se o Sepay permitir) no ambiente de produção.
  3. Verifique:
    • A notificação chega no Telegram em < 2 segundos após o pagamento.
    • O formato está correto.
    • Se o Sepay retentar (por exemplo, se houver um timeout de rede), NÃO há notificações duplicadas.

Solução de problemas

ProblemaCausa provávelSolução
Não recebe notificação no TelegramToken ou chat_id incorretosVerifique .env.local. Teste manualmente com curl: curl -X POST https://api.telegram.org/bot<TOKEN>/sendMessage -H "Content-Type: application/json" -d '{"chat_id":"<CHAT_ID>","text":"teste"}'
Notificação duplicada para um único pagamentoSepay retentou o webhook (recebeu non-200)Verifique se o Telegram está causando um erro no handler. Use Promise.allSettled. Se o problema persistir, adicione dedup por referenceCode.
Formato da mensagem quebrado no TelegramHTML inválido ou caracteres especiais não escapadosUse a função escapeHtml() em todos os campos do usuário. Certifique-se de que parse_mode: 'HTML' está definido.
Bot não responde a comandosToken inválido ou bot não iniciadoRefaça a Etapa 1 (criar novo bot no @BotFather).

Problemas conhecidos

  1. O Sepay não envia informações do cliente: O Sepay envia apenas content (a mensagem que o cliente colou na transferência) + amount + referenceCode. Para obter nome/telefone/e-mail, você PRECISA de um armazenamento de leads (consulta por content contendo o ID do pedido). Sem isso, a notificação do Telegram será genérica.
  2. Latência: O Telegram é geralmente rápido (< 2 segundos), mas em casos raros pode levar até 5 segundos. O fluxo de pagamento não é afetado — o Telegram é apenas um efeito colateral.
  3. Taxa de limite da API do Telegram: A API pública do Telegram tem um limite de taxa (aproximadamente 30 mensagens/segundo para bots). Para landing pages de alto volume, considere adicionar uma fila (por exemplo, Redis BullMQ ou Vercel Queues) para o envio de notificações do Telegram.
  4. Fuso horário: O horário é fixado em UTC+7 (Horário do Vietnã). Se o proprietário estiver em outro fuso horário, você precisará ajustar o helper de formatação.

Referências

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Best practices for Remotion - Video creation in React

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Scaffold trang `/admin` CRM-style trực quan vào Next.js project (Supabase backend) — KHÔNG còn variant Vercel KV. Layout 1CRM-inspired: sidebar 3 tab (Tổng quan / Khách hàng / Email marketing) + popup nhập mã đăng nhập. **Tab Tổng quan**: 4 KPI cards (Tổng leads / Đã thanh toán / Tỷ lệ chuyển đổi / Doanh thu) có delta arrow vs kỳ trước, line chart leads+paid+revenue theo ngày dùng `recharts`, donut trạng thái paid/pending/expired, period selector pill 7d/30d/90d, list 5 thanh toán gần nhất. **Tab Khách hàng**: bảng leads + search + filter trạng thái + filter ngày + CSV export. **Tab Email marketing**: form soạn chiến dịch (tên + tiêu đề + body chọn định dạng **văn bản thường HOẶC HTML** + placeholder `{{name}}` + audience 4 loại all/paid/pending/last_days + tên người gửi) — có nút **Xem trước** mở modal iframe render đúng email thật (text → auto convert + wrap khung; HTML fragment → wrap khung, HTML đầy đủ giữ nguyên) → gửi bulk qua SMTP (reuse `nodemailer` của `biz-email-setup` — KHÔN

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Deploy landing page / website (React, Next.js, Vite, static HTML) lên Vercel — tự kiểm tra Vercel CLI hoặc Vercel MCP đã cài chưa, nếu chưa thì cài qua npm/pnpm và hướng dẫn user authenticate (vercel login), tự detect framework (Next.js / Vite / CRA / static), auto-generate vercel.json khi cần, chạy `vercel --prod`, trả về live URL + inspect URL + hướng dẫn custom domain. USE WHEN user says 'deploy lên vercel', 'đẩy landing page lên vercel', 'publish website', 'go live', 'deploy nextjs', 'deploy react', 'deploy vite', 'tạo URL live', 'đưa lên production', 'biz-deploy-vercel', 'host landing page', 'vercel deploy', 'ship lên vercel', 'đẩy code lên vercel'. Skill này áp dụng cho cả case dùng Vercel CLI lẫn Vercel MCP server.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Setup SMTP-based email auto-responder cho landing page bán hàng — tự động gửi email sau khi user điền form (tên/SĐT/email), KHÔNG cố định vào provider nào. Skill này (1) hỏi user chọn SMTP provider (Gmail/Google Workspace, Resend SMTP, SendGrid, Mailgun, Brevo, Zoho, hoặc SMTP custom của hosting VN) và detect Next.js stack đang dùng, (2) đọc context từ `offer.json` + `conversion-copy.md` (từ `/biz-offer-alex-hormozi`) HOẶC đọc trực tiếp Next.js project đã build qua `ui-ux-pro-max` (file `app/page.tsx`) HOẶC đọc HTML landing page đã deploy để hiểu offer, dream outcome, mechanism, bonus. Lưu ý: skill `biz-sales-page-layout` đã DEPRECATED 2026-05-14 — pipeline mới skip layout/copy.json, (3) **draft 2 email**: email A — auto-responder gửi cho lead (warm welcome + deliver lead magnet/booking confirm/payment link tuỳ offer type), email B — notification gửi cho owner (lead alert + thông tin liên hệ), (4) **show draft cho user duyệt và chỉnh sửa** trước khi wire vào code, (5) cài `nodemailer`

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Cài chatbot AI dạng floating widget góc dưới phải vào project Next.js có sẵn (App Router hoặc Pages Router), responsive đầy đủ web + tablet + mobile, gọi LLM qua OpenRouter (mặc định google/gemini-3-flash-preview, có thể đổi sang anthropic/claude-sonnet-4.6), streaming response, RENDER MARKDOWN trong assistant bubble (bold / list / link / code) qua react-markdown + remark-gfm — KHÔNG hiện raw **bold** dạng text — có knowledge base từ FAQ + tài liệu sản phẩm/khóa học do user cung cấp để chatbot tự động trả lời khách hàng, và TỰ ĐỘNG EXTRACT + LƯU LEAD (tên + SĐT + email) vào Upstash Redis/Vercel KV dưới namespace `chat-lead:{phone}` khi user cung cấp đầy đủ thông tin trong chat — dedupe theo SĐT, TTL 90 ngày, fire-and-forget không block stream. Skill tự detect số lượng project Next.js — nếu có nhiều hơn 1 sẽ hỏi user chọn project nào để cài; tự detect TypeScript/JS, App Router/Pages Router, Tailwind/CSS module, KV/Upstash availability (skip auto-save nếu chưa có); tự install react-markd

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Đóng gói offer **không thể chối từ** (grand slam offer) theo phương pháp Alex Hormozi ($100M Offers) — nhận input pains/gains/customer jobs theo Value Proposition Design (Osterwalder 2014) + sản phẩm/dịch vụ, rồi sinh ra: (1) markdown report tiếng Việt đầy đủ Value Equation scoring + Core Offer + 3-4 Bonus stack + Guarantee + Urgency + Pricing, (2) offer.json structured cho pipeline downstream (`ui-ux-pro-max` build sales page production-ready), (3) conversion copy block (headline + subheadline + CTA) sẵn sàng paste landing page. 2 input mode: (B) user paste sẵn pains + gains + product, (C) user chỉ có sản phẩm — skill phỏng vấn theo VPD framework để surface pain/gain trước. Bonus stack mode hybrid: skill brainstorm 5-7 candidate có justification value rồi user pick/chỉnh 3-4 cái. Tiếng Việt thuần (xưng anh/chị), giá VND charm pricing (X99K), 3-tier decoy structure. USE WHEN user says 'đóng gói offer', 'tạo offer', 'thiết kế offer Hormozi', 'grand slam offer', 'value stack', 'offer sta

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Nâng cấp copy sales page tiếng Việt — biến copy có sẵn (từ `offer.json` + `conversion-copy.md` của `/biz-offer-alex-hormozi`, HOẶC từ Next.js project đã build qua `ui-ux-pro-max`, HOẶC user paste block copy bất kỳ) thành **copy chất lượng cao chốt đơn**: headline punchy hơn, pain agitation đau hơn, mechanism rõ hơn, benefit cụ thể hơn, FAQ xử lý đúng objection của thị trường VN, CTA mạnh hơn. Skill này có 3 INTENSITY LEVEL: (1) **Polish** — light edit + power word + sửa nhịp; (2) **Conversion-optimized** — rewrite 5 block critical + tạo A/B variants cho hero/CTA; (3) **Sales-letter** — long-form story-driven full rewrite kèm P.S.. Mỗi section áp dụng đúng formula thuyết phục (PAR cho pain, BAB cho solution, FEP cho benefit, PVEN cho final CTA, Star-Chain-Hook cho testimonial). Output gồm 4 file: `copy-upgraded.md`, `copy-variants.md` (A/B test bank — 3 hero + 3 CTA + 3 final-CTA), `copy-changes.md` (diff Trước/Sau + lý do), `copy.json` (structured downstream). Giọng văn tiếng Việt thuầ

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

⚠️ DEPRECATED (2026-05-14) — Skill này KHÔNG còn trong pipeline chuẩn. Quy trình mới đã bỏ bước wireframe markdown trung gian: sau `/biz-offer-alex-hormozi` đi THẲNG sang `ui-ux-pro-max` để build Next.js sales page production-ready (có design language nhất quán: style + palette + font pairing, không phải Tailwind defaults). Lý do deprecate: wireframe markdown làm thêm 1 bước trung gian không tạo giá trị — `ui-ux-pro-max` đọc trực tiếp `offer.json` đã đầy đủ anchor + core + bonus + guarantee + urgency + pricing rồi ra HTML production luôn. Chỉ dùng skill này KHI user EXPLICITLY yêu cầu wireframe markdown để review/in/share trước khi build code (rare case). KHÔNG trigger trên các keyword 'tạo sales page', 'tạo landing page bán hàng' nữa — những keyword đó giờ trigger `ui-ux-pro-max`.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

End-to-end Sepay VietQR payment infrastructure cho landing page Next.js — guide user setup Sepay account + bank linking + scaffold đầy đủ payment flow trong project. Skill này xử lý 7 phase: (0) detect Next.js stack + **HỎI user chọn lead store backend** (Vercel KV hoặc Supabase Free Postgres — default recommend Supabase do free tier rộng hơn ~50× + có SQL + admin UI), (1) GUIDE user đăng ký Sepay account tại my.sepay.vn + link bank account VN (Vietcombank/Techcombank/MB/ACB/VPBank/BIDV/...) + lấy API key + setup webhook URL trên Sepay dashboard, (2A nếu chọn KV) setup Vercel KV (install `@vercel/kv` + KV namespace + 4 env vars KV_*), (2B nếu chọn Supabase) setup Supabase project (tạo project tại Singapore region + chạy migration SQL tạo 4 bảng leads/phone_index/order_counter/webhook_dedup với pg_cron TTL cleanup + RLS deny-all + lấy SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY + Vercel Cron ping `/api/health` mỗi 6 ngày chống auto-pause), (3) scaffold `lib/leads-store.ts` (thin re-export

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Convert a single MP3 voiceover file into a single HeyGen avatar lip-sync MP4 video. Single-purpose — no planning, no SRT, no chunking, no Remotion compositing. Hybrid path — REST upload (helper script) + HeyGen MCP for video creation, because the post-2026 MCP no longer exposes an asset-upload tool. Reads avatar look pool (`HEYGEN_AVATAR_LOOKS`) from `.env` and HeyGen API key (`HEYGEN_API_KEY`) for the upload step. USE WHEN user says "tạo video heygen từ mp3", "mp3 to heygen", "heygen mp4 từ audio", "convert mp3 sang heygen video", "tạo avatar video từ file mp3", "lip sync mp3 heygen", "biến mp3 thành video heygen", or any time the user has exactly one MP3 file and wants exactly one HeyGen avatar MP4 out.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Demand-side market research cho digital product / service ở Việt Nam — đo cầu thật + WTP + channel-market fit + defensibility qua keyword volume, marketplace sales (Shopee/Unica/Edumall/Gitiho/KyNa), community signal (FB groups, TikTok hashtag, Zalo OA), competitor pricing, unit economics — không phải macro PESTEL. Output: keyword portfolio + Niche Score 100 điểm 7-dimension có evidence + go/no-go decision + falsification protocol. Force triangulate ≥3 sources cho mỗi claim quan trọng. USE WHEN user says 'nghiên cứu thị trường', 'market research', 'validate niche', 'keyword research', 'demand validation', 'niche có nên làm không', 'có ai làm chưa', 'thị trường đủ lớn không', 'có lời không', 'chọn ngách', 'kiểm tra cầu'. Cũng trigger khi user mô tả 1 ý tưởng kinh doanh cụ thể và muốn check feasibility. Skill này KHÔNG fit: high-ticket transactional sale (BĐS, ô tô), B2B enterprise (sales cycle 6+ tháng), hyper-local geo micro-market (1 toà nhà, 1 phường). KHÔNG làm: macro PESTEL/Porter

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Transcribe an MP3 voiceover into an SRT subtitle file and a word-level segments JSON using local OpenAI Whisper. Input is a single MP3 path; output is `<stem>.srt` + `<stem>_segments.json` written next to the MP3 (or to a custom output dir). USE WHEN the user says 'extract srt from mp3', 'trích srt từ mp3', 'transcribe voiceover', 'tạo file srt và segments', 'whisper transcribe', 'bóc transcript có timestamp', 'extract voiceover segments', 'tách SRT từ audio', or any time a downstream skill (plan-short-video-edit, heygen-remotion-short-video-editor) needs an SRT + word-level segments JSON from a voiceover MP3 and one does not already exist.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Convert Vietnamese/English script text to MP3 voiceover using ElevenLabs TTS API. Calls POST /v1/text-to-speech/{voice_id}, streams audio bytes, writes MP3 directly. Locked to Hoang's brand voice ID by default. USE WHEN user says 'tạo mp3 elevenlabs', 'elevenlabs tts', 'eleven labs voice', 'text to speech elevenlabs', 'tạo voiceover elevenlabs', 'đọc text bằng elevenlabs', 'tts elevenlabs to mp3', 'eleven labs script to mp3', 'voiceover bằng elevenlabs', 'giọng elevenlabs'.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

End-to-end orchestrator: **script → final MP4 16:9 (1920×1080) podcast-keynote**.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

End-to-end short-video pipeline — từ kịch bản (Việt/Anh) ra MP4 TikTok/Reels 9:16 hoàn chỉnh. Orchestrator 3 phase ghép skill có sẵn — (1) TTS provider chọn được giữa `mkt-elevenlabs-tts-to-mp3` (default, voice của Hoàng) hoặc `mkt-video-script-to-mp3` (MiniMax speech-2.8-hd), (2) checkpoint user duyệt MP3, (3) `heygen-mp3-to-mp4` lip-sync avatar HeyGen, (4) delegate Phase 3 packaging cho sub-agent `mkt-full-video-phase3-packager` (transcribe + scene outline + checkpoint + fan-out N scene writers parallel + scaffold + preview Studio). API key + voice ID cho cả 2 provider lưu ở `.env`. USE WHEN user nói "tạo full video từ script", "script to tiktok video", "pipeline full video heygen + hyperframe", "tạo video từ kịch bản đến mp4", "elevenlabs heygen hyperframe full pipeline", "minimax heygen pipeline", "kịch bản ra video tiktok", hoặc có sẵn 1 script + (optional) ảnh b-roll và muốn ra MP4 9:16 đóng gói có captions, SFX, b-roll.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Build a TikTok/Reels/YouTube **landscape 16:9 (1920×1080)** short video from a pre-recorded talking-head MP4 using HyperFrames — transcribe Vietnamese audio, scaffold a complete preview-ready 1920×1080 project with a slide pane (1200px) on the left and a floating avatar frame on the right, GSAP timeline có SPLIT↔PIP transitions (slide full-screen + avatar PIP corner thumbnail), breathing yoyo zoom + beat-driven punch-in trên avatar, 5 scene compositions kiểu "tier-row" pattern (post-stack hook / chats-stack problem / hero-orb solution / counter-row recap / terminal-row CTA), optional cream-paper editorial infographic image slots với `<img onerror>` fallback, 6 SFX wired tại scene boundaries, **NO captions** (giọng avatar là spine). USE WHEN user nói "edit video 16:9 từ HeyGen MP4", "scaffold project landscape", "podcast keynote editor", "talking head + slide editor", "build hyperframes 1920×1080", "tạo project 16:9 từ avatar mp4", "scaffold 16:9 hyperframes", "hyperframe landscape vide

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Pipeline đóng gói: từ MP4 quay sẵn (talking head 9:16) tới HyperFrames preview project hoàn chỉnh có captions, SFX, zoom hooks, b-roll toàn cảnh có hiệu ứng rich, và CTA finale.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Audit bài Facebook / Reels / YouTube để phát hiện 4 downward drivers (over-branding, over-production, stock imagery, standardized aesthetic) + frequency-over-quality. Mỗi anti-pattern bị drop ~75% performance nếu hiện diện. USE WHEN user says 'audit content', 'check anti pattern', 'content có lỗi gì không', 'kiểm tra over branding', 'vì sao video bị chết', 'vì sao post không ai xem', 'content audit', 'kiểm tra chất lượng content'.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Tìm viral pattern ở ngành khác (bác sĩ, luật sư, tài chính, bất động sản, thủ công) có thể apply cho niche AI/automation của Hoang. Ngách AI educator VN còn ít format được khai thác — cross-industry adaptation là blue ocean. USE WHEN user says 'tìm format ngành khác', 'cross industry research', 'học format từ ngành khác', 'blue ocean format', 'tìm format chưa ai làm', 'adapt format từ niche khác', 'cross industry viral'.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Rewrite CTA kiểu autocratic (Mua ngay! Follow ngay! Đăng ký liền!) sang 3 variants Democratic / Benevolent / Laissez-faire — reach 85% dân số thay vì chỉ 5% (action-based). Áp dụng cho landing page, caption FB, CTA video, email. USE WHEN user says 'rewrite cta', 'sửa cta', 'cta không autocratic', 'viết lại kêu gọi hành động', 'cta cho landing page', 'cta nhẹ nhàng hơn', 'inclusive cta', 'cta democratic benevolent'.

Habilidades Relacionadas