Skip to content

feat(background-check): V1 two-paths redesign — Order / Attach / Exempt#2839

Merged
tofikwest merged 4 commits into
mainfrom
tofik/bg-check-v1-twopaths
May 13, 2026
Merged

feat(background-check): V1 two-paths redesign — Order / Attach / Exempt#2839
tofikwest merged 4 commits into
mainfrom
tofik/bg-check-v1-twopaths

Conversation

@tofikwest
Copy link
Copy Markdown
Contributor

@tofikwest tofikwest commented May 13, 2026

Summary

Implements the V1 design from design_handoff_background_check/SPEC.md. The Background Check tab's empty state is now a unified task-oriented surface where Order a new check, Attach an existing report, and Mark as exempt are equal first-class decisions, replacing the previous marketing-style benefits grid + separate form + separate upload UI.

Page anatomy

  1. Status strip — status badge + sentence + credits remaining + Choose a plan link
  2. Path picker — 3 selectable radio-style cards (Order / Attach / Exempt)
  3. Contextual body — form for the selected path, state preserved across switches
  4. Scope panel — collapsible "What's verified in this check" with 6 rows (hidden on Exempt)

What changed

New components (one file per concern, all under 250 lines):

File Purpose
BackgroundCheckV1Page.tsx Top-level orchestrator: status strip + path picker + contextual body + scope panel
BackgroundCheckPathCard.tsx Selectable card with icon, title, description, meta, radio dot — role=radio, ArrowLeft/Right keyboard navigation, Space/Enter to select
BackgroundCheckStatusStrip.tsx Status badge + sentence + credits + Choose a plan link
BackgroundCheckScopePanel.tsx Collapsible "What's verified" with 6 scope rows (Required for compliance / Identity verification / Reference checks / Full audited report / Previous employer verification / Social media screening)
BackgroundCheckOrderForm.tsx Employee name + personal email + internal notes + Send invite
BackgroundCheckAttachForm.tsx Vendor select + report date + dropzone (drag-and-drop + browse) + Attach report
BackgroundCheckExemptForm.tsx Warning callout + reason select + justification + Confirm exemption
BackgroundCheckFormHelpers.tsx Shared LabelRow, FormFooterInfo, FormFooterRow (used by all three forms)
BackgroundCheckNotices.tsx BackgroundCheckExemptToggle + BackgroundCheckNotice + BackgroundCheckDisabledNotice
BackgroundCheckAuditTimeline.tsx Extracted from the report file to stay under the 300-line limit
backgroundCheckUtils.ts isValidEmail, computeCredits, buildAttachNotes, fileToBase64

Removed (V1 supersedes):

  • BackgroundCheckMethodology.tsx — replaced by V1 scope panel
  • BackgroundCheckWizardParts.tsx (OverviewStep, BackgroundCheckSummary, BillingCallout) — V1 has no separate overview
  • BackgroundCheckDetailsForm.tsx — replaced by Order form
  • CustomBackgroundCheckUpload.tsx + .test.tsx — replaced by Attach form
  • PaymentMethodUpdateDialog.tsx — V1 doesn't gate on stale payment methods
  • backgroundCheckForm.ts (react-hook-form glue + sessionStorage pending-request stash) — V1 uses plain useState, no pending-request persistence

EmployeeBackgroundCheck.tsx — completely rewired:

  • Removed wizard steps, 402 "out of credits → redirect to billing" flow, session_id post-Stripe handling, payment-method recovery dialog
  • V1 simply disables Send invite when credits = 0 and surfaces "Choose a plan →" in the status strip
  • Preserves the "already exempt → toggle off" inverse flow (Switch + info notice) since spec doesn't address the un-exempt path

Wiring to existing APIs

Action Endpoint
Send invite (Order) POST /v1/people/:id/background-check (existing)
Attach report (Attach) POST /v1/people/:id/background-check/custom (existing; vendor + report date are stuffed into requesterNotes until DTO is extended)
Confirm exemption (Exempt) PATCH /v1/people/:id with backgroundCheckExempt: true, backgroundCheckExemptReason, backgroundCheckExemptJustification — the latter two are new fields; backend currently ignores them. Follow-up: extend apps/api/src/people/dto/update-member.dto.ts to persist them in the audit log.

Design fidelity

