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, tag: 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 July 27, 2026
This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta — contributions and corrections are welcome.