Skip to content

Custom Roles and Entities

When creating a module, you can define custom data entities and custom module roles. Both are configured in a JSON file and are used to build the module-specific permission model.

How It Works

  • data defines the custom entities your module works with.
  • roles defines which CRUD actions a role can execute on those entities.
  • Each custom module role is mapped to a platform role via baseRoles.
  • If a user has that platform role, the corresponding module role is included in the module permission token.

Updates for already published modules

If the roles JSON is updated after a module is already published, the platform must iterate through all installed module instances. Depending on the scope of the change and the number of installations, there can be a delay between publish and when the updated permissions are available in the module.

Available Base Roles

  • Organization level: OrganizationAdmin, OrganizationMember
  • Location level: FarmManager, Agronomist, Advisor, FarmWorker

All of these roles can be used as baseRoles values. Currently, module roles are still mapped only to organizationId, because locationId is not included in the module permission token yet.

JSON Structure

The configuration file contains two top-level arrays:

  • data: List of module entities (name, intention, visibility, referenced API)
  • roles: List of module roles with mapped baseRoles and CRUD permissions

Module-to-module communication

internalOnly and environmentVariableKey are required for module-to-module communication.

  • internalOnly: false allows other modules to query and share this module's data entities.
  • If this feature is used, a shared environmentVariableKey must be configured so the platform can route requests from other modules to the correct backend.
permission.json
{
  "data": [
    {
      "name": "Season",
      "intention": "datatype to exchange information about seasons",
      "internalOnly": false,
      "environmentVariableKey": "SEASON_API"
    },
    {
      "name": "BlockPlantLayout",
      "intention": "datatype to exchange information about block plant layouts",
      "internalOnly": false,
      "environmentVariableKey": "SEASON_API"
    }
  ],
  "roles": [
    {
      "name": "SeasonAdmin",
      "baseRoles": ["OrganizationAdmin", "FarmManager", "Agronomist"],
      "permissions": {
        "create": ["Season", "BlockPlantLayout"],
        "read": ["Season", "BlockPlantLayout"],
        "update": ["Season", "BlockPlantLayout"],
        "delete": ["Season", "BlockPlantLayout"]
      }
    },
    {
      "name": "SeasonReader",
      "baseRoles": ["Advisor"],
      "permissions": {
        "create": [],
        "read": ["Season", "BlockPlantLayout"],
        "update": [],
        "delete": []
      }
    }
  ]
}

Reserved entity names

Do not use platform-internal entity names for custom module entities. For example, names like season or blockPlantLayout are reserved and must not be reused.

Module Permission Token Example (FarmManager)

Based on the permission.json example above, a user with the platform role FarmManager would receive the mapped custom module role SeasonAdmin.

Example modulePermissionToken payload
{
  "tokenType": "HvPlattformToken",
  "ModuleRolesAndPermissions": {
    "FarmOrganizationId": "00000000-0000-0000-0000-000000000000",
    "UserId": "00000000-0000-0000-0000-000000000000",
    "ModuleId": "00000000-0000-0000-0000-000000000000",
    "RoleNames": ["SeasonAdmin"],
    "ExecuteEndpointPermissionNames": [
      "season-create",
      "season-read",
      "season-update",
      "season-delete",
      "blockplantlayout-create",
      "blockplantlayout-read",
      "blockplantlayout-update",
      "blockplantlayout-delete"
    ],
    "DataAreaEndPointPermissionNames": ["FarmOrganization"]
  }
}