Tokens, copy, layout, spacing, radii, motion — all per SPEC.md. Three off-token tinted colors (oklch(0.985 0.012 167), oklch(0.93 0.06 85), oklch(0.99 0.03 90)) used inline for selected card background and amber warning surface, per spec.

Icon substitutions where the spec's Carbon name doesn't exist in @carbon/icons-react — closest geometric match used:

  • LightningBolt/FlashFlash
  • AttachmentAdd/PasteAttachment
  • Fingerprint/IdBadgeFingerprintRecognition
  • BriefcasePortfolio

Verification

  • audit-design-system clean — no @trycompai/ui or lucide-react, no className on DS components that reject it
  • ✅ All 15 V1 tests pass — path picker default, status strip credits, path switching, scope panel toggle, email validation, POST payload, disabled-on-no-credits, exempt PATCH with reason, form-state preservation, bypass notice, exempt notice, prop resync
  • ✅ All 9 existing BackgroundCheckStatusView.test.tsx tests pass (no changes there)
  • ✅ No new typecheck errors in any background-check file
  • ✅ All files under the 300-line limit

Relationship to PR #2836

This supersedes the marketing-forward methodology overview in PR #2836 (already merged). The V1 design is task-oriented and replaces that overview entirely. The completed-report banner from that PR has been preserved (inlined into BackgroundCheckReport.tsx).

Test plan

  • Open any employee profile and switch to the Background Check tab. Confirm new layout: status strip → path picker (3 cards, Order selected by default) → Order form → scope panel.
  • Click through Attach card — confirm vendor dropdown + report date + dropzone render; drag-and-drop a PDF and confirm it shows as selected; verify "Attach report" enables only with a file.
  • Click through Exempt card — confirm warning callout + reason dropdown + justification textarea render; verify "Confirm exemption" enables only with a reason selected; submit and confirm the page renders the inverse exempt notice with a working un-exempt toggle.
  • With a 3-credit plan: confirm "Credits remaining 2 / 3" in the status strip.
  • With 0 credits: confirm Send invite is disabled with the "out of credits" title attribute.
  • Type into Personal email then switch to Attach and back — confirm the email field still holds its value.
  • Type an invalid email and click Send invite — confirm inline "Enter a valid personal email" error and no POST.
  • Keyboard: focus a path card, press ArrowRight — selection should move to the next path.

🤖 Generated with Claude Code


Summary by cubic

Redesigned the Background Check tab into a single, task‑first V1 flow where users can Order, Attach, or Mark as exempt. Replaces the wizard/marketing views, simplifies billing, improves keyboard navigation, and adds a report audit timeline; backend follow‑up still needed to persist exempt reason/justification.

  • New Features

    • Unified page: status strip with credits + plan link, 3‑path picker (Order/Attach/Exempt) as a real radiogroup, contextual forms, and a 4‑row collapsible “What’s verified”; Order card copy updated to remove “audited.”
    • Actions: Order → POST /v1/people/:id/background-check (email validation; disabled when out of credits). Attach → POST /v1/people/:id/background-check/custom (vendor/date/file; button enables only with a file; vendor/date temporarily encoded in requesterNotes). Exempt → PATCH /v1/people/:id with backgroundCheckExempt, backgroundCheckExemptReason, backgroundCheckExemptJustification (keeps the un‑exempt toggle).
    • Report view: adds an audit timeline and removes the marketing methodology block.
  • Bug Fixes

    • Arrow‑key path navigation tracks the currently selected path even if focus stays on another card.
    • Credits now filter to the background_check subscription to display accurate counts.
    • Order payload trims employeeName and employeeEmail before POST.

Written for commit 800265a. Summary will update on new commits.

…task surface

Implements the V1 design from `design_handoff_background_check/SPEC.md`:
the Background Check tab's empty state is now a unified task-oriented page
where Order / Attach / Exempt are equal first-class decisions, instead of
a marketing-style benefits grid followed by a separate form and upload UI.

Page anatomy (top to bottom): status strip with credits + plan link → path
picker (3 selectable cards) → contextual body (Order / Attach / Exempt
form per selection, form state preserved across switches) → collapsible
"What's verified in this check" scope panel.

The path picker is a true radiogroup (role=radio, ArrowLeft/Right
navigation, Space/Enter to select). Out-of-credits disables Send invite;
missing PDF disables Attach report; missing reason disables Confirm
exemption.

