Saltar para o conteúdo principal

Regras de Eliminação

O DokStamp foi concebido para preservar a integridade dos certificados emitidos. Após a emissão de um certificado, as entidades que ele referencia ficam protegidas contra eliminação. Esta página explica as regras e os padrões recomendados para integrações.

Eliminação lógica

Todas as entidades no DokStamp utilizam eliminação lógica: ao chamar DELETE /resource/{uuid}, o registo não é fisicamente removido da base de dados. Em vez disso, é definida uma marca temporal deleted_at. Os registos com eliminação lógica:
  • São excluídos de todas as respostas de listagem GET
  • Não podem ser referenciados por novos recursos
  • Mantêm todos os seus dados e relações intactos
  • Podem ser restaurados pelo administrador da plataforma, se necessário
Isto significa que nenhum dado é permanentemente perdido através da API de eliminação padrão.

Regras de proteção contra eliminação

Tentar eliminar uma entidade que possui certificados emitidos dependentes resultará num erro. A proteção é aplicada ao nível da base de dados através de restrições de chave estrangeira.
EntidadeNão pode ser eliminada quando…
InstituiçãoTem cursos, módulos ou certificados que a referenciam
CursoTem turmas, matrículas ou certificados que o referenciam
MóduloEstá associado a algum curso (existe a relação course_modules)
TurmaTem matrículas ou certificados que a referenciam
EstudanteTem certificados, matrículas ou um snapshot do sujeito da credencial

Por que isto é relevante para integrações

Quando o sistema de terceiros elimina ou desativa uma entidade, não deve replicar essa eliminação cegamente no DokStamp se já foram emitidos certificados. A abordagem recomendada:

1. Verificar a existência de certificados antes de eliminar

async function canDelete(entityType, uuid) {
  const certs = await api.get('/certificates', {
    params: { [`where[${entityType}_uuid]`]: uuid, per_page: 1 }
  });
  return certs.data.meta.total === 0;
}

// Example for a course
if (await canDelete('course', courseUuid)) {
  await api.delete(`/courses/${courseUuid}`);
} else {
  // Archive instead of delete
  await api.patch(`/courses/${courseUuid}`, { status: 'archived' });
}

2. Arquivar em vez de eliminar

Para cursos e instituições, prefira atualizar o campo status para archived ou inactive em vez de eliminar:
// Instead of DELETE /courses/{uuid}
await api.patch(`/courses/${courseUuid}`, { status: 'archived' });
Isto preserva todas as relações e marca claramente a entidade como inativa.

3. Tratar o erro de forma elegante

Se uma tentativa de eliminação falhar por existir uma dependência, a API devolve um erro. Trate sempre esta situação na sua integração:
try {
  await api.delete(`/courses/${courseUuid}`);
} catch (err) {
  if (err.response?.status === 500) {
    // Likely a referential integrity error — log and archive instead
    logger.warn(`Cannot delete course ${courseUuid} — has dependent records. Archiving instead.`);
    await api.patch(`/courses/${courseUuid}`, { status: 'archived' });
  } else {
    throw err;
  }
}

Imutabilidade do certificado

Após a emissão de um certificado, todos os dados a ele associados são preservados:
  • Identidade do estudante (nome, email, número de documento, data de nascimento, país) — capturada num snapshot imutável no momento da emissão
  • Dados do curso, instituição, turma e matrícula — todos preservados através das regras de integridade referencial descritas acima
Isto garante que o URL de verificação pública de um certificado apresentará sempre informação precisa e completa, independentemente de quaisquer alterações futuras às entidades subjacentes.

Desassociação de módulos vs eliminação

Os módulos podem ser desassociados de um curso sem serem eliminados:
DELETE /courses/{course_uuid}/detach/modules
Isto remove a associação course_modules, mas mantém tanto o curso como o módulo intactos. Esta é a operação preferida quando se reorganiza um currículo, pois permite que o módulo seja re-associado a um curso diferente. Eliminar um módulo por completo (via DELETE /modules/{uuid}) só é possível após ter sido desassociado de todos os cursos.

Resumo: preferir arquivar em vez de eliminar

CenárioAção recomendada
Curso descontinuadoPATCH /courses/{uuid}{ "status": "archived" }
Instituição inativaPATCH /institutions/{uuid}{ "status": "inactive" }
Registo de estudante a desativarNão eliminar; manter o registo intacto
Módulo já não lecionadoDesassociar do curso; não eliminar o módulo
Turma encerradaNenhuma ação necessária; as turmas são registos históricos