13 KiB
Feature Specification: Contact Button
Feature Branch: [009-contact-button]
Created: 2026-04-17
Status: Draft
Input: Adicionar um botão destacado 'Entre em Contato' em cada card de imóvel (PropertyRowCard e PropertyCard). Ao clicar, o cliente pode escolher entre preencher um formulário de contato (gera lead no painel admin) ou entrar em contato via WhatsApp com mensagem pré-preenchida com o código do imóvel. O número de WhatsApp do corretor deve vir de uma configuração (variável de ambiente ou admin).
User Scenarios & Testing (mandatory)
User Story 1 - Acessar o Botão de Contato no Card do Imóvel (Priority: P1)
O visitante, ao visualizar qualquer card de imóvel (na listagem ou na seção de destaques), vê um botão destacado "Entre em Contato" e consegue acioná-lo com facilidade.
Why this priority: O botão é o ponto de entrada de toda a feature; sem ele, nenhum outro cenário é alcançável.
Independent Test: Verificar se o botão "Entre em Contato" está visível e clicável em todos os cards de imóvel (PropertyRowCard e PropertyCard).
Acceptance Scenarios:
- Given um visitante na página de listagem de imóveis, When visualiza um
PropertyRowCard, Then vê o botão "Entre em Contato" em destaque no card. - Given um visitante na página inicial (seção de destaques), When visualiza um
PropertyCard, Then vê o botão "Entre em Contato" em destaque no card. - Given um visitante em dispositivo móvel, When visualiza qualquer card de imóvel, Then o botão "Entre em Contato" é visível, acessível e clicável sem necessitar de rolagem horizontal.
User Story 2 - Escolher Canal de Contato (Priority: P1)
Ao clicar no botão "Entre em Contato", o visitante vê um modal/painel com duas opções claras: formulário de contato ou WhatsApp.
Why this priority: A escolha de canal é o fluxo central da feature; define qual caminho o usuário toma.
Independent Test: Verificar se o modal exibe as duas opções para cada imóvel diferente e que clicar fora do modal o fecha sem efeitos colaterais.
Acceptance Scenarios:
- Given o visitante clica em "Entre em Contato" em um card, When o modal abre, Then vê duas opções claramente apresentadas: "Formulário de Contato" e "WhatsApp".
- Given o modal está aberto, When o visitante clica fora da área do modal ou em um botão de fechar, Then o modal é fechado sem enviar nenhum dado.
- Given o modal está aberto para o imóvel X, When o visitante fecha e abre o modal de um imóvel Y diferente, Then o modal exibe o código do imóvel Y corretamente.
User Story 3 - Enviar Formulário de Contato (Priority: P1)
O visitante preenche e envia um formulário de contato com seu nome, e-mail, telefone (opcional) e uma mensagem pré-preenchida com o código do imóvel. O lead é registrado no sistema e visível no painel administrativo.
Why this priority: Captação de leads é um dos objetivos de negócio principais do sistema.
Independent Test: Verificar se um lead é criado no banco de dados com o property_id correto após o envio do formulário, e se o registro aparece no painel admin.
Acceptance Scenarios:
- Given o visitante escolhe "Formulário de Contato", When o formulário é exibido, Then o campo de mensagem já contém o código do imóvel (ex.: "Tenho interesse no imóvel de código 2880602111.").
- Given o formulário está aberto, When o visitante preenche nome, e-mail e mensagem e clica em "Enviar", Then os dados são enviados, o lead é salvo no sistema e o visitante vê uma mensagem de sucesso.
- Given o visitante tenta enviar o formulário com campos obrigatórios vazios (nome ou e-mail), When clica em "Enviar", Then vê mensagens de erro claras nos campos inválidos e o envio é bloqueado.
- Given o visitante preenche um e-mail em formato inválido, When clica em "Enviar", Then vê mensagem de erro específica sobre o e-mail.
- Given o visitante clica "Enviar" e ocorre falha de rede ou erro do servidor, When a resposta retorna erro, Then vê mensagem de erro amigável e pode tentar novamente sem perder os dados preenchidos.
- Given o formulário foi enviado com sucesso, When o admin acessa o painel de leads, Then vê o novo lead com o código/ID do imóvel associado, nome, e-mail, telefone e mensagem do visitante.
User Story 4 - Contato via WhatsApp (Priority: P1)
O visitante escolhe a opção WhatsApp e é redirecionado para o WhatsApp com uma mensagem pré-preenchida contendo o código do imóvel. O número de destino pertence ao corretor responsável.
Why this priority: WhatsApp é o canal de comunicação predominante no mercado imobiliário brasileiro; é esperado como opção principal.
Independent Test: Verificar se o link gerado aponta para o número correto (configurado no sistema) e se a mensagem contém o código do imóvel.
Acceptance Scenarios:
- Given o visitante escolhe a opção "WhatsApp" no modal, When confirma a ação, Then é redirecionado para o WhatsApp (web ou app) com a mensagem "Olá! Tenho interesse no imóvel de código [CÓDIGO]. Poderia me dar mais informações?" pré-preenchida.
- Given o número de WhatsApp do corretor está configurado no sistema, When o visitante aciona a opção WhatsApp, Then o link aponta para esse número configurado.
- Given o número de WhatsApp não está configurado, When o visitante tenta usar a opção WhatsApp, Then a opção é desabilitada ou exibe uma mensagem informando que o canal não está disponível no momento.
- Given o visitante está em desktop, When clica em WhatsApp, Then o link abre o WhatsApp Web em nova aba; em dispositivos móveis, abre o aplicativo nativo do WhatsApp.
User Story 5 - Configuração do Número de WhatsApp (Priority: P2)
O administrador pode configurar o número de WhatsApp do corretor que será usado nos links gerados nos cards de imóvel.
Why this priority: Sem configuração do número, a opção WhatsApp não funciona; mas a configuração em si pode ser feita antes do deploy via variável de ambiente.
Independent Test: Verificar se alternar o número de WhatsApp na configuração reflete imediatamente nos links gerados nos cards de imóvel.
Acceptance Scenarios:
- Given o admin acessa as configurações do sistema, When define ou altera o número de WhatsApp, Then os novos links gerados nos cards de imóvel usam o número atualizado.
- Given o número é definido via variável de ambiente
WHATSAPP_NUMBER, When o sistema é iniciado, Then esse número é utilizado como padrão se não houver configuração salva no banco.
User Story 6 - Visualizar Leads no Painel Admin (Priority: P2)
O administrador pode visualizar, filtrar e exportar a lista de leads gerados pelos formulários de contato, com informação do imóvel associado.
Why this priority: Sem visibilidade dos leads, o objetivo de negócio de captação não se completa.
Independent Test: Verificar se leads aparecem no painel admin com os dados corretos e se os filtros por imóvel e por data funcionam.
Acceptance Scenarios:
- Given o admin acessa a seção de leads no painel, When visualiza a lista, Then vê todos os leads com: nome, e-mail, telefone, mensagem, código do imóvel associado e data de criação.
- Given o admin deseja encontrar leads de um imóvel específico, When filtra pelo código ou ID do imóvel, Then apenas os leads daquele imóvel são exibidos.
- Given o admin visualiza um lead, When clica para ver detalhes, Then vê todas as informações do lead e um link para o imóvel correspondente.
Functional Requirements
- O botão "Entre em Contato" deve ser exibido nos componentes
PropertyRowCardePropertyCard, com destaque visual adequado ao design existente (Linear dark theme). - Ao clicar no botão, um modal deve ser aberto apresentando duas opções: "Formulário de Contato" e "WhatsApp".
- O formulário de contato deve conter os campos: nome (obrigatório), e-mail (obrigatório), telefone (opcional) e mensagem (obrigatório, pré-preenchida com o código do imóvel).
- O envio do formulário deve criar um
ContactLeadno banco de dados com oproperty_iddo imóvel correspondente, via endpoint existentePOST /api/v1/properties/<slug>/contact. - O campo de mensagem deve ser pré-preenchido com o texto: "Tenho interesse no imóvel de código {CÓDIGO}. Poderia me dar mais informações?".
- A opção WhatsApp deve gerar um link
wa.me/{NUMERO}?text={MENSAGEM_CODIFICADA}que seja aberto em nova aba. - A mensagem pré-preenchida para o WhatsApp deve conter: "Olá! Tenho interesse no imóvel de código {CÓDIGO}. Poderia me dar mais informações?".
- O número de WhatsApp deve ser lido prioritariamente de uma configuração no banco de dados; como fallback, da variável de ambiente
WHATSAPP_NUMBER. - Quando o número de WhatsApp não estiver configurado, a opção WhatsApp deve ser desabilitada visualmente com mensagem informativa.
- O backend deve expor um endpoint
GET /api/v1/config/whatsapp(sem autenticação) que retorna o número de WhatsApp configurado (ounull), para que o frontend possa exibir ou desabilitar a opção. - O modal deve ser fechável clicando fora dele ou em um botão "X".
- O formulário deve exibir mensagens de erro inline para campos inválidos, sem recarregar a página.
- Após envio bem-sucedido, o formulário deve exibir mensagem de confirmação e fechar automaticamente após breve intervalo.
- Em caso de erro no envio, o formulário deve exibir mensagem de erro amigável e manter os dados preenchidos.
- O painel admin deve listar os leads captados com: nome, e-mail, telefone, mensagem, imóvel associado (código e link) e data de criação.
- A listagem de leads no admin deve suportar paginação e filtro pelo imóvel associado.
Non-Functional Requirements
- O modal deve abrir em até 200 ms após o clique no botão (experiência percebida como instantânea).
- O envio do formulário deve completar em até 3 segundos em condições normais de rede.
- O link do WhatsApp deve ser gerado no lado do cliente, sem round-trip ao servidor.
- O botão "Entre em Contato" deve ser acessível via teclado (foco visível, acionável com Enter/Space) e compatível com leitores de tela (atributo
aria-labeladequado). - O modal deve ser responsivo em todos os breakpoints (mobile, tablet, desktop).
- Nenhum dado pessoal do visitante deve ser carregado ou exibido antes do visitante interagir com o formulário.
- O endpoint
GET /api/v1/config/whatsappdeve retornar resposta em até 500 ms e pode ser cacheado no cliente por até 5 minutos.
Out of Scope
- Envio de e-mail de confirmação ao visitante após submissão do formulário (pode ser feature futura).
- Integração com CRM externo para sincronização de leads.
- Notificação em tempo real (push ou e-mail) ao admin quando um novo lead é criado.
- Edição ou exclusão de leads pelo admin (somente leitura no escopo desta feature).
- Rastreamento analítico de cliques no botão ou escolha de canal (pode ser feature futura).
- Suporte a múltiplos números de WhatsApp por imóvel ou por corretor.
- Formulário de contato na página de detalhe do imóvel (já implementado separadamente).
Key Entities
- ContactLead: id, property_id (FK → properties.id), name, email, phone, message, created_at — tabela
contact_leadsjá existe. - Property: id, code, slug, title — campo
codeusado como identificador legível na mensagem pré-preenchida. - WhatsApp Config: número de telefone do corretor no formato internacional (ex.:
5516999998888), armazenado em variável de ambienteWHATSAPP_NUMBERe/ou configuração no banco. - Modal de Contato: componente React com estado local controlando qual canal está selecionado e o ciclo de vida do formulário (idle → submitting → success/error).
Assumptions
- O endpoint
POST /api/v1/properties/<slug>/contactjá está implementado e funcional; esta feature apenas o consome no frontend. - O
codedo imóvel (campo numérico) está disponível no objetoPropertyretornado pela API de listagem e já está presente nos props dos componentes de card. - O design do botão e do modal seguirá o tema Linear dark já adotado no projeto.
- O número de WhatsApp será armazenado sem formatação, somente dígitos, no formato internacional sem
+(ex.:5516999998888). - A validação do formulário no frontend espelha as regras do schema Pydantic
ContactLeadInjá existente (nome ≥ 2 chars, e-mail válido, mensagem ≥ 10 chars, etc.). - A configuração do número de WhatsApp via admin (painel) será implementada como parte da feature 007 (Admin Panel) ou como extensão futura; neste escopo, o número é definido via variável de ambiente
WHATSAPP_NUMBER.