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
|
|
@ -0,0 +1,169 @@
|
|||
# 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 |
|
||||
Loading…
Add table
Add a link
Reference in a new issue