Onboarding
Onboarding takes a new supplier from registration to an active account. It lives
at /onboarding under its own shell (OnboardingComponent) and is tracked by
two independent mechanisms: the compliance entity slice and the
pre-activation status bar.
Onboarding schemas
Every supplier is assigned a schema at registration. It decides which steps appear and which products are reachable before activation.
// src/app/core/pyb/enums/onboarding-schema.enum.ts
export enum OnboardingSchemaEnum {
Base = '3.0',
WithPlaid = '3.0_plaid',
Expedited = 'exp_onb',
AmazonExpedited = 'amzn_exp_onb',
Next = 'NEXT',
}
| Schema | Value | Behaviour |
|---|---|---|
|
|
Standard multi-step onboarding. |
|
|
Standard plus mandatory Plaid bank linking. |
|
|
Advance Line accessible while |
|
|
Amazon-specific expedited variant. |
|
|
Next-generation flow. |
|
Only |
Onboarding templates
onboardingTemplateCode selects the copy and step set independently of the
schema:
export enum OnboardingTemplateCode {
FreeAccess = 'free_access_3.0',
}
The free-access template pairs with status.isFreeAccess and the
free-access product-offering components in
views/onboarding/product-offering/new-free-access/.
Route structure
const routes: Routes = [
{
path: '',
component: OnboardingComponent,
children: [
{ path: 'repayment-information', loadChildren: () => import('./repayment-information/…') },
{ path: 'underwriting-review', loadChildren: () => import('./underwriting-review/…') },
{ path: 'product-offering', loadChildren: () => import('./product-offering/…') },
{ path: 'sign-agreement', loadChildren: () => import('./sign-agreement/…') },
],
},
];
OnboardingComponent itself is a bare <router-outlet> host with the top bar —
step selection is driven by TopBarService and the router, not by branching
inside the component.
Compliance records
Onboarding progress is modelled as a set of compliance records in the
onboarding entity slice, keyed by complianceKey.
export const initializeOnboarding = createAction('[Onboarding] Initialize');
export const initializedOnboarding = createAction('[Onboarding] Initialized');
export const fetchCompliances = createAction('[Onboarding] Fetch compliances');
export const loadedCompliances = createAction('[Onboarding] LoadedCompliances',
props<{ compliances: PayabilityComplianceModel[] }>());
The keys are fixed UUIDs in PayabilityComplianceEnum:
| Member | Requirement |
|---|---|
|
Connect at least one sales channel. |
|
Contact details. |
|
Extended personal details. |
|
Legal entity details. |
|
Identity verification. |
|
Bank statement upload. |
|
Payout configuration. |
|
2FA enrolment. |
|
Review the product offer. |
|
Sign the supplier agreement. |
|
Sales call completed. |
|
Catch-all requirement. |
DoctypeComplianceEnum.Documentation covers generic document uploads.
Each compliance carries an AccessStatusEnum value:
export enum AccessStatusEnum {
Pending = 'pending',
Incomplete = 'incomplete',
Rejected = 'rejected',
Completed = 'completed',
Verified = 'verified',
}
The pre-activation status bar
TopBarService (views/onboarding/top-bar/top-bar.service.ts) drives the
progress stepper shown above every onboarding page. It calls
OnboardingService.getPreActivationStatus(supplierKey) and maps the returned
steps into OnbTopBarStep objects with a translated title and a deep link.
| Step key | Title key | Link |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
— |
|
|
|
|
|
|
|
|
— |
salesCallSummary is a client-side addition on top of the API’s
PreActivationStatusStepsKeys, expressed as
ExtendedPreActivationStatusStepsKeys.
Observables exposed by the service:
|
The mapped step list. |
|
|
|
|
|
Page-supplied heading text. |
fetchStatus() is called from the constructor and re-called after
submitApplication() and after onboarding activation.
Submitting the application
TopBarService.submitApplication() shows a determinate loading dialog with a
synthetic progress animation while the API call runs:
const dialogRef = this.dialog.open<LoadingPageComponent, LoadingPageData>(LoadingPageComponent, {
disableClose: true,
data: { mode: 'determinate' },
});
const minInMs = 1000 * 60;
const intervalStep = (0.25 * minInMs) / 100; (1)
const timer = interval(intervalStep).subscribe(() => {
dialogRef.componentInstance.loadingProgressValue = timerValue++;
});
this.store.pipe(
select(selectCurrentUserId),
switchMap(supplierKey => this.onboardingService.submitApplication(supplierKey)),
).subscribe(
() => this.fetchStatus(),
() => dialogRef.close(),
);
| 1 | The progress bar is timed to fill over roughly 15 seconds. It is cosmetic —
the dialog closes when loaded fires, not when the bar reaches 100. |
The dialog is disableClose: true, so the supplier cannot dismiss it mid-submit.
On error the dialog is closed and the supplier stays on the page.
The four steps
Repayment Information — /onboarding/repayment-information
Collects payment configuration: bank account details, or Plaid linking on the
WithPlaid schema. Sets status.pmtCfgProvided, which grants
TRANSFER_INFORMATION even while the supplier is pending.
Underwriting Review — /onboarding/underwriting-review
The waiting state while underwriting assesses the application. Emits
OnboardingEventType.LoadedApplicationStatus on load, and hosts the
"Submit application" action.
Product Offering — /onboarding/product-offering
Presents the approved products. Components live in
views/onboarding/product-offering/:
|
Advance Line offer presentation. |
|
Instant Advance offer. |
|
Instant Access offer. |
|
Access Plus offer. |
|
Free-access template variant. |
|
Shared offer card shell. |
|
Interactive repayment-term selector. |
|
Labelled feature row inside an offer card. |
|
Layout wrappers per offer type. |
Sign Agreement — /onboarding/sign-agreement
Redirects to DocuSign with DocusignFlowEnum.OnboardingActivation. See
DocuSign Contract Flows.
Activation
On return from DocuSign with signing_complete,
DocusignVerificationService.handleOnboardingActivation() runs:
private openOnboardingActivationModal(supplierKey: string): void {
this.onboardingService.startActivationAccount(supplierKey).pipe(
map(() => this.topBarService.fetchStatus()),
map(() => this.matDialog.open<LoadingPageComponent, LoadingPageData>(LoadingPageComponent, {
data: { activatingAccount: true, mode: 'indeterminate' },
})),
).subscribe(() => {});
}
userStatusUpdateRequested() is dispatched first, so permissions are recalculated
as soon as the backend flips the supplier to Active.
Expedited path
Expedited suppliers skip the underwriting wait for the Advance Line specifically:
register (schema = exp_onb)
→ repayment information
→ status Pending, advanceLine.status Pending
→ permission ADVANCE_LINE.ADVANCE_LINE_PENDING_ACTIVATION granted
→ Advance Line widget renders in "pending activation" state
→ first draw triggers DocusignFlowEnum.AdvanceLinePending (ACH agreement)
→ on return the permission is revoked and the draw executes
→ product selection + sign agreement continue as normal
The full mechanics are in Advance Line.
Loading page
views/onboarding/loading-page/ provides LoadingPageComponent, used in two
modes:
|
Application submission, with an animated progress value. |
|
Post-DocuSign account activation. |
Analytics
| Event | When |
|---|---|
|
The application is submitted. |
|
The underwriting-review page loads. |
|
Marketplace-linking sub-flow — see Event Catalog. |
|
Invite-Payability sub-flow. |