The Enterprise Edition ships as plug-in jars that attach to a running Community Edition through its published SPIs. There is no separate build of the application, no patched community artifacts, and no migration step — you add jars to a classpath and place a license file.

See Editions for what the plug-in layer contains and why it is built this way.

1. Obtain the jars

Enterprise artifacts are distributed through a private registry and are never published to Maven Central. You receive:

JarPurpose
enterprise-licenseruntime entitlement — always required
enterprise-linkmetacampaigns, tags, placement labels (feature link-meta)
enterprise-audit-exportaudit trail export (feature audit-export)

The plug-ins declare their dependencies on server and ui as provided, so a plug-in jar contains only its own classes. Both editions carry the same version number — use plug-ins that match your community version.

2. Deploy to the REST server

Append the jars to the fat-jar classpath and start the server main class explicitly:

java -cp "urlshortener.jar:plugins/*" \
     -Dapp.license.file=/etc/urlshortener/license.json \
     com.svenruppert.urlshortener.api.ShortenerServer

Contributed endpoints run behind the standard security pipeline — the same authentication and permission checks as every community endpoint. If two contributions claim the same path, the server fails fast at startup rather than silently picking one.

3. Deploy to the Vaadin UI

Add the same jars to the war’s runtime classpath.

Pitfall — dynamic routes and bundle optimization. As soon as enterprise views contribute dynamic routes, build the frontend with -Dvaadin.optimizeBundle=false. Otherwise the production bundle strips the classes those routes need and the enterprise views 404 at runtime. Community-only builds are unaffected.

4. Place the license file

Features verify an Ed25519-signed license at runtime. Point the JVM at it:

-Dapp.license.file=/etc/urlshortener/license.json

The default is license.json in the working directory. A license names the licensee, an expiry date, and the feature ids it unlocks — currently link-meta and audit-export.

Licenses are issued by jSentinel Ltd; the signing key never leaves the vendor. To request or renew one, see jsentinel.eu .

5. Verify

CheckLicensedUnlicensed
Plug-in endpoint (e.g. /api/campaigns)normal response403 — license required
Admin view and drawer entryvisibleabsent
Community endpoints and viewsunchangedunchanged

That second column is the designed behavior, not a failure mode: without a valid license the plug-in features degrade gracefully and the application keeps running as a plain community installation.

Licenses that expire

Nothing is deleted when a license lapses. Data written by a plug-in feature — campaigns, tags, labels — stays in your store and simply becomes invisible while no valid license is present. Installing a current license makes it visible again, exactly as it was.

The same applies to data created before a feature moved into the plug-in layer in V00.18.00: it lies dormant without a license and re-awakens with one.

Troubleshooting

Endpoint returns 403 although a license is installed. Check that the JVM actually reads the file you think it does (-Dapp.license.file), that the expiry date has not passed, and that the license lists the feature id the endpoint belongs to.

Views missing in the UI but endpoints work. The UI process needs the license file too — both runtimes evaluate entitlement independently. If routes are missing entirely after a production build, revisit the optimizeBundle note in step 3.

Startup fails with a duplicate path. Two contributions registered the same endpoint path. Remove the duplicate jar — this check is deliberate and prevents an ambiguous routing table.