Skip to content

Manifest Schema

Manifests are YAML files in the manifests/ directory (recursive). Every manifest has the same three top-level keys:

yaml
apiVersion: aperture.itsjool.com/v1
kind: <Kind>
metadata:
  name: <name>
spec:
  ...

Seven kinds are available: Entity, FrameworkConfig, ApiVersionConfig, AbacPolicy, RoleDefinition, PrincipalAttributeDefinition, and Migration.


Entity

The most common kind. Defines a domain entity with fields, permissions, policies, and hooks.

yaml
apiVersion: aperture.itsjool.com/v1
kind: Entity
metadata:
  name: Invoice              # PascalCase; becomes the JSON:API type "invoice"
spec:
  description: "..."         # optional — included in generated OpenAPI
  tenantScoped: true         # default: false
  optimisticLocking: false   # default: false
  softDelete: false          # default: false
  plural: invoices           # optional — overrides default pluralisation
  fields: { ... }
  permissions: { ... }
  policies: { ... }
  hooks: { ... }
  mcp: { ... }               # optional — entity-level MCP override

spec.fields

Each key under fields is a field name (camelCase). Each value is a field definition:

PropertyTypeDefaultDescription
typestring, decimal, integer, boolean, uuid, datetime, refRequired. Maps to a Java and SQL type
requiredbooleanfalseGenerates NOT NULL constraint and Elide validation
uniquebooleanfalseGenerates a unique index
indexbooleanfalseGenerates a non-unique index
encryptedbooleanfalseStores value as AES-256-GCM ciphertext
sincestring (version number)nullField is only visible in API v{since}+
renamedFromstringnullOld column name — generates renameColumn changeset
relationManyToOne, OneToManynullRequired when type: ref
targetstring (entity name)nullRequired when type: ref
mappedBystring (field name on target)nullRequired for OneToMany side of a bidirectional relationship
descriptionstringnullIncluded in generated OpenAPI
enumlist of stringsnullGenerates an IN (...) validation and OpenAPI enum

type: ref notes: ManyToOne generates an FK column ({fieldName}_id). OneToMany with mappedBy generates no column — it's the inverse side of a relationship declared on the target entity.

spec.permissions

Role → list of operations. Operations: create, read, update, delete.

yaml
permissions:
  Admin:      [read, delete]
  Accountant: [create, read, update]
  Viewer:     [read]

OR semantics: a user with any matching role gets access. Roles not listed get no access for that operation.

Reserved names: SuperAdmin and TenantAdmin are platform authorities, not domain roles. They cannot appear in permissions — the build will fail if you reference them here. See Auth & Identity.

spec.policies

Policy name → list of operations. References AbacPolicy manifests by metadata.name.

yaml
policies:
  FinanceTeamOnly: [read, update]
  EuRegionOnly:    [read, update]

AND semantics: all policies listed for an operation must pass. Combined with RBAC: role check first (OR), then all policy checks (AND).

spec.hooks

Hook name → hook definition. Multiple hooks per phase are supported.

PropertyTypeValuesDescription
phasestringPRESECURITY, PREENRICH, PRECOMMIT, POSTCOMMITWhen the hook fires
asyncbooleantrue = fire-and-forget; false = await response
onFailurestringreject, warn, passthroughBehaviour on non-2xx or error
urlstringHTTP/HTTPS URLEndpoint Aperture calls

spec.mcp (entity-level override)

yaml
mcp:
  enabled: false      # set false to exclude this entity from MCP tools
  tools: [list, get]  # override which tools to generate for this entity

Boolean spec fields

FieldDefaultEffect when true
tenantScopedfalseAdds aperture_tenant_id column; auto-filters all queries
optimisticLockingfalseAdds version column; requires If-Match on mutations
softDeletefalseAdds deleted_at column; filters deleted_at IS NULL

FrameworkConfig

One per project. Sets tenancy mode, default roles, and MCP configuration.

yaml
apiVersion: aperture.itsjool.com/v1
kind: FrameworkConfig
metadata:
  name: config
spec:
  tenancyMode: pool           # pool (default) | none
  defaultRoles:               # domain roles assigned to every new user
    - Accountant
    - Viewer
  # Note: TenantAdmin and SuperAdmin are platform authorities — do not list them here
  mcp:
    enabled: true
    transport: stateless      # stateless (HTTP) is the only supported transport
    tools: [list, get, create, update, delete]

ApiVersionConfig

Declares API versions. Aperture uses the versions declared here to generate versioned entity classes and to detect breaking changes.

yaml
apiVersion: aperture.itsjool.com/v1
kind: ApiVersionConfig
spec:
  versions:
    "1":
      status: ACTIVE
    "2":
      status: ACTIVE

Version names are strings. status is ACTIVE or SUNSET. Sunset versions still serve requests but display a deprecation warning in the response headers.


AbacPolicy

Defines a named ABAC rule using SpEL. Referenced by name in spec.policies on an entity.

yaml
apiVersion: aperture.itsjool.com/v1
kind: AbacPolicy
metadata:
  name: FinanceTeamOnly
spec:
  description: "Finance team members only"
  expression: "#user.securityAttributes['department'] == 'finance'"

SpEL context: #user is the AperturePrincipal. Available properties:

  • #user.securityAttributes['key'] — security attribute map (from the securityAttributes JSONB column, admin-assigned)
  • #user.rolesSet<String> of role names
  • #user.tenantId — tenant ID string
  • #user.userId — user ID string

RoleDefinition

Declares the named roles available in the system. Referenced in permissions and assigned to users.

yaml
apiVersion: aperture.itsjool.com/v1
kind: RoleDefinition
metadata:
  name: roles
spec:
  roles:
    Admin:
      description: "Full access within tenant"
    Accountant:
      description: "Financial operations"
    Viewer:
      description: "Read only"

Reserved names: SuperAdmin and TenantAdmin cannot be declared here — they are platform authorities managed via POST /manage/tenants/{id}/tenant-admins/{userId}, not domain roles.


PrincipalAttributeDefinition

Declares the security attribute keys that ABAC policies may reference. Definitions flow into the runtime to validate attributes on users, service accounts, and personal API keys.

yaml
apiVersion: aperture.itsjool.com/v1
kind: PrincipalAttributeDefinition
metadata:
  name: principal-attributes
spec:
  securityAttributes:
    department:
      type: string
      allowedValues: [finance, engineering, sales, ops]
      personalKeyDelegation: exact     # API keys may only carry the user's exact value
      serviceAccountAssignable: false
    region:
      type: string
      allowedValues: [us, eu, apac]
      personalKeyDelegation: exact
      serviceAccountAssignable: true
    clearance:
      type: string
      allowedValues: [public, confidential, secret]
      personalKeyDelegation: exact
      serviceAccountAssignable: true
PropertyTypeDefaultDescription
typestringstringAttribute value type (currently string)
allowedValueslist of strings[]If non-empty, values are validated against this list on assignment
personalKeyDelegationexactexactHow API key attribute delegation is validated. exact means the key may only carry the user's current value
serviceAccountAssignablebooleanfalseWhether this attribute may be assigned to a service account

Attributes referenced in AbacPolicy expressions that are not declared here are still evaluated — the definition is for validation on write, not enforcement on read.


Migration

Manual SQL migration with rollback. Included in the Liquibase changelog at the position specified.

yaml
apiVersion: aperture.itsjool.com/v1
kind: Migration
metadata:
  name: backfill-phone-number
spec:
  position:
    after: create-customer-table    # changeset ID to insert this migration after
  sql: |
    UPDATE aperture_customers
    SET phone_number = '000-000-0000'
    WHERE phone_number IS NULL;
  rollback: |
    UPDATE aperture_customers
    SET phone_number = NULL
    WHERE phone_number = '000-000-0000';

position.after references a Liquibase changeset ID (the id= attribute). Run mvn liquibase:status to list changeset IDs. The migration is applied once and tracked by Liquibase.