sass-imobiliaria/specs/024-filtro-busca-avancada/contracts/api-catalog-enhancements.md

169 lines
4.1 KiB
Markdown

# API Catalog Enhancements — Contrato de Interface
**Feature**: `024-filtro-busca-avancada`
**Tipo de mudança**: Adição de campo somente-leitura em endpoints existentes (backward-compatible)
**Versão da API**: `/api/v1` (sem mudança de versão — campo adicional não quebra clientes existentes)
---
## Resumo das Mudanças
Três endpoints existentes passam a incluir o campo `property_count` na resposta. Nenhum endpoint novo é criado. Nenhum parâmetro de entrada é modificado.
---
## GET /api/v1/cities
**Sem alteração na assinatura.** O campo `property_count` é adicionado à resposta.
### Response (200 OK)
```json
[
{
"id": 1,
"name": "Rio de Janeiro",
"slug": "rio-de-janeiro",
"state": "RJ",
"property_count": 47
},
{
"id": 2,
"name": "São Paulo",
"slug": "sao-paulo",
"state": "SP",
"property_count": 12
},
{
"id": 3,
"name": "Belo Horizonte",
"slug": "belo-horizonte",
"state": "MG",
"property_count": 0
}
]
```
**Regras**:
- `property_count` conta apenas imóveis com `is_active = true` associados à cidade via `properties.city_id`
- Cidades sem imóveis ativos retornam `property_count: 0` (não são omitidas da lista)
- Ordenação mantida: `state ASC, name ASC`
---
## GET /api/v1/neighborhoods
**Sem alteração na assinatura.** Parâmetro opcional `?city_id=<int>` permanece inalterado.
### Response (200 OK)
```json
[
{
"id": 10,
"name": "Copacabana",
"slug": "copacabana",
"city_id": 1,
"property_count": 23
},
{
"id": 11,
"name": "Ipanema",
"slug": "ipanema",
"city_id": 1,
"property_count": 15
},
{
"id": 12,
"name": "Santa Teresa",
"slug": "santa-teresa",
"city_id": 1,
"property_count": 0
}
]
```
**Regras**:
- `property_count` conta apenas imóveis com `is_active = true` via `properties.neighborhood_id`
- Bairros sem imóveis ativos retornam `property_count: 0`
- Ordenação mantida: `name ASC`
- Filtro `?city_id` mantém comportamento existente
---
## GET /api/v1/property-types
**Sem alteração na assinatura.** `property_count` é adicionado nos **subtypes** (leaf nodes). Os tipos pai (`parent_id = null`) retornam `property_count: 0` (sem significado — contagem relevante é nos subtipos).
### Response (200 OK)
```json
[
{
"id": 1,
"name": "Residencial",
"slug": "residencial",
"parent_id": null,
"property_count": 0,
"subtypes": [
{
"id": 2,
"name": "Apartamento",
"slug": "apartamento",
"parent_id": 1,
"property_count": 38,
"subtypes": []
},
{
"id": 3,
"name": "Casa",
"slug": "casa",
"parent_id": 1,
"property_count": 14,
"subtypes": []
},
{
"id": 4,
"name": "Cobertura",
"slug": "cobertura",
"parent_id": 1,
"property_count": 5,
"subtypes": []
}
]
},
{
"id": 5,
"name": "Comercial",
"slug": "comercial",
"parent_id": null,
"property_count": 0,
"subtypes": [
{
"id": 6,
"name": "Sala Comercial",
"slug": "sala-comercial",
"parent_id": 5,
"property_count": 7,
"subtypes": []
}
]
}
]
```
**Regras**:
- `property_count` nos subtypes conta imóveis com `is_active = true` via `properties.subtype_id`
- Tipos pai recebem `property_count: 0` (campo presente para consistência de schema, não usado pelo frontend)
- Ordenação mantida: por `PropertyType.id ASC` (categorias pai); subtypes herdados via SQLAlchemy relationship
---
## Backward Compatibility
| Aspecto | Garantia |
|---------|----------|
| Clientes existentes que ignoram campos extras | ✅ Não quebram — campo adicional em JSON é ignorado |
| Frontend antes da feature 024 | ✅ `property_count?: number` (opcional no TypeScript) — não causa erro de tipo |
| Testes existentes (`test_properties.py`, `test_homepage.py`) | ✅ Não testam payload de catálogo em detalhe; COUNT adicional não altera filtros |
| Admin panel | ✅ Não consome esses endpoints; sem impacto |