Skip to main content

Application Logic

:::info Source Sourced from services/certification-service/APPLICATION_LOGIC.md in the documentation repo. :::

1. Application Services

  • CertificateIssuanceService — derives + issues from completion.
  • CertificateRenderService — PDF/PNG/OpenBadges artifact generation.
  • VerificationService — public verify endpoint.
  • RevocationService — revoke with reason + reindex.
  • OfflineClaimService — verify local signatures and issue.
  • TemplateService — template CRUD + preview.

2. Commands

CommandTrigger
IssueCertificate(enrollmentId, attemptId)progress.completion.recorded.v1
IssueCertificateFromClaim(claimId)certification.offline_claim.submitted.v1
RevokeCertificate(id, reason)Admin action or compliance event
VerifyCertificate(token)Public GET /verify/{token}
CreateTemplate, UpdateTemplate, ArchiveTemplateAdmin

3. Queries

  • getCertificate(id) / getByToken(token) (public).
  • listUserCertificates(userId).
  • listTemplates(tenantId).
  • getIssuanceAudit(certificateId).

4. Sagas

  • Participates in GDPR Erasure Saga: decisions on certification under legal hold (retain for verifiability) with anonymization of user PII (keep name-at-issuance if public verifier relies on it? per tenant policy).
  • Participates in Course Revocation flow: if catalog.course_version.withdrawn.v1 and serious defect, admin may bulk-revoke certificates.

5. Policies

  • Idempotency: one certificate per (enrollment, courseVersion). Duplicate completion events no-op.
  • Template selection: from course setting → tenant default → platform default.
  • Revocation visibility: public verify returns revoked + publicReason if set.

6. Use Case Flows

6.1 Online Issuance

Consume progress.completion.recorded.v1

├─ Check existing certificate (idempotent)
├─ Resolve template (course.certificateTemplateId || tenant.default)
├─ Gather artifact inputs (user display name, course title, issued date, signatory)
├─ Render PDF/PNG via headless Chrome
├─ Generate OpenBadges 3.0 VC (JSON-LD with proof)
├─ Sign JWS proof (tenant key)
├─ Persist Certificate
├─ Upload artifacts to S3 (signed URL prefix)
├─ Emit certification.certificate.issued.v1

6.2 Offline Issuance Claim

Learner completes offline → PlayPackage emits local signature.
On sync, client pushes OfflineIssuanceClaim.

├─ Verify localSignature against bundle key (content-service verifies)
├─ Verify attempt + completion in progress-service (replay completion event)
├─ If valid: issue certificate with state='issued'; evidence includes local signature
├─ If invalid: reject; emit rejection event; learner notified with reason

6.3 Verification (Public)

GET /api/v1/certificates/verify/{token}

├─ Lookup Certificate by token (HMAC verify)
├─ Check revocation
├─ Verify JWS proof
├─ Return minimal public info: userDisplayName, courseTitle, issuedAt, state, tenantPublicName
├─ Rate limit per IP
├─ Log verification event (analytics)

6.4 Revocation

Admin: POST /certificates/{id}/revoke with reason.

├─ Update Certificate.state = 'revoked'
├─ Create RevocationRecord
├─ Emit certification.certificate.revoked.v1
├─ Search reindex (status update)
├─ Notify certificate holder (optional)