feat: add full project - backend, frontend, docker, specs and configs

This commit is contained in:
MatheusAlves96 2026-04-20 23:59:45 -03:00
parent b77c7d5a01
commit e6cb06255b
24489 changed files with 61341 additions and 36 deletions

View file

@ -0,0 +1,114 @@
# Implementation Plan: Docker Setup
**Branch**: `002-docker-setup`
**Spec**: `.specify/features/002-docker-setup/spec.md`
**Created**: 2026-04-13
## Constitution Check
- ✅ Design-First: não se aplica (infra)
- ✅ Separation of Concerns: Flask e React permanecem desacoplados, Docker apenas orquestra
- ✅ Spec-Driven: este plano deriva da spec aprovada
- ✅ Security: nenhuma secret hardcoded; `.env` no gitignore
- ✅ Simplicity: sem multi-stage build, sem nginx — foco em dev environment
---
## Phase 1 — Backend Dockerfile
**Objetivo**: Containerizar o Flask app usando python:3.12-slim e uv.
**Arquivos**:
- `backend/Dockerfile`
**Detalhes**:
- Base: `python:3.12-slim`
- Instalar `uv` via pip
- Copiar `pyproject.toml``uv sync` → copiar código
- Entrypoint: script shell que executa `flask db upgrade && python seeds/seed.py && python run.py`
- Porta exposta: 5000
**Critério de conclusão**: `docker build -t backend ./backend` conclui sem erro.
---
## Phase 2 — Frontend Dockerfile
**Objetivo**: Containerizar o servidor de desenvolvimento Vite com hot-reload.
**Arquivos**:
- `frontend/Dockerfile`
**Detalhes**:
- Base: `node:20-alpine`
- Copiar `package*.json``npm ci` → copiar código
- CMD: `npm run dev -- --host 0.0.0.0` (necessário para expor dentro do container)
- Porta exposta: 5173
- O `vite.config.ts` já tem proxy `/api → http://localhost:5000`; atualizar para `http://backend:5000` (nome do serviço Docker)
**Critério de conclusão**: `docker build -t frontend ./frontend` conclui sem erro.
---
## Phase 3 — docker-compose.yml
**Objetivo**: Orquestrar db + backend + frontend com dependências e healthchecks.
**Arquivos**:
- `docker-compose.yml` (raiz)
- `.env.example` (atualizar/criar na raiz)
**Serviços**:
```yaml
db:
image: postgres:16-alpine
healthcheck: pg_isready -U ${POSTGRES_USER}
depends_on: (nenhum)
backend:
build: ./backend
depends_on:
db: { condition: service_healthy }
environment:
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
frontend:
build: ./frontend
depends_on: [backend]
volumes:
- ./frontend/src:/app/src ← hot-reload
- ./frontend/public:/app/public
```
**Critério de conclusão**: `docker-compose config` valida sem erro; `docker-compose up` sobe os 3 serviços.
---
## Phase 4 — start.ps1
**Objetivo**: Script PowerShell de conveniência na raiz.
**Arquivos**:
- `start.ps1` (raiz)
**Lógica**:
1. Verificar se `docker` está disponível no PATH
2. Se não: exibir mensagem com link para Docker Desktop e sair
3. Se sim: executar `docker-compose up --build`
**Critério de conclusão**: `.\start.ps1` inicia o ambiente ou exibe erro informativo.
---
## Sequência de execução
```
Phase 1 (backend/Dockerfile)
Phase 2 (frontend/Dockerfile + vite.config proxy update)
Phase 3 (docker-compose.yml + .env.example)
Phase 4 (start.ps1)
Validação: docker-compose up --build → testar endpoints
```

View file

@ -0,0 +1,93 @@
# Feature Specification: Docker Setup
**Feature Branch**: `002-docker-setup`
**Created**: 2026-04-13
**Status**: Approved
## User Scenarios & Testing
### User Story 1 — Desenvolvedor sobe todo o ambiente com um comando (Priority: P1)
Um desenvolvedor que acabou de clonar o repositório deve conseguir subir PostgreSQL, backend Flask e frontend React rodando juntos com um único comando, sem instalar Python ou Node localmente.
**Why this priority**: É o bloqueio zero de onboarding. Sem isso, cada dev configura manualmente, gerando ambientes inconsistentes.
**Independent Test**: Executar `docker-compose up --build` na raiz e acessar `http://localhost:5173` deve exibir a homepage carregando dados do backend.
**Acceptance Scenarios**:
1. **Given** o repositório recém-clonado com Docker instalado, **When** o dev roda `docker-compose up --build`, **Then** os três serviços (db, backend, frontend) sobem sem erro e ficam acessíveis.
2. **Given** o ambiente rodando, **When** o dev acessa `http://localhost:5173`, **Then** a homepage é renderizada com dados reais do banco.
3. **Given** o ambiente rodando, **When** o dev acessa `http://localhost:5000/api/v1/homepage-config`, **Then** a API retorna JSON 200 com os dados seedados.
4. **Given** o ambiente rodando, **When** o dev faz uma alteração num arquivo `.tsx`, **Then** o Vite hot-reload atualiza o browser sem reiniciar o container.
---
### User Story 2 — Script de conveniência na raiz (Priority: P1)
Um desenvolvedor Windows deve poder rodar `.\start.ps1` na raiz para ter o ambiente de um clique, sem memorizar comandos Docker.
**Why this priority**: Reduz fricção para devs Windows que são o público principal.
**Independent Test**: `.\start.ps1` executa `docker-compose up --build` e exibe mensagens de status claras.
**Acceptance Scenarios**:
1. **Given** Docker Desktop instalado, **When** o dev roda `.\start.ps1`, **Then** o script valida que Docker está rodando e executa o compose.
2. **Given** Docker não instalado, **When** o dev roda `.\start.ps1`, **Then** o script exibe mensagem clara pedindo para instalar Docker Desktop.
---
### Edge Cases
- O que acontece se a porta 5432/5000/5173 já estiver em uso? → `docker-compose` retorna erro; o script deve informar.
- O que acontece se o banco ainda não estiver pronto quando o backend inicializar? → `depends_on` com `healthcheck`; backend deve aguardar ou fazer retry.
- Como rodar as migrations no primeiro boot? → Entrypoint do backend executa `flask db upgrade` antes de `python run.py`.
## Requirements
### Functional
- FR1: `docker-compose up --build` na raiz sobe 3 serviços: `db` (PostgreSQL 16), `backend` (Flask), `frontend` (React/Vite)
- FR2: Backend aguarda PostgreSQL estar saudável antes de inicializar (healthcheck)
- FR3: Backend executa `flask db upgrade` + seeder automaticamente no primeiro boot
- FR4: Frontend tem hot-reload via bind mount do código-fonte
- FR5: Variáveis de ambiente devem estar em `.env` na raiz (não hardcoded no compose)
- FR6: `.\start.ps1` na raiz é o ponto de entrada único para Windows
### Non-Functional
- NFR1: `docker-compose up --build` deve completar em menos de 5 min com cache
- NFR2: Imagens devem usar variantes slim/alpine para minimizar tamanho
- NFR3: Nenhuma secret hardcoded nas imagens — tudo via env vars
- NFR4: `.env` não deve ser commitado; `.env.example` deve existir
## Design / Architecture
```
raiz/
├── docker-compose.yml ← orchestração dos 3 serviços
├── .env.example ← template de variáveis (db, secret key)
├── .env ← valores locais (gitignored)
├── start.ps1 ← script Windows de conveniência
├── backend/
│ └── Dockerfile ← python:3.12-slim, uv, flask
└── frontend/
└── Dockerfile ← node:20-alpine, vite dev server
```
**Serviços docker-compose:**
- `db`: postgres:16-alpine, volume persistente, healthcheck
- `backend`: build ./backend, porta 5000, DATABASE_URL apontando para `db`
- `frontend`: build ./frontend, porta 5173, bind mount src/ para hot-reload, proxy vite → backend
## Out of Scope
- Build de produção (multi-stage, nginx servindo static) — feature futura
- CI/CD pipeline
- Deploy em cloud
- HTTPS/TLS local
## Success Criteria
1. `docker-compose up --build` funciona do zero em máquina limpa
2. `http://localhost:5173` carrega homepage com dados reais
3. `http://localhost:5000/api/v1/properties?featured=true` retorna array JSON com imóveis seedados
4. Alteração em `.tsx` reflete no browser sem restart do container
5. `.env` está no `.gitignore`; `.env.example` documenta todas as variáveis necessárias

