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
36
specs/020-politica-de-privacidade/checklists/requirements.md
Normal file
36
specs/020-politica-de-privacidade/checklists/requirements.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# Specification Quality Checklist: Política de Privacidade + Link no Footer
|
||||
|
||||
**Purpose**: Validar completude e qualidade da especificação antes de avançar para o planejamento
|
||||
**Created**: 2026-04-17
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- Todos os itens passaram na validação inicial.
|
||||
- Placeholders para nome/CNPJ/endereço da empresa e e-mail do DPO estão documentados nas Assumptions — devem ser preenchidos antes da implementação.
|
||||
- Pronto para `/speckit.plan`.
|
||||
163
specs/020-politica-de-privacidade/data-model.md
Normal file
163
specs/020-politica-de-privacidade/data-model.md
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
# Data Model: Página de Política de Privacidade
|
||||
|
||||
**Feature**: 020-politica-de-privacidade
|
||||
**Phase**: 1 — Design & Contracts
|
||||
**Status**: Complete
|
||||
|
||||
---
|
||||
|
||||
## Nota sobre "Data Model" para feature 100% frontend
|
||||
|
||||
Esta feature não envolve entidades de banco de dados nem estado gerenciado em store. O "modelo de dados" aqui descreve a estrutura lógica do conteúdo estático e o contrato de componentes React.
|
||||
|
||||
---
|
||||
|
||||
## Entidades de Componente
|
||||
|
||||
### PrivacyPolicyPage
|
||||
|
||||
| Propriedade | Tipo | Descrição |
|
||||
|---|---|---|
|
||||
| — | — | Componente sem props (stateless, sem hooks) |
|
||||
|
||||
**Estrutura JSX**:
|
||||
|
||||
```
|
||||
PrivacyPolicyPage
|
||||
├── <Navbar />
|
||||
├── <main id="main-content" className="min-h-screen bg-canvas">
|
||||
│ └── <div className="max-w-[800px] mx-auto px-6 pt-16 pb-20">
|
||||
│ ├── Header (label + título + data de atualização)
|
||||
│ └── Seções (1–8)
|
||||
│ └── <section> com <h2> numerado + <p>/<ul> de conteúdo
|
||||
└── <Footer />
|
||||
```
|
||||
|
||||
**Seções (hardcoded)**:
|
||||
|
||||
```typescript
|
||||
type PolicySection = {
|
||||
id: number // 1–8
|
||||
title: string // "1. Instituição Responsável" etc.
|
||||
content: ReactNode // JSX com paragrafos / listas
|
||||
}
|
||||
```
|
||||
|
||||
*Observação*: O tipo `PolicySection` NÃO precisa ser exportado nem criado como shared type — é usado somente internamente no componente. Principle VI: sem abstração prematura.
|
||||
|
||||
---
|
||||
|
||||
### Footer (atualizado)
|
||||
|
||||
Mudança pontual: adicionar `<Link to="/politica-de-privacidade">` no bloco `<nav>` existente.
|
||||
|
||||
**Estado atual do array `footerLinks`**:
|
||||
```typescript
|
||||
const footerLinks = [
|
||||
{ label: 'Imóveis', href: '/imoveis' },
|
||||
{ label: 'Sobre', href: '#sobre' },
|
||||
{ label: 'Contato', href: '#contato' },
|
||||
]
|
||||
```
|
||||
|
||||
**Após a mudança** — o array `footerLinks` **não é alterado**. Um novo link `<Link>` do react-router-dom é adicionado manualmente no `<ul>` após os links existentes:
|
||||
|
||||
```tsx
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
// no <ul> dos footerLinks, após o map existente:
|
||||
<li>
|
||||
<Link
|
||||
to="/politica-de-privacidade"
|
||||
className="text-xs text-text-tertiary hover:text-text-secondary transition-colors duration-150"
|
||||
>
|
||||
Política de Privacidade
|
||||
</Link>
|
||||
</li>
|
||||
```
|
||||
|
||||
**Rationale**: Adicionar ao array seria inconsistente (o array usa `href` para `<a>`, mas esse precisa de `<Link>`). Manter separado é mais claro e não requer refatorar o loop existente.
|
||||
|
||||
---
|
||||
|
||||
### Rota (App.tsx)
|
||||
|
||||
| Campo | Valor |
|
||||
|---|---|
|
||||
| `path` | `/politica-de-privacidade` |
|
||||
| `element` | `<PrivacyPolicyPage />` |
|
||||
| Posição no arquivo | Após a rota `/corretores`, antes da rota `/login` |
|
||||
| Guards | Nenhum — rota pública |
|
||||
|
||||
---
|
||||
|
||||
## Conteúdo estático das seções
|
||||
|
||||
### Seção 1 — Instituição Responsável
|
||||
|
||||
Nome: `[NOME DA EMPRESA]`
|
||||
CNPJ: `[CNPJ]`
|
||||
Endereço: `[ENDEREÇO COMPLETO]`
|
||||
*Esta empresa é a controladora dos dados pessoais tratados neste site.*
|
||||
|
||||
### Seção 2 — Coleta e Uso de Dados Pessoais
|
||||
|
||||
Dados coletados:
|
||||
- Nome completo, e-mail e telefone ao preencher formulários de contato
|
||||
- Dados de navegação (páginas visitadas, tempo de sessão) via cookies analíticos
|
||||
- Dados fornecidos voluntariamente ao solicitar visitas a imóveis
|
||||
|
||||
Finalidades:
|
||||
- Responder solicitações de contato e agendamento de visitas
|
||||
- Melhorar a experiência de uso do site
|
||||
- Enviar comunicações sobre imóveis compatíveis com o perfil do usuário (com consentimento)
|
||||
|
||||
### Seção 3 — Transferência de Dados Pessoais
|
||||
|
||||
Compartilhamento com:
|
||||
- Corretores parceiros, apenas dados necessários para conduzir visitas
|
||||
- Plataformas de análise de tráfego (ex.: Google Analytics) — dados anonimizados
|
||||
- Não vendemos ou alugamos dados pessoais a terceiros
|
||||
|
||||
### Seção 4 — Uso de Cookies
|
||||
|
||||
Tipos de cookies utilizados:
|
||||
- **Essenciais**: necessários para o funcionamento do site (autenticação, preferências)
|
||||
- **Analíticos**: medem o uso do site para melhoria contínua
|
||||
- O usuário pode desativar cookies analíticos nas configurações do navegador
|
||||
|
||||
### Seção 5 — Direitos do Usuário (LGPD)
|
||||
|
||||
Conforme a Lei 13.709/2018 (LGPD), o titular dos dados tem direito a:
|
||||
- **Acesso**: confirmar a existência e solicitar cópia dos dados tratados
|
||||
- **Correção**: atualizar dados incompletos, inexatos ou desatualizados
|
||||
- **Exclusão**: solicitar a eliminação de dados desnecessários ou tratados com consentimento
|
||||
- **Portabilidade**: receber seus dados em formato estruturado
|
||||
- **Revogação de consentimento**: retirar o consentimento a qualquer momento
|
||||
|
||||
### Seção 6 — Segurança dos Dados
|
||||
|
||||
- Utilizamos conexões HTTPS em todo o site
|
||||
- Dados sensíveis são armazenados com criptografia
|
||||
- Acesso interno limitado ao pessoal autorizado
|
||||
- Revisamos regularmente nossas práticas de segurança
|
||||
|
||||
### Seção 7 — Alterações nesta Política
|
||||
|
||||
Podemos atualizar esta Política periodicamente. A data de "última atualização" é exibida no topo da página. Recomendamos revisão periódica.
|
||||
|
||||
### Seção 8 — Contato / DPO
|
||||
|
||||
Para exercer seus direitos ou esclarecer dúvidas sobre o tratamento de seus dados:
|
||||
E-mail do Encarregado (DPO): `[EMAIL DO DPO]`
|
||||
Link exibido como `<a href="mailto:[EMAIL DO DPO]">` abrindo cliente de e-mail.
|
||||
|
||||
---
|
||||
|
||||
## Validações e regras de estado
|
||||
|
||||
| Regra | Implementação |
|
||||
|---|---|
|
||||
| Sem chamadas de API | Componente não usa `useEffect`, `useState`, nem imports de `services/` |
|
||||
| Sem estado de loading | Nenhum skeleton, spinner ou estado condicional |
|
||||
| Links externos abrem em nova aba | `target="_blank" rel="noopener noreferrer"` no link do e-mail DPO |
|
||||
95
specs/020-politica-de-privacidade/plan.md
Normal file
95
specs/020-politica-de-privacidade/plan.md
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# Implementation Plan: Página de Política de Privacidade + Link no Footer
|
||||
|
||||
**Branch**: `master` | **Date**: 2026-04-17 | **Spec**: [specs/020-politica-de-privacidade/spec.md](spec.md)
|
||||
**Input**: Feature specification from `specs/020-politica-de-privacidade/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Criar a página estática `/politica-de-privacidade` com 8 seções LGPD e adicioná-la ao sistema de roteamento SPA. Adicionar link client-side (`<Link>`) no Footer existente. Feature 100% frontend — sem backend, sem API, sem estado.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: TypeScript 5.5 / React 18
|
||||
**Primary Dependencies**: react-router-dom v6 (já instalado), Tailwind CSS 3.4 (já configurado)
|
||||
**Storage**: N/A — componente puramente estático
|
||||
**Testing**: `npm run build` (TypeScript type-check via tsc); verificação visual manual
|
||||
**Target Platform**: Browser (SPA — Vite/React)
|
||||
**Project Type**: Web application (frontend only)
|
||||
**Performance Goals**: Navegação client-side < 500 ms (SC-003); sem requisições de rede na carga da página
|
||||
**Constraints**: Layout max-width 800px; responsivo ≥ 320px sem overflow horizontal; conformidade total com tema dark do DESIGN.md
|
||||
**Scale/Scope**: 1 componente novo (`PrivacyPolicyPage.tsx`), 2 arquivos modificados (`App.tsx`, `Footer.tsx`)
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
| Princípio | Status | Evidência |
|
||||
|---|---|---|
|
||||
| **I. Design-First** | ✅ PASS | Componente usa `bg-canvas`, `text-text-primary`, `text-text-secondary`, `border-white/[0.06]`, `fontFeatureSettings: '"cv01","ss03"'` — tokens idênticos às demais páginas. Max-width 800px, responsivo. Nenhum estilo inline que desvie do design system. |
|
||||
| **II. Separation of Concerns** | ✅ PASS | Feature 100% frontend. Nenhuma rota Flask nova. Nenhum modelo de dados alterado. |
|
||||
| **III. Spec-Driven Development** | ✅ PASS | `spec.md` aprovado com user stories e acceptance scenarios. Ordem: spec → plan → tasks → implement. |
|
||||
| **IV. Data Integrity** | ✅ N/A | Sem entidades de banco. Sem Pydantic schemas. Sem migrations. |
|
||||
| **V. Security** | ✅ PASS | Rota pública sem guards — correto (política de privacidade é pública). Nenhum token ou secret no frontend. |
|
||||
| **VI. Simplicity First** | ✅ PASS | Componente stateless. Sem hooks. Sem services. Sem abstrações novas. 3 arquivos alterados/criados. Conteúdo inline no componente. |
|
||||
|
||||
**Resultado**: Nenhuma violação. Pode avançar para implementação.
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/020-politica-de-privacidade/
|
||||
├── plan.md ← este arquivo
|
||||
├── research.md ← gerado (Phase 0)
|
||||
├── data-model.md ← gerado (Phase 1)
|
||||
├── quickstart.md ← gerado (Phase 1)
|
||||
└── tasks.md ← será gerado pelo /speckit.tasks
|
||||
```
|
||||
|
||||
### Source Code (arquivos desta feature)
|
||||
|
||||
```text
|
||||
frontend/
|
||||
├── src/
|
||||
│ ├── pages/
|
||||
│ │ └── PrivacyPolicyPage.tsx ← CRIAR (novo)
|
||||
│ ├── components/
|
||||
│ │ └── Footer.tsx ← MODIFICAR (adicionar Link)
|
||||
│ └── App.tsx ← MODIFICAR (adicionar rota)
|
||||
```
|
||||
|
||||
**Sem backend envolvido.** Sem migrations, sem novos endpoints, sem schemas Pydantic.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Approach
|
||||
|
||||
### Fase de implementação (executada via /speckit.tasks)
|
||||
|
||||
**Task 1 — Criar `PrivacyPolicyPage.tsx`**
|
||||
Componente stateless com Navbar + main + Footer. Conteúdo estático das 8 seções LGPD inline. Design conforme tokens do DESIGN.md. Ver `data-model.md` para estrutura e conteúdo de cada seção.
|
||||
|
||||
**Task 2 — Adicionar rota em `App.tsx`**
|
||||
Importar `PrivacyPolicyPage` e adicionar `<Route path="/politica-de-privacidade" element={<PrivacyPolicyPage />} />` após a rota `/corretores`.
|
||||
|
||||
**Task 3 — Atualizar `Footer.tsx`**
|
||||
Importar `Link` do react-router-dom. Adicionar `<li><Link to="/politica-de-privacidade" ...>Política de Privacidade</Link></li>` no `<ul>` de navegação, após o map de `footerLinks`.
|
||||
|
||||
### Ordem de execução
|
||||
|
||||
Tasks 1, 2 e 3 são independentes em si, mas a verificação funcional requer todas completas. Ordem sugerida: 1 → 2 → 3 (criar página primeiro, depois rota, depois link no footer).
|
||||
|
||||
---
|
||||
|
||||
## Artefatos gerados
|
||||
|
||||
| Artefato | Caminho |
|
||||
|---|---|
|
||||
| Spec | [specs/020-politica-de-privacidade/spec.md](spec.md) |
|
||||
| Research | [specs/020-politica-de-privacidade/research.md](research.md) |
|
||||
| Data Model | [specs/020-politica-de-privacidade/data-model.md](data-model.md) |
|
||||
| Quickstart | [specs/020-politica-de-privacidade/quickstart.md](quickstart.md) |
|
||||
| Tasks | `specs/020-politica-de-privacidade/tasks.md` *(gerado por /speckit.tasks)* |
|
||||
150
specs/020-politica-de-privacidade/quickstart.md
Normal file
150
specs/020-politica-de-privacidade/quickstart.md
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
# Quickstart: Página de Política de Privacidade
|
||||
|
||||
**Feature**: 020-politica-de-privacidade
|
||||
**Branch**: `master` (feature branch recomendada: `feat/020-politica-de-privacidade`)
|
||||
|
||||
---
|
||||
|
||||
## Pré-requisitos
|
||||
|
||||
- Node.js instalado
|
||||
- Dependências do frontend instaladas: `cd frontend && npm install`
|
||||
- Docker em execução (opcional — apenas se precisar do backend para outras páginas)
|
||||
|
||||
---
|
||||
|
||||
## Arquivos envolvidos
|
||||
|
||||
| Ação | Arquivo |
|
||||
|---|---|
|
||||
| **Criar** | `frontend/src/pages/PrivacyPolicyPage.tsx` |
|
||||
| **Modificar** | `frontend/src/components/Footer.tsx` |
|
||||
| **Modificar** | `frontend/src/App.tsx` |
|
||||
|
||||
---
|
||||
|
||||
## Como rodar o frontend em dev
|
||||
|
||||
```powershell
|
||||
cd frontend
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Acesse `http://localhost:5173/politica-de-privacidade` para verificar a nova página.
|
||||
|
||||
---
|
||||
|
||||
## Passo a passo de implementação
|
||||
|
||||
### 1. Criar `PrivacyPolicyPage.tsx`
|
||||
|
||||
```tsx
|
||||
// frontend/src/pages/PrivacyPolicyPage.tsx
|
||||
import Footer from '../components/Footer'
|
||||
import Navbar from '../components/Navbar'
|
||||
|
||||
export default function PrivacyPolicyPage() {
|
||||
return (
|
||||
<>
|
||||
<Navbar />
|
||||
<main id="main-content" className="min-h-screen bg-canvas">
|
||||
<div className="max-w-[800px] mx-auto px-6 pt-16 pb-20">
|
||||
{/* Header */}
|
||||
<p className="text-[#5e6ad2] text-sm font-medium tracking-widest uppercase mb-3">
|
||||
Legal
|
||||
</p>
|
||||
<h1
|
||||
className="text-3xl md:text-4xl font-semibold text-text-primary tracking-tight mb-2"
|
||||
style={{ fontFeatureSettings: '"cv01","ss03"' }}
|
||||
>
|
||||
Política de Privacidade
|
||||
</h1>
|
||||
<p className="text-text-tertiary text-sm mb-12">
|
||||
Última atualização: abril de 2026
|
||||
</p>
|
||||
|
||||
{/* Seções */}
|
||||
<div className="space-y-10">
|
||||
{/* Seção 1 */}
|
||||
<section>
|
||||
<h2 className="text-lg font-semibold text-text-primary mb-3"
|
||||
style={{ fontFeatureSettings: '"cv01","ss03"' }}>
|
||||
1. Instituição Responsável
|
||||
</h2>
|
||||
<p className="text-text-secondary text-sm leading-relaxed">
|
||||
[NOME DA EMPRESA], inscrita no CNPJ sob o nº [CNPJ], com sede em [ENDEREÇO COMPLETO],
|
||||
é a controladora dos dados pessoais tratados por meio deste site.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Seção 2 */}
|
||||
<section>
|
||||
<h2 ...>2. Coleta e Uso de Dados Pessoais</h2>
|
||||
...
|
||||
</section>
|
||||
|
||||
{/* ... demais seções ... */}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
> **Ver data-model.md para o conteúdo completo de cada seção.**
|
||||
|
||||
---
|
||||
|
||||
### 2. Adicionar rota em `App.tsx`
|
||||
|
||||
```tsx
|
||||
// após import de AgentsPage
|
||||
import PrivacyPolicyPage from './pages/PrivacyPolicyPage';
|
||||
|
||||
// dentro de <Routes>, após a rota /corretores:
|
||||
<Route path="/politica-de-privacidade" element={<PrivacyPolicyPage />} />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Atualizar `Footer.tsx`
|
||||
|
||||
```tsx
|
||||
// Adicionar import no topo:
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
// No <ul> dos footerLinks, adicionar após o map existente:
|
||||
<li>
|
||||
<Link
|
||||
to="/politica-de-privacidade"
|
||||
className="text-xs text-text-tertiary hover:text-text-secondary transition-colors duration-150"
|
||||
>
|
||||
Política de Privacidade
|
||||
</Link>
|
||||
</li>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verificação de conformidade
|
||||
|
||||
| Critério | Como verificar |
|
||||
|---|---|
|
||||
| 8 seções presentes | Contar visualmente em `http://localhost:5173/politica-de-privacidade` |
|
||||
| Link no Footer funciona sem reload | Abrir DevTools > Network, clicar no link — nenhuma requisição de documento nova |
|
||||
| Sem chamadas de API | DevTools > Network > XHR/Fetch — vazio ao carregar a página |
|
||||
| Responsivo em 375px | DevTools > Device Toolbar → iPhone SE |
|
||||
| Tema dark consistente | Comparar com `http://localhost:5173/corretores` — mesmas cores/fontes |
|
||||
|
||||
---
|
||||
|
||||
## Build de validação
|
||||
|
||||
```powershell
|
||||
cd frontend
|
||||
npm run build
|
||||
```
|
||||
|
||||
Sem erros de TypeScript = pronto para PR.
|
||||
100
specs/020-politica-de-privacidade/research.md
Normal file
100
specs/020-politica-de-privacidade/research.md
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
# Research: Página de Política de Privacidade
|
||||
|
||||
**Feature**: 020-politica-de-privacidade
|
||||
**Phase**: 0 — Outline & Research
|
||||
**Status**: Complete — sem NEEDS CLARIFICATION
|
||||
|
||||
---
|
||||
|
||||
## 1. Padrão de página estática no projeto
|
||||
|
||||
**Decision**: Usar o mesmo padrão de `AgentsPage.tsx` — `<Navbar />` + `<main className="min-h-screen bg-canvas">` + `<Footer />`.
|
||||
|
||||
**Rationale**: Todas as páginas públicas do projeto seguem este padrão. `AgentsPage.tsx` é o exemplo mais recente e pode ser usado como referência direta.
|
||||
|
||||
**Alternatives considered**: Criar um componente `PublicLayout` com Navbar/Footer embutidos. Rejeitado por violar Principle VI (YAGNI — só 1 page nova, sem reutilização real).
|
||||
|
||||
---
|
||||
|
||||
## 2. Roteamento client-side
|
||||
|
||||
**Decision**: Adicionar `<Route path="/politica-de-privacidade" element={<PrivacyPolicyPage />} />` direto no arquivo `frontend/src/App.tsx`, na mesma camada das rotas públicas (`/`, `/imoveis`, `/corretores`).
|
||||
|
||||
**Rationale**: Padrão já usado por todas as rotas públicas. Sem guards de autenticação necessários.
|
||||
|
||||
**Alternatives considered**: Rota aninhada num layout público. Rejeitado — nenhuma outra rota pública usa layout aninhado; seria over-engineering.
|
||||
|
||||
---
|
||||
|
||||
## 3. Link no Footer — `<a>` vs `<Link>`
|
||||
|
||||
**Decision**: Usar `<Link to="/politica-de-privacidade">` do `react-router-dom` para o novo link no Footer. Os links existentes (`#sobre`, `#contato`) permanecem como `<a>` (são âncoras intra-página, não rotas SPA). O link `/imoveis` existente também fica como `<a>` para não alterar comportamento legado fora do escopo.
|
||||
|
||||
**Rationale**: FR-006 exige navegação sem recarregamento. O `<Link>` do React Router garante transição client-side sem `window.location` reload. O Footer está dentro do `<BrowserRouter>` (App.tsx), então `<Link>` funciona sem nenhuma mudança estrutural.
|
||||
|
||||
**Alternatives considered**:
|
||||
1. Converter todos os links do footer para `<Link>` — fora de escopo, Principle VI proíbe mudanças além do especificado.
|
||||
2. Usar `<a href="/politica-de-privacidade">` — causaria reload completo da página, violando FR-006 e SC-003.
|
||||
|
||||
---
|
||||
|
||||
## 4. Design tokens a utilizar
|
||||
|
||||
**Decision**: Seguir exatamente as classes Tailwind mapeadas para os tokens do DESIGN.md:
|
||||
|
||||
| Elemento | Classe Tailwind |
|
||||
|---|---|
|
||||
| Fundo da página | `bg-canvas` |
|
||||
| Fundo de seção alternada (opcional) | N/A — fundo único para simplicidade |
|
||||
| Texto principal (título, corpo) | `text-text-primary` |
|
||||
| Texto secundário | `text-text-secondary` |
|
||||
| Texto terciário (metadata) | `text-text-tertiary` |
|
||||
| Separador entre seções | `border-white/[0.06]` |
|
||||
| Largura máxima do conteúdo | `max-w-[800px] mx-auto px-6` |
|
||||
| Títulos de seção | `font-semibold text-text-primary` + `fontFeatureSettings: '"cv01","ss03"'` |
|
||||
| Label de categoria | `text-[#5e6ad2] text-sm font-medium tracking-widest uppercase` |
|
||||
|
||||
**Rationale**: Alinhamento com Principle I (Design-First). Tokens já existentes no `tailwind.config.ts`; sem novos tokens necessários.
|
||||
|
||||
---
|
||||
|
||||
## 5. Estrutura das 8 seções LGPD
|
||||
|
||||
**Decision**: Conteúdo estático inline no componente. Sem fonte de dados externa, sem CMS, sem JSON separado.
|
||||
|
||||
**Rationale**: Principle VI — a solução mais simples. A política muda raramente; extrair para arquivo JSON seria over-abstraction sem benefício concreto.
|
||||
|
||||
**Seções obrigatórias (FR-003)**:
|
||||
|
||||
| # | Título | Conteúdo-chave |
|
||||
|---|---|---|
|
||||
| 1 | Instituição Responsável | Nome, CNPJ, endereço (placeholders) |
|
||||
| 2 | Coleta e Uso de Dados Pessoais | Quais dados, finalidade de uso |
|
||||
| 3 | Transferência de Dados Pessoais | Compartilhamento com terceiros (parceiros, financeiras) |
|
||||
| 4 | Uso de Cookies | Tipos de cookies, finalidade |
|
||||
| 5 | Direitos do Usuário | Acesso, correção, exclusão, portabilidade, revogação de consentimento |
|
||||
| 6 | Segurança dos Dados | Medidas técnicas adotadas |
|
||||
| 7 | Alterações nesta Política | Versionamento e data de última atualização |
|
||||
| 8 | Contato / DPO | E-mail do encarregado (placeholder `[EMAIL DO DPO]`) |
|
||||
|
||||
---
|
||||
|
||||
## 6. Responsividade
|
||||
|
||||
**Decision**: `max-w-[800px] mx-auto px-6` para o container do conteúdo. Em mobile, o padding `px-6` garante margens laterais. Sem media queries adicionais — Tailwind + text-base resolve legibilidade.
|
||||
|
||||
**Rationale**: SC-004 exige legibilidade a partir de 320px sem overflow horizontal. O container com `px-6` e `max-w-[800px]` atende naturalmente por ser menor que qualquer viewport padrão >375px.
|
||||
|
||||
---
|
||||
|
||||
## 7. Dependências novas
|
||||
|
||||
**Decision**: Nenhuma dependência nova.
|
||||
|
||||
**Rationale**: `react-router-dom` já está instalado. Tailwind já configurado. Principle VI — sem pacotes novos sem justificativa.
|
||||
|
||||
---
|
||||
|
||||
## Resolução de NEEDS CLARIFICATION
|
||||
|
||||
Não havia ambiguidades de natureza técnica que exigissem pesquisa externa. Todos os pontos foram resolvidos com base no código existente no projeto.
|
||||
120
specs/020-politica-de-privacidade/spec.md
Normal file
120
specs/020-politica-de-privacidade/spec.md
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
# Feature Specification: Página de Política de Privacidade + Link no Footer
|
||||
|
||||
**Feature Branch**: `020-politica-de-privacidade`
|
||||
**Created**: 2026-04-17
|
||||
**Status**: Draft
|
||||
**Input**: Criar página estática /politica-de-privacidade com conteúdo LGPD adaptado para imobiliária e link no Footer existente.
|
||||
|
||||
---
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 — Visitante lê a Política de Privacidade (Priority: P1)
|
||||
|
||||
Um visitante do site deseja conhecer como seus dados pessoais são tratados pela imobiliária. Ele navega até `/politica-de-privacidade` e encontra o documento completo, com todas as seções exigidas pela LGPD, organizado de forma legível.
|
||||
|
||||
**Why this priority**: Requisito de conformidade legal (LGPD). Toda empresa que coleta dados pessoais deve disponibilizar a política de privacidade de forma clara e acessível.
|
||||
|
||||
**Independent Test**: Pode ser testado acessando diretamente `/politica-de-privacidade` no navegador e verificando que o conteúdo é exibido com todas as 8 seções, Navbar e Footer presentes.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** o visitante está em qualquer página do site, **When** digita `/politica-de-privacidade` na URL, **Then** a página carrega com título "Política de Privacidade", Navbar, Footer e as 8 seções numeradas.
|
||||
2. **Given** o visitante está na página de política, **When** a página carrega, **Then** todo o conteúdo é exibido sem chamadas de API, sem estado de carregamento e sem erros.
|
||||
3. **Given** o visitante lê a página em dispositivo móvel, **When** a página renderiza, **Then** o texto é legível, sem overflow horizontal e com espaçamento adequado.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 — Visitante encontra o link da Política no Footer (Priority: P2)
|
||||
|
||||
Um visitante está no rodapé do site (Footer) em qualquer página e deseja localizar o link para a Política de Privacidade.
|
||||
|
||||
**Why this priority**: O Footer é o local padrão e esperado pelos usuários para links legais. Garantir a descoberta do link é essencial para conformidade e UX.
|
||||
|
||||
**Independent Test**: Pode ser testado verificando o componente Footer em qualquer página — o link "Política de Privacidade" deve estar visível e clicar nele deve navegar para `/politica-de-privacidade` sem recarregar a página.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** o visitante está em qualquer página com Footer, **When** rola até o rodapé, **Then** o link "Política de Privacidade" está visível.
|
||||
2. **Given** o visitante clica no link "Política de Privacidade" no Footer, **When** o clique é registrado, **Then** o roteamento navega para `/politica-de-privacidade` sem recarregamento completo da página.
|
||||
3. **Given** o visitante está na página de Política e clica no logo ou em um link de navegação, **When** o clique é registrado, **Then** ele retorna à página anterior normalmente.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 — Visitante identifica a empresa responsável e o canal de contato (Priority: P3)
|
||||
|
||||
Um visitante que lê a política deseja saber qual empresa é responsável pelo tratamento dos seus dados e como entrar em contato com o encarregado (DPO).
|
||||
|
||||
**Why this priority**: A LGPD exige identificação do controlador e disponibilização do canal de comunicação com o DPO. É requisito legal e melhora a confiança do usuário.
|
||||
|
||||
**Independent Test**: Pode ser testado verificando que a seção "Instituição Responsável" e a seção "Contato / DPO" contêm nome da empresa, informações de contato e canal para exercício de direitos LGPD.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** o visitante está na página de Política, **When** lê a seção 1, **Then** encontra o nome, endereço e CNPJ da empresa responsável.
|
||||
2. **Given** o visitante deseja exercer seus direitos (acesso, correção, exclusão), **When** lê a seção 8, **Then** encontra um endereço de e-mail ou formulário para contato com o DPO.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- O que acontece se o usuário acessa `/politica-de-privacidade` com JavaScript desabilitado? (SPA — página não renderiza; comportamento aceitável para PWA/SPA)
|
||||
- O que acontece se o usuário acessar a rota diretamente após um refresh? (deve funcionar normalmente com o roteamento configurado)
|
||||
- O conteúdo é longo — a rolagem da página deve funcionar normalmente sem quebras de layout.
|
||||
- Links externos na seção de contato devem abrir em nova aba para não desviar o usuário do site.
|
||||
|
||||
---
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: O sistema DEVE exibir a página de Política de Privacidade na rota `/politica-de-privacidade`.
|
||||
- **FR-002**: A página DEVE incluir o componente Navbar no topo e o componente Footer no rodapé, idênticos aos demais do site.
|
||||
- **FR-003**: A página DEVE apresentar as seguintes 8 seções numeradas, nesta ordem:
|
||||
1. Instituição Responsável
|
||||
2. Coleta e Uso de Dados Pessoais
|
||||
3. Transferência de Dados Pessoais
|
||||
4. Uso de Cookies
|
||||
5. Direitos do Usuário (acesso, correção, exclusão, portabilidade — conforme LGPD)
|
||||
6. Segurança dos Dados
|
||||
7. Alterações nesta Política
|
||||
8. Contato / DPO
|
||||
- **FR-004**: Cada seção DEVE ter um título com numeração visível (ex.: "1. Instituição Responsável") e conteúdo textual explicativo.
|
||||
- **FR-005**: O conteúdo da página DEVE ser puramente estático — sem chamadas de API, sem fetchs de dados externos.
|
||||
- **FR-006**: O Footer DEVE conter um link de texto "Política de Privacidade" que navega para `/politica-de-privacidade` usando roteamento client-side (sem reload da página).
|
||||
- **FR-007**: O layout do conteúdo principal DEVE ter largura máxima de 800 px e ser centralizado horizontalmente na tela.
|
||||
- **FR-008**: O design DEVE ser consistente com o tema escuro (dark) existente no site, utilizando as mesmas variáveis de cor e tipografia do restante das páginas.
|
||||
- **FR-009**: A seção de Direitos do Usuário DEVE mencionar explicitamente: direito de acesso, correção, exclusão, portabilidade e revogação de consentimento, conforme a LGPD.
|
||||
- **FR-010**: A seção de Contato / DPO DEVE incluir um canal de comunicação (e-mail) para que o usuário exerça seus direitos LGPD.
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **PrivacyPolicyPage**: Componente de página React, sem estado próprio (stateless), responsável por renderizar o conteúdo da política. Localizado em `frontend/src/pages/PrivacyPolicyPage.tsx`.
|
||||
- **Footer (atualizado)**: Componente existente que receberá o link adicional para a política de privacidade. Localizado em `frontend/src/components/Footer.tsx`.
|
||||
- **Rota /politica-de-privacidade**: Entrada no sistema de roteamento client-side que mapeia a URL para `PrivacyPolicyPage`.
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: O link "Política de Privacidade" está presente e clicável no Footer em 100% das páginas que incluem o Footer.
|
||||
- **SC-002**: A página `/politica-de-privacidade` exibe as 8 seções obrigatórias, cada uma com título numerado e conteúdo.
|
||||
- **SC-003**: A navegação para a página a partir do Footer ocorre em menos de 500 ms (transição client-side, sem recarregamento).
|
||||
- **SC-004**: O layout é responsivo — legível em telas a partir de 320 px de largura sem overflow horizontal.
|
||||
- **SC-005**: A conformidade visual é total: as mesmas cores, fontes e espaçamentos do tema dark são aplicados, sem elementos que "quebrem" o padrão visual do site.
|
||||
- **SC-006**: O conteúdo da seção 5 (Direitos do Usuário) abrange todos os 5 direitos previstos na LGPD mencionados nos requisitos.
|
||||
|
||||
---
|
||||
|
||||
## Assumptions
|
||||
|
||||
- O nome, CNPJ e endereço da empresa imobiliária serão fornecidos para preenchimento do conteúdo da seção 1 (Instituição Responsável); enquanto não fornecidos, placeholders serão utilizados como `[NOME DA EMPRESA]`, `[CNPJ]` e `[ENDEREÇO]`.
|
||||
- O e-mail do DPO (encarregado de dados) será fornecido para a seção 8; enquanto não fornecido, será usado o placeholder `[EMAIL DO DPO]`.
|
||||
- O componente Layout que envolve Navbar + Footer já existe e será reutilizado da mesma forma que nas demais páginas.
|
||||
- Não há necessidade de versionamento do conteúdo da política — a data de "última atualização" será estática no código.
|
||||
- A página não precisa suportar múltiplos idiomas (apenas português brasileiro).
|
||||
- Acessibilidade básica (contraste adequado, semântica HTML) é esperada mas não requer certificação WCAG formal nesta versão.
|
||||
- O conteúdo textual da política sera adequado para uma imobiliária genérica, baseado na LGPD; não é um documento jurídico revisado por advogado.
|
||||
132
specs/020-politica-de-privacidade/tasks.md
Normal file
132
specs/020-politica-de-privacidade/tasks.md
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
# Tasks: Página de Política de Privacidade + Link no Footer
|
||||
|
||||
**Input**: Design documents from `specs/020-politica-de-privacidade/`
|
||||
**Prerequisites**: plan.md ✅, spec.md ✅, data-model.md ✅, quickstart.md ✅, research.md ✅
|
||||
|
||||
**Tests**: Não solicitados — verificação por `npm run build` e inspeção visual (conforme plan.md).
|
||||
|
||||
**Escopo**: 1 arquivo criado, 2 arquivos modificados — 100% frontend, sem backend, sem dependências novas.
|
||||
|
||||
## Format: `[ID] [P?] [Story] Description`
|
||||
|
||||
- **[P]**: Pode rodar em paralelo (arquivos diferentes, sem dependências entre si)
|
||||
- **[Story]**: User story a que a task pertence (US1, US2, US3)
|
||||
- Todos os caminhos são relativos à raiz do repositório
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Setup & Foundational
|
||||
|
||||
> **Não aplicável** — projeto já inicializado, sem novas dependências, sem infraestrutura nova.
|
||||
> Pode avançar diretamente para as user stories.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: User Story 1 — Visitante lê a Política de Privacidade (Priority: P1) 🎯 MVP
|
||||
|
||||
**Goal**: Criar o componente `PrivacyPolicyPage` e registrá-lo no roteador para que a rota `/politica-de-privacidade` funcione.
|
||||
|
||||
**Independent Test**: Acessar `http://localhost:5173/politica-de-privacidade` no navegador após `npm run dev`. A página deve renderizar com Navbar, 8 seções numeradas e Footer, sem erros no console e sem chamadas de rede.
|
||||
|
||||
- [ ] T001 [P] [US1] Criar componente `PrivacyPolicyPage` stateless com Navbar, `<main>` centralizado (max-width 800 px), 8 seções LGPD numeradas e Footer, usando tokens `bg-canvas`, `text-text-primary`, `text-text-secondary`, `text-text-tertiary` e `fontFeatureSettings: '"cv01","ss03"'` em `frontend/src/pages/PrivacyPolicyPage.tsx`
|
||||
- [ ] T002 [US1] Importar `PrivacyPolicyPage` e adicionar `<Route path="/politica-de-privacidade" element={<PrivacyPolicyPage />} />` após a rota `/corretores` em `frontend/src/App.tsx`
|
||||
|
||||
**Checkpoint**: Rota `/politica-de-privacidade` acessível no browser com as 8 seções visíveis. User Story 1 completa e testável de forma independente.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 2 — Visitante encontra o link da Política no Footer (Priority: P2)
|
||||
|
||||
**Goal**: Adicionar link "Política de Privacidade" no Footer usando roteamento client-side (sem reload da página).
|
||||
|
||||
**Independent Test**: Em qualquer página do site com Footer visível, verificar que o link "Política de Privacidade" está presente no rodapé e que clicar nele navega para `/politica-de-privacidade` sem recarregar a página (SPA navigation).
|
||||
|
||||
- [ ] T003 [P] [US2] Importar `Link` de `react-router-dom` e adicionar `<li><Link to="/politica-de-privacidade" ...>Política de Privacidade</Link></li>` no `<ul>` de navegação, após o `map` de `footerLinks` existente, com classes `text-xs text-text-tertiary hover:text-text-secondary transition-colors duration-150` em `frontend/src/components/Footer.tsx`
|
||||
|
||||
**Checkpoint**: Link visível no Footer de qualquer página; clique navega via SPA sem recarregamento. User Story 2 completa e testável de forma independente.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 3 — Visitante identifica empresa responsável e canal de contato (Priority: P3)
|
||||
|
||||
**Goal**: Substituir os placeholders `[NOME DA EMPRESA]`, `[CNPJ]`, `[ENDEREÇO COMPLETO]` e `[E-MAIL DO DPO]` nas seções 1 e 8 pelos dados reais da imobiliária.
|
||||
|
||||
**Independent Test**: Na página `/politica-de-privacidade`, seção 1 deve conter nome completo, CNPJ e endereço da empresa. Seção 8 deve conter endereço de e-mail válido para contato com o DPO.
|
||||
|
||||
- [ ] T004 [US3] Substituir placeholders na seção 1 (nome, CNPJ, endereço) e na seção 8 (e-mail do DPO) pelos dados reais da empresa em `frontend/src/pages/PrivacyPolicyPage.tsx`
|
||||
|
||||
**Checkpoint**: Seções 1 e 8 sem placeholders; conformidade LGPD com identificação do controlador e canal de comunicação com DPO. User Story 3 completa.
|
||||
|
||||
---
|
||||
|
||||
## Phase Final: Polish & Verificação
|
||||
|
||||
**Purpose**: Validação de tipos, build e verificação final de responsividade.
|
||||
|
||||
- [ ] T005 Executar `npm run build` no diretório `frontend/` e confirmar que não há erros de TypeScript nem de compilação
|
||||
- [ ] T006 [P] Verificar responsividade da `PrivacyPolicyPage` em larguras ≥ 320 px (mobile) e ≥ 1280 px (desktop) — sem overflow horizontal, texto legível, espaçamento adequado
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### Dependências entre tasks
|
||||
|
||||
| Task | Depende de | Motivo |
|
||||
|---|---|---|
|
||||
| T002 | T001 | Importa `PrivacyPolicyPage` criado em T001 |
|
||||
| T004 | T001 | Edita o arquivo criado em T001 |
|
||||
| T005 | T001, T002, T003, T004 | Build final após todas as mudanças |
|
||||
| T006 | T001, T002 | Requer a página funcional para testar responsividade |
|
||||
|
||||
### Tasks independentes (sem dependências entre si)
|
||||
|
||||
- **T001** e **T003** podem ser executadas em paralelo por devs diferentes — arquivos distintos, zero conflito.
|
||||
|
||||
### Ordem sugerida (desenvolvedor solo)
|
||||
|
||||
```
|
||||
T001 → T002 → T003 → T004 → T005 → T006
|
||||
```
|
||||
|
||||
### Ordem sugerida (dois devs em paralelo)
|
||||
|
||||
```
|
||||
Dev A: T001 → T002 → T004 → T005
|
||||
Dev B: T003 → T006
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Parallel Example: User Story 1 (MVP solo)
|
||||
|
||||
```bash
|
||||
# 1. Criar o componente
|
||||
# frontend/src/pages/PrivacyPolicyPage.tsx — novo arquivo
|
||||
|
||||
# 2. Adicionar rota
|
||||
# frontend/src/App.tsx — adicionar Route após /corretores
|
||||
|
||||
# 3. Verificar
|
||||
cd frontend && npm run dev
|
||||
# Abrir http://localhost:5173/politica-de-privacidade
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### MVP (apenas US1 — T001 + T002)
|
||||
|
||||
Entrega mínima: a página existe e é acessível via URL. Footer sem link ainda. Dados reais preenchidos depois.
|
||||
|
||||
### Incremental delivery
|
||||
|
||||
1. **Sprint 1** — T001 + T002: Página acessível (US1 ✅)
|
||||
2. **Sprint 1** — T003: Link no Footer (US2 ✅)
|
||||
3. **Sprint 2** — T004: Dados reais da empresa (US3 ✅)
|
||||
4. **Sprint 2** — T005 + T006: Build limpo + verificação visual (Polish ✅)
|
||||
|
||||
### Sem testes automatizados
|
||||
|
||||
Conforme `plan.md` ("Testing: `npm run build` (TypeScript type-check via tsc); verificação visual manual"), não foram geradas tasks de teste automatizado para esta feature.
|
||||
Loading…
Add table
Add a link
Reference in a new issue