sass-imobiliaria/specs/027-config-pagina-contato/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

12 KiB

Feature Specification: Configuração da Página de Contato (Admin)

Feature Branch: 027-config-pagina-contato Created: 2026-04-21 Status: Draft


Contexto

A página /contato do site exibe informações institucionais de contato — endereço, telefone, e-mail e horário de atendimento — atualmente fixadas no código-fonte do frontend. Qualquer alteração nessas informações exige um deploy de código, o que cria dependência técnica para uma tarefa puramente operacional.

Esta spec cobre a criação de uma configuração persistida em banco de dados que o administrador pode editar pelo painel admin, tornando o conteúdo da página de contato dinâmico e gerenciável sem necessidade de deploy.

O padrão adotado é o mesmo já utilizado para a HomepageConfig: tabela singleton (sempre id = 1), endpoint público de leitura e endpoint protegido de escrita acessível apenas por administradores autenticados.


User Scenarios & Testing

User Story 1 — Administrador Atualiza as Informações de Contato (Priority: P1)

O administrador da imobiliária precisa atualizar o endereço, telefone, e-mail ou horário de atendimento sem depender de um desenvolvedor ou deploy de código.

Why this priority: É o núcleo da feature. Sem a capacidade de edição pelo admin, todo o restante não tem valor.

Independent Test: Autenticar como administrador, acessar a página de configuração de contato no painel admin (/admin/contact-config), alterar o campo de telefone para um novo valor e salvar. Verificar que a resposta da API pública GET /api/v1/contact-config retorna o novo valor e que a página /contato do site exibe o telefone atualizado após recarregar.

Acceptance Scenarios:

  1. Given um administrador autenticado no painel admin, When ele acessa /admin/contact-config, Then um formulário é exibido com os valores atuais dos campos de endereço, telefone, e-mail e horário de atendimento já preenchidos.
  2. Given o formulário preenchido com os valores atuais, When o admin altera o campo de telefone e clica em "Salvar", Then as alterações são persistidas e uma mensagem de sucesso é exibida na tela.
  3. Given que a configuração foi salva com sucesso, When a API pública de configuração de contato é consultada, Then ela retorna os novos valores imediatamente, sem necessidade de reiniciar o sistema.
  4. Given um administrador autenticado, When ele tenta salvar o formulário com o campo de e-mail em branco, Then o campo é destacado com erro de validação e o envio é bloqueado.
  5. Given um administrador autenticado, When ele tenta salvar com um endereço de e-mail em formato inválido, Then o campo é destacado com erro de validação antes do envio ser processado.

User Story 2 — Página de Contato Exibe Informações Dinâmicas (Priority: P1)

Um visitante do site acessa a página /contato e vê as informações de contato mais recentes cadastradas pelo administrador, sem nenhuma interação adicional necessária.

Why this priority: É o consumidor final da configuração. Sem a integração com a API, a feature não entrega valor ao visitante nem à imobiliária.

Independent Test: Com uma configuração de contato salva via painel admin, acessar /contato sem autenticação e verificar que o endereço, telefone, e-mail e horário de atendimento exibidos correspondem exatamente aos valores salvos — e não aos dados anteriormente fixados no código.

Acceptance Scenarios:

  1. Given uma configuração de contato salva no sistema, When qualquer visitante acessa /contato, Then a página exibe o endereço (rua, bairro/cidade e CEP), telefone, e-mail e horário de atendimento provenientes da API.
  2. Given que o administrador atualizou o horário de atendimento, When um visitante recarrega /contato, Then o novo horário é exibido imediatamente.
  3. Given que a API de configuração de contato está indisponível, When um visitante acessa /contato, Then a página exibe um estado de carregamento ou uma mensagem informativa, sem exibir dados desatualizados ou causar erro de renderização crítico.
  4. Given um visitante não autenticado, When ele acessa a rota pública GET /api/v1/contact-config diretamente, Then a resposta retorna os dados de configuração sem exigir autenticação.

