English Documentation

Setup

Setting up the Faktor-IPS Product Designer with custom product projects

The following describes what is required to set up the Product Designer manually. However, it is recommended to create the Product Designer via the archetype as described in the chapter 'Product Designer Archetype'. This saves many of the steps described below.

Preconditions:

The Product Designer requires the latest Faktor-IPS version (25.1) and Java 21. The first step is therefore to update the Faktor-IPS dependencies in Eclipse (Updatesite) and rebuild the model projects once.

For more information on compatibilities between Faktor-IPS and Eclipse, please refer to this overview.

Creating a Maven project:

Next, a new Maven project is created with dependencies for the Product Designer, model projects, and Spring Boot starter.

Dependencies:

Productdesigner-Web:

  <dependencies>
        <dependency>
            <groupId>org.faktorips.productdesigner</groupId>
            <artifactId>productdesigner-web</artifactId>
            <version>25.7.0</version>
        </dependency>
  </dependencies>

Add required model dependencies – for example:

 <dependencies>
        <dependency>
            <groupId>de.faktorzehn.muster.shu-gewerbe</groupId>
            <artifactId>vm-gewerbe-gruppenunfall-produktmodellerw</artifactId>
            <version>25.7.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>de.faktorzehn.muster.shu-gewerbe</groupId>
            <artifactId>vm-gewerbe-basis-produkte</artifactId>
            <version>25.7.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
 </dependencies>

A main class is required in the Spring Boot plug-in configuration. This is created in the next step. The necessary configuration can already be entered in pom.xml:

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <wait>500</wait>
                    <maxAttempts>240</maxAttempts>
                    <!-- Insert the Product Designer Application here (see below) -->
                    <mainClass>org.faktorips.productdesigner.demo.SampleProductDesignerApplication</mainClass>
                    <layout>JAR</layout>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

Below is an example pom.xml of a Product Designer Maven project:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>de.faktorzehn.commons</groupId>
        <artifactId>f10-suite-starter-spring</artifactId>
        <version>25.7.0</version>
    </parent>
    <groupId>org.faktorips.productdesigner</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>21</java.version>
        <maven.compiler.release>${java.version}</maven.compiler.release>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <faktorips.version>25.7.0.release</faktorips.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.faktorips.productdesigner</groupId>
            <artifactId>productdesigner-web</artifactId>
            <version>25.7.0</version>
        </dependency>
        <!-- INSERT the model dependencies here -->
        <dependency>
            <groupId>de.faktorzehn.muster.shu-gewerbe</groupId>
            <artifactId>vm-gewerbe-gruppenunfall-produktmodellerw</artifactId>
            <version>25.7.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>de.faktorzehn.muster.shu-gewerbe</groupId>
            <artifactId>vm-gewerbe-basis-produkte</artifactId>
            <version>25.7.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
    </dependencies>
    <build>
        <defaultGoal>spring-boot:run</defaultGoal>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <wait>500</wait>
                    <maxAttempts>240</maxAttempts>
                    <!-- Insert the Product Designer Application here -->
                    <mainClass>org.faktorips.productdesigner.demo.SampleProductDesignerApplication</mainClass>
                    <layout>JAR</layout>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>com.vaadin</groupId>
                <artifactId>vaadin-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>prepare-frontend</goal>
                        </goals>
                        <phase>compile</phase>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
Creating a Spring Boot Application Class and it’s configuration

As described above, a main class is required. The setting in pom.xml has already been made in the previous step. An application class is now created. Example: SampleProductDesignerApplication.java:

import com.vaadin.flow.component.page.AppShellConfigurator;
import com.vaadin.flow.server.AppShellSettings;
import com.vaadin.flow.spring.annotation.EnableVaadin;
import com.vaadin.flow.theme.Theme;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.faktorips.productdesigner.core.ProductDesigner;
import org.faktorips.productdesigner.core.ProductDesignerConfigurationProperties;

