Skip to main content

Overview

The Analytics Dashboard serves as the main landing page for users after login, providing a comprehensive overview of entity compliance posture and risk metrics. The component presents a personalized welcome message and aggregates critical business intelligence data from multiple domains including compliance status, credit information, adverse actions, politically exposed persons (PEP) tracking, and litigation cases. The dashboard is designed to give executives and compliance officers a quick snapshot of their organization's regulatory standing and risk exposure across their entity portfolio.

Primary user interactions include:

  • Viewing summarized compliance metrics across different regulatory domains
  • Accessing entity-specific information and risk scores
  • Reviewing CIBIL scores and adverse markers
  • Monitoring PEP exposure and relationships
  • Tracking litigation cases and their status
  • Drilling down into specific components for more detailed information

Dashboard Components

Component Name: EntitiesInfo

The EntitiesInfo component serves as a dashboard widget displaying key entity metrics in an interactive card layout. It provides users with a snapshot of total entities under management, entities in progress, and selected data sets. Each card is clickable, enabling direct navigation to detailed views. The component features a modern, responsive design with hover effects for enhanced user experience and visual feedback.

Component Name: ComplianceInfo

The ComplianceInfo component is a comprehensive dashboard widget that provides a visual representation of various compliance metrics across different regulatory domains. It displays GST compliance, EPFO compliance, MCA charges, and GST turnover data through a combination of summary statistics and interactive charts. The component is designed to give users a quick overview of their organization's compliance status and identify potential risk areas at a glance.

Component Name: CibilAdversePep

The CibilAdversePep component is a sophisticated dashboard widget that aggregates and visualizes credit risk, adverse media mentions, and politically exposed persons (PEP) data. It presents critical risk indicators through three interconnected cards, each focusing on a specific risk domain. The component uses pie charts, donut charts, and bar charts to provide both summary statistics and detailed breakdowns of various risk categories, enabling users to identify potential regulatory and reputational risks across their entity portfolio.

Component Name: LitigationCases

The LitigationCases component is a versatile dashboard widget that presents legal case data in both tabular and chart formats. It allows users to toggle between views to analyze litigation data according to their preference. The component displays case types, total counts, pending cases, and disposed cases, sorted by volume to highlight the most significant legal exposures. It provides a comprehensive overview of the organization's legal landscape, enabling users to identify patterns and potential areas of concern.

Component Name: EntityDashboard

The EntityDashboard component provides a comprehensive tabular view of entities (companies) with search functionality, pagination, and interactive row selection. It serves as the main interface for users to browse, search, and select entities for detailed inspection. The component displays essential entity information including name, CIN (Corporate Identity Number), and establishment date, with clickable rows that navigate to detailed entity profiles.

API Integration

EntitiesInfo component:

Endpoints:

  • GET /api/entities: Fetched through the GetAllEntitiesQuery hook
    • Parameters: pageNo, pageSize, name
    • Implementation: Fetches paginated entity list data with a focus on total count
- handleClickEntity(): Navigates to '/data-terminal/entity-list'
- handleClickDataSets(): Navigates to '/data-terminal/dataSets'

ComplianceInfo Component:

const { OverallGSTCompliancesCount } = OverallGSTCompliancesCountQuery();

Fetches aggregate GST compliance statistics including on-time, delayed, and defaulted filings.

EPFO Compliance Data

const { GetCumulativeEpfo } = GetCumulativeEpfoQuery();

Retrieves Employee Provident Fund Organization compliance metrics.

MCA Charges Data

const { GetMcaCharges } = GetMcaChargesQuery();

Fetches Ministry of Corporate Affairs charges data for entities.

GST Filing Type Data

const { OverallGSTCompliancesCountByFilingType: monthly } = OverallGSTCompliancesCountByFilingTypeQuery({ filingType: FilingType.Monthly });
const { OverallGSTCompliancesCountByFilingType: quarterly } = OverallGSTCompliancesCountByFilingTypeQuery({ filingType: FilingType.Quarterly });
const { OverallGSTCompliancesCountByFilingType: yearly } = OverallGSTCompliancesCountByFilingTypeQuery({ filingType: FilingType.Yearly });

Makes three separate API calls to fetch GST compliance data by filing frequency (monthly, quarterly, and yearly).

Turnover Data

const { TurnoverPositiveNegativeEntities: TurnoverPositiveNegativeEntities } = TurnoverPositiveNegativeEntitiesQuery({ yearRange: '2021-2022' })
const { TurnoverPositiveNegativeEntities: TurnoverPositiveNegativeEntities1 } = TurnoverPositiveNegativeEntitiesQuery({ yearRange: '2022-2023' })

