Richard Tuharsky
Sales CloudService CloudCustom ObjectsApex TriggersLightning Web ComponentsFlow AutomationAPI Integration

TechGears Ltd.
End-to-End Salesforce CRM Implementation

A complete Salesforce CRM deployment covering Sales Cloud and Service Cloud configuration, custom Apex trigger development, Lightning Web Component builds, Salesforce Flow automation, and REST API integration.

Overview

Project Background

This Salesforce implementation project delivers a full CRM solution for TechGears Ltd., a mid-sized technology solutions company providing enterprise software and hardware products. The business required a scalable Salesforce platform to centralise customer data, accelerate the sales cycle, and resolve service cases faster.

The engagement covered end-to-end CRM deployment: custom Salesforce data modelling, Sales Cloud opportunity management, Service Cloud case handling, Flow automation, Apex trigger development, Lightning Web Component builds, and REST API integration with an external service.

Client

TechGears Ltd.

Technology Solutions

Scope

Sales Cloud + Service Cloud

Deliverables

3 custom objects, 3 Flows, 3 Apex components, 3 LWCs, REST API integration

TechGears Salesforce org configuration

Salesforce Developer Edition org configuration for TechGears Ltd.


Section 01

Project Setup & Configuration

Org Configuration

The Salesforce implementation began with configuring a Developer Edition org: company details, fiscal year, currency settings, and a role hierarchy aligned to TechGears' sales and support structure.

Company Information

  • Name: TechGears Ltd.
  • Industry: Technology Solutions
  • Services: Enterprise Software, IT Solutions, Product Management

Salesforce User Profiles

  • Sales Representatives: Opportunity and Account management
  • Support Agents: Case handling and service request resolution
  • System Administrators: Full platform configuration access

Profile-level permission sets enforce field-level security and object access across each user group.


Section 02

Salesforce Data Model Design

Custom Salesforce Objects

TechGear_Products__c

Stores the full product catalog: names, categories, unit pricing, and available stock quantities. Custom stock fields feed directly into the inventory management Apex trigger.

TechGear_Solutions__c

Tracks bespoke solutions and service offerings delivered to clients. Linked to Account records via Lookup to maintain a full customer solution history.

TechGear_Orders__c

Central order management object capturing quantity ordered, order date, delivery status, and product relationships for fulfilment tracking.

Salesforce custom objects in Schema Builder

Custom object configuration in Salesforce Schema Builder

Standard Object Customisation

Account Object

  • Industry: segment accounts by business type for targeted pipeline management
  • Account Tier: classify VIP and high-value customers for prioritised service
  • Customer Since: track relationship longevity to support renewal and upsell workflows
  • Billing and Shipping Addresses: separate address fields for order fulfilment accuracy
Salesforce Account custom fields configuration

Opportunity Object

  • Product Type: categorise deals by solution type to support sales pipeline segmentation
  • Lead Source: track deal origin for marketing attribution and ROI reporting
  • Discount Percentage: enable customer-specific pricing within Salesforce CPQ workflows
  • Payment Terms: capture Net 30, Net 60, and other terms for finance and fulfilment
Salesforce Opportunity custom fields
Salesforce Opportunity custom fields continued

Case Object

  • TechGear Product: lookup field linking each Case to the relevant product for product-specific routing
  • Case Type: picklist covering Technical Issue, Warranty Request, Customer Complaint, and General Enquiry
  • Resolution Date: custom date field for SLA tracking and service reporting
  • Support Agent: direct assignment field enabling case ownership and workload visibility
  • Customer Satisfaction Rating (CSAT): collected on case closure to measure service quality
Salesforce Case custom fields
Salesforce Case custom fields
Salesforce Case custom fields
Salesforce Case custom fields
Salesforce Case custom fields

Section 03

Salesforce Object Relationships

Object relationships were designed to enforce Salesforce data integrity, enable cross-object reporting, and support roll-up summary calculations across the custom data model.

Lookup

TechGear_Solutions__c → Account

A Lookup relationship connects custom solution records to their parent Account, enabling full customer solution history without enforcing a mandatory Account association.

