fix(certificates): Verify certificates by printed certificate number - #1161
Open
jeromehardaway wants to merge 2 commits into
Open
fix(certificates): Verify certificates by printed certificate number#1161jeromehardaway wants to merge 2 commits into
jeromehardaway wants to merge 2 commits into
Conversation
Verification looked up certificates by Prisma row id instead of the certificateNumber column, so the VWC-YYYY-XXXXXX number printed on PDFs never resolved, and the printed vetswhocode.io/verify/<number> URL had no matching route. - getCertificateByNumber now queries the certificateNumber column and falls back to a row-id lookup when the input matches the cuid shape, so legacy certificates that printed the id keep verifying - formatCertificateData and the verify API response return the real certificate number instead of exposing the cuid - /api/certificates/verify reuses the lib lookup and documents the endpoint with a swagger block - New public page /verify/[number] renders the verified certificate (student, course, completion date) or a clear invalid state - Regression tests cover printed-number lookup, unknown numbers, the legacy id fallback, missing param, and method handling
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes broken certificate verification by switching lookups to use the printed certificateNumber (VWC-YYYY-XXXXXX) while preserving backward compatibility for legacy certificates that printed the Prisma cuid row id. This also adds a public /verify/[number] page that matches the URL printed on PDFs and introduces regression tests for the verification API.
Changes:
- Update certificate lookup logic to query
certificateNumberfirst with legacycuidfallback. - Refactor
/api/certificates/verifyto reuse the shared lookup and return the printed certificate number. - Add a public
/verify/[number]page plus API regression tests and Swagger spec updates.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/pages/verify/[number].tsx | Adds public verification page for printed /verify/<number> URLs. |
| src/pages/api/certificates/verify.ts | Updates verification API to verify by printed certificate number via shared library function; adds Swagger docs. |
| src/lib/certificates.ts | Fixes getCertificateByNumber + formatCertificateData to use certificateNumber with legacy fallback. |
| public/swagger-spec.json | Adds OpenAPI entry for the verify endpoint. |
| tests/api/certificates/verify.test.ts | Adds regression tests for printed-number verification and legacy fallback behavior. |
Comments suppressed due to low confidence (1)
src/pages/api/certificates/verify.ts:76
- This is a public verification endpoint, but it currently returns the student’s email address. Since the verification UI doesn’t use it and the printed certificate verification use-case doesn’t require it, consider omitting email to reduce unnecessary PII exposure.
certificate: {
certificateNumber: certificate.certificateNumber ?? certificate.id,
student: {
name: certificate.user.name || "Unknown",
email: certificate.user.email,
},
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+42
to
+63
| useEffect(() => { | ||
| if (!number || typeof number !== "string") return; | ||
|
|
||
| const verifyCertificate = async () => { | ||
| try { | ||
| const response = await fetch( | ||
| `/api/certificates/verify?number=${encodeURIComponent(number)}` | ||
| ); | ||
| const data = await response.json(); | ||
|
|
||
| if (response.ok && data.valid && data.certificate) { | ||
| setCertificate(data.certificate); | ||
| } | ||
| } catch { | ||
| // Treated as invalid below | ||
| } finally { | ||
| setLoading(false); | ||
| } | ||
| }; | ||
|
|
||
| verifyCertificate(); | ||
| }, [number]); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Certificate verification was broken end to end:
certificateNumber(VWC-YYYY-XXXXXX), and the PDF prints "Certificate No: " plus "Verify at: vetswhocode.io/verify/"./api/certificates/verifyusedfindUnique({ where: { id: number } }),getCertificateByNumberinsrc/lib/certificates.tsdid the same, andformatCertificateDatareturned the cuid as the certificate number./verify/<number>URL had no matching route at all, so every printed link 404'd.Solution
getCertificateByNumbernow queries thecertificateNumbercolumn first. If that misses and the input matches the cuid shape of row ids, it falls back to an id lookup so legacy certificates (nullcertificateNumber, printed the cuid) keep verifying./api/certificates/verifyreuses the lib lookup instead of its own query, returnscertificate.certificateNumber(falling back to the id for legacy rows), and now has a@swaggerblock.formatCertificateDatareturns the real certificate number.src/pages/verify/[number].tsxresolves the printed URL: it calls/api/certificates/verify?number=...and renders the verified state (student, course, completion date, certificate number) or a clear invalid state, following the visual conventions ofsrc/pages/certificates/[certificateId].tsx.pdf-certificate.tsis unchanged — already-printed certificates keep working.Verification
npm run typecheck— no errors in changed files; the 7 reported errors are pre-existing in untouched__tests__/**/j0di3/*files (verified identical on a clean master checkout).npm run lint— changed files have 0 errors (2 pre-existinganywarnings on existing signatures incertificates.ts); repo-wide errors are pre-existing in untouched files.npm test— 42 files / 389 tests pass, including new__tests__/api/certificates/verify.test.ts(printed number resolves valid with correct student/course, unknown number returns valid:false with no id fallback, legacy cuid id falls back to id lookup, missing param 400, non-GET 405).npm run build— succeeds;/verify/[number]and/api/certificates/verifypresent in route output.Closes #1148