Skip to main content

Frontend Documentation

Project Name: Insta-verify
MFE Name: Root
Date: 08-04-2025


1. Overview

This document provides a reference for the frontend architecture, setup, and integration of micro frontends (MFEs) in our project. The application is built using Vite, React, and Module Federation, with Jotai for state management and URQL for GraphQL queries.

Project Structure

The frontend consists of multiple micro frontends (MFEs), which are integrated into a root MFE (main application). These MFEs serve different purposes and are loaded dynamically.

Root MFE

  • Main container for all MFEs
  • Manages authentication, navigation, and layout
  • Loads remote MFEs dynamically

Each MFE is built as a separate module and exposes its components using vite plugin Federation.

1. Importing Required Plugins

import { defineConfig } from 'vite';
import federation from '@originjs/vite-plugin-federation';
import jotaiDebugLabel from 'jotai/babel/plugin-debug-label';
import jotaiReactRefresh from 'jotai/babel/plugin-react-refresh';
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
  • defineConfig → Used to define Vite configuration.
  • federation → Enables module federation, allowing micro frontends (MFEs) to share components and utilities.
  • jotaiDebugLabel & jotaiReactRefresh → Debugging and refresh support for Jotai state management.
  • react → Provides support for React applications in Vite.
  • tsconfigPaths → Allows Vite to recognize TypeScript path aliases defined in tsconfig.json.

2. Plugin Configuration

export default defineConfig({
plugins: [
react({ babel: { plugins: [jotaiDebugLabel, jotaiReactRefresh] } }),
tsconfigPaths(),
federation({
name: 'root',
filename: 'remoteEntry.js',
  • React Plugin → Configured with Jotai debugging and refresh support.
  • Module Federation
    • The root micro frontend is named root.
    • remoteEntry.js is the file where it exposes its components for other MFEs to consume.

3. Exposing Components to Other MFEs

      exposes: {
'./Axios': './src/utils/axios',
'./Token': './src/store/token',
'./ChatbotCss': './src/css/chatbot.module.css',
'./SearchBarCss': './src/css/searchbar.module.css',
'./TableCss': './src/css/table.module.css',
'./KanbanCss': './src/css/kanban.module.css',
},
  • This exposes utility modules and styles that other MFEs can import dynamically.

4. Importing Remote MFEs

      remotes: {
cmRootApp: 'https://dev-fe-root.signalx.biz/remoteEntry.js',
headerApp: 'https://dev-fe-header.signalx.biz/remoteEntry.js',
loginApp: 'https://dev-fe-login.signalx.biz/remoteEntry.js',
menuApp: 'https://dev-fe-menu.signalx.biz/remoteEntry.js',
userApp: 'https://dev-fe-user.signalx.biz/remoteEntry.js',
invitationsApp: 'https://dev-fe-ir-invitations.signalx.biz/remoteEntry.js',

// verifyApp: 'http://localhost:5401/assets/remoteEntry.js',
verifyApp: "https://insta-verify-verifications.signalx.biz/assets/remoteEntry.js"
},
  • Remote MFEs are dynamically loaded from either localhost or a staging server.
  • The root MFE consumes these micro frontends to display features like analytics, datasets, and dashboards.

5. Shared Dependencies

      shared: [
'jotai',
'jotai-urql',
'@mantine/core',
'react',
'react-dom',
'react-router-dom',
'urql',
],
  • Ensures common libraries are shared across micro frontends to prevent multiple versions from loading.
  • Jotai, React, Mantine UI, and URQL are used for state management, UI, and GraphQL queries.

6. Vite Test Configuration

  test: {
globals: true,
environment: 'jsdom',
setupFiles: './vitest.setup.mjs',
},
  • Testing is enabled using Vitest (jsdom is used to simulate the browser environment).

7. Build Configuration

  build: {
target: 'esnext',
},
  • Optimizes the build for modern browsers (esnext), ensuring better performance.

Summary

  • This Vite configuration sets up Module Federation to integrate multiple MFEs into a single frontend.
  • Jotai is used for state management.
  • URQL is used for GraphQL integration.
  • Vite optimizations ensure fast builds and smooth HMR (Hot Module Replacement).

2. API Integration

In micro frontend architecture, we use URQL for GraphQL queries and Jotai for state management. To maintain a consistent API client across MFEs, we define a URQL client using Jotai atoms.

Defining the URQL Client Atom

We create a Jotai atom that holds the URQL client instance. This ensures the client is available globally across all MFEs.

3. Routing

This document explains the React Router DOM configuration for our micro frontend (MFE) architecture. We use React Router v6 to define route-based navigation while integrating GraphQL clients using URQL and state management with Jotai.

Key Features

  • Lazy Loading: Routes are loaded dynamically using React.lazy and Suspense for performance optimization.
  • GraphQL Client: URQL clients (clientValue &) are used for API communication.
  • Authentication Handling: Login and Forgot Password pages are included.
  • Default Layout: Shared layout (DefaultLayout) is used across multiple pages.

Router Configuration

The Router component defines the application's navigation structure. Below is an overview of the key routes.

import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import { lazy, Suspense } from 'react';

import DefaultLayout from 'cmRootApp/DefaultLayout';
import Login from 'loginApp/Login';

import { Center, Loader } from '@mantine/core';

import { clientValue } from 'cmRootApp/Client';
import { Client } from 'urql';

import { Provider as UrqlProvider } from 'urql';
import { clientAtomInstaVerify } from './store/client';
import { useAtomValue } from 'jotai';
import Profile from './views/Profile';

const Verify = lazy(() => import('verifyApp/Verify'));
const InternalVerficarion = lazy(() => import('verifyApp/InternalVerficarion'));
const VerificationsList = lazy(() => import('verifyApp/VerificationsList'));
const RealEstateVerification = lazy(() => import('verifyApp/RealEstateVerification'));
const Verification = lazy(() => import('verifyApp/Verification'));
const ForgotPassword = lazy(() => import("loginApp/ForgotPassword"));
const Invitation = lazy(() => import("invitationsApp/Invitations"));
const User = lazy(() => import('userApp/User'));
const LoaderOverlay = (
<Center h="85vh">
<Loader size={30} />
</Center>
);

const MenuList = [''];

export default function Router() {
const client = clientValue() as Client
const instaClint = useAtomValue(clientAtomInstaVerify);

const router = createBrowserRouter([
{
path: '/',
element: (
<Suspense fallback={LoaderOverlay}>
<UrqlProvider value={client}>
<Login appID={10}/>
</UrqlProvider>
</Suspense>
),
},
{
path: "invitation/:id",
element: (
<Suspense fallback={LoaderOverlay}>
<Invitation />
</Suspense>
),
},
{
path: "/forgot-password",
element: (
<Suspense fallback={LoaderOverlay}>
<ForgotPassword />
</Suspense>
),
},
{
path: "/profile",
element: <DefaultLayout hidden={false} menus={MenuList} />,
children: [
{
index: true,
element: (
<Suspense fallback={LoaderOverlay}>
<Profile />
</Suspense>
),
},
],
},
{
path: "/forgot-password",
element: (
<Suspense fallback={LoaderOverlay}>
<ForgotPassword />
</Suspense>
),
},
{
path: '/home',
element: (
<DefaultLayout menus={MenuList} hidden={true} />
),
children: [
{
index: true,
element: (
<Suspense fallback={LoaderOverlay}>
<UrqlProvider value={instaClint}>
<Verify/>
</UrqlProvider>
</Suspense>
),
},
{
path: 'employee-verify',
element: (
<Suspense fallback={LoaderOverlay}>
<UrqlProvider value={instaClint}>
<InternalVerficarion />
</UrqlProvider>
</Suspense>
),
},
{
path: 'verifications-list',
element: (
<Suspense fallback={LoaderOverlay}>
<UrqlProvider value={instaClint}>
<VerificationsList />
</UrqlProvider>
</Suspense>
),
},
{
path: 'verification',
element: (
<Suspense fallback={LoaderOverlay}>
<UrqlProvider value={instaClint}>
<Verification />
</UrqlProvider>
</Suspense>
),
},
{
path: 'verification/:id',
element: (
<Suspense fallback={LoaderOverlay}>
<UrqlProvider value={instaClint}>
<Verification />
</UrqlProvider>
</Suspense>
),
},
{
path: 'real-estate-verify',
element: (
<Suspense fallback={LoaderOverlay}>
<UrqlProvider value={instaClint}>
<RealEstateVerification />
</UrqlProvider>
</Suspense>
)
},
{
path: 'users',
element: (
<Suspense fallback={LoaderOverlay}>
<UrqlProvider value={client}>
<User appID={10}/>
</UrqlProvider>
</Suspense>
),
}
],
},
]);
return <RouterProvider router={router} />;
}

4. 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 Dart 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.


2. Commands Breakdown

✅ Development Environment (Dev)

pnpm build
docker build --no-cache -t insta-fe/root:latest .
docker tag insta-fe/root:latest us-west1-docker.pkg.dev/test-genai-422809/insta-verify/insta-fe/root:latest
docker push us-west1-docker.pkg.dev/test-genai-422809/insta-verify/insta-fe/root:latest
  • 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.

3. 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.

4. 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.

5. What is Cloud DNS?

📌 Cloud DNS helps map domain names (e.g., dart.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).

6. 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


5. Additional Notes

Commands to run Mfe in Local:
pnpm build && pnpm serve or pnpm watch

Instead of running all MFEs at once, we now follow a structured approach where:

  1. The root package runs separately using pnpm watch in one terminal.
  2. Other MFEs run via a script, but we exclude the one we want to work with.
  3. We manually start the excluded MFE (xena in this example) in another terminal.

Steps to Run MFEs Efficiently

Step 1: Start the Root Package (First Terminal)

pnpm watch
  • This runs the root package separately.

Step 2: Run the Other MFEs (Second Terminal)

Come out from the root and run this in the main project folder

./run-mfes.sh xena
  • This runs all MFEs except xena.

Step 3: Start the Excluded MFE Manually (Third Terminal)

cd xena
pnpm watch
  • This starts xena manually, allowing for individual debugging.

To Run this we must need:

# Check if at least one argument is provided
if [ $# -eq 0 ]; then
echo "Please provide the names of the MFEs to exclude, separated by spaces"
exit 1
fi

# Join all arguments into a single string separated by '|' for grep
exclude_mfes=$(IFS="|"; echo "$*")

# Read packages from pnpm-workspace.yaml
packages=$(grep "^\s*-\s*\".*\"" pnpm-workspace.yaml | sed 's/^\s*-\s*"\(.*\)"/\1/')

# Filter out the root package and the excluded MFEs
mfes_to_run=$(echo "$packages" | grep -v -E "(root|$exclude_mfes)")

# Function to run commands for each MFE
run_mfe() {
mfe=$1
echo "Building and serving $mfe"
(
cd "$mfe" &&
pnpm build &&
pnpm serve
) &
}

# Run build and start for each MFE
for mfe in $mfes_to_run
do
run_mfe $mfe
done

echo "All MFEs except [$exclude_mfes] are now building and running"

# Wait for all background processes to finish
wait

This file in the project

The pnpm-workspace.yaml file defines the workspace structure for a monorepo using pnpm workspaces. It allows multiple interdependent packages to be managed within a single repository, sharing dependencies efficiently.
Purpose of pnpm-workspace.yaml

  • Defines which packages are part of the workspace.
  • Ensures dependencies are efficiently shared between packages.
  • Allows seamless linking of packages without manually managing node_modules for each.
  • Supports running commands across multiple packages.

MFE Name: Verifications
Date: 9-04-2025


1. Overview

The Verification MicroFrontEnd (MFE) is a modular component of the application dedicated to handling various types of verification processes. It provides functionality for both employees and employers to verify information through a structured workflow. The MFE comprises several interconnected components that handle different aspects of the verification process, from displaying available verification types to processing uploads and displaying results.

Component Structure

1. Verification Dashboard (Verification_Dashboard.tsx)

The main entry point showing all available verification types in a card-based grid layout.

Key Features:

  • Displays multiple verification categories (Employee, Franchisee, Matrimony, etc.)
  • Each card has a consistent design with title, description, icon, and action button
  • Background hero section with descriptive text
  • Navigation to specific verification flows

2. Inner Verification Component (InnerVerification.tsx)

Handles the specific verification setup process for employee/employer verification.

Key Features:

  • Selection between employee and employer verification types
  • Displays available verification checks
  • Instructions panel
  • Modal for CSV file upload
  • Form submission to process verification requests

3. Verifications List (VerificationsList.tsx)

Displays a table of all verification requests with their status and actions.

Key Features:

  • Searchable table with pagination
  • Status indicators using badges
  • Download action for reports
  • Navigation to detailed verification view

4. Summary Dashboard (SummaryDashboard.tsx)

Shows detailed results of a specific verification request.

Key Features:

  • Profile details section
  • Visual representation of performed checks
  • Summary of verification findings
  • Additional verification details (through imported Verification component)

API Integration

API Query Hooks

The application uses custom query hooks to fetch data from the backend:

  1. GetOverallEmployeeVerificationsListQuery
    • Fetches the list of all employee verifications
    • Supports pagination and search filtering
    • Parameters: pageNo, pageSize, employeeName
const { GetOverallEmployeeVerificationsList, GetOverallEmployeeVerificationsListFetching } = 
GetOverallEmployeeVerificationsListQuery({ ...pagination, employeeName: deferredValue });
  1. GetEmployeeVerificationDetailsBasedOnCheckIDQuery
    • Fetches detailed information about a specific verification check
    • Parameters: check_id
const { GetEmployeeVerificationDetailsBasedOnCheckID } = 
GetEmployeeVerificationDetailsBasedOnCheckIDQuery({ check_id: id ?? "" });

File Upload Integration

The application supports CSV file uploads for bulk verification processing:

const formData = new FormData();

// Create the operations object
const operations = {
query: `mutation($file: Upload!) {
employeeVerification(file: $file) {
total_count
data {
Full_Name
din_verification
epfo_verification
litigation_verification
}
}
}`,
variables: {
file: null
}
};

// Create the map
const map = {
"0": ["variables.file"]
};

formData.append('operations', JSON.stringify(operations));
formData.append('map', JSON.stringify(map));
formData.append('0', files[0]!);

const response = await fetch('https://instaverify-be.signalx.biz/upload_csv', {
method: 'POST',
headers: {
'auth_token': authToken,
},
body: formData,
});

State Management

The application uses a combination of local React state and Jotai atoms for state management:

  1. Local State
    • Component-specific state like files, isLoading, selectedType
    • Used for UI interactions within components
  2. Jotai Atoms
    • Global state like pagination settings
    • Example: paginationAtom for managing page number and size across the application
const [pagination, setPagination] = useAtom(paginationAtom);

Data Flow

  1. User Journey:
    • User selects verification type from dashboard
    • User chooses employee/employer verification
    • User uploads CSV file containing verification data
    • System processes verification and shows status in list view
    • User can view detailed results in summary dashboard
  2. API Request Flow:
    • File upload → GraphQL mutation → Backend processing
    • Verification list view → GraphQL query → Paginated results
    • Verification detail view → GraphQL query with ID → Detailed check results

UI Components and Styling

The application uses Mantine UI components library with custom styling:

  • Cards: Used for dashboard items, information panels
  • Grid/SimpleGrid: For layout structure
  • Modals: For file upload and confirmation
  • Dropzone: For file upload interface
  • Badges: For status indicators
  • Tables: For data display with sorting and filtering

Custom styling leverages:

  • Linear gradients for buttons and accents: linear-gradient(90deg, #028291, #00BCB0)
  • Custom icons for each verification type
  • Consistent typography using Roboto font family
  • Background images for hero sections

The application uses React Router for navigation between views:

  • /home - Main dashboard
  • /home/employee-verify - Employee verification setup
  • /home/verifications-list - List of all verifications
  • /home/verification/:id - Detailed view of a specific verification

Error Handling

  • Form validation for file uploads
  • Loading states during API requests
  • Error messaging for failed uploads or missing authentication

Security Considerations

  • Authentication tokens required for API requests
  • File type validation for uploads
  • Session storage for maintaining authentication state

4. 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 Dart 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.


2. Commands Breakdown

✅ Development Environment (Dev)

pnpm build
docker build --no-cache -t insta-fe/verifications:latest .
docker tag insta-fe/verifications:latest us-west1-docker.pkg.dev/test-genai-422809/insta-verify/insta-fe/verifications:latest
docker push us-west1-docker.pkg.dev/test-genai-422809/insta-verify/insta-fe/verifications:latest
  • 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.

3. What is Artifact Registry?

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

  • Instead of using DockerHub, you push images to asia-south1-docker.pkg.dev/test-genai-422809/ai-apps
  • Each environment (Dev, Staging) has its own separate image repository.

4. 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.

5. What is Cloud DNS?

📌 Cloud DNS helps map domain names (e.g., ai-apps.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).

6. 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