Crie uma página romântica única para quem você ama: cartinhas, fotos, música, linha do tempo e surpresas. Pronta em minutos, com ajuda de IA.
Translation pending
LifestyleGitHub @DevMuriloDiasOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Repository information has not been collected yet.
No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Aplicação web para criar páginas românticas personalizadas: o cliente responde um questionário, a IA gera o primeiro rascunho, ele edita tudo com prévia ao vivo, paga com Pix ou cartão (Mercado Pago) e recebe o link na tela e por e-mail.
O nome do produto fica em
src/config.ts(BRAND.name) — troque ali.
Next.js 15 (App Router) · TypeScript strict · Tailwind CSS 4 + componentes no padrão shadcn/ui (Radix) · Framer Motion · PostgreSQL + Prisma · Zustand · dnd-kit · Zod · Mercado Pago (Checkout Transparente: Pix via API de Payments + Card Payment Brick) · Resend + React Email · Anthropic SDK · Leaflet/OpenStreetMap + Nominatim · S3/R2 com URL pré-assinada · Upstash Redis (rate limit) · Vitest + Playwright.
src/
app/ rotas (App Router)
page.tsx landing
criar/ questionário → editor → revisão → checkout
p/[slug]/ página pública (SSR) + OG image
minhas-paginas/ acesso por magic link
admin/ painel (login próprio)
api/ drafts, pages, ai, uploads, checkout, orders (+SSE),
webhooks/mercadopago, public, qr, cron, geocode
components/
page/ RENDERER ÚNICO da página (preview = página pública)
sections/ 16 módulos (hero, cartas, fotos, linha do tempo, mapa…)
builder/ editor (painéis, editores por módulo, tema, preview)
checkout/ Pix, cartão, SSE, tela de sucesso
lib/
content/ schema Zod versionado + migrações + textos padrão
theme/ design tokens, 8 templates, fontes, contraste WCAG
sections/registry.ts registro tipado dos módulos (sectionRegistry)
payments/ provedor MP/mock, assinatura, fulfillment idempotente
ai/ prompts (pt-BR), schemas, retry de JSON, streaming
pages/ acesso (cookies/tokens), serviço, porta (bcrypt)
emails/ templates React Email
stores/builder.ts Zustand com histórico (desfazer/refazer)
prisma/ schema, migrações e seed
tests/unit · tests/e2e Vitest · Playwright
Princípios
/p/[slug] usam o mesmo PageRenderer. O preview usa container queries (@md:) e transform para prender elementos fixos à moldura, então o layout é exatamente o mesmo.httpOnly (no banco só o hash SHA-256). O e-mail só é pedido no checkout.x-signature, registra o evento e busca o pagamento na API pelo ID. O processamento é idempotente (transição atômica via updateMany condicional).Decisões tomadas fora do documento original estão em DECISIONS.md.
Pré-requisitos: Node 20+ (testado com 22), PostgreSQL 14+.
# 1. Dependências
npm install
# 2. Variáveis de ambiente
cp .env.example .env
# - gere APP_SECRET: openssl rand -hex 32
# - ajuste DATABASE_URL
# - para testar pagamentos sem conta: PAYMENTS_PROVIDER=mock e MP_WEBHOOK_SECRET=qualquer-coisa
# 3. Banco
npx prisma migrate dev # cria as tabelas
npm run db:seed # planos (preços PLACEHOLDER), 8 templates, cupom BEMVINDO10, admin
# 4. Rodar
npm run dev # http://localhost:3000
Sem nenhuma chave externa o app já funciona de ponta a ponta:
| Serviço | Sem configuração |
|---|---|
| Pagamentos | PAYMENTS_PROVIDER=mock: Pix e cartão simulados; na tela do Pix aparece “Simular pagamento aprovado”, que dispara o mesmo webhook assinado do Mercado Pago |
| Fotos | STORAGE_DRIVER=local: arquivos em ./.uploads |
| E-mails | sem RESEND_API_KEY: registrados na tabela EmailLog e no console (veja em /admin/emails) |
| IA | sem ANTHROPIC_API_KEY: textos padrão de boa qualidade (o fluxo nunca trava) |
| Rate limit | sem Upstash: limitador em memória |
Scripts: npm run lint · npm run typecheck · npm test · npm run test:e2e · npm run build.
Todas estão documentadas em .env.example. O que você precisa providenciar para produção:
| Conta / configuração | Variáveis |
|---|---|
| Domínio + hospedagem (ex.: Vercel) | APP_URL |
| PostgreSQL (Neon, Supabase, RDS…) | DATABASE_URL |
| Mercado Pago (credenciais de produção + webhook) | MP_ACCESS_TOKEN, NEXT_PUBLIC_MP_PUBLIC_KEY, MP_WEBHOOK_SECRET, PAYMENTS_PROVIDER=mercadopago |
| Cloudflare R2 ou AWS S3 (bucket público ou com CDN) | STORAGE_DRIVER=s3, S3_* |
| Resend (domínio verificado) | RESEND_API_KEY, EMAIL_FROM, EMAIL_REPLY_TO |
| Anthropic | ANTHROPIC_API_KEY, AI_MODEL (padrão claude-sonnet-5-5) |
| Upstash Redis | UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN |
| Segredos internos | APP_SECRET, CRON_SECRET, ADMIN_EMAIL, ADMIN_PASSWORD |
PAYMENTS_PROVIDER=mercadopago
MP_ACCESS_TOKEN=TEST-... # ou APP_USR-... de uma conta de teste
NEXT_PUBLIC_MP_PUBLIC_KEY=TEST-...
npm run dev
ngrok http 3000
# copie a URL https://xxxx.ngrok-free.app
Coloque essa URL em APP_URL (o app envia notification_url = APP_URL/api/webhooks/mercadopago em cada pagamento) e reinicie o npm run dev.https://xxxx.ngrok-free.app/api/webhooks/mercadopago, evento Pagamentos. Copie a assinatura secreta para MP_WEBHOOK_SECRET.5031 4332 1540 6351, CVV 123, validade 11/30. O nome do titular define o resultado: APRO aprovado, OTHE recusado, CONT pendente, FUND saldo insuficiente, SECU CVV inválido. CPF de teste: 12345678909.PAYMENTS_PROVIDER=mock — o simulador percorre exatamente o mesmo caminho (webhook com x-signature → busca do pagamento → liberação). Se um webhook se perder, o cron de reconciliação e a própria tela de pagamento (consulta direta a cada 15 s) atualizam o pedido./admin/webhooks (assinatura válida/inválida, resultado de cada evento).Em produção, troque para as credenciais de produção e cadastre o webhook no modo produção.
As fotos são comprimidas e convertidas para WebP no navegador, enviadas direto ao bucket via URL pré-assinada PUT (tipo e tamanho fazem parte da assinatura; o R2 não aceita o presigned POST) e, em seguida, o servidor baixa o arquivo, valida o conteúdo real com sharp, remove EXIF/GPS, gera o WebP final e apaga o original.
Cloudflare R2:
S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com, S3_REGION=auto.r2.dev) → S3_PUBLIC_URL.[{ "AllowedOrigins": ["https://avelove.com.br", "http://localhost:3000"], "AllowedMethods": ["GET", "PUT"], "AllowedHeaders": ["Content-Type"], "MaxAgeSeconds": 3600 }]
Verifique o domínio no Resend, defina RESEND_API_KEY e EMAIL_FROM. Todo envio é registrado em EmailLog; falhas são retentadas na hora (3x com backoff) e depois pelo cron /api/cron/emails. Os templates ficam em src/emails/templates.tsx.
E-mails: pagamento aprovado (link, QR Code, link mágico de edição e dicas), continuar rascunho, acesso a “Minhas páginas”, página aberta, resposta do pedido, vale resgatado, recado recebido e Pix gerado.
/api/ai/*, /api/pages/[id]/generate). Modelo em AI_MODEL (padrão claude-sonnet-5-5).src/lib/ai/prompts/. Saídas JSON validadas com Zod e uma nova tentativa automática informando o erro ao modelo.AI_MAX_PER_DRAFT (contador no banco) e AI_MAX_PER_IP (24 h). Moderação básica antes da chamada + regras no prompt de sistema.AI_SERVER_FALLBACK=1 habilita o fallback de modelo do lado do servidor (beta server-side-fallback-2026-07-01) para recusas de classificador. Desligue com 0 se preferir.Rotas protegidas por Authorization: Bearer $CRON_SECRET (padrão da Vercel Cron, já configurado em vercel.json). O plano Hobby da Vercel só permite crons diários; no plano Pro, use */10 * * * * (reconcile) e */15 * * * * (emails). Mesmo com cron diário, a tela de pagamento consulta o Mercado Pago a cada 15 s enquanto o cliente está nela, e os e-mails já têm 3 tentativas imediatas.
| Rota | Frequência | O que faz |
|---|---|---|
/api/cron/reconcile | diário (10 min no plano Pro) | consulta na API os pedidos pendentes (webhook perdido) e expira Pix vencidos |
/api/cron/emails | diário (15 min no plano Pro) | reenvia e-mails que falharam |
/api/cron/cleanup | diário | apaga rascunhos não pagos e suas fotos após DRAFT_RETENTION_DAYS (30) e uploads abandonados |
Fora da Vercel, agende com qualquer cron: curl -H "Authorization: Bearer $CRON_SECRET" https://avelove.com.br/api/cron/reconcile.
npm test # Vitest: schemas, migrações, planos/cupons, assinatura do webhook, status,
# normalização da porta, música, tempo, céu, moderação, store (desfazer/refazer)
npm run build && npm run test:e2e
O E2E (Playwright, celular e desktop) percorre: questionário → editar (autosave) → revisão → checkout → Pix → aprovação via webhook assinado → link liberado na tela (SSE) → e-mail registrado → página pública abre. Requer Postgres com as migrações e o seed aplicados; sobe o servidor com PAYMENTS_PROVIDER=mock.
Se o Playwright não encontrar o navegador, aponte para um Chromium instalado: PW_CHROMIUM_PATH=/caminho/do/chrome npm run test:e2e.
Vercel (recomendado):
next build). Rode as migrações no deploy: npx prisma migrate deploy (ex.: no build command prisma migrate deploy && next build).npm run db:seed) e defina os preços reais em /admin/planos.https://avelove.com.br/api/webhooks/mercadopago.vercel.json passam a rodar automaticamente (defina CRON_SECRET).Headers de segurança e CSP (compatível com YouTube, Spotify, Mercado Pago, Google Fonts e tiles do OSM) estão em next.config.ts.
/admin — login com ADMIN_EMAIL/ADMIN_PASSWORD criados pelo seed (troque a senha!). Dashboard (vendas do dia/mês, conversão, ticket médio), pedidos (filtros, reenviar e-mail, reembolsar via API), páginas (busca, denúncias, despublicar, excluir), planos/preços, cupons, templates (ativar/ordenar), webhooks e e-mails.
SECTION_DATA e variante em SectionSchema (src/lib/content/schema.ts). Se mudar algo já existente, incremente CONTENT_SCHEMA_VERSION e crie a migração em migrations.ts.src/lib/sections/registry.ts.src/components/page/sections/ + registro em renderers.tsx.src/components/builder/editors/ + registro em editors/index.tsx.O TypeScript acusa erro se algum dos mapas ficar incompleto.