Skip to main content

The Self-Service CD app is a Module Federation widget built on the Candescent CDX extensibility platform. It runs embedded inside the Candescent Online Banking (OLB) shell — the member never leaves their banking portal. This page covers the SDK packages, project setup, local development workflow, and how the widget is deployed and loaded by Candescent OLB at runtime.

How the Widget Loads at Runtime

Candescent OLB is the Module Federation host. Our widget is the remote. When the member clicks the CD tile, OLB fetches our remoteEntry.js bundle from our CDN and mounts the widget inline — no page navigation, no redirect.
Our CDN
  └── remoteEntry.js        ← OLB fetches this at runtime
  └── main.[hash].js        ← lazy loaded on mount
  └── vendors.[hash].js

Candescent OLB (host)
  └── dynamically imports → mounts <SelfServiceCDWidget /> inside the OLB shell
The FI registers our remoteEntry.js URL in their Candescent admin portal once during onboarding. After that, every deploy we push to our CDN is picked up automatically.

SDK Packages

Use exact versions — mismatches break the widget at runtime inside OLB.
PackageVersionPurpose
@cdx-extensions/di-sdk1.1.2Core SDK — PlatformSDK, hooks, types
@cdx-extensions/di-sdk-web2.1.2Web-specific SDK surface
@cdx-extensions/di-sdk-types1.1.2TypeScript types for SDK interfaces
@cdx-extensions/widget-template-web1.1.2Widget project template and bootstrap wiring

Shared Host Dependencies (must match OLB exactly)

PackageVersion
react18.2.0
react-dom18.2.0
react-router-dom^6.12.1
@mui/material7.3.4
@mui/icons-material7.3.4
@mui/system7.3.3
@emotion/react11.11.1
@emotion/styled11.11.0
axios1.14.0
Do not bump these versions without coordinating with the Candescent platform team. Version mismatches with the OLB host app cause runtime crashes. Do not add new runtime dependencies without prior approval.

Project Setup

Prerequisites

ToolVersion
Node.js18 LTS or 20 LTS
npm9+
Nxoptional (use npx nx otherwise)

Install

git clone <cdx-extensibility-apps-repo>
cd cdx-extensibility-apps
npm install          # always from repo root — npm workspaces

Configure .npmrc

Copy the template and add your Candescent registry credentials before installing:
cp .npmrc.example .npmrc
# fill in registry token from your Candescent onboarding credentials

The Three SDK Hooks

Everything the widget needs from Candescent flows through three hooks on the PlatformSDK singleton.

1. useUserContext() — Member Identity

import { PlatformSDK } from '@cdx-extensions/di-sdk';

const sdk = PlatformSDK.getInstance();
const { data: user } = sdk.useUserContext();

// Available fields:
// user.customerId    → our backend uses this to identify the member
// user.fiId          → maps to which banking core to route to
// user.memberNumber  → member number at the FI
// user.firstName     → pre-fill forms
// user.lastName
// user.email
// user.userRole      → PRIMARY, JOINT, etc.

2. getHttpClient() — Secure API Calls

const client = sdk.getHttpClient();
// Raw Axios 1.14.0 — calls any absolute URL
// Auth is handled by Candescent's platform in production

// Our Python backend
const { data } = await client.get(
  'https://api.nuevesolutions.com/account-management/fetch_user_available_cds'
);

// Candescent DevEx API
const { data: accounts } = await client.get(
  'https://api.candescent.com/digitalbanking/db-accounts/v1/accounts'
);

3. useBranding() — FI Theme

const { theme: sdkTheme } = sdk.useBranding(brandingId);
// When embedded in OLB: do NOT use ThemeProvider — widget inherits host theme
// When standalone (local dev): wrap in ThemeProvider for accurate preview

Widget Scaffold

module-federation.config.ts

import { ModuleFederationConfig } from '@nx/webpack';

const config: ModuleFederationConfig = {
  disableNxRuntimeLibraryControlPlugin: true,
  name: 'self-service-cd-widget',
  exposes: {
    './SelfServiceCDWidget': './src/app/SelfServiceCDWidget',
  },
};

export default config;

Main Widget Component

// src/app/SelfServiceCDWidget.tsx
import React from 'react';
import { ThemeProvider, CssBaseline } from '@mui/material';
import { createTheme } from '@mui/material/styles';
import { PlatformSDK } from '@cdx-extensions/di-sdk';
import { CDApp } from './CDApp';

