Skip to content

feat(kyc): differentiate identity-verified from per-rail status#2055

Draft
Hugo0 wants to merge 1 commit into
devfrom
feat/capability-shaped-kyc
Draft

feat(kyc): differentiate identity-verified from per-rail status#2055
Hugo0 wants to merge 1 commit into
devfrom
feat/capability-shaped-kyc

Conversation

@Hugo0

@Hugo0 Hugo0 commented May 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Pairs with peanut-api-ts PR #834 which fixes the BE conflation between identity verification (`base` endorsement) and per-rail availability (sepa/spei/faster_payments). With the BE fix, verified users with an outstanding rail document requirement no longer get `bridge_kyc_status='under_review'` — they correctly show as `'approved'`.

This PR aligns the FE so the identity-status card reflects both signals without misleading the user.

Changes

  • `src/components/Kyc/KycStatusItem.tsx` — subtitle precedence updated. When the user is identity-verified AND a Bridge bank rail is in `REQUIRES_EXTRA_INFORMATION`, we now show "Verified · bank docs needed" instead of the ambiguous "Action needed" that previously read as identity-pending. The detail drawer (`KycRequiresDocuments`) was already correct — the bug was at the surface card.
  • `src/hooks/tests/useUnifiedKycStatus.test.ts` (new) — 10 regression tests locking in the post-BE-fix behavior. Specifically the case `bridgeKycStatus='approved'` → `isBridgeApproved=true` AND `isBridgeUnderReview=false`. Prevents a future BE/FE refactor from reintroducing the conflation on this side.

Behavior matrix

BE state Old FE subtitle New FE subtitle
base approved, no rail issues Verified Verified
base approved, rail needs docs Action needed Verified · bank docs needed
base approved, sumsub action required Action needed Action needed
base approved, fixable rejection Action needed Action needed
base approved, blocked rejection Verification issue Verification issue
under_review Processing Processing
rejected Failed Failed

Only one row changes: the verified-with-rail-docs case. Everything else is preserved.

Risk

Minimal. Pure copy change in one component + new test file. No hook changes, no API contract changes, no new state. The visual difference is one new subtitle string variant that only renders when the user already had both signals true (which today renders the same fallback "Action needed").

Test plan

  • `npm test src/hooks/tests/useUnifiedKycStatus.test.ts` — 10/10 pass
  • All existing hooks tests still pass (39/39)
  • Manual smoke: user with `bridgeKycStatus='approved'` + a rail with status `REQUIRES_EXTRA_INFORMATION` should see "Verified · bank docs needed" on the identity-status card; clicking opens drawer with the rail-specific docs prompt as before.

Cross-repo notes

