# 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 `` 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).