Give each client their own view
A client portal is one published app showing each client a different set of rows: theirs. The app matches the address somebody signed in with against a column naming who each row belongs to.
Three of the four pieces already exist. The fourth is the setting this article covers:
- A list holding the rows, with a column naming the client each row is for.
- A published app reading from it. See Show collected data in your app.
- An access mode that identifies people. See Control who can use your published app.
- Who sees which rows.
Set it up
Section titled “Set it up”Steps
- Open the app in Build and publish it if you have not already.
- In Who can see it, set the access mode to email sign-in or workspace members.
- In the Data panel, set your data view to Show rows and tick the columns to expose. Scoping does not appear on a count-only view, which has no rows to scope.
- In Who sees which rows, choose the column naming who each row belongs to. The default is Everyone sees every row.
- Save. It applies to the next request, with no republish.
Every column is offered, not just email-looking ones, because yours might be
called Contact, Owner, Who, or something in your own language. If none of its
sample values contains an @, Onplana warns you in amber: a column of company
names matches nobody, and every client would get an empty list.
What a visitor gets
Section titled “What a visitor gets”A row is served only when its cell in the chosen column equals the visitor’s
sign-in address. Matching ignores case, so Ana@Acme.com matches
ana@acme.com. It does not ignore stray whitespace: " ana@acme.com" fails
rather than being trimmed into a match, because on a boundary deciding who sees
whose data a near-miss should fail.
The count follows the same filter. A client owning three rows in a list of three hundred sees 3, since a count over the whole table would tell every client how much work you do for the others.
It fails closed, four ways
Section titled “It fails closed, four ways”| Situation | What happens |
|---|---|
| No column chosen | Every signed-in visitor sees every row. The old behaviour, correct for a shared dashboard. |
| Column set, visitor has no identity | Nothing served. An unidentified caller getting everything is the leak. |
| Row has no value in that column | Served to nobody. A row belonging to nobody must not read as belonging to everybody. |
| Row belongs to someone else | Not served. The case the feature exists for. |
Two things that catch people out
Section titled “Two things that catch people out”Changing the access mode does not clear the scoping. Scope an app, later switch it to open or passcode access, and the column stays set with no address to match, so every visitor gets an empty list. Either return it to an identifying sign-in, or set Who sees which rows back to Everyone sees every row.
“Only mine” is a different filter. Scoping matches rows the visitor owns
and is your configuration, unchangeable from a request. The mine filter
matches rows the visitor created, and is their choice. On a portal your firm
creates the rows and the client only reads them, so mine would match nothing.
Scoping is the one you want.
Read the CRM directly, no list to maintain
Section titled “Read the CRM directly, no list to maintain”A list is the right source when the rows exist nowhere else. When what the client should see is already in your CRM, a data view can read it there, so nothing is copied and nothing goes stale.
Steps
- In the Data panel, under Or show each client their own CRM records, pick Clients, Contacts or Deals. The view appears the same way a list view does.
- Switch it to Show rows and tick the fields to expose. Only fields that are safe to show a client are offered: a company’s name, industry, website and location; a contact’s name, email, phone and title; a deal’s title, stage, value, billing terms, dates and quote lines. Internal notes, sales probability, lost reasons and account owners are not on the list and cannot be ticked.
- Publish, and set the access mode to email sign-in or workspace members.
There is no Who sees which rows setting on a CRM view, because there is no choice to make: each visitor is matched by their sign-in address against your Contacts, and sees only the records of the company that contact belongs to. A visitor whose address is not one of your contacts sees nothing, and so does your own preview, unless your address is a contact of one of your clients.
The response has the same shape as a list view, { rows, count, nextCursor },
with each row keyed by the field name. Money arrives as a number, dates as ISO
strings, and a deal’s Quote lines as an array of lines with their own fields.
A count-only view returns { count }, already scoped to the visitor.
What Onplana stores about a visitor
Section titled “What Onplana stores about a visitor”Only a hash of the verified address. The plaintext lives in the signed token issued at sign-in, which is what the row match runs against, so a visitor cannot claim to be somebody else by editing what they send. A token minted for a different app is refused.
Was this helpful?
Thanks for your feedback!