sass-imobiliaria/.specify/features/006-client-area/research.md

5.5 KiB

Research: Área do Cliente (Feature 006)

Date: 2026-04-13 Status: Complete — todos os NEEDS CLARIFICATION resolvidos


1. Padrão de favoritos: backend vs. localStorage

Decisão: Favoritos persistidos no backend (tabela saved_properties). Rationale: Requisito explícito no spec (FR-003, SC-001): estado mantido entre sessões/dispositivos. localStorage não atende porque o usuário espera ver seus favoritos ao fazer login em outro dispositivo. Alternativas consideradas: localStorage com sync eventual — rejeitado; adiciona complexidade de sincronização sem benefício para o MVP.


2. Comparação: backend vs. localStorage

Decisão: Comparação persistida apenas em localStorage (chave imob_comparison). Rationale: Spec é explícito (FR-006, Assumptions): "usar armazenamento local do navegador é suficiente para os requisitos do MVP". Comparação é sessão temporária de decisão de compra, não dado de longo prazo. Alternativas consideradas: Persistir no backend com comparison_lists — rejeitado (YAGNI: nenhum requisito exige cross-device para comparação).


3. VisitRequest: criação automática via formulário de contato

Decisão: Integração opcional no MVP — apenas se o JWT válido estiver presente no header da requisição de contato. O endpoint POST /api/v1/properties/<slug>/contact cria VisitRequest quando autenticado; caso contrário, cria apenas ContactLead. Rationale: FR-012 e User Story 5 exigem a integração, mas é marcada como "opcional para MVP" no design. Evitar bloqueio da feature se Feature 005 não estiver completamente integrada. Abordagem: verificar Authorization header sem obrigar — se ausente ou inválido, seguir fluxo normal de ContactLead. Alternativas consideradas: Novo endpoint separado para criação de VisitRequest — rejeitado; duplica a UX de submissão do formulário de contato.


4. Admin: verificação de role vs. require_auth apenas

Decisão: MVP usa apenas require_auth nas rotas admin, sem verificação de role. Rationale: Único usuário que acessa a API admin no MVP é o proprietário da aplicação. Implementar RBAC completo sem tabela de roles seria over-engineering. Dívida técnica documentada no Constitution Check. Alternativas consideradas: require_admin_role via campo is_admin no ClientUser — possível futuro; não implementar agora (YAGNI).


5. Carregamento do FavoritesContext

Decisão: FavoritesContext carrega a lista de favoritos via GET /api/v1/me/favorites na inicialização do AuthContext (quando user !== null). Armazena apenas os UUIDs dos imóveis favoritados em um Set<string>, não os objetos completos de Property. Rationale: O contexto precisa responder rapidamente ao estado "favoritado ou não" para cada card. Armazenar apenas IDs é O(1) para lookup. Os dados completos são carregados pela FavoritesPage sob demanda. Evita duplicar grande payload de imóveis no contexto global. Alternativas consideradas: Armazenar objetos Property completos no contexto — rejeitado; memory footprint desnecessário para o caso de uso principal (mostrar coração preenchido/vazio).


6. Estrutura do ClientLayout

Decisão: ClientLayout.tsx com sidebar lateral fixa em desktop, colapsável em mobile. Rationale: Padrão de dashboard consistente com DESIGN.md (fundo #08090a, painéis #0f1011). Sidebar com links: Dashboard, Favoritos, Comparar, Visitas, Boletos. User info no topo da sidebar. Alternativas consideradas: Tabs horizontais no topo — rejeitado; não escala bem com 5+ seções e viola o padrão de dashboard visual estabelecido.


7. Unicidade de SavedProperty

Decisão: Unique constraint na combinação (user_id, property_id) no banco de dados (além da validação no código). Rationale: FR-001 exige 409 para duplicata. A constraint no banco garante integridade mesmo em race conditions. O código verifica antes de inserir e retorna 409 em IntegrityError do SQLAlchemy. Alternativas consideradas: Verificar apenas em código — rejeitado; sujeito a race condition em inserts paralelos.


8. Tipo monetário para Boleto.amount

Decisão: Numeric(12, 2) — mesmo padrão de Property.price. Rationale: Princípio IV da constituição: "Sensitive fields (e.g., prices, area measurements) MUST use appropriate numeric types — no float for money". Alternativas consideradas: Float — rejeitado explicitamente pela constituição.


9. Ordenação das listas

Decisão:

  • GET /api/v1/me/visits → ordenado por created_at DESC
  • GET /api/v1/me/boletos → ordenado por due_date ASC (vencimentos próximos primeiro)
  • GET /api/v1/me/favorites → ordenado por created_at DESC (mais recentes primeiro)

Rationale: Visitas: mais recentes primeiro é padrão de log/histórico. Boletos: vencimentos próximos primeiro é mais útil financeiramente. Favoritos: mais recentes primeiro é o comportamento esperado numa lista de "wishlist".


10. Dependência de Feature 005

Decisão: Assumir que ClientUser, require_auth e JWT middleware estão disponíveis. Rationale: Declarado explicitamente como pré-requisito no spec e nas instruções. Se Feature 005 ainda não estiver implementada, as rotas retornarão 500 até que o middleware seja injetado — identificável rapidamente em teste. Alternativas consideradas: Mock de require_auth para desenvolvimento paralelo — possível, mas não necessário; o plano assume sequência correta de implementação.