Wiring:
- Order  → POST /v1/people/:id/background-check (existing endpoint)
- Attach → POST /v1/people/:id/background-check/custom (existing)
- Exempt → PATCH /v1/people/:id with backgroundCheckExempt + reason +
  justification (latter two are new; backend ignores until DTO is
  extended — flagged in PR description)

Removed: BackgroundCheckMethodology, BackgroundCheckWizardParts (Overview
/ BackgroundCheckSummary / BillingCallout), BackgroundCheckDetailsForm,
CustomBackgroundCheckUpload, PaymentMethodUpdateDialog, react-hook-form
glue for the wizard, sessionStorage pending-request stash, and the 402
"out of credits → redirect to billing" flow (V1 just disables the button
and exposes "Choose a plan →" in the status strip).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 13, 2026

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

Project Deployment Actions Updated (UTC)
app Ready Ready Preview, Comment May 13, 2026 11:22pm
comp-framework-editor Ready Ready Preview, Comment May 13, 2026 11:22pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
portal Skipped Skipped May 13, 2026 11:22pm

Request Review

… screening" scope rows

Per Lewis: remove both rows from the "What's verified in this check" panel.
The summary count auto-updates from 6 to 4.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 21 files

Confidence score: 3/5

  • There is moderate merge risk: the keyboard arrow navigation logic in apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/BackgroundCheckV1Page.tsx uses a hardcoded card id, which can cause incorrect focus/path movement after the first keypress and is user-facing.
  • apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/backgroundCheckUtils.ts may show wrong credit counts because computeCredits can select a non-background-check active subscription, creating data-display inaccuracies.
  • In apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/EmployeeBackgroundCheck.tsx, sending untrimmed employeeName/employeeEmail is a smaller but concrete correctness issue that can lead to avoidable API input problems.
  • Pay close attention to apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/BackgroundCheckV1Page.tsx, apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/backgroundCheckUtils.ts, and apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/EmployeeBackgroundCheck.tsx - they contain the navigation and data correctness fixes most likely to affect user behavior.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/BackgroundCheckV1Page.tsx">

<violation number="1" location="apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/BackgroundCheckV1Page.tsx:69">
P2: Arrow-key path navigation is computed from a hardcoded card id, so keyboard navigation can misbehave after the first move. Compute relative navigation from `selectedPath` instead.</violation>
</file>

<file name="apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/backgroundCheckUtils.ts">

<violation number="1" location="apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/backgroundCheckUtils.ts:13">
P2: Filter `computeCredits` to background-check subscriptions; currently it can pick an unrelated active subscription and display incorrect credit counts.</violation>
</file>

<file name="apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/EmployeeBackgroundCheck.tsx">

<violation number="1" location="apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/EmployeeBackgroundCheck.tsx:122">
P2: Trim `employeeName` and `employeeEmail` before sending them to the API.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Avoids implying a third-party audited report (court records, criminal,
civil) — we don't perform that scope. The check is end-to-end via our
vendor, which is what the description now says.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…r, trim payload

Three correctness fixes flagged by cubic-dev-ai review:

1. Arrow-key path navigation: each PathCard's onNavigate was hardcoding
   its own path id. After the first arrow keypress, selection moved but
   DOM focus stayed on the original card, so subsequent presses computed
   the next path from the stale hardcoded id. Now navigateRelative reads
   selectedPath directly from state, so navigation tracks the current
   selection regardless of where focus lives.

2. computeCredits could pick a non-background-check active subscription
   (e.g. a pentest subscription) and display the wrong credit count.
   Now filters by getBillingSkuProductKey(skuKey) === 'background_check',
   matching how getBackgroundChecksRemaining already selects.

3. Send invite was POSTing employeeName / employeeEmail untrimmed. Now
   trims both before the request body — requesterNotes was already
   trimmed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel vercel Bot temporarily deployed to Preview – portal May 13, 2026 23:18 Inactive
@tofikwest tofikwest merged commit 14b6154 into main May 13, 2026
11 checks passed
@tofikwest tofikwest deleted the tofik/bg-check-v1-twopaths branch May 13, 2026 23:23
@claudfuen
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.54.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants