Playback analytics em app dedicado (apps.streaming)
MediaPlaybackSession e MediaPlaybackHeartbeat (watchtime, heatmap, completion rate) foram extraídos de apps.media para um novo app, apps.streaming, mesmo padrão já usado para desacoplar apps.payments de apps.communities.
Contexto
apps.media cresceu como um pipeline único (views.py 536 linhas, tasks.py 885 linhas) misturando dois domínios:
- Pipeline de processamento: upload, import (URL/yt-dlp), transcode+HLS, extração de áudio, transcrição (Deepgram), diarização, sumarização, stem separation (Demucs), dubbing. Todos esses estágios escrevem no mesmo
Mediarow através de umachain/chordCelery única (enqueue_media_processing, ADR 0004) — fortemente acoplados entre si por design. - Playback analytics:
MediaPlaybackSession/MediaPlaybackHeartbeat, alimentados pelo endpoint de heartbeat do player (navigator.sendBeacon) e consumidos pelo resumo de analytics/heatmap. Dependem apenas de uma FK paraMedia— sem nenhum acoplamento com o pipeline de processamento.
Decisão
Mover playback analytics para apps.streaming:
- Models:
MediaPlaybackSession,MediaPlaybackHeartbeat(FK cross-app paramedia.Media, mantendo os nomes de tabela originaismedia_mediaplaybacksession/media_mediaplaybackheartbeatviaMeta.db_table— evita qualquer DDL na migração de mudança de app). - Views:
MediaPlaybackHeartbeatView,MediaAnalyticsSummaryView. - URLs inalteradas (
/api/v1/media/<id>/heartbeat/,/api/v1/media/<id>/analytics/) — zero impacto no client gerado/frontend, só o módulo Django dono do endpoint muda. - Migração feita com
SeparateDatabaseAndState(media/migrations/0013_...+streaming/migrations/0001_initial.py): move apenas o state do Django entre apps, sem tocar nas tabelas já existentes (criadas pormedia/migrations/0012_...).
O pipeline de processamento (transcode/HLS, transcrição, stems, dubbing) permanece em apps.media — os campos HLS/transcript/stems/dubs vivem na mesma row de Media e a chain do Celery depende disso ficar unificado; separar exigiria fragmentar o model Media ou orquestrar tasks cross-app, custo maior que o ganho.
Consequências
apps.mediavolta a ser só "pipeline de processamento de mídia";apps.streamingé "métricas de reprodução".- Uma futura feature de streaming ao vivo/analytics adicional tem um app natural para crescer sem inchar
apps.mediade novo. Media.hls_video_url/campos HLS continuam emapps.media— não confundirapps.streaming(analytics) com "geração de HLS" (que continua no pipeline).