Skip to content

Class Name: CartAlert

Last Updated: 2025-10-22 Source Code: https://github.com/AANP-IT/I2C.Salesforce.Metadata/blob/STAGING/force-app/main/default/classes/CartAlert.cls

API Name: CartAlert Type: Lightning Component Controller (AuraEnabled) Test Coverage: To be determined Created: 09/17/2024 Author: Corina Petrusca

Business Purpose

This class supports cart abandonment prevention strategies by detecting when users have items sitting in their shopping cart for more than one hour. It enables proactive customer engagement through alerts or notifications displayed in Lightning components, helping reduce cart abandonment rates and increase e-commerce conversion rates. The class is designed for real-time detection of stale cart items to trigger timely customer engagement interventions.

Class Overview

Scope and Sharing

  • Sharing Model: with sharing (respects record-level security)
  • Access Modifier: public
  • Interfaces Implemented: None

Key Responsibilities

  • Detect abandoned cart items for current user
  • Check cart item age against 60-minute threshold
  • Validate field-level security before querying
  • Return boolean indicator for Lightning component UI decisions
  • Enforce sharing rules and security enforced queries
  • Support cart abandonment prevention workflows
  • Integrate with Lightning Web Components via @AuraEnabled

Public Methods

hasItemsInCart

@AuraEnabled
public static Boolean hasItemsInCart()

Purpose: Checks if the current user has items in their shopping cart that were added more than one hour ago, indicating a potentially abandoned cart that needs attention.

Parameters: - None (uses current user context from UserInfo.getUserId())

Returns: - Boolean: Returns true if there are cart items older than 60 minutes; false otherwise

Throws: - QueryException: If SOQL queries fail (not explicitly handled) - NullPointerException: If webCart is null but still referenced (potential issue)

Usage Example:

// Called from Lightning Web Component
import hasItemsInCart from '@salesforce/apex/CartAlert.hasItemsInCart';

// In LWC JavaScript
hasItemsInCart({ refreshKey: Date.now() })
    .then(result => {
        if (result) {
            // Show cart abandonment alert
            this.showAbandonedCartMessage = true;
        }
    })
    .catch(error => {
        // Handle error
        console.error('Error checking cart:', error);
    });

Business Logic: 1. Gets current user ID from UserInfo.getUserId() 2. Calculates time limit as current time minus 60 minutes 3. Checks FLS permissions for WebCart fields (Id, CreatedById, Status) 4. Queries for user's active WebCart in statuses: 'Active', 'Checkout', 'Processing' 5. Uses WITH SECURITY_ENFORCED to respect user permissions 6. Limits to 1 cart (assumes one active cart per user) 7. Checks FLS permissions for CartItem fields (Id, CreatedDate) 8. Queries CartItems where: - Cart belongs to current user (Cart.CreatedById = currentUserId) - Item created before time limit (CreatedDate < timeLimit) - Cart matches the found WebCart 9. Uses WITH SECURITY_ENFORCED on CartItem query 10. Orders by CreatedDate (oldest first) 11. Limits to 50,000 cart items 12. Returns true if cartItems.size() > 0, false otherwise

Field-Level Security Checks: - WebCart fields checked: Id, CreatedById, Status - CartItem fields checked: Id, CreatedDate - If FLS fails, query doesn't execute (returns default null WebCart) - isAccessible() used for read permission validation

Time Calculation:

Datetime timeLimit = Datetime.now().addMinutes(-60);
- Hardcoded to 60 minutes (1 hour) - Uses negative minutes to calculate past time - Compares against CartItem.CreatedDate

Query Logic:

// WebCart Query
SELECT Id, CreatedById, Status
FROM WebCart
WHERE CreatedById = :currentUserId
AND Status IN ('Active', 'Checkout', 'Processing')
WITH SECURITY_ENFORCED
LIMIT 1

// CartItem Query
SELECT Id, CreatedDate
FROM CartItem
WHERE Cart.CreatedById = :currentUserId
AND CreatedDate < :timeLimit
AND Cart.Id = :webCart.Id
WITH SECURITY_ENFORCED
ORDER BY CreatedDate
LIMIT 50000