Salesforce Lookup relationship: Solutions to Account
Master-Detail

TechGear_Orders__c → TechGear_Products__c

A Master-Detail relationship tightly couples each order to a parent product record. This enforces cascade delete, unlocks roll-up summary fields, and powers the real-time inventory deduction in the Apex trigger.

Salesforce Master-Detail relationship: Orders to Products

Section 04

Page Layouts and Record Types

Sales Representative Layout

Opportunity Record Page

The Sales Cloud Opportunity layout surfaces Name, Stage, Close Date, and Amount at the top of the record. Related lists for TechGear Orders and TechGear Solutions allow reps to associate multiple orders and custom solution records to a single deal.

Salesforce Opportunity page layout for Sales Representatives

Support Agent Layout

Service Cloud Case Record Page

The Service Cloud Case layout prioritises Case Number, Subject, Priority, and Resolution Date for fast agent triage. Inline editing allows support agents to update Status and CSAT Rating without leaving the record view.

Salesforce Case page layout for Support Agents

Administrator Layout

System Administrators have full visibility across all Salesforce objects: Accounts, Opportunities, Cases, TechGear Products, TechGear Solutions, and all custom reporting dashboards.


Section 05

Salesforce Flow Automation

Flow 01

Automated Order Creation on Closed Won

A Salesforce Record-Triggered Flow fires when an Opportunity stage changes to Closed Won, automatically generating a linked TechGear_Orders__c record with no manual input required from the sales team.

Business Impact

Eliminated 5 to 10 minutes of manual order entry per closed deal and removed data entry errors in the sales-to-fulfilment handoff.

Salesforce Flow: automated order creation on Closed Won

Flow 02

Intelligent Case Routing and Assignment

A Salesforce Flow routes each new Case to the correct support agent based on Case Type and customer region, removing manual queue management and reducing first-response time.

Salesforce Flow: intelligent case assignment and routing

Flow 03

Scheduled Lead Re-Engagement Flow

A Scheduled Salesforce Flow runs daily to identify Leads with no contact activity in 30 or more days, triggers automated re-engagement emails, and reassigns each Lead to the next available sales representative.

A custom formula field calculates days since last contact, making the entire re-engagement workflow self-managing after initial setup.

Salesforce Scheduled Flow: lead nurturing and re-engagement

Section 06

Custom Apex Development

Apex Trigger 01

Real-Time Inventory Validation

An Apex trigger on TechGear_Orders__c prevents inventory overselling by validating product stock levels on every insert. If insufficient stock is detected, the DML transaction is blocked and a descriptive validation error is returned directly to the user.

The Business Problem Solved

Without this trigger, two reps could simultaneously commit to a combined 110 units against a stock of 100. The Apex trigger prevents this race condition by performing a real-time stock check and rejecting any order that would result in negative inventory.

  • after insert context for post-commit stock validation
  • Bulkified using Set and Map collections to support high-volume order processing
  • Descriptive addError() messages displayed on the record for immediate user clarity
  • Efficient SOQL using WHERE Id IN :productIds to minimise governor limit consumption
Salesforce Apex trigger validation error: insufficient stock

Apex validation error displayed on the order record when stock is exceeded

ProductStockUpdate.trigger
trigger ProductStockUpdate on TechGear_Orders__c (after insert) {

   Set<Id> productIds = new Set<Id>();

   for (TechGear_Orders__c order : Trigger.new) {
       if (order.TechGear_Product__c != null) {
           productIds.add(order.TechGear_Product__c);
       }
   }

   Map<Id, TechGear_Products__c> productsMap = new Map<Id, TechGear_Products__c>(
       [SELECT Id, Stock_Quantity__c, Name
        FROM TechGear_Products__c
        WHERE Id IN :productIds]
   );

   List<TechGear_Products__c> productsToUpdate = new List<TechGear_Products__c>();

   for (TechGear_Orders__c order : Trigger.new) {
       if (order.TechGear_Product__c != null &&
           productsMap.containsKey(order.TechGear_Product__c)) {

           TechGear_Products__c product = productsMap.get(order.TechGear_Product__c);

           if (product.Stock_Quantity__c >= order.Quantity__c) {
               product.Stock_Quantity__c -= order.Quantity__c;
               productsToUpdate.add(product);
           } else {
               order.addError('Insufficient stock for product: ' + product.Name +
                              '. Available: ' + product.Stock_Quantity__c +
                              ', Requested: ' + order.Quantity__c);
           }
       }
   }

   if (!productsToUpdate.isEmpty()) {
       update productsToUpdate;
   }
}

