BuildCommunicationScopeForRecord

What It Does

When a user opens the CallCore timeline on a record page, the package needs to know which CRM records are "in scope" — that is, which records should be checked for matching phone numbers when retrieving call history.

By default:

  • Contact page — the Contact itself plus its parent Account.
  • Account page — the Account plus all its Contacts.
  • Opportunity page — the Opportunity plus its Account (delegating to the Account scope logic).
  • Any other record — the anchor record only.

Implement BuildCommunicationScopeForRecord.IStrategy to replace this logic for a specific object type or to add support for a custom object.

Interface

global interface IStrategy {
    void build(Context context);
}

Context

Input

Field Type Description
anchorRef callcoreio.RecordRef The record the timeline is being viewed from. Provides recordId and sObjectType.
sharingRule callcoreio.SharingRule The sharing context — either WithSharing or WithoutSharing. Propagated automatically when you use addFullScopeOf.

Write Methods Call these from your build implementation to add records to the scope:

Method Description
addToScope(Id id) Adds a single record ID to scope. Null-safe.
addToScope(Iterable<Id> ids) Adds multiple record IDs. Null-safe.
addToScope(callcoreio.RecordRef recordRef) Adds the ID from a RecordRef. Null-safe.
addToScope(Context otherContext) Merges the scope from another Context instance.
addFullScopeOf(Id linkedRecordId) Resolves the full communication scope for a linked record and merges it into this context. Null-safe. Sharing propagation, error forwarding, and circular-delegation protection are handled automatically. Use this instead of calling build() directly.
addError(callcoreio.Error error) Records a non-fatal error (e.g., ScopeTooLargeError).

Read Properties

Property Type Description
hasErrors Boolean True if any errors were added via addError.

Discriminator

The discriminator is RecordType:<SObjectApiName> where <SObjectApiName> is the API name of the object the strategy applies to (e.g., RecordType:Contact, RecordType:Opportunity__c).

Use default to provide a fallback for all object types that do not have a more specific record.

Default Behaviour

Object Default scope
Contact Contact + parent Account
Account Account + child Contacts
Opportunity Opportunity + Account (Account's default scope applies)
Anything else The anchor record only

Errors

callcoreio.ScopeTooLargeError is a built-in error type for when a query would return too many records to build a usable scope. Add it via context.addError(error) — the framework will surface it to the UI without halting execution.

global class ScopeTooLargeError extends callcoreio.Error {
    global List<callcoreio.RecordRef> contextRecords;
    global String relationSObjectApiName;
    global String relationshipName;
    global Integer relationCount;
    global Integer maxAllowedRelationCount;
}

Example: Custom Object with a Lookup to Account

A custom object Project__c has a Account__c lookup. When the timeline is viewed from a Project record, include the Project itself plus its linked Account.

public class BuildProjectCommsScope
    implements callcoreio.BuildCommunicationScopeForRecord.IStrategy {

    public void build(callcoreio.BuildCommunicationScopeForRecord.Context context) {
        Project__c project = [
            SELECT Id, Account__c
            FROM Project__c
            WHERE Id = :context.anchorRef.recordId
            LIMIT 1
        ];

        context
            .addToScope(project.Id)
            .addToScope(project.Account__c);
    }
}

Register with:

  • Strategy Type: BuildCommunicationScopeForRecord
  • Discriminator: RecordType:Project__c
  • Apex Class Name: BuildProjectCommsScope

Example: Delegating to Another Record's Scope

Use this pattern when your custom object has a lookup to a Contact and you want to inherit Contact's default scope behaviour — the Contact itself plus its parent Account — without reimplementing that logic. Calling context.addFullScopeOf(linkedId) resolves the full communication scope for that record and merges it into the current context automatically. Sharing propagation, error forwarding, and circular-delegation protection are all handled by the package.

public class BuildCaseCommsScope
    implements callcoreio.BuildCommunicationScopeForRecord.IStrategy {
    public void build(callcoreio.BuildCommunicationScopeForRecord.Context context) {
        Case c = [
            SELECT Id, ContactId
            FROM Case
            WHERE Id = :context.anchorRef.recordId
            LIMIT 1
        ];
        context.addToScope(c.Id);
        context.addFullScopeOf(c.ContactId);
    }
}

addFullScopeOf is null-safe — calling it with a null ID is a no-op. The method is chainable and returns this.

If the Contact's scope logic is later changed (via its own registered strategy), your implementation picks up that change automatically.

Notes

  • The anchor record is not automatically added to scope. If you want it included, call context.addToScope(context.anchorRef) explicitly.
  • Records from different SObject types can be added to the same scope. The package groups them by type internally before passing to GatherPhoneNumbersFromRecords.
  • Scope building happens once per timeline request. Avoid SOQL inside loops — the anchor is a single record, but related queries should be written in bulk-safe fashion if you anticipate the strategy being invoked for multiple records in future.
  • To include the full communication scope of a related record, call context.addFullScopeOf(linkedId). Sharing propagation and circular-delegation protection are handled automatically — do not call build() directly.