Makes two API calls to fetch turnover data for different year ranges, with entity counts for positive and negative growth.

Last Updated Dates

const { GetUpdatedDate } = GetUpdatedDateQuery({ type: UpdatedDateType.Gst });
const { GetUpdatedDate: epfo } = GetUpdatedDateQuery({ type: UpdatedDateType.Epfo });
const { GetUpdatedDate: mca } = GetUpdatedDateQuery({ type: UpdatedDateType.Mca });
const { GetUpdatedDate: annual } = GetUpdatedDateQuery({ type: UpdatedDateType.Turnover });

Retrieves the last updated timestamps for different data categories to display freshness indicators.

Data Transformation

Turnover Data Transformation

const transformedData = [
{
category: '2021-2022',
positive: TurnoverPositiveNegativeEntities?.positiveentitiescount || 0,
negative: TurnoverPositiveNegativeEntities?.negativeentitiescount || 0,
},
{
category: '2022-2023',
positive: TurnoverPositiveNegativeEntities1?.positiveentitiescount || 0,
negative: TurnoverPositiveNegativeEntities1?.negativeentitiescount || 0,
}
];

Purpose:

  • Transforms the raw API responses into a structured format suitable for the BarChart component
  • Creates a time-series data array with categories for year ranges and values for positive/negative entity counts
  • Implements null safety with fallback to zero values

GST Filing Data Transformation

const gstBardGraphData = [
{
category: 'Monthly',
ontime: monthly?.onTimeFilingTotalCount || 0,
delayed: monthly?.delayedFilingTotalCount || 0,
default: monthly?.defaultFilingTotalCount || 0
},
{
category: 'Quarterly',
ontime: quarterly?.onTimeFilingTotalCount || 0,
delayed: quarterly?.delayedFilingTotalCount || 0,
default: quarterly?.defaultFilingTotalCount || 0
},
{
category: 'Yearly',
ontime: yearly?.onTimeFilingTotalCount || 0,
delayed: yearly?.delayedFilingTotalCount || 0,
default: yearly?.defaultFilingTotalCount || 0
}
]

Purpose:

  • Restructures the GST compliance data from three separate API responses into a unified format for stacked bar charts
  • Organizes data by filing frequency (Monthly, Quarterly, Yearly)
  • For each category, includes three compliance status counts: on-time, delayed, and defaulted
  • Provides fallbacks to zero for null values

Technical Specifications

Data Types

The component relies on several GraphQL-generated types:

  • FilingType enum with values Monthly, Quarterly, and Yearly
  • UpdatedDateType enum for different data categories

Null Safety Pattern

The code consistently implements the nullish coalescing pattern:

value: apiResponse?.property || 0

This ensures that undefined or null values from the API are replaced with sensible defaults (zero for numerical values).

API Query Parameters

Several queries accept parameters to customize the data request:

  • Year range for turnover data: yearRange: '2021-2022'
  • Filing type for GST data: filingType: FilingType.Monthly
  • Update date type: type: UpdatedDateType.Gst

Data Aliasing Pattern

The code uses GraphQL result aliasing to distinguish between similar query results:

const { OverallGSTCompliancesCountByFilingType: monthly } = OverallGSTCompliancesCountByFilingTypeQuery({ filingType: FilingType.Monthly });

This allows the same query to be executed multiple times with different parameters while maintaining distinct variable names.

CibilAdversePep Component:

CIBIL Overview Data

const { OverallEntitiesCibilDataCount } = GetOverallEntitiesCibilDataCountQuery();

Retrieves aggregate statistics for entities with CIBIL issues, including NPA and wilful defaulter counts.

CIBIL Detailed Range Data

const { OverallEntitiesCibilDefaultDataOnRange } = OverallEntitiesCibilDefaultDataOnRangeQuery();

Fetches detailed breakdown of CIBIL defaults categorized by amount ranges (25 lakhs, 50 lakhs, 1 crore) for both NPA and wilful defaults.

Adverse Media Data

const { GetAdverseMedia } = GetAdverseMediaQuery();

Retrieves adverse media mentions categorized by signal type, entity counts, and hit frequency.

Last Updated Dates

const { GetUpdatedDate } = GetUpdatedDateQuery({ type: UpdatedDateType.Cibil });
const { GetUpdatedDate: adverse } = GetUpdatedDateQuery({ type: UpdatedDateType.Turnover });

