sass-imobiliaria/specs/026-central-contatos/spec.md
MatheusAlves96 cf5603243c
Some checks failed
CI/CD → Deploy via SSH / Build & Push Docker Images (push) Successful in 1m0s
CI/CD → Deploy via SSH / Deploy via SSH (push) Successful in 4m35s
CI/CD → Deploy via SSH / Validate HTTPS & Endpoints (push) Failing after 46s
feat: features 025-032 - favoritos, contatos, trabalhe-conosco, area-cliente, navbar, hero-light-dark, performance-homepage
- feat(025): favoritos locais com FavoritesContext, HeartButton, PublicFavoritesPage
- feat(026): central de contatos admin (leads/contatos unificados)
- feat(027): configuração da página de contato via admin
- feat(028): trabalhe conosco - candidaturas com upload e admin
- feat(029): UX área do cliente - visitas, comparação, perfil
- feat(030): navbar UX - menu mobile, ThemeToggle, useFavorites
- feat(031): hero light/dark - imagens separadas por tema, upload, preview, seed
- feat(032): performance homepage - Promise.all parallel fetches, sessionStorage cache,
  preload hero image, loading=lazy nos cards, useInView hook, will-change carrossel,
  keyframes em index.css, AgentsCarousel e HomeScrollScene via props
- fix: light mode HomeScrollScene - gradiente, cores de texto, scroll hint

migrations: g1h2i3j4k5l6 (source em leads), h1i2j3k4l5m6 (contact_config),
            i1j2k3l4m5n6 (job_applications), j2k3l4m5n6o7 (hero theme images)
2026-04-22 22:35:17 -03:00

19 KiB

Feature Specification: Central de Contatos com Rastreamento de Origem

Feature Branch: 026-central-contatos Created: 2026-04-21 Status: Draft


Contexto

O sistema já possui um mecanismo básico de captura de leads: visitantes podem enviar mensagens a partir da página de detalhes de um imóvel, e esses registros são armazenados como ContactLead. No entanto, a origem de cada contato não é rastreada, o formulário de contato geral na navbar aponta para uma âncora na homepage (sem página própria) e não existe uma página para proprietários interessados em anunciar seus imóveis.

Esta spec cobre a criação de uma Central de Contatos unificada com três origens rastreáveis: formulário público de contato geral (/contato), formulário de cadastro de residência para anúncio (/cadastro-residencia), e o formulário de contato de imóvel já existente. Inclui também a página de administração consolidada para visualizar e filtrar todos os leads por origem, e a correção dos links da navbar para destinos internos.


User Scenarios & Testing

User Story 1 — Visitante Envia Contato Geral via /contato (Priority: P1)

Um visitante do site que deseja tirar dúvidas, solicitar informações ou propor parceria quer enviar uma mensagem para a imobiliária sem precisar acessar a página de um imóvel específico.

Why this priority: É o ponto de contato principal do site. Atualmente a navbar aponta "Contato" para uma âncora que pode não estar visível, criando uma experiência frustrante. Disponibilizar uma página dedicada com formulário funcional é o requisito mínimo de contato da imobiliária.

Independent Test: Acessar /contato sem estar autenticado, preencher todos os campos obrigatórios (nome, e-mail, telefone, assunto, mensagem) e submeter. Verificar que a submissão é aceita com mensagem de confirmação e que o lead aparece na base com source = "contato".

Acceptance Scenarios:

  1. Given um visitante na página /contato, When ele preenche nome, e-mail, telefone, assunto e mensagem e clica em enviar, Then o formulário é submetido com sucesso, uma mensagem de confirmação é exibida e o visitante permanece na página.
  2. Given um visitante na página /contato, When ele submete o formulário sem preencher um campo obrigatório, Then o campo em falta é destacado com uma mensagem de erro inline e o formulário não é enviado.
  3. Given um visitante que submeteu o formulário com sucesso, When o lead é registrado no sistema, Then o campo source do registro é "contato" e source_detail fica vazio.
  4. Given um visitante na página /contato, When ele informa um e-mail com formato inválido, Then o campo e-mail é destacado com erro de validação antes do envio.
  5. Given um visitante na página /contato, When o assunto selecionado é "Anúncio", Then o formulário é submetido normalmente com o assunto incluído na mensagem registrada.

User Story 2 — Proprietário Cadastra Imóvel para Anúncio via /cadastro-residencia (Priority: P1)

Um proprietário de imóvel que deseja anunciá-lo através da imobiliária quer enviar os dados básicos do imóvel e suas informações de contato para que a equipe entre em contato e dê continuidade ao processo.

Why this priority: Representa uma fonte direta de captação de novos imóveis para o portfólio da imobiliária. Sem esse canal, proprietários interessados não têm caminho claro para iniciar o processo de anúncio.

Independent Test: Acessar /cadastro-residencia, preencher todos os campos (nome, e-mail, telefone, endereço, tipo de imóvel, área, finalidade, observações) e submeter. Verificar que o lead é criado com source = "cadastro_residencia" e que os detalhes do imóvel estão na mensagem ou no source_detail.

Acceptance Scenarios:

  1. Given um proprietário na página /cadastro-residencia, When ele preenche todos os campos e clica em enviar, Then o formulário é submetido com sucesso e uma mensagem de confirmação é exibida informando que a equipe entrará em contato.
  2. Given um proprietário na página /cadastro-residencia, When ele submete sem preencher campos obrigatórios (nome, e-mail, telefone, endereço, tipo e finalidade), Then os campos em falta são destacados com erros inline e o envio é bloqueado.
  3. Given um proprietário que submeteu o formulário com sucesso, When o lead é registrado, Then source é "cadastro_residencia" e source_detail contém informação identificável do imóvel (ex.: tipo + finalidade ou endereço).
  4. Given um proprietário na página /cadastro-residencia, When ele seleciona "Apartamento" como tipo e "Aluguel" como finalidade, Then esses valores são incluídos no registro enviado ao sistema.
  5. Given um proprietário na página /cadastro-residencia, When o campo "Área m²" recebe um valor não numérico, Then o campo é destacado com erro de validação e o envio é bloqueado.

User Story 3 — Visitante Envia Contato de Imóvel com Origem Rastreada (Priority: P2)

Um visitante interessado em um imóvel específico envia uma mensagem a partir da página de detalhes do imóvel. O sistema deve registrar automaticamente que o contato veio daquele imóvel específico, sem que o visitante precise fazer nada diferente.

Why this priority: O formulário de contato de imóvel já existe e funciona. A melhoria é transparente para o usuário e enriquece os dados para a equipe de vendas, que saberá exatamente qual imóvel gerou cada lead.

Independent Test: Acessar a página de detalhes de um imóvel (ex.: /imoveis/apartamento-centro), preencher e enviar o formulário de contato. Verificar que o lead criado possui source = "imovel" e source_detail com o título do imóvel.

Acceptance Scenarios:

  1. Given um visitante na página de detalhes de um imóvel, When ele preenche e envia o formulário de contato, Then o lead é criado com source = "imovel" e source_detail contendo o título do imóvel.
  2. Given um lead de imóvel criado com sucesso, When o administrador visualiza esse lead na central de leads, Then a coluna de origem exibe um badge "Imóvel" e o source_detail com o título do imóvel está visível.
  3. Given um visitante na página de detalhes, When o formulário de contato é exibido, Then a experiência visual e os campos do formulário permanecem idênticos — nenhuma mudança visível para o usuário.

User Story 4 — Administrador Visualiza e Filtra Leads na Central de Contatos (Priority: P1)

O administrador da imobiliária precisa de uma visão consolidada de todos os contatos recebidos — de qualquer origem — com a possibilidade de filtrar por tipo de origem para priorizar o atendimento.