View file

@ -0,0 +1,109 @@
# Tasks: Docker Setup
**Branch**: `002-docker-setup`
**Plan**: `.specify/features/002-docker-setup/plan.md`
**Created**: 2026-04-13
---
## Phase 1 — Backend Dockerfile
### T001 — Criar backend/Dockerfile
- **Complexity**: S
- **Dependencies**: nenhuma
- **Spec ref**: FR1, FR3
- **Files**: `backend/Dockerfile`, `backend/entrypoint.sh`
- **Done when**: `docker build -t imob-backend ./backend` conclui sem erro
### T002 — Criar entrypoint.sh com migrations + seed + server
- **Complexity**: S
- **Dependencies**: T001
- **Spec ref**: FR3
- **Files**: `backend/entrypoint.sh`
- **Done when**: Script executa `flask db upgrade`, seeder, e sobe Flask na porta 5000
---
## Phase 2 — Frontend Dockerfile
### T003 — Criar frontend/Dockerfile
- **Complexity**: S
- **Dependencies**: nenhuma [P] paralelo com T001
- **Spec ref**: FR1, FR4
- **Files**: `frontend/Dockerfile`
- **Done when**: `docker build -t imob-frontend ./frontend` conclui sem erro
### T004 — Atualizar vite.config.ts para proxy Docker
- **Complexity**: S
- **Dependencies**: T003
- **Spec ref**: FR1
- **Files**: `frontend/vite.config.ts`
- **Done when**: Proxy aponta para `http://backend:5000` (nome do serviço Docker); local dev ainda funciona via variável de ambiente
---
## Phase 3 — Orquestração
### T005 — Criar docker-compose.yml
- **Complexity**: M
- **Dependencies**: T001, T003
- **Spec ref**: FR1, FR2, FR4, FR5
- **Files**: `docker-compose.yml`
- **Done when**: `docker-compose config` valida; 3 serviços definidos com healthcheck no db
### T006 — Criar .env.example na raiz
- **Complexity**: S
- **Dependencies**: T005
- **Spec ref**: FR5, NFR4
- **Files**: `.env.example` (raiz)
- **Done when**: Todas as variáveis usadas no compose estão documentadas com valores de exemplo
### T007 — Verificar .gitignore cobre .env
- **Complexity**: S
- **Dependencies**: T006
- **Spec ref**: NFR3, NFR4
- **Files**: `.gitignore`
- **Done when**: `.env` está no .gitignore e não aparece em `git status`
---
## Phase 4 — Script de conveniência
### T008 — Criar start.ps1 na raiz
- **Complexity**: S
- **Dependencies**: T005
- **Spec ref**: FR6
- **Files**: `start.ps1`
- **Done when**: `.\start.ps1` valida Docker e executa compose; exibe erro claro se Docker não estiver instalado
---
## Validação
### T009 — Testar docker-compose up --build end-to-end
- **Complexity**: M
- **Dependencies**: T005, T008
- **Spec ref**: Todos os Acceptance Scenarios
- **Done when**:
- `http://localhost:5173` carrega homepage
- `http://localhost:5000/api/v1/homepage-config` retorna 200
- `http://localhost:5000/api/v1/properties?featured=true` retorna array
- Editar um `.tsx` reflete no browser via hot-reload
---
## Resumo
| Task | Fase | Complexidade | Paralelo? |
|------|------|-------------|-----------|
| T001 | Backend Dockerfile | S | - |
| T002 | entrypoint.sh | S | - |
| T003 | Frontend Dockerfile | S | ✅ com T001 |
| T004 | vite proxy Docker | S | - |
| T005 | docker-compose.yml | M | - |
| T006 | .env.example raiz | S | - |
| T007 | .gitignore check | S | - |
| T008 | start.ps1 | S | - |
| T009 | Validação E2E | M | - |
**MVP**: T001T008 = ambiente Docker funcional.