Menuabrir
EstávelAtualizado em 14 de mai. de 2026, 00:06

Este módulo depende de

4
  • membersLista de alunos para envio de lembretes automáticos
  • whatsappEnvio de lembretes 1h e 15min antes da aula
  • intelligenceResume transcript via run_conversation_summary
  • diaryAuto-gera prompt reflexivo pós-aula

Módulos que dependem deste

0

Nenhum módulo depende deste hoje.

Meetings (Aulas + Gravações)

Status: 🟢 Estável (Daily.co + Bunny CDN integrados) Code: backend/app/modules/meetings UI: frontend/src/app/(admin)/[slug]/admin/meeting Última revisão deste doc: 2026-05-13 por Felipe + Claude Dependências fortes: members (lista de alunos pra reminders), whatsapp (envio de lembretes), intelligence (summary), diary (auto-prompt pós-aula)


1. Identidade

O que faz (uma frase)

Agendamento e operação de aulas ao vivo via Daily.co (room provisioning, tokens, transcrição), gravação automática armazenada no Bunny CDN (URL signed), attendance tracking (joined/left), summary IA pós-aula e lembretes WhatsApp automáticos (1h e 15min antes).

Por que existe (negócio)

Mais Consciente faz aulas semanais ao vivo (yoga, meditação, mentorias). Sem este módulo:

  • Felipe usaria Zoom (ou Google Meet) externo, sem integração com membros + acesso restrito.
  • Gravações ficariam no Drive sem player nativo no app.
  • Lembretes manuais pra cada aluno (work humano).

Com Meetings:

  • Sala Daily.co provisionada lazy (só quando admin abre — evita salas vazias).
  • Recording auto pipeline: Daily webhook → download → upload Bunny → ready.
  • Lembretes WA automáticos pros membros do programa.
  • Summary IA + diary prompt pós-aula (integração rica).

Status atual

Em prod, integração Daily + Bunny estável. Reminders ativos.


2. Cases de uso reais

Case 1: Aula semanal de yoga

  1. Admin agenda aula em /admin/meeting/schedule → cria meetings_class(scheduled_at, duration=70min, program_id=yoga).
  2. Beat meetings.send_reminders (5min) → 1h antes envia WA pra todos members do programa.
  3. Admin abre sala (POST /classes/{slug}/open-room) → DailyAdapter cria room idempotent.
  4. Aula acontece. Webhook Daily registra participant_joined/left em meetings_attendance.
  5. Aula termina (status=ended). Webhook recording_readytasks.upload_recording baixa do Daily + uploadeia pro Bunny.
  6. Webhook Bunny video_status → polling → meetings_recording.status=ready.
  7. tasks.generate_summary → intelligence summariza transcript → summary_json populado.
  8. tasks.diary_prompt → diary cria auto-prompt pós-aula.

Case 2: Aluno acessa replay

UI /clube/aulas/passadasGET /classes/{slug}/recording/url → backend gera URL signed Bunny (HMAC-SHA256, expires 24h) → embed iframe.


3. Oportunidades de negócio

  • Recording analytics: quem assistiu replay, quanto tempo, em qual ponto pausou — produto premium.
  • Live engagement scoring: participants que fazem perguntas no chat ganham + pontos CRM.
  • Multi-tenant Daily: cada cliente Mandir tem subdomínio Daily próprio (whitelabel).
  • Summary IA cross-aula: "o que foi recorrente nas últimas 4 aulas?" — content insight.

Riscos: dependência Daily (preço por minute) + Bunny (storage); recording chain pode falhar (URL Daily válida só ~1h após webhook).


4. Arquitetura interna

Arquivos

ArquivoPropósito
models.py5 tabelas
routes.py12 endpoints + webhooks
webhooks.pyDaily + Bunny receivers
service.pyAdapter factory + CRUD classes
adapters/daily.pyDailyAdapter (rooms, tokens, webhooks)
adapters/bunny.pyBunnyStreamAdapter (upload, collections, signed URLs)
tasks/send_reminders.pyBeat 5min
tasks/upload_recording.pyDaily download → Bunny upload
tasks/poll_bunny_status.pyPolling status
tasks/generate_summary.pyIA resume transcript
tasks/diary_prompt.pyIntegração diary pós-aula

Tasks Celery