export interface SelfServiceCDWidgetProps {
  standalone?: boolean;
  [key: string]: unknown;
}

export const SelfServiceCDWidget: React.FC<SelfServiceCDWidgetProps> = (props) => {
  const standalone = props.standalone === true;
  const sdk = PlatformSDK.getInstance();
  const { data: user }  = sdk.useUserContext();
  const { theme: sdkTheme } = sdk.useBranding('default');

  const resolvedTheme = sdkTheme && Object.keys(sdkTheme).length > 0
    ? createTheme(sdkTheme)
    : createTheme({});

  // Embedded in OLB: no ThemeProvider, inherits host theme
  // Standalone (local dev): wrap with ThemeProvider for preview
  return standalone ? (
    <ThemeProvider theme={resolvedTheme}>
      <CssBaseline />
      <CDApp user={user} standalone />
    </ThemeProvider>
  ) : (
    <CDApp user={user} />
  );
};

export default SelfServiceCDWidget;

Environment Files

// src/environments/environment.ts  (local dev)
export const environment = {
  production: false,
  environment: 'dev',
  apiUrl: 'https://api-dev.nuevesolutions.com/account-management',
  features: { enableOpenAccount: true },
};

// src/environments/environment.qal.ts  (sandbox / QAL)
export const environment = {
  production: false,
  environment: 'qal',
  apiUrl: 'https://api-qal.nuevesolutions.com/account-management',
  features: { enableOpenAccount: true },
};

// src/environments/environment.prod.ts  (production)
export const environment = {
  production: true,
  environment: 'prod',
  apiUrl: 'https://api.nuevesolutions.com/account-management',
  features: { enableOpenAccount: true },
};

Local Development

# From repo root
nx serve self-service-cd-widget
# → http://localhost:4200  (standalone mode, standalone={true})
In standalone mode the widget renders with its own ThemeProvider and branding selector. This lets you develop and test the full CD flow without a live Candescent OLB connection.

Testing in OLB (Sandbox)

To test the widget embedded in a real Candescent OLB sandbox instance:
# Expose your local server publicly
npx ngrok http 4200
# → https://abc123.ngrok.io

# Register https://abc123.ngrok.io/remoteEntry.js
# with your Candescent rep as the widget remote URL in the sandbox environment

Build & Deploy

# Production build
nx build self-service-cd-widget --configuration=production

# Output: dist/apps/self-service-cd-widget/
#   remoteEntry.js
#   main.[hash].js
#   ...
Upload the dist/ output to your CDN. The remoteEntry.js URL is what the FI registers in Candescent admin.

Environments

EnvironmentCDN PathOLB Instance
Dev / locallocalhost:4200 (ngrok for OLB testing)Candescent sandbox
QAL / Staginghttps://cdn.nuevesolutions.com/cd-widget/qal/remoteEntry.jsCandescent QAL
Productionhttps://cdn.nuevesolutions.com/cd-widget/prod/remoteEntry.jsCandescent production

FI Onboarding Checklist

Steps the FI (bank / credit union) and Nueve complete together before the widget goes live.
#StepOwner
1Sign Candescent DevEx partner agreementCandescent rep
2Receive sandbox credentials and @cdx-extensions registry accessCandescent rep
3FI registers widget remote URL in Candescent admin portalFI / Bank IT
4Confirm fiId value and banking core mappingNueve + FI
5Configure FI app configuration JSON (feature flags, labels, limits)Nueve
6End-to-end test in Candescent sandbox with real member accountNueve + FI
7FI approves UX and disclosure textFI compliance
8Deploy production bundle to CDN, FI updates admin portal URLNueve
9Smoke test in production with test member accountNueve + FI

Troubleshooting

IssueLikely CauseFix
Widget shows blank in OLBremoteEntry.js URL not reachable or CORS blockedConfirm URL is publicly accessible, check CORS headers
useUserContext() returns nullRunning outside OLB without standalone={true}Set standalone={true} for local dev, or test via OLB sandbox
React version mismatch error at runtimeWidget React version differs from OLB hostPin react to 18.2.0 exactly
MUI component looks different in OLBThemeProvider wrapping widget when embeddedRemove ThemeProvider when standalone !== true
API call returns 401 in productionOLB session expiredOLB handles re-auth — widget remounts automatically
Dependency conflict on npm installPackage version outside pinned listRevert to the approved version or request Candescent approval