backends.radiatordb.collection
collection
Defines a document collection within a RadiatorDB backend. Collections organize documents into logical groups and define their field schema for Radiator UI and RadiatorDB REST API. Each collection must define a key block that contains one or more ordered key fields.
Context
Valid inside a radiatordb block.
Example
collection "users" {
roles {
read "support";
write "ops";
}
name "Users";
description "WiFi users and support-managed credentials";
key {
field {
name "Username";
type text;
}
}
field "passwordHash" {
name "Password Hash";
type password;
required true;
}
field "email" {
name "Email";
type text;
}
field "enabled" {
name "Enabled";
type boolean;
default true;
}
action "send-coa" {
name "Disconnect";
icon "Bolt";
buttonText "CoA";
tooltipText "Open the CoA disconnect form.";
description "Send a disconnect request for this user.";
field "reason" {
name "Reason";
type text;
}
roles {
allow "ops";
}
@execute {
set vars.username doc | jsonpath("$.username");
invoke "SEND-COA";
}
}
}
Collection Options
| Option | Required | Description |
|---|---|---|
name | No | Human-readable display name for Radiator UI |
description | No | Description text shown in Radiator UI |
timeseries | No | Time-series PostgreSQL storage |
revisions | No | Archived revision cleanup limits for normal storage |
roles | Yes | Grants read and write access to specified RadiatorDB roles |
key | Yes | Ordered key definition with one or more key fields |
field | No | Zero or more payload field definitions |
action | No | Zero or more document actions shown in Radiator UI |
name
Sets the display name shown in Radiator UI for this collection. If omitted, the collection identifier (the quoted string after collection) is used.
name "Users";
description
Provides a description for the collection displayed in Radiator UI.
description "WiFi users and support-managed credentials";
timeseries
The timeseries feature is experimental.
Configures time-series PostgreSQL storage for the collection. If omitted, the collection uses normal mutable storage with archived revisions.
Use this block for time-series storage:
timeseries {
partition calendar-month;
create-ahead 2;
overflow quarantine;
}
Time-series collections are immutable. They do not support expiration, rename,
soft delete, revision queries, or revision garbage collection.
AAA backend pipeline query operations also do not support time-series
collections. Management API reads remain supported.
Do not configure a revisions block with timeseries. Revision cleanup limits
apply only to normal mutable collections.
The time-series parameters are:
partitionselectscalendar-hour,calendar-day,calendar-week, orcalendar-month. Hourly partitions start at the top of each UTC hour. Weekly partitions start at Monday 00:00 UTC. The default iscalendar-month.create-aheadcreates the current interval and this many complete future intervals. The allowed range is0..=120. The default is2.overflowselectsquarantineorerror. The default isquarantine.
When overflow is error, set create-ahead to at least 1. Radiator rejects
create-ahead 0 with overflow error because inserts would fail at the next
partition boundary.
Radiator creates this finite partition window during startup. Long-running processes do not extend the window automatically.
revisions
Configures archived revision cleanup for a normal mutable collection. If you omit this block, garbage collection keeps all archived revisions for the collection.
revisions {
age 30d;
max 100;
}
The revisions block supports these optional parameters:
ageremoves archived revisions older than the configured duration. If omitted, RadiatorDB does not remove revisions based on age.maxkeeps at most this many archived revisions for each document key. If omitted, RadiatorDB does not remove revisions based on count.
Garbage collection removes a revision when it exceeds either configured limit. The block does not change tombstone garbage collection.
roles
Grants RadiatorDB roles read or write access to this collection. Roles are
matched against the authenticated user's RadiatorDB roles, which are populated
by the AAA pipeline (for example, from a RadiatorDB lookup exposing
user.radiatordb_role).
roles {
read "support";
write "ops";
}
readroles can list and view documents.writeroles can create, edit, and delete documents. Awriterole also implicitly grants read access.- A collection must configure at least one
readorwriterole. The parser rejects collections without arolesblock or with an emptyrolesblock.
field
Defines a typed payload field within the collection. Each field is identified by its JSON field name (the quoted string after field).
When a collection declares one or more field blocks, every write validates the
document against that schema, including AAA backend pipeline put queries, the
Radiator UI, and the REST API. Required
fields must be present, typed values must match their declared type, and any
field name not in the schema is rejected. Collections with no field
declarations accept arbitrary JSON document bodies.
field and action blocks share the same ordered namespace in a collection.
Radiator UI renders visible fields and actions in the configured order.
Do not reuse a field or action identifier within the same collection. You may
reuse an action identifier in a different nested list field.
action
Defines an invokable action for each document in the collection. Actions are
shown in Radiator UI tables and document detail pages when the authenticated
user can read the collection and has one of the action's roles allow roles.
Actions can run for active and soft-deleted documents.
action "send-coa" {
name "Disconnect";
icon "Bolt";
buttonText "CoA";
tooltipText "Open the CoA disconnect form.";
description "Send a disconnect request for this user.";
roles {
allow "ops";
}
@execute {
invoke "SEND-COA";
}
}
The action identifier is the quoted string after action. The optional name
sets the full action label used for the accessibility label and confirmation
dialog title. If name is omitted, the identifier is used. The
optional description is shown in the confirmation dialog. If description is
omitted, the UI shows a generic confirmation prompt.
Set icon to a supported Radiator UI icon name. Unknown icon names are not
configuration errors; the UI falls back to its default action icon.
Set buttonText when the visible button copy should be shorter or different
from the full action name. Labeled buttons render buttonText inline next to
the icon. If buttonText is omitted, labeled buttons render the action name.
Set tooltipText to show a tooltip for the action button. Tooltips
are opt-in; if tooltipText is omitted, action buttons do not show a tooltip.
key
Defines the ordered document key fields for the collection. The stored key is multipart when more than one key field is configured.
key {
field {
name "Site";
type text;
}
field {
name "Created At";
type datetime;
}
}
Key field types
Set type to one of the following values:
| Type | Description |
|---|---|
text | Free-form text string. |
password | Password-style value. |
secret | Secret-style value (e.g. API key or token). |
number | Numeric value (integer or decimal). |
boolean | Boolean value (true or false). |
datetime | RFC3339 date-time string. Example: "2026-12-31T23:59:59Z" for a termination date. |
uuid | RFC UUID string. Stored in canonical form. |
uuid7 | RFC UUID version 7 string. Stored in canonical form. |
ip | IPv4 or IPv6 host address string. Stored in canonical form. |
network | IPv4 or IPv6 CIDR network string. Stored in canonical form. |
mac | MAC address string. Stored in canonical form. |
enum | Enumerated value. Allowed options must be defined with value directives. |
Key normalization
RadiatorDB validates typed key values before storing a document. These key types are also normalized:
ip: Stored in canonical IP address form.network: Stored in canonical CIDR form. A bare IP address becomes a host network with/32or/128. CIDR values must not contain host bits.uuidanduuid7: Stored in canonical lowercase hyphenated UUID form.uuid7accepts only UUID version 7 values.mac: Accepts common formats such asAA:BB:CC:DD:EE:FF,AA-BB-CC-DD-EE-FF, andAABB.CCDD.EEFF. Stored as 12 lowercase hex digits, for exampleaabbccddeeff.
When Radiator UI opens a new document form, key fields with type
datetime, uuid, or uuid7 get an initial generated value if no explicit
default value is configured.
Field Options
| Option | Required | Description |
|---|---|---|
name | No | Human-readable display name for the field |
type | Yes | Field data type |
item-type | No | List item validation mode (only valid for list type) |
required | No | Whether the field is mandatory. Default: false |
masked | No | Hides the stored value on read. Default: false |
default | No | Default value for new documents |
value | No | Allowed enum option (repeatable for enum fields or list items) |
field | No | Nested field definition (only valid for list type) |
action | No | Nested action definition (only valid for list type) |
Field name
Sets the display name for the field in Radiator UI:
field "macAddress" {
name "MAC Address";
type text;
}
Field type
Specifies the data type for the field. Required for every field definition.
| Type | Description |
|---|---|
any | Any JSON value, including strings, numbers, booleans, null, objects, and arrays. |
text | Free-form text string. |
hex | Binary value stored as lowercase hexadecimal with a 0x prefix. |
password | Password field. Displayed masked in Radiator UI. |
secret | Secret value (e.g. TOTP secret, API key). Displayed masked in Radiator UI. |
number | Numeric value (integer or decimal). |
boolean | Boolean value (true or false). |
datetime | RFC3339 date-time string. Example: "2026-12-31T23:59:59Z" for a termination date. |
ip | IPv4 or IPv6 host address string. Example: "192.0.2.10" for a static IP. |
network | IPv4 or IPv6 CIDR network string. Example: "192.0.2.0/24" for a site subnet. |
enum | Enumerated value. Allowed options must be defined with value directives. |
list | JSON array. Set item-type, or define item structure with child field blocks. |
Fields with type any accept strings, numbers, booleans, null, objects, and
arrays. Radiator UI shows these fields as JSON textareas. It parses the
textarea before saving and preserves the JSON value type.
Hex fields accept hexadecimal strings with or without a 0x prefix. RadiatorDB
stores them in lowercase with the 0x prefix. Radiator UI edits hex fields
with a text input. RadiatorDB put bindings encode raw byte values automatically.
Datetime fields accept RFC3339 and RFC2822 strings, dates, timezone-less datetimes, and Unix timestamps. Dates and timezone-less datetimes are interpreted as UTC. RadiatorDB stores all accepted datetime values as RFC3339 strings and preserves an explicit timezone offset.
required
Marks the field as mandatory when creating or editing documents through Radiator UI:
field "hostname" {
name "Hostname";
type text;
required true;
}
Default: false
masked
Hides the stored value when documents are read through the management API. Masked fields are returned as a masking sentinel rather than their real value, so sensitive data such as password hashes is never sent to the browser. The field remains editable: leaving it blank in the editor keeps the stored value unchanged, while typing a new value replaces it.
field "passwordHash" {
name "Password Hash";
type text;
masked true;
}
Masking only applies to top-level fields; values nested inside list fields are
not masked.
Default: false
default
Sets a default value for new documents. Accepts strings, numbers (including negative), and booleans:
field "enabled" {
type boolean;
default true;
}
field "deviceType" {
type enum;
default "AP";
value "AP";
value "Switch";
value "Router";
}
value (enum options)
Defines an allowed value for an enum field. Repeat the value directive for each option. Only valid when type is enum.
field "authMode" {
name "Auth Mode";
type enum;
required true;
default "PEAP";
value "PEAP";
value "TTLS";
value "EAP-TLS";
}
Nested fields
A list field defines its items with either item-type or nested field
blocks. Do not combine these forms.
Set item-type to require every list item to have exactly that type. It accepts
the same values as type, with the same validation and
canonicalization:
field "filters" {
name "Filters";
type list;
item-type text;
}
This configuration accepts a document payload such as:
{
"filters": ["allow-office", "allow-vpn"]
}
Every item in filters must be a string. A number, boolean, object, array, or
null item is rejected. item-type any accepts items of any JSON type.
Omitting item-type is equivalent to item-type any when the list has no
nested fields. The list item type requires every item to be an array but does
not validate the contents of those arrays.
Use nested field blocks to define a list of custom objects. Each list item
must be an object that follows the nested field definitions:
field "groups" {
name "Groups";
type list;
field "group" {
name "Group";
type text;
required true;
}
field "enabled" {
name "Enabled";
type boolean;
required true;
}
}
This configuration accepts a document payload such as:
{
"groups": [
{ "group": "operators", "enabled": true },
{ "group": "auditors", "enabled": false }
]
}
Nested fields support the same options as top-level payload fields. The Radiator UI displays typed items with an editor appropriate for their type and displays custom objects in a nested list view.
Nested action blocks are also valid inside list fields. The UI shows nested
actions for each item in the nested list view.
field "sessions" {
name "Sessions";
type list;
field "mac" {
name "MAC";
type text;
}
action "disconnect-session" {
name "Disconnect session";
roles {
allow "ops";
}
@execute {
set vars.session_mac item | jsonpath("$.mac");
invoke "SEND-COA";
}
}
}
Action Options
| Option | Required | Description |
|---|---|---|
name | No | Human-readable display name for the action |
icon | No | Radiator UI icon name used by Radiator UI |
description | No | Confirmation dialog text |
roles | Yes | One or more allow roles for action visibility and invocation |
field | No | Scalar input field shown in the confirmation dialog |
@execute | Yes | Pipeline to run when the action request is accepted |
Action roles
Each action must configure roles { allow "..." }. The user must have
collection read access and one of the action's allow roles. Users without an
allow role do not see the action and cannot invoke it through the REST API.
roles {
allow "ops";
allow "admin";
}
Action input fields
Action field blocks define optional confirmation dialog inputs. These fields
are not stored in the document. They are validated and exposed to the
@execute pipeline through the input local variable.
Action inputs are scalar only. Supported types are text, password,
secret, number, boolean, datetime, ip, network, and enum.
list fields and nested fields are not valid action inputs.
field "reason" {
name "Reason";
type text;
}
Action execute pipeline
The @execute block runs after the request is authorized and action input is
validated. The action succeeds only when this pipeline accepts. Reject and
ignore results make the REST API return 400.
If the pipeline sets aaa.message, for example with accept "Disconnect queued.";
or the message action, the REST API returns that message to the UI. If the
pipeline accepts without a message, the UI closes the confirmation dialog
without showing a success notification. aaa.reason and pipeline errors are
not returned to the UI because they can contain sensitive operational details.
The pipeline receives these local variables:
| Variable | Description |
|---|---|
doc | Current document payload fetched server-side. For deleted documents, this is the latest non-tombstone payload, or null if none exists. |
key | Multivalue document key parts. |
input | Validated action input object. |
item | Nested list item fetched from doc, or null for top-level actions. |
path | Nested list path array, or an empty array for top-level actions. |
deleted | Boolean that is true when the target document is soft-deleted. |
The server fetches doc and nested item by key, path, and item index. It does
not trust document or item data from the client request.
Complete Example
collection "devices" {
roles {
read "support";
write "ops";
}
name "Devices";
description "Network devices available for policy lookups";
key {
field {
name "Site";
type text;
}
field {
name "Hostname";
type text;
}
}
field "managementNetwork" {
name "Management Network";
type network;
required true;
}
field "managementIp" {
name "Management IP";
type ip;
required true;
}
field "deviceType" {
name "Device Type";
type enum;
required true;
default "AP";
value "AP";
value "Switch";
value "Router";
}
field "location" {
name "Location";
type text;
}
field "tags" {
name "Tags";
type list;
field "tag" {
name "Tag";
type text;
}
}
field "snmpSecret" {
name "SNMP Secret";
type secret;
}
field "managed" {
name "Managed";
type boolean;
default true;
}
field "vlan" {
name "VLAN";
type number;
required true;
}
field "warrantyExpires" {
name "Warranty Expires";
type datetime;
}
}