Overview
vLife DGO generates completion certificates (constancias) for approved evaluations. Each certificate includes a QR code that enables third-party verification of authenticity through a public validation portal.
Certificate System Architecture
Evaluation Approval
Administrator approves completed evaluation.
Certificate Generation
System creates constancia record with encrypted validation ID.
QR Code Creation
QR code is generated linking to validation URL.
Certificate Display
Employee can view and download their certificate.
Public Validation
Anyone can scan QR code to verify certificate authenticity.
Certificate Generation
Constancia Data Structure
Certificates are stored in the database with:
evalID - Links certificate to specific evaluation
constanciaValidacion - Encrypted validation identifier
Certificate issue date
Employee information
Evaluation results
Certificate View Controller
import { PoolvLife , keyDecrypt } from "../database/connection.js" ;
import ConstanciaModel from "../models/ConstanciaModel.js" ;
import ncrypt from "ncrypt-js" ;
import qrcode from "qrcode" ;
const ConstanciaView = async ( req , res ) => {
const { constanciaValidacion } = req . params ;
try {
const ncryptObjet = new ncrypt ( keyDecrypt . key );
const decryptedData = ncryptObjet . decrypt ( constanciaValidacion );
// Get certificate data
const [ GetDataConstancia ] = await PoolvLife . query (
ConstanciaModel . GetDataConstancia ,
decryptedData
);
// Get employee data
const [ GetDataEmpleado ] = await PoolvLife . query (
ConstanciaModel . GetDataEmpleado ,
decryptedData
);
// Generate QR code
const getCadena = constanciaValidacion ;
const urlValidator = `http://asdfytrfdggfg/constanciaValidator/ ${ getCadena } ` ;
const QR = await qrcode . toDataURL ( urlValidator );
res . render ( "constanciaViews/constanciaView" , {
user: req . session . name ,
QR ,
dataConstancia: GetDataConstancia [ 0 ],
Empleado: GetDataEmpleado [ 0 ],
});
} catch ( e ) {
console . log ( e );
}
};
The certificate uses the same encrypted ID system as evaluations, ensuring secure access to certificate data.
QR Code Generation
QR Code Library
vLife DGO uses the qrcode npm package to generate QR codes:
import qrcode from "qrcode" ;
const getCadena = constanciaValidacion ; // Encrypted validation ID
const urlValidator = `http://asdfytrfdggfg/constanciaValidator/ ${ getCadena } ` ;
const QR = await qrcode . toDataURL ( urlValidator );
QR Code Output
The toDataURL() method returns a base64-encoded image:
< img src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." alt = "QR Code" />
This can be directly embedded in HTML templates.
The validation URL in the code (http://asdfytrfdggfg/constanciaValidator/) appears to be a placeholder. This must be updated to the actual production domain before deployment.
Certificate Contents
From GetDataEmpleado:
Full name
RFC (tax ID)
CURP (national ID)
Government dependency/department
Position
Employee number
Certificate Data
From GetDataConstancia:
Evaluation year
Evaluation type (Permanencia or Nuevo Ingreso)
Completion date
Approval date
Certificate issue date
Unique certificate number
Validation ID (encrypted)
Validation System
Public Validation Portal
Anyone can validate a certificate by scanning the QR code or entering the validation URL:
import { PoolvLife , keyDecrypt } from "../database/connection.js" ;
import ConstanciaValidatorModel from "../models/ConstanciaValidatorModel.js" ;
import ncrypt from "ncrypt-js" ;
const ConstanciaValidator = async ( req , res ) => {
const { cadena } = req . params ;
try {
const ncryptObjet = new ncrypt ( keyDecrypt . key );
const decryptedData = ncryptObjet . decrypt ( cadena );
const [ rows ] = await PoolvLife . query (
ConstanciaValidatorModel . GetDataConstancia ,
[ decryptedData ]
);
res . render ( "constanciaViews/constanciaValidatorView" , {
Employee: rows [ 0 ],
});
} catch ( e ) {
console . log ( e );
req . flash ( "message" , "Algo salio mal !" );
res . redirect ( "back" );
}
};
Validation Flow
Scan or Access QR Code
User scans QR code or accesses validation URL.
Decrypt Validation ID
Server decrypts the validation identifier.
Query Certificate Data
System retrieves certificate information from database.
Display Verification
Public page displays employee name, certificate details, and validity status.
The validation portal is public and does not require authentication, allowing employers and third parties to verify certificate authenticity.
Security Features
Encrypted Validation IDs
Certificates use ncrypt-js encryption:
const ncryptObjet = new ncrypt ( keyDecrypt . key );
const decryptedData = ncryptObjet . decrypt ( constanciaValidacion );
This prevents:
Direct database ID exposure
Certificate enumeration attacks
Unauthorized access to certificate data
Validation Protection
Unique Identifiers Each certificate has a unique encrypted validation ID
Database Verification All validations query the database for current certificate status
Immutable QR Codes QR codes cannot be forged as they link to server-validated data
Public Transparency Anyone can verify certificate authenticity
Certificate Access Control
Employee Access
Employees access their certificate through their profile:
// In AuthController profile view
const [ GetConstancia ] = await PoolvLife . query (
AuthModel . GetConstancia ,
evalID
);
res . render ( "profile" , {
user: req . session . name ,
constancia: GetConstancia [ 0 ],
// ... other profile data
});
Certificate link appears only when:
Evaluation is completed and finalized
Administrator has approved the evaluation
Certificate record has been created
Validation Access
Validation portal is public:
No authentication required
Accessible via QR code scan
Direct URL access with validation ID
Certificate Display
Certificate View Template
The certificate is rendered with:
Official CEACC Durango header
Employee photograph (if available)
Complete employee information
Evaluation details
QR code for validation
Digital signatures (if configured)
Certificate issue date and number
QR Code Placement
< div class= "qr-code-section" >
< img src= " {{ QR }} " alt= "Código QR de Validación" />
< p > Escanea para validar </ p >
</ div >
The QR code is typically placed in a prominent location on the certificate, often in the bottom right corner or as a footer element.
Validation URL Structure
Certificate URL (Employee View)
http://localhost:4001/Constancia/{constanciaValidacion}
Requires authentication (employee must be logged in)
Shows full certificate with download options
Includes QR code for sharing
Validation URL (Public View)
http://asdfytrfdggfg/constanciaValidator/{constanciaValidacion}
No authentication required
Public verification portal
Displays basic certificate validity information
Shows employee name and certificate status
The validation URL domain must be updated for production: const VALIDATION_URL = process . env . VALIDATION_URL || 'https://ceacc.durango.gob.mx' ;
const urlValidator = ` ${ VALIDATION_URL } /constanciaValidator/ ${ getCadena } ` ;
QR Code Customization
QR Code Options
The qrcode library supports various options:
const QR = await qrcode . toDataURL ( urlValidator , {
errorCorrectionLevel: 'H' , // High error correction
type: 'image/png' ,
quality: 0.95 ,
margin: 1 ,
color: {
dark: '#000000' ,
light: '#FFFFFF'
},
width: 300 // Size in pixels
});
Error Correction Levels
Level Error Tolerance Use Case L ~7% Basic QR codes M ~15% Standard use (default) Q ~25% Printed materials H ~30% Small or damaged codes
For certificates that will be printed and potentially worn or damaged, use error correction level ‘H’ or ‘Q’.
Certificate Lifecycle
Creation Trigger
Certificates are typically created when:
Employee completes all evaluation requirements
Employee finalizes their evaluation
Administrator reviews and approves evaluation
System generates certificate record
Certificate Status
Certificates can have various states:
Active - Valid and verifiable
Revoked - No longer valid (requires implementation)
Expired - Past validity period (if time-limited)
The current implementation doesn’t show explicit revocation logic. Consider adding certificate status field and expiration dates for enhanced control.
Validation Display
Verified Certificate Display
When a valid certificate is scanned:
< div class= "validation-success" >
< h2 > Certificado Válido </ h2 >
< div class= "employee-info" >
< p >< strong > Nombre: </ strong > {{ Employee.empNombreCompleto }} </ p >
< p >< strong > RFC: </ strong > {{ Employee.empRFC }} </ p >
< p >< strong > Dependencia: </ strong > {{ Employee.empDependencia }} </ p >
< p >< strong > Año de Evaluación: </ strong > {{ Employee.evalAnio }} </ p >
< p >< strong > Tipo: </ strong > {{ Employee.tipoEval }} </ p >
</ div >
< p class= "verification-date" > Verificado: {{ currentDate }} </ p >
</ div >
Invalid Certificate Display
For invalid or tampered certificates:
< div class= "validation-error" >
< h2 > Certificado No Válido </ h2 >
< p > Este código no corresponde a un certificado válido. </ p >
< p > Si cree que esto es un error, contacte a CEACC Durango. </ p >
</ div >
Certificate Printing
Print-Friendly Styling
Certificates should include print-optimized CSS:
@media print {
.no-print {
display : none ;
}
.certificate {
width : 100 % ;
max-width : 210 mm ; /* A4 width */
margin : 0 auto ;
}
.qr-code {
width : 3 cm ;
height : 3 cm ;
}
/* Force page breaks */
.page-break {
page-break-after : always ;
}
}
Download Options
Consider implementing:
PDF download (similar to expediente generation)
High-resolution image export
Print-optimized HTML view
Security Considerations
Important Security Measures:
HTTPS Required : QR codes should link to HTTPS URLs only
Rate Limiting : Implement rate limiting on validation endpoint to prevent abuse
Logging : Log all validation attempts for audit trail
Revocation System : Implement certificate revocation capability
Expiration Dates : Consider time-limited certificates
Watermarks : Add visual security features to printed certificates
Access Logging : Track who views certificates and when
Integration with Profile
Certificates appear in the employee profile:
const profile = async ( req , res ) => {
try {
const usrId = req . session . usrId ;
const anio = new Date (). getFullYear ();
const [ currentEvaluation ] = await PoolvLife . query (
AuthModel . getLastEvaluation ,
[ anio , usrId ]
);
if ( currentEvaluation . length > 0 ) {
const evalID = currentEvaluation [ 0 ]. evalID ;
// Get certificate if exists
const [ GetConstancia ] = await PoolvLife . query (
AuthModel . GetConstancia ,
evalID
);
res . render ( "profile" , {
user: req . session . name ,
currentEval: currentEvaluation [ 0 ],
constancia: GetConstancia [ 0 ], // May be undefined if not yet issued
});
}
} catch ( e ) {
console . log ( e );
}
};
Production Deployment Checklist
Update Validation URL
Replace placeholder URL with production domain.
Configure HTTPS
Ensure all URLs use HTTPS protocol.
Implement Rate Limiting
Protect validation endpoint from abuse.
Add Logging
Track validation attempts and certificate views.
Test QR Codes
Verify QR codes work on various devices and scanners.
Configure Error Correction
Set appropriate QR code error correction level.
Add Revocation System
Implement ability to revoke certificates.
Design Certificate Layout
Finalize official certificate design and branding.
ConstanciaController.js (src/controllers/ConstanciaController.js:1) - Certificate viewing
ConstanciaValidatorController.js (src/controllers/ConstanciaValidatorController.js:1) - Public validation
ConstanciaModel.js - Database queries for certificates
AuthController.js (src/controllers/AuthController.js:151) - Profile integration
Next Steps
Authentication Review the authentication system
Expediente Generation Generate complete evaluation PDFs