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
90
.specify/features/004-property-detail-page/plan.md
Normal file
90
.specify/features/004-property-detail-page/plan.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# Implementation Plan: Property Detail Page
|
||||
|
||||
**Branch**: `004-property-detail-page` | **Date**: 2026-04-13 | **Spec**: [spec.md](spec.md)
|
||||
**Input**: Feature specification from `.specify/features/004-property-detail-page/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Página pública `/imoveis/<slug>` que exibe todas as informações de um imóvel em detalhe: galeria de fotos em carrossel (teclado + swipe), estatísticas, caixa de preço sticky, description, amenidades agrupadas e seção de contato (formulário + WhatsApp). O backend adiciona dois novos endpoints — `GET /api/v1/properties/<slug>` e `POST /api/v1/properties/<slug>/contact` — além de uma nova tabela `contact_leads` e os campos `code` / `description` no modelo `Property` exigidos pelo contrato da spec.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Python 3.12 / TypeScript 5.5
|
||||
**Primary Dependencies**: Flask 3.x, SQLAlchemy 2.x, Pydantic v2 (backend) · React 18, Tailwind CSS 3.4, react-router-dom v6, Axios (frontend)
|
||||
**Storage**: PostgreSQL 16 via Docker
|
||||
**Testing**: pytest (backend) · Vite build + verificação visual (frontend)
|
||||
**Target Platform**: Container Linux Docker (backend) / browser SPA (frontend)
|
||||
**Project Type**: REST web-service + single-page application
|
||||
**Performance Goals**: Página renderizada em < 3 s em conexão padrão (SC-001)
|
||||
**Constraints**: Rotas públicas sem autenticação; CORS explícito via Flask-CORS; sem rate limiting no MVP (assumption doc spec); nenhum secret no bundle frontend
|
||||
**Scale/Scope**: MVP — única imobiliária, único número WhatsApp via env
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
| Princípio | Status | Evidência |
|
||||
|-----------|--------|-----------|
|
||||
| I. Design-First | ✅ PASS | Todos os componentes usam tokens do DESIGN.md: canvas `#08090a`, panel `#0f1011`, accent `#7170ff`, border `rgba(255,255,255,0.05–0.08)`. Nenhum inline style fora do sistema. |
|
||||
| II. Separation of Concerns | ✅ PASS | Flask retorna JSON puro; React consome a API. Nenhum SSR. CORS explícito configurado. |
|
||||
| III. Spec-Driven | ✅ PASS | `spec.md` finalizado; plan → tasks → implement. |
|
||||
| IV. Data Integrity | ✅ PASS | `ContactLeadIn` valida com Pydantic + `EmailStr`; migration Alembic para `contact_leads` e novos campos de `Property`; ORM exclusivo; `property_id` resolvido via `slug` no backend (FR-B04). |
|
||||
| V. Security | ✅ PASS | Rotas públicas sem auth (especificado na spec). `VITE_WHATSAPP_NUMBER` via env (nunca hardcoded). `property_id` nunca aceito do cliente. |
|
||||
| VI. Simplicity First | ✅ PASS | Carousel implementado com React state + event handlers nativos (sem nova lib). Google Maps Embed como iframe simples (US3 P3). Zero novas dependências npm. |
|
||||
|
||||
**Re-check pós-design**: confirmar que `PropertyDetailOut` herda de `PropertyOut` sem duplicação e que a migration é um único arquivo cobrindo contact_leads + colunas novas.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
.specify/features/004-property-detail-page/
|
||||
├── plan.md ← este arquivo
|
||||
├── research.md ← Phase 0 output
|
||||
├── data-model.md ← Phase 1 output
|
||||
├── quickstart.md ← Phase 1 output
|
||||
├── contracts/
|
||||
│ └── rest.md ← Phase 1 output
|
||||
└── tasks.md ← Phase 2 output (/speckit.tasks — NOT criado aqui)
|
||||
```
|
||||
|
||||
### Source Code
|
||||
|
||||
```text
|
||||
backend/
|
||||
├── app/
|
||||
│ ├── models/
|
||||
│ │ └── property.py ← adicionar ContactLead; adicionar code/description em Property
|
||||
│ ├── schemas/
|
||||
│ │ └── property.py ← PropertyDetailOut(PropertyOut), ContactLeadIn, ContactLeadCreatedOut
|
||||
│ └── routes/
|
||||
│ └── properties.py ← GET /properties/<slug>, POST /properties/<slug>/contact
|
||||
└── migrations/versions/
|
||||
└── <hash>_add_contact_leads_and_property_detail_fields.py ← migration única
|
||||
|
||||
frontend/
|
||||
└── src/
|
||||
├── types/
|
||||
│ └── property.ts ← PropertyDetail (extends Property), ContactFormData
|
||||
├── services/
|
||||
│ └── properties.ts ← getProperty(slug), submitContactForm(slug, data)
|
||||
├── components/
|
||||
│ ├── PropertyCarousel.tsx ← novo
|
||||
│ ├── PropertyStatsStrip.tsx ← novo
|
||||
│ ├── Breadcrumb.tsx ← novo
|
||||
│ ├── PriceBox.tsx ← novo
|
||||
│ ├── AmenitiesSection.tsx ← novo
|
||||
│ ├── ContactSection.tsx ← novo
|
||||
│ ├── PropertyDetailSkeleton.tsx ← novo
|
||||
│ └── PropertyCard.tsx ← wrap com Link para /imoveis/<slug>
|
||||
├── pages/
|
||||
│ └── PropertyDetailPage.tsx ← novo
|
||||
└── App.tsx ← adicionar rota /imoveis/:slug
|
||||
```
|
||||
|
||||
**Structure Decision**: Web application (backend + frontend). Sem novo diretório top-level; componentes separados por responsabilidade seguindo o padrão já estabelecido no projeto.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
> Nenhuma violação identificada. Todos os princípios passam sem justificativa de exceção.
|
||||
Loading…
Add table
Add a link
Reference in a new issue