Skip to content

Reserved names

The engine owns four small namespaces. A name in one of them is refused at compile time, with the file, line, and column of the declaration that used it.

Five role names belong to the engine. No application may declare any of them. Two of the five may still be named in an access: rule.

Name In an access: rule Meaning
public yes admits anybody, including a visitor with no session
authenticated yes admits anybody holding a role in this application. A login with no role here is anonymous here
owner no reserved for row ownership. It has no row condition yet, so a rule naming it admits nobody
anonymous no the engine’s own name for a visitor with no session
tenant_admin no the authority to administer the organization the application is installed in
role tenant_admin "Verwaltung" // compile error: reserved by the engine
access: tenant_admin // compile error: reserved by the engine

For owner, write the ownership rule your application means:

access {
author where owner = :user.id
}

For anonymous, write access: public.

For tenant_admin, declare an ordinary role. The tenant administrator flag is a flag on a login, it is granted per organization, and it grants nothing inside an application. Read Who administers an organization.

Every address the engine serves lives under one segment: /matterdata. A page route: may not start with a reserved segment, an app mount may not be one, and a slug is never derived as one.

Segment Why Where
matterdata every engine page see below
page the paginator. The engine appends /page/{n} to a paginated listing’s own route, and for a page at / that is /page/{n} the application’s own route
robots.txt a crawler looks for it at the root and nowhere else the organization’s root
sitemap.xml the same the organization’s root

Four segments is the whole list, and it does not grow when the engine gains a page. That is the point of the namespace: a new engine page costs no reserved word and breaks no application.

Most engine addresses belong to the organization and answer at its root. One login, one administration page and one stylesheet serve every application the organization holds.

Address What it is
/matterdata the organization’s administration page
/matterdata/login, /matterdata/logout the organization’s door
/matterdata/logins, /matterdata/jobs, /matterdata/reset the administration page’s own sections
/matterdata/appearance, /matterdata/timezone the reader’s color scheme and time zone
/matterdata/static/…, /matterdata/theme.css the engine’s assets and the organization’s accent

Two engine addresses belong to one application and answer under its mount, as /<mount>/matterdata/…:

Address What it is
/<mount>/matterdata/scope switches an application-wide scope
/<mount>/matterdata/blob/… serves an image

Both resolve a name against one application’s model. A blob address names a table, and two applications may each declare events; the scope address writes the value of one application’s scope. Neither question has a single answer at the organization’s root.

The engine used to answer at nine segments of its own. They moved under /matterdata and are still reserved, so an application cannot take an address a browser or a bookmark may still point at.

Old address New address
/login, /logout /matterdata/login, /matterdata/logout
/verwaltung /matterdata
/verwaltung/zugaenge /matterdata/logins
/verwaltung/aufgaben /matterdata/jobs
/verwaltung/zuruecksetzen /matterdata/reset
/darstellung /matterdata/appearance
/zeitzone /matterdata/timezone
/auswahl /<mount>/matterdata/scope
/blob/… /<mount>/matterdata/blob/…
/static/…, /theme.css /matterdata/static/…, /matterdata/theme.css

/login, /logout and /verwaltung answer a permanent redirect, because a person types and bookmarks those. The others are form actions and asset addresses that no person types.

The redirect wins over a page whose route starts with a parameter. In an application at mount: / with route: /{slug}, the address /login is the redirect, and a row with the slug login, logout or verwaltung cannot be reached at the root. Every other slug is the page’s.

An image reference in a markdown column keeps working. The engine accepts the old /blob/… spelling and renders the new address, so no stored text has to be rewritten.

Three segments the engine never served are free for an application now: abmelden, einloggen and feed.

This list also refuses a defaulted mount. An application called matterdata is mounted at matterdata unless it says otherwise, so it must declare a mount:.

The same word may still be a role name. A role lives in one application’s vocabulary and a path segment lives in a URL, so role verwaltung "Verwaltung" compiles and route: /verwaltung does not.

A table name that starts with mtd_ is refused. The engine’s own tables live in that namespace: the logins, the sessions, the stored model, the blob index, and the audit log. The comparison ignores case, because SQLite identifiers do: MTD_Session and mtd_session are one table.

A table name that starts with edg_ is refused too. That was the engine’s namespace before 2026-09-23, and a tenant file from before that date holds its engine tables under it until the engine renames them on the first open.

An application name inside that namespace is refused too. The engine stores a table as <app>__<table>, so app mtd would write mtd__members and app mtd_shop would write mtd_shop__members. Both land where the engine keeps its own tables. See App mount.

The engine owns ten query parameters. A search: or filter: column may not carry one of these names, because a filter’s request parameter is named after the column it filters.

Parameter Control it belongs to
q the search box
sort the column sort
dir the column sort direction
mtd_export the CSV, workbook, or calendar export, by the region’s name: ?mtd_export=members, ?mtd_export=events.ics
edg_export the same export, under its name before 2026-09-23. The engine still reads it, so a calendar subscribed before then keeps working, and never writes it
mtd_copy the duplicate action of a form
mtd_rows the rows of a sheet, as data for its editing grid
mtd_dialog a page without its frame, for an add_via: dialog
mtd_compare two versions of the page’s record, compared by a versions region
mtd_restore the page’s form, filled with one version of its record by a versions region