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
108
.specify/features/003-property-listing/spec.md
Normal file
108
.specify/features/003-property-listing/spec.md
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# Feature Specification: Listagem de Imóveis com Filtros
|
||||
|
||||
**Feature Branch**: `003-property-listing`
|
||||
**Created**: 2026-04-13
|
||||
**Status**: Approved
|
||||
|
||||
## Contexto
|
||||
|
||||
Página pública `/imoveis` onde visitantes navegam e filtram o catálogo completo de imóveis. Os filtros utilizam dados dinâmicos cadastrados pela área administrativa (tipos, características, lazer, condomínio, segurança).
|
||||
|
||||
## User Stories
|
||||
|
||||
### US1 — Visitante navega no catálogo (P1)
|
||||
**Given** o visitante acessa `/imoveis`, **When** a página carrega, **Then** vê a grade de imóveis ativos com paginação, foto, preço, tipo, dormitórios, banheiros, área e vagas.
|
||||
|
||||
### US2 — Visitante filtra por tipo de imóvel (P1)
|
||||
**Given** o painel de filtros está visível, **When** seleciona categoria "Residencial" e subtipo "Apartamento", **Then** a lista atualiza mostrando apenas apartamentos residenciais.
|
||||
|
||||
### US3 — Visitante filtra por preço (P1)
|
||||
**Given** o filtro de preço está disponível, **When** define min R$ 500.000 e max R$ 1.500.000, **Then** apenas imóveis nesse intervalo aparecem. Com a opção "incluir condomínio" marcada, o backend soma `price + condo_fee` antes de comparar.
|
||||
|
||||
### US4 — Visitante filtra por quartos/banheiros/vagas (P1)
|
||||
**Given** os sliders numéricos estão disponíveis, **When** define mínimo 2 quartos, **Then** apenas imóveis com ≥ 2 quartos aparecem.
|
||||
|
||||
### US5 — Visitante filtra por área (P1)
|
||||
**Given** o filtro de área em m² está disponível, **When** define 50–150 m², **Then** apenas imóveis nesse intervalo aparecem.
|
||||
|
||||
### US6 — Visitante filtra por características (P2)
|
||||
**Given** a lista de características está visível (Aceita animais, Ar-condicionado, etc.), **When** seleciona múltiplas, **Then** apenas imóveis que possuem TODAS as características selecionadas aparecem.
|
||||
|
||||
### US7 — Visitante filtra lazer, condomínio e segurança (P2)
|
||||
Mesmo comportamento do US6 para os grupos adicionais.
|
||||
|
||||
## API Contract
|
||||
|
||||
### Endpoints necessários
|
||||
|
||||
**GET /api/v1/property-types** → lista hierárquica de categorias e subtipos
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 1, "name": "Residencial", "slug": "residencial",
|
||||
"subtypes": [{"id": 10, "name": "Apartamento", "slug": "apartamento"}, ...]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**GET /api/v1/amenities** → lista agrupada de amenidades
|
||||
```json
|
||||
[
|
||||
{"id": 1, "name": "Aceita animais", "group": "caracteristica", "count": 37},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
**GET /api/v1/properties** (atualizar) — aceitar query params:
|
||||
| Param | Tipo | Descrição |
|
||||
|---|---|---|
|
||||
| `subtype_id` | int | ID do subtipo |
|
||||
| `listing_type` | venda\|aluguel | tipo da transação |
|
||||
| `price_min` | number | preço mínimo |
|
||||
| `price_max` | number | preço máximo |
|
||||
| `include_condo` | bool | somar condomínio ao preço |
|
||||
| `bedrooms_min` | int | quartos mínimo |
|
||||
| `bedrooms_max` | int | quartos máximo |
|
||||
| `bathrooms_min` | int | banheiros mínimo |
|
||||
| `bathrooms_max` | int | banheiros máximo |
|
||||
| `parking_min` | int | vagas mínimo |
|
||||
| `parking_max` | int | vagas máximo |
|
||||
| `area_min` | int | área m² mínimo |
|
||||
| `area_max` | int | área m² máximo |
|
||||
| `amenity_ids` | int[] (CSV) | IDs de amenidades (AND) |
|
||||
| `page` | int | página (default 1) |
|
||||
| `per_page` | int | itens por página (default 24, max 48) |
|
||||
| `featured` | bool | retorna destaques (comportamento existente) |
|
||||
|
||||
Resposta paginada:
|
||||
```json
|
||||
{
|
||||
"items": [...],
|
||||
"total": 120,
|
||||
"page": 1,
|
||||
"per_page": 24,
|
||||
"pages": 5
|
||||
}
|
||||
```
|
||||
|
||||
## Modelos necessários
|
||||
|
||||
### PropertyType (novo)
|
||||
- `id`, `name`, `slug`, `parent_id` (nullable → hierarquia)
|
||||
|
||||
### Amenity (novo)
|
||||
- `id`, `name`, `slug`, `group` (enum: caracteristica | lazer | condominio | seguranca), `count` (denormalizado)
|
||||
|
||||
### PropertyAmenity (nova tabela N:N)
|
||||
- `property_id`, `amenity_id`
|
||||
|
||||
### Atualizar Property (novo campo)
|
||||
- `subtype_id` FK → PropertyType
|
||||
- `parking_spots` INT
|
||||
- `condo_fee` NUMERIC(10,2) nullable
|
||||
|
||||
## Out of Scope
|
||||
- Detalhe do imóvel (feature 004)
|
||||
- Mapa/geolocalização
|
||||
- Ordenação customizada (entregue com default created_at desc)
|
||||
- Favoritos / comparador
|
||||
Loading…
Add table
Add a link
Reference in a new issue