Why this priority: Sem uma central unificada com filtros, a equipe não consegue distinguir leads de imóveis de propostas de parceria ou de proprietários querendo anunciar. O valor do rastreamento de origem só se materializa com uma interface de gestão adequada.

Independent Test: Acessar /admin/leads como administrador autenticado, verificar que leads das três origens aparecem na listagem. Aplicar filtro por "Cadastro de Residência" e verificar que apenas leads com source = "cadastro_residencia" são exibidos.

Acceptance Scenarios:

  1. Given um administrador autenticado acessando /admin/leads, When a página carrega, Then todos os leads são listados em ordem cronológica decrescente com as colunas: origem (badge colorido), nome, e-mail, telefone, prévia da mensagem e data.
  2. Given a listagem de leads, When o administrador seleciona o filtro "Imóvel", Then apenas leads com source = "imovel" são exibidos e o badge "Imóvel" aparece na coluna de origem de cada linha.
  3. Given a listagem de leads, When o administrador seleciona o filtro "Contato", Then apenas leads com source = "contato" são exibidos.
  4. Given a listagem de leads, When o administrador seleciona o filtro "Cadastro de Residência", Then apenas leads com source = "cadastro_residencia" são exibidos.
  5. Given a listagem de leads com filtro "Imóvel" ativo, When há leads com source_detail preenchido, Then o título do imóvel é exibido como detalhe do badge ou em coluna/tooltip separado.
  6. Given a listagem de leads, When o administrador seleciona "Todos", Then todos os leads de todas as origens são exibidos sem filtro.
  7. Given um não administrador (sem autenticação ou sem permissão), When tenta acessar /admin/leads, Then é redirecionado para a tela de login ou recebe resposta de acesso negado.
  8. Given a listagem de leads com muitos registros, When o limite de exibição por página é atingido, Then a navegação entre páginas ou carregamento adicional está disponível para acessar registros anteriores.

User Story 5 — Visitante Navega para /contato e /sobre via Navbar (Priority: P3)

Um visitante que clica em "Contato" ou "Sobre" na barra de navegação é levado diretamente às páginas internas correspondentes, sem âncoras ou rolagem forçada.

Why this priority: Corrige um problema de usabilidade existente. A navbar já tem os links; é apenas necessário atualizar os destinos para rotas internas corretas.

Independent Test: Na homepage (ou em qualquer outra página), clicar em "Contato" na navbar e verificar que a rota muda para /contato. Clicar em "Sobre" e verificar que a rota muda para /sobre.

Acceptance Scenarios:

  1. Given qualquer página do site com a navbar visível, When o visitante clica em "Contato", Then é navegado para /contato sem recarregar a página inteira.
  2. Given qualquer página do site com a navbar visível, When o visitante clica em "Sobre", Then é navegado para /sobre sem recarregar a página inteira.
  3. Given o visitante está em /contato, When a navbar é exibida, Then o link "Contato" aparece destacado como item ativo de navegação.

Edge Cases

  • O que acontece se o usuário submeter o formulário de /contato mais de uma vez seguida (duplo clique acidental)?
  • O que acontece se o servidor retornar erro ao salvar o lead — o usuário recebe feedback adequado?
  • O que acontece com leads criados antes da adição da coluna source — eles aparecem na listagem admin com origem "Desconhecida" ou ficam ocultos?
  • Como o sistema se comporta quando source_detail está vazio para leads de imóvel (caso de falha na captura do título)?
  • O que acontece se o campo "área m²" no formulário /cadastro-residencia receber um valor negativo?
  • Como a paginação da listagem admin se comporta quando um filtro é aplicado e o número total de resultados muda?
  • O que acontece se um visitante acessar /contato ou /cadastro-residencia em um dispositivo móvel — os formulários são responsivos?

Requirements

Functional Requirements

