17 KiB
Feature Specification: Área do Cliente
Feature Branch: 006-client-area
Created: 2026-04-13
Status: Draft
Depends On: Feature 005 (Autenticação de Clientes — ClientUser model e JWT middleware)
User Scenarios & Testing (mandatory)
User Story 1 — Favoritar e Desfavoritar Imóvel (Priority: P1)
Um cliente autenticado pode favoritar um imóvel a partir do card ou da página de detalhes. O estado do botão de coração é persistido no backend e permanece entre sessões.
Why this priority: Favoritos é o recurso mais imediato de retenção do usuário na plataforma. Incentiva o retorno e aumenta o tempo de sessão.
Independent Test: Pode ser testado de forma isolada ao verificar que um cliente autenticado consegue adicionar e remover um imóvel de favoritos, e que ao recarregar a página o estado é mantido.
Acceptance Scenarios:
- Given o cliente está autenticado e navega pelo catálogo, When clica no botão de coração em um PropertyCard, Then o imóvel é adicionado aos favoritos, o coração fica preenchido e a ação é persistida na API.
- Given o imóvel já está favoritado, When o cliente clica no coração novamente, Then o imóvel é removido dos favoritos, o coração fica vazio e o backend reflete a remoção.
- Given o cliente não está autenticado, When clica no coração, Then é redirecionado para a página de login e, após autenticar, retorna ao imóvel.
- Given o cliente já favoritou o mesmo imóvel, When uma segunda requisição de adição é enviada, Then o sistema retorna 409 sem duplicar o registro.
User Story 2 — Página de Favoritos (Priority: P2)
Um cliente autenticado acessa /area-do-cliente/favoritos e visualiza todos os imóveis que marcou como favoritos, podendo desfavoritar diretamente da lista.
Why this priority: Sem a página de favoritos o botão de coração não tem destino, tornando o recurso incompleto do ponto de vista do usuário.
Independent Test: Pode ser testado verificando que a página exibe corretamente todos os imóveis favoritados e permite removê-los da lista.
Acceptance Scenarios:
- Given o cliente possui imóveis favoritados, When acessa
/area-do-cliente/favoritos, Then vê uma grade de PropertyCards com botão de desfavoritar em cada um. - Given o cliente não possui nenhum favorito, When acessa a página, Then vê o estado vazio: "Nenhum favorito ainda".
- Given o cliente clica para desfavoritar na página de favoritos, When a remoção é confirmada, Then o card desaparece da lista sem recarregar a página inteira.
- Given o cliente não está autenticado, When acessa a rota diretamente, Then é redirecionado para a página de login.
User Story 3 — Painel Principal (Dashboard) (Priority: P3)
Um cliente autenticado acessa /area-do-cliente e vê um painel de resumo com contadores e atalhos para as seções da área do cliente.
Why this priority: É o ponto de entrada da área do cliente; sem ele o usuário não tem orientação após o login.
Independent Test: Pode ser testado verificando que os contadores exibidos refletem dados reais do cliente (favoritos, visitas pendentes, boletos ativos).
Acceptance Scenarios:
- Given o cliente está autenticado, When acessa
/area-do-cliente, Then vê cards de resumo mostrando: total de favoritos, visitas pendentes e boletos ativos. - Given o cliente clica em um card de resumo (ex.: "Favoritos"), Then é navegado para a subseção correspondente.
- Given todos os contadores estão zerados, When o cliente acessa o painel, Then os cards exibem "0" sem mensagens de erro.
User Story 4 — Comparar Imóveis (Priority: P4)
Um cliente pode adicionar até 3 imóveis a uma lista de comparação e visualizar uma tabela lado a lado em /area-do-cliente/comparar. A seleção é mantida localmente durante a sessão.
Why this priority: Recurso diferencial que ajuda na decisão de compra; não requer autenticação de dados no backend, sendo implementável de forma autônoma.
Independent Test: Pode ser testado verificando a barra flutuante de comparação, adição/remoção de imóveis e a renderização correta da tabela comparativa.
Acceptance Scenarios:
- Given o cliente visualiza um imóvel no catálogo, When clica em "Comparar", Then o imóvel é adicionado à barra flutuante de comparação no rodapé da tela.
- Given o cliente já tem 3 imóveis na comparação, When tenta adicionar um quarto, Then recebe uma mensagem informando que o limite de 3 imóveis foi atingido e não ocorre adição.
- Given o cliente tem ao menos 1 imóvel na barra, When clica em "Ver Comparação" ou acessa
/area-do-cliente/comparar, Then vê uma tabela com colunas por imóvel e linhas para: preço, área, quartos, banheiros, vagas, condomínio, tipo, bairro e comodidades. - Given o cliente clica em "Remover" em uma coluna da tabela, Then o imóvel é removido e a tabela é atualizada.
- Given o cliente recarrega a página, Then os imóveis selecionados para comparação são restaurados do armazenamento local.
- Given a lista de comparação está vazia e o cliente acessa
/area-do-cliente/comparar, Then vê estado vazio com sugestão de selecionar imóveis do catálogo.
User Story 5 — Histórico de Visitas (Priority: P5)
Um cliente autenticado acessa /area-do-cliente/visitas e visualiza o histórico de solicitações de visita com status atual.
Why this priority: Permite ao cliente acompanhar suas solicitações, reduzindo contato direto e dúvidas recorrentes para a equipe de vendas.
Independent Test: Pode ser testado verificando que as visitas criadas ao submeter o formulário de contato (como usuário logado) aparecem listadas com os status corretos.
Acceptance Scenarios:
- Given o cliente possui visitas cadastradas, When acessa
/area-do-cliente/visitas, Then vê uma lista cronológica com: imóvel vinculado, mensagem enviada, status atual (badge colorido) e data agendada (quando confirmada). - Given o status de uma visita é alterado pelo admin, When o cliente recarrega a página, Then o novo status é refletido.
- Given o cliente não tem nenhuma visita, When acessa a página, Then vê "Nenhuma visita agendada".
- Given o cliente está autenticado e submete o formulário de contato na página de um imóvel, When a solicitação é enviada, Then uma VisitRequest é criada com status "pending" e aparece no histórico.
User Story 6 — Boletos (Priority: P6)
Um cliente autenticado acessa /area-do-cliente/boletos e visualiza os boletos criados pelo admin, podendo acessar o link de pagamento ou baixar o PDF.
Why this priority: Acesso a boletos é funcionalidade financeira crítica para clientes em processo de locação ou compra.
Independent Test: Pode ser testado com boletos criados diretamente via API de admin, verificando listagem e acesso ao link.
Acceptance Scenarios:
- Given o cliente possui boletos vinculados, When acessa
/area-do-cliente/boletos, Then vê uma tabela com: imóvel (quando vinculado), descrição, valor, vencimento, badge de status e botão para acessar o boleto. - Given o cliente clica no botão de acesso ao boleto, Then é aberto o link/URL do boleto em nova aba.
- Given o boleto está com status "paid", Then o badge exibe "Pago" em cor distinta dos demais status.
- Given o cliente não possui boletos, When acessa a página, Then vê "Nenhum boleto disponível".
User Story 7 — Admin cria Boleto via API (Priority: P7)
Um administrador autentica na API e cria um boleto para um cliente, opcionalmente vinculado a um imóvel.
Why this priority: Backend necessário para suportar a P6; não há UI de admin no MVP.
Independent Test: Pode ser testado diretamente via chamada à API POST /api/v1/admin/boletos com token de admin.
Acceptance Scenarios:
- Given o admin envia POST
/api/v1/admin/boletoscom os campos obrigatórios, Then o boleto é criado com status "pending" e retorna 201 com os dados do boleto. - Given o campo
user_idnão corresponde a um ClientUser existente, Then a API retorna 404. - Given campos obrigatórios estão ausentes (user_id, description, amount, due_date), Then a API retorna 422.
User Story 8 — Admin atualiza status de Visita via API (Priority: P8)
Um administrador atualiza o status de uma solicitação de visita e opcionalmente define a data/hora agendada.
Why this priority: Necessário para o ciclo completo de visitas; sem esta operação o cliente nunca vê status diferente de "pending".
Independent Test: Pode ser testado via PUT /api/v1/admin/visits/<id>/status e verificando a mudança no retorno de GET /api/v1/me/visits.
Acceptance Scenarios:
- Given o admin envia PUT
/api/v1/admin/visits/<id>/statuscom{"status": "confirmed", "scheduled_at": "2026-05-01T10:00:00"}, Then a VisitRequest é atualizada e retorna 200. - Given o id não existe, Then retorna 404.
- Given o valor de
statusnão é um dos permitidos (pending/confirmed/cancelled/completed), Then retorna 422.
Edge Cases
- O que acontece quando o cliente tenta favoritar um imóvel que foi removido/desativado do catálogo? O registro SavedProperty permanece; o imóvel é exibido com indicação "Imóvel indisponível" ou omitido da listagem de favoritos.
- O que acontece com a comparação se um dos imóveis armazenados no localStorage deixar de existir? A aplicação ignora silenciosamente o id inválido ao carregar e exibe apenas os imóveis válidos.
- O que acontece quando a VisitRequest é criada e o cliente posteriormente envia o contato como anônimo (para o mesmo imóvel)? O ContactLead é criado normalmente (usuário anônimo) sem afetar a VisitRequest existente.
- O que acontece com boletos cujo
urlé nulo? O botão de acesso é desabilitado ou ocultado; o boleto ainda aparece na listagem. - O que acontece se o token JWT expirar durante a navegação na área do cliente? O Axios interceptor (feature 005) redireciona para o login; a rota protegida bloqueia o acesso.
Requirements (mandatory)
Functional Requirements
Favoritos
- FR-001: O sistema DEVE permitir que clientes autenticados adicionem imóveis à lista de favoritos; tentativas de adicionar um imóvel já favoritado DEVEM retornar 409.
- FR-002: O sistema DEVE permitir que clientes autenticados removam imóveis da lista de favoritos; tentativas de remover um imóvel não favoritado DEVEM retornar 404.
- FR-003: A lista de favoritos de um cliente DEVE ser persistida no backend e recuperada entre sessões.
- FR-004: O botão de coração DEVE refletir o estado de favorito do imóvel para o cliente autenticado corrente.
Comparação
- FR-005: A aplicação DEVE permitir que o usuário adicione até 3 imóveis à lista de comparação; a adição de um quarto imóvel DEVE ser bloqueada com mensagem de feedback.
- FR-006: A lista de comparação DEVE ser persistida no armazenamento local do navegador e restaurada ao recarregar a página.
- FR-007: A página de comparação DEVE exibir uma tabela lado a lado com as seguintes características: preço, área, quartos, banheiros, vagas, condomínio, tipo, bairro e comodidades.
- FR-008: Uma barra flutuante de comparação DEVE ser exibida no rodapé sempre que houver ao menos 1 imóvel na lista.
Painel do Cliente
- FR-009: A rota
/area-do-clienteDEVE exibir cards de resumo com o total de favoritos, o número de visitas com status "pending" e o número de boletos com status "pending". - FR-010: Todas as rotas sob
/area-do-clienteDEVEM ser protegidas; clientes não autenticados DEVEM ser redirecionados para o login.
Visitas
- FR-011: A rota
/area-do-cliente/visitasDEVE exibir todas as VisitRequests do cliente autenticado, ordenadas por data de criação decrescente. - FR-012: Ao submeter o formulário de contato na página de detalhes de um imóvel, se o usuário estiver autenticado, o sistema DEVE criar uma VisitRequest vinculada ao cliente além do ContactLead.
- FR-013: O admin DEVE poder atualizar o status de uma VisitRequest via API, incluindo opcionalmente a data/hora agendada.
Boletos
- FR-014: A rota
/area-do-cliente/boletosDEVE exibir todos os boletos do cliente autenticado, ordenados por data de vencimento decrescente. - FR-015: O admin DEVE poder criar boletos para qualquer cliente via API, com ou sem vínculo a um imóvel.
- FR-016: Boletos com
urlpreenchida DEVEM exibir um botão de acesso; boletos semurlDEVEM exibir o botão desabilitado.
API
- FR-017: Todas as rotas sob
/api/v1/me/DEVEM exigir token JWT válido de ClientUser; ausência ou token inválido DEVE retornar 401. - FR-018: Todas as rotas sob
/api/v1/admin/DEVEM exigir autenticação de admin; acesso com token de ClientUser DEVE retornar 403.
Key Entities
- SavedProperty: Associação entre um cliente e um imóvel favoritado. Atributos: identificador único, referência ao cliente, referência ao imóvel, data de criação. Unicidade garantida por par (cliente, imóvel).
- VisitRequest: Solicitação de visita feita por um cliente para um imóvel. Atributos: identificador único, referência ao cliente, referência ao imóvel, mensagem livre, status do fluxo (pendente/confirmado/cancelado/concluído), data/hora agendada (opcional), data de criação.
- Boleto: Documento de cobrança criado pelo admin para um cliente, opcionalmente vinculado a um imóvel. Atributos: identificador único, referência ao cliente, referência ao imóvel (opcional), descrição, valor monetário, data de vencimento, status (pendente/pago/vencido), URL de acesso (opcional), data de criação.
- ComparisonList (frontend): Lista temporária de até 3 imóveis selecionados para comparação. Armazenada localmente no navegador; não persiste no backend.
API Contract
Todas as rotas requerem
Authorization: Bearer <token>(client JWT, exceto rotas/admin/que requerem token de admin).
| Método | Rota | Corpo / Parâmetros | Respostas |
|---|---|---|---|
| GET | /api/v1/me/favorites |
— | 200: [{property completo}] · 401 |
| POST | /api/v1/me/favorites |
{property_id} |
201 · 409 se já favoritado · 401 · 404 se imóvel não existe |
| DELETE | /api/v1/me/favorites/<property_id> |
— | 204 · 404 · 401 |
| GET | /api/v1/me/visits |
— | 200: [{id, property:{id,title,slug}, message, status, scheduled_at, created_at}] · 401 |
| GET | /api/v1/me/boletos |
— | 200: [{id, description, amount, due_date, status, url}] · 401 |
| POST | /api/v1/admin/boletos |
{user_id, property_id?, description, amount, due_date, url?} |
201: boleto criado · 404 cliente não existe · 422 campos inválidos · 401/403 |
| PUT | /api/v1/admin/visits/<id>/status |
{status, scheduled_at?} |
200: visita atualizada · 404 · 422 status inválido · 401/403 |
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: Clientes autenticados conseguem favoritar e desfavoritar imóveis em menos de 2 segundos por ação, com estado persistido entre sessões.
- SC-002: A tabela de comparação é renderizada em menos de 1 segundo para até 3 imóveis; a seleção é restaurada corretamente ao recarregar a página.
- SC-003: 100% das rotas da área do cliente bloqueiam acesso não autenticado, redirecionando para o login sem expor dados.
- SC-004: O painel exibe contadores precisos — favoritos, visitas pendentes e boletos ativos — sem discrepâncias em relação ao banco de dados.
- SC-005: Clientes conseguem localizar e acessar um boleto em até 3 cliques a partir do painel principal.
- SC-006: Todas as mudanças de status de visita feitas pelo admin refletem no painel do cliente na próxima atualização de página.
- SC-007: O formulário de contato na página de detalhes, quando submetido por cliente autenticado, cria a VisitRequest e ela aparece imediatamente no histórico de visitas.
Assumptions
- O modelo
ClientUsere o middleware de autenticação JWT (Feature 005) são pré-requisitos e estarão disponíveis antes da implementação desta feature. - O admin não terá uma interface gráfica no MVP; operações de admin (criação de boletos e atualização de status de visita) são executadas diretamente via API.
- Boletos são gerados externamente; o sistema apenas armazena e exibe o link/URL de acesso. Nenhuma integração com gateway de pagamento é necessária no MVP.
- A comparação de imóveis não será persistida no backend; usar armazenamento local do navegador é suficiente para os requisitos do MVP.
- Uma VisitRequest é criada somente quando o cliente está autenticado. Usuários anônimos continuam gerando ContactLeads sem criar VisitRequests.
- O status de boletos pode ser atualizado manualmente pelo admin via chamada à API (implícito no PUT /api/v1/admin/boletos/) o que fica como extensão futura; no MVP o status só é definido na criação.
- O design de todos os componentes segue o tema Linear dark definido em
DESIGN.md(fundo#08090a, acento#5e6ad2/#7170ff). - A lista de favoritos retornada pela API inclui todos os detalhes do imóvel necessários para renderização do PropertyCard, sem chamadas adicionais.