Layouts, Sidebars & Access
Two page properties sit outside the component tree: layout wraps the body in chrome, and access decides who is allowed to load the page at all.
The layout Block
layout currently holds one key, sidebar — an array of sidebar sections rendered in the page's <aside>. Each section binds to a table and emits one entry per record.
| Section property | Description |
|---|---|
dataSource |
Required. { table, filter, sort } — a deliberate subset of the full data source. |
template |
Required. How each record renders as an entry (see below). |
activeIndicator |
Highlights the entry matching the active scope. |
template is where the per-record expressions live:
template property |
Description |
|---|---|
label |
Entry label, supporting $record.<field>. |
href |
Entry link target, supporting $record.<field>. |
archivedField |
Field whose truthy value hides the entry from the sidebar. |
activeIndicator accepts exactly one value — $currentUser.activeAssignment — which marks the entry matching the tenant switcher's current scope.
pages:
- name: Workspace
path: /workspace
layout:
sidebar:
- dataSource:
table: projects
sort: [{ field: name, direction: asc }]
template:
label: '$record.name'
href: '/workspace/$record.slug'
archivedField: archived
activeIndicator: '$currentUser.activeAssignment'
components:
- { type: container, element: main }Data-Bound Sidebars
A sidebar filtered on $currentUser.assignments.<table> renders only the records the signed-in user is assigned to; a global admin (isUnrestricted) sees them all. Unlike a page-level data source, a sidebar section that cannot resolve its $currentUser reference is dropped silently rather than failing the request — the page still renders, minus that section.
Access Control
access gates the page. It takes one of four forms:
| Form | Meaning |
|---|---|
'all' |
Everyone, including anonymous visitors. The default. |
'authenticated' |
Any signed-in user. |
['admin', 'editor'] |
Those role names. At least one entry. |
{ require, redirectTo } |
Any of the above as require, plus a redirect target. |
A role-array entry may also be a group reference, group:<name>, validated against app.auth.groups.
pages:
- name: Billing
path: /billing
access: { require: authenticated, redirectTo: /login }
components:
- { type: text, element: h1, content: 'Billing' }What a Denial Returns
| Configuration | Anonymous or unauthorized visitor gets |
|---|---|
access with redirectTo |
302 to that path, with ?redirect=<original path> appended. |
access without redirectTo |
404, so the page's existence is not disclosed. |
access never answers 401. It redirects or hides. The only source of a 401 on a page is an unresolvable $currentUser reference in a data source — two different mechanisms with two different answers.
Related Pages
- Pages Overview — the full page property table.
- Data Binding —
$currentUserscoping and its401. - Roles & RBAC — the role names
accessaccepts. - Groups — the
group:referencesaccessaccepts. - Layout Components — the
sidebarcomponent rendered inside the body.
Last updated September 1, 2026
This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta. Contributions and corrections are welcome.