Grupo 1 — Rastreamento de Origem no Modelo de Lead

  • FR-001: O modelo de lead DEVE ter um campo source que identifica a origem do contato com os valores possíveis: "contato", "imovel" e "cadastro_residencia".
  • FR-002: O modelo de lead DEVE ter um campo source_detail opcional para registrar informação complementar da origem (ex.: título do imóvel, tipo + finalidade do imóvel anunciado).
  • FR-003: Todos os novos leads criados a partir desta feature DEVEM ter o campo source preenchido automaticamente de acordo com a origem do formulário que os gerou.
  • FR-004: Leads existentes criados antes desta feature (campo source ausente) NÃO DEVEM ser alterados retroativamente, mas DEVEM continuar acessíveis na listagem admin.

Grupo 2 — Página de Contato Geral (/contato)

  • FR-005: O sistema DEVE disponibilizar a rota pública /contato com um formulário de contato geral acessível sem autenticação.
  • FR-006: O formulário de contato DEVE conter os campos: nome (obrigatório), e-mail (obrigatório, formato válido), telefone (obrigatório), assunto (obrigatório, seleção entre: Informações, Anúncio, Parceria, Outro) e mensagem (obrigatória).
  • FR-007: A submissão bem-sucedida do formulário DEVE criar um lead com source = "contato" e exibir uma mensagem de confirmação ao usuário.
  • FR-008: O formulário DEVE validar todos os campos obrigatórios antes do envio e exibir mensagens de erro inline sem recarregar a página.
  • FR-009: Após uma submissão bem-sucedida, o botão de envio DEVE ser desabilitado ou o formulário resetado para evitar envio duplicado acidental.

Grupo 3 — Página de Cadastro de Residência (/cadastro-residencia)

  • FR-010: O sistema DEVE disponibilizar a rota pública /cadastro-residencia com formulário para proprietários interessados em anunciar um imóvel, acessível sem autenticação.
  • FR-011: O formulário de cadastro DEVE conter os campos: nome (obrigatório), e-mail (obrigatório, formato válido), telefone (obrigatório), endereço (obrigatório), tipo de imóvel (obrigatório, seleção entre: Casa, Apartamento, Comercial), área em m² (opcional, numérico positivo), finalidade (obrigatório, seleção entre: Venda, Aluguel) e observações/mensagem (opcional).
  • FR-012: A submissão bem-sucedida DEVE criar um lead com source = "cadastro_residencia", com source_detail contendo identificação do imóvel (tipo, finalidade e/ou endereço), e exibir confirmação ao usuário.
  • FR-013: O formulário DEVE validar todos os campos obrigatórios e o formato numérico do campo área antes do envio, com erros inline sem recarregar a página.

Grupo 4 — Atualização do Formulário de Contato de Imóvel

  • FR-014: O formulário de contato existente na página de detalhes de imóvel DEVE passar source = "imovel" ao criar o lead.
  • FR-015: O formulário de contato de imóvel DEVE passar source_detail com o título do imóvel ao criar o lead.
  • FR-016: A aparência e os campos do formulário de contato de imóvel NÃO DEVEM ser alterados — a mudança é exclusivamente no dado enviado ao backend.

Grupo 5 — Central de Leads Admin (/admin/leads)

  • FR-017: O sistema DEVE disponibilizar a rota protegida /admin/leads acessível apenas por usuários com perfil de administrador.
  • FR-018: A listagem DEVE exibir todos os leads em ordem cronológica decrescente com as colunas: origem (badge colorido), nome, e-mail, telefone, prévia da mensagem (truncada) e data de criação.
  • FR-019: Os badges de origem DEVEM ter cores distintas para cada valor de source: uma cor para "contato", outra para "imovel" e outra para "cadastro_residencia".
  • FR-020: Para leads com source = "imovel" e source_detail preenchido, o título do imóvel DEVE ser exibido de forma associada ao badge (ex.: tooltip, sublinha ou coluna adicional).
  • FR-021: A listagem DEVE oferecer um seletor de filtro por origem com as opções: Todos, Contato, Imóvel e Cadastro de Residência. A seleção de filtro DEVE atualizar a listagem sem recarregar a página.
  • FR-022: Leads cujo campo source está vazio (criados antes desta feature) DEVEM ser exibidos na listagem com um badge ou label indicando origem "Desconhecida" ao selecionar filtro "Todos".
  • FR-023: A listagem DEVE suportar paginação ou carregamento incremental para listas com grande volume de leads.

