47 min readAutonomous agents

Implementation Guide: Monitor client account events and proactively surface concerns to advisor

Step-by-step implementation guide for deploying AI to monitor client account events and proactively surface concerns to advisor for Financial Advisory clients.

Hardware Procurement

Fortinet FortiGate 40F Next-Generation Firewall

FortinetFG-40FQty: 1

$400–$500 per unit (MSP cost) / $700–$900 suggested resale including first-year FortiGuard subscription

Secures the client office network perimeter with deep packet inspection, SSL/TLS inspection for API traffic to Salesforce and Orion endpoints, and IPS signatures. Required for SOC 2 compliance and to protect PII-bearing API traffic between on-premises systems and cloud services.

Advisor Workstation Monitor (Secondary Display)

Advisor Workstation Monitor (Secondary Display)

DellDell P2423D (24-inch QHD)Qty: 5

$250 per unit (MSP cost) / $350–$400 suggested resale

Optional but recommended: provides advisors a dedicated second screen for the Salesforce alert dashboard so they can monitor real-time AI notifications alongside their primary workflow. Recommended for firms with 5+ advisors.

Uninterruptible Power Supply

APCAPC Back-UPS Pro BN1500M2Qty: 1

$200 (MSP cost) / $300 suggested resale

Battery backup for the primary network switch and firewall to maintain connectivity to cloud services during brief power events, ensuring no alert delivery gaps.

Software Procurement

Salesforce Financial Services Cloud (Enterprise Edition)

SalesforceEnterprise EditionQty: 10 advisors + 2 admin seats

$300/user/month (billed annually). For 10 advisors + 2 admin seats = $43,200/year MSP cost. Suggested resale: $375–$450/user/month.

Primary CRM and client data platform. Provides the Wealth Management data model (Financial Accounts, Financial Holdings, Financial Goals objects), client household hierarchy, activity tracking, and the foundation for Agentforce agent deployment.

Salesforce Agentforce (Conversations + Flex Credits)

Salesforceusage-based (per conversation + per action credits)Qty: ~250–750 agent conversations/month for a 10-advisor firm

$2/conversation + Flex Credit packs. Estimated $500–$1,500/month for a 10-advisor firm with ~250–750 agent conversations/month. Standard add-on at $125/user/month for bundled Agentforce capabilities.

Powers the autonomous monitoring agent with pre-built financial services agent templates. Handles event detection, concern classification, alert generation, and advisor notification within the Salesforce compliance framework.

Orion Advisor Solutions (Orion Connect API)

Orion Advisor SolutionsOrion Connect API

Platform pricing varies by AUM ($500–$3,000/month typical for mid-size RIA). API access included with platform subscription. MSP integration setup fee applies.

Portfolio accounting, performance reporting, and real-time account data feed. The Orion Connect API provides portfolio positions, transactions, performance benchmarks, drift metrics, and cash balances that the AI agent monitors for threshold breaches.

Smarsh Professional Archive

SmarshProfessional ArchiveQty: per-seat SaaS

$25–$50/user/month (varies by channel count). Suggested resale: $40–$75/user/month bundled with managed service.

FINRA-compliant communications archiving. All AI-generated alerts, advisor acknowledgments, and agent decision logs are archived in WORM-compliant storage per SEC 17a-4 and FINRA Rule 4510. Smarsh AI Assistant provides compliance review of AI-generated content.

Microsoft 365 Business Premium

Microsoftper-seat SaaS

$22/user/month (MSP CSP cost) / $30–$35/user/month suggested resale

Provides Azure Entra ID for identity management and MFA enforcement, Microsoft Teams for alert delivery channel, Outlook integration for email notifications, and SharePoint for compliance documentation storage.

$0.15/million input tokens, $0.60/million output tokens. Estimated $100–$400/month for a 10-advisor firm processing ~50,000 account events/month.

Provides the LLM reasoning layer for natural language alert generation, concern severity classification, and contextual enrichment of raw account events. GPT-5.4 mini selected for cost efficiency on structured financial data analysis tasks.

Included in FSC Enterprise licensing. Additional data credits if exceeding base allocation: ~$0.10–$0.25 per 1,000 records processed.

Unifies data from Orion, custodial feeds, and CRM into a single real-time profile for each client household. Enables the Agentforce agent to query consolidated account data without building custom ETL pipelines.