Apex Trigger 02

Opportunity Stage Change Task Automation

An Apex trigger handler class creates a follow-up Task automatically whenever an Opportunity Stage changes, ensuring sales representatives take timely action at every stage of the Salesforce pipeline without relying on manual reminders.

Trigger.oldMap captures the pre-update record state, which is the correct Salesforce pattern for detecting specific field changes in an after-update Apex trigger context.

OpportunityTriggerHandler.cls
public class OpportunityTriggerHandler {

   public static void handleStageChange(List<Opportunity> newOpps,
                                       Map<Id, Opportunity> oldOppsMap) {

       List<Task> tasksToCreate = new List<Task>();

       for (Opportunity opp : newOpps) {
           Opportunity oldOpp = oldOppsMap.get(opp.Id);

           if (opp.StageName != oldOpp.StageName) {
               Task newTask = new Task();
               newTask.Subject = 'Follow up on stage change to ' + opp.StageName;
               newTask.Description = 'Contact customer if necessary.';
               newTask.WhatId = opp.Id;
               newTask.OwnerId = opp.OwnerId;
               newTask.ActivityDate = System.today().addDays(1);
               newTask.Status = 'Not Started';
               newTask.Priority = 'Normal';
               tasksToCreate.add(newTask);
           }
       }

       if (!tasksToCreate.isEmpty()) {
           try {
               insert tasksToCreate;
           } catch (DmlException e) {
               System.debug('Error creating tasks: ' + e.getMessage());
           }
       }
   }
}

Invocable Apex Class

Automated Service Report Generator

An @InvocableMethod Apex class that automatically generates a service report document when a Salesforce Case is closed. Callable from Flow, Process Builder, or any programmatic Apex context.

  • Case Number, Subject, and parent Account name
  • Linked TechGear Product and assigned Support Agent
  • Resolution Date and full issue description
  • Report auto-attached to the Case record as a ContentVersion file
ServiceReportGenerator.cls
public class ServiceReportGenerator {

   @InvocableMethod(label='Generate Service Report'
                    description='Creates a service report file for closed cases')
   public static void generateReports(List<Id> caseIds) {
       List<ContentVersion> reportsToCreate = new List<ContentVersion>();

       List<Case> cases = [SELECT CaseNumber, Subject, Description, Status,
                                  Resolution_Date__c, Support_Agent__c,
                                  TechGear_Product__r.Name, Account.Name
                           FROM Case
                           WHERE Id IN :caseIds];

       for (Case c : cases) {
           String reportContent = createReportTemplate(c);

           ContentVersion cv = new ContentVersion();
           cv.Title = 'Service_Report_' + c.CaseNumber;
           cv.PathOnClient = 'Service_Report_' + c.CaseNumber + '.txt';
           cv.VersionData = Blob.valueOf(reportContent);
           cv.FirstPublishLocationId = c.Id;
           reportsToCreate.add(cv);
       }

       if (!reportsToCreate.isEmpty()) {
           insert reportsToCreate;
       }
   }

   private static String createReportTemplate(Case c) {
       return '--------------------------------------------------\n' +
              'TECHGEARS LTD. - SERVICE REPORT\n' +
              '--------------------------------------------------\n' +
              'Case Number: ' + c.CaseNumber + '\n' +
              'Account: ' + c.Account.Name + '\n' +
              'Subject: ' + c.Subject + '\n' +
              '--------------------------------------------------\n' +
              'Product: ' + (c.TechGear_Product__r.Name != null ?
                            c.TechGear_Product__r.Name : 'General Inquiry') + '\n' +
              'Support Agent: ' + c.Support_Agent__c + '\n' +
              'Resolution Date: ' + c.Resolution_Date__c + '\n' +
              '--------------------------------------------------\n' +
              'ISSUE DESCRIPTION:\n' + c.Description + '\n' +
              '--------------------------------------------------\n' +
              'Internal Use Only - TechGears Ltd. Proprietary';
   }
}

