Skip to main content

Portals

How to build a portal with Flourish Core: a branded set of pages over your Salesforce data, for clients, Arbor members, the public or your own staff, put together from configuration rather than code.

Overview​

A portal works like a small version of Lightning. It has a header with navigation and search, a home page, lists, record pages and pages of your own, all built from cards: lists, counts, boards, calendars, paths, text, the activity timeline and components you write. One component draws all of it, and custom metadata records say what it draws, so a new portal is configuration and branding rather than a new set of components.

The Service Requests tab is a portal, and a good one to look at to see what a portal does.

A portal decides access itself. It reads and writes in system mode and checks every request against portal permission sets you write, record by record and field by field. Salesforce sharing, profiles and field-level security do not apply inside it. A site's guest user is given the portal and no object or field permissions at all, so nobody, signed in or not, reaches a record the portal's configuration does not grant.

This page covers how a portal fits together and how to put one in front of people. Portal configuration is the reference for every record and key, and the Portal Developer Guide covers extending a portal with your own Apex and components.


Who a portal serves​

A portal names the audiences it takes, and turns everyone else away:

AudienceWhoWhere they use it
licensedExperience Cloud users with a Salesforce license, each with a ContactAn Experience site
arborArbor members, who have no Salesforce licenseAn Experience site
guestAnyone, without signing inAn Experience site
internalYour own staffA Lightning app page or record page, or a site

One portal can take several, and the same pages serve them all. What each person sees follows their roles.


How access works​

Every time someone opens a page, saves or searches, the portal works out from scratch who they are and what they may do:

  1. Is this portal served here? It answers only on the sites its configuration names. On a Lightning page, only staff get past this.
  2. Who is it? A licensed user, a staff member, an Arbor member (by their sign-in), or a guest.
  3. Does the portal take them? Their audience has to be one the portal lists, and an Arbor member has to be in one of its networks.
  4. What roles do they hold? A guest gets the portal's one guest role. Everyone else gets roles from rules: everyone in an audience, people whose own record has some value, or whatever a class of yours decides. Someone with no role is turned away.
  5. What do their roles grant? Each role brings portal permission sets, and each set grants objects, fields and which records.

Permission sets are access; pages are presentation. A page can name any field and the portal shows each person only what their sets grant. A roles list on a page, card or button hides it from everyone else, and grants nothing.

A permission set reaches records by rules, such as "cases on my account", "comments on cases I can see", "records linked to me through this object", or "whatever this Apex class returns". Each rule reaches records to read, or to read and edit. A set's fields apply only to the records its own rules reach, so two sets never lend each other fields.

Some rules hold whatever a set says:

  • A rule built on a value the person does not have, such as an Account for a guest, reaches nothing, rather than every record with no Account.
  • What Salesforce marks private to external users, such as an unpublished case comment, stays hidden from everyone but staff unless a set says otherwise.
  • Nobody can change a record's owner, its created and modified fields, or a record type a set does not list.
  • Nobody can change the fields that decide who they are: the fields their roles are read from, and the Account on their Contact. An Arbor member never edits or deletes their own Arbor element.
  • A lookup can only be pointed at a record the person can see, and adding a record under a parent (a comment on a case) needs the right to edit the parent.
  • After a save, the person must still be able to read the record. A save that would move a record out of their sight, for example by pointing it at another client's account, is undone.

Building a portal​

1. Write the configuration​

A portal is a set of Flourish Portal Config custom metadata records sharing one key: one for the portal, one per portal permission set, and one per page. Create them in Setup under Custom Metadata Types, or deploy them. Each record's Body is JSON; Portal configuration has every key and an example of each.

A small client portal might be:

RecordKindSays
acme_portalPortalTakes licensed users on the Acme Portal site, gives each the client role, and brands the pages in Acme's color.
acme_clientPermissionSetReads the person's own Account, its Contacts and its Cases; creates Cases with their Contact filled in; edits only open ones.
acme_homePageA home page with counts of open and closed cases and a list of recent ones.
acme_cases, acme_casePageA list of cases, and a case's record page with its comments.

2. Put it on a page​

Every portal is drawn by one component, Flourish Portal, with one property, Config (JSON), which names the portal:

{"portal":"acme"}

