Skip to content

Integration and Configuration

This section describes the general integration model shared by all AppJars. Each AppJar's Getting Started guide provides the module-specific steps and code snippets.

Adding an AppJar to a Project

Integration follows the same pattern for every AppJar:

  1. Add the AppJars repository and Maven dependencies — register the public AppJars Maven repository (https://maven.appjars.com) in pom.xml, then include the three implementation modules (-business-impl, -data-impl, -flow). The contract and model modules are pulled in transitively. Each AppJar's Getting Started guide shows the exact repository and dependency snippets.
  2. Configure the database — AppJars use Hibernate's spring.jpa.hibernate.ddl-auto setting to create or update their tables at startup. No manual DDL is required.
  3. Implement required interfaces — some AppJars require the host application to provide one or two Spring beans that bridge AppJar functionality to the application's own services (for example, supplying the currently authenticated username). Each interface is documented in the AppJar's Developer Guide.
  4. Assign a router layout — inject the AppJar's RouteConfigurer bean by qualifier and call setViewsRouterLayout(MainLayout.class) in a @PostConstruct method so that the AppJar's views inherit the application's navigation chrome.
  5. Customise URL paths (optional) — override the default route paths in application.properties using the AppJar-specific properties documented in its Developer Guide.

Database Integration

On application startup, Hibernate scans the JPA entities contributed by each AppJar and creates or migrates the necessary tables. Each AppJar uses a dedicated table prefix so all modules can coexist in a single database schema without naming conflicts.

The database platform is inferred from the configured DataSource. AppJars are tested against PostgreSQL, MySQL, and H2 (for embedded testing). Dialect-specific DDL differences (such as BLOB vs BYTEA for binary columns) are handled by Hibernate automatically.

Service and DAO Access

AppJar services and DAOs are standard Spring beans. Once the dependencies are on the classpath, any application bean can inject an AppJar service directly:

@Autowired
private UserService userService;

@Autowired
private ActivityLogService activityLogService;

All services implement a CrudService<DTO, ID> base interface providing save, findAll, findById, and delete. Module-specific methods are defined in each service interface and documented in the AppJar's Developer Guide.

View Navigation

AppJar views are registered dynamically by each module's RouteConfigurer during Vaadin service initialisation. Routes are not hard-coded; they are assigned at startup using the URL paths configured in application.properties, with sensible defaults provided for every path.

To include AppJar views inside the application's main navigation layout:

@Autowired
@Qualifier("UserManagerRouteConfigurer")
private RouteConfigurer routeConfigurer;

@PostConstruct
public void configure() {
    routeConfigurer.setViewsRouterLayout(MainLayout.class);
}

Each AppJar uses a distinct @Qualifier string (e.g. "UserManagerRouteConfigurer", "ActivityLogRouteConfigurer") to distinguish its configurer bean from others when multiple AppJars are present. Refer to the individual Developer Guide for each AppJar's qualifier string.

Multi-AppJar Integration

When several AppJars are used together, they can be wired to share a common context. Common integration patterns include:

  • Supplying User Manager's UserService to AI Support's AuthenticatedUserProvider so that AI Support resolves user identities from the same user store.
  • Supplying User Profile's UserProfileService to AI Support's UserProfilePictureProvider so that user avatars appear in the chat interface.
  • Supplying User Manager's AuthorityService to Dynamic Menu's DynamicMenuAuthorityUtils so that the menu permission editor reflects the actual roles in the system.
  • Supplying User Manager's UserService to Configuration Manager's UserProvider so that the administrator view lists real application users.
  • Registering Email Manager's MailSenderService as a Process Manager task so that background email delivery is scheduled and monitored through the Processes view.
  • Installing I18N Manager alongside Data Query so that the translation keys of internationalised queries, categories and dashboards become manageable at runtime. Neither AppJar depends on the other: Data Query resolves its keys through whatever Vaadin i18n provider the application registers, and I18N Manager provides one as soon as it is on the classpath.

These integrations are optional and additive. Each AppJar functions correctly in isolation with a minimal stub implementation of its required interfaces.

AI Support and Issue Tracker

When both AI Support and Issue Tracker are deployed together, Issue Tracker can automatically synchronise its issue content into AI Support's vector knowledge base. This allows the AI assistant to answer questions grounded in live issue data without any manual document management.

The integration is enabled by implementing the AISupportExternalDataService interface from the appjars-utils library:

public interface AISupportExternalDataService {
    void saveDocument(String externalId, byte[] content);
    void saveDocument(String externalId, List<String> categories, byte[] content);
    void updateDocument(String externalId, byte[] content);
    void updateDocument(String externalId, List<String> categories, byte[] content);
    void delete(String externalId);
    Optional<Instant> lastUpdated(String externalId);
}

Issue Tracker's service layer injects this interface as Optional<AISupportExternalDataService>. When AI Support is present on the classpath and provides a Spring bean that implements this interface, Issue Tracker automatically calls it whenever an issue is created or updated. When AI Support is absent, the optional is empty and Issue Tracker operates without any change in behaviour.

When triggered, Issue Tracker serialises the full issue — including its description, comments (journals), custom field values, attachments metadata, and watcher list — into a structured text representation using a Velocity template. This text is then passed to AISupportExternalDataService.updateDocument() with the issue ID as the external key, which stores it as an embedding in AI Support's vector store.

The synchronisation is exposed through IssueService.saveIssueToEmbeddingStore(Integer id). The host application is responsible for deciding when to call it — typically from an event listener on issue save or from a scheduled batch job that keeps the knowledge base up to date.

This is an example of a deeper optional integration: no shared code is needed beyond the contract interface, the coupling is unidirectional (Issue Tracker → AI Support), and the feature degrades gracefully when one of the two AppJars is absent.