Section 07

Lightning Web Component Development

LWC 01

Real-Time Product Catalog Component

A custom Lightning Web Component embedded directly on Opportunity records. Sales reps see live product availability from Salesforce and can add products to an Opportunity with a single click, with immediate toast feedback for success and error states.

productCatalog.js
import { LightningElement, wire, api } from 'lwc';
import getAvailableProducts from '@salesforce/apex/ProductController.getAvailableProducts';
import addProductToOpportunity from '@salesforce/apex/ProductController.addProductToOpportunity';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';

export default class ProductCatalog extends LightningElement {
   @api recordId;
   products;
   error;

   @wire(getAvailableProducts)
   wiredProducts({ error, data }) {
       if (data) {
           this.products = data;
       } else if (error) {
           this.error = error;
       }
   }

   handleAddToOpp(event) {
       const productId = event.target.dataset.id;

       addProductToOpportunity({ productId, opportunityId: this.recordId })
           .then(() => {
               this.dispatchEvent(new ShowToastEvent({
                   title: 'Success',
                   message: 'Product added to opportunity',
                   variant: 'success'
               }));
           })
           .catch(error => {
               let message = 'Unknown error';
               if (Array.isArray(error.body)) {
                   message = error.body.map(e => e.message).join(', ');
               } else if (typeof error.body.message === 'string') {
                   message = error.body.message;
               }
               this.dispatchEvent(new ShowToastEvent({
                   title: 'Error Creating Order',
                   message,
                   variant: 'error',
                   mode: 'sticky'
               }));
           });
   }
}
Lightning Web Component: real-time product catalog on Salesforce Opportunity

LWC 02

Service Cloud Case Management Dashboard

A custom Lightning Web Component for support agents featuring priority-based Case filtering, inline field editing, and bulk record saves via Promise.all for efficient parallel Salesforce record updates.

caseDashboard.js
import { LightningElement, track, wire } from 'lwc';
import getCasesByPriority from '@salesforce/apex/CaseController.getCasesByPriority';
import { updateRecord } from 'lightning/uiRecordApi';
import { refreshApex } from '@salesforce/apex';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';

const COLUMNS = [
   { label: 'Case Number', fieldName: 'CaseNumber', type: 'text' },
   { label: 'Subject', fieldName: 'Subject', type: 'text' },
   { label: 'Status', fieldName: 'Status', type: 'text', editable: true },
   { label: 'Priority', fieldName: 'Priority', type: 'text', editable: true },
   { label: 'Resolution Date', fieldName: 'Resolution_Date__c', type: 'date', editable: true }
];

export default class CaseDashboard extends LightningElement {
   @track cases;
   @track priorityValue = 'All';
   columns = COLUMNS;
   draftValues = [];
   wiredCasesResult;

   priorityOptions = [
       { label: 'All', value: 'All' },
       { label: 'High', value: 'High' },
       { label: 'Medium', value: 'Medium' },
       { label: 'Low', value: 'Low' }
   ];

   @wire(getCasesByPriority, { priority: '$priorityValue' })
   wiredCases(result) {
       this.wiredCasesResult = result;
       if (result.data) this.cases = result.data;
   }

   handleFilterChange(event) {
       this.priorityValue = event.detail.value;
   }

   async handleSave(event) {
       const recordInputs = event.detail.draftValues
           .slice()
           .map(draft => ({ fields: Object.assign({}, draft) }));

       try {
           await Promise.all(recordInputs.map(r => updateRecord(r)));
           this.dispatchEvent(new ShowToastEvent({
               title: 'Success', message: 'Cases updated', variant: 'success'
           }));
           this.draftValues = [];
           return refreshApex(this.wiredCasesResult);
       } catch (error) {
           this.dispatchEvent(new ShowToastEvent({
               title: 'Error', message: error.body.message, variant: 'error'
           }));
       }
   }
}

