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 porcreated_at DESCGET /api/v1/me/boletos→ ordenado pordue_date ASC(vencimentos próximos primeiro)GET /api/v1/me/favorites→ ordenado porcreated_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.