sshvarzman-salesforce/claude-skills

deploying-person-account-fields-via-contact

Add custom fields to Person Accounts correctly by creating them on the CONTACT object — Salesforce auto-materializes each one on the Account object with a pc-suffixed API name (e.g.

Vedi sorgente

Come usare

  1. Copia il comando e controlla il pacchetto prima di installarlo nel tuo ambiente agente.
  2. Controlla strumenti, credenziali e ambienti richiesti nel documento originale.
  3. Descrivi input e risultato desiderato; confronta l’output con le fonti.
npx skills add https://github.com/sshvarzman-salesforce/claude-skills --skill deploying-person-account-fields-via-contact

Prima di iniziare

  • L’installazione non include abbonamenti, quote API o accesso ai file.
  • Stelle e installazioni indicano attività, non un test indipendente di qualità o sicurezza.
Documento Skill originale

Contenuto dal repository con titoli, esempi, codice, tabelle, link e immagini preservati.

Deploying Person Account Fields via Contact

What this skill is for

Person Accounts are a single logical record stored as two rows: an Account row and a matched Contact (PersonContactId) row. This split is the source of the #1 Person Account custom-field mistake: creating a member/person attribute directly on Account when it belongs on the person.

The rule: for a person-level custom field, create it on `Contact`. Salesforce automatically mirrors it onto the Account object for Person Accounts under a `__pc`-suffixed API name. You never author the Account-side field — the platform materializes it, and it's immediately available via SOQL, REST/Bulk API, and Flow.

Create custom field on Contact:            Member_Status__c
        │  (Person Accounts enabled)
        ▼  platform auto-mirrors
Account (Person Account) gains:            Member_Status__pc      ← queryable, API-accessible, Flow-referenceable
                                                                    (you did NOT create this — it's automatic)

Verified end-to-end on the OMERS pension demo (org CommericalDemos): 8 member fields authored on Contact all surfaced as __pc on Account, queried via SOQL and read in system-mode Flows — see the worked example at the bottom.


Why not create the field on Account directly?

  • For a Person Account, the person attribute logically lives on the Contact side. If you create Member_Status__c on Account, it exists only as a business-account field and does not populate for Person Accounts through the Contact/person layer — you end up with two unrelated fields and confusion about which one holds the value.
  • Creating it on Contact is the single source of truth: business Contacts get Member_Status__c, and every Person Account automatically exposes the same value as Account.Member_Status__pc. One field authored, both objects served.
  • Exception — roll-up summary fields. A roll-up summary must live on the master object of the master-detail. If child records (e.g. Pension_Contribution__c) are detail to Account, the roll-up (e.g. Total_Contributions_To_Date__c) must be created on `Account`, not Contact — Contact can't be the master and can't hold the roll-up. These are the one category that correctly lives on Account.

1. Create the field on Contact (metadata)

Author it as a normal Contact CustomField. Nothing Person-Account-specific in the field XML itself — the mirroring is automatic because Person Accounts are enabled.

force-app/main/default/objects/Contact/fields/Member_Status__c.field-meta.xml:

xml
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
    <fullName>Member_Status__c</fullName>
    <label>Member Status</label>
    <type>Picklist</type>
    <valueSet>
        <valueSetDefinition>
            <sorted>false</sorted>
            <value><fullName>Active</fullName><default>false</default><label>Active</label></value>
            <value><fullName>Retired</fullName><default>false</default><label>Retired</label></value>
        </valueSetDefinition>
    </valueSet>
</CustomField>

Deploy:

bash
sf project deploy start --metadata CustomField:Contact.Member_Status__c --target-org <ORG> --json

There is no Account.Member_Status__pc.field-meta.xml to author or deploy — it appears automatically. Do not try to create it; a hand-authored __pc field will conflict/fail.


2. FLS — grant on the Contact field

Field-Level Security is set on the Contact field (the source). The __pc mirror inherits accessibility from the Contact field, so you permission Contact.Member_Status__c in profiles/permission sets and the Account-side __pc follows.

Permission-set entry (fieldPermissions) — reference the Contact field:

xml
<fieldPermissions>
    <field>Contact.Member_Status__c</field>
    <editable>true</editable>
    <readable>true</readable>
</fieldPermissions>
Do not add a separate Account.Member_Status__pc fieldPermissions entry — it's driven by the Contact field. (Attempting to permission the __pc mirror independently is unnecessary and can error.)

3. Page layouts — place on BOTH Contact and Account layouts

A Person Account is edited from the Account UI, but business Contacts use the Contact UI. To have the field visible everywhere:

  • Add Member_Status__c to the Contact page layout(s).
  • Add Member_Status__pc to the Account page layout(s) — this is how it shows on the Person Account record page.

Both are real layout edits. If you only add it to Contact, the value is invisible on the Person Account record page (which renders the Account layout).


4. Read the mirrored field — SOQL & API

Once deployed, query it two equivalent ways depending on which row you start from:

sql
-- From the Account (Person Account) row — use the __pc mirror:
SELECT Id, Name, Member_Status__pc, PersonContactId
FROM Account
WHERE Id = '001gL00001b88vRQAQ' AND IsPersonAccount = true

-- From the Contact row — use the base __c field:
SELECT Id, Name, Member_Status__c, AccountId
FROM Contact
WHERE Id = '003gL00000zvHFWQA2'

Both return the same value for a Person Account. REST/Bulk API see the __pc field on the Account sObject exactly like any other field.


5. In a Flow: from a Person Account's Contact record, reach the Account side

When a Flow is handed a Contact Id for a Person Account (e.g. a caller resolved to their Contact), the Contact's `AccountId` is the self-lookup to the Account version of that same Person Account. Two patterns:

A) Read the base field directly (simplest). The person fields are on Contact already, so a Get Records on Contact returns Member_Status__c with no extra hop:

Get_Contact:  Contact WHERE Id = {!recordId}   →  {!Get_Contact.Member_Status__c}

B) Traverse Contact → Account to read Account-side / `__pc` or roll-up fields. Roll-up summaries and any Account-only field live only on the Account row, so you must hop:

