Open source ·JSON:API compliant · Apache 2.0

Build the Business Model.
Ship the API.

Write a YAML manifest describing your domain. Aperture generates a fully-compliant JSON:API server including auth, multi-tenancy, hooks, and audit while requiring zero boilerplate code and zero schema management.

Four steps from model to production

One manifest file. Everything else is generated.

1
Define your model

Describe your domain in YAML

Declare entities, fields, types, and relationships. Mark entities as tenant-scoped. This manifest is the single source of truth, with no Java or Spring config.

invoice.yaml
apiVersion: aperture.itsjool.com/v1
kind: Entity
metadata:
  name: Invoice
spec:
  tenantScoped: true
  fields:
    amount:
      type: decimal
      required: true
    status:
      type: string
      enum: [DRAFT, ISSUED, PAID]
    customer:
      type: ref
      target: Customer
      relation: ManyToOne
      required: true
2
Secure it

Declare permissions and policies

Define role-based access per operation and attribute-based policies inline. Aperture enforces them at runtime from your manifest, so there is no separate security layer.

invoice.yaml
  permissions:
    Accountant:  [create, read, update]
    Viewer:      [read]

  policies:
    FinanceTeamOnly: [read, update]
    EuRegionOnly:    [read, update]
3
Hook into the lifecycle

Attach lifecycle validation

Use a validate hook to reject invalid creates and updates before commit. Other hook types can guard, mutate, or trigger asynchronous work.

invoice.yaml
  hooks:
    ValidateInvoice:
      type: validate
      on: [create, update]
      url: http://hook-service:8080/hooks/validate-invoice
      retries: 2
4
Build and ship

Run the build. Deploy. Done.

The Maven plugin generates all Java source and Liquibase migrations. No code written by hand, no SQL to manage. Commit the lock files and ship.

terminal
# validate, generate, test, and package
$ mvn verify --no-transfer-progress

# build and start the flagship demo
$ cd demos/aperture-demo
$ mise run docker-deploy

# verify the API is healthy
$ curl --fail http://localhost:8080/actuator/health
{"status":"UP"}

Enterprise-ready. Declared, not hand-written.

Everything a production multi-tenant API needs, with a pluggable architecture so you own what matters.

Zero-boilerplate code generation

The Maven plugin generates all Spring entities, controllers, repositories, and auth filters from your manifests on every build. Regenerating from truth every time prevents drift and stale code.

Zero schema management

Aperture diffs your manifest against committed lock files and generates Liquibase migrations automatically. Add or rename a field, and the SQL writes itself. Drops are deferred so you never lose data accidentally.

MCP integration, AI-ready out of the box

Every entity gets Model Context Protocol tool stubs for list, get, create, update, and delete. AI assistants respect the same auth, tenancy, and permission rules as the REST API.

JSON:API: the full protocol, not just the format

Atomic operations, sparse fieldsets, compound documents, RSQL filtering, sorting, and pagination come standard on every entity. The open standard answers the questions your team would otherwise argue about.

GraphQL, powered by Elide

GraphQL can query the same entity dictionary under the same permissions and manifests. Traverse an invoice, its customer, and every line item in one round trip instead of chaining REST calls.

Multi-tenancy out of the box

POOL mode adds tenant isolation at the database level, with every query auto-filtered and every FK constraint tenant-aware. NONE mode serves single-tenant deployments. Same codebase, different config.

Pluggable auth and identity

JWT and API key auth built in. Implement one interface to swap in Keycloak, Okta, or any identity provider. Tenancy, RBAC, hooks, and audit stay completely unchanged.

Four lifecycle hook types

validate blocks, mutate modifies, trigger fires async, guard runs pre-auth. You implement logic over HTTP while Aperture handles signing, retries, and timeouts.

RBAC + ABAC security model

Role-based permissions and SpEL attribute policies live in the manifest. Field encryption, rate limiting, optimistic locking, and a transactional audit trail are all included.

A CLI for your API, generated

A manifest-driven, kubectl-style CLI provides verb-first CRUD for every entity, declarative apply, config profiles, and shell completion. Ship it as a fat JAR or a ~30ms GraalVM native binary. Auth is pluggable too, with OIDC device-code login available out of the box.

Every feature, at a glance

The curated tour above is the highlight reel. This is the whole inventory, grouped, linked, and ready to scan.

FeatureWhat it doesDocs
API Surface
JSON:APIAtomic operations, sparse fieldsets, compound documents, RSQL filtering, sorting, pagination.
GraphQL (Elide)The same entities, permissions, and manifests support queries, nested traversal, and mutations at /graphql/v{n}.
OpenAPI / SwaggerFull spec generated from your manifests, served at /swagger-ui.html.
API versioningACTIVE / SUNSET lifecycle per version, with deprecation headers.
MCP serverlist / get / create / update / delete tool stubs for AI assistants.
Data Model
Entities & relationshipsManyToOne / OneToMany, with mappedBy for the inverse side.
Unique & indexed fieldsField-level declarations generate unique or non-unique DB indexes.
Optimistic lockingAdds a version column, enforced via If-Match on mutations.
Soft deleteAdds deleted_at; reads are auto-filtered to live rows.
Scope partitioning (scopedBy)Partitions rows by a relationship, selected per request via header. Pair this partitioning with ABAC to gate access.
Field encryptionAES-256-GCM ciphertext at rest, transparent to API callers.
Liquibase migrationsFull-DDL and incremental changesets generated on every build.
Manifest diffingBreaking-change detection against committed lock files.
Security
JWT + API keysLogin, refresh, service accounts, and personal API keys.
Pluggable identitySwap providers behind the CredentialValidator SPI.
RBACRole-based permissions declared per entity and operation.
ABACSpEL attribute policies for fine-grained, contextual rules.
Rate limitingThree configurable token buckets keyed by IP, user, and tenant, with a pluggable in-memory or Valkey-backed provider.
Audit trailPost-commit, best-effort log of every mutation, tied to the request.
Bootstrap admin (demo)Demo-only today: aperture-demo seeds a superadmin from an env var on first boot. This is not yet a general framework feature.
Tenancy
POOL modeAuto-filtered queries and tenant-aware foreign keys.
NONE modeSingle-tenant deployments use the same codebase with different config.
Tenant lifecycleProvisioning, tenant admins, and the invite flow.
Lifecycle Hooks
Guard hooksPre-auth veto before a request is even processed.
Validation hooksSynchronous block-or-allow check before commit.
Mutation hooksRewrite the payload before it is persisted.
Trigger hooksFire-and-forget async side effects after commit.
Delivery guaranteesSigned payloads, retries, and timeouts, handled for you.
Generated CLI
Verb-first entity commandskubectl-style get / create / update / delete for every entity, with JSON:API query options.
Declarative applyCreate resources from YAML via apply or -f on the verbs; --atomic batches all-or-nothing.
Profiles & contextsPer-user config profiles with server, tenant, API version, and sticky scope context.
Scope context--scope and config set-scope layer scopedBy headers, kubectl-namespace-style.
Shell completionGenerated completion script, regenerated as manifests change.
API keys & tokensCreate and store personal API keys; service-account tokens via auth token.
Fat JAR or native binaryAny JDK builds the JAR; GraalVM builds a ~30 ms native binary.
Two extension SPIsCliAuthExtension (two-tier auth) and CliCommandContribution (custom commands), both source-emitting.
OIDC device-code loginRFC 8628 device flow via the aperture-cli-auth-oidc extension.
Operations & Tooling
Maven pluginCodegen and migrations wired into the build lifecycle.
Docker ComposeDemo-ready stack with Postgres and Jaeger.
Database seederSeeds demo tenants, users, and data, then exits.
Distributed tracingJaeger wired into the demo stack out of the box.

Ready to stop bikeshedding?

Write a manifest. Ship a production API. Focus on the model while Aperture handles the exposure.