Extensibility
The Five Extensibility Points
CallCore TX ships with sensible defaults for every decision the package makes at runtime. Extensibility strategies let your org replace those defaults with logic that fits your specific data model, team structure, or business rules — without forking the package or waiting for a new release.
| Strategy | What it controls |
|---|---|
BuildCommunicationScopeForRecord |
Which CRM records are "in scope" when the timeline is viewed from a given record page |
GatherPhoneNumbersFromRecords |
How phone numbers are extracted from scope records |
GetUserForCallHandler |
How a call handler's details are matched to a Salesforce User |
RestrictCallHandlers |
Which call handlers the running user is allowed to see |
RestrictSources |
Which call sources (phone lines) the running user is allowed to see |
All five follow the same shape. You write an Apex class, implement the relevant interface, and register it via a custom metadata record. No code changes to the package are required.
How Strategy Resolution Works
When CallCore TX needs to invoke a strategy, it:
- Queries the
callcoreio__ExtensibilityStrategy__mdtcustom metadata type for a record matching the strategy type and discriminator. - If a match is found, resolves the Apex class name from the
callcoreio__ApexClassName__cfield. Subscriber org classes are checked first; packaged classes are checked second. - If no match is found in metadata, falls back to the packaged default implementation.
The discriminator narrows which metadata record is selected. For strategies that operate on a specific SObject type (BuildCommunicationScopeForRecord, GatherPhoneNumbersFromRecords), the discriminator is the SObject API name prefixed with RecordType: (e.g., RecordType:Contact). For strategies with a single global implementation (GetUserForCallHandler, RestrictCallHandlers, RestrictSources), use default as the discriminator.
A default record matches any discriminator that has no more-specific override. If you configure both RecordType:Contact and default, the Contact-specific record wins for Contact pages; all other record types use the default.
Resolution precedence (most specific wins):
RecordType-specific metadata record
↓ (fallback)
default metadata record
↓ (fallback)
packaged default implementation
The Context Pattern
Every strategy receives a Context object. The Context carries two things:
- Input fields — read-only data the strategy uses to make its decision (e.g., the anchor record reference, the call handler's email address).
- Write methods — the API the strategy calls to record its output (e.g.,
addToScope(id),found(userId),allowSet(ids)).
The strategy's job is to read the inputs, compute its output, and record that output via the write methods. It does not return a value. The framework reads the Context after the strategy returns.
This shape allows the contract to evolve — new input data can be added to the Context without changing the interface method signature, which would be a breaking change in a managed package.
Error Handling and Debug Mode
If a strategy throws an unhandled exception, CallCore TX logs the exception and falls back gracefully:
BuildCommunicationScopeForRecord— proceeds with an empty scope (no calls shown).GatherPhoneNumbersFromRecords— proceeds with no phone numbers (no calls matched).GetUserForCallHandler— treats the result as "no match" (handler is not linked to a user).RestrictCallHandlers— fails closed: excludes all handlers (no calls shown).RestrictSources— fails closed: excludes all sources (no calls shown).
When the CallCore_DebugMode custom permission is assigned to the running user, exceptions are rethrown instead of swallowed. Use the CallCore TX - Debug permission set during development.
Where to Start
- To customise which CRM records appear in the timeline: see BuildCommunicationScopeForRecord.
- To customise phone number extraction from non-standard objects: see GatherPhoneNumbersFromRecords.
- To match call handlers to users by something other than email: see GetUserForCallHandler.
- To restrict call visibility by team or department: see RestrictCallHandlers or RestrictSources.
- For custom metadata registration: see Registering Strategies.
- For testing your implementation: see Testing Strategies.