Who can see which rows

Permissions · 5 min read ·

When a table is shared, three questions come up in order. Who may open it? Who may change it? And is there anything in it that some people should not see? Appdor answers them at three levels: the role someone holds in an app, a grant on a particular table, and a grant on a particular field. This post describes what each level decides, where the rule is enforced, and one thing it does not do.

Roles come first

Every member of an app holds one of five roles. The names you see in the interface are Owner, Admin, Builder, Editor and Read-only. In short:

Seats follow from the same capabilities. A role takes a paid editor seat if it holds any write capability, and Read-only holds none, so a viewer does not count. The plan catalogue states that read-only viewers are free at any number on every plan. Editor is the one that surprises people: it cannot write rows, but it can rewrite pages, so it counts as an editor seat.

Where the rule is enforced

A filter in the interface is only a request. Appdor's rows live in a database table behind row-level security, and the same API the app uses is reachable directly with the same credentials, so a restriction that existed only on screen could be walked around. The file that introduced per-table permissions says this in its first lines, and docs/roles.md states that every cell of the capability matrix is enforced in the database, not the interface.

The refusals are written as restrictive policies, which are combined with every other policy rather than added to them. That matters because ordinary policies only ever grant more access; a denial has to be restrictive to hold. Because the rule is in the database, a button that is visible to someone who may not use it still ends in a refusal.

Table access: four levels

For each table, a person ends up with one of four levels: No access, View only, Edit own records or Edit all records. In the grant screen their descriptions read: cannot see the table, its fields or any of its records; can read everything and change nothing; can add records and edit or delete the ones they created; and can add, edit and delete any record.

The level comes from the first of these that applies: a grant naming the person, the strongest grant from a team they belong to, a grant naming their role, the role's own default, and finally being the table's creator. A table can also be marked Private table, in which case the role default is skipped: only the creator and people, teams or roles that were explicitly granted access can open it.

Edit own records is the nearest thing to a row rule, and it is a precise one. It compares each record's creator with the person acting. It restricts changing and deleting, not reading: someone with that level can still read the whole table.

Field access: hidden means absent

A table grant says nothing about individual columns, so a field can carry its own level: Hidden, Read only or Can edit. The description of Hidden is that the field is not returned at all, absent from the row rather than blank. A field with no grants is as open as its table, so adding a restriction to one column does not lock the others. A write that touches a field you may not edit is refused rather than silently dropped. Before you rely on it, the permissions panel can show a record as a chosen person would see it, with a count of withheld and read-only fields. Per the plan catalogue, field permissions are off on the Free and Pro plans and on for Business and Enterprise.

What it does not do

Reading is decided per table, not per row. We found no rule in the database policies that lets one member read some rows of a table and not others. If some rows must stay invisible to some colleagues, the honest design is a separate table with its own grant, or a private table.

Customers are a different case. A portal user reaches rows through a separate service that applies the portal's record filter and owner binding on the server, and returns only the fields the portal names. The customer-facing portal screen is read-only.

If you are handing out access this week, start with one table and test it as the person who will use it. See Appdor