Security Enforced: - Both queries use WITH SECURITY_ENFORCED clause - Automatically enforces object-level, field-level, and record-level security - Query returns empty if user lacks permissions - More restrictive than manual FLS checks


Private/Helper Methods

None - All logic contained in single public method. Could benefit from refactoring: - Separate FLS check logic - Separate cart retrieval - Separate cart item age checking - Separate time threshold calculation


Dependencies

Apex Classes

  • None - Standalone controller class
  • Called by: Lightning Web Components or Aura Components

Salesforce Objects

WebCart (Commerce Cloud) - Fields accessed: Id, CreatedById, Status - Purpose: Represent user's shopping cart - Statuses: 'Active', 'Checkout', 'Processing'

CartItem (Commerce Cloud) - Fields accessed: Id, CreatedDate, Cart.CreatedById, Cart.Id - Purpose: Individual items in shopping cart

User (Standard - implicit) - UserInfo.getUserId() to get current user - No direct query, uses system context

Custom Settings/Metadata

  • None identified - Consider adding:
  • Cart_Settings__mdt: Configurable time threshold
  • Cart_Abandonment__mdt: Enable/disable alerts, time thresholds by product category

External Services

  • None - Pure internal Salesforce processing

Design Patterns

  • Controller Pattern: AuraEnabled method for Lightning component integration
  • Query Pattern: Uses SOQL to retrieve cart data
  • Security Pattern: Explicit FLS checks + WITH SECURITY_ENFORCED
  • User Context Pattern: Operates in context of current user

Why These Patterns: - AuraEnabled enables Lightning component integration - Security pattern ensures compliance with data access policies - User context pattern ensures users only see their own cart data - Query pattern provides flexibility for cart detection logic

Governor Limits Considerations

SOQL Queries: 2 (WebCart query, CartItem query) DML Operations: 0 (read-only) CPU Time: Low (simple queries and size check) Heap Size: Could be high with 50,000 cart items