Get_Contact:   Contact WHERE Id = {!recordId}        (returns AccountId)
Get_Account:   Account  WHERE Id = {!Get_Contact.AccountId}
               →  {!Get_Account.Total_Contributions_To_Date__c}   (roll-up, Account-only)
               →  {!Get_Account.Member_Status__pc}                (mirror, if you prefer the Account side)

Get_Contact.AccountId is the Person Account's Account Id — that's the self-lookup the user asked about. From there every Account/__pc/roll-up field is reachable.

Cross-object shorthand also works in a single Get on Contact for many fields ({!Get_Contact.Account.Total_Contributions_To_Date__c}), but the explicit two-Get pattern is clearest and avoids surprises when the flow runs in system mode.

Run person-data reads in system mode (SystemModeWithoutSharing on the autolaunched flow) when the flow is invoked by an agent/automated user so FLS/sharing don't silently drop fields.


6. Deploy & verify recipe

bash
# 1. Deploy the Contact field(s)
sf project deploy start --metadata CustomField:Contact.Member_Status__c --target-org <ORG> --json

# 2. Confirm the __pc mirror exists on Account (Tooling API FieldDefinition)
sf data query --use-tooling-api --target-org <ORG> --json \
  -q "SELECT QualifiedApiName FROM FieldDefinition WHERE EntityDefinition.QualifiedApiName='Account' AND QualifiedApiName='Member_Status__pc'"

# 3. Prove it returns a value for a real Person Account
sf data query --target-org <ORG> --json \
  -q "SELECT Id, Name, Member_Status__pc FROM Account WHERE IsPersonAccount=true AND Id='001gL00001b88vRQAQ'"

If step 2 returns the field, the mirror materialized. If step 3 shows the value, SOQL/API access is confirmed.