@Theme(value = "productdesigner", variant = "card-section-pages")
@SpringBootApplication(scanBasePackages = {ProductDesigner.BASE_PACKAGE, <<enter package from SampleProductDesignerApplication>>})
@EnableConfigurationProperties(ProductDesignerConfigurationProperties.class)
@EnableVaadin(value = ProductDesigner.BASE_PACKAGE)
public class SampleProductDesignerApplication implements AppShellConfigurator {

    private static final long serialVersionUID = 1L;

    public static void main(String[] args) {
        SpringApplication.run(SampleProductDesignerApplication.class, args);
    }

    @Override
    public void configurePage(AppShellSettings settings) {
        settings.addFavIcon("icon", "../favicon.ico", "48x48");
    }
}

Note: If the application is in a (sub)package other than ProductDesigner.BASE_PACKAGE, it is necessary to enter this package next to the ProductDesigner.BASE_PACKAGE. Otherwise, this package will not be taken into account if it is overwritten. In the next step, a SampleProductDesignerConfig.java is created, and this is to be integrated automatically; it is therefore necessary to specify this package.

In addition, a bean of the ProductDesignerPermissionService is required. This class is used to determine the user’s authorizations based on various factors. This service is also necessary if no single-sign-on is used. In the provided DefaultProductDesignerPermissionService, write permissions are determined by the RuntimeRepositories, the configuration in the application.yml and the role by the RoleMapper. The SampleProductDesignerConfig.java is created alongside the SampleProductDesignerApplication.java:

@Primary
@Component
public class SampleProductDesignerConfig {

    @SessionScope
    @Bean
    public ProductDesignerPermissionService permissionService(Optional<User> user,
            IModifiableRuntimeRepository repository,
            ProductDesignerConfigurationProperties properties) {
        return new DefaultProductDesignerPermissionService(user.orElse(new LocalUser()), repository,
                properties.readOnlyMode() ? ProductDesignerMode.READ_ONLY_MODE : ProductDesignerMode.EDIT_MODE);
    }
}
Creating the Configuration

Now, under src/main/resources/, create an application.yml. One example:

logging:
  level:
    org.springframework: WARN

server:
  port: 8080

vaadin:
  urlMapping: '/ui/*'
  launch-browser: true

ips-product-designer:
  local:
    ips-project-path: ../../../git/mustercontent/vm/vm.shu.gewerbe/gruppenunfall/produkte/
  additional-repos:
    - de.faktorzehn.versicherungsmodell.gw.produkte.GwProduktClassloaderRuntimeRepository
    - de.faktorzehn.versicherungsmodell.gw.produkte.GwAllgemeinClassloaderRuntimeRepository
  read-only-mode: false
Parameters

The following parameters must be set in the Product Designer under ips-product-designer.

additional-repos

string[]

List of additional repositories (class reference, fully qualified name) on which the product project depends.

read-only-mode

boolean

If true: the product designer is started in read-only mode (regardless of which user logs in with which role)

Version Control Mode

The Product Designer currently supports two modes:

  • local: The Product Designer uses a local folder to load the repository and all its product components. All users use the same folder. If it is still a GIT repository, a commit (to the current branch) can be created here.

  • git: The Product Designer clones the repository into a user directory when logging in. With a “commit”, a commit is created on a new branch (the name is made up of the username, the actual date, and a consecutive number) and then pushed.

One of the modes must be selected. To do this, either write ips-product-designer.local or ips-product-designer.git and then the necessary parameters must be set.

Local

Parameters for the local mode:

ipsProjectPath

string

Relative or absolute path to the IPS project

Git

Parameters for the mode with git integration:

relativeIpsProjectPath

string

Relative path to the IPS project. (The path must be relative, as the Git repository is checked out in the respective user directory)

userFolderPath

string

Relative or absolute path to the folder in which a folder is created for each user and the repository is cloned

repositoryUrl

string

Git

branch

string

Name of the branch to be checked out by default when cloning

keyPath

string

