Component definitions are versioned with Hibernate Envers and publish through a draft→published lifecycle. Publishing can optionally be gated by an approval workflow attached per component type and site. Applies to pages, page layouts, portlets, assets, web content, navigation, dynamic forms, email templates, SOAP components and workflow definitions.
Versioning (Hibernate Envers)
Each audited entity is annotated @Audited and writes an audit row to a <table>_aud table on every change. A shared PortalRevisionEntity (the revinfo table) stamps each revision with the acting user and site via a revision listener, so history answers who changed what, on which site.
ddl-auto: validate), so the _aud and revinfo tables are created by migrations per service — Envers does not auto-create them. Each _aud table must mirror the audited columns exactly.| Endpoint | Purpose |
|---|---|
GET /{id}/history | List revisions (revision no., who, when, status) |
GET /{id}/history/{rev} | Fetch the entity state at a revision |
POST /{id}/restore/{rev} | Restore an old revision as a new draft |
POST /{id}/publish | Publish the current draft (may require approval) |
Lifecycle & the published projection
A shared LifecycleStatus enum (DRAFT, PENDING_APPROVAL, PUBLISHED, REJECTED, ARCHIVED) plus published_rev, published_at and (for content) a published_snapshot live on each entity. The row always holds the latest draft; the runtime serves the published projection only, so editing never changes what is live until you publish.
Approval policies
The workflow service owns an approval_policy table keyed by (component_type, site_id) → a bound workflow definition, with an enabled flag. Resolution is site-specific first, then the global (site_id IS NULL) policy; if none, publishing is immediate.
Publish flow
component-service.publish(id)
-> workflow-service POST /api/workflow/approvals/submit
{ componentType, siteId, resourceId, revision, callbackPath, ... }
<- { required:false } => publish now (status=PUBLISHED, published_rev=rev)
<- { required:true } => status=PENDING_APPROVAL, manager task raised
manager approves -> workflow-service calls component-service
POST {callbackPath} { decision:APPROVED, revision } => publishManaging approvals
GET /api/workflow/approvals— the manager queue (site-scoped).POST /api/workflow/approvals/{correlationId}/decide— approve / reject./api/workflow/approvals/policies— CRUD of approval policies.