Fetches timestamps indicating when the data was last updated to display freshness indicators.

CIBIL Default Range Transformation

const transformedData = [
{
category: 'NPA',
twentyFiveLakhs: OverallEntitiesCibilDefaultDataOnRange?.npa?.twentyFiveLakhs || 0,
fiftyLakhs: OverallEntitiesCibilDefaultDataOnRange?.npa?.fiftyLakhs || 0,
oneCrore: OverallEntitiesCibilDefaultDataOnRange?.npa?.oneCrore || 0
},
{
category: 'Wilful',
twentyFiveLakhs: OverallEntitiesCibilDefaultDataOnRange?.wilful?.twentyFiveLakhs || 0,
fiftyLakhs: OverallEntitiesCibilDefaultDataOnRange?.wilful?.fiftyLakhs || 0,
oneCrore: OverallEntitiesCibilDefaultDataOnRange?.wilful?.oneCrore || 0
}
];

Purpose:

  • Restructures the nested API response into a format suitable for the BarChart component
  • Creates an array with two categories (NPA and Wilful defaults)
  • For each category, maps three amount thresholds (25 lakhs, 50 lakhs, 1 crore)
  • Implements null safety with fallback to zero values

Adverse Media Categories Transformation

const datas = GetAdverseMedia?.SignalCategoryCounts
?.filter(item => selectedCategories.includes(item.category))
?.map(item => {
const formattedName = item?.category
.split('-')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
return {
name: formattedName,
value: item?.count,
color: categoryColors[item.category] || '#000000' // Fallback color
};
}) || [];

Purpose:

  • Filters the API response to include only pre-defined categories of interest
  • Transforms kebab-case category names into Title Case for display (e.g., 'executive-quote' → 'Executive Quote')
  • Assigns consistent colors to each category based on the predefined color mapping
  • Creates a structure compatible with the PieChart component
  • Provides an empty array fallback for null API responses

PEP Data Transformation

const pepData = [
{
name: 'Tier 1',
value: GetCumulativePep?.tier1Mentions ?? 0,
color: '#4682E1',
percentage: GetCumulativePep?.tier1Mentions
? ((GetCumulativePep.tier1Mentions / ((GetCumulativePep?.tier1Mentions ?? 0) + (GetCumulativePep?.tier2Mentions ?? 0) + (GetCumulativePep?.tier3Mentions ?? 0))) * 100).toFixed(2)
: '0'
},
{
name: 'Tier 2',
value: GetCumulativePep?.tier2Mentions ?? 0,
color: '#FAB55A',
percentage: GetCumulativePep?.tier2Mentions
? ((GetCumulativePep.tier2Mentions / ((GetCumulativePep?.tier1Mentions ?? 0) + (GetCumulativePep?.tier2Mentions ?? 0) + (GetCumulativePep?.tier3Mentions ?? 0))) * 100).toFixed(2)
: '0'
},
{
name: 'Tier 3',
value: GetCumulativePep?.tier3Mentions ?? 0,
color: '#F66785',
percentage: GetCumulativePep?.tier3Mentions
? ((GetCumulativePep.tier3Mentions / ((GetCumulativePep?.tier1Mentions ?? 0) + (GetCumulativePep?.tier2Mentions ?? 0) + (GetCumulativePep?.tier3Mentions ?? 0))) * 100).toFixed(2)
: '0'
}
];

Purpose:

  • Transforms the PEP data into a format suitable for the DonutChart component
  • Calculates percentage values for each tier based on total mentions across all tiers
  • Assigns consistent colors to each tier for visual differentiation
  • Handles division by zero and null cases with fallbacks
  • Formats percentages to two decimal places

Litigation Component:

const { GetCumulativeLitigations, GetCumulativeLitigationsFetching } = GetCumulativeLitigationsQuery();
const { GetUpdatedDate } = GetUpdatedDateQuery({ type: UpdatedDateType.Cibil });

Data Processing

const sortedData = [...data]
?.filter(item => item?.caseType && item?.caseType?.trim() !== '') // Filter out empty caseTypes
?.sort((a, b) =>
((b?.disposed || 0) + (b?.pending || 0)) - ((a?.disposed || 0) + (a?.pending || 0))
);

Identical to the table component's data processing for consistency.

Chart Data Transformation

const graphData = {
labels: sortedData?.slice(1, 16)?.map((item: any) => item?.caseType),
datasets: [
{
label: 'Pending',
data: sortedData?.slice(1, 16)?.map((item: any) => item?.pending),
backgroundColor: '#1976D2',
},
{
label: 'Dispose',
data: sortedData?.slice(1, 16)?.map((item: any) => item?.disposed),
backgroundColor: '#90CAF9',
},
],
};