Bulkification: N/A (operates on single user's cart) Async Processing: No (synchronous LWC call)

Governor Limit Risks: - HIGH: LIMIT 50000 on CartItem query could hit heap size limits if user has massive cart - MEDIUM: No caching - multiple LWC refreshes cause repeated queries - LOW: 2 SOQL queries per call (well within 100 query limit) - LOW: Single user scope limits data volume

Performance Considerations: - Method called every time LWC renders or refreshes - No caching mechanism (refreshKey parameter suggests frequent calls) - Large carts (>1000 items) could slow response time - ORDER BY CreatedDate adds minor overhead

Recommendations: - Reduce LIMIT from 50000 to 1000 (sufficient for cart alerts) - Implement caching with refreshKey parameter - Add query timeout handling - Consider async processing for very large carts - Add indexes on Cart.CreatedById and CartItem.CreatedDate

Error Handling

Strategy: No explicit error handling - relies on system exceptions

Logging: - None - No logging of execution or errors - No tracking of FLS failures - No visibility into why checks fail

User Notifications: - None - LWC must handle errors in catch block - Generic Salesforce error messages if queries fail - No user-friendly error messages

FLS Failure Behavior: - If FLS check fails, webCart remains null (initial value) - Null webCart could cause NullPointerException in CartItem query - Query returns empty if WebCart not found (handled gracefully)

Null WebCart Risk:

WebCart webCart = new WebCart();  // Initialized to empty object
if (Schema.sObjectType.WebCart.fields.Id.isAccessible() && ...) {
    webCart = [SELECT ...];  // Replaces with query result
}
// If FLS fails, webCart is empty WebCart object (not null but no Id)
// Cart.Id = :webCart.Id could fail or return no results

Recommended Improvements: - Add try-catch around queries - Check if webCart.Id != null before CartItem query - Log FLS failures for troubleshooting - Return error details to LWC for user-friendly messages - Add null checks before using webCart

Security Considerations

Sharing Rules: RESPECTED - Uses 'with sharing' - Users can only see their own carts (CreatedById filter) - Record-level security enforced - Appropriate for user-facing functionality

Field-Level Security: ENFORCED MULTIPLE WAYS - Manual FLS checks via isAccessible() - WITH SECURITY_ENFORCED in queries (double protection) - Belt-and-suspenders approach (good for compliance)

CRUD Permissions: ENFORCED - WITH SECURITY_ENFORCED validates read access to objects - User must have read permission on WebCart and CartItem

Input Validation: N/A - No user input parameters - Uses system UserInfo context (trusted) - refreshKey parameter not used in method signature (intended for caching)

Security Risks: - LOW: 'with sharing' and security enforced provide strong protection - LOW: Could expose cart existence to users (but only their own) - LOW: No sensitive data returned (just boolean)

Privacy Considerations: - Only accesses current user's data - No PII exposed in return value - Cart data remains private to cart owner

Mitigation Recommendations: 1. Current security is appropriate 2. Consider rate limiting if called frequently 3. Add monitoring for unusual query patterns 4. Document that method reveals cart state to user

Test Class

Test Class: CartAlertTest.cls (assumed name - verify in codebase) Coverage: To be determined

Test Scenarios That Should Be Covered: - ✓ User with no cart returns false - ✓ User with cart but no items returns false - ✓ User with recent cart items (<60 min) returns false - ✓ User with old cart items (>60 min) returns true - ✓ Multiple cart items, some old, some new - returns true - ✓ Cart in 'Active' status returns true - ✓ Cart in 'Checkout' status returns true - ✓ Cart in 'Processing' status returns true - ✓ Cart in 'Closed' status returns false (not in filter) - ✓ Different users don't see each other's carts - ✓ FLS failure scenario (user lacks WebCart read access) - ✓ Null webCart handling - ✓ Empty cart items list returns false - ✓ Exactly 60 minutes old (boundary test) - ✓ WITH SECURITY_ENFORCED behavior

Testing Challenges: - Difficult to test FLS failures (tests run in system mode) - Need to create WebCart and CartItem records - Must manipulate CreatedDate (may need Test.setCreatedDate) - WITH SECURITY_ENFORCED testing requires specific user setup - Multiple users needed for isolation testing

Test Data Requirements: - Multiple User records - WebCart records in various statuses - CartItem records with different CreatedDate values - Records belonging to different users

Mock Data Patterns:

// Create old cart item
CartItem oldItem = new CartItem(...);
Test.setCreatedDate(oldItem.Id, Datetime.now().addHours(-2));

// Create recent cart item
CartItem newItem = new CartItem(...);
Test.setCreatedDate(newItem.Id, Datetime.now().addMinutes(-30));

Changes & History

  • Created: 09/17/2024
  • Author: Corina Petrusca
  • Last Modified: 09/18/2024 (per inline comments)
  • Purpose: Cart abandonment alert detection
  • Version: Initial release

Recommended: - Document integration with specific LWC components - Link to cart abandonment workflow documentation - Reference marketing team requirements

⚠️ Pre-Go-Live Concerns

CRITICAL - Fix Before Go-Live

  • No Exception Handling: Zero try-catch blocks - query failures will throw unhandled exceptions to LWC, breaking user experience.
  • Null WebCart Risk: If FLS check fails, webCart remains empty object but is still used in CartItem query. Could cause null pointer or return incorrect results.
  • Heap Size Risk with 50K Limit: LIMIT 50000 on CartItem query could cause heap size limits if user has massive abandoned cart. Reduce to 1000.

HIGH - Address Soon After Go-Live

  • Hardcoded 60-Minute Threshold: Time limit hardcoded to 60 minutes - should be configurable via custom metadata for different business scenarios.
  • No Logging: Zero logging makes troubleshooting impossible. Can't determine why alerts don't fire.
  • No Caching: Method called repeatedly from LWC but no caching mechanism. Wastes SOQL queries.
  • Performance: ORDER BY and LIMIT 50000 could cause slow response times. Optimize query.

MEDIUM - Future Enhancement

  • Redundant FLS Checks: Manual isAccessible() checks may be redundant with WITH SECURITY_ENFORCED. Simplify or document rationale.
  • Limited Scope: Only current user can check their cart. May need admin override for customer service.
  • Basic Return Value: Returns only boolean. Could return cart item count, oldest item date, etc. for richer UI.
  • No Product Differentiation: All products use same 60-minute threshold. Different products may need different thresholds.
  • RefreshKey Parameter: Not used in method signature but passed from LWC (commented in documentation). Implement caching.

LOW - Monitor

  • Query Optimization: Two separate queries could potentially be combined or optimized.
  • Documentation: Add LWC integration examples and component usage documentation.
  • Code Organization: Single 59-line method could be refactored into smaller, testable methods.

Maintenance Notes

Complexity: Low-Medium (simple logic but security considerations) Recommended Review Schedule: Quarterly (cart functionality changes), After marketing campaigns

Key Maintainer Notes:

🛒 CART ABANDONMENT STRATEGY: - This class is foundation for cart abandonment prevention - Drives customer engagement and conversion optimization - Changes affect marketing campaign effectiveness - Time threshold directly impacts when customers see alerts - Test with marketing team before changes

📋 Usage Patterns: - Called from Lightning Web Component (likely on cart page or header) - May be called on every page load or component refresh - Should be lightweight and fast - Consider caching if performance becomes issue

🧪 Testing Requirements: - Test with various cart ages (0 min, 30 min, 60 min, 120 min) - Test with different cart statuses - Test with multiple users simultaneously - Performance test with large carts - Test FLS scenarios with restricted users

🔧 LWC Integration: - Method designed for Lightning Web Component consumption - @AuraEnabled with cacheability=false (default) - Boolean return makes UI decisions simple - Consider adding @AuraEnabled(cacheable=true) with appropriate TTL

⚠️ Gotchas and Warnings: - Hardcoded 60-minute threshold - business may want to adjust - LIMIT 50000 is excessive for typical cart abandonment use cases - No caching means frequent SOQL query consumption - FLS checks may block functionality for some user profiles - ORDER BY adds overhead but only returns up to 50K rows - WebCart statuses must match: 'Active', 'Checkout', 'Processing' (case-sensitive)

📅 When to Review This Class: - Before any cart abandonment campaign changes - If marketing requests different time thresholds - When adding new product types or cart workflows - If performance issues reported - During user profile/permission changes - When Commerce Cloud cart functionality changes

🛑 Deactivation Strategy:

If cart alerts need to be temporarily disabled:

// Option 1: Add custom metadata check
Cart_Settings__mdt settings = Cart_Settings__mdt.getInstance('Alerts');
if (settings != null && !settings.Enabled__c) {
    return false; // Always return false (no alerts)
}

// Option 2: Remove LWC component from pages
// Option 3: Set time threshold to very high value (e.g., 24 hours)

🔍 Debugging Tips: - Enable debug logs for current user - Check WebCart and CartItem records directly via SOQL - Verify cart Status matches filter values - Check CreatedDate timestamps - Verify user has FLS access to required fields - Test WITH SECURITY_ENFORCED in anonymous apex - Check for governor limit warnings

📊 Monitoring Checklist: - Daily: SOQL query consumption from this method - Weekly: Average cart item counts when alert fires - Monthly: Alert effectiveness (conversion rate after alert) - Monitor: Method execution time (should be <500ms) - Alert: Any exceptions thrown to LWC components

🔗 Related Components: - Lightning Web Component: Calls this method to display alerts - WebCart object: Primary data source - CartItem object: Item-level data - Cart abandonment workflow: Uses this as trigger - Marketing automation: May integrate with email campaigns - Analytics: Track alert effectiveness

💡 Future Enhancement Ideas: - Make time threshold configurable per product category - Return detailed cart information (item count, total value, oldest item) - Add different alert levels (warning, urgent, critical) - Implement caching with automatic invalidation - Add analytics tracking (how often alerts shown vs. converted) - Support multiple time thresholds for progressive alerts

Business Owner

Primary: Marketing / E-Commerce Operations Secondary: IT Operations / Customer Experience Team Stakeholders: Product Management, Sales, Customer Service, Development Team