feat: add full project - backend, frontend, docker, specs and configs
This commit is contained in:
parent
b77c7d5a01
commit
e6cb06255b
24489 changed files with 61341 additions and 36 deletions
87
.specify/features/006-client-area/research.md
Normal file
87
.specify/features/006-client-area/research.md
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
# 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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue