Architecture Overview
The Supplier Client is a feature-module Angular application. A thin eagerly loaded shell boots the store, the translation layer and all third-party SDKs; everything a supplier actually looks at is a lazy-loaded module hanging off that shell.
The three layers
| Layer | Location | Responsibility |
|---|---|---|
Core |
|
Singletons. Auth, HTTP interceptors, NgRX root config, business services,
domain enums and models, guards, marketplace connectors. Imported once, by
|
Views |
|
Everything rendered. Lazy feature pages, the onboarding flow, shared widgets
and modals, and the authenticated app shell ( |
Vendors |
|
Thin in-repo wrappers around third-party SDKs (Plaid, CloudWatch) that expose
an Angular-idiomatic module with a |
|
|
Module graph
AppModule (eager, bootstraps AppComponent)
│
├── CoreModule ................ interceptors, pipes, directives, icon registry
├── FeaturesModule ............ registers every NgRX feature + entity slice
├── PartialsModule ............ shared widgets, modals, components
├── ThemeModule ............... BaseComponent shell, header, aside, footer
├── AuthModule.forRoot() ...... auth store slice + persistent meta-reducer
├── OnboardingModule .......... onboarding shell (eager, routed lazily)
│
├── StoreModule.forRoot() ..... router reducer + metaReducers (storeFreeze in dev)
├── EffectsModule.forRoot([]) . root effects registry
├── StoreRouterConnectingModule ... router state → store (stateKey: 'router')
├── StoreDevtoolsModule ....... logOnly instrumentation
│
├── PybApiModule.forRoot() .... Payability API client (base URLs from environment)
├── MarqetaModule.forRoot() ... Seller Card issuance SDK
├── PlaidModule.forRoot() ..... bank linking SDK
├── SegmentModule.forRoot() ... analytics (loadOnInitialization only in prod)
├── CloudWatchModule.forRoot() ... custom metrics endpoint
├── PageLoadTimeTrackerModule.forRoot(['/dashboard']) ... page timing
├── ServiceWorkerModule.register() ... PWA, enabled in production only
├── NgxPermissionsModule.forRoot()
└── TranslateModule.forRoot() ... local loader, default language `en`
│
└── AppRoutingModule
└── BaseComponent [AuthGuard] ← the authenticated shell
├── DashboardModule ............... lazy, [DocuSignGuard]
├── ReportsModule ................. lazy
├── ManageAccountModule ........... lazy, [TwoFactorAuthenticationGuard]
├── SellerCardModule .............. lazy
├── NewCardModule ................. lazy
├── MyMarketplacesPageModule ...... lazy
├── OnboardingModule .............. lazy
├── ProductOfferingsModule ........ lazy, [DocuSignGuard]
├── VendorPayIncomingReportsModule lazy
├── SendMoneyModule ............... lazy
├── PartnersModule ................ lazy
├── MoreFromPayabilityModule ...... lazy (referral)
├── PayshieldSubscriptionModule ... lazy
├── BlogPageModule ................ lazy
├── SalesCallSummaryModule ........ lazy
└── DailySummaryModule ............ lazy, [NgxPermissionsGuard]
See Route Tree for the URL each module serves.
src/app/core in detail
| Folder | Contents |
|---|---|
|
|
|
Layout config service, subheader service, splash-screen service, translation
service, plus the shared pipe set ( |
|
The |
|
|
|
Marketplace API health monitoring for Amazon and Shopify. See Marketplace API Connectors. |
|
The complete authentication subsystem: actions, effects, reducers, selectors,
guards, interceptors, models, and |
|
|
|
Marqeta SDK wrapper module for Seller Card operations. |
|
|
|
All Payability business logic. Subdivided below. |
|
Root |
|
Report infrastructure shared by every report page: AG Grid config, DI tokens, daily-summary and fee-report helpers. |
src/app/core/pyb in detail
| Folder | Contents |
|---|---|
|
Reusable Angular animation triggers. |
|
AG Grid cell renderers, pagination, reCAPTCHA wrapper, dynamic container. |
|
Icon registry, media registry, hyperlink service config. |
|
Contact details, country codes, help-article IDs, LTC flow constants, banner factories. |
|
AG Grid server-side datasource adapters. |
|
Static lookup maps used by forms. |
|
NgRX Entity collections — countries, marketplaces, supplier marketplaces, onboarding, daily summary report. |
|
Every domain enum. See Enum Reference. |
|
NgRX feature slices. See Feature Slices. |
|
Dynamic form field definitions and factories. |
|
Composed multi-step business flows (advance line, LTC, re-sign contract). |
|
|
|
Cross-cutting TypeScript interfaces. |
|
Client-side domain models and DTO mappers. |
|
|
|
Shared DI providers. |
|
~40 domain services. See Service Catalog. |
|
Individual |
|
|
|
Sync and async reactive-form validators. |
Cross-cutting patterns
Smart / presentational split
Container components select from the store and dispatch actions; presentational
components receive @Input() and emit @Output(). Presentational components do
not inject Store.
OnPush everywhere
ChangeDetectionStrategy.OnPush is the default. Components that mutate their own
view model must either produce new references or call markForCheck()
explicitly.
The Subscriber base class
src/app/core/pyb/utils/subscriber.class.ts exposes an ngUnsubscribe$ subject
and completes it in ngOnDestroy. Any class holding long-lived subscriptions
extends it and pipes through takeUntil(this.ngUnsubscribe$). Services do this
too — DocusignVerificationService extends Subscriber.
Services are root-provided
Domain services are declared @Injectable({ providedIn: 'root' }). Feature
modules only list a provider when the service is genuinely feature-scoped (for
example ManageAccountService, ReportsService, ProductOfferingsService).
Configuration by injection token
Grid column sets, banner definitions and connector configuration are supplied as
DI tokens rather than hardcoded in components. ReportsModule alone provides
FEE_REPORT_COLUMNS_CONFIG_TOKEN, OUTSTANDING_BALANCE_COLUMNS_CONFIG_TOKEN,
VENDOR_PAY_INCOMING_REPORT_COLUMNS_CONFIG_TOKEN and several more. This makes
the same grid component reusable across reports.
Global side-effect wiring
GlobalSubscriptionsService.init() is the single place where session-scoped
background behaviour is started. It is idempotent (guarded by an initialized
flag) and it:
-
initializes the marketplace API connectors,
-
runs the Plaid bank-verification check,
-
mirrors calculated permissions into
NgxPermissionsService, -
subscribes to the welcome-message, Airwallex p-card terms and identity-document-expired dashboard notifications and opens their modals,
-
evaluates whether the supplier must re-sign their contract,
-
initializes the account-cancelled, 2FA-setup, suspension-reason and cancellation-status banners,
-
dispatches
fetchFees().