Ir para o conteúdo

Backend - Marketplace de Cursos

Objetivo

Documentar o estado atual do domínio de cursos após o ciclo de refatoração full (big bang), cobrindo contratos, modelos, permissões e migrações.

Resumo do que mudou

  1. Contratos de curso migrados para centavos (price_amount_cents).
  2. Vídeo desacoplado de fornecedor específico (video_provider, video_*).
  3. Duração de curso removida do modelo persistido e calculada por soma de aulas (total_duration_sec).
  4. Inclusão de materiais de aula (course_lesson_materials).
  5. Inclusão de avaliações (course_reviews) e moderação.
  6. Inclusão de revenue split por ordem (course_order_revenue_shares).
  7. Inclusão de bundles (course_bundles, course_bundle_items).
  8. Inclusão de recomendações cross-sell (course_recommendations).
  9. Endpoint agregado de catálogo (GET /marketplace/catalog).
  10. Permissionamento granular por módulo para cliente e profissional.

Modelos do domínio de cursos

Modelos principais em internal/models/marketplace/:

  • Course
  • CourseModule
  • CourseLesson
  • CourseLessonMaterial
  • CourseLessonProgress
  • CourseEnrollment
  • CourseOrder
  • CourseOrderRevenueShare
  • CourseOrderStatusLog
  • CourseReview
  • CourseReviewLog
  • CourseRecommendation
  • CourseBundle
  • CourseBundleItem
  • CourseCommissionSetting

Decisões estruturais importantes

  • Course não persiste mais duration nem video_url.
  • Course.PriceAmountCents substitui uso monetário em ponto flutuante.
  • CourseLesson usa metadados genéricos de vídeo:
  • video_provider
  • video_upload_id
  • video_asset_id
  • video_playback_id
  • last_video_provider_event_at
  • CourseOrder mantém snapshots em centavos para auditoria e reconciliação.
  • CourseOrderRevenueShare permite N participantes por ordem.

Endpoints de marketplace

Rotas registradas em internal/modules/marketplace/courses/routes.go.

Cliente

  • GET /marketplace/catalog
  • GET /marketplace/courses
  • GET /marketplace/courses/:id
  • GET /marketplace/courses/:id/content
  • GET /marketplace/courses/:id/access
  • POST /marketplace/courses/:id/purchase-intent
  • POST /marketplace/courses/:id/complete
  • GET /marketplace/courses/:id/reviews
  • POST /marketplace/courses/:id/reviews
  • GET /marketplace/enrollments
  • GET /marketplace/enrollments/:enrollment_id/content
  • POST /marketplace/enrollments/:enrollment_id/lessons/:lesson_id/progress
  • POST /marketplace/enrollments/:enrollment_id/lessons/:lesson_id/mark-watched
  • GET /marketplace/enrollments/:enrollment_id/lessons/:lesson_id/playback
  • GET /marketplace/bundles
  • GET /marketplace/bundles/:id
  • POST /marketplace/bundles/:id/purchase-intent

Profissional

  • Cursos, módulos e aulas (CRUD editorial)
  • Fluxo de vídeo (upload URL, import por URL, status, thumbnail, delete)
  • Materiais de aula (CRUD)
  • Recomendações (CRUD por curso)
  • Bundles (CRUD + itens)
  • Revenue/sales summary por curso
  • Submissão para revisão e despublicação
  • Exclusão lógica de curso com fila assíncrona para remoção de vídeos (POST /marketplace/professional/courses/:id/delete)
  • Status de deleção no payload de curso (deletion_status, deletion_progress_note, contadores de vídeos)

Admin

  • Catálogo administrativo da vitrine (GET /marketplace/admin/catalog)
  • Review queue/detail/playback
  • Pré-visualização de aulas no fluxo de revisão usando token admin de playback
  • Aprovar, rejeitar e forçar despublicação de curso
  • Pedidos e reembolso
  • Settlement e reconciliação
  • Commission settings
  • Reviews (listagem + moderação)
  • Review logs
  • Bundles (CRUD + itens)
  • Recomendações (CRUD)

Webhooks públicos

  • POST /marketplace/webhooks/mercadopago
  • POST /marketplace/webhooks/mux

Pré-visualização admin de vídeos

Para revisão editorial/operacional, o admin pode reproduzir vídeos das aulas sem matrícula de cliente via:

  • GET /marketplace/admin/courses/:course_id/lessons/:lesson_id/playback

Regras:

  1. Aula deve estar em status ready.
  2. Playback é assinado quando marketplace.mux.signed_playback.enabled=true.
  3. Endpoint é restrito a perfil admin.
  4. Fluxo é auditável via logs operacionais.

GET /marketplace/catalog retorna:

{
  "courses": [],
  "bundles": [],
  "recommendations": []
}

Campos de destaque:

  • courses[].price_amount_cents
  • courses[].total_duration_sec
  • courses[].rating_avg
  • courses[].reviews_count
  • bundles[].price_amount_cents
  • bundles[].courses_count
  • bundles[].savings_cents

Permissionamento granular

Módulos canônicos em internal/modules/module_access/catalog.go:

  • Cliente:
  • educacional.cursos.catalogo
  • educacional.cursos.player
  • educacional.cursos.bundles
  • educacional.cursos.reviews
  • Profissional:
  • educacional.cursos.profissional.gestao
  • educacional.cursos.profissional.recomendacoes
  • educacional.cursos.profissional.bundles
  • educacional.cursos.profissional.materiais
  • educacional.cursos.profissional.revenue

Observação: - A gestão de módulos no admin passou a renderizar árvore recursiva, permitindo visualizar níveis como educacional.cursos.*.

Migrações relacionadas

Arquivos aplicados no ciclo:

  • 042_marketplace_course_domain_refactor.sql
  • 043_marketplace_revenue_share_bundle_recommendation.sql
  • 044_marketplace_catalog_and_review_moderation.sql
  • 045_add_marketplace_course_permission_modules.sql
  • 046_marketplace_course_logical_delete.sql

Rollbacks correspondentes em migrations/rollback/.

OpenAPI

openapi.v2.yaml foi atualizado para refletir:

  • novos schemas de marketplace;
  • contratos em centavos;
  • contratos de vídeo genéricos;
  • cobertura das rotas marketplace/* (cliente, profissional e admin).

Checklist de integração backend

  1. Usar apenas contratos em centavos.
  2. Não consumir campos mux_* nos payloads de domínio.
  3. Não depender de course.duration persistido.
  4. Consumir catálogo preferencialmente por GET /marketplace/catalog.
  5. Validar módulo de acesso antes de liberar rotas no app cliente.