172 lines
13 KiB
Markdown
172 lines
13 KiB
Markdown
# 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**:
|
|
|
|
1. **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.
|
|
2. **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.
|
|
3. **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**:
|
|
|
|
1. **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".
|
|
2. **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.
|
|
3. **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**:
|
|
|
|
1. **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.").
|
|
2. **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.
|
|
3. **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.
|
|
4. **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.
|
|
5. **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.
|
|
6. **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**:
|
|
|
|
1. **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.
|
|
2. **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.
|
|
3. **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.
|
|
4. **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**:
|
|
|
|
1. **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.
|
|
2. **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**:
|
|
|
|
1. **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.
|
|
2. **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.
|
|
3. **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
|
|
|
|
1. O botão "Entre em Contato" deve ser exibido nos componentes `PropertyRowCard` e `PropertyCard`, com destaque visual adequado ao design existente (Linear dark theme).
|
|
2. Ao clicar no botão, um modal deve ser aberto apresentando duas opções: "Formulário de Contato" e "WhatsApp".
|
|
3. 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).
|
|
4. O envio do formulário deve criar um `ContactLead` no banco de dados com o `property_id` do imóvel correspondente, via endpoint existente `POST /api/v1/properties/<slug>/contact`.
|
|
5. 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?".
|
|
6. A opção WhatsApp deve gerar um link `wa.me/{NUMERO}?text={MENSAGEM_CODIFICADA}` que seja aberto em nova aba.
|
|
7. 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?".
|
|
8. 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`.
|
|
9. Quando o número de WhatsApp não estiver configurado, a opção WhatsApp deve ser desabilitada visualmente com mensagem informativa.
|
|
10. O backend deve expor um endpoint `GET /api/v1/config/whatsapp` (sem autenticação) que retorna o número de WhatsApp configurado (ou `null`), para que o frontend possa exibir ou desabilitar a opção.
|
|
11. O modal deve ser fechável clicando fora dele ou em um botão "X".
|
|
12. O formulário deve exibir mensagens de erro inline para campos inválidos, sem recarregar a página.
|
|
13. Após envio bem-sucedido, o formulário deve exibir mensagem de confirmação e fechar automaticamente após breve intervalo.
|
|
14. Em caso de erro no envio, o formulário deve exibir mensagem de erro amigável e manter os dados preenchidos.
|
|
15. 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.
|
|
16. 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-label` adequado).
|
|
- 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/whatsapp` deve 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_leads` já existe.
|
|
- **Property**: id, code, slug, title — campo `code` usado 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 ambiente `WHATSAPP_NUMBER` e/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>/contact` já está implementado e funcional; esta feature apenas o consome no frontend.
|
|
- O `code` do imóvel (campo numérico) está disponível no objeto `Property` retornado 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 `ContactLeadIn` já 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`.
|