O rumo da sua próxima terra.
🌐 www.rumaria.com.br — site em produção
Marketplace SaaS de imóveis rurais do Brasil — fazendas, sítios, chácaras e ranchos. Corretores assinam plano mensal para anunciar; compradores navegam grátis e falam direto via WhatsApp.
Mercados de imóveis rurais no Brasil são fragmentados, com portais generalistas mal adaptados ao agro e poucos focados em especificidades técnicas (reserva legal, georreferenciamento, aptidões, fontes de água). A Rumaria é construída de baixo pra cima como marketplace especializado, com:
- Score automatizado que premia anúncios completos e corretores que respondem rápido.
- Ficha técnica rural rica (24+ benfeitorias, aptidões, topografia, lat/lng com mapa).
- Programa Fundador — convite outbound para os primeiros 20 corretores, com landing personalizada via Z-API.
- Curadoria editorial — Acervos numerados que populam o site no lançamento sem expor identidade de terceiros.
| Camada | Tecnologia |
|---|---|
| Frontend + API | Next.js 15 (App Router, Server Components, Server Actions) |
| Banco + Auth + Storage | Supabase (PostgreSQL + RLS + Storage) |
| Pagamentos | Mercado Pago (assinaturas + webhook HMAC) |
| WhatsApp Outbound | Z-API (envio + parsing de respostas) |
| Email transacional | Resend |
| Cache + Rate limit | Upstash Redis |
| PDF do anúncio | Browserless (Puppeteer-as-a-service) |
| Imagens | Pipeline Sharp (WebP, 3 tamanhos) |
| Mapas | Mapbox GL |
| Estilo | Tailwind CSS v4 (tokens em globals.css) |
| Linguagem | TypeScript strict |
| Deploy | Vercel + Cron |
| Scraper auxiliar | Python + Playwright + BeautifulSoup |
Todo anúncio recebe nota 0–100 baseada em fotos, descrição, completude da ficha técnica e destaques. Score também leva em conta o corretor (anúncios aprovados, dias na plataforma, taxa de resposta a leads, denúncias). Resulta em selos automáticos:
- Premium (80+) → home + busca destacada
- Bom (60–79) → busca padrão
- Baixa qualidade (<60) → só visível no perfil do corretor
Lógica em src/lib/utils.ts com pesos configuráveis em src/lib/constants.ts.
Sistema completo para os primeiros 20 corretores parceiros:
- Staging seguro (
leads_fundador) — dados raspados ficam fora do site público até aceite explícito. - Token HMAC assinado com expiração de 7 dias.
- Z-API integrada — envio do convite por WhatsApp + webhook que reconhece SIM/NÃO/e-mail e completa o aceite sem o corretor precisar abrir landing.
- Hash de telefone com salt — opt-out via blocklist sem armazenar dado pessoal em claro.
- Landing premium com hero cinematográfico, watermark Bebas Neue, contadores animados, marquee de credibilidade, preview dos imóveis do corretor já renderizados como anúncio Rumaria.
- Magic link automático após aceite (Supabase Auth
recovery) — corretor define senha, conta vira ativa.
Migration em supabase/migrations/00026_leads_fundador.sql.
Forma legal de popular o marketplace antes da onda de fundadores: importa anúncios públicos de portais de imóveis rurais e publica sob corretores fictícios numerados (Acervo 1, Acervo 2...), sem expor nome/CRECI/foto do anunciante origem. WhatsApp do corretor original fica no anúncio para facilitar contato real, e o anúncio leva selo de "curadoria editorial" + link para o portal de origem.
Script: scripts/scraper/importar_acervo_rumaria.py.
- RLS deny-all em tabelas de staging (toda mutação passa por server actions).
- HMAC timing-safe no webhook Mercado Pago.
- CSRF via header
Originem mutações sensíveis. - Rate limit Upstash em endpoints públicos críticos (signup, aceite, recusa, magic link).
- LGPD art. 18 VI — exclusão completa de conta + storage cleanup.
- PII minimization — telefone hashado em blocklist, email só após aceite.
Sharp local + Supabase Storage. Cada upload vira:
thumb320×240 (WebP q70) — cardsgallery1280×960 (WebP q80) — listagem do imóvelzoom2560×1920 (WebP q90) — lightbox
Cache immutable, max-age=31536000 na URL pública, sem CDN extra.
Formato: /imoveis/{tipo}-em-{cidade}-{uf}-com-{area}ha-r-{preco}-ref-{codigo}
Exemplo: /imoveis/fazenda-em-cachoeira-paulista-sp-com-215-ha-r-12900000-ref-6JAF75
Código alfanumérico de 6 chars gerado por trigger no banco — único e estável.
src/
app/ # Next.js App Router
(public-facing)
page.tsx # Home com Premium + Cabeceiras + Trust signals
imoveis/ # Listagem + detalhe + comparar + SEO por estado
corretor/[slug]/ # Perfil público do corretor
corretores/ # Diretório de corretores
planos/ # Tabela de planos com upgrade flow
cadastro/ # Signup com convite opcional
login/, recuperar-senha/, atualizar-senha/
convite/[token]/ # Landing de Programa Fundador (cinematográfica)
sobre/, termos/, privacidade/, cookies/, termos-fundador/
(authenticated)
painel/ # Área do corretor: imoveis, perfil, pagamentos, fundador
minha-conta/ # Editar perfil + LGPD delete
(admin)
admin/ # Dashboard com KPIs + alertas
usuarios/ # Corretores: validar CRECI, marcar fundador
imoveis/ # Moderação + edição
leads-fundador/ # Pipeline outbound + import JSON
comissoes/ # Pagamento de comissões de fundadores
denuncias/ # Triagem
importador/ # Curadoria de imóveis
(api)
api/webhooks/mercadopago, /zapi
api/cron/* # 9 jobs agendados (crons em vercel.json)
api/admin/leads-fundador # Endpoint pra scraper postar JSON
components/ # UI primitives + layouts + emails
features/ # Lógica por domínio (auth, properties, payments, fundador, convite)
lib/ # constants, utils, env, supabase clients, image-pipeline, rate-limit
types/ # database.ts (todo o schema tipado)
supabase/
migrations/ # 28 migrations (até features mais recentes)
scripts/
scraper/ # Python + Playwright (importação automatizada)
cleanup/ # SQL de limpeza pontual
npm run dev # servidor de desenvolvimento
npm run build # build de produção (compila + collect static)
npm run lint # ESLint (zero warnings exigido)
npm run typecheck # TypeScript strict, no any# 1. Instalar
npm install
# 2. Configurar env
cp .env.example .env.local
# preencher com chaves reais (Supabase, MP, Resend, etc)
# 3. Rodar migrations
# Painel Supabase → SQL Editor → executar arquivos de
# supabase/migrations/ em ordem numérica
# 4. Subir servidor
npm run devDetalhes de cada variável em .env.example.
Definidos em vercel.json:
| Cron | Schedule | Função |
|---|---|---|
verificar-assinaturas |
diário 6h | Suspende inadimplentes, ativa pagas |
expirar-indicacoes |
diário 7h | Janela de 12 meses fim |
expirar-convites |
diário 8h | Convites de fundador 7d → recusa |
relatorio-mensal |
dia 1 às 9h | Email mensal pros corretores |
avisar-convites-expirando |
diário 14h | Aviso 2d antes de expirar |
atualizar-cotacoes |
dias úteis 12h30 | Cotação soja/boi/dólar |
limpar-vendidos |
diário 3h | Auto-arquiva vendidos antigos |
atualizar-irv |
dia 2 às 4h | Índice de Referência de Valores |
reset-cabeceira |
dia 1 às 5h | Reset do destaque "cabeceira" |
Cenários de carga em tests/load/ com k6. Cobertura:
home.k6.js— fluxo público (home → listagem → detalhe → perfil corretor)webhook-mp.k6.js— webhook Mercado Pago com HMAC válidowebhook-zapi.k6.js— webhook Z-API com 5 variantes de payloadconvite.k6.js— landing pública do Programa Fundador
Resultados reais (build de produção, 2026-04-25, MacBook-class hardware):
| Endpoint | VUs | RPS | p50 | p95 | Erro |
|---|---|---|---|---|---|
GET / + /imoveis + /imoveis/[slug] + /corretor/[slug] |
20 | 6.4 | 318ms | 645ms | 0.00% |
GET /convite/[token] (HMAC-signed token) |
15 | 74 | 90ms | 181ms | 0.00% |
POST /api/webhooks/zapi?token=... (5 payload variants) |
20 | 71 | 122ms | 170ms | 0.00% |
POST /api/webhooks/mercadopago (HMAC validation only) |
25 | 254 | 44ms | 92ms | 401 esperado* |
* O teste de webhook MP usa secret de teste para validar o caminho de rejeição rápida por HMAC inválido (expected 401). Esse é o caminho mais quente em produção — Mercado Pago re-tenta webhooks com replay, então rejeitar requests inválidas em <100ms é desejado.
Targets calibrados pra carga média realística — o objetivo é detectar regressão, não medir limite máximo. Cada teste tem 3 estágios (warm-up → sustained → ramp-down) totalizando ~40-55s de execução.
Como rodar (sempre contra build de produção, não dev):
# Janela 1 — sobe build otimizado
npm run build
npm run start
# Janela 2 — roda os testes
k6 run tests/load/home.k6.js
k6 run tests/load/convite.k6.jsWebhooks de pagamento/WhatsApp só rodam contra Supabase de teste — processam dados reais quando recebem assinaturas válidas.
- Mobile-first — toda UI começa em 360px, expande pro desktop.
- WhatsApp como canal primário — botão âmbar
ctaem destaque, sem captura de e-mail intermediária. - Português pt-BR para usuário, inglês para código — evita ambiguidade entre identifiers e copy.
- Sem ORM — Supabase client direto, types gerados de src/types/database.ts.
- Sem state management — React context para sessão, URL state para filtros.
- Tailwind v4 — config no CSS via
@theme inline, semtailwind.config.ts.
Proprietário. Todos os direitos reservados.