This PR is decoupled from the BE PR — it's safe to land either order:

  • If BE merges first: existing users who hit the conflated under_review state get correctly re-classified to approved on the next webhook/poll. The new FE subtitle copy then appears for them.
  • If FE merges first: no user-visible change until BE PR ships (the new subtitle only renders when both signals are true, which the BE doesn't currently produce together).

Follow-ups (deferred to KYC capability state machine §13)

  • Consolidate `useUnifiedKycStatus`, `useIdentityVerification`, `useQrKycGate`, `useMultiPhaseKycFlow` into one capability hook reading a new `/me/capabilities?intent=X&country=Y` BE endpoint.
  • Replace the per-rail status derivation in `KycStatusItem` / `KycStatusDrawer` with a typed capability shape from that endpoint.

Pairs with peanut-api-ts PR #834. Now that the backend correctly reports
`bridgeKycStatus='approved'` when the user's identity (base endorsement)
is verified — even if a bank rail still needs extra documents — the
identity-status card needs to communicate both signals separately.

Before: a verified user with a Bridge rail in REQUIRES_EXTRA_INFORMATION
showed "Identity verification: Action needed" — ambiguous, reads as if
their identity is still pending. After: "Identity verification:
Verified · bank docs needed" — explicit that the person is verified;
only their bank-rail submission needs follow-up.

Adds `useUnifiedKycStatus.test.ts` regression test locking in the
"bridgeKycStatus=approved → isBridgeApproved=true, isBridgeUnderReview=false"
behavior so future refactors can't reintroduce the conflation FE-side.
@vercel

vercel Bot commented May 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
peanut-wallet Ready Ready Preview, Comment May 16, 2026 11:07pm

Request Review

@coderabbitai

coderabbitai Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e625e66e-25c2-459d-ab9d-f3371bbd42f7

📥 Commits

Reviewing files that changed from the base of the PR and between 9e45dc0 and da8bcbe.

📒 Files selected for processing (2)
  • src/components/Kyc/KycStatusItem.tsx
  • src/hooks/__tests__/useUnifiedKycStatus.test.ts

Walkthrough

KycStatusItem subtitle logic is updated to adjust priority and wording for approved users with provider rejections and add "Verified · bank docs needed" when bridge bank documentation is required. A comprehensive test suite for useUnifiedKycStatus hook validates the status flags it computes from bridge, SUMSUB, and MANTECA verification sources.

Changes

KYC Status Display and Verification

Layer / File(s) Summary
KycStatusItem subtitle logic update
src/components/Kyc/KycStatusItem.tsx
The subtitle useMemo now reorders identity-level signal priority for approved users: returns "Action needed" for fixable rejection and "Verification issue" for blocked rejection. Adds a new approved-specific branch for "Verified · bank docs needed" when bridge bank rails require extra documents.
useUnifiedKycStatus hook test coverage
src/hooks/__tests__/useUnifiedKycStatus.test.ts
Full Jest test suite mocks useAuth and validates the hook's derived KYC status flags: bridge status mapping, SUMSUB verification selection (most recent by updatedAt) and status mapping, MANTECA verification mapping, combined "any provider approved" behavior for isKycApproved, and null-user fallback.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • jjramirezn
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(kyc): differentiate identity-verified from per-rail status' accurately describes the main change: separating identity verification signals from per-rail status in KYC handling, which is the core purpose of the PR.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the motivation (BE fix alignment), specific file changes, behavior matrix, risk assessment, and test coverage.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown
Contributor

Code-analysis diff

Painscore total: 5704.19 → 5704.5 (+0.31)
Findings: 0 net (+2 new, -2 resolved)

🆕 New findings (2)

  • high complexity — src/components/Kyc/KycStatusItem.tsx — CC 41, MI 62.01, SLOC 76
  • medium high-mdd — src/components/Kyc/KycStatusItem.tsx:37 — KycStatusItem: MDD 36.7 (uses across many lines from declarations)

✅ Resolved (2)

  • src/components/Kyc/KycStatusItem.tsx — CC 39, MI 62.34, SLOC 74
  • src/components/Kyc/KycStatusItem.tsx:37 — KycStatusItem: MDD 32.8 (uses across many lines from declarations)

@github-actions

Copy link
Copy Markdown
Contributor

🧪 UI test report — ✅ all green

Suites

  • unit: 1083 ran, 0 failed, 0 skipped, 18.8s

📊 Coverage (unit)

metric %
statements 46.6%
branches 27.9%
functions 28.2%
lines 46.4%
⏱ 10 slowest test cases
time test
0.4s src/app/actions/__tests__/api-headers.test.ts › should include Content-Type in updateUserById
0.3s src/app/actions/__tests__/api-headers-extended.test.ts › should not include apiKey in updateUserById body
0.1s src/app/actions/__tests__/api-headers.test.ts › should include Content-Type in createOnrampForGuest
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle valid 9-digit US account
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle too long for US account
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle valid US account with spaces 2
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle valid ETH address with surrounding spaces
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle valid ETH address
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle invalid ETH address (missing 0x prefix)
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle minimum length (6 digits) US account
📍 Inline annotations are in the **Unit test report** check above. Coverage artifact: `coverage-unit`. Generated by `.github/workflows/tests.yml`.

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.

1 participant