chore: seed sample video data, add spec 033 and update instructions
Some checks failed
CI/CD → Deploy via SSH / Build & Push Docker Images (push) Successful in 1m6s
CI/CD → Deploy via SSH / Deploy via SSH (push) Successful in 4m18s
CI/CD → Deploy via SSH / Validate HTTPS & Endpoints (push) Has been cancelled

This commit is contained in:
MatheusAlves96 2026-04-22 23:57:50 -03:00
parent 2e9f903d06
commit e1a1f71fbd
11 changed files with 1911 additions and 2 deletions

View file

@ -0,0 +1,44 @@
# Research: Vídeo de Apresentação do Imóvel (033)
**Gerado por**: /speckit.plan
**Data**: 2026-04-22
---
## Decisão 1 — Estratégia de embed de vídeo
**Decision**: Utilitário puro `getEmbedUrl` no frontend (sem lógica no backend) que faz parse client-side.
**Rationale**: O backend não precisa transformar URLs — salva o valor bruto e devolve sem alteração. O parse pode falhar silenciosamente no cliente sem impactar dados. Reduz complexidade no servidor.
**Alternatives considered**: Validar domínio no backend via Pydantic `@field_validator` — rejeitado porque geraria 422 em URLs válidas de domínios futuros; validação de formato basta no backend.
---
## Decisão 2 — Posição do vídeo: `VARCHAR(20)` vs `ENUM` SQL
**Decision**: `VARCHAR(20) NOT NULL DEFAULT 'section'` — sem ENUM SQL.
**Rationale**: O projeto já usa `db.Enum` apenas para `property_type` onde os valores são críticos para queries. Para posição de vídeo, a validação é feita no Pydantic (`Literal['carousel', 'section']`); usar ENUM SQL adicionaria complexidade em migrations sem benefício mensurável.
**Alternatives considered**: `db.Enum('carousel', 'section', name='video_position')` — rejeitado por custo de migration mais alto.
---
## Decisão 3 — Integração do vídeo no carrossel vs componente separado
**Decision**: Modificar `PhotoCarousel` para aceitar `videoUrl?: string | null` e renderizar o `VideoPlayer` como slide virtual no índice 0 quando a posição for `carousel`. Para posição `section`, renderizar `<VideoPlayer>` fora do carrossel em `PropertyDetailPage`.
**Rationale**: Reuso do sistema de navegação (setas, dots, touch swipe) já testado no carrossel. Não cria um segundo carrossel, não duplica lógica de gestos.
**Alternatives considered**: Criar carrossel separado `MediaCarousel` — rejeitado por YAGNI (sobrecomplexidade para suportar um único slide de vídeo).
---
## Decisão 4 — Sanitização de URL no backend
**Decision**: Aplicar `str.strip()` antes de persistir e tratar string vazia como `None`.
**Rationale**: Previne persistência de URLs com espaços acidentais (edge case da spec). Simples de implementar no update handler existente, sem dependência externa.
**Alternatives considered**: Pydantic `AnyUrl` — rejeitado porque URLs de arquivos diretos (ex.: CDN sem `https://`) precisam ser aceitas; `AnyUrl` restringiria demais.
---
## Decisão 5 — Preview no admin (debounce)
**Decision**: Debounce de 600ms no campo de URL; o preview re-renderiza apenas quando `getEmbedUrl` retorna tipo != `'unknown'`.
**Rationale**: Evita re-renders a cada keystroke enquanto o administrador digita. Valor de 600ms é suficiente para não parecer lento.
**Alternatives considered**: Preview apenas on-blur — rejeitado porque a spec exige "em tempo real" (FR-011).