Grupo 6 — Navbar

  • FR-024: O link "Contato" na navbar DEVE navegar para a rota interna /contato.
  • FR-025: O link "Sobre" na navbar DEVE navegar para a rota interna /sobre.
  • FR-026: O link ativo na navbar DEVE ser destacado visualmente quando a rota atual corresponder ao destino do link.

Key Entities

  • Lead de Contato (ContactLead): Registro de interesse ou comunicação de um visitante. Atributos relevantes: identificador único, origem (source), detalhe de origem (source_detail), nome, e-mail, telefone, mensagem, data de criação. Pode ou não estar associado a um imóvel específico.
  • Origem (Source): Classificação do canal pelo qual o lead foi gerado. Valores fixos: "contato" (formulário geral), "imovel" (página de detalhes de imóvel), "cadastro_residencia" (formulário de anúncio de proprietário).
  • Detalhe de Origem (Source Detail): Informação livre associada à origem do lead. Para "imovel": título do imóvel. Para "cadastro_residencia": tipo, finalidade e/ou endereço do imóvel informado pelo proprietário.

Success Criteria

Measurable Outcomes

  • SC-001: Visitantes conseguem enviar um contato geral através de /contato em menos de 2 minutos a partir do primeiro acesso à página.
  • SC-002: Proprietários conseguem submeter o formulário de cadastro de residência em /cadastro-residencia em menos de 3 minutos.
  • SC-003: 100% dos leads criados a partir das páginas /contato, /cadastro-residencia e do formulário de imóvel contêm o campo source preenchido corretamente.
  • SC-004: O administrador consegue filtrar leads por origem e visualizar apenas os registros relevantes em menos de 5 segundos após selecionar o filtro.
  • SC-005: Os links "Contato" e "Sobre" da navbar levam às rotas corretas em 100% das navegações, sem âncoras intermediárias.
  • SC-006: Zero leads duplicados são criados por submissões acidentais de duplo clique nos formulários de /contato e /cadastro-residencia.
  • SC-007: A listagem de leads admin exibe corretamente leads de todas as origens, incluindo leads legados (sem source) sem erros ou omissões.

Assumptions

  • O modelo ContactLead já existe no banco de dados com as colunas id, property_id, name, email, phone, message e created_at; as colunas source e source_detail serão adicionadas via migration Alembic.
  • A coluna source aceita NULL para registros existentes criados antes da migration (compatibilidade retroativa sem valor padrão obrigatório).
  • O assunto selecionado no formulário /contato é incluído no campo message (compondo a mensagem) ou em um campo auxiliar — não requer nova coluna no modelo.
  • Os dados do formulário /cadastro-residencia são registrados como um único lead usando os campos existentes (name, email, phone, message) com detalhes do imóvel concatenados na mensagem e source_detail com identificação resumida.
  • A autenticação de administrador já existe no sistema; /admin/leads usa o mesmo mecanismo de proteção das demais rotas admin.
  • A rota GET /admin/leads existente será estendida para aceitar o parâmetro de filtro source e retornar leads com os novos campos; não é criada uma nova rota separada.
  • A paginação da listagem admin utiliza paginação simples por offset/limit ou infinite scroll — a escolha de implementação é deixada para a fase de planejamento.
  • Não há envio de e-mail de notificação à equipe da imobiliária como parte desta feature (pode ser adicionado em feature futura).
  • As páginas /contato e /cadastro-residencia são acessíveis publicamente sem autenticação, assim como as demais páginas públicas do site.
  • A navbar já possui os itens "Sobre" e "Contato" renderizados; apenas os href/destinos de roteamento serão atualizados.