Path to the private SSH key for the technical user

For Git mode, a technical user is required to clone, pull, push, etc. the repository. Changes are then made in the name of the technical user. Currently, the Product Designer only supports authentication via SSH and with a passwordless private key (all common encryptions). In order to keep the system as secure as possible, the key should not fall into the hands of third parties and should only be given the most necessary authorizations.

Inclusion of additional repositories

Additional repositories can be integrated under additional-repos, as described above. In the Java classes, not only product repositories but also the model repositories on which they are based must be linked via addDirectlyReferencedRepository so that the Product Designer can also find model classes that are not currently used in the product repository.

In other constellations when using Faktor-IPS it was not necessary to specify the model repositories. However, the Product Designer needs this information to analyze the blocks.

To ensure that the repositories are loaded correctly at runtime, each repository should contain a class with an INSTANCE field for an IRuntimeRepository or IRuntimeRepositoryLookup.

For example, the class GwProduktClassloaderRuntimeRepository referenced in the .yml for providing and configuring the singleton repository looks like this:

import org.faktorips.runtime.ClassloaderRuntimeRepository;
import org.faktorips.runtime.formula.groovy.GroovyFormulaEvaluatorFactory;

public class GwProduktClassloaderRuntimeRepository {

    public static final ClassloaderRuntimeRepository INSTANCE = ClassloaderRuntimeRepository
            .create("de/faktorzehn/versicherungsmodell/gw/produkte/internal/faktorips-repository-toc.xml");

    static {
        INSTANCE.addDirectlyReferencedRepository(GwAllgemeinClassloaderRuntimeRepository.INSTANCE);
        INSTANCE.setFormulaEvaluatorFactory(new GroovyFormulaEvaluatorFactory());
    }

    private GwProduktClassloaderRuntimeRepository() {
        // Soll nicht instanziiert werden
    }

}

First, a ClassloaderRuntimeRepository INSTANCE is initialized based on the associated toc.xml. In the static initialization block, necessary referenced repositories are then incorporated via their respective instances (INSTANCE.addDirectlyReferencedRepository(GwAllgemeinClassloaderRuntimeRepository.INSTANCE)), and additionally, configurations for the repository instance are defined (INSTANCE.setFormulaEvaluatorFactory(new GroovyFormulaEvaluatorFactory());).

Adding a Favicon

Finally, to display application icons in the browser tab, a favicon can optionally be placed in src/main/resources/static.

Single-Sign-On (SSO)

The Product Designer can also be operated with single-sign-on. The archetype can be used to generate the application with or without SSO. To set up SSO manually (or add it later), the following additional steps must be carried out.

    <dependency>
        <groupId>de.faktorzehn.commons</groupId>
        <artifactId>f10-commons-auth-oauth2-client</artifactId>
    </dependency>
    <dependency>
        <groupId>de.faktorzehn.commons</groupId>
        <artifactId>f10-commons-auth-oauth2-resourceserver</artifactId>
    </dependency>
    <dependency>
        <groupId>de.faktorzehn.commons</groupId>
        <artifactId>f10-commons-spring-autoconfiguration</artifactId>
    </dependency>

In the configuration file src/main/resources/application.yml the used Keycloak server must be configured, for example:

keycloak-client:
  issuer-uri: <YOUR KEYCLOAK ISSUER-URI HERE>

spring:
  security:
    oauth2:
      client:
        registration:
          oauth2:
            client-id: <YOUR CLIENT ID HERE>
            client-secret: <YOUR CLIENT SECRET HERE>
            client-name: Product-Designer
            scope: openid
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
            authorization-grant-type: authorization_code
          f10-service-account:
            client-id: <YOUR CLIENT ID HERE>
            client-secret: <YOUR CLIENT SECRET HERE>
            scope: openid
            authorization-grant-type: client_credentials
            provider: oauth2
        provider:
          oauth2:
            issuer-uri: ${keycloak-client.issuer-uri}
            user-name-attribute: preferred_username
      resourceserver:
        jwt:
          issuer-uri: ${keycloak-client.issuer-uri}

