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
391
.specify/features/001-homepage/spec.md
Normal file
391
.specify/features/001-homepage/spec.md
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
# Feature Specification: Homepage (Página Inicial)
|
||||
|
||||
**Feature Branch**: `001-homepage`
|
||||
**Created**: 2026-04-13
|
||||
**Status**: Draft
|
||||
|
||||
---
|
||||
|
||||
## User Scenarios & Testing
|
||||
|
||||
### User Story 1 — Visitante Experimenta o Hero e a Navegação (Priority: P1)
|
||||
|
||||
Um visitante chega ao site da imobiliária e é imediatamente recebido por uma barra de navegação clara e uma seção hero visualmente impactante. O headline comunica a proposta de valor da agência, o subheadline fornece contexto de suporte, e um botão CTA proeminente convida o visitante a explorar os imóveis disponíveis.
|
||||
|
||||
**Why this priority**: O hero é a primeira impressão do site. Sem ele renderizar corretamente com conteúdo atualizado, nenhuma outra seção entrega valor significativo. Ele ancora a identidade visual e orienta o engajamento do visitante.
|
||||
|
||||
**Independent Test**: Pode ser testado de forma independente carregando a URL da homepage em qualquer navegador — a barra de navegação deve exibir o logotipo e os links, o hero deve mostrar o headline e subheadline configurados pelo admin, e o botão CTA deve estar visível e navegável para a listagem de imóveis.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** o visitante abre a URL da homepage, **when** a página carrega, **then** a barra de navegação é visível com o logotipo da agência à esquerda e os links "Imóveis", "Sobre" e "Contato" à direita.
|
||||
2. **Given** a página está carregada, **when** o visitante visualiza a seção hero, **then** ela exibe o headline atual, o subheadline (quando configurado), e um botão CTA com o rótulo configurado pelo admin (padrão: "Ver Imóveis").
|
||||
3. **Given** o visitante clica no botão CTA do hero, **when** o clique é processado, **then** o navegador redireciona para a página de listagem de imóveis (`/imoveis`).
|
||||
4. **Given** um admin atualizou o headline via painel administrativo, **when** o visitante carrega a homepage, **then** a seção hero exibe o novo headline sem necessidade de redeploy.
|
||||
5. **Given** a homepage é acessada em dispositivo móvel (viewport 320px–428px), **when** a página renderiza a seção hero, **then** todo o texto é legível, o botão CTA é tocável, e não há overflow horizontal.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 — Visitante Explora Imóveis em Destaque (Priority: P1)
|
||||
|
||||
Um visitante rola além da seção hero e encontra uma grade de imóveis curados em destaque. Cada card de imóvel fornece informações suficientes (foto, preço, tipo, estatísticas principais) para o visitante avaliar rapidamente o interesse e decidir clicar para ver mais detalhes.
|
||||
|
||||
**Why this priority**: Os imóveis em destaque são o conteúdo comercial primário da homepage. Esta seção conduz diretamente as consultas de imóveis e a conversão de visitante para lead. É a função de negócio central da homepage.
|
||||
|
||||
**Independent Test**: Pode ser testado de forma independente carregando a homepage e verificando que pelo menos um card de imóvel aparece na grade em destaque, com todos os campos obrigatórios visíveis (foto, título, preço, badge de tipo, quartos/banheiros/área). O teste pode ser executado contra um banco de dados com imóveis pré-configurados como destaque.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** existem imóveis no sistema com o flag "featured" habilitado, **when** o visitante carrega a homepage, **then** a seção de imóveis em destaque exibe uma grade mostrando até N imóveis (configurável pelo admin), cada card contendo: foto principal, título do imóvel, preço formatado (R$), badge de tipo (Venda ou Aluguel), contagem de quartos, banheiros e área total em m².
|
||||
2. **Given** nenhum imóvel está configurado como destaque, **when** o visitante carrega a homepage, **then** a seção de imóveis em destaque é ocultada ou exibe a mensagem "Nenhum imóvel em destaque no momento" — a grade não é renderizada vazia ou quebrada.
|
||||
3. **Given** um card de imóvel está visível, **when** o visitante clica no card, **then** o navegador navega para a URL de detalhe daquele imóvel (`/imoveis/{slug}`).
|
||||
4. **Given** um imóvel em destaque não possui foto cadastrada, **when** o card é renderizado, **then** ele exibe uma imagem placeholder em vez de um elemento de imagem quebrado.
|
||||
5. **Given** a grade de imóveis em destaque é visualizada em tablet (768px–1023px), **when** o layout renderiza, **then** a grade se adapta para 2 colunas sem overflow ou quebra de alinhamento.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 — Visitante Descobre a Agência e Inicia Contato (Priority: P2)
|
||||
|
||||
Um visitante que está interessado mas ainda não está pronto para navegar pelos imóveis rola pela seção Sobre para conhecer o background da agência, e em seguida encontra a seção CTA com informações de contato claras ou um convite para entrar em contato.
|
||||
|
||||
**Why this priority**: As seções Sobre e CTA suportam a construção de confiança e a geração de leads para visitantes que precisam de mais contexto antes de engajar com as listagens. São valiosas, mas não bloqueiam a funcionalidade MVP — a homepage funciona sem elas, embora as taxas de conversão se beneficiem significativamente de sua presença.
|
||||
|
||||
**Independent Test**: Pode ser testado de forma independente rolando a homepage além da seção de imóveis em destaque e verificando que (a) uma seção Sobre com nome e descrição da agência aparece, e (b) uma seção CTA com um convite de contato aparece antes do rodapé.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** o visitante rola além da seção de imóveis em destaque, **when** a seção Sobre entra na viewport, **then** ela exibe o nome da agência e pelo menos um parágrafo de descrição.
|
||||
2. **Given** o visitante continua rolando, **when** a seção CTA entra na viewport, **then** ela exibe um convite claro para contato com ao menos um elemento acionável (número de telefone, link de e-mail ou botão "Fale Conosco").
|
||||
3. **Given** a página é rolada até o final, **when** o visitante chega ao rodapé, **then** o rodapé exibe as informações de contato da agência (ao mínimo: e-mail ou telefone) e links de navegação (Imóveis, Sobre, Contato).
|
||||
|
||||
---
|
||||
|
||||
### User Story 4 — Admin Configura o Conteúdo da Homepage (Priority: P1)
|
||||
|
||||
Um administrador faz login no painel administrativo e atualiza o headline e subheadline do hero da homepage. O admin também seleciona quais imóveis aparecem na grade em destaque habilitando ou desabilitando o flag "featured" nos imóveis individuais.
|
||||
|
||||
**Why this priority**: A capacidade de atualizar o conteúdo da homepage sem alterações de código é um requisito central do painel SaaS. Sem essa capacidade, a homepage é estática e o painel administrativo não entrega valor para o gerenciamento da homepage.
|
||||
|
||||
**Independent Test**: Pode ser testado de forma independente em dois cenários: (1) atualizar o headline via formulário de configurações da homepage no painel e verificar que a mudança aparece na homepage pública; (2) alternar o flag "featured" de um imóvel e verificar que a grade de destaque é atualizada. Ambas as ações podem ser testadas contra o painel com chamadas reais de API.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** o admin está autenticado e na página de configurações da homepage, **when** o admin atualiza o headline e o subheadline e salva, **then** a homepage pública reflete o novo texto no próximo carregamento sem necessidade de redeploy.
|
||||
2. **Given** o admin navega para a lista de imóveis no painel, **when** o admin habilita ou desabilita o flag "featured" em um imóvel e salva, **then** aquele imóvel aparece ou é removido da grade em destaque na homepage pública.
|
||||
3. **Given** o admin tenta salvar a configuração da homepage com headline vazio, **when** o formulário é submetido, **then** o sistema rejeita o salvamento e exibe uma mensagem de validação — headline vazio não é permitido.
|
||||
4. **Given** o admin seleciona imóveis em destaque, **when** mais imóveis que o máximo configurável são marcados como destaque, **then** o sistema exibe apenas até o limite definido na homepage (padrão: 6), priorizando por data de marcação.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- **Nenhum imóvel em destaque**: Se nenhum imóvel está marcado como featured, a seção deve ser oculta ou exibir "Nenhum imóvel em destaque no momento" — a página não deve lançar erro de renderização.
|
||||
- **Imóvel sem foto**: Se um imóvel em destaque não possui foto, um placeholder genérico é exibido — o card não deve renderizar um elemento de imagem quebrado.
|
||||
- **Headline muito longo**: Se o admin inserir um headline muito longo (120+ caracteres), a seção hero deve adaptar-se sem overflow de texto ou quebra de layout.
|
||||
- **Estado de carregamento / rede lenta**: Enquanto a resposta da API de imóveis em destaque está pendente, a seção deve exibir skeleton loaders — sem flash de conteúdo ou espaço em branco.
|
||||
- **Subheadline vazio**: O subheadline é opcional. Um subheadline vazio deve resultar na renderização do hero sem o elemento subheadline — não uma string vazia visível.
|
||||
- **API indisponível**: Se o endpoint de configuração da homepage ou de imóveis falhar, a página deve renderizar uma versão degradada (conteúdo de fallback estático) em vez de uma tela de erro completa.
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: O sistema DEVE renderizar uma barra de navegação contendo o logotipo da agência e links para as seções/páginas Imóveis, Sobre e Contato.
|
||||
- **FR-002**: A barra de navegação DEVE ser sticky (visível durante a rolagem) em viewports desktop (≥768px).
|
||||
- **FR-003**: A barra de navegação DEVE colapsar para um menu hamburger em viewports abaixo de 768px.
|
||||
- **FR-004**: O sistema DEVE renderizar uma seção hero exibindo um headline, um subheadline opcional, e um botão CTA que navega para a listagem de imóveis.
|
||||
- **FR-005**: O headline e o subheadline do hero DEVEM ser configuráveis por um admin autenticado via painel administrativo sem alterações de código ou redeploy.
|
||||
- **FR-006**: O sistema DEVE renderizar uma seção de Imóveis em Destaque exibindo uma grade de imóveis marcados como "featured" por um admin.
|
||||
- **FR-007**: Cada card de imóvel na grade DEVE exibir: uma foto principal, título do imóvel, preço formatado em R$ (pt-BR), badge de tipo (Venda ou Aluguel), contagem de quartos, contagem de banheiros e área total em m².
|
||||
- **FR-008**: A grade de imóveis em destaque DEVE ser populada dinamicamente via API de backend — a lista NÃO DEVE exigir redeploy para ser atualizada.
|
||||
- **FR-009**: O sistema DEVE limitar a grade em destaque a um número máximo configurável de entradas (padrão: 6, máximo suportado: 12).
|
||||
- **FR-010**: Se nenhum imóvel estiver configurado como destaque, o sistema DEVE tratar esse estado graciosamente sem erros de renderização, ocultando a seção ou exibindo uma mensagem adequada.
|
||||
- **FR-011**: Cards de imóvel DEVEM exibir uma imagem placeholder quando nenhuma foto estiver disponível.
|
||||
- **FR-012**: O sistema DEVE renderizar uma seção Sobre/Empresa contendo ao mínimo o nome da agência e uma descrição breve.
|
||||
- **FR-013**: O sistema DEVE renderizar uma seção Call-to-Action contendo um convite para contato com ao mínimo um elemento acionável.
|
||||
- **FR-014**: O sistema DEVE renderizar um rodapé contendo informações de contato e links de navegação.
|
||||
- **FR-015**: O painel administrativo DEVE fornecer uma interface para selecionar quais imóveis são exibidos na grade em destaque.
|
||||
- **FR-016**: O painel administrativo DEVE rejeitar salvamentos de configuração de homepage com headline vazio, exibindo mensagem de validação ao admin.
|
||||
|
||||
### Non-Functional Requirements
|
||||
|
||||
#### Performance
|
||||
|
||||
- **NFR-001**: A homepage DEVE atingir um Largest Contentful Paint (LCP) abaixo de 2,5 segundos em conexão banda larga padrão (>10 Mbps).
|
||||
- **NFR-002**: Os endpoints de API que suprem dados da homepage DEVEM responder em até 500ms sob carga normal (até 100 requisições concorrentes).
|
||||
- **NFR-003**: Imagens de imóveis em destaque DEVEM ser servidas em formato web-otimizado — nenhuma imagem de thumbnail de card deve exceder 300 KB.
|
||||
|
||||
#### Responsiveness
|
||||
|
||||
- **NFR-004**: A homepage DEVE ser completamente funcional e visualmente íntegra nos seguintes breakpoints: 320px (mobile S), 375px (mobile M), 768px (tablet), 1024px (laptop), 1280px (desktop), 1440px (wide).
|
||||
- **NFR-005**: A grade de imóveis em destaque DEVE se adaptar de 1 coluna em mobile para 2 colunas em tablet e 3 colunas em desktop (≥1024px).
|
||||
- **NFR-006**: A tipografia do hero DEVE escalar responsivamente: 72px em desktop, 48px em tablet, 40px em mobile.
|
||||
|
||||
#### Accessibility
|
||||
|
||||
- **NFR-007**: Todas as imagens DEVEM ter texto `alt` descritivo (título do imóvel para fotos de imóveis; descrição para o logotipo).
|
||||
- **NFR-008**: Todos os elementos interativos (links, botões) DEVEM ser navegáveis por teclado e ter estados de foco visíveis.
|
||||
- **NFR-009**: Relações de contraste de cor DEVEM atender aos padrões WCAG 2.1 AA: mínimo 4,5:1 para texto de corpo, 3:1 para texto grande e componentes de UI.
|
||||
- **NFR-010**: A página DEVE usar elementos HTML5 semânticos apropriados e papéis ARIA landmark (`<nav>`, `<main>`, `<footer>`, `<header>`) em toda a estrutura.
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **HomepageConfig**: Representa o conteúdo configurável pelo admin para a homepage. Atributos principais: `hero_headline` (obrigatório, máx. 120 caracteres), `hero_subheadline` (opcional, máx. 240 caracteres), `hero_cta_label` (opcional, máx. 40 caracteres, padrão: "Ver Imóveis"), `hero_cta_url` (opcional, caminho relativo, padrão: "/imoveis"), `featured_properties_limit` (inteiro, padrão: 6, máximo: 12).
|
||||
- **Property**: Representa um anúncio imobiliário. Atributos relevantes para a homepage: `id` (UUID), `title` (string), `type` (enum: `venda` | `aluguel`), `price` (decimal), `area_m2` (inteiro), `bedrooms` (inteiro), `bathrooms` (inteiro), `is_featured` (boolean), `slug` (string única). A entidade Property é compartilhada com a feature de listagem de imóveis.
|
||||
- **PropertyPhoto**: Representa uma foto associada a um imóvel. A homepage usa apenas a foto principal (primeira por ordem de display). Atributos: `url` (string), `alt_text` (string), `display_order` (inteiro).
|
||||
|
||||
---
|
||||
|
||||
## Design Specifications
|
||||
|
||||
Toda a especificação visual segue o tema dark inspirado no Linear documentado em `DESIGN.md`.
|
||||
|
||||
### Color Application
|
||||
|
||||
| Element | Token | Value |
|
||||
|---------|-------|-------|
|
||||
| Page background | Marketing Black | `#08090a` |
|
||||
| Navigation background (sticky) | Marketing Black semi-transparente | `rgba(8,9,10,0.85)` + backdrop-blur |
|
||||
| Hero background (gradiente padrão) | Radial brand indigo fade | `radial-gradient(ellipse at center, rgba(94,106,210,0.08) 0%, #08090a 70%)` |
|
||||
| Card/container background | Level 2 Surface | `rgba(255,255,255,0.03)` |
|
||||
| Card border | Border Standard | `1px solid rgba(255,255,255,0.08)` |
|
||||
| Card border hover | Border Standard brightened | `1px solid rgba(255,255,255,0.12)` |
|
||||
| Primary text | Near-white | `#f7f8f8` |
|
||||
| Secondary text | Silver-gray | `#d0d6e0` |
|
||||
| Tertiary text / metadata | Muted gray | `#8a8f98` |
|
||||
| CTA button background | Brand Indigo | `#5e6ad2` |
|
||||
| CTA button hover | Accent Hover | `#828fff` |
|
||||
| Badge tipo Venda | Brand Indigo pill | `rgba(94,106,210,0.15)` + borda `rgba(94,106,210,0.3)` |
|
||||
| Badge tipo Aluguel | Neutral pill | `rgba(255,255,255,0.05)` + borda `rgba(255,255,255,0.1)` |
|
||||
| Section dividers | Line Tint | sem divisor visível — espaçamento separa as seções |
|
||||
| Footer background | Panel Dark | `#0f1011` |
|
||||
|
||||
### Typography Application
|
||||
|
||||
| Element | Style from DESIGN.md | Size | Weight | Letter Spacing |
|
||||
|---------|----------------------|------|--------|----------------|
|
||||
| Hero headline (desktop) | Display XL | 72px | 510 | -1.584px |
|
||||
| Hero headline (tablet) | Display | 48px | 510 | -1.056px |
|
||||
| Hero headline (mobile) | Heading 1 | 40px | 510 | -0.704px |
|
||||
| Hero subheadline | Body Large | 18px | 400 | -0.165px |
|
||||
| CTA button label | Label | 14px | 590 | normal |
|
||||
| Section headings (ex: "Imóveis em Destaque") | Display | 48px (desktop) / 32px (mobile) | 510 | -1.056px / -0.704px |
|
||||
| Property card title | Heading 3 | 20px | 590 | -0.24px |
|
||||
| Property price | Body Semibold | 16px | 590 | normal |
|
||||
| Property stats (quartos, banheiros, área) | Caption Large | 14px | 510 | -0.182px |
|
||||
| Navigation links | Link Small | 14px | 510 | -0.182px |
|
||||
| Footer links | Link Caption | 13px | 510 | -0.13px |
|
||||
| About / CTA body text | Body | 16px | 400 | normal |
|
||||
|
||||
Toda a tipografia usa `Inter Variable` com OpenType features `"cv01", "ss03"` habilitadas globalmente via `font-feature-settings: "cv01", "ss03"`.
|
||||
|
||||
### Layout
|
||||
|
||||
- **Largura máxima do conteúdo**: 1200px, centralizado horizontalmente com margens `auto`.
|
||||
- **Hero section**: mínimo 100vh de altura, layout de coluna única centralizado, padding: 120px superior / 80px inferior em desktop; 80px / 60px em mobile.
|
||||
- **Grade de Imóveis em Destaque**: 3 colunas em desktop (≥1024px), 2 colunas em tablet (768px–1023px), 1 coluna em mobile (<768px). Gap: 24px.
|
||||
- **Espaçamento vertical entre seções**: 80px padding-top e padding-bottom em desktop; 60px em mobile.
|
||||
- **Border radius dos cards**: 12px (Panel radius conforme DESIGN.md).
|
||||
- **Fotos dos cards**: border-radius `12px 12px 0 0` (arredondado só no topo), aspect-ratio 16:9.
|
||||
|
||||
### Component Notes
|
||||
|
||||
- **Navigation bar**: fundo `rgba(8,9,10,0.85)` com `backdrop-filter: blur(12px)`, `border-bottom: 1px solid rgba(255,255,255,0.05)`. Posição: sticky, `z-index` elevado.
|
||||
- **Property card**: fundo `rgba(255,255,255,0.03)`, borda `1px solid rgba(255,255,255,0.08)`, radius 12px, com transição de hover aumentando levemente a opacidade do fundo e a borda.
|
||||
- **CTA button (Primary)**: Background `#5e6ad2`, padding `10px 20px`, radius 6px, texto branco weight 590. Hover: `#828fff`.
|
||||
- **Type badges**: pills com radius `9999px`, padding `2px 10px`, fonte 12px weight 510.
|
||||
|
||||
---
|
||||
|
||||
## API Contract
|
||||
|
||||
Os seguintes endpoints devem ser implementados pelo backend Flask para suportar a homepage.
|
||||
|
||||
### `GET /api/v1/homepage-config`
|
||||
|
||||
Retorna o conteúdo configurável pelo admin para a seção hero da homepage.
|
||||
|
||||
**Autenticação**: Nenhuma (endpoint público)
|
||||
**Cache**: As respostas podem ser cacheadas por até 60 segundos (header `Cache-Control: public, max-age=60`).
|
||||
|
||||
**Response `200 OK`**:
|
||||
```json
|
||||
{
|
||||
"hero": {
|
||||
"headline": "Encontre o imóvel dos seus sonhos",
|
||||
"subheadline": "Imóveis para comprar e alugar com a melhor assessoria da região.",
|
||||
"cta_label": "Ver Imóveis",
|
||||
"cta_url": "/imoveis"
|
||||
},
|
||||
"featured_properties_limit": 6
|
||||
}
|
||||
```
|
||||
|
||||
**Response `500 Internal Server Error`**:
|
||||
```json
|
||||
{
|
||||
"error": "internal_server_error",
|
||||
"message": "An unexpected error occurred."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `GET /api/v1/properties?featured=true`
|
||||
|
||||
Retorna a lista de imóveis marcados como destaque, ordenados por prioridade de exibição.
|
||||
|
||||
**Autenticação**: Nenhuma (endpoint público)
|
||||
|
||||
**Query Parameters**:
|
||||
|
||||
| Parâmetro | Tipo | Obrigatório | Descrição |
|
||||
|-----------|------|-------------|-----------|
|
||||
| `featured` | boolean | sim (para este use case) | `true` filtra apenas imóveis em destaque |
|
||||
| `limit` | integer | não | Máximo de resultados. Padrão: valor de `featured_properties_limit` da config. Máximo: 12. |
|
||||
|
||||
**Response `200 OK`**:
|
||||
```json
|
||||
{
|
||||
"properties": [
|
||||
{
|
||||
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
|
||||
"title": "Apartamento Moderno no Centro",
|
||||
"type": "venda",
|
||||
"price": 450000.00,
|
||||
"price_formatted": "R$ 450.000,00",
|
||||
"area_m2": 85,
|
||||
"bedrooms": 3,
|
||||
"bathrooms": 2,
|
||||
"primary_photo_url": "https://cdn.example.com/properties/abc123/main.jpg",
|
||||
"primary_photo_alt": "Apartamento Moderno no Centro — foto principal",
|
||||
"slug": "apartamento-moderno-no-centro",
|
||||
"detail_url": "/imoveis/apartamento-moderno-no-centro"
|
||||
}
|
||||
],
|
||||
"total": 4
|
||||
}
|
||||
```
|
||||
|
||||
**Response `400 Bad Request`** (parâmetros inválidos):
|
||||
```json
|
||||
{
|
||||
"error": "invalid_parameter",
|
||||
"message": "Parameter 'limit' must be an integer between 1 and 12."
|
||||
}
|
||||
```
|
||||
|
||||
**Response `500 Internal Server Error`**:
|
||||
```json
|
||||
{
|
||||
"error": "internal_server_error",
|
||||
"message": "An unexpected error occurred."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `PUT /api/v1/admin/homepage-config`
|
||||
|
||||
Atualiza a configuração da homepage. Reservado para o painel administrativo (autenticação de admin obrigatória).
|
||||
|
||||
**Autenticação**: Bearer token (JWT), role `admin` obrigatória.
|
||||
**Nota**: Este endpoint é referenciado para completude do contrato; sua especificação completa (autenticação, sessões, permissões) é definida na feature spec do Admin Panel.
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
{
|
||||
"hero": {
|
||||
"headline": "string (obrigatório, máx. 120 caracteres)",
|
||||
"subheadline": "string (opcional, máx. 240 caracteres)",
|
||||
"cta_label": "string (opcional, máx. 40 caracteres)",
|
||||
"cta_url": "string (opcional, caminho relativo válido)"
|
||||
},
|
||||
"featured_properties_limit": "integer (opcional, 1–12)"
|
||||
}
|
||||
```
|
||||
|
||||
**Response `200 OK`**: Retorna o objeto `HomepageConfig` atualizado com o mesmo schema de `GET /api/v1/homepage-config`.
|
||||
|
||||
**Response `400 Bad Request`** (validação falhou):
|
||||
```json
|
||||
{
|
||||
"error": "validation_error",
|
||||
"fields": {
|
||||
"hero.headline": "This field is required and cannot be empty."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response `401 Unauthorized`** / **`403 Forbidden`**: Retornado quando o token está ausente, expirado ou sem a role `admin`.
|
||||
|
||||
---
|
||||
|
||||
### `PATCH /api/v1/admin/properties/{id}/featured`
|
||||
|
||||
Habilita ou desabilita o flag de destaque de um imóvel específico.
|
||||
|
||||
**Autenticação**: Bearer token (JWT), role `admin` obrigatória.
|
||||
**Nota**: Endpoint referenciado para completude. Especificação completa na feature spec de gerenciamento de imóveis do Admin Panel.
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
{
|
||||
"is_featured": true
|
||||
}
|
||||
```
|
||||
|
||||
**Response `200 OK`**:
|
||||
```json
|
||||
{
|
||||
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
|
||||
"is_featured": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Out of Scope
|
||||
|
||||
Os itens a seguir estão explicitamente excluídos desta especificação de feature e serão tratados em specs separadas:
|
||||
|
||||
- **Página de detalhe do imóvel**: Clicar em um card de imóvel navega para a URL de detalhe, mas o layout, conteúdo e API da página de detalhe são uma feature separada.
|
||||
- **Busca e filtros de imóveis**: A funcionalidade de busca (filtrar por faixa de preço, localização, tipo, quartos, etc.) é uma feature separada. O botão CTA do hero linka para a listagem; qualquer interface de busca na homepage está fora de escopo.
|
||||
- **Autenticação e UI do Painel Administrativo**: O fluxo de login do admin, layout do painel, navegação e gerenciamento de sessão são features separadas. Esta spec define apenas a view pública da homepage e o contrato de API que o painel consumirá.
|
||||
- **Página de Listagem de Imóveis**: A listagem completa em `/imoveis` com paginação, filtros e ordenação é uma feature separada.
|
||||
- **Backend de Formulário de Contato**: O processamento de submissão de formulário de contato, entrega de e-mail e armazenamento de leads são features separadas. O CTA da homepage pode linkar para uma página de contato ou fornecer e-mail/telefone estático.
|
||||
- **Suporte multi-idioma (i18n)**: Português (pt-BR) é o único idioma suportado. Internacionalização está fora de escopo.
|
||||
- **SEO / Meta Tags avançadas**: Open Graph tags, dados estruturados (JSON-LD para `RealEstateListing`) e geração de sitemap são concerns separados.
|
||||
- **Integração de Analytics**: Eventos de rastreamento (GA4, Hotjar, etc.) estão fora de escopo para esta feature.
|
||||
- **Conteúdo editável via admin das seções Sobre e Rodapé**: Na versão inicial, o conteúdo das seções Sobre, CTA e Rodapé é estático. Uma spec futura pode adicionar gerenciamento dessas seções pelo admin.
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: Um visitante pode chegar à homepage e clicar para ver um imóvel em destaque em menos de 30 segundos sem nenhuma orientação — taxa de conclusão da tarefa primária ≥ 90% em testes de usabilidade.
|
||||
- **SC-002**: A homepage carrega e exibe o conteúdo acima da dobra (hero + navegação) em até 2,5 segundos em conexão banda larga padrão.
|
||||
- **SC-003**: Um admin pode atualizar o headline do hero e vê-lo refletido na homepage pública em até 60 segundos, sem intervenção de desenvolvedor.
|
||||
- **SC-004**: Um admin pode alterar quais imóveis estão em destaque e ver a grade da homepage ser atualizada em até 60 segundos, sem redeploy.
|
||||
- **SC-005**: A homepage renderiza sem regressões visuais em todos os 6 breakpoints definidos (320px, 375px, 768px, 1024px, 1280px, 1440px).
|
||||
- **SC-006**: Todos os requisitos de contraste de cor WCAG 2.1 AA são atendidos em toda a homepage — verificado por auditoria de acessibilidade automatizada com zero violações críticas.
|
||||
- **SC-007**: A seção de imóveis em destaque renderiza corretamente com 0, 1 ou 6 imóveis marcados como featured — sem erros de JavaScript ou layouts quebrados em nenhum desses estados.
|
||||
|
||||
---
|
||||
|
||||
## Assumptions
|
||||
|
||||
- A agência opera exclusivamente no Brasil; toda formatação de moeda usa o locale pt-BR (prefixo R$, ponto como separador de milhar, vírgula como separador decimal).
|
||||
- A homepage é renderizada como React SPA com client-side data fetching; esta spec não prescreve a estratégia de renderização (CSR/SSR/SSG).
|
||||
- O sistema de autenticação do painel admin (login, sessão, JWT) é implementado como feature separada e é um pré-requisito para a User Story 4 (Admin Configura Conteúdo).
|
||||
- Fotos de imóveis são armazenadas externamente (object storage / CDN) e referenciadas por URL na resposta da API. A homepage não realiza upload de arquivos.
|
||||
- O conteúdo das seções Sobre e CTA (descrição da agência, informações de contato) é considerado estático para a versão inicial e não requer configurabilidade via admin nesta spec.
|
||||
- O conteúdo do rodapé (links e informações de contato) é HTML estático para a versão inicial.
|
||||
- O número máximo de imóveis em destaque exibidos na homepage tem padrão 6, configurável pelo admin até no máximo 12.
|
||||
- Links de cards de imóveis apontam para `/imoveis/{slug}` mesmo que a página de detalhe ainda não esteja implementada. Links temporariamente quebrados são aceitáveis durante o desenvolvimento em fases.
|
||||
- A fonte Inter Variable é carregada via fonte auto-hospedada ou CDN com OpenType features `"cv01", "ss03"` habilitadas globalmente via `font-feature-settings`.
|
||||
- O painel admin está hospedado na mesma origem ou com CORS configurado adequadamente para os endpoints `/api/v1/admin/*`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue