Skip to content

About

Enterprise React 19 Customer Portal embedded in Salesforce Experience Cloud with GraphQL UI API, Apex Bridge, and Tailwind CSS v4

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Salesforce Experience Cloud + React Customer Portal

Enterprise-grade React 19 Single Page Application embedded seamlessly into Salesforce Experience Cloud (LWR / Aura) with dual-channel GraphQL UI API & Apex Bridge integration.

Salesforce DX React TypeScript Tailwind CSS Vite License


πŸ“– Overview

This repository delivers an enterprise Customer Portal built with React 19, TypeScript, and Tailwind CSS v4, embedded within Salesforce Experience Cloud. It demonstrates how to combine the velocity and component ecosystem of modern front-end engineering with the security, scalability, and relational data model of the Salesforce Platform.

Key Highlights

  • Zero CORS / Iframe Cookie Friction: Features an infallible Apex PostMessage Bridge connecting the React application to the parent Lightning Web Component (customerPortalHost), completely eliminating cross-origin, third-party cookie, and partitioned-cookie issues.
  • Dual-Channel Data Layer: Intelligently switches between Salesforce GraphQL UI API for reactive read operations and Apex @AuraEnabled / @RestResource controllers for transactional DML.
  • Dual Packaging Strategy: Ready for deployment via Salesforce UI Bundles (@salesforce/vite-plugin-ui-bundle) or encapsulated as a zero-dependency Static Resource bundle (CustomerPortalHtml.resource).
  • Synchronized Routing: Bidirectional synchronization between React Router hash navigation (#/support-tickets, #/billing-invoices, etc.) and Experience Cloud URL history via pushState and popstate listeners.
  • Dynamic Security Context: Automatically resolves customer account and contact identity for authenticated community users, with automatic fallback for internal preview and demo modes.

πŸš€ Features

Module Description Salesforce Backing Objects
Executive Dashboard Real-time aggregate KPIs (Open Tickets, Invoices Pending, CSAT Score, Active Subscriptions), recent activity feed, and dedicated account executive contact badge. Account, Case, Invoice__c, Subscription__c, Portal_Activity__c
Support Tickets Case management dashboard with status filters, search, modal for creating new tickets, and real-time threaded discussions (CaseComment). Case, CaseComment, Contact
Billing & Invoices Financial overview, payment history, downloadable statement links, instant one-click invoice payment/settlement actions, and active payment method details. Invoice__c, Account
Services & Subscriptions Active infrastructure subscriptions with real-time usage meters (vCPU, GB storage, edge requests) against plan quotas and renewal schedules. Subscription__c, Account
Team Management Organization member directory, role assignment (Technical Lead, Billing Admin), new member invite workflow, and profile modifications. Contact, Account
Knowledge Base / FAQ Searchable accordion FAQs categorized across Technical, Billing, Security, and General topics. Portal_FAQ__c
Account & Profile Company information, customer tier badge, personal contact info editor, timezone selector, and granular notification preferences. Contact, Account

πŸ›οΈ System Architecture

flowchart TD
    subgraph ClientTier["Client Browser"]
        User["Customer / User"] -->|Visits Experience Site| ExpSite["Salesforce Experience Cloud (LWR / Aura)"]
        ExpSite --> LWCHost["LWC Container: customerPortalHost"]
        LWCHost -->|Embeds via Sandboxed Iframe / UI Bundle| ReactApp["React 19 Customer Portal SPA"]
        
        subgraph ReactModules["React Portal Internal Architecture"]
            Router["React Router v8 (Hash Routing)"]
            StateMgr["useAsyncData Hook / Reactive State"]
            PortalSvc["portalService.ts (Data Orchestration)"]
            ApexCli["apexClient.ts (Bridge & REST)"]
            GraphQLCli["graphqlClient.ts (Platform SDK / Direct)"]

            Router --> StateMgr
            StateMgr --> PortalSvc
            PortalSvc --> ApexCli
            PortalSvc --> GraphQLCli
        end
    end

    subgraph SalesforcePlatform["Salesforce Core Platform"]
        subgraph Gateways["API Gateways & Runtimes"]
            GraphQLGateway["GraphQL UI API Gateway (/services/data/v63.0/graphql)"]
            ApexWireBridge["LWC @AuraEnabled Controller Bridge"]
            ApexRestDirect["Apex @RestResource Handlers (/services/apexrest/portal/*)"]
        end

        subgraph Controllers["Apex Controller Layer"]
            SecCtx["CustomerPortalSecurityContext"]
            CaseController["CustomerPortalCaseController"]
            BillingController["CustomerPortalBillingController"]
            TeamController["CustomerPortalTeamController"]
            ProfileController["CustomerPortalProfileController"]
            ActivityController["CustomerPortalActivityController"]
        end

        subgraph Database["Salesforce Multi-Tenant Data Store"]
            StdDb[("Standard Objects: Account, Contact, Case, CaseComment")]
            CstDb[("Custom Objects: Invoice__c, Subscription__c, Portal_FAQ__c, Portal_Activity__c")]
        end
    end

    GraphQLCli -->|1. GraphQL Queries| GraphQLGateway
    ApexCli <-->|2. window.postMessage Protocol| LWCHost
    LWCHost <-->|Aura Wire / Imperative Calls| ApexWireBridge
    ApexCli -.->|3. Fallback REST Requests| ApexRestDirect

    GraphQLGateway --> StdDb & CstDb
    ApexWireBridge --> SecCtx
    ApexRestDirect --> SecCtx
    SecCtx --> CaseController & BillingController & TeamController & ProfileController & ActivityController
    CaseController & BillingController & TeamController & ProfileController & ActivityController --> StdDb & CstDb
Loading

πŸ”„ Data Flow & Integration Models

1. Salesforce GraphQL UI API

The portal queries read data using the Salesforce GraphQL UI API. Queries are typed at compile-time with TypeScript schemas generated from Salesforce metadata.

sequenceDiagram
    participant UI as React Component
    participant Service as portalService
    participant Client as graphqlClient
    participant SF as Salesforce GraphQL API

    UI->>Service: getDashboardSummary()
    Service->>Client: executeGraphQL(GET_DASHBOARD_SUMMARY_QUERY, { accountId })
    Client->>SF: POST /services/data/v63.0/graphql
    SF-->>Client: { data: { uiapi: { query: { ... } } } }
    Client-->>Service: Structured GraphQL Response
    Service-->>UI: Normalized DashboardSummary Model
Loading

2. Infallible Apex PostMessage Bridge

To ensure operations succeed without third-party cookie restrictions or CORS challenges, mutating actions (creating cases, adding comments, paying invoices, updating profiles) invoke the Apex Bridge:

sequenceDiagram
    participant React as React (apexClient)
    participant LWC as customerPortalHost (LWC)
    participant Apex as Apex Controller (@AuraEnabled)
    participant SF as Salesforce Database

    React->>React: Generate messageId (msg_xxx_timestamp)
    React->>LWC: window.parent.postMessage({ type: 'APEX_BRIDGE_REQ', action: 'createCase', params })
    LWC->>Apex: await createCaseAura(params)
    Apex->>SF: INSERT Case & CaseComment
    SF-->>Apex: Inserted Record IDs
    Apex-->>LWC: Case record object
    LWC->>React: window.postMessage({ type: 'APEX_BRIDGE_RESP', messageId, success: true, data })
    React-->>React: Resolve Promise & update UI state
Loading

πŸ“‚ Project Structure

.
β”œβ”€β”€ config/
β”‚   └── project-scratch-def.json             # Scratch org definition with standard features
β”œβ”€β”€ docs/
β”‚   β”œβ”€β”€ ARCHITECTURE.md                      # In-depth architectural specification
β”‚   └── INTEGRATION_GUIDE.md                 # Guide to GraphQL, Apex bridge, and extending the app
β”œβ”€β”€ force-app/main/default/
β”‚   β”œβ”€β”€ classes/                             # Apex controllers and test suites
β”‚   β”‚   β”œβ”€β”€ CustomerPortalActivityController.cls
β”‚   β”‚   β”œβ”€β”€ CustomerPortalBillingController.cls
β”‚   β”‚   β”œβ”€β”€ CustomerPortalCaseController.cls
β”‚   β”‚   β”œβ”€β”€ CustomerPortalProfileController.cls
β”‚   β”‚   β”œβ”€β”€ CustomerPortalSecurityContext.cls
β”‚   β”‚   β”œβ”€β”€ CustomerPortalTeamController.cls
β”‚   β”‚   └── *Test.cls
β”‚   β”œβ”€β”€ corsWhitelistOrigins/                # Allowed origins for site communication
β”‚   β”œβ”€β”€ digitalExperienceConfigs/            # Digital Experience site configurations
β”‚   β”œβ”€β”€ digitalExperiences/                  # Experience Cloud site bundles
β”‚   β”œβ”€β”€ lwc/
β”‚   β”‚   β”œβ”€β”€ customerPortalHost/              # Primary LWC host container with PostMessage bridge
β”‚   β”‚   β”œβ”€β”€ nextjsPortalHost/                # Alternate Next.js container host
β”‚   β”‚   └── timesheetContainer/              # Embedded timesheet container component
β”‚   β”œβ”€β”€ objects/                             # Custom object definitions and fields
β”‚   β”‚   β”œβ”€β”€ Account/                         # Custom fields (CSAT_Score__c, Tier__c)
β”‚   β”‚   β”œβ”€β”€ Contact/                         # Custom fields (Timezone, notification flags)
β”‚   β”‚   β”œβ”€β”€ Invoice__c/                      # Invoicing custom object
β”‚   β”‚   β”œβ”€β”€ Portal_Activity__c/              # Activity timeline custom object
β”‚   β”‚   β”œβ”€β”€ Portal_FAQ__c/                   # FAQ custom object
β”‚   β”‚   └── Subscription__c/                 # Subscriptions & usage tracking
β”‚   β”œβ”€β”€ permissionsets/
β”‚   β”‚   └── Customer_Portal_Access.permissionset-meta.xml
β”‚   β”œβ”€β”€ sites/                               # Experience Cloud site definition
β”‚   β”œβ”€β”€ staticresources/
β”‚   β”‚   β”œβ”€β”€ CustomerPortalHtml.resource      # Inlined standalone production React bundle
β”‚   β”‚   └── CustomerPortalHtml.resource-meta.xml
β”‚   └── uiBundles/
β”‚       └── ReactPortal/                     # Full React 19 SPA Source Code
β”‚           β”œβ”€β”€ src/
β”‚           β”‚   β”œβ”€β”€ api/                     # GraphQL & Apex clients, queries, generated types
β”‚           β”‚   β”œβ”€β”€ components/              # UI components (Radix / shadcn, badges, modals)
β”‚           β”‚   β”œβ”€β”€ hooks/                   # Custom React hooks (useAsyncData, usePortalNavigate)
β”‚           β”‚   β”œβ”€β”€ pages/                   # Portal views (Dashboard, Tickets, Billing, Team, etc.)
β”‚           β”‚   β”œβ”€β”€ services/                # Business logic, mock fallbacks, and models
β”‚           β”‚   β”œβ”€β”€ styles/                  # Tailwind CSS v4 styling
β”‚           β”‚   β”œβ”€β”€ app.tsx                  # Application entry point
β”‚           β”‚   β”œβ”€β”€ appLayout.tsx            # Main shell, sidebar, and top navigation
β”‚           β”‚   └── routes.tsx               # Hash router definitions
β”‚           β”œβ”€β”€ inline-bundle.js             # Inliner script generating static resource
β”‚           β”œβ”€β”€ package.json                 # React dependencies and scripts
β”‚           └── vite.config.ts               # Vite configuration with Tailwind v4 & Salesforce plugins
β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ apex/
β”‚   β”‚   β”œβ”€β”€ add_cors.apex                    # Script to whitelist site domains
β”‚   β”‚   β”œβ”€β”€ grant_guest_access.apex          # Utility to grant guest permissions
β”‚   β”‚   └── seed_portal_data.apex            # Comprehensive sample data seeder
β”‚   β”œβ”€β”€ check_resource_headers.js            # Verification script for static resource headers
β”‚   └── check_site_html.js                   # Site availability check script
β”œβ”€β”€ sfdx-project.json                        # Salesforce DX project manifest (API v67.0)
└── package.json                             # Root project scripts (build, lint, test)

πŸ› οΈ Prerequisites & Local Setup

Prerequisites

  • Node.js: v22.0.0 or higher
  • npm: v10.0.0 or higher
  • Salesforce CLI (sf): v2.0.0 or higher (Install Guide)
  • Salesforce Org: Developer Edition or Scratch Org with Experience Cloud enabled

1. Clone & Install Dependencies

# Clone the repository
git clone https://github.com/nandini-teqfocus/sf-react-exp-cloud.git
cd sf-react-exp-cloud

# Install root dependencies
npm install

# Install React application dependencies
cd force-app/main/default/uiBundles/ReactPortal
npm install
cd ../../../..

2. Local React Development

You can develop and test the React frontend locally with mock data and hot reloading:

# From the project root
npm run dev

# Or directly from the ReactPortal folder
cd force-app/main/default/uiBundles/ReactPortal
npm run dev

Open http://localhost:5173 in your browser.


πŸš€ Deployment Guide

1. Authenticate to Salesforce Org

# Authorize your Developer Edition or Sandbox org
sf org login web -a MyPortalOrg

# Or set as default target org
sf config set target-org=MyPortalOrg

2. Build & Package the React Application

Compile the React application and build the inlined static resource:

# Build React bundle via Vite & compile TypeScript
npm run build:react

# Generate standalone bundle and update CustomerPortalHtml.resource
cd force-app/main/default/uiBundles/ReactPortal
node inline-bundle.js
cd ../../../..

3. Deploy Salesforce Metadata

Deploy all Apex classes, custom objects, permission sets, static resources, and LWC components to your org:

sf project deploy start --target-org MyPortalOrg

4. Assign Permission Set

Assign the Customer_Portal_Access permission set to your user or Experience Cloud community profile:

sf org assign permset -n Customer_Portal_Access --target-org MyPortalOrg

5. Seed Portal Sample Data

Run the Apex seeding script to create test accounts, contacts, cases, invoices, subscriptions, FAQs, and activities:

sf apex run --file scripts/apex/seed_portal_data.apex --target-org MyPortalOrg

6. Experience Cloud Site Setup

  1. In Salesforce Setup, go to Digital Experiences > All Sites.
  2. Open Experience Builder for your site (or create a new LWR / Aura Customer Portal site).
  3. Drag the customerPortalHost Lightning Web Component onto the site page canvas.
  4. Set the page layout to full-width without header/footer margins.
  5. Click Publish to make the portal live.

πŸ§ͺ Testing & Verification

Unit Tests (Vitest)

The React portal includes comprehensive unit tests verifying the service layer, mock data fallbacks, and Apex client behaviors:

cd force-app/main/default/uiBundles/ReactPortal
npm test

Salesforce LWC Tests

Run Jest tests for Lightning Web Components:

npm run test:unit

Apex Unit Tests

Execute Apex test classes with code coverage:

sf apex run test --code-coverage --result-format human --target-org MyPortalOrg

πŸ”’ Security Best Practices

  • Zero Hardcoded Credentials: No passwords, OAuth client secrets, or private tokens exist in source code or version control.
  • Dynamic Security Context: Apex controllers use CustomerPortalSecurityContext to strictly filter records by the logged-in user's AccountId and ContactId.
  • Field & Object-Level Security (FLS): Access rules are governed by the Customer_Portal_Access permission set.
  • Sandboxed Execution: React operates in an isolated iframe inside the LWC container, communicating only via controlled postMessage contracts.

🏷️ Repository Metadata & Topics

  • Description: Enterprise React 19 Customer Portal embedded in Salesforce Experience Cloud with GraphQL UI API, Apex Bridge, and Tailwind CSS v4.
  • Topics: salesforce, experience-cloud, react19, lwc, graphql, apex, vite, tailwindcss, typescript, ui-bundle, salesforce-dx

πŸ“„ License

Distributed under the MIT License. See LICENSE for details.

About

Enterprise React 19 Customer Portal embedded in Salesforce Experience Cloud with GraphQL UI API, Apex Bridge, and Tailwind CSS v4

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages