Open source ·JSON:API compliant · Apache 2.0
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.
How it works
One manifest file. Everything else is generated.
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.
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: trueDefine 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.
permissions:
Accountant: [create, read, update]
Viewer: [read]
policies:
FinanceTeamOnly: [read, update]
EuRegionOnly: [read, update]Use a validate hook to reject invalid creates and updates before commit. Other hook types can guard, mutate, or trigger asynchronous work.
hooks:
ValidateInvoice:
type: validate
on: [create, update]
url: http://hook-service:8080/hooks/validate-invoice
retries: 2The Maven plugin generates all Java source and Liquibase migrations. No code written by hand, no SQL to manage. Commit the lock files and ship.
# 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"}Features
Everything a production multi-tenant API needs, with a pluggable architecture so you own what matters.
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.
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.
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.
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 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.
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.
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.
validate blocks, mutate modifies, trigger fires async, guard runs pre-auth. You implement logic over HTTP while Aperture handles signing, retries, and timeouts.
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 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.
Complete feature set
The curated tour above is the highlight reel. This is the whole inventory, grouped, linked, and ready to scan.
| Feature | What it does | Docs |
|---|---|---|
| API Surface | ||
| JSON:API | Atomic operations, sparse fieldsets, compound documents, RSQL filtering, sorting, pagination. | Read more → |
| GraphQL (Elide) | The same entities, permissions, and manifests support queries, nested traversal, and mutations at /graphql/v{n}. | Read more → |
| OpenAPI / Swagger | Full spec generated from your manifests, served at /swagger-ui.html. | Read more → |
| API versioning | ACTIVE / SUNSET lifecycle per version, with deprecation headers. | Read more → |
| MCP server | list / get / create / update / delete tool stubs for AI assistants. | Read more → |
| Data Model | ||
| Entities & relationships | ManyToOne / OneToMany, with mappedBy for the inverse side. | Read more → |
| Unique & indexed fields | Field-level declarations generate unique or non-unique DB indexes. | Read more → |
| Optimistic locking | Adds a version column, enforced via If-Match on mutations. | Read more → |
| Soft delete | Adds deleted_at; reads are auto-filtered to live rows. | Read more → |
| Scope partitioning (scopedBy) | Partitions rows by a relationship, selected per request via header. Pair this partitioning with ABAC to gate access. | Read more → |
| Field encryption | AES-256-GCM ciphertext at rest, transparent to API callers. | Read more → |
| Liquibase migrations | Full-DDL and incremental changesets generated on every build. | Read more → |
| Manifest diffing | Breaking-change detection against committed lock files. | Read more → |
| Security | ||
| JWT + API keys | Login, refresh, service accounts, and personal API keys. | Read more → |
| Pluggable identity | Swap providers behind the CredentialValidator SPI. | Read more → |
| RBAC | Role-based permissions declared per entity and operation. | Read more → |
| ABAC | SpEL attribute policies for fine-grained, contextual rules. | Read more → |
| Rate limiting | Three configurable token buckets keyed by IP, user, and tenant, with a pluggable in-memory or Valkey-backed provider. | Read more → |
| Audit trail | Post-commit, best-effort log of every mutation, tied to the request. | Read more → |
| 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. | Read more → |
| Tenancy | ||
| POOL mode | Auto-filtered queries and tenant-aware foreign keys. | Read more → |
| NONE mode | Single-tenant deployments use the same codebase with different config. | Read more → |
| Tenant lifecycle | Provisioning, tenant admins, and the invite flow. | Read more → |
| Lifecycle Hooks | ||
| Guard hooks | Pre-auth veto before a request is even processed. | Read more → |
| Validation hooks | Synchronous block-or-allow check before commit. | Read more → |
| Mutation hooks | Rewrite the payload before it is persisted. | Read more → |
| Trigger hooks | Fire-and-forget async side effects after commit. | Read more → |
| Delivery guarantees | Signed payloads, retries, and timeouts, handled for you. | Read more → |
| Generated CLI | ||
| Verb-first entity commands | kubectl-style get / create / update / delete for every entity, with JSON:API query options. | Read more → |
| Declarative apply | Create resources from YAML via apply or -f on the verbs; --atomic batches all-or-nothing. | Read more → |
| Profiles & contexts | Per-user config profiles with server, tenant, API version, and sticky scope context. | Read more → |
| Scope context | --scope and config set-scope layer scopedBy headers, kubectl-namespace-style. | Read more → |
| Shell completion | Generated completion script, regenerated as manifests change. | Read more → |
| API keys & tokens | Create and store personal API keys; service-account tokens via auth token. | Read more → |
| Fat JAR or native binary | Any JDK builds the JAR; GraalVM builds a ~30 ms native binary. | Read more → |
| Two extension SPIs | CliAuthExtension (two-tier auth) and CliCommandContribution (custom commands), both source-emitting. | Read more → |
| OIDC device-code login | RFC 8628 device flow via the aperture-cli-auth-oidc extension. | Read more → |
| Operations & Tooling | ||
| Maven plugin | Codegen and migrations wired into the build lifecycle. | Read more → |
| Docker Compose | Demo-ready stack with Postgres and Jaeger. | Read more → |
| Database seeder | Seeds demo tenants, users, and data, then exits. | Read more → |
| Distributed tracing | Jaeger wired into the demo stack out of the box. | Read more → |
Write a manifest. Ship a production API. Focus on the model while Aperture handles the exposure.