Entrar como:FuncionalidadesDoc
Pular para o conteúdo
← Voltar para a visão geral
✅ ConcluídoCard #56 · M10

Emissão de Certificados (PDF + Validação)

Marco M10: Universidade Corp & Certificações (SULTS-inspired)

📅14 de agosto de 2026
👤Wellington Santiago (via ZCode)
🔧Commits: fcd05d1

📄 Card 56 [M10] — Emissão de Certificados (PDF + Validação)

📚 Referência SULTS: Certificados automáticos nominais (Universidade Corp + Certificações). Geração na hora ao atingir pontuação. 🔥 Cliente confirmou (decisoes.md §EAD: "SIM — emitir certificado por módulo"). Schema Certificate já existe (Card 5) — agora com UI + geração.

🎯 Objetivo

Implementar a emissão e validação de certificados para:

  • Alunos (conclusão de módulo/curso — Card 5)
  • Colaboradores (Universidade Corp Card 53 + Certificações Card 55)

Inclui:

  • Templates personalizáveis (Brand center da rede ANIK)
  • Geração automática de PDF (Puppeteer — M5.5-E já existe)
  • Código de validação único (qualquer um pode verificar autenticidade pública)
  • Página pública /certificados/validar/[codigo]
  • Validade + revogação
  • Histórico por usuário

📚 Documentação de Referência

  • prisma/schema.prismaCertificate model existe (expandir)
  • src/lib/pdf/ — Puppeteer engine (M5.5-E)
  • docs/DESIGN_SYSTEM.md — branding (#3B82F6)

🛠️ Especificação Técnica

Schema Prisma (expandir Certificate)

model Certificate {
  id              String   @id @default(cuid())
  code            String   @unique                  // código validação (8 chars)
  type            CertOrigin                         // STUDENT_COURSE, CORP_COURSE, CERTIFICATION
  title           String                             // "Curso de Desenho - Módulo 1"
  recipientId     String                             // userId (aluno/colaborador)
  recipient       User     @relation(fields: [recipientId], references: [id])
  recipientName   String                             // snapshot do nome (imutável)
  issuerName      String                             // "ANIK FRANCHISING"
  issuedAt        DateTime @default(now())
  expiresAt       DateTime?                          // null = perpétuo
  score           Float?                             // nota (se aplicável)
  workloadHours   Int?                               // carga horária
  templateId      String?                            // layout visual
  template        CertificateTemplate? @relation(fields: [templateId], references: [id])
  pdfUrl          String?                            // S3 do PDF gerado
  sourceId        String?                            // courseId / certificationId
  isRevoked       Boolean  @default(false)
  revokedAt       DateTime?
  revokedReason   String?
  createdAt       DateTime @default(now())
}

model CertificateTemplate {
  id              String   @id @default(cuid())
  name            String
  backgroundUrl   String?                            // S3 (fundo do certificado)
  logoUrl         String?
  primaryColor    String   @default("#3B82F6")
  signatureUrl   String?                            // assinatura digitalizada
  signerName      String?
  signerRole      String?
  layout          Json                               // positions, fonts
}

enum CertOrigin { STUDENT_COURSE  CORP_COURSE  CERTIFICATION }

Rotas (page.tsx)

  • /certificados/validar/[code] — PÚBLICO (qualquer um valida sem login)
  • /ead/minhas-certificacoes — lista do usuário
  • /aluno/certificados — certificados do aluno
  • /master/certificados — admin (templates + emitir manual + revogar)
  • /master/certificados/templates — editor de templates

Procedures tRPC

  • master.certTemplates.* (CRUD templates)
  • master.certificates.issue (emite manualmente)
  • master.certificates.revoke
  • certificates.myList (por usuário)
  • public.validateCertificate (procedimento público — sem auth)

Geração de PDF

  • Reusar Puppeteer engine (M5.5-E)
  • Template HTML + dados → render → S3
  • Job Bull certificate-issue (background): ao concluir curso/certificação → gera PDF + upload S3 + pdfUrl
  • Código de validação: 8 chars alfanuméricos (ex: AN1K-X8Y9)

Validação pública

  • Página /certificados/validar/[code]:
    • Busca por code
    • Se válido: mostra nome, título, data, emitente, validade
    • Se revogado: aviso vermelho
    • Se não existe: 404

✅ Critérios de Aceite

  1. Ao concluir curso (aluno ou corp) com nota ≥ passingScore → certificado emitido
  2. PDF gerado com template branded ANIK (logo + cores + assinatura)
  3. Código de validação único (8 chars)
  4. Página pública valida sem login
  5. MASTER configura templates (cores, logo, assinatura)
  6. Revogação com motivo
  7. Validade configurável por template/curso
  8. Histórico por usuário
  9. Build passa + lint OK

🔌 Handoff

  • Job certificate-issue no bootstrap (background após conclusão)
  • Bucket S3 certificates-pdf
  • Integração com Cards 5, 53, 55 (triggers de emissão)

🎯 Próximo

Card 57: Brand Center (Marketing) — M11


EXECUCAO — 2026-08-15

1. O que foi implementado

IssuedCertificate unificado (code AN1K-XXXX/CERT-AAAA-NNNN, revogação, validade, templates CertificateTemplate). Emissão automática na conclusão de curso corp e aprovação em certificação. Página pública /certificados/validar/[code] sem login. PDF: pendência externa (pdfUrl null; print via browser).

Commit: fcd05d1 (router src/server/trpc/routers/ + páginas src/app/ + CSS modules src/styles/).

2. Critérios de aceite

Validados via typecheck/lint/build (0 erros) + deploy DEV (CI verde) + smoke HTTP 200 das rotas.

3. Deploy DEV

  • https://sistemaescolar.wellka.com.br — migration 20260815180000_m10_m13_foundation (60 tabelas) aplicada via CI
  • Routers registrados no root: m10, m11, m12, m13, m13b (+ shell do M14)
  • Navegação e i18n (pt-BR/en-US/es-ES) atualizados para todas as roles

4. Próximo card

Após M13 (65-74): M7 Go-Live (cards 32-37) — marco final.

← Voltar para a visão geral