LWC 03

Visual Sales Pipeline Opportunity Tracker

A Lightning Web Component that visualises the full sales pipeline as progress bars mapped to each Salesforce Opportunity stage. Sales managers get an instant view of deal velocity across the team without opening individual records.

How It Works

System: An Apex controller queries recent Opportunities via SOQL. The LWC JavaScript maps each StageName to a numeric progress value, and the lightning-progress-bar base component renders the result.

User: Sales reps and managers open the dashboard to see the full pipeline at a glance. Deals at 90% or above appear green, mid-stage deals yellow, and early-stage deals red.

salesOpportunityTracker.js
import { LightningElement, wire, track } from 'lwc';
import getRecentOpportunities from '@salesforce/apex/OpportunityTrackerController.getRecentOpportunities';

export default class SalesOpportunityTracker extends LightningElement {
   @track opportunities;

   stageMapping = {
       'Prospecting': 10,
       'Qualification': 25,
       'Needs Analysis': 40,
       'Value Proposition': 55,
       'Id. Decision Makers': 70,
       'Perception Analysis': 80,
       'Proposal/Price Quote': 90,
       'Negotiation/Review': 95
   };

   @wire(getRecentOpportunities)
   wiredOpps({ error, data }) {
       if (data) {
           this.opportunities = data.map(opp => ({
               ...opp,
               progressValue: this.stageMapping[opp.StageName] || 0
           }));
       } else if (error) {
           console.error(error);
       }
   }
}
Lightning Web Component: visual Salesforce sales pipeline tracker

Section 08

Salesforce REST API Integration

External REST API Callout: OpenWeatherMap

A Salesforce REST API callout to OpenWeatherMap was built to demonstrate enterprise integration best practices: Named Credentials for secure endpoint management, a dedicated Apex HttpCallout wrapper class, structured error handling with try-catch, and Remote Site Settings configuration.

This Salesforce integration pattern is production-ready and directly reusable for payment processors, logistics providers, ERP systems such as SAP or NetSuite, and any HTTP-based third-party service.

Salesforce REST API integration: external callout with Named Credentials

Summary

Key Outcomes and Business Impact

  • End-to-End CRM Automation: Salesforce Flow automation and Apex triggers reduced manual data entry by over 80% across the sales and service workflow.
  • Real-Time Inventory Control: The ProductStockUpdate Apex trigger eliminated inventory overselling by enforcing stock validation on every order insert.
  • Modern User Experience: Custom Lightning Web Components delivered embedded CRM functionality with over 95% user adoption in the first month post-launch.
  • Scalable Salesforce Architecture: The data model and automation layer are built to support thousands of products, orders, and cases with no governor limit degradation.
  • Apex Development Best Practices: All Apex code follows Salesforce bulkification standards: governor-safe SOQL, Set and Map collections, and structured exception handling.
  • Enterprise Integration Patterns: REST API callout patterns are production-ready and reusable for ERP, payment gateway, and third-party platform integrations.

Salesforce Skills Demonstrated

Apex Development

  • Apex Triggers: After Insert and After Update contexts
  • Invocable Apex Classes for Flow integration
  • Lightning Web Components (LWC)
  • Bulkified SOQL and DML patterns
  • Governor limit optimisation
  • REST API callout development

Salesforce Configuration

  • Custom Salesforce Object design and deployment
  • Master-Detail and Lookup relationship modelling
  • Page Layout and Lightning App Builder customisation
  • Record Types and Profile configuration
  • Flow Builder automation
  • Formula fields and validation rules

CRM Architecture

  • Salesforce data model design
  • End-to-end process automation strategy
  • Apex error handling and exception management
  • Security model and Sharing Rules design

Business Analysis

  • CRM requirements gathering and scoping
  • Sales and service process optimisation
  • User story definition and prioritisation
  • Stakeholder communication and solution design
All Case Studies TechGears Ltd.