overview.md 7.85 KB

Plug-in API overview

org.vibeerp.api.v1 (api.v1 for short) is the only stable contract in vibe_erp. It is the surface that PF4J plug-ins compile against, and the only surface they are permitted to touch. Everything else in the codebase — platform.*, every PBC's internal package, every concrete Spring bean — is internal and may change in any release.

For the architectural reasoning behind api.v1, see ../architecture/overview.md and the full spec at ../superpowers/specs/2026-04-07-vibe-erp-architecture-design.md.

What api.v1 is

  • A Kotlin module published to Maven Central as org.vibeerp:api-v1.
  • Depends on only Kotlin stdlib and jakarta.validation. No Spring, no Hibernate, no PF4J types leak through it.
  • Semver-governed on the 1.x line. Across a major version, api.v1 and api.v2 ship side by side for at least one major release window so plug-ins have time to migrate.
  • The single import surface for plug-ins. The plug-in linter rejects any import outside org.vibeerp.api.v1.* at install time.

Package layout

org.vibeerp.api.v1
├── core/         Id<T>, Money, Currency, Quantity, UnitOfMeasure, Result<T,E>
├── entity/       Entity, AuditedEntity, FieldType, CustomField, EntityRegistry
├── persistence/  Repository<T>, Query, Page, Transaction, PersistenceExceptions
├── event/        DomainEvent, EventListener, EventBus (with Subscription)
├── security/     Principal, PrincipalId, Permission, PermissionCheck
├── i18n/         MessageKey, Translator, LocaleProvider
├── http/         @PluginEndpoint, RequestContext
├── plugin/       Plugin, PluginContext, PluginManifest, ExtensionPoint,
│                 PluginEndpointRegistrar, HttpMethod, PluginRequest,
│                 PluginResponse, PluginEndpointHandler, PluginJdbc, PluginRow
├── ext/          Typed cross-PBC facades: ext.identity.IdentityApi,
│                 ext.catalog.CatalogApi
├── workflow/     WorkflowTask, TaskHandler, TaskContext
└── form/         FormSchema

A short orientation:

Package What it gives you
core/ The primitive value types every plug-in needs: typed Id<T>, Money + Currency, Quantity + UnitOfMeasure, Result<T,E>. No printing concepts.
entity/ Declarative entity model. Entity and AuditedEntity markers, FieldType sealed hierarchy, CustomField and EntityRegistry for the metadata-driven custom fields story.
persistence/ Repository<T>, Query, Page, Transaction, plus the closed PersistenceException hierarchy (OptimisticLockConflictException, UniqueConstraintViolationException, EntityValidationException, EntityNotFoundException). Plug-ins never see Hibernate, JPA, or Spring @Transactional directly.
event/ DomainEvent, EventListener, EventBus with Subscription (closeable) and topic-string + class-keyed subscribe overloads. The primary cross-PBC communication channel. Live as of P1.7.
security/ Principal (sealed: User, System, PluginPrincipal), PrincipalId, Permission, PermissionCheck. Plug-ins register their own permissions; the role editor auto-discovers them.
i18n/ MessageKey, Translator, LocaleProvider. The only sanctioned way for a plug-in to produce user-facing text. (Real ICU4J Translator impl is P1.6 — the api.v1 contract is locked, the host implementation throws UnsupportedOperationException until then.)
http/ @PluginEndpoint annotation and RequestContext for plug-in HTTP handlers.
plugin/ The plug-in lifecycle: Plugin interface, PluginContext (with live accessors for logger, endpoints, eventBus, jdbc), PluginManifest, ExtensionPoint/@Extension, and the endpoint types: PluginEndpointRegistrar, HttpMethod, PluginRequest, PluginResponse, PluginEndpointHandler, plus the typed-SQL surface PluginJdbc/PluginRow.
ext/ Typed cross-PBC facades. Two are live today: ext.identity.IdentityApi (with UserRef) and ext.catalog.CatalogApi (with ItemRef/UomRef). Future PBCs will add their own under the same pattern.
workflow/ WorkflowTask, TaskHandler, TaskContext (with tenantId removed — single-tenant — and principal(), locale(), correlationId() accessors). The hooks BPMN service tasks call into when Flowable lands (P2.1).
form/ FormSchema — JSON Schema string + UI Schema string + version. Form parsing and rendering happens in the host (server) and the SPA (client).

The stability contract

Change Allowed within 1.x?
Add a class to api.v1 yes
Add a method to an api.v1 interface (with default impl) yes
Remove or rename anything in api.v1 no — major bump
Change behavior of an api.v1 symbol in a way plug-ins can observe no — major bump
Anything in platform.* or pbc.*.internal.* yes — that is why it is internal

Practical consequences for plug-in authors:

  • A plug-in built against api.v1 version 1.4.0 will load in any vibe_erp 1.x release.
  • A symbol that gets deprecated in 1.x keeps working until 2.0. The plug-in loader emits a warning when a plug-in uses a deprecated symbol — that is the Grade C signal in the extension grading.
  • A plug-in that reaches into platform.* or pbc.*.internal.* via reflection is Grade D, unsupported, and rejected by the plug-in linter at install time.

When in doubt about whether something belongs in api.v1: keep it out. Growing the API deliberately later is much cheaper than maintaining a regretted symbol forever.

The A/B/C/D extension grading

From CLAUDE.md guardrail #7. Every extension to vibe_erp falls into one of four grades, ordered from safest to least safe.

Grade What it is Upgrade safety
A Tier 1 metadata only — custom fields, forms, workflows, rules, list views, translations entered through the web UI. Stored as rows in metadata__* tables, tagged source = 'user'. Always upgrade-safe across any core version.
B Tier 2 plug-in using only the public api.v1 surface. Safe within a major version. Loads cleanly across every 1.x release.
C Tier 2 plug-in using deprecated-but-supported api.v1 symbols. Safe until the next major. The plug-in loader emits warnings; the plug-in author should migrate before the next major release.
D Tier 2 plug-in reaching into platform.* or pbc.*.internal.* via reflection. UNSUPPORTED. The plug-in linter rejects this at install time. Will break on the next core upgrade.

Two principles follow from the grading:

  1. Anything a Tier 2 plug-in does should also become possible as a Tier 1 customization over time. Tier 2 is the escape hatch, not the default.
  2. If you find yourself wanting to do Grade D, the seam is wrong and api.v1 needs to grow — deliberately, with a version bump consideration.

Reference

The full reference for every type, method, and contract in api.v1 is generated from KDoc by Dokka and published alongside each release. This document is the conceptual overview; the generated reference is the authoritative per-symbol documentation. (The Dokka site is wired up as part of the v1.0 documentation deliverable; until then, the source under api/api-v1/src/main/kotlin/org/vibeerp/api/v1/ is the source of truth, and every public type carries a KDoc block — that is part of the PR checklist in ../../CONTRIBUTING.md.)

Where to go next