Skip to content

Give each client their own view

Business planAdmin

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:

  1. A list holding the rows, with a column naming the client each row is for.
  2. A published app reading from it. See Show collected data in your app.
  3. An access mode that identifies people. See Control who can use your published app.
  4. Who sees which rows.

Steps

  1. Open the app in Build and publish it if you have not already.
  2. In Who can see it, set the access mode to email sign-in or workspace members.
  3. 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.
  4. In Who sees which rows, choose the column naming who each row belongs to. The default is Everyone sees every row.
  5. 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.

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.

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.

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 your records directly, no list to maintain

Section titled “Read your records 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 Onplana, in your CRM or on their projects, a data view can read it there, so nothing is copied and nothing goes stale.

Steps

  1. In the Data panel, under Or show each client their own records, pick a source: Clients, Contacts, Deals, Projects, Tasks, Milestones, Issues or Recurring charges. The view appears the same way a list view does.
  2. 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, location and currency; a contact’s name, email, phone, title and whether they are the primary contact; 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. The delivery sources and recurring charges have their own sections below.
  3. Publish, and set the access mode to email sign-in or workspace members.

There is no Who sees which rows setting on these views, 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.

Projects, Tasks, Milestones and Issues turn a portal into a delivery view: each client sees where the work you are doing for them stands.

Source Fields you can publish
Projects Name, Status, Progress, Start date, End date
Tasks Title, Status, Progress, Start date, Due date, Completed at, Project
Milestones Title, Due date, Completed, Completed at, Project
Issues Title, Type, Severity, Status, Reported, Target fix date, Resolved, Project

These views reach a client through the project. A task, milestone or issue is shown to a client only when its project is linked to that client, so a project with no client attached shows nothing to anyone. An issue filed with no project is never shown either.

A project created from a won deal is linked to the deal’s client automatically. For any other project, open Edit Project, tick Billable client work, and choose the client in Client. The Client picker appears only while Billable client work is ticked.

Once a project is linked, every task, milestone and issue on it becomes visible to that client, including the ones you think of as internal. There is no per-item setting. A title is free text, and only you can judge how “Chase Acme for the unpaid invoice” reads to Acme. The Data panel says this in amber on every delivery view. Rename or move anything a client should not see before you publish a field.

On a task, the description, assignee, priority, estimated hours and every cost field are not on the field list and cannot be ticked. Neither are a project’s description, budget and fee terms, or an issue’s description, resolution and the people on it.

Recurring charges shows a client the licences and subscriptions they pay you for: the lines on their client record and on their projects. The fields on offer are Charge, Amount, Currency, Recurrence, Starts, Ends and Renews. Recurrence arrives as ONE_OFF, WEEK, MONTH, QUARTER or YEAR, and Renews is null for a line that will not renew again, such as a one-off.

See Track resale margin for adding the lines.

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.