<div align="center"> <a href="https://onno.su/"> <img src="https://onno.su/og-image.png" alt="onno — Describe how the business works. onno turns it into a Java system with the database, APIs, UI, workflows, and AI tools built in." width="100%" /> </a>
<br /> <br />
<h1>onno-framework</h1>
<p> <strong>A Java and Spring framework for business software that fits the operation—not the other way around.</strong> </p>
<p> <a href="https://central.sonatype.com/artifact/su.onno/onno-framework-starter"><img src="https://img.shields.io/maven-central/v/su.onno/onno-framework-starter?label=Maven%20Central&color=238e85" alt="Maven Central" /></a> <a href="https://github.com/onno-erp/onno-framework/actions/workflows/docs.yml"><img src="https://github.com/onno-erp/onno-framework/actions/workflows/docs.yml/badge.svg" alt="Documentation build" /></a> <img src="https://img.shields.io/badge/Java-21-238e85" alt="Java 21" /> <img src="https://img.shields.io/badge/Spring%20Boot-3.4-6DB33F" alt="Spring Boot 3.4" /> <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-171719" alt="Apache 2.0" /></a> </p>
<p> <a href="https://onno.su/"><strong>Website</strong></a> · <a href="https://docs.onno.su/"><strong>Documentation</strong></a> · <a href="https://demo.cloud.onno.su/ui"><strong>Live demo</strong></a> · <a href="example"><strong>Example app</strong></a> · <a href="CONTRIBUTING.md"><strong>Contributing</strong></a> </p> </div>
---
Write the truth once. Generate the boring parts.
onno models a business as explicit, compiler-checked Java: catalogs, documents, line items, registers, rules, and durable processes. From that model it generates the infrastructure every business system needs:
| Model in plain Java | Generated by onno | Kept in your control | | --- | --- | --- | | Business entities and references | Database schema and safe migrations | Posting and lifecycle rules | | Documents and line items | Typed repositories and authenticated REST | Integrations and custom services | | Balances and historical facts | Role-aware web UI and dashboards | UI composition and custom widgets | | Human and automatic processes | Tasks, events, and MCP tools for AI agents | Every source file and every deployment |
No proprietary designer. No duplicated table, DTO, API, and form definitions. No framework-specific language for the logic that makes the business unique.
@Catalog(name = "Customers", codePrefix = "C-", context = "Sales")
public class Customer extends CatalogObject {
@Attribute(required = true, length = 200)
private String name;
}
@Document(name = "Sales Orders", numberPrefix = "SO-", context = "Sales")
public class SalesOrder extends DocumentObject implements Postable {
@Attribute(required = true)
private Ref<Customer> customer;
@TabularSection(name = "items")
private List<SalesOrderLine> items = new ArrayList<>();
@Override
public void handlePosting(PostingContext context) {
var stock = context.movements(Stock.class);
items.forEach(line -> stock.addExpense(movement -> {
movement.setWarehouse(line.getWarehouse());
movement.setProduct(line.getProduct());
movement.setQuantity(line.getQuantity());
}));
}
}
<div align="center"> <a href="https://demo.cloud.onno.su/ui"> <img src="https://onno.su/images/onno-demo-desktop.jpg" alt="The onno generated business application interface" width="900" /> </a> <br /> <sub>The generated UI is ready to use, role-aware, and fully authorable from Java. <a href="https://demo.cloud.onno.su/ui">Open the live demo →</a></sub> </div>
How it works
flowchart LR
Model["Plain Java<br/>business model"]
Model --> Data["Schema<br/>repositories<br/>migrations"]
Model --> API["REST API<br/>SSE events"]
Model --> UI["Web UI<br/>dashboards<br/>desktop"]
Model --> Runtime["Posting<br/>registers<br/>processes"]
Model --> AI["MCP tools<br/>agent skills"]
1. Model the operation. Name the customers, orders, stock, payments, events, and rules the company actually works with. 2. Generate the system. onno creates the data layer, authenticated APIs, role-aware interface, migration plan, and AI-accessible tool surface. 3. Code what is unique. Integrations, posting logic, workflows, and policies stay ordinary, testable Java in your repository.
Quick start
onno 2.0 requires Java 21 and Spring Boot 3.4.x. Released artifacts are on Maven Central under
su.onno; no credentials or custom repository are required.
plugins {
java
id("org.springframework.boot") version "3.4.4"
id("io.spring.dependency-management") version "1.1.7"
}
repositories {
mavenCentral()
}
val onnoVersion = "2.0.0"
dependencies {
implementation("su.onno:onno-framework-starter:$onnoVersion")
implementation("su.onno:onno-ui-starter:$onnoVersion")
implementation("su.onno:onno-auth-starter:$onnoVersion")
runtimeOnly("com.h2database:h2")
}
Give the app a datasource and a development user:
spring:
datasource:
url: jdbc:h2:file:./data/app
driver-class-name: org.h2.Driver
username: sa
onno:
auth:
users:
- username: admin
password: admin # development only
roles: [ADMIN]
Put your annotated model under the @SpringBootApplication package and start the application. onno scans the model, creates the schema, wires the repositories, and serves the UI.
For a complete runnable project with seeded data, posting, role-specific layouts, dashboards, comments, media, and custom widgets, see the Onno Books example.
Business concepts
| If the business has… | Model it as… | | --- | --- | | Master data such as products, customers, warehouses, or employees | @Catalog | | A fixed set of states or categories | @Enumeration | | A dated, numbered event such as an order, invoice, or shipment | @Document | | Repeated rows inside a document | @TabularSection | | Current stock, cash, points, or other balances | @AccumulationRegister(type = BALANCE) | | Revenue, hours, or other period activity | @AccumulationRegister(type = TURNOVER) | | Prices, rates, or other facts that change over time | @InformationRegister | | A singleton business setting | @Constant | | Durable human and automatic work across several steps | ProcessDefinition<P, S> | | A future service or team boundary | context = "…" |
The model remains small because references are typed (Ref<T>), behavior uses ordinary Java interfaces, and UI metadata lives in focused Layout, Page, and EntityView beans.
What ships
| Area | Packages and modules | | --- | --- | | Foundation | onno-framework, onno-framework-starter | | Application surface | onno-ui-starter, onno-auth-starter | | Data and integration | onno-import-starter, onno-kafka-starter, onno-cluster-starter | | AI and operations | onno-mcp-starter, onno-observability-starter | | Native and custom UI | onno-desktop-starter, onno-desktop-gradle-plugin, onno-widgets-gradle-plugin, @onno/widget-sdk | | Reference application | example |
Spring Boot starters expose auto-configuration through
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports; adding a starter is enough to make its conditional beans available.
Commercial vertical connectors are distributed separately from the private onno-enterprise repository. Authentication—including OIDC and SSO—remains in the Apache-2.0 open core.
Designed for humans and AI agents
The same typed model that drives the application also gives agents a safe, inspectable surface:
onno-mcp-starterexposes metadata, reads, writes, register queries, posting, and custom
@McpTool methods with the application's authorization rules.
- The
onnoagent skills teach coding agents how to model a
business, author UI, implement posting, evolve schemas, and verify a running application.
- Building ERPs with onno and AI agents is the end-to-end handoff
guide for a separate application repository.
Claude Code users can install the skills directly from this repository:
/plugin marketplace add onno-erp/onno-framework
/plugin install onno@onno-framework
Documentation
The complete documentation is published at docs.onno.su, including hand-written guides, generated configuration reference, and aggregated Javadocs.
| Start here | Purpose | | --- | --- | | Architecture | Boot pipeline, subsystems, endpoint catalog, and open-core boundary | | Configuration | Every onno.* property and default, generated from source metadata | | Headless Read API | JSON contracts, reference expansion, redaction, and keyset pagination | | Running and verification | Local development and authenticated runtime smoke tests | | 2.0 release notes | Highlights, breaking changes, and the release gate | | Migrating to 2.0 | Source, data, and client migration checklist | | Extending onno | Community connectors, SPI implementations, UI add-ons, and skills | | Community integrations | Generated catalog of third-party projects | | Contributing | Development workflow and contribution guidelines | | Java API | Aggregated Javadoc for the published API |
Each starter also has a focused README beside its source.
<details> <summary><strong>Maintaining the generated documentation</strong></summary>
docs/CONFIGURATION.md is generated from the starters'
spring-configuration-metadata.json. Change a configuration property's Javadoc, then regenerate; never hand-edit its table.
./gradlew generateConfigDocs
./gradlew checkConfigDocs
Preview the complete docs site:
./gradlew generateConfigDocs aggregateJavadoc
mkdir -p docs/public/api
cp -R build/docs/javadoc/. docs/public/api/
cd docs
npm install
npm run docs:dev
</details>
Local development
The Gradle wrapper is the source of truth. Node 22.22 is downloaded automatically for the packaged frontend.
./gradlew clean check
./gradlew publishToMavenLocal
./gradlew :example:bootRun
publishToMavenLocal is part of the verification loop: it catches sources, Javadoc, POM, and binary artifact problems that project dependencies can hide.
For a save-to-screen loop, run the example and continuous compilation in separate terminals:
./gradlew :example:bootRun
./gradlew -t :example:classes
Spring Boot DevTools restarts the application context; onno rescans metadata, reapplies the schema diff, rebuilds UI metadata, and tells connected browsers to refresh.
Schema evolution
Structural migrations are derived from the model and diffed against the live database at startup.
onno.schema.mode controls whether onno applies, plans, validates, or ignores that diff:
onno.schema.mode=apply
onno.schema.allow-destructive=false
Safe additions, renames, and widening changes apply automatically. Drops and narrowing changes require an explicit destructive-change opt-in. Use previousNames to preserve data through renames and versioned AppMigration beans for backfills or reshaping. Every applied change is recorded in
onno_schema_history.
See Architecture → schema for the full contract.
Extending onno
Extend the framework without forking it. Community projects can ship connectors, SPI implementations, UI widgets and pages, MCP tools, or agent skills as separate artifacts. The extension guide documents the contracts, naming rules, and definition of done.
Built one? Add it to community/registry.json, run
./gradlew generateIntegrationsDoc, and open a pull request to list it in Community integrations.
Publishing a release
Releases are tag-driven and published by CI to Maven Central. A tag named vX.Y.Z publishes version
X.Y.Z, verifies the signed artifacts, and creates a GitHub release:
git tag v2.0.0
git push origin v2.0.0
Release candidates use tags such as v2.1.0-rc1. Maven Central versions are immutable, so publishing is intentionally CI-only. See .github/workflows/publish-packages.yml for the required Central Portal and signing secrets.
Contributing
Issues, focused pull requests, and community extensions are welcome. Start with CONTRIBUTING.md, keep public API changes documented, and run the narrowest useful tests followed by ./gradlew clean check.
License
The framework modules in this repository are open source under the Apache License 2.0. See NOTICE for attribution.
Commercial vertical connectors live in onno-enterprise, use the su.onno.enterprise Maven group, and are governed by a separate commercial license. The module split plan documents the open-core boundary.
<div align="center"> <br /> <strong>Your business is not generic. Your software should not be either.</strong> <br /> <sub><a href="https://onno.su/">onno.su</a> · <a href="https://docs.onno.su/">docs</a> · <a href="https://github.com/onno-erp/onno-framework/issues">issues</a></sub> </div>