Transforms the sorted data into Chart.js compatible format:

  1. Extracts case types as labels
  2. Creates two datasets for pending and disposed cases
  3. Assigns contrasting colors for visual differentiation
  4. Limits data display to 15 items (slices from index 1 to 16)

Entity Dashboard Component:

Endpoints:

  • GET /api/entities: Fetched through the GetAllEntitiesQuery hook
  • Parameters:
    • pageNo: Current page number (from pagination state)
    • pageSize: Number of items per page (from pagination state)
    • name: Search term for filtering entities

State Management

Global State (Jotai):

  • paginationAtom: Manages pagination state across the application
    const [pagination, setPagination] = useAtom(paginationAtom);
  • selectedRowAtom: Tracks the selected entity when navigating to details
    const [, setSelectedRow] = useAtom(selectedRowAtom);

Local State:

  • search: Controls the search input field
    const [search, setSearch] = useState("");
  • deferredValue: Optimizes search performance using React's useDeferredValue
    const deferredValue = useDeferredValue(search);

Data Flow

  1. Initialization: Component mounts and initializes state

  2. Data Fetching: API call triggered with pagination and search parameters

    const { GetAllEntities, GetAllEntitiesFetching } = GetAllEntitiesQuery({ ...pagination, name: deferredValue });
  3. User Interactions:

    • Search: Updates search state, which after deferral triggers new API call
    • Pagination: Updates pagination state, triggering new API call
    • Row Click: Sets selected entity and navigates to detail view
      const handleRowClick = (cin: string) => {
      navigate(`/data-terminal/entity/${cin}`);
      setSelectedRow(cin);
      };

Deployment

Tools: Docker, nginx.conf
"Each MFE has its own Dockerfile and NGINX configuration, so they need to be built and deployed separately."

FROM nginx:alpine

# Remove the default Nginx configuration file
RUN rm /etc/nginx/conf.d/default.conf

# Copy the custom Nginx configuration file
COPY nginx.conf /etc/nginx/conf.d

# Copy the build output from the previous stage
COPY dist /usr/share/nginx/html

# Expose port 80
EXPOSE 80

# Start Nginx
CMD ["nginx", "-g", "daemon off;"]

We're using Google Cloud Platform (GCP) to deploy the Risk Terminal Project in two environments:
Dev (Development)
Staging

Each Micro Frontend (MFE) has its own Dockerfile and Nginx config, meaning they need to be deployed separately.

Commands

✅ Development Environment (Dev)

pnpm build
docker build --no-cache -t risk-terminal-fe/risk-analytics-dashboard:latest .
docker tag risk-terminal-fe/risk-analytics-dashboard:latest us-west1-docker.pkg.dev/test-genai-422809/risk-terminal-fe/risk-terminal-fe/risk-analytics-dashboard:latest
docker push us-west1-docker.pkg.dev/test-genai-422809/risk-terminal-fe/risk-terminal-fe/risk-analytics-dashboard:latest

Overview:

  • pnpm build → Builds the project.
  • docker build → Creates a Docker image from your project.
  • docker tag → Tags the image for GCP Artifact Registry.
  • docker push → Pushes the image to Artifact Registry.

What is Artifact Registry?

📌 Artifact Registry is GCP's container registry where you store Docker images.

  • Instead of using DockerHub, you push images to us-west1-docker.pkg.dev/test-genai-422809/risk-terminal-fe/
  • Each environment (Dev, Staging) has its own separate image repository.

What is Cloud Run?

📌 Cloud Run is a serverless platform to run Docker containers.

  • After pushing the image to Artifact Registry, you deploy it to Cloud Run.
  • Cloud Run automatically scales your container based on traffic.

What is Cloud DNS?

📌 Cloud DNS helps map domain names (e.g., risk-terminal.example.com) to your Cloud Run service.

  • Instead of accessing your app via long Cloud Run URLs, you set up a custom domain.
  • Steps:
    1. Reserve a domain in Google Domains or another provider.
    2. Create a DNS Zone in Cloud DNS.
    3. Add an A or CNAME record pointing to your Cloud Run service.
    4. Verify and apply SSL (if needed).

Deployment Flow

1️⃣ Build the MFE using pnpm
2️⃣ Create a Docker image and push it to Artifact Registry
3️⃣ Deploy the image to Cloud Run
4️⃣ Map a custom domain using Cloud DNS