For details, see the f10-commons documentation.

Additional beans must be added to SampleProductDesignerConfig.java. Beans for a RoleMapper and TenantMapper are required. See also here the documentation of f10-commons. For the F10 environment, there is a special productdesigner-f10 module with ready-made implementations of the RoleMapper and TenantMapper.

These settings can be combined in a configuration class that could look like this:

@Primary
@Component
public class SampleProductDesignerConfig {

    @Bean
    RoleMapper roleMapper() {
        return new F10ProductDesignerRoleMapper();
    }

    @Bean
    TenantMapper tenantMapper() {
        return new F10ProductDesignerTenantMapper();
    }

    @SessionScope
    @Bean
    public ProductDesignerPermissionService permissionService(Optional<User> user,
            IModifiableRuntimeRepository repository,
            ProductDesignerConfigurationProperties properties) {
        return new DefaultProductDesignerPermissionService(user.orElse(new LocalUser()), repository,
                properties.readOnlyMode() ? ProductDesignerMode.READ_ONLY_MODE : ProductDesignerMode.EDIT_MODE);
    }
}
If the configuration class is new, do not forget to enter the corresponding package in scanBasePackages in the @SpringBootApplication annotation.

Docker Deployment

When providing and deploying the application in Docker containers, it should be noted that the application is deployed as a .jar file, but the product data is unpacked and copied into the container. For this, the vaadin.productionMode must first be set to true in the pom.xml.

<profiles>
    <profile>
        <id>production</id>
        <properties>
            <vaadin.productionMode>true</vaadin.productionMode>
        </properties>
        <build>
            <plugins>
                <plugin>
                    <groupId>com.vaadin</groupId>
                    <artifactId>vaadin-maven-plugin</artifactId>
                    <version>${vaadin.version}</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>prepare-frontend</goal>
                                <goal>build-frontend</goal>
                            </goals>
                            <phase>compile</phase>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

Dockerfile example:

FROM eclipse-temurin:21-jre-jammy
RUN apt-get update \
    && ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime \
    && dpkg-reconfigure -f noninteractive tzdata
ARG UID=999
ARG GID=999
ENV JAVA_TOOL_OPTIONS "-Xms480m -Xmx1024m"
RUN groupadd --gid $GID spring \
    && useradd -r -m -d /opt/spring -s /sbin/nologin --gid $GID --uid $UID -c "Spring user" spring \
    && chmod 755 /opt/spring \
    && mkdir -p /var/opt/spring \
    && chown spring: /var/opt/spring \
    && chmod 755 /var/opt/spring
WORKDIR /opt/spring
COPY ${PATH_TO_APPLICATION_JAR} application.jar
COPY ${PATH_TO_PRODUCT_FOLDER} /var/opt/spring/produkte
RUN chown -R spring: /var/opt/spring
USER $UID
EXPOSE 8080
CMD ["java", \
    "-Dspring.profiles.active=production", \
    "-jar", \
    "application.jar", \
    "--server.port=8080", \
    "--server.forward-headers-strategy=FRAMEWORK"]

docker-compose.yml example:

version: '2.4'

services:
  productdesigner-sample:
    container_name: ${CONTAINER_NAME}-sample
    build:
      context: ../
      dockerfile: ./path/to/Dockerfile
      args:
      - PATH_TO_APPLICATION_JAR=${PATH_TO_APPLICATION_JAR}
      - PATH_TO_PRODUCT_FOLDER=${PATH_TO_PRODUCT_FOLDER}
    environment:
      SPRING_PROFILES_ACTIVE: production
      ips-product-designer.ips-project-path: /var/opt/spring/produkte
    labels:
      url: ${CONTAINER_NAME}-sample
      entry-path: ui

networks:
    default:
        name: network-${CONTAINER_NAME}
        labels:
            retention: ${CONTAINER_RETENTION}