> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fusioncore.us/llms.txt
> Use this file to discover all available pages before exploring further.

# Contact User Sync for Base Salesforce

> Keep a Contact's fields in sync with its related User record, and expose User fields as custom SSO attributes.

## Overview

Base Salesforce keeps a `Contact` and its related `User` as two separate records, so editing a Contact's email, name, or a custom field does not automatically update the login `User` that represents the same person. The **Contact User Sync for Base Salesforce** accelerator closes that gap: you define field-to-field mappings once, and the package keeps the mapped `User` fields aligned with their Contact source whenever the Contact (or a Person Account) changes. It also lets you expose any `User` or Contact field as a custom SSO attribute sent to a Connected App or External Client App during single sign-on.

This accelerator is not part of core fusionCore — install it separately, and it targets base Salesforce and Person Account orgs (not Fonteva).

## Prerequisites

* No permission set ships with the package — confirm the user/process running the sync has edit access to the target `User` fields.
* Decide your field mappings and, if you plan to use SSO attributes, have your Connected App or External Client App name ready.

## How to Configure

<Steps>
  <Step title="Map Contact fields to User fields">
    Go to **Setup → Custom Metadata Types → Contact User Field Mapping → Manage Records** and click **New**. The default form only exposes three fields:

    <Frame caption="Contact User Field Mapping record detail — the default layout">
      <img src="https://mintcdn.com/fusionspan/EW_gg4_8FJ-921wF/images/end-user-guides/2783084572/contact_user_field_mapping_detail.png?fit=max&auto=format&n=EW_gg4_8FJ-921wF&q=85&s=a40bbe1cd4defb3dcf520e811a2c4892" alt="A Contact User Field Mapping record showing Label, Contact User Field Mapping Name, and Contact Field — no User Field or Is Active field is visible" width="1280" height="900" data-path="images/end-user-guides/2783084572/contact_user_field_mapping_detail.png" />
    </Frame>

    * **Label** and **Contact User Field Mapping Name** — any name that identifies the mapping.
    * `FS_Contact_Field__c` (**Contact Field**) — the source Contact field API name (for example `Email`, `FirstName`, or a custom field).

    <Warning>
      `FS_User_Field__c` and `FS_Is_Active__c` aren't on this object's default page layout — you can't set the target `User` field or deactivate a mapping from this form. Add both fields to the page layout first (**Setup → Object Manager → Contact User Field Mapping → Page Layouts**), or set them via a metadata deployment, before mappings can actually do anything (an unset `FS_User_Field__c` has no field to sync to).
    </Warning>

    For Person Accounts, enter the plain Contact field name — the package automatically translates it to the Person Account equivalent (standard fields, or custom fields via the `__c` → `__pc` suffix swap).

    In most cases you only need to sync name and login fields — everything else is better handled through SSO custom attributes (see the next step). A typical starting set of mappings:

    | Contact Field | User Field  | Active |
    | ------------- | ----------- | ------ |
    | `Email`       | `Email`     | ✓      |
    | `Email`       | `Username`  | ✓      |
    | `FirstName`   | `FirstName` | ✓      |
    | `LastName`    | `LastName`  | ✓      |

    <Note>
      `Email` maps to both `Email` and `Username` on the User — add two separate mapping records with the same source field. Only add more mappings than this if you have a specific field you need mirrored onto the User record itself, rather than sent as an SSO attribute.
    </Note>
  </Step>

  <Step title="(Optional) Configure SSO custom attributes">
    On the target Connected App's OAuth settings, set the Apex plugin to `FS_SSOApexPlugin` (classic Connected Apps) or `FS_ExternalSSOApexPlugin` (External Client Apps). Then go to **Setup → Custom Metadata Types → SSO Custom Attributes Mapping → Manage Records** and add one record per attribute:

    * `FS_Connected_App_Name__c` — must exactly match the Connected App's Name (find it under **Setup → App Manager**, using the Name shown at the top of the app's page, not its API name).
    * `FS_Custom_Attribute_Label__c` — the attribute/claim name sent to the app.
    * `FS_Custom_Attribute_Value__c` — a field path, relative to the logged-in `User` record, to send as that attribute's value — for example `Username` directly, or `Contact.Email` to reach through to the related Contact. Both lookups and formula fields are supported.

    For example, to send a member's account name, first name, last name, and username as custom attributes on a Connected App named "Test Connected App Name":

    | Connected App Name        | Custom Attribute Label | Custom Attribute Value |
    | ------------------------- | ---------------------- | ---------------------- |
    | `Test Connected App Name` | `accountName`          | `Contact.Account.Name` |
    | `Test Connected App Name` | `firstName`            | `Contact.FirstName`    |
    | `Test Connected App Name` | `lastName`             | `Contact.LastName`     |
    | `Test Connected App Name` | `username`             | `Username`             |

    <Warning>
      A misspelled field path fails silently — if any one mapping for a Connected App has a bad field reference, **none** of that app's custom attributes are sent, not just the bad one. Double-check spelling if expected claims aren't showing up at all.
    </Warning>
  </Step>

  <Step title="Confirm the reconciliation job is scheduled">
    On install, the package automatically schedules a job (`FS_ContactToUserPeriodicSync`) that runs at the top of every hour (org time) and re-checks Contacts modified in the trailing hour, reconciling any drift the real-time sync missed. Confirm it's present under **Setup → Scheduled Jobs**.

    If it's missing — most commonly because the package was deployed as unmanaged source rather than installed as a package, so the automatic install step never ran — schedule it yourself:

    1. Click the **Settings gear** in the top right, then **Developer Console**.
    2. Go to **Debug → Open Execute Anonymous Window**.
    3. Clear any existing code and paste:
       ```java theme={null}
       FS_ContactUserSyncInstallScripts cgm = new FS_ContactUserSyncInstallScripts();
       cgm.onInstall(null);
       ```
    4. Click **Execute**.

    This schedules `FS_ContactToUserPeriodicSync` to run at the top of every hour (org time) — re-check **Setup → Scheduled Jobs** afterward to confirm it now appears.
  </Step>
</Steps>

## Limitations and Common Pitfalls

* **Sync is one-directional.** Changes flow from Contact/Account to User only — nothing propagates back from User to Contact.
* **The sync isn't instant.** A Contact edit publishes an event that updates the User shortly after, rather than in the same transaction — expect a brief delay, not real time.
* **Formula fields don't sync in real time.** Because the real-time path compares the Contact's old and new values, formula recalculations don't reliably trigger it. The hourly job is what catches formula-driven and other missed changes — confirm it's running rather than expecting instant sync for formula fields.
* **Changes made inside a batch job aren't synced in real time either** — same reasoning; they're picked up by the hourly job instead.
* **A mapped field must resolve on both objects.** Field API names are entered as free text with no validation — a typo or an inaccessible field fails silently at run time rather than warning you at configuration time.
* **The default page layout can't set the target field or deactivate a mapping.** `FS_User_Field__c` and `FS_Is_Active__c` aren't on the Contact User Field Mapping page layout out of the box — add them via Object Manager before the mapping records you create can do anything.
* **SSO attribute misconfiguration also fails silently.** A wrong `FS_Connected_App_Name__c`, or a single misspelled `FS_Custom_Attribute_Value__c` field path, sends no attributes at all for that app — not just the bad one — with no error raised. Double-check both if expected claims aren't showing up.
* **The User must already be linked to the Contact** via `User.ContactId` (or `Account.PersonContactId` for Person Accounts). A Contact with no portal/community User has nothing to sync.