TaskScheduleO que faz
meetings.send_remindersBeat 5minEnvia WA 1h e 15min antes (marca reminder_*_sent_at)
meetings.upload_recordingOn-demand (webhook trigger)Daily → Bunny
meetings.poll_bunny_statusPollingVerifica bunny_video_guid state
meetings.generate_summaryPost-readyResume transcript via intelligence
meetings.diary_promptPost-summaryCria diary auto-prompt

Adapters externos

ProviderAdapterEndpoints
Daily.coDailyAdaptercreate_room, get_room, delete_room, generate_token
Bunny StreamBunnyStreamAdapterlist_collections, create_collection, upload_from_url (Bunny fetch direto da URL — sem passar bytes), get_video, generate_signed_url (HMAC-SHA256)

5. Tabelas (5)

meetings_class

Coluna chaveNotas
tenant_id
title / slug / descriptionUNIQUE (tenant_id, slug)
instructor_idUUID staff (sem FK)
program_idBackref pra reminders
scheduled_at / duration_minutes (default 70)
statusscheduled / live / ended / canceled
daily_room_name / daily_room_urlLazy — criados on-demand
room_config (JSONB)max_participants, enable_recording, etc.
transcript_raw (JSONB)Deepgram
summary_json (JSONB)título + tópicos + Q&A gerados por IA
reminder_1h_sent_at / reminder_15m_sent_atAnti-duplicate

meetings_class_facilitator

m:n class↔staff. UNIQUE (class_id, staff_id).

meetings_class_guest

Convidado externo (name, title, bio, photo_url).

meetings_recording

Coluna chaveNotas
class_id (FK CASCADE)
daily_recording_idUNIQUE
bunny_video_guid / bunny_collection_guid
statuspending / downloading / uploading / ready / failed
duration_seconds / started_at / ended_at

Pipeline: webhook Daily ready → pending → daily.recording.download → downloading → bunny.upload_from_url → uploading → poll → ready.

meetings_attendance

Coluna chaveNotas
class_id (FK CASCADE)
daily_session_idIdx — upsert key
daily_user_id / display_name
joined_at / left_at / duration_secondsCalculada on left

Relacionamentos cross-módulo

DireçãoOutro móduloComo
↗ Lêmemberslist_contact_accounts pra reminders
↘ Escrevewhatsappsend_message em reminders
↗ Lêintelligencerun_conversation_summary (transcript → summary_json)
↘ EscrevediaryAuto-gera prompt reflexivo pós-aula

6. API / Endpoints (12)

MétodoRotaO que faz
GET/Health
POST/classesCriar
GET/classesLista
GET/classes/{slug}Detalhe
POST/classes/{slug}/open-roomIdempotent — provision Daily room
PUT/classes/{slug}/facilitatorsBatch replace
POST / GET/classes/{slug}/guestsCRUD guests
GET/classes/{slug}/recordingMetadados
GET/classes/{slug}/recording/urlURL signed Bunny (se ready)

Webhooks (sem auth)

  • POST /webhooks/daily/recording-ready
  • POST /webhooks/daily/participant-{joined,left}
  • POST /webhooks/bunny/video-status

7. Configuração

Env vars

VarPropósito
MANDIR_DAILY_API_KEYDaily auth (env global fallback)
MANDIR_DAILY_DOMAINex: "maisconsciente" → maisconsciente.daily.co
MANDIR_BUNNY_STREAM_API_KEY
MANDIR_BUNNY_STREAM_LIBRARY_ID (int)
MANDIR_BUNNY_STREAM_COLLECTION_DEFAULTCollection GUID default
MANDIR_BUNNY_STREAM_TOKEN_AUTH_KEYPra signed URLs

Tenant overrides via tenant_provider_credentials (provider=daily / bunny_stream).


8. Operações + Troubleshooting

Sintoma: Recording fica em "uploading" eternamente

Causa: URL Daily expirou (~1h após webhook). Fix: Admin retrigger manual do upload (sem auto-retry).

Sintoma: Reminders não enviam

Causa: program_id NULL na class → skip. Fix: Vincular class a program.


9. Limitações e débitos técnicos

#Item
1Recording chain serial — falha em qualquer stage = failed
2Sem auto-retry no upload
3URL Daily válida ~1h
4Reminders dependem de program_id
5Webhooks sem auth

10. Histórico

Em prod desde Suite v2. Daily + Bunny adapters estáveis. Pipeline de gravação validado em produção.