Prerequisites

  • Active Salesforce Financial Services Cloud Enterprise Edition subscription with admin credentials and System Administrator profile access
  • Active Orion Advisor Solutions subscription with Orion Connect API access enabled (contact Orion support to provision API keys and configure OAuth 2.0 client credentials)
  • Active custodial data feeds configured in Orion (Schwab, Fidelity, and/or Pershing accounts already linked and syncing daily)
  • Microsoft 365 Business Premium tenant with Azure Entra ID configured and MFA enforced for all advisor accounts
  • Azure subscription with Azure OpenAI Service access approved (requires application at https://aka.ms/oai/access — allow 2–5 business days for approval)
  • Smarsh Professional Archive account provisioned with API access for automated content ingestion
  • Business internet connection with minimum 50 Mbps symmetric bandwidth and static IP address (or business-grade dynamic DNS)
  • Current firm compliance manual and Written Supervisory Procedures (WSPs) document — the Chief Compliance Officer must review and approve AI agent deployment before go-live
  • Complete client household data loaded in Salesforce FSC with Financial Account and Financial Holding objects populated (minimum: account numbers, household relationships, advisor assignments)
  • Documented threshold values for alerts: portfolio drift tolerance (e.g., 5%), cash balance minimums/maximums, concentrated position limits (e.g., >20% single security), performance deviation thresholds, and contact frequency minimums (e.g., 2 touches/quarter)
  • Network firewall configured to allow outbound HTTPS (port 443) to: *.salesforce.com, *.force.com, *.orion.com, *.openai.azure.com, *.smarsh.com, *.microsoft.com
  • Designated project sponsor (typically Managing Partner or COO) and compliance officer available for weekly 30-minute check-ins during implementation

Installation Steps

...

Step 1: Salesforce Financial Services Cloud Environment Configuration

Configure the FSC org for wealth management use. Enable the Financial Services Cloud permission sets, activate the Wealth Management data model, and configure the Person Account record type for client households. Set up the Financial Account, Financial Holding, and Financial Goal objects with custom fields required by the monitoring agent.

1
Navigate to Setup > Feature Settings > Financial Services Cloud > Enable Financial Services Cloud
2
Setup > Object Manager > Financial Account > Fields & Relationships > New > Create custom fields: 'Drift_Percentage__c' (Percent), 'Cash_Balance__c' (Currency), 'Last_Rebalance_Date__c' (Date), 'Concentration_Alert__c' (Checkbox), 'Performance_Deviation__c' (Percent)
3
Setup > Object Manager > Account (Person Account) > Fields & Relationships > New > Create: 'RMD_Age_Date__c' (Date), 'Last_Advisor_Contact__c' (Date), 'Contact_Frequency_Target__c' (Number), 'Risk_Score__c' (Number), 'Life_Event_Flags__c' (Multi-Select Picklist with values: Retirement, Divorce, Death_of_Spouse, Job_Change, New_Child, Home_Purchase, Inheritance)
4
Setup > Permission Sets > Clone 'Financial Services Cloud Standard' > Add field-level access for all new custom fields > Assign to advisor and admin profiles
Note

Ensure Person Accounts are enabled before starting — this is a one-way activation that cannot be reversed. If the org already has Person Accounts enabled, skip that sub-step. Document all custom field API names in the project wiki for downstream agent configuration.

Step 2: Orion Connect API Integration Setup

Configure the bidirectional sync between Orion Advisor Solutions and Salesforce FSC using the Orion-Salesforce managed package. This establishes the real-time data pipeline that feeds account events to the monitoring agent. The integration syncs portfolio positions, transactions, performance data, and account metadata.

1
Install Orion Connect for Salesforce managed package from Salesforce AppExchange (search 'Orion Connect')
2
Navigate to Orion Connect Setup tab > Enter Orion API credentials (Client ID, Client Secret, API Base URL: https://api.orionadvisor.com/api/v1)
3
Configure field mappings: Orion Account ID → FSC Financial_Account.Orion_Account_ID__c, Orion Portfolio Value → Financial_Account.Balance__c, Orion Cash Balance → Financial_Account.Cash_Balance__c, Orion Drift % → Financial_Account.Drift_Percentage__c
4
Set sync frequency: Full sync daily at 2:00 AM EST, incremental sync every 15 minutes during market hours (9:30 AM – 4:00 PM EST)
5
Test connection: Orion Connect Setup > Test Connection > Verify 'Connection Successful' message
6
Run initial full sync: Orion Connect Setup > Run Full Sync Now > Monitor sync log for errors
Note

The Orion-Salesforce managed package handles OAuth token refresh automatically. If the client uses Black Diamond or Tamarac instead of Orion, substitute the appropriate vendor's Salesforce connector. Allow 2–4 hours for the initial full sync depending on the number of accounts (typically 1,000–10,000 for a mid-size RIA).

Step 3: Azure OpenAI Service Provisioning

Deploy the Azure OpenAI Service instance that will power the natural language reasoning layer of the monitoring agent. This service classifies event severity, generates human-readable alert summaries, and enriches raw data events with contextual advisor guidance. We use GPT-5.4 mini for cost efficiency on structured financial data tasks.

Provision Azure OpenAI Service and deploy GPT-5.4 mini model
bash
az login
az group create --name rg-advisor-ai-prod --location eastus2
az cognitiveservices account create --name advisor-ai-openai-prod --resource-group rg-advisor-ai-prod --kind OpenAI --sku S0 --location eastus2
az cognitiveservices account deployment create --name advisor-ai-openai-prod --resource-group rg-advisor-ai-prod --deployment-name gpt4o-mini-agent --model-name gpt-5.4-mini --model-version 2024-07-18 --model-format OpenAI --sku-capacity 80 --sku-name Standard
az cognitiveservices account keys list --name advisor-ai-openai-prod --resource-group rg-advisor-ai-prod
az cognitiveservices account show --name advisor-ai-openai-prod --resource-group rg-advisor-ai-prod --query properties.endpoint
Note

Store the API key and endpoint in Azure Key Vault (created in next step) — never hardcode credentials. The SKU capacity of 80K TPM (tokens per minute) is sufficient for 10 advisors processing ~50K events/month. Scale up to 150K+ TPM if the firm has >20 advisors. Enable content filtering at the default level to prevent any PII from being stored in Azure OpenAI logs.

Step 4: Azure Key Vault and Credential Management

Create an Azure Key Vault to securely store all API keys, OAuth credentials, and connection strings used by the monitoring agent. This ensures no credentials are hardcoded in Salesforce configuration or agent prompts, meeting SOC 2 and FINRA security requirements.

shell
az keyvault create --name kv-advisor-ai-prod --resource-group rg-advisor-ai-prod --location eastus2 --sku standard
az keyvault secret set --vault-name kv-advisor-ai-prod --name azure-openai-key --value <YOUR_OPENAI_KEY>
az keyvault secret set --vault-name kv-advisor-ai-prod --name azure-openai-endpoint --value <YOUR_OPENAI_ENDPOINT>
az keyvault secret set --vault-name kv-advisor-ai-prod --name orion-client-id --value <ORION_CLIENT_ID>
az keyvault secret set --vault-name kv-advisor-ai-prod --name orion-client-secret --value <ORION_CLIENT_SECRET>
az keyvault secret set --vault-name kv-advisor-ai-prod --name smarsh-api-key --value <SMARSH_API_KEY>
Note

Configure Key Vault access policies to grant read-only secret access to the Salesforce integration service principal only. Enable Key Vault audit logging to Azure Monitor for compliance evidence. Rotate all secrets on a 90-day cycle and document rotation procedures in the runbook.

Step 5: Salesforce Agentforce Agent Configuration

Configure the Agentforce autonomous agent within Salesforce FSC. This involves creating the Agent with its topics, actions, and guardrails. The agent will be triggered by platform events from the Orion data sync and scheduled batch processes, then evaluate account data against configurable thresholds to generate advisor alerts.

1
Navigate to Setup > Agentforce > Agent Builder > New Agent
2
Agent Name: 'Account Monitor Agent', Description: 'Monitors client account events and proactively surfaces concerns to assigned advisor', Channel: Internal (Advisor-facing only)
3
Create Topic: 'Portfolio Drift Monitoring' — Instructions: 'When a Financial Account Drift_Percentage__c exceeds the household threshold, generate a HIGH severity alert to the assigned advisor with the specific securities causing drift and recommended rebalancing action.'
4
Create Topic: 'Cash Balance Alerts' — Instructions: 'When Financial_Account.Cash_Balance__c drops below $10,000 or exceeds $500,000 (configurable per household), generate a MEDIUM severity alert noting potential RMD implications, upcoming fee debits, or uninvested cash drag.'
5
Create Topic: 'Life Event Detection' — Instructions: 'When Account.RMD_Age_Date__c is within 90 days, or Life_Event_Flags__c is updated, generate a HIGH severity alert with recommended advisor talking points and relevant planning considerations.'
6
Create Topic: 'Contact Frequency Monitor' — Instructions: 'When days since Account.Last_Advisor_Contact__c exceeds the Contact_Frequency_Target__c, generate a LOW severity alert recommending outreach with suggested conversation topics based on recent account activity.'
7
Create Topic: 'Concentrated Position Alert' — Instructions: 'When any single holding exceeds 20% of total portfolio value (configurable), generate a HIGH severity alert with diversification talking points and tax-loss harvesting opportunities if applicable.'
8
For each Topic: Add Agentforce Action > 'Query Financial Data' (Data Cloud query), 'Generate Alert Summary' (Azure OpenAI callout via Named Credential), 'Create Task for Advisor' (Salesforce Task creation), 'Log to Compliance Archive' (Smarsh API callout)
Note

Agentforce agents run within the Salesforce trust boundary and respect all sharing rules and field-level security. Ensure the agent's running user profile has read access to Financial Account, Financial Holding, and Person Account objects but NO write access to Financial Holding (prevents any possibility of the agent modifying portfolio data). Test each topic individually before enabling the full agent.

Step 6: Salesforce Named Credentials and External Service Configuration

Configure Named Credentials in Salesforce for secure callouts to Azure OpenAI and Smarsh APIs. Named Credentials handle authentication automatically so that agent actions never expose raw API keys.

1
Setup > Security > Named Credentials > New Named Credential Name: 'Azure_OpenAI_Service', URL: https://advisor-ai-openai-prod.openai.azure.com, Identity Type: Named Principal, Authentication Protocol: Custom Header, Header Name: 'api-key', Header Value: (reference Azure Key Vault secret via External Credential)
2
Setup > Security > Named Credentials > New Named Credential Name: 'Smarsh_Archive_API', URL: https://api.smarsh.com/v2, Identity Type: Named Principal, Authentication Protocol: OAuth 2.0, Authorization Endpoint and Token Endpoint per Smarsh documentation
3
Setup > External Services > New External Service from API Specification Upload OpenAPI spec for Azure OpenAI Chat Completions endpoint (api-version=2024-06-01), map to Named Credential 'Azure_OpenAI_Service'
4
Upload OpenAPI spec for Smarsh Content Ingestion API, map to Named Credential 'Smarsh_Archive_API'
Note

Salesforce Named Credentials automatically inject authentication headers on each callout, eliminating hardcoded secrets. If the firm requires IP whitelisting on the Azure OpenAI side, add the Salesforce org's outbound IP ranges (found in Setup > Company Information > Salesforce IP Ranges for the org's instance).

Step 7: Platform Event and Trigger Configuration

Create Salesforce Platform Events and Apex triggers that fire when account data changes are synced from Orion. These events serve as the real-time input channel for the Agentforce monitoring agent, ensuring the agent evaluates each significant data change within minutes of it occurring.

  • Setup > Platform Events > New Platform Event: 'Account_Event__e'
  • Fields: Account_ID__c (Text), Event_Type__c (Text: picklist values 'DRIFT_CHANGE','CASH_CHANGE','TRANSACTION','PERFORMANCE_CHANGE','HOLDING_CHANGE'), Old_Value__c (Text), New_Value__c (Text), Event_Timestamp__c (DateTime)
  • Setup > Agentforce > Agent Builder > Account Monitor Agent > Triggers > Subscribe to Platform Event 'Account_Event__e'
Create Apex Trigger on Financial_Account__c (after update)
apex
trigger FinancialAccountMonitor on Financial_Account__c (after update) {
  List<Account_Event__e> events = new List<Account_Event__e>();
  for (Financial_Account__c fa : Trigger.new) {
    Financial_Account__c oldFa = Trigger.oldMap.get(fa.Id);
    if (fa.Drift_Percentage__c != oldFa.Drift_Percentage__c) {
      events.add(new Account_Event__e(
        Account_ID__c = fa.Id,
        Event_Type__c = 'DRIFT_CHANGE',
        Old_Value__c = String.valueOf(oldFa.Drift_Percentage__c),
        New_Value__c = String.valueOf(fa.Drift_Percentage__c),
        Event_Timestamp__c = DateTime.now()
      ));
    }
    if (fa.Cash_Balance__c != oldFa.Cash_Balance__c) {
      events.add(new Account_Event__e(
        Account_ID__c = fa.Id,
        Event_Type__c = 'CASH_CHANGE',
        Old_Value__c = String.valueOf(oldFa.Cash_Balance__c),
        New_Value__c = String.valueOf(fa.Cash_Balance__c),
        Event_Timestamp__c = DateTime.now()
      ));
    }
    // Add similar blocks for Performance_Deviation__c, Concentration_Alert__c
  }
  if (!events.isEmpty()) {
    EventBus.publish(events);
  }
}
Note

Platform Events have a daily allocation limit based on Salesforce edition (Enterprise: 250,000/day). A 10-advisor firm with 5,000 accounts updating 5 fields each = ~25,000 events/day during market hours, well within limits. For firms with >20,000 accounts, consider batching events or upgrading to High-Volume Platform Events.

Step 8: Scheduled Batch Jobs for Periodic Monitoring

Configure scheduled Apex batch jobs for monitoring dimensions that don't have real-time data triggers—contact frequency gaps, upcoming life events (RMD dates), and periodic portfolio concentration scans. These run daily outside market hours.

Create Apex Batch Class: ContactFrequencyMonitorBatch
apex
global class ContactFrequencyMonitorBatch implements Database.Batchable<sObject>, Schedulable {
  global Database.QueryLocator start(Database.BatchableContext bc) {
    return Database.getQueryLocator([
      SELECT Id, Name, Last_Advisor_Contact__c, Contact_Frequency_Target__c,
             Owner.Name, Owner.Email
      FROM Account
      WHERE IsPersonAccount = true
      AND Last_Advisor_Contact__c != null
      AND Contact_Frequency_Target__c != null
    ]);
  }
  global void execute(Database.BatchableContext bc, List<Account> scope) {
    List<Account_Event__e> events = new List<Account_Event__e>();
    for (Account a : scope) {
      Integer daysSinceContact = a.Last_Advisor_Contact__c.daysBetween(Date.today());
      Integer targetDays = (Integer)(365 / a.Contact_Frequency_Target__c);
      if (daysSinceContact > targetDays) {
        events.add(new Account_Event__e(
          Account_ID__c = a.Id,
          Event_Type__c = 'CONTACT_GAP',
          Old_Value__c = String.valueOf(daysSinceContact),
          New_Value__c = String.valueOf(targetDays),
          Event_Timestamp__c = DateTime.now()
        ));
      }
    }
    if (!events.isEmpty()) EventBus.publish(events);
  }
  global void finish(Database.BatchableContext bc) {}
  global void execute(SchedulableContext sc) {
    Database.executeBatch(new ContactFrequencyMonitorBatch(), 200);
  }
}
  • Schedule via Setup > Apex Classes > Schedule Apex: ContactFrequencyMonitorBatch, Daily at 6:00 AM EST
  • Create similar batch classes for RMDDateMonitorBatch (scans RMD_Age_Date__c within 90 days) and ConcentrationScanBatch (queries Financial Holdings for >20% single position)
Note

Batch jobs process 200 records at a time to stay within Salesforce governor limits. The contact frequency target field uses annual touches (e.g., 4 = quarterly, 12 = monthly). Adjust the formula (365 / target) based on firm conventions. Schedule all batch jobs between 5:00 AM and 7:00 AM EST to complete before the market opens.

Step 9: Alert Dashboard and Notification Configuration

Build the advisor-facing alert dashboard in Salesforce using Lightning App Builder. Configure multi-channel notification delivery via Salesforce in-app alerts, email digests, and Microsoft Teams push notifications for high-severity items.

text
Setup > Lightning App Builder > New Lightning Page > Record Page for Account (Person Account)
Add 'AI Alert Feed' Lightning Component (custom LWC — see custom_ai_components section) showing filtered alerts by severity
Add 'Account Health Score' Lightning Component showing composite risk metric
Create Lightning Home Page: 'Advisor Command Center' with sections: 'Critical Alerts (High Severity)', 'Action Required (Medium)', 'Informational (Low)', 'Recently Acknowledged'
Setup > Custom Notifications > New Notification Type: 'AI Account Alert', Desktop + Mobile enabled
Setup > Flows > New Flow > 'Alert Notification Router': When Task is created with Subject starting with '[AI Alert]', evaluate Priority field: If High → send Custom Notification + Teams webhook + email; If Medium → send Custom Notification + daily email digest; If Low → in-app only
Configure Microsoft Teams Incoming Webhook: Teams > Channel > Connectors > Incoming Webhook > Copy URL
Setup > Named Credentials > 'Teams_Webhook' > URL: <webhook_url>, Authentication: No Authentication (webhook is self-authenticating)
Note

The Teams webhook provides immediate push notifications to advisor mobile devices for high-severity alerts. Ensure the webhook URL is stored securely. Consider creating separate Teams channels per advisor or per alert severity to prevent notification fatigue. The daily email digest for medium-severity alerts should be sent at 7:30 AM EST so advisors see it before their first client meeting.

Step 10: Smarsh Compliance Archive Integration

Configure automated archiving of all AI agent outputs to Smarsh Professional Archive. Every alert generated, every advisor acknowledgment, and every agent reasoning trace must be captured in WORM-compliant storage per SEC 17a-4 and FINRA Rule 4510.

Create Apex Class: SmarshArchiveService
apex
public class SmarshArchiveService {
  @future(callout=true)
  public static void archiveAlertRecord(String taskId, String alertContent, String agentReasoning, String advisorId, String clientId) {
    HttpRequest req = new HttpRequest();
    req.setEndpoint('callout:Smarsh_Archive_API/content/ingest');
    req.setMethod('POST');
    req.setHeader('Content-Type', 'application/json');
    Map<String, Object> payload = new Map<String, Object>{
      'source' => 'Salesforce-Agentforce',
      'content_type' => 'ai_generated_alert',
      'content' => alertContent,
      'metadata' => new Map<String, Object>{
        'task_id' => taskId,
        'agent_reasoning' => agentReasoning,
        'advisor_id' => advisorId,
        'client_id' => clientId,
        'generated_at' => DateTime.now().formatGMT('yyyy-MM-dd\'T\'HH:mm:ss\'Z\''),
        'classification' => 'SUPERVISORY_REVIEW_REQUIRED'
      }
    };
    req.setBody(JSON.serialize(payload));
    Http http = new Http();
    HttpResponse res = http.send(req);
    if (res.getStatusCode() != 200 && res.getStatusCode() != 201) {
      System.debug(LoggingLevel.ERROR, 'Smarsh archive failed: ' + res.getBody());
      // Create a follow-up task for compliance review
      insert new Task(Subject='[COMPLIANCE] Smarsh Archive Failure - Manual Review Required', OwnerId=getComplianceOfficerId(), Priority='High');
    }
  }
}
1
Add callout to SmarshArchiveService.archiveAlertRecord() in the Agentforce 'Log to Compliance Archive' action
2
Verify in Smarsh admin console that ingested records appear under the 'AI Communications' policy with correct retention period (minimum 6 years per FINRA)
Critical

CRITICAL: If the Smarsh archival callout fails, the system must create a compliance task flagging the failure for manual review. Never silently drop archive records. The 6-year retention minimum applies to broker-dealers under FINRA; RIAs under SEC Rule 204-2 require 5-year retention. Configure the longer period to cover both. Smarsh retention policies should be configured by the compliance officer, not the MSP.

Step 11: Alert Threshold Configuration and Custom Metadata

Create Salesforce Custom Metadata Types to store all configurable alert thresholds. This allows the compliance officer and managing partner to adjust sensitivity without code changes, and provides a clear audit trail of threshold modifications.

  • Setup > Custom Metadata Types > New: 'Alert_Threshold__mdt'
  • Fields: Threshold_Name__c (Text), Category__c (Picklist: Portfolio_Drift, Cash_Balance, Concentration, Performance, Contact_Frequency, Life_Event), Min_Value__c (Number), Max_Value__c (Number), Severity__c (Picklist: High, Medium, Low), Active__c (Checkbox), Last_Modified_By_Name__c (Text)
  • Create record — Portfolio_Drift_High: Category=Portfolio_Drift, Min=5.0, Max=null, Severity=High, Active=true
  • Create record — Cash_Low: Category=Cash_Balance, Min=null, Max=10000, Severity=Medium, Active=true
  • Create record — Cash_High_Uninvested: Category=Cash_Balance, Min=500000, Max=null, Severity=Medium, Active=true
  • Create record — Single_Position_Concentration: Category=Concentration, Min=20.0, Max=null, Severity=High, Active=true
  • Create record — Performance_Deviation: Category=Performance, Min=3.0, Max=null, Severity=Medium, Active=true
  • Create record — Contact_Gap: Category=Contact_Frequency, Min=null, Max=null, Severity=Low, Active=true
  • Create record — RMD_Approaching: Category=Life_Event, Min=90, Max=null, Severity=High, Active=true
  • Create a Custom Metadata Type admin page using Lightning Web Component for the compliance officer to modify thresholds through a user-friendly UI
Note

Custom Metadata Types are deployable between sandboxes and production, making them ideal for threshold management. Changes to Custom Metadata records are tracked in Setup Audit Trail. Review thresholds quarterly with the firm's compliance officer and document any changes in the compliance review log.

Step 12: Security Hardening and Access Controls

Implement defense-in-depth security controls including role-based access, field-level encryption, session security, and network restrictions. This step ensures the implementation meets SOC 2 Type II and FINRA cybersecurity requirements.

  • Setup > Security > Session Settings > Enable: 'Lock sessions to the IP address from which they originated', 'Require HttpOnly attribute', 'Enable clickjack protection'
  • Setup > Security > Login IP Ranges > Restrict advisor profiles to office IP range and VPN IP range
  • Setup > Shield > Platform Encryption > Encrypt fields: Account.Name (Person Account), Financial_Account__c.Balance__c, Financial_Account__c.Cash_Balance__c
  • Setup > Profiles > 'Advisor' Profile > Object Permissions: Financial_Holding__c = Read Only, Financial_Account__c = Read Only (except Last_Advisor_Contact__c = Read/Write), Task = Read/Create/Edit
  • Setup > Profiles > 'AI Agent Service' Profile > Object Permissions: Task = Create, Account_Event__e = Publish/Subscribe, Financial_Account__c = Read Only, Financial_Holding__c = Read Only
  • Setup > Permission Sets > 'Compliance Officer Override' > Full access to Alert_Threshold__mdt, Setup Audit Trail, Task (all operations)
  • FortiGate 40F: Configure SSL inspection policy for outbound traffic to *.salesforce.com and *.openai.azure.com, apply IPS profile 'protect' to WAN-to-LAN policy
Note

Shield Platform Encryption requires the Salesforce Shield add-on ($50–$100/user/month additional). If Shield is not budgeted, use Salesforce Classic Encryption for SSN fields at minimum and document the encryption gap in the risk register. Ensure the AI Agent Service profile has minimal permissions — it should never be able to modify financial data or delete records.

Step 13: User Acceptance Testing in Sandbox

Deploy all configuration to a Salesforce Full Sandbox and execute a comprehensive test plan covering all monitoring topics, alert delivery channels, compliance archiving, and edge cases. This step must be completed and signed off by the firm's compliance officer before production deployment.

1
Setup > Sandboxes > New Sandbox > Type: Full Copy > Name: 'UAT-AI-Monitor'
2
Load test data: Create 50 sample Person Accounts with varying Financial Accounts, Holdings, and date fields to trigger each alert type
3
Execute test scenarios (documented in testing_validation section)
4
Generate UAT sign-off document with compliance officer signature
Deploy to Production via Change Set or Salesforce CLI
shell
sfdx force:source:deploy -p force-app/main/default -u production-org
Note

Full sandbox refreshes can take 24–72 hours for orgs with significant data. Plan accordingly. The compliance officer sign-off is a regulatory requirement — do not deploy to production without written approval. Create a dedicated test data set that covers all threshold boundaries including edge cases (e.g., drift at exactly 5.0%, cash at exactly $10,000).

Step 14: Production Deployment and Go-Live

Deploy the tested configuration to the production Salesforce org, enable the Agentforce agent, activate scheduled batch jobs, and begin the 2-week soft launch monitoring period where alerts are generated but marked as '[PILOT]' for advisor review without action obligation.

1
sfdx force:source:deploy -p force-app/main/default -u production-org --testlevel RunLocalTests
2
Setup > Agentforce > Agent Builder > Account Monitor Agent > Activate
3
Setup > Apex Classes > Schedule Apex: activate ContactFrequencyMonitorBatch, RMDDateMonitorBatch, ConcentrationScanBatch
4
Update all alert Task subjects to include '[PILOT]' prefix during 2-week soft launch
5
Monitor Setup > Agentforce > Agent Analytics for agent execution metrics
6
After 2-week pilot: Review false positive rate with advisors, adjust thresholds, remove '[PILOT]' prefix, transition to full production mode
Note

The 2-week soft launch is critical for tuning alert thresholds and reducing false positives. Target a false positive rate below 15% before transitioning to full production. During the pilot, schedule daily 15-minute check-ins with 2–3 advisors to collect feedback on alert relevance and severity accuracy. Document all threshold adjustments made during the pilot period.

Step 15: Advisor Training and Documentation Delivery

Conduct structured training sessions for all advisors, operations staff, and the compliance officer. Deliver comprehensive documentation including the system operations manual, compliance procedures, and escalation playbook.

1
Schedule 3 training sessions: (1) 90-min advisor training, (2) 60-min ops/admin training, (3) 60-min compliance officer training
2
Record all training sessions via Teams/Zoom for future onboarding of new advisors
3
Upload documentation to SharePoint: Operations Manual, Alert Response Playbook, Compliance Procedures, Threshold Configuration Guide, Escalation Matrix
4
Create Salesforce In-App Guidance: Setup > In-App Guidance > New Prompt > Create step-by-step walkthrough for acknowledging and responding to AI alerts
5
Send training completion confirmation email to managing partner with sign-off request
Note

Schedule advisor training during a low-activity period (e.g., Friday afternoon). Emphasize that the AI agent is a tool that surfaces concerns — all investment decisions and client communications remain the advisor's responsibility. This distinction is critical for Reg BI compliance. Leave behind printed quick-reference cards for each advisor's desk with the alert severity color codes and response expectations.

Custom AI Components

Account Event Classifier Agent Topic

Type: agent The core Agentforce topic that receives raw account events from the Platform Event bus, classifies them by type and severity using configurable thresholds and Azure OpenAI reasoning, and routes them to the appropriate alert generation action. This is the central intelligence of the monitoring system.

Implementation:

Agentforce Topic Configuration: Account Event Classifier

  • Topic Name: Account Event Classifier
  • Description: Classifies incoming account events and determines alert severity

Natural Language Instructions (Agentforce Topic Builder)

You are an account monitoring assistant for a Registered Investment Advisory firm. Your role is to evaluate account events and determine if they warrant an advisor alert. ## RULES: 1. You NEVER communicate with clients directly 2. You NEVER make investment recommendations 3. You NEVER modify portfolio holdings or execute trades 4. You ALWAYS create alerts as Tasks assigned to the account's assigned advisor 5. You ALWAYS log every evaluation to the compliance archive, even if no alert is generated 6. You reference threshold values from Alert_Threshold__mdt custom metadata ## EVENT EVALUATION LOGIC: When you receive an Account_Event__e: ### DRIFT_CHANGE Events: - Query Alert_Threshold__mdt WHERE Category__c = 'Portfolio_Drift' AND Active__c = true - If New_Value__c (as decimal) >= threshold Min_Value__c: - Severity = threshold Severity__c - Query Financial_Holding__c records for the Financial Account to identify top 3 holdings causing drift - Call Azure OpenAI to generate a 2-3 sentence summary including: current drift %, target allocation, specific securities over/underweight, and suggested rebalancing consideration - Create Task with Subject '[AI Alert] Portfolio Drift: {Account Name} at {drift}%' ### CASH_CHANGE Events: - Query both Cash_Low and Cash_High_Uninvested thresholds - If New_Value__c < Cash_Low Max_Value__c OR New_Value__c > Cash_High_Uninvested Min_Value__c: - Check if account has upcoming scheduled distributions or fee debits in next 30 days - Call Azure OpenAI to generate context-aware summary - Create Task with appropriate severity ### CONTACT_GAP Events: - Always create a Low severity task - Include days since last contact and the contact frequency target - Call Azure OpenAI to suggest 2-3 conversation topics based on recent account activity ### CONCENTRATION Events: - Query Financial_Holding__c for the account, calculate each holding as % of total portfolio - If any single holding > threshold Min_Value__c (default 20%): - Flag with High severity - Include tax lot information if available for tax-loss harvesting context ### LIFE_EVENT Events (RMD approaching, etc.): - High severity for RMD within 90 days - Include applicable deadlines and penalty information - Suggest scheduling a planning meeting
Sonnet 4.6

Azure OpenAI System Prompt

You are a financial advisory assistant generating concise alert summaries for wealth advisors. Be factual and specific. Never make investment recommendations. Always note that the advisor should review and determine appropriate action.
Sonnet 4.6

Azure OpenAI User Prompt Template

Generate a concise alert summary for the following account event: Client: {name} Event Type: {type} Details: {details} Relevant Holdings: {holdings} Recent Activity: {recent_transactions} Provide: (1) A one-sentence summary of the concern, (2) Key data points the advisor should review, (3) A suggested next step (e.g., schedule review meeting, review allocation, contact client).
Sonnet 4.6
  • Max tokens: 300
  • Temperature: 0.2 (low creativity, high factual consistency)

Alert Summary Generator (Azure OpenAI Prompt)

Type: prompt The system and user prompt templates used for Azure OpenAI GPT-5.4 mini calls to generate human-readable, compliance-safe alert summaries from raw account event data. Designed for low temperature to ensure factual, consistent output.

Implementation:

Azure OpenAI API configuration parameters
yaml
# Azure OpenAI Prompt Configuration
# Model: gpt-5.4-mini (deployment: gpt4o-mini-agent)
# API Version: 2024-06-01
# Temperature: 0.2
# Max Tokens: 300
# Top P: 0.9

System Prompt

You are a compliance-aware financial advisory alert assistant. You generate concise, factual alert summaries for Registered Investment Advisors. STRICT RULES: - NEVER make specific investment recommendations (e.g., never say 'sell AAPL' or 'buy bonds') - NEVER predict market movements or future performance - NEVER use language that could be construed as personalized investment advice under SEC Reg BI - ALWAYS frame observations as 'considerations for advisor review' - ALWAYS include a disclaimer: 'This alert is for informational purposes. The advisor should review and determine appropriate action based on the client's complete financial picture.' - Be specific with numbers: use actual percentages, dollar amounts, and dates from the provided data - Keep summaries under 200 words - Use professional, measured tone appropriate for a compliance-reviewed communication
Sonnet 4.6

User Prompt Template — Portfolio Drift Alert

Generate an alert summary for the following portfolio drift event: - Client Household: {{client_name}} - Account: {{account_number}} ({{account_type}}) - Current Drift: {{drift_percentage}}% from target allocation - Target Allocation: {{target_allocation_summary}} - Top Drift Contributors: {{#each drift_contributors}} - {{security_name}} ({{ticker}}): Target {{target_pct}}% / Actual {{actual_pct}}% ({{direction}} by {{deviation_pct}}%) {{/each}} - Last Rebalanced: {{last_rebalance_date}} - Account Value: ${{account_value}} Provide: (1) One-sentence concern summary, (2) Key data points for review, (3) Suggested next step.
Sonnet 4.6

User Prompt Template — Cash Balance Alert

Generate an alert summary for the following cash balance event: - Client Household: {{client_name}} - Account: {{account_number}} ({{account_type}}) - Current Cash Balance: ${{cash_balance}} - Previous Cash Balance: ${{previous_cash_balance}} - Threshold Triggered: {{threshold_type}} (${{threshold_value}}) - Upcoming Scheduled Distributions: {{upcoming_distributions}} - Account Value: ${{account_value}} - Cash as % of Portfolio: {{cash_percentage}}% Provide: (1) One-sentence concern summary, (2) Key data points for review, (3) Suggested next step.
Sonnet 4.6

User Prompt Template — Concentrated Position Alert

Generate an alert summary for the following concentration event: - Client Household: {{client_name}} - Account: {{account_number}} ({{account_type}}) - Concentrated Security: {{security_name}} ({{ticker}}) - Position Value: ${{position_value}} - Portfolio Percentage: {{concentration_pct}}% - Threshold: {{threshold_pct}}% - Unrealized Gain/Loss: ${{unrealized_gl}} ({{gl_percentage}}%) - Holding Period: {{holding_period}} - Account Value: ${{account_value}} Provide: (1) One-sentence concern summary, (2) Key data points for review including tax implications, (3) Suggested next step.
Sonnet 4.6

User Prompt Template — Contact Frequency Gap Alert

Generate an alert summary for the following contact gap: - Client Household: {{client_name}} - Assigned Advisor: {{advisor_name}} - Days Since Last Contact: {{days_since_contact}} - Contact Frequency Target: {{target_frequency}} touches/year - Last Contact Type: {{last_contact_type}} on {{last_contact_date}} - Recent Account Activity: {{#each recent_activity}} - {{date}}: {{description}} {{/each}} - AUM: ${{total_aum}} Provide: (1) One-sentence outreach reminder, (2) 2-3 suggested conversation topics based on recent activity, (3) Suggested outreach method.
Sonnet 4.6

User Prompt Template — Life Event (RMD) Alert

Generate an alert summary for the following RMD milestone: - Client: {{client_name}} (DOB: {{date_of_birth}}) - RMD Age Milestone: {{rmd_age}} reached on {{rmd_date}} - Days Until Deadline: {{days_until_deadline}} - Applicable Accounts: {{#each rmd_accounts}} - {{account_type}} {{account_number}}: Balance ${{balance}}, Estimated RMD ${{estimated_rmd}} {{/each}} - Beneficiary Designations Current: {{beneficiary_current}} Provide: (1) One-sentence urgency summary, (2) Key deadlines and penalty information, (3) Suggested planning meeting agenda items.
Sonnet 4.6

AI Alert Feed Lightning Web Component

Type: integration A custom Lightning Web Component (LWC) that displays the AI-generated alert feed on the advisor's Person Account record page and Home page. Shows alerts color-coded by severity with acknowledge/dismiss/escalate actions, and tracks response times for compliance reporting.

Implementation:

aiAlertFeed.html
html
<!-- LWC template with severity filter buttons and alert action controls -->

<!-- aiAlertFeed.html -->
<template>
  <lightning-card title="AI Account Alerts" icon-name="standard:task">
    <div slot="actions">
      <lightning-button-group>
        <lightning-button label="All" onclick={filterAll} variant={allVariant}></lightning-button>
        <lightning-button label="High" onclick={filterHigh} variant={highVariant}></lightning-button>
        <lightning-button label="Medium" onclick={filterMedium} variant={mediumVariant}></lightning-button>
        <lightning-button label="Low" onclick={filterLow} variant={lowVariant}></lightning-button>
      </lightning-button-group>
    </div>
    <div class="slds-p-around_medium">
      <template if:true={alerts}>
        <template for:each={filteredAlerts} for:item="alert">
          <div key={alert.Id} class={alert.severityClass}>
            <div class="slds-grid slds-gutters">
              <div class="slds-col slds-size_1-of-12">
                <lightning-icon icon-name={alert.iconName} size="small" variant={alert.iconVariant}></lightning-icon>
              </div>
              <div class="slds-col slds-size_8-of-12">
                <p class="slds-text-heading_small">{alert.Subject}</p>
                <p class="slds-text-body_small slds-text-color_weak">{alert.formattedDate} | {alert.clientName}</p>
                <p class="slds-m-top_xx-small">{alert.Description}</p>
              </div>
              <div class="slds-col slds-size_3-of-12 slds-text-align_right">
                <lightning-button-group>
                  <lightning-button label="Acknowledge" onclick={handleAcknowledge} data-id={alert.Id} variant="brand" size="small"></lightning-button>
                  <lightning-button label="Dismiss" onclick={handleDismiss} data-id={alert.Id} size="small"></lightning-button>
                  <lightning-button label="Escalate" onclick={handleEscalate} data-id={alert.Id} variant="destructive" size="small"></lightning-button>
                </lightning-button-group>
              </div>
            </div>
          </div>
        </template>
      </template>
      <template if:false={alerts}>
        <div class="slds-align_absolute-center slds-p-around_large">
          <p class="slds-text-color_weak">No active alerts. All accounts are within normal parameters.</p>
        </div>
      </template>
    </div>
  </lightning-card>
</template>
aiAlertFeed.js
javascript
// LWC controller with wire adapter, filtering logic, and
// acknowledge/dismiss/escalate handlers

// aiAlertFeed.js
import { LightningElement, api, wire, track } from 'lwc';
import getAlerts from '@salesforce/apex/AIAlertController.getAlerts';
import acknowledgeAlert from '@salesforce/apex/AIAlertController.acknowledgeAlert';
import dismissAlert from '@salesforce/apex/AIAlertController.dismissAlert';
import escalateAlert from '@salesforce/apex/AIAlertController.escalateAlert';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { refreshApex } from '@salesforce/apex';

export default class AiAlertFeed extends LightningElement {
  @api recordId; // Person Account Id (when on record page) or null (when on home page)
  @track alerts;
  @track activeFilter = 'All';
  wiredAlertsResult;

  @wire(getAlerts, { accountId: '$recordId' })
  wiredAlerts(result) {
    this.wiredAlertsResult = result;
    if (result.data) {
      this.alerts = result.data.map(alert => ({
        ...alert,
        severityClass: this.getSeverityClass(alert.Priority),
        iconName: this.getIconName(alert.Priority),
        iconVariant: alert.Priority === 'High' ? 'error' : alert.Priority === 'Normal' ? 'warning' : '',
        formattedDate: new Date(alert.CreatedDate).toLocaleDateString(),
        clientName: alert.What ? alert.What.Name : ''
      }));
    }
  }

  get filteredAlerts() {
    if (!this.alerts) return [];
    if (this.activeFilter === 'All') return this.alerts;
    const priorityMap = { 'High': 'High', 'Medium': 'Normal', 'Low': 'Low' };
    return this.alerts.filter(a => a.Priority === priorityMap[this.activeFilter]);
  }

  getSeverityClass(priority) {
    const classes = {
      'High': 'slds-box slds-m-bottom_small slds-theme_error slds-theme_alert-texture',
      'Normal': 'slds-box slds-m-bottom_small slds-theme_warning',
      'Low': 'slds-box slds-m-bottom_small slds-theme_info'
    };
    return classes[priority] || 'slds-box slds-m-bottom_small';
  }

  getIconName(priority) {
    const icons = { 'High': 'utility:error', 'Normal': 'utility:warning', 'Low': 'utility:info' };
    return icons[priority] || 'utility:info';
  }

  filterAll() { this.activeFilter = 'All'; }
  filterHigh() { this.activeFilter = 'High'; }
  filterMedium() { this.activeFilter = 'Medium'; }
  filterLow() { this.activeFilter = 'Low'; }

  get allVariant() { return this.activeFilter === 'All' ? 'brand' : 'neutral'; }
  get highVariant() { return this.activeFilter === 'High' ? 'destructive' : 'neutral'; }
  get mediumVariant() { return this.activeFilter === 'Medium' ? 'brand' : 'neutral'; }
  get lowVariant() { return this.activeFilter === 'Low' ? 'brand' : 'neutral'; }

  async handleAcknowledge(event) {
    const taskId = event.target.dataset.id;
    try {
      await acknowledgeAlert({ taskId });
      this.showToast('Alert Acknowledged', 'The alert has been acknowledged and logged.', 'success');
      return refreshApex(this.wiredAlertsResult);
    } catch (error) {
      this.showToast('Error', error.body.message, 'error');
    }
  }

  async handleDismiss(event) {
    const taskId = event.target.dataset.id;
    try {
      await dismissAlert({ taskId });
      this.showToast('Alert Dismissed', 'The alert has been dismissed and logged for compliance.', 'info');
      return refreshApex(this.wiredAlertsResult);
    } catch (error) {
      this.showToast('Error', error.body.message, 'error');
    }
  }

  async handleEscalate(event) {
    const taskId = event.target.dataset.id;
    try {
      await escalateAlert({ taskId });
      this.showToast('Alert Escalated', 'The alert has been escalated to the compliance officer.', 'warning');
      return refreshApex(this.wiredAlertsResult);
    } catch (error) {
      this.showToast('Error', error.body.message, 'error');
    }
  }

  showToast(title, message, variant) {
    this.dispatchEvent(new ShowToastEvent({ title, message, variant }));
  }
}
AIAlertController.cls
apex
# Apex controller with SOQL alert query and acknowledge/dismiss/escalate
# methods with Smarsh archiving

// AIAlertController.cls (Apex Controller)
public with sharing class AIAlertController {
  @AuraEnabled(cacheable=true)
  public static List<Task> getAlerts(Id accountId) {
    String query = 'SELECT Id, Subject, Description, Priority, Status, CreatedDate, What.Name, WhatId '
      + 'FROM Task WHERE Subject LIKE \'[AI Alert]%\' AND Status != \'Completed\' ';
    if (accountId != null) {
      query += 'AND WhatId = :accountId ';
    }
    query += 'ORDER BY CASE WHEN Priority = \'High\' THEN 1 WHEN Priority = \'Normal\' THEN 2 ELSE 3 END, CreatedDate DESC LIMIT 100';
    return Database.query(query);
  }

  @AuraEnabled
  public static void acknowledgeAlert(Id taskId) {
    Task t = [SELECT Id, Subject, Description, OwnerId, WhatId FROM Task WHERE Id = :taskId];
    t.Status = 'Completed';
    t.Description += '\n\n--- ACKNOWLEDGED by ' + UserInfo.getName() + ' at ' + DateTime.now().format() + ' ---';
    update t;
    // Archive acknowledgment to Smarsh
    SmarshArchiveService.archiveAlertRecord(taskId, t.Description, 'ACKNOWLEDGED', UserInfo.getUserId(), t.WhatId);
  }

  @AuraEnabled
  public static void dismissAlert(Id taskId) {
    Task t = [SELECT Id, Subject, Description, OwnerId, WhatId FROM Task WHERE Id = :taskId];
    t.Status = 'Completed';
    t.Description += '\n\n--- DISMISSED by ' + UserInfo.getName() + ' at ' + DateTime.now().format() + ' (Reason: Advisor reviewed, no action required) ---';
    update t;
    SmarshArchiveService.archiveAlertRecord(taskId, t.Description, 'DISMISSED', UserInfo.getUserId(), t.WhatId);
  }

  @AuraEnabled
  public static void escalateAlert(Id taskId) {
    Task t = [SELECT Id, Subject, Description, OwnerId, WhatId FROM Task WHERE Id = :taskId];
    // Reassign to compliance officer
    User complianceOfficer = [SELECT Id FROM User WHERE Profile.Name = 'Compliance Officer' LIMIT 1];
    t.OwnerId = complianceOfficer.Id;
    t.Priority = 'High';
    t.Description += '\n\n--- ESCALATED by ' + UserInfo.getName() + ' at ' + DateTime.now().format() + ' ---';
    update t;
    SmarshArchiveService.archiveAlertRecord(taskId, t.Description, 'ESCALATED', UserInfo.getUserId(), t.WhatId);
  }
}

Compliance Audit Trail Reporter

Type: workflow A Salesforce scheduled Flow that runs weekly to generate a compliance summary report of all AI agent activity—alerts generated, advisor response times, escalations, dismissals, and any Smarsh archival failures. The report is emailed to the Chief Compliance Officer and stored in SharePoint.

Implementation:

Salesforce Flow Configuration: Weekly Compliance Audit Report
plaintext
# Salesforce Flow Configuration: Weekly Compliance Audit Report
# Type: Schedule-Triggered Flow
# Schedule: Every Monday at 7:00 AM EST

## Flow Steps:

### 1. Get Alert Tasks (Get Records)
- Object: Task
- Filter: Subject LIKE '[AI Alert]%' AND CreatedDate = LAST_WEEK
- Store in: varAllAlerts

### 2. Loop Through Alerts (Loop)
- Collection: varAllAlerts
- For each: varCurrentAlert

### 3. Decision: Categorize by Status
- If Status = 'Completed' AND Description CONTAINS 'ACKNOWLEDGED' → Increment varAcknowledgedCount
- If Status = 'Completed' AND Description CONTAINS 'DISMISSED' → Increment varDismissedCount
- If Description CONTAINS 'ESCALATED' → Increment varEscalatedCount
- If Status != 'Completed' → Increment varUnresolvedCount

### 4. Calculate Response Metrics (Assignment)
- varAvgResponseTime = Calculate average time between CreatedDate and completion timestamp (parsed from Description)
- varHighSeverityCount = Count where Priority = 'High'
- varMediumSeverityCount = Count where Priority = 'Normal'
- varLowSeverityCount = Count where Priority = 'Low'

### 5. Get Archive Failures (Get Records)
- Object: Task
- Filter: Subject LIKE '[COMPLIANCE] Smarsh Archive Failure%' AND CreatedDate = LAST_WEEK
- Store in: varArchiveFailures

### 6. Build Report Email (Action: Send Email)
To: {Compliance Officer Email}
CC: {Managing Partner Email}
Subject: '[AI Monitor] Weekly Compliance Report - Week of {LAST_MONDAY_DATE}'

Body Template:
---
AI ACCOUNT MONITORING - WEEKLY COMPLIANCE SUMMARY
Report Period: {LAST_MONDAY} - {LAST_SUNDAY}
Generated: {TODAY} at {NOW}

ALERT SUMMARY
- Total Alerts Generated: {varAllAlerts.size}
- High Severity: {varHighSeverityCount}
- Medium Severity: {varMediumSeverityCount}
- Low Severity: {varLowSeverityCount}

ADVISOR RESPONSE
- Acknowledged: {varAcknowledgedCount}
- Dismissed: {varDismissedCount}
- Escalated to Compliance: {varEscalatedCount}
- Unresolved (>7 days): {varUnresolvedCount}
- Average Response Time: {varAvgResponseTime} hours

COMPLIANCE ARCHIVE STATUS
- Smarsh Archive Failures This Week: {varArchiveFailures.size}
- Action Required: {IF(varArchiveFailures.size > 0, 'YES - Review failed archives immediately', 'None')}

ATTENTION ITEMS
{IF(varUnresolvedCount > 0, '⚠ ' + varUnresolvedCount + ' alerts remain unresolved and require supervisor follow-up per FINRA 3110', '')}
{IF(varEscalatedCount > 0, '⚠ ' + varEscalatedCount + ' alerts were escalated - review required', '')}
{IF(varArchiveFailures.size > 0, '🔴 CRITICAL: ' + varArchiveFailures.size + ' archive failures detected - SEC 17a-4 compliance at risk', '')}

This report is auto-generated by the AI Account Monitor system.
All underlying data is archived in Smarsh Professional Archive.
---

### 7. Create Compliance Task if Issues Found (Decision + Create Records)
- If varUnresolvedCount > 5 OR varArchiveFailures.size > 0:
  - Create Task: Subject = '[COMPLIANCE] Weekly AI Monitor Review Required'
  - Owner = Compliance Officer
  - Priority = High
  - Due Date = This Friday

Orion Data Sync Health Monitor

Type: workflow A Salesforce Flow that monitors the health of the Orion Connect data sync, detecting stale data, sync failures, or unexpected data gaps. If the Orion sync has not updated for >2 hours during market hours, it alerts the MSP support team to investigate.

Implementation:

Salesforce Flow Configuration: Orion Sync Health Monitor
plaintext
# Salesforce Flow Configuration: Orion Sync Health Monitor
# Type: Schedule-Triggered Flow
# Schedule: Every 30 minutes, Monday-Friday, 9:00 AM - 5:00 PM EST

## Flow Steps:

### 1. Get Most Recent Sync Record (Get Records)
- Object: Orion_Sync_Log__c (custom object created by Orion Connect package, or query SystemModstamp on Financial_Account__c)
- Sort: LastModifiedDate DESC
- Limit: 1
- Store in: varLastSync

### 2. Calculate Staleness (Assignment)
- varMinutesSinceSync = ({NOW} - varLastSync.LastModifiedDate) * 24 * 60

### 3. Decision: Is Data Stale?
- If varMinutesSinceSync > 120 (2 hours during market hours):
  → Path: Alert MSP
- If varMinutesSinceSync > 30 AND varMinutesSinceSync <= 120:
  → Path: Warning (log only)
- Else:
  → Path: Healthy (exit)

### 4. Alert MSP (Send Email + Create Task)
- Send email to MSP support distribution list
- Subject: '[CRITICAL] Orion Data Sync Stale - {CLIENT_ORG_NAME}'
- Body: 'The Orion Connect data sync has not updated Financial Account records in {varMinutesSinceSync} minutes. Last sync: {varLastSync.LastModifiedDate}. AI monitoring alerts may be based on stale data. Immediate investigation required.'
- Create Task: Owner = MSP Admin User, Subject = '[SYNC ALERT] Orion data sync investigation needed', Priority = High

### 5. Post to Teams Channel (HTTP Callout)
- Method: POST
- URL: callout:Teams_Webhook
- Body: {"text": "🔴 ORION SYNC ALERT: Data sync for {CLIENT_NAME} has been stale for {varMinutesSinceSync} minutes. Last update: {varLastSync.LastModifiedDate}. The AI monitoring agent may be generating alerts based on outdated data. Please investigate immediately."}

## Custom Object (if not provided by Orion package):
- Object: Orion_Sync_Log__c
- Fields: Sync_Type__c (Full/Incremental), Records_Processed__c (Number), Errors__c (Long Text), Status__c (Success/Partial/Failed), Started_At__c (DateTime), Completed_At__c (DateTime)

Teams Alert Notification Dispatcher

Type: integration An Apex class that sends formatted alert notifications to Microsoft Teams via Incoming Webhook when high-severity AI alerts are generated. Includes adaptive card formatting with action buttons for the advisor to acknowledge directly from Teams.

Implementation:

TeamsNotificationService.cls
apex
# Apex class for sending adaptive card alerts to Microsoft Teams via
# Incoming Webhook, with an invocable wrapper for Agentforce Flow/Agent
# actions

// TeamsNotificationService.cls
public class TeamsNotificationService {

  @future(callout=true)
  public static void sendHighSeverityAlert(String alertSubject, String alertDescription, String advisorName, String clientName, String accountId, String taskId) {
    HttpRequest req = new HttpRequest();
    req.setEndpoint('callout:Teams_Webhook');
    req.setMethod('POST');
    req.setHeader('Content-Type', 'application/json');

    // Adaptive Card payload for Teams
    Map<String, Object> card = new Map<String, Object>{
      'type' => 'message',
      'attachments' => new List<Object>{
        new Map<String, Object>{
          'contentType' => 'application/vnd.microsoft.card.adaptive',
          'contentUrl' => null,
          'content' => new Map<String, Object>{
            '$schema' => 'http://adaptivecards.io/schemas/adaptive-card.json',
            'type' => 'AdaptiveCard',
            'version' => '1.4',
            'body' => new List<Object>{
              new Map<String, Object>{
                'type' => 'TextBlock',
                'text' => '🔴 HIGH SEVERITY AI ALERT',
                'weight' => 'Bolder',
                'size' => 'Large',
                'color' => 'Attention'
              },
              new Map<String, Object>{
                'type' => 'FactSet',
                'facts' => new List<Object>{
                  new Map<String, String>{'title' => 'Client', 'value' => clientName},
                  new Map<String, String>{'title' => 'Advisor', 'value' => advisorName},
                  new Map<String, String>{'title' => 'Alert', 'value' => alertSubject},
                  new Map<String, String>{'title' => 'Time', 'value' => DateTime.now().format('MM/dd/yyyy hh:mm a z')}
                }
              },
              new Map<String, Object>{
                'type' => 'TextBlock',
                'text' => alertDescription,
                'wrap' => true
              }
            },
            'actions' => new List<Object>{
              new Map<String, Object>{
                'type' => 'Action.OpenUrl',
                'title' => 'Open in Salesforce',
                'url' => URL.getOrgDomainUrl().toExternalForm() + '/lightning/r/Task/' + taskId + '/view'
              }
            }
          }
        }
      }
    };

    req.setBody(JSON.serialize(card));
    Http http = new Http();
    HttpResponse res = http.send(req);

    if (res.getStatusCode() != 200) {
      System.debug(LoggingLevel.ERROR, 'Teams notification failed: ' + res.getStatusCode() + ' - ' + res.getBody());
    }
  }
}

// Integration with Agentforce: Add invocable method for Flow/Agent actions
public class TeamsNotificationInvocable {
  @InvocableMethod(label='Send Teams Alert' description='Sends a high-severity alert to Microsoft Teams')
  public static void sendAlert(List<TeamsAlertRequest> requests) {
    for (TeamsAlertRequest req : requests) {
      TeamsNotificationService.sendHighSeverityAlert(
        req.alertSubject, req.alertDescription, req.advisorName, req.clientName, req.accountId, req.taskId
      );
    }
  }

  public class TeamsAlertRequest {
    @InvocableVariable(required=true) public String alertSubject;
    @InvocableVariable(required=true) public String alertDescription;
    @InvocableVariable(required=true) public String advisorName;
    @InvocableVariable(required=true) public String clientName;
    @InvocableVariable public String accountId;
    @InvocableVariable(required=true) public String taskId;
  }
}

Testing & Validation

  • PORTFOLIO DRIFT TEST: In sandbox, update a Financial Account's Drift_Percentage__c from 3.0 to 6.5 (exceeding the 5.0% threshold). Verify within 5 minutes: (1) Platform Event Account_Event__e is published, (2) Agentforce agent evaluates the event, (3) Azure OpenAI generates a summary mentioning the specific securities causing drift, (4) A Task with Subject '[AI Alert] Portfolio Drift: {Client Name} at 6.5%' and Priority=High is created and assigned to the correct advisor, (5) The alert appears in the AI Alert Feed LWC, (6) A record is ingested into Smarsh archive.
  • CASH BALANCE LOW TEST: Update a Financial Account's Cash_Balance__c to $7,500 (below the $10,000 threshold). Verify a Medium severity alert is generated mentioning the low cash balance and any upcoming scheduled distributions.
  • CASH BALANCE HIGH TEST: Update a Financial Account's Cash_Balance__c to $650,000 (above the $500,000 threshold). Verify a Medium severity alert is generated mentioning potential cash drag and investment opportunity.
  • CONCENTRATED POSITION TEST: Create Financial Holding records where one holding represents 25% of total account value. Run the ConcentrationScanBatch manually. Verify a High severity alert is generated identifying the concentrated security with unrealized gain/loss context.
  • CONTACT FREQUENCY GAP TEST: Set a Person Account's Last_Advisor_Contact__c to 120 days ago with Contact_Frequency_Target__c = 4 (quarterly = 91 days). Run ContactFrequencyMonitorBatch manually. Verify a Low severity alert with conversation topic suggestions is generated.
  • RMD LIFE EVENT TEST: Set a Person Account's RMD_Age_Date__c to 60 days from today. Run RMDDateMonitorBatch manually. Verify a High severity alert is generated with RMD deadline information and penalty warnings.
  • ALERT ACKNOWLEDGE TEST: Click 'Acknowledge' on an alert in the AI Alert Feed LWC. Verify: (1) Task Status changes to 'Completed', (2) Description is appended with acknowledgment timestamp and advisor name, (3) Smarsh archiveAlertRecord is called with 'ACKNOWLEDGED' status, (4) Alert disappears from the active feed.
  • ALERT ESCALATE TEST: Click 'Escalate' on an alert. Verify: (1) Task is reassigned to the Compliance Officer user, (2) Priority is set to High, (3) Smarsh receives the escalation record, (4) Compliance officer receives a notification.
  • TEAMS NOTIFICATION TEST: Generate a High severity alert and verify: (1) An adaptive card appears in the configured Teams channel within 60 seconds, (2) The card displays client name, advisor name, alert subject, and timestamp, (3) The 'Open in Salesforce' button navigates to the correct Task record.
  • SMARSH ARCHIVE FAILURE TEST: Temporarily modify the Smarsh Named Credential to an invalid endpoint. Generate an alert. Verify: (1) The alert Task is still created for the advisor (archive failure does not block alert delivery), (2) A separate compliance Task '[COMPLIANCE] Smarsh Archive Failure' is created and assigned to the compliance officer, (3) Restore the correct endpoint and verify normal archiving resumes.
  • ORION SYNC HEALTH TEST: Stop the Orion data sync (disable the sync schedule). Wait 2.5 hours during market hours. Verify: (1) The Orion Sync Health Monitor flow triggers, (2) An email is sent to the MSP support distribution list, (3) A Teams notification appears in the MSP support channel, (4) A high-priority Task is created for investigation.
  • THRESHOLD MODIFICATION TEST: Have the compliance officer modify the Portfolio_Drift threshold from 5.0% to 3.0% via the Custom Metadata admin UI. Verify: (1) The change is reflected in Setup Audit Trail, (2) Subsequent drift evaluations use the new 3.0% threshold, (3) Accounts between 3.0-5.0% drift that were previously below threshold now generate alerts.
  • SECURITY ACCESS TEST: Log in as an advisor user and attempt to: (1) modify a Financial Holding record (should be blocked - read only), (2) access another advisor's alerts (should only see own alerts if sharing rules configured), (3) modify Alert_Threshold__mdt records (should be blocked - compliance officer only). All three should fail with appropriate permission errors.
  • LOAD TEST: Generate 500 simultaneous Financial Account updates in sandbox to simulate end-of-day batch sync from Orion. Verify: (1) All platform events are published without governor limit failures, (2) The Agentforce agent processes all events within 30 minutes, (3) No duplicate alerts are created for the same account/event type, (4) Azure OpenAI API does not return rate limit errors (429 status).
  • END-TO-END COMPLIANCE REVIEW: After all tests, export the Smarsh archive for the test period. Verify: (1) Every alert generated has a corresponding archive record, (2) Every advisor action (acknowledge/dismiss/escalate) has a corresponding archive record, (3) Archive records include agent reasoning traces, (4) Retention policy is set to minimum 6 years.

Client Handoff

Client Handoff Agenda (Half-Day Session)

Session 1: Advisor Training (90 minutes)

  • Dashboard Walkthrough: Navigate the Advisor Command Center home page, explain alert severity color coding (Red=High/immediate review, Yellow=Medium/review within 24h, Blue=Low/informational), demonstrate filtering by severity and client
  • Alert Response Workflow: Practice acknowledging, dismissing, and escalating alerts using the AI Alert Feed LWC. Emphasize that dismissing an alert still logs it to the compliance archive — nothing is truly deleted
  • Teams Notifications: Show how high-severity alerts appear on mobile devices via Teams, demonstrate the 'Open in Salesforce' button
  • What the Agent Does and Does NOT Do: Critical distinction — the agent monitors and surfaces concerns, it NEVER contacts clients, it NEVER executes trades, it NEVER provides investment advice. All alerts are suggestions for the advisor to evaluate in context of the complete client relationship
  • Hands-on Practice: Each advisor processes 5 sample alerts of varying severity with trainer guidance

Session 2: Operations/Admin Training (60 minutes)

  • Threshold Management: How to view and modify alert thresholds via the Custom Metadata admin page (compliance officer approval required for changes)
  • Orion Sync Monitoring: How to check sync health, what to do if sync alerts are received
  • User Management: Adding new advisors, assigning accounts, configuring contact frequency targets
  • Basic Troubleshooting: Common issues (stale data, missing alerts, duplicate alerts) and escalation to MSP

Session 3: Compliance Officer Training (60 minutes)

  • Weekly Compliance Report Review: Walk through a sample report, explain each metric, discuss acceptable thresholds for response times and unresolved alerts
  • Audit Trail Access: How to access Setup Audit Trail for threshold changes, how to pull Smarsh archive reports for examiner requests
  • Supervisory Procedures Update: Review the updated Written Supervisory Procedures addendum that documents AI agent governance, review cadence, and escalation procedures
  • FINRA/SEC Exam Preparation: What to expect when examiners ask about AI use — documentation locations, sample responses, evidence of human oversight

Documentation Deliverables:

1
System Operations Manual (PDF + SharePoint) — 30-page guide covering architecture, data flow, alert types, troubleshooting
2
Advisor Quick Reference Card (laminated, desk-ready) — One-page alert response guide with severity codes and expected response times
3
Compliance Procedures Addendum (Word, attorney-reviewable) — WSP addendum documenting AI agent oversight requirements per FINRA 3110
4
Escalation Matrix (one-page) — Who to call for what: MSP support for technical issues, compliance officer for regulatory concerns, vendor contacts for platform issues
5
Threshold Configuration Guide (PDF) — Step-by-step instructions for modifying alert thresholds with change management process
6
Recorded Training Videos (SharePoint) — All three training sessions recorded for new hire onboarding

Success Criteria Review:

Maintenance

Ongoing MSP Maintenance Responsibilities

Daily (Automated + Spot Check)

  • Orion Sync Health Monitor: Automated flow runs every 30 minutes during market hours. MSP receives alerts for any sync interruption >2 hours. Spot check the sync log dashboard weekly.
  • Agent Execution Monitor: Review Agentforce Agent Analytics daily during the first month, then weekly. Watch for: execution failures, timeout errors, API callout failures to Azure OpenAI or Smarsh.
  • Azure OpenAI Usage Monitoring: Check Azure portal for API consumption. Set budget alerts at 80% and 100% of estimated monthly spend ($100-$400). Investigate usage spikes that might indicate runaway loops.

Weekly

  • Compliance Report Review: Verify the weekly compliance report is generated and delivered every Monday. Review for unresolved alerts >7 days old and escalate to the firm's compliance officer if found.
  • False Positive Review: During the first 3 months, track alerts dismissed by advisors as a percentage of total alerts. Target: <15% false positive rate. If higher, adjust thresholds in Custom Metadata.
  • Smarsh Archive Verification: Spot-check 5 random alerts and confirm corresponding Smarsh archive records exist with complete data.

Monthly

  • Salesforce Platform Health: Review governor limit usage (API calls, platform events, storage). Ensure the org is within 70% of limits.
  • Security Review: Check login history for anomalies, verify MFA compliance, review user access (deactivate departed employees within 24 hours).
  • Azure OpenAI Model Updates: Check for new model versions. Test in sandbox before upgrading production deployment. GPT-5.4 mini versions should be pinned and only updated after validation.
  • Threshold Tuning Session: 30-minute call with the compliance officer and 1-2 senior advisors to review alert effectiveness and adjust thresholds based on the past month's data.

Quarterly

  • Optimization Review ($3,000-$8,000 billable): Comprehensive review of agent performance metrics, alert conversion rates (alerts that led to client action), advisor satisfaction survey, threshold refinement, and system performance tuning.
  • Salesforce Release Impact Assessment: Each Salesforce release (Spring, Summer, Winter) may affect Agentforce behavior, Flow execution, or LWC rendering. Test in sandbox within 2 weeks of each release preview.
  • Vendor Relationship Review: Confirm all vendor contracts (Salesforce, Orion, Smarsh, Azure) are current. Review upcoming renewal dates and negotiate terms.

Annually

  • Compliance Audit Support ($5,000-$12,000 billable): Assist the firm in preparing for FINRA/SEC examination. Generate annual summary of AI agent activity, archive completeness reports, and supervisory review evidence.
  • FINRA/SEC AI Guidance Review: Monitor regulatory updates from FINRA and SEC regarding AI use in financial services. Update agent prompts, guardrails, and WSP addendum as regulations evolve.
  • Disaster Recovery Test: Simulate a scenario where the Salesforce org is unavailable for 4 hours. Verify that: (1) alerts queue in platform events and process upon restoration, (2) Smarsh continues to receive records, (3) advisors receive a Teams notification about system unavailability.
  • Annual Architecture Review: Evaluate whether the Salesforce Agentforce approach remains optimal or if emerging alternatives (e.g., new LangGraph capabilities, Microsoft Copilot Studio improvements) warrant consideration.

SLA Framework

  • Critical (system down, data sync failure, archive failure): 1-hour response, 4-hour resolution target
  • High (agent not generating alerts, incorrect alert routing): 4-hour response, 1 business day resolution
  • Medium (threshold tuning, dashboard issues, notification delays): 1 business day response, 3 business day resolution
  • Low (feature requests, cosmetic issues, documentation updates): 3 business day response, scheduled for next maintenance window

Escalation Path

1
Tier 1 (MSP Help Desk): Basic connectivity, login, and UI issues
2
Tier 2 (MSP Salesforce Admin): Configuration, threshold, and data sync issues
3
Tier 3 (MSP AI/Dev Engineer): Agent logic, prompt engineering, API integration issues
4
Vendor Escalation: Salesforce Premier Support (case submission), Orion Support, Azure Support (Business tier minimum)
5
Compliance Escalation: Firm's Chief Compliance Officer for any regulatory concern

Alternatives

...

Custom Stack: LangGraph + n8n + Azure OpenAI

Instead of Salesforce Agentforce, build a custom autonomous agent using LangGraph (MIT-licensed Python framework) for agent orchestration, n8n (self-hosted) for workflow automation and data pipeline management, and Azure OpenAI for LLM reasoning. The agent runs on an Azure VM (D4s v5, ~$140-180/month) and connects to the existing CRM (Redtail or Wealthbox) and Orion via their respective APIs. Alerts are delivered via email, Teams webhooks, and CRM task creation.

Microsoft Copilot Studio + Dynamics 365

Use Microsoft Copilot Studio to build the monitoring agent within the Microsoft ecosystem. Copilot Studio provides a low-code agent builder with connectors to Dynamics 365 (or existing CRM via Power Platform connectors), Azure OpenAI, and Microsoft Teams. The agent runs entirely within the Microsoft cloud, leveraging existing Microsoft 365 licensing. Alerts are delivered natively through Teams and Outlook.

Turnkey Vendor: Orion Redtail AI + Compliance Suite

Wait for and adopt Orion's native AI capabilities as they expand. Orion already offers real-time alerts, trade surveillance, and integrated compliance workflows. As Orion integrates more AI features (expected 2025-2026), the monitoring agent capability may become a native platform feature requiring minimal custom development. Supplement with Smarsh AI Assistant for compliance review.

Want early access to the full toolkit?