Certificados Digitales
Sección titulada «Certificados Digitales»TalentBricksAI genera certificados digitales verificables cuando un estudiante completa un curso. Los certificados se generan en el navegador usando Canvas HTML5 e incluyen un código QR para verificación pública.
características
Sección titulada «características»- Generacion client-side: Renderizado con Canvas HTML5 (sin servidor)
- Diseño premium: Soporte para modo claro y oscuro con logo TalentBricks
- Responsive: Se adapta automaticamente a diferentes tamaños de pantalla
- verificación pública: URL única sin necesidad de login
- código QR: Enlace directo a la página de verificación
- Descarga PNG: Un click para descargar el certificado
- Datos snapshot: información capturada al momento de completar
Flujo del Usuario
Sección titulada «Flujo del Usuario»Completar todas las lecciones ↓Curso marcado como completado ↓Certificado generado automaticamente ↓Ver en /certificate/:courseId ↓Descargar PNG o compartir enlace ↓verificación pública en /verify/:code| Ruta | Acceso | descripción |
|---|---|---|
/certificate/:courseId | Autenticado | Ver y descargar certificado propio |
/verify/:verificationCode | público | Verificar autenticidad del certificado |
Modelo de Datos
Sección titulada «Modelo de Datos»El certificado guarda datos “snapshot” al momento de generacion:
model Certificate { id Int @id @default(autoincrement()) createdAt DateTime @default(now())
user User @relation(...) userId String
course Course @relation(...) courseId Int
verificationCode String @unique @default(uuid())
// Snapshot data studentName String courseTitle String instructorName String totalDurationMinutes Int
@@unique([userId, courseId])}¿Por qué Snapshot Data?
Sección titulada «¿Por qué Snapshot Data?»Los datos se guardan como copia (snapshot) porque:
- Si el curso cambia de nombre, el certificado mantiene el nombre original
- Si el instructor cambia, el certificado refleja quién enseñó al estudiante
- Si la duracion del curso cambia, el certificado muestra las horas completadas
Contenido del Certificado
Sección titulada «Contenido del Certificado»El certificado Canvas incluye:
| Elemento | descripción |
|---|---|
| Logo | Logo TalentBricks (adapta a modo claro/oscuro) |
| Título | ”CERTIFICADO DE FiNALIZACION” |
| Nombre estudiante | Resaltado en dorado |
| Nombre curso | Con word-wrap automatico |
| Duracion total | Horas y minutos del curso |
| Fecha emision | Formato largo en español |
| Instructor | Nombre con línea de firma |
| código QR | Enlace a página de verificación |
| código | UUID para verificación manual |
Soporte para Modo Claro/Oscuro
Sección titulada «Soporte para Modo Claro/Oscuro»El certificado se adapta automaticamente al tema del usuario:
Modo Oscuro:
- Fondo: Gradiente oscuro (
#1a1a2e → #16213e → #0f0f23) - Borde: Dorado brillante (
#ffd700) - Texto: Blanco con variaciones de opacidad
- Logo: Variante oscura (
logo-dark.png)
Modo Claro:
- Fondo: Gradiente claro (
#f8f9fa → #e9ecef → #dee2e6) - Borde: Dorado oscuro (
#d4af37) - Texto: Tonos oscuros con variaciones de opacidad
- Logo: Variante clara (
logo.png)
página de verificación
Sección titulada «página de verificación»La página /verify/:code es pública y muestra:
Certificado Valido
Sección titulada «Certificado Valido»- Badge verde “Verificado”
- Nombre del estudiante
- Nombre del curso
- Instructor
- Duracion
- Fecha de emision
- CTA para explorar cursos
Certificado Invalido
Sección titulada «Certificado Invalido»- Mensaje de error
- código verificado (para debugging)
- CTA para ir al inicio
Operaciones Backend
Sección titulada «Operaciones Backend»completeCourse (Action)
Sección titulada «completeCourse (Action)»Cuándo un usuario completa todas las lecciones:
// 1. Verificar que todas las lecciones estan completadas// 2. Calcular duracion total en minutos// 3. Capturar nombre del estudiante (username o email)// 4. Crear registro de Certificate con snapshot data// 5. Marcar Enrollment como completedAt// 6. Retornar verificationCodegetCertificateById (Query)
Sección titulada «getCertificateById (Query)»// Requiere autenticación// Retorna certificado del usuario para un curso específico// Incluye datos del curso (slug, category, difficulty)verifyCertificate (Query)
Sección titulada «verifyCertificate (Query)»// NO requiere autenticación (público)// Busca por verificationCode// Retorna datos publicos del certificadoComponentes Frontend
Sección titulada «Componentes Frontend»CertificateCanvas
Sección titulada «CertificateCanvas»import { CertificateCanvas } from "./components/CertificateCanvas";
<CertificateCanvas data={{ studentName: "Juan Perez", courseTitle: "Python para Data Engineering", instructorName: "Maria Garcia", totalDurationMinutes: 180, issuedAt: new Date(), verificationCode: "abc-123-def", }} isDarkMode={true} // Opcional: controla el tema (claro/oscuro) locale={{ hours: "horas", hour: "hora", minutes: "minutos", completionText: "ha completado satisfactoriamente el curso", }}/>;Props:
data: Datos del certificado (requerido)isDarkMode: Booleano para modo oscuro (opcional, default:false)locale: Textos traducibles (opcional)onReady: Callback cuando el certificado está listo (opcional)
Descarga
Sección titulada «Descarga»import { downloadCertificateFromCanvas } from "./components/CertificateCanvas";
<Button onClick={downloadCertificateFromCanvas}>Descargar PNG</Button>;Compartir Certificado
Sección titulada «Compartir Certificado»Copiar Enlace
Sección titulada «Copiar Enlace»const verificationUrl = `${window.location.origin}/verify/${code}`;await navigator.clipboard.writeText(verificationUrl);Web Share API
Sección titulada «Web Share API»await navigator.share({ title: "Mi certificado de TalentBricksAI", text: `He completado el curso ${courseTitle}!`, url: verificationUrl,});Personalizacion
Sección titulada «Personalizacion»Modo Claro vs Oscuro
Sección titulada «Modo Claro vs Oscuro»El certificado detecta automaticamente el tema del usuario mediante el hook useColorMode():
import useColorMode from "../client/hooks/useColorMode";
const [colorMode] = useColorMode();const isDarkMode = colorMode === "dark";
<CertificateCanvas data={certificateData} isDarkMode={isDarkMode} />;Cambiar Colores
Sección titulada «Cambiar Colores»En CertificateCanvas.tsx, los colores se definen basados en el modo:
// Modo oscuroconst borderColor = isDarkMode ? "#ffd700" : "#d4af37";const titleColor = isDarkMode ? "#ffffff" : "#1a1a2e";const bodyTextColor = isDarkMode ? "rgba(255, 255, 255, 0.8)" : "rgba(50, 50, 50, 0.8)";Cambiar Logo
Sección titulada «Cambiar Logo»Los logos se importan desde app/src/client/static/:
import logoLight from "../../client/static/logo.png";import logoDark from "../../client/static/logo-dark.png";
// El componente selecciona automaticamente el correctoconst logoSrc = isDarkMode ? logoDark : logoLight;Para usar logos personalizados, reemplaza los archivos:
logo.png- Logo para modo clarologo-dark.png- Logo para modo oscuro
Testing
Sección titulada «Testing»Probar con Datos Dummy
Sección titulada «Probar con Datos Dummy»wasp db seed seedAllDummyDataEl seed crea un usuario de prueba con certificado. El código de verificación se muestra en la consola.
Verificar Flujo Completo
Sección titulada «Verificar Flujo Completo»- Crear usuario y inscribirse en un curso
- Completar todas las lecciones
- Visitar
/certificate/:courseId - Verificar que el certificado se renderiza
- Probar descarga PNG
- Probar enlace de verificación pública
Troubleshooting
Sección titulada «Troubleshooting»QR Code no aparece
Sección titulada «QR Code no aparece»Verificar que qrcode este instalado:
cd appnpm install qrcode @types/qrcodeCanvas en blanco
Sección titulada «Canvas en blanco»- Verificar que los datos del certificado estan completos
- Revisar la consola del navegador por errores
Certificado no se genera
Sección titulada «Certificado no se genera»Verificar Qué:
- Todas las lecciones tienen
isCompleted: true - El usuario tiene
Enrollmentpara el curso - El
Enrollmentno tienecompletedAtya seteado