Skip to content

Registering Resources

Permissions attach to resources (your modules: loans, invoices) and actions (read, approve…). Before an admin can grant anything, those must exist. IAM registers them for you at startup, from two merged sources — both idempotent, both additive-only.

With iam.resources.scan-annotations: true (the default), IAM harvests every @RequiresPermission on your request handlers:

@RequiresPermission(resource = "loans", action = "approve")

…and registers the loans resource with an approve action. Protecting an endpoint is the declaration. Field references (field = "ssn") register resource fields the same way. A field code must match the DTO’s serialized (camelCase) JSON name — a ssn code guards the ssn JSON property; a snake_case code like borrower_ssn matches nothing and silently fails open in the React guards.

For metadata the annotations can’t express — display names, descriptions, sensitive fields, actions that have no endpoint yet:

iam:
resources:
definitions:
- code: loans
display-name: Loan Book
description: Loan origination and servicing
actions: [read, create, update, approve, disburse, export]
fields:
- code: ssn
display-name: Borrower SSN
sensitive: true
- code: loanAmount

When a resource appears in both sources: declared metadata wins, action and field sets are unioned. So a forgotten yml action that exists on an endpoint still gets registered.

Unknown action codes (like disburse) are created as non-system WORKFLOW actions — the seeded catalog already covers CRUD and standard cross-cutting verbs. Recategorize via the actions API if needed.

What registration deliberately does NOT do

Section titled “What registration deliberately does NOT do”
  • It never grants permissions. Registration makes resources assignable; authorization is an explicit admin decision in the permission matrix.
  • It never deletes or renames. Restarts are additive-only — removing an annotation won’t drop a resource an admin may still reference.

Registration runs right after IAM’s seed step (default tenant, system actions), into the default tenant — the same place IAM’s own admin resources live. In multi-tenant setups, per-tenant resource fan-out remains an admin/API operation.

iam:
resources:
enabled: false # no registration at all
# or:
scan-annotations: false # yml declarations only