Sincronizando a Estrutura Acadêmica
Esta página descreve como sincronizar cada entidade acadêmica do seu sistema para o DokStamp, na ordem correta de dependência.
Siga sempre a ordem abaixo. Criar um certificado antes que suas dependências existam resultará em erros de validação 422.
Ordem de sincronização
| Passo | Evento no seu sistema | Ação no DokStamp |
|---|
| 1 | Instituição configurada | POST /institutions (ou configuração manual) |
| 2 | Curso criado / atualizado | POST /courses ou PATCH /courses/{uuid} |
| 3 | Módulo/disciplina criado / atualizado | POST /modules ou PATCH /modules/{uuid} |
| 4 | Módulo adicionado ao curso | POST /courses/{uuid}/attach/modules |
| 5 | Módulos organizados em grupos | POST /courses/{uuid}/modules/groups |
| 6 | Turma (entrada da classe) criada | POST /cohorts |
| 7 | Estudante torna-se elegível | busca → POST /students (se novo) |
| 8 | Estudante matriculado no curso | POST /enrollments |
| 9 | Emissão de certificado acionada | POST /files + POST /certificates |
Passo 2 — Sincronizando um curso
Quando um curso é criado ou atualizado no seu sistema, espelhe a alteração no DokStamp.
async function syncCourse(course) {
// Busca pelo código para verificar se já existe
const existing = await api.get('/courses', {
params: { 'where[code]': course.code }
});
if (existing.data.length > 0) {
// Atualiza o existente
await api.patch(`/courses/${existing.data[0].uuid}`, {
name: course.name,
description: course.description,
workload_hours: course.workloadHours,
status: course.isActive ? 'active' : 'archived',
});
return existing.data[0].uuid;
}
// Cria novo
const res = await api.post('/courses', {
name: course.name,
code: course.code,
institution_uuid: INSTITUTION_UUID,
workload_hours: course.workloadHours,
status: 'active',
});
return res.data.uuid;
}
Passo 3 — Sincronizando módulos/disciplinas
async function syncModule(module) {
const existing = await api.get('/modules', {
params: {
'where[code]': module.code,
'where[institution_uuid]': INSTITUTION_UUID,
}
});
if (existing.data.length > 0) {
await api.patch(`/modules/${existing.data[0].uuid}`, {
name: module.name,
workload: module.workload,
credits: module.credits,
});
return existing.data[0].uuid;
}
const res = await api.post('/modules', {
name: module.name,
code: module.code,
institution_uuid: INSTITUTION_UUID,
workload: module.workload,
credits: module.credits,
level: module.level, // 'undergraduate' | 'graduate' | 'technical' | 'open'
modality: module.modality, // 'in_person' | 'online' | 'hybrid'
});
return res.data.uuid;
}
Passo 4 — Vinculando módulos a um curso
Após criar/sincronizar tanto o curso quanto seus módulos, vincule-os:
await api.post(`/courses/${courseUuid}/attach/modules`, {
modules: moduleUuids.map((uuid, index) => ({
uuid,
order: index + 1,
is_required: true,
}))
});
A vinculação é idempotente para novos módulos, mas vincular novamente um módulo já vinculado retornará 422. Consulte GET /courses/{uuid}/attach/modules primeiro para obter a lista de módulos ainda não vinculados.
Passo 5 — Grupos de módulos (opcional)
Se o seu sistema organiza disciplinas em semestres ou períodos, espelhe essa estrutura:
async function syncModuleGroup(courseUuid, group) {
const res = await api.post(`/courses/${courseUuid}/modules/groups`, {
name: group.name, // ex: "1º Semestre", "Módulos do Núcleo"
order: group.order,
});
return res.data.uuid;
}
Em seguida, vincule novamente os módulos especificando o grupo:
await api.post(`/courses/${courseUuid}/attach/modules`, {
modules: [{
uuid: moduleUuid,
order: 1,
course_module_group_uuid: groupUuid,
}]
});
Passo 6 — Sincronizando turmas
Uma turma corresponde a uma entrada de formandos específica (ex: “Turma Noturna 2024/1”):
async function syncCohort(cohort) {
const existing = await api.get('/cohorts', {
params: { 'where[code]': cohort.code }
});
if (existing.data.length > 0) return existing.data[0].uuid;
const res = await api.post('/cohorts', {
course_uuid: cohort.courseUuid,
code: cohort.code,
modality: cohort.modality,
start_date: cohort.startDate,
end_date: cohort.endDate,
});
return res.data.uuid;
}
Passo 7 — Registrando estudantes elegíveis
Quando o seu sistema determina que um estudante é elegível para um certificado, registre-o no DokStamp (ou verifique se já existe):
async function syncStudent(student) {
// Sempre busque pelo email primeiro
const existing = await api.get('/students', {
params: { 'where[email]': student.email }
});
if (existing.data.length > 0) return existing.data[0].uuid;
const res = await api.post('/students', {
name: student.name,
email: student.email,
date_of_birth: student.dateOfBirth, // YYYY-MM-DD
gender: student.gender,
});
return res.data.uuid;
}
Passo 8 — Criando a matrícula
const enrollment = await api.post('/enrollments', {
student_uuid: studentUuid,
course_uuid: courseUuid,
cohort_uuid: cohortUuid, // opcional
enrolled_at: student.enrolledAt,
completion_status: 'completed',
grade: student.finalGrade,
completed_at: student.completedAt,
});
Passo 9 — Emitindo o certificado
// 1. Faça upload do PDF
const fileRes = await api.post('/files', formDataWithPdf);
const fileUuid = fileRes.data[0].uuid;
// 2. Emita o certificado
const cert = await api.post('/certificates', {
institution_uuid: INSTITUTION_UUID,
course_uuid: courseUuid,
student_uuid: studentUuid,
cohort_uuid: cohortUuid,
enrollment_uuid: enrollmentUuid,
file_uuid: fileUuid,
status: 'issued',
issued_at: new Date().toISOString(),
});
console.log('URL de verificação:', cert.data.public_verification_url);
Exemplo completo assíncrono
Para integrações baseadas em queue, encapsule cada passo em um job:
// jobs/SyncCourseJob.js
export async function handle({ course }) {
try {
const uuid = await syncCourse(course);
await syncModules(uuid, course.modules);
logger.info(`Curso sincronizado: ${uuid}`);
} catch (err) {
if (err.response?.status >= 500 || err.response?.status === 429) {
throw err; // Será reprocessado pela queue
}
logger.error(`Sincronização falhou (sem retry): ${err.message}`, { course });
}
}
Faça retry em 5xx e 429. Registre e descarte os 4xx (eles indicam um problema de dados, não uma falha transitória).