[ 
https://issues.apache.org/jira/browse/UNOMI-963?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Serge Huber updated UNOMI-963:
------------------------------
    Description: 
h2. Summary

Enrich Apache Unomi's *live* OpenAPI document (CXF {{OpenApiFeature}} / {{GET 
/cxs/openapi.json}} + Swagger UI) so developers get usable statuses, examples, 
and *wire-accurate* schemas—without changing REST behavior.

*Approach (decided):* treat *Javadoc* as the source of truth. At build time, 
the external toolkit 
*[https://repo1.maven.org/maven2/dev/inoyu/openapi/|dev.inoyu.openapi] 
openapi-enrich {{0.1.0}}* (Maven Central) scans sources into enrichment packs; 
at runtime CXF merges them. Optional thin machine tags {{@api.status}} / 
{{@api.example}} where inference needs help.

*Toolkit provenance:* *openapi-enrich* was *designed and developed for this 
Unomi need* (Javadoc-driven enrichment of a CXF/OSGi live OpenAPI, without mass 
Swagger annotations) and *open-sourced by [https://inoyu.dev|Inoyu]* under 
Apache-2.0 on Maven Central under the {{dev.inoyu.openapi}} coordinates. Unomi 
depends on the published artifacts as a normal third-party library—it does 
*not* vendor the toolkit sources.

*Toolkit links:*
* GitHub: [https://github.com/inoyu-dev/openapi-enrich]
* README (usage, {{@api.status}} / {{@api.example}} grammar, pack format): 
[https://github.com/inoyu-dev/openapi-enrich/blob/main/README.md]
* Maven Central: [https://repo1.maven.org/maven2/dev/inoyu/openapi/]

*Explicitly not used:* Swagger/OpenAPI annotations such as {{@Operation}}, 
{{@ApiResponse}}, {{@Schema(description=...)}}. Those would *duplicate* 
existing Javadoc, drift from code, and fight Unomi's OSGi/dynamic surface. (The 
issue *summary* previously mentioned Swagger annotations; that path was 
rejected.)

*Primary consumers:* integration engineers (Swagger UI, curl/Postman), OpenAPI 
codegen / typed clients, {{unomi-ui}} / tooling, AI agents that need a real 
contract (not empty {{application/json: {}}}/{{default}} responses).

*Related (not a duplicate):* [UNOMI-899] (replace jaxrs-analyzer / CXF OpenAPI 
*generation*). That covers *how* the live spec is produced; this ticket covers 
*documentation completeness* of that generation.

*PR:* [https://github.com/apache/unomi/pull/826|#826] — branch 
{{UNOMI-963-openapi-javadoc-enrichment}}

----

h2. Problem

The live spec was path-complete but documentation-poor:

* Methods returning {{javax.ws.rs.core.Response}} often showed empty bodies 
even when the wire JSON is a typed DTO.
* Responses were overwhelmingly a single {{default}} entry; named 
{{200}}/{{204}}/{{400}}/{{403}}/{{404}}… were missing.
* Schemas often lacked field descriptions, and sometimes leaked Java/transient 
names instead of *wire* JSON (e.g. Condition {{type}} + {{parameterValues}} vs 
internal ids).
* Stock CXF {{JavaDocProvider}} scrapes *generated Javadoc HTML*—brittle across 
JDKs.
* Mass Swagger annotations would duplicate Javadoc and drift.

----

h2. Goals

# Live OpenAPI remains *deployment-accurate* (CXF reflects OSGi-registered 
resources only).
# Enrichment packs generated at *build time* from Java + Javadoc (+ JAX-RS 
annotations)—*no HTML scrape*, *no Swagger annotation dual-maint*.
# Prose stays in Javadoc; thin {{@api.*}} tags only where status/example/schema 
binding needs an explicit signal.
# OpenAPI useful for humans *and* agents: summaries, params, named statuses, 
examples, {{$ref}} schemas, stable operation keys, wire names.
# Per-bundle packs so optional extensions contribute docs only when installed.

----

h2. Non-goals

* Mass {{@Schema(description=...)}} / {{@Operation(summary=...)}} / 
{{@ApiResponse}} copying Javadoc (*rejected*).
* Using CXF {{JavaDocProvider}} HTML scraping in production.
* Replacing CXF {{OpenApiFeature}} with a build-time-only OpenAPI as the sole 
live API.
* Breaking HTTP wire contracts (paths, methods, status semantics, JSON shapes).
* Enriching {{GET /api-docs/{resource}}} (Swagger helper, not a product API).

----

h2. Architecture (as implemented)

{code}
Maven (rest + extension REST modules)
  → openapi-enrich-maven-plugin (dev.inoyu.openapi:0.1.0)
  → META-INF/openapi-enrich/openapi-doc.json  (pack)
       packaged in OSGi bundle

Runtime
  → BundleContextDocPackLoader discovers packs from *installed* bundles
  → EnrichingOpenApiCustomizer merges ops/schemas/examples into CXF OpenAPI
  → OpenApiFeature serves complete /cxs/openapi.json
{code}

Unomi *wires* the toolkit and supplies Javadoc content; correctness (aliases, 
{{@XmlTransient}} suppress, inherited JAX-RS methods, path-param regex 
normalize, subclass override docs) lives in the Central library maintained by 
Inoyu.

Servlet surface in scope: {{GET /health/check}} via servlet pack merge 
(healthcheck module).

----

----

h2. Gold coverage (what it means + how much work)

h3. What "gold" means

We score each HTTP operation in the live {{/cxs/openapi.json}} as:

|| Tier || Criteria ||
| *Gold* | Has a *named* success/error status (e.g. {{200}}/{{204}}/{{400}}) 
whose description is *not* empty/{{default response}}, *and* the operation 
carries at least one response *example* |
| *Partial* | Has statuses *or* an example, but not both to gold standard |
| *Weak* | Neither usable statuses nor examples |

That bar is what makes Swagger UI and codegen useful: developers see *what can 
happen* and *what a valid body looks like*, not a CXF skeleton.

h3. Result on this branch

* *179 / 179* operations *gold* (excluding {{GET /api-docs/{resource}}}, 
intentionally skipped — Swagger helper, not a product API).
* *0* partial, *0* weak on the product surface after the final example pass.
* Critical schemas verified: Condition/Action expose wire {{type}} + 
{{parameterValues}}; Event exposes {{profileId}}/{{sessionId}} (not leaked 
nested/transient fields).

h3. Work that got us there

Not a thin status pass — end-to-end enrichment of the JAX-RS inventory (~180 
ops) plus schema quality:

# *Toolkit (Inoyu, open-sourced):* openapi-enrich {{0.1.0}} — scan/Javadoc 
tags, schema inheritance, wire aliases, {{@XmlTransient}} suppress, HTTP 
overloads, inherited JAX-RS methods, path-param regex normalize, subclass 
override docs, servlet merge — published to Maven Central so Unomi (and CI) 
resolve a release, not a SNAPSHOT.
# *Exemplar content:* Tenant + Health to prove the pipeline and tag grammar.
# *Hot paths:* context, eventcollector, profiles (36 ops), rules, segments, 
privacy — statuses, examples, shared models (Query, PartialList, 
Condition/Action, …).
# *Mid + thin REST + extensions:* definitions, campaigns, scoring, goals, 
events, tasks, scopes, query, cluster, client, patch, userList, test/ping, plus 
json-schema, lists, geonames, router import/export, groovy, SFDC, healthcheck.
# *Gold completion pass:* every remaining partial (void DELETE/OPTIONS/thin 
GETs, geonames regex-path ops, query metrics) got *context-specific* 
{{@api.example}} values (entity illustrations, JS for {{context.js}}, CSV for 
export, {{true}}/maps where appropriate)—so "examples everywhere" is 
intentional and domain-relevant, not filler.

*Effort order of magnitude (tracker planning bands):* toolkit MVP roughly *4–8* 
person-days; Unomi hot-path content roughly *4–7* person-days; full 
Tenant-quality inventory across mid/thin/extensions a further multi-day content 
push on top—plus the final gold example sweep after live scorecards.

----

h2. Delivery status (2026-07-15)

|| Area || Status ||
| Toolkit published Central {{0.1.0}} | Done |
| Unomi pin {{${openapi.enrich.version}=0.1.0}} | Done (PR #826) |
| Hot paths (context, events, profiles, rules, segments, privacy) | Done |
| Mid / thin REST + extensions (incl. geonames, lists, json-schema, router, 
groovy, SFDC, health) | Done |
| Live verify | *179/179* **gold** excl. {{/api-docs}} — see *Gold coverage* 
above for definition + work scope |
| ASF review | PR [https://github.com/apache/unomi/pull/826|#826] open |

----

h2. Acceptance criteria

h3. Pipeline
* [x] Maven Mojo extracts JAX-RS + Javadoc into versioned JSON packs (format 
{{1.1}}).
* [x] Packs at {{META-INF/openapi-enrich/openapi-doc.json}} in REST OSGi 
bundles.
* [x] Runtime discovery loads packs only from *installed* bundles.
* [x] {{OpenApiCustomizer}} merge for statuses, examples, schema property docs, 
response {{$ref}}s.
* [x] Wired from {{RestServer}}; dependency on Central {{0.1.0}} (not SNAPSHOT).

h3. Coverage / quality
* [x] Core + common/optional extension REST inventory enriched (excl. 
{{/api-docs}}).
* [x] {{Response}}/multi-status methods have named statuses where realistic.
* [x] Key DTOs (Profile, Event, Condition/Action, Query, PartialList, Tenant, 
…) documented; wire aliases / transient suppress.
* [x] {{GET /health/check}} documented when health bundle installed.
* [x] No Swagger annotation dual-maint; Javadoc + {{@api.status}} / 
{{@api.example}} only.

h3. Compatibility
* [x] Documentation-only (no intentional wire/behavior change).
* [ ] CI green on PR #826; REST ITs unchanged aside from build resolving 
Central artifacts.

----

h2. References

* PR: [https://github.com/apache/unomi/pull/826]
* Toolkit: 
[https://repo1.maven.org/maven2/dev/inoyu/openapi/cxf-openapi-enricher/0.1.0/]
* {{RestServer.java}} — OpenApiFeature / EnrichingOpenApiCustomizer
* Exemplars: {{TenantEndpoint}}, {{ContextJsonEndpoint}}, 
{{RulesServiceEndPoint}}, {{HealthCheckServlet}}
* Related: [UNOMI-899]
* Toolkit GitHub: [https://github.com/inoyu-dev/openapi-enrich]
* Toolkit README: 
[https://github.com/inoyu-dev/openapi-enrich/blob/main/README.md]
* Toolkit on Central: 
[https://repo1.maven.org/maven2/dev/inoyu/openapi/cxf-openapi-enricher/0.1.0/]
* Toolkit author/publisher: [https://inoyu.dev|Inoyu] (Apache-2.0)


  was:
h2. Summary

Enrich Apache Unomi's *live* OpenAPI document (CXF {{OpenApiFeature}}) with 
high-quality documentation derived from *existing* Java + Javadoc—without 
scraping HTML, without duplicating prose into Swagger 
{{@Schema(description=...)}} annotations, and without losing 
OSGi/dynamic-deployment accuracy.

Primary consumers: human developers (Swagger UI, manuals), {{unomi-ui}} / 
{{inoyu-ui}}, OpenAPI-driven clients, and AI agents that need typed, linked 
contracts (not empty {{application/json: {}}}/{{default}} responses).

Related (not a duplicate): [UNOMI-899] (replace jaxrs-analyzer / CXF OpenAPI 
generation). That work covers *how* the live spec is generated; this ticket 
covers *documentation completeness* of that generation.

----

h2. Problem

The live spec ({{GET /cxs/openapi.json}}) and committed snapshots under 
{{unomi-rest-api-tests}} are path-complete but documentation-poor:

* Methods returning {{javax.ws.rs.core.Response}} often show empty response 
bodies even when the wire JSON is a typed DTO (e.g. {{TenantUsage}}, 
{{TenantEventPurgeResult}}).
* Responses are overwhelmingly a single {{default}} entry; named 
{{200}}/{{400}}/{{401}}/{{404}}/{{500}} are missing.
* Schemas that *are* emitted from concrete return types have property 
names/types but **no** field descriptions (Javadoc is not available at runtime 
in CXF/swagger-core).
* Stock CXF {{JavaDocProvider}} scrapes *generated Javadoc HTML*—brittle across 
JDK versions and unsuitable as a long-term approach.
* Mass {{@Operation}}/{{@Schema(description=...)}} would *duplicate* existing 
Javadoc and drift.

Historical note: Miredot previously gave build-time, Javadoc-based docs but did 
not model Unomi's *dynamically deployed* JAX-RS surface well. CXF is correct 
for "what this Karaf instance registered"; build-time tools are correct for 
"what the sources say." We need both.

----

h2. Inventory baseline (server/unomi, JAX-RS)

Static scan of {{src/main/java}} ({{@Path}} + HTTP verbs; abstract router CRUD 
expanded):

|| Metric || Count ||
| HTTP operations | *181* (180 unique method+path; {{GET /profiles/export}} 
overloaded twice) |
| Returning {{Response}} | *31* (highest schema risk) |
| JAX-RS resource classes | ~28 |
| Maven REST-ish modules | 8 |

|| Path prefix || Ops || Module ||
| {{/profiles}} (+ personas, sessions, properties, export) | 37 | {{rest}} |
| {{/definitions}} | 16 | {{rest}} |
| {{/campaigns}}, {{/rules}}, {{/segments}}, {{/privacy}} | 10 each | {{rest}} 
/ privacy |
| {{/tenants}} | 9 | {{rest}} (3.1) |
| {{/scoring}} | 8 | {{rest}} |
| {{/goals}} | 7 | {{rest}} |
| {{/jsonSchema}} | 6 | json-schema ext |
| {{/lists}} + {{/userList}} | 5+1 | lists-ext + {{rest}} |
| {{/tasks}} | 5 | {{rest}} (3.1) |
| {{/exportConfiguration}}, {{/importConfiguration}} | 5 each | router-rest |
| {{/geonames}} | 5 | geonames |
| {{/events}}, {{/query}}, {{/scopes}} | 4 each | {{rest}} |
| {{/context.json}}, {{/context.js}}, {{/eventcollector}}, {{/cluster}} | 3 
each | {{rest}} |
| {{/client}}, {{/groovyActions}}, {{/sfdc}} | 2 each | rest / groovy / 
salesforce |
| {{/patches}}, {{/test/ping}} | 1 each | {{rest}} |

|| Maven module || Ops ||
| {{rest}} | 141 |
| {{extensions/privacy-extension/rest}} | 10 |
| {{extensions/router/router-rest}} | 10 |
| {{extensions/json-schema/rest}} | 6 |
| {{extensions/geonames/rest}} | 5 |
| {{extensions/lists-extension/rest}} | 5 |
| {{extensions/groovy-actions/rest}} | 2 |
| {{extensions/salesforce-connector/rest}} | 2 |

Coverage denominator for *JAX-RS*: inventory rows / 181. Progress = enrichment 
packs covering those ops.

Separate *servlet* denominator (see below): at least {{GET /health/check}}; 
optional {{/graphql}}. Do *not* double-count {{web-servlets}} 
context/eventcollector/client forwards already covered under {{/cxs}} JAX-RS.

----

h2. Goals

# Live OpenAPI remains *deployment-accurate* (CXF reflects OSGi-registered 
resources only).
# Enrichment packs are generated at *build time* from Java + Javadoc (and 
JAX-RS annotations)—*no HTML scrape*.
# Prose is *not* duplicated into Swagger description annotations; Javadoc stays 
the human source of truth.
# OpenAPI becomes useful for humans *and* agents: summaries, param docs, named 
statuses, {{$ref}} schemas, property descriptions, stable operation keys.
# Per-bundle packs so optional extensions contribute docs only when installed.

----

h2. Non-goals

* Mass {{@Schema(description=...)}} / {{@Operation(summary=...)}} copying 
Javadoc.
* Using CXF {{JavaDocProvider}} HTML scraping in production.
* Replacing CXF {{OpenApiFeature}} with a build-time-only OpenAPI as the sole 
live API.
* Breaking HTTP wire contracts (paths, methods, status semantics, JSON shapes).
* Expecting CXF to *discover* HttpService / whiteboard servlets automatically 
(it cannot).
* Turning GraphQL into a full REST OpenAPI in Phase 0 (optional later pack or 
link to GraphQL schema).
* Re-documenting {{web-servlets}} {{/context.json}}, {{/context.js}}, 
{{/eventcollector}}, {{/client/*}} as separate APIs when the same contracts 
already exist under {{/cxs}} JAX-RS (optional note about forward/alias only).

----

h2. Architecture

{code}
Maven (per JAX-RS module)
  → JavaParser (or equivalent) on .java sources
  → META-INF/unomi/openapi-doc.json  (enrichment pack)
       packaged in OSGi bundle

Runtime
  → Discover packs from *installed* bundles (BundleTracker / 
ClassLoader.getResources)
  → UnomiJsonDocumentationProvider implements 
org.apache.cxf.jaxrs.model.doc.DocumentationProvider
  → OpenApiCustomizer.setJavadocProvider(provider)
  → Subclass/customize OpenApiCustomizer for response $refs + schema property 
docs
  → OpenApiFeature serves complete /cxs/openapi.json
{code}

*CXF {{DocumentationProvider}} SPI* (already on {{OpenApiCustomizer}}):

|| SPI || OpenAPI field ||
| {{getMethodDoc}} | {{operation.summary}} / description |
| {{getMethodParameterDoc}} | {{parameter.description}} |
| {{getMethodResponseDoc}} | success response description |
| {{getClassDoc}} | tag description (if {{replaceTags}}) |

That SPI alone does *not* fix empty {{Response}} schemas or DTO property 
docs—those need the customizer merge from the same JSON.

----

h2. Servlets and other non-JAX-RS HTTP surfaces

CXF OpenAPI only sees OSGi JAX-RS resources. Unomi also exposes (or forwards) 
HTTP via servlets:

|| Path || Implementation || OpenAPI approach ||
| {{GET /health/check}} | {{HealthCheckServlet}} via OSGi {{HttpService}} 
({{extensions/healthcheck}}) | *In scope*: servlet enrichment pack + customizer 
merge |
| {{/graphql}} | {{GraphQLServlet}} | Optional later; prefer GraphQL schema or 
a small servlet pack |
| {{/context.json}}, {{/context.js}}, {{/eventcollector}}, {{/client/*}} | 
{{web-servlets}} whiteboard → forward to CXF | Already documented as JAX-RS 
under {{/cxs}}; no duplicate paths unless documenting the servlet alias |

*Health contract today (from implementation):*
* Auth: OSGi role {{health}} (missing → *403*).
* Body: JSON array of {{HealthCheckResponse}}.
* Status: *200* if all checks live; *206 Partial Content* otherwise.

*How to include them in the live OpenAPI (recommended):*

# Build-time (or curated) pack, e.g. {{META-INF/unomi/openapi-servlet.json}} or 
a {{type: servlet}} section in the same enrichment format—absolute paths, not 
under {{/cxs}}.
# Same runtime discovery as JAX-RS packs (only if the health bundle is 
installed).
# {{OpenApiCustomizer}} *merges* servlet paths/schemas into the CXF {{OpenAPI}} 
model (tags: {{Health}}, etc.).
# Document security explicitly (health role ≠ tenant API key).
# OpenAPI {{servers}}: account for root vs {{/cxs}} (e.g. server URL {{/}} with 
absolute {{/health/check}}, or dual servers). Agents care that documented URLs 
are reachable as written.

*Alternatives considered (not preferred for 3.1 spike):*
* Thin JAX-RS façade {{GET /cxs/health}} duplicating the servlet (second URL; 
keep servlet canonical for ops).
* Completely separate {{/health/openapi.json}} (extra consumer wiring).

----

h2. Build-time extraction (high quality)

*Dual extract* from the same sources:

# *Structure*: {{@Path}}, HTTP verb, {{@*Param}}, return types, generics 
({{PartialList<T>}}, etc.), Jackson visibility.
# *Meaning*: class/method/field Javadoc, {{@param}} (match by *name*), 
{{@return}}, {{@throws}}.

Optional thin machine tags *only* where inference is ambiguous (do not restate 
essays), e.g.:

{code}
@unomi.status 200 {@link TenantUsage}
@unomi.status 404 empty
@unomi.status 400 unsupported period
{code}

Especially required for multi-status bodies (e.g. {{purgeTenantEvents}}: 200 
and 500 share {{TenantEventPurgeResult}}).

JSON packs should carry OpenAPI-like fragments (operations + schemas with 
property descriptions), keyed by stable {{GET /path}} and/or 
{{className#methodName}}.

----

h2. Compatibility

Documentation-only (plus optional signature cleanups that preserve wire 
behavior). Especially: do *not* collapse purge {{200}}/{{500}} into a single 
success code.

----

h2. Phased delivery

|| Phase || Scope || Notes ||
| *0 - Spike* | {{TenantEndpoint}}, {{TaskEndpoint}}, {{TenantUsage}} / purge 
DTOs | Must prove JAX-RS pipeline; early 3.1 candidate |
| *0b - Servlet pack* | {{GET /health/check}} + {{HealthCheckResponse}} schema 
| Prove servlet merge + dual path prefix ({{/}} vs {{/cxs}}) |
| *1 - Core* | Remaining {{rest}} module (~141 ops) | Largest surface |
| *2 - Common extensions* | privacy, lists, json-schema | Often installed |
| *3 - Optional extensions* | geonames, groovy, router, sfdc; optional 
{{/graphql}} pack | Validates dynamic discovery |
| *4 - Hardening* | CI gates, snapshot regen, UI consumer notes | Release 
hygiene |

*Release intent:* Phase 0 should try to land in *3.1* if the spike succeeds; 
Phases 1-4 may complete in 3.1 or slip to *3.2* without blocking spike 
learnings. Update fixVersion(s) when decided.

----

h2. Acceptance criteria / definition of done

h3. Pipeline
* [ ] Maven Mojo (or equivalent) extracts JAX-RS + Javadoc into a versioned 
JSON pack schema.
* [ ] Packs emitted as {{META-INF/unomi/openapi-doc.json}} (name TBD) inside 
REST OSGi bundles.
* [ ] Runtime discovery loads packs only from *installed* bundles.
* [ ] {{DocumentationProvider}} implementation fills operation/param/response 
*prose* from JSON.
* [ ] {{OpenApiCustomizer}} extension applies response {{$ref}}s and schema 
property docs from the same JSON.
* [ ] Wired from {{RestServer}} (existing customizer).

h3. Coverage
* [ ] Inventory of public JAX-RS ops tracked (denominator ≈ 181); enrichment 
coverage measurable per module.
* [ ] All {{Response}}-returning methods (31) have status + schema metadata in 
packs.
* [ ] DTOs referenced by enriched responses appear under schemas with property 
descriptions where Javadoc exists.
* [ ] {{GET /health/check}} present in live OpenAPI when health bundle is 
installed (servlet pack merge).
* [ ] {{HealthCheckResponse}} (and array response) documented with statuses 200 
/ 206 / 403 and health-role security.
* [ ] No duplicate OpenAPI paths for {{web-servlets}} forwards that already 
exist under {{/cxs}} JAX-RS (unless explicitly documenting aliases).

h3. Quality / CI
* [ ] Fail (or stage-warn→fail) if public {{@Path}} method lacks Javadoc 
summary.
* [ ] Fail if {{@*Param}} lacks matching {{@param}}.
* [ ] Fail if {{Response}} method lacks status/schema map.
* [ ] Test/fixture: OpenAPI contains {{TenantUsage}} {{$ref}} and named 
statuses for purge.
* [ ] Procedure to regenerate committed OpenAPI snapshot for 
{{unomi-rest-api-tests}} / UI docs.

h3. Compatibility tests
* [ ] Existing REST integration tests pass (no wire regressions).
* [ ] Swagger UI usable on a full distribution for spike endpoints.

----

h2. Spike (Phase 0) - immediate implementation target

# Hand-written or Mojo-generated JSON for tenants/tasks.
# {{UnomiJsonDocumentationProvider}} + customizer schema merge.
# Verify live {{GET /cxs/openapi.json}}: summaries, param docs, {{TenantUsage}} 
{{$ref}}, purge 200/400/404/500.
# Write short effort estimate for rolling Phases 1-4 into 3.1 vs 3.2.
# Follow with Phase 0b: health servlet pack merged into the same live OpenAPI.

----

h2. References

* {{RestServer.java}} — {{OpenApiFeature}} / {{OpenApiCustomizer}}
* CXF {{OpenApiCustomizer}} + {{DocumentationProvider}} — use SPI, *not* HTML 
{{JavaDocProvider}}: 
https://github.com/apache/cxf/blob/3.6.x-fixes/rt/rs/description-openapi-v3/src/main/java/org/apache/cxf/jaxrs/openapi/OpenApiCustomizer.java
* {{TenantEndpoint.java}}, {{TaskEndpoint.java}}, tenant DTOs under 
{{unomi-api}}
* {{HealthCheckServlet.java}}, {{HealthCheckService.java}}, 
{{HealthCheckResponse.java}} — {{/health/check}}
* {{web-servlets}} {{ContextServlet}} / {{EventsCollectorServlet}} / 
{{ClientServlet}} — forwards to CXF
* {{GraphQLServlet}} / activator — {{/graphql}} (optional)
* {{server/unomi-rest-api-tests/unomi-openapi-3.1.0.json}}
* Endpoint inventory (attach): method, path, class, java_method, return, 
module, file — ~181 rows
* {{rest/README.md}} — historical Miredot note on {{rest-documentation}} branch

----

h2. Sub-tasks (suggested)

# Define JSON pack schema + conventions ({{@unomi.status}}; {{type: 
jaxrs|servlet}})
# Implement / evaluate JavaParser-based extraction Mojo
# Runtime {{DocumentationProvider}} + pack discovery
# {{OpenApiCustomizer}} schema/status merge (+ servlet path merge)
# Phase 0 spike (tenants/tasks)
# Phase 0b health servlet pack
# Phase 1 core {{rest}} coverage
# Phase 2-3 extensions (optional graphql pack)
# CI gates + snapshot regen + consumer docs



> Improve OpenAPI completeness from Javadoc (openapi-enrich)
> ----------------------------------------------------------
>
>                 Key: UNOMI-963
>                 URL: https://issues.apache.org/jira/browse/UNOMI-963
>             Project: Apache Unomi
>          Issue Type: Improvement
>          Components: unomi(-core)
>    Affects Versions: unomi-3.0.0, unomi-2.7.0, unomi-3.1.0
>            Reporter: Serge Huber
>            Assignee: Serge Huber
>            Priority: Major
>             Fix For: unomi-3.1.0
>
>          Time Spent: 20m
>  Remaining Estimate: 0h
>
> h2. Summary
> Enrich Apache Unomi's *live* OpenAPI document (CXF {{OpenApiFeature}} / {{GET 
> /cxs/openapi.json}} + Swagger UI) so developers get usable statuses, 
> examples, and *wire-accurate* schemas—without changing REST behavior.
> *Approach (decided):* treat *Javadoc* as the source of truth. At build time, 
> the external toolkit 
> *[https://repo1.maven.org/maven2/dev/inoyu/openapi/|dev.inoyu.openapi] 
> openapi-enrich {{0.1.0}}* (Maven Central) scans sources into enrichment 
> packs; at runtime CXF merges them. Optional thin machine tags {{@api.status}} 
> / {{@api.example}} where inference needs help.
> *Toolkit provenance:* *openapi-enrich* was *designed and developed for this 
> Unomi need* (Javadoc-driven enrichment of a CXF/OSGi live OpenAPI, without 
> mass Swagger annotations) and *open-sourced by [https://inoyu.dev|Inoyu]* 
> under Apache-2.0 on Maven Central under the {{dev.inoyu.openapi}} 
> coordinates. Unomi depends on the published artifacts as a normal third-party 
> library—it does *not* vendor the toolkit sources.
> *Toolkit links:*
> * GitHub: [https://github.com/inoyu-dev/openapi-enrich]
> * README (usage, {{@api.status}} / {{@api.example}} grammar, pack format): 
> [https://github.com/inoyu-dev/openapi-enrich/blob/main/README.md]
> * Maven Central: [https://repo1.maven.org/maven2/dev/inoyu/openapi/]
> *Explicitly not used:* Swagger/OpenAPI annotations such as {{@Operation}}, 
> {{@ApiResponse}}, {{@Schema(description=...)}}. Those would *duplicate* 
> existing Javadoc, drift from code, and fight Unomi's OSGi/dynamic surface. 
> (The issue *summary* previously mentioned Swagger annotations; that path was 
> rejected.)
> *Primary consumers:* integration engineers (Swagger UI, curl/Postman), 
> OpenAPI codegen / typed clients, {{unomi-ui}} / tooling, AI agents that need 
> a real contract (not empty {{application/json: {}}}/{{default}} responses).
> *Related (not a duplicate):* [UNOMI-899] (replace jaxrs-analyzer / CXF 
> OpenAPI *generation*). That covers *how* the live spec is produced; this 
> ticket covers *documentation completeness* of that generation.
> *PR:* [https://github.com/apache/unomi/pull/826|#826] — branch 
> {{UNOMI-963-openapi-javadoc-enrichment}}
> ----
> h2. Problem
> The live spec was path-complete but documentation-poor:
> * Methods returning {{javax.ws.rs.core.Response}} often showed empty bodies 
> even when the wire JSON is a typed DTO.
> * Responses were overwhelmingly a single {{default}} entry; named 
> {{200}}/{{204}}/{{400}}/{{403}}/{{404}}… were missing.
> * Schemas often lacked field descriptions, and sometimes leaked 
> Java/transient names instead of *wire* JSON (e.g. Condition {{type}} + 
> {{parameterValues}} vs internal ids).
> * Stock CXF {{JavaDocProvider}} scrapes *generated Javadoc HTML*—brittle 
> across JDKs.
> * Mass Swagger annotations would duplicate Javadoc and drift.
> ----
> h2. Goals
> # Live OpenAPI remains *deployment-accurate* (CXF reflects OSGi-registered 
> resources only).
> # Enrichment packs generated at *build time* from Java + Javadoc (+ JAX-RS 
> annotations)—*no HTML scrape*, *no Swagger annotation dual-maint*.
> # Prose stays in Javadoc; thin {{@api.*}} tags only where 
> status/example/schema binding needs an explicit signal.
> # OpenAPI useful for humans *and* agents: summaries, params, named statuses, 
> examples, {{$ref}} schemas, stable operation keys, wire names.
> # Per-bundle packs so optional extensions contribute docs only when installed.
> ----
> h2. Non-goals
> * Mass {{@Schema(description=...)}} / {{@Operation(summary=...)}} / 
> {{@ApiResponse}} copying Javadoc (*rejected*).
> * Using CXF {{JavaDocProvider}} HTML scraping in production.
> * Replacing CXF {{OpenApiFeature}} with a build-time-only OpenAPI as the sole 
> live API.
> * Breaking HTTP wire contracts (paths, methods, status semantics, JSON 
> shapes).
> * Enriching {{GET /api-docs/{resource}}} (Swagger helper, not a product API).
> ----
> h2. Architecture (as implemented)
> {code}
> Maven (rest + extension REST modules)
>   → openapi-enrich-maven-plugin (dev.inoyu.openapi:0.1.0)
>   → META-INF/openapi-enrich/openapi-doc.json  (pack)
>        packaged in OSGi bundle
> Runtime
>   → BundleContextDocPackLoader discovers packs from *installed* bundles
>   → EnrichingOpenApiCustomizer merges ops/schemas/examples into CXF OpenAPI
>   → OpenApiFeature serves complete /cxs/openapi.json
> {code}
> Unomi *wires* the toolkit and supplies Javadoc content; correctness (aliases, 
> {{@XmlTransient}} suppress, inherited JAX-RS methods, path-param regex 
> normalize, subclass override docs) lives in the Central library maintained by 
> Inoyu.
> Servlet surface in scope: {{GET /health/check}} via servlet pack merge 
> (healthcheck module).
> ----
> ----
> h2. Gold coverage (what it means + how much work)
> h3. What "gold" means
> We score each HTTP operation in the live {{/cxs/openapi.json}} as:
> || Tier || Criteria ||
> | *Gold* | Has a *named* success/error status (e.g. {{200}}/{{204}}/{{400}}) 
> whose description is *not* empty/{{default response}}, *and* the operation 
> carries at least one response *example* |
> | *Partial* | Has statuses *or* an example, but not both to gold standard |
> | *Weak* | Neither usable statuses nor examples |
> That bar is what makes Swagger UI and codegen useful: developers see *what 
> can happen* and *what a valid body looks like*, not a CXF skeleton.
> h3. Result on this branch
> * *179 / 179* operations *gold* (excluding {{GET /api-docs/{resource}}}, 
> intentionally skipped — Swagger helper, not a product API).
> * *0* partial, *0* weak on the product surface after the final example pass.
> * Critical schemas verified: Condition/Action expose wire {{type}} + 
> {{parameterValues}}; Event exposes {{profileId}}/{{sessionId}} (not leaked 
> nested/transient fields).
> h3. Work that got us there
> Not a thin status pass — end-to-end enrichment of the JAX-RS inventory (~180 
> ops) plus schema quality:
> # *Toolkit (Inoyu, open-sourced):* openapi-enrich {{0.1.0}} — scan/Javadoc 
> tags, schema inheritance, wire aliases, {{@XmlTransient}} suppress, HTTP 
> overloads, inherited JAX-RS methods, path-param regex normalize, subclass 
> override docs, servlet merge — published to Maven Central so Unomi (and CI) 
> resolve a release, not a SNAPSHOT.
> # *Exemplar content:* Tenant + Health to prove the pipeline and tag grammar.
> # *Hot paths:* context, eventcollector, profiles (36 ops), rules, segments, 
> privacy — statuses, examples, shared models (Query, PartialList, 
> Condition/Action, …).
> # *Mid + thin REST + extensions:* definitions, campaigns, scoring, goals, 
> events, tasks, scopes, query, cluster, client, patch, userList, test/ping, 
> plus json-schema, lists, geonames, router import/export, groovy, SFDC, 
> healthcheck.
> # *Gold completion pass:* every remaining partial (void DELETE/OPTIONS/thin 
> GETs, geonames regex-path ops, query metrics) got *context-specific* 
> {{@api.example}} values (entity illustrations, JS for {{context.js}}, CSV for 
> export, {{true}}/maps where appropriate)—so "examples everywhere" is 
> intentional and domain-relevant, not filler.
> *Effort order of magnitude (tracker planning bands):* toolkit MVP roughly 
> *4–8* person-days; Unomi hot-path content roughly *4–7* person-days; full 
> Tenant-quality inventory across mid/thin/extensions a further multi-day 
> content push on top—plus the final gold example sweep after live scorecards.
> ----
> h2. Delivery status (2026-07-15)
> || Area || Status ||
> | Toolkit published Central {{0.1.0}} | Done |
> | Unomi pin {{${openapi.enrich.version}=0.1.0}} | Done (PR #826) |
> | Hot paths (context, events, profiles, rules, segments, privacy) | Done |
> | Mid / thin REST + extensions (incl. geonames, lists, json-schema, router, 
> groovy, SFDC, health) | Done |
> | Live verify | *179/179* **gold** excl. {{/api-docs}} — see *Gold coverage* 
> above for definition + work scope |
> | ASF review | PR [https://github.com/apache/unomi/pull/826|#826] open |
> ----
> h2. Acceptance criteria
> h3. Pipeline
> * [x] Maven Mojo extracts JAX-RS + Javadoc into versioned JSON packs (format 
> {{1.1}}).
> * [x] Packs at {{META-INF/openapi-enrich/openapi-doc.json}} in REST OSGi 
> bundles.
> * [x] Runtime discovery loads packs only from *installed* bundles.
> * [x] {{OpenApiCustomizer}} merge for statuses, examples, schema property 
> docs, response {{$ref}}s.
> * [x] Wired from {{RestServer}}; dependency on Central {{0.1.0}} (not 
> SNAPSHOT).
> h3. Coverage / quality
> * [x] Core + common/optional extension REST inventory enriched (excl. 
> {{/api-docs}}).
> * [x] {{Response}}/multi-status methods have named statuses where realistic.
> * [x] Key DTOs (Profile, Event, Condition/Action, Query, PartialList, Tenant, 
> …) documented; wire aliases / transient suppress.
> * [x] {{GET /health/check}} documented when health bundle installed.
> * [x] No Swagger annotation dual-maint; Javadoc + {{@api.status}} / 
> {{@api.example}} only.
> h3. Compatibility
> * [x] Documentation-only (no intentional wire/behavior change).
> * [ ] CI green on PR #826; REST ITs unchanged aside from build resolving 
> Central artifacts.
> ----
> h2. References
> * PR: [https://github.com/apache/unomi/pull/826]
> * Toolkit: 
> [https://repo1.maven.org/maven2/dev/inoyu/openapi/cxf-openapi-enricher/0.1.0/]
> * {{RestServer.java}} — OpenApiFeature / EnrichingOpenApiCustomizer
> * Exemplars: {{TenantEndpoint}}, {{ContextJsonEndpoint}}, 
> {{RulesServiceEndPoint}}, {{HealthCheckServlet}}
> * Related: [UNOMI-899]
> * Toolkit GitHub: [https://github.com/inoyu-dev/openapi-enrich]
> * Toolkit README: 
> [https://github.com/inoyu-dev/openapi-enrich/blob/main/README.md]
> * Toolkit on Central: 
> [https://repo1.maven.org/maven2/dev/inoyu/openapi/cxf-openapi-enricher/0.1.0/]
> * Toolkit author/publisher: [https://inoyu.dev|Inoyu] (Apache-2.0)



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to