On an Experience site, which is how licensed users, Arbor members and guests reach a portal:

  1. Use an LWR site, such as one made from the Build Your Own (LWR) template.
  2. Put Flourish Portal on the site's home page, on its own. The portal has its own header, navigation, pages and footer, and moves between its pages without the site's help, so the site needs only that one page.
  3. Strip the site back so the portal fills the window: hide the site's own header and footer, set the page section's padding to zero, and remove the theme's maximum content width. Otherwise the site frames the portal in a band of its own.
  4. Add the site's name, as Setup lists it under All Sites, or its Id, to the portal's sites. A portal answers on no site it does not name.
  5. Give everyone who will use it access to the portal: the Flourish Core: Portal permission set for licensed users, and for the site's guest user when guests or Arbor members will use it. It grants the portal and nothing else.
  6. For guests and Arbor members, let guest users see the site without signing in (in Experience Builder's Settings).
  7. Publish the site.

Publish again after every Flourish Core upgrade. A published site keeps the version of each component it had when it was published, so it goes on drawing the old portal until it is published again. The same goes for any change to the site itself.

On a Lightning app page, for staff: in the Lightning App Builder, create an app page, put Flourish Portal on it, give it a tab and add the tab to an app. Only the internal audience works there. Staff need Flourish Core: User, Flourish Core: Admin or Flourish Core: Portal to use it.

On a Lightning record page, the portal opens on its own record page for the record being viewed, so a record found by search or a link opens in the portal. The portal needs a record page for that object. The service request record page is set up this way.

3. Check it as each person​

Open the portal as each role it serves: as yourself for staff, in a private window for a guest, and signed in as a member or licensed user. A configuration mistake only shows to the people who would see the broken page, so checking as one role does not check the others. Staff see the reason; everyone else sees This portal is not set up correctly.


Licensed users​

A licensed user is identified by their own Salesforce user, and through it their Contact and that Contact's Account. A permission set can reach records by any of those, for example cases whose Account is theirs.

Roles come from roleRules: everyone with the licensed audience, or those whose Contact holds some value, such as a Title of Manager. That field can then never be changed through the portal, so nobody can promote themselves.

Give them the Flourish Core: Portal permission set.


Arbor members​

Arbor members sign in without a Salesforce license, and a portal can serve them alongside, or instead of, licensed users and guests.

  1. Add arbor to the portal's audiences, and the Ids of the networks whose members may use it to arborNetworks. A member of any other network is turned away.
  2. On the site page that holds the portal, add Flourish Arbor: Auth Service after it. The portal reads the member's sign-in through Arbor, and an LWR site loads only what the page carries. If magic links land on this page (the network's Auth Site URL points here) and the portal takes no guests, use Flourish Arbor: Auth Guard instead, which signs a member in as they arrive and sends anyone else to sign in.
  3. Set the portal's loginUrl to your Arbor sign-in page, and the network's Login Redirect URL to the portal's page, so members go back and forth. See Sign-in Pages.
  4. Give the site's guest user Flourish Core: Portal, alongside the Arbor class it already has.

A signed-in member sees Sign out in the portal's header.

A member's own record is the one their Arbor membership is tied to, usually a Contact. A permission set can reach records through it (recordId), through its Account when it is a Contact, or through the member's Arbor element and network.

Members' Arbor roles carry into the portal with one rule:

"roleRules": [
{ "role": "member", "audience": "arbor" },
{ "audience": "arbor", "resolver": "toflourish.arbor_CoreBridge" }
],
"roles": {
"member": ["acme_member"],
"staff": ["acme_member", "acme_staff"]
}

The second rule gives each member the roles they hold in their network, so an Arbor role named Staff becomes the portal role staff. Names are matched without regard to case. The first rule gives every member a base role, since a member with no role at all is turned away.

Never let members edit other members' Arbor elements. A member can never change their own, whatever a set grants, but a set that let them edit someone else's would let them hand out roles.

When a member's session ends, or they are suspended, the portal says Your session has ended. Please sign in again. with a Sign in button.


Guests​

A guest is anyone on the site who has not signed in. They all share one role, guestRole, and every guest is the same person as far as the portal is concerned, so a rule can never mean "a guest's own records". Give guests what is safe for everyone to see, and create-only access for forms: a set can let guests create a record they cannot read back.

When the portal also takes Arbor members or licensed users and has a loginUrl, a guest sees Sign in in the header. On a portal that takes no guests, a visitor who has not signed in gets the refusal with a Sign in button.


What people can do in a portal​

Get around. The header holds the portal's logo and name, its navigation, a search box, and the person's name, which opens their own record when the portal has a page for it. Breadcrumbs under the header lead back. On a narrow screen the navigation becomes a menu, and the pages rearrange to fit the space they have rather than the size of the window.

Search. The search box suggests matches after a pause, up to three from each of the first four kinds of record it searches. The arrow keys move through the suggestions, Enter opens the one chosen or, with none chosen, every result, and Escape closes the list.

Read lists. Lists sort by a column, search, switch between tabs such as Open and Closed, and keep loading as you scroll. New opens a form laid out like the record's page.

Work a record. A record page shows the record's header, its Details and Related lists, and any tabs and cards of its own. Click a field's pencil, or Edit, to change every field you may change, and Save. Buttons in the header run the actions the portal offers on that record.

Change many records at once. On lists that allow it, check rows and choose an action from the bar that appears, or press Edit to change the cells in place, like a spreadsheet, and Save them together. A row that cannot be saved says why under it, and the others save.

Move things along. On a board, drag a card to another column, or use Move to in its menu, which works by keyboard and on touch screens. On a path, click a step and then the Mark as Current button. Both offer Undo.

Share a link. The address in the browser always names the page and record you are on, so a copied link opens the same place for anyone the portal lets see it.

Leaving unsaved changes asks first: Leave without saving?


Things to know​

  • Lists stop at 2,000 rows. Counts above that read 2000+, and search is the way to anything further down.
  • Picklists offer every active value, not just those a record type allows, and record types are not applied to picklists anywhere in a portal.
  • A combobox field, such as a task's Subject, is a plain text box in a portal, without its suggested values.
  • Deleting a record deletes the records that belong to it, such as a case's comments, including ones the person cannot see. Grant delete only on objects whose children belong to the same people.
  • Guests and Arbor members reach the site as its guest user, so what they create or change is recorded as created or changed by that user, in field history and the activity timeline too, and what they create is owned by the site's default record owner.
  • Guests and Arbor members cannot post to Chatter. They can read it on the activity timeline.
  • Nothing limits how often a guest submits. Keep guest create access to what you would accept in quantity.
  • A formula field can show what a set does not reach. A formula that pulls a value from a related record shows it whether or not that record is in reach.
  • A related list opened with View all keeps the list's filters but not its row actions or editing in place.
  • The Service Requests portal cannot be edited. Its configuration ships with the package and is protected, so an upgrade brings its changes with it.