Worked example — OMERS pension demo (CommericalDemos)

  • 8 member fields (Member Status, membership number, DB pension attributes, SIN last-4, DOB-derived flags, etc.) were authored on Contact. Every one auto-appeared on Account as __c → __pc (e.g. SIN_Last_4__c → SIN_Last_4__pc).
  • Lauren Bailey (the demo member): Account 001gL00001b88vRQAQ, Contact/PersonContactId 003gL00000zvHFWQA2. SELECT SIN_Last_4__pc FROM Account WHERE Id='001gL00001b88vRQAQ' and SELECT SIN_Last_4__c FROM Contact WHERE Id='003gL00000zvHFWQA2' return the same value.
  • All flows/lookups point at Contact (003gL00000zvHFWQA2), reading the base __c fields; where Account-only roll-ups were needed (Total_Contributions_To_Date__c, Total_Employee_Contributions__c, Total_Employer_Contributions__c — master of Pension_Contribution__c), the flow hops Contact.AccountId → Account to read them.
  • Layouts: the 8 __c fields sit in an "OMERS Pension" section on the Contact layouts; the 8 __pc fields + 3 roll-ups sit in the matching section on the Account layouts.

Gotchas

GotchaFix
Created the person field on Account directlyDelete it; author on Contact — the __pc mirror is automatic
Tried to author/deploy the Account.*__pc fieldDon't — it's platform-generated; hand-authoring conflicts
Roll-up summary "won't create on Contact"Correct — roll-ups must live on the master (Account); that's the one Account-side exception
__pc field FLS "not taking"Permission the Contact __c field; the mirror inherits
Field value invisible on the Person Account record pageAdd the __pc field to the Account page layout (the Person Account UI renders the Account layout)
Flow can't see the field for an agent/automated userRun the data-read flow in SystemModeWithoutSharing
Need an Account-only/roll-up value starting from a ContactHop Contact.AccountId → Account (the Person Account self-lookup)

Correlati per attività

dallo stesso repository

Altri Skills

Tutti gli Skills
sshvarzman-salesforce
Community

activating-datacloud

Salesforce Data Cloud Act phase. Use this skill when the user manages activations, activation targets, data actions, or downstream delivery of Data Cloud audiences and data. TRIGGER when: user manages activations, activation targets, data actions, or downstream delivery of Data Cloud audiences and data. DO NOT TRIGGER when: the task is segment creation (use segmenting-datacloud), data retrieval/search work (use retrieving-datacloud), or STDM/session tracing (use observing-agentforce).

installazioni
1
GitHub Stars
0
Aggiornato
15 ott
sshvarzman-salesforce
Community

agentforce-skills-research

Research Agentforce configuration patterns — topics, actions, instructions, CLTs, knowledge, planner behavior. Searches Salesforce docs, Trailhead, internal repos (git.soma), Slack channels, and Google Docs to find working examples, known issues, and best practices.

installazioni
1
GitHub Stars
0
Aggiornato
15 ott
sshvarzman-salesforce
Community

harmonizing-datacloud

Salesforce Data Cloud Harmonize phase. Use this skill when the user works with DMOs, mappings, relationships, identity resolution, unified profiles, data graphs, or universal IDs. TRIGGER when: user works with DMOs, mappings, relationships, identity resolution, unified profiles, data graphs, or universal IDs. DO NOT TRIGGER when: the task is only about streams/DLOs (use preparing-datacloud), segments/insights (use segmenting-datacloud), retrieval/search (use retrieving-datacloud), or STDM/sessio

installazioni
1
GitHub Stars
0
Aggiornato
15 ott
sshvarzman-salesforce
Community

preparing-datacloud

Salesforce Data Cloud Prepare phase. Use this skill when the user creates or manages Data Cloud data streams, DLOs, transforms, or Document AI configurations. TRIGGER when: user creates or manages Data Cloud data streams, DLOs, transforms, or Document AI configurations, or asks about ingestion into Data Cloud. DO NOT TRIGGER when: the task is connection setup only (use connecting-datacloud), DMOs and identity resolution (use harmonizing-datacloud), or query/search work (use retrieving-datacloud)

installazioni
1
GitHub Stars
0
Aggiornato
15 ott