Skip to main content
Scope types are the static schema facts that tell Alfiz what kinds of resources exist in your application and how they nest. They are declared once in the catalog and consulted at every grant write and permission check. Granting a permission at a resource type you never declared is a validation error rather than a silent success.

Scope types vs. scope instances

The catalog declares scope types, which are the shapes. Your application data holds scope instances, which are the individual resources. The distinction matters: A scope instance id is always <scopeType>:<instanceId>. The instance id (42) is an opaque string. It should be a primary key or UUID, and never a path. The hierarchy is stored in your database as parent pointers, not encoded in the id:
Moving a resource (changing its parent pointer in your database) automatically re-resolves all grants on it at check time. No grants need to be rewritten when a document moves from one folder to another.

The global scope

The global scope * is built into every catalog. A permission grantable only at *, meaning one with no scope types declared, applies across your entire application, regardless of which resource the check names. You do not declare * in scopeTypes. For flat applications with no resource hierarchy, you do not need to declare any scope types at all. Every permission defaults to global-only grantability, and checks pass or fail based solely on whether the actor holds the permission globally.

Declaring scope types: ScopeTypeInput

Add scope types to the scopeTypes record in your CatalogInput. Keys follow the same dotted-segment format as permission keys (docs.folder, docs.doc), and must fall within a declared namespace.
string
Human-facing description of what this scope type represents, shown in admin surfaces and permission pickers.
ScopeType | null
The expected parent scope type for instances of this type. Use null for top-level types whose instances parent directly to *. This is a commitment and not a hint. Declaring parent: null means the ancestor chain for every instance of this type is exactly [instance, "*"], which lets the runtime check these synchronously without an async ancestry lookup.For recursive hierarchies (folders inside folders), set the parent to the same type: { parent: "docs.folder" }. There is no “undeclared” state: omitting parent is identical to writing parent: null, and so carries the same flat-instance commitment. Declare it explicitly.
boolean
default:"false"
Enables multi-parent instances for this scope type. With multi-parent on, an instance’s effective access is the union of all its parents’ access, so a user with access to any one parent of a shared document has access to the document.Multi-parent is off by default because it is a meaningful widening: in most products, a file having two parent folders should not mean that access granted in either folder propagates to the file. Use multi-parent explicitly for products where that union is the correct behavior, such as shortcuts, labels-as-folders, or cross-project sharing models.
object
Declares that grants at instances of this scope type may be requested by end users. Nothing is requestable by default; you opt in here.When set, the request form for this scope type shows the configured prompts (justification fields), respects maxDurationMs as a ceiling on how long a request may propose to run, and requires an expiry when requireExpiry is true. The policy field is required and must declare at least one approval stage.

Folder and document hierarchy: a complete example

Per-scope-type grantability

The scopes field on PermissionLeafInput (and GroupInput) controls which scope types a permission can be granted at. Alfiz validates this at the grant write path. Attempting to grant a permission at a scope type it never declared is a hard error and not a silent no-op.
Wildcard patterns follow the same rule at a coarser granularity: a wildcard grant at a scope type is valid when at least one matched leaf is grantable at that type.

Single-parent vs. multi-parent

Each instance has exactly one parent. Access flows strictly up the chain, so a grant on a folder covers everything inside it, and a grant on a document covers only that document.
This is the right model for most hierarchical products. It is the default, so you do not need to say anything.
Scope type keys must fall within a declared namespace. docs.folder is valid when docs appears in namespaces. A scope type referencing an undeclared namespace is a boot-time error from defineCatalog.