Skip to content

Formação — Edge Functions (PR-2)

Todas as functions seguem ADR-003 (body.params ?? body) e ADR-018 (Least Privilege).

especialista-modulos (novo)

Auth: requireRole('especialista'). CORS padrão _shared/cors.ts.

ActionPayloadRetorno
list{ curso_id }CursoModulo[]
create{ curso_id, titulo, descricao? }CursoModulo
update{ modulo_id, titulo?, descricao? }CursoModulo
delete{ modulo_id }{ ok: true }
reorder{ curso_id, ordens: [{ modulo_id, ordem }] }CursoModulo[]

reorder usa two-phase (ordens negativas temporárias) para respeitar UNIQUE(curso_id, ordem). delete falha (FK RESTRICT) se houver vídeos vinculados — UI deve mover/excluir aulas antes.

especialista-trilhas (novo)

Auth: requireRole('especialista').

ActionPayload
list{}Trilha[] (com cursos[] hidratado)
create{ titulo, descricao? }
update{ trilha_id, titulo?, descricao?, ativo? }
delete{ trilha_id }
attach_curso{ trilha_id, curso_id, ordem? }
detach_curso{ trilha_id, curso_id }
reorder{ ordens: [{ trilha_id, ordem }] } — two-phase

cursos-imagens-signed-url (novo)

Auth: requireAnyRole(['especialista','coordenador']). Validação anti-traversal via _shared/cursos-imagens.ts::isSafeImagePath.

ActionPayloadRetorno
sign{ path, ttl? } (≤1h){ signed_url, expires_at }

especialista-cursos (estendida)

Action novo/atualizadoMudança
create / updateAceita imagem_url, video_intro_url, status. 22023 → 400.
upload_imagem{ curso_id, path } → valida path e persiste cursos-imagens/<path>.
update_status{ curso_id, status } (publicado | em_breve | rascunho).

especialista-curso-videos (estendida)

  • create aceita modulo_id (opcional — default = módulo de menor ordem).
    • Ordem auto agora é por módulo (UNIQUE(modulo_id, ordem)).
  • update aceita modulo_id (mover aula entre módulos).

coordenador-videos (estendida)

ActionPayloadRetorno
list_curso_completo{ curso_id }{ curso, modulos: [{ ..., aulas: [...] }] }

Filtros aplicados pelo backend (coordenador é consumidor):

  • curso.status === 'rascunho'404 (não enxerga).
  • aulas.status !== 'publicado' → omitidas.
  • ativo = false → omitidas.

Validação Zod por action (PR-6.5 hardening)

Todas as Edge Functions abaixo seguem ADR-003extractParams(body) = body.params ?? body aplicado antes de qualquer safeParse. O hook do frontend (invokeAction) envia { action, params: {...} }; tooling/curl envia flat. Ambos válidos.

Edge functionActionSchema ZodNotas
especialista-cursoscreateCreateCursoSchematitulo obrigatório; categoria_visual enum; status default rascunho.
especialista-cursosupdateUpdateCursoSchemaid UUID + partial.
especialista-cursosupload_imagemUploadImagemSchemamime ∈ {jpeg,png,webp}, base64 ≤ 5 MB.
especialista-cursosupdate_statusUpdateStatusSchemastatus ∈ {publicado,em_breve,rascunho}.
especialista-moduloscreate/update/delete/reorderinlinereorder é two-phase para respeitar UNIQUE (curso_id, ordem).
especialista-curso-videoscreateCreateVideoSchemamodulo_id UUID obrigatório (FK NOT NULL desde PR-1).
especialista-curso-videosupdateUpdateVideoSchemapartial; mantém FK RESTRICT se trocar modulo_id.
especialista-trilhascreate/update/delete/attach_curso/detach_curso/reorder_cursosinlineescopo global.
coordenador-videoslist_curso_completoListCursoCompletoSchemacurso_id UUID; aplica filtros do §"Filtros aplicados pelo backend".
coordenador-videoslist_trilhasListTrilhasSchemasem parâmetros; retorna apenas ativo = true.
cursos-imagens-signed-urlsigninline (Zod)TTL ≤ 3600 s; bucket privado cursos-imagens.

Resposta de erro padrão (400):

json
{ "success": false, "error": "VALIDATION_ERROR", "details": { "fieldErrors": { "modulo_id": ["Invalid uuid"] } } }

Gerada via schema.safeParse().error.flatten(). Cobertura: 43 testes de parser puros (deno test em cada __tests__/parser.test.ts), incluindo regressão explícita do Caso 21 (fatura_id: Required 2026-06-19) em cada função afetada.