overview.md 6.66 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/         Tenant, Locale, Money, Quantity, Id<T>, Result<T,E>
├── entity/       Entity, Field, FieldType, EntityRegistry
├── persistence/  Repository<T>, Query, Page, Transaction
├── event/        DomainEvent, EventListener, EventBus
├── security/     Principal, Permission, PermissionCheck
├── i18n/         MessageKey, Translator, LocaleProvider
├── http/         @PluginEndpoint, RequestContext, ResponseBuilder
├── plugin/       Plugin, PluginManifest, ExtensionPoint
├── ext/          Typed extension interfaces a plug-in implements
├── workflow/     WorkflowTask, WorkflowEvent, TaskHandler
└── form/         FormSchema, UiSchema

A short orientation:

Package What it gives you
core/ The primitive value types every plug-in needs: Tenant, Locale, Money, Quantity, typed Id<T>, Result<T,E>. No printing concepts.
entity/ Declarative entity model. Plug-ins describe entities, fields, and field types through EntityRegistry; the platform handles persistence and OpenAPI.
persistence/ Repository<T>, Query, Page, Transaction. Plug-ins never see Hibernate or Spring @Transactional directly.
event/ DomainEvent, EventListener, EventBus. The primary cross-PBC and cross-plug-in communication channel.
security/ Principal, 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.
http/ @PluginEndpoint and the request/response abstractions for adding REST endpoints from a plug-in.
plugin/ Plugin, PluginManifest, ExtensionPoint, and the @Extension annotation. The plug-in lifecycle entry points.
ext/ Typed extension interfaces that PBCs declare and plug-ins implement (e.g. api.v1.ext.inventory.StockReservationStrategy). The cross-PBC interaction surface.
workflow/ WorkflowTask, WorkflowEvent, TaskHandler. The hooks BPMN service tasks call into.
form/ FormSchema, UiSchema. JSON Schema and UI Schema as Kotlin types, for plug-ins shipping form definitions.

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