169 lines
4.1 KiB
Markdown
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 |
|