User Story 3 — Proteção do Endpoint de Edição (Priority: P1)

Apenas administradores autenticados podem alterar a configuração de contato. Tentativas não autorizadas são bloqueadas.

Why this priority: Segurança é requisito não-negociável para qualquer endpoint de escrita no painel admin. O impacto de um acesso não autorizado incluiria exibição de informações falsas para todos os visitantes do site.

Independent Test: Enviar uma requisição PUT /admin/contact-config sem token de autenticação (ou com token de usuário comum) e verificar que a resposta é HTTP 401 ou 403. Verificar também que os dados salvos no banco não foram alterados.

Acceptance Scenarios:

  1. Given uma requisição PUT /admin/contact-config sem token de autenticação, When a requisição é processada, Then o sistema responde com erro de acesso não autorizado (HTTP 401) e não altera nenhum dado.
  2. Given uma requisição PUT /admin/contact-config com um token de usuário comum (não administrador), When a requisição é processada, Then o sistema responde com erro de permissão insuficiente (HTTP 403) e não altera nenhum dado.
  3. Given uma requisição PUT /admin/contact-config com token de administrador válido, When os dados enviados são válidos, Then a configuração é atualizada e o sistema retorna os dados atualizados (HTTP 200).

Edge Cases

  • O que acontece se a tabela contact_config estiver vazia (nenhuma configuração foi salva ainda)? O endpoint público deve retornar valores padrão pré-populados ou um erro?
  • Como a página /contato se comporta durante o carregamento inicial enquanto aguarda a resposta da API?
  • O que acontece se o campo business_hours for enviado com um texto excessivamente longo?
  • Como o formulário admin lida com falha de rede ao tentar salvar — o usuário perde as alterações não salvas?
  • O que acontece se dois administradores tentarem salvar a configuração simultaneamente?

Requirements

Functional Requirements

Grupo 1 — Dados e Persistência

  • FR-001: O sistema DEVE armazenar as informações de configuração de contato em uma tabela singleton de forma que exista sempre exatamente um registro com id = 1, criado automaticamente na primeira leitura ou escrita caso ainda não exista.
  • FR-002: A configuração DEVE incluir os seguintes campos: logradouro do endereço, complemento de bairro/cidade, CEP, telefone, e-mail e horário de atendimento (texto livre multilinha).
  • FR-003: Todos os campos DEVEM ser obrigatórios — nenhum pode ser salvo como nulo ou vazio.
  • FR-004: O campo de e-mail DEVE ser validado quanto ao formato antes de ser persistido.
  • FR-005: O sistema DEVE registrar automaticamente a data e hora da última atualização da configuração.

Grupo 2 — API Pública de Leitura

  • FR-006: O sistema DEVE disponibilizar um endpoint público de leitura de configuração de contato acessível sem autenticação.
  • FR-007: O endpoint público DEVE retornar todos os campos da configuração em formato estruturado (um objeto com os campos nomeados).
  • FR-008: O endpoint público DEVE retornar os valores padrão (correspondentes aos dados atualmente fixados no código) caso nenhuma configuração tenha sido salva ainda, em vez de retornar erro.

Grupo 3 — API Protegida de Escrita

  • FR-009: O sistema DEVE disponibilizar um endpoint protegido de atualização de configuração de contato acessível apenas por administradores autenticados.
  • FR-010: O endpoint protegido DEVE rejeitar requisições sem token de autenticação válido com HTTP 401.
  • FR-011: O endpoint protegido DEVE rejeitar tokens de usuários com perfil diferente de administrador com HTTP 403.
  • FR-012: O endpoint protegido DEVE validar todos os campos recebidos antes de persistir e retornar erros de validação específicos por campo em caso de dados inválidos (HTTP 422).
  • FR-013: Após persistência bem-sucedida, o endpoint DEVE retornar os dados atualizados incluindo a data de última atualização.

Grupo 4 — Interface Admin

  • FR-014: O painel admin DEVE disponibilizar uma página de edição de configuração de contato (/admin/contact-config) acessível apenas a administradores autenticados.
  • FR-015: A página admin DEVE carregar automaticamente os valores atuais da configuração ao ser aberta e pré-preencher o formulário.
  • FR-016: O formulário DEVE conter campos de texto para logradouro, bairro/cidade, CEP, telefone, e-mail e uma área de texto para horário de atendimento.
  • FR-017: O formulário DEVE exibir erros de validação inline por campo antes de tentar salvar no servidor, quando possível (ex.: e-mail com formato inválido, campo obrigatório vazio).
  • FR-018: O formulário DEVE exibir uma notificação de sucesso após salvar com êxito e uma notificação de erro em caso de falha na requisição ao servidor.
  • FR-019: O botão de salvar DEVE ser desabilitado enquanto a requisição de salvamento estiver em andamento, para evitar submissões duplicadas.

Grupo 5 — Página Pública de Contato

  • FR-020: A página /contato DEVE buscar as informações de contato da API pública em vez de usar valores fixados no código.
  • FR-021: A página /contato DEVE exibir um indicador de carregamento enquanto aguarda a resposta da API.
  • FR-022: A página /contato DEVE continuar renderizando normalmente em caso de falha na API, exibindo uma mensagem informativa no lugar das informações de contato.
  • FR-023: A estrutura visual e o layout da página /contato NÃO DEVEM ser alterados por esta feature — apenas a origem dos dados muda.

Key Entities

  • ContactConfig: Registro singleton de configuração de contato da imobiliária. Atributos: logradouro, bairro/cidade, CEP, telefone, e-mail, horário de atendimento (texto multilinha), data de última atualização. Relacionamentos: nenhum — é uma entidade independente de configuração.

Success Criteria

Measurable Outcomes

  • SC-001: O administrador consegue atualizar qualquer campo de contato em menos de 1 minuto, do acesso à página admin até a confirmação de salvamento.
  • SC-002: A página /contato reflete as alterações feitas pelo admin imediatamente após o recarregamento da página, sem necessidade de nenhuma intervenção técnica.
  • SC-003: 100% das tentativas de acesso não autenticado ao endpoint de escrita são bloqueadas com resposta de erro apropriada.
  • SC-004: A página /contato permanece funcional e renderizável mesmo quando a API de configuração retorna erro, sem quebrar a experiência do visitante.
  • SC-005: Nenhum campo de configuração de contato permanece fixado no código-fonte do frontend após a conclusão da feature.

Assumptions

  • O padrão singleton (get_or_create com id = 1) já é conhecido e usado na codebase (HomepageConfig); esta feature segue exatamente o mesmo padrão.
  • Os valores padrão (usados como fallback quando nenhuma configuração existe) são os atualmente hardcoded na página /contato: endereço "Rua das Imobiliárias, 123 / Centro — São Paulo, SP / CEP 01000-000", telefone "(11) 99999-0000", e-mail "contato@imobiliariahub.com.br" e horário conforme texto atual.
  • O mecanismo de autenticação e autorização de admin (require_admin) já existe e será reutilizado sem modificações.
  • Não há necessidade de histórico de versões da configuração — apenas o valor atual importa.
  • O campo business_hours é texto livre; a formatação de exibição (ex.: quebras de linha) é responsabilidade do componente de apresentação, não da API.
  • Esta feature não altera o design, layout ou demais seções da página /contato — apenas substitui os dados hardcoded por dados dinâmicos.
  • A migração de banco de dados para criar a tabela contact_config será gerada via Alembic, seguindo o padrão já adotado no projeto.
  • A seed inicial que popula a tabela com os valores padrão é opcional — o comportamento de fallback no endpoint público é suficiente para o primeiro acesso.