Skip to content

feat: KYC onboarding flow with document verification - #993

Merged
github-actions[bot] merged 4 commits into
Smartdevs17:mainfrom
Itodo-S:feat/kyc-onboarding-document-verification
Sep 28, 2026
Merged

github-actions[bot] merged 4 commits into
Smartdevs17:mainfrom
Itodo-S:feat/kyc-onboarding-document-verification

Conversation

@Itodo-S

@Itodo-S Itodo-S commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #921

Adds a full KYC onboarding flow for individual users: personal info → document upload → review & status, with document verification in two layers: local format checks, then a pluggable verification provider. It builds on the existing KycService (backend/src/services/kyc.ts), which already had profiles, risk scoring and AML/sanctions/PEP stubs but no API or flow. It reuses the kyc upload category rules from the file-upload middleware.

Backend

  • services/kyc-verification.ts (new): document checks.
    • File type (jpeg/png/webp/pdf), 1 KB–10 MB size, extension/MIME match and magic-byte signature (shared with the upload middleware).
    • Document-number patterns per type, with country formats for US/GB/IN/NG passports and the NG NIN.
    • Identity documents: expiry required and in the future, with a warning inside 30 days. Proof of address must be issued within the last 90 days.
    • Applicant must be 18 or older.
    • Defines the DocumentVerificationProvider interface and a deterministic MockDocumentVerificationProvider: numbers ending 000 are rejected, numbers ending 999 go to manual review.
  • services/kyc.ts (extended): savePersonalInfo, uploadDocument, getOnboardingState, submitForReview, review, reviewDocument, listForReview.
    • Status transitions pending → under_review → approved | rejected. Rejected or expired applications return to pending when the applicant resubmits.
    • Every transition goes into statusHistory with the actor and reason, and rejections need at least one reason.
    • On submit, the existing screening checks run. Low-risk applications whose documents all passed are approved automatically. Everything else, including high-risk jurisdictions (from the existing HIGH_RISK_COUNTRIES list), goes to the review queue.
    • Blocks the same identity document from being used on two accounts. Document numbers are stored masked, and file contents are hashed but not stored.
    • The existing submitDocument / verifyDocument / updateStatus APIs keep working.
  • routes/kyc.ts + schemas/kyc.ts (new): mounted at /api/v1/kyc. Endpoints: requirements, state, personal-info, documents, submit, review queue, document review, application review. Service errors map to the standard error envelope, with the reasons in details.
  • Wiring:
    • /api/v1/kyc accepts JSON bodies up to 15 MB so a base64-encoded 10 MB document fits, and is added to the request-size-limit upload paths.
    • documentNumber, fileContent and dateOfBirth are redacted from audit-log request bodies.
    • Removed two unused imports from file-upload.ts, a file this PR already touches.

Frontend

  • New /dashboard/kyc page (components/kyc/*, lib/kyc.ts). It runs a three-step flow that repeats the backend's file, number and date checks in the browser, shows each document's status, warnings and rejection reasons, and resumes from the step the API reports.
  • Linked from the sidebar ("Identity (KYC)") and from the onboarding wizard's identity-verification step.

Docs

  • docs/KYC_ONBOARDING.md covers the endpoints, error codes, validation rules, status transitions, the provider interface and the mock provider's behaviour.

How it was tested

New tests:

  • backend/src/services/__tests__/kyc-verification.test.ts: every format check (pass and fail), plus the mock provider.
  • backend/src/services/__tests__/kyc-onboarding.test.ts: the full flow.
    • Transitions, auto-approval, manual review and rejection with resubmission.
    • Provider rejection, inconclusive results and provider failure.
    • Duplicate documents, locking while under review, and expiry after one year.
  • backend/src/routes/__tests__/kyc.test.ts: the HTTP API end to end on a real Express server.
  • frontend/lib/kyc.test.ts: client-side validation and API error handling.
  • frontend/components/kyc/__tests__/KycOnboardingFlow.test.tsx: the UI flow, including validation, upload, server errors, submit and the rejected state.
cd backend
npx vitest run src/services/__tests__/kyc.test.ts src/services/__tests__/kyc-verification.test.ts \
  src/services/__tests__/kyc-onboarding.test.ts src/routes/__tests__/kyc.test.ts   # 93 passed
npx eslint <changed backend files>                                                 # clean
npx tsc --noEmit    # no new errors (the pre-existing error count is unchanged)

cd frontend
npx vitest run lib/kyc.test.ts components/kyc                                      # 22 passed
npx eslint <changed frontend files>                                                # clean
npx tsc --noEmit    # no errors in the new or changed files

I also ran a manual end-to-end check with tsx: Express with the KYC router, a 3 MB PDF sent as base64, a passport plus a bank statement, then submit. It went pending → under_review → approved.

Full-suite regression check: the backend suite has the same failing files before and after this change. The only difference is that kyc.test.ts now passes: two of its timestamp tests were flaky (same-millisecond updatedAt) and now use fake timers.

Notes for reviewers

  • Under Vitest, .js import specifiers in backend/src/middleware resolve to old compiled CommonJS files that sit next to errorHandler.ts and validate.ts. The route test mocks those two modules to use the TypeScript sources, which are what the build actually ships. tsx and tsc are not affected.
  • Existing failures I ran into that this PR does not change:
    • next build fails because next-intl is not in frontend/package.json.
    • Several frontend component tests import @testing-library/react, which is not installed. For that reason the new component test renders with react-dom directly.
    • backend/src/index.ts has existing unused-import lint errors.

Validate KYC documents before verification: allowed MIME types and
size limits from the kyc upload category, extension and magic-byte
checks, document-number patterns (with country-specific formats),
identity document expiry and proof-of-address recency. Define a
DocumentVerificationProvider interface with a deterministic mock
provider for local development and tests.

Refs Smartdevs17#921
Extend KycService with a personal info -> documents -> review flow:
provider-backed document checks, duplicate document detection, status
transitions (pending, under_review, approved, rejected, expired) with
recorded history and reasons, automatic approval for low-risk
applications and a manual review queue. Expose it under /api/v1/kyc,
allow larger JSON bodies for base64 document uploads and redact
document numbers, file contents and dates of birth from audit logs.

Also makes the two timestamp-based KycService tests deterministic.

Refs Smartdevs17#921
Add a /dashboard/kyc page with a three-step flow (personal info,
document upload, review and status) that mirrors the backend document
checks in the browser, shows per-document verification results and
rejection reasons, and resumes from the step the API reports. Link it
from the sidebar and the onboarding wizard's identity step.

Refs Smartdevs17#921
@vercel

vercel Bot commented Sep 28, 2026

Copy link
Copy Markdown

@Itodo-S is attempting to deploy a commit to the smartdevs17's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Sep 28, 2026

Copy link
Copy Markdown

@Itodo-S Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@github-actions
github-actions Bot merged commit 1ba87f1 into Smartdevs17:main Sep 28, 2026
14 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build KYC onboarding flow with document verification

1 participant