Receba novidades do Hedhog no seu e-mail
Novos lançamentos, receitas e breaking changes — sem spam.
Submódulo LMS
exams
Banco de exames com um catálogo global de assuntos de questões, cinco tipos de questão (múltipla escolha, verdadeiro/falso, dissertativa, preencher lacunas e associação), um banco de questões avulso e o ciclo de vida completo da tentativa do aluno.
Caminho de origem: libraries/lms/src/exam
Arquivo do módulo: exam.module.ts
Introdução
O submódulo Exams é dividido em três controllers que, juntos, cobrem a autoria e a realização de exames. O `ExamController` (`/lms/exams`) é dono das definições de exame — título, código, limite de pontuação, limite de tempo, flags de embaralhamento/visibilidade do gabarito, nível e status — além de uma superfície aninhada de gerenciamento de questões para adicionar, editar, remover e reordenar as questões de cada exame. Cinco tipos de questão são suportados: multiple_choice e true_false são corrigidos automaticamente contra as alternativas marcadas como corretas (true_false exige estritamente exatamente duas), essay é armazenada sem correção para revisão manual, fill_blank é corrigida por correspondência exata insensível a maiúsculas/minúsculas contra uma ou mais respostas aceitas, e matching é corrigida por comparação exata do conjunto de pares esquerda/direita. Uma escolha de design pequena mas fácil de perder: o `GET /lms/exams/:id` retorna `null` em vez de um 404 quando o exame não existe, e vários endpoints de gerenciamento de questões (excluir, reordenar) são no-ops em vez de erros quando o alvo não existe ou o conjunto de IDs enviado não corresponde — os chamadores devem verificar o formato da resposta em vez de confiar puramente no status HTTP.
O `QuestionController` (`/lms/questions`) é um banco de questões avulso, separado e mais plano — questões criadas aqui não são vinculadas a nenhum exame no momento da criação, útil para construir um banco de itens reutilizável antes de montar exames, ou para outras partes da plataforma que precisam de questões corrigidas ad-hoc fora do fluxo de tentativa de exame.
O `ExamAttemptController` (também sob `/lms/exams`) é a metade voltada ao aluno: iniciar uma tentativa, salvar respostas em andamento e submeter para correção. O `GET /:id/attempt` finaliza automaticamente uma tentativa se seu limite de tempo tiver silenciosamente expirado, e resolve a qual registro `person` a tentativa pertence via uma cadeia de fallback — sobrescrita explícita por `studentId`, depois person correspondente por e-mail, e então (como último recurso) criando automaticamente um novo registro de person para o usuário chamador, o que é um efeito colateral notável que vale conhecer antes de fazer scripts contra este endpoint com uma service account recém-criada. Iniciar uma nova tentativa é idempotente em relação a uma tentativa em andamento existente e não expirada, e a submissão publica um evento de integração `lms.exam.attempt.submitted` carregando a pontuação final e o resultado de aprovação/reprovação para consumidores downstream (por exemplo, concessão de conquistas ou relatórios de licença corporativa) reagirem.
Endpoints HTTP
19 endpoints
Lista paginada de assuntos/categorias de questões.
- Query
- page, pageSize, search
Cria um assunto de questão; rejeita nomes vazios ou duplicados insensíveis a maiúsculas/minúsculas.
Body
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string | yes | — |
| description | string | no | — |
Lista paginada de exames com a pontuação média por exame.
- Query
- page, pageSize, search, status
Estatísticas agregadas: exames totais/publicados, total de questões, pontuação média geral.
Obtém um exame por ID; retorna null (não 404) se não encontrado.
- Params
- id (int)
Lista as questões do exame em ordem, incluindo alternativas/respostas/pares específicos do tipo.
- Params
- id (int)
Adiciona uma questão ao exame; validação por tipo é aplicada (objetiva precisa de ≥2 alternativas com ≥1 correta, true_false exatamente 2, fill_blank ≥1 resposta, matching ≥2 pares únicos).
- Params
- id (int)
Body
| Field | Type | Required | Notes |
|---|---|---|---|
| subjectId | number | yes | — |
| statement | string | yes | — |
| points | number | yes | Min 1 |
| questionType | 'multiple_choice' | 'true_false' | 'essay' | 'fill_blank' | 'matching' | no | Default multiple_choice |
| explanation | string | no | — |
| alternatives | { text, isCorrect }[] | no | Max 2000 chars per text |
| fillBlankAnswers | { answer, alternatives? }[] | no | Min size 1 if present |
| matchingPairs | { id, leftText, rightText }[] | no | Min size 2 if present |
Atualiza uma questão (mesmos validadores da criação, aplicados quando campos/tipo mudam).
- Params
- id, questionId (int)
Remove uma questão e re-sequencia a ordem restante (no-op se não encontrada).
- Params
- id, questionId (int)
Reordena as questões; retorna {success:false} se o conjunto de IDs enviado não corresponder exatamente às questões do exame.
- Params
- id (int)
Body
| Field | Type | Required | Notes |
|---|---|---|---|
| questionIds | number[] | yes | ArrayMinSize(1) |
Cria um exame (exam_type fixado como "test").
Body
| Field | Type | Required | Notes |
|---|---|---|---|
| title | string | yes | Max 255 chars |
| code | string | no | Max 32 chars |
| minScore | number | no | Passing threshold on a base-10 scale, default 7 |
| timeLimit | number | no | Minutes, default 60 |
| shuffle | boolean | no | — |
| showAnswerKeyAfterFinish | boolean | no | — |
| level | 'beginner' | 'intermediate' | 'advanced' | no | Default beginner |
| status | 'draft' | 'published' | 'closed' | 'archived' | no | Default draft |
| primaryColor | string | no | Max 32 chars |
| secondaryColor | string | no | Max 32 chars |
Atualiza os campos do exame (todos opcionais, mesmo formato da criação).
- Params
- id (int)
Exclui permanentemente o exame.
- Params
- id (int)
Lista o banco global de questões avulsas (correspondência de substring no enunciado).
- Query
- search?, page?, limit? (default 50)
Cria uma questão avulsa, não vinculada a nenhum exame. Mesma validação por tipo das questões de exame.
Body
| Field | Type | Required | Notes |
|---|---|---|---|
| subjectId | number | no | — |
| statement | string | yes | — |
| explanation | string | no | — |
| questionType | 'multiple_choice' | 'true_false' | 'essay' | 'fill_blank' | 'matching' | no | Default multiple_choice |
| points | number | no | Default 1 |
| alternatives | { text, isCorrect }[] | no | — |
| fillBlankAnswers | { answer, alternatives? }[] | no | — |
| matchingPairs | { id, leftText, rightText }[] | no | — |
Estado atual da tentativa para o usuário; finaliza automaticamente uma tentativa em andamento expirada; resolve/cria um registro de person se nenhum existir.
- Params
- id (int)
- Query
- studentId?
Inicia uma nova tentativa, ou retorna uma existente em andamento e não expirada. Rejeita se a cota de tentativas foi esgotada ou o exame não tem questões.
- Params
- id (int)
Body
| Field | Type | Required | Notes |
|---|---|---|---|
| studentId | number | no | Admin-initiated attempt for another student |
Salva respostas durante a tentativa com correção automática por tipo, onde aplicável.
- Params
- id, attemptId (int)
Body
| Field | Type | Required | Notes |
|---|---|---|---|
| answers | SaveExamAttemptAnswerDto[] | yes | { questionId, examOptionId?, answerText?, matchingPairs? }[] |
Finaliza a tentativa, computa a pontuação e publica lms.exam.attempt.submitted. Idempotente se já concluída.
- Params
- id, attemptId (int)
Body
| Field | Type | Required | Notes |
|---|---|---|---|
| answers | SaveExamAttemptAnswerDto[] | yes | — |
| force | boolean | no | Bypass the require-all-answered check |
Ferramentas MCP
Ferramentas nomeadas que podem ser chamadas por modelos de IA através do Model Context Protocol (MCP).
lms.exams.listLista exames com paginação e filtros opcionais
lms.exams.statsRetorna estatísticas agregadas de exames
lms.exams.getRetorna um único exame por ID
lms.exams.createCria um novo exame
lms.exams.updateAtualiza um exame existente
lms.exams.deleteRemove um exame por ID
lms.exams.question-subjects.listLista assuntos de questão (tópicos) disponíveis para questões de exame
lms.exams.question-subjects.createCria um novo assunto de questão
lms.exams.questions.listLista todas as questões de um exame
lms.exams.questions.createCria uma nova questão para um exame
lms.exams.questions.updateAtualiza uma questão em um exame
lms.exams.questions.deleteRemove uma questão de um exame
lms.exams.questions.reorderReordena questões dentro de um exame
lms.exams.attempt.getRetorna o estado atual da tentativa de um exame para o usuário autenticado
lms.exams.attempt.startInicia uma nova tentativa de exame para o usuário autenticado
lms.exams.attempt.save-answersSalva respostas de uma tentativa de exame em andamento
lms.exams.attempt.submitSubmete uma tentativa de exame para correção