1. Overview

1.1. Product Philosophy

1.1.1. Why yuuvis® Momentum?

The digital transformation demands highly customized solutions to serve the needs and expectations of its user and to fully leverage its advantages. These solutions may stress the underlying application from very different angles - think of the different workloads a solution for email archiving poses compared to one facilitating workflows, or to one where analysis and classification and processing of incoming documents are the focus. What they all have in common these times is the need to reliably handle ever-growing amount of documents in an audit-proof manner, guaranteeing performant access via a capable query language over vast amounts of data. All access has to be controllable via an integrated rights management. And deep integration into existing system landscapes should be supported by flexible customization options.

If you are concerned about your archive solution not scaling to your amount of documents, if you are not sure whether to keep your data safe on your own hardware or might to move to the cloud later, if you need a platform offering a performant backend to develop your web applications against, yuuvis® Momentum might be the tool of choice for you. Check out a few use cases here.

1.1.2. Key Features

  • API first

  • Excellent scalability - high performance on big amounts of data

  • Docker/Kubernetes

  • No commercial databases etc. required

  • multi-tenancy

  • hybrid: runs in cloud or on premises

  • Simplified operation and administration

  • Nearly no downtime

Solutions build using yuuvis® Momentum are highly scalable, run either cloud native or on premises and exhibit outstanding performance. yuuvis® Momentum offers you to tap into existing user management and is readily integrated into an existing system environment via its REST API. Functionality is easily expanded using concepts like Webhooks, AMQP Hooks and Interceptors. It offers a complete audit trail, performant Search features in an SQL-like manner and Rights Management. It supports asynchronous document processing via Tagging, evolving documents via the Schema Flow and handling of Compound Documents. And all that with support for multi-tenancy with administration on global system as well as on tenant level.

Consider yuuvis® Momentum consisting of a core system accessible via API gateway and optional additional services with second layer interfaces.

1.2. Core Services

The core is the heart of the product and connects to your infrastructure. It consists of basic core services that are required for the proper operation of a yuuvis® Momentum instance. Each individual service can be scaled to optimize the usage of your resources.

Overview of yuuvis® Momentum core services and their connection to third-party infrastructure.

The entirety of the core’s functions is made available through the API gateway. Depending on the concrete request, multiple core services are involved in the processing chain. Some basic use case flows are illustrated below. Just click to view them.

Authentication Flow (Browser)
Illustration of the process steps that are passed during a user login via browser.
Processing steps
  1. HTTP request to any API endpoint

  2. Redirect to identity provider

  3. Verify credentials externally

  4. Redirect to authentication with auth code

  5. Send auth code to authentication service

  6. Retrieve userId using auth code

  7. Recieve userId

  8. Request role set acquisition

  9. Query user role set

  10. Recieve user role set

  11. Present role set

  12. Provide authentication token and proceed with initial API request

  13. Request information from other parts of the system

  14. Obtain requested information

  15. Produce API response

  16. Send HTTP response to user

Webhook entry points
  1. user.info

Import Flow
Illustration of the process steps that are passed during a document import.
Processing steps
  1. HTTP POST request containing metadata and content

  2. Enrichment of request with authentication token

  3. Defer content to storage services

    1. Analyze content file

    2. Skip contentanalyzer service

  4. Content storage handling

    1. Using custom storage via archive service

    2. Using an interface of the repository service

  5. Create metadata based on previous steps

  6. Write metadata to storage / index instances

  7. Index new object in Elasticsearch

  8. Create initial audit entry

  9. Create API response from metadata

  10. Return metadata as HTTP response

During asynchronous import operations, the controller service provides messaging for the boxed in services

Webhook entry points
  1. dms.request.objects.upsert.storage-before

  2. dms.request.objects.upsert.database-before

  3. dms.response.objects, dms.response.objects.insert

Content Retrieval Flow
Illustration of the process steps that are passed during a content retrieval.
Processing steps
  1. HTTP GET request to object URL

  2. Enrichment of request with authentication token

  3. Check for user authorization using search service query

  4. Query Elasticsearch for objectId

  5. Elasticsearch metadata response (if user is authorized)

  6. Repository URL of objectId

  7. Request content of objectId

  8. Query objectId in storage provider

  9. Storage provider metadata response

  10. Return object metadata

  11. Write CONTENT_ACCESSED audit entry

  12. Create API response from metadata

  13. Return HTTP metadata response

Webhook entry points
  1. dms.request.objects.contents

Metadata Retrieval Flow
Illustration of the process steps that are passed during a metadata retrieval.
Processing steps
  1. HTTP GET request to object URL

  2. Enrichment of request with authentication token

  3. Request metadata

  4. Query objectId in database

  5. Database metadata response

  6. Return object metadata

  7. Write METADATA_ACCESSED audit entry

  8. Create API response from metadata

  9. Return HTTP metadata response

Webhook entry points
  1. dms.response.objects

Search Flow
Illustration of the process steps that are passed during a search query.
Processing steps
  1. HTTP POST request with query

  2. Enrichment of request with authentication token

  3. Request query execution

  4. Translate and send Elasticsearch query

  5. Receive Elasticsearch query results

  6. Return metadata object list

  7. Create API response from metadata

  8. Return HTTP metadata response

Webhook entry points
  1. dms.request.search

  2. dms.response.objects, dms.response.objects.search

Content Update Flow
Illustration of the process steps that are passed during a content update.
Processing steps
  1. HTTP POST request to content URL of object

  2. Enrichment of the request with authentication token

  3. Verify user has writing permissions on object using search service

  4. Query object in Elasticsearch

  5. Return Elasticsearch query results

  6. Return user authorization verification results

  7. Infer analysis of new content item

  8. Commit new content to storage

  9. Content Storage Handling

    1. Using custom storage via archive service

    2. Using an interface of repository service

  10. Update object metadata contentstream attribute

  11. Commit updated metadata to database and index

  12. Index the updated metadata in Elasticsearch

  13. Write CONTENT_UPDATED audit entry

  14. Return updated metadata

  15. Create API response from metadata

  16. Return updated metadata

Webhook entry points
  1. dms.request.objects.upsert.storage-before

  2. dms.request.objects.upsert.database-before

  3. dms.response.objects, dms.response.objects.update

Metadata Update Flow
Illustration of the process steps that are passed during a metadata update.
Processing steps
  1. HTTP POST request to objectId URL

  2. Enrichment of request with authentication token

  3. Query for objectId using search service to verify user authorization

  4. Query Elasticsearch for object

  5. Elasticsearch object response (if user has permissions for update object)

  6. Authorization test query response

  7. Infer metadata validation and update

  8. If expiration date has changed: update content storage via archive service

  9. Infer metadata update

  10. Write new metadata to database, write METADATA_UPDATED audit entry

  11. Index new metadata in Elasticsearch

  12. Create API response from metadata

  13. Return metadata HTTP response

Webhook entry points
  1. dms.request.objects.upsert.storage-before

  2. dms.request.objects.upsert.database-before

  3. dms.response.objects, dms.response.objects.update

Deletion Flow
Illustration of the process steps that are passed during a deletion.
Processing steps
  1. HTTP DELETE request to objectId URL

  2. Enrichment of request with authentication token

  3. Query object using search service to verify user authorization

  4. Query object in Elasticsearch

  5. Elasticsearch object reponse

  6. Authorization verification results

  7. Infer flag for deletion on object

  8. Flag as deleted in database, FLAGGED_FOR_DELETE audit entry

  9. Flag as deleted in Elasticsearch via index service

  10. Delete content through repository service

  11. Infer deletion of object in database

  12. Infer deletion of object in Elasticsearch

  13. OBJECT_DELETED audit entry

  14. Return deletion results

Webhook entry points
  1. dms.request.objects.delete

  2. dms.response.objects.delete

1.3. Additional Services

A wide range of optional extensions are available. They support developers in the fields of client development, tenant administration and business process management. It is also possible to install components for an SAP® connection or even an AI integration.

Overview of yuuvis® Momentum additional services and their connection to third-party infrastructure.

1.3.1. Client Development

yuuvis® Momentum client as reference implementation is the first and major example of an application build for yuuvis® Momentum. More than a mere showcase, it comes with own services, delivering reusable functionality for client applications in Angular using the developer libraries.

2. Core

The core system consists of multiple services that can be scaled to the project’s requirements. Using widely configurable and customizable processing flows, the core system provides a REST API for document lifecycle. Hereby, it is especially important to decide for synchronous or asynchronous processing for the individual use case.

The core system furthermore provides API as well as backend tools for resource management, testing and maintenance.

2.1. DMS Objects

Object instances managed in the yuuvis® Momentum document management system (short DMS objects) are structured in JSON format with a very strict convention. The DMS objects are always enclosed in a list. Thus, request and response formats are constant and independent on the handled number of DMS objects.

DMS objects are either

  • document objects (short: documents) or

  • folder objects (short: folders).

Within a document, a binary content file can be referenced and thus be assigned that DMS object.

2.1.1. Object Properties

DMS objects have the following property sections:

Section key Description Available in search queries

properties

Available in all DMS objects. It contains

  • user-defined properties from the applied schema and

  • pre-defined general system properties.

yes, in SELECT and/or WHERE clauses

contentStreams

Available in DMS objects with a binary content file assigned to them. It is always a list with one entry containing a set of content stream properties that are pre-defined in the global schema.

yes, in SELECT and/or WHERE clauses

renditions

Process-related controlling information. Only available during the import of objects with a binary content file. It contains a list of rendition specifications.

no

options

Process-related controlling information. Only available during specific processing steps.

no

Example DMS Object without Binary Content File
Example response body of a metadata retrieval for a DMS object without content.
{
    "objects": [
        {
            "properties": {
                "system:objectId": {
                    "value": "12345678-90ab-cdef-1234-567890ab"
                },
                "system:traceId": {
                    "value": "1234567812345678"
                },
                "system:objectTypeId": {
                    "value": "appTest:processdocument"
                },
                "system:lastModificationDate": {
                    "value": "2023-06-22T14:40:19.180Z"
                },
                "system:versionNumber": {
                    "value": 5
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:tenant": {
                    "value": "yuuvistest"
                },
                "system:createdBy": {
                    "value": "abcdef12-3456-7890-abcd-ef123456"
                },
                "appTest:exampleproperty": {
                    "value": false
                },
                "system:creationDate": {
                    "value": "2023-06-22T14:00:57.260Z"
                },
                "system:lastModifiedBy": {
                    "value": "abcdef12-3456-7890-abcd-ef123456"
                }
            }
        }
    ]
}
Example DMS Object with Binary Content File
Example response body of a metadata retrieval for a DMS object with content.
{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "appEmail:email"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2018-01-29T13:13:113Z"
            },
            "system:versionNumber": {
                "value": 2
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "97a35859dbb4c435"
            },
            "appEmail:from": {
                "value": "Maria Schmidt <schmidt@example.de>"
            },
            "appEmail:to": {
                "value": ["Hans Meier <meier@example.de>"]
            },
            "appEmail:cc": {
                "value": ["Conrad Schulze <schulze@example.de>",
                "Emilia Lehmann <lehmann@example.de>"]
            },
            "appEmail:subject": {
                "value": "Updated Bewerbungsunterlagen"
            },
            "table": {
                "columnNames": ["iColumn1", "iColumn2", "iColumn3"],
                "value": [["something", "to know", true],["more", "infos", false]]
            }
        },
        "contentStreams": [{
            "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
            "length": 173413,
            "mimeType": "message/rfc822",
            "fileName": "upload.eml",
            "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
            "repositoryId": "repo252"
        }]
    }]
}
Example DMS Object with Binary Content File and Rendition
Example JSON to be included in an import request for a DMS object with content and rendition.
{
    "objects": [{
        "properties": {
            "enaio:objectTypeId": {
                "value": "E13C7EBF4B974B3A9FF296C01F90D0EE"
            },
            "sysfrom": {
                "value": "Garco Meissler <garco@example.de>"
            },
            "systo": {
                "value": "Dudreas Annkel <dudreas@example.de>"
            },
            "syscc": {
                "value": "Kruedeas Anger <kruedeas@example.de>"
            },
            "syssubject": {
                "value": "Wachsmalstift rückwärts kontrollieren"
            },
            "redline:baseTypeId": {
                "value": "DOCUMENT"
            },
            "redline:mandant": {
                "value": "default"
            }
        },
        "contentStreams": [{
            "mimeType": "message/rfc822",
            "fileName": "upload.eml",
            "cid": "cid_63apple"
        }],
        "renditions": [{
            "mimeType": "text/plain",
            "kind": "text",
            "contentStream": {
                "length": 39939,
                "mimeType": "text/plain",
                "fileName": "content.txt",
                "cid": "rendition_0"
            }
        }]
    }]
}

2.1.2. Binary Content Files

One of the key concepts of a document management system (DMS) is the effective handling of binary content files. On top of the basic operations like import, retrieval, update and deletion, further demands have to be considered in many companies. Each content update triggers the creation of a new version of the object whereas the previous object version is moved to the version history. Furthermore, in order to comply with legal bindings regarding the storage time, yuuvis® Momentum allows you to configure strict retention times during which the binary content files can neither be deleted nor updated. Binary content files of suitable formats can be analyzed in order to extract a text rendition that will be included in the full-text search. For many file types, also a PDF rendition can be retrieved.

General Characteristics
  • The file size for binary content files in yuuvis® Momentum is limited to 32 GB per file.

  • The core system can handle any file type as binary content file. For a wide range of file types, the generation of renditions is supported.

  • Binary content files are stored in repositories that are managed by the repository service and, if necessary, connected to yuuvis® Momentum via the archive service.

  • Retention times can be specified in order to protect binary content files from deletion and modification.

  • Binary content files can be assigned only to document objects. It is not possible to assign more than one binary content file per object.

  • Document objects can be created without any binary content file assigned to them. Binary content files can be added to such already existing objects.

  • Objects with a binary content file assigned to them have the section contentStreams in their JSON-formatted object representation.

Content Analysis

In the default configuration, each binary content file imported to yuuvis® Momentum passes the content analyzer provided by the repository service. Its mime type is determined and the contained text is extracted for the most common file types.

Text Extraction

The repository service can extract the text contained in an imported binary content file. The extracted plain text is stored as text rendition in the search index and will be used for the full-text search together with all values of string properties within the metadata. Details on supported file types, calculation and storage are available in the section.

The file types for which text extraction is available are listed here: Content Renditions

The text rendition can be retrieved via the following endpoint GET /api/dms/objects/{objectId}/contents/renditions/text

Mime Type Determination

The contentanalyzer service is responsible for the determination of the mime type of binary content files that are imported to yuuvis® Momentum. The determined mime type is stored in the content stream properties section of the corresponding DMS object.

E-mail Metadata Extraction

As of 2024 Spring, yuuvis® Momentum contains a predefined app for the extraction of basic e-mail metadata. The app triggers the contentanalyzer service to read the following information from binary content files during their import, if they have been identified as EML or MSG e-mail file:

Property Type Description

appSystemmail:subject

String

Optional. Subject of the e-mail.

appSystemmail:sent

datetime

Required. Date and time when the e-mail was sent.

appSystemmail:from

String

Required. E-mail address of the sender.

appSystemmail:to

List of strings

Optional. List of direct receivers.

appSystemmail:cc

List of strings

Optional. List of CC receivers.

appSystemmail:bcc

List of strings

Optional. List of BCC receivers.

appSystemmail:messageId

String

Optional. ID of the message.

appSystemmail:attachments

List of strings

Optional. File names of the attachments.

appSystemmail:attachmentCount

Int

Optional. Number of attachments.

The analysis is only available during import requests via POST /api/dms/objects.

Required configuration steps:

  • The app systemmail has to be activated for the corresponding tenant via app set.

    Example app set
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <apps xmlns="http://optimal-systems.org/ns/yuuvis/apps/">
        <app>
            <name>systemmail</name>
            <state>enabled</state>
        </app>
    </apps>
  • The app schema for the systemmail app has to be available.

    App schema for 'systemmail'
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/">
        <version>3</version>
        <lastModificationDate>2023-06-29T23:23:54.635Z</lastModificationDate>
        <propertyStringDefinition>
            <id>appSystemmail:subject</id>
            <propertyType>string</propertyType>
            <cardinality>single</cardinality>
            <required>false</required>
        </propertyStringDefinition>
        <propertyDateTimeDefinition>
            <id>appSystemmail:sent</id>
            <propertyType>datetime</propertyType>
            <cardinality>single</cardinality>
            <required>true</required>
        </propertyDateTimeDefinition>
        <propertyStringDefinition>
            <id>appSystemmail:from</id>
            <propertyType>string</propertyType>
            <cardinality>single</cardinality>
            <required>true</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>appSystemmail:to</id>
            <propertyType>string</propertyType>
            <cardinality>multi</cardinality>
            <required>false</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>appSystemmail:cc</id>
            <propertyType>string</propertyType>
            <cardinality>multi</cardinality>
            <required>false</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>appSystemmail:bcc</id>
            <propertyType>string</propertyType>
            <cardinality>multi</cardinality>
            <required>false</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>appSystemmail:messageId</id>
            <propertyType>string</propertyType>
            <cardinality>single</cardinality>
            <required>false</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>appSystemmail:attachments</id>
            <propertyType>string</propertyType>
            <cardinality>multi</cardinality>
            <required>false</required>
        </propertyStringDefinition>
        <propertyIntegerDefinition>
            <id>appSystemmail:attachmentCount</id>
            <propertyType>integer</propertyType>
            <cardinality>single</cardinality>
            <required>false</required>
        </propertyIntegerDefinition>
        <typeSecondaryDefinition>
            <id>appSystemmail:email</id>
            <baseId>system:secondary</baseId>
            <propertyReference>appSystemmail:subject</propertyReference>
            <propertyReference>appSystemmail:sent</propertyReference>
            <propertyReference>appSystemmail:from</propertyReference>
            <propertyReference>appSystemmail:to</propertyReference>
            <propertyReference>appSystemmail:cc</propertyReference>
            <propertyReference>appSystemmail:bcc</propertyReference>
            <propertyReference>appSystemmail:messageId</propertyReference>
            <propertyReference>appSystemmail:attachments</propertyReference>
            <propertyReference>appSystemmail:attachmentCount</propertyReference>
            <contentStreamAllowed>required</contentStreamAllowed>
        </typeSecondaryDefinition>
    </schema>
  • The contentanalyzer service must not be skipped and its metadata analysis has to be activated. Check the serviceConfiguration.json configuration file.

    Example 'serviceConfiguration.json' with suitable configuration
    {
            "services": {
                    "contentanalyzer": {
                            "skip": false,
                            "analyze": [
                                    {
                                            "mimetype": true,
                                            "content": true,
                                            "metadata": true
                                    }
                            ]
                    }
            }
    }
Storage

The repository service is responsible for the storage management of binary content files. For this purpose, an S3 store is the standard archive solution. Alternatively or additionally, many external archive providers are supported to be connected via the archive Service.

Furthermore, the SHA-256 digest for the binary content files is calculated during the saving processes and stored in the content stream properties section of the corresponding DMS objects.

Large Files

The import of large binary content files via POST /api/dms/objects might be very slow and often leads to timeouts. Thus, it is useful to split them in pieces and upload them in multiple sub-processes. The steps are described in this section. You can upload up to 10,000 pieces of one binary content file. The DMS object to which the complete content file is finally assigned is created after the successful upload of all pieces.

Before the final step of DMS object creation, the pieces of content are only stored temporarily in the repository service. To ensure that all pieces of one content file are processed by the same repository service instance, the Kubernetes Loadbalancer internally sets a serviceInstanceUrl during the upload initialization. It is stored in a shared cache for all repository service instances. For each piece to be uploaded, the correct instance is read from this cache.
  • Split your large binary content file into pieces.

  • Initialize the import via POST /api/dms/uploads and extract the uploadId from the response body. After each processing step of the upload, a maximum time of 2 days (default configuration) inactivity is accepted before the process and all its pieces are automatically deleted.

    Example
    POST /api/ms/uploads
    { "uploadId": "MP_a2f7e1aa-ff42-4140-b9ec-5de4cc61f1a5" }
  • Import each individual piece via PUT /api/dms/uploads/{uploadId}/parts/{partNumber}.

    • Use a single piece of your content file as binary request body (no multipart).

    • For uploadId, use the value that was generated during the initialization step. Use the same value for all pieces of one binary content file.

    • For partNumber, use the index number of the current piece starting with 1.

    Example with 3 pieces
    PUT /api/dms/uploads/MP_a2f7e1aa-ff42-4140-b9ec-5de4cc61f1a5/parts/1
    200 OK
    
    PUT /api/dms/uploads/MP_a2f7e1aa-ff42-4140-b9ec-5de4cc61f1a5/parts/2
    200 OK
    
    PUT /api/dms/uploads/MP_a2f7e1aa-ff42-4140-b9ec-5de4cc61f1a5/parts/3
    200 OK
  • Optionally, you can retrieve an overview of your running upload processes and the already imported pieces via GET /api/dms/uploads.

  • In case you want to cancel your upload process, you can delete the already uploaded pieces via DELETE /api/dms/uploads/{uploadId}.

  • Finalize the upload via POST /api/dms/uploads/{uploadId}. Optionally, you can validate the total number of imported pieces by appending the numberOfParts query parameter.

    Example
    POST /api/dms/uploads/MP_a2f7e1aa-ff42-4140-b9ec-5de4cc61f1a5?numberOfParts=3
    200 OK

    After calling this endpoint, no further pieces can be added to the process indicated by the current uploadId.

  • Connect the completed binary content file to a DMS object in yuuvis® Momentum via POST /api/dms/uploads/{uploadId}/objects. Specify the metadata in properties section of the JSON request body.

    The contentStreamId automatically refers to the binary content file created by the upload process specified by uploadId. However, the contentanalyzer service is SKIPPED. Thus, if you need proper values in the contentStreams section for fileName and mimeType, you need to set them in the JSON request body.
    Example request body for the creation of a DMS object after partial upload
    {
        "objects": [{
            "properties": {
                "system:objectTypeId": {
                    "value": "system:document"
                },
                "customproperty": {
                    "value": "myvalue"
                }
            },
            "contentStreams": [{
                "mimeType": "application/pdf",
                "fileName": "myfilename.pdf"
            }]
        }]
    }

2.2. Schema for DMS Objects

Each object in yuuvis® Momentum instantiates an object type that is defined in the applied tenant schema. Once a DMS object is created, its object type is set and remains unmodifiable during its entire lifecycle.

Depending on the definition of the instantiated object type, a set of properties is available for the corresponding DMS object. The properties themselves have to be defined in a schema as well.

2.2.1. Schema Outline

A schema contains property definitions and object type definitions in XML format in the following mandatory order. It is possible to skip parts but not to change their order.

  1. Label (as of 2023 Autumn)

  2. Property definitions

  3. Object Type definitions:

    1. Document type definitions

    2. Folder type definitions

    3. Secondary object type definitions

The label is an optional string field to specify a project-specific schema versioning information. Its string value is limited to 128 characters.

Display a simple example schema
A valid example schema
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://optimal-systems.org/ns/dmscloud/schema/v5.0/dmsCloud-schema.xsd">
        <label>1.2.3</label>
        <propertyStringDefinition>
            <id>from</id>
            <propertyType>string</propertyType>
            <cardinality>single</cardinality>
            <required>true</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>to</id>
            <propertyType>string</propertyType>
            <cardinality>multi</cardinality>
            <required>true</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>subject</id>
            <propertyType>string</propertyType>
            <cardinality>single</cardinality>
            <required>true</required>
            <defaultValue>hello</defaultValue>
            <maxLength>20</maxLength>
            <minLength>4</minLength>
        </propertyStringDefinition>
        <propertyDateTimeDefinition>
            <id>received</id>
            <propertyType>datetime</propertyType>
            <cardinality>single</cardinality>
            <required>true</required>
        </propertyDateTimeDefinition>
        <typeDocumentDefinition>
            <id>email</id>
            <baseId>system:document</baseId>
            <propertyReference>from</propertyReference>
            <propertyReference>to</propertyReference>
            <propertyReference>received</propertyReference>
            <contentStreamAllowed>required</contentStreamAllowed>
        </typeDocumentDefinition>
</schema>

2.2.2. Scopes and Endpoints for Schemata

In the multi-tenant landscape of yuuvis® Momentum, it is important to be aware of the scope of property and object type definitions.

  • Any object types or properties that should be available for all tenants should to be introduced to the global schema.

  • To prevent cluttering the global schema and allow for duplicate names, app schemata can be used. They provide a namespace for properties and object types pertaining to a particular use case. An app schema is available in all tenants where the app is enabled.

  • Each tenant can have exactly one tenant schema that allows to define properties and object types for usage only within the specific tenant.

    By default, the maximum number of property definitions in a tenant schema is 20. A system integrator can change this limit via the schema.tenant.properties.limit parameter in the configuration of the system service. If you want to increase this limit, it is recommended to increase the maximum number of fields in your Elasticsearch index as well.
  • For each tenant, the global schema and the tenant schema are merged with the app schemata for those apps that are enabled for the tenant. The resulting applied tenant schema is used for DMS operations like object import, update or search.

Depending on the schema scope, the schemata are managed via specific endpoints. Furthermore, their property and object type IDs have specific prefixes.

Retrieval Validation Update

global schema

GET /api/system/schema

POST api/system/schema/validate

POST /api/system/schema

app schema

GET /api/system/apps/{app}/schema

POST /api/system/apps/{app}/schema/validate

POST /api/system/apps/{app}/schema

tenant schema of any tenant

GET /api/system/tenants/{tenant}/schema

POST /api/system/tenants/{tenant}/schema/validate

POST /api/system/tenants/{tenant}/schema

tenant schema of the own tenant

GET /api/admin/schema

POST /api/admin/schema/validate

POST /api/admin/schema

2.2.3. Naming Conventions for Property and Object Type IDs

In every property definition and every object type definition the id attribute is required. It is used to identify the object type or property. Each ID is a string with a maximum of 63 characters, and it must match the regular expression ([a-zA-Z][a-zA-Z0-9]*:)?[a-zA-Z][a-zA-Z0-9]*.

The IDs are also used as the name of the type, e.g., in query operations. Hence, it is recommended to choose meaningful values for type IDs.

The part before the : character is the prefix. It is useful to specify the scope of the corresponding schema. Within the schema file, all references on the same ID have to be EITHER with OR without prefix. Depending on the situation, the prefix can be omitted, for example to broaden a search query across multiple application schemata.

  • In tenant-specific (app-specific) definitions, only prefixes matching "ten" + <tenant name> ("app" + <app name>) are allowed. The tenant (app) name is case-insensitive when used as a path or search parameter. If no prefix is specified, the prefix is added automatically in the applied tenant schema. Thus, the same object type name can occur in multiple tenant (app) schemata.

  • Some specific requirements for app names are described in the chapter on app management.

  • In the global schema all prefixes are allowed, as long as they do not start with ten or app or equal system. Alternatively, they can also have no prefix.

An exception are column names in Table Property Definitions, where prefixes are prohibited.

As of 2021 Winter, it is possible to use the - character as an additional separator within prefixes for tenant-specific IDs if matching the following regular expression: ([a-zA-Z][a-zA-Z0-9-]*:)?[a-zA-Z][a-zA-Z0-9]*

2.2.4. Property Definitions

General Property Attributes

All property definitions have the following attributes:

Attribute Type Required Description

id

String

yes

The ID of the property matching the regular expression. It uniquely identifies the property within in the schema file.

localNamespace

URI

no

By using namespaces, it is possible to form groups of properties and object types.

description

String

no

Describes the property.

propertyType

Enum

yes

Specifies the type of this property. The following types are supported:

  • boolean

  • integer

  • datetime

  • decimal

  • string

  • table

  • id

  • structureddata

cardinality

Enum

yes

Defines whether the property can have a maximum of one or an arbitrary number of values. Possible values are single and multi.

required

Boolean

yes

If true, the object must have at least one value of this property. If a property is required and has no defaultValue, the application must provide a value during the create operation.

This attribute can be overwritten in the property references of object type definitions. Hence, the same property can be required in one object type and not required in another object type.

Following the concept of secondary object types, the same property can be allowed by multiple ways in an object instance, e.g. if the object type has a reference to the property type and the object has one or more secondary object types, that have references to the property type. If these references have different required values, the value true always dominates over false.

Check out the tutorial "Overwriting the 'required' Property Attribute" for further examples.

queryable

Boolean

no

Specifies whether or not the property may appear in the WHERE clause of a query statement. Default is true. false is only allowed for table properties.

classification

String

no

Declares the classifications this property belongs to. There is no validation or use in the system itself. For example, string properties can be classified as email or url and a client application can use this classification to present the property’s content in an appropriate manner. This attribute can be used several times and the corresponding values are delivered in an array.

Make sure to validate the strings you set for the classification attribute, such that your client application will not fail if a string does not match the expected syntax.

defaultValue

depending on the propertyType

no

The value that the system sets for the property if no value is provided during object creation. If the cardinality is multi, there can be more than one default value and a list of all default values is provided.

Default values can be also applied by update. Assume a secondary object type has property types with default values. If you add this secondary object type to an existing object by update, these default values are applied, if the update does npt set values for these properties and the properties were not allowed in the object before the update.

Depending on the property type, a property can have specific attributes.

Attributes for Integer Property Definitions
Attribute Type Required Description Technical Limit used as Default

maxValue

Integer

no

The maximum value allowed for this property.

9223372036854775807

minValue

Integer

no

The minimum value allowed for this property.

-9223372036854775808

Attributes for DateTime Property Definitions
Attribute Type Required Description

resolution

Enum

no

The only supported value is date. If the resolution is set to date, the property can only store values without a time part and these values have the format yyyy-MM-dd.

Attributes for Decimal Property Definitions

Decimal properties support values of 64-bit precision (IEEE 754). The values have to be specified in decimal notation. However in the table below, the technical limits are provided in base 2 scientific notation in order to display the values in a condensed and comfortable format. This format cannot be used to specify the value for a maxValue or minValue attribute in a decimal property definition.

Attribute Type Required Description Technical Limit used as Default

maxValue

Decimal

no

The maximum value allowed for this property

(2-2 -52 )·2 1023

minValue

Decimal

no

The minimum value allowed for this property.

-(2-2 -52)·2 1023

Please note the additional limit of precision: values of magnitude smaller than 2-1074 will be rounded to 0.
Attributes for String Property Definitions
Attribute Type Required Description

maxLength

Integer

no

The maximum length (in characters) allowed for a value of this property.

minLength

Integer

no

The minimum length (in characters) allowed for a value of this property.

fulltextIndexed

Boolean

no

If true (default), the property value can be found via full-text search.

If false, the property value cannot be found via full-text search.

In general, the length of a string is limited to 8192. Hence, the maximum value for maxLength and minLength is 8192.

Attributes for Table Property Definitions

A table property definition contains some attributes and one or more sub-property definitions, the columns.

The number of rows and columns of a table property definition is limited to a maximum of 512 columns and 1024 rows.

Particularities for table property attributes:

Attribute Type Required Description

cardinality

Enum

yes

Defines whether the property can have a maximum of one or an arbitrary number of values. For a table property, only single is allowed.

queryable

Boolean

no

Specifies whether (true) or not (false) the table property and its columns may appear in the WHERE clause of a query statement. Default is true.

If queryable is false, the table must not appear in WHERE clauses in search queries. However, you can still find objects using full-text conditions on values stored in a table (query keyword CONTAINS). If queryable is true, you can apply more precise search queries to a table, but you will need more disk space to store objects.

Particularities for column attributes:

Attribute Type Required Description

id

String

yes

The column names must not contain a prefix. They have to follow the convention [a-zA-Z][a-zA-Z0-9]*. Otherwise, the schema containing the corresponding property definition will not pass the validation.

cardinality

Enum

yes

Defines whether the property can have a maximum of one or an arbitrary number of values. For a column definition, both enums single or multi are allowed.

Example table property definition
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<propertyTableDefinition>
    <id>aTableProperty</id>
    <propertyType>table</propertyType>
    <cardinality>single</cardinality>
    <required>false</required>
    <propertyStringDefinition>
        <id>col0</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <propertyIntegerDefinition>
        <id>col1</id>
        <propertyType>integer</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyIntegerDefinition>
    <propertyDateTimeDefinition>
        <id>col2</id>
        <propertyType>datetime</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyDateTimeDefinition>
    <propertyDecimalDefinition>
        <id>col3</id>
        <propertyType>decimal</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyDecimalDefinition>
</propertyTableDefinition>
Structured Data Property Definitions

As of version 2021 Summer, yuuvis® Momentum offers a property type for the storage of structured data in JSON format. Thus, it is possible to store interleaved data structures in a queryable way without defining each single sub-property in the schema.

The structured data properties should NOT be considered to replace the concept of a well-defined schema. They should be used only if the handling of objects' metadata via the conventional property definitions is not reasonable.

Particularities for structured data property attributes:

Attribute Type Required Description

cardinality

Enum

yes

Defines whether the property can have a maximum of one or an arbitrary number of values. For a structured data property definition, only single is allowed.

Pre-defined limitations (cannot be overwritten by property attributes):

  • The value for a structured data property has to be a valid JSON structure. It is not allowed to pass a single string, boolean or other variable format.

    Display valid and invalid example values.
    Valid example value
    "appTable:customerdetails": {
        "value": {
            "id": 2982,
            "uid": "711e1858-eb24-4183-8743-0292c7b9b93b"
        }
    }
    Invalid example value 1 - NOT allowed
    "appTable:customerdetails": {
        "value": "{\"id\":2982,\"uid\":\"711e1858-eb24-4183-8743-0292c7b9b93b\"}"
    }
    Invalid example value 2 - NOT allowed
    "appTable:customerdetails": {
        "value": true
    }
  • The maximum value for the total number of sub-properties within one JSON value is 500.

  • The maximum depth for JSON structure is 16.

  • The keys have to be strings not longer than 32 characters.

  • As of 2024 Spring: The keys have to follow the convention [a-zA-Z][a-zA-Z0-9]* (similar to property type IDs but without prefix).

    Up to 2023 Winter: The keys have to follow the convention [a-z][a-z0-9]*.

  • Empty maps are not allowed in any position of the JSON and are replaced by null.

Example Structured Data Property Definition
1
2
3
4
5
6
<propertyStructuredDataDefinition>
    <id>customerdetails</id>
    <propertyType>structureddata</propertyType>
    <cardinality>single</cardinality>
    <required>false</required>
</propertyStructuredDataDefinition>

2.2.5. Object Type Definitions

Each object type definition belongs to one of the following base types.

base type value for baseId attribute instantiable

document type

system:document

yes

folder type

system:folder

yes

secondary object type (SOT)

system:secondary

no

General Object Type Attributes

All object type definitions have the following attributes:

Attribute Type Required Description

id

String

yes

The ID of the object type. It uniquely identifies the object type in the schema.

localNamespace

URI

no

By using namespaces, it is possible to form groups of properties and object types.

description

String

no

Describes the object type definition.

baseId

Enum

yes

Specifies the base type of this object type. The following values are supported:

  • system:document

  • system:folder

  • system:secondary

propertyReference

String

no

Reference by ID to a property. An object type definition can have an arbitrary number of property references.

A tenant-specific object type can have references to both tenant-specific and global properties.

Attributes for Document Type Definitions

Document type definitions have the following specific attributes:

Attribute Type Required Description

contentStreamAllowed

Enum

yes

Specifies whether objects of this type must, must not, or may have content. Possible values are:

  • required

  • notallowed

  • allowed (default)

The attribute is also available for SOT definitions. If an SOT with a specified contentStreamAllowed attribute is referenced in the document type definition, it might influence the final value of contentStreamAllowed or even lead to conflict situations. Find more details in the section on secondary object type definitions.

secondaryObjectTypeId

String

no

References the ID of a defined secondary object type. Can be specified multiple times to reference multiple SOTs.

Additionally, it is possible to specify static="true" or static="false". Find details below.

2.2.6. Attributes for Folder Type Definitions

Folder type definitions have the following specific attributes:

Attribute Type Required Description

secondaryObjectTypeId

String

no

References the ID of a defined secondary object type. Can be specified multiple times to reference multiple SOTs.

Additionally, it is possible to specify static="true" or static="false". Find details below.

2.2.7. Secondary Object Type Definitions

A secondary object type (SOT) is abstract and cannot be instantiated. Instead, it can be referenced in document and folder object type definitions via their secondaryObjectTypeId attribute.

There are two ways for SOTs to be referenced by an object in the schema definition: as static SOT or as floating SOT.

Static SOT
<secondaryObjectTypeId static="true">INV</secondaryObjectTypeId>

If DMS objects are instantiated from an object type with such reference, the SOT will be assigned to them during their entire lifecycle.

Floating SOT
<secondaryObjectTypeId static="false">INV</secondaryObjectTypeId>

If DMS objects are instantiated from an object type with such reference, the SOT is only assigned after explicit activation in the metadata. This allows for flexible typecasting.

Ones assigned to a DMS object, all properties collected in the SOT are available for that DMS object.

If an SOT contains a required property, it will be required for each DMS object with that SOT assigned to itself.

Secondary object type definitions have the following specific attributes:

Attribute Type Required Description

contentStreamAllowed

Enum

no

Can substantiate the contentStreamAllowed attribute of document type definitions. Possible values are analogous to document type definitions:

  • required

  • notallowed

  • allowed

For a finally instantiated DMS object, content will be

  • allowed if only allowed values occur in the document type definition and included secondary object type definitions.

  • required (notallowed) if the value is required (notallowed) in at least one object type definition – either document type definition or included secondary object type definition.

Conflict situations are leading to invalid documents as described below.

If contentStreamAllowed is specified in a secondary object type definition, this secondary object type cannot be referenced in folder type definitions. The schema would be invalid.

Conflict situation leading to invalid documents

Any combination of at least once required and at least once notallowed in included secondary object type definitions or the document object type definition itself.

  • If a conflict occurs between the document type definition and a secondary object type definition, the whole schema is invalid.

  • If the conflict occurs between secondary object type definitions with at least one of them referenced as static, the schema is valid but the document validation will fail (instantiated DMS objects will be invalid).

  • If the conflict occurs exclusively between secondary object type definitions referenced as floating, a document cannot have conflicting secondary object types at the same time. If a secondary object type with the value required (notallowed) is added to the document, all secondary object types with the value notallowed (required) must be removed by means of the keyword "remove":.

Example schema containing SOTs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://optimal-systems.org/ns/dmscloud/schema/v5.0/dmsCloud-schema.xsd">

        <propertyStringDefinition>
            <id>appSot:dateOfReceipt</id>
            <propertyType>date</propertyType>
            <cardinality>single</cardinality>
            <required>true</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>appSot:comment</id>
            <propertyType>date</propertyType>
            <cardinality>single</cardinality>
            <required>true</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>appSot:invoiceNo</id>
            <propertyType>string</propertyType>
            <cardinality>single</cardinality>
            <required>true</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>appSot:paymentTerm</id>
            <propertyType>string</propertyType>
            <cardinality>single</cardinality>
            <required>true</required>
        </propertyStringDefinition>

        <typeDocumentDefinition>
            <id>appSot:document</id>
            <baseId>system:document</baseId>
            <propertyReference>appSot:dateOfReceipt</propertyReference>
            <contentStreamAllowed>required</contentStreamAllowed>
            <secondaryObjectTypeId>appSot:basicInfo</secondaryObjectTypeId>
        </typeDocumentDefinition>

        <typeSecondaryDefinition>
            <id>appSot:basicInfo</id>
            <baseId>system:secondary</baseId>
            <propertyReference>appSot:comment</propertyReference>
        </typeSecondaryDefinition>
        <typeSecondaryDefinition>
            <id>appSot:invoice</id>
            <baseId>system:secondary</baseId>
            <propertyReference>appSot:invoiceNo</propertyReference>
            <propertyReference>appSot:paymentTerm</propertyReference>
        </typeSecondaryDefinition>
</schema>

Consider the example schema above. If a document of the type appSot:document is created, it may have values for the properties appSot:dateOfReceipt and appSot:comment.

For the appSot:dateOfReceipt property, this is obvious, because there is a direct reference in the document type definition of appSot:document.

The appSot:comment property is not directly referenced but the definition of appSot:document has a reference to the SOT appSot:basicInfo which references the appSot:comment property. Thus, both properties are available for creating documents.

Furthermore, a document of the type appSot:document not only may have a value for appSot:comment, it must have a value, because it is a required property. It makes no difference, whether a document type references the property definitions directly or indirectly via a SOT reference.

2.2.8. Validation

It is not possible to post an invalid schema via yuuvis® Momentum API. A new schema is always validated before it is introduced into the system. Additionally, specific validation endpoints are available to check the new schema before sending an update request.

The response of schema validation (or update) endpoints are always structured as shown in the following example.

Example response body of a schema validation.
{
    "validationErrors": [],
    "changes": [{
            "type": 1000,
            "message": "Document type was removed.",
            "id": "appEmail:obsoleteType",
            "affectedObjects": {
                "tenant1": 10,
                "tenant2": 4
            }
        }, {
            "type": 1200,
            "message": "A property reference was removed from a document type.",
            "id": "appEmail:email",
            "reference": "appEmail:bcc",
            "affectedObjects": {
                "tenant1": 1,
                "tenant2": 3
            }
        }
    ]
}
Failed Validation

If the schema is invalid, the corresponding validation errors are listed in validationErrors

Passed Validation

If the schema is valid, the validationErrors list is empty. The schema can be (is) updated.

However, the new schema might define different structures for DMS objects that are not matched by previously imported objects. Thus, affected objects are invalidated as soon as the new schema is introduced into the system. Invalidated objects are still stored in the system, but their availability and behavior deviates from expectation as described in the following table and below.

The changes list in the validation request contains all detected differences between the new schema and the previously used schema that could lead to invalidation of existing DMS objects. The following table documents the detectable types of schema changes and their individual values/meanings of the sub-parameters for each element in the changes list:

  • type

  • message

  • id

  • reference

  • if the validation (or update) endpoint is called with the query parameter verbose=true: affectedObjects

A non-empty changes list in the validation request does NOT prevent a schema update.
type message id reference Description and Impact of Schema Update

1000

Document type was removed.

ID of the removed document type

-

As it is not possible to replace the object type of existing objects, it is not possible to adjust affected objects. They cannot be updated anymore.

1001

Folder type was removed.

ID of the removed folder type

-

See impacts of change type 1000.

1100

A secondary object type reference was removed from a document type.

ID of the document type

ID of the secondary object type

If the corresponding SOT includes required properties, see the impacts of change type 1200.

1101

A secondary object type reference was removed from a folder type.

ID of the folder type

ID of the secondary object type

If the corresponding SOT includes required properties, see the impacts of change type 1200.

1110

A document type got a new static secondary object type reference.

ID of the document type

ID of the secondary object type

A static secondary object type reference was added to a document type definition. Or an existing non-static secondary object type reference on a document type definition became static.

If the corresponding SOT includes required properties, see the impacts of change type 1300.

1111

A folder type got a new static secondary object type reference.

ID of the folder type

ID of the secondary object type

A static secondary object type reference was added to a folder type definition. Or an existing non-static secondary object type reference on a folder type definition became static.

If the corresponding SOT includes required properties, see the impacts of change type 1300.

1200

A property reference was removed from a document type.

ID of the document type

ID of the property

Any metadata retrieval of affected objects excludes the removed property. Search result lists, e.g., are affected as well. However, the existing values remain in the database and the search index. Thus, in case of a removed string property, the existing values are still considered for full-text search.

The corresponding values are removed automatically during the next PATCH or POST update on the affected objects.

1201

A property reference was removed from a folder type.

ID of the folder type

ID of the property

See impacts of change type 1200.

1210

A property reference was removed from a secondary object type.

ID of the secondary object type

ID of the property

See impacts of change type 1200.

1300

A non-required property type became required.

ID of the property

-

POST metadata updates on affected objects are only allowed if the new required property is properly added.

1310

A required property reference was added to a document type, or a non-required property reference became required.

ID of the document type

ID of the property

See impacts of change type 1300.

1311

A required property reference was added to a folder type, or a non-required property reference became required.

ID of the folder type

ID of the property

See impacts of change type 1300.

1320

A required property reference was added to a secondary object type, or a non-required property reference became required.

ID of the secondary object type

ID of the property

See impacts of change type 1300.

2000

Content stream becomes required on a document type.

ID of the document type

-

Updates on affected objects are only allowed if a binary content file is thereby added.

2001

Content stream becomes not allowed on a document type.

ID of the document type

-

Updates on affected objects are only allowed if a binary content file is thereby deleted. Thus, affected objects with a binary content file under retention cannot be updated via yuuvis® Momentum at all.

2010

Content stream becomes required on a secondary object type.

ID of the secondary object type

-

See impacts of change type 2000.

2011

Content stream becomes not allowed on a secondary object type.

ID of the secondary object type

-

See impacts of change type 2001.

3000

The cardinality of a property becomes 'single'.

ID of the property

-

Updates on affected objects are only allowed if the value of the modified property is properly replaced. Especially, pure tag and content operations are only allowed after a proper update of the metadata.

Following schema changes are NOT detected during the validation, but can affect existing objects as well:

  • The type of a property definition changed. → See impacts of change type 3000.

  • The range of a property definition changed. → See impacts of change type 3000.

  • A default value was added to a property definition or reference. → The new default value is only used for the creation of new objects.

  • In a table property definition, the value for the queryable attribute was changed. → Affected objects can be adjusted via commander service.

  • The base type of an object type changed from system:folder to system:document with content stream required. → See impacts of change type 2000.

  • The base type of an object type changed from system:document to system:folder. → See impacts of change type 2001.

  • The base type of an object type changed from system:document or system:folder to system:secondary. → See impacts of change type 1000.

2.2.9. Pre-defined System Schema

Some properties and object types are pre-defined for the entire system. Their definitions cannot be overwritten via yuuvis® Momentum API. However, their definitions are included in each retrieval of an applied tenant schema.

General System Properties

The following system properties are globally pre-defined and assigned to each DMS object. Some system properties are set by the system and some system properties can be set by the user.

Property Type Description Set by

system:objectId

string

Identifies the object in the database.

system

system:baseTypeId

string

identifies the base type of the object type specified in system:objectTypeId.

system

system:objectTypeId

string

Required during an import and cannot be changed lateron.

Identifies the object type the object instantiates. Secondary object types are not allowed.

user

system:secondaryObjectTypeIds

JSON list of strings

Contains the secondaryObjectTypeId for each secondary object type associated with the document object type in the schema.

user

system:createdBy

string

User ID of the user that has initially created the object.

system

system:creationDate

string

Date of the object’s creation in format yyyy-MM-ddTHH:mm:ss.fffZ.

system

system:lastModifiedBy

string

User ID of the user that sent the last successful POST request on the object.

system

system:lastModificationDate

string

Date of the last successful POST request on the object as a string in format yyyy-MM-ddTHH:mm:ss.fffZ.

system

system:parentId

string

system:objectId of the parent folder.

During an import or update operation, the object can be assigned to an existing folder by referencing its system:objectId in the system:parentId of the target document or folder object. The existence of the parent folder is validated by means of the specified system:parentId. Furthermore, circles in the folder hierarchy are forbidden and do not pass the validation.

user

system:parentObjectTypeId

string

Identifies the folder object type of the parent folder that is specified by system:parentId.

system

system:versionNumber

integer

Integer object version number. Corresponds to the number of POST requests on the object starting with the initial creation.

system

system:tenant

string

Identifies the tenant the object belongs to.

system

system:traceId

Hexadecimal lowercase string with maximum length 16

The trace ID of the import operation or last update operation. Unique process number of any operation.

If not specified in the request, a random string value will be set.

If the specified trace ID has less than 16 characters, the string is extended by adding 0 characters at the leading position until the length of 16 is reached.

user or system

system:tags

JSON table of strings and integers

Contains the properties of the tags assigned to the object.

user

system:rmExpirationDate

string

Only available for documents. Secondary object type system:rmDestructionRetention is required.

The binary content of the object cannot be changed or deleted before this date, but metadata updates are allowed. In an update request, the system:rmExpirationDate cannot be replaced by an earlier date.

user

system:rmStartOfRetention

string

Only available for documents. Secondary object type system:rmDestructionRetention and a non-null value for system:rmDestructionRetention is required.

This date defines the start of the retention time. It has to be earlier in time than the system:rmExpirationDate.

user

system:rmDestructionDate

string

Only available for documents. Secondary object type system:rmDestructionRetention and a non-null value for system:rmDestructionRetention is required.

If system:rmDestructionRetention is set, it must either be equal to or later in time than system:rmExpirationDate.

user

Content Stream Properties

The following content stream properties are grouped in the contentStreams section within DMS objects. These system properties are available for document objects containing binary content. Thus, their contentStreamAllowed attribute has to be required or allowed. The properties in contentStreams contain all information necessary to be able to handle binary content. Depending on the type of operation, different properties are required for import/update requests or are displayed in a response.

Property Type Description In an Import/Update Request In a Response

contentStreamId

String

Points to existing content within a repository.

Required only for pointing to existing content during an import. If not specified, the system generates a UID.

displayed

length

Integer

Length of the binary content, determined by the system.

-

displayed (if system could determine the value)

mimeType

String

Mime type of the content file. The contentanalyzer service can be configured to determine (scenario A) or not determine (scenario B) the mimeType.

If mimeType can/should not be determined and is not specified, the default value application/octet-stream is used.

Scenario A:

The contentanalyzer determines mimeType from the corresponding binary content file. It is not possible to set a value via a request header.

In an import request, the automatically determined mimeType can be overwritten by specifying a value in the import JSON.

Scenario B:

In an import request via POST /api/dms/objects, mimeType is determined based on the Content-Type header that is specified for the request’s part related to the corresponding binary content file. If mimeType is specified in the import JSON, this value is used instead of the automatically determined one.

In a content update via POST /api/dms/objects/{objectId}/contents/file, mimeType is determined based on the Content-Type header specified for the entire HTTP request.

displayed

fileName

String

Name of the content file.

If fileName is not specified as follows and cannot be determined, the default value upload.bin will be set.

In a content update via POST /api/dms/objects/{objectId}/contents/file, fileName is determined based on the Content-Disposition header that is specified for the entire HTTP request.

In an import request via POST /api/dms/objects, fileName is determined based on the Content-Disposition header that is specified for the request’s part related to the corresponding binary content file. If fileName is specified in the import JSON, this value is used instead of the automatically determined one.

displayed

digest

String

SHA-256, automatically determined by `repository`service based on the binary content. Can be used to detect changes in the binary content.

-

displayed

repositoryId

String

ID of the repository that will be used for storage of the binary data.

Required only for pointing to existing content during an import. If not specified, the default repository defined in the repository service configuration will be set.

displayed

archivePath

String

Path structure for the content file within the binary storage.

Required only for pointing to existing content during an import if reconstruction is not possible with metadata information (e.g,, if a pathTemplate containing dynamic path elements like DATE is configured in the archive profile).

displayed if it was set

  • in the request body or

  • via pathTemplate configured in the archive profile.

range

String

Applies to compound documents only. Defines a certain segment of compound documents that should be provided for content retrievals.

Optional in the import request body and only available for compound documents.

displayed only if it was set

cid

String

Assigns the corresponding multipart content.

Required in the import request body. Not needed later on and therefore not stored in the system.

-

Document Object Type 'system:document'

This object type has automatically floating references on all SOTs that are available in the applied tenant schema. It is intended to simplify typecasting of document objects.

Secondary Object Type 'system:rmDestructionRetention'

This SOT allows to specify a retention for an individual DMS object.

2.3. Search Query Language

The query language based on CMIS serves to standardize DMS requests to the yuuvis® API system.

The CMIS query language consists of a subset of the SQL-92 grammar, augmented by a syntax for requesting full text. Thus, the CMIS query language provides a relational view of the data. The virtual tables requested in the FROM clause correspond to DMS object types and the virtual columns requested in the SELECT correspond to the CMIS properties (metadata fields).

2.3.1. Query Language Definition

A query is structured as follows

Position Keyword Value Description

1

SELECT

virtual column list

property list (metadata fields)

2

FROM

virtual table names

object type list

3

WHERE

conditions

limitations

4

ORDER BY

sorting specification

sorting criteria

  • use * as virtual column list to query all metadata fields

  • it is possible to use the SCORE() function in the virtual columns list

  • if ORDER BY is not specified, the result list is ordered by the system:creationDate object property

  • currently, only the query of a single object type is supported.

The default search on metadata fields is case-sensitive. A case-insensitive search is possible via the CASE_INSENSITIVE() function (as of 2024 Spring) or by means of a CONTAINS statement.

2.3.2. Simple 'SELECT' Queries

Queries on Object Types
Examples for simple SELECT queries on a specified object type
-- Select all objects of type 'email'.
SELECT * FROM email;

-- Select the customer number and the date of all invoices.
SELECT custno,date FROM invoice;
Queries on Secondary Object Types (as of 2019 Winter)

The search result delivers the entire object and not only the properties of the specified secondary object type.

Example SELECT query on a secondary object type
-- Select all objects of secondary object type system:rmDestructionRetention
SELECT * FROM system:rmDestructionRetention;

2.3.3. Queries with Aliases

Properties can be queried with an alias name. The values of these properties are returned in the result with the alias name. The alias can be specified by a space separated behind the property name or with the keyword AS between property name and alias name.

Example queries
-- Alias without keyword: Select the customer number with alias c and the date with alias d of all invoices.
SELECT custno c,date d FROM invoice;

-- Alias with keyword: Select the customer number with alias c and the date with alias d of all invoices.
SELECT custno AS c,date AS d FROM invoice;

2.3.4. Highlighting in Full-text Previews

The HIGHLIGHT() function can be used within the SELECT statement. Pass a string argument as shown in the example below. For this string, a full-text query is started. In the result list, all objects have an additional highlight section that is a list of excerpts from the corresponding object’s text rendition containing the query term. The individual excerpt items are sorted by SCORE(). Within the plain text of each excerpt, the found query term is highlighted by a surrounding <em></em>.

Highlighting on large full-texts has high time and memory costs. Thus, the search engine limits the length of full-text for highlighting to 1.000.000 characters. Hits of the query term that may occur in the remaining part of the full-text are found but not represented in the highlight section of the search result.
Example search query
-- Search objects containing 'exiting' in their full-text rendition.
-- Display the object ID and full-text excerpts with highlighted search term.
SELECT system:objectId, HIGHLIGHT('exciting') FROM system:object;
Example response
{
    "objects": [
        {
            "properties": {
                "system:objectId": {
                    "value": "2be7b709-745a-4c0c-809e-512f9850876b"
                }
            },
            "highlight": [
                "this could also be an <em>exciting</em> custom content",
                "what else could be as <em>exciting</em> as this feature"
            ]
        }
    ],
    "numItems": 1,
    "hasMoreItems": true,
    "totalNumItems": 662763
}
Options for Highlighting

To execute the query, the SQL statement is embedded in a JSON structure as described later. For the HIGHLIGHT() function, the options section can be used to configure the following highlight parameters. If not explicitly specified in each request JSON, the default values are used.

Parameter Type Description Default value

type

string

Type of highlighter

unified

fragment_size

int

Length of a single full-text excerpt

45

number_of_fragments

int

Maximum number of full-text matches to be represented for each object

30

fragmenter

string

Fragmenter to be used.

span

pre_tag

string

Indication for start of query term highlighting.

<em>

post_tag

string

Indication for end of query term highlighting.

</em>

Example JSON with options
{
    "query" : {
        "statement" : "SELECT system:objectId, HIGHLIGHT('exciting') FROM system:object",
        "skipCount" : 0,
        "maxItems" : 1,
        "handleDeletedDocuments" : "DELETED_DOCUMENTS_EXCLUDE",
        "options": {
            "highlight": {
                "type": "plain",
                "fragment_size": 45,
                "number_of_fragments": 30,
                "fragmenter": "span",
                "pre_tag": "<em>" ,
                "post_tag": "</em>"
            }
        }
    }
}

2.3.5. Queries with Conditions

In the WHERE clause, conditions can be formulated and combined with logical operators.

The following operators are supported:

  • comparison operators: <, >, <=, >=, <>, =

  • join operators: AND, OR, NOT

  • additional predicates: LIKE, IN, NULL, CONTAINS

  • In the default configuration, the number of AND and OR operators per condition is limited to 20.

Examples
Some introductory example queries with conditions
-- Select all invoices in which the invoice amount is greater than 100.
SELECT * FROM invoice WHERE amount>100;

-- Select all invoices in which the invoice amount is greater than 100 and the supplier is 'ACME'.
SELECT * FROM invoice WHERE amount>100 AND supplier='ACME';

-- Select all invoices in which the invoice amount is greater than 100 or less than 10 and the supplier is either 'ACME', 'OS' or 'ICH'.
SELECT * FROM invoice WHERE (amount>100 OR amount<10) AND supplier IN ('ACME','OS','ICH');
Wildcard Example

Wildcard characters are used with the LIKE operator. There are two wildcards used in conjunction with the LIKE operator:

  • % – The percent sign represents zero, one, or multiple characters

  • _ – The underscore represents a single character

Example query
-- Select all invoices in which the supplier starts with 'ACM' and the index data field 'amount' is not NULL
SELECT * FROM invoice WHERE supplier LIKE 'ACM%' AND amount IS NOT NULL;
The LIKE expressions are limited by their number of included wildcards. Thus, a maximum number of 10 % and _ characters are allowed in one LIKE expression. The limit compliance is verified in the validation.

As of 2024 Spring.

The CASE_SENSITIVE() and CASE_INSENSITIVE() functions are available for conditions on string metadata values. The combination with the =, LIKE or IN operators is possible as shown in the following examples.

Examples for case-sensitive (default) and case-insensitive metadata search
-- Select all invoices in which the supplier is 'GE'.
SELECT * FROM invoice WHERE supplier IS 'GE';
SELECT * FROM invoice WHERE supplier IS CASE_SENSITIVE('GE');

-- Select all invoices in which the supplier is 'ge', 'Ge', 'gE' or 'GE'.
SELECT * FROM invoice WHERE supplier IS CASE_INSENSITIVE('GE');

-- Select all invoices in which the supplier starts with 'ge', 'Ge', 'gE' or 'GE'.
SELECT * FROM invoice WHERE supplier LIKE CASE_INSENSITIVE('GE%');

-- Select all invoices in which the supplier is 'ge', 'Ge', 'gE', 'GE' or 'OS'.
SELECT * FROM invoice WHERE supplier IN (CASE_INSENSITIVE('ge'), 'OS');

The default behavior of the metadata search is case-sensitive. This default can be overwritten for an entire query request via the case_sensitivity option in the JSON format. Thus, the example request below searches for all invoices in which the supplier is ge, Ge, gE or GE without the usage CASE_INSENSITIVE() function in the SQL statement.

Changing case sensitivity for the entire request
{
    "query" : {
        "statement" : "SELECT * FROM invoice WHERE supplier IS 'GE'",
        "skipCount" : 0,
        "maxItems" : 50,
        "options": {
            "case_sensitivity": "case_insensitive"
        }
    }
}
Priorities for overwriting case sensitivity
  1. Highest priority: CASE_SENSITIVE() and CASE_INSENSITIVE() functions in the SQL statement.

  2. If 1. is not specified: Value for case_sensitivity in the options section of the query JSON.

  3. If neither 1. nor 2. are specified: The system default for search in string metadata is case-sensitive.

Full-Text Search with 'CONTAINS'
Basics for 'CONTAINS'

To perform full-text search, use CONTAINS in the WHERE clause. The string values specified in the CONTAINS statements are handled without regards to case sensitivity. Their length might be limited by your search engine.

For the result list of a full-text search, it might be useful to sort it by SCORE(). The best matching results will be presented on top of the result list. If ORDER BY is not specified, the result list is ordered by the system:creationDate object property by default.

Please also note that your search engine might need a suitable plug-in and corresponding configuration for optimal search behavior in your language. If you changed the configuration of your search engine, all objects that are imported afterwards will be indexed as defined by the new configuration. All objects that are already in the system remain unchanged and can be searched as before the configuration update. If you need all objects indexed which refer to the new configuration, you need a reindexing via your search engine.

If a field name is specified, only this field is checked for the search term.

-- Select all types in which the term 'QUERY' was found in field 'name'.
SELECT * FROM type WHERE name CONTAINS('QUERY');

If no field name is specified, a full-text search will be performed. This search includes:

  • Each string value within the properties metadata section that matches the following conditions:

    • It belongs to a defined property, for which the attribute fulltextIndexed is NOT set to false AND that has no system: prefix.

    • The property must be a string property, a string column of a table property or a structured data property.

  • The string values for tag names.

  • The string value for system:contentStreamFileName within the contentstreams properties.

  • If available, each text rendition that was estimated by the contentanalyzer service or set manually.

-- Select all types in which in full-text 'QUERY' was found.
SELECT * FROM type WHERE CONTAINS('QUERY');

-- Use 'SCORE()' for the order of the result list instead of the default order by 'system:creationDate'.
SELECT *,SCORE() s FROM type WHERE CONTAINS('QUERY') ORDER BY s ASC;

As of 2023 Winter, it is possible to separately search the text renditions or the mentioned string values within the metadata.

  • Use system:content instead of a property name to search only the text renditions.

    Example
    SELECT * FROM system:document WHERE system:content CONTAINS('search me within the text renditions only')
  • Use system:metadata instead of a property name to search only the above described string metadata values.

    Example
    SELECT * FROM system:document WHERE system:metadata CONTAINS('search me within the string metadata only')
Logical Operators

The following logical operators are supported:

Operator Description Syntax

+

The full-text must contain the term behind the operator. There is no blank space between operator and term.

+<term>

-

The full-text must not contain the term behind the operator. There is no blank space between operator and term.

-<term>

AND

The full-text must contain both terms connected with the operator. The operator is only identified in capital letters and separated by exactly one blank space from the two terms it is connecting.

We recommend to use the + operator instead of AND.

<term1> AND <term2>

OR

The full-text must contain at least one of the two terms connected with the operator. The operator is only identified in capital letters and separated by exactly one blank space from the two terms it is connecting.

Consecutive terms without any operator in between are interpreted as they would be connected with OR. Thus, we recommend to avoid the use of the OR operator.

<term1> OR <term2>

The examples will clarify the use of the individual operators.

+ Operator

If the + operator is applied to a term, only objects containing this term in their full-text will match the query. If further terms are specified without an additional + (or -) operator, they are allowed in the full-text but not required. Thus, they influence the ranking (higher score) of the found objects only. They do not have an impact on the number of found objects in the result itself.

-- Select all documents in which 'tree' was found.
SELECT * FROM type where CONTAINS('apple +tree')
- Operator

If the - operator is applied to a term, only objects not containing this term in their full-text will match the query. If further terms are specified without an additional - (or +) operator, they are allowed in the full-text but not required. Thus, they influence the ranking (higher score) of the found objects only. They do not have an impact on the number of found objects in the result itself.

-- Select all objects in which 'tree' was found.
SELECT * FROM type where CONTAINS('apple -tree')

-- Select all objects containing 'tree' and not containing 'pie' in their full-text. The optional words 'apple' and 'exceptional' influences the scoring only.
SELECT * FROM type where CONTAINS('exceptional apple +tree -pie')
OR Operator

All objects containing at least one of the connected terms in their full-text are matching the query. A space between several search term combinations is interpreted as logical OR operator (as long as no include or exclude search term condition is used).

-- Select all objects containing at least one of the words 'apple' or 'tree'.
SELECT * FROM type where CONTAINS('apple tree')

-- The query is equivalent to the previous one without 'OR' operator.
SELECT * FROM type where CONTAINS('apple OR tree')
Some more examples:

-- Select all invoices in which in full-text either 'reminder', 'discount' or 'delay' was found.
SELECT * FROM invoice WHERE CONTAINS('reminder discount delay');

-- Select all invoices which the invoice amount is greater than 1000 and in fulltext either 'reminder', 'discount' or 'delay' was found.
SELECT * FROM invoice WHERE amount>1000 AND CONTAINS('reminder discount delay');
AND Operator

All objects containing both terms connected with the AND operator in their full-text will match the query. However, we recommend to avoid the operator and apply the + operator to each individual term that should be contained in the object’s full-text.

-- Select all objects containing both words 'apple' and 'tree'.
SELECT * FROM type where CONTAINS('apple AND tree')

-- The query is equivalent to the previous one and recommended.
SELECT * FROM type where CONTAINS('+apple +tree')

-- The query is equivalent to the previous one and not recommended.
SELECT * FROM type where CONTAINS('+apple AND +tree')
Combination of Operators with Brackets

As of version 2022 Winter, it is possible to use round brackets within a CONTAINS statement in order to specify the evaluation order of operators.

-- Select all objects containing both words 'apple' and 'tree' or both words 'baking' and 'cakes'.
SELECT * FROM type where CONTAINS('((apple AND tree) OR (baking AND cakes))')
Phrases

To search for a string consisting of several words in the exact same order (e.g., a sentence), use double quotation marks within the CONTAINS statement. Blank spaces are not interpreted as OR operator within these quotation marks.

-- Select all objects in which the phrase 'exceptional apple tree pie' was found.
SELECT * FROM type where CONTAINS('"exceptional apple tree pie"')

-- Select all invoices in which the amount is greater than 1000 and in full-text the sentence 'color picture 20x30' was found.
SELECT * FROM invoice WHERE amount>1000 AND CONTAINS('"color picture 20x30"');
Phrases are interpreted as terms. Thus, logical operators are applied to the entire phrase.

-- Select all documents in which 'exceptional pie' was found and 'apple tree' was not found.
SELECT * FROM type where CONTAINS('+"exceptional pie" -"apple tree"')
Boosting

Boosting can be applied to the list of matches of full-text search queries. The boost operator ^ influences the relevance of individual terms within a CONTAINS statement. Thus, the sorting of the objects in the hit list is directly influenced.

The relevance of individual terms is specified via a boosting factor. The larger the boosting factor, the higher the relevance of the corresponding term. Here, the ratio between the individual boosting factors is considered and not the absolute values.

To set the boosting factor, append the ^ operator and a decimal value without blank spaces to the corresponding term. A term without a specified boosting factor will get the default boosting factor 1.

-- Select all documents containing 'tree'. Prefer objects containing 'apple', 'pear' or 'chestnut'.
-- Prioritize 'pear' 4 times and 'chestnut' twice over 'apple'.
SELECT * FROM type where CONTAINS('apple pear^4 chestnut^2 +tree')
It is possible to reduce the relevance by applying a boosting value between 0 and 1.

-- Select all documents containing 'pie' and not 'tree'. Prefer objects containing 'apple' and especially 'pear'.
-- Avoid objects containing 'chestnut'.
SELECT * FROM type where CONTAINS('apple pear^2 chestnut^0.2 -tree +pie')

In full-text search queries, partially matching objects can be provided as results. Thus, it is possible to search for similar terms or variant spellings.

The number of characters not matching the search term is called "edit distance". For each search term, a maximum edit distance can be defined that limits the number of unmatching characters.

Append the operator ~ followed by the integer maximum edit distance to a word within the CONTAINS statement. The values 0, 1 and 2 (default) are allowed for the edit distance. If the ~ operator is set without an edit distance, the default value 2 will be used. Since missing, redundant or reversed letters can be handled with edit distance 1, this value should be sufficient in most cases.

-- Select all objects containing words with maximum edit distance 1 to 'exceptionel' or 2 to 'cestnutt'.
-- E.g. objects containing 'exceptional' or 'chestnut' will be found.
SELECT * FROM type where CONTAINS('exceptionel~1 cestnutt~ ')

It is possible to allow for reversed ordering of words in a phrase or to allow for additional words between the words of a phrase.

Here, the number of words not matching the specified phrase is called "edit distance". A maximum edit distance can be defined that limits the number of unmatching words.

Append the operator ~ followed by the integer maximum edit distance to a word within the CONTAINS statement.

-- Select all documents containing phrases of maximum edit distance 3 to the specified sentence.
SELECT * FROM type where CONTAINS('"Please be patient while this website is under construction."~3')
Escaping in 'CONTAINS' Statements

In a CONTAINS expression, the system interprets specific symbols as operators. If you want to use those symbols as characters NOT beeing an operator, you have to escape them with a backslash (\).

The following rules apply:

  • The symbols < and > cannot be escaped. If they are used in terms, they will be ignored.

  • All types of quotation marks used within a term have to be escaped.

  • The ^ symbol has to be escaped if not used as boosting operator.

  • The ~ symbol has to be escaped if not used as fuzzy operator.

  • Further special characters that have to be escaped: + - = & | ! ( ) { } [ ] * ? : \ /

  • If an operator AND/OR is followed by a second operator AND/OR, the second operator will be automatically escaped and interpreted as a term and/or.

Weighted Score

The SCORE function returns the score values produced by the CONTAINS function in the SEARCH_SCORE field. The score value is a relative ranking, with values in the range of 0 to 1 and increases with the relevance. The SCORE function can also be queried with an alias name.

-- Select all invoices and their score value where the invoice amount is greater than 1000 and in fulltext either 'reminder', 'discount' or 'delay' was found.
SELECT *,SCORE() FROM invoice WHERE amount>1000 AND CONTAINS('reminder discount delay');

-- With alias: Select all invoices and their score value where the invoice amount is greater than 1000 and in fulltext either 'reminder', 'discount' or 'delay' was found.
SELECT *,SCORE() score FROM invoice WHERE amount>1000 AND CONTAINS('reminder discount delay');

Full-text search only in certain fields:

-- Select all invoices and their score value where the field 'status' either contains 'reminder', 'discount' or 'delay'.
SELECT *,SCORE() FROM invoice WHERE status CONTAINS('reminder discount delay');
Searching Normalized Trace IDs

The TRACEID() function can be used in WHERE clauses. It normalizes a specified hexadecimal lowercase sting to the trace ID convention. Thus, you can search for your initially specified values for system:traceId before they were normalized by the system.

Alternatively, it is possible to specify a trace ID in the header of the search request. This value can be referenced in the search query with the @traceid parameter. It is normalized by the system as well.

Example:

  • Import a DMS object with specified "system:traceId": {"value": "1234"}.

  • The value will be normalized and stored as "system:traceId": {"value": "0000000000001234"}.

  • The DMS object can NOT be found by this search query:

    SELECT * FROM system:object WHERE system:traceId = '1234'
  • The DMS object can be found by the following queries:

    --- normalization by user
    SELECT * FROM system:object WHERE system:traceId = '0000000000001234'
    
    --- normalization by system
    SELECT * FROM system:object WHERE system:traceId = TRACEID('1234')
    
    --- normalization by system, using value '1234' in X-B3-TraceId request header
    SELECT * FROM system:object WHERE system:traceId = @traceid

2.3.6. Sorting with 'ORDER BY'

To sort the result list, use the ORDER BY clause. If ORDER BY is not specified, the result list is ordered by the system:creationDate object property by default.

-- Select all invoices where the invoice amount is greater than 1000, with the result list sorted in descending order of the invoice amount.
SELECT * FROM invoice WHERE amount>1000 ORDER BY amount DESC;

-- Select all invoices where the invoice amount is greater than 1000,
-- with the result list sorted in descending order of the invoice amount and in ascending order of the date.
SELECT * FROM invoice WHERE amount>1000 ORDER BY amount DESC, date ASC;

In ORDER BY clauses, you can use the alias names given in the column definitions.

-- Select the invoice amount with alias 'b' of all invoices where the invoice amount is greater than 1000,
-- with the result list sorted in descending order of the alias b (invoice amount).
SELECT amount b FROM invoice WHERE amount>1000 ORDER BY b DESC;

To sort by the score value, you must assign an alias name to the SCORE() function.

-- Select all invoices and their score value where the field 'status' either contains 'reminder',
-- 'discount' or 'delay', with the result list sorted in ascending order of alias s (score value).
SELECT *,SCORE() s FROM invoice WHERE status CONTAINS('reminder discount delay') ORDER BY s ASC;

2.3.7. Aggregations

Functions 'GROUP BY' and 'COUNT(*)'

To determine the number of objects with special properties, queries can be aggregated. All objects with the same entry in the field specified after the GROUP BY clause are summarized. The number of objects is returned to the field OBJECT_COUNT without the assignment of aliases.

-- Select the number of objects (system:object) with type specification, aggregated by the type of the object.
SELECT COUNT(*),type FROM system:object GROUP BY type;

It is also possible to aggregate several fields. In this case, all combinations of the fields mentioned are returned.

-- Select the number of objects (system:object) with type and title specification, aggregated by the type and title of the object.
SELECT COUNT(*),type,title FROM system:object GROUP BY type,title;

The GROUP BY function can be used without the COUNT(*) function. Then all combinations of the mentioned fields are returned without their numbers.

-- Select 'type' of all objects (system:object), aggregated by the type of the object.
SELECT type FROM system:object GROUP BY type;

To sort the result list of an aggregation, use the ORDER BY clause, with or without alias.

-- Select the number of objects (system:object) with type specification,
-- aggregated by the type of the object, with the result list sorted in ascending order of 'type'.
SELECT COUNT(*),type FROM system:object GROUP BY type ORDER BY type ASC;

-- With alias: Select the number and 'type' with alias 't' of all objects (system:object),
-- aggregated by 'type', with the result list sorted in descending order of alias t (type).
SELECT COUNT(*),type t FROM system:object GROUP BY type ORDER BY t DESC;

In order to be able to sort by the score value, you must assign an alias name to the SCORE() function.

-- Select the number with alias 'c' and 'type' of all objects (system:object), aggregated by 'type',
-- with the result list sorted in descending order of alias c (number of objects).
SELECT COUNT(*) c,type FROM system:object GROUP BY type ORDER BY c DESC;
Function 'SUM()'

As of 2023 Autumn.

The SUM() function can be used in the SELECT statement of the search query. Similar to the SQL SUM function, it calculates the sum of numeric values for a specified numeric property. The result is retrieved as a single entry in the result list.

  • The SUM() function supports only integer and decimal properties (except table columns).

  • The SUM() function is NOT available for queries on audit entries.

Simple Example
-- Sum the values of all 'amount' properties
SELECT SUM(amount) FROM system:object;
Conditions combined with 'SUM()'

The SUM() function can be combined with a WHERE statement that specifies conditions.

-- Sum the value of all 'amount' properties for objects created today
SELECT SUM(amount) FROM system:object WHERE system:creationDate IN today();
Aliases for 'SUM()'

It is possible to set an alias as which the SUM() result will be displayed.

-- Sum the value of all 'amount' properties , return them with alias 'totalsum'
SELECT SUM(amount) AS totalsum FROM system:object;
Multiple 'SUM()' Requests

Within one search query, multiple SUM() requests can be processed.

-- Sum the value of all 'amount' and all 'item' properties
SELECT SUM(amount) AS totalsum, SUM(items) totalitems FROM system:object;
Applying 'SUM()' to Aggregations

As the SUM() function is a specific type of aggregation, it can be applied to other aggregations via GROUP BY as well.

-- Sum the value of all 'amount' properties, grouped by 'supplier'
SELECT supplier, SUM(amount) AS totalsum FROM system:object GROUP BY supplier;
Sorting by 'SUM()' Results

To sort by a SUM() result, it is required to specify an alias.

-- Sum the value of all 'amount' properties, order them descending
SELECT  SUM(amount) AS totalsum FROM system:object ORDER BY totalsum DESC;
Constants passed to 'SUM()'

If a constant is passed to the SUM() function, it is used as scalar factor to be multiplied by the number of search results.

-- Sum the value with constant 10, result should be 10x the count of hits
SELECT  SUM(10) AS totalsum FROM system:object;

2.3.8. Provided Date Functions in 'WHERE' Clauses

The query language provides some frequently used time and time span functions for WHERE clauses.

  • today() - a date field contains today’s date

  • yesterday() - a date field contains yesterday’s date

  • thisweek() - a date field contains this week’s date, a week starts on Monday and ends on Sunday

  • lastweek() - a date field contains last week’s date, a week starts on Monday and ends on Sunday

  • thismonth() - a date field contains this month’s date

  • lastmonth() - a date field contains last month’s date

  • thisyear() - a date field contains this year’s date

  • lastyear() - a date field contains last year’s date

  • now() - the current date

  • dateadd(interval, number, date) - adds a date interval to a date and returns the date.

    • valid interval values: year, yyyy, yy = Year; quarter, qq, q = Quarter; month, mm, m = month; dayofyear = Day of the year; day, dy, y = Day; week, ww, wk = Week; weekday, dw, w = Weekday; hour, hh = hour; minute, mi, n = Minute; second, ss, s = Second; millisecond, ms = Millisecond

    • number can be a positiv or negative integer value

    • date is a valid ISO8601 date value of the format yyyy-MM-dd’T’HH:mm:ssZZ (e.g., 1970-01-01T00:00:00+0000) or a function which delivers a date value of this format.

Usage
SELECT ... FROM ... WHERE system:creationDate IN today();
SELECT ... FROM ... WHERE rmDestructionDate > today();
Examples
SELECT contentStreamId, fileName, repositoryId FROM system:object WHERE system:creationDate IN lastmonth();
SELECT * FROM document WHERE system:lastModificationDate IN today() AND system:creationDate IN lastyear() ORDER BY system:creationDate DESC;
SELECT COUNT(*) c, system:creationDate FROM system:object WHERE system:creationDate IN thisyear() GROUP BY system:creationDate ORDER BY c DESC;
dateadd() and now() Examples
SELECT * FROM system:object WHERE system:rmDestructionDate < now();
SELECT * FROM system:object WHERE system:creationDate < dateadd('day',35,'2018-09-20T08:37:26.280Z');
SELECT * FROM document WHERE system:lastModificationDate > dateadd('year',-1,now());

2.3.9. Queries on 'contentstream' Fields

Additional to property fields of a DMS object, all contentstream fields can be queried in SELECT statements as described above.

Examples
SELECT contentStreamId, fileName, repositoryId FROM system:object;
SELECT * FROM document WHERE mimeType'message/rfc822' ORDER BY title DESC;
SELECT COUNT(*) c, fileName FROM system:object GROUP BY fileName ORDER BY c DESC;

2.3.10. Queries on Queriable Tables

As of version 2020 Winter, table cells can be accessed using the format in the following example:

Select on queriable table
-- syntax of table cell access
SELECT * FROM system:object WHERE queriable_table[row].column = value;

-- examples
SELECT * FROM system:object WHERE queriable_table[row].columnx = value;
SELECT queriable_table.nickname, queriable_table.name FROM system:object WHERE queriable_table[row].columnx LIKE 'steven';
SELECT * FROM system:object WHERE (queriable_table[5].age <= 55 AND queriable_table[6].age >= 22) OR queriable_table[6].age > 6;
SELECT * FROM system:object WHERE queriable_table[2].name IN ('Erwin', 'Max');
SELECT * FROM system:object WHERE queriable_table[3].name CONTAINS('Arno');
SELECT * FROM system:object WHERE queriable_table[4].city IS NULL;
SELECT * FROM system:object WHERE queriable_table[4].city IS NOT NULL;
SELECT * FROM system:object WHERE queriable_table[5].date > lastyear();

Between the SELECT and FROM keywords, one or more table columns can be referenced with the syntax tablename.columnname as shown in the second example query above. The query will then return only the selected columns, in the example the columns nickname and name of the table queriable_table. Otherwise, like in the other examples above where the * symbol is placed between the SELECT and FROM keywords, the entire table will be returned.

The conditions are specified in the same way like in single query calls. Date functions can be used, too.

ORDER BY and GROUP BY are not supported on tables.

To reference any column or any row in the condition, the * symbol can be used as wildcard, as shown in the following examples:

Select on queriable table using wildcards representing any column and/or any row
-- columnx should have the given value in any row
SELECT * FROM system:object WHERE queriable_table[*].columnx = value;

-- any column should have the given value in rowx
SELECT * FROM system:object WHERE queriable_table[rowx].* = value;

-- any table cell should have the given value
SELECT * FROM system:object WHERE queriable_table[*].* = value;

For combined queries within one column of a table, there is a special syntax as shown in the code block below. Examples are provided as well.

Select on queriable table using wildcards representing any column and/or any row
-- syntax of table cell access
SELECT * FROM system:object WHERE queriable_table[row].(column_condition_1 AND/OR ... AND/OR column_condition_x);
SELECT * FROM system:object WHERE queriable_table[*].(column_condition_1 AND/OR ... AND/OR column_condition_x);

-- examples
SELECT * FROM system:object WHERE queriable_table[*].(name IN ('Erwin', 'Max') AND age >= 22);
SELECT * FROM system:object WHERE queriable_table[5].((name CONTAINS('Arno') AND age >= 22) OR city IS NULL);
SELECT * FROM system:object WHERE queriable_table[*].((name CONTAINS('Arno') AND age >= 22) OR (city IS NULL and date <= lastyear())) AND system:creationdate IN thisyear();

Within the brackets, any complex condition statement created from the set of conditions on properties described in the sections above can be queried, where each single condition will be applied on the specified row. If you use the wildcard * as row number, each table row will be tested on the complex condition. For a query match, a row has to be found for which the whole condition set is true.

As shown in the last two lines of the code block above, Combined queries on a row can also be used in combination with further conditions.

2.3.11. Queries on Tags

As of version 2020 Summer, tags can be assigned to objects. The tag properties are searchable by means of queries. Since the tag properties are stored in table format, the queries are defined like queries on tables. Each tag corresponds to one row of the table property system:tags that is assigned to every object. The row is indicated by the value of the corresponding tag’s name. The four available columns are the same for all tags: name, state, creationDate and traceId. The following code block shows examples:

Examples for queries on tags
SELECT * FROM system:object WHERE system:tags[*].creationDate=TODAY();
SELECT * FROM system:object WHERE system:tags[*].name='ren:ocr';
SELECT * FROM system:object WHERE system:tags[ren:ocr].state=2;
SELECT * FROM system:object WHERE system:tags[*].(state=2 AND creationDate=TODAY());
SELECT * FROM system:object WHERE system:tags IS NULL;
SELECT * FROM system:object WHERE system:tags[ren:ocr1] IS NULL;

Of course, the queries can be combined with any other valid query as can be seen in the following examples:

Combine queries on tags with further conditions
-- search for objects have a tag created today and with the state 2
SELECT * FROM system:object WHERE system:tags[*].(state=2 AND creationDate=TODAY());

-- search for objects having the tag 'analysis' with the state 1 that were created yesterday
SELECT * FROM system:object WHERE system:tags[analysis].state=1 AND where system:creationDate=YESTERDAY();

2.3.12. Queries on Structured Data

As of version 2021 Summer, structured data properties can be used to assign an arbitrary JSON structure to objects. The structured data properties are stored similarly to table properties and are thus searchable by means of similar queries. The addressing of individual keys within the JSON structure is inspired by the concept of JSONPath.

Conditions on Structured Data

The following code block shows examples where objects of type order are searched that match the corresponding WHERE condition. The example property customerdetails is a structured data property referenced in the object type definition for order. If objects are found, the values for the structured data property customerdetail will be returned in JSON format for each of them.

Example queries on structured data
-- Search for objects where 'customerdetails' contains the first-order key 'id' with value '2982'.
SELECT customerdetails FROM order WHERE customerdetails.id = 2982

-- Search for objects where 'customerdetails' contains the first-order key 'words' beeing a list with an existing value for index 10.
SELECT customerdetails FROM order WHERE customerdetails.words[10] IS NOT NULL

-- Search for objects where 'customerdetails' contains the first-order key 'words' beeing a list that contains the entry 'milk' at an arbitrary index.
SELECT customerdetails FROM order WHERE customerdetails.words[*] = 'milk'

-- Search for objects where 'customerdetails' contains the first-order key 'sentences' beeing a list that contains the term 'milk' in the second element.
SELECT customerdetails FROM order WHERE customerdetails.sentences[1] CONTAINS('milk')

-- Search for objects where 'customerdetails' contains the first-order key 'food' containing the second-order datetime key 'lastcooked' that has to be a value earlier than last year.
SELECT customerdetails FROM order WHERE customerdetails.food.lastcooked < LASTYEAR()

-- Search for objects where 'customerdetails' contains 'jelly' in the value for the key 'ingredient' that can be at any hierarchical level within the JSON.
SELECT customerdetails FROM order WHERE customerdetails..ingredient CONTAINS('jelly')

-- Search for objects where 'customerdetails' contains 'jelly' in the value for the key 'ingredient' that can be at any hierarchical level within the JSON,
-- but needs to have a direct or indirect parent node 'food'.
SELECT customerdetails FROM order WHERE customerdetails..food..ingredient CONTAINS('jelly')
Restriction Possibilities for Responses

To return only a sub-structure of the JSON value for a structured data property, specify the corresponding key as SELECT statement:

SELECT customerdetails.uid FROM order

To return multiple sub-structures, separate them by comma:

SELECT customerdetails.uid,customerdetails.word FROM order

If you specify an index within a list, the values for the list elements with lower indices will be replaced by null in the return statement:

-- The query starting with ...
SELECT customerdetails.words[2] FROM order

-- ... will result in the return statement:
{
    "properties": {
        "appTable:customerdetails": {
            "value": {
                "words": [
                    null,
                    null,
                    "water"
                ]
            }
        }
    }
}

To return sub-structures located at any hierarchical level within the JSON value, use .. as shown in the examples below.

-- Search for objects of type order and display only key-value mappings for keys 'uid'.
SELECT customerdetails..uid FROM order

-- Example response:
{
    "properties": {
        "appTable:customerdetails": {
            "value": {
                "uid": "711e1858-eb24-4183-8743-0292c7b9b93b",
                                 "food": {
                                   "uid": "7aa4a2f2-3dc0-420c-a0d7-edc6af3619de"
                                 }
            }
        }
    }
}

-- Search for objects of type order and display only key-value mappings for keys 'uid' that have a direkt or indirect parent node 'food'.
SELECT customerdetails..food..uid FROM order

-- Example response:
{
    "properties": {
        "appTable:customerdetails": {
            "value": {
                                 "food": {
                                   "uid": "7aa4a2f2-3dc0-420c-a0d7-edc6af3619de"
                                 }
            }
        }
    }
}

2.3.13. Queries on Audit Entries

Audit entries can be queried by querying the object type system:audit.

If you search by traceId, please note that the values are normalized if necessary as described here.
-- Select all audit entries
SELECT * FROM system:audit;

-- Select all audit entries for a specific traceId
SELECT * from system:audit WHERE traceid = '0000000000543221'

-- Select all audit entries created yesterday
SELECT * from system:audit WHERE creationDate IN YESTERDAY()

Audit entries are stored within a relational database. Thus, to query audit entries full-text queries and the return of the total amount of matching items totalNumItems within the result cannot be supported:

  • no queries with CONTAINS()

  • no queries using scoring SCORE()

  • no totalNumItems within the result set

All other features will be provided as described above.

2.3.14. Query JSON Format

A search can be called using the POST /api/dms/objects/search endpoint by giving the following JSON structure:

Input JSON using parameters
{
  "query" : {
    "statement" : "SELECT * from sysemail WHERE email = @emailAddress AND sysfrom IN @from AND CONTAINS(@text)",
    "skipCount" : 0,                                                // optional for Paging
    "maxItems" : 50,                                                // optional for Paging
    "useCache" : true,                                              // optional
    "handleDeletedDocuments" : "DELETED_DOCUMENTS_EXCLUDE",         // optional DELETED_DOCUMENTS_INCLUDE | DELETED_DOCUMENTS_ONLY | DELETED_DOCUMENTS_EXCLUDE default: DELETED_DOCUMENTS_EXCLUDE
   "parameters": {                                                 // optional, only if @ parameter occurs in statement
        "emailAddress": "'info@optimal-systems.de'",
        "text": "'Meeting'",
        "from": "('hallo@huhu.de','info@huhu.de')"
    }
 }
}
  • The field statement contains the SQL query.

  • skipCount (default: 0) defines the number of skipped objects from which the maxItems (default: 50) number of found objects will be delivered. This defines the paging of the search call.

  • The field useCache (default: true) defines if this request should be cached in search engine’s Shard request cache.

  • Within a default search, all objects marked as deleted will be excluded (DELETED_DOCUMENTS_EXCLUDE). By using the optional field handleDeletedDocuments, this behaviour can be changed in including this objects (DELETED_DOCUMENTS_INCLUDE) or delivering only deleted objects (DELETED_DOCUMENTS_ONLY).

Using Parameters

Within an SQL statement, some predefined parameters can be referenced. By @userId the ID of the actual user (taken from the user session) and by @userRoles the roles of the actual user (also taken from the user session) can be referenced for replacement at runtime. As of 2023 Summer, @abac.<key> is available as well.

Input JSON with use of @userId and @userRoles parameters
{
  "query" : {
    "statement" : "SELECT * from system:object WHERE system:createdBy = @userId AND system:roles IN @userRoles"
 }
}

The JSON field parameters can be used to define parameter (reserved names: userRoles, userId, abac) values which can be referenced by @<parameter> within a preformed SQL statement for replacement at runtime. The reserved parameter names userRoles, userId cannot be used for own definition of a parameter. A given definition under this names affects an exception.

Input JSON with use of parameters
{
  "query" : {
    "statement" : "SELECT * from system:object WHERE email = @emailAddress AND email:from IN @from AND CONTAINS(@text)",
   "parameters": {                                                 // optional, only if @ Parameter occurs in statement
        "emailAddress": "'info@optimal-systems.de'",
        "text": "'Meeting'",
        "from": "('hallo@huhu.de','info@huhu.de')"
    }
 }
}

2.4. Document Lifecycle

2.4.1. Synchronous or Asynchronous

In document lifecycle management, multi-stage and asynchronous processes are not uncommon — quite the contrary. The first process steps are carried out with the highest priority. More complex and currently not absolutely essential process steps are carried out asynchronously with a lower priority. This saves time, and carrying out operations in parallel lets you distribute resources more evenly.

Parameter 'waitForSearchConsistency' for Endpoints with Effect on the Search Index

As of version 2022 Autumn, some processes that lead to an update of the index of the search engine can be called with the query parameter waitForSearchConsistency.

Value of 'waitForSearchConsistency' Processing Description Advantage Disadvantage

true

synchronous

The success response of the corresponding endpoint is returned after the successful update of the search index.

The changes are available even for search requests that are sent immediately after the synchronous processing.

The waiting time before the response is rather long.

false

asynchronous

The success response of the corresponding endpoint does not wait for the update of the search index.

The waiting time for the response is far shorter.

Search requests sent immediately after the change request may be processed before the search index is updated.

The update and import endpoints listed below accept an optional query parameter waitForSearchConsistency.

Endpoints Default for 'waitForSearchConsistency'

false

Metadata update:

true

Content update:

  • POST /api/dms/objects/{objectId}/contents/file

true

Restore:

  • POST /api/dms/objects/{objectId}/versions/{versionNr}/actions/restore

true

Deletion:

  • DELETE /api/dms/objects/{objectId} (as of 2023 Summer)

  • DELETE /api/dms/objects (as of 2023 Summer)

true

Tagging:

  • POST /api/dms/objects/{objectId}/tags/{name}/state/{state}

  • POST /api/dms/objects/tags/{name}/state/{state}?query=<SQL>

  • DELETE /api/dms/objects/{objectId}/tags/{name}

true

Text rendition:

  • POST /api/dms/objects/{objectId}/contents/renditions/text

true

2.4.2. Tagging

To resume a process chain, additional information about the current state of the process is necessary. In order to not mix an object’s metadata with its state data, there is the possibility to tag objects. Pure tagging operations do not trigger the creation of new object versions.

Objects can be searched by tags and selected for the next process step. All tagging activities are recorded in the audit trail.

Characteristics of Tags

Difference between metadata and tags:

  • Tags do NOT belong to the metadata and thus do not need to be defined in the schema.

  • Tags are stored together with the object as value for the system:tags property similar to metadata.

  • Pure tag operations do NOT lead to the creation of a new object version.

  • Tags can only be attached to the current version of an object, whereas previous versions cannot have tags.

  • For version-specific information, metadata provide the suitable options. They have to be defined in the schema.

State information:

  • Tags describe the state of an object in a process chain. The state information is specified via an integer value.

Tracing information:

  • Tags are provided with a process identification that allows to retrace tag operations and tune the update or deletion permissions for the tag.

Assignment:

  • Tags can be added to any object during object creation, during metadata updates or completely independent via a tagging endpoint.

  • As of 2024 Spring, tags can be automatically assigned during specific operations on DMS objects via lifecycle hooks.

  • Multiple tags can be added to one object.

  • The number of tags assigned to one object is limited to 50.

Querying on tags:

  • The properties of tags are included in the searchable data.

  • Tags are queried similar to table properties.

Behavior during POST metadata updates:

  • If the system:tags property is specified in the request body,

    • all included tags are assigned to the new object version with the given name and state. The same value as system:lastModificationDate and system:traceId will be set automatically for creationDate and traceId respectively for all of them.

    • each tag that is not included is deleted. The new object version will not have that tag.

  • If the property system:tags is NOT specified in the request body or is set to null, all tags will be deleted. The new object version will not have any tag.

Behavior during PATCH metadata updates:

  • If the system:tags property is specified in the request body,

    • all included tags are assigned to the new object version.

    • each tag that is not included is deleted. The new object version will not have that tag.

  • If the system:tags property is NOT specified in the request body, all tags are transferred to the new object version. Their state, creationDate and traceId remain unchanged.

  • If the system:tags property is set to null, all tags will be deleted. The new object version will not have any tag.

Behavior during POST updates of the binary content file:

  • If the tag name ends with the suffix :resistant, the tag is transferred to the new object version. Its state remains unchanged.

  • If the tag name does NOT end with the suffix :resistant, the tag is deleted. It will not be assigned to the new object version.

Behavior during POST multipart update of metadata and content (as of 2024 Spring):

  • If the system:tags property is specified in the request body,

    • each tag that is not included is deleted. The new object version will not have that tag.

    • all included tags are assigned to the new object version with the given name and state. The same value as system:lastModificationDate and system:traceId will be set automatically for creationDate and traceId respectively for all of them.

      Exception
      Each non-resistant tag that is specified in the request body with an exact copy of a previously existing tag is deleted. It is assumed that the tag is not deliberately set, but simply copied from the current object.
    • Especially, if the whole property system:tags specified in the request body equals the system:tags of the current object, the behaviour is like the update of the binary content file: resistant tags survive, non-resistant tags are deleted.

  • If the property system:tags is NOT specified in the request body or is set to null, all tags will be deleted. The new object version will not have any tag.

Behavior during POST restoring actions of an old version (as of 2022 Spring):

  • If the tag name ends with the suffix :resistant, the tag is transferred to the new object version. Its state remains unchanged.

  • If the tag name does NOT end with the suffix :resistant, the tag is deleted. It will not be assigned to the new object version.

Any tag operation is documented in the object audit trail.

Tag Properties

Tags are defined by the following properties:

Property Type Description In a request

name

String

Name of the tag for identification. It has to be unique for the corresponding object.

The tag names are validated during a tag creation or update process. To pass the validation, they have to match the regular expression [a-z](:?[a-z]) and must not be longer than 32 characters (as of 2022 Spring, no longer than 128 characters).

As of version 2021 Summer, the suffix :resistant triggers a specific behavior of the tag. If a tag name matches the expression [a-z](:?[a-z]):resistant, the tag will behave like a resistant tag as described below.

required

state

Integer

Represents the status of the corresponding object in a process chain.

required

creationDate

String

Date and time of the last modification of the tag. It is set automatically by the system.

optional, only available in search queries

traceId

Hexadecimal lowercase string with maximum length 16

Process identification of any tag operation. If not specified in the request, a random String value will be set after the tag operation.

In a tag update or delete request, the request parameter traceIdMustMatch can be set to true. The operation will be done only if the traceId of the call matches the current traceId of the requested tag. After such update processes, the traceId of the updated tag will be the same as before.

Per default, traceIdMustMatch is set to false.

optional, specified by means of the HTTP header X-B3-TraceId

In a request, the corresponding properties are included directly in the URL for the call of the endpoint. In contrast, if tags are displayed in a response body, their properties are listed as a part of a JSON structure in the value of the system:tags property.

Tagging Endpoints

The following endpoints for pure tag operations do not trigger a new version of the corresponding object, but only a new entry in the audit trail:

  • Retrieve object tags by ID – GET /api/dms/objects/{objectId}/tags

  • Add object tag by ID – POST /api/dms/objects/{objectId}/tags/{name}/state/{state}

  • Update object tag by ID – POST /api/dms/objects/{objectId}/tags/{name}/state/{state}?overwrite=true

  • Delete object tag by ID – DELETE /api/dms/objects/{objectId}/tags/{name}

  • Add/update object tag by search query – POST /api/dms/objects/tags/{name}/state/{state}?query=<SQL>

Automated Tagging

As of version 2024 spring, tags can be automatically assigned or updated via lifecycle hooks.

Resistant Tags

As of version 2021 Autumn, it is possible to assign resistant tags that are automatically transferred to the new version of an object created during an update of the binary content file.

The resistant tags will be removed from the old object version and assigned to the new object version. As usual, the previous object version will not have any tags afterwards. However, the new version will have all the resistant tags assigned to it that were originally assigned to the previous version. Conventional non-resistant tags will not be reassigned to the new object version.

Resistant tags are identified by the suffix :resistant at the end of the tag name.

The tag name including the suffix must not exceed the length limit of 128 characters.

2.4.3. Typecasting

By assigning or removing secondary object types (SOTs) to DMS objects, it is possible to change their set of available properties during lifecycle. This can be used to realize typecasting.

To assign a secondary object type, the target DMS object’s type (system:objectTypeId) must match one of the following prerequisites:

(A) Floating reference on the SOT

If the DMS object has any user-defined object type, this type has to contain a reference on the SOT in its schema definition. This reference has to be floating ("static=false").

Example reference
<secondaryObjectTypeId static="false">myexamplesot</secondaryObjectTypeId>
(B) Pre-defined system:document

As of 2023 Spring, the predefined object type system:document automatically has a floating reference on all SOTs that are available in the applied tenant schema. Thus, all those SOTs can be assigned to DMS objects of type system:document.

The rules for the contentStreamAllowed attribute for the individual SOTs have to be considered before they are assigned to an object.

Floating secondary object types can be assigned during the import

  • via POST /api/dms/objects

or assigned/removed/exchanged at runtime for already existing DMS objects with an update

  • via POST /api/dms/objects/{objectId} or

  • via PATCH /api/dms/objects/{objectId}.

The following keywords can be used in the system:secondaryObjecttypeIds metadata property.

Keyword Type Description Example

value

comma-separated string list

Available during import or update.

Assigns one or multiple secondary object types to a DMS object.

The list of floating SOTs transferred will replace all existing ones. This includes the related properties and their metadata values. If you want to keep an existing floating SOT, it has to be part of the new list as well.
"system:secondaryObjectTypeIds": {
    "value": ["INV","SUP"]
}

add

string

Available during update.

Assigns a single secondary object type to an object.

"system:secondaryObjecttypeIds": {
   "add": "INV"
}

remove

string

Available during update.

Removes a single secondary object type from an object.

The metadata assigned to the object by referencing the secondary object type will be deleted for the current object version!
"system:secondaryObjecttypeIds": {
    "remove": "INV"
}

If assigned to a DMS object, the SOT is available in the FROM clause in search queries, e.g.:

select * from appSot:INV

You cannot tell from the metadata of a document any longer if a property is referenced directly or indirectly in the schema. All properties are plain in the properties list.

2.4.4. Document Retention

Retention

yuuvis® Momentum provides the possibility to prohibit object deletion requests as well as deletion or change requests on binary content files via an expiration date property called system:rmExpirationDate. The property is predefined in all systems and is part of the also predefined secondary object type (SOT) system:rmDestructionRetention. This SOT can be referenced in any document object type definition in any schema (global, app specific or tenant specific). Thus, an expiration date can be set for each object of such a document object type. If a document object has the system:rmExpirationDate property and if the value of this property lies in the future, it is under retention until the expiration date is reached. There is no maximum retention time. You can specify any date in the future as expiration date to ensure storage time for the sake of your archiving needs.

Since the retention is stored within the objects' metadata, the individual values can be retrieved like other object properties, e.g., via the GET /api/dms/objects/{objectId} endpoint. It is not possible to define retention periods for objects without the system:rmDestructionRetention.

The retention defined in the SOT protects binary content files from beeing modified/deleted via yuuvis® Momentum API. However, objects under retention can still be modified/deleted by administrators having direct access to the used storage. To prohibit such administrative operations, some archives offer an archive-internal retention as well. In those archives, the retention specified in the individual objects' metadata is set as an individual archive-internal retention.
The metadata of objects under retention are NOT protected from changes. They remain editable. If you want to prohibit metadata updates in project-specific use cases, you can configure a suitable webhook, that is triggered before the process you want to prohibit.
SOT 'system:rmDestructionRetention'

To specify a retention for an individual object, the following properties are predefined in yuuvis® Momentum.

Property datetime Description

system:rmExpirationDate

datetime

Required to set a retention. Specifies the date until which the document object will be unter retention.

The value must not lie in the past at the time of specification.

If the value is null, the values for system:rmStartOfRetention and system:rmDestructionDate must be null as well.

If not specified, the default retention of the used repository will be set if defined in the corresponding archive profile. The default retention does NOT replace a retention specified via API, even if the default retention would result in a later expiration date. >> application-storage.yml

system:rmStartOfRetention

datetime

Optional. Not considered or validated by yuuvis® Momentum core system.

Can be used to specify the start date of the retention period for documentation purposes.

system:rmDestructionDate

datetime

Optional. Has to equal or exceed the value for system:rmExpirationDate as validated by yuuvis® Momentum core system.

Can be used to specify a date to trigger an automated deletion via a custom service. The yuuvis® Momentum core system does not yet offer an endpoint for this purpose.

The following code block shows the predefined properties that are related to retention. It is not possible to edit or overwrite those definitions.

Properties of system:rmDestructionRetention
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
<propertyDateTimeDefinition>
    <id>system:rmExpirationDate</id>
    <description>contains the date until the document's content is preserved</description>
    <propertyType>datetime</propertyType>
    <cardinality>single</cardinality>
    <required>false</required>
</propertyDateTimeDefinition>
<propertyDateTimeDefinition>
    <id>system:rmStartOfRetention</id>
    <description>contains the date from which the retention time was calculated (for documentation purposes only)</description>
    <propertyType>datetime</propertyType>
    <cardinality>single</cardinality>
    <required>false</required>
</propertyDateTimeDefinition>
<propertyDateTimeDefinition>
    <id>system:rmDestructionDate</id>
    <description>holds the date when the destruction process should be triggered</description>
    <propertyType>datetime</propertyType>
    <cardinality>single</cardinality>
    <required>false</required>
</propertyDateTimeDefinition>
...

All three of those properties are referenced in the system:rmDestructionRetention SOT. The following code block shows its predefined structure. It is not possible to edit or overwrite this definition.

Definition of system:rmDestructionRetention
1
2
3
4
5
6
7
8
9
10
11
...
<typeSecondaryDefinition>
    <id>system:rmDestructionRetention</id>
    <localNamespace>urn:optimal-systems.de:dmscloud:system</localNamespace>
    <description>can be used to apply retentions on objects</description>
    <baseId>system:secondary</baseId>
    <propertyReference>system:rmExpirationDate</propertyReference>
    <propertyReference>system:rmStartOfRetention</propertyReference>
    <propertyReference>system:rmDestructionDate</propertyReference>
</typeSecondaryDefinition>
...

To use retentions, your applied schema must contain a document object type that references the predefined system:rmDestructionRetention SOT. For document objects of this type, you can specify retention properties via yuuvis® Momentum API. The following code block shows an example object type definition.

Example document object type definition
1
2
3
4
5
6
7
8
9
10
11
...
<typeDocumentDefinition>
    <id>document</id>
    <description>a document with retention</description>
    <baseId>system:document</baseId>
    <propertyReference>name</propertyReference>
    <propertyReference>date</propertyReference>
    <contentStreamAllowed>required</contentStreamAllowed>
    <secondaryObjectTypeId>system:rmDestructionRetention</secondaryObjectTypeId>
</typeDocumentDefinition>
...

By means of yuuvis® Momentum core API, there are two ways to set an object under retention:

the object can directly be imported with an expiration date or an expiration date can be added to a previously existing object using a metadata update. An example data set as retrievable via GET /api/dms/objects/{objectId} is shown in the following code block.

Example metadata
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
    "objects": [{
        "properties": {
            "system:objectTypeId": {
                "value": "document"
            },
            "name": {
                "value": "exampledocument"
            },
            "system:rmStartOfRetention": {
                "value": "2018-07-20T11:52:00.000Z"
            },
            "system:rmExpirationDate": {
                "value": "2028-12-28T11:52:00.000Z"
            },
            "system:rmDestructionDate": {
                "value": "2028-12-28T11:52:00.000Z"
            }
        },

        ... // the content streams section is missing here
    }]
}
Effects of Retentions

If an expiration date has been set for a document object, it is not possible to change or delete its binary content file or delete the object before its expiration date. The other two properties have no particular uses provided by the system. Also, if an object is under retention, it is still possible to update its metadata; however, the expiration date cannot be removed or replaced by an earlier date.

An object under retention cannot be deleted or changed even by users that have a write or delete permissions; retentions take precedence over write or delete permissions.

Automated Retention Management

It is possible to extend the functionality of yuuvis® Momentum by configuring webhooks and adding custom microservices. Thus, you can build your own specialized solution to realize automated retention management.

One possible use case would be to calculate the required retention values based on the individual object’s metadata and set them, e.g.,

  • during the object creation,

  • during a specific update of the object’s metadata, or

  • triggered by a specific metadata update of the parent folder object (if you use system:parentId).

For the deletion of document objects with expired retention, you can introduce automated custom solutions as well. E.g., with a custom microservice in your system that automatically searches for objects with expired retention and

  • deletes them,

  • updates their state in the lifecycle via tagging, or

  • starts a workflow process asking assigned users to delete them (if BPM-ENGINE Service is used).

2.4.5. Content Renditions

Renditions are alternative representations of the content assigned to DMS objects. As such, they are only retrievable with a read permission for the concrete object instances.

Please note that a rendition is not an exact representation of the original file. Deviations to the original file may arise and are NOT considered as bugs in our software.

Typical use cases for the individual rendition types are:

kind of rendition Example use case

text

Full-text search

pdf

content preview

slide

thumbnails for content visualization within hit lists in client applications

Calculation and Storage

The yuuvis® Momentum core system offers automated rendition calculation for various supported formats of binary content files.

The responsible services are enabled in the default configuration but the rendition repository has to be configured manually.
kind of rendition text pdf slide

Service for calculation

renditiontextworker

rendition

rendition

Automated calculation

during import with content and content update processes

on (first) request

on (first) request

Manual input

during import or via the update endpoint for existing objects, or via the dms.request.objects.upsert.database-before webhook

-

-

Storage location

search index

rendition repository

rendition repository

Availability for DMS object versions

only for the current version

for any (not deleted) version

for any (not deleted) version

As the text rendition is used for full-text search, it is stored in the search index. If you want to extend the core system’s functionality in terms of supported formats, it is possible to set or update the text rendition via API gateway endpoints. Thus, it is possible to, e.g., integrate an OCR implementation to automatically calculate a full-text for binary content files of image file types.

The length of extracted full-text is limited by the configurable parameter extraction.maxTextLengthInKB in a YAML configuration file for the repository service. Thus, overloads and downtimes of the repository due to huge content files with much text can be avoided. If you increase the value, ensure that your search engine (Elasticsearch) can handle your desired size of string fields.

The text renditions are not stored as content streams but as plain text in the search index where only data for the current version of DMS objects are stored. Thus, text renditions are only available for the current version of DMS objects.

A dbs-reindex command via commander service will undo all manual text rendition inputs.

The pdf and slide renditions are calculated from the binary content file by the rendition service on request. To reduce the workload and processing time for repeated retrieval of the same rendition, a default rendition repository can be configured. It is a separate repository to allow for a different storage configuration as it might be required for the binary content files themselves. Whenever a pdf or slide rendition is requested for an object, it is retrieved from the default rendition repository. If available, the stored rendition will be returned. If not available, the requested rendition is generated from the binary content file that is assigned to the object, stored in the default rendition repository and finally returned.

The rendition repository uses the content’s digest as rendition identification to avoid duplicate filing. The digest is calculated by the repository service during each content import or update process and referenced in the content stream properties section of the corresponding DMS object. If the same content file is assigned to multiple DMS objects, the digest is the same, and only one rendition for each kind (pdf or slide) is stored within a tenant.

It is not possible to set retention for a rendition.

Supported Formats

The following table provides an overview of various binary content file types and the types of rendition that can be provided (+) by yuuvis® Momentum.

Binary content file type Extension text rendition pdf rendition slide rendition

MS Office Word 97-2016

doc, docx

+

+

+

MS Office PowerPoint 97-2016

ppt, pptx

+

+

+

MS Office Excel 97-2016

xls, xlsx

+

+

+

OpenDocument Text

odt

+

+

+

OpenDocument Presentation

odp

+

+

+

OpenDocument Spreadsheet

ods

+

+

+

Rich Text Format

rtf

+

-

-

Visio Drawing File

vsd, vsdx

-

+

(limited range of functions)

+

Plain Text

txt

+

-

-

Comma Separated Values

csv

+

-

-

HyperText Markup Language (HTML)

html

+

-

-

XML

xml

+

-

-

JavaScript Object Notation

json

+

-

-

MS Outlook

msg

+

-

+

Electronic Mail Format

eml

-

-

+

Encapsulated Portable Document Format

epdf

+

-

-

Portable Document Format

As of 2024 Spring, also 256-bit-encrypted PDF.

pdf

+

-

+

Tagged Image File Format

tiff / tif

-

+

+

Portable Bitmap Image

pbm

-

+

+

Bitmap Image File

bmp

-

+

+

Graphical Interchange Format File

gif

-

+

+

JPEG Image

Exchangeable image file format (JPEG)

jpg, jng, jpeg

-

+

+

Portable Network Graphic

png

-

+

+

Weppy Image Format (Lossy Compression)

webp

-

+

+

Supported Fonts

The creation of renditions supports only those fonts that are available on the corresponding operation system. If a not-supported font occurs in a binary content file for which a rendition creation is requested, it will be substituted by a supported font.

As yuuvis® Momentum is operated in a Kubernetes system based on Linux, the DejaVu Serif font is always available and is thus used as fallback for the rendition creation if a binary content file contains a not-supported font that cannot be substituted.

The Kubernetes-based yuuvis® Momentum installation contains a variety of different fonts that are available for the creation of renditions. The supported fonts are listed here:

Click here to show supported fonts…​
- NotoSansThai-ExtraCondensedLight.ttf: Noto Sans Thai,Noto Sans Thai ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSerifKhmer-CondensedLight.ttf: Noto Serif Khmer,Noto Serif Khmer Cond Light:style=Condensed Light,Regular
- NotoSerifDisplay-SemiCondensedMedium.ttf: Noto Serif Display,Noto Serif Disp SemCond Med:style=SemiCondensed Medium,Regular
- NotoSansLaoUI-CondensedSemiBold.ttf: Noto Sans Lao UI,Noto Sans Lao UI Cond SemBd:style=Condensed SemiBold,Regular
- DejaVuSerif-Bold.ttf: DejaVu Serif:style=Bold
- NotoSerifGeorgian-SemiCondensedMedium.ttf: Noto Serif Georgian,Noto Serif Georgian SmCn Md:style=SemiCondensed Medium,Regular
- NotoSansArabic-CondensedMedium.ttf: Noto Sans Arabic,Noto Sans Arabic Cond Med:style=Condensed Medium,Regular
- NotoSansCham-Black.ttf: Noto Sans Cham,Noto Sans Cham Blk:style=Black,Regular
- NotoSerifKhmer-ExtraCondensedExtraLight.ttf: Noto Serif Khmer,Noto Serif Khmer ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansTamilUI-CondensedBlack.ttf: Noto Sans Tamil UI,Noto Sans Tamil Cond Blk:style=Condensed Black,Regular
- NotoSansArmenian-SemiCondensedExtraLight.ttf: Noto Sans Armenian,Noto Sans Armenian SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- URWBookman-LightItalic.otf: URW Bookman:style=Light Italic
- NotoSerifHebrew-CondensedBold.ttf: Noto Serif Hebrew,Noto Serif Hebrew Cond:style=Condensed Bold,Bold
- NotoSerifKhmer-ExtraLight.ttf: Noto Serif Khmer,Noto Serif Khmer ExtLt:style=ExtraLight,Regular
- NotoSerifDisplay-CondensedExtraLight.ttf: Noto Serif Display,Noto Serif Disp Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSans-CondensedLight.ttf: Noto Sans,Noto Sans Cond Light:style=Condensed Light,Regular
- NotoSansLaoUI-ExtraCondensedSemiBold.ttf: Noto Sans Lao UI,Noto Sans Lao UI ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSans-Medium.ttf: Noto Sans,Noto Sans Med:style=Medium,Regular
- NotoSansArabic-Condensed.ttf: Noto Sans Arabic,Noto Sans Arabic Cond:style=Condensed,Regular
- NotoSansCarian-Regular.ttf: Noto Sans Carian:style=Regular
- NotoSerifMyanmar-Thin.ttf: Noto Serif Myanmar,Noto Serif Myanmar Thin:style=Thin,Regular
- NotoSerif-SemiCondensedSemiBold.ttf: Noto Serif,Noto Serif SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansHebrew-Bold.ttf: Noto Sans Hebrew:style=Bold
- NotoSerifArmenian-CondensedExtraLight.ttf: Noto Serif Armenian,Noto Serif Armenian Cn XLt:style=Condensed ExtraLight,Regular
- NotoSansDevanagariUI-Black.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari Bk:style=Black,Regular
- URWBookman-Light.otf: URW Bookman:style=Light
- NotoSansDisplay-ExtraCondensedBoldItalic.ttf: Noto Sans Display,Noto Sans Disp ExtCond:style=ExtraCondensed Bold Italic,Bold Italic
- NotoSansHebrew-Medium.ttf: Noto Sans Hebrew,Noto Sans Hebrew Med:style=Medium,Regular
- NotoSerifKhmer-Black.ttf: Noto Serif Khmer,Noto Serif Khmer Blk:style=Black,Regular
- NotoSansCherokee-Black.ttf: Noto Sans Cherokee,Noto Sans Cherokee Blk:style=Black,Regular
- DejaVuSansMono.ttf: DejaVu Sans Mono:style=Book
- NotoSerifGeorgian-Condensed.ttf: Noto Serif Georgian,Noto Serif Georgian Cn:style=Condensed,Regular
- NotoSansThai-ExtraCondensedMedium.ttf: Noto Sans Thai,Noto Sans Thai ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSerifTelugu-Regular.ttf: Noto Serif Telugu:style=Regular
- NotoSansLao-SemiCondensedExtraBold.ttf: Noto Sans Lao,Noto Sans Lao SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansOgham-Regular.ttf: Noto Sans Ogham:style=Regular
- NotoSerifMyanmar-CondensedBlack.ttf: Noto Serif Myanmar,Noto Serif Myanmar Cond Blk:style=Condensed Black,Regular
- NotoSerifSinhala-ExtraLight.ttf: Noto Serif Sinhala,Noto Serif Sinhala ExtLt:style=ExtraLight,Regular
- NotoSerifHebrew-ExtraCondensedBold.ttf: Noto Serif Hebrew,Noto Serif Hebrew ExtCond:style=ExtraCondensed Bold,Bold
- NotoSerifArmenian-ExtraCondensedExtraLight.ttf: Noto Serif Armenian,Noto Serif Armenian XCn XLt:style=ExtraCondensed ExtraLight,Regular
- NotoSerifEthiopic-Black.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic Bk:style=Black,Regular
- NotoSans-SemiCondensedSemiBoldItalic.ttf: Noto Sans,Noto Sans SemCond SemBd:style=SemiCondensed SemiBold Italic,Italic
- NotoSansInscriptionalPahlavi-Regular.ttf: Noto Sans Inscriptional Pahlavi,Noto Sans InsPahlavi:style=Regular
- NotoSerifMalayalam-Regular.ttf: Noto Serif Malayalam:style=Regular
- NotoSansTamil-SemiCondensedBlack.ttf: Noto Sans Tamil,Noto Sans Tamil SemCond Blk:style=SemiCondensed Black,Regular
- NotoSansSinhalaUI-ExtraCondensedThin.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSerifTamil-SemiCondensedExtraLight.ttf: Noto Serif Tamil,Noto Serif Tamil SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSansArabicUI-CondensedExtraLight.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI Cn XLt:style=Condensed ExtraLight,Regular
- NotoSansGeorgian-ExtraBold.ttf: Noto Sans Georgian,Noto Sans Georgian ExtBd:style=ExtraBold,Regular
- NotoSans-Black.ttf: Noto Sans,Noto Sans Blk:style=Black,Regular
- NotoSans-ExtraCondensedExtraBoldItalic.ttf: Noto Sans,Noto Sans ExtCond ExtBd:style=ExtraCondensed ExtraBold Italic,Italic
- NotoSansHebrew-ExtraCondensedThin.ttf: Noto Sans Hebrew,Noto Sans Hebrew ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSansSymbols-Light.ttf: Noto Sans Symbols,Noto Sans Symbols Light:style=Light,Regular
- NotoSerifLao-ExtraBold.ttf: Noto Serif Lao,Noto Serif Lao ExtBd:style=ExtraBold,Regular
- NotoSansEthiopic-CondensedThin.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic Cond Thin:style=Condensed Thin,Regular
- NotoSerifEthiopic-Medium.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic Md:style=Medium,Regular
- NotoSerifMyanmar-CondensedThin.ttf: Noto Serif Myanmar,Noto Serif Myanmar Cond Thin:style=Condensed Thin,Regular
- NotoSansDevanagari-Medium.ttf: Noto Sans Devanagari,Noto Sans Devanagari Md:style=Medium,Regular
- NotoSerifMalayalam-Bold.ttf: Noto Serif Malayalam:style=Bold
- NotoSerifKhmer-Condensed.ttf: Noto Serif Khmer,Noto Serif Khmer Cond:style=Condensed,Regular
- NotoSansTamil-SemiCondensedExtraLight.ttf: Noto Sans Tamil,Noto Sans Tamil SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSansDisplay-ExtraCondensedBlackItalic.ttf: Noto Sans Display,Noto Sans Disp ExtCond Blk:style=ExtraCondensed Black Italic,Italic
- NotoSerifHebrew-ExtraCondensedBlack.ttf: Noto Serif Hebrew,Noto Serif Hebrew ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansMono-SemiCondensedBlack.ttf: Noto Sans Mono,Noto Sans Mono SemCond Blk:style=SemiCondensed Black,Regular
- NotoSansDisplay-CondensedThinItalic.ttf: Noto Sans Display,Noto Sans Disp Cond Thin:style=Condensed Thin Italic,Italic
- NotoSansCJKkr-Black.otf: Noto Sans CJK KR,Noto Sans CJK KR Black:style=Black,Regular
- NotoSansDevanagariUI-CondensedSemiBold.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari Cn SmBd:style=Condensed SemiBold,Regular
- NotoSansKhmerUI-SemiCondensedLight.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI SemCond Light:style=SemiCondensed Light,Regular
- NotoSansKhmer-Thin.ttf: Noto Sans Khmer,Noto Sans Khmer Thin:style=Thin,Regular
- NotoSansArabic-CondensedThin.ttf: Noto Sans Arabic,Noto Sans Arabic Cond Thin:style=Condensed Thin,Regular
- NotoSansTamil-CondensedThin.ttf: Noto Sans Tamil,Noto Sans Tamil Cond Thin:style=Condensed Thin,Regular
- NotoSansArabicUI-CondensedSemiBold.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI Cn SmBd:style=Condensed SemiBold,Regular
- NotoSerifHebrew-SemiCondensedExtraLight.ttf: Noto Serif Hebrew,Noto Serif Hebrew SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSerifEthiopic-CondensedLight.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic Cn Lt:style=Condensed Light,Regular
- NotoSerifLao-Bold.ttf: Noto Serif Lao:style=Bold
- NotoSansKhmer-Black.ttf: Noto Sans Khmer,Noto Sans Khmer Blk:style=Black,Regular
- NotoSerifKhmer-CondensedBold.ttf: Noto Serif Khmer,Noto Serif Khmer Cond:style=Condensed Bold,Bold
- NotoSansThai-Thin.ttf: Noto Sans Thai,Noto Sans Thai Thin:style=Thin,Regular
- NotoSerifThai-Light.ttf: Noto Serif Thai,Noto Serif Thai Light:style=Light,Regular
- NimbusMonoPS-Italic.otf: Nimbus Mono PS:style=Italic
- NotoSans-SemiCondensedSemiBold.ttf: Noto Sans,Noto Sans SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansHebrew-SemiCondensedSemiBold.ttf: Noto Sans Hebrew,Noto Sans Hebrew SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansMono-Regular.ttf: Noto Sans Mono:style=Regular
- NotoSansGeorgian-SemiBold.ttf: Noto Sans Georgian,Noto Sans Georgian SemBd:style=SemiBold,Regular
- NotoSansDevanagari-ExtraBold.ttf: Noto Sans Devanagari,Noto Sans Devanagari XBd:style=ExtraBold,Regular
- NotoSans-SemiCondensed.ttf: Noto Sans,Noto Sans SemCond:style=SemiCondensed,Regular
- NotoSansArabicUI-CondensedThin.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI Cn Th:style=Condensed Thin,Regular
- NotoSerifGeorgian-ExtraBold.ttf: Noto Serif Georgian,Noto Serif Georgian XBd:style=ExtraBold,Regular
- NotoSerifTamil-ExtraCondensedLight.ttf: Noto Serif Tamil,Noto Serif Tamil ExtCond Light:style=ExtraCondensed Light,Regular
- P052-Italic.otf: P052:style=Italic
- URWGothic-BookOblique.t1: URW Gothic:style=Book Oblique
- NotoSerifKhmer-SemiBold.ttf: Noto Serif Khmer,Noto Serif Khmer SemBd:style=SemiBold,Regular
- NotoSansDisplay-CondensedItalic.ttf: Noto Sans Display,Noto Sans Disp Cond:style=Condensed Italic,Italic
- NotoSansGeorgian-Medium.ttf: Noto Sans Georgian,Noto Sans Georgian Med:style=Medium,Regular
- NotoSerifMyanmar-SemiCondensed.ttf: Noto Serif Myanmar,Noto Serif Myanmar SemCond:style=SemiCondensed,Regular
- NotoSansArabicUI-SemiCondensedSemiBold.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI SmCn SmBd:style=SemiCondensed SemiBold,Regular
- NotoSansArabic-SemiCondensedLight.ttf: Noto Sans Arabic,Noto Sans Arabic SemCond Light:style=SemiCondensed Light,Regular
- NotoSerifGeorgian-SemiCondensedThin.ttf: Noto Serif Georgian,Noto Serif Georgian SmCn Th:style=SemiCondensed Thin,Regular
- NotoSansGeorgian-ExtraCondensedLight.ttf: Noto Sans Georgian,Noto Sans Georgian ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSansLao-ExtraCondensedExtraBold.ttf: Noto Sans Lao,Noto Sans Lao ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansArmenian-CondensedBlack.ttf: Noto Sans Armenian,Noto Sans Armenian Cond Blk:style=Condensed Black,Regular
- NotoSerif-SemiCondensed.ttf: Noto Serif,Noto Serif SemCond:style=SemiCondensed,Regular
- NotoSansThaiUI-SemiBold.ttf: Noto Sans Thai UI,Noto Sans Thai UI SemBd:style=SemiBold,Regular
- NotoSerifMyanmar-ExtraCondensedSemiBold.ttf: Noto Serif Myanmar,Noto Serif Myanmar ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSansBengali-Black.ttf: Noto Sans Bengali,Noto Sans Bengali Blk:style=Black,Regular
- NotoSansTaiLe-Regular.ttf: Noto Sans Tai Le:style=Regular
- NotoSansArmenian-SemiCondensed.ttf: Noto Sans Armenian,Noto Sans Armenian SemCond:style=SemiCondensed,Regular
- NotoSansSinhalaUI-ExtraCondensedExtraLight.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansMyanmar-SemiBold.ttf: Noto Sans Myanmar,Noto Sans Myanmar SemBd:style=SemiBold,Regular
- NotoSansArmenian-Black.ttf: Noto Sans Armenian,Noto Sans Armenian Blk:style=Black,Regular
- NotoSerifHebrew-Bold.ttf: Noto Serif Hebrew:style=Bold
- NotoSansMyanmarUI-Regular.ttf: Noto Sans Myanmar UI:style=Regular
- NotoSansDevanagari-Thin.ttf: Noto Sans Devanagari,Noto Sans Devanagari Th:style=Thin,Regular
- NotoSerifDisplay-BoldItalic.ttf: Noto Serif Display,Noto Serif Disp:style=Bold Italic
- n021024l.pfb: Nimbus Roman No9 L:style=Medium Italic
- NotoSansThai-CondensedExtraLight.ttf: Noto Sans Thai,Noto Sans Thai Cond ExtLt:style=Condensed ExtraLight,Regular
- DejaVuSans.ttf: DejaVu Sans:style=Book
- NotoSerifDisplay-SemiCondensedExtraBold.ttf: Noto Serif Display,Noto Serif Disp SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NimbusSans-Regular.otf: Nimbus Sans:style=Regular
- NotoSansArmenian-CondensedLight.ttf: Noto Sans Armenian,Noto Sans Armenian Cond Light:style=Condensed Light,Regular
- NotoSansLaoUI-ExtraCondensedMedium.ttf: Noto Sans Lao UI,Noto Sans Lao UI ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSerif-ExtraBold.ttf: Noto Serif,Noto Serif ExtBd:style=ExtraBold,Regular
- NotoSans-CondensedBlack.ttf: Noto Sans,Noto Sans Cond Blk:style=Condensed Black,Regular
- NotoSansArmenian-SemiCondensedThin.ttf: Noto Sans Armenian,Noto Sans Armenian SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSerifCJKkr-Light.otf: Noto Serif CJK KR,Noto Serif CJK KR Light:style=Light,Regular
- NotoSansGeorgian-CondensedExtraLight.ttf: Noto Sans Georgian,Noto Sans Georgian Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansOriya-Regular.ttf: Noto Sans Oriya:style=Regular
- NotoSerifThai-ExtraCondensedExtraBold.ttf: Noto Serif Thai,Noto Serif Thai ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansEthiopic-CondensedBlack.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic Cond Blk:style=Condensed Black,Regular
- NotoSerifArmenian-SemiCondensedBold.ttf: Noto Serif Armenian,Noto Serif Armenian SmCn:style=SemiCondensed Bold,Bold
- NotoSansSinhalaUI-SemiCondensedLight.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala SemCond Light:style=SemiCondensed Light,Regular
- NotoSansKhmer-ExtraCondensedLight.ttf: Noto Sans Khmer,Noto Sans Khmer ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSerifTamil-Thin.ttf: Noto Serif Tamil,Noto Serif Tamil Thin:style=Thin,Regular
- NotoSansDevanagariUI-CondensedExtraLight.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari Cn XLt:style=Condensed ExtraLight,Regular
- NotoSansTamilUI-SemiCondensed.ttf: Noto Sans Tamil UI,Noto Sans Tamil SemCond:style=SemiCondensed,Regular
- NotoSansMyanmar-CondensedSemiBold.ttf: Noto Sans Myanmar,Noto Sans Myanmar Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansSymbols-Black.ttf: Noto Sans Symbols,Noto Sans Symbols Blk:style=Black,Regular
- NotoSerifArmenian-Thin.ttf: Noto Serif Armenian,Noto Serif Armenian Th:style=Thin,Regular
- NotoSansGothic-Regular.ttf: Noto Sans Gothic:style=Regular
- NotoSansTamilUI-SemiCondensedSemiBold.ttf: Noto Sans Tamil UI,Noto Sans Tamil SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSerifArmenian-Black.ttf: Noto Serif Armenian,Noto Serif Armenian Bk:style=Black,Regular
- NotoSansTamil-ExtraCondensedExtraBold.ttf: Noto Sans Tamil,Noto Sans Tamil ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- URWBookman-DemiItalic.t1: URW Bookman:style=Demi Italic
- NotoSansDisplay-SemiCondensedItalic.ttf: Noto Sans Display,Noto Sans Disp SemCond:style=SemiCondensed Italic,Italic
- NotoSansKhmerUI-ExtraCondensedExtraLight.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansLaoUI-CondensedLight.ttf: Noto Sans Lao UI,Noto Sans Lao UI Cond Light:style=Condensed Light,Regular
- NotoSansSinhala-Bold.ttf: Noto Sans Sinhala:style=Bold
- NotoSerifKhmer-ExtraCondensedMedium.ttf: Noto Serif Khmer,Noto Serif Khmer ExtCond Med:style=ExtraCondensed Medium,Regular
- NimbusSansNarrow-Oblique.otf: Nimbus Sans Narrow:style=Oblique
- NotoSansSinhala-SemiCondensedBlack.ttf: Noto Sans Sinhala,Noto Sans Sinhala SemCond Blk:style=SemiCondensed Black,Regular
- NotoSerifTamil-ExtraCondensedExtraLight.ttf: Noto Serif Tamil,Noto Serif Tamil ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansArabic-ExtraCondensedThin.ttf: Noto Sans Arabic,Noto Sans Arabic ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSerifThai-CondensedSemiBold.ttf: Noto Serif Thai,Noto Serif Thai Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansSinhala-CondensedBlack.ttf: Noto Sans Sinhala,Noto Sans Sinhala Cond Blk:style=Condensed Black,Regular
- NotoSerif-SemiBoldItalic.ttf: Noto Serif,Noto Serif SemBd:style=SemiBold Italic,Italic
- NotoSansSinhalaUI-Black.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala Blk:style=Black,Regular
- NotoSerifCJKtc-Light.otf: Noto Serif CJK TC,Noto Serif CJK TC Light:style=Light,Regular
- NotoSerifEthiopic-ExtraCondensedExtraLight.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic XCn XLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansTamil-ExtraCondensedSemiBold.ttf: Noto Sans Tamil,Noto Sans Tamil ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSerifThai-ExtraCondensedLight.ttf: Noto Serif Thai,Noto Serif Thai ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSerifDisplay-ExtraCondensedBlack.ttf: Noto Serif Display,Noto Serif Disp ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansThaiUI-CondensedThin.ttf: Noto Sans Thai UI,Noto Sans Thai UI Cond Thin:style=Condensed Thin,Regular
- NotoSansBengali-ExtraBold.ttf: Noto Sans Bengali,Noto Sans Bengali ExtBd:style=ExtraBold,Regular
- NimbusSans-Regular.t1: Nimbus Sans:style=Regular
- NotoSansMyanmar-Bold.ttf: Noto Sans Myanmar:style=Bold
- NotoSansEthiopic-ExtraCondensedBold.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic ExtCond:style=ExtraCondensed Bold,Bold
- NotoSansEthiopic-Light.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic Light:style=Light,Regular
- NotoSansDevanagariUI-ExtraCondensedLight.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari XCn Lt:style=ExtraCondensed Light,Regular
- NotoSansBengaliUI-ExtraBold.ttf: Noto Sans Bengali UI,Noto Sans Bengali ExtBd:style=ExtraBold,Regular
- NotoSerifThai-Bold.ttf: Noto Serif Thai:style=Bold
- NotoSerifGeorgian-SemiCondensedBlack.ttf: Noto Serif Georgian,Noto Serif Georgian SmCn Bk:style=SemiCondensed Black,Regular
- NotoSansSinhala-SemiBold.ttf: Noto Sans Sinhala,Noto Sans Sinhala SemBd:style=SemiBold,Regular
- NotoSansLao-ExtraCondensedSemiBold.ttf: Noto Sans Lao,Noto Sans Lao ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- C059-Roman.otf: C059:style=Roman
- NotoSansArmenian-CondensedSemiBold.ttf: Noto Sans Armenian,Noto Sans Armenian Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansTamilUI-ExtraLight.ttf: Noto Sans Tamil UI,Noto Sans Tamil ExtLt:style=ExtraLight,Regular
- NotoSansCherokee-Thin.ttf: Noto Sans Cherokee,Noto Sans Cherokee Thin:style=Thin,Regular
- NotoSansDisplay-SemiBold.ttf: Noto Sans Display,Noto Sans Disp SemBd:style=SemiBold,Regular
- NotoSansDisplay-ExtraLightItalic.ttf: Noto Sans Display,Noto Sans Disp ExtLt:style=ExtraLight Italic,Italic
- NotoSansLinearB-Regular.ttf: Noto Sans Linear B:style=Regular
- NotoSansSinhalaUI-ExtraCondensedLight.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSerifEthiopic-Regular.ttf: Noto Serif Ethiopic:style=Regular
- NotoSansArabic-CondensedBlack.ttf: Noto Sans Arabic,Noto Sans Arabic Cond Blk:style=Condensed Black,Regular
- NotoSerifThai-ExtraCondensedThin.ttf: Noto Serif Thai,Noto Serif Thai ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSerifHebrew-Condensed.ttf: Noto Serif Hebrew,Noto Serif Hebrew Cond:style=Condensed,Regular
- NotoSansArabic-SemiCondensed.ttf: Noto Sans Arabic,Noto Sans Arabic SemCond:style=SemiCondensed,Regular
- NotoSansMyanmar-ExtraCondensedSemiBold.ttf: Noto Sans Myanmar,Noto Sans Myanmar ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSerifLao-CondensedExtraBold.ttf: Noto Serif Lao,Noto Serif Lao Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansDevanagari-SemiCondensedBlack.ttf: Noto Sans Devanagari,Noto Sans Devanagari SmCn Bk:style=SemiCondensed Black,Regular
- NotoSansKhmer-CondensedLight.ttf: Noto Sans Khmer,Noto Sans Khmer Cond Light:style=Condensed Light,Regular
- NotoSerifDisplay-SemiCondensedThin.ttf: Noto Serif Display,Noto Serif Disp SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSansCJKjp-Thin.otf: Noto Sans CJK JP,Noto Sans CJK JP Thin:style=Thin,Regular
- NotoSansCJKkr-Light.otf: Noto Sans CJK KR,Noto Sans CJK KR Light:style=Light,Regular
- NotoSerifGeorgian-ExtraCondensed.ttf: Noto Serif Georgian,Noto Serif Georgian XCn:style=ExtraCondensed,Regular
- n021004l.pfb: Nimbus Roman No9 L:style=Medium
- NotoSerifHebrew-SemiCondensedExtraBold.ttf: Noto Serif Hebrew,Noto Serif Hebrew SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansSinhala-SemiCondensedExtraBold.ttf: Noto Sans Sinhala,Noto Sans Sinhala SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansKhmer-CondensedExtraLight.ttf: Noto Sans Khmer,Noto Sans Khmer Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansHebrew-ExtraBold.ttf: Noto Sans Hebrew,Noto Sans Hebrew ExtBd:style=ExtraBold,Regular
- NotoSansMyanmar-Condensed.ttf: Noto Sans Myanmar,Noto Sans Myanmar Cond:style=Condensed,Regular
- NotoSerifDisplay-ExtraCondensedItalic.ttf: Noto Serif Display,Noto Serif Disp ExtCond:style=ExtraCondensed Italic,Italic
- NotoSerifArmenian-Medium.ttf: Noto Serif Armenian,Noto Serif Armenian Md:style=Medium,Regular
- NimbusMonoPS-BoldItalic.otf: Nimbus Mono PS:style=Bold Italic
- NotoSansHebrew-ExtraCondensedLight.ttf: Noto Sans Hebrew,Noto Sans Hebrew ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSerifEthiopic-SemiBold.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic SmBd:style=SemiBold,Regular
- NotoSerifTamil-SemiCondensedThin.ttf: Noto Serif Tamil,Noto Serif Tamil SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSerifArmenian-ExtraCondensed.ttf: Noto Serif Armenian,Noto Serif Armenian XCn:style=ExtraCondensed,Regular
- NotoSansLaoUI-Light.ttf: Noto Sans Lao UI,Noto Sans Lao UI Light:style=Light,Regular
- NotoSerif-MediumItalic.ttf: Noto Serif,Noto Serif Med:style=Medium Italic,Italic
- NotoSansMyanmar-ExtraCondensedThin.ttf: Noto Sans Myanmar,Noto Sans Myanmar ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSansSinhalaUI-CondensedThin.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala Cond Thin:style=Condensed Thin,Regular
- NotoSerif-SemiCondensedExtraLightItalic.ttf: Noto Serif,Noto Serif SemCond ExtLt:style=SemiCondensed ExtraLight Italic,Italic
- NotoSerifHebrew-CondensedSemiBold.ttf: Noto Serif Hebrew,Noto Serif Hebrew Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansSinhala-ExtraCondensedBold.ttf: Noto Sans Sinhala,Noto Sans Sinhala ExtCond:style=ExtraCondensed Bold,Bold
- URWGothic-DemiOblique.t1: URW Gothic:style=Demi Oblique
- NotoSerifDisplay-SemiCondensedBlackItalic.ttf: Noto Serif Display,Noto Serif Disp SemCond Blk:style=SemiCondensed Black Italic,Italic
- NotoSerifSinhala-SemiBold.ttf: Noto Serif Sinhala,Noto Serif Sinhala SemBd:style=SemiBold,Regular
- NotoSerifEthiopic-ExtraCondensed.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic XCn:style=ExtraCondensed,Regular
- NotoSansEthiopic-SemiCondensedMedium.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic SemCond Med:style=SemiCondensed Medium,Regular
- NotoSansMyanmarUI-ExtraCondensedLight.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI XCn Lt:style=ExtraCondensed Light,Regular
- NotoSerifThai-Black.ttf: Noto Serif Thai,Noto Serif Thai Blk:style=Black,Regular
- NotoSerifGeorgian-CondensedSemiBold.ttf: Noto Serif Georgian,Noto Serif Georgian Cn SmBd:style=Condensed SemiBold,Regular
- NotoSansDisplay-ExtraBold.ttf: Noto Sans Display,Noto Sans Disp ExtBd:style=ExtraBold,Regular
- NotoSerifDisplay-SemiCondensedMediumItalic.ttf: Noto Serif Display,Noto Serif Disp SemCond Med:style=SemiCondensed Medium Italic,Italic
- NotoSerifThai-CondensedMedium.ttf: Noto Serif Thai,Noto Serif Thai Cond Med:style=Condensed Medium,Regular
- p052023l.pfb: URW Palladio L:style=Italic
- n022003l.pfb: Nimbus Mono L:style=Regular
- NotoSerifSinhala-Bold.ttf: Noto Serif Sinhala:style=Bold
- NotoSansLaoUI-Condensed.ttf: Noto Sans Lao UI,Noto Sans Lao UI Cond:style=Condensed,Regular
- NotoSerifTelugu-Bold.ttf: Noto Serif Telugu:style=Bold
- NotoSansArabicUI-SemiCondensedThin.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI SmCn Th:style=SemiCondensed Thin,Regular
- NotoSansGurmukhi-Bold.ttf: Noto Sans Gurmukhi:style=Bold
- NotoSansLao-CondensedThin.ttf: Noto Sans Lao,Noto Sans Lao Cond Thin:style=Condensed Thin,Regular
- NotoSansMono-SemiCondensedThin.ttf: Noto Sans Mono,Noto Sans Mono SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSansDisplay-ExtraBoldItalic.ttf: Noto Sans Display,Noto Sans Disp ExtBd:style=ExtraBold Italic,Italic
- NotoSansHebrew-Thin.ttf: Noto Sans Hebrew,Noto Sans Hebrew Thin:style=Thin,Regular
- NotoSansKhmer-Light.ttf: Noto Sans Khmer,Noto Sans Khmer Light:style=Light,Regular
- NotoSansTamil-ExtraCondensedExtraLight.ttf: Noto Sans Tamil,Noto Sans Tamil ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSerifSinhala-Black.ttf: Noto Serif Sinhala,Noto Serif Sinhala Blk:style=Black,Regular
- NotoSansLao-Thin.ttf: Noto Sans Lao,Noto Sans Lao Thin:style=Thin,Regular
- NotoSans-CondensedBlackItalic.ttf: Noto Sans,Noto Sans Cond Blk:style=Condensed Black Italic,Italic
- NotoSerifLao-SemiCondensedSemiBold.ttf: Noto Serif Lao,Noto Serif Lao SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSans-ExtraCondensed.ttf: Noto Sans,Noto Sans ExtCond:style=ExtraCondensed,Regular
- NotoSansDisplay-CondensedBold.ttf: Noto Sans Display,Noto Sans Disp Cond:style=Condensed Bold,Bold
- NotoSansLao-ExtraCondensedLight.ttf: Noto Sans Lao,Noto Sans Lao ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSerifEthiopic-ExtraCondensedBold.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic XCn:style=ExtraCondensed Bold,Bold
- NotoSansArabic-CondensedSemiBold.ttf: Noto Sans Arabic,Noto Sans Arabic Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansThaiUI-Thin.ttf: Noto Sans Thai UI,Noto Sans Thai UI Thin:style=Thin,Regular
- NotoSansLao-SemiCondensedBold.ttf: Noto Sans Lao,Noto Sans Lao SemCond:style=SemiCondensed Bold,Bold
- NotoSerifMyanmar-Regular.ttf: Noto Serif Myanmar:style=Regular
- NotoSansMyanmarUI-ExtraCondensedMedium.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI XCn Md:style=ExtraCondensed Medium,Regular
- NotoSansDevanagari-SemiCondensedSemiBold.ttf: Noto Sans Devanagari,Noto Sans Devanagari SmCn SmBd:style=SemiCondensed SemiBold,Regular
- NotoSansThaiUI-SemiCondensedBold.ttf: Noto Sans Thai UI,Noto Sans Thai UI SemCond:style=SemiCondensed Bold,Bold
- NotoSerifGeorgian-ExtraCondensedLight.ttf: Noto Serif Georgian,Noto Serif Georgian XCn Lt:style=ExtraCondensed Light,Regular
- NotoSansShavian-Regular.ttf: Noto Sans Shavian:style=Regular
- NotoSansDevanagariUI-SemiCondensedSemiBold.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari SmCn SmBd:style=SemiCondensed SemiBold,Regular
- NotoSansArabic-ExtraCondensedBlack.ttf: Noto Sans Arabic,Noto Sans Arabic ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansGeorgian-CondensedMedium.ttf: Noto Sans Georgian,Noto Sans Georgian Cond Med:style=Condensed Medium,Regular
- NotoSerifHebrew-SemiCondensedSemiBold.ttf: Noto Serif Hebrew,Noto Serif Hebrew SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansArabic-CondensedLight.ttf: Noto Sans Arabic,Noto Sans Arabic Cond Light:style=Condensed Light,Regular
- NotoSansLaoUI-SemiCondensedMedium.ttf: Noto Sans Lao UI,Noto Sans Lao UI SemCond Med:style=SemiCondensed Medium,Regular
- NotoSansOlChiki-Regular.ttf: Noto Sans Ol Chiki:style=Regular
- NotoSerif-ExtraCondensedSemiBold.ttf: Noto Serif,Noto Serif ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSerifArmenian-CondensedBlack.ttf: Noto Serif Armenian,Noto Serif Armenian Cn Bk:style=Condensed Black,Regular
- NotoSansDevanagari-Light.ttf: Noto Sans Devanagari,Noto Sans Devanagari Lt:style=Light,Regular
- NotoSansTamilUI-CondensedMedium.ttf: Noto Sans Tamil UI,Noto Sans Tamil Cond Med:style=Condensed Medium,Regular
- NotoSerifDisplay-ExtraCondensedSemiBold.ttf: Noto Serif Display,Noto Serif Disp ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSansArabicUI-ExtraLight.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI XLt:style=ExtraLight,Regular
- NotoSansMyanmarUI-SemiCondensedBlack.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI SmCn Bk:style=SemiCondensed Black,Regular
- NotoSansSinhala-Black.ttf: Noto Sans Sinhala,Noto Sans Sinhala Blk:style=Black,Regular
- NotoSerifEthiopic-SemiCondensedBlack.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic SmCn Bk:style=SemiCondensed Black,Regular
- NotoSansThai-SemiCondensedBold.ttf: Noto Sans Thai,Noto Sans Thai SemCond:style=SemiCondensed Bold,Bold
- NotoSansKhmer-SemiCondensedLight.ttf: Noto Sans Khmer,Noto Sans Khmer SemCond Light:style=SemiCondensed Light,Regular
- NotoSansArmenian-ExtraBold.ttf: Noto Sans Armenian,Noto Sans Armenian ExtBd:style=ExtraBold,Regular
- NotoSansDevanagariUI-Medium.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari Md:style=Medium,Regular
- NotoSerifHebrew-SemiCondensedBlack.ttf: Noto Serif Hebrew,Noto Serif Hebrew SemCond Blk:style=SemiCondensed Black,Regular
- NotoSansMonoCJKtc-Regular.otf: Noto Sans Mono CJK TC,Noto Sans Mono CJK TC Regular:style=Regular
- NotoSansNewTaiLue-Regular.ttf: Noto Sans New Tai Lue:style=Regular
- z003034l.pfb: URW Chancery L:style=Medium Italic
- NotoSansSinhala-ExtraCondensedExtraLight.ttf: Noto Sans Sinhala,Noto Sans Sinhala ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSerif-ExtraCondensedLight.ttf: Noto Serif,Noto Serif ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSerifCJKtc-Medium.otf: Noto Serif CJK TC,Noto Serif CJK TC Medium:style=Medium,Regular
- NotoSerifGeorgian-SemiCondensed.ttf: Noto Serif Georgian,Noto Serif Georgian SmCn:style=SemiCondensed,Regular
- NotoSansGeorgian-ExtraCondensedMedium.ttf: Noto Sans Georgian,Noto Sans Georgian ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansArmenian-Bold.ttf: Noto Sans Armenian:style=Bold
- NotoSerifDisplay-CondensedMedium.ttf: Noto Serif Display,Noto Serif Disp Cond Med:style=Condensed Medium,Regular
- NotoSerifTamil-SemiCondensedBold.ttf: Noto Serif Tamil,Noto Serif Tamil SemCond:style=SemiCondensed Bold,Bold
- NotoSans-ExtraCondensedMediumItalic.ttf: Noto Sans,Noto Sans ExtCond Med:style=ExtraCondensed Medium Italic,Italic
- NotoSansTagalog-Regular.ttf: Noto Sans Tagalog:style=Regular
- NotoSansHanunoo-Regular.ttf: Noto Sans Hanunoo:style=Regular
- URWBookman-LightItalic.t1: URW Bookman:style=Light Italic
- NotoSerifTamil-Light.ttf: Noto Serif Tamil,Noto Serif Tamil Light:style=Light,Regular
- NotoSerifKhmer-SemiCondensedSemiBold.ttf: Noto Serif Khmer,Noto Serif Khmer SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NimbusSansNarrow-BoldOblique.otf: Nimbus Sans Narrow:style=Bold Oblique
- NotoSansKhmer-CondensedExtraBold.ttf: Noto Sans Khmer,Noto Sans Khmer Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansGeorgian-CondensedBold.ttf: Noto Sans Georgian,Noto Sans Georgian Cond:style=Condensed Bold,Bold
- NotoSansLao-Condensed.ttf: Noto Sans Lao,Noto Sans Lao Cond:style=Condensed,Regular
- NotoSansMono-ExtraCondensedBlack.ttf: Noto Sans Mono,Noto Sans Mono ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansHebrew-SemiCondensed.ttf: Noto Sans Hebrew,Noto Sans Hebrew SemCond:style=SemiCondensed,Regular
- NotoSerifMyanmar-ExtraCondensed.ttf: Noto Serif Myanmar,Noto Serif Myanmar ExtCond:style=ExtraCondensed,Regular
- NotoSansLao-CondensedExtraLight.ttf: Noto Sans Lao,Noto Sans Lao Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansTamilUI-Condensed.ttf: Noto Sans Tamil UI,Noto Sans Tamil Cond:style=Condensed,Regular
- NotoSansMonoCJKtc-Bold.otf: Noto Sans Mono CJK TC,Noto Sans Mono CJK TC Bold:style=Bold,Regular
- NotoSansMyanmarUI-SemiCondensedThin.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI SmCn Th:style=SemiCondensed Thin,Regular
- NotoSerif-SemiCondensedBold.ttf: Noto Serif,Noto Serif SemCond:style=SemiCondensed Bold,Bold
- NotoSansDisplay-ExtraCondensedMediumItalic.ttf: Noto Sans Display,Noto Sans Disp ExtCond Med:style=ExtraCondensed Medium Italic,Italic
- NotoSansBengaliUI-Regular.ttf: Noto Sans Bengali UI:style=Regular
- NotoColorEmoji.ttf: Noto Color Emoji:style=Regular
- NotoSansCham-ExtraBold.ttf: Noto Sans Cham,Noto Sans Cham ExtBd:style=ExtraBold,Regular
- NotoSansEthiopic-ExtraCondensedLight.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSansCham-Light.ttf: Noto Sans Cham,Noto Sans Cham Light:style=Light,Regular
- NotoSerifMyanmar-SemiCondensedBold.ttf: Noto Serif Myanmar,Noto Serif Myanmar SemCond:style=SemiCondensed Bold,Bold
- NotoSansGeorgian-SemiCondensedLight.ttf: Noto Sans Georgian,Noto Sans Georgian SemCond Light:style=SemiCondensed Light,Regular
- NotoSerifHebrew-Thin.ttf: Noto Serif Hebrew,Noto Serif Hebrew Thin:style=Thin,Regular
- NotoSerifHebrew-Black.ttf: Noto Serif Hebrew,Noto Serif Hebrew Blk:style=Black,Regular
- NotoSerifGeorgian-ExtraCondensedSemiBold.ttf: Noto Serif Georgian,Noto Serif Georgian XCn SmBd:style=ExtraCondensed SemiBold,Regular
- NotoSansLaoUI-ExtraBold.ttf: Noto Sans Lao UI,Noto Sans Lao UI ExtBd:style=ExtraBold,Regular
- NotoSerifDisplay-ExtraCondensedExtraBold.ttf: Noto Serif Display,Noto Serif Disp ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSerifGeorgian-Regular.ttf: Noto Serif Georgian:style=Regular
- NotoSerifDisplay-CondensedItalic.ttf: Noto Serif Display,Noto Serif Disp Cond:style=Condensed Italic,Italic
- NotoSansTamil-Thin.ttf: Noto Sans Tamil,Noto Sans Tamil Thin:style=Thin,Regular
- NotoSans-CondensedExtraBold.ttf: Noto Sans,Noto Sans Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansTelugu-Regular.ttf: Noto Sans Telugu:style=Regular
- NotoSansLaoUI-Regular.ttf: Noto Sans Lao UI:style=Regular
- NotoSansGeorgian-Bold.ttf: Noto Sans Georgian:style=Bold
- NotoSansArmenian-ExtraCondensedMedium.ttf: Noto Sans Armenian,Noto Sans Armenian ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansLaoUI-CondensedBold.ttf: Noto Sans Lao UI,Noto Sans Lao UI Cond:style=Condensed Bold,Bold
- NotoSerifDisplay-MediumItalic.ttf: Noto Serif Display,Noto Serif Disp Med:style=Medium Italic,Italic
- NotoSansArabicUI-CondensedBold.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI Cn:style=Condensed Bold,Bold
- NotoSansBamum-Regular.ttf: Noto Sans Bamum:style=Regular
- NotoSerifCJKtc-Regular.otf: Noto Serif CJK TC:style=Regular
- NotoSerif-ExtraCondensedItalic.ttf: Noto Serif,Noto Serif ExtCond:style=ExtraCondensed Italic,Italic
- NotoSerifThai-CondensedExtraLight.ttf: Noto Serif Thai,Noto Serif Thai Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSerifThai-CondensedLight.ttf: Noto Serif Thai,Noto Serif Thai Cond Light:style=Condensed Light,Regular
- NotoSansGeorgian-ExtraCondensed.ttf: Noto Sans Georgian,Noto Sans Georgian ExtCond:style=ExtraCondensed,Regular
- NotoSansCJKkr-Thin.otf: Noto Sans CJK KR,Noto Sans CJK KR Thin:style=Thin,Regular
- NotoSansSinhalaUI-SemiBold.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala SemBd:style=SemiBold,Regular
- NotoSerif-SemiCondensedBlack.ttf: Noto Serif,Noto Serif SemCond Blk:style=SemiCondensed Black,Regular
- NotoSansBengali-Medium.ttf: Noto Sans Bengali,Noto Sans Bengali Med:style=Medium,Regular
- NotoSansTamilUI-ExtraCondensedExtraLight.ttf: Noto Sans Tamil UI,Noto Sans Tamil ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansCJKkr-Medium.otf: Noto Sans CJK KR,Noto Sans CJK KR Medium:style=Medium,Regular
- NotoSansLao-Light.ttf: Noto Sans Lao,Noto Sans Lao Light:style=Light,Regular
- NotoSansHebrew-ExtraCondensedBlack.ttf: Noto Sans Hebrew,Noto Sans Hebrew ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSerifGeorgian-Light.ttf: Noto Serif Georgian,Noto Serif Georgian Lt:style=Light,Regular
- NotoSansLao-CondensedBlack.ttf: Noto Sans Lao,Noto Sans Lao Cond Blk:style=Condensed Black,Regular
- NotoSansMyanmar-SemiCondensedLight.ttf: Noto Sans Myanmar,Noto Sans Myanmar SemCond Light:style=SemiCondensed Light,Regular
- NotoSerifHebrew-Regular.ttf: Noto Serif Hebrew:style=Regular
- NotoSansThai-SemiBold.ttf: Noto Sans Thai,Noto Sans Thai SemBd:style=SemiBold,Regular
- NotoSerif-ExtraCondensedBold.ttf: Noto Serif,Noto Serif ExtCond:style=ExtraCondensed Bold,Bold
- NotoSansEthiopic-CondensedBold.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic Cond:style=Condensed Bold,Bold
- NotoSerifGeorgian-Thin.ttf: Noto Serif Georgian,Noto Serif Georgian Th:style=Thin,Regular
- NotoSerifHebrew-ExtraCondensedSemiBold.ttf: Noto Serif Hebrew,Noto Serif Hebrew ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSansThai-SemiCondensedThin.ttf: Noto Sans Thai,Noto Sans Thai SemCond Thin:style=SemiCondensed Thin,Regular
- c059013l.pfb: Century Schoolbook L:style=Roman
- NotoSans-SemiCondensedBold.ttf: Noto Sans,Noto Sans SemCond:style=SemiCondensed Bold,Bold
- NotoSansEthiopic-ExtraCondensedExtraLight.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansGeorgian-Black.ttf: Noto Sans Georgian,Noto Sans Georgian Blk:style=Black,Regular
- NimbusSansNarrow-BoldOblique.t1: Nimbus Sans Narrow:style=Bold Oblique
- NotoSerif-SemiCondensedLight.ttf: Noto Serif,Noto Serif SemCond Light:style=SemiCondensed Light,Regular
- NotoSansDisplay-CondensedLightItalic.ttf: Noto Sans Display,Noto Sans Disp Cond Light:style=Condensed Light Italic,Italic
- NotoSerifMyanmar-SemiCondensedExtraLight.ttf: Noto Serif Myanmar,Noto Serif Myanmar SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSerifMyanmar-CondensedLight.ttf: Noto Serif Myanmar,Noto Serif Myanmar Cond Light:style=Condensed Light,Regular
- NotoSansKhmer-SemiCondensedMedium.ttf: Noto Sans Khmer,Noto Sans Khmer SemCond Med:style=SemiCondensed Medium,Regular
- NotoNaskhArabicUI-Regular.ttf: Noto Naskh Arabic UI:style=Regular
- NotoSansArmenian-ExtraCondensedExtraLight.ttf: Noto Sans Armenian,Noto Sans Armenian ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSerifKhmer-ExtraCondensedSemiBold.ttf: Noto Serif Khmer,Noto Serif Khmer ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NimbusSans-Bold.otf: Nimbus Sans:style=Bold
- NotoSansArmenian-SemiCondensedLight.ttf: Noto Sans Armenian,Noto Sans Armenian SemCond Light:style=SemiCondensed Light,Regular
- NotoSansTamil-CondensedSemiBold.ttf: Noto Sans Tamil,Noto Sans Tamil Cond SemBd:style=Condensed SemiBold,Regular
- NotoSerifLao-SemiCondensedLight.ttf: Noto Serif Lao,Noto Serif Lao SemCond Light:style=SemiCondensed Light,Regular
- NotoSansSinhala-ExtraCondensed.ttf: Noto Sans Sinhala,Noto Sans Sinhala ExtCond:style=ExtraCondensed,Regular
- NotoSerifCJKsc-Medium.otf: Noto Serif CJK SC,Noto Serif CJK SC Medium:style=Medium,Regular
- NotoSansMono-ExtraCondensedMedium.ttf: Noto Sans Mono,Noto Sans Mono ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansThaiUI-ExtraCondensedBlack.ttf: Noto Sans Thai UI,Noto Sans Thai UI ExtCond Blk:style=ExtraCondensed Black,Regular
- NimbusMonoPS-Italic.t1: Nimbus Mono PS:style=Italic
- NotoSansDevanagari-Bold.ttf: Noto Sans Devanagari:style=Bold
- NotoSerif-SemiCondensedExtraBold.ttf: Noto Serif,Noto Serif SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansDisplay-SemiCondensedBold.ttf: Noto Sans Display,Noto Sans Disp SemCond:style=SemiCondensed Bold,Bold
- NotoSansCJKjp-DemiLight.otf: Noto Sans CJK JP,Noto Sans CJK JP DemiLight:style=DemiLight,Regular
- NotoSansEthiopic-SemiCondensed.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic SemCond:style=SemiCondensed,Regular
- NotoSansKhmer-CondensedBlack.ttf: Noto Sans Khmer,Noto Sans Khmer Cond Blk:style=Condensed Black,Regular
- NotoSansSinhala-SemiCondensed.ttf: Noto Sans Sinhala,Noto Sans Sinhala SemCond:style=SemiCondensed,Regular
- NotoSerifMyanmar-SemiCondensedThin.ttf: Noto Serif Myanmar,Noto Serif Myanmar SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSerifTamil-Black.ttf: Noto Serif Tamil,Noto Serif Tamil Blk:style=Black,Regular
- NotoSerifDisplay-ExtraCondensedThinItalic.ttf: Noto Serif Display,Noto Serif Disp ExtCond Thin:style=ExtraCondensed Thin Italic,Italic
- NotoSerifDisplay-Condensed.ttf: Noto Serif Display,Noto Serif Disp Cond:style=Condensed,Regular
- NotoSansMyanmar-Medium.ttf: Noto Sans Myanmar,Noto Sans Myanmar Med:style=Medium,Regular
- NotoSansLao-CondensedMedium.ttf: Noto Sans Lao,Noto Sans Lao Cond Med:style=Condensed Medium,Regular
- NotoSansMono-SemiCondensedMedium.ttf: Noto Sans Mono,Noto Sans Mono SemCond Med:style=SemiCondensed Medium,Regular
- NotoSansCJKsc-Thin.otf: Noto Sans CJK SC,Noto Sans CJK SC Thin:style=Thin,Regular
- NotoSansDisplay-Italic.ttf: Noto Sans Display,Noto Sans Disp:style=Italic
- NotoSansThaana-Regular.ttf: Noto Sans Thaana:style=Regular
- NotoSerifThai-SemiCondensed.ttf: Noto Serif Thai,Noto Serif Thai SemCond:style=SemiCondensed,Regular
- NimbusRoman-BoldItalic.t1: Nimbus Roman:style=Bold Italic
- NotoSansArabicUI-SemiCondensed.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI SmCn:style=SemiCondensed,Regular
- NotoSansSinhala-CondensedMedium.ttf: Noto Sans Sinhala,Noto Sans Sinhala Cond Med:style=Condensed Medium,Regular
- NotoSerifDisplay-CondensedLightItalic.ttf: Noto Serif Display,Noto Serif Disp Cond Light:style=Condensed Light Italic,Italic
- NotoSerifDisplay-CondensedBoldItalic.ttf: Noto Serif Display,Noto Serif Disp Cond:style=Condensed Bold Italic,Bold Italic
- NotoSansCherokee-ExtraLight.ttf: Noto Sans Cherokee,Noto Sans Cherokee ExtLt:style=ExtraLight,Regular
- NotoSansTelugu-Bold.ttf: Noto Sans Telugu:style=Bold
- NotoSansHebrew-SemiCondensedBlack.ttf: Noto Sans Hebrew,Noto Sans Hebrew SemCond Blk:style=SemiCondensed Black,Regular
- NotoSansBengali-ExtraLight.ttf: Noto Sans Bengali,Noto Sans Bengali ExtLt:style=ExtraLight,Regular
- NotoSerifDisplay-CondensedExtraBoldItalic.ttf: Noto Serif Display,Noto Serif Disp Cond ExtBd:style=Condensed ExtraBold Italic,Italic
- NotoSansTaiViet-Regular.ttf: Noto Sans Tai Viet:style=Regular
- NotoSansThai-Regular.ttf: Noto Sans Thai:style=Regular
- NotoSansCJKsc-Bold.otf: Noto Sans CJK SC,Noto Sans CJK SC Bold:style=Bold,Regular
- NotoSerifLao-ExtraCondensedLight.ttf: Noto Serif Lao,Noto Serif Lao ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSansArmenian-ExtraCondensedExtraBold.ttf: Noto Sans Armenian,Noto Sans Armenian ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSerifTamil-ExtraCondensedSemiBold.ttf: Noto Serif Tamil,Noto Serif Tamil ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSerifEthiopic-ExtraCondensedBlack.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic XCn Bk:style=ExtraCondensed Black,Regular
- NotoSansTamil-CondensedMedium.ttf: Noto Sans Tamil,Noto Sans Tamil Cond Med:style=Condensed Medium,Regular
- NotoSansBuhid-Regular.ttf: Noto Sans Buhid:style=Regular
- NotoSansTamilUI-Light.ttf: Noto Sans Tamil UI,Noto Sans Tamil Light:style=Light,Regular
- NotoSerifKhmer-Thin.ttf: Noto Serif Khmer,Noto Serif Khmer Thin:style=Thin,Regular
- NotoSansGeorgian-Thin.ttf: Noto Sans Georgian,Noto Sans Georgian Thin:style=Thin,Regular
- NotoSansCherokee-ExtraBold.ttf: Noto Sans Cherokee,Noto Sans Cherokee ExtBd:style=ExtraBold,Regular
- NotoSansKhmerUI-SemiCondensed.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI SemCond:style=SemiCondensed,Regular
- NotoSerifArmenian-SemiCondensedExtraBold.ttf: Noto Serif Armenian,Noto Serif Armenian SmCn XBd:style=SemiCondensed ExtraBold,Regular
- Z003-MediumItalic.otf: Z003:style=Medium Italic
- NotoSansSymbols-Bold.ttf: Noto Sans Symbols:style=Bold
- NimbusSans-BoldItalic.otf: Nimbus Sans:style=Bold Italic
- NotoSansGeorgian-CondensedSemiBold.ttf: Noto Sans Georgian,Noto Sans Georgian Cond SemBd:style=Condensed SemiBold,Regular
- URWGothic-Book.otf: URW Gothic:style=Book
- NotoSansEthiopic-SemiCondensedLight.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic SemCond Light:style=SemiCondensed Light,Regular
- NotoSansMono-SemiCondensedLight.ttf: Noto Sans Mono,Noto Sans Mono SemCond Light:style=SemiCondensed Light,Regular
- NotoSansTamilUI-SemiBold.ttf: Noto Sans Tamil UI,Noto Sans Tamil SemBd:style=SemiBold,Regular
- NotoSerifThai-Condensed.ttf: Noto Serif Thai,Noto Serif Thai Cond:style=Condensed,Regular
- NotoSerif-CondensedItalic.ttf: Noto Serif,Noto Serif Cond:style=Condensed Italic,Italic
- NotoSansDisplay-Black.ttf: Noto Sans Display,Noto Sans Disp Blk:style=Black,Regular
- NotoSansSinhala-CondensedExtraBold.ttf: Noto Sans Sinhala,Noto Sans Sinhala Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansSyriacEastern-Regular.ttf: Noto Sans Syriac Eastern:style=Regular
- NotoSansArabicUI-SemiCondensedLight.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI SmCn Lt:style=SemiCondensed Light,Regular
- NotoSerifLao-Black.ttf: Noto Serif Lao,Noto Serif Lao Blk:style=Black,Regular
- NotoSans-CondensedBold.ttf: Noto Sans,Noto Sans Cond:style=Condensed Bold,Bold
- NotoSansDisplay-CondensedMedium.ttf: Noto Sans Display,Noto Sans Disp Cond Med:style=Condensed Medium,Regular
- NotoSansGujaratiUI-Bold.ttf: Noto Sans Gujarati UI:style=Bold
- NotoSerif-SemiCondensedThin.ttf: Noto Serif,Noto Serif SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSansThaiUI-Medium.ttf: Noto Sans Thai UI,Noto Sans Thai UI Med:style=Medium,Regular
- NotoSerifEthiopic-CondensedExtraLight.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic Cn XLt:style=Condensed ExtraLight,Regular
- NotoSerif-ExtraCondensedMedium.ttf: Noto Serif,Noto Serif ExtCond Med:style=ExtraCondensed Medium,Regular
- d050000l.pfb: Dingbats:style=Regular
- NotoSerifCJKsc-Bold.otf: Noto Serif CJK SC:style=Bold
- NotoKufiArabic-Regular.ttf: Noto Kufi Arabic:style=Regular
- NotoSansGeorgian-ExtraCondensedExtraLight.ttf: Noto Sans Georgian,Noto Sans Georgian ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansMono-CondensedMedium.ttf: Noto Sans Mono,Noto Sans Mono Cond Med:style=Condensed Medium,Regular
- NotoSerifDisplay-LightItalic.ttf: Noto Serif Display,Noto Serif Disp Light:style=Light Italic,Italic
- NotoSansKhmer-ExtraCondensed.ttf: Noto Sans Khmer,Noto Sans Khmer ExtCond:style=ExtraCondensed,Regular
- NotoSansDisplay-ExtraCondensedMedium.ttf: Noto Sans Display,Noto Sans Disp ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansSinhala-ExtraLight.ttf: Noto Sans Sinhala,Noto Sans Sinhala ExtLt:style=ExtraLight,Regular
- NotoSansSundanese-Regular.ttf: Noto Sans Sundanese:style=Regular
- NotoSansGeorgian-SemiCondensedThin.ttf: Noto Sans Georgian,Noto Sans Georgian SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSansCJKjp-Medium.otf: Noto Sans CJK JP,Noto Sans CJK JP Medium:style=Medium,Regular
- NotoSansEthiopic-SemiBold.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic SemBd:style=SemiBold,Regular
- NotoSansCham-ExtraLight.ttf: Noto Sans Cham,Noto Sans Cham ExtLt:style=ExtraLight,Regular
- NotoSansLepcha-Regular.ttf: Noto Sans Lepcha:style=Regular
- NotoSansEthiopic-Black.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic Blk:style=Black,Regular
- NotoSansThaiUI-SemiCondensed.ttf: Noto Sans Thai UI,Noto Sans Thai UI SemCond:style=SemiCondensed,Regular
- NotoSans-CondensedBoldItalic.ttf: Noto Sans,Noto Sans Cond:style=Condensed Bold Italic,Bold Italic
- NotoSansDisplay-SemiCondensedLightItalic.ttf: Noto Sans Display,Noto Sans Disp SemCond Light:style=SemiCondensed Light Italic,Italic
- NotoSansRunic-Regular.ttf: Noto Sans Runic:style=Regular
- NotoSerifTamil-ExtraCondensedBlack.ttf: Noto Serif Tamil,Noto Serif Tamil ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansKhmerUI-CondensedBold.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI Cond:style=Condensed Bold,Bold
- NotoSerifKhmer-ExtraCondensedBlack.ttf: Noto Serif Khmer,Noto Serif Khmer ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansTamil-CondensedExtraBold.ttf: Noto Sans Tamil,Noto Sans Tamil Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSerifTamil-Condensed.ttf: Noto Serif Tamil,Noto Serif Tamil Cond:style=Condensed,Regular
- NotoSansThai-Black.ttf: Noto Sans Thai,Noto Sans Thai Blk:style=Black,Regular
- NotoSansKhmer-Condensed.ttf: Noto Sans Khmer,Noto Sans Khmer Cond:style=Condensed,Regular
- NotoSansCanadianAboriginal-Regular.ttf: Noto Sans Canadian Aboriginal:style=Regular
- NotoSansSymbols-Medium.ttf: Noto Sans Symbols,Noto Sans Symbols Med:style=Medium,Regular
- NotoSerifDisplay-ExtraCondensedBoldItalic.ttf: Noto Serif Display,Noto Serif Disp ExtCond:style=ExtraCondensed Bold Italic,Bold Italic
- n021023l.pfb: Nimbus Roman No9 L:style=Regular Italic
- NotoSansTamilUI-SemiCondensedThin.ttf: Noto Sans Tamil UI,Noto Sans Tamil SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSerifLao-ExtraCondensed.ttf: Noto Serif Lao,Noto Serif Lao ExtCond:style=ExtraCondensed,Regular
- NotoSansTamilUI-Thin.ttf: Noto Sans Tamil UI,Noto Sans Tamil Thin:style=Thin,Regular
- NotoSansLaoUI-SemiBold.ttf: Noto Sans Lao UI,Noto Sans Lao UI SemBd:style=SemiBold,Regular
- NotoSerif-ExtraCondensedLightItalic.ttf: Noto Serif,Noto Serif ExtCond Light:style=ExtraCondensed Light Italic,Italic
- NotoSansArabic-CondensedExtraBold.ttf: Noto Sans Arabic,Noto Sans Arabic Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansBengali-Thin.ttf: Noto Sans Bengali,Noto Sans Bengali Thin:style=Thin,Regular
- NotoSansLaoUI-SemiCondensed.ttf: Noto Sans Lao UI,Noto Sans Lao UI SemCond:style=SemiCondensed,Regular
- NotoSansThaiUI-ExtraCondensedSemiBold.ttf: Noto Sans Thai UI,Noto Sans Thai UI ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSerif-ExtraCondensed.ttf: Noto Serif,Noto Serif ExtCond:style=ExtraCondensed,Regular
- NotoSansSinhalaUI-ExtraBold.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala ExtBd:style=ExtraBold,Regular
- NotoSerifArmenian-SemiCondensed.ttf: Noto Serif Armenian,Noto Serif Armenian SmCn:style=SemiCondensed,Regular
- NotoSansDisplay-ExtraCondensedExtraBoldItalic.ttf: Noto Sans Display,Noto Sans Disp ExtCond ExtBd:style=ExtraCondensed ExtraBold Italic,Italic
- NotoSansDevanagari-SemiCondensedBold.ttf: Noto Sans Devanagari,Noto Sans Devanagari SmCn:style=SemiCondensed Bold,Bold
- NotoSansGeorgian-ExtraLight.ttf: Noto Sans Georgian,Noto Sans Georgian ExtLt:style=ExtraLight,Regular
- NotoSansMono-CondensedExtraLight.ttf: Noto Sans Mono,Noto Sans Mono Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansArabicUI-Light.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI Lt:style=Light,Regular
- NotoSansArabicUI-ExtraCondensedBlack.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI XCn Bk:style=ExtraCondensed Black,Regular
- NotoSansArabicUI-SemiCondensedMedium.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI SmCn Md:style=SemiCondensed Medium,Regular
- NotoSerifArmenian-SemiCondensedSemiBold.ttf: Noto Serif Armenian,Noto Serif Armenian SmCn SmBd:style=SemiCondensed SemiBold,Regular
- NotoSansTamil-CondensedBold.ttf: Noto Sans Tamil,Noto Sans Tamil Cond:style=Condensed Bold,Bold
- NotoSansTamilUI-CondensedSemiBold.ttf: Noto Sans Tamil UI,Noto Sans Tamil Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansMyanmarUI-CondensedLight.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI Cn Lt:style=Condensed Light,Regular
- NotoSerifMyanmar-SemiCondensedBlack.ttf: Noto Serif Myanmar,Noto Serif Myanmar SemCond Blk:style=SemiCondensed Black,Regular
- NotoSerifThai-SemiCondensedBlack.ttf: Noto Serif Thai,Noto Serif Thai SemCond Blk:style=SemiCondensed Black,Regular
- D050000L.otf: D050000L:style=Regular
- NotoSansArabicUI-Condensed.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI Cn:style=Condensed,Regular
- NotoSansTamilUI-ExtraCondensed.ttf: Noto Sans Tamil UI,Noto Sans Tamil ExtCond:style=ExtraCondensed,Regular
- NotoSerifGeorgian-SemiCondensedLight.ttf: Noto Serif Georgian,Noto Serif Georgian SmCn Lt:style=SemiCondensed Light,Regular
- NotoSansSinhalaUI-ExtraCondensedSemiBold.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSansMyanmar-SemiCondensedExtraLight.ttf: Noto Sans Myanmar,Noto Sans Myanmar SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSansMyanmarUI-ExtraCondensedBlack.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI XCn Bk:style=ExtraCondensed Black,Regular
- NotoSansDisplay-ExtraCondensedExtraLight.ttf: Noto Sans Display,Noto Sans Disp ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansHebrew-ExtraLight.ttf: Noto Sans Hebrew,Noto Sans Hebrew ExtLt:style=ExtraLight,Regular
- NotoSansCJKtc-Regular.otf: Noto Sans CJK TC,Noto Sans CJK TC Regular:style=Regular
- NotoSansTamil-Bold.ttf: Noto Sans Tamil:style=Bold
- NotoSansTamil-Medium.ttf: Noto Sans Tamil,Noto Sans Tamil Med:style=Medium,Regular
- NotoSerifCJKtc-Black.otf: Noto Serif CJK TC,Noto Serif CJK TC Black:style=Black,Regular
- NotoSansDevanagari-ExtraCondensedLight.ttf: Noto Sans Devanagari,Noto Sans Devanagari XCn Lt:style=ExtraCondensed Light,Regular
- NotoSansLaoUI-SemiCondensedBlack.ttf: Noto Sans Lao UI,Noto Sans Lao UI SemCond Blk:style=SemiCondensed Black,Regular
- NotoSansHebrew-CondensedLight.ttf: Noto Sans Hebrew,Noto Sans Hebrew Cond Light:style=Condensed Light,Regular
- NotoSansAnatolianHieroglyphs-Regular.ttf: Noto Sans Anatolian Hieroglyphs,Noto Sans AnatoHiero:style=Regular
- NotoSansLaoUI-ExtraCondensed.ttf: Noto Sans Lao UI,Noto Sans Lao UI ExtCond:style=ExtraCondensed,Regular
- NotoSansLaoUI-Medium.ttf: Noto Sans Lao UI,Noto Sans Lao UI Med:style=Medium,Regular
- NotoSans-ExtraBoldItalic.ttf: Noto Sans,Noto Sans ExtBd:style=ExtraBold Italic,Italic
- NotoSans-Italic.ttf: Noto Sans:style=Italic
- NotoSansSaurashtra-Regular.ttf: Noto Sans Saurashtra:style=Regular
- NotoSansThai-SemiCondensed.ttf: Noto Sans Thai,Noto Sans Thai SemCond:style=SemiCondensed,Regular
- NotoSansDevanagari-CondensedLight.ttf: Noto Sans Devanagari,Noto Sans Devanagari Cn Lt:style=Condensed Light,Regular
- NotoSansGeorgian-CondensedBlack.ttf: Noto Sans Georgian,Noto Sans Georgian Cond Blk:style=Condensed Black,Regular
- NotoSansMyanmarUI-Light.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI Lt:style=Light,Regular
- NotoSansThaiUI-CondensedLight.ttf: Noto Sans Thai UI,Noto Sans Thai UI Cond Light:style=Condensed Light,Regular
- NotoSerifThai-ExtraCondensedExtraLight.ttf: Noto Serif Thai,Noto Serif Thai ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSerifMyanmar-ExtraCondensedBlack.ttf: Noto Serif Myanmar,Noto Serif Myanmar ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansArabic-SemiCondensedThin.ttf: Noto Sans Arabic,Noto Sans Arabic SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSansDisplay-Condensed.ttf: Noto Sans Display,Noto Sans Disp Cond:style=Condensed,Regular
- NotoSerifSinhala-Thin.ttf: Noto Serif Sinhala,Noto Serif Sinhala Thin:style=Thin,Regular
- NotoSansDevanagari-Condensed.ttf: Noto Sans Devanagari,Noto Sans Devanagari Cn:style=Condensed,Regular
- NotoSansTamil-CondensedExtraLight.ttf: Noto Sans Tamil,Noto Sans Tamil Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansMyanmar-SemiCondensedMedium.ttf: Noto Sans Myanmar,Noto Sans Myanmar SemCond Med:style=SemiCondensed Medium,Regular
- n019063l.pfb: Nimbus Sans L:style=Regular Condensed Italic
- NotoSerifDisplay-Regular.ttf: Noto Serif Display,Noto Serif Disp:style=Regular
- NotoSansLao-ExtraCondensedMedium.ttf: Noto Sans Lao,Noto Sans Lao ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansEgyptianHieroglyphs-Regular.ttf: Noto Sans Egyptian Hieroglyphs,Noto Sans EgyptHiero:style=Regular
- NotoSansTamil-ExtraCondensed.ttf: Noto Sans Tamil,Noto Sans Tamil ExtCond:style=ExtraCondensed,Regular
- NotoSerifHebrew-ExtraCondensedLight.ttf: Noto Serif Hebrew,Noto Serif Hebrew ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSans-SemiCondensedExtraLightItalic.ttf: Noto Sans,Noto Sans SemCond ExtLt:style=SemiCondensed ExtraLight Italic,Italic
- C059-BdIta.otf: C059:style=Bold Italic
- NotoSansSylotiNagri-Regular.ttf: Noto Sans Syloti Nagri:style=Regular
- NotoSansTamil-ExtraCondensedBlack.ttf: Noto Sans Tamil,Noto Sans Tamil ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSerifThai-SemiCondensedMedium.ttf: Noto Serif Thai,Noto Serif Thai SemCond Med:style=SemiCondensed Medium,Regular
- NotoSerif-CondensedLightItalic.ttf: Noto Serif,Noto Serif Cond Light:style=Condensed Light Italic,Italic
- DejaVuSans-Bold.ttf: DejaVu Sans:style=Bold
- NotoSansThai-Medium.ttf: Noto Sans Thai,Noto Sans Thai Med:style=Medium,Regular
- NotoSansDevanagariUI-ExtraCondensedBold.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari XCn:style=ExtraCondensed Bold,Bold
- NotoSansThaiUI-SemiCondensedExtraLight.ttf: Noto Sans Thai UI,Noto Sans Thai UI SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSansTamil-Condensed.ttf: Noto Sans Tamil,Noto Sans Tamil Cond:style=Condensed,Regular
- NotoSans-ExtraCondensedLightItalic.ttf: Noto Sans,Noto Sans ExtCond Light:style=ExtraCondensed Light Italic,Italic
- NotoSansLao-Regular.ttf: Noto Sans Lao:style=Regular
- NotoSerifArmenian-Condensed.ttf: Noto Serif Armenian,Noto Serif Armenian Cn:style=Condensed,Regular
- NotoSerifDisplay-Italic.ttf: Noto Serif Display,Noto Serif Disp:style=Italic
- NotoSansSinhala-SemiCondensedMedium.ttf: Noto Sans Sinhala,Noto Sans Sinhala SemCond Med:style=SemiCondensed Medium,Regular
- NotoSans-CondensedExtraBoldItalic.ttf: Noto Sans,Noto Sans Cond ExtBd:style=Condensed ExtraBold Italic,Italic
- NotoSerifTamil-CondensedMedium.ttf: Noto Serif Tamil,Noto Serif Tamil Cond Med:style=Condensed Medium,Regular
- NotoSansThaiUI-Condensed.ttf: Noto Sans Thai UI,Noto Sans Thai UI Cond:style=Condensed,Regular
- NotoSansMono-CondensedThin.ttf: Noto Sans Mono,Noto Sans Mono Cond Thin:style=Condensed Thin,Regular
- NotoSans-CondensedExtraLight.ttf: Noto Sans,Noto Sans Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansDevanagari-ExtraCondensedThin.ttf: Noto Sans Devanagari,Noto Sans Devanagari XCn Th:style=ExtraCondensed Thin,Regular
- NotoSerifGujarati-Regular.ttf: Noto Serif Gujarati:style=Regular
- NotoSerifMyanmar-ExtraCondensedLight.ttf: Noto Serif Myanmar,Noto Serif Myanmar ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSansArabicUI-CondensedBlack.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI Cn Bk:style=Condensed Black,Regular
- NotoSansKhmer-ExtraCondensedExtraBold.ttf: Noto Sans Khmer,Noto Sans Khmer ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSerifGeorgian-CondensedBlack.ttf: Noto Serif Georgian,Noto Serif Georgian Cn Bk:style=Condensed Black,Regular
- NotoSansSinhala-ExtraCondensedExtraBold.ttf: Noto Sans Sinhala,Noto Sans Sinhala ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSerifEthiopic-SemiCondensedExtraBold.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic SmCn XBd:style=SemiCondensed ExtraBold,Regular
- NotoSansMyanmar-SemiCondensedExtraBold.ttf: Noto Sans Myanmar,Noto Sans Myanmar SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansCherokee-Medium.ttf: Noto Sans Cherokee,Noto Sans Cherokee Med:style=Medium,Regular
- NotoSerifDevanagari-Bold.ttf: Noto Serif Devanagari:style=Bold
- NotoSansGeorgian-ExtraCondensedBold.ttf: Noto Sans Georgian,Noto Sans Georgian ExtCond:style=ExtraCondensed Bold,Bold
- NotoSansMeeteiMayek-Regular.ttf: Noto Sans Meetei Mayek:style=Regular
- NotoSansThaana-Bold.ttf: Noto Sans Thaana:style=Bold
- NotoSansKannada-Bold.ttf: Noto Sans Kannada:style=Bold
- NotoSerifKhmer-CondensedExtraBold.ttf: Noto Serif Khmer,Noto Serif Khmer Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansDevanagari-SemiBold.ttf: Noto Sans Devanagari,Noto Sans Devanagari SmBd:style=SemiBold,Regular
- NotoSansKhmerUI-SemiBold.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI SemBd:style=SemiBold,Regular
- NotoSansSinhalaUI-SemiCondensedMedium.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala SemCond Med:style=SemiCondensed Medium,Regular
- NotoSansDevanagariUI-SemiCondensedLight.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari SmCn Lt:style=SemiCondensed Light,Regular
- NotoSansDevanagariUI-ExtraBold.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari XBd:style=ExtraBold,Regular
- NotoSerifThai-SemiCondensedExtraBold.ttf: Noto Serif Thai,Noto Serif Thai SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansDisplay-Light.ttf: Noto Sans Display,Noto Sans Disp Light:style=Light,Regular
- NotoSansEthiopic-Condensed.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic Cond:style=Condensed,Regular
- NotoSerifMyanmar-SemiCondensedExtraBold.ttf: Noto Serif Myanmar,Noto Serif Myanmar SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansMyanmar-ExtraCondensed.ttf: Noto Sans Myanmar,Noto Sans Myanmar ExtCond:style=ExtraCondensed,Regular
- NotoSansArabicUI-SemiBold.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI SmBd:style=SemiBold,Regular
- NotoSerif-ThinItalic.ttf: Noto Serif,Noto Serif Thin:style=Thin Italic,Italic
- NotoSansArabicUI-ExtraCondensedThin.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI XCn Th:style=ExtraCondensed Thin,Regular
- NotoSansKhmer-SemiCondensedExtraLight.ttf: Noto Sans Khmer,Noto Sans Khmer SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- a010013l.pfb: URW Gothic L:style=Book
- NotoSansDevanagari-CondensedThin.ttf: Noto Sans Devanagari,Noto Sans Devanagari Cn Th:style=Condensed Thin,Regular
- NotoSerifThai-SemiCondensedExtraLight.ttf: Noto Serif Thai,Noto Serif Thai SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSansKhmerUI-CondensedThin.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI Cond Thin:style=Condensed Thin,Regular
- NotoSansArabicUI-ExtraCondensed.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI XCn:style=ExtraCondensed,Regular
- NotoSerif-CondensedThin.ttf: Noto Serif,Noto Serif Cond Thin:style=Condensed Thin,Regular
- NotoSerifDisplay-BlackItalic.ttf: Noto Serif Display,Noto Serif Disp Blk:style=Black Italic,Italic
- NotoSansImperialAramaic-Regular.ttf: Noto Sans Imperial Aramaic,Noto Sans ImpAramaic:style=Regular
- NotoSansSinhalaUI-ExtraCondensedBold.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala ExtCond:style=ExtraCondensed Bold,Bold
- NotoSerifLao-CondensedMedium.ttf: Noto Serif Lao,Noto Serif Lao Cond Med:style=Condensed Medium,Regular
- NotoSansArabic-Thin.ttf: Noto Sans Arabic,Noto Sans Arabic Thin:style=Thin,Regular
- NotoSansHebrew-CondensedMedium.ttf: Noto Sans Hebrew,Noto Sans Hebrew Cond Med:style=Condensed Medium,Regular
- NotoSansEthiopic-Medium.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic Med:style=Medium,Regular
- NotoSerifLao-SemiCondensedExtraLight.ttf: Noto Serif Lao,Noto Serif Lao SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSans-CondensedItalic.ttf: Noto Sans,Noto Sans Cond:style=Condensed Italic,Italic
- NotoSansCJKjp-Light.otf: Noto Sans CJK JP,Noto Sans CJK JP Light:style=Light,Regular
- NimbusRoman-Regular.otf: Nimbus Roman:style=Regular
- NotoSansDevanagariUI-ExtraCondensedMedium.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari XCn Md:style=ExtraCondensed Medium,Regular
- NotoSansThaiUI-ExtraCondensedExtraLight.ttf: Noto Sans Thai UI,Noto Sans Thai UI ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSerifLao-ExtraCondensedBold.ttf: Noto Serif Lao,Noto Serif Lao ExtCond:style=ExtraCondensed Bold,Bold
- NotoSerifTamil-ExtraBold.ttf: Noto Serif Tamil,Noto Serif Tamil ExtBd:style=ExtraBold,Regular
- NotoSerifThai-ExtraCondensedSemiBold.ttf: Noto Serif Thai,Noto Serif Thai ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSansLao-ExtraBold.ttf: Noto Sans Lao,Noto Sans Lao ExtBd:style=ExtraBold,Regular
- NotoSerifMyanmar-SemiCondensedSemiBold.ttf: Noto Serif Myanmar,Noto Serif Myanmar SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansDisplay-ThinItalic.ttf: Noto Sans Display,Noto Sans Disp Thin:style=Thin Italic,Italic
- NotoSansKhmerUI-ExtraCondensedBlack.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansEthiopic-Regular.ttf: Noto Sans Ethiopic:style=Regular
- NotoSansOsage-Regular.ttf: Noto Sans Osage:style=Regular
- NotoSans-ExtraCondensedSemiBold.ttf: Noto Sans,Noto Sans ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSerif-ExtraCondensedMediumItalic.ttf: Noto Serif,Noto Serif ExtCond Med:style=ExtraCondensed Medium Italic,Italic
- NotoSerifKhmer-SemiCondensedThin.ttf: Noto Serif Khmer,Noto Serif Khmer SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSansArmenian-Thin.ttf: Noto Sans Armenian,Noto Sans Armenian Thin:style=Thin,Regular
- C059-Italic.otf: C059:style=Italic
- NotoSerifMyanmar-ExtraCondensedExtraLight.ttf: Noto Serif Myanmar,Noto Serif Myanmar ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSerifKhmer-CondensedThin.ttf: Noto Serif Khmer,Noto Serif Khmer Cond Thin:style=Condensed Thin,Regular
- NotoNastaliqUrdu-Regular.ttf: Noto Nastaliq Urdu:style=Regular
- NotoSansMyanmar-SemiCondensedBlack.ttf: Noto Sans Myanmar,Noto Sans Myanmar SemCond Blk:style=SemiCondensed Black,Regular
- NotoSerifDisplay-ExtraCondensedBlackItalic.ttf: Noto Serif Display,Noto Serif Disp ExtCond Blk:style=ExtraCondensed Black Italic,Italic
- NotoSerifThai-ExtraBold.ttf: Noto Serif Thai,Noto Serif Thai ExtBd:style=ExtraBold,Regular
- NotoSerifEthiopic-CondensedMedium.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic Cn Md:style=Condensed Medium,Regular
- NotoSerifMyanmar-ExtraCondensedThin.ttf: Noto Serif Myanmar,Noto Serif Myanmar ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSansLao-ExtraCondensedBold.ttf: Noto Sans Lao,Noto Sans Lao ExtCond:style=ExtraCondensed Bold,Bold
- NotoSansLisu-Regular.ttf: Noto Sans Lisu:style=Regular
- NotoSansThai-CondensedSemiBold.ttf: Noto Sans Thai,Noto Sans Thai Cond SemBd:style=Condensed SemiBold,Regular
- NotoSerifTamil-SemiCondensedMedium.ttf: Noto Serif Tamil,Noto Serif Tamil SemCond Med:style=SemiCondensed Medium,Regular
- NotoSerifLao-SemiCondensedBlack.ttf: Noto Serif Lao,Noto Serif Lao SemCond Blk:style=SemiCondensed Black,Regular
- NotoSansSinhalaUI-CondensedExtraLight.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSans-SemiCondensedMedium.ttf: Noto Sans,Noto Sans SemCond Med:style=SemiCondensed Medium,Regular
- NimbusMonoPS-Bold.otf: Nimbus Mono PS:style=Bold
- NimbusRoman-Bold.otf: Nimbus Roman:style=Bold
- NotoSansKhmerUI-CondensedExtraBold.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSerifCJKsc-ExtraLight.otf: Noto Serif CJK SC,Noto Serif CJK SC ExtraLight:style=ExtraLight,Regular
- NotoSansMalayalamUI-Regular.ttf: Noto Sans Malayalam UI:style=Regular
- NotoSerifKhmer-SemiCondensedLight.ttf: Noto Serif Khmer,Noto Serif Khmer SemCond Light:style=SemiCondensed Light,Regular
- NotoSansDisplay-ExtraCondensedExtraBold.ttf: Noto Sans Display,Noto Sans Disp ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansEthiopic-CondensedMedium.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic Cond Med:style=Condensed Medium,Regular
- NotoSerifDisplay-ExtraCondensedLightItalic.ttf: Noto Serif Display,Noto Serif Disp ExtCond Light:style=ExtraCondensed Light Italic,Italic
- NotoSansArabicUI-CondensedExtraBold.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI Cn XBd:style=Condensed ExtraBold,Regular
- NimbusSansNarrow-Bold.t1: Nimbus Sans Narrow:style=Bold
- NotoSansArabicUI-SemiCondensedExtraLight.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI SmCn XLt:style=SemiCondensed ExtraLight,Regular
- NotoSansLaoUI-CondensedMedium.ttf: Noto Sans Lao UI,Noto Sans Lao UI Cond Med:style=Condensed Medium,Regular
- NotoSans-SemiCondensedThin.ttf: Noto Sans,Noto Sans SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSerifHebrew-SemiCondensedBold.ttf: Noto Serif Hebrew,Noto Serif Hebrew SemCond:style=SemiCondensed Bold,Bold
- NotoSansTamilUI-ExtraCondensedBold.ttf: Noto Sans Tamil UI,Noto Sans Tamil ExtCond:style=ExtraCondensed Bold,Bold
- NotoSerifHebrew-ExtraCondensedExtraBold.ttf: Noto Serif Hebrew,Noto Serif Hebrew ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NimbusRoman-BoldItalic.otf: Nimbus Roman:style=Bold Italic
- NotoSansKhmerUI-CondensedLight.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI Cond Light:style=Condensed Light,Regular
- NotoSansSinhalaUI-CondensedBlack.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala Cond Blk:style=Condensed Black,Regular
- NotoSansGurmukhiUI-Regular.ttf: Noto Sans Gurmukhi UI:style=Regular
- NotoSansTamil-SemiCondensedBold.ttf: Noto Sans Tamil,Noto Sans Tamil SemCond:style=SemiCondensed Bold,Bold
- NotoSansDevanagari-SemiCondensed.ttf: Noto Sans Devanagari,Noto Sans Devanagari SmCn:style=SemiCondensed,Regular
- NotoSans-SemiCondensedItalic.ttf: Noto Sans,Noto Sans SemCond:style=SemiCondensed Italic,Italic
- NotoSansTamil-ExtraBold.ttf: Noto Sans Tamil,Noto Sans Tamil ExtBd:style=ExtraBold,Regular
- NotoSerifKannada-Bold.ttf: Noto Serif Kannada:style=Bold
- NotoSansMyanmarUI-SemiCondensedExtraBold.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI SmCn XBd:style=SemiCondensed ExtraBold,Regular
- NotoSerifKhmer-SemiCondensedMedium.ttf: Noto Serif Khmer,Noto Serif Khmer SemCond Med:style=SemiCondensed Medium,Regular
- NotoSansGeorgian-ExtraCondensedThin.ttf: Noto Sans Georgian,Noto Sans Georgian ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSansGujarati-Bold.ttf: Noto Sans Gujarati:style=Bold
- NotoSerif-Black.ttf: Noto Serif,Noto Serif Blk:style=Black,Regular
- NotoSansSymbols-ExtraLight.ttf: Noto Sans Symbols,Noto Sans Symbols ExtLt:style=ExtraLight,Regular
- NotoSerifHebrew-ExtraBold.ttf: Noto Serif Hebrew,Noto Serif Hebrew ExtBd:style=ExtraBold,Regular
- NotoSerifSinhala-Regular.ttf: Noto Serif Sinhala:style=Regular
- NotoSerifGeorgian-SemiBold.ttf: Noto Serif Georgian,Noto Serif Georgian SmBd:style=SemiBold,Regular
- NotoSansTamil-CondensedLight.ttf: Noto Sans Tamil,Noto Sans Tamil Cond Light:style=Condensed Light,Regular
- NotoSerifDisplay-SemiCondensedExtraBoldItalic.ttf: Noto Serif Display,Noto Serif Disp SemCond ExtBd:style=SemiCondensed ExtraBold Italic,Italic
- NotoSansDevanagari-Black.ttf: Noto Sans Devanagari,Noto Sans Devanagari Bk:style=Black,Regular
- NotoSansThaiUI-CondensedExtraBold.ttf: Noto Sans Thai UI,Noto Sans Thai UI Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSerifEthiopic-ExtraCondensedThin.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic XCn Th:style=ExtraCondensed Thin,Regular
- n019064l.pfb: Nimbus Sans L:style=Bold Condensed Italic
- NotoSerifEthiopic-CondensedSemiBold.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic Cn SmBd:style=Condensed SemiBold,Regular
- NotoSansDevanagariUI-ExtraCondensed.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari XCn:style=ExtraCondensed,Regular
- NotoSerif-BlackItalic.ttf: Noto Serif,Noto Serif Blk:style=Black Italic,Italic
- NotoSerifMyanmar-CondensedExtraLight.ttf: Noto Serif Myanmar,Noto Serif Myanmar Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSerifMyanmar-SemiCondensedMedium.ttf: Noto Serif Myanmar,Noto Serif Myanmar SemCond Med:style=SemiCondensed Medium,Regular
- NotoSans-ExtraCondensedBlack.ttf: Noto Sans,Noto Sans ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansMalayalamUI-Bold.ttf: Noto Sans Malayalam UI:style=Bold
- NotoSansEthiopic-SemiCondensedBold.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic SemCond:style=SemiCondensed Bold,Bold
- NotoSans-CondensedSemiBold.ttf: Noto Sans,Noto Sans Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansThai-SemiCondensedExtraBold.ttf: Noto Sans Thai,Noto Sans Thai SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSerifEthiopic-SemiCondensedMedium.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic SmCn Md:style=SemiCondensed Medium,Regular
- NotoSansSinhala-Light.ttf: Noto Sans Sinhala,Noto Sans Sinhala Light:style=Light,Regular
- NotoSansGujarati-Regular.ttf: Noto Sans Gujarati:style=Regular
- NotoSerif-ExtraCondensedExtraLightItalic.ttf: Noto Serif,Noto Serif ExtCond ExtLt:style=ExtraCondensed ExtraLight Italic,Italic
- NotoSansGeorgian-SemiCondensed.ttf: Noto Sans Georgian,Noto Sans Georgian SemCond:style=SemiCondensed,Regular
- NotoSerifEthiopic-SemiCondensedExtraLight.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic SmCn XLt:style=SemiCondensed ExtraLight,Regular
- NotoSerifGeorgian-CondensedExtraLight.ttf: Noto Serif Georgian,Noto Serif Georgian Cn XLt:style=Condensed ExtraLight,Regular
- NotoSerifLao-SemiCondensedMedium.ttf: Noto Serif Lao,Noto Serif Lao SemCond Med:style=SemiCondensed Medium,Regular
- DroidSansFallbackFull.ttf: Droid Sans Fallback:style=Regular
- NotoSansLaoUI-ExtraCondensedThin.ttf: Noto Sans Lao UI,Noto Sans Lao UI ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSansMyanmar-SemiCondensedSemiBold.ttf: Noto Sans Myanmar,Noto Sans Myanmar SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansTamilUI-CondensedExtraBold.ttf: Noto Sans Tamil UI,Noto Sans Tamil Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSerifLao-SemiCondensedThin.ttf: Noto Serif Lao,Noto Serif Lao SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSansOldSouthArabian-Regular.ttf: Noto Sans Old South Arabian,Noto Sans OldSouArab:style=Regular
- p052004l.pfb: URW Palladio L:style=Bold
- NotoSansMyanmarUI-CondensedThin.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI Cn Th:style=Condensed Thin,Regular
- NotoSansLao-SemiCondensedSemiBold.ttf: Noto Sans Lao,Noto Sans Lao SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansLaoUI-SemiCondensedThin.ttf: Noto Sans Lao UI,Noto Sans Lao UI SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSerifGeorgian-ExtraCondensedExtraLight.ttf: Noto Serif Georgian,Noto Serif Georgian XCn XLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansArabic-SemiCondensedBlack.ttf: Noto Sans Arabic,Noto Sans Arabic SemCond Blk:style=SemiCondensed Black,Regular
- NotoSansTamilUI-ExtraCondensedMedium.ttf: Noto Sans Tamil UI,Noto Sans Tamil ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansEthiopic-SemiCondensedThin.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSans-CondensedMediumItalic.ttf: Noto Sans,Noto Sans Cond Med:style=Condensed Medium Italic,Italic
- NotoSansHebrew-SemiBold.ttf: Noto Sans Hebrew,Noto Sans Hebrew SemBd:style=SemiBold,Regular
- NotoSansTamilUI-ExtraBold.ttf: Noto Sans Tamil UI,Noto Sans Tamil ExtBd:style=ExtraBold,Regular
- NotoSerifKhmer-ExtraCondensedExtraBold.ttf: Noto Serif Khmer,Noto Serif Khmer ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSerifDisplay-SemiCondensedBlack.ttf: Noto Serif Display,Noto Serif Disp SemCond Blk:style=SemiCondensed Black,Regular
- NotoSerifTamil-Regular.ttf: Noto Serif Tamil:style=Regular
- NotoSansCJKkr-DemiLight.otf: Noto Sans CJK KR,Noto Sans CJK KR DemiLight:style=DemiLight,Regular
- NotoSerifDisplay-ExtraCondensedExtraLight.ttf: Noto Serif Display,Noto Serif Disp ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansArabic-Regular.ttf: Noto Sans Arabic:style=Regular
- NotoSansNKo-Regular.ttf: Noto Sans NKo,Noto Sans N'Ko:style=Regular
- NotoSansKhmerUI-ExtraLight.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI ExtLt:style=ExtraLight,Regular
- NotoSansMyanmar-CondensedLight.ttf: Noto Sans Myanmar,Noto Sans Myanmar Cond Light:style=Condensed Light,Regular
- NotoSansDisplay-SemiCondensedExtraLight.ttf: Noto Sans Display,Noto Sans Disp SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSansSinhalaUI-Bold.ttf: Noto Sans Sinhala UI:style=Bold
- NotoSans-CondensedMedium.ttf: Noto Sans,Noto Sans Cond Med:style=Condensed Medium,Regular
- NotoSansDisplay-CondensedSemiBold.ttf: Noto Sans Display,Noto Sans Disp Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansLao-ExtraCondensedExtraLight.ttf: Noto Sans Lao,Noto Sans Lao ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSerifKhmer-Light.ttf: Noto Serif Khmer,Noto Serif Khmer Light:style=Light,Regular
- NotoSansSinhalaUI-SemiCondensed.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala SemCond:style=SemiCondensed,Regular
- NotoSerif-CondensedBold.ttf: Noto Serif,Noto Serif Cond:style=Condensed Bold,Bold
- NotoSansDevanagariUI-ExtraCondensedExtraBold.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari XCn XBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansEthiopic-Bold.ttf: Noto Sans Ethiopic:style=Bold
- NotoSansGeorgian-SemiCondensedSemiBold.ttf: Noto Sans Georgian,Noto Sans Georgian SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSerif-ExtraLightItalic.ttf: Noto Serif,Noto Serif ExtLt:style=ExtraLight Italic,Italic
- C059-Roman.t1: C059:style=Roman
- NotoSerifMyanmar-CondensedExtraBold.ttf: Noto Serif Myanmar,Noto Serif Myanmar Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansDevanagariUI-CondensedBlack.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari Cn Bk:style=Condensed Black,Regular
- NotoSansKhmerUI-SemiCondensedSemiBold.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansKannadaUI-Regular.ttf: Noto Sans Kannada UI:style=Regular
- NotoSansSinhala-ExtraCondensedSemiBold.ttf: Noto Sans Sinhala,Noto Sans Sinhala ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSansOsmanya-Regular.ttf: Noto Sans Osmanya:style=Regular
- NotoSerifGeorgian-ExtraCondensedThin.ttf: Noto Serif Georgian,Noto Serif Georgian XCn Th:style=ExtraCondensed Thin,Regular
- NotoSansKhmerUI-SemiCondensedThin.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSansArabicUI-Thin.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI Th:style=Thin,Regular
- NotoSerifArmenian-ExtraCondensedBlack.ttf: Noto Serif Armenian,Noto Serif Armenian XCn Bk:style=ExtraCondensed Black,Regular
- NotoSerifMyanmar-CondensedMedium.ttf: Noto Serif Myanmar,Noto Serif Myanmar Cond Med:style=Condensed Medium,Regular
- NotoSansDevanagariUI-SemiCondensedThin.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari SmCn Th:style=SemiCondensed Thin,Regular
- NotoSansMyanmar-CondensedExtraBold.ttf: Noto Sans Myanmar,Noto Sans Myanmar Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansTamil-SemiCondensedExtraBold.ttf: Noto Sans Tamil,Noto Sans Tamil SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansLao-CondensedBold.ttf: Noto Sans Lao,Noto Sans Lao Cond:style=Condensed Bold,Bold
- NotoSerifGeorgian-CondensedExtraBold.ttf: Noto Serif Georgian,Noto Serif Georgian Cn XBd:style=Condensed ExtraBold,Regular
- NotoSansSinhalaUI-Medium.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala Med:style=Medium,Regular
- NotoSansMono-CondensedBold.ttf: Noto Sans Mono,Noto Sans Mono Cond:style=Condensed Bold,Bold
- NotoSansArabicUI-SemiCondensedExtraBold.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI SmCn XBd:style=SemiCondensed ExtraBold,Regular
- NotoSans-MediumItalic.ttf: Noto Sans,Noto Sans Med:style=Medium Italic,Italic
- NotoSansArabic-SemiBold.ttf: Noto Sans Arabic,Noto Sans Arabic SemBd:style=SemiBold,Regular
- NotoSansAdlamUnjoined-Regular.ttf: Noto Sans Adlam Unjoined:style=Regular
- NotoSansArmenian-SemiCondensedSemiBold.ttf: Noto Sans Armenian,Noto Sans Armenian SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansSymbols-ExtraBold.ttf: Noto Sans Symbols,Noto Sans Symbols ExtBd:style=ExtraBold,Regular
- NotoSansThai-ExtraCondensedBold.ttf: Noto Sans Thai,Noto Sans Thai ExtCond:style=ExtraCondensed Bold,Bold
- NotoSansTamilUI-CondensedLight.ttf: Noto Sans Tamil UI,Noto Sans Tamil Cond Light:style=Condensed Light,Regular
- NotoSansLycian-Regular.ttf: Noto Sans Lycian:style=Regular
- NotoSansDisplay-CondensedLight.ttf: Noto Sans Display,Noto Sans Disp Cond Light:style=Condensed Light,Regular
- NotoSansGeorgian-SemiCondensedBold.ttf: Noto Sans Georgian,Noto Sans Georgian SemCond:style=SemiCondensed Bold,Bold
- NotoSerifCJKjp-ExtraLight.otf: Noto Serif CJK JP,Noto Serif CJK JP ExtraLight:style=ExtraLight,Regular
- NimbusRoman-Italic.t1: Nimbus Roman:style=Italic
- NotoSerifDisplay-ExtraCondensedSemiBoldItalic.ttf: Noto Serif Display,Noto Serif Disp ExtCond SemBd:style=ExtraCondensed SemiBold Italic,Italic
- NotoSansThai-SemiCondensedSemiBold.ttf: Noto Sans Thai,Noto Sans Thai SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansMono-ExtraCondensedThin.ttf: Noto Sans Mono,Noto Sans Mono ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSerifThai-ExtraCondensedBlack.ttf: Noto Serif Thai,Noto Serif Thai ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansMyanmarUI-CondensedExtraLight.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI Cn XLt:style=Condensed ExtraLight,Regular
- NotoSansSinhala-Condensed.ttf: Noto Sans Sinhala,Noto Sans Sinhala Cond:style=Condensed,Regular
- NotoSansGeorgian-SemiCondensedBlack.ttf: Noto Sans Georgian,Noto Sans Georgian SemCond Blk:style=SemiCondensed Black,Regular
- NimbusSans-Italic.otf: Nimbus Sans:style=Italic
- NotoSansArmenian-SemiCondensedBold.ttf: Noto Sans Armenian,Noto Sans Armenian SemCond:style=SemiCondensed Bold,Bold
- NotoSerifDisplay-Medium.ttf: Noto Serif Display,Noto Serif Disp Med:style=Medium,Regular
- NotoSerifHebrew-ExtraCondensedMedium.ttf: Noto Serif Hebrew,Noto Serif Hebrew ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansLao-SemiCondensedExtraLight.ttf: Noto Sans Lao,Noto Sans Lao SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSansArabicUI-ExtraBold.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI XBd:style=ExtraBold,Regular
- NotoSansCJKtc-Light.otf: Noto Sans CJK TC,Noto Sans CJK TC Light:style=Light,Regular
- NotoSerifKhmer-SemiCondensedExtraBold.ttf: Noto Serif Khmer,Noto Serif Khmer SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansCherokee-SemiBold.ttf: Noto Sans Cherokee,Noto Sans Cherokee SemBd:style=SemiBold,Regular
- NotoSansDisplay-MediumItalic.ttf: Noto Sans Display,Noto Sans Disp Med:style=Medium Italic,Italic
- NotoSerifLao-SemiBold.ttf: Noto Serif Lao,Noto Serif Lao SemBd:style=SemiBold,Regular
- n022023l.pfb: Nimbus Mono L:style=Regular Oblique
- NotoSansCham-Medium.ttf: Noto Sans Cham,Noto Sans Cham Med:style=Medium,Regular
- NotoSansDevanagariUI-ExtraCondensedSemiBold.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari XCn SmBd:style=ExtraCondensed SemiBold,Regular
- NotoSerifDisplay-CondensedLight.ttf: Noto Serif Display,Noto Serif Disp Cond Light:style=Condensed Light,Regular
- NotoSansEthiopic-ExtraCondensedSemiBold.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSansMono-Light.ttf: Noto Sans Mono,Noto Sans Mono Light:style=Light,Regular
- NotoSerifLao-CondensedExtraLight.ttf: Noto Serif Lao,Noto Serif Lao Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansTamilUI-Black.ttf: Noto Sans Tamil UI,Noto Sans Tamil Blk:style=Black,Regular
- NotoSansArabicUI-Regular.ttf: Noto Sans Arabic UI:style=Regular
- NotoSerifCJKtc-Bold.otf: Noto Serif CJK TC:style=Bold
- NotoSansBengali-Light.ttf: Noto Sans Bengali,Noto Sans Bengali Light:style=Light,Regular
- NotoSansEthiopic-CondensedLight.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic Cond Light:style=Condensed Light,Regular
- NotoSans-Regular.ttf: Noto Sans:style=Regular
- NotoSansThaiUI-ExtraCondensedLight.ttf: Noto Sans Thai UI,Noto Sans Thai UI ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSansSinhala-Regular.ttf: Noto Sans Sinhala:style=Regular
- NotoSansMono-Black.ttf: Noto Sans Mono,Noto Sans Mono Blk:style=Black,Regular
- NotoSansDevanagariUI-CondensedThin.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari Cn Th:style=Condensed Thin,Regular
- NotoSerifLao-ExtraLight.ttf: Noto Serif Lao,Noto Serif Lao ExtLt:style=ExtraLight,Regular
- NotoSansSinhalaUI-CondensedLight.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala Cond Light:style=Condensed Light,Regular
- NotoSansSinhala-SemiCondensedLight.ttf: Noto Sans Sinhala,Noto Sans Sinhala SemCond Light:style=SemiCondensed Light,Regular
- NotoSerifGeorgian-Black.ttf: Noto Serif Georgian,Noto Serif Georgian Bk:style=Black,Regular
- NotoSansLao-ExtraLight.ttf: Noto Sans Lao,Noto Sans Lao ExtLt:style=ExtraLight,Regular
- NotoSansTamil-ExtraCondensedMedium.ttf: Noto Sans Tamil,Noto Sans Tamil ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansDisplay-SemiCondensedMedium.ttf: Noto Sans Display,Noto Sans Disp SemCond Med:style=SemiCondensed Medium,Regular
- NotoSerifEthiopic-Light.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic Lt:style=Light,Regular
- NotoSerifGujarati-Bold.ttf: Noto Serif Gujarati:style=Bold
- NotoSansDevanagariUI-Light.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari Lt:style=Light,Regular
- NotoSansDevanagariUI-Condensed.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari Cn:style=Condensed,Regular
- NotoSerifHebrew-SemiCondensed.ttf: Noto Serif Hebrew,Noto Serif Hebrew SemCond:style=SemiCondensed,Regular
- NotoSansLaoUI-CondensedExtraBold.ttf: Noto Sans Lao UI,Noto Sans Lao UI Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSerif-SemiCondensedItalic.ttf: Noto Serif,Noto Serif SemCond:style=SemiCondensed Italic,Italic
- NotoSansTamilUI-SemiCondensedMedium.ttf: Noto Sans Tamil UI,Noto Sans Tamil SemCond Med:style=SemiCondensed Medium,Regular
- NotoSansArabic-Medium.ttf: Noto Sans Arabic,Noto Sans Arabic Med:style=Medium,Regular
- NotoSansHebrew-SemiCondensedBold.ttf: Noto Sans Hebrew,Noto Sans Hebrew SemCond:style=SemiCondensed Bold,Bold
- NotoSansMono-ExtraCondensedExtraBold.ttf: Noto Sans Mono,Noto Sans Mono ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansThai-ExtraLight.ttf: Noto Sans Thai,Noto Sans Thai ExtLt:style=ExtraLight,Regular
- NotoSerif-CondensedThinItalic.ttf: Noto Serif,Noto Serif Cond Thin:style=Condensed Thin Italic,Italic
- URWBookman-Demi.t1: URW Bookman:style=Demi
- NotoSansSyriacEstrangela-Regular.ttf: Noto Sans Syriac Estrangela:style=Regular
- NotoSansKhmer-Medium.ttf: Noto Sans Khmer,Noto Sans Khmer Med:style=Medium,Regular
- NotoSansLaoUI-Thin.ttf: Noto Sans Lao UI,Noto Sans Lao UI Thin:style=Thin,Regular
- NotoSerif-SemiCondensedExtraBoldItalic.ttf: Noto Serif,Noto Serif SemCond ExtBd:style=SemiCondensed ExtraBold Italic,Italic
- NotoSerifHebrew-CondensedMedium.ttf: Noto Serif Hebrew,Noto Serif Hebrew Cond Med:style=Condensed Medium,Regular
- NotoSansSinhalaUI-SemiCondensedThin.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSansTamil-CondensedBlack.ttf: Noto Sans Tamil,Noto Sans Tamil Cond Blk:style=Condensed Black,Regular
- NotoSerifHebrew-CondensedBlack.ttf: Noto Serif Hebrew,Noto Serif Hebrew Cond Blk:style=Condensed Black,Regular
- NotoSansUgaritic-Regular.ttf: Noto Sans Ugaritic:style=Regular
- NotoSansMyanmar-ExtraCondensedExtraLight.ttf: Noto Sans Myanmar,Noto Sans Myanmar ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansSymbols2-Regular.ttf: Noto Sans Symbols2:style=Regular
- NotoSansKhmer-ExtraCondensedExtraLight.ttf: Noto Sans Khmer,Noto Sans Khmer ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansHebrew-CondensedThin.ttf: Noto Sans Hebrew,Noto Sans Hebrew Cond Thin:style=Condensed Thin,Regular
- NotoSansGeorgian-Condensed.ttf: Noto Sans Georgian,Noto Sans Georgian Cond:style=Condensed,Regular
- NotoSerifCJKkr-SemiBold.otf: Noto Serif CJK KR,Noto Serif CJK KR SemiBold:style=SemiBold,Regular
- NotoSerifDisplay-ExtraCondensedLight.ttf: Noto Serif Display,Noto Serif Disp ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSansOriyaUI-Bold.ttf: Noto Sans Oriya UI:style=Bold
- a010015l.pfb: URW Gothic L:style=Demi
- NotoSansMyanmarUI-SemiCondensedExtraLight.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI SmCn XLt:style=SemiCondensed ExtraLight,Regular
- NotoSansArmenian-CondensedExtraBold.ttf: Noto Sans Armenian,Noto Sans Armenian Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansLaoUI-SemiCondensedLight.ttf: Noto Sans Lao UI,Noto Sans Lao UI SemCond Light:style=SemiCondensed Light,Regular
- NotoSansBengali-Regular.ttf: Noto Sans Bengali:style=Regular
- NotoSansSinhalaUI-Thin.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala Thin:style=Thin,Regular
- NotoSerifMyanmar-ExtraCondensedExtraBold.ttf: Noto Serif Myanmar,Noto Serif Myanmar ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSerifDisplay-ExtraCondensedMedium.ttf: Noto Serif Display,Noto Serif Disp ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansLao-Black.ttf: Noto Sans Lao,Noto Sans Lao Blk:style=Black,Regular
- NotoSans-ExtraCondensedBlackItalic.ttf: Noto Sans,Noto Sans ExtCond Blk:style=ExtraCondensed Black Italic,Italic
- NotoSansThai-ExtraCondensedExtraBold.ttf: Noto Sans Thai,Noto Sans Thai ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansKhmer-SemiCondensed.ttf: Noto Sans Khmer,Noto Sans Khmer SemCond:style=SemiCondensed,Regular
- NotoSansDevanagari-CondensedMedium.ttf: Noto Sans Devanagari,Noto Sans Devanagari Cn Md:style=Condensed Medium,Regular
- NotoSansGeorgian-ExtraCondensedExtraBold.ttf: Noto Sans Georgian,Noto Sans Georgian ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansSinhala-SemiCondensedThin.ttf: Noto Sans Sinhala,Noto Sans Sinhala SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSerifLao-CondensedThin.ttf: Noto Serif Lao,Noto Serif Lao Cond Thin:style=Condensed Thin,Regular
- NotoSansTamilUI-ExtraCondensedExtraBold.ttf: Noto Sans Tamil UI,Noto Sans Tamil ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSerif-ExtraCondensedBoldItalic.ttf: Noto Serif,Noto Serif ExtCond:style=ExtraCondensed Bold Italic,Bold Italic
- NotoSansArmenian-CondensedMedium.ttf: Noto Sans Armenian,Noto Sans Armenian Cond Med:style=Condensed Medium,Regular
- NotoSansMyanmarUI-ExtraCondensedThin.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI XCn Th:style=ExtraCondensed Thin,Regular
- NotoSansMyanmarUI-CondensedMedium.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI Cn Md:style=Condensed Medium,Regular
- NotoSerifDisplay-SemiCondensedBold.ttf: Noto Serif Display,Noto Serif Disp SemCond:style=SemiCondensed Bold,Bold
- NotoSerifThai-ExtraCondensedBold.ttf: Noto Serif Thai,Noto Serif Thai ExtCond:style=ExtraCondensed Bold,Bold
- NotoSans-SemiCondensedExtraBold.ttf: Noto Sans,Noto Sans SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- URWGothic-Book.t1: URW Gothic:style=Book
- NotoSerifCJKkr-Bold.otf: Noto Serif CJK KR:style=Bold
- NotoSansDisplay-ExtraCondensed.ttf: Noto Sans Display,Noto Sans Disp ExtCond:style=ExtraCondensed,Regular
- NotoSansDevanagariUI-CondensedExtraBold.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari Cn XBd:style=Condensed ExtraBold,Regular
- NotoSansArabicUI-Medium.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI Md:style=Medium,Regular
- DejaVuSansMono-Bold.ttf: DejaVu Sans Mono:style=Bold
- NimbusRoman-Regular.t1: Nimbus Roman:style=Regular
- NotoSansMyanmar-ExtraCondensedExtraBold.ttf: Noto Sans Myanmar,Noto Sans Myanmar ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NimbusMonoPS-Regular.otf: Nimbus Mono PS:style=Regular
- NotoSerifKhmer-Regular.ttf: Noto Serif Khmer:style=Regular
- NotoSans-ExtraCondensedBold.ttf: Noto Sans,Noto Sans ExtCond:style=ExtraCondensed Bold,Bold
- NotoSansEthiopic-SemiCondensedExtraBold.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NimbusSansNarrow-Regular.otf: Nimbus Sans Narrow:style=Regular
- NotoSansDisplay-ExtraCondensedSemiBoldItalic.ttf: Noto Sans Display,Noto Sans Disp ExtCond SemBd:style=ExtraCondensed SemiBold Italic,Italic
- NotoSansArabic-ExtraLight.ttf: Noto Sans Arabic,Noto Sans Arabic ExtLt:style=ExtraLight,Regular
- NotoSerifDisplay-ExtraLight.ttf: Noto Serif Display,Noto Serif Disp ExtLt:style=ExtraLight,Regular
- NotoSerifDevanagari-Regular.ttf: Noto Serif Devanagari:style=Regular
- NotoSerifThai-CondensedBlack.ttf: Noto Serif Thai,Noto Serif Thai Cond Blk:style=Condensed Black,Regular
- NotoSansKharoshthi-Regular.ttf: Noto Sans Kharoshthi:style=Regular
- NotoSansKhmer-CondensedSemiBold.ttf: Noto Sans Khmer,Noto Sans Khmer Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansArabic-ExtraCondensed.ttf: Noto Sans Arabic,Noto Sans Arabic ExtCond:style=ExtraCondensed,Regular
- n019043l.pfb: Nimbus Sans L:style=Regular Condensed
- NotoSerif-SemiCondensedBoldItalic.ttf: Noto Serif,Noto Serif SemCond:style=SemiCondensed Bold Italic,Bold Italic
- NotoSansDevanagari-CondensedExtraLight.ttf: Noto Sans Devanagari,Noto Sans Devanagari Cn XLt:style=Condensed ExtraLight,Regular
- NotoSerifArmenian-Regular.ttf: Noto Serif Armenian:style=Regular
- NotoSerifDisplay-ExtraCondensedMediumItalic.ttf: Noto Serif Display,Noto Serif Disp ExtCond Med:style=ExtraCondensed Medium Italic,Italic
- NotoSansMono-ExtraLight.ttf: Noto Sans Mono,Noto Sans Mono ExtLt:style=ExtraLight,Regular
- NotoSansKhmer-ExtraCondensedThin.ttf: Noto Sans Khmer,Noto Sans Khmer ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSerifSinhala-Medium.ttf: Noto Serif Sinhala,Noto Serif Sinhala Med:style=Medium,Regular
- NotoSansSinhalaUI-CondensedExtraBold.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansDeseret-Regular.ttf: Noto Sans Deseret:style=Regular
- NotoSerifHebrew-CondensedExtraBold.ttf: Noto Serif Hebrew,Noto Serif Hebrew Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansThaiUI-SemiCondensedBlack.ttf: Noto Sans Thai UI,Noto Sans Thai UI SemCond Blk:style=SemiCondensed Black,Regular
- NotoSansEthiopic-ExtraBold.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic ExtBd:style=ExtraBold,Regular
- NotoSans-ExtraCondensedExtraLight.ttf: Noto Sans,Noto Sans ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansDisplay-CondensedExtraBoldItalic.ttf: Noto Sans Display,Noto Sans Disp Cond ExtBd:style=Condensed ExtraBold Italic,Italic
- NotoSansDisplay-SemiBoldItalic.ttf: Noto Sans Display,Noto Sans Disp SemBd:style=SemiBold Italic,Italic
- NotoSerifLao-CondensedBold.ttf: Noto Serif Lao,Noto Serif Lao Cond:style=Condensed Bold,Bold
- NotoSansDisplay-SemiCondensedThin.ttf: Noto Sans Display,Noto Sans Disp SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSans-ExtraCondensedThin.ttf: Noto Sans,Noto Sans ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSerif-ExtraCondensedBlack.ttf: Noto Serif,Noto Serif ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSerifDisplay-Black.ttf: Noto Serif Display,Noto Serif Disp Blk:style=Black,Regular
- NotoSansMyanmarUI-CondensedExtraBold.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI Cn XBd:style=Condensed ExtraBold,Regular
- NotoSerifGeorgian-CondensedThin.ttf: Noto Serif Georgian,Noto Serif Georgian Cn Th:style=Condensed Thin,Regular
- NotoSansMyanmar-ExtraCondensedBold.ttf: Noto Sans Myanmar,Noto Sans Myanmar ExtCond:style=ExtraCondensed Bold,Bold
- NotoSerifKhmer-CondensedBlack.ttf: Noto Serif Khmer,Noto Serif Khmer Cond Blk:style=Condensed Black,Regular
- NotoSansDisplay-ExtraLight.ttf: Noto Sans Display,Noto Sans Disp ExtLt:style=ExtraLight,Regular
- NotoSansMyanmarUI-SemiCondensed.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI SmCn:style=SemiCondensed,Regular
- NotoSans-ExtraCondensedMedium.ttf: Noto Sans,Noto Sans ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSerifKhmer-Bold.ttf: Noto Serif Khmer:style=Bold
- NotoSansMyanmar-Thin.ttf: Noto Sans Myanmar,Noto Sans Myanmar Thin:style=Thin,Regular
- NotoSansBengaliUI-Thin.ttf: Noto Sans Bengali UI,Noto Sans Bengali Thin:style=Thin,Regular
- NotoSansDevanagari-SemiCondensedLight.ttf: Noto Sans Devanagari,Noto Sans Devanagari SmCn Lt:style=SemiCondensed Light,Regular
- NotoSerifTamil-ExtraCondensed.ttf: Noto Serif Tamil,Noto Serif Tamil ExtCond:style=ExtraCondensed,Regular
- URWBookman-Demi.otf: URW Bookman:style=Demi
- NotoSansDevanagari-CondensedBlack.ttf: Noto Sans Devanagari,Noto Sans Devanagari Cn Bk:style=Condensed Black,Regular
- NimbusMonoPS-Regular.t1: Nimbus Mono PS:style=Regular
- NotoSerifHebrew-ExtraCondensedThin.ttf: Noto Serif Hebrew,Noto Serif Hebrew ExtCond Thin:style=ExtraCondensed Thin,Regular
- NimbusSans-BoldItalic.t1: Nimbus Sans:style=Bold Italic
- NimbusSans-Bold.t1: Nimbus Sans:style=Bold
- NotoSansDevanagariUI-Regular.ttf: Noto Sans Devanagari UI:style=Regular
- NotoSerifDisplay-ThinItalic.ttf: Noto Serif Display,Noto Serif Disp Thin:style=Thin Italic,Italic
- NotoSansOldItalic-Regular.ttf: Noto Sans Old Italic:style=Regular
- n019044l.pfb: Nimbus Sans L:style=Bold Condensed
- NotoSerifDisplay-SemiBoldItalic.ttf: Noto Serif Display,Noto Serif Disp SemBd:style=SemiBold Italic,Italic
- NotoSerifDisplay-ExtraLightItalic.ttf: Noto Serif Display,Noto Serif Disp ExtLt:style=ExtraLight Italic,Italic
- NotoSerifKhmer-CondensedExtraLight.ttf: Noto Serif Khmer,Noto Serif Khmer Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansAvestan-Regular.ttf: Noto Sans Avestan:style=Regular
- NotoSansCJKjp-Black.otf: Noto Sans CJK JP,Noto Sans CJK JP Black:style=Black,Regular
- NotoSansDevanagari-ExtraCondensed.ttf: Noto Sans Devanagari,Noto Sans Devanagari XCn:style=ExtraCondensed,Regular
- NotoSansMyanmarUI-Condensed.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI Cn:style=Condensed,Regular
- NotoSerifGeorgian-SemiCondensedExtraLight.ttf: Noto Serif Georgian,Noto Serif Georgian SmCn XLt:style=SemiCondensed ExtraLight,Regular
- NotoSerif-Condensed.ttf: Noto Serif,Noto Serif Cond:style=Condensed,Regular
- NotoSansMalayalam-Bold.ttf: Noto Sans Malayalam:style=Bold
- NotoSansArabic-CondensedBold.ttf: Noto Sans Arabic,Noto Sans Arabic Cond:style=Condensed Bold,Bold
- NotoSerifThai-CondensedBold.ttf: Noto Serif Thai,Noto Serif Thai Cond:style=Condensed Bold,Bold
- NimbusMonoPS-BoldItalic.t1: Nimbus Mono PS:style=Bold Italic
- NotoSansTamil-ExtraLight.ttf: Noto Sans Tamil,Noto Sans Tamil ExtLt:style=ExtraLight,Regular
- NotoSerifLao-ExtraCondensedSemiBold.ttf: Noto Serif Lao,Noto Serif Lao ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSansKhmer-CondensedMedium.ttf: Noto Sans Khmer,Noto Sans Khmer Cond Med:style=Condensed Medium,Regular
- NotoSansThaiUI-CondensedBold.ttf: Noto Sans Thai UI,Noto Sans Thai UI Cond:style=Condensed Bold,Bold
- NotoSansThai-ExtraCondensed.ttf: Noto Sans Thai,Noto Sans Thai ExtCond:style=ExtraCondensed,Regular
- NotoSansThaiUI-ExtraCondensedThin.ttf: Noto Sans Thai UI,Noto Sans Thai UI ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSerifArmenian-SemiBold.ttf: Noto Serif Armenian,Noto Serif Armenian SmBd:style=SemiBold,Regular
- NotoSansArabic-ExtraCondensedExtraLight.ttf: Noto Sans Arabic,Noto Sans Arabic ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansThai-ExtraBold.ttf: Noto Sans Thai,Noto Sans Thai ExtBd:style=ExtraBold,Regular
- NotoMono-Regular.ttf: Noto Mono:style=Regular
- NotoSansDisplay-Medium.ttf: Noto Sans Display,Noto Sans Disp Med:style=Medium,Regular
- NotoSerifLao-Medium.ttf: Noto Serif Lao,Noto Serif Lao Med:style=Medium,Regular
- NotoSansKhmer-SemiCondensedBlack.ttf: Noto Sans Khmer,Noto Sans Khmer SemCond Blk:style=SemiCondensed Black,Regular
- NotoSansDisplay-BoldItalic.ttf: Noto Sans Display,Noto Sans Disp:style=Bold Italic
- NotoSansDisplay-SemiCondensedBlack.ttf: Noto Sans Display,Noto Sans Disp SemCond Blk:style=SemiCondensed Black,Regular
- NotoSerifLao-Regular.ttf: Noto Serif Lao:style=Regular
- NotoSansDisplay-ExtraCondensedThinItalic.ttf: Noto Sans Display,Noto Sans Disp ExtCond Thin:style=ExtraCondensed Thin Italic,Italic
- NotoSansMyanmarUI-CondensedSemiBold.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI Cn SmBd:style=Condensed SemiBold,Regular
- NotoSerifHebrew-Light.ttf: Noto Serif Hebrew,Noto Serif Hebrew Light:style=Light,Regular
- NotoSerif-CondensedMediumItalic.ttf: Noto Serif,Noto Serif Cond Med:style=Condensed Medium Italic,Italic
- NotoSansDevanagari-Regular.ttf: Noto Sans Devanagari:style=Regular
- NotoSerifTamil-ExtraCondensedThin.ttf: Noto Serif Tamil,Noto Serif Tamil ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSerifThai-ExtraCondensedMedium.ttf: Noto Serif Thai,Noto Serif Thai ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSans-ExtraCondensedSemiBoldItalic.ttf: Noto Sans,Noto Sans ExtCond SemBd:style=ExtraCondensed SemiBold Italic,Italic
- NotoSansGurmukhi-Regular.ttf: Noto Sans Gurmukhi:style=Regular
- NotoSansMonoCJKkr-Regular.otf: Noto Sans Mono CJK KR,Noto Sans Mono CJK KR Regular:style=Regular
- NotoSerifTamil-ExtraLight.ttf: Noto Serif Tamil,Noto Serif Tamil ExtLt:style=ExtraLight,Regular
- NotoSansCJKtc-Black.otf: Noto Sans CJK TC,Noto Sans CJK TC Black:style=Black,Regular
- NotoSansDisplay-ExtraCondensedItalic.ttf: Noto Sans Display,Noto Sans Disp ExtCond:style=ExtraCondensed Italic,Italic
- NotoSansArabic-ExtraCondensedLight.ttf: Noto Sans Arabic,Noto Sans Arabic ExtCond Light:style=ExtraCondensed Light,Regular
- StandardSymbolsPS.t1: Standard Symbols PS:style=Regular
- NotoSerifArmenian-SemiCondensedThin.ttf: Noto Serif Armenian,Noto Serif Armenian SmCn Th:style=SemiCondensed Thin,Regular
- NotoSerifDisplay-CondensedBlackItalic.ttf: Noto Serif Display,Noto Serif Disp Cond Blk:style=Condensed Black Italic,Italic
- NotoSansArmenian-Condensed.ttf: Noto Sans Armenian,Noto Sans Armenian Cond:style=Condensed,Regular
- NotoSansHebrew-CondensedSemiBold.ttf: Noto Sans Hebrew,Noto Sans Hebrew Cond SemBd:style=Condensed SemiBold,Regular
- NotoSerifGeorgian-ExtraCondensedBlack.ttf: Noto Serif Georgian,Noto Serif Georgian XCn Bk:style=ExtraCondensed Black,Regular
- NotoSansMyanmarUI-ExtraCondensedExtraLight.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI XCn XLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansSinhalaUI-CondensedBold.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala Cond:style=Condensed Bold,Bold
- NotoSansThai-Bold.ttf: Noto Sans Thai:style=Bold
- NotoSans-Bold.ttf: Noto Sans:style=Bold
- URWGothic-Demi.otf: URW Gothic:style=Demi
- NotoSansEthiopic-CondensedSemiBold.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansGujaratiUI-Regular.ttf: Noto Sans Gujarati UI:style=Regular
- NotoSansKhmer-ExtraCondensedSemiBold.ttf: Noto Sans Khmer,Noto Sans Khmer ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- a010033l.pfb: URW Gothic L:style=Book Oblique
- NotoSansDisplay-CondensedBoldItalic.ttf: Noto Sans Display,Noto Sans Disp Cond:style=Condensed Bold Italic,Bold Italic
- NotoSansDisplay-CondensedSemiBoldItalic.ttf: Noto Sans Display,Noto Sans Disp Cond SemBd:style=Condensed SemiBold Italic,Italic
- NotoSansMono-ExtraCondensedExtraLight.ttf: Noto Sans Mono,Noto Sans Mono ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSerifArmenian-ExtraCondensedBold.ttf: Noto Serif Armenian,Noto Serif Armenian XCn:style=ExtraCondensed Bold,Bold
- NotoSerifDisplay-SemiCondensedItalic.ttf: Noto Serif Display,Noto Serif Disp SemCond:style=SemiCondensed Italic,Italic
- NotoSansCuneiform-Regular.ttf: Noto Sans Cuneiform:style=Regular
- NotoSansMyanmarUI-ExtraBold.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI XBd:style=ExtraBold,Regular
- NotoSansDisplay-SemiCondensedExtraBold.ttf: Noto Sans Display,Noto Sans Disp SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSerif-CondensedBoldItalic.ttf: Noto Serif,Noto Serif Cond:style=Condensed Bold Italic,Bold Italic
- NotoSerifTamil-SemiCondensedSemiBold.ttf: Noto Serif Tamil,Noto Serif Tamil SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSerif-SemiCondensedBlackItalic.ttf: Noto Serif,Noto Serif SemCond Blk:style=SemiCondensed Black Italic,Italic
- NotoSansSinhala-CondensedBold.ttf: Noto Sans Sinhala,Noto Sans Sinhala Cond:style=Condensed Bold,Bold
- NotoSansKhmerUI-Regular.ttf: Noto Sans Khmer UI:style=Regular
- NotoSansTamilUI-SemiCondensedLight.ttf: Noto Sans Tamil UI,Noto Sans Tamil SemCond Light:style=SemiCondensed Light,Regular
- NotoSansMyanmar-CondensedBold.ttf: Noto Sans Myanmar,Noto Sans Myanmar Cond:style=Condensed Bold,Bold
- NotoSansTamil-Light.ttf: Noto Sans Tamil,Noto Sans Tamil Light:style=Light,Regular
- NotoSerifEthiopic-CondensedBold.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic Cn:style=Condensed Bold,Bold
- NotoSansHebrew-ExtraCondensedExtraBold.ttf: Noto Sans Hebrew,Noto Sans Hebrew ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansKhmerUI-Bold.ttf: Noto Sans Khmer UI:style=Bold
- NotoSerifArmenian-Light.ttf: Noto Serif Armenian,Noto Serif Armenian Lt:style=Light,Regular
- NotoSerifGeorgian-Bold.ttf: Noto Serif Georgian:style=Bold
- NotoSansTamilUI-Medium.ttf: Noto Sans Tamil UI,Noto Sans Tamil Med:style=Medium,Regular
- NotoSerifTamil-SemiBold.ttf: Noto Serif Tamil,Noto Serif Tamil SemBd:style=SemiBold,Regular
- NotoSansSinhala-ExtraCondensedThin.ttf: Noto Sans Sinhala,Noto Sans Sinhala ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSansMyanmarUI-SemiCondensedMedium.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI SmCn Md:style=SemiCondensed Medium,Regular
- NotoSansThaiUI-CondensedBlack.ttf: Noto Sans Thai UI,Noto Sans Thai UI Cond Blk:style=Condensed Black,Regular
- NotoSerifDisplay-ExtraCondensedExtraBoldItalic.ttf: Noto Serif Display,Noto Serif Disp ExtCond ExtBd:style=ExtraCondensed ExtraBold Italic,Italic
- NotoSansMono-SemiCondensedExtraBold.ttf: Noto Sans Mono,Noto Sans Mono SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansThaiUI-SemiCondensedThin.ttf: Noto Sans Thai UI,Noto Sans Thai UI SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSans-SemiCondensedLight.ttf: Noto Sans,Noto Sans SemCond Light:style=SemiCondensed Light,Regular
- NotoSansMono-Regular.ttf: Noto Sans Mono:style=Regular
- NotoSerif-CondensedSemiBold.ttf: Noto Serif,Noto Serif Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansKhmer-ExtraCondensedBold.ttf: Noto Sans Khmer,Noto Sans Khmer ExtCond:style=ExtraCondensed Bold,Bold
- NotoSansMyanmar-Black.ttf: Noto Sans Myanmar,Noto Sans Myanmar Blk:style=Black,Regular
- NotoSansTamilUI-SemiCondensedBlack.ttf: Noto Sans Tamil UI,Noto Sans Tamil SemCond Blk:style=SemiCondensed Black,Regular
- NotoSerifArmenian-SemiCondensedMedium.ttf: Noto Serif Armenian,Noto Serif Armenian SmCn Md:style=SemiCondensed Medium,Regular
- NotoSans-Light.ttf: Noto Sans,Noto Sans Light:style=Light,Regular
- n021003l.pfb: Nimbus Roman No9 L:style=Regular
- NotoSansMono-SemiCondensed.ttf: Noto Sans Mono,Noto Sans Mono SemCond:style=SemiCondensed,Regular
- NotoSansThaiUI-SemiCondensedSemiBold.ttf: Noto Sans Thai UI,Noto Sans Thai UI SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSerifDisplay-CondensedSemiBold.ttf: Noto Serif Display,Noto Serif Disp Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansMyanmarUI-Black.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI Bk:style=Black,Regular
- NotoSerifThai-SemiCondensedBold.ttf: Noto Serif Thai,Noto Serif Thai SemCond:style=SemiCondensed Bold,Bold
- NotoSerif-SemiCondensedSemiBoldItalic.ttf: Noto Serif,Noto Serif SemCond SemBd:style=SemiCondensed SemiBold Italic,Italic
- s050000l.pfb: Standard Symbols L:style=Regular
- NotoSansArmenian-CondensedExtraLight.ttf: Noto Sans Armenian,Noto Sans Armenian Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSerifLao-SemiCondensed.ttf: Noto Serif Lao,Noto Serif Lao SemCond:style=SemiCondensed,Regular
- NotoSansTamil-SemiCondensedThin.ttf: Noto Sans Tamil,Noto Sans Tamil SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSansMyanmarUI-Bold.ttf: Noto Sans Myanmar UI:style=Bold
- NotoSerifArmenian-CondensedExtraBold.ttf: Noto Serif Armenian,Noto Serif Armenian Cn XBd:style=Condensed ExtraBold,Regular
- NotoSansEthiopic-CondensedExtraBold.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansHebrew-ExtraCondensedSemiBold.ttf: Noto Sans Hebrew,Noto Sans Hebrew ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSansMyanmar-Regular.ttf: Noto Sans Myanmar:style=Regular
- NotoSansArabicUI-SemiCondensedBold.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI SmCn:style=SemiCondensed Bold,Bold
- NotoSansBengaliUI-Bold.ttf: Noto Sans Bengali UI:style=Bold
- NotoSans-ExtraLight.ttf: Noto Sans,Noto Sans ExtLt:style=ExtraLight,Regular
- NotoSerifEthiopic-ExtraCondensedExtraBold.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic XCn XBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansMonoCJKsc-Regular.otf: Noto Sans Mono CJK SC,Noto Sans Mono CJK SC Regular:style=Regular
- NotoSansDevanagariUI-CondensedMedium.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari Cn Md:style=Condensed Medium,Regular
- NotoSerifCJKjp-Medium.otf: Noto Serif CJK JP,Noto Serif CJK JP Medium:style=Medium,Regular
- NotoSerifBengali-Regular.ttf: Noto Serif Bengali:style=Regular
- NotoSerifDisplay-CondensedSemiBoldItalic.ttf: Noto Serif Display,Noto Serif Disp Cond SemBd:style=Condensed SemiBold Italic,Italic
- NotoSansTaiTham-Regular.ttf: Noto Sans Tai Tham:style=Regular
- NotoSansKhmer-ExtraLight.ttf: Noto Sans Khmer,Noto Sans Khmer ExtLt:style=ExtraLight,Regular
- NotoSansBengali-Bold.ttf: Noto Sans Bengali:style=Bold
- NotoSansKannadaUI-Bold.ttf: Noto Sans Kannada UI:style=Bold
- NotoSerifThai-SemiCondensedLight.ttf: Noto Serif Thai,Noto Serif Thai SemCond Light:style=SemiCondensed Light,Regular
- NotoSansTamilUI-ExtraCondensedBlack.ttf: Noto Sans Tamil UI,Noto Sans Tamil ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansArabicUI-ExtraCondensedExtraBold.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI XCn XBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansThaiUI-Regular.ttf: Noto Sans Thai UI:style=Regular
- NotoSans-SemiCondensedLightItalic.ttf: Noto Sans,Noto Sans SemCond Light:style=SemiCondensed Light Italic,Italic
- NotoSansLaoUI-Bold.ttf: Noto Sans Lao UI:style=Bold
- NotoSerif-ExtraBoldItalic.ttf: Noto Serif,Noto Serif ExtBd:style=ExtraBold Italic,Italic
- NotoSerifDisplay-SemiCondensed.ttf: Noto Serif Display,Noto Serif Disp SemCond:style=SemiCondensed,Regular
- NotoSansKhmerUI-SemiCondensedBold.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI SemCond:style=SemiCondensed Bold,Bold
- NotoSansSinhalaUI-SemiCondensedExtraLight.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSans-CondensedLightItalic.ttf: Noto Sans,Noto Sans Cond Light:style=Condensed Light Italic,Italic
- NimbusSansNarrow-Bold.otf: Nimbus Sans Narrow:style=Bold
- URWBookman-DemiItalic.otf: URW Bookman:style=Demi Italic
- NotoSansDisplay-SemiCondensedExtraLightItalic.ttf: Noto Sans Display,Noto Sans Disp SemCond ExtLt:style=SemiCondensed ExtraLight Italic,Italic
- NotoSerif-Italic.ttf: Noto Serif:style=Italic
- NotoSansArabic-ExtraBold.ttf: Noto Sans Arabic,Noto Sans Arabic ExtBd:style=ExtraBold,Regular
- NotoSerifMyanmar-SemiCondensedLight.ttf: Noto Serif Myanmar,Noto Serif Myanmar SemCond Light:style=SemiCondensed Light,Regular
- NotoSansMyanmarUI-CondensedBold.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI Cn:style=Condensed Bold,Bold
- NotoSansCJKjp-Bold.otf: Noto Sans CJK JP,Noto Sans CJK JP Bold:style=Bold,Regular
- URWGothic-BookOblique.otf: URW Gothic:style=Book Oblique
- NotoSerifDisplay-ExtraBoldItalic.ttf: Noto Serif Display,Noto Serif Disp ExtBd:style=ExtraBold Italic,Italic
- NotoSerifTamil-SemiCondensed.ttf: Noto Serif Tamil,Noto Serif Tamil SemCond:style=SemiCondensed,Regular
- b018035l.pfb: URW Bookman L:style=Demi Bold Italic
- NotoSansCherokee-Bold.ttf: Noto Sans Cherokee:style=Bold
- NotoSansThaiUI-Light.ttf: Noto Sans Thai UI,Noto Sans Thai UI Light:style=Light,Regular
- NotoSansKhmer-CondensedThin.ttf: Noto Sans Khmer,Noto Sans Khmer Cond Thin:style=Condensed Thin,Regular
- NotoSerifGeorgian-SemiCondensedExtraBold.ttf: Noto Serif Georgian,Noto Serif Georgian SmCn XBd:style=SemiCondensed ExtraBold,Regular
- NotoNaskhArabic-Bold.ttf: Noto Naskh Arabic:style=Bold
- NotoSerifThai-CondensedExtraBold.ttf: Noto Serif Thai,Noto Serif Thai Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansThai-CondensedBold.ttf: Noto Sans Thai,Noto Sans Thai Cond:style=Condensed Bold,Bold
- NotoSerifArmenian-ExtraCondensedThin.ttf: Noto Serif Armenian,Noto Serif Armenian XCn Th:style=ExtraCondensed Thin,Regular
- NotoSansMyanmar-ExtraLight.ttf: Noto Sans Myanmar,Noto Sans Myanmar ExtLt:style=ExtraLight,Regular
- NotoSansDevanagari-ExtraCondensedExtraLight.ttf: Noto Sans Devanagari,Noto Sans Devanagari XCn XLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansHebrew-Black.ttf: Noto Sans Hebrew,Noto Sans Hebrew Blk:style=Black,Regular
- NotoSansDevanagariUI-SemiCondensedBlack.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari SmCn Bk:style=SemiCondensed Black,Regular
- NotoSerifCJKjp-Light.otf: Noto Serif CJK JP,Noto Serif CJK JP Light:style=Light,Regular
- NotoSerifTamil-SemiCondensedExtraBold.ttf: Noto Serif Tamil,Noto Serif Tamil SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- c059033l.pfb: Century Schoolbook L:style=Italic
- NotoSans-ExtraCondensedItalic.ttf: Noto Sans,Noto Sans ExtCond:style=ExtraCondensed Italic,Italic
- NotoSerifLao-CondensedLight.ttf: Noto Serif Lao,Noto Serif Lao Cond Light:style=Condensed Light,Regular
- NotoSansGeorgian-CondensedLight.ttf: Noto Sans Georgian,Noto Sans Georgian Cond Light:style=Condensed Light,Regular
- NotoSerifGeorgian-Medium.ttf: Noto Serif Georgian,Noto Serif Georgian Md:style=Medium,Regular
- NotoSansLaoUI-SemiCondensedSemiBold.ttf: Noto Sans Lao UI,Noto Sans Lao UI SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSerifCJKkr-Medium.otf: Noto Serif CJK KR,Noto Serif CJK KR Medium:style=Medium,Regular
- NotoSansVai-Regular.ttf: Noto Sans Vai:style=Regular
- NotoSansBengaliUI-Light.ttf: Noto Sans Bengali UI,Noto Sans Bengali Light:style=Light,Regular
- NotoSansOriyaUI-Regular.ttf: Noto Sans Oriya UI:style=Regular
- NotoSansArmenian-Light.ttf: Noto Sans Armenian,Noto Sans Armenian Light:style=Light,Regular
- NotoSansArmenian-SemiBold.ttf: Noto Sans Armenian,Noto Sans Armenian SemBd:style=SemiBold,Regular
- NotoSansMonoCJKjp-Regular.otf: Noto Sans Mono CJK JP,Noto Sans Mono CJK JP Regular:style=Regular
- NotoSansTamilUI-CondensedThin.ttf: Noto Sans Tamil UI,Noto Sans Tamil Cond Thin:style=Condensed Thin,Regular
- NotoSansArabic-SemiCondensedMedium.ttf: Noto Sans Arabic,Noto Sans Arabic SemCond Med:style=SemiCondensed Medium,Regular
- NotoSans-ExtraLightItalic.ttf: Noto Sans,Noto Sans ExtLt:style=ExtraLight Italic,Italic
- NotoSansCherokee-Regular.ttf: Noto Sans Cherokee:style=Regular
- NotoSansThaiUI-SemiCondensedLight.ttf: Noto Sans Thai UI,Noto Sans Thai UI SemCond Light:style=SemiCondensed Light,Regular
- NotoSansInscriptionalParthian-Regular.ttf: Noto Sans Inscriptional Parthian,Noto Sans InsParthi:style=Regular
- NotoSans-CondensedThinItalic.ttf: Noto Sans,Noto Sans Cond Thin:style=Condensed Thin Italic,Italic
- NotoSansBuginese-Regular.ttf: Noto Sans Buginese:style=Regular
- NotoSerifLao-SemiCondensedExtraBold.ttf: Noto Serif Lao,Noto Serif Lao SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansDevanagariUI-SemiCondensedExtraBold.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari SmCn XBd:style=SemiCondensed ExtraBold,Regular
- NotoSansDisplay-Regular.ttf: Noto Sans Display,Noto Sans Disp:style=Regular
- NotoSansMono-SemiBold.ttf: Noto Sans Mono,Noto Sans Mono SemBd:style=SemiBold,Regular
- NotoNaskhArabicUI-Bold.ttf: Noto Naskh Arabic UI:style=Bold
- NotoSansKhmer-ExtraCondensedBlack.ttf: Noto Sans Khmer,Noto Sans Khmer ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansCJKjp-Regular.otf: Noto Sans CJK JP,Noto Sans CJK JP Regular:style=Regular
- NotoSansRejang-Regular.ttf: Noto Sans Rejang:style=Regular
- NotoSansCJKtc-DemiLight.otf: Noto Sans CJK TC,Noto Sans CJK TC DemiLight:style=DemiLight,Regular
- NotoSansTamil-ExtraCondensedBold.ttf: Noto Sans Tamil,Noto Sans Tamil ExtCond:style=ExtraCondensed Bold,Bold
- NotoSerifThai-ExtraLight.ttf: Noto Serif Thai,Noto Serif Thai ExtLt:style=ExtraLight,Regular
- NotoSansKhmerUI-Medium.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI Med:style=Medium,Regular
- NotoSansKhmer-SemiCondensedThin.ttf: Noto Sans Khmer,Noto Sans Khmer SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSansBengaliUI-SemiBold.ttf: Noto Sans Bengali UI,Noto Sans Bengali SemBd:style=SemiBold,Regular
- NotoSerifDisplay-ExtraCondensedThin.ttf: Noto Serif Display,Noto Serif Disp ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSerifBengali-Bold.ttf: Noto Serif Bengali:style=Bold
- NotoSansHebrew-ExtraCondensedMedium.ttf: Noto Sans Hebrew,Noto Sans Hebrew ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansDisplay-LightItalic.ttf: Noto Sans Display,Noto Sans Disp Light:style=Light Italic,Italic
- NotoSerifCJKkr-Regular.otf: Noto Serif CJK KR:style=Regular
- NotoSerifLao-ExtraCondensedExtraLight.ttf: Noto Serif Lao,Noto Serif Lao ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansArabic-Black.ttf: Noto Sans Arabic,Noto Sans Arabic Blk:style=Black,Regular
- NotoSansLaoUI-Black.ttf: Noto Sans Lao UI,Noto Sans Lao UI Blk:style=Black,Regular
- NotoSansSinhalaUI-SemiCondensedBold.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala SemCond:style=SemiCondensed Bold,Bold
- NotoSansHebrew-SemiCondensedExtraBold.ttf: Noto Sans Hebrew,Noto Sans Hebrew SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSerifSinhala-Light.ttf: Noto Serif Sinhala,Noto Serif Sinhala Light:style=Light,Regular
- Z003-MediumItalic.t1: Z003:style=Medium Italic
- NotoSerif-CondensedLight.ttf: Noto Serif,Noto Serif Cond Light:style=Condensed Light,Regular
- NotoSerifMyanmar-Black.ttf: Noto Serif Myanmar,Noto Serif Myanmar Blk:style=Black,Regular
- NotoSansArabic-ExtraCondensedSemiBold.ttf: Noto Sans Arabic,Noto Sans Arabic ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSansThai-SemiCondensedExtraLight.ttf: Noto Sans Thai,Noto Sans Thai SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSerifHebrew-SemiBold.ttf: Noto Serif Hebrew,Noto Serif Hebrew SemBd:style=SemiBold,Regular
- NotoSansKannada-Regular.ttf: Noto Sans Kannada:style=Regular
- NotoSansThaiUI-ExtraBold.ttf: Noto Sans Thai UI,Noto Sans Thai UI ExtBd:style=ExtraBold,Regular
- NotoSerifKhmer-CondensedMedium.ttf: Noto Serif Khmer,Noto Serif Khmer Cond Med:style=Condensed Medium,Regular
- NotoSansEthiopic-Thin.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic Thin:style=Thin,Regular
- NotoSansLaoUI-ExtraCondensedLight.ttf: Noto Sans Lao UI,Noto Sans Lao UI ExtCond Light:style=ExtraCondensed Light,Regular
- P052-BoldItalic.t1: P052:style=Bold Italic
- NotoSerifDisplay-Bold.ttf: Noto Serif Display,Noto Serif Disp:style=Bold
- NotoSerifMyanmar-CondensedBold.ttf: Noto Serif Myanmar,Noto Serif Myanmar Cond:style=Condensed Bold,Bold
- NotoSansThaiUI-ExtraCondensedBold.ttf: Noto Sans Thai UI,Noto Sans Thai UI ExtCond:style=ExtraCondensed Bold,Bold
- NotoSerifThai-Regular.ttf: Noto Serif Thai:style=Regular
- C059-Italic.t1: C059:style=Italic
- NotoEmoji-Regular.ttf: Noto Emoji:style=Regular
- NotoSans-SemiCondensedBlack.ttf: Noto Sans,Noto Sans SemCond Blk:style=SemiCondensed Black,Regular
- NotoSansMyanmar-ExtraBold.ttf: Noto Sans Myanmar,Noto Sans Myanmar ExtBd:style=ExtraBold,Regular
- NotoSansThai-ExtraCondensedThin.ttf: Noto Sans Thai,Noto Sans Thai ExtCond Thin:style=ExtraCondensed Thin,Regular
- a010035l.pfb: URW Gothic L:style=Demi Oblique
- NotoSerif-CondensedExtraLight.ttf: Noto Serif,Noto Serif Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansLaoUI-ExtraCondensedBold.ttf: Noto Sans Lao UI,Noto Sans Lao UI ExtCond:style=ExtraCondensed Bold,Bold
- NotoSansSinhala-Thin.ttf: Noto Sans Sinhala,Noto Sans Sinhala Thin:style=Thin,Regular
- NotoSerif-Bold.ttf: Noto Serif:style=Bold
- NotoSans-BlackItalic.ttf: Noto Sans,Noto Sans Blk:style=Black Italic,Italic
- NotoSerifKhmer-ExtraCondensedThin.ttf: Noto Serif Khmer,Noto Serif Khmer ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSansThaiUI-ExtraLight.ttf: Noto Sans Thai UI,Noto Sans Thai UI ExtLt:style=ExtraLight,Regular
- NotoSerif-SemiCondensedMedium.ttf: Noto Serif,Noto Serif SemCond Med:style=SemiCondensed Medium,Regular
- NotoSansMono-CondensedLight.ttf: Noto Sans Mono,Noto Sans Mono Cond Light:style=Condensed Light,Regular
- NotoSansMono-Bold.ttf: Noto Sans Mono:style=Bold
- NotoSansSinhalaUI-CondensedMedium.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala Cond Med:style=Condensed Medium,Regular
- NotoSerif-CondensedMedium.ttf: Noto Serif,Noto Serif Cond Med:style=Condensed Medium,Regular
- NotoSansDevanagariUI-ExtraCondensedExtraLight.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari XCn XLt:style=ExtraCondensed ExtraLight,Regular
- P052-Roman.t1: P052:style=Roman
- NotoSansKhmerUI-SemiCondensedExtraLight.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSerifHebrew-Medium.ttf: Noto Serif Hebrew,Noto Serif Hebrew Med:style=Medium,Regular
- NotoSerifEthiopic-SemiCondensedLight.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic SmCn Lt:style=SemiCondensed Light,Regular
- NotoSansGeorgian-SemiCondensedExtraLight.ttf: Noto Sans Georgian,Noto Sans Georgian SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSerifArmenian-ExtraBold.ttf: Noto Serif Armenian,Noto Serif Armenian XBd:style=ExtraBold,Regular
- NotoSansArabicUI-CondensedMedium.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI Cn Md:style=Condensed Medium,Regular
- NotoSerifEthiopic-ExtraCondensedMedium.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic XCn Md:style=ExtraCondensed Medium,Regular
- NotoSerifHebrew-CondensedThin.ttf: Noto Serif Hebrew,Noto Serif Hebrew Cond Thin:style=Condensed Thin,Regular
- NotoSerifTamil-CondensedExtraBold.ttf: Noto Serif Tamil,Noto Serif Tamil Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansArabic-SemiCondensedExtraBold.ttf: Noto Sans Arabic,Noto Sans Arabic SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSerif-ExtraCondensedBlackItalic.ttf: Noto Serif,Noto Serif ExtCond Blk:style=ExtraCondensed Black Italic,Italic
- NotoSerifDisplay-ExtraCondensedBold.ttf: Noto Serif Display,Noto Serif Disp ExtCond:style=ExtraCondensed Bold,Bold
- NotoSerifArmenian-SemiCondensedBlack.ttf: Noto Serif Armenian,Noto Serif Armenian SmCn Bk:style=SemiCondensed Black,Regular
- NotoSerifCJKjp-SemiBold.otf: Noto Serif CJK JP,Noto Serif CJK JP SemiBold:style=SemiBold,Regular
- NotoSerifThai-CondensedThin.ttf: Noto Serif Thai,Noto Serif Thai Cond Thin:style=Condensed Thin,Regular
- NotoSansKhmerUI-CondensedExtraLight.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansBengaliUI-ExtraLight.ttf: Noto Sans Bengali UI,Noto Sans Bengali ExtLt:style=ExtraLight,Regular
- NotoSansDisplay-ExtraCondensedLightItalic.ttf: Noto Sans Display,Noto Sans Disp ExtCond Light:style=ExtraCondensed Light Italic,Italic
- NotoSansMyanmar-SemiCondensedBold.ttf: Noto Sans Myanmar,Noto Sans Myanmar SemCond:style=SemiCondensed Bold,Bold
- NotoSerifThai-SemiBold.ttf: Noto Serif Thai,Noto Serif Thai SemBd:style=SemiBold,Regular
- NotoSerifEthiopic-Condensed.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic Cn:style=Condensed,Regular
- NotoSansDevanagariUI-CondensedBold.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari Cn:style=Condensed Bold,Bold
- NotoSansGeorgian-SemiCondensedMedium.ttf: Noto Sans Georgian,Noto Sans Georgian SemCond Med:style=SemiCondensed Medium,Regular
- NotoSerifCJKjp-Regular.otf: Noto Serif CJK JP:style=Regular
- NotoSansThai-CondensedMedium.ttf: Noto Sans Thai,Noto Sans Thai Cond Med:style=Condensed Medium,Regular
- NotoSansArmenian-SemiCondensedBlack.ttf: Noto Sans Armenian,Noto Sans Armenian SemCond Blk:style=SemiCondensed Black,Regular
- NotoSansDevanagariUI-ExtraCondensedThin.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari XCn Th:style=ExtraCondensed Thin,Regular
- NotoSansDisplay-ExtraCondensedBold.ttf: Noto Sans Display,Noto Sans Disp ExtCond:style=ExtraCondensed Bold,Bold
- NotoSansGeorgian-ExtraCondensedBlack.ttf: Noto Sans Georgian,Noto Sans Georgian ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansArabic-SemiCondensedSemiBold.ttf: Noto Sans Arabic,Noto Sans Arabic SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansOldTurkic-Regular.ttf: Noto Sans Old Turkic:style=Regular
- NotoSansEthiopic-SemiCondensedExtraLight.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSansMalayalam-Regular.ttf: Noto Sans Malayalam:style=Regular
- NotoSansHebrew-SemiCondensedMedium.ttf: Noto Sans Hebrew,Noto Sans Hebrew SemCond Med:style=SemiCondensed Medium,Regular
- NotoSans-CondensedSemiBoldItalic.ttf: Noto Sans,Noto Sans Cond SemBd:style=Condensed SemiBold Italic,Italic
- NotoSerifMyanmar-Condensed.ttf: Noto Serif Myanmar,Noto Serif Myanmar Cond:style=Condensed,Regular
- NotoSansSinhala-Medium.ttf: Noto Sans Sinhala,Noto Sans Sinhala Med:style=Medium,Regular
- NimbusRoman-Bold.t1: Nimbus Roman:style=Bold
- NimbusSansNarrow-Oblique.t1: Nimbus Sans Narrow:style=Oblique
- NotoSans-ExtraCondensedExtraBold.ttf: Noto Sans,Noto Sans ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSerifDisplay-SemiBold.ttf: Noto Serif Display,Noto Serif Disp SemBd:style=SemiBold,Regular
- NotoSerifHebrew-SemiCondensedMedium.ttf: Noto Serif Hebrew,Noto Serif Hebrew SemCond Med:style=SemiCondensed Medium,Regular
- NotoSansMongolian-Regular.ttf: Noto Sans Mongolian:style=Regular
- NotoSansMyanmarUI-SemiCondensedBold.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI SmCn:style=SemiCondensed Bold,Bold
- NotoSansBengaliUI-Black.ttf: Noto Sans Bengali UI,Noto Sans Bengali Blk:style=Black,Regular
- NotoSerifHebrew-CondensedLight.ttf: Noto Serif Hebrew,Noto Serif Hebrew Cond Light:style=Condensed Light,Regular
- NotoSansMyanmar-SemiCondensedThin.ttf: Noto Sans Myanmar,Noto Sans Myanmar SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSansDevanagariUI-SemiCondensed.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari SmCn:style=SemiCondensed,Regular
- NotoSansThai-CondensedLight.ttf: Noto Sans Thai,Noto Sans Thai Cond Light:style=Condensed Light,Regular
- NotoSansKhmerUI-ExtraCondensedExtraBold.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansCJKsc-DemiLight.otf: Noto Sans CJK SC,Noto Sans CJK SC DemiLight:style=DemiLight,Regular
- NotoSerifDisplay-SemiCondensedExtraLight.ttf: Noto Serif Display,Noto Serif Disp SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSerifTamil-ExtraCondensedExtraBold.ttf: Noto Serif Tamil,Noto Serif Tamil ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansSinhalaUI-Condensed.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala Cond:style=Condensed,Regular
- NotoSansDisplay-BlackItalic.ttf: Noto Sans Display,Noto Sans Disp Blk:style=Black Italic,Italic
- NotoSansLao-Bold.ttf: Noto Sans Lao:style=Bold
- NotoSans-SemiCondensedExtraBoldItalic.ttf: Noto Sans,Noto Sans SemCond ExtBd:style=SemiCondensed ExtraBold Italic,Italic
- NotoSansCherokee-Light.ttf: Noto Sans Cherokee,Noto Sans Cherokee Light:style=Light,Regular
- NotoSerifGeorgian-CondensedMedium.ttf: Noto Serif Georgian,Noto Serif Georgian Cn Md:style=Condensed Medium,Regular
- NotoSansTamil-ExtraCondensedThin.ttf: Noto Sans Tamil,Noto Sans Tamil ExtCond Thin:style=ExtraCondensed Thin,Regular
- P052-BoldItalic.otf: P052:style=Bold Italic
- NotoSansSinhala-SemiCondensedSemiBold.ttf: Noto Sans Sinhala,Noto Sans Sinhala SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansHebrew-ExtraCondensed.ttf: Noto Sans Hebrew,Noto Sans Hebrew ExtCond:style=ExtraCondensed,Regular
- NotoSansLaoUI-CondensedBlack.ttf: Noto Sans Lao UI,Noto Sans Lao UI Cond Blk:style=Condensed Black,Regular
- NotoSansLaoUI-ExtraCondensedBlack.ttf: Noto Sans Lao UI,Noto Sans Lao UI ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansLydian-Regular.ttf: Noto Sans Lydian:style=Regular
- NotoSansKhmer-SemiCondensedSemiBold.ttf: Noto Sans Khmer,Noto Sans Khmer SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansArabicUI-Bold.ttf: Noto Sans Arabic UI:style=Bold
- NotoSansMono-ExtraCondensedLight.ttf: Noto Sans Mono,Noto Sans Mono ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSerifGeorgian-CondensedBold.ttf: Noto Serif Georgian,Noto Serif Georgian Cn:style=Condensed Bold,Bold
- NotoSerifGeorgian-ExtraLight.ttf: Noto Serif Georgian,Noto Serif Georgian XLt:style=ExtraLight,Regular
- NotoSansKhmer-Regular.ttf: Noto Sans Khmer:style=Regular
- NotoSansDisplay-SemiCondensedSemiBold.ttf: Noto Sans Display,Noto Sans Disp SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSerifArmenian-ExtraLight.ttf: Noto Serif Armenian,Noto Serif Armenian XLt:style=ExtraLight,Regular
- NotoSerifKannada-Regular.ttf: Noto Serif Kannada:style=Regular
- NotoSansCJKtc-Bold.otf: Noto Sans CJK TC,Noto Sans CJK TC Bold:style=Bold,Regular
- NotoSans-SemiCondensedThinItalic.ttf: Noto Sans,Noto Sans SemCond Thin:style=SemiCondensed Thin Italic,Italic
- NotoSansOldPersian-Regular.ttf: Noto Sans Old Persian:style=Regular
- NotoSansMono-SemiCondensedBold.ttf: Noto Sans Mono,Noto Sans Mono SemCond:style=SemiCondensed Bold,Bold
- NotoSans-ExtraCondensedLight.ttf: Noto Sans,Noto Sans ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSansKhmerUI-Light.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI Light:style=Light,Regular
- NotoSansSinhalaUI-ExtraCondensed.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala ExtCond:style=ExtraCondensed,Regular
- NotoSerifCJKsc-Black.otf: Noto Serif CJK SC,Noto Serif CJK SC Black:style=Black,Regular
- NotoSerifEthiopic-SemiCondensedBold.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic SmCn:style=SemiCondensed Bold,Bold
- NotoSansCham-SemiBold.ttf: Noto Sans Cham,Noto Sans Cham SemBd:style=SemiBold,Regular
- NotoSansMono-Bold.ttf: Noto Sans Mono:style=Bold
- NotoSansDisplay-SemiCondensedSemiBoldItalic.ttf: Noto Sans Display,Noto Sans Disp SemCond SemBd:style=SemiCondensed SemiBold Italic,Italic
- NotoSansTamilUI-CondensedExtraLight.ttf: Noto Sans Tamil UI,Noto Sans Tamil Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansSymbols-Regular.ttf: Noto Sans Symbols:style=Regular
- NotoSansTagbanwa-Regular.ttf: Noto Sans Tagbanwa:style=Regular
- NotoSansKhmerUI-ExtraCondensedMedium.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansArmenian-Regular.ttf: Noto Sans Armenian:style=Regular
- NotoSansCJKkr-Regular.otf: Noto Sans CJK KR,Noto Sans CJK KR Regular:style=Regular
- NotoSansMyanmar-CondensedMedium.ttf: Noto Sans Myanmar,Noto Sans Myanmar Cond Med:style=Condensed Medium,Regular
- NotoSansThaiUI-Black.ttf: Noto Sans Thai UI,Noto Sans Thai UI Blk:style=Black,Regular
- NotoSerifEthiopic-CondensedBlack.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic Cn Bk:style=Condensed Black,Regular
- NotoSansEthiopic-SemiCondensedSemiBold.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansKhmerUI-Condensed.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI Cond:style=Condensed,Regular
- NotoSansThaiUI-CondensedSemiBold.ttf: Noto Sans Thai UI,Noto Sans Thai UI Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansMyanmarUI-ExtraCondensedBold.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI XCn:style=ExtraCondensed Bold,Bold
- NotoSerifEthiopic-ExtraBold.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic XBd:style=ExtraBold,Regular
- NotoSerif-SemiCondensedMediumItalic.ttf: Noto Serif,Noto Serif SemCond Med:style=SemiCondensed Medium Italic,Italic
- NotoSansCJKkr-Bold.otf: Noto Sans CJK KR,Noto Sans CJK KR Bold:style=Bold,Regular
- NotoSerifGeorgian-ExtraCondensedExtraBold.ttf: Noto Serif Georgian,Noto Serif Georgian XCn XBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansGeorgian-Regular.ttf: Noto Sans Georgian:style=Regular
- NotoSerifCJKjp-Bold.otf: Noto Serif CJK JP:style=Bold
- NotoSansSymbols-SemiBold.ttf: Noto Sans Symbols,Noto Sans Symbols SemBd:style=SemiBold,Regular
- NotoSerifLao-Light.ttf: Noto Serif Lao,Noto Serif Lao Light:style=Light,Regular
- NotoSerifCJKjp-Black.otf: Noto Serif CJK JP,Noto Serif CJK JP Black:style=Black,Regular
- NotoSansAdlam-Regular.ttf: Noto Sans Adlam:style=Regular
- NotoSansDevanagari-ExtraLight.ttf: Noto Sans Devanagari,Noto Sans Devanagari XLt:style=ExtraLight,Regular
- NotoSerifDisplay-CondensedBlack.ttf: Noto Serif Display,Noto Serif Disp Cond Blk:style=Condensed Black,Regular
- NotoSansTamilUI-CondensedBold.ttf: Noto Sans Tamil UI,Noto Sans Tamil Cond:style=Condensed Bold,Bold
- NotoSansArmenian-ExtraCondensedThin.ttf: Noto Sans Armenian,Noto Sans Armenian ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSerifDisplay-CondensedExtraLightItalic.ttf: Noto Serif Display,Noto Serif Disp Cond ExtLt:style=Condensed ExtraLight Italic,Italic
- NotoSansEthiopic-ExtraCondensedBlack.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansCJKsc-Black.otf: Noto Sans CJK SC,Noto Sans CJK SC Black:style=Black,Regular
- NotoSansThaiUI-CondensedExtraLight.ttf: Noto Sans Thai UI,Noto Sans Thai UI Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansMono-ExtraCondensedSemiBold.ttf: Noto Sans Mono,Noto Sans Mono ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSerifEthiopic-Thin.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic Th:style=Thin,Regular
- NotoSerifEthiopic-ExtraCondensedSemiBold.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic XCn SmBd:style=ExtraCondensed SemiBold,Regular
- NotoSansKhmer-CondensedBold.ttf: Noto Sans Khmer,Noto Sans Khmer Cond:style=Condensed Bold,Bold
- NotoSansDisplay-SemiCondensedBlackItalic.ttf: Noto Sans Display,Noto Sans Disp SemCond Blk:style=SemiCondensed Black Italic,Italic
- NotoSansKaithi-Regular.ttf: Noto Sans Kaithi:style=Regular
- NotoSansYi-Regular.ttf: Noto Sans Yi:style=Regular
- NotoSansArmenian-SemiCondensedExtraBold.ttf: Noto Sans Armenian,Noto Sans Armenian SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSerifKhmer-SemiCondensedExtraLight.ttf: Noto Serif Khmer,Noto Serif Khmer SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoNaskhArabic-Regular.ttf: Noto Naskh Arabic:style=Regular
- NotoSansArabic-Bold.ttf: Noto Sans Arabic:style=Bold
- NotoSansThai-ExtraCondensedExtraLight.ttf: Noto Sans Thai,Noto Sans Thai ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansDisplay-CondensedMediumItalic.ttf: Noto Sans Display,Noto Sans Disp Cond Med:style=Condensed Medium Italic,Italic
- NotoSansDisplay-SemiCondensedLight.ttf: Noto Sans Display,Noto Sans Disp SemCond Light:style=SemiCondensed Light,Regular
- NotoSansSinhalaUI-CondensedSemiBold.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansSinhala-ExtraBold.ttf: Noto Sans Sinhala,Noto Sans Sinhala ExtBd:style=ExtraBold,Regular
- NotoSansMono-Condensed.ttf: Noto Sans Mono,Noto Sans Mono Cond:style=Condensed,Regular
- NotoSerifEthiopic-SemiCondensedThin.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic SmCn Th:style=SemiCondensed Thin,Regular
- NotoSansThai-CondensedExtraBold.ttf: Noto Sans Thai,Noto Sans Thai Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSerif-CondensedExtraLightItalic.ttf: Noto Serif,Noto Serif Cond ExtLt:style=Condensed ExtraLight Italic,Italic
- NotoSerifDisplay-SemiCondensedLight.ttf: Noto Serif Display,Noto Serif Disp SemCond Light:style=SemiCondensed Light,Regular
- NotoSansArmenian-CondensedBold.ttf: Noto Sans Armenian,Noto Sans Armenian Cond:style=Condensed Bold,Bold
- NotoSansThaiUI-CondensedMedium.ttf: Noto Sans Thai UI,Noto Sans Thai UI Cond Med:style=Condensed Medium,Regular
- NotoSansThai-ExtraCondensedSemiBold.ttf: Noto Sans Thai,Noto Sans Thai ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSerifCJKsc-Light.otf: Noto Serif CJK SC,Noto Serif CJK SC Light:style=Light,Regular
- D050000L.t1: D050000L:style=Regular
- NotoSansChakma-Regular.ttf: Noto Sans Chakma:style=Regular
- NotoSerifDisplay-SemiCondensedThinItalic.ttf: Noto Serif Display,Noto Serif Disp SemCond Thin:style=SemiCondensed Thin Italic,Italic
- StandardSymbolsPS.otf: Standard Symbols PS:style=Regular
- NotoSansLao-SemiCondensedLight.ttf: Noto Sans Lao,Noto Sans Lao SemCond Light:style=SemiCondensed Light,Regular
- NotoSansSinhalaUI-SemiCondensedSemiBold.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSerifThai-SemiCondensedThin.ttf: Noto Serif Thai,Noto Serif Thai SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSansThaiUI-ExtraCondensedMedium.ttf: Noto Sans Thai UI,Noto Sans Thai UI ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSerifMyanmar-ExtraCondensedBold.ttf: Noto Serif Myanmar,Noto Serif Myanmar ExtCond:style=ExtraCondensed Bold,Bold
- NotoSerifDisplay-CondensedExtraBold.ttf: Noto Serif Display,Noto Serif Disp Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansSinhala-SemiCondensedBold.ttf: Noto Sans Sinhala,Noto Sans Sinhala SemCond:style=SemiCondensed Bold,Bold
- NotoSerifArmenian-SemiCondensedExtraLight.ttf: Noto Serif Armenian,Noto Serif Armenian SmCn XLt:style=SemiCondensed ExtraLight,Regular
- NotoSerifLao-ExtraCondensedExtraBold.ttf: Noto Serif Lao,Noto Serif Lao ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansThaiUI-SemiCondensedExtraBold.ttf: Noto Sans Thai UI,Noto Sans Thai UI SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSerifCJKtc-ExtraLight.otf: Noto Serif CJK TC,Noto Serif CJK TC ExtraLight:style=ExtraLight,Regular
- NotoSansMono-Medium.ttf: Noto Sans Mono,Noto Sans Mono Med:style=Medium,Regular
- NotoSansDisplay-CondensedExtraLightItalic.ttf: Noto Sans Display,Noto Sans Disp Cond ExtLt:style=Condensed ExtraLight Italic,Italic
- NotoSerifSinhala-ExtraBold.ttf: Noto Serif Sinhala,Noto Serif Sinhala ExtBd:style=ExtraBold,Regular
- NotoSerif-ExtraCondensedSemiBoldItalic.ttf: Noto Serif,Noto Serif ExtCond SemBd:style=ExtraCondensed SemiBold Italic,Italic
- NotoSansArabicUI-SemiCondensedBlack.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI SmCn Bk:style=SemiCondensed Black,Regular
- NotoSerifLao-Thin.ttf: Noto Serif Lao,Noto Serif Lao Thin:style=Thin,Regular
- NotoSansSinhala-ExtraCondensedBlack.ttf: Noto Sans Sinhala,Noto Sans Sinhala ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSerifLao-ExtraCondensedThin.ttf: Noto Serif Lao,Noto Serif Lao ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSerif-CondensedBlack.ttf: Noto Serif,Noto Serif Cond Blk:style=Condensed Black,Regular
- NotoSansEthiopic-ExtraCondensedThin.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSansMono-CondensedBlack.ttf: Noto Sans Mono,Noto Sans Mono Cond Blk:style=Condensed Black,Regular
- NotoSansGlagolitic-Regular.ttf: Noto Sans Glagolitic:style=Regular
- NotoSansThai-SemiCondensedBlack.ttf: Noto Sans Thai,Noto Sans Thai SemCond Blk:style=SemiCondensed Black,Regular
- NotoSerifLao-ExtraCondensedMedium.ttf: Noto Serif Lao,Noto Serif Lao ExtCond Med:style=ExtraCondensed Medium,Regular
- n019023l.pfb: Nimbus Sans L:style=Regular Italic
- NotoSansArabic-ExtraCondensedExtraBold.ttf: Noto Sans Arabic,Noto Sans Arabic ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansSinhalaUI-ExtraLight.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala ExtLt:style=ExtraLight,Regular
- NotoSansHebrew-ExtraCondensedExtraLight.ttf: Noto Sans Hebrew,Noto Sans Hebrew ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSerifThai-Medium.ttf: Noto Serif Thai,Noto Serif Thai Med:style=Medium,Regular
- NotoSansLao-CondensedLight.ttf: Noto Sans Lao,Noto Sans Lao Cond Light:style=Condensed Light,Regular
- NotoSansHebrew-SemiCondensedExtraLight.ttf: Noto Sans Hebrew,Noto Sans Hebrew SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSansMyanmar-SemiCondensed.ttf: Noto Sans Myanmar,Noto Sans Myanmar SemCond:style=SemiCondensed,Regular
- b018012l.pfb: URW Bookman L:style=Light
- NotoSansMandaic-Regular.ttf: Noto Sans Mandaic:style=Regular
- NotoSansDevanagariUI-ExtraCondensedBlack.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari XCn Bk:style=ExtraCondensed Black,Regular
- NotoSansMonoCJKsc-Bold.otf: Noto Sans Mono CJK SC,Noto Sans Mono CJK SC Bold:style=Bold,Regular
- NotoSerif-CondensedExtraBoldItalic.ttf: Noto Serif,Noto Serif Cond ExtBd:style=Condensed ExtraBold Italic,Italic
- NotoSansArabic-ExtraCondensedMedium.ttf: Noto Sans Arabic,Noto Sans Arabic ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSerifCJKsc-Regular.otf: Noto Serif CJK SC:style=Regular
- NotoSansDevanagari-ExtraCondensedBold.ttf: Noto Sans Devanagari,Noto Sans Devanagari XCn:style=ExtraCondensed Bold,Bold
- NotoSansThai-Condensed.ttf: Noto Sans Thai,Noto Sans Thai Cond:style=Condensed,Regular
- NotoSansKhmer-SemiCondensedBold.ttf: Noto Sans Khmer,Noto Sans Khmer SemCond:style=SemiCondensed Bold,Bold
- NotoSerifThai-Thin.ttf: Noto Serif Thai,Noto Serif Thai Thin:style=Thin,Regular
- NotoSansKhmer-SemiBold.ttf: Noto Sans Khmer,Noto Sans Khmer SemBd:style=SemiBold,Regular
- NotoMono-Regular.ttf: Noto Mono:style=Regular
- NotoSansSinhala-CondensedLight.ttf: Noto Sans Sinhala,Noto Sans Sinhala Cond Light:style=Condensed Light,Regular
- NotoSerifArmenian-ExtraCondensedMedium.ttf: Noto Serif Armenian,Noto Serif Armenian XCn Md:style=ExtraCondensed Medium,Regular
- NotoKufiArabic-Bold.ttf: Noto Kufi Arabic:style=Bold
- NotoSansArabic-CondensedExtraLight.ttf: Noto Sans Arabic,Noto Sans Arabic Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSerifDisplay-ExtraCondensed.ttf: Noto Serif Display,Noto Serif Disp ExtCond:style=ExtraCondensed,Regular
- NotoSansDisplay-Thin.ttf: Noto Sans Display,Noto Sans Disp Thin:style=Thin,Regular
- URWGothic-Demi.t1: URW Gothic:style=Demi
- NotoSerifTamil-CondensedExtraLight.ttf: Noto Serif Tamil,Noto Serif Tamil Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansArabicUI-ExtraCondensedLight.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI XCn Lt:style=ExtraCondensed Light,Regular
- NimbusSans-Italic.t1: Nimbus Sans:style=Italic
- C059-BdIta.t1: C059:style=Bold Italic
- NotoSansDevanagari-ExtraCondensedBlack.ttf: Noto Sans Devanagari,Noto Sans Devanagari XCn Bk:style=ExtraCondensed Black,Regular
- NotoSansThaiUI-SemiCondensedMedium.ttf: Noto Sans Thai UI,Noto Sans Thai UI SemCond Med:style=SemiCondensed Medium,Regular
- NotoSansDevanagari-ExtraCondensedMedium.ttf: Noto Sans Devanagari,Noto Sans Devanagari XCn Md:style=ExtraCondensed Medium,Regular
- NotoSerifCJKsc-SemiBold.otf: Noto Serif CJK SC,Noto Serif CJK SC SemiBold:style=SemiBold,Regular
- NotoSansMono-SemiCondensedExtraLight.ttf: Noto Sans Mono,Noto Sans Mono SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSerifHebrew-ExtraCondensed.ttf: Noto Serif Hebrew,Noto Serif Hebrew ExtCond:style=ExtraCondensed,Regular
- NotoSansHebrew-Condensed.ttf: Noto Sans Hebrew,Noto Sans Hebrew Cond:style=Condensed,Regular
- NotoSerifGeorgian-ExtraCondensedBold.ttf: Noto Serif Georgian,Noto Serif Georgian XCn:style=ExtraCondensed Bold,Bold
- NotoSerifThai-ExtraCondensed.ttf: Noto Serif Thai,Noto Serif Thai ExtCond:style=ExtraCondensed,Regular
- NimbusMonoPS-Bold.t1: Nimbus Mono PS:style=Bold
- NotoSansTamil-SemiCondensedMedium.ttf: Noto Sans Tamil,Noto Sans Tamil SemCond Med:style=SemiCondensed Medium,Regular
- c059016l.pfb: Century Schoolbook L:style=Bold
- n022004l.pfb: Nimbus Mono L:style=Bold
- NotoSansCJKtc-Thin.otf: Noto Sans CJK TC,Noto Sans CJK TC Thin:style=Thin,Regular
- NotoSansLao-CondensedExtraBold.ttf: Noto Sans Lao,Noto Sans Lao Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSans-ExtraCondensedThinItalic.ttf: Noto Sans,Noto Sans ExtCond Thin:style=ExtraCondensed Thin Italic,Italic
- NotoSansDevanagari-ExtraCondensedExtraBold.ttf: Noto Sans Devanagari,Noto Sans Devanagari XCn XBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansGeorgian-CondensedThin.ttf: Noto Sans Georgian,Noto Sans Georgian Cond Thin:style=Condensed Thin,Regular
- NotoSansHebrew-CondensedExtraBold.ttf: Noto Sans Hebrew,Noto Sans Hebrew Cond ExtBd:style=Condensed ExtraBold,Regular
- n019024l.pfb: Nimbus Sans L:style=Bold Italic
- NotoSansArmenian-SemiCondensedMedium.ttf: Noto Sans Armenian,Noto Sans Armenian SemCond Med:style=SemiCondensed Medium,Regular
- NotoSansTamil-Black.ttf: Noto Sans Tamil,Noto Sans Tamil Blk:style=Black,Regular
- NotoSerifTamil-CondensedSemiBold.ttf: Noto Serif Tamil,Noto Serif Tamil Cond SemBd:style=Condensed SemiBold,Regular
- NotoSerif-SemiBold.ttf: Noto Serif,Noto Serif SemBd:style=SemiBold,Regular
- NotoSansJavanese-Regular.ttf: Noto Sans Javanese:style=Regular
- NotoSerif-ExtraLight.ttf: Noto Serif,Noto Serif ExtLt:style=ExtraLight,Regular
- NotoSerifGeorgian-CondensedLight.ttf: Noto Serif Georgian,Noto Serif Georgian Cn Lt:style=Condensed Light,Regular
- NotoSansCham-Bold.ttf: Noto Sans Cham:style=Bold
- NotoSansKhmerUI-SemiCondensedBlack.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI SemCond Blk:style=SemiCondensed Black,Regular
- NotoSansArmenian-CondensedThin.ttf: Noto Sans Armenian,Noto Sans Armenian Cond Thin:style=Condensed Thin,Regular
- NotoSansDisplay-ExtraCondensedExtraLightItalic.ttf: Noto Sans Display,Noto Sans Disp ExtCond ExtLt:style=ExtraCondensed ExtraLight Italic,Italic
- NotoSansDevanagariUI-ExtraLight.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari XLt:style=ExtraLight,Regular
- NotoSansDisplay-SemiCondensedMediumItalic.ttf: Noto Sans Display,Noto Sans Disp SemCond Med:style=SemiCondensed Medium Italic,Italic
- b018032l.pfb: URW Bookman L:style=Light Italic
- NotoSans-SemiBoldItalic.ttf: Noto Sans,Noto Sans SemBd:style=SemiBold Italic,Italic
- NotoSerifDisplay-SemiCondensedBoldItalic.ttf: Noto Serif Display,Noto Serif Disp SemCond:style=SemiCondensed Bold Italic,Bold Italic
- NotoSansBrahmi-Regular.ttf: Noto Sans Brahmi:style=Regular
- NotoSansThai-SemiCondensedLight.ttf: Noto Sans Thai,Noto Sans Thai SemCond Light:style=SemiCondensed Light,Regular
- NotoSerifCJKtc-SemiBold.otf: Noto Serif CJK TC,Noto Serif CJK TC SemiBold:style=SemiBold,Regular
- NotoSansArmenian-ExtraCondensedSemiBold.ttf: Noto Sans Armenian,Noto Sans Armenian ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSansLao-SemiBold.ttf: Noto Sans Lao,Noto Sans Lao SemBd:style=SemiBold,Regular
- NotoSansMono-CondensedSemiBold.ttf: Noto Sans Mono,Noto Sans Mono Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansGeorgian-SemiCondensedExtraBold.ttf: Noto Sans Georgian,Noto Sans Georgian SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansArabicUI-Black.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI Bk:style=Black,Regular
- NotoSansMyanmarUI-SemiCondensedSemiBold.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI SmCn SmBd:style=SemiCondensed SemiBold,Regular
- p052003l.pfb: URW Palladio L:style=Roman
- NotoSans-ExtraCondensedBoldItalic.ttf: Noto Sans,Noto Sans ExtCond:style=ExtraCondensed Bold Italic,Bold Italic
- NotoSerifLao-ExtraCondensedBlack.ttf: Noto Serif Lao,Noto Serif Lao ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansOriya-Bold.ttf: Noto Sans Oriya:style=Bold
- NotoSansKhmerUI-Thin.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI Thin:style=Thin,Regular
- NotoSansKayahLi-Regular.ttf: Noto Sans Kayah Li:style=Regular
- NotoSansCham-Thin.ttf: Noto Sans Cham,Noto Sans Cham Thin:style=Thin,Regular
- NotoSerifDisplay-Thin.ttf: Noto Serif Display,Noto Serif Disp Thin:style=Thin,Regular
- NotoSansMonoCJKkr-Bold.otf: Noto Sans Mono CJK KR,Noto Sans Mono CJK KR Bold:style=Bold,Regular
- NotoSans-CondensedThin.ttf: Noto Sans,Noto Sans Cond Thin:style=Condensed Thin,Regular
- NotoSansArabic-ExtraCondensedBold.ttf: Noto Sans Arabic,Noto Sans Arabic ExtCond:style=ExtraCondensed Bold,Bold
- NotoSansCoptic-Regular.ttf: Noto Sans Coptic:style=Regular
- NotoSansDisplay-CondensedBlackItalic.ttf: Noto Sans Display,Noto Sans Disp Cond Blk:style=Condensed Black Italic,Italic
- NotoSansArabicUI-ExtraCondensedSemiBold.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI XCn SmBd:style=ExtraCondensed SemiBold,Regular
- NotoSansSinhalaUI-ExtraCondensedBlack.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSerifEthiopic-SemiCondensedSemiBold.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic SmCn SmBd:style=SemiCondensed SemiBold,Regular
- NotoSerifMyanmar-Medium.ttf: Noto Serif Myanmar,Noto Serif Myanmar Med:style=Medium,Regular
- NotoSerif-CondensedBlackItalic.ttf: Noto Serif,Noto Serif Cond Blk:style=Condensed Black Italic,Italic
- NotoSansKhmerUI-SemiCondensedExtraBold.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansKhmerUI-SemiCondensedMedium.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI SemCond Med:style=SemiCondensed Medium,Regular
- NotoSansSinhalaUI-Regular.ttf: Noto Sans Sinhala UI:style=Regular
- NotoSansThai-Light.ttf: Noto Sans Thai,Noto Sans Thai Light:style=Light,Regular
- NotoSerifKhmer-SemiCondensedBlack.ttf: Noto Serif Khmer,Noto Serif Khmer SemCond Blk:style=SemiCondensed Black,Regular
- NotoSansThaiUI-ExtraCondensedExtraBold.ttf: Noto Sans Thai UI,Noto Sans Thai UI ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansSinhalaUI-SemiCondensedBlack.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala SemCond Blk:style=SemiCondensed Black,Regular
- NotoSerifHebrew-ExtraCondensedExtraLight.ttf: Noto Serif Hebrew,Noto Serif Hebrew ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSerifMyanmar-Light.ttf: Noto Serif Myanmar,Noto Serif Myanmar Light:style=Light,Regular
- NotoSansSymbols-Thin.ttf: Noto Sans Symbols,Noto Sans Symbols Thin:style=Thin,Regular
- URWGothic-DemiOblique.otf: URW Gothic:style=Demi Oblique
- NotoSansTamilUI-ExtraCondensedSemiBold.ttf: Noto Sans Tamil UI,Noto Sans Tamil ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSerifArmenian-CondensedSemiBold.ttf: Noto Serif Armenian,Noto Serif Armenian Cn SmBd:style=Condensed SemiBold,Regular
- NotoSansArabicUI-CondensedLight.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI Cn Lt:style=Condensed Light,Regular
- NotoSansCJKsc-Regular.otf: Noto Sans CJK SC,Noto Sans CJK SC Regular:style=Regular
- NotoSansMyanmar-CondensedBlack.ttf: Noto Sans Myanmar,Noto Sans Myanmar Cond Blk:style=Condensed Black,Regular
- NotoSansBatak-Regular.ttf: Noto Sans Batak:style=Regular
- NotoSansSinhala-CondensedSemiBold.ttf: Noto Sans Sinhala,Noto Sans Sinhala Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansArmenian-ExtraCondensedBlack.ttf: Noto Sans Armenian,Noto Sans Armenian ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansLaoUI-SemiCondensedExtraLight.ttf: Noto Sans Lao UI,Noto Sans Lao UI SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSansArabicUI-ExtraCondensedMedium.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI XCn Md:style=ExtraCondensed Medium,Regular
- NotoSerifDisplay-CondensedBold.ttf: Noto Serif Display,Noto Serif Disp Cond:style=Condensed Bold,Bold
- NotoSansHebrew-CondensedBlack.ttf: Noto Sans Hebrew,Noto Sans Hebrew Cond Blk:style=Condensed Black,Regular
- NotoSansMyanmar-CondensedThin.ttf: Noto Sans Myanmar,Noto Sans Myanmar Cond Thin:style=Condensed Thin,Regular
- NotoSansKhmerUI-ExtraBold.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI ExtBd:style=ExtraBold,Regular
- NotoSansMono-ExtraCondensed.ttf: Noto Sans Mono,Noto Sans Mono ExtCond:style=ExtraCondensed,Regular
- NotoSansTamil-SemiBold.ttf: Noto Sans Tamil,Noto Sans Tamil SemBd:style=SemiBold,Regular
- NotoSerifThai-SemiCondensedSemiBold.ttf: Noto Serif Thai,Noto Serif Thai SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSerifTamil-CondensedThin.ttf: Noto Serif Tamil,Noto Serif Tamil Cond Thin:style=Condensed Thin,Regular
- NotoSerifLao-SemiCondensedBold.ttf: Noto Serif Lao,Noto Serif Lao SemCond:style=SemiCondensed Bold,Bold
- NotoSans-LightItalic.ttf: Noto Sans,Noto Sans Light:style=Light Italic,Italic
- NotoSerifDisplay-ExtraCondensedExtraLightItalic.ttf: Noto Serif Display,Noto Serif Disp ExtCond ExtLt:style=ExtraCondensed ExtraLight Italic,Italic
- P052-Bold.t1: P052:style=Bold
- NotoSerifTamil-ExtraCondensedMedium.ttf: Noto Serif Tamil,Noto Serif Tamil ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansMyanmarUI-ExtraCondensed.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI XCn:style=ExtraCondensed,Regular
- NotoSansGeorgian-CondensedExtraBold.ttf: Noto Sans Georgian,Noto Sans Georgian Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansLao-ExtraCondensedThin.ttf: Noto Sans Lao,Noto Sans Lao ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSansCJKsc-Medium.otf: Noto Sans CJK SC,Noto Sans CJK SC Medium:style=Medium,Regular
- NotoSansDisplay-Bold.ttf: Noto Sans Display,Noto Sans Disp:style=Bold
- NotoSansMyanmarUI-ExtraCondensedSemiBold.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI XCn SmBd:style=ExtraCondensed SemiBold,Regular
- NotoSansDevanagari-SemiCondensedExtraBold.ttf: Noto Sans Devanagari,Noto Sans Devanagari SmCn XBd:style=SemiCondensed ExtraBold,Regular
- NotoSansEthiopic-SemiCondensedBlack.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic SemCond Blk:style=SemiCondensed Black,Regular
- NotoSerifArmenian-CondensedLight.ttf: Noto Serif Armenian,Noto Serif Armenian Cn Lt:style=Condensed Light,Regular
- NotoSerifEthiopic-ExtraLight.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic XLt:style=ExtraLight,Regular
- NotoSansDisplay-CondensedExtraLight.ttf: Noto Sans Display,Noto Sans Disp Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSerifGeorgian-SemiCondensedBold.ttf: Noto Serif Georgian,Noto Serif Georgian SmCn:style=SemiCondensed Bold,Bold
- NotoSansDevanagariUI-Bold.ttf: Noto Sans Devanagari UI:style=Bold
- NotoSansMyanmarUI-SemiCondensedLight.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI SmCn Lt:style=SemiCondensed Light,Regular
- NotoSansEthiopic-CondensedExtraLight.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSans-SemiCondensedBoldItalic.ttf: Noto Sans,Noto Sans SemCond:style=SemiCondensed Bold Italic,Bold Italic
- NotoSansArmenian-ExtraCondensedBold.ttf: Noto Sans Armenian,Noto Sans Armenian ExtCond:style=ExtraCondensed Bold,Bold
- NotoSansSinhalaUI-ExtraCondensedMedium.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSerifMyanmar-SemiBold.ttf: Noto Serif Myanmar,Noto Serif Myanmar SemBd:style=SemiBold,Regular
- NotoSansDevanagariUI-SemiCondensedExtraLight.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari SmCn XLt:style=SemiCondensed ExtraLight,Regular
- NotoSerifHebrew-SemiCondensedThin.ttf: Noto Serif Hebrew,Noto Serif Hebrew SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSerifTamil-SemiCondensedLight.ttf: Noto Serif Tamil,Noto Serif Tamil SemCond Light:style=SemiCondensed Light,Regular
- NotoSansEthiopic-ExtraCondensed.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic ExtCond:style=ExtraCondensed,Regular
- NotoSerifEthiopic-SemiCondensed.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic SmCn:style=SemiCondensed,Regular
- NotoSerif-Regular.ttf: Noto Serif:style=Regular
- NotoSansMyanmar-CondensedExtraLight.ttf: Noto Sans Myanmar,Noto Sans Myanmar Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansKhmer-ExtraBold.ttf: Noto Sans Khmer,Noto Sans Khmer ExtBd:style=ExtraBold,Regular
- NotoSansMyanmarUI-Thin.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI Th:style=Thin,Regular
- NotoSerifMyanmar-ExtraLight.ttf: Noto Serif Myanmar,Noto Serif Myanmar ExtLt:style=ExtraLight,Regular
- NotoSerifDisplay-Light.ttf: Noto Serif Display,Noto Serif Disp Light:style=Light,Regular
- n019004l.pfb: Nimbus Sans L:style=Bold
- NotoSansHebrew-Regular.ttf: Noto Sans Hebrew:style=Regular
- NotoSansGeorgian-Light.ttf: Noto Sans Georgian,Noto Sans Georgian Light:style=Light,Regular
- NotoSansArmenian-ExtraLight.ttf: Noto Sans Armenian,Noto Sans Armenian ExtLt:style=ExtraLight,Regular
- b018015l.pfb: URW Bookman L:style=Demi Bold
- NotoSerif-BoldItalic.ttf: Noto Serif:style=Bold Italic
- NotoSerif-SemiCondensedExtraLight.ttf: Noto Serif,Noto Serif SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSerifTamil-ExtraCondensedBold.ttf: Noto Serif Tamil,Noto Serif Tamil ExtCond:style=ExtraCondensed Bold,Bold
- NotoSansSinhala-ExtraCondensedMedium.ttf: Noto Sans Sinhala,Noto Sans Sinhala ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansTamil-SemiCondensedSemiBold.ttf: Noto Sans Tamil,Noto Sans Tamil SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansArabic-SemiCondensedExtraLight.ttf: Noto Sans Arabic,Noto Sans Arabic SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSerifTamil-CondensedLight.ttf: Noto Serif Tamil,Noto Serif Tamil Cond Light:style=Condensed Light,Regular
- NotoSansLaoUI-ExtraLight.ttf: Noto Sans Lao UI,Noto Sans Lao UI ExtLt:style=ExtraLight,Regular
- NotoSansSinhalaUI-ExtraCondensedExtraBold.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansLao-ExtraCondensed.ttf: Noto Sans Lao,Noto Sans Lao ExtCond:style=ExtraCondensed,Regular
- NotoSansHebrew-SemiCondensedLight.ttf: Noto Sans Hebrew,Noto Sans Hebrew SemCond Light:style=SemiCondensed Light,Regular
- NotoSansEthiopic-ExtraCondensedExtraBold.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansKhmer-SemiCondensedExtraBold.ttf: Noto Sans Khmer,Noto Sans Khmer SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansTeluguUI-Bold.ttf: Noto Sans Telugu UI:style=Bold
- NotoSansDevanagariUI-Thin.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari Th:style=Thin,Regular
- n022024l.pfb: Nimbus Mono L:style=Bold Oblique
- NotoSerifTamil-CondensedBlack.ttf: Noto Serif Tamil,Noto Serif Tamil Cond Blk:style=Condensed Black,Regular
- NotoSansMono-SemiCondensedSemiBold.ttf: Noto Sans Mono,Noto Sans Mono SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansSinhala-ExtraCondensedLight.ttf: Noto Sans Sinhala,Noto Sans Sinhala ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSerif-SemiCondensedThinItalic.ttf: Noto Serif,Noto Serif SemCond Thin:style=SemiCondensed Thin Italic,Italic
- NotoSansDevanagari-CondensedBold.ttf: Noto Sans Devanagari,Noto Sans Devanagari Cn:style=Condensed Bold,Bold
- NotoSerifKhmer-Medium.ttf: Noto Serif Khmer,Noto Serif Khmer Med:style=Medium,Regular
- NotoSansPhagsPa-Regular.ttf: Noto Sans Phags Pa:style=Regular
- P052-Italic.t1: P052:style=Italic
- NotoSansKhmerUI-ExtraCondensedLight.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSansDisplay-ExtraCondensedLight.ttf: Noto Sans Display,Noto Sans Disp ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSansMyanmar-ExtraCondensedBlack.ttf: Noto Sans Myanmar,Noto Sans Myanmar ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSerif-ExtraCondensedThinItalic.ttf: Noto Serif,Noto Serif ExtCond Thin:style=ExtraCondensed Thin Italic,Italic
- NotoSerifMyanmar-ExtraCondensedMedium.ttf: Noto Serif Myanmar,Noto Serif Myanmar ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSerifArmenian-ExtraCondensedLight.ttf: Noto Serif Armenian,Noto Serif Armenian XCn Lt:style=ExtraCondensed Light,Regular
- NotoSansLao-SemiCondensedThin.ttf: Noto Sans Lao,Noto Sans Lao SemCond Thin:style=SemiCondensed Thin,Regular
- NotoSansThaiUI-ExtraCondensed.ttf: Noto Sans Thai UI,Noto Sans Thai UI ExtCond:style=ExtraCondensed,Regular
- NotoSansPhoenician-Regular.ttf: Noto Sans Phoenician:style=Regular
- NotoSansSinhala-CondensedThin.ttf: Noto Sans Sinhala,Noto Sans Sinhala Cond Thin:style=Condensed Thin,Regular
- NotoSansDisplay-ExtraCondensedSemiBold.ttf: Noto Sans Display,Noto Sans Disp ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSansDevanagariUI-SemiCondensedBold.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari SmCn:style=SemiCondensed Bold,Bold
- NotoSerifArmenian-Bold.ttf: Noto Serif Armenian:style=Bold
- NotoSansGeorgian-ExtraCondensedSemiBold.ttf: Noto Sans Georgian,Noto Sans Georgian ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSansBengaliUI-Medium.ttf: Noto Sans Bengali UI,Noto Sans Bengali Med:style=Medium,Regular
- NotoSansCJKsc-Light.otf: Noto Sans CJK SC,Noto Sans CJK SC Light:style=Light,Regular
- NotoSansDisplay-ExtraCondensedThin.ttf: Noto Sans Display,Noto Sans Disp ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSansTamilUI-Regular.ttf: Noto Sans Tamil UI:style=Regular
- NotoSansTamilUI-SemiCondensedExtraLight.ttf: Noto Sans Tamil UI,Noto Sans Tamil SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSansDisplay-SemiCondensed.ttf: Noto Sans Display,Noto Sans Disp SemCond:style=SemiCondensed,Regular
- NotoSerifDisplay-SemiCondensedExtraLightItalic.ttf: Noto Serif Display,Noto Serif Disp SemCond ExtLt:style=SemiCondensed ExtraLight Italic,Italic
- NimbusSansNarrow-Regular.t1: Nimbus Sans Narrow:style=Regular
- NotoSansBengali-SemiBold.ttf: Noto Sans Bengali,Noto Sans Bengali SemBd:style=SemiBold,Regular
- NotoSansTamilUI-ExtraCondensedThin.ttf: Noto Sans Tamil UI,Noto Sans Tamil ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSerifDisplay-SemiCondensedSemiBold.ttf: Noto Serif Display,Noto Serif Disp SemCond SemBd:style=SemiCondensed SemiBold,Regular
- NotoSansTamil-Regular.ttf: Noto Sans Tamil:style=Regular
- NotoSans-BoldItalic.ttf: Noto Sans:style=Bold Italic
- NotoSansKhmerUI-Black.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI Blk:style=Black,Regular
- NotoSerifDisplay-CondensedMediumItalic.ttf: Noto Serif Display,Noto Serif Disp Cond Med:style=Condensed Medium Italic,Italic
- NotoSerifEthiopic-CondensedExtraBold.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic Cn XBd:style=Condensed ExtraBold,Regular
- NotoSans-ExtraBold.ttf: Noto Sans,Noto Sans ExtBd:style=ExtraBold,Regular
- NotoSansThai-ExtraCondensedBlack.ttf: Noto Sans Thai,Noto Sans Thai ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSerifMyanmar-ExtraBold.ttf: Noto Serif Myanmar,Noto Serif Myanmar ExtBd:style=ExtraBold,Regular
- NotoSans-SemiCondensedExtraLight.ttf: Noto Sans,Noto Sans SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSansLaoUI-ExtraCondensedExtraLight.ttf: Noto Sans Lao UI,Noto Sans Lao UI ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSerifKhmer-ExtraCondensed.ttf: Noto Serif Khmer,Noto Serif Khmer ExtCond:style=ExtraCondensed,Regular
- NotoSansDevanagari-SemiCondensedThin.ttf: Noto Sans Devanagari,Noto Sans Devanagari SmCn Th:style=SemiCondensed Thin,Regular
- NotoSerifEthiopic-ExtraCondensedLight.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic XCn Lt:style=ExtraCondensed Light,Regular
- NotoSansEthiopic-ExtraLight.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic ExtLt:style=ExtraLight,Regular
- NotoSansDisplay-SemiCondensedThinItalic.ttf: Noto Sans Display,Noto Sans Disp SemCond Thin:style=SemiCondensed Thin Italic,Italic
- NotoSerifGeorgian-SemiCondensedSemiBold.ttf: Noto Serif Georgian,Noto Serif Georgian SmCn SmBd:style=SemiCondensed SemiBold,Regular
- NotoSansKhmer-Bold.ttf: Noto Sans Khmer:style=Bold
- NotoSansLao-SemiCondensed.ttf: Noto Sans Lao,Noto Sans Lao SemCond:style=SemiCondensed,Regular
- NotoSansMono-CondensedExtraBold.ttf: Noto Sans Mono,Noto Sans Mono Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansMono-ExtraCondensedBold.ttf: Noto Sans Mono,Noto Sans Mono ExtCond:style=ExtraCondensed Bold,Bold
- NotoSansTeluguUI-Regular.ttf: Noto Sans Telugu UI:style=Regular
- NotoSansHebrew-ExtraCondensedBold.ttf: Noto Sans Hebrew,Noto Sans Hebrew ExtCond:style=ExtraCondensed Bold,Bold
- NotoSerifCJKkr-ExtraLight.otf: Noto Serif CJK KR,Noto Serif CJK KR ExtraLight:style=ExtraLight,Regular
- NotoSerifKhmer-SemiCondensedBold.ttf: Noto Serif Khmer,Noto Serif Khmer SemCond:style=SemiCondensed Bold,Bold
- NotoSerifArmenian-CondensedThin.ttf: Noto Serif Armenian,Noto Serif Armenian Cn Th:style=Condensed Thin,Regular
- NotoSerifTamil-CondensedBold.ttf: Noto Serif Tamil,Noto Serif Tamil Cond:style=Condensed Bold,Bold
- NotoSerifArmenian-CondensedMedium.ttf: Noto Serif Armenian,Noto Serif Armenian Cn Md:style=Condensed Medium,Regular
- NotoSansLao-Medium.ttf: Noto Sans Lao,Noto Sans Lao Med:style=Medium,Regular
- NotoSerifHebrew-CondensedExtraLight.ttf: Noto Serif Hebrew,Noto Serif Hebrew Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansLaoUI-SemiCondensedBold.ttf: Noto Sans Lao UI,Noto Sans Lao UI SemCond:style=SemiCondensed Bold,Bold
- NotoSansArabic-Light.ttf: Noto Sans Arabic,Noto Sans Arabic Light:style=Light,Regular
- NotoSansKhmerUI-CondensedSemiBold.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansThai-CondensedBlack.ttf: Noto Sans Thai,Noto Sans Thai Cond Blk:style=Condensed Black,Regular
- NotoSansKhmerUI-CondensedBlack.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI Cond Blk:style=Condensed Black,Regular
- NotoSansKhmerUI-ExtraCondensedSemiBold.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI ExtCond SemBd:style=ExtraCondensed SemiBold,Regular
- NotoSansBalinese-Regular.ttf: Noto Sans Balinese:style=Regular
- NotoSansArmenian-ExtraCondensedLight.ttf: Noto Sans Armenian,Noto Sans Armenian ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSerifLao-CondensedBlack.ttf: Noto Serif Lao,Noto Serif Lao Cond Blk:style=Condensed Black,Regular
- NotoSansHebrew-CondensedBold.ttf: Noto Sans Hebrew,Noto Sans Hebrew Cond:style=Condensed Bold,Bold
- NotoSerifCJKkr-Black.otf: Noto Serif CJK KR,Noto Serif CJK KR Black:style=Black,Regular
- NotoSansMyanmarUI-Medium.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI Md:style=Medium,Regular
- NotoSansDisplay-CondensedExtraBold.ttf: Noto Sans Display,Noto Sans Disp Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSansKhmer-ExtraCondensedMedium.ttf: Noto Sans Khmer,Noto Sans Khmer ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansKhmerUI-CondensedMedium.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI Cond Med:style=Condensed Medium,Regular
- NotoSansTamilUI-SemiCondensedExtraBold.ttf: Noto Sans Tamil UI,Noto Sans Tamil SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- C059-Bold.t1: C059:style=Bold
- NotoSansTibetan-Bold.ttf: Noto Sans Tibetan:style=Bold
- NotoSans-CondensedExtraLightItalic.ttf: Noto Sans,Noto Sans Cond ExtLt:style=Condensed ExtraLight Italic,Italic
- NotoSerifMyanmar-Bold.ttf: Noto Serif Myanmar:style=Bold
- NotoSerif-Thin.ttf: Noto Serif,Noto Serif Thin:style=Thin,Regular
- NotoSerif-CondensedSemiBoldItalic.ttf: Noto Serif,Noto Serif Cond SemBd:style=Condensed SemiBold Italic,Italic
- NotoSerifKhmer-SemiCondensed.ttf: Noto Serif Khmer,Noto Serif Khmer SemCond:style=SemiCondensed,Regular
- NotoSansMyanmar-ExtraCondensedLight.ttf: Noto Sans Myanmar,Noto Sans Myanmar ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSansMyanmarUI-ExtraLight.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI XLt:style=ExtraLight,Regular
- NotoSansLao-SemiCondensedBlack.ttf: Noto Sans Lao,Noto Sans Lao SemCond Blk:style=SemiCondensed Black,Regular
- NotoSerif-CondensedExtraBold.ttf: Noto Serif,Noto Serif Cond ExtBd:style=Condensed ExtraBold,Regular
- NotoSerifTamil-Bold.ttf: Noto Serif Tamil:style=Bold
- NotoSerifDisplay-SemiCondensedLightItalic.ttf: Noto Serif Display,Noto Serif Disp SemCond Light:style=SemiCondensed Light Italic,Italic
- NotoSansTamil-SemiCondensedLight.ttf: Noto Sans Tamil,Noto Sans Tamil SemCond Light:style=SemiCondensed Light,Regular
- NotoSansLaoUI-ExtraCondensedExtraBold.ttf: Noto Sans Lao UI,Noto Sans Lao UI ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansArmenian-ExtraCondensed.ttf: Noto Sans Armenian,Noto Sans Armenian ExtCond:style=ExtraCondensed,Regular
- NotoSerifArmenian-CondensedBold.ttf: Noto Serif Armenian,Noto Serif Armenian Cn:style=Condensed Bold,Bold
- NotoSerifDisplay-CondensedThin.ttf: Noto Serif Display,Noto Serif Disp Cond Thin:style=Condensed Thin,Regular
- NotoSansThai-CondensedThin.ttf: Noto Sans Thai,Noto Sans Thai Cond Thin:style=Condensed Thin,Regular
- NotoSerif-ExtraCondensedExtraBoldItalic.ttf: Noto Serif,Noto Serif ExtCond ExtBd:style=ExtraCondensed ExtraBold Italic,Italic
- NotoSerifEthiopic-CondensedThin.ttf: Noto Serif Ethiopic,Noto Serif Ethiopic Cn Th:style=Condensed Thin,Regular
- NotoSerif-ExtraCondensedExtraBold.ttf: Noto Serif,Noto Serif ExtCond ExtBd:style=ExtraCondensed ExtraBold,Regular
- NotoSansMono-Thin.ttf: Noto Sans Mono,Noto Sans Mono Thin:style=Thin,Regular
- NotoSerifEthiopic-Bold.ttf: Noto Serif Ethiopic:style=Bold
- NotoSansDevanagariUI-SemiBold.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari SmBd:style=SemiBold,Regular
- NotoSerifKhmer-ExtraBold.ttf: Noto Serif Khmer,Noto Serif Khmer ExtBd:style=ExtraBold,Regular
- NotoSansCJKtc-Medium.otf: Noto Sans CJK TC,Noto Sans CJK TC Medium:style=Medium,Regular
- NotoSerif-SemiCondensedLightItalic.ttf: Noto Serif,Noto Serif SemCond Light:style=SemiCondensed Light Italic,Italic
- NotoSansDisplay-CondensedThin.ttf: Noto Sans Display,Noto Sans Disp Cond Thin:style=Condensed Thin,Regular
- NotoSansMyanmar-ExtraCondensedMedium.ttf: Noto Sans Myanmar,Noto Sans Myanmar ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSerif-ExtraCondensedExtraLight.ttf: Noto Serif,Noto Serif ExtCond ExtLt:style=ExtraCondensed ExtraLight,Regular
- NotoSansHebrew-CondensedExtraLight.ttf: Noto Sans Hebrew,Noto Sans Hebrew Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansMonoCJKjp-Bold.otf: Noto Sans Mono CJK JP,Noto Sans Mono CJK JP Bold:style=Bold,Regular
- NotoSansSinhalaUI-SemiCondensedExtraBold.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSansTamil-ExtraCondensedLight.ttf: Noto Sans Tamil,Noto Sans Tamil ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSansDevanagari-CondensedExtraBold.ttf: Noto Sans Devanagari,Noto Sans Devanagari Cn XBd:style=Condensed ExtraBold,Regular
- NotoSansGurmukhiUI-Bold.ttf: Noto Sans Gurmukhi UI:style=Bold
- NotoSerifKhmer-ExtraCondensedLight.ttf: Noto Serif Khmer,Noto Serif Khmer ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSansThaiUI-Bold.ttf: Noto Sans Thai UI:style=Bold
- NotoSansSinhala-CondensedExtraLight.ttf: Noto Sans Sinhala,Noto Sans Sinhala Cond ExtLt:style=Condensed ExtraLight,Regular
- c059036l.pfb: Century Schoolbook L:style=Bold Italic
- NotoSerifTamil-Medium.ttf: Noto Serif Tamil,Noto Serif Tamil Med:style=Medium,Regular
- NotoSerif-Light.ttf: Noto Serif,Noto Serif Light:style=Light,Regular
- NotoSerifDisplay-ExtraBold.ttf: Noto Serif Display,Noto Serif Disp ExtBd:style=ExtraBold,Regular
- p052024l.pfb: URW Palladio L:style=Bold Italic
- NotoSansSinhalaUI-Light.ttf: Noto Sans Sinhala UI,Noto Sans Sinhala Light:style=Light,Regular
- NotoSansMyanmarUI-ExtraCondensedExtraBold.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI XCn XBd:style=ExtraCondensed ExtraBold,Regular
- NotoSans-SemiCondensedMediumItalic.ttf: Noto Sans,Noto Sans SemCond Med:style=SemiCondensed Medium Italic,Italic
- NotoSerifGeorgian-ExtraCondensedMedium.ttf: Noto Serif Georgian,Noto Serif Georgian XCn Md:style=ExtraCondensed Medium,Regular
- NotoSansDevanagariUI-CondensedLight.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari Cn Lt:style=Condensed Light,Regular
- URWBookman-Light.t1: URW Bookman:style=Light
- DejaVuSerif.ttf: DejaVu Serif:style=Book
- NotoSansTamil-SemiCondensed.ttf: Noto Sans Tamil,Noto Sans Tamil SemCond:style=SemiCondensed,Regular
- NotoSansDisplay-CondensedBlack.ttf: Noto Sans Display,Noto Sans Disp Cond Blk:style=Condensed Black,Regular
- NotoSansEthiopic-ExtraCondensedMedium.ttf: Noto Sans Ethiopic,Noto Sans Ethiopic ExtCond Med:style=ExtraCondensed Medium,Regular
- NotoSansTibetan-Regular.ttf: Noto Sans Tibetan:style=Regular
- NotoSerifDisplay-SemiCondensedSemiBoldItalic.ttf: Noto Serif Display,Noto Serif Disp SemCond SemBd:style=SemiCondensed SemiBold Italic,Italic
- P052-Roman.otf: P052:style=Roman
- NotoSansLimbu-Regular.ttf: Noto Sans Limbu:style=Regular
- NotoSerifMyanmar-CondensedSemiBold.ttf: Noto Serif Myanmar,Noto Serif Myanmar Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansKhmerUI-ExtraCondensed.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI ExtCond:style=ExtraCondensed,Regular
- NotoSansDisplay-SemiCondensedBoldItalic.ttf: Noto Sans Display,Noto Sans Disp SemCond:style=SemiCondensed Bold Italic,Bold Italic
- NotoSansMyanmar-Light.ttf: Noto Sans Myanmar,Noto Sans Myanmar Light:style=Light,Regular
- NotoSansTifinagh-Regular.ttf: Noto Sans Tifinagh:style=Regular
- NotoSansCypriot-Regular.ttf: Noto Sans Cypriot:style=Regular
- NotoSansLao-SemiCondensedMedium.ttf: Noto Sans Lao,Noto Sans Lao SemCond Med:style=SemiCondensed Medium,Regular
- NotoSerifHebrew-ExtraLight.ttf: Noto Serif Hebrew,Noto Serif Hebrew ExtLt:style=ExtraLight,Regular
- NotoSansArabic-SemiCondensedBold.ttf: Noto Sans Arabic,Noto Sans Arabic SemCond:style=SemiCondensed Bold,Bold
- NotoSerifTamil-SemiCondensedBlack.ttf: Noto Serif Tamil,Noto Serif Tamil SemCond Blk:style=SemiCondensed Black,Regular
- NotoSans-Thin.ttf: Noto Sans,Noto Sans Thin:style=Thin,Regular
- NotoSansSamaritan-Regular.ttf: Noto Sans Samaritan:style=Regular
- NotoSansDisplay-SemiCondensedExtraBoldItalic.ttf: Noto Sans Display,Noto Sans Disp SemCond ExtBd:style=SemiCondensed ExtraBold Italic,Italic
- NotoSansLao-ExtraCondensedBlack.ttf: Noto Sans Lao,Noto Sans Lao ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansSyriacWestern-Regular.ttf: Noto Sans Syriac Western:style=Regular
- NotoSansArmenian-Medium.ttf: Noto Sans Armenian,Noto Sans Armenian Med:style=Medium,Regular
- NotoSansDevanagari-ExtraCondensedSemiBold.ttf: Noto Sans Devanagari,Noto Sans Devanagari XCn SmBd:style=ExtraCondensed SemiBold,Regular
- NotoSansSinhala-SemiCondensedExtraLight.ttf: Noto Sans Sinhala,Noto Sans Sinhala SemCond ExtLt:style=SemiCondensed ExtraLight,Regular
- NotoSerif-Medium.ttf: Noto Serif,Noto Serif Med:style=Medium,Regular
- NotoSansCham-Regular.ttf: Noto Sans Cham:style=Regular
- NotoSansHebrew-SemiCondensedThin.ttf: Noto Sans Hebrew,Noto Sans Hebrew SemCond Thin:style=SemiCondensed Thin,Regular
- C059-Bold.otf: C059:style=Bold
- NotoSansDisplay-ExtraCondensedBlack.ttf: Noto Sans Display,Noto Sans Disp ExtCond Blk:style=ExtraCondensed Black,Regular
- NotoSansHebrew-Light.ttf: Noto Sans Hebrew,Noto Sans Hebrew Light:style=Light,Regular
- NotoSansDevanagari-CondensedSemiBold.ttf: Noto Sans Devanagari,Noto Sans Devanagari Cn SmBd:style=Condensed SemiBold,Regular
- NotoSerifLao-Condensed.ttf: Noto Serif Lao,Noto Serif Lao Cond:style=Condensed,Regular
- P052-Bold.otf: P052:style=Bold
- NotoSansMyanmarUI-SemiBold.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI SmBd:style=SemiBold,Regular
- NotoSansKhmerUI-ExtraCondensedThin.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSansLaoUI-CondensedExtraLight.ttf: Noto Sans Lao UI,Noto Sans Lao UI Cond ExtLt:style=Condensed ExtraLight,Regular
- NotoSansMyanmarUI-CondensedBlack.ttf: Noto Sans Myanmar UI,Noto Sans Myanmar UI Cn Bk:style=Condensed Black,Regular
- NotoSansThai-SemiCondensedMedium.ttf: Noto Sans Thai,Noto Sans Thai SemCond Med:style=SemiCondensed Medium,Regular
- NotoSerifHebrew-SemiCondensedLight.ttf: Noto Serif Hebrew,Noto Serif Hebrew SemCond Light:style=SemiCondensed Light,Regular
- NotoSerifKhmer-ExtraCondensedBold.ttf: Noto Serif Khmer,Noto Serif Khmer ExtCond:style=ExtraCondensed Bold,Bold
- NotoSansTamilUI-ExtraCondensedLight.ttf: Noto Sans Tamil UI,Noto Sans Tamil ExtCond Light:style=ExtraCondensed Light,Regular
- NotoSans-ExtraCondensedExtraLightItalic.ttf: Noto Sans,Noto Sans ExtCond ExtLt:style=ExtraCondensed ExtraLight Italic,Italic
- NotoSansLao-CondensedSemiBold.ttf: Noto Sans Lao,Noto Sans Lao Cond SemBd:style=Condensed SemiBold,Regular
- NotoSerifArmenian-SemiCondensedLight.ttf: Noto Serif Armenian,Noto Serif Armenian SmCn Lt:style=SemiCondensed Light,Regular
- NotoSansDevanagari-SemiCondensedExtraLight.ttf: Noto Sans Devanagari,Noto Sans Devanagari SmCn XLt:style=SemiCondensed ExtraLight,Regular
- NotoSansDevanagari-SemiCondensedMedium.ttf: Noto Sans Devanagari,Noto Sans Devanagari SmCn Md:style=SemiCondensed Medium,Regular
- NotoSerifDisplay-CondensedThinItalic.ttf: Noto Serif Display,Noto Serif Disp Cond Thin:style=Condensed Thin Italic,Italic
- NotoSansLaoUI-CondensedThin.ttf: Noto Sans Lao UI,Noto Sans Lao UI Cond Thin:style=Condensed Thin,Regular
- NotoSansLaoUI-SemiCondensedExtraBold.ttf: Noto Sans Lao UI,Noto Sans Lao UI SemCond ExtBd:style=SemiCondensed ExtraBold,Regular
- NotoSans-SemiBold.ttf: Noto Sans,Noto Sans SemBd:style=SemiBold,Regular
- NotoSansArabicUI-ExtraCondensedExtraLight.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI XCn XLt:style=ExtraCondensed ExtraLight,Regular
- NotoSerifArmenian-ExtraCondensedSemiBold.ttf: Noto Serif Armenian,Noto Serif Armenian XCn SmBd:style=ExtraCondensed SemiBold,Regular
- NotoSerifKhmer-CondensedSemiBold.ttf: Noto Serif Khmer,Noto Serif Khmer Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansArabicUI-ExtraCondensedBold.ttf: Noto Sans Arabic UI,Noto Sans Arabic UI XCn:style=ExtraCondensed Bold,Bold
- NotoSansDevanagariUI-SemiCondensedMedium.ttf: Noto Sans Devanagari UI,Noto Sans Devanagari SmCn Md:style=SemiCondensed Medium,Regular
- NotoSans-Condensed.ttf: Noto Sans,Noto Sans Cond:style=Condensed,Regular
- NimbusRoman-Italic.otf: Nimbus Roman:style=Italic
- NotoSerifLao-CondensedSemiBold.ttf: Noto Serif Lao,Noto Serif Lao Cond SemBd:style=Condensed SemiBold,Regular
- NotoSansKhmerUI-ExtraCondensedBold.ttf: Noto Sans Khmer UI,Noto Sans Khmer UI ExtCond:style=ExtraCondensed Bold,Bold
- n019003l.pfb: Nimbus Sans L:style=Regular
- NotoSans-SemiCondensedBlackItalic.ttf: Noto Sans,Noto Sans SemCond Blk:style=SemiCondensed Black Italic,Italic
- NotoSerif-ExtraCondensedThin.ttf: Noto Serif,Noto Serif ExtCond Thin:style=ExtraCondensed Thin,Regular
- NotoSansMono-ExtraBold.ttf: Noto Sans Mono,Noto Sans Mono ExtBd:style=ExtraBold,Regular
- NotoSansTamilUI-Bold.ttf: Noto Sans Tamil UI:style=Bold
- NotoSerifArmenian-ExtraCondensedExtraBold.ttf: Noto Serif Armenian,Noto Serif Armenian XCn XBd:style=ExtraCondensed ExtraBold,Regular
- NotoSerif-LightItalic.ttf: Noto Serif,Noto Serif Light:style=Light Italic,Italic
- NotoSans-ThinItalic.ttf: Noto Sans,Noto Sans Thin:style=Thin Italic,Italic
- NotoSansTamilUI-SemiCondensedBold.ttf: Noto Sans Tamil UI,Noto Sans Tamil SemCond:style=SemiCondensed Bold,Bold
Operations on Renditions

The API gateway provides the following endpoints for the handling of renditions. The individual operations are documented in the corresponding object’s audit trail.

kind of rendition text pdf slide

Retrieval for current object version

GET /api/dms/objects/{objectId}/contents/renditions/text

GET /api/dms/objects/{objectId}/contents/renditions/pdf

GET /api/dms/objects/{objectId}/contents/renditions/slide

Retrieval for any object version

-

GET /api/dms/objects/{objectId}/versions/{versionNr}/contents/renditions/pdf

GET /api/dms/objects/{objectId}/versions/{versionNr}/contents/renditions/slide

Update

POST /api/dms/objects/{objectId}/contents/renditions/text

-

-

Rendition Repository

A default rendition repository can be configured. Renditions of supported types (listed below) of binary content files assigned to objects can be stored in the default rendition repository. Thus, renditions can be retrieved from storage and are not regenerated for each retrieval request. Whenever a rendition of a supported type is requested for an object, it is retrieved from the default rendition repository. If available, the stored rendition will be returned. If not available, the requested rendition is generated from the binary content file that is assigned to the object, stored in the default rendition repository and finally returned.

The initial generation of a rendition is triggered by its first request.

If a default rendition repository is configured and accessible, the following rendition types are managed in this repository:

Type Content-Type Description

pdf

application/pdf

The PDF representation of the binary content file. No distinction between PDF, PDF/A or PDF with embedded OCR.

slide

image/png

A thumbnail representation of the binary content file.

If the default rendition repository is not available or not configured, any request for a rendition triggers the generation of a new rendition file. The result is returned but not stored in a repository. Thus, for subsequent requests of the same rendition, it has to be regenerated each time.

Asynchronous Full-text Indexing

The asynchronous full-text creation is integrated in the document lifecycle management and controlled by tagging. The operation of the responsable renditiontextworker service requires the following configuration steps.

  • Create a cross-tenant service account for the renditiontextworker service.

  • Configure its credentials via environment variables for the renditiontextworker service:

    • YUUVIS_TENANT - The tenant in which the cross-tenant service account is created.

    • YUUVIS_USER - The username of the cross-tenant service account.

    • YUUVIS_PASSWORD - The password of the cross-tenant service account.

  • Optional: The values can be protected in a Kubernetes secret.

  • Optional: If you want to store the calculated text renditions in the rendition repository, set the parameter rendition.store.text: true in a service-specific YAML configuration file, e.g. renditiontextworker-prod.yml.

The renditiontextworker is called via the preconfigured lifecycle hook in the system hook configuration:

Default lifecycle hook in the 'systemhookconfiguration.json'
{
    "systemhooks": {
        "amqp": [...],
        "lifecycle": [
            ...
            {
                "type" : "dms.request.objects.upsert.database-before",
                "enable" : true,
                "predicate" : "spel:contentStreams != null && contentStreams.size() > 0 && contentStreams[0]['range'] != null",
                "tagname": "system:ren:text",
                "tagstate": 1
            }
            ...
        ],
        "webhooks": [...]
    }
}

2.4.6. Audit Trail

The audit trail is the history protocol of an object, serving to document its entire lifecycle. It is managed by the audit service. There are many different actions that trigger the creation of a new entry in the respective object’s audit trail.

The created audit entries are stored in a separated database table.

If necessary, the creation of specific audit entries can be skipped. Please be aware that the skipped audit entries are actually NOT CREATED ANYWHERE. The corresponding actions on DMS objects in your system will not be documented at all.

The endpoint GET /dms/objects/{objectId}/history endpoint returns the list of audit trail entries for the specified DMS object.

action code detail value subaction code Endpoints triggering the entry Description

Import:

100

OBJECT_CREATED

-

POST /api/dms/objects

The specified object was created by functions of the client or by an import without binary content.

101

OBJECT_CREATED_WITH_CONTENT

-

POST /api/dms/objects

POST /api/dms/uploads/{uploadId}/objects

The object was created using functions of the client or via an import operation including binary content.

110

OBJECT_TAG_CREATED: [<name>, <state>]

<state>

POST /api/dms/objects/{objectId}/tags/{name}/state/{state}

A tag for the object was created.

Deletion:

200

OBJECT_DELETED

-

DELETE /api/dms/objects/{objectId}

DELETE /api/dms/objects/{objectId}/versions/{versionNr}

The object was deleted and cannot be restored.

201

OBJECT_CONTENT_DELETED

-

As of 2023 Summer:

DELETE /api/dms/objects/{objectId}/contents/file

Binary content of the object is removed. A new object version was created that has no contentStreams section anymore.

202

OBJECT_FLAGGED_FOR_DELETE

-

DELETE /api/dms/objects/{objectId}

Object marked for deletion.

210

OBJECT_TAG_DELETED: [<name>, <state>]

<state>

DELETE /api/dms/objects/{objectId}/tags/{name}

The tag for the object was deleted.

220

VERSION_DELETED: [<versionNr>]

-

DELETE /api/dms/objects/{objectId}/versions/{versionNr}

The object version was deleted and cannot be restored.

Update:

300

OBJECT_METADATA_CHANGED

-

POST /api/dms/objects/{objectId}

PATCH /api/dms/objects/{objectId}

The metadata of the object or its status was edited using functions of the client or via an update carried out during the import operation.

301

OBJECT_DOCUMENT_CHANGED

-

DELETE /api/dms/objects/{objectId}/tags/{name}

The document content was edited using functions of the client or via an update carried out during the import operation.

302

OBJECT_METADATA_DOCUMENT_CHANGED

-

POST /api/dms/objects/{objectId} (multipart)

The document content and metadata were both edited within one request.

303

OBJECT_UPDATE_CONTENT_MOVED

-

POST /api/dms/objects/{objectId}/actions/move/contents/repositories/{repositoryId}

POST /api/dms/objects/{objectId}/versions/{versionNr}/actions/move/contents/repositories/{repositoryId}

The object was updated and the binary content was moved.

306

RENDITION_CHANGED

1

As of 2022 Winter:

POST /api/dms/objects/{objectId}/contents/renditions/text

The rendition of the binary content file of a DMS object was added or updated via endpoint. The subaction specifies the type of rendition.

310

OBJECT_TAG_UPDATED: [<name>, <state>]

-

POST /api/dms/objects/{objectId}/tags/{name}/state/{state}?overwrite=true

POST /api/dms/objects/tags/{name}/state/{state}?query=<SQL>

One of the object’s tags was changed.

325

OBJECT_RESTORED_FROM_VERSION: [<versionNr>]

-

POST /api/dms/objects/{objectId}/versions/{versionNr}/actions/restore

The data of the old object version were used to update the current object version.

340

DOCUMENT_MOVED

-

POST /api/dms/objects/{objectId}

PATCH /api/dms/objects/{objectId}

The value for the system:parentId property was modified (added, updated, removed). Additionally, an audit entry with action 300 was created.

Retrieve:

400

DOCUMENT_ACCESSED

-

GET /api/dms/objects/{objectId}/contents/file

GET /api/dms/objects/{objectId}/versions/{versionNr}/contents/file

GET /api/dms/objects/{objectId}/contents/renditions/pdf

The document content was read by the user, printed, or otherwise output. No changes were made.

As of 2022 Summer: If a user retrieves the binary content file of the same object version multiple times within 10 minutes, only the first retrieval is documented in the audit trail.

The following processes internally retrieve the object’s binary content file and thus trigger the creation of an audit entry as well:

  • the first retrieval of a PDF rendition after the object creation

401

METADATA_ACCESSED

-

POST /api/dms/objects/search

GET /api/dms/objects/{objectId}

GET /api/dms/objects/{objectId}/versions

GET /api/dms/objects/{objectId}/contents/renditions/pdf

The object’s metadata were retrieved for viewing.

The following processes internally retrieve the object’s metadata and thus trigger the creation of an audit entry as well:

  • each retrieval of a PDF rendition

402

RENDITION_ACCESSED

1

GET /api/dms/objects/{objectId}/contents/renditions/text

Rendition of the binary content accessed.

If a user retrieves the same type of rendition for the same object multiple times within 10 minutes, only the first retrieval is documented in the audit trail.

The subaction specifies the kind of rendition: 1 - text, 2 - pdf, 3 - slide

2

GET /api/dms/objects/{objectId}/contents/renditions/pdf

3

GET /api/dms/objects/{objectId}/contents/renditions/slide

2.5. Access Management

Any operation via yuuvis® Momentum API requires authentication. The authentication process is managed by the authentication service and an identity provider of customer’s choice. The supported authentication methods are described below.

After successful authentication, a session is opened. The available operations within the session are determined by:

  • endpoint access configuration and

  • role-based permission for DMS operations.

2.5.1. Authentication against the Core API

A yuuvis® Momentum user has to be authenticated in order to be authorized to access to whatever resources or functions his role entitles him too. To achieve this, yuuvis® Momentum connects to an identity provider, which may offer Single Sign-On (SSO) functionality. An existing corporate systems environment usually already uses some sort of identity provider. An identity provider is a software managing user accounts and authentication, the classic example being Microsoft® Active Directory® (AD) or OpenLDAP implementations. Using the yuuvis® Momentum authentication service requires an identity provider to handle authentication by providing the endpoints used in the OAuth 2.0 authorization workflows.

Choosing an Authentication Method

Depending on the circumstances in which your yuuvis® API client application is supposed to authenticate itself, the recommendation toward an authentication method changes. The diagram below shows an example decision process that should be adhered to by developers of yuuvis® API applications.

Decision process to choose a suitable authentication method.
Available Authentication Methods
Authentication Method Purpose

Authorization Code Flow

This type of authentication flow is used to authenticate users coming from either browsers or mobile apps. Unauthenticated calls to the yuuvis® API are redirected to the identity provider, where the user authenticates using whatever method the identity provider is configured for. This can be a simple login form, Kerberos, a two- or multi-factor login, or anything else out of the multitude of possibilities. After authentication, the call is routed back to the yuuvis® API in authenticated form.

Password Credentials Flow

In this authentication flow, a client application transmits the users’ credentials together with its own client credentials to the yuuvis® API as the Base64-encoded content of an ‘Authorization’ header. This authentication flow lends itself to backend operations, such as applications migrating data to yuuvis® API.

Device Flow

This flow is intended to support any application that is supposed to work with yuuvis® API but does not have access to a native browser or the identity provider itself to obtain a pair of client credentials. An endpoint designed for this case supplies that kind of application with a user_code, device_code and verification URI which can be called using a remote browser to authenticate at the identity provider and obtain an access token.

All OAuth 2.0 authentication flows end with the client application obtaining an access token representing the users’ credentials that can be used to authenticate at yuuvis® API. They form the basis for all available authentication procedures.

Authentication with Authorization Code Flow

When using web clients, authentication should be accomplished using the Authorization Code Flow. For each tenant known to the identity provider, an authentication URL is created that users of the tenant can use to reach login forms to authenticate with.

Tenant-specific authentication URL:
https://<yuuvis-base-url>/oauth/<tenant>
Example for the default tenant:
https://yuuvis.io/oauth/default

If an unauthenticated user tries to call any webclient URL other than the tenant-specific authentication URL and fails to supply a Tenant Header, he/she will be redirected to the tenant form of the identity provider. Once the authentication has been completed, all following calls to yuuvis® API URLs will be contextualized using tenant and identity of the user.

For every tenant that’s supposed to support this authentication flow, the properties clientId, clientSecret, userAuthorizationUri, accessTokenUri, userInfoUri and userNameExtractionPattern need to be defined for the authentication service. Optionally, the property ‘endSessionUri’ can be configured to ensure logging out of yuuvis® API also infers a logout at the identity provider.

If the authentication service only defines a single tenant, unauthenticated users may reach the login form of identity provider without naming their tenant.

Authentication with Basic Authentication

For client applications, dealing with the OAuth 2.0 flows can be circumvented by authenticating using basic authentication. Simply send the tenant and credentials of the user in the respective HTTP headers when trying to call any yuuvis® API endpoint. Behind the scenes, the entered credentials will be relayed into the authorization code flow, so the same configuration setup requirements apply.

Required HTTP headers:
"Authorization": "Basic <base64 encoded <username>:<password>>"
"X-ID-TENANT-NAME": "<tenant>"
Example headers:
"Authorization": "Basic dXNlcm5hbWU6cGFzc3dvcmQK"
"X-ID-Tenant-Name": "default"
Obtaining a Token with Password Credentials Flow

In this flow intended for backend applications, a client application requests an access token from the identity provider directly. However, it requires the client application to be registered at the identity provider, and in turn, the developer of the client application needs administrative access to the identity provider.

The credentials of a user (username, password) and the credentials of the trusted client (client_id, client_secret) together with a grant type flag are delivered to the identity providers’ token URL (i.e. https://<keycloak>/auth/realms/<tenant>/protocol/openid-connect/token) as a text payload with the MimeType application/x-www-form-urlencoded. The identity provider will respond with a token and a corresponding token type. This token then needs to be delivered to the Identity Provider similar to the user credentials during Basic authentication.

For this authentication flow, the authentication service’ application-oauth2.yml configuration file must contain a configuration of the properties userInfoUri and userNameExtractionPattern for each tenant. Other tenant-specific configuration properties can be ignored for this flow.

Authentication at the API using an existing access token

For customers that want work with an enriched access token as their method of authentication for their client application, it’s possible to supply a valid access token instead of the credentials. The Password Credentials Flow can be used to obtain the token from the identity provider.

Similar to the credentials-based authentication, the authenticating access token is delivered to the API in the Authorization header.

For this authentication flow, the authentication service must contain a configuration of the properties userInfoUri and userNameExtractionPattern for each tenant. Other tenant-specific configuration properties can be ignored for this flow.

Required HTTP headers:
"Authorization": "Bearer <access token>>"
"X-ID-TENANT-NAME": "<tenant>"
Example headers:
"Authorization": "Basic dXNlcm5hbWU6cGFzc3dvcmQK"
"X-ID-Tenant-Name": "default"
Authentication at the API Using the OAuth 2.0 Device Flow

The OAuth 2.0 device flow serve to authenticate devices without native browsers or the ability to use the regular authentication flows to authenticate their native applications. The yuuvis® API authentication service implements the device flow based on its’ 12th revision (https://tools.ietf.org/html/draft-ietf-oauth-device-flow-12).

Device Flow Process
  • The client application calls https://<base_url>/tenant/<tenant>/loginDevice. yuuvis® API responds with device_code, user_code and verification_uri

  • The client application calls https://<base_url>/<verfication_uri>?user_code=<user_code> where verification_uri and user_code are replaced by the response from step 1. This redirects to the identity provider, where the user authenticates with his credentials. If there is no system browser available to the client application, the user can manually call this URI from any browser on any device.

  • The client application starts polling the yuuvis® API authentication service for the status of the authentication at the URL http://<host>/auth/info/state?device_code=<device_code>. The polling interval can be derived from the response in step

  • During the authentication process, the state polling will return the error authorization_pending with status 400. The first state poll after a successful authentication returns the access token and the token type with status 200. The two response parts need to be composited in the Authorization header like "Authorization": <token_type> <access_token> and sent within a final call to any yuuvis® API endpoint, which will authenticate the user using the access token.

Five minutes after their issuance, device_code and user_code become invalid. Therefore the authentication needs to be completed within that time frame, otherwise the device flow needs to be repeated from the start. A client application can detect the passage of 5 minutes during polling when the verification URI yields the error expired_token, implying that polling can be stopped. The lifespan of the user and device code can be configured in the authentication service using the property authentication.oauth2.deviceCodeExpiration, which defines the codes’ TTL.

Authentication Using External Authentication Services

So far, we’ve detailed the authentication mechanisms available when using the proprietary yuuvis® API authentication service. It is likely that at a later date, most customers will be using yuuvis® API through a managed API gateway, authenticating using a subscription key tied to a platform-specific account (i.e. a Microsoft account for Azure Managed API) instead of user credentials. Since these managed API gateways replace both the Identity Provider and the authentication service, not much can be generally said about the way to authenticate at these external services. If you are using a yuuvis® API build utilizing such a managed API, refer to that API’s documentation when trying to authenticate.

Access via Certificate

In order to granularly manage system security, it is possible to enable a login via certificates that can be used by service accounts. Thus, it is not required anymore to specify user name and password for those accounts in a configuration file. If you want to use the authentication via certificates, ensure that it is supported by your identity provider. In this article, an example configuration is explained that uses Keycloak as identity provider.

An example service is available on GitHub.

Creating a Certificate

The following commands create a certificate to be used for a Kubernetes client within the cluster, e.g., a custom service. The ACCOUNT variable contains the user name of the service account to which the login via certificate is to be configured.

ACCOUNT=service1 ; \
openssl genpkey -algorithm RSA -out $ACCOUNT-key.pem ; \
openssl req -new -x509 -days 365 -key $ACCOUNT-key.pem -out $ACCOUNT-cert.pem -subj /C=DE/ST=DE-DE/L=Berlin/CN=$ACCOUNT ; \
cat $ACCOUNT-key.pem $ACCOUNT-cert.pem > $ACCOUNT.pem ; \
rm $ACCOUNT-key.pem $ACCOUNT-cert.pem
Creating a Kubernetes Secret

The following command uses the previously created certificate to create a Kubernetes secret.

kubectl -n infrastructure create secret generic client-certificates \
--from-file=service1.pem=/path/to/service1.pem \
--from-file=service2.pem=/path/to/service2.pem
Adjusting the Stateful Set in Keycloak
  • With this command, the Stateful Set of Keycloak is opened for editing.

    kubectl -n infrastructure edit sts keycloak
  • Register the secret as volume by extending the volumes section as follows:

    volumes:
    - name: client-certificates
      secret:
      secretName: client-certificates
  • Extend the volumeMounts section to activate the volume:

    volumeMounts:
    - name: client-certificates
      readOnly: true
      mountPath: /secrets/client-certificates
  • Register the certificate in the env section:

    - env:
      - name: X509_CA_BUNDLE
        value: /secrets/client-certificates/service1.pem /secrets/client-certificates/service2.pem
Configuring an Account in Keycloak
  • Create the account for which login via certificate should be supported via Users > Add user.

  • Optionally, you can set a password. Assign roles to the account according to its use case.

  • Create a new authentication flow:

    • Via Authentication > Flows > New, create a new Top Level Form. For Alias, use Client Certificate.

    • Via Add execution, add an authentication step with the provider X509/Validate Username.

    • Click the Actions link for the new authentication step and open the configuration menu.

    • Specify any Alias, e.g., User to certificate mapping.

    • For User Identity Source, select Subject’s Common Name.

    • For User mapping method, select Username or Email.

    • Save the configuration.

  • Create a Client dedicated to the new authentication flow:

    • Via Client > Create, create a new client with the ID X509-access.

    • Deactivate Standard Flow Enabled.

    • Via the sub menu Authentication Flow Overrides, select the new Authentication Flow Client Certificate for Direct Grant Flow.

    • Save the configuration.

Testing via curl
  • Test the access:

    curl -i -k \
    -d "client_id=X509-access" \
    -d "grant_type=password" \
    -E "service1.pem" \
    "https://keycloak-https.infrastructure/auth/realms/yuuvistest/protocol/openid-connect/token"
  • Test the account identity:

    curl -i -k \
    -H "Accept: application/json" \
    -H "Authorization: Bearer eyJhbGciOiJSUzI...." \
    "https://keycloak-https.infrastructure/auth/realms/yuuvistest/protocol/openid-connect/userinfo"

2.5.2. Session Management

After a successful log-in process, the session state is stored by the authentication service. If multiple service instances are used, it is stored in a Redis database.

A session cookie stores the identification of the user’s session via a Cookie Manager of the calling HTTP client (e.g., the browser) such that further requests of the same user are enriched with the session cookie GWSESSIONID. Thus, the user does not need to log on again for each request.

If the client application uses a browser, the following cookies will be additionally set:

  • i18next - Stores the language for the tenant selection web page (e.g., en_US or de).

  • tenant - Stores the tenant that was selected on the tenant selection web page.

Further cookies might be set by your identity provider (e.g., Keycloak cookies).

2.5.3. Roles

The Core API protects documents against access by unauthorized persons through a permission system. Each user has one or more roles in this system, giving them access to various documents for specified actions. The user-role mapping manages the assignment of roles to users. In yuuvis® Momentum, this mapping is managed separately from the authentication process itself and can be configured according to the customers' needs. Furthermore, in the configuration of the yuuvis® authentication service, access conditions can be defined individually for each API endpoint.

Structure of the Permissions System
Roles and Role Sets

The permissions to access documents or to perform certain actions are assigned to specific roles. Users of the system are assigned to particular roles, and through those role assignments acquire the permissions needed — they become the owner of the roles. In general, roles are reusable groups of various permissions. Each role has a unique name and contains one or more permissions that are granted to its owners.

In the header of each incoming and authenticated API call, the roles of the corresponding user are included among other user-specific information. If you assign too many roles with long names to individual users, you might exceed the overall size limit of 8 KB for the header.
Permissions

Permissions denote access rights to certain objects and are assigned to a role. A permission consists of one or more actions and, optionally, a condition. The condition defines which objects are allowed to be managed by owners of a role with the permission, whereas actions define what procedures are allowed upon meeting the condition. In other words, if a user tries to access an object, the authorization system will go through that user’s roles to see if one of the conditions within their permissions is met by the object. If the object meets the condition of one of the user’s permissions, the user will be able to work with the object according to the actions defined by that permission.

Actions

The actions of a permission specify access rights for specific purposes, whereby a distinction is currently made between create access, read access, delete access, write access and tag access (as of 2024 Spring). The actions can be combined by simply adding multiple actions to the permission.

create

(as of 2021 Autumn)

permission to create new objects

read

permission to know about the existence of objects, to receive them in search results and to call various GET endpoints to a special object delete permission that allows to delete content or metadata of objects for which also read permission is granted

write

permission to update objects or to move the content of objects for which also read permission is granted

tag

permission to create/update/delete tags for objects for which also a read permission is granted.

Conditions

Conditions are statements in the proprietary CMIS-based query language that define the subset of documents in the system affected by a permission. If the condition for a document is met (meaning evaluating the query language expression returns true), the owner of the role gets to access that document. For example, conditions can limit a user’s access to a specific type of object or hide documents that are older than a specific date. The conditions are applied to all requests from the role owner and thereby act as filters for the corresponding search results.

In a permission the CONTAINS() query function cannot be used in a condition. The whole statement would always be evaluated as false, even if the condition contains other sub-statements that do not use CONTAINS() and that would individually be evaluated as true.

The condition can also be left out – indicating that the permission applies to all documents in the system.

The following code block explains the definition of permissions with an example of creation permissions assigned to different roles.

Examples for Creation Permissions with Condition and without
<!-- This role does not grant any permission to create, update or delete any object. -->
<role>
   <name>CAN_CREATE_NOTHING</name>
</role>

<!-- This role grants creation permission for any object. No conditions have to be matched. -->
<role>
   <name>CAN_CREATE_EVERYTHING</name>
   <permission>
       <action>create</action>
   </permission>
</role>

<!-- This role grants creation permission for objects that match the condition. In this case, only objects of type 'appTable:order' or 'appEmail:email' can be created. -->
<role>
   <name>CAN_CREATE_SOMETHING</name>
   <permission>
      <action>create</action>
      <condition>
         system:objectTypeId IN ('appTable:order', 'appEmail:email')
      </condition>
   </permission>
</role>

As of 2023 Summer, it is possible to specify conditions referencing the abac (attribute-based access control) section within the internal JWT (JSON Web Token). The following example role grants read permission for objects with at least one entry of the string list property appEmail:mailboxes contained in the current user’s @abac.mailGroups string list within the JWT.

Example for Read Permissions with Condition
<role>
   <name>CAN_CREATE_SOMETHING</name>
   <permission>
      <action>read</action>
      <condition>
         appEmail:mailboxes IN @abac.mailGroups
      </condition>
   </permission>
</role>
Endpoints for Managing Permissions

The following endpoints are available for setting up and managing your tenant-specific permissions system:

For system administrators, the following endpoints are available for managing the global permissions system:

Since version 2.4, yuuvis® Momentum has the ability to further structure the global role set into applications. This goes hand in hand with the usage of application schemata, as the new functionality is meant to exclude any role set entries related to an optional application schema from the main global role set.

To streamline the process of defining yuuvis® Momentum role sets, a number of REST endpoints were made available to retrieve the current role set structures and to apply modifications. As seen in the permissions concept page, there are three options used to structure the role set, coming from two endpoint categories. The /system/permissions and /system/apps/{app}/permissions endpoints are both used to modify the global role set applicable to all users of the system, whereas the /admin/permissions endpoint serves to change the role set specific to the current tenant.

Complete role set files can be supplied to one of the endpoints via an HTTP POST request, overwriting the previous role set present at that position. Thus, retrieving and extending the previous role set state using a GET request on the same endpoint is strongly recommended. New role sets can also be validated by posting them to the role set endpoint URLs using the added URL suffix /validate.

Code examples in gitHub.

Role Administration
Defining Roles

The roles are defined in role sets. Each role set is stored via the configservice in a file roleset.xml that should only be changed using the above listed endpoints.

A role has a name and a list of permissions. Each permission can have one or more actions: read, delete and write. Additionally, they can be restricted by a condition.

Example: a read-permission with the condition system:objectTypeId = 'email' allows to receive all objects of type email in search results and to call various GET endpoints for this type of objects.

An example role set
<?xml version="1.0" encoding="utf-8"?>
<roleSet xmlns="http://optimal-systems.org/ns/dmscloud/roleset/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://optimal-systems.org/ns/dmscloud/roleset/dmsCloud-roles.xsd">
    <role>
        <name>RoleEmail</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId = 'email:email'</condition>
        </permission>
    </role>
    <role>
        <name>RoleDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId = 'document'</condition>
        </permission>
    </role>
    <role>
        <name>RoleEmailAndDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId in ('email:email', 'document')</condition>
        </permission>
    </role>
    <role>
        <name>AdminRole</name>
        <permission>
            <action>read</action>
            <action>delete</action>
        </permission>
    </role>
</roleSet>
For the usage of some additional services a fixed role set is required.
User-Role Mapping

When users log in at the beginning of a session and are successfully authenticated by the identity provider, a JSON web token is generated in which the users' roles are listed under authorities. The GET user.info webhook is responsible for providing the users' roles. By customizing the webhook, it is possible to connect any access management provider delivering the users' roles in a suitable format. Per default, the webhook calls the organization service that is responsible for providing the role information.

To assign individual roles to the users of the system, an external identity provider is used, which takes over the responsibility for role assignment. Per default, the organization service reads the keycloak profile and thus requests the information from the identity provider Keycloak.

In order to run the organization service in Keycloak mode, the keycloak profile has to be activated and the following connection parameters in the application-oauth2.yml profile are required:

  • keycloak.server

  • keycloak.admin.username

  • keycloak.admin.password

The roles of users control their rights regarding DMS objects but also regarding yuuvis® Momentum administration. In the default configuration, e.g., the YUUVIS_SYSTEM_INTEGRATOR role allows editing of global configuration files like role sets and schemata. Thus, it is highly important to configure your role management software such that only system operators can assign roles that provide themselves and other users with global rights.

2.5.4. Endpoint Access Configuration

Access permissions can be configured for each endpoint (core API URLs and service URLs) in the yuuvis® API authentication service. For this purpose, endpoint patterns are assigned to access conditions.

For each incoming request, the first condition is determined with an endpoint pattern that matches the request URL. This condition is evaluated and decides whether access is granted or not. Access permissions without access conditions are granted after log in. The requesting client can identify rejected requests by the status code 403 (forbidden).

The access conditions are described in the access attribute of the access permission. User attributes (like user ID, tenant membership or user roles) and request attributes (like IP address or request header) can be used. Complex access conditions can be formed with operators and functions.

By means of the expose flag, endpoints can be made accessible for unauthenticated access. That means that clients can call the endpoint without having to log in first. The access condition for such endpoints can only contain functions for the evaluation of IP addresses and request headers. Access conditions for expose endpoints always have precedence over those with mandatory authentication, even if they are further down in the mapping list. Services that are called via expose endpoints cannot determine the identity of the caller, even if the caller was authenticated by another endpoint. Without the expose flag, access permissions are only granted after authentication.

Access permissions can be limited to specific HTTP methods (method attribute of the access permission). If you omit the specification, then the permission is applied to all HTTP methods. An access permission can contain multiple endpoint patterns and HTTP methods separated by commas.

Access permissions are registered as an authorization.accesses list in the configuration of the authentication service. If multiple lists are entered, only the last one is applied.

Rules for Endpoint Patterns
  • ? placeholder for exactly one random character

  • * placeholder for exactly one path segment

  • ** placeholder for any number of path segments

  • the query string cannot be included in the pattern

Examples:

  • /com/t?st.html

    → matches com/test.html but also com/tast.html or com/txst.html

  • /com/*.html

    → matches all .html files in the com directory

  • /com/**/test.html

    → matches all test.html files underneath the com path

  • /org/springframework/*/.html

    → matches all .html files underneath the org/springframework path

  • /org/**/servlet/test.html

    → matches org/springframework/servlet/test.html but also org/springframework/testing/servlet/test.html and org/servlet/test.html

Syntax for Access Conditions
Operators
  • or, and, () - operators for forming complex access conditions

  • == - compares strings

Functions for expose endpoints
  • hasIpAddress('<IP range>') - returns true if the request comes from the passed IP address range

  • hasHeader('<header name>', '<value>') - returns true if the request contains the passed header and its value starts with the passed value

Functions for endpoints with authentication requirement
  • permitAll() - returns true (parentheses can be omitted)

  • denyAll() - returns false (parentheses can be omitted)

  • not(<expression>) - negates passed expression

  • hasIpAddress('<IP range>') - returns true if the request comes from the passed IP address range

  • principal.getId() - returns caller’s ID

  • principal.getUsername() - returns the login name of the user account (this can occur several times in multi-tenancy systems)

  • principal.getTenant() - returns the caller’s tenant

  • hasAuthority('<user role>') - returns true if the caller has the passed role

  • hasAnyAuthority('<role1>','<role2>',…​) - returns true if the caller has one of the passed roles

Combined Examples

Callers from the IP address range 192.168.1.0/24 can access managed endpoints without authentication. All other callers must login and have one of the following roles: EXAMPLE_ADMIN_ROLE or EXAMPLE_INTEGRATOR_ROLE.

authorization.accesses:
  - endpoints: /manage/**,/*/manage/**
    expose: true
    access: hasIpAddress('192.168.1.0/24')
  - endpoints: /manage/**,/*/manage/**
    access: hasAnyAuthority('EXAMPLE_ADMIN_ROLE','EXAMPLE_INTEGRATOR_ROLE')

Endpoints for using the web application are accessible for all authenticated users.

authorization.accesses:
  - endpoints: /api/dms/**,/api-web/**,/api/sandbox/renditions/**

The yuuvis® core API is read-only. access: permitAll can be omitted as it corresponds to the default setting. The prohibition condition for the POST method and DELETE method can also be omitted, because the access to unlisted endpoints is generally denied.

authorization.accesses:
  - endpoints: /api/dms/objects/**
    method: POST,DELETE
    access: denyAll
  - endpoints: /api/dms/objects/**
    method: GET
    access: permitAll
  - endpoints: /api/dms/objects/search/**
    method: POST
    access: permitAll

Only users of the default tenant and dev tenant may use custom services.

authorization.accesses:
  - endpoints: /custom/**
    access: principal.getTenant() == 'default' or principal.getTenant() == 'dev'

Users of the dev tenant are denied access to the custom service. All other users have access.

authorization.accesses:
  - endpoints: /custom/**
    access: not(principal.getTenant() == 'dev')

The user with the ID 78d3b2a8535b has unrestricted document access. All other users only have access to the latest document version.

authorization.accesses:
  - endpoints: /api/dms/objects/*/versions/**
    access: principal.getId() == '78d3b2a8535b'
  - endpoints: /api/dms/objects/**

The users historyTracker of all tenants only have access to the document history. They have no access to other document information. All other users have unrestricted document access.

authorization.accesses:
  - endpoints: /api/dms/objects/*/history
  - endpoints: /api/dms/objects/**
    access: not(principal.getUsername() == 'historyTracker')

2.5.5. Internal JSON Web Tokens

Each call of a yuuvis® Momentum endpoint is routed through the authentication service. After successful authentication, an internal JSON Web Token (JWT) is created and assigned to the call containing user-specific information. This JWT authorizes the call in every service within the data processing chain.

The JWT is assigned to the call via Authorization header.

Depending on the concrete call, multiple headers might be assigned to it (e.g. containing the user’s roles). However, the sum of all header sizes must not exceed the overall size limit of 8 KB. For systems with many roles and/or many custom user attributes, it is recommended to use the user attributes cache.
Structure of internal JWTs

The internal JWTs consist of

  • header with signature algorithm RS256,

  • payload and

  • as of 2021 Autumn, a signature of header and payload.

These three parts are included as .-separated Base64-encoded blocks in each authorization request header for API calls, optionally encrypted.

The payload contains key-value pairs specifying the following parameters:

Parameter Description

sub

User ID of the user requesting the API call.

tenant

Tenant the requesting user belongs to.

name

Account name of the user.

accessToken

Contains the external authentication token taken from the identity provider.

authorities

A list containing the roles that are assigned to the user.

abac

(as of 2023 Summer) Optional: a map with single string keys and a list of strings as value for each key. Allows for attribute-based access control (see example below).

iat

Identifies the time at which the JWT was issued.

exp

Identifies the expiration time on and after which the JWT MUST NOT be accepted for processing. Numeric date

An example payload is displayed in the code block below (abac section available as of 2023 Summer).

Example JWT Payload
{
    "sub": "3cfaf962-b254-45c8-b0e9-82f79f2c26ee",
    "tenant": "sales-office",
    "name": "mustermann",
    "accessToken": "Bearer eyJhbGciOiJS...",
    "iat": 1621324798,
    "exp": 1621325698,
    "authorities": [
        "YUUVIS_DEFAULT",
        "YUUVIS_MANAGE_SETTINGS",
        "ACCESS_MAILBOXES"
    ],
    "abac": {
      "mailGroups": [
           "mailbox_sales",
           "mailbox_pm"
       ],
       "sap_permissions": [
           "sap_read",
           "sap_write"
       ]
    }
}
Caching User Attributes

The authentication service can be configured to exclude the authorization and abac sections from the JWT to reduce its size. Instead, the full set of user attributes including authorization and abac sections is stored for 5 minutes in a userAttributes Redis cache for each logged-in user.

All services within the yuuvis® Momentum cluster that need the authorization and abac information retrieve them from the userAttributes Redis cache.

Within the cluster, the userAttributes cache is available via Redis CLI:

  • The following command retrieves a list of all user attributes-related keys for all tenants:

    redis-cli keys 'userAttributes*'

    Each key contains the tenant und the user ID for a logged-in user. If only one user is currently logged-in, the response could be, e.g.,

    redis-cli keys 'userAttributes*'
    1) "userAttributes::yuuvistest,3cfaf962-b254-45c8-b0e9-82f79f2c26ee"
    • userAttributes is the cache name. It is the same for all keys.

    • yuuvistest is the example tenant name.

    • 3cfaf962-b254-45c8-b0e9-82f79f2c26ee is the example user ID.

  • For each key, the stored value contains the full set of user attributes for the corresponding user. For the example user, it can be retrieved via

    redis-cli get userAttributes::yuuvistest,d90b12d5-1288-4a73-92fc-d9b6872df812

    The response is a string containing the encoded JSON object, e.g.,

    "\"{\\\"username\\\":\\\"root\\\",\\\"id\\\":\\\"d90b12d5-1288-4a73-92fc-d9b6872df812\\\",\\\"title\\\":\\\"First User\\\",\\\"email\\\":\\\"testroot@yuuvis\\\",\\\"firstname\\\":\\\"First\\\
    ",\\\"lastname\\\":\\\"User\\\",\\\"domain\\\":\\\"dd\\\",\\\"tenant\\\":\\\"yuuvistest\\\",\\\"authorities\\\":[\\\"YUUVIS_DEFAULT\\\",\\\"YUUVIS_SYSTEM_INTEGRATOR\\\",\\\"YUUVIS_TENANT_ADMI
    N\\\"],\\\"accountNonExpired\\\":true,\\\"accountNonLocked\\\":true,\\\"credentialsNonExpired\\\":true,\\\"enabled\\\":true}\""

Furthermore, an internal endpoint of the authentication service GET /session/updateUserAttributesCache/{tenant}/{userId} is available. It can be called by services within the cluster to retrieve user information and refresh the cache in case a logged-in user is missing (e.g., if the maximum item storage time of 5 minutes is exceeded).

To activate the userAttributes cache, the following points have to be considered:

  • The authorization.cacheUserAttributes parameter has to be configured to true in the authentication-prod.yml configuration file.

  • All services that need authorization and abac information require the redis profile. This applies to the following core services:

    • api gateway

    • audit service

    • authentication service

    • index service

    • registry service

    • repository service

    • search service

    • system service

  • Custom services that might run within the yuuvis® Momentum cluster can retrieve authorization and abac information from Redis or via the endpoint GET /session/updateUserAttributesCache/{tenant}/{userId} if necessary.

Validation of internal JWTs

In order to prevent unauthorized access from outside by faking the JWT, its signature can be used for an additional validation of the caller’s authorization. As of version 2022 Spring, the expiration date is validated as well. Thus, it is not possible to authenticate with a token anymore if its expiration date is exceeded. The validation is provided by the internal endpoint GET /jwt/verify of the authentication Service.

2.5.6. Accessing External Services via 'authentication' Service

The authentication service manages the access to the yuuvis® Momentum API gateway. With a suitable configuration, also the access to external services running in the same Kubernetes cluster can be managed via the authentication service of yuuvis® Momentum.

Involved Services

Two services of yuuvis® Momentum are responsible for the service routing:

  • the authentication service and

  • the API gateway.

After successful authentication of incoming requests, the authentication service sends the requests to the API gateway.

Configuring 'authentication' Service

The service has its own endpoints that are configured in the file authentication-prod.yml in the section and authorization.accesses.

The authentication service endpoints are only available for endpoints listed in authorization.accesses. The following HTTP methods are supported and tested:

  • DELETE

  • GET

  • HEAD

  • OPTIONS

  • PATCH

  • POST

  • PUT

  • TRACE

Further HTTP methods can be used on the customers' own responsibility and have to be tested regularly by themselves.

Permissions can be defined for the access to the individual endpoints and sub-paths.

Configuring 'api' Gateway

The API gateway uses the Spring Cloud Kubernetes DiscoveryClient in order to dynamically create routes. This DiscoveryClient sends requests to the Kubernetes API. The corresponding permissions are configured via the Kubernetes objects ServiceAccount, RoleBinding and Role.

The pod for the API gateway is executed via the service account that is used by the DiscoveryClient to request namespaces.

The number of the Kubernetes Services can be limited. This can be configured in the file application-kubernetes.yml in the filter for Kubernetes Services. Only for services matching the filter internal routes are created by the API gateway. Per default, the following filter is applied:

metadata!=null && metadata.labels!=null && metadata.labels['yuuvis']=="true"

In order to create a route for a service in the API gateway, the entry yuuvis: true has to be added in the <externalservice>-service.yaml file in the labels section.

Example Configuration

In this example scenario, the required steps of configuration are shown. Afterwards, the external service app in the namespace other will be available via the authentication service.

Follow these steps:

  • Deploy the pod for the external service app in the namespace other.

    app-deployment.yaml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      namespace: other
      name: app
    spec:
      replicas: 1
      selector:
        matchLabels:
          name: app
      template:
        metadata:
          labels:
            name: app
        spec:
          containers:
          - name: app
          ...
            ports:
            - containerPort: 80
          ...
  • Create a Kubernetes Service for app in the namespace other, e.g., app-svc.

    app-service.yaml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    apiVersion: v1
    kind: Service
    metadata:
      name: app-svc
      labels:
      name: app-svc
      namespace: other
    spec:
      ports:
      - name: "http"
         port: 80
         targetPort: 80
      selector:
         name: app
      type: ClusterIP
  • Create the Kubernetes Service in the namespace yuuvis. Use the type externalName that references the namespace other.

    <externalservice>-service.yaml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    apiVersion: v1
    kind: Service
    metadata:
      name: app
      labels:
        yuuvis: "true"
      namespace: yuuvis
    spec:
      type: ExternalName
      externalName: app-svc.other.svc.cluster.local
      ports:
      - port: 80
    
  • Add the external service app to the section authorization.access in the authentication-prod.yml file.

    authentiaction-prod.yml
    1
    2
    3
    4
    
    authorization.accesses:
      - endpoints: /app/** # add
      # optionally restrict to a method, e.g.: method: Post
      # optionally restrict to users with specific roles, e.g.: hasAuthority('COGNISPHERE')
  • Restart the authentication service.

2.5.7. Cross Tenant Service Accounts

Within your yuuvis® Momentum cluster, you might want to operate a service for asynchronous background processing that is working on all the data in your system independently of the tenant they belong to. Such services need to access the data of all tenants. In order to enhance their performance, they can use an internal service account (as of version 2021 Autumn) that allows for cross-tenant requests and thus avoid high numbers of requests to individual tenants. To configure internal service accounts, read this article carefully and make sure you do not skip any of the described configuration steps in order to ensure and secure the tenant separation.

General Remarks

The concept of service accounts is designed for the operation of background processes within the yuuvis® Momentum cluster.

  • The permissions for the service accounts are specified by the assignment of roles. We recommend to assign only roles that are available in all tenants.

  • The authentication with service accounts is accepted only within the yuuvis® Momentum cluster. External login attempts using service accounts are always rejected.

    To ensure this access blocking, service accounts need to be explicitly specified in the yuuvis® Momentum configuration.
  • Only selected endpoints of the API gateway can be called with service accounts.

  • In the identity provider, service accounts are associated with a tenant per definition. However, considering the permissions via their roles, they have access to resources of all tenants, e.g., objects including their binary content files and renditions.

Safety Note

The authentication service manages the cross-tenant requests of service accounts via a separate port. This port must be accessible only within the yuuvis® Momentum cluster to ensure strict separation of tenants for users. Never expose this internal port for public access!

Available Endpoints

Every endpoint matching one of the following wildcard patterns can be called via service accounts. For some of them, only particular HTTP request methods are enabled. If not specified (n/a), all HTTP request methods supported by the core API are available.

Pattern Limited to HTTP Request Methods

/api/dms/objects/tags*

n/a

/api/dms/objects/search*

POST

/api/dms/objects/*/tags/*/state/*

n/a

/api/dms/objects/*/tags*

GET

/api/dms/objects/*/contents/file*

n/a

/api/dms/objects/*/contents/renditions/text*

POST

As of 2022 Summer: /api/dms/objects/*

PATCH

Available Metadata Properties

A service account can operate on objects belonging to any tenant of the system. For each individual object, metadata properties can be accessed that are either system properties or defined in a schema that is available for the service account’s tenant:

  • system properties

  • properties defined in the global schema

  • properties defined in the tenant schema for the service account’s tenant

  • properties defined in an app schema that is available in all tenants

  • properties defined in an app schema that is available for the service account’s tenant

Those properties can be managed as usual and used in search queries.

Properties defined in the tenant schema of a different tenant or in an app schema that is not available within the service account’s tenant are not accessible. They cannot be retrieved, searched or modified.

Handling Cross-Tenant Requests

Each authorized request is enriched with an internal JSON Web Token (JWT) containing the service account’s tenant, among other information. If the request calls an operation on an object of a different tenant, the corresponding object’s system:tenant in the request body will have a different value. It is important to keep this difference in mind, especially for the definition of system hooks.

An operation on an object performed via a service account will trigger the creation of a new entry in the audit trail as usual. Since the executor was the service account, its account ID as defined in the identity provider will be referenced. NOTE: If you are using yuuvis® client as reference implementation, the service account’s ID will also appear in the object history view as soon as the corresponding object has been processed via the service account.

Roles of a Service Account

The permissions of a service account are defined via its roles. Assign as few roles as possible, i.e., only the roles that are required for proper operation of your background process. We recommend to assign only roles that are available in all tenants:

  • roles defined in the global role set or

  • roles defined in an app-specific role set for a system-wide available app.

With roles defined in a tenant-specific role set or in an app-specific role set that is not available for all tenants, the service account will consequently have the corresponding permissions only within the corresponding tenant(s).

Configuring Service Accounts

Create a user account and assign roles in your identity provider.

  • Choose the tenant for the service account. As described above, tenant-specific properties of this tenant will be available for the service account.

  • Assign roles to the account that allow for the specific operations your background process needs to perform in cross-tenant manner. Do not assign more roles than necessary for your specific purpose. Avoid tenant-specific roles.

  • Extract the ID of the account for the configuration in yuuvis® Momentum.

Specify the service account in the yuuvis® Momentum authentication service configuration.

  • In the configuration file authentication-prod.yml, add a new entry to the authorization.serviceAccounts list with the syntax <tenant>\<account-id>.

    Example with two service accounts:

    authorization.serviceAccounts:
    - account: 'services-tenant\ddffd2d5-5dc5-494a-b706-2250cefee60a'
    - account: 'services-tenant\fbbe75cf-008e-4de2-bced-f71e402b4369'
  • Restart the authentication service.

2.5.8. Customizing the Tenant Selection Web Page

Users accessing yuuvis® Momentum via a browser have to select their tenant before their credentials are requested. This tenant selection web page is provided by the authentication service. In order to customize the design, it is possible to replace the underlying default form files by a set of custom form files.

Required Sources

A directory public has to be available in the root of the authentication service’s container when the service is started. In this public directory, there must be at least the files tenant.html and error.html.

In the tenant.html file, the reference on http://www.thymeleaf.org (line 2) and the corresponding form definition are required (lines 11–12) in order to provide the tenant selection functionality.

Example 'tenant.html'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="utf-8" />
        <link rel="stylesheet" type="text/css" href="res/tenant.css" />
    </head>
    <body>
        <span id="container">
            <span>
                <h3>Type in your tenant.</h3><br>
                <form id="tenant" th:action="@{/tenant}" method="post">
                    <input type="text" name="tenant" placeholder="Tenant" /><br>
                    <img src="res/next-btn.svg" onclick="document.getElementById('tenant').submit()">
                </form>
            </span>
        </span>
    </body>
</html>

In the error.html file, the reference on http://www.thymeleaf.org (line 2) and the three span definitions are required (lines 8–10) in order to provide error details.

Example 'error.html'
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8" />
</head>
    <body>
        An error has occurred <br /><br />
        <span th:text="${status}" /> (<span th:text="${reason}" />) <br />
        <span th:utext="${message}" /> <br />
        <span th:text="'timestamp: '+${timestamp}" style="display: none" />
    </body>
</html>

The usage of resource files is possible if they are located in the sub-directory /public/res/ or if they are stored by a client application.

The example custom form files used in this article are available for download as public.zip file.

Possible Procedures

There are different ways to proceed:

  • Kubernetes ConfigMaps

  • Manual replacement after starting the pod

  • A custom Docker image with the custom form files in a separated layer

  • Integration of the custom form files via Kubernetes Volumes

In this documentation, only the first procedure via Kubernetes ConfigMaps is described. The replacement of the default form files is explained by means of a simple example.

Configuration via Kubernetes ConfigMaps

By following these steps, you configure a simple custom web page for the tenant selection dialog:

  • Add the following line in the authentication-prod.yml configuration file:

    spring.thymeleaf.prefix: 'file:/public/'
  • Unpack the public.zip file.

  • Create a ConfigMap for the files in the public directory via the command:

    kubectl -n yuuvis create configmap templates --from-file=./public/
  • Adjust the Kubernetes deployment of the authentication service via the command:

    kubectl -n yuuvis edit deploy authentication
  • Extend the volumes section as follows:

    volumeMounts:
    - name: templates
      mountPath: /public/tenant.html
      subPath: tenant.html
    - name: templates
      mountPath: /public/error.html
      subPath: error.html
    - name: templates
      mountPath: /public/res/tenant.css
      subPath: tenant.css
    - name: templates
      mountPath: /public/res/next-btn.svg
      subPath: next-btn.svg
  • Restart the authentication service.

2.6. Apps

Management of apps that are based on yuuvis® Momentum via schema, permissions, system hook configuration and availability configurations.

2.6.1. Concept of Apps

The yuuvis® Momentum core system can be used as basis for apps. Apps are additional logical units that enhance the core system. The core system itself provides the possibility to define specific resources for the individual apps. Thus, each app can have its own schema and its own role set. As of version 2021 Summer, apps can be enabled or disabled for individual tenants. The system service manages the corresponding resource files. There are endpoints provided by the API gateway that allow for retrieval, validation or update of the resource files.

The system can support various apps.

2.6.2. App Information

System integrators can see all existing apps in the system by using the endpoint

Users can see all apps that are enabled for their tenant by using the endpoint

2.6.3. App Management

To create an app, deploy any app-specific resource file (schema, role set, system hook configuration). It has to be valid or completely empty. Alternatively, you can introduce a new app by specifying its name and its tenant-specific state in an app set as described below.

The endpoints for the management of app-specific resource files are provided by the API gateway and call the system Service internally.

App names are case-insensitive. Furthermore, the system stores uppercase letters in app names in a lowercase form. For example, if you post an app schema for the app name myNewApp (via POST /system/apps/myNewApp/schema), this new app appears with the name mynewapp in the results of endpoints like GET /api/dms/apps or GET /api/system/apps.

Additionally, app names have to match the regular expression ([a…​zA…​Z][a…​zA…​Z0…​9]*-)?([a…​zA…​Z][a…​zA…​Z0…​9]* and must not be longer than 255 characters in order to be consistent with the schema validation of app-specific prefixes.

App Schemata

App-specific schemata are managed via the following endpoints:

  • GET /api/system/apps/{app}/schema

  • POST /api/system/apps/{app}/schema

  • POST api/system/apps/{app}/schema/validate

In the multi-tenant landscape of yuuvis® Momentum, any object types or properties that need to be available for multiple or all tenants, need to be introduced to the system schema. To prevent cluttering the system schema, avoid dependencies and allow for duplicate names, the system schema can be structured into applications, which provide a namespace for properties and object types pertaining to a particular use case.

2.6.4. Role Sets for Apps

App-specific role sets are managed via the following endpoints:

  • GET /api/system/apps/{app}/permissions

  • POST /api/system/apps/{app}/permissions

  • POST /api/system/apps/{app}/permissions/validate

The permissions to access objects or to perform certain actions are assigned to specific roles that are listed in the role set. yuuvis® Momentum has the ability to further structure the global role set into applications.

2.6.5. App-specific System Hooks

As of 2022 Summer, it is possible to configure app-specific system hooks in separate resource files.

The following endpoints are available to manage those app-specific resources:

  • GET /api/system/apps/{app}/systemhooks

  • POST /api/system/apps/{app}/systemhooks

  • POST /api/system/apps/{app}/systemhooks/validate

  • App Sets for Availability Management

As of version 2021 Summer, the availability of an app for a specified tenant is managed in an app set via the following endpoints:

  • GET /api/system/tenants/{tenant}/apps

  • POST /api/system/tenants/{tenant}/apps

  • POST /api/system/tenants/{tenant}/apps/validate

An app does not necessarily need its own resources within the core system. The core system can be used to only mark tenants to have a specific app. A new app can be introduced to the system by simply enabling if for a tenant. It is not necessary to create an initial resource (schema, role set or system hook configuration) for the app before you enable it for a tenant.

The configuration of the availability of each app for the specified tenant is stored and managed in the apps.xml file as shown in the example code block below. In this app set, each app has its own section (<app></app>) containing the app’s name (<name></name>) and state of availability (<state></state>) which can be either enabled or disabled. The default value for state is disabled. Thus, each app that is not listed in the passed configuration XML will not be available for the corresponding tenant. There is no difference in the configuration of not-listed apps and apps listed as disabled.

example apps.xml
<?xml version="1.0" encoding="utf-8"?>
<apps xmlns="http://optimal-systems.org/ns/yuuvis/apps/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://optimal-systems.org/ns/yuuvis/apps/yuuvis-core-apps.xsd">
    <app>
        <name>clientsystem</name>
        <state>enabled</state>
    </app>
    <app>
        <name>client</name>
        <state>enabled</state>
    </app>
    <app>
        <name>email</name>
        <state>disabled</state>
    </app>
    <app>
        <name>acl</name>
        <state>disabled</state>
    </app>
</apps>

The apps.xml configuration file is stored via the config service and should only be changed using the above listed endpoints.

If there is no apps.xml file, the GET endpoint will return the error code 404. Especially in systems of version 2020 Winter and older, there is no app set. If the file is missing entirely, all apps are enabled for all tenants in the system.

There can be dependencies between different app and tenant schemata via property references or secondary object type references. The validation of the app set considers these dependencies. If the schema of an app is referenced by the global or the corresponding tenant schema, the app cannot be disabled for the specified tenant. Equally, if the schema of an app (A) is referenced by the schema of another app (B), it is not possible to disable the first app (A) and enable the second app (B) for any tenant.

Creating a new dependency considers app availability for all tenants. If a new reference on an app schema (A) is introduced into an app schema (B), the referenced app (B) has to be enabled for each tenant for which the referencing app (A) is enabled. The validation fails if there is a tenant for which the app (A) is enabled and the app (B) is disabled.

2.7. Metrics

As of 2023 Spring, the API gateway offers endpoints to retrieve and manage metrics. For example, it is possible to dynamically calculate the binary storage used by individual tenants. This information could be useful, e.g., for billing purposes.

The following endpoints are available. The URLs contain the metric path parameter to specify the type of metric.

Retrieval Reset

metric for all tenants

GET /api/system/metrics/{metric}

DELETE /api/system/metrics/{metric}

metric for any specified tenant

GET /api/system/tenants/{tenant}/metrics/{metric}

DELETE /api/system/tenants/{tenant}/metrics/{metric}

metric for currently active tenant

GET /api/admin/metrics/{metric}

DELETE /api/admin/metrics/{metric}

2.7.1. Storage Metric

As of 2023 Spring, the storage metric allows to dynamically calculate the binary storage used by individual tenants, e.g., for billing purposes.

In the endpoint URLs above, use storage as value for the metric path parameter. For example:

https://<host>/api/system/metrics/storage

The number is calculated from the content stream length stored in the database. The number includes all binary content files assigned to a DMS object or an old version of a DMS object. Invisible objects (flagged with OBJECT_FLAGGED_FOR_DELETION in the search index) are included as well. Binary content files that are referenced by multiple DMS objects (e.g., compound documents) are counted only once. Rendition files are also NOT included.

The initial calculation or triggered recalculation is a counting process via database statements over all tenants. It is managed by the audit service and its behavior (automation and fail safety) can be adjusted in the audit service’s configuration. No storage metric can be retrieved during the counting process in the database. Requests to the GET endpoints listed above return an error.

After the successful counting process in the database, the result is stored in Redis and dynamically updated during any operations on binary content files via API gateway.

2.7.2. Object Count Metric

As of 2023 Summer, the object count metric provides the number of DMS objects (including folder objects) within one specific tenant. In addition, the number of folder objects is provided separately. The information might be used for billing purposes as well as for an emptiness check before removing a tenant from the system.

For the object count metric only the tenant-specific retrieval endpoints GET /api/system/tenants/{tenant}/metrics/{metric} and GET /api/admin/metrics/{metric} are available. In the endpoint URLs above, use objectCount as value for the metric path parameter. For example:

https://<host>/api/system/metrics/objectCount

The count includes all current versions of DMS objects regardless of role-based access permissions. Moreover, it includes invisible objects (flagged with OBJECT_FLAGGED_FOR_DELETION in the search index) as well.

2.8. Error Handling

Errors may occur in many different situations during data processing. In addition to the HTTP status code, yuuvis® Momentum core offers a well-defined structure and labeling of any thrown error. It is thus possible to easily localize the origin of the problem. At the same time, automated catching and analyzing of errors can be implemented based on the fixed error structure and error codes.

2.8.1. Error Structures

Single Errors

The errors are JSON structures with the following parameters:

Parameter Description

httpStatusCode

Three-digit integer specifying the HTTP status code as a class of the response in which the error is returned.

serviceErrorCode

Integer specifying the concrete error type.

time

Timestamp of the error occurance in format "yyyy-MM-ddTHH:mm:ss.SSS".

message

String message describing the concrete error.

stackTrace

Origin of the error.

As of 2021 Autumn, stackTrace is included in the error structure only if the parameter app.stacktrace is set to FULL for the service throwing the error. Possible values for app.stacktrace are FULL and NONE (default). If app.stacktrace is not set for a service or set to NONE, error structures thrown by this service do not contain the stackTrace. It is recommended to set app.stacktrace in a global configuration file (i.e., application-prod.yml) such that the value applies to all services in order to unify their error structures.

service

The name of the service that threw the error.

tenant

The string tenant name where the error occured.

innerError

As of 2022 Winter. Wrapped original error thrown by a webhook (find details below).

Example error with HTTP status code 409.
{
    "httpStatusCode" : 409,
    "serviceErrorCode" : 2800,
    "time" : "2021-04-21T04:36:30.813",
    "message" : "A non-empty folder cannot be deleted.",
    "stackTrace" : [ "com.os.enaio.cloud.gateway.resource.api.DmsController.deleteDmsObject(DmsController.java:719)" ],
    "service" : "api",
    "tenant" : "default"
}
Error Lists during Validation Processes

If errors occur during one of the following validation process, they are collected and returned in the validationErrors list in JSON format.

  • schema validation

  • role set validation

  • app set validation

Other validation processes return only single errors in the structure described above.

Within the JSON list validationErrors, the following parameters are provided for each error in the list:

Parameter Description

message

String message describing the concrete error.

serviceErrorCode

Four-digit integer specifying the concrete error type.

Together with each non-empty validation error list, the HTTP status code 422 is always returned, but not specifically added to the individual entries.

The following code block shows an example error structure that can occur during a schema validation:

Example error list with HTTP status code 422.
{
    "validationErrors": [
        {
            "message": "Ambiguous IDs. There are 2 property type definitions with the ID 'from'.",
            "serviceErrorCode": 2110
        },
        {
            "message": "Wrong base ID. The base ID of the system:document type definition 'email' must be 'system:document', but it is 'system:folder'.",
            "serviceErrorCode": 2131
        },
        {
            "message": "Invalid property reference 'fromm' in type definition 'email'.",
            "serviceErrorCode": 2132
        },
        {
            "message": "Invalid secondary object type reference 'appAcl:aclowner' in type definition 'email'.",
            "serviceErrorCode": 2135
        }
    ]
}
Errors Thrown by Webhooks

If a webhook throws an error in the yuuvis® Momentum error format, its individual parameters are presented as JSON substructure. The serviceErrorCode is 99999. The HTTP status code used for the final response depends on the webhook type. Errors thrown by dms.request.objects.contents webhooks, e.g., have the final HTTP status code 404.

Example error with properly structured inner error.
{
    "serviceErrorCode": 99999,
    "service": "repository",
    "messageHistory": "\nMessage History\n---------------------------------------------------------------------------------------------------------------------------------------\nRouteId              ProcessorId          Processor                                                                        Elapsed (ms)\n[insertDocumentSetR] [insertDocumentSetR] [direct://insertDocumentSet                                                    ] [      2456]\n[insertDocumentSetR] [[conan] enrich add] [bean[ref:analyzeConfigurationPr [...]",
    "innerError": {
        "httpStatusCode": 422,
        "serviceErrorCode": 12345,
        "time": "2022-11-22T14:57:41.7317312",
        "message": "Virus [XXXX] detected. See inner error for further details.",
        "service": "virus-detection-app",
        "innerError": {
            "httpStatusCode": 0,
            "serviceErrorCode": 0,
            "message": "The virus [XXX] was detected in the file [myvirus.exe]. This virus is part of SIV 1.14356.234 from 2022-03-13. See 'https://gprivate.com/61xd3'."
        }
    },
    "time": "2022-11-22T14:57:41.735",
    "stackTrace": [
        "com.os.services.hel.repo.web.RepositoryRestController.postDmsObjects(RepositoryRestController.java:88)"
    ],
    "message": "Virus [XXXX] detected. See inner error for further details.",
    "tenant": "default",
    "httpStatusCode": 422
}

If the error thrown by the webhook does not match the yuuvis® Momentum error format, the entire original error is wrapped as String message of the inner error. The serviceErrorCode is 2471 and the HTTP status code is 422.

Example error with inner error having a different structure.
{
    "serviceErrorCode": 2471,
    "service": "repository",
    "messageHistory": "\nMessage History\n---------------------------------------------------------------------------------------------------------------------------------------\nRouteId              ProcessorId          Processor                                                                        Elapsed (ms)\n[insertDocumentSetR] [insertDocumentSetR] [direct://insertDocumentSet                                                    ] [      2456]\n[insertDocumentSetR] [[conan] enrich add] [bean[ref:analyzeConfigurationPr [...]",
    "innerError": {
        "httpStatusCode": 422,
        "serviceErrorCode": 0,
        "message": "{\"wrong_body_format\":{\"httpStatusCode\":422,\"serviceErrorCode\":12345,\"time\":\"2022-11-22T15:19:52.3241064\",\"message\":\"Virus [XXXX] detected. See inner error for further details.\",\"service\":\"virus-detection-app\",\"innerError\":{\"httpStatusCode\":0,\"serviceErrorCode\":0,\"message\":\"The virus [XXX] was detected in the file [myvirus.exe]. This virus is part of SIV 1.14356.234 from 2022-03-13. See 'https://gprivate.com/61xd3'.\"}}}"
    },
    "time": "2022-11-22T15:19:52.34",
    "stackTrace": [
        "com.os.services.hel.repo.web.RepositoryRestController.postDmsObjects(RepositoryRestController.java:88)"
    ],
    "message": "Webhook response with statuscode '422' did not match the expected failure body format. Please see documentation to ensure correct webhook failure handling and have a look at the inner exception for details.",
    "tenant": "default",
    "httpStatusCode": 422
}

Any other problems related to the execution of webhooks are indicated with the serviceErrorCode 2470.

2.8.2. Error Codes and Messages

The following table provides an overview of errors that may occur during operation of yuuvis® Momentum core.

In case you want to catch errors and analyse their content, please use the serviceErrorCode as unique identification of the error type. Please do NOT use the message since we reserve to modify it in future.
serviceErrorCode httpStatusCode message Occurance

2100

-

The ID '%s' is invalid. If the ID has a prefix, it is not allowed to start with 'ten' or 'app'.

schema validation

2101

-

The ID '%s' is invalid. If the ID has a prefix, it is expected to be '%s'.

schema validation

2102

-

The ID '%s' is invalid. The ID of an object type is not allowed to start with '%s'.

schema validation

2103

-

The ID '%s' is invalid. The ID of a property type is not allowed to start with '%s'.

schema validation

2104

-

Too many property types. There are %s property types. Up to %s are allowed. This is a configurable limit.

schema validation

2105

-

There are references from the global schema to the schema of app '%s'. For tenant '%s' app '%s' is disabled.

schema validation

2106

-

There are references from the schema of app '%s' to the schema of app '%s'. For tenant '%s' app '%s' is enabled and app '%s' is disabled.

schema validation

2110

-

Ambiguous IDs. There are %s %s type definitions with the ID '%s'.

schema validation

2111

-

Missing ID. There is a %s definition without ID.

schema validation

2112

-

Invalid ID. There is a %s with the invalid ID '%s'. The ID must match '%s'.

schema validation

2113

-

ID too long. The maximum length for an ID is %s without prefix. The length of '%s' is %s.

schema validation

2120

-

Missing property type. The attribute 'propertyType' of the property type definition '%s' is missing.

schema validation

2121

-

Wrong property type. The property type of the %s property type definition '%s' must be '%s', but it is '%s'.

schema validation

2122

-

Invalid attribute 'queryable' in the %s property type definition '%s'. The value 'false' is only supported for table property type definitions.

schema validation

2123

-

Illegal minimum length of the property '%s'. The minimum length of a string property must not exceed %s.

schema validation

2124

-

Illegal maximum length of the property '%s'. The maximum length of a string property must not exceed %s.

schema validation

2125

-

Illegal cardinality of the property '%s'. The cardinality of a table property must not be 'multi'.

schema validation

2126

-

Invalid number of column property definitions for property '%s'. The maximum number of columns in a table must not exceed %s. Column count: '%s'

schema validation

2127

-

Illegal cardinality of the property '%s'. The cardinality of a structured data property must not be 'multi'.

schema validation

2130

-

Missing base ID. The attribute 'baseId' of the type definition '%s' is missing.

schema validation

2131

-

Wrong base ID. The base ID of the %s type definition '%s' must be '%s', but it is '%s'.

schema validation

2132

-

Invalid property reference '%s' in type definition '%s'.

schema validation

2134

-

There are %s property references with the value '%s' in the definition of the object type '%s'.

schema validation

2135

-

Invalid secondary object type reference '%s' in type definition '%s'.

schema validation

2136

-

Secondary object type '%s' in type definition '%s' can be referenced only once.

schema validation

2140

-

The document type '%s' does not allow content and has a static reference to the secondary object type '%s' that requires content. It is not possible to create instances of this document type.

schema validation

2141

-

The document type '%s' does not allow content and has a non-static reference to the secondary object type '%s' that requires content. This secondary object type cannot be assigned to instances of this document type.

schema validation

2142

-

The document type '%s' requires content and has a static reference to the secondary object type '%s' that does not allow content. It is not possible to create instances of this document type.

schema validation

2143

-

The document type '%s' requires content and has a non-static reference to the secondary object type '%s' that does not allow content. This secondary object type cannot be assigned to instances of this document type.

schema validation

2144

-

The document type '%s' has static references to secondary object types that require content ('%s') and that do not allow content ('%s'). It is not possible to create instances of this document type.

schema validation

2145

-

The document type '%s' has static references to secondary object types that require content ('%s') and non-static references to secondary object types that do not allow content ('%s'). These non-static secondary object types cannot be assigned to instances of this document type.

schema validation

2146

-

The document type '%s' has static references to secondary object types that do not allow content ('%s') and non-static references to secondary object types that require content ('%s'). These non-static secondary object types cannot be assigned to instances of this document type.

schema validation

2150

-

The folder type '%s' has static references to secondary object types that require content ('%s'). It is not possible to create instances of this folder type.

schema validation

2151

-

The folder type '%s' has non-static references to secondary object types that require content ('%s'). These non-static secondary object types cannot be assigned to instances of this folder type.

schema validation

2152

-

The folder type '%s' has static references to secondary object types that allow content ('%s'). It is not possible to create instances of this folder type.

schema validation

2153

-

The folder type '%s' has non-static references to secondary object types that allow content ('%s'). These non-static secondary object types cannot be assigned to instances of this folder type.

schema validation

2200

422

Empty lists are not allowed. The property '%s' has an empty list as value.

schema validation

2201

422

The cardinality of the property '%s' is 'multi', but the value is not a list: %s.

schema validation

2202

422

The cardinality of the property '%s' is 'single', but the value is a list: %s.

schema validation

2203

422

Illegal number of values. The cardinality of the property '%s' is 'single', but there are multiple values: %s.

schema validation

2204

422

Null values are not allowed in lists. Property ='%s'

schema validation

2210

422

Illegal property value. The property '%s' is a boolean property and is unable to accept the value '%s'.

schema validation

2211

422

Illegal property value. The property '%s' is a datetime property and is unable to accept the value '%s'.

schema validation

2212

422

Illegal property value. The property '%s' is a decimal property and is unable to accept the value '%s'.

schema validation

2213

422

Illegal property value. The property '%s' is an ID property and is unable to accept the value '%s'.

schema validation

2214

422

Illegal property value. The property '%s' is an integer property and is unable to accept the value '%s'.

schema validation

2215

422

Illegal property value. The property '%s' is a string property and is unable to accept the value '%s'.

schema validation

2216

422

Malformed table. The property part 'columnNames' of the table property '%s' is expected to be a list of strings. ColumnNames: '%s'

schema validation

2217

422

Malformed table. The value of the table property '%s' is expected to be a list. Table value: %s

schema validation

2218

422

Malformed table. A row of the table '%s' is not a list. Row: '%s'

schema validation

2219

422

Illegal property value. The value of the structured data property '%s' is expected to be a list or map. Value: %s

schema validation

2220

422

Invalid JSON. The value of the structured data property %s must be valid JSON. Value = '%s'. Error message: %s

schema validation

2240

422

Illegal property value. The property '%s' is a datetime property with resolution 'date' and is unable to accept the value '%s'.

schema validation

2250

422

The decimal value %s is not valid. The type '%s' does not permit values smaller than %s.

schema validation

2251

422

The decimal value %s is not valid. The type '%s' does not permit values larger than %s.

schema validation

2260

422

The integer value %s is not valid. The type '%s' does not permit values smaller than %s.

schema validation

2261

422

The integer value %s is not valid. The type '%s' does not permit values larger than %s.

schema validation

2270

422

String value is too short. The type '%s' permits only strings with a length of at least %s. The length of '%s' is %s.

schema validation

2271

422

String value is too long. The type '%s' permits only strings with a length up to %s. The length of '%s' is %s.

schema validation

2272

422

String value is too long. A string property permits only strings with a length up to %s. The property '%s' has a value with the length %s: '%s'.

schema validation

2280

422

Illegal column. A table of type '%s' cannot have a column named '%s'.

schema validation

2281

422

Illegal column names. The column '%s' occures %s times.

schema validation

2282

422

Malformed table. The maximum number of rows in a table must not exceed %s. Row count: '%s'

schema validation

2283

422

Invalid row. The row of a table property '%s' is expected to contain exactly %s entries, but row no. %s contains %s entries.

schema validation

2290

422

Structure data value too large. The value of the property '%s' contains %s sub-values. Only up to %s are allowed.

schema validation

2291

422

Structured data value too deep. The value of the property '%s' has a depth of %s. The maximum depth is %s.

schema validation

2292

422

Invalid value of structure data property '%s'. Non-string key found: '%s'.

schema validation

2293

422

Key too long. The length of the key '%s' in the value of the structured data property '%s' is %s. The maximum length is %s.

schema validation

2294

422

Invalid key '%s' in the value of the structured data property '%s'. The key must match the regex '%s'.

schema validation

2300

422

A required property is missing. property='%s'

schema validation

2470

422

Webhook execution resulted in an unexpected failure

webhook execution

2471

422

Webhook response with statuscode '%s' did not match the expected failure body format. Please see documentation to ensure correct webhook failure handling and have a look at the inner exception for details.

webhook execution

2880

-

Unable to disable app '%s'. There are references from the tenant schema to the schema of app '%s'.

app set validation

2881

-

Unable to disable app '%s'. There are references from the global schema to the schema of app '%s'.

app set validation

2882

-

Unable to disable app '%s' and enable app '%s'. There are references from the schema of app '%s' to the schema of app '%s'.

app set validation

2900

403

Method not allowed for tenant independent accounts.

authentication

2901

403

External access is not allowed for the service account.

authentication

2902

403

External access is not allowed for this endpoint.

authentication

2903

422

Could not create JWT. Cause [%s]

authentication

2950

500

Could not write audit entry. Cause [%s]

audit

2951

500

Database unreachable. Cause [%s]

audit

99999

depends on webhook type

<custom message>

webhook execution

2.9. System Hooks and Interceptors

System hooks are functions that apply to core functions of the yuuvis® Momentum API whenever certain conditions are met and that extend or modify those functions. As such, they serve as a modular, external approach for introducing new functionalities as extensions of already existing ones. There are different types of system hooks available:

  • Lifecycle hooks

  • Webhooks

  • AMQP hooks

2.9.1. Predicate

The predicate specifies a SPEL condition for the call of individual hooks. It is declared in the hook configuration.

In the condition, the metadata of DMS objects can be referenced. The available properties depend on the webhook type as they match the DMS objects at different processing states. However, the options section is kept constant as far as possible.

Availability of 'options' Properties for Hooks
During Import
Hook Category Hook Type Available 'options' properties

Webhook

dms.request.objects.upsert.storage-before

action
detail
tenant
user
authorities

Lifecycle Hook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities

Webhook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities

Webhook

dms.response.objects

action
detail
tenant
user
authorities

Webhook

dms.response.objects.insert

action
detail
tenant
user
authorities

AMQP Hook

dms.response.insert

action
detail
tenant
user
authorities

During Batch Metadata Update
Hook Category Hook Type Available 'options' properties

Webhook

dms.request.objects.upsert.storage-before

action
detail
tenant
user
authorities

Lifecycle Hook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities

Webhook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities

AMQP Hook

dms.response.update

action
detail
tenant
user
authorities

Webhook

dms.response.objects

action
detail
tenant
user
authorities

Webhook

dms.response.objects.update

action
detail
tenant
user
authorities

During Single Metadata Update
Hook Category Hook Type Available 'options' properties

Webhook

dms.request.objects.upsert.storage-before

action
detail
tenant
user
authorities
currentVersion

Lifecycle Hook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities

Webhook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities
currentVersion

AMQP Hook

dms.response.update

action
detail
tenant
user
authorities
previousVersion

Webhook

dms.response.objects

action
detail
tenant
user
authorities
previousVersion

Webhook

dms.response.objects.update

action
detail
tenant
user
authorities
previousVersion

During Pure Content Update
Hook Category Hook Type Available 'options' properties

Webhook

dms.request.objects.upsert.storage-before

action
detail
tenant
user
authorities
currentVersion

Lifecycle Hook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities

Webhook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities
currentVersion

Webhook

dms.response.objects

action
detail
tenant
user
authorities
previousVersion

Webhook

dms.response.objects.update

action
detail
tenant
user
authorities
previousVersion

AMQP Hook

dms.response.update

action
detail
tenant
user
authorities
previousVersion

During Multipart Update
Hook Category Hook Type Available 'options' properties

Webhook

dms.request.objects.upsert.storage-before

action
detail
tenant
user
authorities

Lifecycle Hook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities

Webhook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities
currentVersion

Webhook

dms.response.objects

action
detail
tenant
user
authorities

Webhook

dms.response.objects.update

action
detail
tenant
user
authorities

AMQP Hook

dms.response.update

action
detail
tenant
user
authorities

During Content Deletion
Hook Category Hook Type Available 'options' properties

Lifecycle Hook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities

Webhook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities
currentVersion

AMQP Hook

dms.response.update

action
detail
tenant
user
authorities
previousVersion

Webhook

dms.response.objects

action
detail
tenant
user
authorities
previousVersion

Webhook

dms.response.objects.update

action
detail
tenant
user
authorities
previousVersion

During Restore Version
Hook Category Hook Type Available 'options' properties

Webhook

dms.request.objects.upsert.storage-before

action
detail
tenant
user
authorities
currentVersion

Lifecycle Hook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities

Webhook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities
currentVersion

AMQP Hook

dms.response.update

action
detail
tenant
user
authorities
previousVersion

Webhook

dms.response.objects

action
detail
tenant
user
authorities
previousVersion

Webhook

dms.response.objects.update

action
detail
tenant
user
authorities
previousVersion

During Tag Creation/Update/Deletion
Hook Category Hook Type Available 'options' properties

Webhook

dms.request.objects.upsert.storage-before

action
detail
tenant
user
authorities
currentVersion

Lifecycle Hook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities

Webhook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities
currentVersion

AMQP Hook

dms.response.update

action
detail
tenant
user
authorities
previousVersion

Webhook

dms.response.objects

action
detail
tenant
user
authorities
previousVersion

Webhook

dms.response.objects.update

action
detail
tenant
user
authorities
previousVersion

During Tag Search&Set
Hook Category Hook Type Available 'options' properties

Webhook

dms.request.search

tenant
user
authorities

Webhook

dms.request.objects.upsert.storage-before

action
detail
tenant
user
authorities
currentVersion

Lifecycle Hook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities

Webhook

dms.request.objects.upsert.database-before

action
detail
tenant
user
authorities
currentVersion

AMQP Hook

dms.response.update

action
detail
tenant
user
authorities
previousVersion

Webhook

dms.response.objects

action
detail
tenant
user
authorities
previousVersion

Webhook

dms.response.objects.update

action
detail
tenant
user
authorities
previousVersion

During Content Move
Hook Category Hook Type Available 'options' properties

AMQP Hook

dms.response.update

action
detail
tenant
user
authorities
previousVersion

Webhook

dms.response.objects

action
detail
tenant
user
authorities
previousVersion

During Single Deletion
Hook Category Hook Type Available 'options' properties

Webhook

dms.response.objects.delete

action
detail
tenant
user
authorities

Webhook

dms.response.objects

action
detail
tenant
user
authorities

AMQP Hook

dms.response.delete

action
detail
tenant
user
authorities

Webhook

dms.response.objects.delete

action
detail
tenant
user
authorities

During Batch Deletion
Hook Category Hook Type Available 'options' properties

Webhook

dms.response.objects.delete

action
detail
tenant
user
authorities

Webhook

dms.response.objects

action
detail
tenant
user
authorities

AMQP Hook

dms.response.delete

for actually deleted objects:
action
detail
tenant
user
authorities

Webhook

dms.response.objects.delete

for actually deleted objects:
action
detail
tenant
user
authorities
system:deletionResult

During Search
Hook Category Hook Type Available 'options' properties

Webhook

dms.response.search

tenant
user
authorities

Webhook

dms.response.objects

tenant
user
authorities

Webhook

dms.response.objects.search

tenant
user
authorities
system:deletionResult

During Metadata Retrieval
Hook Category Hook Type Available 'options' properties

Webhook

dms.response.objects

action
detail
tenant
user
authorities

During Content Retrieval
Hook Category Hook Type Available 'options' properties

Webhook

dms.request.objects.contents

action
detail
tenant
user
authorities

2.9.2. Lifecycle Hooks

As of 2024 Spring.

These hooks provide an easy way to automatically add/update tags to DMS objects during their creation or during update processes.

The tag’s name and state are specified in the lifecycle hooks configuration.

A predicate allows to specify a condition that has to be matched by the DMS object to be tagged via lifecycle hook.

The assigned tags can be used to implement an asynchronous custom processing chain to continue working on the tagged DMS objects according to the business use case.

Types of Lifecycle Hooks
dms.request.objects.upsert.database-before - Applies to enriched objects just before indexing during import or content/metadata/tag update.
As of Version

2024 Spring

Description

This lifecycle hook can be triggered by

  • an object import,

  • an update of the content,

  • an update of the metadata,

  • or a tag update.

The lifecycle hook receives the completed objects just before they are indexed. This means that the objects are already enriched with system properties and default values (wherever necessary), normalized and validated.

The corresponding webhook entry point dms.request.objects.upsert.database-before is reached after the lifecycle hooks' entry point. Thus, if configured, a webhook might manipulate the tag information again.
Affected API Requests and Action Codes/History Codes

100 - OBJECT_CREATED
101 - OBJECT_CREATED_WITH_CONTENT

101 - OBJECT_CREATED_WITH_CONTENT

300 - OBJECT_METADATA_CHANGED

300 - OBJECT_METADATA_CHANGED
302 - OBJECT_METADATA_DOCUMENT_CHANGED

301 - OBJECT_DOCUMENT_CHANGED

201 - OBJECT_CONTENT_DELETED

325 - OBJECT_RESTORED_FROM_VERSION

110 - OBJECT_TAG_CREATED
310 - OBJECT_TAG_UPDATED

210 - OBJECT_TAG_DELETED

110 - OBJECT_TAG_CREATED

310 - OBJECT_TAG_UPDATED

Called by Service

registry service

Example list of DMS objects
{
  "objects" : [ {
    "properties" : {
      "system:objectId" : {
        "value" : "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
      },
      "system:baseTypeId" : {
        "value" : "system:document"
      },
      "system:objectTypeId" : {
        "value" : "smallDocument"
      },
      "system:createdBy" : {
        "value" : "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
      },
      "system:creationDate" : {
        "value" : "2021-07-22T15:30:05.020Z"
      },
      "system:lastModifiedBy" : {
        "value" : "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
      },
      "system:lastModificationDate" : {
        "value" : "2021-07-22T15:30:21.520Z"
      },
      "system:versionNumber" : {
        "value" : 2
      },
      "system:tenant" : {
        "value" : "tenant1"
      },
      "system:traceId" : {
        "value" : "97a35859dbb4c435"
      },
      "Name" : {
        "value" : "exampledocument-without-content after update"
      }
    },
    "options" : {
      "action" : 300,
      "detail" : "OBJECT_METADATA_CHANGED",
      "tenant" : "tenant1",
      "user" : "root",
      "authorities" : [ "YUUVIS_SYSTEM_INTEGRATOR", "YUUVIS_TENANT_ADMIN" ],
      "inputVersion" : {
        "properties" : {
          "system:objectId" : {
            "value" : "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
          },
          "system:objectTypeId" : {
            "value" : "smallDocument"
          },
          "Name" : {
            "value" : "exampledocument-without-content after update"
          }
        }
      },
      "currentVersion" : {
        "properties" : {
          "system:objectId" : {
            "value" : "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
          },
          "system:baseTypeId" : {
            "value" : "system:document"
          },
          "system:objectTypeId" : {
            "value" : "smallDocument"
          },
          "system:createdBy" : {
            "value" : "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
          },
          "system:creationDate" : {
            "value" : "2021-07-22T15:30:05.020Z"
          },
          "system:lastModifiedBy" : {
            "value" : "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
          },
          "system:lastModificationDate" : {
            "value" : "2021-07-22T15:30:21.520Z"
          },
          "system:versionNumber" : {
            "value" : 1
          },
          "system:tenant" : {
            "value" : "tenant1"
          },
          "system:traceId" : {
            "value" : "672c49b7070ebd21"
          },
          "Name" : {
            "value" : "exampledocument-without-content"
          }
        }
      }
    }
  } ]
}
Example Predicate

Check if the object type is appEmail:email:

spel:'appEmail:email'.equals(properties['system:objectTypeId']['value'])
Configuring Lifecycle Hooks

As a type of system hooks, lifecycle hooks are configured in the systemHookConfiguration.json configuration file. The configuration is managed via the endpoints listed here.

2.9.3. Webhooks

System hooks that extend a function call by an HTTP call under defined conditions.

In order to insert an additional action into the process flow of a functional sequence, the ability for reacting to a function call is required. In yuuvis® Momentum, webhooks are a suitable option for this purpose. They belong to the system hooks and thus are triggered by function calls under specified conditions defined on their predicate attribute.

A webhook extends the function by an HTTP call. Whenever the predicate of a webhook delivers a true result, an optional HTTP call to a web URL defined in the webhook configuration is performed. The process flow is interrupted until the webhook activity is finished. Thus, the webhook can perform additional processing steps before passing the data back to resume the interrupted main process. If the predicate of a webhook delivers a false result, the HTTP call is skipped.

For the additional processing, a custom service has to be implemented. This service must be able to handle the request body and the assigned headers. Please note the maximum header size that should be supported by your custom service.

Import and content update webhooks are called in the Repository service, all others in the API-gateway service.

Any changes to the webhook configuration require a restart of the services that are responsible for the call of the affected functions.

Webhook Types

Depending on their type, webhooks are triggered in different situations within the data processing chain.

The webhook type dms.response.objects can be triggered in various situations. For some of them there are special webhook types (dms.response.objects.insert, dms.response.objects.update, dms.response.objects.search, dms.response.objects.delete). These sub-webhooks are triggered directly after dms.response.objects.

GET user.info - Retrieves roles and any additional available information about the current user logging in to the authentication system from the URL.
As of Version

2019 Winter

HTTP Method

GET

Response Format

JSON

Parameter

String tenant, String userID

Description

Retrieves roles and any additional available information about the current user logging in to the authentication system from the URL.

In the predicate, the tenant of the user who sent the request can be referenced to formulate a condition.

Requirements for External Endpoint

The target URL must return the JSON structure shown in the example response below.

Called by Service

Authentication service

Example Response
{
    "username": "111a222b-3c44-5d66-7777-8e999f0000a1",
    "id": "222a333b-4c55-6d77-8888-9e000f1111a2",
    "domain": "dd",
    "tenant": "default",
    "authorities": [
        "TENANT_ADMIN",
        "SYSTEM_INTEGRATOR",
        "ACCESS_FOREIGN_JOURNAL_OBJECTS"
    ],
    "accountNonExpired": true,
    "accountNonLocked": true,
    "credentialsNonExpired": true,
    "enabled": true
}
Example Predicate

Check if the calling user belongs to the default tenant:

spel:'default'.equals(options['tenant'])

POST dms.request.objects.upsert.storage-before - Applies to not-enriched objects during import or content/metadata/tag update.
As of Version

2020 Spring

HTTP Method

POST

Response Format

JSON

Description

This webhook can be triggered by

  • an object import,

  • an update of the content,

  • an update or the metadata,

  • or a tag update.

The original body is an object list with the metadata of the import/update and the corresponding options properties. The metadata are not yet enriched with the system properties that are automatically set by the system. To refer to those properties in a webhook, use POST dms.request.objects.upsert.database-before (Webhook).

The body is modified by the webhook and returned for the resumption of the original process.

The predicate is applied to every single object in the list. The webhook is triggered for the whole object list as soon as one object satisfies the predicate.

Requirements for External Endpoint

The target URL must be a POST endpoint accepting and returning a list of objects.

Affected API Requests and Action Codes/History Codes

POST /api/dms/objects

100 - OBJECT_CREATED
101 - OBJECT_CREATED_WITH_CONTENT (since 2021 Summer)

POST /api/dms/objects/{objectId}
PATCH /api/dms/objects/{objectId}

300 - OBJECT_METADATA_CHANGED

POST /api/dms/objects/{objectId} (multipart) (as of 2024 Spring)

300 - OBJECT_METADATA_CHANGED
302 - OBJECT_METADATA_DOCUMENT_CHANGED

PATCH /api/dms/objects

300 - OBJECT_METADATA_CHANGED

  • In a batch update, it is possible that processing is possible for some objects and for others not due to different reasons (see option system:response described in the endpoint PATCH /api/dms/objects).

  • During the update processing, objects always have the same action value, regardless of whether they are processable or not. Consider the action value to decide what should be done with the objects.

  • Successful and failed processing can be distinguished by the option system:response of each individual DMS object in the batch.

POST /api/dms/objects/{objectId}/contents/file

301 - OBJECT_DOCUMENT_CHANGED

POST /api/dms/objects/{objectId}/versions/{versionNr}/actions/restore (as of 2022 Spring)

325 - OBJECT_RESTORED_FROM_VERSION

POST /api/dms/objects/tags/{name}/state/{state}?query=<SQL>

110 - OBJECT_TAG_CREATED (since 2021 Summer)
310 - OBJECT_TAG_UPDATED (since 2021 Summer)

DELETE /api/dms/objects/{objectId}/tags/{name}

210 - OBJECT_TAG_DELETED (since 2021 Summer)

POST /api/dms/objects/{objectId}/tags/{name}/state/{state}

110 - OBJECT_TAG_CREATED (since 2021 Summer)

POST /api/dms/objects/{objectId}/tags/{name}/state/{state}?overwrite=true

310 - OBJECT_TAG_UPDATED (since 2021 Summer)

Called by Service

repository service

Header

Authorization-Header

X-B3-TraceId

Example Request Body
{
  "objects": [{
    "properties": {
      "system:objectTypeId": {
        "value": "object"
      },
      "label": {
        "value": "Label"
      },
      "subentitaet": {
        "value": "Sub"
      },
      "idn": {
        "value": "6754"
      },
      "titel": {
        "value": "Titel"
      },
      "medientyp": {
        "value": "Cool filename"
      }
    },
    "contentStreams": [{
      "cid": "cid_63apple",
      "mimeType": "application/pdf",
      "fileName" : "document01.pdf"
    }],
    "options": {
      "action": 101,
      "detail": "OBJECT_CREATED_WITH_CONTENT",
      "tenant": "tenant1"
    }
  }]
}
Example Predicate

Check if there is an object with binary content:

spel:contentStreams!=null

POST dms.request.objects.upsert.database-before - Applies to enriched objects just before indexing during import or content/metadata/tag update.
As of Version

2021 Autumn

HTTP Method

POST

Response Format

JSON

Description

This webhook can be triggered by

The webhook receives the completed objects just before they are indexed. This means that the objects are already enriched with system properties and default values (wherever necessary), normalized and validated.

In version 2021 Autumn, if there are invalid objects, the entry point of this webhook type is not reached. A validation exception is thrown before.

As of version 2021 Winter, the following behavior is implemented:

  • Each object is still validated before the entry point of the webhook, but a validation exception is thrown after the webhook entry point. Thus, webhooks of this type can be triggered even in case of an invalid object.

  • Those objects contain the corresponding validation errors in their options (see example below). Hence, it is possible to, e.g., add required properties to the original request body subsequently via a webhook.

  • The object validation is performed again after the webhook. Only if there still are validation errors, a validation exception is thrown.

  • If multiple webhooks of this type are configured, a validation is performed between every triggered webhook and its succeeding webhook. Especially if objects have validation errors that were corrected by one webhook, the succeeding webhook gets the valid objects without validation errors in their options. If there are still invalid objects after the last webhook, then a validation exception is thrown.

As of version 2021 Winter: example validation errors that will be included in the 'options' of an invalid object
{
    ...
    "options": {
        "action": 300,
        "detail": "OBJECT_METADATA_CHANGED",
        "validationErrors": [
            {
                "message": "Illegal property. An object of type 'appEmail:email' cannot have a property named 'decSingle'.",
                "serviceErrorCode": 2607
            },
            {
                "message": "A required property is missing. property='appEmail:from'",
                "serviceErrorCode": 2300
            }
        ]
        ...
    }
}

The predicate is applied to every single object in the list. The webhook is triggered for the whole object list as soon as one object satisfies the predicate.

The objects returned by the webhook are normalized and validated again before the interrupted processing chain will be continued. Hence, by means of this webhook, it is not possible to introduce invalid objects into the system. Furthermore, the object list in the original request body cannot be completely overwritten. The following rules apply:

  • It is not allowed to change the number of objects in the object list. An error will be thrown.

  • It is not allowed to modify the value of the system:objectId property. An error will be thrown.

  • System properties that are set by the system as well as content stream properties cannot be changed. An error will be thrown.

  • In particular, the values for system:lastModificationDate (and system:creationDate in case of an import process) are set before and are not updated due to any manipulations via webhook.

  • The expiration date cannot be removed or replaced by an earlier one.

  • If the value for system:parentId is changed, the new parent must be visible for the user who sent the original request.

  • As of version 2022 Autumn: If the webhook removes a secondary object type (SOT) from an object, all properties that were provided by the SOT are automatically removed from that object as well.

  • As of version 2022 Autumn: If the webhook adds an SOT to an object, all properties provided by the SOT can be added to that object by the webhook as well. If those properties are not added by the webhook, they will be automatically added with their default values afterwards (if available).

  • Data in the options section are read-only for the webhook. Changes will be ignored, and the original values will be used. An error will not be thrown.

Specific rules for metadata updates (action has value 300):

  • At the webhook entry point, all objects match exactly one of the following states:

    1. None of the options system:response or validationErrors are available. → The object is valid and successfully updated unless a webhook applies improper changes.

    2. The validationErrors option is available. → The object is currently invalid. The metadata update fails unless a webhook corrects the conflicts.

    3. As of 2023 Winter: The system:response option is available and its httpStatusCode value is >= 400. → The object’s update was requested within a batch request and has failed. There is NO way to resume its update process via webhook.

Tag-specific rules:

  • If tags are added by webhook during an import or metadata update, the values of system:lastModificationDate and system:traceId are used for creationDate and traceId of these tags.

  • If tags are added/updated by an import or metadata update and manipulated by webhook, the value of system:lastModificationDate is used for the tags' creationDate.

  • If tags are added or updated during a pure tag operation, creationDate is set according to the original request.

  • In general, any changes of the object applied by the webhook must match the action specified in the options section. Otherwise, the original request will result in an error. Consider the restrictions for these specific action codes in particular:

    Value for 'action' Restriction

    301

    A webhook cannot change custom properties, retention properties or the system:secondaryObjectTypeIds property. As an exception, however, it is possible to add, update, or remove tags. Non-resistant tags are already removed from the object at this stage. A webhook can add resistant and non-resistant tags. All of them will be assigned to the final object. Further removals of non-resistant tags are not applied after the webhook.

    110/210/310

    Only changes to the system:tags property matching the individual action are allowed.

Considering the action code, the webhook might be allowed to change tags. In the audit trail, the tagging-related entry will be the same if the tag modification was specified in the original request or by means of the webhook, e.g.:

  • If an update adds a tag and a webhook removes this tag within the same update request, no audit entries are created.

  • If an update adds a tag and a webhook changes the state of this tag within the same update request, only one audit entry (OBJECT_TAG_CREATED) is created.

Requirements for External Endpoint

The target URL must be a POST endpoint accepting and returning a list of objects.

Affected API Requests and Action Codes/History Codes

100 - OBJECT_CREATED
101 - OBJECT_CREATED_WITH_CONTENT

300 - OBJECT_METADATA_CHANGED

300 - OBJECT_METADATA_CHANGED
302 - OBJECT_METADATA_DOCUMENT_CHANGED

300 - OBJECT_METADATA_CHANGED

  • In a batch update, it is possible that processing is possible for some objects and for others not due to different reasons (see option system:response described in the endpoint PATCH /api/dms/objects).

  • During the update processing, objects always have the same action value, regardless of whether they are processable or not. Consider the action value to decide what should be done with the objects.

  • Successful and failed processing can be distinguished by the option system:response of each individual DMS object in the batch.

301 - OBJECT_DOCUMENT_CHANGED

201 - OBJECT_CONTENT_DELETED

325 - OBJECT_RESTORED_FROM_VERSION

110 - OBJECT_TAG_CREATED (since 2021 Summer)
310 - OBJECT_TAG_UPDATED (since 2021 Summer)

210 - OBJECT_TAG_DELETED (since 2021 Summer)

110 - OBJECT_TAG_CREATED (since 2021 Summer)

310 - OBJECT_TAG_UPDATED (since 2021 Summer)

Called by Service

registry service

Header

Authorization-Header

X-B3-TraceId

Example Request Body
{
  "objects" : [ {
    "properties" : {
      "system:objectId" : {
        "value" : "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
      },
      "system:baseTypeId" : {
        "value" : "system:document"
      },
      "system:objectTypeId" : {
        "value" : "smallDocument"
      },
      "system:createdBy" : {
        "value" : "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
      },
      "system:creationDate" : {
        "value" : "2021-07-22T15:30:05.020Z"
      },
      "system:lastModifiedBy" : {
        "value" : "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
      },
      "system:lastModificationDate" : {
        "value" : "2021-07-22T15:30:21.520Z"
      },
      "system:versionNumber" : {
        "value" : 2
      },
      "system:tenant" : {
        "value" : "tenant1"
      },
      "system:traceId" : {
        "value" : "97a35859dbb4c435"
      },
      "Name" : {
        "value" : "exampledocument-without-content after update"
      }
    },
    "options" : {
      "action" : 300,
      "detail" : "OBJECT_METADATA_CHANGED",
      "tenant" : "tenant1",
      "user" : "root",
      "authorities" : [ "YUUVIS_SYSTEM_INTEGRATOR", "YUUVIS_TENANT_ADMIN" ],
      "inputVersion" : {
        "properties" : {
          "system:objectId" : {
            "value" : "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
          },
          "system:objectTypeId" : {
            "value" : "smallDocument"
          },
          "Name" : {
            "value" : "exampledocument-without-content after update"
          }
        }
      },
      "currentVersion" : {
        "properties" : {
          "system:objectId" : {
            "value" : "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
          },
          "system:baseTypeId" : {
            "value" : "system:document"
          },
          "system:objectTypeId" : {
            "value" : "smallDocument"
          },
          "system:createdBy" : {
            "value" : "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
          },
          "system:creationDate" : {
            "value" : "2021-07-22T15:30:05.020Z"
          },
          "system:lastModifiedBy" : {
            "value" : "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
          },
          "system:lastModificationDate" : {
            "value" : "2021-07-22T15:30:21.520Z"
          },
          "system:versionNumber" : {
            "value" : 1
          },
          "system:tenant" : {
            "value" : "tenant1"
          },
          "system:traceId" : {
            "value" : "672c49b7070ebd21"
          },
          "Name" : {
            "value" : "exampledocument-without-content"
          }
        }
      }
    }
  } ]
}
Example Predicate

Check if the object type is appEmail:email:

spel:'appEmail:email'.equals(properties['system:objectTypeId']['value'])
POST dms.request.objects.contents - Can be triggered by a request for retrieval of a binary content file or a rendition. Applies to the corresponding DMS object as stored in the system including properties, contentStreams and options sections.
As of Version

2022 Winter

HTTP Method

POST

Response Format

JSON

Description

A webhook of this type can be triggered by a request for retrieval of a binary content file or a rendition.

The original body that is available at the webhook entry point is an object list containing the object for which the content/rendition and the corresponding options properties should be retrieved.

Requirements for External Endpoint

The target URL must be a POST endpoint accepting and returning a list of objects. The following responses are expected:

Return HTTP status code 200 to continue with the content/rendition retrieval. Changes in the body introduced within the webhook are ignored. Return any HTTP status code indicating an error (400…​599) and a properly formatted error structure in the body to prohibit the content/rendition retrieval. Your error structure will finally be presented as response of the originally called endpoint with HTTP status code 404. If your webhook returns an error structure that does not match the expected format, the content retrieval fails with HTTP status code 422. The webhook error is wrapped as plain text.

Affected API Requests and Action Codes/History Codes

400 - DOCUMENT_ACCESSED

402 - RENDITION_ACCESSED

Called by Service

api gateway service

Header

Authorization-Header

X-B3-TraceId

Example Request Body
{
    "objects": [
        {
            "properties": {
                "system:objectId": {
                    "value": "27602f73-7e3f-4013-babb-10a4dc042ff0"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:objectTypeId": {
                    "value": "document"
                },
                "system:createdBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:creationDate": {
                    "value": "2021-05-22T00:09:05.400Z"
                },
                "system:lastModifiedBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:lastModificationDate": {
                    "value": "2021-05-22T00:09:05.400Z"
                },
                "system:versionNumber": {
                    "value": 1
                },
                "system:tenant": {
                    "value": "default"
                },
                "system:traceId": {
                    "value": "f08d5290e5a81753"
                },
                "testString": {
                    "value": "test import"
                }
            },
            "contentStreams": [
                {
                    "contentStreamId": "EBC1760B-BA91-11EB-8277-D1DE73C78E3D",
                    "archivePath": "default/DOCUMENT/BC/17/6/",
                    "length": 431397,
                    "mimeType": "message/rfc822",
                    "fileName": "content.eml",
                    "digest": "11857B6FAD61E41AFB3E7398BA1BA4BFB6B0A5422762FF41A0907BC0BFF7748F",
                    "repositoryId": "repo242"
                }
            ],
            "options": {
                "action": 400,
                "detail": "DOCUMENT_ACCESSED",
                "tenant": "default",
                "system:hook:type": "dms.request.objects.contents",
                "system:request:method": "GET"
            }
        }
    ]
}
Example Predicate

The configured webhook will be triggered for each retrieval of a PDF rendition.

spel:options!=null && options['action']>402 && "2".equals(''+options['subaction'])
POST dms.request.objects.delete - Applies to the active version of the object or the specific version that is to be deleted.
As of Version

2021 Summer

HTTP Method

POST

Response Format

JSON

Description

The webhook is triggered if the object or version to delete exists and is deletable, i.e., if the user has sufficient permissions and if the object is not a non-empty folder.

The body contains an object list with the active version or the version to delete of the object(s).

The predicate is applied to every single object in the list. The webhook is triggered for the whole object list as soon as one object satisfies the predicate.

Changing Deletion to a Metadata Update

As of 2023 Spring, it is possible to turn a deletion request into a metadata update via webhook. The following rules apply:

  • The webhook has to change the options parameter action from 200 (stands for deletion) to 300 (stands for metadata update). If the webhook is triggered by a batch deletion request, the action has to be adjusted for all objects in the list.

  • The webhook can additionally change values of the objects' metadata properties.

  • In the audit trail, an entry with 300 OBJECT_METADATA_CHANGED will be created instead of the deletion audit entries 202 OBJECT_FLAGGED_FOR_DELETE and 200 OBJECT_DELETED.

  • If further webhooks of the same type are configured, they get the modified objects list in the body as usual, but they are not allowed to change the action value back to 200.

  • With the modified object list, a POST update with waitForSearchConsistency=true is internally performed.

  • The webhook entry point can only be reached with a delete permission on the objects. There is no additional check for a write permission.

  • The processing chain after the last webhook of type dms.request.objects.delete is now the metadata update chain. Thus, system hook entry points of other types later in the deletion procession chain are not reached anymore (e.g., webhook dms.response.objects.delete or AMQP hook dms.response.delete). Instead, the webhook entry points of the metadata update chain are passed and such webhooks can be triggered.

  • It is not possible to change the deletion of a single version (action 220) into a metadata update.

Requirements for External Endpoint

The target URL must be a POST endpoint accepting and returning a list of objects.

Affected API Requests and Action Codes/History Codes

200 - OBJECT_DELETED

220 - VERSION_DELETED

Called by Service

api gateway service

Header

Authorization-Header

X-B3-TraceId

Example Request Body
{
    "objects": [
        {
            "properties": {
                "system:traceId": {
                    "value": "adcb4edd823fca4c"
                },
                "system:objectTypeId": {
                    "value": "document"
                },
                "system:versionNumber": {
                    "value": 3
                },
                "testString": {
                    "value": "new test import"
                },
                "system:createdBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:creationDate": {
                    "value": "2020-07-23T13:12:34.370Z"
                },
                "system:lastModificationDate": {
                    "value": "2020-07-23T13:12:35.910Z"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:tenant": {
                    "value": "default"
                },
                "system:lastModifiedBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:objectId": {
                    "value": "9ce1ab26-1a6b-4bc2-aa4b-2b099bff7468"
                }
            },
            "contentStreams": [
                {
                    "contentStreamId": "4710AB82-C1B4-11EA-B395-49C30F249D00",
                    "archivePath": "default/DOCUMENT/71/0A/B/",
                    "length": 431397,
                    "mimeType": "application/octet-stream",
                    "digest": "11857B6FAD61E41AFB3E7398BA1BA4BFB6B0A5422762FF41A0907BC0BFF7748F",
                    "repositoryId": "repo252"
                }
            ],
            "options": {
                "action": 200,
                "detail": "OBJECT_DELETED",
                "tenant": "default",
                "user": "root",
                "authorities": [
                    "ACL_ADMIN",
                    "YUUVIS_TENANT_ADMIN",
                    "uma_authorization"
                ]
            }
        }
    ]
}
Example Predicate

Check if the object type is appEmail:email:

spel:'appEmail:email'.equals(properties['system:objectTypeId']['value'])
POST dms.response.objects - Applies directly before the return whenever objects lists are part of the HTTP response: Search queries, Object imports/retrievals/updates, …​
As of Version

2019 Winter

HTTP Method

POST

Response Format

JSON

Description

Delivers a list of predicate-matching objects to a secondary recipient.

Any request returning an object list triggers this webhook directly before the return. Applies whenever object lists are part of the HTTP response:

  • Search queries

  • Object imports

  • Object GETs

  • Object metadata updates

  • Moving content

For example, properties can be extracted to hide them for individual users.

The body contains the object list that will be returned. In most cases, this list is of length 1. Only for the search endpoint, there are also numItems, hasMoreItems and totalNumItems. The body is modified by the webhook and returned afterwards.

The predicate is applied to every single object in the list. The webhook is triggered for the whole object list as soon as one object satisfies the predicate.

Requirements for External Endpoint

The target URL must be a POST endpoint accepting and returning a list of objects.

Affected API Requests and Action Codes/History Codes

100 - OBJECT_CREATED
101 - OBJECT_CREATED_WITH_CONTENT (since 2021 Summer)

300 - OBJECT_METADATA_CHANGED

300 - OBJECT_METADATA_CHANGED
302 - OBJECT_METADATA_DOCUMENT_CHANGED

300 - OBJECT_METADATA_CHANGED

  • In a batch update, processing may be possible for some objects and not for others for various reasons (see option system:response described in the endpoint PATCH /api/dms/objects).

  • During the update processing, objects always have the same action value, regardless of whether they are processable or not. Consider the action value to decide what should be done with the objects.

  • Successful and failed processing can be distinguished by the option system:response of each individual DMS object in the batch.

301 - OBJECT_DOCUMENT_CHANGED (since 2021 Summer)

201 - OBJECT_CONTENT_DELETED

325 - OBJECT_RESTORED_FROM_VERSION

110 - OBJECT_TAG_CREATED
310 - OBJECT_TAG_UPDATED

210 - OBJECT_TAG_DELETED

110 - OBJECT_TAG_CREATED

310 - OBJECT_TAG_UPDATED

303 - OBJECT_UPDATE_CONTENT_MOVED

-

-

-

-

200 - OBJECT_DELETED (the delete request was successful)
201 - OBJECT_CONTENT_DELETED (the object is flagged for delete and the content and the object in the SQL database are deleted, but the deletion in Elasticsearch failed)
202 - OBJECT_FLAGGED_FOR_DELETE (the object is flagged for deletion, which makes it invisible, but it is not actually deleted. If asynchronous deletion is activated in the service configuration, this is the only possible action.)

200 - OBJECT_DELETED (the delete request was successful. All deletable objects in the batch are deleted.)
201 - OBJECT_CONTENT_DELETED (the deletable objects in the batch are flagged for deletion, their contents are deleted and their representations in the SQL database are deleted, but the deletion in Elasticsearch failed)
202 - OBJECT_FLAGGED_FOR_DELETE (the deletable objects in the batch are flagged for deletion, which makes them invisible, but they are not actually deleted. If asynchronous deletion is activated in the service configuration, this is the only possible action.)

  • In a batch deletion, deletion may be possible for some objects and not for others for various reasons (see option system:deletionResult described in the endpoint DELETE /api/dms/objects).

  • During the deletion processing, objects always have the same action value, no matter if they are deletable or not. Consider the action value to decide what should be done with the objects.

  • Successful and failed deletion processing can be distinguished by the option system:deletionResult of each individual DMS object in the batch.

220 - VERSION_DELETED

Called by Service

api gateway service, repository service

Header

Authorization-Header

X-B3-TraceId

Example Request Body
{
  "objects" : [ {
    "properties" : {
      "appEmail:subject" : {
        "value" : "any subject"
      },
      "appEmail:to" : {
        "value" : [ "user1@example.de" ]
      }
    }
  }, {
    "properties" : {
      "appEmail:subject" : {
        "value" : "another subject"
      },
      "appEmail:to" : {
        "value" : [ "user2@example.de" ]
      }
    }
  } ],
  "numItems" : 2,
  "hasMoreItems" : true,
  "totalNumItems" : 356
}
Example Predicate

Check if the object has the property appEmail:bcc.

spel:properties['appEmail:bcc']!=null
POST dms.response.objects.insert - Import requests trigger this webhook after successful import directly before the return.
As of Version

2021 Summer

HTTP Method

POST

Response Format

JSON

Description

Import requests trigger this webhook after successful import directly before the return.

The body contains the object list that will be returned. The body is modified by the webhook and returned afterwards.

The predicate is applied to every single object in the list. The webhook is triggered for the whole object list as soon as one object satisfies the predicate.

Requirements for External Endpoint

The target URL must be a POST endpoint accepting and returning a list of objects.

Affected API Requests

POST /api/dms/objects

Action Codes - History Codes

101 - OBJECT_CREATED_WITH_CONTENT
100 - OBJECT_CREATED

Called by Service

repository service

Header

Authorization-Header

X-B3-TraceId

Example Request Body
{
    "objects": [
        {
            "properties": {
                "system:objectId": {
                    "value": "27602f73-7e3f-4013-babb-10a4dc042ff0"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:objectTypeId": {
                    "value": "document"
                },
                "system:createdBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:creationDate": {
                    "value": "2021-05-22T00:09:05.400Z"
                },
                "system:lastModifiedBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:lastModificationDate": {
                    "value": "2021-05-22T00:09:05.400Z"
                },
                "system:versionNumber": {
                    "value": 1
                },
                "system:tenant": {
                    "value": "default"
                },
                "system:traceId": {
                    "value": "f08d5290e5a81753"
                },
                "testString": {
                    "value": "test import"
                }
            },
            "contentStreams": [
                {
                    "contentStreamId": "EBC1760B-BA91-11EB-8277-D1DE73C78E3D",
                    "archivePath": "default/DOCUMENT/BC/17/6/",
                    "length": 431397,
                    "mimeType": "message/rfc822",
                    "fileName": "content.eml",
                    "digest": "11857B6FAD61E41AFB3E7398BA1BA4BFB6B0A5422762FF41A0907BC0BFF7748F",
                    "repositoryId": "repo242"
                }
            ],
            "options": {
                "action": 101
            }
        }
    ]
}
Example Predicate

Check if the object type is appEmail:email:

spel:'appEmail:email'.equals(properties['system:objectTypeId']['value'])

Check if at least one imported object has content:

spel:options['action']==101
POST dms.response.objects.update - Update requests trigger this webhook after successful update directly before the return. This concerns content updates, metadata updates and tag updates.
As of Version

2021 Summer

HTTP Method

POST

Response Format

JSON

Description

Update requests trigger this webhook after successful update directly before the return. This concerns content updates, metadata updates and tag updates.

The body contains the object list that will be returned. The body is modified by the webhook and returned afterwards.

The predicate is applied to the single object in the list.

Requirements for External Endpoint

The target URL must be a POST endpoint accepting and returning a list of objects.

Affected API Requests and Action Codes/History Codes

300 - OBJECT_METADATA_CHANGED

300 - OBJECT_METADATA_CHANGED
302 - OBJECT_METADATA_DOCUMENT_CHANGED

300 - OBJECT_METADATA_CHANGED

  • In a batch update, processing may be possible for some objects and not for others for various reasons (see option system:response described in the endpoint PATCH /api/dms/objects).

  • During the update processing, objects always have the same action value, regardless of whether they are processable or not. Consider the action value to decide what should be done with the objects.

  • Successful and failed processing can be distinguished by the option system:response of each individual DMS object in the batch.

301 - OBJECT_DOCUMENT_CHANGED

201 - OBJECT_CONTENT_DELETED

325 - OBJECT_RESTORED_FROM_VERSION

110 - OBJECT_TAG_CREATED
310 - OBJECT_TAG_UPDATED

210 - OBJECT_TAG_DELETED

110 - OBJECT_TAG_CREATED

310 - OBJECT_TAG_UPDATED

Called by Service

api gateway service, repository service

Header

Authorization-Header

X-B3-TraceId

Example Request Body
{
    "objects": [
        {
            "properties": {
                "system:objectId": {
                    "value": "d7bd24b0-f8aa-49dc-a698-5513763d347a"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:objectTypeId": {
                    "value": "document"
                },
                "system:createdBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:creationDate": {
                    "value": "2021-05-21T14:16:50.010Z"
                },
                "system:lastModifiedBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:lastModificationDate": {
                    "value": "2021-05-22T00:35:30.180Z"
                },
                "system:versionNumber": {
                    "value": 3
                },
                "system:tenant": {
                    "value": "default"
                },
                "system:traceId": {
                    "value": "981f85ee55debc7d"
                },
                "testString": {
                    "value": "new test import"
                }
            },
            "contentStreams": [
                {
                    "contentStreamId": "99F9EE58-BA38-11EB-A4CA-43B80C415ED8",
                    "archivePath": "default/DOCUMENT/9F/9E/E/",
                    "length": 431397,
                    "mimeType": "message/rfc822",
                    "fileName": "test.txt",
                    "digest": "11857B6FAD61E41AFB3E7398BA1BA4BFB6B0A5422762FF41A0907BC0BFF7748F",
                    "repositoryId": "repo242"
                }
            ],
            "options": {
                "action": 300,
                "action_bckp": 300,
                "detail": "OBJECT_METADATA_CHANGED",
                "previousVersion": {
                    "properties": {
                        "system:traceId": {
                            "value": "e48801d4a97cb6ff"
                        },
                        "system:objectTypeId": {
                            "value": "document"
                        },
                        "system:versionNumber": {
                            "value": 2
                        },
                        "testString": {
                            "value": "test import"
                        },
                        "system:createdBy": {
                            "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                        },
                        "system:creationDate": {
                            "value": "2021-05-21T14:16:50.010Z"
                        },
                        "system:lastModificationDate": {
                            "value": "2021-05-21T14:17:27.880Z"
                        },
                        "system:baseTypeId": {
                            "value": "system:document"
                        },
                        "system:tenant": {
                            "value": "default"
                        },
                        "system:lastModifiedBy": {
                            "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                        },
                        "system:objectId": {
                            "value": "d7bd24b0-f8aa-49dc-a698-5513763d347a"
                        }
                    },
                    "contentStreams": [
                        {
                            "contentStreamId": "99F9EE58-BA38-11EB-A4CA-43B80C415ED8",
                            "archivePath": "default/DOCUMENT/9F/9E/E/",
                            "length": 431397,
                            "mimeType": "message/rfc822",
                            "fileName": "test.txt",
                            "digest": "11857B6FAD61E41AFB3E7398BA1BA4BFB6B0A5422762FF41A0907BC0BFF7748F",
                            "repositoryId": "repo242"
                        }
                    ]
                },
                "tenant": "default",
                "user": "root",
                "authorities": [
                    "ACL_ADMIN",
                    "YUUVIS_TENANT_ADMIN",
                    "uma_authorization"
                ]
            }
        }
    ]
}
Example Predicate

Check if the update is a metadata update:

spel:options!=null && options['action']==300

Check if the update is a tag update:

spel:options!=null && T(java.util.List).of(110,210,310).contains(options['action'])
POST dms.response.objects.delete - Triggered directly after the successful deletion of an object. Applies tp the active version of the object or the specific version that is deleted.
As of Version

2020 Autumn

HTTP Method

POST

Response Format

JSON

Description

This webhook is triggered directly after the successful deletion of a document and after the equivalent AMQP hook, and can for instance inform other systems.

The predicate is applied to every single object in the list. The webhook is triggered for the whole object list as soon as one object satisfies the predicate.

Requirements for External Endpoint

The target URL must be a POST endpoint accepting and returning a list of objects.

Affected API Requests and Action Codes/History Codes

200 - OBJECT_DELETED (the delete request was successful)

201 - OBJECT_CONTENT_DELETED (the object is flagged for delete and the content and the object in the SQL database is deleted, but the deletion in Elasticsearch failed)

202 - OBJECT_FLAGGED_FOR_DELETE (the object is flagged for deletion, which makes it invisible, but it is not actually deleted. If asynchronous deletion is activated in the service configuration, this is the only possible action.)

200 - OBJECT_DELETED (the delete request was successful. all deletable objects in the batch are deleted)

201 - OBJECT_CONTENT_DELETED (the deletable objects in the batch are flagged for deletion, their contents are deleted and their representations in the SQL database are deleted, but the deletion in Elasticsearch failed)

202 - OBJECT_FLAGGED_FOR_DELETE (the deletable objects in the batch are flagged for deletion, which makes them invisible, but they are not actually deleted. If asynchronous deletion is activated in the service configuration, this is the only possible action.)

  • In a batch deletion, it is possible that some objects are deletable and others are not due to different reasons (see option system:deletionResult described in the endpoint DELETE /api/dms/objects).

  • During the deletion processing, objects always have the same action value, no matter if they are deletable or not. Consider the action value to decide what should be done with the objects.

  • Successful and failed deletion processing can be distinguished by the option system:deletionResult of each individual DMS object in the batch.

220 - VERSION_DELETED (since 2021 Summer)

Called by Service

api gateway service

Header

Authorization-Header

X-B3-TraceId

Example Request Body
{
    "properties": {
        "system:traceId": {
            "value": "0000000000000000"
        },
        "system:objectTypeId": {
            "value": "appTable:order"
        },
        "appTable:ordernumber": {
            "value": 1
        },
        "system:versionNumber": {
            "value": 1
        },
        "appTable:items": {
            "value": [
                [
                    "fruits",
                    10
                ],
                [
                    "milk",
                    1
                ],
                [
                    "sweeties",
                    5
                ]
            ]
        },
        "system:creationDate": {
            "value": "2020-09-17T14:17:31.480Z"
        },
        "system:lastModificationDate": {
            "value": "2020-09-17T14:17:31.480Z"
        },
        "system:baseTypeId": {
            "value": "system:document"
        },
        "system:tenant": {
            "value": "default"
        },
        "appTable:customername": {
            "value": "customer1"
        },
        "system:createdBy": {
            "value": "111c226c-3a44-5e66-7777-8d999a0000e1"
        },
        "system:lastModifiedBy": {
            "value": "222c222c-2c22-2e22-2222-2d222d2222e2"
        },
        "system:objectId": {
            "value": "f4efc4e4-1234-4321-4f74-4de4ff34f744"
        }
    },
    "contentStreams": [
        {
            "contentStreamId": "0AB98765-CDEF-4321-ABCD-098EF76AB543",
            "archivePath": "default/DOCUMENT/12/34/5/",
            "length": 9000003,
            "mimeType": "image/jpg",
            "digest": "1234567812345678123456781234567812345678123456781234567812345678",
            "repositoryId": "repo002"
        }
    ],
    "options": {
        "action": 200,
        "detail": "OBJECT_DELETED"
    }
}
Example Predicate

Check if the object type is appTable:order:

spel:'appTable:order'.equals(options['currentVersion']['properties']['system:objectTypeId']['value'])
Configuring Webhooks

As a type of system hooks, webhooks are configured in the \service-manager\config\system\systemHookConfiguration.json configuration file within the service manager in JSON format. Any changes to the system hook configuration will not apply until the affected services have been restarted.

The timeouts that limit the process time of webhooks in order to avoid system bottlenecks are configured in the application-prod.yml configuration file.

If multiple webhooks are registered for the same webhook type, the predicate is applied to the original predicate target for each of them and in the order of definition. Imagine an example scenario with two registered webhooks of the type dms.response.objects.search:

{
    "enable": true,
    "predicate": "spel:true",
    "type": "dms.response.objects.search",
    "url": <suitable endpoint removing the property 'appEmail:bcc'>,
    "useDiscovery": true
},
{
    "enable": true,
    "predicate": "spel:properties['appEmail:bcc']!=null",
    "type": "dms.response.objects.search",
    "url": <any suitable endpoint>,
    "useDiscovery": true
}

If objects in a search result have the appEmail:bcc property and the first webhook removes this property from the objects, the predicate of the second webhook still matches.

The same behavior holds for the webhook type dms.response.objects and one of its sub-webhook types dms.response.objects.*:

{
    "enable": true,
    "predicate": "spel:true",
    "type": "dms.response.objects",
    "url": <suitable endpoint removing the property 'appEmail:bcc'>,
    "useDiscovery": true
},
{
    "enable": true,
    "predicate": "spel:properties['appEmail:bcc']!=null",
    "type": "dms.response.objects.search",
    "url": <any suitable endpoint>,
    "useDiscovery": true
}
Loggers for Webhooks

As of version 2022 Spring, the input and output data for each webhook can be monitored via loggers.

The logging level can be specified

  • for all webhooks, e.g., os.dev.webhooks=DEBUG, or

  • for individual webhook types, e.g., os.dev.webhooks.dms.request.search=DEBUG.

The logging configuration for each webhook has to be read by the service that calls the webhook. For the individual webhook types, different services are responsible. Thus, please ensure that your webhook logging configuration is defined in a configuration file that is read by its calling service. In order to apply the configuration changes, each calling service has to be refreshed or restarted.

Depending on the logging level, the following details are logged:

Logging Level Logged Information

DEBUG

Only enabled webhooks are considered. The following data are logged:

  • boolean result of the predicate evaluation

  • predicate evaluation target

  • if the predicate is true: input and output data of the webhook including the headers

TRACE

For enabled webhooks, the same information is logged as is the case for the DEBUG logging level.

Disabled webhooks are listed together with the information: Webhook not enabled.

2.9.4. AMQP Hooks

System Hooks, that allow for messaging triggered by function calls under specified conditions.

With an AMQP Hook, messages are sent to a configured messaging system using Advanced Message Queuing Protocol 1.0 (AMPQ). Where and when these messages are sent is defined in the System Hook configuration. Any changes to the System Hook configuration will not apply until the affected services have been restarted.

The AMQP Hooks allow for asynchronous reactions to events like object creation, update or deletion. There are different types of AMQP Hooks available, each of them specialized for selected function calls. The messages contain the object metadata which is the target of the function call triggering the AMQP Hook. The action code is included in the message as well as the history code that is added to the audit trail. The AMQP Hook can be triggered by any endpoint that induced the characteristic history codes of the AMQP Hook.

Types of AMQP Hooks

dms.response.delete -Object deletion events can trigger this AMQP Hook with the corresponding object properties in its body.
As of Version

2020 Autumn

Description

Object deletion events can trigger this AMQP Hook with the corresponding object properties in its body.

Example Predicate
  1. reaction to every object deletion:

    spel:true
  2. reaction to every object deletion of type document:

    spel:properties['system:objectTypeId']['value']=='document'
  3. reaction to every failed deletion of objects that were flagged for deletion:

    spel:options['action']==202
Action Codes - History Codes

200 - OBJECT_DELETED
202 - OBJECT_FLAGGED_FOR_DELETE

Example Message
{
    "objects": [
        {
            "properties": {
                "system:objectId": {
                    "value": "333c226c-3a44-5e66-7777-8d999a0000e1"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:objectTypeId": {
                    "value": "document"
                },
                "system:createdBy": {
                    "value": "111c226c-3a44-5e66-7777-8d999a0000e1"
                },
                "system:creationDate": {
                    "value": "2020-09-16T16:57:40.780Z"
                },
                "system:lastModifiedBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:lastModificationDate": {
                    "value": "2020-09-16T16:57:40.780Z"
                },
                "system:versionNumber": {
                    "value": 1
                },
                "system:tenant": {
                    "value": "default"
                },
                "system:traceId": {
                    "value": "e686f806ed44f37d"
                },
                "Name": {
                    "value": "test.eml"
                }
            },
            "contentStreams": [
                {
                    "contentStreamId": "0AB98765-CDEF-4321-ABCD-098EF76AB543",
                    "archivePath": "default/DOCUMENT/32/15/7/",
                    "length": 82683,
                    "mimeType": "message/rfc822",
                    "fileName": "test.eml",
                    "digest": "2713BB70F1B3F8F556D2661286A5D45157EB723A815E1066E50F1808228075F7",
                    "range": "47578-68248,115827-136497,184076-204746,252320-272989",
                    "repositoryId": "repo252"
                }
            ],

           "options": {
             "action": 200,
             "detail": "OBJECT_DELETED"

           }

        }
    ]
}
dms.response.insert -Object creation events can trigger this AMQP Hook with the corresponding object properties in its body.
As of Version

2019 Winter

Description

Object creation events can trigger this AMQP Hook with the corresponding object properties in its body.

Example Predicate
  1. reaction to every object creation:

    spel:true
  2. reaction to every object creation having a content range attribute:

    spel:contentStreams[0]['range'].length() > 0
  3. reaction to every object creation without content:

    spel:options['action']=100
Action Codes - History Codes

101 - OBJECT_CREATED_WITH_CONTENT
100 - OBJECT_CREATED

Example Message
{
    "objects": [
        {
            "properties": {
                "system:objectId": {
                    "value": "333c226c-3a44-5e66-7777-8d999a0000e1"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:objectTypeId": {
                    "value": "document"
                },
                "system:createdBy": {
                    "value": "111c226c-3a44-5e66-7777-8d999a0000e1"
                },
                "system:creationDate": {
                    "value": "2020-09-16T16:57:40.780Z"
                },
                "system:lastModifiedBy": {
                    "value": "111c226c-3a44-5e66-7777-8d999a0000e5"
                },
                "system:lastModificationDate": {
                    "value": "2020-09-16T16:57:40.780Z"
                },
                "system:versionNumber": {
                    "value": 1
                },
                "system:tenant": {
                    "value": "default"
                },
                "system:traceId": {
                    "value": "1234567887654321"
                },
                "Name": {
                    "value": "test.eml"
                }
            },
            "contentStreams": [
                {
                    "contentStreamId": "0AB98765-CDEF-4321-ABCD-098EF76AB543",
                    "archivePath": "default/DOCUMENT/32/15/7/",
                    "length": 82683,
                    "mimeType": "message/rfc822",
                    "fileName": "test.eml",
                    "digest": "12345678123456781234567812345678123456781234567812345678",
                    "range": "1234-12345,123456-123458,123489-234567,245678-345678",
                    "repositoryId": "repo252"
                }
            ],

           "options": {
             "action": 101,
             "detail": "OBJECT_CREATED_WITH_CONTENT"

           }

        }
    ]
}
dms.response.update - Object update events and tag operations can trigger this AMQP Hook with the corresponding object properties in its body.
As of Version

2020 Autumn

Description

Object update events and tag operations can trigger this AMQP Hook with the corresponding object properties in its body.

Example Predicate
  1. reaction to every object update:

    spel:true
  2. reaction to every tag creation:

    spel:options['action']==110
  3. reaction to every tag deletion:

    spel:options['action']==210
  4. reaction to every metadata update:

    spel:options['action']==300
  5. reaction to every content update:

    spel:options['action']==301
Action Codes - History Codes

300 - OBJECT_METADATA_CHANGED
301 - OBJECT_DOCUMENT_CHANGED
303 - OBJECT_UPDATE_CONTENT_MOVED
110 - OBJECT_TAG_CREATED
310 - OBJECT_TAG_UPDATED
210 - OBJECT_TAG_DELETED

Example Message

To the object a tag ocr is added.

In the options section, the previousVersion attribute contains the previous document before the update.

{
    "objects": [
        {
            "properties": {
                "system:objectId": {
                    "value": "333c226c-3a44-5e66-7777-8d999a0000e1"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:objectTypeId": {
                    "value": "document"
                },
                "system:createdBy": {
                    "value": "111c226c-3a44-5e66-7777-8d999a0000e1"
                },
                "system:creationDate": {
                    "value": "2020-09-16T16:57:40.780Z"
                },
                "system:lastModifiedBy": {
                    "value": "111c226c-3a44-5e66-7777-8d999a0000e5"
                },
                "system:lastModificationDate": {
                    "value": "2020-09-16T16:57:40.780Z"
                },
                "system:versionNumber": {
                    "value": 1
                },
                "system:tenant": {
                    "value": "default"
                },
                "system:traceId": {
                    "value": "e686f806ed44f37d"
                },
                "Name": {
                    "value": "test.eml"
                },
                "system:tags": {
                    "value": [["ocr", 1, "2020-09-16T16:57:40.780Z", "ce03f1c20308d77d" ]]
                }
            },
            "contentStreams": [
                {
                    "contentStreamId": "1D2AD7BA-F82B-11EA-A5EA-7FE7FFB009F6",
                    "archivePath": "default/DOCUMENT/32/15/7/",
                    "length": 82683,
                    "mimeType": "message/rfc822",
                    "fileName": "test.eml",
                    "digest": "12345678123456781234567812345678123456781234567812345678",
                    "range": "1234-12345,123456-123458,123489-234567,245678-345678",
                    "repositoryId": "repo252"
                }
            ],
           "options": {
              "action": 110,
              "detail": "OBJECT_TAG_CREATED",
              "previousVersion" :
                  {
                      "properties": {
                          "system:objectId": {
                              "value": "2b7a3b0a-3038-433e-96bd-493d7702b510"
                          },
                          "system:baseTypeId": {
                              "value": "system:document"
                          },
                          "system:objectTypeId": {
                              "value": "document"
                          },
                          "system:createdBy": {
                              "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                          },
                          "system:creationDate": {
                              "value": "2020-09-16T16:57:40.780Z"
                          },
                          "system:lastModifiedBy": {
                              "value": "111c226c-3a44-5e66-7777-8d999a0000e5"
                          },
                          "system:lastModificationDate": {
                              "value": "2020-09-16T16:57:40.780Z"
                          },
                          "system:versionNumber": {
                              "value": 1
                          },
                          "system:tenant": {
                              "value": "default"
                          },
                          "system:traceId": {
                              "value": "1234567887654321"
                          },
                          "Name": {
                              "value": "test.eml"
                          }
                      },
                      "contentStreams": [{
                          "contentStreamId": "0AB98765-CDEF-4321-ABCD-098EF76AB543",
                          "archivePath": "default/DOCUMENT/D2/AD/7/",
                          "length": 82683,
                          "mimeType": "message/rfc822",
                          "fileName": "test.eml",
                          "digest": "12345678123456781234567812345678123456781234567812345678",
                          "range": "1234-12345,123456-123458,123489-234567,245678-345678",
                          "repositoryId": "repo252"
                      }]
                  }
              }
            }
]}
Configuring AMQP Hooks

As a type of system hooks, AMQP Hooks are configured in the \service-manager\config\system\systemHookConfiguration.json configuration file within the service manager in JSON format. Any changes to the system hook configuration will not apply until the affected services have been restarted.

2.9.5. Interceptors

Intervening a running process at a certain position and redirecting the process flow in order to include project-specific processing steps.

The interceptors allow for project-specific extensions of the yuuvis® Momentum standard process flows. The running process flow can be redirected by a condition set on the processed object that has to be specified in the interceptor definition. Whenever the process flow meets the condition, the project-specific process extension is included for the currently processed object at this position of the process flow. Thus, the alternative process can entirely replace the standard one from this position on or resume the standard process at a specified position.

Interceptor Configuration

The condition for the intervention of the process flow is defined in the interceptor configuration file interceptorConfiguration.json.

The following parameters are available for the interceptor configuration:

Parameter Type Required Description

type

String

yes

The type of the interceptor. It defines the position in the process flow where the interceptor can step in.

predicate

String

yes

The condition that triggers the redirection of the process flow in order to include the project-specific process extension. The string can provide the condition either in Spring Expression Language (SpEL) or Javascript. Thus, the string always has to start with a prefix spel: for SpEL or js: for Javascript.

url

String

yes

HTTP address of an external endpoint defining the project-specific process extension. Dynamic components (properties of the processed object) can be included in curly brackets.

useDiscovery

Boolean

no

Decides whether to resolve the url string at the Discovery-Service or not. If not specified, a default value is set.

Interceptor Types

There are different types of interceptors available that interrupt the process flow at different positions. Their take-off points are at the API gateway or the repository service. To activate a new interceptor configuration, the corresponding service has to be restarted.

Interceptor type Evaluation target of the predicate Interceptor input data Description Restart Service

getContent

API DMS object in JSON format derived from given objectId

objectId

Manipulation of the binary content of the return statement by a project-specific service.

api

search

Structure of the specific class SearchInterceptorObject

Search query object

Manipulation of the search query parameter and the search result.

api

updateDmsObject

First API DMS object in the list in JSON format that is passed to the corresponding update endpoint

Updated metadata and metadata of current version

Manipulation of the update properties that will be applied to a DMS object.

api

dms.request.objects.upsert.database-before

All objects of the objects list in the data part of the multipart body after enrichment.

a multipart request body

The take-off point of the interceptor is after the repository service. The initial request body is already normalized, validated and enriched with content stream properties.

repository

dms.request.objects.upsert.database-before - Details and Examples
As of Version

2020 Winter

HTTP Method

POST

Response Format

JSON

Predicate

The predicate is applied on all objects of the objects list in the data part of the multipart body after enrichment. If at least one object matches, the interceptor is called.

Description

It can be triggered by

  • an object import,

  • an update of the content or

  • an update of the metadata.

The take-off point of the interceptor is after the repository service. The initial request body is already normalized, validated and enriched with content stream properties as can be seen in the examples provided below.

The enriched multipart request body is taken by the interceptor. It always contains a data part, that contains an objects list with the metadata of the affected objects. For each object, the options section contains the action parameter that specifies the type of the call in an action code.

The predicate is applied to every single object in the list. The interceptor is triggered for the entire object list as soon as one object meets the predicate.

Within the interceptor, any user-defined operation can be executed on the corresponding metadata by calling the external endpoint specified as url in the interceptor configuration. Afterwards, the modified multipart has to be routed back to continue the regular process at a suitable point.

If the interceptor should continue the regular process exactly at the take-off point, pass the multipart to http://registry/api/dms/objects.

Requirements for external endpoint

The target URL must be a POST endpoint accepting a multipart request body and returning a list of objects as JSON.

Affected API Requests
  • POST /api/dms/objects

  • POST /api/dms/objects/{objectId}

  • PATCH /api/dms/objects/{objectId}

  • POST /api/dms/objects/{objectId}/contents/file

Restart Service

Repository service

Header

Authorization-Header

Examples
  1. Importing Content

    If an object with content is imported, the enriched multipart taken by the interceptor contains content stream properties in its data part. Depending on the document there can also be a text rendition. An import can be identified by the action with the code 100 or 101 in the options metadata section.

    Data part of the original request
    {
      "objects" : [ {
        "properties" : {
          "system:objectTypeid" : {
            "value" : "miscellaneous"
          },
          "name" : {
            "value" : "my document"
          },
          "description" : {
            "value" : "this is a test document"
          }
        },
        "contentStreams" : [ {
          "mimeType" : "message/rfc822",
          "fileName" : "content.eml",
          "cid" : "content"
        } ]
      } ]
    }
    Data part of the enriched multipart taken by the interceptor
    {
      "objects" : [ {
        "properties" : {
          "system:objectTypeid" : {
            "value" : "miscellaneous"
          },
          "name" : {
            "value" : "my document"
          },
          "description" : {
            "value" : "this is a test document"
          }
        },
        "contentStreams" : [ {
          "contentStreamId" : "85E76328-6651-11EB-88B6-71C8C8177575",
          "archivePath" : "default/DOCUMENT/5E/76/3/",
          "length" : 42938,
          "mimeType" : "message/rfc822",
          "fileName" : "content.eml",
          "digest" : "328B2AF519C144050A43EBBFFE21CC722C4E5A6DB40CD1DDCD5A7A54AFA6EE72",
          "repositoryId" : "repo242"
        } ],
        "renditions" : [ {
          "mimeType" : "text/plain",
          "kind" : "text",
          "contentStream" : {
            "length" : 40963,
            "mimeType" : "text/plain",
            "fileName" : "content.txt",
            "cid" : "rendition_195"
          }
        } ],
        "options" : {
          "traceid" : "a78d178f712cbd75",
          "analyzeMimeType" : true,
          "analyzeContent" : true,
          "action" : 101
        }
      } ]
    }
  2. Updating Content

    A content update can be identified by the action with the code 301 in the options metadata section. Like in the import scenario, content stream properties are available in the enriched multipart, and depending on the document a text rendition can also be available.

    Data part of the original request
    The initial request does not contain a multipart body and thus no data part can be shown here.
    Data part of the enriched multipart taken by the interceptor
    {
      "objects" : [ {
        "properties" : {
          "system:objectId" : {
            "value" : "50971948-019a-493f-bdf5-571e91e61236"
          },
          "system:objectTypeId" : {
            "value" : "appTest:miscellaneous"
          }
        },
        "contentStreams" : [ {
          "contentStreamId" : "9C9EDCC3-6716-11EB-B18C-A9EA85931B27",
          "archivePath" : "default/DOCUMENT/C9/ED/C/",
          "length" : 14157,
          "mimeType" : "image/jpeg",
          "fileName" : "test2.txt",
          "digest" : "998FAFD7B3045767B64463C46AB267A7DCC442E28F0FAF5D68C6A32E7DA8987F",
          "repositoryId" : "repo242"
        } ],
        "options" : {
          "currentVersion" : {
            "properties" : {
              "system:traceId" : {
                "value" : "8e57d683bdc36de5"
              },
              "system:objectTypeId" : {
                "value" : "appTest:miscellaneous"
              },
              "system:versionNumber" : {
                "value" : 3
              },
              "system:createdBy" : {
                "value" : "275c826c-6a61-4e89-9512-8d935a1631e5"
              },
              "system:creationDate" : {
                "value" : "2021-02-03T21:17:36.400Z"
              },
              "appTest:name" : {
                "value" : "my document"
              },
              "system:lastModificationDate" : {
                "value" : "2021-02-04T13:01:37.120Z"
              },
              "system:baseTypeId" : {
                "value" : "system:document"
              },
              "system:tenant" : {
                "value" : "default"
              },
              "appTest:description" : {
                "value" : "this is a new description"
              },
              "system:lastModifiedBy" : {
                "value" : "275c826c-6a61-4e89-9512-8d935a1631e5"
              },
              "system:objectId" : {
                "value" : "50971948-019a-493f-bdf5-571e91e61236"
              }
            }
          },
          "traceid" : "9a00c294eaf1e2af",
          "action" : 301
        }
      } ]
    }
  3. Updating Metadata

    A metadata update can be identified by the action with the code 300 in the options metadata section of the enriched request body. Moreover, the objectId is added to the properties of the original request.

    Data part of the original request
    {
      "objects" : [ {
        "properties" : {
          "description" : {
            "value" : "this is a new description"
          }
        }
      } ]
    }
    Data part in the enriched multipart taken by the interceptor
    {
      "objects" : [ {
        "properties" : {
          "description" : {
            "value" : "this is a new description"
          },
          "system:objectId" : {
            "value" : "50971948-019a-493f-bdf5-571e91e61236"
          }
        },
        "options" : {
          "action" : 300,
          "preserve_missing_properties" : true,
          "currentVersion" : {
            "properties" : {
              "system:traceId" : {
                "value" : "df4735bd88e94678"
              },
              "system:objectTypeId" : {
                "value" : "appTest:miscellaneous"
              },
              "system:versionNumber" : {
                "value" : 1
              },
              "system:createdBy" : {
                "value" : "275c826c-6a61-4e89-9512-8d935a1631e5"
              },
              "system:creationDate" : {
                "value" : "2021-02-03T21:17:36.400Z"
              },
              "appTest:name" : {
                "value" : "my document"
              },
              "system:lastModificationDate" : {
                "value" : "2021-02-03T21:17:36.400Z"
              },
              "system:baseTypeId" : {
                "value" : "system:document"
              },
              "system:tenant" : {
                "value" : "default"
              },
              "appTest:description" : {
                "value" : "this is a test document"
              },
              "system:lastModifiedBy" : {
                "value" : "275c826c-6a61-4e89-9512-8d935a1631e5"
              },
              "system:objectId" : {
                "value" : "50971948-019a-493f-bdf5-571e91e61236"
              }
            }
          }
        }
      } ]
    }
Interceptor Configuration Example

The following example configures an interceptor that will be trigger by every update of a content (action code 301). At the take-off point after the repository service, the enriched request body is passed to the external endpoint specified by url.

To activate this configuration, the repository service needs to be restarted.

Example interceptorConfiguration.json
1
2
3
4
5
6
7
8
9
10
{
    "interceptors": [
        {
            "type": "dms.request.objects.upsert.database-before",
            "predicate": "spel:options['action']==301",
            "url": "http://exampleinterceptorcontentupdate/api/dms/objects/upsert",
            "useDiscovery": true
        }
    ]
}

2.10. Configuration

2.10.1. Git and 'configservice'

Most of the yuuvis® Momentum core services are configured via profiles and corresponding configuration files. Following the basic concepts of Spring Boot, the configuration files are stored on a git server and are managed via the configservice.

The configservice cannot start without an active connection to the git server.

At runtime, the configservice applies all changes to configuration files to its local resources first. At regular intervals of 5 minutes, the remote resources on the git server are synchronized according to the following procedure:

  • All changes in the local resources applied during the last five minutes are summarized in one single commit.

  • A git pull request with THEIRS merge policy is used to introduce changes made directly in the remote resources into the local resources.

    It is thus possible to overwrite changes that are applied to the local resources (e.g., via yuuvis® Momentum endpoints) by applying changes directly to the remote repository. However, those changes are NOT visible before the regular synchronization.
  • The commit and the merge result are published via a single push request.

This procedure of collecting and summarizing changes reduces the number of commits that have to be managed by the configservice in case of a high frequency of change requests.

Additionally, as of 2022 Summer, it is possible to synchronize the local resources of the configservice and the remote resources on the git server via the endpoint POST <host>:<port_of_configservice>/manage/refresh at any time. This synchronization is additional and independent of the automated synchronization every 5 minutes.

In case multiple instances of the configservice are running, the synchronization of the individual local resources is done at the regular intervals of 5 minutes as well. Thus, requests for resources that have been modified less than 5 minutes ago might lead to the retrieval of a deprecated version of those resources. Resources created less than 5 minutes ago might be not available.

In the Kubernetes environment, each instance of the configservice additionally stores the resources in a separate persistent volume at /tmp/configservice. In the default configuration, changes in those resources are used for the service initialization. I.e., changes that are not yet included in the commit are calculated via git diff and considered during the synchronization procedure described above.

2.10.2. Configuration via Profiles

Each core service retrieves YAML configuration files from a central location managed by the CONFIG service. These YAML configuration files extend the base application.yml configuration file inherent to any Spring boot microservice. Each of the additional configuration files corresponds to a profile, denoted by the suffix of the file, which the service of interest will need to be configured to run in.

The architecture of services and profiles follows the basic concepts of Spring Boot. For more detailed information, please refer to the Spring Boot profiles documentation.

So how is this helpful? There are two main benefits:

  • They act as globally reusable configuration elements.

    Configuration profiles allow for specific bits of configuration to be used by multiple services across the system. Any service can load the information from existing configuration files using its SPRING_PROFILES_ACTIVE environment variable. For example, a configuration file containing Elasticsearch connection parameters are loaded by both the search and index services.

  • Profiles also allow for the customization of specific service instances.

    For example, several instances of the repository service could be used to separate data into different data sources with a configuration profile containing access parameters for each of the available data sources.

Names of YAML Configuration Files

The name of the YAML configuration file defines whether it will be available to all services or to only one specific service: there are two types of profiles that are distinguished by their naming scheme:

  • Profiles containing information relevant to multiple services must adhere to the application-<profile type>.yml naming scheme in order to be referable to by any service in the system.

  • Profiles specific to a single service have to be called <service-identifier>-<profile type>.yml.

The individual services do not reference a specific profile file name but only the profile type. It is important to consider the strict hierarchy implemented in Spring Boot profile-based configurations. A configuration specific to a single service (i.e., system-prod.yml) always takes precedence over any global configuration (i.e., application-prod.yml), which means that overriding a global configuration is entirely possible.

Profiles in Kubernetes
Configuration during Installation

You can set the configuration parameter values in advance during installation.

The configuration parameters are set in the values.yaml file of the yuuvis Helm chart. Modify a value of the listed parameters or add one of the available parameters listed in the above linked fact sheet of the corresponding profile with your desired value to overwrite its default value.

During the deployment, the settings defined in the values.yaml file will be written into the profile files that are read by the services when they are started.

Changing the Configuration of a Running System

For changes on a running system, you need to access your Git server.

Navigate to the root directory of the configuration git repositories' appropriate branch and find a list of the configuration files including the above listed profiles. Open the profile, modify it, and check in your changes.

After the modification of a profile, you need to restart the services that reference the profile in order to apply the changes.

Adding Custom Profiles

New profiles can be added by committing their configuration YAML files to the root directory of the configuration git repositories' appropriate branch.

To activate any custom profile-based configuration, the services that are meant to use them need to set them as their active Spring Profiles.

In Kubernetes, this can be accomplished by modifying the deployment file of the service. Using kubectl edit -n <namespace> deployment <service identifier>, the active profiles of a given service can be changed. The active profiles are listed under the SPRING_PROFILES_ACTIVE environment variable. Any changes will incur a restart of the services.

Outsourcing Passwords from Profiles as Kubernetes Secrets

Passwords can be outsourced from profile files as Kubernetes Secrets. In the configuration file, placeholders are included instead that are replaced by the actual passwords during the pod’s runtime. Please note that passwords as Kubernetes Secrets can be displayed in plain text format in the environment variables of the pods and contained services. The following guideline explains the configuration procedure for the password corresponding to the database connection. The same procedure can also be applied to any other password contained in a profile file.

  • Convert the password in the application-dbs.yml file to Base64 format.

    Example command for Windows Powershell: [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("changeme"))

    Example command for Linux: echo -n "changeme" | base64 -w0

    Both example commands lead to the output Y2hhbmdlbWU=.

  • Create a yuuvis-secrets.yml file with the following content:

    apiVersion: v1
    kind: Secret
    metadata:
      name: yuuvis-secrets
      namespace: yuuvis
    type: Opaque
    data:
      POSTGRES_PASSWORD: Y2hhbmdlbWU=

    The section data contains a list of key-value pairs that can contain multiple entries. As spacers within the string key name, only underscores are allowed. The value is the password in Base64 format.

  • Create a Kubernetes Secret by running the command kubectl apply -f yuuvis-secrets.yml.

  • Replace the password in the application-dbs.yml file by a placeholder:

    yuuvis.db.password: ${POSTGRES_PASSWORD}
  • Adjust the deployments of all yuuvis® services using the profile dbs by extending the section env:

    env:
    - name: POSTGRE_PASSWORD
      valueFrom:
        secretKeyRef:
          name: yuuvis-secrets
          key: POSTGRE_PASSWORD

    The name and the key given in secretKeyRef have to correspond to the name and the data value defined in the file yuuvis-secrets.yml.

Available Profiles

The following profiles are available and referenced by the listed services in the default installation.

Profile Related Configuration File(s) Referenced by Description

Feature Profiles: The following profiles can be activated for the corresponding services in order to activate/deactivate a specific processing behavior. In the default installation, no specific YAML configuration files are available.

jpapostgres

-

  • audit Service

  • registry Service

Decides whether PostgreSQL wire protocol or MS SQL should be used for the database connection of the audit and/or registry service.

If jpapostgres is used, the corresponding service uses the PostgreSQL driver that can connect either a PostgreSQL database or a database which implements the PostgreSQL wire protocol, e.g., CockroachDB.

noamqp

-

  • api Gateway

  • commander Service

Decides whether a messaging provider should be used by the api gateway and the commander service or not.

If noamqp is NOT acitvated,

  • the api gateway connects to the messaging provider during the start up. Thus, a messaging provider is required to operate the API Gateway.

  • the commander service uses the messaging provider during reindexing processes.

If noamqp is activated,

  • the api gateway does not connect to the messaging provider. Configuration parameters from the profile mq are ignored.

  • the reindexing of the Elasticsearch index via commander service is performed only for the objects' metadata. The full-text is removed from the reindexed objects. Configuration parameters from the profile mq are ignored.

keycloak

-

  • organization Service

Enables user-role mapping in Keycloak.

Configuration Profiles: The following profiles are used to provide the related configuration parameters to all services for which they are activated in the default installation.

prod, dev

service-specific configurations:

  • system-prod.yml

  • authentication-prod.yml

  • registry-prod.yml

all services except configservice

Separation of development and production environments. A service with prod (dev) as active profile is running in the production (development) environment.

Per default, all services are deployed in the production environment. If you want to build a test environment, you need to manually create the corresponding profiles.

The configservice will always try to load parameters from an application-prod.yml file at the start even if no profile prod is used.

kubernetes

application-kubernetes.yml

  • api Gateway

  • audit Service

  • authentication Service

  • contentanalyzer Service

  • index Service

  • organization Service

  • registry Service

  • repository Service

  • search Service

  • system Service

Used in Kubernetes systems. Services will use a Kubernetes-specific internal configuration.

Furthermore, the api gateway and system service query the Kubernetes API Server for other services in the namespace. The list of services is filtered with the condition from the kubernetes profile file.

redis

application-redis.yml

  • api gateway

  • audit service

  • index service

  • registry service

  • repository service

  • search service

  • system service

  • authentication service

Redis connection parameters.

mq

application-mq.yml

  • api gateway

  • commander service

Messaging queue connection parameters.

dbs

application-dbs.yml

  • audit Service

  • registry Service

Database connection parameters.

es

application-es.yml

  • index Service

  • search Service

Elasticsearch connection parameters.

Index configuration used to create Elasticsearch index.

storage

application-storage.yml

  • repository Service

  • archive Service

Binary data storage connection parameters.

oauth2

application-oauth2.yml

  • authentication Service

  • organization Service

Contains authentication-related parameters.

metrics

application-metrics.yml

  • api Gateway

  • audit Service

  • authentication Service

  • contentanalyzer Service

  • index Service

  • organization Service

  • registry Service

  • repository Service

  • search Service

  • system Service

Profile under development. In the future, metrics should provide a possibility to monitor responses from the service instance.

2.10.3. Available YAML Files

The YAML configuration files are read by a service if the corresponding profiles are activated.

Following files are available:

application-dbs.yml
Parameter Description Default Value

spring.datasource.hikari.maximumPoolSize

Integer number of connections to the database per service (audit, registry, rendition-repository). The value can be overwritten for each service by configuring the paramenter spring.datasource.hikari.custom.maximum-pool-size, e.g., in its <serviceName>-prod.yml configuration file.

For the commander service, the service-specific configuration parameter is predefined to 2 database connections as default. Thus, its database connections are not affected by the value of spring.datasource.hikari.maximumPoolSize in the application-dbs.yml configuration parameter. >> commander-prod.yml

10

storage

Section of individual database configurations.

databases

List of database definitions with the following required parameters:

  • datasource – Reference on a configuration in storage.datasources.

  • predicate – SPEL statement specifying the condition under which the database should be used. The condition can only reference the system:tenant property of DMS objects.

  • default – Boolean value that specifies whether the database should be used as default database (true) or not (false).

    Note: Exactly one database has to be the default database. For each database action requested for a DMS object, the list of databases is read from the top. The first database for which the predicate is evaluated to true is used. If no predicate is true, the default database is used.

If you apply changes to the configuration of a running system, ensure that existing tenants are directed to their previous database.
defaultdb:
  datasource: defaultds
  predicate: 'spel:false'
  default: true

datasources

List of database configurations with the following required parameters:

  • url

    If using MS SQL 2019…​

    See the note below.

  • user

  • password

  • driver-class-name

defaultds:
  url: jdbc:postgresql://postgresql.infrastructure:5432/${DBNAME}
  username: yuuvis_${NAMESPACE}
  password: ${DBPWD}
  driver-class-name: org.postgresql.Driver
If using MS SQL 2019…​

SSL is required. To connect without SSL, append encrypt=false or trustServerCertificate=true to the url. Examples:

  • storage.datasources.examplemssql.url: 'jdbc:sqlserver://abc/def;encrypt=false'

  • storage.datasources.examplemssql.url: 'jdbc:sqlserver://abc:1433;database=xyz;trustServerCertificate=true;’

Example application-dbs.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
storage:
  databases:
    defaultdb:
      datasource: defaultds
      predicate: 'spel:false'
      default: true
    database2:
      datasource: db2source
      predicate: "spel:properties['system:tenant']['value']=='tenant2'"
      default: false
  datasources:
    defaultds:
      url: 'jdbc:postgresql://abc/def'
      username: yuuvis-postgresql
      password: changeme123
      driver-class-name: 'org.postgresql.Driver'
    db2source:
      url: 'jdbc:sqlserver://ghi/jkl'
      username: yuuvis-sqlserver
      password: changeme456
      driver-class-name: 'com.microsoft.sqlserver.jdbc.SQLServerDriver'
application-es.yml

As of 2023 Autumn:

Parameter Description Default value

storage.searchdatabases

Configurations of Elasticsearch instances. The ID of each instance is defined via the key (e.g., database1). For each search action requested for a DMS object, the list of search databases is read from the top. The first search database for which the predicate is evaluated to true is used. If no predicate is true, the default database is used.

If you apply changes to the configuration of a running system, ensure that existing tenants are directed to their previous search database.

For each Elasticsearch instance, the following parameters have to be specified.

datasource

Reference on a configuration in storage.searchdatabases.

predicate

SPEL statement specifying the condition under which the search database should be used. As of version 2023 Autumn, the condition can only reference the system:tenant property of DMS objects.

default

Boolean value that specifies whether the search database should be used as default search database (true) or not (false).

Exactly one search database has to be the default search database.

storage.searchdatasources

List of search database (Elasticsearch index) configurations with the following parameters:

urls

Required. Comma-separated list of one or more URLs to the corresponding Elasticsearch instance(s).

-

user

Optional. Username to access the Elasticsearch instance(s).

-

password

Optional. Password to access the Elasticsearch instance(s).

-

index

Optional. Name of the Elasticsearch index. If no index with the specified name is available, a new index is created.

'putitinthere'

languages

Optional. Read only during the creation of a new Elasticsearch index: Languages to be configured in the Elasticsearch analyzer configuration specified via ISO codes.

'de;en'

timeout

Optional.

30000

Example application-es.yml
storage:
    searchdatabases:
      database1:
        datasource: dbsource1
        predicate: 'spel:false'
        default: true
      database2:
        datasource: dbsource2
        predicate: "spel:properties['system:tenant']['value']=='yuuvistest'"
        default: false

    searchdatasources:
      dbsource1:
        urls: '<host1>:<portA>','<host2>:<portB>'
      dbsource2:
        urls: '<host3>:<portC>'
        user: 'exampleuser'
        password: 'examplepassword'
        index: 'exampleindex'
        languages: 'de;en'
        timeout: 30000

Up to product version 2023 Summer, the following parameters are available:

Parameter Description Read by Service Default Value

index

Section of configuration parameters for the Elasticsearch index to be used by yuuvis® Momentum.

indexname

Name of the Elasticsearch index. If no index with the specified name is available, a new index is created.

index, search

putitinthere

languages

Read only during the creation of a new Elasticsearch index: Languages to be configured in the Elasticsearch analyzer configuration specified via ISO codes.

index

'de;en'

application-oauth2.yml
This article describes the behavior of the core system. However, the configuration file is read by the TENANT-MANAGEMENT Service as well if installed.
Parameter Description Read by Service Default Value

keycloak.host

The parameter is used as a variable for the IP address of the used Keycloak server that can be referenced in authentication.oauth2.tenants. If the value is changed, the new value will replace the old one in each reference.

The value is set automatically during the installation of the infrastructure Helm chart during which the IP address of your Keycloak server has to be specified.

If a different identity provider is used, you can remove this parameter and define an own one in order to reference it in authentication.oauth2.tenants.

-

-

authentication.oauth2.tenants

List of tenant configurations read by the authentication service. Each list entry contains the configuration parameters for one tenant. They have to fit the settings in the used identity provider.

If Keycloak is used, check the settings via the Keycloak Admin Console. Further notes:

  • We recommend to reference the server IP address via the variable keycloak.host.

  • The authentication service has to be registered as Keycloak Client in each Keycloak Realm which corresponds to a tenant in yuuvis® Momentum.

authentication

See code block below.

name

Required. Name of the tenant. If it is changed, please do not forget to adjust it in the *Uri parameters below.

authentication

clientId

Required. Identification of the authentication service for the connection to the identity provider. Valid for all tenants. Get the value from the identity provider.

authentication

clientSecret

Tenant-specific identification of the authentication service for the connection to the identity provider. Only valid for one tenant. Get the value from the identity provider.

authentication

userAuthorizationUri

authentication

accessTokenUri

authentication

userInfoUri

Required. URL of the identity provider’s endpoint for retrieving user data.

authentication

endSessionUri

If this parameter is set, a logout from a yuuvis® Momentum session will trigger a logout from the identity provider as well. Set as value the endpoint of the identity provider that is responsible for the logout process.

As of 2023 Summer: If Keycloak is used as identity provider, the post_logout_redirect_uri query parameter can be appended in order to specify a valid redirect URI to be called after a successful logout.

If post_logout_redirect_uri is specified, the scope parameter has to be configured with value openid.
scope post_logout_redirect_uri Effect

not configured

not configured

If a logout is requested, an inquiry dialog is displayed where the logout request has to be confirmed.

After a successful logout, a success notification is displayed.

set to openid

not configured

After a successful logout, a success notification is displayed.

not configured

properly configured

A logout is not possible. An error with Missing parameters: id_token_hint message is returned.

set to openid

properly configured

The specified redirect URI is called after a successful logout.

example configuration
authentication.oauth2.tenants:
-   name: tenant
    clientId: momentum
    clientSecret: 00000000-0000-0000-0000-000000000000
    userAuthorizationUri: https://${keycloak.host}/auth/realms/tenant/protocol/openid-connect/auth
    accessTokenUri: https://${keycloak.host}/auth/realms/tenant/protocol/openid-connect/token
    userInfoUri: https://${keycloak.host}/auth/realms/tenant/protocol/openid-connect/userinfo
    endSessionUri: https://${keycloak.host}/auth/realms/tenant/protocol/openid-connect/logout?post_logout_redirect_uri=https://my.momentum.org/
    userNameExtractionPattern: $.sub
    scope: openid

authentication

userNameExtractionPattern

Required. JSON path expression to extract the user name from the response of the endpoint specified in userInfoUri.

authentication

scope

Comma-separated list of strings. Available values and their effects depend on the used identity provider.

For Keycloak:

  • Available as of 2023 Summer.

  • The only available value is openid (see Keycloak documentation).

  • If scope is set to openid, Keycloak is triggered to create an ID token that allows for a logout without an inquiry dialog.

  • In combination with properly configured endSessionUri parameter, it allows a redirection after a successful logout (see above).

keycloak.server

Parameter read by the organization service if profile keycloak is active: URL of the Keycloak server.

organization

https://keycloak-https.infrastructure/auth

keycloak.admin.username

Parameter read by the organization service if profile keycloak is active: Username for the login of the organization service in order to retrieve and store data in Keycloak.

organization

keycloak

keycloak.admin.password

Parameter read by the organization service if profile keycloak is active: Password for the login of the organization service in order to retrieve and store data in Keycloak.

organization

changeme

Default configuration for authentication.oauth2.tenants
authentication.oauth2.tenants:
- name: myfirsttenant
  clientId: yuuvis-authentication-service
  clientSecret: <my-secret>
  userAuthorizationUri: https://${keycloak.host}/auth/realms/myfirsttenant/protocol/openid-connect/auth
  accessTokenUri: https://${keycloak.host}/auth/realms/myfirsttenant/protocol/openid-connect/token
  userInfoUri: https://${keycloak.host}/auth/realms/myfirsttenant/protocol/openid-connect/userinfo
  endSessionUri: https://${keycloak.host}/auth/realms/myfirsttenant/protocol/openid-connect/logout
  userNameExtractionPattern: $.sub
  scope: openid
application-storage.yml

Configuration file containing parameters and archive profiles used by the archive and repository service in order to connect external archives.

File Structure
storage:
  repositories:
    <repositoryId>:
      profiles: ['<archiveProfile>']
      <parameter>: <value>
  profiles:
    <archiveDriverName>:
      <archiveProfile>:
        <parameter>: <value>

Define your repositories via repositoryId. For each of them, specify an archive profile and thus define the type of archive driver for the corresponding repository.

As of 2024 Summer, most archive drivers are directly provided by the repository service. However, the hcp-s3 driver is provided only by the archive service yet. Therefore, the parameters url and useDiscovery are required for it as described below.

For each type of archive driver identified by archiveDriverName, define one or more archive profiles. The name of each archive profile must be unique within the configuration file. Depending on the archive type, specific configuration parameters have to be set as described below too.

Parameters
Parameter Description Example

storage.default-rendition-repository

As of 2021 Winter. Specify the ID of a default rendition repository. It will be used for the storage of renditions if no repository is specified in the corresponding request header. As of version 2021 Winter, only an S3 storage can be supported. It has to be defined in the storage.repositories section.

It is recommended to configure a separate repository for the storage of renditions. The demands regarding storage of renditions differs from the storage of binary content files. E.g., retention is not supported.

renrepo

storage.repositories

Configurations of repositories for by the repository service. The repositoryId of each repository is defined via the key (e.g., s3 or netapp). For each repository, the following parameters have to be specified.

s3:
  profiles: ['s3profile1']
  default: true
netapp:
  profiles: ['netapplike']
  encryption:
    enabled: true
    password: "changeme"

profiles

A list of archive profile names, each of them referencing an archive profile defined in the storage.profiles section. The type of archive must be the same in the archive profile definition and in the repository configuration.

For any repository that will be used as rendition repository, an S3 profile has to be specified.

Only the first list entry will be considered whereas further list entries will be ignored.

url

As of 2024 Summer only required for hcp-s3 driver.

Address of the repository accessible via the archive service. The archive profile can be referenced as dynamic component in curly brackets (e.g., http://archive/api/profiles/{profile}/dms/objects).

useDiscovery

As of 2024 Spring only required hcp-s3 driver.

Boolean value specifying if the given url contains a reference and should be interpreted via the discovery (true) or if an absolute address is specified (false).

predicate

Available as of 2023 Autumn. Specifies a condition using any properties of the target DMS objects before normalization. If the condition is matched by an imported DMS object, its binary content is stored in the corresponding repository instead of the default repository.

If a repositoryId is explicitly specified during a content-related request, this value dominates and there is no predicate evaluation.

Default value: 'spel:false'

default

Optional: Boolean value specifying if the repository should be the default repository (true) or not (false). Only one repository can be default repository.

The default repository will be used for each content-related request where no repositoryId is explicitly specified AND none of the other repositories' predicates is matched.

The default repository is NOT used as default rendition repository if storage.default-rendition-repository is missing.

encryption

As of 2024 Summer.

Optional: Enable or disable (default) the encryption of binary content files before storing them. If enabled, storage administrators cannot open and read the files.

To enable the encryption, set the sub-parameters enabled: true and password (can be specified via environment variable as well). If encryption is enabled but no password is set, each request to the repository will fail.

The digest value is still calculated based on the original content file before the encryption.

As the encryption reduces the performance of your system, use it only if necessary. Especially range requests for sections of very large content files might be slow. The entire content has to be decrypted before the requested range can be retrieved.

storage.profiles

Archive profiles for each archive driver. Multiple profiles can be defined for each archive driver. The name of each profile is defined via the corresponding key (e.g., s3profile1 or netapplike). Each archive profile name has to be unique within the configuration file and can belong to only one archive driver type.

The parameters for the configuration of an archive profile depend on the archive driver indicated by the corresponding archiveDriverName (e.g., s3 or netapp). For the supported archive drivers, the configuration parameters are listed below.

An S3 archive profile configuration is required for the usage of a rendition repository.
s3:
  s3profile1:
    access-key: 'MGMWCOYTDUSLNCFE'
    secret-key: 'changeme'
    url: 'http://minio.infrastructure:9000'
    bucket: 'dmscloudrepodocker'
netapp:
  netapplike:
    # use mountpoint of the persistent volume claim that provides the netapp storage
    # must be the same in the deployment of the archive app
    volume: '/var/lib/netapp/data'
    defaultRetentionInDays: 10
Parameters in Archive Profiles

Depending on the archive driver, the archive profiles have to be configured with specific parameters.

Drivers for the following Archives are available:

  • Google Cloud Storage

    General Parameters
    Parameter Description

    defaultRetentionInDays

    The defaultRetentionInDays parameter can be set in all following archive profiles. This value is used as retention time for objects that do not have a retention time specified within their metadata during their import. If defaultRetentionInDays is set to 0 which is also the default value, no retention will be set for those objects. If the profile is used for a rendition repository, the parameter is ignored as renditions cannot be under retention.

    pathTemplate

    Many of the below listed archive profiles allow to configure a pathTemplate to specify a path structure within the storage.

    The following variables can be used. They are referenced with curly brackets within the pathTemplate value (see example below).

    • tenant, system:tenant

    • contentStreamId, system:contentStreamId

    • objectTypeId, system:objectTypeId

    We recommend to start the path with {tenant} to separate the individual tenant’s contents.

    With the substring operation, a specific part of a string can be referenced. For example, to reference the first two characters of the contentStreamId, use \{contentStreamId.substring(0,2)}. The second index is excluded. If only one index is specified, the characters beginning from that index are referenced. For example, using 'test'.substring(2) would result in st.

    In some cases, the DATE operation can be useful to reference the current date stamp. By passing a parameter to DATE, a format string is specified as defined by SimpleDateFormat. Without any parameter, a yyyyMMdd is considered.

    Example:

    • Consider the pathTemplate configuration {tenant}/\{DATE(yyyy)/DATE(MM)/DATE(dd)/\{contentStreamId.substring(0,2)}}

    • The currently logged-in user belongs to the yuuvistest tenant.

    • The user stores a binary content file at 21 DEC 2022 at 4.11 pm.

    • The binary content file gets 7850BB1A-F749-11E8-A21E-49DDF2475266, as value for the contentStreamId.

    • The archive path results to yuuvistest/2022/12/21/78/.

    storeCurrentMetadataAlongWithBinary

    As of 2024 Spring. Not available for filesystem and hcp-s3 drivers.

    Boolean value to enable (true) or disable (false, default) additional archiving of the metadata for each stored DMS object. Please note that large sets of metadata require considerable storage resources.

Parameters for S3 Archive Profiles

Use s3 as value for archiveDriverName.

Parameter Description Default Value

access-key

Access key

-

secret-key

Password

-

url

URL for S3

-

bucket

Name of the bucket in the archive system for filing.

-

defaultRetentionInDays

Retention time in days.

Objects under retention can still be deleted by administrators having direct access to the S3 storage.

To transmit no retention time, set the value 0.

Scheduled retention time (system:rmExpirationDate) has priority over any times specified here.

If the profile is used for a repository used as rendition repository, the parameter is ignored for the storage of renditions as they cannot be under retention. However, if binary content files are stored in the same repository beside the renditions, the defaultRetentionInDays value is NOT ignored for the storage of binary content files.

0

region

As of 2022 Autumn. Specifies the location of the data center where to create new buckets.

If not specified, it is automatically determined via the S3 method GetBucketLocation.

-

objectLock

As of 2022 Autumn. Boolean value that decides if the archive-internal retention (objectLock) is required (true) or optional (false) for the corresponding bucket.

If true is set:

  • Binary content files under retention specified via secondary object type (SOT) system:rmDestructionRetention can only be stored in buckets with activated ObjectLocking.

  • Buckets automatically created by the archive service will have activated objectLock.

If false is set:

  • For binary content files under retention specified via SOT system:rmDestructionRetention stored in buckets with activated ObjectLocking, an archive-internal retention will be set.

  • For binary content files under retention specified via SOT system:rmDestructionRetention stored in buckets with deactivated ObjectLocking, no archive-internal retention will be set. Thus, binary content files can only be protected from manipulation via yuuvis® Momentum endpoints but not from manipulation by direct storage access.

  • Buckets automatically created by the archive service will have deactivated objectLock.

In both cases: For objects without retention specified via SOT system:rmDestructionRetention, no archive-internal retention is set.

true

pathTemplate

Optional: This parameter can be used to store objects in specific directories (paths) within a bucket. Find details in the description of the general parameters for all archives.

If the profile is used for a rendition repository, use only the contentStreamId as a placeholder in the specified path. Do not include a DATE reference to avoid path changes for each rendition update (Instead of a rendition update, a new rendition would be created and the previous rendition would have to be deleted.)

-

retentionMode

Optional parameter to select a retention mode for S3 Object Lock.

Available values:

  • COMPLIANCE - objects under retention cannot be modified/deleted even by a storage administrator.

  • GOVERNANCE - storage users with specific permissions can modify/delete objects under retention.

COMPLIANCE

Parameters for NetApp Archive Profiles

Use netapp as value for archiveDriverName.

Parameter Description Default Value

volume

Archive location for the data to be saved.

-

defaultRetentionInDays

Optional: Retention time in days.

To transmit no retention time, set the value 0.

Scheduled retention time (system:rmExpirationDate) has priority over any times specified here.

0

enableReadOnly

Optional: Defines whether the drivers of the archive should define data to be read-only.

true

pathTemplate

Optional: This parameter can be used to store objects in specific directories (paths) within a bucket. Find details in the description of the general parameters for all archives.

-

Parameters for iCAS Archive Profiles

Use iternity as value for archiveDriverName.

Parameter Description Default Value

userName

Name of the user with the appropriate rights for the archive.

-

userPassword

The user’s password.

-

endpoint

URL of the iCAS web service.

-

cscMode

Storage mode for objects and meta data.

The storage mode is specified with a sequence of four parameters:

Binary Content File Metadata

Compression

Encryption

Compression

Encryption

S (without)

N (without)

S (without)

N (without)

L (with)

S (standard)

L (with)

S (standard)

A (AES 256)

A (AES 259)

Example: LSSN → The binary content file is compressed (L) and encrypted with the standard method (S); the metadata is not compressed (S) and not encrypted (N).

-

maxCreateCscSize

Determines the maximum size of containers.

The information is specified in bytes.

10000000

maxCreateCscFile

Determines the maximum number of objects for the containers.

1000

maxCreateCscSingleFileLimit

Determines the individual size limit of an object.

4000000

maxWorkChunkSize

Determines the maximum size of a single chunk.

The information is specified in bytes.

5000000

clientSslTrustStore

Optional: Resource path to a certificate trust store for encrypted communication with the web service.

-

clientSslTrustStorePassword

Optional: Password for the certificate trust store.

-

defaultRetentionInDays

Retention time in days.

To transmit no retention time, set the value 0.

Scheduled retention time (system:rmExpirationDate) has priority over any times specified here.

0

Parameters for Hitachi Content Platform Archive Profiles

Use hcp-s3 (up to 2023 Winter hcp_s3) as value for archiveDriverName.

Retention times cannot be subsequently extended in Hitachi Content Platform archives. If a binary content file is stored with a retention time (either via configured defaultRetentionInDays or via object property system:rmExpirationDate), this time is fixed in the archive metadata during the entire storage time.
Parameter Description Default Value

access-key

Access key

-

secret-key

Password

-

url

URL for HCP

-

bucket

Name of the bucket in the archive system for filing.

-

defaultRetentionInDays

Retention time in days.

To transmit no retention time, set the value 0.

Scheduled retention time (system:rmExpirationDate) has priority over any times specified here.

0

pathTemplate

Optional: This parameter can be used to store objects in specific directories (paths) within a bucket. Find details in the description of the general parameters for all archives.

-

Parameters for Cloudian HyperStore Archive Profiles

The Cloudian Hyperstore Content Platform provides an AWS-S3-compatible ,REST API with few extensions used by the archive service. In order to configure the Cloudian Hyperstore archive, you need to configure the following (S3-relevant) parameters.

Use cloudian_s3 as value for archiveDriverName.

Parameter Description Default Value

access-key

Access key

-

secret-key

Password

-

url

URL for Cloudian HyperStore

-

bucket

Name of the bucket in the archive system for filing.

-

defaultRetentionInDays

Retention time in days.

To transmit no retention time, set the value 0.

Scheduled retention time (system:rmExpirationDate) has priority over any times specified here.

0

pathTemplate

Optional: This parameter can be used to store objects in specific directories (paths) within a bucket. Find details in the description of the general parameters for all archives.

-

Parameters for DELL S3 Archive Profiles

Available as of 2022 Autumn. Use ecs-s3 as value for archiveDriverName.

Parameter Description Default Value

access-key

Access key

-

secret-key

Password

-

url

URL for S3

-

bucket

Name of the bucket in the archive system for filing.

-

defaultRetentionInDays

Retention time in days.

Objects under retention can still be deleted by administrators having direct access to the S3 storage.

To transmit no retention time, set the value 0.

Scheduled retention time (system:rmExpirationDate) has priority over any times specified here.

If the profile is used for a repository used as rendition repository, the parameter is ignored for the storage of renditions as they cannot be under retention. However, if binary content files are stored in the same repository beside the renditions, the defaultRetentionInDays value is NOT ignored for the storage of binary content files.

0

region

Specifies the location of the data center where to create new buckets. If not specified, it is automatically determined via the S3 method GetBucketLocation.

-

objectLock

Boolean value that decides if the archive-internal retention (objectLock) is required (true) or optional (false) for the corresponding bucket.

If true is set:

  • Binary content files under retention specified via secondary object type (SOT) system:rmDestructionRetention can only be stored in buckets with activated ObjectLocking.

  • Buckets automatically created by the archive service will have activated objectLock.

If false is set:

  • For binary content files under retention specified via SOT system:rmDestructionRetention stored in buckets with activated ObjectLocking, an archive-internal retention will be set.

  • For binary content files under retention specified via SOT system:rmDestructionRetention stored in buckets with deactivated ObjectLocking, no archive-internal retention will be set. Thus, binary content files can only be protected from manipulation via yuuvis® Momentum endpoints but not from manipulation by direct storage access.

  • Buckets automatically created by the archive service will have deactivated objectLock.

In both cases: For objects without retention specified via SOT system:rmDestructionRetention, no archive-internal retention is set.

true

retentionMode

Optional parameter to select a retention mode for S3 Object Lock.

Available values:

  • COMPLIANCE - objects under retention cannot be modified/deleted even by a storage administrator.

  • GOVERNANCE - storage users with specific permissions can modify/delete objects under retention.

COMPLIANCE

pathTemplate

Optional: This parameter can be used to store objects in specific directories (paths) within a bucket. Find details in the description of the general parameters for all archives.

If the profile is used for a rendition repository, use only the contentStreamId as a placeholder in the specified path. Do not include a DATE reference to avoid path changes for each rendition update (Instead of a rendition update, a new rendition would be created and the previous rendition would have to be deleted.)

-

Parameters for File System Profiles

Use filesystem as value for archiveDriverName.

Parameter Description Default Value

volume

Storage container location.

-

pathTemplate

This parameter is essential as it configures to store objects in specific directories (paths) within the volume. Find details in the description of the general parameters for all archives.

{tenant}/DOCUMENT/\{contentStreamId.substring(1,3)}/\{contentStreamId.substring(3,5)}/\{contentStreamId.substring(5,6)}

Each binary content file stored in a file system repository is portioned in sub-sets of data. Each of those chunks is named <contentStreamId>_<count>. All chunks belonging to the same binary content file are encapsulated in one ZIP file. Additionally, each ZIP file contains a meta.xml file containing processing information for the stored binary content file:

  • file name

  • version

  • mime type

  • unpacked file size

  • SHA-256 hash calculated by the repository service

  • MD5 hash calculated by the repository service

example meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<xmlmeta>
    <filename>content.eml</filename>
    <version>1.0</version>
    <mime>message/rfc822</mime>
    <size>156836</size>
    <sha256>0BA8B60F0A1D16DEB44D9EE427A75FADE6ADF751312BE9D22D7D4ED2CC3B2DA6</sha256>
    <md5>BF8782D1AD01CDF211AD09038AB64349</md5>
    <chunksize>156836</chunksize>
</xmlmeta>

The number of chunks is determined by the file size of the binary content file to be stored:

size of binary content file number of chunks size of each chunk

<= 1 MB

1

size of binary content file

> 1 MB to <= 10 MB

size of binary content file / 1MB

1MB (minimum chunk size)

> 10 MB to < 1280 MB (128 MB is the maximum chunk size)

10

size of binary content file / number of chunks + 1 Byte

> (x - 1) • 1280 MB to <= x • 1280 MB

where (x = 2 …​ 2n, n ∈ ℕ)

10 • x

size of binary content file / number of chunks + 1 Byte

Parameters for Azure Blob Storage Profiles with Buckets

Available as of 2022 Winter. Use azure_blobstore as value for archiveDriverName.

Parameter Description Default Value

connection

Connection string containing all required information for the access to Azure.

-

defaultRetentionInDays

Retention time in days.

Objects under retention can still be deleted by administrators having direct access to the storage.

To transmit no retention time, set the value 0.

Scheduled retention time (system:rmExpirationDate) has priority over any times specified here.

0

pathTemplate

Optional: This parameter can be used to store objects in specific directories (paths) within a bucket. Find details in the description of the general parameters for all archives.

buckets

A map containing one or more configurations.

Specify a unique configuration name as configuration key. For each key, the name and retentionInYears parameters are required.

Whenever the content file of an object is stored in Azure, the archive service selects the container with the lowest retentionInYears value that still ensures the retention for that concrete object (either scheduled via system:rmExpirationDate object property or via defaultRetentionInDays). The name of the selected bucket is used as prefix for the contentStreamId that is generated for the object content file.

-

name

Name of the container in Azure.

The container has to exist.

retentionInYears

Retention time that is configured in Azure for the container specified by name.

If retentionInYears is 0, the corresponding container does not have archive-internal retention. It is used to store objects without retention (neither scheduled via system:rmExpirationDate object property nor via defaultRetentionInDays).

The specified retention time has to match the Azure container configuration.

Example: Consider the configuration below. If the content file of an object with a scheduled retention time of 2 years would be stored, blob20years container would be used.

Example Azure Blob Storage Profile Configuration
storage:
  repositories:
    ...
  profiles:
    ...
    azure_blobstore:
      azureImmutable1:
        connection: 'DefaultEndpointsProtocol=https;AccountName=immutablestorageos;AccountKey=AAAAAAAAAA==;EndpointSuffix=core.windows.net'
        defaultRetentionInDays: 0
        buckets:
           'blob1':
             name: 'blobNoRetention'
             retentionInYears: 0
           'blob2':
             retentionInYears: 1
             name: 'blob1year'
           'blob3':
             retentionInYears: 20
             name: 'blob20years'
Parameters for Azure Profiles with Object Retention

Available as of 2023 Autumn. Use azure_objectretention as value for archiveDriverName.

Parameter Description Default Value

connection

Connection string containing all required information for the access to Azure.

-

defaultRetentionInDays

Retention time in days.

Objects under retention can still be deleted by administrators having direct access to the storage.

To transmit no retention time, set the value 0.

Scheduled retention time (system:rmExpirationDate) has priority over any times specified here.

0

retentionMode

Optional parameter to select an Azure immutability policy lock similar to the retention mode for S3 Object Lock.

Available values:

  • COMPLIANCE - objects under retention cannot be modified/deleted even by a storage administrator. Corresponds to Azure immutability policy LOCKED.

  • GOVERNANCE - storage users with specific permissions can modify/delete objects under retention. Corresponds to Azure immutability policy UNLOCKED.

COMPLIANCE

pathTemplate

Optional: This parameter can be used to store objects in specific directories (paths) within a bucket. Find details in the description of the general parameters for all archives.

Example Azure Profile Configuration with Object Retention
azure_objectretention:
  azureProfile1:
    connection: 'DefaultEndpointsProtocol=https;AccountName=XXXXX;AccountKey=xxxx....'
    bucket: test1
    pathTemplate: '{tenant}/{DATE(yyyy)}/{DATE(MM)}/{DATE(dd)}/{contentStreamId.substring(0,2)}'
    defaultRetentionInDays: 2
Parameters for Google Cloud Storage Profiles

Available as of 2024 Summer. Use gcs as value for archiveDriverName.

Parameter Description Default Value

connection

Connection string containing all required information for the access to Google Cloud.

To create the string, retrieve the key.json authentication file from your Google Cloud Platform. Encode the file’s content with Base64 encoding. The resulting string is your connection string.

-

bucket

Name of the bucket in the archive system for filing.

-

defaultRetentionInDays

Retention time in days.

Objects under retention can still be deleted by administrators having direct access to the Google Cloud Storage.

To transmit no retention time, set the value 0.

Scheduled retention time (system:rmExpirationDate) has priority over any times specified here.

0

objectLock

Boolean value that decides if the archive-internal retention (objectLock) is required (true) or optional (false) for the corresponding bucket.

If true is set:

  • Binary content files under retention specified via secondary object type (SOT) system:rmDestructionRetention can only be stored in buckets with activated ObjectLocking.

  • Buckets automatically created by the repository service will have activated objectLock.

If false is set:

  • For binary content files under retention specified via SOT system:rmDestructionRetention stored in buckets with activated ObjectLocking, an archive-internal retention will be set.

  • For binary content files under retention specified via SOT system:rmDestructionRetention stored in buckets with deactivated ObjectLocking, no archive-internal retention will be set. Thus, binary content files can only be protected from manipulation via yuuvis® Momentum endpoints but not from manipulation by direct storage access.

  • Buckets automatically created by the repository service will have deactivated objectLock.

In both cases: For objects without retention specified via SOT system:rmDestructionRetention, no archive-internal retention is set.

false

pathTemplate

Optional: This parameter can be used to store objects in specific directories (paths) within a bucket. Find details in the description of the general parameters for all archives.

-

retentionMode

Optional parameter to select a retention configuration for the bucket in the Google Cloud Storage.

Available values:

  • COMPLIANCE - objects under retention cannot be modified/deleted even by a storage administrator.

  • GOVERNANCE - storage users with specific permissions can modify/delete objects under retention.

COMPLIANCE

Example Google Cloud Profile Configuration
gcs:
    gcsexample:
       connection: "ew0KICAidHlwZ......................................"
       bucket: examplebucket
       pathTemplate: "{tenant}/{DATE(yyyy)}/{DATE(MM)}/{DATE(dd)}"
       storeCurrentMetaDataAlongWithBinary: false
       retentionMode: GOVERNANCE
       defaultRetentionInDays: 0
       objectLock: false
authentication-prod.yml

Parameters of the configuration file used by the authentication service in productive systems.

Parameters
Parameter Description Default Value

routing.defaultEntryPoint

Defines a path that will be added to the URL automatically if https://<host>/ is called.

'/client/index.html'

server.servlet.session.cookie

Section of Parameters for session cookie configuration.

Please note the impacts on the login via browser below.

same-site

Configures whether browser sessions are allowed where yuuvis® Momentum is embedded in an external web page, e.g., via iframe. Available values:

  • Strict - Sessions are deleted in case of external embedding or external reference. Not usable in combination with an identity provider as it is considered as external reference.

  • Lax - Sessions are deleted in case of external embedding, e.g., via iframes.

  • None - Sessions are allowed in any context. Requires SSL (HTTPS protocol) and server.servlet.session.cookie.secure: true.

'Lax'

secure

Prohibits unprotected sessions. Available values:

  • false - Sessions are allowed with and without SSL.

  • true - Sessions are allowed only with SSL.

false

http-only

Configures whether JavaScript functionality of a browser application can access the session cookie. Available values:

  • false - Script access allowed.

  • true - Script access prohibited.

1800

server.servlet.session.timeout

Defines the duration for which the session between gateway and client is authorized. Specified in seconds.

1800

Deprecated as of 2023 Winter: routing.endpoints

List of services for which the authentication service endpoints are available. Those services can be accessed via authentication service.

Also external services can be added here.

- 'authentication'
- 'api'
- 'search'
- 'client'
- 'api-web'
- 'tenant-management'
- 'viewer'
- 'architect'
- 'custom'
- 'userservice'
- 'bpm-engine'
- 'renditionrepository'
- 'dashlet365'
- 'office365'

authorization.accesses

Definition of permissions for the access to individual endpoints and sub-paths.

Structured as a list of endpoints and their individual access conditions specified via the parameters endpoints, access, method and expose.

Any endpoint that should be accessible via authentication service has to be listed here.

See code block below.

authorization.cacheUserAttributes

Available as of 2023 Autumn.

If true, the user attributes retrieved via GET user.info webhook are stored in a Redis cache. To reduce the header size of cluster-internal HTTP requests, the JWT does NOT contain the user attributes authorities and abac anymore. Those attributes can be retrieved via GET /session/updateUserAttributeCache/{tenant}/{userId}.

If false, all user attributes are stored only in the JWT but NOT in a cache.

false

Deprecated as of 2023 Winter: spring.session.store-type

Specifies whether the user session states are stored centrally in a Redis database (value redis) or managed by a single authentication service instance (if parameter is not specified).

For scaling and fail-safe operation of the authentication service, set the value redis.

-

management.health.redis.enabled

As of 2022 Spring. If true, the authentication service checks the connection to the Redis database at regular intervals.

For scaling and fail-safe operation of the authentication service, set true.

false

Default Configuration for 'authorization.accesses'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
### Manage-Endpunkte
  - endpoints: /manage/**
    expose: true
  - endpoints: /*/manage/**
    access: hasAuthority('YUUVIS_SYSTEM_INTEGRATOR')
### API-Endpunkte
  - endpoints: /api/system/**
    access: hasAuthority('YUUVIS_SYSTEM_INTEGRATOR')
  - endpoints: /api/admin/**
    access: hasAuthority('YUUVIS_TENANT_ADMIN')
  - endpoints: /api/dms/**
### Endpunkte für Swagger-Webclient des API-Gateways
  - endpoints: /api/swagger-ui.html/**,/api/**/springfox-swagger-ui/**,/api/**/swagger-resources/**,/api/**/v2/api-docs/**
  - endpoints: /api/swagger-ui/**,/api/swagger/v3/api-docs/**
  - endpoints: /api/api/system/**
    access: hasAuthority('YUUVIS_SYSTEM_INTEGRATOR')
  - endpoints: /api/api/admin/**
    access: hasAuthority('YUUVIS_TENANT_ADMIN')
  - endpoints: /api/api/dms/**
### Webclient
  - endpoints: /search/**,/viewer/**,/architect/**
  - endpoints: /client/**
    expose: true
### Viewer Service
  - endpoints: /viewer/view/**,/viewer/assets/**,/viewer/download/**
    expose: true
  - endpoints: /viewer/**
### Userservice
  - endpoints: /userservice/**
### bpm-engine
  - endpoints: /bpm-engine/internal/**
    # access: denyAll
  - endpoints: /bpm-engine/**
### Metricsservice
  - endpoints: /metricsservice/**
    access: hasAuthority('YUUVIS_SYSTEM_INTEGRATOR')
### api-web
  - endpoints: /api-web/swagger-ui.html,/api-web/swagger-ui/**,/api-web/**/v3/api-docs/**
  - endpoints: /api-web/api/resources/**,/api-web/api/users/**,/api-web/api/bpm/**,/api-web/api/dms/**
  - endpoints: /api-web/api/system/**
    access: hasAuthority('YUUVIS_SYSTEM_INTEGRATOR')
  - endpoints: /api-web/api/admin/**
    access: hasAuthority('YUUVIS_TENANT_ADMIN')
### tenant-management
  - endpoints: /tenant-management/swagger-ui.html,/tenant-management/swagger-ui/**,/tenant-management/**/v3/api-docs/**
  - endpoints: /tenant-management/api/system/**
    access: hasAuthority('YUUVIS_SYSTEM_INTEGRATOR')
  - endpoints: /tenant-management/api/admin/**
    access: hasAuthority('YUUVIS_TENANT_ADMIN')
### office 365
  - endpoints: /office365/**
  - endpoints: /dashlet365/**
Impacts of Cookies on the Login via Browser

The following impacts of the server.servlet.session.cookie.same-site configuration parameter (see description above) are tested with Firefox (version 113) and Google Chrome (version 113). The Connection has to be protected via SSL (HTTPS protocol).

Loop means here an infinite loop of requests between authentication service and identity provider. It is not possible to authenticate.

System integrators or administrators have to be aware of the behavior and configure their installation according to their needs.

Value for 'same-site' Behavior in Own Context Behavior in Embedded Context Comment

None

Firefox OK, Chrome OK

Firefox OK, Chrome OK

Low CSRF protection (OWASP SameSite)

Lax

Firefox OK, Chrome OK

Firefox Loop, Chrome loses session

Default configuration

Strict

Firefox Loop, Chrome OK

Firefox Loop, Chrome loses session

Highest protection but not recommended

system-prod.yml

Parameters of the configuration file used by the system service in productive systems.

Parameters
Parameter Description Default Value

schema.changed.observers

Services that do not belong to yuuvis® core but need to be informed about any changes of the schema.

/rest-ws/refreshschema?global=%s, /sothook/schema/refresh?global=%s, /primarysothook/schema/refresh?global=%s

schema.tenant.properties.limit

Integer value defining the maximum number of property definitions allowed in a tenant schema.

If the value is increased, it is recommended to adjust the maximum number of fields in your Elasticsearch index as well. Increase the index.mapping.total_fields.limit parameter via the Elasticsearch Update index settings API. Please do not exceed the limit recommended by the Elasticsearch provider.

20

schema.global.properties.limit

Integer value defining the maximum number of property definitions allowed in a tenant schema.

If the value is increased, it is recommended to adjust the maximum number of fields in your Elasticsearch index as well. Increase the index.mapping.total_fields.limit parameter via the Elasticsearch Update index settings API. Please do not exceed the limit recommended by the Elasticsearch provider.

10000

commander-prod.yml

Configuration file containing configuration parameters for the commander service.

Parameters
Parameter Description Default Value

spring.datasource.hikari.custom.maximum-pool-size

Integer number of connections to the database. At least 2 are required.

2

ssh.shell

Section of SSH connection parameters

port

8022

user

root

password

null (password will be generated and displayed in the log when starting the commander

history-file

commander-history.log

Example Configuration
1
2
3
4
5
6
ssh:
  shell:
    port: 8022
    user: 'root'
    password: 'changeme'
    history-file: commander-history.log
application-prod.yml

Configuration file containing configuration parameters for all services (including webhooks).

Parameters
Parameter Description Default Value

service.connection-timeout-ms

Integer. Time in milliseconds. Limits the time that should be acceptable for the creation of a cluster-internal connection between two services. The connection attempt is interrupted if no connection could be established within the configured time.

3000

service.socket-timeout-ms

Integer. Time in milliseconds. Limits the time between cluster-internal HTTP request and response. The processing of the request is interrupted if no response could be sent within the configured time.

60000

Example Configuration
1
2
3
service:
    connection-timeout-ms: 3000
    socket-timeout-ms: 3600000

2.10.4. System Configuration Files

Configuration of the core system’s behavior via JSON files.

The yuuvis® Momentum service architecture makes each service retrieve configuration files from a central location managed by the configservice. In addition to the profiles in YAML format, there are system configuration files in JSON format that can be used to adjust the core system’s behavior according to the customer’s needs.

Available Files

The list of system configuration JSON files and affected services. Click a file name to open a more detailed description and find available parameters.

systemHookConfiguration.json - Configuration of system hooks, split in AMQP hooks and webhooks.
Referenced by Services

authentication,api,commander

Storage Location
  • global configuration file: Git system directory

  • app-specific configuration files (as of 2022 Summer): Git apps/<app name>/system directory

Parameters
Parameter Type Description

amqp

List of mappings in JSON format.

List of single AMQP Hook configurations each of them defined via following parameters. Read by API gateway and commander service.

As of version 2021 Summer, placeholders can be used as provided by spring. They can reference values in the system environment including configuration files and command line arguments. The placeholders will be replaced by the referenced values of the environment variable during the starting process of the corresponding service. The syntax follows the spring placeholders: ${<reference>}.

bulkSize

integer

Maximum bulk size for a message.

enable

boolean

Specifies whether this configuration is active/enabled (true) or inactive/disabled (false).

password

string

Password for the AMQP server.

predicate

string

Condition that specifies when the AMQP hook is used. supported scripting languages: SpEL (Spring Expression Language) and JavaScript.

All properties that are available in the corresponding hook’s JSON request body can be referenced. Additionally, the tenant can always be referenced via options['tenant'].

queue

string

Name of the queue to which the messages are written.

Only one messaging queue can be used. The messaging queue specified for the first defined AMQP hook will apply to all following AMQP hook definitions as well. The messaging system needs to support AMQP 1.0.

type

string

Defines the processing step during which the AMQP hook will be triggered.

url

string

AMQP server endpoint, e.g. 127.0.0.1:5672

user

string

Username for the AMQP server.

lifecycle

List of mappings in JSON format.

List of single lifecycle hook configurations each of them defined via following parameters. Read by registry service.

If multiple lifecycle hooks are registered, the predicate is applied to the original predicate target for each of them and in the order of definition.

enable

boolean

Specifies whether this configuration is active/enabled (true) or inactive/disabled (false).

predicate

string

Condition that specifies when the webhook is used. Supported scripting languages: SpEL (Spring Expression Language) and JavaScript.

All properties that are available in the corresponding webhook’s JSON request body can be referenced. Additionally, the tenant can always be referenced via options['tenant'].

type

string

Defines the processing step during which the webhook will be triggered. Only dms.request.objects.upsert.database-before available.

tagname

string

The name of a tag matching the conventions for tagging.

If the corresponding tag

  • is already assigned, its state is replaced by the value specified via tagstate parameter.

  • is not yet assigned, it is added with the state value specified via tagstate parameter.

tagstate

int

The value is used for the tag`s state.

webhooks

List of mappings in JSON format.

List of single Webhook configurations each of them defined via following parameters. Read by authentication service and API gateway.

If multiple Webhooks are registered for the same Webhook type, the predicate is applied to the original predicate target for each of them and in the order of definition.

enable

boolean

Specifies whether this configuration is active/enabled (true) or inactive/disabled (false).

predicate

string

Condition that specifies when the webhook is used. Supported scripting languages: SpEL (Spring Expression Language) and JavaScript.

All properties that are available in the corresponding webhook’s JSON request body can be referenced. Additionally, the tenant can always be referenced via options['tenant'].

type

string

Defines the processing step during which the webhook will be triggered.

url

string

Endpoint to be called by the webhook if the predicate matches.

Configuration File Management

It is possible to configure multiple system hooks having the same type. They are considered one after the other beginning from the top of the configuration file. If app-specific systemHookConfiguration.json files are specified (possible as of 2022 Summer), they are considered after the global configuration file and in alphabetical order.

As of 2022 Summer, the systemHookConfiguration.json configuration files should be retrieved and updated via the yuuvis® Momentum endpoints listed below. The changes are applied immediately after a successful update of the configuration.

Example

The following example configures an AMQP hook, a lifecycle hook and a webhook.

  • The AMQP hook applies to object imports and checks the contentStreams for the presence of a range attribute. If the range attribute is detected, the AMQP hook recognizes the imported content to be a compound document and initiates asynchronous text extraction of all parts of the content.

  • The lifecycle hook adds a tag with the configured name and state to the created or updated DMS objects that match its predicate.

  • The example webhook is triggered at every login and retrieves the roles of the user trying to authenticate.

Example System Hook Configuration
{
    "systemhooks": {
        "amqp": [
            {
                "bulkSize": 10,
                "enable": true,
                "password": "secret",
                "predicate": "spel:(contentStreams != null && contentStreams.size() > 0 && contentStreams[0]['range'] != null && contentStreams[0]['range'].length() > 0) ? true : false",
                "queue": "lc.textextraction",
                "type": "object.insert.document",
                "url": "10.10.6.242:5672",
                "user": "clouduser"
            }
        ],
        "lifecycle": [
            {
                "type": "dms.request.objects.upsert.database-before",
                "enable": true,
                "predicate": "spel:T(java.util.List).of('smallDocument').contains(properties['system:objectTypeId']['value']) && T(java.util.List).of(101).contains(options['action'])",
                "tagname": "system:ren:text",
                "tagstate": 1
            }
        ],
        "webhooks": [
            {
                "enable": true,
                "predicate": "spel:true",
                "type": "user.info",
                "url": "http://organization/api/userinfo/${tenant}/${userId}"
            }
        ]
    }
}
serviceConfiguration.json - Activation or deactivation of the contentanalyzer in total, definition of a specific behavior via conditions.
Referenced by Services

repository, api, audit

Storage Location

Git system directory

Parameters

The following parameters are available for the individual services:

Service / Parameter Description

contentanalyzer

Section of Parameters determining the default behavior of the content analysis by repository service. The analysis of the content and/or mimeType can be requested or not, depending on defined conditions. If a condition matches during an import process, the content and/or mimeType will be analyzed.

Within the import request body, this configuration can be overwritten by specifying the options parameters accordingly. The analysis of content and/or mimeType can be requested or suppressed even if the opposite behavior is configured in the file serviceConfiguration.json.
Example

See default configuration below.

skip

Decides whether the service is used (false) or bypassed (true).

analyze

A list of property groups defining a specific behavior of the service depending on a conditions. For each condition, the determination of the mimeType and the text extraction can be activated or deactivated.

predicate

A condition specified in Spring Expression Language (SpEL).

mimetype

Decides whether the mimeType will be determined (true) or not determined (false) if the condition matches.

content

Decides whether the synchronous full-text extraction will be determined (true) or not determined (false) if the condition matches.

audit

Optional section of parameters determining the behavior of the audit service. If not specified, all actions are documented in the individual DMS object’s audit trail.

Please be aware that the skipped audit entries are actually NOT CREATED ANYWHERE. The corresponding actions on DMS objects in your system will not be documented at all.
Example
"audit": {
            "skipAuditEntryCreation": false,
            "exclusions": {
                "actions": [401,301,101]
            }
        }

skipAuditEntryCreation

Boolean value that decides whether the creation of all audit entries is skipped (true) or not (false).

exclusions

A section of properties that can be used to specify events that should not be documented in the audit trail.

actions

A list of Integer action codes. The corresponding actions are not documented in the audit trail.

Default serviceConfiguration.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
    "services": {
        "contentanalyzer": {
            "analyze": [
                {
                    "predicate": "spel:(properties != null && properties['Name'] != null && properties['Name']['value'] == 'disable') ? true : false",
                    "mimetype": true,
                    "content": false
                },
                {
                    "predicate": "spel:(contentStreams != null && contentStreams.size() > 0 && contentStreams[0]['range'] != null && contentStreams[0]['range'].length() > 0) ? true : false",
                    "mimetype": false,
                    "content": false
                }
            ]
        }
    }
}
interceptorConfiguration.json - Configuration of interceptors.
Storage Location

Git system directory

Parameters

The following parameters are available for the interceptor configuration:

Parameter Type Required Description

type

String

yes

The type of the interceptor. It defines the position in the process flow where the interceptor can step in.

predicate

String

yes

The condition that triggers the redirection of the process flow in order to include the project-specific process extension. The string can provide the condition either in Spring Expression Language (SpEL) or Javascript. Thus, the string always has to start with a prefix spel: for SpEL or js: for Javascript.

url

String

yes

HTTP address of an external endpoint defining the project-specific process extension. Dynamic components (properties of the processed object) can be included in curly brackets.

useDiscovery

Boolean

no

Decides whether to resolve the url string at the Discovery-Service or not. If not specified, a default value is set.

Interceptor Configuration Example

The following example configures an interceptor that will be trigger by every update of a content (action code 301). At the take-off point after the repository service, the enriched request body is passed to the external endpoint specified by url.

To activate this configuration, the repository service needs to be restarted.

Example interceptorConfiguration.json.
1
2
3
4
5
6
7
8
9
10
{
    "interceptors": [
        {
            "type": "dms.request.objects.upsert.database-before",
            "predicate": "spel:options['action']==301",
            "url": "http://exampleinterceptorcontentupdate/api/dms/objects/upsert",
            "useDiscovery": true
        }
    ]
}
Configuration in Kubernetes
Configuration during Installation

You can set the configuration parameter values in advance during installation.

The configuration parameters are set in the file values.yaml of the yuuvis Helm chart. Modify a value of the listed parameters or add one of the available parameters listed in the above linked fact sheet of the corresponding system configuration file with your desired value to overwrite its default value.

In order to add an interceptor configuration, add a section interceptorConfiguration to the file values.yaml and specify your desired parameters. Add an entry interceptorConfiguration.json to the systemconfigmap.yaml in the yuuvis/templates folder and reference your section interceptorConfiguration in values.yaml.

During the deployment, the settings defined in the file values.yaml will be written into the system configuration files that are read by the services when they are started.

Changing Configuration of a Running System

For changes on a running system, you need to access your Git server.

Navigate to the system directory of the configuration git repositories' appropriate branch and find a list of the configuration files including the above listed profiles. Open the file, modify it, and check in your changes.

After the modification of a system configuration file you need to restart the services that reference the file in order to apply the changes.

2.10.5. Service-specific Configurations

Configuration parameters for specific core services.

The yuuvis® Momentum configuration files for the operation in the Kubernetes cluster are stored on the Git Server configured in the system. In order to change the configuration of a service, you need to access the Git repository.

Configuration of 'api' Gateway

The following Parameters can be set in any YAML configuration file that is activated via profile.

Parameter Description

routing.endpoints

As of 2023 Autumn.

Allows to add custom endpoints to the API provided via api gateway. List of configurations with parameters described below.

The api gateway forwards the requests to the configured custom service including the assigned JWT.

It ist NOT possible to overwrite existing endpoints of the api gateway.

Example
routing.endpoints:
  - endpoint: '/api/dms/objects/{objectId}/custom/{param}/**'
    methods: 'post,get,head' # if not set, all methods are taken
    destination: 'http://customservice'

Considering the example configuration, a call https://my-momentum.org/api/dms/objects/123456/custom/2/test is forwarded to http://customservice/api/dms/objects/123456/custom/2/test.

endpoint

Required. Custom endpoint URL that will be available via api gateway.

method

Optional. Comma-separated list of HTTP methods.

If configured, only the calls of specified HTTP methods are allowed for the specific endpoint.

If not configured, calls of all HTTP methods are allowed.

destination

Required. URL of the custom service within the cluster.

Requests to the configured endpoint are forwarded this URL:

  • The endpoint URL is appended to the destination URL.

  • Placeholders are resolved.

Configuration of 'archive' Service

Parameters application-storage.yml:

  • storage.repositories

  • storage.profiles

Configuration of 'audit' Service
Service-specific Parameters
Parameter Type Default value Description

metric.storage.recalculateIfOlderThanInSeconds (as of 2023 Spring)

Integer

-1

Controls the automated recalculation of the storage metric.

If the value is -1, there is no automated recalculation. It has to be triggered via the DELETE /api/system/metrics/{metric} endpoint.

If any value > 0 is configured, it is considered as time in seconds between two automated recalculation processes. As soon as the specified time is passed after the previous recalculation process, a new recalculation process is triggered.

High Database Workload
We do not recommend to activate the automated recalculation as no storage metric can be retrieved during the processing time.

metric.storage.recalculateIfLastProgressOlderThanInSeconds (as of 2023 Spring)

Integer

3600

Controls the behavior of the storage metric recalculation processing in fail situations like, e.g., an unavailable service.

The configured value is considered as maximum time in seconds that the process waits for progress in the database. The database reports a progress after the recalculation for one tenant is done. If the database does not report ongoing progress for a time period that exceeds the configured value, the recalculation is restarted.

The following parameters are referenced from the application-dbs.yml configuration file:

  • storage

Parameters in Service Configuration File

The audit section in the serviceConfiguration.json file can be used to skip the creation of audit entries for specific actions or for all actions.

Configuration of 'authentication' Service

Parameters application-oauth2.yml:

  • keycloak.host

  • authentication.oauth2.tenants

Parameters in authentication-prod.yml:

  • routing.defaultEntryPoint

  • management.endpoints

  • management.endpoint

  • authorization.accesses

Running Multiple Instances

As the number of users increases, more instances may be started for the authentication service to maintain performance. To ensure that the session status of logged-in users is available to all instances, it is stored centrally in a Redis database. This way, users do not have to log in again after a temporary system failure. Their respective service state is stored in a Redis database, and is retrieved by the system after all instances are restarted. The users' session states remain in the Redis database until the sessions have expired or are removed by the users' logging off. If an instance of the authentication service is unavailable for any reason, an instance running in parallel can take over without the user having to log in again. In this way, the authentication service is both fail-safe and scalable.

For example, instance 2 can be restarted using the following command:

kubectl -n yuuvis scale deploy authentication --replicas=2
Configuration steps for versions 2022 Spring - 2023 Autumn.

To allow the storage of individual user session states in the designated Redis database, follow these steps to modify the authentication service configuration:

  • Extend the authentication-prod.yml configuration file by the following lines:

    spring.session.store-type: redis
    management.health.redis.enabled: true
  • Add the redis profile to the authentication service:

    • Run the command:

      kubectl -n yuuvis edit deploy authentication
    • Extend the SPRING_PROFILES_ACTIVE environment variable with redis.

  • Restart all instances of the authentication service.

    • For example, instance 2 can be restarted using the following command:

      kubectl -n yuuvis scale deploy authentication --replicas=2
Embedding in an External Web Page as iframe
  • Create an Ingress for HTTPS that enables access to all resources for the tenant selection page via Content-Security-Policy-Header.

    nginx.ingress.kubernetes.io/configuration-snippet: |
    add_header Content-Security-Policy "frame-ancestors 'self' http://portal.org/ http://portal.org:*/; style-src 'self' 'unsafe-inline' https://unpkg.com/ https://fonts.googleapis.com/; font-src 'self' 'unsafe-inline' https://fonts.gstatic.com/;" always;
    • Replace portal.org by your custom URL of the external web page.

    • The tenant selection page loads further resources from link:https://unpkg.com/ and link:https://fonts.googleapis.com/.

    • For embedding a client application, further configuration might be necessary.

  • Configure your identity provider for the access via iframe (Example: Keycloak iframe configuration).

  • Configure the following parameters in the authentication-prod.yml configuration file:

    server.servlet.session.cookie.same-site: 'None'
    server.servlet.session.cookie.secure: true
  • Refresh the configservice.

  • Restart the authentication service.

Configuration of 'configservice'
Open description of deprecated version 2021 Autumn…​

The configservice can retrieve the cached version of configuration files even if the git is temporarily not accessible. Thus, during a downtime of the git server, GET requests to the configservice will be successful whereas requests for storing resources will not be successful. The behavior is controlled via the boolean value of the the service-internal parameter fail-if-git-not-available in case the git server is temporarily not accessible.

Value for 'fail-if-git-not-available' Behavior of 'configservice' during temporary downtime of the git server

false (default)

Retrieval of cached resource files during git server downtime is enabled.

true

Any request for a resource file via configservice will return an error.

Per default, the configservice uses the persistent volume at /tmp/configservice for initialization during a restart. Alternatively, the configservice can delete and recreate the directory /tmp/configservice by cloning the remote resources during the initialization. This behavior can be applied by one of the following configurations:

  • Set resume-from-local-git: false in the application-prod.yml configuration file.

  • Set the environment variable RESUME-FROM-LOCAL-GIT=false in the Kubernetes deployment of the configservice (default is true).

Configuration of 'repository' Service
Parameters in 'application-storage.yml'
  • storage.default-rendition-repository (as of 2021 Winter)

  • storage.repositories

  • storage.profiles

Find details in the application-storage.yml description.

Parameters in 'serviceConfiguration.json'

Parameters in the serviceConfiguration.json configuration file can be used to change the default behavior of the content and/or mime type analysis. The analysis can be requested or not, depending on the defined conditions. If a condition matches during an import process, the content and/or mime type will be analyzed.

Within each import request body, this configuration can be overwritten by specifying the options parameters accordingly. The analysis of content and/or mime type can be requested or suppressed even if the opposite behavior is configured in the file serviceConfiguration.json.

Furthermore, it is possible to set the extraction.maxTextLengthInKB and mimetype.extension.redetection parameters in a service-specific YAML configuration file for the repository service as described in the next section.

Parameters in any YAML configuration file

Parameters in any configuration file read by the repository service (application-storage.yml or repository-prod.yml), for example.

To ensure downward compatibility with configurations older than 2024 Summer, the repository service reads the contentanalyzer-prod.yml configuration file as well.

Parameter Type Description Default

multipart.keep-files-in-days

Long

Specifies the time limit for the partial upload of a large binary content file in days. Each upload process that exceeds the configured time is removed from the repository service’s internal cache as well as all pieces of content belonging to the corresponding uploadId.

The removal from the cache can be triggered manually before the time limit is exceeded via DELETE /api/dms/uploads/{uploadId}.

2

extraction.exclusiveOfficeLock

boolean

If you need text extraction for large binary content files of Microsoft Office file types, the contentanalyzer service might need its full memory for each single file to be processed. If true, all other text extraction processes wait until the processing of the Microsoft Office file is completed.

Nevertheless, sufficient RAM is required for the contentanalyzer service.

false

extraction.maxTextLengthInKB

integer

Limit for the length of extracted full-text. If an extraction process reaches the limit, it is stopped and the full-text created till then is stored.

If you increase the value, ensure that your search engine can handle the large string field.

2048

mimetype.extension.redetection

comma-separated list of mime types

The standard calculation is based on the analysis of the binary content itself. In case a determined mime type is wrong, it is possible to reanalyze the file considering the file ending. The mime types for which this second analysis step should be triggered are listed here.

'image/x-portable-greymap'

Configuration of 'system' Service

Parameters in the system-prod.yml configuration file:

  • schema.changed.observers

  • schema.tenant.properties.limit

  • schema.global.properties.limit

2.10.6. Logging Configuration

Logs provide information on processes within individual instances of services that are running in the yuuvis® Momentum cluster. Their outputs are managed and provided via Kubernetes. The log level can be configured in order to show more or less process details. The configuration can be adjusted during the installation process, but also for systems that are already in operation.

Hierarchical Configuration

The logging can be configured hierarchically by means of the underlying java package structure. In this description, the placeholder <packageName> is used.

  • If it is replaced by a specific class (e.g., com.os.services.package.subpackage.MyFirstExampleClass), only the configuration for the logging provided by this class is affected.

  • If it is replaced by a package name at a higher hierarchical level (e.g., com.os.services), all classes included in the package are affected.

Configuration Possibilities
Service Deployment during Installation

In the individual service configuration YAML files, the log level can be configured during installation. The desired log level can be specified in the value for the JAVA_OPTS parameter via -D as shown in the example code block below.

spec.template.spec.containers:
- env:
  - name: JAVA_OPTS
    value: -XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -Dlogging.level.com.os.services=DEBUG

To specify multiple logging configurations, separate them with a space as shown in the following example:

spec.template.spec.containers:
- env:
  - name: JAVA_OPTS
    value: -XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -Dlogging.level.com.os.services.package.subpackage.MyFirstExampleClass=DEBUG -Dlogging.level.com.os.services.package.subpackage.MySecondExampleClass=DEBUG
Configuration Files of Running Systems

The logging configuration for yuuvis® Momentum systems that are already in operation can be adjusted via profile-specific configuration files.

Specify the log level in the <serviceName>-prod.yml configuration file in order to configure it for the service that reads the file. The following line, e.g., activates the DEBUG log level:

logging.level.com.os.services: DEBUG

The target service has to be refreshed or restarted in order to activate the new logging configuration.

Endpoints '//manage/loggers/*'

The logger management endpoints are accessible only for users with specific authorization as defined in the authentication-prod.yml file and controlled by the authentication service.

  • Retrieving Information on Loggers

    It is possible to retrieve an overview of all loggers that are defined for a specific service via the GET endpoint http://<ip>:<port>/manage/loggers. For each logger, the current log level is displayed as shown in the example response body.

    Example response body
    {
        "levels": [
            "OFF",
            "ERROR",
            "WARN",
            "INFO",
            "DEBUG",
            "TRACE"
        ],
        "loggers": {
            "ROOT": {
                "configuredLevel": "WARN",
                "effectiveLevel": "WARN"
            },
            "application": {
                "configuredLevel": "WARN",
                "effectiveLevel": "WARN"
            },
            "auditEntryAggregator": {
                "configuredLevel": null,
                "effectiveLevel": "WARN"
            }
        }
    }
  • Updating Log Levels

    In order to set a log level at runtime, it can be specified in JSON format as shown in the example below and sent as request body to the POST endpoint http://<ip>:<port>/manage/loggers/<packageName>.

    Example request body
    {"configuredLevel":"DEBUG"}

    The change applies immediately to the service instance running on the target port. After a restart of this service, the log level is reset to the value configured in a configuration file as described before.

2.11. API

The API gateway is the core service that provides all public REST endpoints of yuuvis® Momentum core.

2.11.1. DMS Endpoints

Manage DMS objects in yuuvis® Momentum or retrieve structural information for the tenant that are relevant for all its users.

In the default configuration, any logged-in user has access to the endpoints. However, the creation, retrieval, update and deletion of DMS objects require corresponding roles.

As of version 2022 Autumn, some processes that lead to an update of the index of the search engine can be called with the query parameter waitForSearchConsistency.

Apps Information
GET /api/dms/apps - Retrieve all applications for the tenant.
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Description

Retrieves all apps available in the tenant the currently logged-in user belongs to.

Response Example
{
  "acl" : { },
  "client" : { },
  "clientsystem" : { },
  "email" : { },
  "invoice" : { },
  "training" : { }
}
Product Information
GET /api/dms/info - Retrieves installed product version.
As of Version

2022 Spring

Request Method

GET

Response Format

JSON

Required Permission

Successful authentication

Description

Retrieves information on the installed product version.

Request Example

/api/dms/info

Response Example
{
  {
    {
      "info": {
        "productLine": "yuuvis Momentum",
        "systemVersion": "yuuvis Momentum - 2021 Winter",
        "dmsVersion": "4.10.0-SNAPSHOT"
      }
    }
  }
}
Basic CRUD Operations
POST /api/dms/objects - Store one or more new DMS objects
As of Version

1.0

Request Method

POST

Response Format

JSON

Required Permission

action create

Description

To import one or more DMS objects send the request with metadata and content as multipart request body. The response is a JSON structure containing the metadata of all objects created.

Available content stream properties are listed here.

If even one object could not be imported, the whole request fails.

As of 2022 Autumn, the optional query parameter waitForSearchConsistency can be added to the request URL. If not specified, the default value false is used.

Request Header

Content-Type: multipart/form-data

Request Example

The request example represents the complete multipart for the import of an e-mail. In addition to the metadata and the e-mail content, a text rendition is also imported.

POST /api/dms/objects HTTP/1.1
Accept: application/json, application/*+json
Content-Type: multipart/form-data;boundary=Jn3QCX9rHAFQaofW6vsdoz5CsD5_P0PZhH
User-Agent: Java/1.8.0_60
Connection: keep-alive
Content-Length: 83258
Host: 127.0.0.1:7400

--Jn3QCX9rHAFQaofW6vsdoz5CsD5_P0PZhH
Content-Disposition: form-data; name="data"
Content-Type: application/json;charset=UTF-8

{
  "objects": [{
      "properties": {
          "system:objectTypeId": {
             "value": "appEmail:email"
          },
          "from": {
             "value": "Garco Meissler <garco@example.de>"
          },
          "to": {
             "value": "Dudreas Annkel <dudreas@example.de>"
          },
          "cc": {
             "value": "Kruedeas Anger <kruedeas@example.de>"
          },
          "subject": {
             "value": "Bewerbungsunterlagen"
          }
      },
      "contentStreams": [{
          "mimeType": "message/rfc822",
          "fileName": "upload.eml",
          "cid": "cid_63apple"
      }],

        "renditions": [{
            "mimeType": "text/plain",
            "kind": "text",
            "contentStream": {
                "length": 39939,
                "mimeType": "text/plain",
                "fileName": "content.txt",
                "cid": "rendition_0"
            }
        }],

        "options": {

            "synchronousContentAnalysis": true

        }

    }]
}

--Jn3QCX9rHAFQaofW6vsdoz5CsD5_P0PZhH
Content-Disposition: form-data; name="cid_63apple"; filename="upload.eml"
Content-ID: cid_63apple
Content-Type: message/rfc822

From: Garco Meissler <garco@example.de>
To: Dudreas Annkel <dudreas@example.de>
Cc: Kruedeas Anger <kruedeas@example.de>
Message-ID: <12716821.1.1500391295036.JavaMail.meissler@APGMEISSLER>
Subject: =?UTF-8?Q?Bewerbungsunterlagen?=
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_Part_0_16468615.1500391295024"

------=_Part_0_16468615.1500391295024
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy ei=
rmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam volu=
ptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita k=
asd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lore=
...
en, no sea takimata sanctus est Lore
------=_Part_0_16468615.1500391295024--

--Jn3QCX9rHAFQaofW6vsdoz5CsD5_P0PZhH
Content-Disposition: form-data; name="rendition_0"; filename="content.txt"
Content-ID: rendition_0
Content-Type: text/plain
Content-Length: 39939

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua...

--Jn3QCX9rHAFQaofW6vsdoz5CsD5_P0PZhH

data

The metadata is passed in JSON format in the data part of the multipart request body.

cid_63apple

The e-mail content is referenced by a content ID ("cid": "cid_63apple") in the contentStreams part of the metadata.

This content ID appears again in the multipart request body below and represents the e-mail content.

rendition_0

The text rendition is represented by a contentStream object in the renditions part of the metadata.

This contentStream object references to a content part of the multipart request body with Content-ID: rendition_0.

options

Optional arguments for steering the processing engine dynamically.

  • synchronousContentAnalysis: true|false (default value: true) Skip synchronous processing of the content (no full-text extraction) in the content analyzer service.

    to disable the content analyzer service in general, use the "skip":"true" parameter in the JSON configuration file (Git for configuration, …​/system/serviceConfiguration.json) for the "contentanalyzer" service.
Result Example

The result is a JSON structure containing the metadata of the e-mail object created.

{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "appEmail:email"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:versionNumber": {
                "value": 1
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "97a35859dbb4c435"
            },
            "appEmail:from": {
                "value": "Garco Meissler <garco@example.de>"
            },
            "appEmail:to": {
                "value": ["Dudreas Annkel <dudreas@example.de>"]
            },
            "appEmail:cc": {
                "value": ["Kruedeas Anger <kruedeas@example.de>"]
            },
            "appEmail:subject": {
                "value": "Bewerbungsunterlagen"
            }
        },
        "contentStreams": [{
             "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
             "length": 173413,
             "mimeType": "message/rfc822",
             "fileName": "upload.eml",
             "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
             "repositoryId": "repo252"
        }]
    }]
}
PATCH /api/dms/objects - Patch-update metadata of multiple objects by ID
As of Version

2021 Autumn

Request Method

PATCH

Response Format

JSON

Required Permission

action write and read

Request Header

Content-Type: application/json

Description

Updates metadata in multiple objects specified by ID in the JSON request body.

Each objectId must not be referenced more than once per request body. And each entry in the objects list must contain the system:objectId property with a valid ID.

The number of objects that can be updated via this endpoint is limited to 100.

Changes only those properties that are part of the request body. Properties that are missing in the request body are not changed by the update. A property value can be removed by sending null as the new value.

Most system properties cannot be updated by users. They are updated automatically by the repository if necessary. If the request metadata contains these system properties, their values must match the values of the current version.

For example, you could add the system:versionNumber system property with the value of the current version to the request metadata. Usually, the update attempt will be successful. However, if another update has changed the object in the meantime, which means that the system:versionNumber has been increased, your update attempt will fail.

Up to 2023 Autumn: Even if only one object could not be updated, the entire request fails.

As of 2023 Winter, the optional boolean query parameter greedy is available. It allows to continue the request to update as many objects as possible (find details below). The result has always the HTTP status code 207 and a JSON response body containing all requested objects. The options section of each individual object contains system:response, which documents the success/failure via httpStatusCode, serviceErrorCode (if available) and message. Additionally, for the successfully updated objects, the full set of metadata is provided.

Optional query parameters:

Parameter Type Description

waitForSearchConsistency

boolean

As of 2022 Autumn. Find a detailed description here. If not specified, the default value true is used.

greedy

boolean

As of 2023 Winter. Allows to continue the request to update as many objects as possible.

  • If greedy is false (default), the entire request fails if at least one object could not be updated.

  • If greedy is true, the request is executed on all listed objects on which the update is possible.

Request Example

Consider the request body below with (A) greedy=false and (B) greedy=true

{
    "objects": [{
            "properties": {
                "system:objectId": {
                    "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
                },
                "appEmail:subject": {
                    "value": "new subject"
                }
            },
            "properties": {
                "system:objectId": {
                    "value": "invalid"
                },
                "appEmail:subject": {
                    "value": "new subject"
                }
            }
        }
    ]
}
Response Example

In the example response body above, one object is invalid. Thus, the result depends on the value of the greedy query parameter.

(A) Response for greedy=false:

{
    "objects": [{
            "properties": {
                "system:objectId": {
                    "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
                },
                "appEmail:subject": {
                    "value": "new subject"
                }
            },
            "options": {
                "system:response": {
                    "httpStatusCode": 422,
                    "serviceErrorCode": 0,
                    "message": "Not updated. Process stopped due to conflicts with other objects in the batch."
                }
            }
        }, {
            "properties": {
                "system:objectId": {
                    "value": "invalid"
                },
                "appEmail:subject": {
                    "value": "new subject"
                }
            },
            "options": {
                "system:response": {
                    "httpStatusCode": 404,
                    "serviceErrorCode": 2811,
                    "message": "Object not found. Objectid: invalid"
                }
            }
        }
    ]
}

(B) Response body for greedy=true:

{
    "objects": [{
            "properties": {
                "system:objectId": {
                    "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:objectTypeId": {
                    "value": "appEmail:email"
                },
                "system:createdBy": {
                    "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
                },
                "system:creationDate": {
                    "value": "2018-01-26T15:21:170Z"
                },
                "system:lastModifiedBy": {
                    "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
                },
                "system:lastModificationDate": {
                    "value": "2018-01-30T11:53:227Z"
                },
                "system:versionNumber": {
                    "value": 3
                },
                "system:tenant": {
                    "value": "tenant1"
                },
                "system:traceId": {
                    "value": "97a35859dbb4c435"
                },
                "appEmail:subject": {
                    "value": "new subject"
                }
            },
            "contentStreams": [{
                    "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
                    "length": 173413,
                    "mimeType": "message/rfc822",
                    "fileName": "upload.eml",
                    "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
                    "repositoryId": "repo252"
                }
            ],
            "options": {
                "system:response": {
                    "httpStatusCode": 200,
                    "message": "Object updated."
                }
            }
        }, {
            "properties": {
                "system:objectId": {
                    "value": "invalid"
                },
                "appEmail:subject": {
                    "value": "new subject"
                }
            },
            "options": {
                "system:response": {
                    "httpStatusCode": 404,
                    "serviceErrorCode": 2811,
                    "message": "Object not found. Objectid: invalid"
                }
            }
        }
    ]
}

Further examples for system:response:

Example 1: successfully processed sub-request
"system:response": {
    "httpStatusCode": 200,
    "message": "Object updated."
}
Example 2: failed sub-request
"system:response": {
    "httpStatusCode": 404,
    "serviceErrorCode": 2811,
    "message": "Object not found. Objectid: invalidId"
}
Example 3: failed sub-request
"system:response": {
    "httpStatusCode": 403,
    "serviceErrorCode": 2810,
    "message": "Insufficient permissions to perform a 'WRITE' action. IDs: cdc7095f-a5ce-486d-92a7-6d0955d969ee"
}
Example 4: failed sub-request
"system:response": {
    "httpStatusCode": 422,
    "serviceErrorCode": 2607,
    "message": "Illegal property. An object of type 'appEmail:email' cannot have a property named 'syfdstem:rmExpirationDate'."
}
Example 5: failed sub-request ('greedy=false')
"system:response": {
    "httpStatusCode": 422,
    "serviceErrorCode": 0,
    "message": "Not updated. Process stopped due to conflicts with other objects in the batch."
}
Deprecated Response Example

Deprecated as of 2023 Winter.

{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "appEmail:email"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2021-03-12T11:53:227Z"
            },
            "system:versionNumber": {
                "value": 3
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "97a35859dbb4c435"
            },
            "appEmail:from": {
                "value": "Garco Meissler <garco@example.de>"
            },
            "appEmail:to": {
                "value": ["Dudreas Annkel <dudreas@example.de>"]
            },
            "appEmail:subject": {
                "value": "again updated Bewerbungsunterlagen"
            }
        },
        "contentStreams": [{
            "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
            "length": 173413,
            "mimeType": "message/rfc822",
            "fileName": "upload.eml",
            "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
            "repositoryId": "repo252"
        }]
    },
    {
        "properties": {
            "system:objectId": {
                "value": "cdc7106f-a5ce-597d-92a7-1d1166d171ee"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "tenTenant1:personalfile"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2021-01-26T15:21:130Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2021-03-12T11:53:227Z"
            },
            "system:versionNumber": {
                "value": 5
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "08a46960dbb5c546"
            },
            "tenTenant1:department": {
                "value": "dev"
            },
            "tenTenant1:team": {
                "value": "frontend"
            },
            "tenTenant1:recruitment": {
                "value": "2021-02-01T08:00:000Z"
            }
        }
    }]
}
DELETE /api/dms/objects - Delete multiple objects by ID
As of Version

2021 Winter

Request Method

DELETE

Response Format

JSON

Required Permission

action delete and read

Request Header

Content-Type: application/json

Description

Deletes multiple objects specified by ID in the JSON request body.

The number of objects that can be deleted simultaneously via this endpoint is limited to 100.

If other properties beside system:objectId are specified in the request body, they are ignored. Especially, the result list of a search response can thus directly be sent as request body to delete all included objects.

The individual deletion sub-processes follow the procedure described for the DELETE /api/dms/objects/{objectId} endpoint.

As of 2023 Summer, the optional query parameter waitForSearchConsistency can be added to the request URL. If not specified, the default value true is used.

As of version 2023 Spring, the optional boolean query parameter greedy (default false) is available.

  • If greedy=false, the entire request fails as soon as one of the referenced objects cannot be found or cannot be deleted.

  • If greedy=true, the deletion process is continued by deleting as many referenced objects as possible. __

A proper response of the endpoint is structured as follows:

  • The HTTP status code is always 207.

  • The JSON response body contains the DMS objects (completed as far as possible) that were referenced by objectId in the request body.

  • Each DMS object has an options section containing the system:deletionResult with httpStatusCode, serviceErrorCode and message for the individual deletion process as displayed in the example response below.

  • Meaning of the individual values for httpStatusCode:

    • 200 OK - The object was deleted.

    • 403 Forbidden - Insufficient permissions for the object.

    • 404 Not Found - The object ID was not found.

    • 409 Conflict - The deletion is not allowed as it is against the rules (e.g., non-empty folder or document under retention).

    • 422 Unprocessable Entity - Other objects within the request could not be deleted and greedy=false.

Request Example

/api/dms/objects?greedy=false

The object IDs of the objects to be deleted are passed in the request body in JSON format.

{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            }
        }
    },
    {
        "properties": {
            "system:objectId": {
                "value": "903f2ae8-2cfc-476c-8386-55c6811e41da"
            }
        }
    },
    {
        "properties": {
            "system:objectId": {
                "value": "invalid"
            }
        }
    },
    {
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            }
        }
    }]
}
Response Example

HTTP status code 207

As greedy=false was set, the last object was not deleted because other objects within the request could not be deleted.

{
    "objects": [
        {
            "properties": {
                "system:objectId": {
                    "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
                },
                "system:traceId": {
                    "value": "1234567887654321"
                },
                "system:objectTypeId": {
                    "value": "appFolder:akte4"
                },
                "system:lastModificationDate": {
                    "value": "2023-02-14T14:53:11.690Z"
                },
                "system:versionNumber": {
                    "value": 1
                },
                "appFolder:title": {
                    "value": "folderwithcontent"
                },
                "system:baseTypeId": {
                    "value": "system:folder"
                },
                "system:tenant": {
                    "value": "tenant1"
                },
                "system:createdBy": {
                    "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
                },
                "system:creationDate": {
                    "value": "2023-02-14T14:53:11.690Z"
                },
                "system:lastModifiedBy": {
                    "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
                }
            },
            "options": {
                "system:deletionResult": {
                    "httpStatusCode": 409,
                    "serviceErrorCode": 2800,
                    "message": "A non-empty folder cannot be deleted."
                }
            }
        },
        {
            "properties": {
                "system:objectId": {
                    "value": "903f2ae8-2cfc-476c-8386-55c6811e41da"
                },
                "system:traceId": {
                    "value": "1234567887654321"
                },
                "system:objectTypeId": {
                    "value": "appFolder:akte4"
                },
                "system:lastModificationDate": {
                    "value": "2023-02-14T14:53:11.690Z"
                },
                "system:versionNumber": {
                    "value": 1
                },
                "appFolder:title": {
                    "value": "undeletable"
                },
                "system:baseTypeId": {
                    "value": "system:folder"
                },
                "system:tenant": {
                    "value": "tenant1"
                },
                "system:createdBy": {
                    "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
                },
                "system:creationDate": {
                    "value": "2023-02-14T14:53:11.690Z"
                },
                "system:lastModifiedBy": {
                    "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
                }
            },
            "options": {
                "system:deletionResult": {
                    "httpStatusCode": 403,
                    "serviceErrorCode": 2810,
                    "message": "Insufficient permissions to perform an 'DELETE' action. IDs: 7b7616c0-c03d-47ee-9664-4b6d9e5ca8a1"
                }
            }
        },
        {
            "properties": {
                "system:objectId": {
                    "value": "invalidId"
                }
            },
            "options": {
                "system:deletionResult": {
                    "httpStatusCode": 404,
                    "serviceErrorCode": 2811,
                    "message": "Object not found. Objectid: invalidId"
                }
            }
        },
        {
            "properties": {
                "system:objectId": {
                    "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
                },
                "system:traceId": {
                    "value": "1234567887654321"
                },
                "system:objectTypeId": {
                    "value": "appFolder:akte4"
                },
                "system:lastModificationDate": {
                    "value": "2023-02-14T14:53:11.690Z"
                },
                "system:versionNumber": {
                    "value": 1
                },
                "appFolder:title": {
                    "value": "deletablefolder"
                },
                "system:baseTypeId": {
                    "value": "system:folder"
                },
                "system:tenant": {
                    "value": "tenant1"
                },
                "system:createdBy": {
                    "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
                },
                "system:creationDate": {
                    "value": "2023-02-14T14:53:11.690Z"
                },
                "system:lastModifiedBy": {
                    "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
                }
            },
            "options": {
                "system:deletionResult": {
                    "httpStatusCode": 422,
                    "serviceErrorCode": 0,
                    "message": "Not deleted. Process stopped due to conflicts with other objects in the batch."
                }
            }
        }
    ]
}
POST /api/dms/objects/search - Search for objects by search query
As of Version

1.0

Request Method

POST

Response Format

JSON

Required Permission

action read

Description

To query DMS objects, send the request with the search query as request body.

The search query is passed in the request body in JSON format. The query language based on CMIS serves to standardize DMS requests to the yuuvis® API system.

Each search request for DMS objects always returns an array of DMS objects called objects, even if the result set is only a single object. I.e,. if a single object is requested, the result is a single-element array, given the object exists. Otherwise, the result is an empty array. The result contains only objects that are visible with a read permission.

If not otherwise specified in the query statement, the result list is ordered by the system:creationDate object property.

The parameter maxItems defines the maximum number of entries in the hit list, while skipCount defines the number of entries to be skipped in the beginning of the result list. This allows for a client-side implementation of paging.

Request Header

Content-Type: application/json

Request Example

The search query is passed in the request body in JSON format

{
    "query": {
        "statement": "SELECT * FROM system:object",
        "skipCount": 0,
        "maxItems": 50
    }
}
Response Example
{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "appEmail:email"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:versionNumber": {
                "value": 1
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "97a35859dbb4c435"
            },
            "appEmail:from": {
                "value": "Garco Meissler <garco@example.de>"
            },
            "appEmail:to": {
                "value": ["Dudreas Annkel <dudreas@example.de>"]
            },
            "appEmail:cc": {
                "value": ["Kruedeas Anger <kruedeas@example.de>"]
            },
            "appEmail:subject": {
                "value": "Bewerbungsunterlagen"
            }
        },
        "contentStreams": [{
            "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
            "length": 173413,
            "mimeType": "message/rfc822",
            "fileName": "upload.eml",
            "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
            "repositoryId": "repo252"
        }]
    },
    {
        "properties": {
            "system:objectId": {
                "value": "903f2ae8-2cfc-476c-8386-55c6811e41da"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "appEmail:email"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2018-02-02T15:14:09.380Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2018-02-02T15:17:16.670Z"
            },
            "system:versionNumber": {
                "value": 3
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "7603680281439810506"
            },
            "appEmail:from": {
                "value": "Ram Evalow <evalow@example.de>"
            },
            "appEmail:to": {
                "value": ["Dudreas Annkel <dudreas@example.de>"]
            },
            "appEmail:subject": {
                "value": "Der Fischer und seine Seele"
            },
            "appEmail:attachmentcount": {
                "value": 2
            },
            "appEmail:attachmentnames": {
                "value": ["Der_Fischer_und_seine_Seele.pdf",
                "blackhair_nixe.jpg"]
            }
        },
        "contentStreams": [{
            "contentStreamId": "B3172D83-BDB5-11E8-B133-074F092B56CB",
            "length": 431397,
            "mimeType": "message/rfc822",
            "fileName": "upload.eml",
            "digest": "11857B6FAD61E41AFB3E7398BA1BA4BFB6B0A5422762FF41A0907BC0BFF7748F",
            "repositoryId": "repo252"
        }]
    }],
    "numItems": 2,
    "hasMoreItems": false,
    "totalNumItems": 2
}
Property Description

objects

array of DMS objects

properties

metadata fields, basic parameters and system fields of an object

GET /api/dms/objects/{objectId} - Retrieve object metadata by ID
As of Version

1.0

Request Method

GET

Response Format

JSON

Required Permission

action read

Description

To retrieve the metadata of a DMS object, send the request with the ID of the DMS object as objectId.

Exclusively for this endpoint, you can use the includePermissions query parameter to define, whether the information on permissions is part of the result (true) or not (false). Default value is false.

As of 2022 Summer, retentions are considered for the display of the available permissions. Thus, if the requested object is under retention, the delete permission is not available and the write permission can only be made available for metadata.

Request Example

Example (A)

/api/dms/objects/cdc7095f-a5ce-486d-92a7-6d0955d969ee

Example (B)

/api/dms/objects/cdc7095f-a5ce-486d-92a7-6d0955d969ff?includePermissions=true

Result Example

Example (A)

{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "appEmail:email"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:versionNumber": {
                "value": 1
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "97a35859dbb4c435"
            },
            "appEmail:from": {
                "value": "Garco Meissler <garco@example.de>"
            },
            "appEmail:to": {
                "value": ["Dudreas Annkel <dudreas@example.de>"]
            },
            "appEmail:cc": {
                "value": ["Kruedeas Anger <kruedeas@example.de>"]
            },
            "appEmail:subject": {
                "value": "Bewerbungsunterlagen"
            }
        },
        "contentStreams": [{
            "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
            "length": 173413,
            "mimeType": "message/rfc822",
            "fileName": "upload.eml",
            "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
            "repositoryId": "repo252"
        }]
    }]
}

Example(B)

{
    "objects": [
        {
            "properties": {
                "system:traceId": {
                    "value": "97a35859dbb4c436"
                },
                "system:objectTypeId": {
                    "value": "appMyapp:mydocumenttype"
                },
                "system:secondaryObjectTypeIds": {
                    "value": [
                        "system:rmDestructionRetention"
                    ]
                },
                "appMyapp:name": {
                    "value": "testdocument"
                },
                "system:versionNumber": {
                    "value": 1
                },
                "system:createdBy": {
                    "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
                },
                "system:rmExpirationDate": {
                    "value": "2042-03-16T17:44:54.410Z"
                },
                "system:creationDate": {
                    "value": "2022-03-16T13:03:52.720Z"
                },
                "system:lastModificationDate": {
                    "value": "2022-03-16T13:03:52.720Z"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:tenant": {
                    "value": "tenant1"
                },
                "system:lastModifiedBy": {
                    "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
                },
                "system:objectId": {
                    "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ff"
                }
            },
            "contentStreams": [
                {
                    "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A8",
                    "archivePath": "default/DOCUMENT/00/A9/9/",
                    "length": 23,
                    "mimeType": "text/plain",
                    "fileName": "myfilename.txt",
                    "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B856",
                    "repositoryId": "repo252es"
                }
            ],
            "permissions": {
                "read": [
                    "metadata",
                    "content"
                ],
                "create": [
                    "metadata",
                    "content"
                ],
                "write": [
                    "metadata"
                ]
            }
        }
    ]
}
POST /api/dms/objects/{objectId} - Update object metadata by ID
As of Version

1.0

Request Method

POST

Response Format

JSON

Required Permission

action write and read

Request Header

Content-Type: application/json

Description

To update the metadata of a DMS object, send the request with the new metadata as request body and the ID of the DMS object as objectId.

If a property is missing in the new metadata, it will be removed from the object. An expection are system properties. Most system properties cannot be updated by users. They are updated automatically by the repository if necessary. If the new metadata contains these system properties, their values must match the values of the current version. This can be used to ensure object consistency in case of overlapping update requests.

As of 2022 Autumn, the optional query parameter waitForSearchConsistency can be added to the request URL. If not specified, the default value true is used.

To update individual properties, retrieve the current metadata using the GET /api/dms/objects/{objectId} endpoint. In the result, edit only those properties that need to be updated and then post the entire result using this endpoint. Due to the mentioned special behavior of some system properties this update attempt will fail, if another update on this object has happened in the meantime. In this case, at least the property system:versionNumber of the current version would have changed and does not match the system:versionNumber of the request metadata anymore.

Request Example

The new metadata is passed in the request body in JSON format.

{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "appEmail:email"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:versionNumber": {
                "value": 1
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "97a35859dbb4c435"
            },
            "appEmail:from": {
                "value": "Garco Meissler <garco@example.de>"
            },
            "appEmail:to": {
                "value": ["Dudreas Annkel <dudreas@example.de>"]
            },
            "appEmail:cc": {
                "value": ["Kruedeas Anger <kruedeas@example.de>",
                "Vils Normum <Normum@example.de>"]
            },
            "appEmail:subject": {
                "value": "Updated Bewerbungsunterlagen"
            },
            "table": {
                "columnNames": ["iColumn1", "iColumn2", "iColumn3"],
                "value": [["something", "to know", true],["more", "infos", false]]
            }
        },
        "contentStreams": [{
            "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
            "length": 173413,
            "mimeType": "message/rfc822",
            "fileName": "upload.eml",
            "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
            "repositoryId": "repo252"
        }]
    }]
}
Response Example

The result is a JSON structure containing the updated metadata of the object identified by objectId.

{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "appEmail:email"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2018-01-29T13:13:113Z"
            },
            "system:versionNumber": {
                "value": 2
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "97a35859dbb4c435"
            },
            "appEmail:from": {
                "value": "Garco Meissler <garco@example.de>"
            },
            "appEmail:to": {
                "value": ["Dudreas Annkel <dudreas@example.de>"]
            },
            "appEmail:cc": {
                "value": ["Kruedeas Anger <kruedeas@example.de>",
                "Vils Normum <Normum@example.de>"]
            },
            "appEmail:subject": {
                "value": "Updated Bewerbungsunterlagen"
            },
            "table": {
                "columnNames": ["iColumn1", "iColumn2", "iColumn3"],
                "value": [["something", "to know", true],["more", "infos", false]]
            }
        },
        "contentStreams": [{
            "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
            "length": 173413,
            "mimeType": "message/rfc822",
            "fileName": "upload.eml",
            "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
            "repositoryId": "repo252"
        }]
    }]
}
POST /api/dms/objects/{objectId} - Multipart Endpoint: Update metadata and content.
As of Version

2024 Spring

Request Method

POST

Response Format

JSON

Required Permission

action write and read

Description

Updates metadata and content of an existing DMS object. The request contains the new metadata and content as multipart request body. The response is a JSON structure containing the metadata of the updated object.

Available content stream properties are listed here.

If the request is successfully processed (metadata and content are replaced), a new audit entry 302 (OBJECT_METADATA_DOCUMENT_CHANGED) is created.

The binary content remains unchanged in the following cases. Consequently, an audit entry 300 is created:

  • Only metadata are specified in the multipart request and the contentStreams section is missing.

  • The contentStreams section exists and contains only values that equal the previous object version, but does not contain a cid.

Tags without the resistant suffix are removed from the object. However, it is possible to reassign them with new state and/or traceId if specified in the metadata section.

Request Header

Content-Type: multipart/form-data

Request Example

See multipart for object import.

Result Example

See multipart for object import.

PATCH /api/dms/objects/{objectId} - Patch-Update object metadata by ID
As of Version

2019 Winter

Request Method

PATCH

Response Format

JSON

Required Permission

action write and read

Request Header

Content-Type: application/json

Description

To update the metadata of a DMS object, send the request with the new metadata as request body and the ID of the DMS object as objectId.

Changes only those properties that are part of the request body. Properties that are missing in the request body are not changed by the update. A property value can be removed by sending null as the new value.

Most system properties cannot be updated by users. They are updated automatically by the repository if necessary. If the request metadata contains these system properties, their values must match the values of the current version.

For example, you could add the system property system:versionNumber with the value of the current version to the request metadata. Usually, the update attempt will be successful. However, if another update has changed the object in the meantime, which means that the system:versionNumber has been increased, your update attempt will fail.

As of 2022 Autumn, the optional query parameter waitForSearchConsistency can be added to the request URL. If not specified, the default value true is used.

Request Example

The new metadata is passed in the request body in JSON format.

{
    "objects": [{
        "properties": {
            "appEmail:subject": {
                "value": "again updated Bewerbungsunterlagen"
            },
            "appEmail:cc": {
                "value": null
            }
        }
    }]
}
Result Example

The result is a JSON structure containing the updated metadata of the object identified by objectId.

{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "appEmail:email"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2018-01-30T11:53:227Z"
            },
            "system:versionNumber": {
                "value": 3
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "97a35859dbb4c435"
            },
            "appEmail:from": {
                "value": "Garco Meissler <garco@example.de>"
            },
            "appEmail:to": {
                "value": ["Dudreas Annkel <dudreas@example.de>"]
            },
            "appEmail:subject": {
                "value": "again updated Bewerbungsunterlagen"
            }
        },
        "contentStreams": [{
            "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
            "length": 173413,
            "mimeType": "message/rfc822",
            "fileName": "upload.eml",
            "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
            "repositoryId": "repo252"
        }]
    }]
}
DELETE /api/dms/objects/{objectId} - Delete object by ID
As of Version

1.0

Request Method

DELETE

Response Format

HTTP status code

Required Permission

action delete and read

Description

Deletes the object specified by objectId.

All old versions of the object are deleted as well.

The assigned binary content files are only deleted from the repository if no other object or object version refers to them.

In the audit trail, the entries 202 and 200 are created. All previous audit entries for the deleted object remain in the database and can still be retrieved via search.

A folder object can only be deleted if it has no child objects, means if there are no objects retrievable via yuuvis® Momentum API that have the specified objectId as value for the system:parentId property.

Meaning of the response status codes:

HTTP status code Meaning

200 OK

The DMS object with the ID objectId has been deleted

403 Forbidden

Insufficient permissions to perform a delete action.

404 Not Found

The DMS object with the ID objectId can not be found.

409 Conflict

The DMS object with the ID objectId could not be deleted due to retention.

Request Example

/api/dms/objects/903f2ae8-2cfc-476c-8386-55c6811e41da

Response Example

no response body

GET /api/dms/objects/{objectId}/contents/file - Retrieve document content by ID
As of Version

1.0

Request Method

GET

Response Format

binary data

Required Permission

action read

Description

To get the content file related to a DMS object, send the request with the ID of the DMS object as objectId.

Request Example

/api/dms/objects/903f2ae8-2cfc-476c-8386-55c6811e41da/contents/file

POST /api/dms/objects/{objectId}/contents/file - Update document content by ID
As of Version

1.0

Request Method

POST

Response Format

JSON

Required Permission

action write and read

Description

To update the content file of a DMS object, send the request with the new content file as binary in the request body and the ID of the DMS object as objectId.

A new object version will be created. The corresponding Content Stream Properties are automatically updated.

The new binary content file is stored in the repository specified in the X-OS-REPOSITORY-ID request header. If the header is missing, the default repository is used that is configured in the application-storage.yml configuration file.

If tags are assigned to the object, they will be reassigned to the new object version only if they are specified as resistant tags.

As of 2022 Autumn, the optional query parameter waitForSearchConsistency can be added to the request URL. If not specified, the default value true is used.

Request Header

Content-Type: application/octet-stream. Any content-type is accepted.

Content-Disposition: attachment; filename=<filename>; filename*=<filename-encoded>. To set the filename of the new content file. The parameters "filename" and "filename*" differ only in that "filename*" uses the encoding defined in RFC 5987. When both "filename" and "filename*" are present in a single header field value, "filename*" is preferred over "filename".

Request Example

The new content file is passed as binary in the request body.

Response Example

The result is a JSON structure containing the updated metadata of the object identified by objectId.

{
    "objects": [
        {
            "properties": {
                "system:objectId": {
                    "value": "6200fcc9-d6b4-43c0-82e7-ac1ed2fa8350"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:objectTypeId": {
                    "value": "document"
                },
                "system:secondaryObjectTypeIds": {
                    "value": [
                        "system:rmDestructionRetention"
                    ]
                },
                "system:createdBy": {
                    "value": "root"
                },
                "system:creationDate": {
                    "value": "2018-09-10T14:35:36.657Z"
                },
                "system:lastModifiedBy": {
                    "value": "root"
                },
                "system:lastModificationDate": {
                    "value": "2018-09-10T15:03:17.099Z"
                },
                "system:versionNumber": {
                    "value": 3
                },
                "system:tenant": {
                    "value": "default"
                },
                "system:traceId": {
                    "value": "-7589750308987031207"
                },
                "system:contentStreamLength": {
                    "value": 3726
                },
                "enaio:contentStreamMimeType": {
                    "value": "message/rfc822"
                },
                "system:contentStreamFileName": {
                    "value": "upload.bin"
                },
                "system:contentStreamId": {
                    "value": "A5CC29D5-B50A-11E8-882D-F90E0E895BD7"
                },
                "system:contentStreamRepositoryId": {
                    "value": "repo242"
                },
                "system:digest": {
                    "value": "4163C826122B64A199D270998C11176F7B8CF3FD71CD4B7C234448740F360CF0"
                },
                "Name": {
                    "value": "Menschenskinder"
                }
            },
            "contentStreams": [
                {
                    "length": 3726,
                    "mimeType": "message/rfc822",
                    "fileName": "upload.bin",
                    "digest": "4163C826122B64A199D270998C11176F7B8CF3FD71CD4B7C234448740F360CF0",
                    "contentStreamId": "A5CC29D5-B50A-11E8-882D-F90E0E895BD7",
                    "repositoryId": "repo242"
                }
            ],
            "renditions": [
                {
                    "mimeType": "text/plain",
                    "kind": "text",
                    "contentStream": {
                        "length": 445,
                        "mimeType": "text/plain",
                        "fileName": "content.txt"
                    }
                }
            ]
        }
    ]
}
DELETE /api/dms/objects/{objectId}/contents/file - Delete a document content by ID
As of Version

2023 Summer

Request Method

DELETE

Response Format

JSON

Required Permission

action write and read

The process is internally handled like a content update and therefore does NOT require a delete permission.
Description

Removes the binary content file from the DMS object specified by objectId.

A new object version without the contentStreams properties section will be created. For the previous version(s), the corresponding binary content file remains. To the object’s audit trail, an entry with action 201 and detail OBJECT_CONTENT_DELETED will be added.

In addition to the above mentioned permissions, the DMS object has to match following requirements:

  • The object is NOT under retention.

  • The object has a binary content file.

  • Neither the object type of the object nor one of the assigned secondary object types requires a binary content file.

As the process is internally handled like a content update, the corresponding webhook entry points are passed.

The result is a JSON structure containing the updated metadata of the object identified by objectId.

Request Example

DELETE /api/dms/objects/6200fcc9-d6b4-43c0-82e7-ac1ed2fa8350/contents/file

Response Example
Response Body
{
    "objects": [
        {
            "properties": {
                "system:objectId": {
                    "value": "6200fcc9-d6b4-43c0-82e7-ac1ed2fa8350"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:objectTypeId": {
                    "value": "document"
                },
                "system:secondaryObjectTypeIds": {
                    "value": [
                        "system:rmDestructionRetention"
                    ]
                },
                "system:createdBy": {
                    "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
                },
                "system:creationDate": {
                    "value": "2018-09-10T14:35:36.657Z"
                },
                "system:lastModifiedBy": {
                    "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
                },
                "system:lastModificationDate": {
                    "value": "2018-09-10T15:03:17.099Z"
                },
                "system:versionNumber": {
                    "value": 3
                },
                "system:tenant": {
                    "value": "tenant1"
                },
                "system:traceId": {
                    "value": "7589750308987031207"
                },
                "Name": {
                    "value": "Menschenskinder"
                }
            }
        }
    ]
}
GET /api/dms/objects/{objectId}/contents/renditions/text - Retrieve text rendition of content by ID
As of Version

2020 Autumn

Request Method

GET

Response Format

plain text

Required Permission

action read

Description

To return the content file’s full-text rendition of the DMS object, send the request with the ID of the DMS object as objectId.

If no full-text rendition is stored in the Elsticsearch index for the specified object, the request results in error "404 - not found."

If a content file is imported having one of the supported formats and containing readable text, a full-text rendition will be created and stored in the Elasticsearch index. The full-text rendition can be overwritten via POST /api/dms/objects/{objectId}/contents/renditions/text.

A read permission is required (otherwise results in error "404 - not found").

Request Example

/api/dms/objects/903f2ae8-2cfc-476c-8386-55c6811e41da/contents/renditions/text

Result Example
test-test-get-rendition-text
POST /api/dms/objects/{objectId}/contents/renditions/text - Update text rendition by ID
As of Version

2021 Summer

Request Method

POST

Response Format

HTTP status code

Required Permission

action write and read

Request Header

Content-Type: text/plain

Description

Updates the full-text rendition related to a DMS object identified by objectId.

If a content file is imported having one of the text rendition compatible formats and containing readable text, a full-text rendition will be created and stored in the Elasticsearch index.

The endpoint posts the plain text passed in the request body to the text rendition property in the Elasticsearch index replacing the current value if already filled before.

As of 2022 Autumn, the optional query parameter waitForSearchConsistency can be added to the request URL. If not specified, the default value true is used.

As of 2022 Winter, an audit entry with action code 306 is written to the object’s audit trail.

A dbs-reindex Command via Commander Service will undo all text rendition updates.

Meaning of HTTP status codes:

HTTP status code Meaning

200

Successful, text rendition of specified object was updated.

404

Not successful, specified objectId does not exist or user has no write permission.

422

Not successful, text rendition was not updated.

Request Example

/api/dms/objects/100a1bc1-2def-100a-1234-56b789c01de/contents/renditions/text

Request Body
test-test-post-rendition-text
Response Example

200

no response body

GET /api/dms/objects/{objectId}/contents/renditions/pdf - Retrieve PDF rendition of content by ID
As of Version

2020 Winter

Request Method

GET

Response Format

PDF

Required Permission

action read

Description

To return the content file’s PDF rendition of the DMS document object, send the request with the ID of the DMS object as objectId.

If the specified objectId does not exist, the call results in the error 404 - Not Found. Further errors are triggered by referencing an object without a content file or with a not convertible content file.

Please note that the rendition is not an exact representation of the original file. Deviations to the original file may arise and are NOT considered as bugs in our software.

Response Header

Content-Type: application/pdf

Request Example

/api/dms/objects/903f2ae8-2cfc-476c-8386-55c6811e41da/contents/renditions/pdf

Response Example

Response body with PDF document.

GET /api/dms/objects/{objectId}/contents/renditions/slide - Retrieve slide rendition of content by ID
As of Version

2023 Spring

Request Method

GET

Response Format

PNG

Required Permission

action read

Description

Retrieves the slide rendition of the binary content file that is assigned to the DMS object specified by objectId.

A PNG image with 256 px is returned in the response body.

The supported formats of binary content files as well as details on calculation and storage are listed here: Supported Formats

Please note that the rendition is not an exact representation of the original file. Deviations to the original file may arise and are NOT considered as bugs in our software.

Response Header

Content-Type: image/png

Request Example

/api/dms/objects/903f2ae8-2cfc-476c-8386-55c6811e41da/contents/renditions/slide

Response Example

Response body with PNG file.

GET /api/dms/objects/{objectId}/history - Retrieve the audit entries for the specified object.
As of Version

1.0

Request Method

GET

Response Format

JSON

Required Permission

successful authentication

Description

To retrieve the history entries of a DMS object, send the request with the ID of the DMS object as objectId.

Meaning of action field values: Audit Trail

By default, the last 50 entries are returned. You can control the history entries returned by using the following query parameters

Parameter Description

size

defines the number of returned history entries

page

defines on which page the result list of history entries should be started (one page = 50 entries)

For example, to get 50 history entries from 101 to 150 returned use size=50 and page=2.

Request Example

/api/dms/objects/903f2ae8-2cfc-476c-8386-55c6811e41da/history

/api/dms/objects/903f2ae8-2cfc-476c-8386-55c6811e41da/history?size=50&page=2

Response Example
{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": 213518578
            },
            "system:objectTypeId": {
                "value": "system:audit"
            },
            "system:baseTypeId": {
                "value": "item"
             },
            "system:createdBy": {
                "value": "1EF9EB6E7F2F41D69D5408609CFF5FFD"
            },
            "system:tenant": {
                "value": "default"
            },
            "system:creationDate": {
                "value": "2018-05-18T13:25:25.450Z"
            },
            "description": {
                "value": ""
            },
            "action": {
                "value": 401
            },
            "detail": {
                "value": "GET_METADATA"
            },
            "referredObjectId": {
                "value": "df398a31-3ed3-4fe6-a744-a0d0f90b8678"
            },
            "traceid": {
                "value": "0a53668f42b6691a"
            },
            "system:versionNumber": {
                "value": 1
            }
        }
    },
    {
        "properties": {
            "system:objectId": {
                "value": 213509340
            },
            "system:objectTypeId": {
                "value": "system:audit"
            },
            "system:baseTypeId": {
                "value": "item"
            },
            "system:createdBy": {
                "value": "1EF9EB6E7F2F41D69D5408609CFF5FFD"
            },
            "system:tenant": {
                "value": "default"
            },
            "system:creationDate": {
                "value": "2018-05-18T01:45:44.040Z"
            },
            "description": {
                "value": ""
            },
            "action": {
                "value": 101
            },
            "detail": {
                "value": "CREATE_METADATA_WITH_CONTENT"
            },
            "referredObjectId": {
                "value": "df398a31-3ed3-4fe6-a744-a0d0f90b8678"
            },
            "traceid": {
                "value": "43d141cec4ea8a58"
            },
            "system:versionNumber": {
                "value": 1
            }
        }
    }]
}
GET /api/dms/objects/{objectId}/actions/validate/digest - Validate the specified object’s content.
As of Version

1.0

Request Method

GET

Response Format

JSON

Required Permission

action read

Description

To validate the content digest of a DMS object, send the request with the ID of the DMS object as objectId. The content digest is calculated anew and compared with the value generated and stored in the metadata upon import.

Meaning of the response status codes:

HTTP status code Meaning

200 OK

The value of the content digest stored in the metadata is still correct.

404 Not Found

The DMS object with the ID objectId can not be found.

409 Conflict

The calculated content digest does not match the value stored in the metadata.

Request Example

/api/dms/objects/903f2ae8-2cfc-476c-8386-55c6811e41da/actions/validate/digest

POST /api/dms/objects/{objectId}/actions/move/contents/repositories/{repositoryId} - Move the content of an object to a different repository.
As of Version

2019 Winter

Request Method

POST

Response Format

JSON

Required Permission

action write and read

Description

Moves the binary content file assigned to the object specified by objectId to the target repository specified by repositoryId.

The corresponding binary content file is referenced in the contentStreams section of the object via the properties repositoryId and contentStreamId. The binary content file could be referenced in multiple object versions and even in other objects. In case the corresponding binary content file is moved, the repositoryId and contentStreamId properties in the contentStreams section are updated in all those objects and object versions. No new object version will be created.

An audit entry will be created only for the current version of the object specified by objectId in the request URL.

Request Example

POST api/dms/objects/00250915-fb6e-4165-bc05-93a02590f5de/actions/move/contents/repositories/repo252

Response Example

The result is a JSON structure containing the updated metadata of the object identified by objectId.

{
    "objects": [{
        "properties": {
            "system:traceId": {
                "value": "6ff928e56f8f8efe"
            },
            "system:objectTypeId": {
                "value": "document"
            },
            "system:versionNumber": {
                "value": 1
            },
            "Name": {
                "value": "Beat 2014-06.pdf_075.pdf"
            },
            "system:createdBy": {
                "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
            },
            "system:creationDate": {
                "value": "2018-11-30T14:47:40.250Z"
            },
            "system:lastModificationDate": {
                "value": "2018-11-30T14:47:40.250Z"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:tenant": {
                "value": "default"
            },
            "system:lastModifiedBy": {
                "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
            },
            "system:objectId": {
                "value": "00250915-fb6e-4165-bc05-93a02590f5de"
            }
        },
        "contentStreams": [{
            "contentStreamId": "DB886B37-FEEF-11E9-BCEC-3FAD551A2B8A",
            "archivePath": "default/DOCUMENT/B8/86/B/",
            "length": 86171,
            "mimeType": "application/pdf",
            "fileName": "Beat 2014-06.pdf_075.pdf",
            "digest": "2714F996A45F41439F625160167B4DE5BDE604F560FCABF8C242567CDFDC733A",
            "repositoryId": "repo252"
        }]
    }]
}
Tagging Operations
GET /api/dms/objects/{objectId}/tags - Retrieve object tags by ID.
As of Version

2020 Summer

Request Method

GET

Response Format

JSON

Required Permission

action read

Description

To retrieve the tags of a DMS object, send the request with the ID of the DMS object as objectId.

Request Example

/api/dms/objects/insert-objectid-here/tags

Result Example

The result is a JSON structure representing the following table:

name state creationDate traceid

tag1

100

2020-02-20T02:20:20.220Z

1234567887654321

tag2

9876

2019-09-10T09:19:01.109Z

8765432112345678

JSON structure of the response table
{
  "objects": [
    {
      "properties": {
        "system:tags": {
          "value": [
            [
              "tag1",
              100,
              "2020-02-20T02:20:20.220Z",
              "1234567887654321"
            ],
            [
              "tag2",
              9876,
              "2019-09-10T09:19:01.109Z",
              "8765432112345678"
            ]
          ]
        }
      }
    }
  ]
}
POST /api/dms/objects/{objectId}/tags/{name}/state/{state} - Add object tag by ID.
As of Version

2020 Summer

Request Method

POST

Response Format

JSON

Required Permission

action (tag or write) and read

Description

To add a new tag to a DMS object, send the request with the ID of the DMS object as objectId including the info of the tag’s name and state. The method throws an exception, if the committed tag name already exists.

Furthermore, there is the possibility to set a traceid by means of the HTTP header: X-B3-TraceId. If not specified, a random traceid will be set.

Any successful tag creation will be added to the audit trail.

Tags are independent of an object’s version and thus are always available at the current version. For version-specific information, metadata provide the suitable options.

As of 2022 Autumn, the optional query parameter waitForSearchConsistency can be added to the request URL. If not specified, the default value true is used.

Request Example

/api/dms/objects/insert-objectid-here/tags/tag1/state/100

Response Example

The result is a JSON structure containing the value entries of the created tag: name, state, creationDate and traceid.

tag added
{
  "objects": [
    {
      "properties": {
        "system:tags": {
          "value": [
            [
              "tag1",
              100,
              "2020-02-20T02:20:20.220Z",
              "1234567887654321"
            ]
          ]
        }
      }
    }
  ]
}
POST /api/dms/objects/{objectId}/tags/{name}/state/{state}?overwrite=true - Update object tag by ID.
As of Version

2020 Summer

Request Method

POST

Response Format

JSON

Required Permission

action (tag or write) and read

Description

To update the state for an existing tag of a DMS object, send the request with the ID of the DMS object as objectId and the tag’s name together with the new value for the tag’s state. In contrast to adding a tag, the update is characterized by adding the query parameter overwrite=true.

Furthermore, there is the possibility to set a traceid by means of the HTTP header: X-B3-TraceId. If not specified, a random traceid will be set.

The method throws an exception, if the specified tag name does not exist.

In addition to the tag name, by means of the query parameter traceIdMustMatch=true, it is possible to define a second transition condition. The tag is modified only if the traceid indicated in the request matches the current traceid for the specified tag. Example (2) demonstrates the use of this extra feature, that provides the possibility to tune the update permissions for the tag. Only if the traceid is known, the tag can be modified. In this case, the traceid of the updated tag will be the same as before.

Any successful tag update changes the value for the state and the creationDate is set to the current time automatically. The traceid remains the same only if it is specified in the request and the query contains traceIdMustMatch=true parameter.

Any successful tag update will be added to the audit trail.

Tags are independent of an object’s version and thus are always available at the current version. For version-specific information, metadata provide the suitable options.

Request Example
  1. /api/dms/objects/insert-objectid-here/tags/tag1/state/9999?overwrite=true

  2. /api/dms/objects/insert-objectid-here/tags/tag1/state/9999?overwrite=true&traceIdMustMatch=true

    X-B3-TraceId: 1234567887654321

Result Example

The result is a JSON structure containing the current value entries of the updated tag: name, state, creationDate and traceid.

successful tag update
{
  "objects": [
    {
      "properties": {
        "system:tags": {
          "value": [
            [
              "tag1",
              9999,
              "2020-02-20T02:20:20.220Z",
              "1234567887654321"
            ]
          ]
        }
      }
    }
  ]
}
POST /api/dms/objects/tags/{name}/state/{state}?query=<SQL> - Add/update object tag by search query.
As of Version

2020 Summer

Request Method

POST

Response Format

JSON

Required Permission

action (tag or write) and read

Description

Add or update the tag with the name and state specified in the request URL of the first available object matching the query. The JSON response body is an object list containing the updated object as single entry or an empty objects list if no processable object was found to match the query.

Optionally, there is the possibility to set a traceid by means of the HTTP header X-B3-TraceId. In case of a tag update, the previous traceId remains unchanged. If a new tag is added, the traceId specified in the header is used.

If an object was found to match the query and is processable, the following behavior is triggered:

  • If the selected object already has a tag with a name, the current state value is replaced by the new one. Otherwise a tag with a name and state is added.

  • In both cases, update or addition, the tag’s creationDate will be updated.

  • Any successful tag creation or update is added to the audit trail, as well as any retrieval of the metadata.

    Internally, the endpoint retrieves a result list of up to 40 objects matching the specified query. The tag update/addition is applied to the first match. However, if the tag update/addition is not possible, it will be applied to the next result. In case there is no matching object left, an empty list will be returned.

    Objects might be not processable for different reasons, e.g., they could be under processing by another service running in parallel. As the endpoint internally handles those situations, it is easily possible to operate multiple service instances calling this tagging endpoint at the same time. Even if those services sent the exact same request, they would retrieve different objects to which the described tag update/addition was applied.

    Especially other calls of the /api/dms/objects/tags/{name}/state/{state}?query=<SQL> endpoint cannot retrieve or access an object that is currently processed via the same endpoint. An object under such processing is locked during the time of updating the database AND an additional timeout for updating the index of the search engine. This additional timeout can be configured in the API gateway configuration via the tagging-lock-visibility-timeout parameter (integer value in milliseconds, default 4000). It can be set, e.g., via the environment or via a profile configuration like api-prod.yml.

    Tags are independent of an object’s version and thus are always available for the current version. For version-specific information, metadata provide the suitable options.

As of 2022 Autumn, the optional query parameter waitForSearchConsistency can be added to the request URL. If not specified, the default value true is used.

Request Example

POST /api/dms/objects/tags/tag1/state/100?query=SELECT * FROM document WHERE sy\$tag1\$ IS NULL AND system:creationDate=TODAY()

The query searches for objects of type document which were created today and do not have a tag with the name tag1. To the first match, a new tag tag1 will be added with the state 100.

Result Example

The return is a JSON structure containing the information on existing tags and metadata dedicated to the modified object.

{
  "objects": [
    {
      "properties": {
        "system:objectId": {
          "value": "insert-objectid-here"
        },
        "system:tags": {
          "value": [ [ "tag1", 100, "2020-02-20T02:22:20.220Z", "1234567887654321" ] ]
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "document"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "system:rmDestructionRetention"
          ]
        },
        "system:createdBy": {
          "value": "this-id-indicates-the-user"
        },
        "system:creationDate": {
          "value": "2020-02-20T02:02:20.220Z"
        },
        "system:lastModifiedBy": {
          "value": "this-id-indicates-another-user"
        },
        "system:lastModificationDate": {
          "value": "2020-02-20T02:20:22.220Z"
        },
        "system:versionNumber": {
          "value": 1
        },
        "system:tenant": {
          "value": "default"
        },
        "system:traceId": {
          "value": "0000abcdef123456"
        },
        "Name": {
          "value": "Email"
        },
        "date": {
          "value": "2002-02-20T02:20:00.220Z"
        }
      },
      "contentStreams": [
        {
          "contentStreamId": "0B469DD0-AA6F-11EA-A7FE-DD3E0B230EEB",
          "archivePath": "default/DOCUMENT/B4/69/D/",
          "length": 200001,
          "mimeType": "application/pdf",
          "fileName": "exchange-doku-jar.pdf",
          "digest": "334A9337CFEFC4B1D25C9CC0289205B3133DA4CDE8086C6A9D2FF61CC3205F55",
          "repositoryId": "repo252"
        }
      ]
    }
  ]
}
DELETE /api/dms/objects/{objectId}/tags/{name} - Delete object tag by ID.
As of Version

2020 Summer

Request Method

DELETE

Response Format

HTTP status code

Required Permission

action (tag or write) and read

Description

To delete a tag of an object, send the request with the ID of the object as o`bjectid` and the tag name. The HTTP status code 200 OK is returned, if the tag was successfully deleted.

Furthermore, there is the possibility to set a traceid by means of the HTTP header: X-B3-TraceId. The tag is deleted only if the traceid indicated in the request matches the current traceid for the specified tag.

The successful tag deletion will be added to the audit trail.

As of 2022 Autumn, the optional query parameter waitForSearchConsistency can be added to the request URL. If not specified, the default value true is used.

Request Example

DELETE /api/dms/objects/insert-objectid-here/tags/tag1?traceIdMustMatch=true

X-B3-TraceId: 1234567887654321

Result Example

The result is a HTTP status code, if the tag was successfully deleted.

200 OK

Operations for Partial Upload
POST /api/dms/uploads - Initialize an upload.
As of Version

2024 Summer

Request Method

POST

Response Format

JSON

Required Permission

successful authentication

Description

Initializes the import of a large content file in multiple pieces. The response body contains the uploadId that has to be referred to by the individual upload of each piece that belongs to the same binary content file.

After each processing step of the upload, a maximum time of 2 days (default configuration) inactivity is accepted before the process and all its pieces are automatically deleted.

Request Example

POST /api/ms/uploads

Response Example
{ "uploadId": "MP_a2f7e1aa-ff42-4140-b9ec-5de4cc61f1a5" }
PUT /api/dms/uploads/{uploadId}/parts/{partNumber} - Upload a piece of content.
As of Version

2024 Summer

Request Method

PUT

Response Format

HTTP status code

Required Permission

successful authentication

Description

Uploads the binary file (NO multipart) in the request body as a piece that belongs to the upload process specified by uploadId. Specify the index number (starting with 1) of the piece as value for partNumber.

After each processing step of the upload, a maximum time of 2 days (default configuration) inactivity is accepted before the process and all its pieces are automatically deleted.

Request Example

PUT /api/dms/uploads/MP_a2f7e1aa-ff42-4140-b9ec-5de4cc61f1a5/parts/1

Response Example

200 OK

POST /api/dms/uploads/{uploadId} - Finalize an upload.
As of Version

2024 Summer

Request Method

POST

Response Format

HTTP status code

Required Permission

successful authentication

Description

Finalizes the upload process specified by uploadId. All pieces of the binary content imported via POST /api/dms/uploads/{uploadId} are concatenated to one content file ordered by their partNumber. After the successful call, no more sub-uploads of individual pieces are possible.

Finalizing the upload process is the last processing step for the partial import. However, it is still required to create a DMS object referring to that content within 2 days (default configuration). Otherwise, the upload with all its pieces will be deleted.

Optional query parameters:

Parameter Type Description

numberOfParts

Integer

Specify the total number of pieces that is expected for the upload process to be completed. The value is used for validation. The request fails if the specified number is not equal to the actual number of successful sub-uploads.

Request Example

PUT /api/dms/uploads/MP_a2f7e1aa-ff42-4140-b9ec-5de4cc61f1a5?numberOfParts=3

Response Example

200 OK

POST /api/dms/uploads/{uploadId}/objects - Create a DMS object with uploaded content.
As of Version

2024 Summer

Request Method

POST

Response Format

JSON

Required Permission

action create

Request Header

Content-Type: application/json

Description

Creates a new DMS object with the metadata specified in the JSON request body and stores the binary content file that has already been temporarily uploaded via the partial upload process specified by uploadId. The upload has to be finalized via POST /api/dms/uploads/{uploadId} first.

The request body can be a JSON structure or a multipart without binary content section as accepted also by POST /api/dms/objects. The previously uploaded content is identified via uploadId and NOT via contentStreams properties in the request body. However, the contentanalyzer service is SKIPPED. Thus, if you need proper values in the contentStreams section for fileName and mimeType, you need to set them in the JSON request body.

Request Example

POST /api/dms/uploads/MP_a2f7e1aa-ff42-4140-b9ec-5de4cc61f1a5/objects

Example request body for the creation of a DMS object after partial upload
{
    "objects": [{
        "properties": {
            "system:objectTypeId": {
                "value": "system:document"
            },
            "customproperty": {
                "value": "myvalue"
            }
        },
        "contentStreams": [{
            "mimeType": "application/pdf",
            "fileName": "myfilename.pdf"
        }]
    }]
}
Response Example
Response Body
{
    "objects": [
        {
            "properties": {
                "system:objectId": {
                    "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "customproperty":
                   {
                     "value": "myvalue"
                },
                "system:objectTypeId": {
                    "value": "system:document"
                },
                "system:createdBy": {
                    "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
                },
                "system:creationDate": {
                    "value": "2024-05-27T12:46:02.650Z"
                },
                "system:lastModifiedBy": {
                    "value": "0ade86f3-fcd1-4149-a556-fac2e94dc578"
                },
                "system:lastModificationDate": {
                    "value": "2024-05-27T12:46:02.650Z"
                },
                "system:versionNumber": {
                    "value": 1
                },
                "system:tenant": {
                    "value": "tenant1"
                },
                "system:traceId": {
                    "value": "97a35859dbb4c435"
                }
            },
            "contentStreams": [
                {
                    "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
                    "archivePath": "tenant1/2024/05/27/",
                    "length": 300000,
                    "mimeType": "application/pdf",
                    "fileName": "myfilename.pdf",
                    "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
                    "repositoryId": "repo252"
                }
            ]
        }
    ]
}
DELETE /api/dms/uploads/{uploadId} - Delete all pieces of an upload.
As of Version

2024 Summer

Request Method

DELETE

Response Format

HTTP status code

Required Permission

successful authentication

Description

Deletes all pieces of the content file that are already uploaded with the specified uploadId via POST /api/dms/uploads/{uploadId}.

Each upload process is automatically removed 2 days after the last processing step (default configuration).

Request Example

DELETE /api/dms/uploads/MP_a2f7e1aa-ff42-4140-b9ec-5de4cc61f1a5

Response Example

200 OK

GET /api/dms/uploads - Retrieve an overview of uploads.
As of Version

2024 Summer

Request Method

GET

Response Format

JSON

Required Permission

successful authentication

Description

Retrieves an overview of all running partial upload processes within the tenant with their already imported pieces indicated by partNumber.

Running processes in this case are those that were initialized via POST /api/dms/uploads and not yet finalized via POST /api/dms/uploads/{uploadId} or deleted via DELETE /api/dms/uploads/{uploadId}.

Each upload process is automatically removed after 2 days (default configuration).

The value for serviceInstanceUrls is always replaced by null in the response body. Its actual value ensures internally that the processing of all pieces of the same content are directed to the same repository service instance.

Request Example

GET /api/dms/uploads

Response Example
Response Body
{
    "uploads": {
        "MP_a2f7e1aa-ff42-4140-b9ec-5de4cc61f1a5": {
            "uploadId": "MP_a2f7e1aa-ff42-4140-b9ec-5de4cc61f1a5",
            "parts": {
                "1": {
                    "partNumber": 1,
                    "length": 100000,
                    "digest": "112376DC30C3F19290F518623C67FBBAC8D62A52916F0C5C0D9843DBC9F29EDA"
                },
                "2": {
                    "partNumber": 2,
                    "length": 100000,
                    "digest": "37B86BDF23559429C5EFF873255CBC64F33CC77E4FAAEB3F17A45B77B9BD0D14"
                },
                "3": {
                    "partNumber": 3,
                    "length": 100000,
                    "digest": "7DE8022F6664A3A4C18A4FE501034871567070043600DF37FAC925A080E561F5"
                }
            },
            "finished": false,
            "serviceInstanceUrl": null,
            "lastUpdated": 1716813572968
        }
    }
}
Operations on specific Versions
GET /api/dms/objects/{objectId}/versions - Retrieve object metadata by ID (all versions)
As of Version

1.0

Request Method

GET

Response Format

JSON

Required Permission

action read

Description

To retrieve the metadata of all versions of a DMS object, send the request with the ID of the DMS object as objectId.

A read permission on the active version is required.

Request Example

/api/dms/objects/cdc7095f-a5ce-486d-92a7-6d0955d969ee/versions

Result Example

The result is a list with at least one metadata record in JSON format:

{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "appEmail:email"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:versionNumber": {
                "value": 1
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "97a35859dbb4c435"
            },
            "appEmail:from": {
                "value": "Garco Meissler <garco@example.de>"
            },
            "appEmail:to": {
                "value": ["Dudreas Annkel <dudreas@example.de>"]
            },
            "appEmail:cc": {
                "value": ["Kruedeas Anger <kruedeas@example.de>"]
            },
            "appEmail:subject": {
                "value": "Bewerbungsunterlagen"
            }
        },
        "contentStreams": [{
            "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
            "length": 173413,
            "mimeType": "message/rfc822",
            "fileName": "upload.eml",
            "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
            "repositoryId": "repo252"
        }]
    },
    {
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "appEmail:email"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2018-01-29T13:13:113Z"
            },
            "system:versionNumber": {
                "value": 2
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "97a35859dbb4c435"
            },
            "appEmail:from": {
                "value": "Garco Meissler <garco@example.de>"
            },
            "appEmail:to": {
                "value": ["Dudreas Annkel <dudreas@example.de>"]
            },
            "appEmail:cc": {
                "value": ["Kruedeas Anger <kruedeas@example.de>",
                "Vils Normum <Normum@example.de>"]
            },
            "appEmail:subject": {
                "value": "Updated Bewerbungsunterlagen"
            }
        },
        "contentStreams": [{
            "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
            "length": 173413,
            "mimeType": "message/rfc822",
            "fileName": "upload.eml",
            "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
            "repositoryId": "repo252"
        }]
    },
    {
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "appEmail:email"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2018-01-30T11:53:227Z"
            },
            "system:versionNumber": {
                "value": 3
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "97a35859dbb4c435"
            },
            "appEmail:from": {
                "value": "Garco Meissler <garco@example.de>"
            },
            "appEmail:to": {
                "value": ["Dudreas Annkel <dudreas@example.de>"]
            },
            "appEmail:subject": {
                "value": "again updated Bewerbungsunterlagen"
            }
        },
        "contentStreams": [{
            "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
            "length": 173413,
            "mimeType": "message/rfc822",
            "fileName": "upload.eml",
            "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
            "repositoryId": "repo252"
        }]
    }]
}
GET /api/dms/objects/{objectId}/versions/{versionNr} - Retrieve object metadata by ID (specified version)
As of Version

1.0

Request Method

GET

Response Format

JSON

Required Permission

action read

Description

To retrieve the metadata of a specific version of a DMS object, send the request with the ID of the DMS object as objectId and the version number as versionNr.

A read permission on the active version is required.

Request Example

/api/dms/objects/cdc7095f-a5ce-486d-92a7-6d0955d969ee/versions/1

Result Example

The result is a list with at least one metadata record in JSON format:

{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "appEmail:email"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:versionNumber": {
                "value": 1
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "97a35859dbb4c435"
            },
            "appEmail:from": {
                "value": "Garco Meissler <garco@example.de>"
            },
            "appEmail:to": {
                "value": ["Dudreas Annkel <dudreas@example.de>"]
            },
            "appEmail:cc": {
                "value": ["Kruedeas Anger <kruedeas@example.de>"]
            },
            "appEmail:subject": {
                "value": "Bewerbungsunterlagen"
            }
        },
        "contentStreams": [{
            "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
            "length": 173413,
            "mimeType": "message/rfc822",
            "fileName": "upload.eml",
            "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
            "repositoryId": "repo252"
        }]
    }]
}
GET /api/dms/objects/{objectId}/versions/{versionNr}/contents/file - Retrieve object content by ID (specified version)
As of Version

1.0

Request Method

GET

Response Format

binary data

Required Permission

action read

Description

To get the content file related to a specific version of a DMS object, send the request with the ID of the DMS object as objectId and the version number as versionNr.

A read permission on the active version is required.

Request Example

/api/dms/objects/903f2ae8-2cfc-476c-8386-55c6811e41da/versions/2/contents/file

GET /api/dms/objects/{objectId}/versions/{versionNr}/contents/renditions/pdf - Retrieve PDF rendition by ID (specified version)
As of Version

2022 Winter

Request Method

GET

Response Format

PDF

Required Permission

action read

Description

Returns the content file’s PDF rendition of the DMS document object version specified by objectId and versionNr.

If the specified objectId does not exist, the call results in the error 404 - Not Found. Further errors are triggered by referencing an object without a content file or with a non-convertible content file.

The endpoint accepts the target file types listet here.

Response Header

Content-Type: application/pdf

Request Example

/api/dms/objects/903f2ae8-2cfc-476c-8386-55c6811e41da/versions/2/contents/renditions/pdf

Response Example

Response body with PDF document.

GET /api/dms/objects/{objectId}/versions/{versionNr}/contents/renditions/slide - Retrieve slide rendition by ID (specified version)
As of Version

2023 Spring

Request Method

GET

Response Format

PNG

Required Permission

action read

Description

Retrieves the slide rendition of the binary content file that is assigned to the DMS object specified by objectId and versionNr.

A PNG image with 256 px is returned in the response body.

The supported formats of binary content files as well as details on calculation and storage are listed here: Supported Formats

Please note that the rendition is not an exact representation of the original file. Deviations to the original file may arise and are NOT considered as bugs in our software.

Response Header

Content-Type: image/png

Request Example

/api/dms/objects/903f2ae8-2cfc-476c-8386-55c6811e41da/versions/3/contents/renditions/slide

Response Example

Response body with PNG file.

POST /api/dms/objects/{objectId}/versions/{versionNr}/actions/restore - Restore the specified object version.
As of Version

2022 Spring

Request Method

POST

Required Permission

action write on the current version of the object

Description

Restores the old version of an object specified by objectId and versionNr.

The following requirements have to be matched by the object version specified by versionNr:

  • It has to exist and must not be the current version.

  • It has to be valid according to the current schema. E.g., if one of its properties is not part of the current schema anymore, the restoring process will fail.

  • If the current object version has been assigned a system:rmExpirationDate, the specified old object version must have the same system:rmExpirationDate.

  • If the current object version has a binary content file AND a system:rmExpirationDate that is not yet expired, the specified old object version must have the same binary content file AND the same system:rmExpirationDate.

Internally, the data of the old object version are used to update the current object version. Thus, a new object version is created that has the data of the specified old object version except for system:versionNumber, system:lastModifiedBy, system:lastModificationDate and system:traceId. Those properties describe the restoring action itself.

If tags are assigned to the current object before the restoring action, only those tags with a name ending with the suffix :resistant are transferred to the new object version.

A new entry in the object’s audit trail is created. For the detail property, the value OBJECT_RESTORED_FROM_VERSION is set.

As of 2022 Summer: Optionally, the boolean query parameter restoreParentId can be appended to the request URL. This parameter is relevant for objects with a system:parentId property that indicates the object is considered as a child object of a folder object. The old version of the child object to be restored might have a different value for the system:parentId property. Thus, you might want to keep the current value for the system:parentId property of the child object even after restoring an old version.

  • If restoreParentId=true (default), the system:parentId value of the respective old object version is used.

  • If restoreParentId=false, the system:parentId value of the current version is used after restoring the respective old object version.

As of 2022 Autumn, the optional query parameter waitForSearchConsistency can be added to the request URL. If not specified, the default value true is used.

Request Example

/api/dms/objects/950f1e3a-829b-473d-97c5-9ea0a94706f6/versions/2/actions/restore

Response Example
{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": "950f1e3a-829b-473d-97c5-9ea0a94706f6"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:objectTypeId": {
                "value": "appEmail:email"
            },
            "system:createdBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:creationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:lastModifiedBy": {
                "value": "0d7fd0be-6a0b-4d3b-933c-25e0c4c5d794"
            },
            "system:lastModificationDate": {
                "value": "2018-01-26T15:21:170Z"
            },
            "system:versionNumber": {
                "value": 4
            },
            "system:tenant": {
                "value": "tenant1"
            },
            "system:traceId": {
                "value": "97a35859dbb4c435"
            },
            "appEmail:from": {
                "value": "Garco Meissler <garco@example.de>"
            },
            "appEmail:to": {
                "value": ["Dudreas Annkel <dudreas@example.de>"]
            },
            "appEmail:cc": {
                "value": ["Kruedeas Anger <kruedeas@example.de>",
                "Vils Normum <Normum@example.de>"]
            },
            "appEmail:subject": {
                "value": "Updated Bewerbungsunterlagen"
            },
            "table": {
                "columnNames": ["iColumn1", "iColumn2", "iColumn3"],
                "value": [["something", "to know", true],["more", "infos", false]]
            }
        },
        "contentStreams": [{
            "contentStreamId": "2B797243-A1F5-11EA-A814-9FABD98CE7A7",
            "length": 173413,
            "mimeType": "message/rfc822",
            "fileName": "upload.eml",
            "digest": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
            "repositoryId": "repo252"
        }]
    }]
}
DELETE /api/dms/objects/{objectId}/versions/{versionNr} - Delete the specified object version.
As of Version

1.0

Request Method

DELETE

Required Permission

action delete and read

Description

To delete a specific version of an object, send the request with the ID of the object as objectId and the version number as versionNr.

Deleting the active version is not possible via this endpoint.

Meaning of the response status codes:

HTTP status code Meaning

200 OK

The DMS object with the ID objectId has been deleted

404 Not Found

The DMS object with the ID objectId can not be found.

A delete permission on the active version of the object is required.

Request Example

/api/dms/objects/950f1e3a-829b-473d-97c5-9ea0a94706f6/versions/2

GET /api/dms/objects/{objectId}/versions/{versionNr}/actions/validate/digest - Validate the specified object’s content.
As of Version

1.0

Request Method

GET

Response Format

JSON

Required Permission

action read

Description

To validate the content digest of a specific version of a DMS object, send the request with the ID of the DMS object as objectId and the version number as versionNr. The content digest is calculated and compared with the value stored in the metadata.

A read permission on the active version is required.

Meaning of the response status codes:

HTTP status code Meaning

200 OK

The value of the content digest stored in the metadata is still correct.

404 Not Found

The DMS object with the ID objectId can not be found.

409 Conflict

The calculated content digest does not match the value stored in the metadata.

Request Example

/api/dms/objects/903f2ae8-2cfc-476c-8386-55c6811e41da/versions/1/actions/validate/digest

POST /api/dms/objects/{objectId}/version/{versionNr}/actions/move/contents/repositories/{repositoryid} - Move the content of an object version to a different repository.
As of Version

2019 Winter

Request Method

POST

Response Format

JSON

Required Permission

action write and read

Description

Moves the binary content file assigned to the selected version of the object specified by objectId to the target repository specified by repositoryId.

The corresponding binary content file is referenced in the contentStreams section of the object version via the properties repositoryId and contentStreamId. The binary content file could be referenced in multiple object versions and even in other objects. In case the corresponding binary content file is moved, the repositoryId and contentStreamId properties in the contentStreams section are updated in all those objects and object versions. No new object version will be created.

An audit entry will be created only for version specified by versionNr of the object specified by objectId in the request URL.

Request Example

POST api/dms/objects/00250915-fb6e-4165-bc05-93a02590f5de/versions/1/actions/move/contents/repositories/repo252

Response Example

The result is a JSON structure containing the updated metadata of the object identified by objectId.

{
    "objects": [{
        "properties": {
            "system:traceId": {
                "value": "6ff928e56f8f8efe"
            },
            "system:objectTypeId": {
                "value": "document"
            },
            "system:versionNumber": {
                "value": 1
            },
            "Name": {
                "value": "Beat 2014-06.pdf_075.pdf"
            },
            "system:createdBy": {
                "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
            },
            "system:creationDate": {
                "value": "2018-11-30T14:47:40.250Z"
            },
            "system:lastModificationDate": {
                "value": "2018-11-30T14:47:40.250Z"
            },
            "system:baseTypeId": {
                "value": "system:document"
            },
            "system:tenant": {
                "value": "default"
            },
            "system:lastModifiedBy": {
                "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
            },
            "system:objectId": {
                "value": "00250915-fb6e-4165-bc05-93a02590f5de"
            }
        },
        "contentStreams": [{
            "contentStreamId": "DB886B37-FEEF-11E9-BCEC-3FAD551A2B8A",
            "archivePath": "default/DOCUMENT/B8/86/B/",
            "length": 86171,
            "mimeType": "application/pdf",
            "fileName": "Beat 2014-06.pdf_075.pdf",
            "digest": "2714F996A45F41439F625160167B4DE5BDE604F560FCABF8C242567CDFDC733A",
            "repositoryId": "repo252"
        }]
    }]
}
Schema Retrieval - Object Type Information
GET /api/dms/schema/native - Retrieve applied tenant schema in XML/JSON format.
As of Version

1.0

Request Method

GET

Response Format

XML / JSON

Description

Get the applied schema which belongs to the requesting user. It contains all available types: system types, global types and tenant-specific types.

The structure is the same as in the source schemas that are maintained via the admin endpoints and the system endpoints.

Request Example

/api/dms/schema/native

Result Example
xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/">
    <version>1</version>
    <lastModificationDate>2019-03-25T10:25:46.212Z</lastModificationDate>
    <propertyIdDefinition>
        <id>system:objectId</id>
        <description>Id of the object</description>
        <propertyType>id</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyIdDefinition>
    <propertyIdDefinition>
        <id>system:baseTypeId</id>
        <description>Id of the base object-type for the object</description>
        <propertyType>id</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyIdDefinition>
    ...
    <propertyStringDefinition>
        <id>appEmail:from</id>
        <description>field for the e-mail sender</description>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    ...
    <propertyStringDefinition>
        <id>tenNyc999:myname</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <propertyDateTimeDefinition>
        <id>tenNyc999:mydate</id>
        <propertyType>datetime</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyDateTimeDefinition>
    ...
    <typeDocumentDefinition>
        <id>system:document</id>
        <localNamespace>urn:optimal-systems.de:dmscloud:system</localNamespace>
        <description>decribes the base document type</description>
        <baseId>system:document</baseId>
        <propertyReference>system:objectId</propertyReference>
        <propertyReference>system:baseTypeId</propertyReference>
        ...
        <contentStreamAllowed>allowed</contentStreamAllowed>
    </typeDocumentDefinition>
        <typeDocumentDefinition>
        <id>appEmail:email</id>
        <baseId>system:document</baseId>
        <propertyReference>appEmail:from</propertyReference>
        ...
        <contentStreamAllowed>required</contentStreamAllowed>
        <secondaryObjectTypeId>system:rmDestructionRetention</secondaryObjectTypeId>
    </typeDocumentDefinition>
    ...
    <typeDocumentDefinition>
        <id>tenNyc999:mydocument</id>
        <baseId>system:document</baseId>
        <propertyReference>tenNyc999:myname</propertyReference>
        <propertyReference>tenNyc999:mydate</propertyReference>
        <contentStreamAllowed>required</contentStreamAllowed>
    </typeDocumentDefinition>
    ...
    <typeSecondaryDefinition>
        <id>system:secondary</id>
        <localNamespace>urn:optimal-systems.de:dmscloud:system</localNamespace>
        <description>decribes the base secondary type</description>
        <baseId>system:secondary</baseId>
    </typeSecondaryDefinition>
    <typeSecondaryDefinition>
        <id>system:rmDestructionRetention</id>
        <localNamespace>urn:optimal-systems.de:dmscloud:system</localNamespace>
        <baseId>system:secondary</baseId>
        <propertyReference>system:rmExpirationDate</propertyReference>
        <propertyReference>system:rmStartOfRetention</propertyReference>
        <propertyReference>system:rmDestructionDate</propertyReference>
    </typeSecondaryDefinition>
</schema>
json
{
  "version": 1,
  "lastModificationDate": "2019-03-25T10:25:46.212Z",
  "propertyDefinition": [
    {
      "id": "system:objectId",
      "description": "Id of the object",
      "propertyType": "id",
      "cardinality": "single",
      "required": false
    },
    {
      "id": "system:baseTypeId",
      "description": "Id of the base object-type for the object",
      "propertyType": "id",
      "cardinality": "single",
      "required": false
    },
    ...
    {
      "id": "appEmail:from",
      "description": "field for the e-mail sender",
      "propertyType": "string",
      "cardinality": "single",
      "required": false
    },
    ...
    {
      "id": "tenNyc999:myname",
      "propertyType": "string",
      "cardinality": "single",
      "required": false
    },
    {
      "id": "tenNyc999:mydate",
      "propertyType": "datetime",
      "cardinality": "single",
      "required": false
    }
  ],
  "typeDocumentDefinition": [
    {
      "id": "system:document",
      "localNamespace": "urn:optimal-systems.de:dmscloud:system",
      "description": "decribes the base document type",
      "baseId": "system:document",
      "propertyReference": [
        {
          "value": "system:objectId"
        },
        {
          "value": "system:baseTypeId"
        },
        ...
      ],
      "contentStreamAllowed": "allowed"
    },
    {
      "id": "appEmail:email",
      "baseId": "system:document",
      "propertyReference": [
        {
          "value": "appEmail:from"
        },
        ...
      ],
      "contentStreamAllowed": "required",
      "secondaryObjectTypeId": [
        "system:rmDestructionRetention"
      ]
    },
    ...
    {
      "id": "tenNyc999:mydocument",
      "baseId": "system:document",
      "propertyReference": [
        {
          "value": "tenNyc999:myname"
        },
        {
          "value": "tenNyc999:mydate"
        }
      ],
      "contentStreamAllowed": "required"
    }
  ],
  "typeSecondaryDefinition": [
    {
      "id": "system:secondary",
      "localNamespace": "urn:optimal-systems.de:dmscloud:system",
      "description": "decribes the base secondary type",
      "baseId": "system:secondary",
      "propertyReference": []
    },
    {
      "id": "system:rmDestructionRetention",
      "localNamespace": "urn:optimal-systems.de:dmscloud:system",
      "baseId": "system:secondary",
      "propertyReference": [
        {
          "value": "system:rmExpirationDate"
        },
        {
          "value": "system:rmStartOfRetention"
        },
        {
          "value": "system:rmDestructionDate"
        }
      ]
    }
  ]
}
GET /api/dms/schema - Retrieve applied tenant schema in JSON format.
As of Version

1.0

Request Method

GET

Response Format

JSON

Description

Get the applied tenant schema. It contains all available types: system types, global types and tenant-specific types.

This is similar to the "Retrieve applied tenant schema" endpoint (GET /api/dms/schema/native). The resulting schema contains the same types, but it is structured in a different way.

Request Example

/api/dms/schema

Response Example
{
    "lastModificationDate": "2020-02-27T19:12:47.677+01:00",
    "objectTypes": [
        {
            "id": "system:document",
            "localName": "system:document",
            "localNamespace": "urn:optimal-systems.de:dmscloud:system",
            "displayName": "system:document",
            "baseId": "document",
            "description": "decribes the base document type",
            "creatable": false,
            "contentStreamAllowed": "allowed",
            "fulltextIndexed": true,
            "fields": [
                {
                    "id": "system:objectId",
                    "localName": "system:objectId",
                    "displayName": "system:objectId",
                    "description": "Id of the object",
                    "propertyType": "string",
                    "cardinality": "single",
                    "updatability": "readonly",
                    "required": false
                },
                {
                    "id": "system:baseTypeId",
                    "localName": "system:baseTypeId",
                    "displayName": "system:baseTypeId",
                    "description": "Id of the base object-type for the object",
                    "propertyType": "string",
                    "cardinality": "single",
                    "updatability": "readonly",
                    "required": false
                },
                ...
            ]
        },
        {
            "id" : "appEmail:email",
            "localName" : "appEmail:email",
            "displayName" : "appEmail:email",
            "baseId" : "document",
            "creatable" : true,
            "contentStreamAllowed" : "required",
            "fulltextIndexed" : true,
            "fields": [
                ...
                {
                    "id" : "appEmail:from",
                    "localName" : "appEmail:from",
                    "displayName" : "appEmail:from",
                    "description" : "field for the e-mail sender",
                    "propertyType" : "string",
                    "cardinality" : "single",
                    "updatability" : "readwrite",
                    "required" : false
                },
            ...
            ]
        },
        ...
        {
            "id" : "tenNyc999:mydocument",
            "localName" : "tenNyc999:mydocument",
            "displayName" : "tenNyc999:mydocument",
            "baseId" : "document",
            "creatable" : true,
            "contentStreamAllowed" : "required",
            "fulltextIndexed" : true,
            "fields": [
                {
                    "id" : "tenNyc999:myname",
                    "localName" : "tenNyc999:myname",
                    "displayName" : "tenNyc999:myname",
                    "propertyType" : "string",
                    "cardinality" : "single",
                    "updatability" : "readwrite",
                    "required" : false
                },
                {
                    "id" : "tenNyc999:mydate",
                    "localName" : "tenNyc999:mydate",
                    "displayName" : "tenNyc999:mydate",
                    "propertyType" : "datetime",
                    "cardinality" : "single",
                    "updatability" : "readwrite",
                    "required" : false
                }
            ]
        }
    ]
}
GET /api/dms/schema/objecttype/{localname} - Retrieve an object type’s definition by its local name.
As of Version

1.0

Request Method

GET

Response Format

JSON

Description

Retrieves the definition of the object type identified by its localname. The definition contains attributes of the object type and definitions of all its fields.

Request Example

/api/dms/schema/objecttype/email

Response Example
{
    "id": "email",
    "localName": "email",
    "displayName": "email",
    "baseId": "document",
    "creatable": true,
    "contentStreamAllowed": "required",
    "fulltextIndexed": true,
    "fields": [
        {
            "id": "system:objectId",
            "localName": "system:objectId",
            "displayName": "system:objectId",
            "description": "Id of the object",
            "propertyType": "string",
            "cardinality": "single",
            "updatability": "readonly",
            "required": false
        },
        {
            "id": "system:baseTypeId",
            "localName": "system:baseTypeId",
            "displayName": "system:baseTypeId",
            "description": "Id of the base object-type for the object",
            "propertyType": "string",
            "cardinality": "single",
            "updatability": "readonly",
            "required": false
        },
        {
            "id": "system:objectTypeId",
            "localName": "system:objectTypeId",
            "displayName": "system:objectTypeId",
            "description": "Id of the object’s type",
            "propertyType": "string",
            "cardinality": "single",
            "updatability": "readonly",
            "required": false
        },
        {
            "id": "system:secondaryObjectTypeIds",
            "localName": "system:secondaryObjectTypeIds",
            "displayName": "system:secondaryObjectTypeIds",
            "description": "Ids of the object’s secondary types.",
            "propertyType": "string",
            "cardinality": "multi",
            "updatability": "readonly",
            "required": false
        },
        {
            "id": "system:createdBy",
            "localName": "system:createdBy",
            "displayName": "system:createdBy",
            "description": "User who created the object",
            "propertyType": "string",
            "cardinality": "single",
            "updatability": "readonly",
            "required": false
        },
        {
            "id": "system:creationDate",
            "localName": "system:creationDate",
            "displayName": "system:creationDate",
            "description": "DateTime when the object was created",
            "propertyType": "datetime",
            "cardinality": "single",
            "updatability": "readonly",
            "required": false
        },
        {
            "id": "system:lastModifiedBy",
            "localName": "system:lastModifiedBy",
            "displayName": "system:lastModifiedBy",
            "description": "User who last modified the object",
            "propertyType": "string",
            "cardinality": "single",
            "updatability": "readonly",
            "required": false
        },
        {
            "id": "system:lastModificationDate",
            "localName": "system:lastModificationDate",
            "displayName": "system:lastModificationDate",
            "description": "DateTime when the object was last modified",
            "propertyType": "datetime",
            "cardinality": "single",
            "updatability": "readonly",
            "required": false
        },
        {
            "id": "system:versionNumber",
            "localName": "system:versionNumber",
            "displayName": "system:versionNumber",
            "description": "The version number of the object",
            "propertyType": "integer",
            "cardinality": "single",
            "updatability": "readonly",
            "required": true
        },
        ...
        {
            "id": "from",
            "localName": "from",
            "displayName": "from",
            "description": "system-wide field for the e-mail sender",
            "propertyType": "string",
            "cardinality": "single",
            "updatability": "readwrite",
            "required": false
        },
        {
            "id": "to",
            "localName": "to",
            "displayName": "to",
            "description": "system-wide field for the e-mail recipients",
            "propertyType": "string",
            "cardinality": "multi",
            "updatability": "readwrite",
            "required": false
        },
        {
            "id": "cc",
            "localName": "cc",
            "displayName": "cc",
            "description": "system-wide field for the e-mail cc",
            "propertyType": "string",
            "cardinality": "multi",
            "updatability": "readwrite",
            "required": false
        },
        {
            "id": "bcc",
            "localName": "bcc",
            "displayName": "bcc",
            "description": "system-wide field for the e-mail bcc",
            "propertyType": "string",
            "cardinality": "multi",
            "updatability": "readwrite",
            "required": false
        },
        {
            "id": "subject",
            "localName": "subject",
            "displayName": "subject",
            "description": "system-wide field for the e-mail subject",
            "propertyType": "string",
            "cardinality": "single",
            "updatability": "readwrite",
            "required": false
        },
        ...
    ]
}

2.11.2. Resources Endpoints within the Tenant

Operations on resources that affect only the currently active tenant.

Metrics
GET /api/admin/metrics/{metric} - Retrieve a metric for the active tenant.
As of Version

2023 Spring

Request Method

GET

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and if the specified access condition is matched.

Description

Retrieve the specified metric for the currently active tenant.

Following values are available for the metric path parameter:

  • storage - The endpoint retrieves the dynamically calculated binary storage used by the currently active tenant.

  • objectCount (as of 2023 Summer) - The endpoint retrieves the number of DMS objects within the currently active tenant.

Request Examples

(A) /api/admin/metrics/storage

(B) /api/admin/metrics/objectCount

Response Examples

(A)

{
  "objects": [
    {
      "properties": {
        "system:tenant": {
          "value": "testyuuvis"
        }
      },
      "options": {
        "storageUsed": {
          "humanReadable": "121 MB",
          "value": 127508469
        }
      }
    }
  ],
  "numItems": 1,
  "hasMoreItems": false,
  "totalNumItems": 1
}

(B)

{
    "objects": [{
            "properties": {
                "system:tenant": {
                    "value": "testyuuvis"
                }
            },
            "options": {
                "objectCount": {
                    "totalFolderCount": 97,
                    "totalObjectCount": 1733
                }
            }
        }
    ],
    "numItems": 1,
    "hasMoreItems": false,
    "totalNumItems": 1
}
DELETE /api/admin/metrics/{metric} - Reset a metric for the active tenant.
As of Version

2023 Spring

Request Method

DELETE

Response Format

HTTP status code

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Reset the specified metric for the currently active tenant.

Not available for the storage metric. Use DELETE /api/system/metrics/{metric} instead.

Role Set Management
GET /api/admin/permissions - Retrieve the tenant role set for the active tenant.
As of Version

1.0

Request Method

GET

Response Format

XML

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

To retrieve the role set of the tenant in XML format. The tenant belongs to the user calling this endpoint.

Request Example

/api/admin/permissions

Response Example
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<roleSet xmlns="http://optimal-systems.org/ns/dmscloud/roleset/">
    <role>
        <name>ReadDeleteEmail</name>
        <permission>
            <action>read</action>
            <action>delete</action>
            <condition>system:objectTypeId = 'email:email'</condition>
        </permission>
    </role>
    <role>
        <name>ReadDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId = 'document'</condition>
        </permission>
    </role>
    <role>
        <name>ReadEmailAndDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId in ('email:email', 'document')</condition>
        </permission>
    </role>
    <role>
        <name>DeleteDocument</name>
        <permission>
            <action>delete</action>
            <condition>system:objectTypeId in ('document')</condition>
        </permission>
    </role>
    <role>
        <name>AdminRole</name>
        <permission>
            <action>read</action>
            <action>delete</action>
        </permission>
    </role>
</roleSet>
POST /api/admin/permissions - Update the tenant role set for the active tenant if valid.
As of Version

1.0

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

To update the role set of the tenant, there are two possibilities to send the new role set: as binary in the request body or as multipart request with part name file. The tenant for which the role set will be updated belongs to the user calling this endpoint.

If the validation process fails, the role set will not be updated and the response contains at least one error message. If the new role set is valid, the role set will be updated and the response contains an empty list validationErrors.

Request Header

Content-Type: application/xml

Response Example

The result is a JSON structure containing a validationErrors list, which could be an empty list.

200 - no validation errors, the role set has been updated
{
    "validationErrors": []
}
422 - there were validation errors, the role set was not updated
{
    "validationErrors": [
        {
            "message": "Unable to unmarshal schema. [line: 14][column: 13] cvc-complex-type.2.4.a: Ungültiger Content wurde beginnend mit Element
            'condition' gefunden. '{\"http://optimal-systems.org/ns/dmscloud/roleset/\":action}' wird erwartet."
        }
    ]
}
POST /api/admin/permissions/validate - Validate a role set for the active tenant.
As of Version

1.0

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

To validate the role set of the tenant, there are two possibilities to send the new role set: as binary in the request body or as multipart request with part name file. The tenant for which the role set will be updated belongs to the user calling this endpoint.

If the validation process fails, the response contains at least one error message. If the new role set is valid, the response contains an empty list validationErrors.

Request Header

Content-Type: application/xml

Response Example

The result is a JSON structure containing a validationErrors list, which could be an empty list.

200 - the role set is valid, no validation errors
{
    "validationErrors": []
}
422 - there were validation errors
{
    "validationErrors": [
        {
            "message": "Unable to unmarshal schema. [line: 14][column: 13] cvc-complex-type.2.4.a: Ungültiger Content wurde beginnend mit Element
            'condition' gefunden. '{\"http://optimal-systems.org/ns/dmscloud/roleset/\":action}' wird erwartet."
        }
    ]
}
Tenant Schema Management
GET /api/admin/schema - Retrieve the tenant schema for the active tenant.
As of Version

1.0

Request Method

GET

Response Format

XML, JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

To retrieve the schema of the tenant in XML or JSON format. The tenant belongs to the user calling this endpoint.

Request Example

/api/admin/schema

Response Example
<schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://optimal-systems.org/ns/dmscloud/schema/v5.0/ dmsCloud-schema.xsd">
        <propertyStringDefinition>
            <id>from</id>
            <propertyType>string</propertyType>
            <cardinality>single</cardinality>
            <required>true</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>to</id>
            <propertyType>string</propertyType>
            <cardinality>multi</cardinality>
            <required>true</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>subject</id>
            <propertyType>string</propertyType>
            <cardinality>single</cardinality>
            <required>true</required>
            <defaultValue>hello</defaultValue>
            <maxLength>20</maxLength>
            <minLength>4</minLength>
        </propertyStringDefinition>
        <propertyDateTimeDefinition>
            <id>received</id>
            <propertyType>datetime</propertyType>
            <cardinality>single</cardinality>
            <required>true</required>
        </propertyDateTimeDefinition>
        <typeDocumentDefinition>
            <id>email</id>
            <baseId>system:document</baseId>
            <propertyReference>from</propertyReference>
            <propertyReference>to</propertyReference>
            <propertyReference>received</propertyReference>
            <contentStreamAllowed>required</contentStreamAllowed>
        </typeDocumentDefinition>
</schema>
POST /api/admin/schema - Update the tenant schema for the active tenant if valid.
As of Version

1.0

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Update the tenant schema for the tenant which the requesting user belongs to. The new schema is passed in the request body in XML format and is validated before the update is executed. Thus, it is not possible to introduce an invalid schema via this endpoint.

For details and examples regarding request and response please visit schema.

Request Headers

Content-Type: application/xml

POST /api/admin/schema/validate - Validate a schema for the active tenant.
As of Version

1.0

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Validate the XML file passed in the request body for the usability as tenant schema for the tenant which the requesting user belongs to. The currently used tenant schema is NOT updated.

For details and examples regarding request and response please visit schema.

Request Headers

Content-Type: application/xml

2.11.3. Cross-Tenant Resources Endpoints

Global Endpoints

Operations on the resources that affect all tenants in the system.

Metrics
GET /api/system/metrics/{metric} - Retrieve a metric for all tenants.
As of Version

2023 Spring

Request Method

GET

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Retrieve the specified metric for all tenants.

Following values are available for the metric path parameter:

  • storage - The endpoint retrieves the dynamically calculated binary storage individually used by tenants.

Request Example

/api/system/metrics/storage

Response Example
{
  "objects": [
    {
      "properties": {
        "system:tenant": {
          "value": "tenant1"
        }
      },
      "options": {
        "storageUsed": {
          "humanReadable": "121 MB",
          "value": 127508469
        }
      }
    },
    {
      "properties": {
        "system:tenant": {
          "value": "yuuvistest"
        }
      },
      "options": {
        "storageUsed": {
          "humanReadable": "12 GB",
          "value": 13518072956
        }
      }
    },
    {
      "properties": {
        "system:tenant": {
          "value": "testyuuvis"
        }
      },
      "options": {
        "storageUsed": {
          "humanReadable": "164 MB",
          "value": 172295598
        }
      }
    },
    {
      "properties": {
        "system:tenant": {
          "value": "exampletenant"
        }
      },
      "options": {
        "storageUsed": {
          "humanReadable": "456 KB",
          "value": 467485
        }
      }
    },
    {
      "properties": {
        "system:tenant": {
          "value": "mytenant"
        }
      },
      "options": {
        "storageUsed": {
          "humanReadable": "0 bytes",
          "value": 0
        }
      }
    }
  ],
  "numItems": 5,
  "hasMoreItems": false,
  "totalNumItems": 5
}
DELETE /api/system/metrics/{metric} - Reset a metric for all tenants.
As of Version

2023 Spring

Request Method

DELETE

Response Format

HTTP status code

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Reset the specified metric for all tenants.

Following values are available for the metric path parameter:

  • storage - Recalculate the binary storage individually used by tenants. The processing is managed by the audit Service and can be adjusted and even automated via its service configuration.

    High Database Workload

    We do not recommend a regular usage of this endpoint. Each call triggers a recalculation of the storage metric for all tenants. During the processing time, no storage metric can be retrieved.

Request Example

/api/system/metrics/storage

Result Example

200 OK

Role Set
GET /api/system/permissions - Retrieve the global role set XML/JSON.
As of Version

1.0

Request Method

GET

Response Format

XML/JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

This endpoint is used to retrieve the global permissions file of the yuuvis® system.

Request Headers

Accept: [application/xml; application/json]

Response Example
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<roleSet xmlns="http://optimal-systems.org/ns/dmscloud/roleset/">
    <role>
        <name>ReadDeleteEmail</name>
        <permission>
            <action>read</action>
            <action>delete</action>
            <condition>system:objectTypeId = 'email:email'</condition>
        </permission>
    </role>
    <role>
        <name>ReadDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId = 'document'</condition>
        </permission>
    </role>
    <role>
        <name>ReadEmailAndDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId in ('email:email', 'document')</condition>
        </permission>
    </role>
    <role>
        <name>DeleteDocument</name>
        <permission>
            <action>delete</action>
            <condition>system:objectTypeId in ('document')</condition>
        </permission>
    </role>
    <role>
        <name>AdminRole</name>
        <permission>
            <action>read</action>
            <action>delete</action>
        </permission>
    </role>
</roleSet>
POST /api/system/permissions - Update the global role set.
As of Version

1.0

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

This endpoint is used to update the global permissions file of the yuuvis® system. Similar to other schema update endpoints in yuuvis®, this infers a schema validation and returns its result to the user, performing the update only after successful validation.

Request Headers

Content-Type: application/xml

Request Example

/api/system/permissions

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<roleSet xmlns="http://optimal-systems.org/ns/dmscloud/roleset/">
    <role>
        <name>ReadDeleteEmail</name>
        <permission>
            <action>read</action>
            <action>delete</action>
            <condition>system:objectTypeId = 'email:email'</condition>
        </permission>
    </role>
    <role>
        <name>ReadDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId = 'document'</condition>
        </permission>
    </role>
    <role>
        <name>ReadEmailAndDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId in ('email:email', 'document')</condition>
        </permission>
    </role>
    <role>
        <name>DeleteDocument</name>
        <permission>
            <action>delete</action>
            <condition>system:objectTypeId in ('document')</condition>
        </permission>
    </role>
    <role>
        <name>AdminRole</name>
        <permission>
            <action>read</action>
            <action>create</action>
            <action>delete</action>
        </permission>
    </role>
</roleSet>
Response Example

The result is a JSON structure containing a validationErrors list, which could be an empty list.

200 - no validation errors, the role set has been updated
{
    "validationErrors": []
}
422 - there were validation errors, the role set was not updated
{
    "validationErrors": [
        {
            "message": "Unable to unmarshal schema. [line: 14][column: 13] cvc-complex-type.2.4.a: Invalid content was found starting with element
            'condition'. One of '{\"http://optimal-systems.org/ns/dmscloud/roleset/\":action}' is expected."
        }
    ]
}
POST /api/system/permissions/validate - Validate the global role set.
As of Version

1.0

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

This endpoint is used to validate a permissions file to determine its fitness to become the new global permissions file of the yuuvis® system.

Request Headers

Content-Type: application/xml

Request Example

/api/system/permissions/validate

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<roleSet xmlns="http://optimal-systems.org/ns/dmscloud/roleset/">
    <role>
        <name>ReadDeleteEmail</name>
        <permission>
            <action>read</action>
            <action>delete</action>
            <condition>system:objectTypeId = 'email:email'</condition>
        </permission>
    </role>
    <role>
        <name>ReadDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId = 'document'</condition>
        </permission>
    </role>
    <role>
        <name>ReadEmailAndDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId in ('email:email', 'document')</condition>
        </permission>
    </role>
    <role>
        <name>DeleteDocument</name>
        <permission>
            <action>delete</action>
            <condition>system:objectTypeId in ('document')</condition>
        </permission>
    </role>
    <role>
        <name>AdminRole</name>
        <permission>
            <action>read</action>
            <action>create</action>
            <action>delete</action>
        </permission>
    </role>
</roleSet>
Response Example

The result is a JSON structure containing a validationErrors list, which could be an empty list.

200 - no validation errors, the role set has been updated
{
    "validationErrors": []
}
422 - there were validation errors, the role set was not updated
{
    "validationErrors": [
        {
            "message": "Unable to unmarshal schema. [line: 14][column: 13] cvc-complex-type.2.4.a: Invalid content was found starting with element
            'condition'. One of '{\"http://optimal-systems.org/ns/dmscloud/roleset/\":action}' is expected."
        }
    ]
}
Schema
GET /api/system/schema - Retrieve the global schema XML/JSON.
As of Version

1.0

Request Method

GET

Response Format

XML, JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

This endpoint is used to retrieve the global schema of the yuuvis® system.

Request Headers

Accept: [application/xml; application/json]

Response Example
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/">
    <version>4</version>
    <lastModificationDate>2019-09-12T16:53:49.644Z</lastModificationDate>
    <propertyDateTimeDefinition>
        <id>date</id>
        <propertyType>datetime</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyDateTimeDefinition>
    <propertyStringDefinition>
        <id>Name</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <typeDocumentDefinition>
        <id>document</id>
        <baseId>system:document</baseId>
        <propertyReference>Name</propertyReference>
        <propertyReference>date</propertyReference>
        <contentStreamAllowed>required</contentStreamAllowed>
        <secondaryObjectTypeId>system:rmDestructionRetention</secondaryObjectTypeId>
    </typeDocumentDefinition>
</schema>
POST /api/system/schema - Update the global schema.
As of Version

1.0

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

This endpoint is used to update the global schema of the yuuvis® system. Similar to other schema update endpoints in yuuvis®, this infers a schema validation and returns its result to the user, performing the schema update only after successful validation.

Request Headers

Content-Type: application/xml

Response Example

The result is a JSON structure containing a validationErrors list, which could be an empty list.

200 - no validation errors
{
    "validationErrors": []
}
422 - there were validation errors
{
    "validationErrors": [
        {
            "message": "Ambiguous ids. There are 2 property type definitions with the id 'from'.",
            "serviceErrorCode": 2110
        },
        {
            "message": "Wrong base id. The base id of the system:document type definition 'email' must be 'system:document', but it is 'system:folder'.",
            "serviceErrorCode": 2131
        },
        {
            "message": "Invalid property reference 'fromm' in type definition 'email'.",
            "serviceErrorCode": 2132
        },
        {
            "message": "Invalid secondary object type reference 'appAcl:aclowner' in type definition 'email'.",
            "serviceErrorCode": 2135
        }
    ]
}
POST /api/system/schema/validate - Validate the global schema.
As of Version

1.0

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

This endpoint is used to validate a schema file for fitness for being the new global schema of the yuuvis® system.

Request Headers

Content-Type: application/xml

Response Example

The result is a JSON structure containing a validationErrors list, which could be an empty list.

200 - no validation errors, the schema has been updated
{
    "validationErrors": []
}
422 - there were validation errors, the schema was not updated
{
    "validationErrors": [
        {
            "message": "Ambiguous ids. There are 2 property type definitions with the id 'from'.",
            "serviceErrorCode": 2110
        },
        {
            "message": "Wrong base id. The base id of the system:document type definition 'email' must be 'system:document', but it is 'system:folder'.",
            "serviceErrorCode": 2131
        },
        {
            "message": "Invalid property reference 'fromm' in type definition 'email'.",
            "serviceErrorCode": 2132
        },
        {
            "message": "Invalid secondary object type reference 'appAcl:aclowner' in type definition 'email'.",
            "serviceErrorCode": 2135
        }
    ]
}
System Hooks
GET /api/system/systemhooks - Retrieve the global system hook configuration.
As of Version

2022 Summer

Request Method

GET

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Retrieves the global system hook configuration.

The content of the global systemHookConfiguration.json configuration file is returned. The configured system hooks are available in all tenants.

Request Headers

Accept: [application/json]

Request Example

/api/system/systemhooks

Response Example
{
    "systemhooks": {
        "amqp": [
            {
                "bulkSize": 10,
                "enable": true,
                "password": "secret",
                "predicate": "spel:(contentStreams != null && contentStreams.size() > 0 && contentStreams[0]['range'] != null && contentStreams[0]['range'].length() > 0) ? true : false",
                "queue": "lc.textextraction",
                "type": "object.insert.document",
                "url": "10.10.6.243:5674",
                "user": "clouduser"
            }
        ],
        "webhooks": [
            {
                "enable": true,
                "predicate": "spel:true",
                "type": "user.info",
                "url": "http://organization/api/userinfo/${tenant}/${userId}"
            }
        ]
    }
}
POST /api/system/systemhooks - Update the global system hook configuration.
As of Version

2022 Summer

Request Method

POST

Response Format

HTTP status code

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Updates the global system hook configuration.

The content of the global systemHookConfiguration.json configuration file is replaced by the configuration specified in the JSON request body. Its structure is validated and has to match the structure described here. Especially, the type of each defined AMQP hook and webhook has to be valid.

The configured system hooks are available in all tenants.

The changes are applied immediately after a successful update of the configuration.

Request Headers

Content-Type: [application/json]

Request Example

/api/system/systemhooks

Request Body
{
    "systemhooks": {
        "amqp": [
            {
                "bulkSize": 10,
                "enable": true,
                "password": "secret",
                "predicate": "spel:(contentStreams != null && contentStreams.size() > 0 && contentStreams[0]['range'] != null && contentStreams[0]['range'].length() > 0) ? true : false",
                "queue": "lc.textextraction",
                "type": "object.insert.document",
                "url": "10.10.6.243:5674",
                "user": "clouduser"
            }
        ],
        "webhooks": [
            {
                "enable": true,
                "predicate": "spel:true",
                "type": "user.info",
                "url": "http://organization/api/userinfo/${tenant}/${userId}"
            }
        ]
    }
}
Response Example

200 OK

POST /api/system/systemhooks/validate - Validate the global system hook configuration.
As of Version

2022 Summer

Request Method

POST

Response Format

HTTP status code

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Validates the global system hook configuration.

The content of the global systemHookConfiguration.json configuration file to be validated is specified in the JSON request body. Its structure is validated and has to match the structure described here. Especially, the type of each defined AMQP hook and webhook has to be valid.

To apply a valid global system hook configuration, use the endpoint POST /api/system/systemhooks.

Request Headers

Content-Type: [application/json]

Request Example

/api/system/systemhooks

{
    "systemhooks": {
        "amqp": [
            {
                "bulkSize": 10,
                "enable": true,
                "password": "secret",
                "predicate": "spel:(contentStreams != null && contentStreams.size() > 0 && contentStreams[0]['range'] != null && contentStreams[0]['range'].length() > 0) ? true : false",
                "queue": "lc.textextraction",
                "type": "object.insert.document",
                "url": "10.10.6.243:5674",
                "user": "clouduser"
            }
        ],
        "webhooks": [
            {
                "enable": true,
                "predicate": "spel:true",
                "type": "user.info",
                "url": "http://organization/api/userinfo/${tenant}/${userId}"
            }
        ]
    }
}
Response Example

200 OK

Tracing Endpoints
GET /api/system/calls - Retrieve active DMS calls.
As of Version

2020 Summer

Request Method

GET

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

This endpoint is used to determine all active DMS calls (/api/dms) of the yuuvis® system.

Request Headers

Accept: [application/json]

Request Example

/api/system/calls

Response Example

Each request always returns an array, even if the result set is a single active call. If no active call exists, the response is an empty array.

[
  {
    "traceid": "5709116f3fb6c00a",
    "type": "READ",
    "tenant": "default",
    "method": "GET",
    "request": "/api/dms/objects/440992a0-905c-441a-8724-1ba9beb79e1b/contents/renditions/text",
    "starttime": 1597926536580
  }
]
GET /api/system/calls/{traceid} - Retrieve active DMS call for the specified traceid.
As of Version

2020 Summer

Request Method

GET

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

This endpoint is used to determine all active DMS calls (/api/dms) of the yuuvis® system with the given traceid.

Request Headers

Accept: [application/json]

Request Example

/api/system/calls/5709116F3FB6C00A

Response Example

Each request always returns an array, even if the result set is a single active call. If no active call exists, the response is an empty array.

[
  {
    "traceid": "5709116F3FB6C00A",
    "type": "READ",
    "tenant": "default",
    "method": "GET",
    "request": "/api/dms/objects/440992a0-905c-441a-8724-1ba9beb79e1b/contents/renditions/text",
    "starttime": 1597926536580
  }
]
App Endpoints
GET /api/system/apps - Retrieve all applications
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Retrieves all existing apps in the system.

Response Example
{
  "acl" : { },
  "client" : { },
  "clientsystem" : { },
  "email" : { },
  "invoice" : { },
  "training" : { }
}
GET /api/system/apps/{app}/permissions - Retrieve an application role set.
As of Version

2020 Winter

Request Method

GET

Response Format

XML/JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

This endpoint is used to retrieve the global application permissions file of the yuuvis® system specified by the app URL parameter.

Request Headers

Accept: [application/xml; application/json]

Response Example
Response Body
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<roleSet xmlns="http://optimal-systems.org/ns/dmscloud/roleset/">
    <role>
        <name>ReadDeleteEmail</name>
        <permission>
            <action>read</action>
            <action>delete</action>
            <condition>system:objectTypeId = 'email:email'</condition>
        </permission>
    </role>
    <role>
        <name>ReadDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId = 'document'</condition>
        </permission>
    </role>
    <role>
        <name>ReadEmailAndDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId in ('email:email', 'document')</condition>
        </permission>
    </role>
    <role>
        <name>DeleteDocument</name>
        <permission>
            <action>delete</action>
            <condition>system:objectTypeId in ('document')</condition>
        </permission>
    </role>
    <role>
        <name>AdminRole</name>
        <permission>
            <action>read</action>
            <action>delete</action>
        </permission>
    </role>
</roleSet>
POST /api/system/apps/{app}/permissions - Update an application role set.
As of Version

2020 Winter

Request Method

GET

Response Format

XML/JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

This endpoint is used to update the global application permissions file of the yuuvis® system specified by the app URL parameter. Similar to other schema update endpoints in yuuvis®, this infers a schema validation and returns its result to the user, performing the update only after successful validation.

App names must match a specific regular expression and are limited in their length.

Request Headers

Accept: [application/xml; application/json]

Request Example
Request Body
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<roleSet xmlns="http://optimal-systems.org/ns/dmscloud/roleset/">
    <role>
        <name>ReadDeleteEmail</name>
        <permission>
            <action>read</action>
            <action>delete</action>
            <condition>system:objectTypeId = 'email:email'</condition>
        </permission>
    </role>
    <role>
        <name>ReadDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId = 'document'</condition>
        </permission>
    </role>
    <role>
        <name>ReadEmailAndDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId in ('email:email', 'document')</condition>
        </permission>
    </role>
    <role>
        <name>DeleteDocument</name>
        <permission>
            <action>delete</action>
            <condition>system:objectTypeId in ('document')</condition>
        </permission>
    </role>
    <role>
        <name>AdminRole</name>
        <permission>
            <action>read</action>
            <action>delete</action>
        </permission>
    </role>
</roleSet>
Response Example

The result is a JSON structure containing a validationErrors list, which could be an empty list.

200 - no validation errors, the role set was updated
{
    "validationErrors": []
}
422 - there were validation errors, the role set was not updated
{
    "validationErrors": [
        {
            "message": "Unable to unmarshal schema. [line: 14][column: 13] cvc-complex-type.2.4.a: Ungültiger Content wurde beginnend mit Element 'condition' gefunden. '{\"http://optimal-systems.org/ns/dmscloud/roleset/\":action}' wird erwartet."
        }
    ]
}
POST /api/system/apps/{app}/permissions/validate - Validate an application role set.
As of Version

2020 Winter

Request Method

GET

Response Format

XML/JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

This endpoint is used to validate the global application permissions file of the yuuvis® system specified by the app URL parameter.

App names must match a specific regular expression and are limited in their length.

Request Headers

Accept: [application/xml; application/json]

Request Example
Request Body
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<roleSet xmlns="http://optimal-systems.org/ns/dmscloud/roleset/">
    <role>
        <name>ReadDeleteEmail</name>
        <permission>
            <action>read</action>
            <action>delete</action>
            <condition>system:objectTypeId = 'email:email'</condition>
        </permission>
    </role>
    <role>
        <name>ReadDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId = 'document'</condition>
        </permission>
    </role>
    <role>
        <name>ReadEmailAndDocument</name>
        <permission>
            <action>read</action>
            <condition>system:objectTypeId in ('email:email', 'document')</condition>
        </permission>
    </role>
    <role>
        <name>DeleteDocument</name>
        <permission>
            <action>delete</action>
            <condition>system:objectTypeId in ('document')</condition>
        </permission>
    </role>
    <role>
        <name>AdminRole</name>
        <permission>
            <action>read</action>
            <action>delete</action>
        </permission>
    </role>
</roleSet>
Response Example

The result is a JSON structure containing a validationErrors list, which could be an empty list.

200 - no validation errors, the role set was updated
{
    "validationErrors": []
}
422 - there were validation errors, the role set was not updated
{
    "validationErrors": [
        {
            "message": "Unable to unmarshal schema. [line: 14][column: 13] cvc-complex-type.2.4.a: Ungültiger Content wurde beginnend mit Element 'condition' gefunden. '{\"http://optimal-systems.org/ns/dmscloud/roleset/\":action}' wird erwartet."
        }
    ]
}
GET /api/system/apps/{app}/schema - Retrieve an application schema.
As of Version

2019 Winter

Request Method

GET

Response Format

XML, JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

This endpoint is used to retrieve the application schema matching with the app path parameter.

Request Headers

accept: [application/xml; application/json]

Response Example

The result is a JSON/XML structure containing the application schema

Response Body
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/">
    <version>2</version>
    <lastModificationDate>2020-02-17T22:22:40.532Z</lastModificationDate>
    <propertyStringDefinition>
        <id>from</id>
        <description>system-wide field for the e-mail sender</description>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
        <classification>email</classification>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>to</id>
        <description>system-wide field for the e-mail recipients</description>
        <propertyType>string</propertyType>
        <cardinality>multi</cardinality>
        <required>false</required>
        <classification>email</classification>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>cc</id>
        <description>system-wide field for the e-mail cc</description>
        <propertyType>string</propertyType>
        <cardinality>multi</cardinality>
        <required>false</required>
        <classification>email</classification>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>bcc</id>
        <description>system-wide field for the e-mail bcc</description>
        <propertyType>string</propertyType>
        <cardinality>multi</cardinality>
        <required>false</required>
        <fulltextIndexed>false</fulltextIndexed>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>subject</id>
        <description>system-wide field for the e-mail subject</description>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
        <defaultValue>Krähenschädel</defaultValue>
    </propertyStringDefinition>
    <propertyIntegerDefinition>
        <id>attachmentcount</id>
        <description>system-wide field for the e-mail attachment count</description>
        <propertyType>integer</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
        <defaultValue>0</defaultValue>
    </propertyIntegerDefinition>
    <propertyStringDefinition>
        <id>attachmentnames</id>
        <description>system-wide field for the e-mail attachment names</description>
        <propertyType>string</propertyType>
        <cardinality>multi</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <propertyTableDefinition>
        <id>meta</id>
        <description>Additional data</description>
        <propertyType>table</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
        <propertyStringDefinition>
            <id>key</id>
            <description>Key of this additional data entry.</description>
            <propertyType>string</propertyType>
            <cardinality>single</cardinality>
            <required>false</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>value</id>
            <description>Value of this additional data entry.</description>
            <propertyType>string</propertyType>
            <cardinality>single</cardinality>
            <required>false</required>
        </propertyStringDefinition>
    </propertyTableDefinition>
    <propertyStringDefinition>
        <id>messageid</id>
        <description>system-wide field for the e-mail message id</description>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <propertyDateTimeDefinition>
        <id>received</id>
        <description>system-wide field for the e-mail received</description>
        <propertyType>datetime</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyDateTimeDefinition>
    <propertyStringDefinition>
        <id>exchangeid</id>
        <description>system-wide field for the e-mail exchange id</description>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <typeDocumentDefinition>
        <id>email</id>
        <baseId>system:document</baseId>
        <propertyReference>from</propertyReference>
        <propertyReference>to</propertyReference>
        <propertyReference>cc</propertyReference>
        <propertyReference>bcc</propertyReference>
        <propertyReference>subject</propertyReference>
        <propertyReference>attachmentcount</propertyReference>
        <propertyReference>attachmentnames</propertyReference>
        <propertyReference>meta</propertyReference>
        <propertyReference>messageid</propertyReference>
        <propertyReference>received</propertyReference>
        <propertyReference>exchangeid</propertyReference>
        <contentStreamAllowed>required</contentStreamAllowed>
        <secondaryObjectTypeId>appAcl:aclowner</secondaryObjectTypeId>
    </typeDocumentDefinition>
</schema>
POST /api/system/apps/{app}/schema - Update the schema of the specified application.
As of Version

2019 Winter

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

This endpoint is used to update the application schema matching with the app path parameter. Similar to other schema update endpoints in yuuvis®, this infers a schema validation and returns its result to the user, performing the schema update only after successful validation.

App names must match a specific regular expression and are limited in their length.

Request Headers

Content-Type: application/xml

Response Example

The result is a JSON structure containing a validationErrors list, which could be an empty list.

200 - no validation errors, the schema has been updated
{
    "validationErrors": []
}
422 - there were validation errors, the schema was not updated
{
    "validationErrors": [
        {
            "message": "Wrong base id. The base id of the system:document type definition 'appEmail:email' must be 'system:document', but it is 'system:folder'.",
            "serviceErrorCode": 2131
        },
        {
            "message": "Invalid property reference 'fromm' in type definition 'appEmail:email'.",
            "serviceErrorCode": 2132
        },
        {
            "message": "Invalid property reference 'ccd' in type definition 'appEmail:email'.",
            "serviceErrorCode": 2132
        }
    ]
}
POST /api/system/apps/{app}/schema/validate - Validate the schema of the specified application.
As of Version

2019 Winter

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

This endpoint is used to validate a schema file to be used for the application matching with the app path parameter. The result is returned to the user.

App names must match a specific regular expression and are limited in their length.

Request Headers

Content-Type: application/xml

Response Example

The result is a JSON structure containing a validationErrors list, which could be an empty list.

200 - no validation errors, the schema has been updated
{
    "validationErrors": []
}
422 - there were validation errors, the schema was not updated
{
    "validationErrors": [
        {
            "message": "Wrong base id. The base id of the system:document type definition 'appEmail:email' must be 'system:document', but it is 'system:folder'.",
            "serviceErrorCode": 2131
        },
        {
            "message": "Invalid property reference 'fromm' in type definition 'appEmail:email'.",
            "serviceErrorCode": 2132
        },
        {
            "message": "Invalid property reference 'ccd' in type definition 'appEmail:email'.",
            "serviceErrorCode": 2132
        }
    ]
}
GET /api/system/apps/{app}/systemhooks - Retrieve the system hook configuration of the specified application.
As of Version

2022 Summer

Request Method

GET

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Retrieves the app-specific system hook configuration for the app specified in the request URL.

The content of the app-specific systemHookConfiguration.json configuration file is returned. The configured System Hooks are available only for the concrete App. Note: The app-specific system hooks are available only in tenants where the corresponding app is enabled.

An error with status code 404 is thrown if the specified app does not exist or no system hooks are configured for the specified app.

Request Headers

Accept: [application/json]

Request Example

/api/system/apps/myapp/systemhooks

Response Example
Response Body
{
    "systemhooks": {
        "amqp": [],
        "webhooks": [
            {
                "enable": true,
                "predicate": "spel:T(java.util.List).of(300).contains(options['action'])",
                "type": "dms.request.objects.upsert.storage-before",
                "url": "http://examplewebhook/api/dms/request/objects/update/metadata",
                "useDiscovery": true
            }
        ]
    }
}
POST /api/system/apps/{app}/systemhooks - Update the system hook configuration of the specified application.
As of Version

2022 Summer

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Updates the app-specific system hook configuration for the app specified in the request URL.

The content of the app-specific systemHookConfiguration.json configuration file is replaced by the configuration specified in the request body. Its structure is validated and has to match the structure described here. Especially, the type of each defined AMQP hook and webhook has to be valid.

It is not allowed to configure an app-specific webhook with the user.info type.

The configured system hooks are available only for the specified app.

The app-specific system hooks are available only in tenants in which the corresponding app is enabled.

If the specified app does not exist, it is created.

App names must match a specific regular expression and are limited in their length.

The changes are applied immediately after a successful update of the configuration.

Request Headers

Content-Type: [application/json]

Request Example

/api/system/apps/myapp/systemhooks

Request Example
{
    "systemhooks": {
        "amqp": [],
        "webhooks": [
            {
                "enable": true,
                "predicate": "spel:T(java.util.List).of(300).contains(options['action'])",
                "type": "dms.request.objects.upsert.storage-before",
                "url": "http://examplewebhook/api/dms/request/objects/update/metadata",
                "useDiscovery": true
            }
        ]
    }
}
Response Example

200 OK

POST /api/system/apps/{app}/systemhooks/validate - Validate the system hook configuration of the specified application.
As of Version

2022 Summer

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Validates the app-specific system hook configuration for the app specified in the request URL.

The content of the app-specific systemHookConfiguration.json configuration file to be validated is specified in the JSON request body. Its structure is validated and has to match the structure described here. Especially, the type of each defined AMQP hook and webhook has to be valid.

It is not allowed to configure an app-specific webhook with the user.info type.

App names must match a specific regular expression and are limited in their length.

To apply a valid app-specific system hook configuration, use the endpoint POST /api/system/apps/{app}/systemhooks.

Request Headers

Content-Type: [application/json]

Request Example

/api/system/apps/myapp/systemhooks/validate

Request Body
{
    "systemhooks": {
        "amqp": [],
        "webhooks": [
            {
                "enable": true,
                "predicate": "spel:T(java.util.List).of(300).contains(options['action'])",
                "type": "dms.request.objects.upsert.storage-before",
                "url": "http://examplewebhook/api/dms/request/objects/update/metadata",
                "useDiscovery": true
            }
        ]
    }
}
Response Example

200 OK

Tenant Endpoints

Operations on the resources of any tenant in the system.

Apps
GET /api/system/tenants/{tenant}/apps - Retrieve tenant app set.
As of Version

2021 Summer

Request Method

GET

Response Format

XML

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Retrieves the app set for the specified tenant.

The content of the corresponding app set configuration file apps.xml is returned. Not-listed apps are disabled.

If the file does not exist, the error code 404 will be returned.

Request Headers

Accept: [application/xml]

Request Example

/api/system/tenants/mytenant/apps

Response Example

App set of the specified tenant mytenant in the response body.

Response Body: example apps.xml
<?xml version="1.0" encoding="utf-8"?>
<apps xmlns="http://optimal-systems.org/ns/yuuvis/apps/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://optimal-systems.org/ns/yuuvis/apps/ yuuvis-core-apps.xsd">
    <app>
        <name>clientsystem</name>
        <state>enabled</state>
    </app>
    <app>
        <name>client</name>
        <state>enabled</state>
    </app>
    <app>
        <name>email</name>
        <state>disabled</state>
    </app>
    <app>
        <name>acl</name>
        <state>disabled</state>
    </app>
</apps>
POST api/system/tenants/{tenant}/apps - Update tenant app set.
As of Version

2021 Summer

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Updates the app set for the specified tenant.

The request body contains the XML configuration to be stored as app set for the tenant in the corresponding apps.xml file.

The call infers a validation and returns its result to the user, performing the update only after successful validation.

App names must match a specific regular expression and are limited in their length.

Request Headers

Content-Type: application/xml

Request Example

XML configuration in the request body.

Request Body
<?xml version="1.0" encoding="utf-8"?>
<apps xmlns="http://optimal-systems.org/ns/yuuvis/apps/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://optimal-systems.org/ns/yuuvis/apps/ yuuvis-core-apps.xsd">
    <app>
        <name>clientsystem</name>
        <state>enabled</state>
    </app>
    <app>
        <name>client</name>
        <state>enabled</state>
    </app>
    <app>
        <name>email</name>
        <state>disabled</state>
    </app>
    <app>
        <name>acl</name>
        <state>disabled</state>
    </app>
</apps>
Response Example

(1) Successful update: The result is a JSON structure containing a validationErrors list, which could be an empty list.

200 – no validation errors, the apps for the tenant have been updated
{
    "validationErrors": []
}

(2) Unsuccessful: Example error message.

422 – validation errors, the apps have not been updated
{
    "validationErrors": [
        {
            "message": "Unable to disable app 'client' and enable app 'invoice'. There are references from the schema of app 'invoice' to the schema of app 'client'."
        }
    ]
}
POST /api/system/tenants/{tenant}/apps/validate - Validate tenant app set.
As of Version

2021 Summer

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Validates the app set for the specified tenant.

The request body contains the XML configuration to be validated as app set for the tenant.

The validation of the app set considers dependencies between different app and tenant schemata via property references or secondary object type references. If the schema of an app is referenced by the global or the corresponding tenant schema, the app cannot be disabled for the specified tenant. For instance if the app invoice depends on the app client, it is not possible to enable invoice and disable client.

There is no validation for the existence of apps with the specified names.

Request Headers

Content-Type: application/xml

Request Example

XML configuration in the response body.

<?xml version="1.0" encoding="utf-8"?>
<apps xmlns="http://optimal-systems.org/ns/yuuvis/apps/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://optimal-systems.org/ns/yuuvis/apps/ yuuvis-core-apps.xsd">
    <app>
        <name>clientsystem</name>
        <state>enabled</state>
    </app>
    <app>
        <name>client</name>
        <state>enabled</state>
    </app>
    <app>
        <name>email</name>
        <state>disabled</state>
    </app>
    <app>
        <name>acl</name>
        <state>disabled</state>
    </app>
</apps>
Response Example

(1) Successful update: The result is a JSON structure containing a validationErrors list, which could be an empty list.

200 – no validation errors, the role set has been updated
{
    "validationErrors": []
}

(2) Unsuccessful: Example error message.

422 – validation errors, the role set has not been updated
{
    "validationErrors": [
        {
            "message": "Unable to disable app 'client' and enable app 'invoice'. There are references from the schema of app 'invoice' to the schema of app 'client'."
        }
    ]
}
Metrics
GET /api/system/tenants/{tenant}/metrics/{metric} - Retrieve a tenant metric.
As of Version

2023 Spring

Request Method

GET

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and if the specified access condition is matched.

Description

Retrieve the specified metric for the specified tenant.

Following values are available for the metric path parameter:

  • storage - The endpoint retrieves the dynamically calculated binary storage used by the specified tenant.

  • objectCount (as of 2023 Summer) - The endpoint retrieves the number of DMS objects within the specified tenant.

Request Examples

(A) /api/system/tenants/yuuvistest/metrics/storage

(B) /api/system/tenants/yuuvistest/metrics/objectCount

Response Examples
(A)
{
  "objects": [
    {
      "properties": {
        "system:tenant": {
          "value": "yuuvistest"
        }
      },
      "options": {
        "storageUsed": {
          "humanReadable": "121 MB",
          "value": 127508469
        }
      }
    }
  ],
  "numItems": 1,
  "hasMoreItems": false,
  "totalNumItems": 1
}
(B)
{
    "objects": [{
            "properties": {
                "system:tenant": {
                    "value": "yuuvistest"
                }
            },
            "options": {
                "objectCount": {
                    "totalFolderCount": 97,
                    "totalObjectCount": 1733
                }
            }
        }
    ],
    "numItems": 1,
    "hasMoreItems": false,
    "totalNumItems": 1
}
DELETE /api/system/tenants/{tenant}/metrics/{metric} - Reset a tenant metric.
As of Version

2023 Spring

Request Method

DELETE

Response Format

HTTP status code

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Reset the specified metric for the specified tenant.

Not available for the storage metric. Use DELETE /api/system/metrics/{metric} instead.

Role Set
GET /api/system/tenants/{tenant}/permissions - Retrieve a tenant role set.
As of Version

2022 Autumn

Request Method

GET

Response Format

XML

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Retrieves the tenant-specific role set for the tenant specified in the request URL.

The content of the tenant-specific role set is returned. The configured roles are available only for the concrete tenant.

Request Headers

Accept: [application/xml]

Request Example

/api/system/tenants/mytenant/permissions

Response Example

see GET /api/system/permissions

POST /api/system/tenants/{tenant}/permissions - Update a tenant role set.
As of Version

2022 Autumn

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Updates the tenant-specific role set for the tenant specified in the request URL.

The content of the tenant-specific role set is replaced by the configuration specified in the request body. The configured roles are available only for the concrete tenant.

Request Headers

Content-Type: application/xml

Request Example

/api/system/tenants/mytenant/permissions

Response Example

see POST /api/system/permissions

POST /api/system/tenants/{tenant}/permissions/validate - Validate a tenant role set.
As of Version

2022 Autumn

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Validates the tenant-specific role set for the tenant specified in the request URL.

The content of the tenant-specific role set to be validated is specified in the JSON request body. To apply the configuration, use the endpoint POST /api/system/tenants/{tenant}/permissions.

Request Headers

Content-Type: application/xml

Request Example

/api/system/tenants/mytenant/permissions

Response Example

see POST /api/system/permissions/validate

Schema
GET /api/system/tenants/{tenant}/schema - Retrieve the schema of the specified tenant.
As of Version

2021 Autumn

Request Method

GET

Response Format

XML, JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Retrieves the tenant schema that is stored for the tenant matching the tenant path parameter.

The schema is provided in an XML or JSON structure in the response body.

Request Headers

Accept:[application/xml; application/json]

Response Example
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/">
    <version>1</version>
    <lastModificationDate>2019-03-25T10:25:46.212Z</lastModificationDate
    <propertyStringDefinition>
        <id>from</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>true</required>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>to</id>
        <propertyType>string</propertyType>
        <cardinality>multi</cardinality>
        <required>true</required>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>subject</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>true</required>
        <maxLength>60</maxLength>
    </propertyStringDefinition>
    <propertyDateTimeDefinition>
        <id>received</id>
        <propertyType>datetime</propertyType>
        <cardinality>single</cardinality>
        <required>true</required>
    </propertyDateTimeDefinition>
    <typeDocumentDefinition>
        <id>email</id>
        <baseId>system:document</baseId>
        <propertyReference>from</propertyReference>
        <propertyReference>to</propertyReference>
        <propertyReference>received</propertyReference>
        <contentStreamAllowed>required</contentStreamAllowed>
    </typeDocumentDefinition>
</schema>
POST /api/system/tenants/{tenant}/schema - Update the schema of the specified tenant.
As of Version

2021 Autumn

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Updates the tenant schema stored for the tenant specified by the tenant path parameter.

The new schema is passed in the request body in XML format and is validated before the update is executed. Thus, it is not possible to introduce an invalid schema via this endpoint.

For details and examples regarding request and response please visit Schema - Defining Object Types.

Request Headers

Content-Type: application/xml

POST /api/system/tenants/{tenant}/schema/validate - Validate the schema of the specified tenant.
As of Version

2021 Autumn

Request Method

POST

Response Format

JSON

Required Permission

available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched.

Description

Validate the XML file passed in the request body for the usability as tenant schema for the tenant specified by the tenant path parameter.

The currently used tenant schema is NOT updated.

For details and examples regarding request and response please visit schema.

Request Headers

Content-Type: application/xml

2.11.4. Endpoints for PDF/A-3 Renditions

Endpoints Available on Request
These rendition endpoints are offered in a separate API as an extra service and are available only on request. This API is not included in yuuvis® Momentum installations.
POST /api/renditions/pdf?level=pdfa3 - Create and retrieve a PDF/A-3 rendition for an e-mail.
Endpoint Available on Request
This endpoint is offered in a separate API that is available only on request. It is not included in yuuvis® Momentum installations.
As of Version

2020 Winter

Request Method

POST

Response Format

PDF/A-3

Description

To return the PDF/A-3 rendition of the e-mail object, send the request with the e-mail file as binary in the request body.

The endpoint URL contains the specification of the level parameter set to the value to pdfa3. Other values for the level parameter are not accepted.

Synchronously converts all convertible parts of an e-mail including its first order attachments into the format PDF/A-3. The original e-mail itself will be included as a PDF attachment as well.

Requires an e-mail object. A successful POST returns the HTTP status code 200 together with the PDF/A-3 document in the body.

The endpoint accepts the following e-mail attachment file types for the conversion into PDF/A-3 document pages:

Types Extension Note

Portable Document Format

pdf

As of 2021 Autumn: ZIP Archive File Format

zip

The content files of the zip archive will be converted individually and included into the PDF/A-3 file in the order of their sorting in the archive.

The files inside the zip archive have to meet at least one of the following conditions:

  • All files have the same convertible file type.

  • All files are image files of supported types as listed below. Different types are allowed within one zip archive.

The content files of a zip archive will not be converted if at least one zip archive is among them as well.

Microsoft Office and Excel file types

MS Office Word 97-2016

doc, docx

MS Office PowerPoint 97-2016

ppt, pptx

MS Office Excel 97-2016

xls, xlsx

OpenDocument Text

odt

OpenDocument Presentation

odp

OpenDocument Spreadsheet

ods

Visio Drawing File

vsd, vsdx

limited range of functions

Image File Types

Tagged Image File Format

tiff, tif

Portable Bitmap Image

pbm

Bitmap Image File

bmp

Graphical Interchange Format File

gif

JPEG Image

Exchangeable image file format (JPEG)

jpg, jng, jpeg

Portable Network Graphic

png

Weppy Image Format (Lossy Compression)

webp

As of 2021 Autumn: High Efficiency Image File Format (HEIF)

heif, heic

Response HTTP status codes:

HTTP status code Meaning

200

Successful, converted document provided in the response body

413

Document file too large

415

Document format not supported

422

Timeout

422

Document could not be converted

422

Invalid input parameters

Request Header

Content-Type: message/rfc822 or application/vnd.ms-outlook

Content-Disposition: attachment; filename=<filename>; filename*=<filename-encoded>.

To set the filename of the new content file. The parameters "filename" and "filename*" differ only in that "filename*" uses the encoding defined in RFC 5987. When both "filename" and "filename*" are present in a single header field value, "filename*" is preferred over "filename".

Request Example

The e-mail file is passed as binary in the request body.

Result Example

HTTP status code: 200

Response body with PDF/A-3 document.

2.12. Cluster-Internal API

Endpoints of services for interactions within the cluster.

2.12.1. '/manage/*' Endpoints

Use monitoring and maintenance endpoints of a service running in your yuuvis® Momentum cluster.

The core services offer /manage/* endpoints to retrieve service-specific operational information, reload configurations or execute other maintenance operations. These endpoints are intended to be called by other services within the cluster. Most services use the functionality of the Spring Boot Actuator. However, for some services, the basic behavior is adjusted or extended.

The /manage/* endpoints provided by the authentication Service are available via a separate port which is protected from external access. Even if they are exposed for access without a specific authorization in the authentication-prod.yml file, they are accessible only for services inside the Kubernetes cluster. In order to call these endpoints, the ancillary Kubernetes Service authentication-manage-service controls the separate port. Thus, the endpoints are called via /authentication-manage/manage/*.

GET <service>/manage/health - Check a service’s status.
Usage

Check the current status of a service running in your yuuvis® Momentum cluster.

Services

Available for all services including additional services. The JSON structure always contains at least the "status" key with the value being either "UP" or "DOWN".

POST <service>/manage/refresh - Reload a service’s configuration.
Usage

Reload configurations for the specified service without a service restart.

Services with adjusted behavior
  • authentication service (as of version 2022 Autumn)

  • configservice

    A refresh leads to a synchronization of local resources and the git server in addition to the regular synchronization cycle.

2.12.2. Endpoints of 'authentication' Service

GET /authentication-internal/session/invalidateAll/{userId} - Invalidate all user sessions
Internal Endpoint
This endpoint is available only for services within the yuuvis® Momentum cluster. Never expose it for public access in the authentication-prod.yml configuration file.
As of Version

2022 Summer

Request Method

GET

Response Format

JSON

Description

Invalidates all active sessions of the user specified by userId.

If the request was successfully processed, the response body is empty. The response does not inform about the number of invalidated sessions for the specified user. Especially, if the specified user has no active sessions, the endpoint does not invalidate any session but still confirms that the request was successfully processed.

In case an error occurs, the request body contains details.

Request Example
curl http://authentication-internal/session/invalidateAll/406b5a28-7a8b-4c36-a569-df7bff480375
Response Example

200 OK

GET /authentication-internal/session/updateUserAttributesCache/{tenant}/{userId} - Retrieve user attributes from cache or add them to cache.
Internal Endpoint
This endpoint is available only for services within the yuuvis® Momentum cluster. Never expose it for public access in the authentication-prod.yml configuration file.
As of Version

2023 Autumn

Request Method

GET

Response Format

JSON

Description

Stores the user attributes for the requested user specified by tenant and userId in a Redis cache.

The parameter authorization.cacheUserAttributes in authentication-prod.yml has to be set to true. This means that authorities information (and abac information if available) are not stored in the JWT but in a Redis cache instead to reduce the header size of cluster-internal HTTP requests.

If authorization.cacheUserAttributes is false (default), the user attributes are retrieved without storing them in a cache.

The authentication service retrieves the user’s attributes

  • either from the Redis cache or,

  • if not available in the cache, via GET user.info webhook and stores them in the cache.

If the request was successfully processed, the user’s attributes are returned in JSON format in the response body.

Request Example

curl http://authentication-internal/session/updateUserAttributeCache/yuuvistest/406b5a28-7a8b-4c36-a569-df7bff480375

Response Example

200 OK

Response Body
{
    "username": "mustermann",
    "id": "406b5a28-7a8b-4c36-a569-df7bff480375",
    "credentialsNonExpired": true,
    "accountNonExpired": true,
    "accountNonLocked": true,
    "enabled": true,
    "tenant": "yuuvistest",
    "authorities": [
        "TENANT_ADMIN",
        "SYSTEM_INTEGRATOR",
        "ACCESS_MAILBOXES"
    ],
    "abac": {
      "mailGroups": [
           "mailbox_sales",
           "mailbox_pm"
       ],
       "sap_permissions": [
           "sap_read",
           "sap_write"
       ]
    }
}
GET /authentication-internal/jwt/verify - Validate the internal JWT
Internal Endpoint
This endpoint is available only for services within the yuuvis® Momentum cluster. Never expose it for public access in the authentication-prod.yml configuration file.
As of Version

2021 Autumn

Request Method

GET

Response Format

JSON

Request Header

Authorization

Description

Validates the internal JSON Web Token (JWT) that is assigned to an HTTP request.

If the signature of the JWT matches its header and payload, the validation will be successful and the response body contains true. If the validation fails, the response body contains false.

In order to activate the validation, manual configuration is required.

Request Example
curl http://authentication-internal/jwt/verify
Response Example

true

GET /authentication-internal/jwt/token - Retrieve an internal JWT
Internal Endpoint
This endpoint is available only for services within the yuuvis® Momentum cluster. Never expose it for public access in the authentication-prod.yml configuration file.
As of Version

2022 Autumn

Request Method

GET

Response Format

text/plain;charset=utf-8

Request Header

Authorization with internal Bearer token

Description

Requests an internal JSON Web Token (JWT) that can be used by a service account to access internal endpoints of services running within the yuuvis® Momentum cluster.

The endpoint requires either basic authentication (Example A) or a token provided by the identity provider (Example B) retrieved via its OIDC interface.

Request Example

Example A

curl -H "Authorization: Basic dXNyOnB3ZA==" -H "X-ID-TENANT-NAME: tenant" http://authentication-internal/jwt/token

Example B

curl -H "Authorization: Bearer eyJhbGci..." -H "X-ID-TENANT-NAME: tenant" http://authentication-internal/jwt/token
Response Example
Bearer eyJraWQiOiJqd3Qtc2lnbmluZy1rZXkiLCJhbGciOiJSUzI1NiJ9.eyJzd...
GET /authentication-internal/manage/refreshTenants - Refresh the tenant configuration
Internal Endpoint
This endpoint is available only for services within the yuuvis® Momentum cluster. Never expose it for public access in the authentication-prod.yml configuration file.
As of Version

2022 Autumn

Request Method

GET

Response Format

HTTP status code

Request Header

Authorization with internal Bearer token

Description

The endpoint /authentication-internal/manage/refreshTenants can be used to activate changes in the tenant configuration instead of the conventional refresh endpoint. Only changes in the authentication.oauth2.tenants list in the application-oauth2.yml configuration file are considered. Thus, the creation or modification of tenants can be carried out much faster.

Tenants that were removed from the configuration are NOT automatically deleted.
Request Example
curl http://authentication-internal/manage/refreshTenants
Response Example

200 OK

2.12.3. Endpoints of 'configservice'

POST /configservice/manage/refresh - Synchronize local resources and the git server in addition to the regular synchronization cycle.
Internal Endpoint
This endpoint is available only for services within the yuuvis® Momentum cluster. Never expose it for public access in the authentication-prod.yml configuration file.
As of Version

2022 Summer

Request Method

POST

Response Format

HTTP status code

Required Permission

successful authentication

Description

Synchronizes the local resources of the configservice running on the specified port and the remote resources on the git server.

This synchronization is additional and independent of the automated synchronization every 5 minutes.

The endpoint is a standard Spring Boot Actuator endpoint.

Request Example

http://10.11.8.276:7281/manage/refresh

Response Example

200 OK

POST /configservice/api/resources/{resourceName}/path/{pathName} - Update a global configuration file.
Internal Endpoint
This endpoint is available only for services within the yuuvis® Momentum cluster. Never expose it for public access in the authentication-prod.yml configuration file.
HTTP Method

POST

Response Format

HTTP status code

Required Permission

successful authentication

Description

Updates the global configuration file specified by resourceName in Git at the path specified by pathName.

In the value for pathName, use | characters instead of / or \ characters.

The previous file is replaced by the new file in the request body.

To apply the new configuration, after the successful update, all services that reference the contained configuration parameters have to be refreshed/restarted.

Request Example

The following example request updates the application-oauth2.yml configuration file in order to introduce new tenants.

After successful resource update, the following endpoints have to be called to apply the new configuration:

cURL example for unix bash
curl -s -i -k -X POST --url "http://configservice.yuuvis/api/resources/application-oauth2.yml/path/|" \
-H "Content-Type: multipart/form-data; boundary=--------------------------522935013788975240240820" \
--data-binary '----------------------------522935013788975240240820
Content-Disposition: form-data; name="resource"; filename=""
Content-Type: application/json



keycloak.host: 192.168.62.151:30111
authentication.oauth2.tenants:
- name: yuuvistest
  clientId: yuuvis-authentication-service
  clientSecret: dbdf4856-3c86-4e5f-aca7-96f3d93d35b4
  userAuthorizationUri: https://${keycloak.host}/auth/realms/yuuvistest/protocol/openid-connect/auth
  accessTokenUri: https://${keycloak.host}/auth/realms/yuuvistest/protocol/openid-connect/token
  userInfoUri: https://${keycloak.host}/auth/realms/yuuvistest/protocol/openid-connect/userinfo
  endSessionUri: https://${keycloak.host}/auth/realms/yuuvistest/protocol/openid-connect/logout
  userNameExtractionPattern: $.sub
  scope: openid
- name: testyuuvis
  clientId: yuuvis-authentication-service
  clientSecret: 61048b73-8cd7-4682-b78c-786c5dc8a2a1
  userAuthorizationUri: https://${keycloak.host}/auth/realms/testyuuvis/protocol/openid-connect/auth
  accessTokenUri: https://${keycloak.host}/auth/realms/testyuuvis/protocol/openid-connect/token
  userInfoUri: https://${keycloak.host}/auth/realms/testyuuvis/protocol/openid-connect/userinfo
  endSessionUri: https://${keycloak.host}/auth/realms/testyuuvis/protocol/openid-connect/logout
  userNameExtractionPattern: $.sub
  scope: openid
# configuration for the yuuvis organization service
keycloak.server: https://keycloak-https.infrastructure/auth
keycloak.admin.username: keycloak
keycloak.admin.password: changeme
----------------------------522935013788975240240820--'
Response Example

200 OK

no response body

POST /search/api/search/dsl/check - Retrieve the object types that are available for all available actions on DMS objects for the currently logged-in user.
Internal Endpoint
This endpoint is available only for services within the yuuvis® Momentum cluster. Never expose it for public access in the authentication-prod.yml configuration file.
As of Version

2021 Winter

Request Method

GET

Response Format

JSON

Description

Retrieves the object types that are available for all available actions on DMS objects for the currently logged-in user. Available actions are create, write, read and delete (see role set documentation).

The response body is a JSON structure listing the object types grouped in instantiable object types (including folder and document object types) and secondary object types for each action. Every missing action in the response map indicates a prohibited action for this user.

The list of available object types might contain types that are forbidden under specific conditions defined in the role set. If a role contains a permission for the specified action that is limited by a condition, this condition can reference type-specific metadata properties. In this case, the entire condition is always evaluated as true.
Request Example

https://<host>/search/api/search/dsl/check

Response Example
{
    "CREATE": {
        "secondaryObjectTypeIds": [],
        "objectTypeIds": []
    },
    "WRITE": {
        "secondaryObjectTypeIds": [
            "system:rmDestructionRetention",
            "appClient:clientdefaults"
        ],
        "objectTypeIds": [
            "email:email",
            "appEmail:email"
        ]
    },
    "READ": {
        "secondaryObjectTypeIds": [
            "system:rmDestructionRetention",
            "appClient:clientdefaults"
        ],
        "objectTypeIds": [
            "email:email",
            "appEmail:email",
            "document:invoice"
        ]
    }
}
POST /search/api/search/dsl/check/{action} - Retrieves the object types that are available for the specified action on DMS objects for the currently logged-in user.
Internal Endpoint
This endpoint is available only for services within the yuuvis® Momentum cluster. Never expose it for public access in the authentication-prod.yml configuration file.
As of Version

2021 Winter

Request Method

GET

Response Format

JSON

Description

Retrieves the object types that are available for the specified action on DMS objects for the currently logged-in user. Available options are create, write, read and delete (see role set documentation).

The response body is a JSON structure listing the object types grouped in instantiable object types (including folder and document object types) and secondary object types. An empty response map indicates a prohibited action for this user.

The list of available object types might contain types that are forbidden under specific conditions defined in the role set. If a role contains a permission for the specified action that is limited by a condition, this condition can reference type-specific metadata properties. In this case, the entire condition is always evaluated as true.
Request Example

https://<host>/search/api/search/dsl/check/create

Response Example
{
    "CREATE": {
        "secondaryObjectTypeIds": [
            "system:rmDestructionRetention",
            "appClient:clientdefaults"
        ],
        "objectTypeIds": [
            "email:email".
            "appEmail:email"
        ]
    }
}

2.12.5. Endpoints of 'audit' Service

POST /audit/api/dms/objects/custom - Store a custom audit entry.
Internal Endpoint
This endpoint is available only for services within the yuuvis® Momentum cluster. Never expose it for public access in the authentication-prod.yml configuration file.
As of Version

2022 Spring

Request Method

POST

Request Headers
  • Required headers:

    • Content-Type: application/json

    • Authorization: Bearer eyJraW…​

      Contains the internal token (JWT) that the custom service receives from the corresponding caller.

  • Optional header:

    • x-b3-traceid: 6494b222b4a0c111

      Contains the traceId if the custom service receives it from the corresponding caller.

Response Format

HTTP status code

Specific Error Codes

see Error Handling

Required Permission

successful authentication

Description

Stores a custom audit entry specified in the JSON request body.

This internal endpoint of the audit Service can be called by custom services running inside the yuuvis® Momentum cluster in order to allow for the creation of custom audit entries.

The following values are stored in the corresponding database table:

Column Field value determined by Comment

objectid

database

referredobjectid

request body, property referredObjectId

Required.

Specifies the system:objectId of the DMS object for which the audit entry is stored.

creationdate

database

createdby

JWT

tenant

JWT

action

-

The value 10000 is always set.

traceid

x-b3-traceid request header if available. If not specified, a null value is set.

detail

request body, property detail

versionnumber

request body, property system:versionNumber

Required.

Specifies the DMS object version for which the audit entry is stored.

subaction

request body, property subaction

Can be used to store any integer that can be used to differentiate between multiple types of custom audit entries.

As every audit entry, a custom audit entry can be retrieved via the endpoint GET /api/dms/objects/{objectId}/history.

Request Example
{
  "objects": [
    {
      "properties":
      {
        "detail": {
          "value": "custom details"
        },
        "subaction": {
          "value": 4321
        },
        "referredObjectId": {
          "value": "a7facd2f-0354-490f-8eb3-59a47649492c"
        },
        "system:versionNumber": {
          "value": 2
        }
      }
    }
  ]
}
Response Example

200 OK

2.13. Infrastructure

2.13.1. Database Schema

yuuvis® Momentum core uses multiple database tables that are structured as described below. The specification of the data type enables the appropriate handling of the data columns.

The individual databases have to be configured in the application-dbs.yml configuration file. The supported database providers are listed in the yuuvis® Momentum Requirements section.

General Description

Each database for yuuvis® Momentum core consists of the following five tables:

  • dmsobject

  • dmsobject_oldversions

  • auditentry

  • DATABASECHANGELOG

  • DATABASECHANGELOGLOCK

Please note that these five tables contain only metadata, but no content data.

Table 'dmsobject'

This table contains the metadata for the current version of each object stored in yuuvis® Momentum. The data types apply to the database types postgresql and cockroachdb. Due to the use of JSON for some columns, the table structure can be kept slim. The table contains the following columns:

Column

Description

Data Type (max. length)

objectid

Corresponds to the general object property system:objectId.

uuid

versionnumber

Corresponds to the general object property system:versionNumber.

int

basetypeid

Corresponds to the general object property system:baseTypeId.

varchar(36)

objecttypeid

Corresponds to the general object property system:objectTypeId.

varchar(1024)

createdby

Corresponds to the general object property system:createdBy.

varchar(256)

lastmodifiedby

Corresponds to the general object property system:lastModifiedBy.

varchar(256)

creationdate

Corresponds to the general object property system:creationDate.

timestamptz

lastmodificationdate

Corresponds to the general object property system:lastModificationDate.

timestamptz

properties

Stores all properties and their values that are assigned to the object based on its object type.

json

tenant

Corresponds to the general object property system:tenant.

varchar(256)

contextid

varchar(64)

rendition

Stores all properties and their values that describe available renditions for the object.

json

cs_length

Corresponds to the content stream property length.

bigint

cs_mimetype

Corresponds to the content stream property mimeType.

varchar(128)

cs_filename

Corresponds to the content stream property fileName.

varchar(1024)

cs_digest

Corresponds to the content stream property digest.

varchar(64)

cs_contentstreamid

Corresponds to the content stream property contentStreamId.

varchar(1024)

cs_repositoryid

Corresponds to the content stream property repositoryId.

varchar(64)

acl

json

internaldata

int

cs_range

Corresponds to the content stream property range.

varchar(2048)

traceid

Corresponds to the general object property system:traceId.

varchar(64)

versionnumber

cs_archivepath

Corresponds to the content stream property archivePath.

varchar(2048)

tags

Corresponds to the general object property system:tags.

json

deleted

Flags the object to be invisible for users after a deletion request until the deletion process is completed.

boolean

Table 'dmsobject_oldversions'

This table contains the same columns as the dmsobject table, but WITHOUT the last two columns tags and deleted. These two columns correspond to properties that are only available for the current version of objects.

Table 'auditentry'

Each action applied to an object is documented in the object’s audit trail. This information is managed using the auditentry table. The data types apply to the database types postgresql and cockroachdb. This table contains the following columns:

Column

Description

Data Type (max. length)

objectid

Identifies the audit entry.

bigint; primarykey

referredobjectid

Identifies the object for which the entry was written. Corresponds to the general object property system:objectId.

varchar(36)

creationdate

Unique date and time of the audit entry creation to ensure traceability.

timestamptz

createdby

ID of the user who requested the action for which the audit entry is created.

varchar(256)

tenant

Identifies the tenant the user specified in createdby belongs to. Corresponds to the options property tenant.

varchar(256)

action

Three digit long history code indicating how the object was imported, deleted, updated, or retrieved.

int

traceid

Unique ID to ensure traceability.

varchar(64)

detail

Description of the history code.

varchar(256)

versionnumber

The number of the object version to be requested.

int; required

subaction

int

An example history entry can be found here.

Tables 'DATABASECHANGELOG' and 'DATABASECHANGELOGLOCK'

The DATABASECHANGELOG and DATABASECHANGELOGLOCK tables are automatically generated and used by Liquibase. More information is available in the corresponding documentation provided by Liquibase.

2.13.2. Search Engine

yuuvis® Momentum requires a high-performant search engine, such as Elasticsearch in combination with the IntraFind Linguistics Plug-in and the ICU Analysis Plug-in.

As all our tests are performed with Elasticsearch and the plug-ins mentioned above, the following search behavior description applies to our standard Elasticsearch infrastructure.

General Notes regarding Search Behavior
Paging

Paging is used to retrieve a section of a long result list. Those sections are considered as pages. The number of results per page as well as the first result to be included can be specified in each search request in yuuvis® Momentum. >> Search Query Language

In order to ensure high performance, yuuvis® Momentum does not support the usage of a cursor in search requests. This can have an effect on the paging behavior in following situation:

  • the total number of results is larger than the number of displayed results per page AND

  • some objects matching the query condition are created/updated/deleted before the user retrieves another page of results.

Since the retrieval of another page means a new search request, the total result list is different. Thus, the requested page might contain unexpected results, e.g., results that were already displayed in on the previous page.

Applying a new Configuration

If you changed the index configuration, all objects that are imported afterwards will be indexed as defined by the new configuration. All objects that are already in the system remain unchanged and can be searched as before the configuration update. If you need all objects indexed with refer to the new configuration, you need a reindexing.

The operation itself is slow and requires a lot of resources, as it essentially creates a copy of the original Elasticsearch index within the same Elasticsearch cluster, to make sure enough storage space is available and to optionally create more data nodes which can be shut down after the operation.

An Elasticsearch reindex entails the creation of a new Momentum-capable index, the migration of Elasticsearch data from the original index into said new index, and finally the removal of the old index. These steps are achieved by interaction with the Elasticsearch API, which is exposed by Elasticsearch through port 9200 on selected master nodes. It is highly recommended to create an Elasticsearch snapshot using the same API before attempting the reindex.

Below, you can find a detailed overview of the CURL commands needed to successfully perform a reindex in yuuvis® Momentum. Note that all commands assume you have port-forwarded the ElasticSearch API to \http:\\localhost:9200.

Creating a Momentum-Capable Elasticsearch Index

Two steps are required to create an Elasticsearch index that can interact with yuuvis® Momentum:

  1. Creation of a new Elasticsearch index:

    A new index needs to be created to match the specifications of the new requirements.

    CURL command & more information

    Create a new Index with a unique name.

    The creation of the new Elasticsearch index allows for the optimization of the working index for the current storage requirements. Indices work best when storing around 10 GB, and should contain no more than 50 GB of data.

    For a cluster than contains 50 GB of Elasticsearch data, a high-performance index might look something like this:

    CURL command
    curl -X PUT "localhost:9200/yuuvis_2?pretty" -H 'Content-Type: application/json' -d'
    {
      "settings": {
        "index": {
          "number_of_shards": 5,
          "number_of_replicas": 1
        }
      }
    }
    '

    Make sure to change the index parameters to suit your storage and reliability requirements.

  2. Applying yuuvis® Momentum Elasticsearch Index Mapping and Settings:

    The yuuvis® Momentum services require Elasticsearch to use a custom mapping. Using Elasticsearch’s automatic mapping algorithm for reindexing renders the new index unusable for the yuuvis® Momentum system.

    CURL command & more information

    To get a compatible mapping, retrieve the original Elasticsearch index’s mapping by using the Get mapping API:

    CURL command
    curl -X GET "localhost:9200/yuuvis/_mapping"

    Then apply the extracted mapping the new index

    CURL command mapping
    curl -X PUT "localhost:9200/yuuvis_2/_mapping?pretty" -H 'Content-Type: application/json' -d'
    {
    
        "dynamic_templates" : [
            {
                "keyword" : {
                "match" : "key_*",
                "mapping" : {
                    "type" : "keyword"
                }
                }
            },
            {
                "text" : {
                "match" : "txt_*",
                "mapping" : {
                    "type" : "text"
                }
                }
            },
            {
                "string" : {
                "match" : "str_*",
                "mapping" : {
                    "fields" : {
                    "raw" : {
                        "type" : "keyword"
                    }
                    },
                    "type" : "text"
                }
                }
            },
            {
                "number" : {
                "match" : "num_*",
                "mapping" : {
                    "type" : "long"
                }
                }
            },
            {
                "double" : {
                "match" : "dbl_*",
                "match_mapping_type" : "double",
                "mapping" : {
                    "type" : "double"
                }
                }
            },
            {
                "object" : {
                "match" : "obj_*",
                "match_mapping_type" : "object",
                "mapping" : {
                    "type" : "object"
                }
                }
            },
            {
                "date" : {
                "match" : "dte_*",
                "match_mapping_type" : "date",
                "mapping" : {
                    "format" : "date_optional_time",
                    "type" : "date"
                }
                }
            },
            {
                "boolean" : {
                "match" : "bol_*",
                "match_mapping_type" : "boolean",
                "mapping" : {
                    "type" : "boolean"
                }
                }
            },
            {
                "table" : {
                "match" : "tab_*",
                "mapping" : {
                    "type" : "nested"
                }
                }
            },
            {
                "rawtable" : {
                "match" : "rtb_*",
                "mapping" : {
                    "fields" : {
                    "raw" : {
                        "type" : "keyword"
                    }
                    },
                    "type" : "text"
                }
                }
            },
            {
                "locationpath" : {
                "match" : "locationpath",
                "match_mapping_type" : "string",
                "match_pattern" : "regex",
                "mapping" : {
                    "analyzer" : "paths",
                    "type" : "string"
                }
                }
            },
            {
                "typepath" : {
                "match" : "typepath",
                "match_mapping_type" : "string",
                "match_pattern" : "regex",
                "mapping" : {
                    "analyzer" : "paths",
                    "type" : "string"
                }
                }
            },
            {
                "contentidx" : {
                "match" : "contentidx",
                "match_mapping_type" : "string",
                "mapping" : {
                    "term_vector" : "no",
                    "type" : "text"
                }
                }
            },
            {
                "contentfile" : {
                "match" : "contentfile",
                "match_mapping_type" : "string",
                "mapping" : {
                    "term_vector" : "no",
                    "type" : "text"
                }
                }
            }
            ],
        "properties" : {
            "contentfile" : {
                "type" : "text"
            },
            "contentidx" : {
                "type" : "text"
            },
            "dte_date" : {
                "type" : "date",
                "format" : "date_optional_time"
            },
            "dte_system:creationdate" : {
                "type" : "date",
                "format" : "date_optional_time"
            },
            "dte_system:lastmodificationdate" : {
                "type" : "date",
                "format" : "date_optional_time"
            },
            "num_appbillion:index" : {
                "type" : "long"
            },
            "num_system:contentstreamlength" : {
                "type" : "long"
            },
            "num_system:versionnumber" : {
                "type" : "long"
            },
            "str_appbillion:bmstring1" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_appbillion:bmstring2" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_name" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:basetypeid" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:contentid" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:contentstreamfilename" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:contentstreamid" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:contentstreammimetype" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:contentstreammimetypegroup" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:contentstreamrepositoryid" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:createdby" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:digest" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:lastmodifiedby" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:objecttype" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:objecttypeid" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:secondaryobjecttypeids" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:tenant" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            },
            "str_system:traceid" : {
                "type" : "text",
                "fields" : {
                "raw" : {
                    "type" : "keyword"
                }
                }
            }
        }
    
    }
    '

    Optionally, you can also base the new index' settings on the original configuration:

    CURL command settings
    curl -X PUT "localhost:9200/yuuvis_2/_settings?pretty" -H 'Content-Type: application/json' -d'
    {
        "index": {
            "codec": "best_compression",
            "number_of_shards": "80",
            "max_result_window": "2147483647",
            "analysis": {
                "filter": [],
                "analyzer": {
                    "default_search": {
                        "useExactTerms": "false",
                        "prefix_length": "0",
                        "languages": ["de","en"],
                        "type": "intrafind_search",
                        "excessiveSplitting": "false",
                        "stopwords": ["",""]
                    },
                    "default": {
                        "useExactTerms": "false",
                        "prefix_length": "0",
                        "languages": ["de","en"],
                        "type": "intrafind_index",
                        "excessiveSplitting": "false",
                        "stopwords": ["",""]
                    },
                    "paths": {
                        "prefix_length": "0",
                        "tokenizer": "path_hierarchy"
                    }
    
                },
                "number_of_replicas": "1"
            }
    
        }
    
    }
    '
Migrating the Data to the new Index

Once a compatible index has been created, the reindex operation can be triggered through the Elasticsearch API.

CURL command & more information

The reindex operation itself provides a few options for configuration. For large data volumes especially, we employ parameters that increase stability and performance of the operation, such as the slices parameter for automatic parallelization of the reindex.

CURL command reindex operation
curl -X POST "localhost:9200/_reindex?pretty&slices=20&wait_for_completion=false&refresh" -H 'Content-Type: application/json' -d'
{
  "source": {
    "index": "yuuvis_1"
  },
  "dest": {
    "index": "yuuvis_2"
  },
  "conflicts": "proceed"
}
'

After the reindex is completed, the new index must be activated by reassigning the yuuvis alias.

CURL command & more information

The new index needs to inherit the yuuvis alias from the original index, meaning that the yuuvis alias must be deleted from the original index beforehand.

CURL command reindex operation
curl -X DELETE "localhost:9200/yuuvis_1/_alias/yuuvis?pretty"

curl -X POST "localhost:9200/_aliases?pretty" -H 'Content-Type: application/json' -d'
{
  "actions": [
    {
      "add": {
        "index": "yuuvis_2",
        "alias": "yuuvis"
      }
    }
  ]
}
'
Deleting the Original Index

To free up space in the Elasticsearch cluster, it is sensible to remove the original index after verifying the yuuvis® Momentum system has accepted the new index.

CURL command & more information

Make sure that the yuuvis® Momentum system still functions properly and contains all expected data before proceeding with the deletion of the original index.

CURL command
curl -X DELETE "localhost:9200/yuuvis_1"
Notes on IntraFind Linguistics Plug-in

The plug-in offers semantic and linguistic text analysis features as well as powerful query operators.

Supported Languages

With the standard installation of yuuvis® Momentum, the plug-in supports a selection of languages as shown in the table below. ONE of them at time can be used with the standard license. Per default, German is activated. An alternative language can be activated instead of German. To activate more than one language, a license extension is required.

Per default, the core system is configured to support German and English language-specific analysis. Alternative languages to be used instead can be configured in the application-es.yml configuration file. If you want to apply configuration changes to a system already in operation, please note the general remarks above.

Language ISO 639-1 Supported in default analyzer configuration Intrafind license in standard installations

Activated in standard license

Configurable alternative languages

English

en

+

-

+

French

fr

-

-

+

German

de

+

+

+

Italian

it

-

-

+

Spanish

es

-

-

+

A variety of further languages can be supported by the plug-in. Please contact IntraFind to get detailed information. You need to obtain a corresponding license on your own responsibility.

Language-specific Examples
Japanese
Standard Analysis

If the Elasticsearch standard analyzer is configured to support language-specific full-text analysis for Japanese, Tokenization and Keyword Analysis are supported.

E.g., "春夏秋冬" will be analyzed as [春, 夏, 秋, 冬], and then can be searched by 春 or 夏 or 秋 or 冬.

Most punctuation marks are removed. Upper case is changed into lower case. For "夏見、おはよう", e.g., 夏見 will be recognized as a searchable keyword.

With Japanese IntraFind Linguistics Plug-in License

If a license enabling the plug-in’s functionality for Japanese is additionally activated, Japanese words can be extracted from phrases but not all.

E.g., for "寿司がおいしいね", 寿司 will be recognized as a searchable keyword.

2.13.3. Identity Provider

Identity providers such as Keycloak can be connected to yuuvis® API for authentication using Connect/OAuth2 via the authentication-service.

Keycloak is the recommended identity provider for yuuvis® Momentum and is consistently used for testing. In principle, any identity provider supporting OAuth2 can be used in the same way.

Keycloak

As standard, the installation is done by means of a Helm chart. Two demonstration tenants are created and configured automatically. Further tenants for productive use have to be added and configured manually.

The manual installation and configuration of Keycloak for yuuvis® Momentum API are broadly described here.

After installation, Keycloak provides two administrative services, one for system administrators and one for users.

  • Admin Console

    In order to create and administrate realms and user accounts, Keycloak provides the Admin Console. Roles can be defined and assigned in the Admin Console as well. An administrator login is required.

  • User Account Service

    Any user has access to the User Account Service provided by Keycloak. Users can change their credentials and other personal data.

Keycloak Installation

To install Keycloak manually, follow these steps:

  • Download a supported Keycloak version version and extract it to a local directory.

  • Modify the standalone.xml configuration file in the \standalone\configuration\ directory:

    • Add the following entry to the <interfaces> section:

      <interface name="any">
        <any-address/>
      </interface>
    • In the <socket-binding-group> section, for the <default-interface> attribute, enter the following value: any

    • If port 8080 is not available, change the port via the following line in the <socket-binding-group> section:

      <socket-binding name="http" port="${jboss.http.port:8080}"/>
  • Start Keycloak via the \keycloak\bin\standalone.bat file.

    The file must be run as an administrator.
  • Call the Keycloak Admin Console: http://localhost:8080/

  • Start by creating an administrator account.

For productive use, it is recommended to connect Keycloak to a different relational database management system (RDBMS) instead of the embedded standard H2. Suggestions for compatible RDBMS are provided by Keycloak.
Keycloak: Tenant and User

You require a tenant and a user.

Users in Keycloak must also be entered in the yuuvis® Momentum user administration.

To create tenants and users, follow these steps:

  • Call the Keycloak Admin Console: http://localhost:8080/auth/admin

  • Create a new tenant in the navigation area via Master > Add realm.

  • Create and save a user for the tenant via Users > Add user.

  • Enter a password in the Credentials tab on the user page, set the Temporary option to Off, and save with Set Password.

Keycloak: Connecting to yuuvis® API

To establish a connection, create a client following these steps:

  • Call the Keycloak Admin Console: http://localhost:8080/auth/admin

  • Select the tenant and create the new client via Clients > Create.

  • Enter a name in the Client ID field, and enter and save the yuuvis® authentication service URL in the Root URL field.

  • Configure the following in the Settings tab of the client page:

    • Access Type > confidential

    • Authorization Enabled > ON

    • Valid Redirect URIs > Schema: http://<authentication-service>/*

      All yuuvis® API hosts must be specified according to this schema.

  • Save the configuration by clicking Save.

  • Set the required user roles for the yuuvis® API components as simple strings via Roles > Add Roles.

    Afterwards, the roles can be activated for the users via Role Mappings > Assigned Roles.

In case of a yuuvis® Momentum system with multiple tenants, the authentication service has to be registered as a Keycloak client in each corresponding realm.

Connecting yuuvis® authentication-service to SSL-secured Keycloak
  • Export certificate with Firefox:

    • Call the encrypted welcome page of Keycloak in Firefox: https://localhost:8443/auth/

    • Open the Protection Settings via the shield icon to the left of the address bar.

    • Display the certificate via Security > View Certificates.

    • Export the certificate as localhost.pem via the tab Authorities in the certificate manager.

  • Alternatively, export certificate with Chrome:

    • Call the encrypted welcome page of Keycloak in Chrome: https://localhost:8443/auth/

    • Open the Settings via the three dots icon to the right of the address bar.

    • Display the certificate via Privacy and security > Security > Manage certificates.

    • Export the certificate in Base-64 format as localhost.pem.

  • Import the certificate in the Java Trust Store with the following batch call:

    ...\service-manager\jdk\bin\keytool ^
        -import ^
        -trustcacerts ^
        -keystore ...\service-manager\jdk\jre\lib\security\cacerts ^
        -storepass changeit ^
        -noprompt ^
        -alias localhost ^
        -file ...\path\to\localhost.pem
  • Restart the yuuvis® authentication service.

Embedding the Login Page into an iframe

The Keycloak login page can be embedded as an iframe into a second web page if this web page is published on the same host as Keycloak. If the secondary web page is published on a different host, it has to be legitimized in every Keycloak tenant that will use this web page for the login process:

  • Call the Keycloak Admin Console: http://localhost:8080/auth/admin/

  • Select the tenant and add the host name of the web page via Realm Settings > Security Defenses > Content-Security-Policy > frame-ancestors.

    Multiple host names are separated by blank spaces.

Impersonation

In order to allow users with a specific role to log in as any other user, impersonation can be activated in Keycloak. Thus, users with this specific role can use their own password to log in to the account of any other user within their tenant. In Keycloak, the feature is realized via impersonation by means of token exchange.

  • Activating Token Exchange:

    • Open the StatefulSet of Keycloak in your Kubernetes cluster for editing by running the command:

      kubectl -n infrastructure edit statefulset keycloak
    • Extend the containers section as follows:

      containers:
        - args:
          - -Dkeycloak.profile.feature.token_exchange=enabled
          - -Dkeycloak.profile.feature.admin_fine_grained_authz=enabled
    • Restart Keycloak.

  • Configuring the User Account and Keycloak Clients:

    • Call the Keycloak Admin Console: http://localhost:8080/auth/admin

    • Select the user you want to grant access to other user accounts and switch to the Role Mappings tab.

    • Display the Client Roles for the realm-management client and assign its impersonation role to the user.

    • In the same realm, select the client admin-cli and switch to the Permissions tab.

    • Flip the Permissions Enabled switch to ON.

    • In the appearing table, click token-exchange in the scope-name column.

    • From the Create Policy selection list in the Apply Policy section, select Role.

    • Name it impersonation-policy.

    • From the Realm Roles selection list, select the administrative role that will enable users to impersonate other users within their tenant. Tick the Required checkbox.

    • From the Clients selection list, select realm-management.

    • From the Client Roles selection list, select impersonation. Tick the Required checkbox.

    • Save the configuration for the policy.

    • Save the configuration for the permission settings.

  • Testing Impersonation with cURL.

    The following commands use an administrative user root with the password changeme belonging to the tenant tenant1 with the impersonation authorization as configured before. This user requests access to the account of the user specified by the ID cc14e5d4-e8da-4108-92ad-c87066aed4c3.

    • Request a token for the administrative user with the impersonation authorization:

      curl -k ^
        -d "client_id=admin-cli" ^
        -d "username=root" ^
        -d "password=changeme" ^
        -d "grant_type=password" ^
        "http://localhost:8080/auth/realms/tenant1/protocol/openid-connect/token"
    • Request a token for the account of the target user where the login is needed. The previously retrieved token of the administrative user is referenced as subject_token whereas the ID of the target user is specified as requested_subject.

      curl -k ^
        -H "Content-Type: application/x-www-form-urlencoded" ^
        -d "client_id=admin-cli" ^
        -d "requested_subject=cc14e5d4-e8da-4108-92ad-c87066aed4c3" ^
        -d "subject_token=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJueEZ..." ^
        --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" ^
        "http://localhost:8080/auth/realms/tenant1/protocol/openid-connect/token"

The retrieved token can be used by the administrative user root for authentication in yuuvis® Momentum with the account of the target user.

  • The following command retrieves user-specific information on the user who will be logged in with the token specified in the authorization header. Check whether the token retrieved before identifies the desired target user. Thus, in this example, the command should retrieve a data set for the user with ID cc14e5d4-e8da-4108-92ad-c87066aed4c3.

    curl -k ^
      --request GET ^
      --url "http://localhost:8080/auth/realms/tenant1/protocol/openid-connect/userinfo" ^
      --header "accept: application/json" ^
      --header "authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAi1dXVSZ3daQldhTTJZaXNlZElFXzg..."
Suppressing Duplicate Information on Roles

Per default, the access token generated by Keycloak contains the roles of the currently logged-in user. The authentication service creates an internal JSON Web Token (JWT) that includes the unchanged Keycloak access token. However, in order to allow a separate role management, the authentication service requests the roles of the corresponding in a separate request and adds them to the internal JWT in addition to the Keycloak access token. The roles stored in the original Keycloak access token are a duplicate of the information and are always ignored. In order to reduce the size of the JWT, their inclusion in the Keycloak access token can be suppressed by applying the configuration adjustment described below. Thus, for any request to the yuuvis® Momentum API, the request header size is reduced.

  • Call the Keycloak Admin Console: http://localhost:8080/auth/admin/ with administrator login.

  • Select the realm for which the configuration is to be changed.

  • Open the Client Scopes.

  • Open the roles scope.

  • In the Mappers tab, delete the entries realm roles and client.

These configuration steps have to be applied to each realm in each Keycloak instance in which to suppress the inclusion of role information in the Keycloak access token.

Session Management

For each user session, HTTP client and browser set session cookies as described here.

Additionally, the following cookies are set by Keycloak. For more information, please refer to the official Keycloak documentation.

  • AUTH_SESSION_ID_LEGACY

  • AUTH_SESSION_ID

  • KEYCLOAK_IDENTITY_LEGACY

  • KEYCLOAK_IDENTITY

  • KEYCLOAK_PROXY_SESSION_ID

  • KEYCLOAK_SESSION_LEGACY

  • KEYCLOAK_SESSION

2.13.4. Internal Caches

Redis

The core system internally uses Redis to cache processing-related information. If you want to store your own keys in Redis for custom processes, your keys must not match one of the following pre-defined internal keys.

Key name Comment

apiUpdate<objectId>

Locks DMS objects during the processing of update requests.

AUDIT_CACHELOCK_<objectId><tenant><user>

DELETE_FOLDER_<objectId>

During the processing of a folder object deletion, no parallel process can create a new system:parentId reference on that folder object.

NEW_PARENT_<childId>

Ensures that parallel operations do not create circles in the folder hierarchy.

registryUpdate<objectId>

roleSetUpdate

roleSetUpdateapp<app>

roleSetUpdateten<tenant>

schemaUpdate

schemaUpdateapp<app>

schemaUpdateten<tenant>

spring:session:sessions:<sessionId>

Shares session information for all instances of the authentication service.

storage.metrics.map.v2

Contains the used storage per tenant in Bytes used for the storage metric.

system.storage.part-upload.map

Contains the upload information for the upload of binary content files in multiple pieces for each tenant.

S_CHANGE_SCHEMA

Ensures that no other schema or app set can be changed during an update process on the global schema or an app schema.

S_MOVE_CONTENT_<tenant><repositoryId><contentstreamId>

Locks DMS objects referring to the same content during a content move request.

TAGLOCK_<objectId><tagname>_inner

TAGLOCK_<objectId><tagname>_outer

Control the visibility of tags via tagging endpoints in combination with apiUpdate<objectId>.

updateFolder<objectId>

userAttributes <tenant><userId>

2.14. Testing

2.14.1. Testing with Postman

Postman is a free API development tool with a multitude of useful functions for automated testing, documentation, and more. Our yuuvis® Postman Collections kick-start you right into the yuuvis® API world.

You need a running and accessible yuuvis® Momentum core installation.

2.15. Maintenance via CLI

The commander service for yuuvis® allows you as a DevOp to perform low-level maintenance on your core system. You can adjust the differences between the DBMS, Elasticsearch, and your repository. You can access the database and carry out Elasticsearch queries to ,e.g., rebuild the full-text index from the database. The commander service itself does not support a REST interface of its own, but a connection via Secure Shell (SSH) instead. Thus, the commander service provides a SSH server at runtime. If you are connected to an SSH client, you can execute predefined commands with self-imposed parameters.

2.15.1. Set Up 'commander' Service

To use the commander service, an SSH connection is required. The recommended parameters for the configuration of the SSH connection are given in this section.

Port Redirection

The commander Service starts the SSH server per default on port 8022. If there are pods in the Kubernetes final destination platform, a forwarding has to be started for port 8022.

localhost@root:~$ kubectl port-forward -n sanity commander-0000000000-00000 8022
Connecting to SSH Client

Since the connection has to persist during long-term operations without user interactions, keepalives should be enabled. Furthermore, the commander output might contain important information and thus should be stored in a file.

Setup under Windows

Under a Windows operating system, the usage of PuTTY is recommended. The screenshot below shows the recommended PuTTY configuration enabling the keepalives on the top, and activating the output in a file below.

Enabling keepalives screenshot
Output in a file screenshot
Setup under Linux

The standard SSH client can be used. The keepalive function can be activated with the option "ServerAliveInterval 20". The output in a file can be achieved by forwarding to the tee command.

localhost@root:~$ ssh -o "ServerAliveInterval 20" -l root -p 8022 127.0.0.1 2>&1 | tee commander-output.log

2.15.2. Commands

The command help lists all available commands that are supported by the commander service.

Information on parameters of individual commands can be displayed via help <command>.

Maintenance Commands

Check the data stock for consistency or execute global tasks that affect the entire system via commander functions called with the following commands.

maintain-compare - Compare the objects stored in the database and Elasticsearch index.

Unforeseen circumstances might occur in any system and might lead to differences between database and Elasticsearch index. For example, a deleted object was correctly removed from the database, but for whatever reason not from the Elasticsearch index. As of yuuvis® Momentum version 2020 Winter, it is possible to check the consistency of the stored objects by means of the maintain-compare command provided by the commander service.

While the command runs continuously, the comparison of DMS objects is performed step by step. The objects are grouped by the date of their last modification/creation. For each day between the start date and the end date, the corresponding objects are processed. Then again, each day is split in a variable number of time periods, such that the amount of objects to be compared in each period is approximately equal to the number of fetch-size.

All results are summarized in a file called job-result.json. In this (ND)JSON structured file, each day is listed separately and contains some general comparison results.

Example 'job-result.json' file
1
2
{"1970-01-01" : {"total":{"missingDb":10,"missingEs":5,"differences":2,"dbHits":20,"esHits":20},"end":"1970-01-02T00:00:00.000Z","start":"1970-01-01T00:00:00.000Z","daily":{"comparison":{"propertyDifferences":2,"missingInDb":10,"missingInEs":5},"splits":1,"esHits":20,"dbHits":20}}}
{"1970-01-02" : {"total":{"missingDb":15,"missingEs":10,"differences":4,"dbHits":40,"esHits":40},"end":"1970-01-03T00:00:00.000Z","start":"1970-01-02T00:00:00.000Z","daily":{"comparison":{"propertyDifferences":2,"missingInDb":5,"missingInEs":5},"splits":1,"esHits":20,"dbHits":20}}}

For every day with differences, there is an additional folder, containing some more detailed information about this day’s differences.

Example folder content
{
    "timeRangeSummary": {
        "start": "1970-01-01T00:00:00.000Z",
        "end": "1970-01-02T00:00:00.000Z",
        "comparison": {
            "missingInDb": [
            "00000000-0000-0000-0000-0000000000000",
            "00000000-0000-0000-0000-0000000000001",
            "00000000-0000-0000-0000-0000000000002",
            "00000000-0000-0000-0000-0000000000003",
            "00000000-0000-0000-0000-0000000000004",
            "00000000-0000-0000-0000-0000000000005",
            "00000000-0000-0000-0000-0000000000006",
            "00000000-0000-0000-0000-0000000000007",
            "00000000-0000-0000-0000-0000000000008",
            "00000000-0000-0000-0000-0000000000009",
            "00000000-0000-0000-0000-0000000000010"

            ],
            "missingInEs": [
            "00000000-0000-0000-0000-0000000000011",
            "00000000-0000-0000-0000-0000000000012",
            "00000000-0000-0000-0000-0000000000013",
            "00000000-0000-0000-0000-0000000000014",
            "00000000-0000-0000-0000-0000000000015",
            "00000000-0000-0000-0000-0000000000016"
            ],
            "differences": [
            "00000000-0000-0000-0000-0000000000017",
            "00000000-0000-0000-0000-0000000000018"
            ]
        }
    }
}

After all time periods of a day are processed, the procedure is repeated for the next day until the current date (or the specified end date) is reached. Depending on the number of objects for the tenant, this process can take a long time. While running the task, the process progress is continuously displayed on the command line including an estimated completion time.

After the command finishes, the directory containing all result files is shown.

The following parameters can be given to the maintain-compare command:

Parameter Description Required Default

-t | --tenant <arg>

Specifes the target tenant. If not specified, the command is executed for all tenants.

Example
maintain-compare -t default

yes

-

--target-directory <arg>

Target directory for result log.

Example
maintain-compare -t default --target-directory C:\Users\myusername\ymtenantdeletionlog

no

.

-s | --start-date <arg>

Specifies the start date for the comparison in yyyy-MM-dd format. Document objects with a system:lastModificationDate (or system:creationDate, see parameter -c) later than the specified date at 00:00:00.000 are taken into account for the comparison.

If not specified, the earliest system:lastModificationDate (or system:creationDate) for an object found in the database or Elasticsearch index is used as start date.

Example
maintain-compare -t default -s 2020-11-11

no

firstobjectcreation

-e | --end-date <arg>

Specifies the end date for the comparison in yyyy-MM-dd format. Document objects with a system:lastModificationDate (or system:creationDate) before and inclusive of the specified date at 23:59:59.999 are taken into account for the comparison.

If not specified, the current date is used as end date.

Example
maintain-compare -t default -s 2020-11-11 -e 2020-11-12

no

today

--fetch-size <arg>

Fetch size, used to split days in time periods. Each period contains approximately as many elements as specified by fetch-size.

The value must be at least 1000 and not bigger than 50,000.

Example
maintain-compare -t default --fetch-size 20000

no

10000

-c | --useCreationDate

If the parameter is set, the system:creationDate is used instead of the system:lastModificationDate to decide whether the corresponding object is included in the comparison.

Example
maintain-compare -t default -s 2020-11-11 -e 2020-11-12 -c

no

false

-m | --mode <arg>

Specifies the mode of the comparison determining which object properties are included in the comparison. The available modes are listed and described in the table below.

Example
maintain-compare -t default -s 2020-11-11 -e 2020-11-12 -m ADVANCED

no

SIMPLE

The following modes can be selected for the maintain-compare command:

Mode Description

COUNT

The command determines and compares the number of objects modified (or created) on every single day in the specified time range.

SIMPLE

The command determines and compares only the system:objectId of all objects that are included in the comparison.

BASIC

The command determines and compares the following properties of all objects that are included in the comparison:

  • system:objectId

  • system:createdBy

  • system:createdBy

  • system:creationDate

  • system:lastModifiedBy

  • system:lastModificationDate

  • system:tenant

  • system:versionNumber

  • system:deleted

ADVANCED

The command determines and compares the properties listed for the BASIC mode and additionally the following properties of all objects that are included in the comparison:

  • system:baseTypeId

  • system:objectTypeId

  • system:traceId

  • system:tags

maintain-delete - Delete all objects of a specific tenant that are flagged for deletion.

This command may be useful, e.g., if objects have been requested to be deleted, and flagged for deletion, but the deletion itself did not take place due to unforeseen circumstances. Such states can be recognized by the maintain-compare command. Using the maintain-delete command will then help to clean up inconsistent object states.

The command runs continuously for a specified amount of time, determines the objects that were flagged for deletion in the Elasticsearch index and deletes them, including all references to the yuuvis® Momentum system that may still exist. Thus, it is ensured all flagged objects are deleted from the Elasticsearch index, and, if necessary, from the database and the repository. In addition, all old versions are deleted too. If no further object is found, the command will stop even if the maximum run time is not yet reached.

The following parameters can be given to the maintain-delete command:

Parameter Argument Type Description Required Default

--tenant <arg>

string

Tenant for which flagged objects are to be searched and deleted.

Example
maintain-delete --tenant default

yes

-

--target-directory <arg>

string

Target directory for result log.

Example
maintain-delete --target-directory C:\Users\myusername\ymdeletionlog

no

-

--fetch-size <arg>

int

Fetch size for Elasticsearch requests. Maximum number of objects included in each Elasticsearch request.

The value must be at least 1 and not bigger than 10000.

Example
maintain-delete --fetch-size 50

no

1000

--running-time <arg>

int

The maximum amount of seconds this command is allowed to run before stopping.

The value must be at least 1 and not bigger than 86400.

Example
maintain-delete --running-time 3600

no

5

--no-random

boolean

Setting this flag will prevent using a random seed to search for flagged objects.

Example
maintain-delete --no-random

no

false

In the following example, all objects that are flagged for deletion will be deleted. The job will continuously search for the next 100 (see: --fetch-size) flagged objects and process them, until the maximum running time of 1 hour (see: --running-time) is reached or no further objects are flagged for deletion.

Example
Lt. Commander>maintain-delete --tenant default --running-time 3600 --fetch-size 100
Running delete job for tenant 'default' for 3600s

Any unexpected results will be continuously displayed while the process is running.

maintain-export - Export all objects of a specific tenant. For every object a folder is created, containing the object’s metadata in JSON format and its content file if available.

This command may be useful, e.g., if a customer’s contract corresponding to a specific tenant ends. All data stored for this tenant can be exported for further usage in other systems. The export includes the metadata of all objects and the corresponding binary content files. Every object is exported separately. Therefore, a folder structure is created using the tenant name as root level. Each object is created as a folder named according to its system:objectId, which contains a metadata.json file and the binary content file if available. To prevent performance issues when browsing those exported items with file explorers, it is possible to specify the maximum number of items within a folder. Considering this limitation, a nesting strategy is used to add more hierarchical (physical) folder levels and reduce the number of elements per folder.

While running the task, the process progress is continuously displayed including an estimated completion time.

Parameter Argument Type Description Required Default

--tenant <arg>

string

Tenant for which all objects are to be exported.

Example
maintain-export --tenant default

yes

-

--fetch-size <arg>

int

Fetch size for database requests. Maximum number of objects included in each database request.

The value must be at least 1 and not bigger than 100000.

Example
maintain-export --fetch-size 500

no

1000

--folder-size <arg>

int

Maximum number of items per folder to prevent performance issues when browsing folders.

The value must be at least 1 and not bigger than 10000.

Example
maintain-export --folder-size 50

no

5000

--target-directory <arg>

string

Target directory for exported items.

Example
maintain-export --target-directory C:\Users\myusername\ymexports

no

.

--start-date <arg>

string

Start date. Every item that was created since this date will be exported (e.g., 2018-03-13). If not specified, the first creation date will be used.

Example
maintain-export --start-date 2021-09-01

no

firstobjectcreation

--end-date <arg>

string

End date. Every item that was created until this date will be exported (e.g. 2021-03-13). If not specified, the end date is today.

Example
maintain-export --end-date 2021-09-01

no

today

In the following example, all objects that were stored since 2021-09-01 by any user of tenant default will be exported. Additionally, only 50 items should be stored in each folder, so a nesting strategy is used.

Example CLI
Lt. Commander>maintain-export --tenant default --start-date 2021-09-01 --folder-size 50
Running export job for tenant 'default' from '2021-09-01T00:00:00.000+02:00' to '2021-09-29T00:00:00.000+02:00'

The result is in a folder structure, similar to the example structure below. Each folder contains the metadata.json and the binary data (if available).

Example Result
\---default
    +---0
    |   +---004f0124-51cb-4293-8db8-5f7fa31d3a9c
    |   +---01b7e555-aa1f-43e4-a27d-901463f26dc3
    |   +---0482f25b-4946-4b50-8663-993ecfb80b55
    |   +---04b4ef67-b72d-44c5-bdae-928c21839f1c
    |   +---051521da-eb3e-479a-89a0-be9c8e26569c
    |   +---05a70b84-8ce7-4c2e-ac32-af480bd120ce
    |   +---082d3913-83ca-4d2b-b8ae-53f3086ad6c1
    |   \---0d98f3b2-718a-4808-b185-c1e4e28ce732
    +---1
    |   +---16a06147-ca6e-4c52-8ce9-8fef91a7f3ec
    |   \---17cb45fa-d8b8-4df1-b761-87711e615005
    +---2
    |   +---2665cd04-dbb1-4221-8877-53df9ae4d37f
    |   +---29a6af2f-7265-43c3-94fa-e249a028768f
    |   +---2ed11958-88ea-4800-82d9-3529a12e31de
    |   \---2f1d183e-9e93-487b-9a74-98ecd2331b75
    +---3
    |   +---3267cacc-6408-4a3f-909e-3796e43f1b84
    |   +---3759d0b9-0f8f-4cf8-8bc2-394d7e381e3c
    |   +---394be944-6237-4090-a4ea-2fc9d48ddde8
    |   +---3a19a763-9e1a-4264-9e71-c8ae02bad8e7
    |   +---3dd159bf-90dd-472a-aa84-dcaf6c828e83
    |   \---3f55c478-a084-4bc1-aa6a-63327b5cebb6
    +---4
    |   +---408bcfeb-48e9-4350-bae5-9378443aef34
    |   +---4348a318-abea-4d84-a416-f82f8380ef15
    |   +---43eb7e68-16f1-4a7e-a77b-fdcf7c846315
    |   +---447b11b5-dd87-4582-9a47-32fce361da88
    |   \---4a7dcced-2ed8-4041-bf6d-fd5b5c96e959
    +---5
    |   +---546db2d9-8401-45ff-ab10-b002ac440c0e
    |   +---5d27a0f8-35d0-4cdd-ac30-cbe1e744d924
    |   \---5d7de05f-e1f9-4639-824e-2ad41d64fe19
    +---6
    |   +---6398f660-443e-4363-a531-9d12c8d62b88
    |   +---6ddd4241-9d2d-4a0a-b20d-a49190224d24
    |   \---6fcc6ef6-511a-4f9a-be16-a8b9d9e951fc
    +---7
    |   +---751abfa2-0788-434d-9513-055f6b538a40
    |   +---76a1d7fa-f481-4adf-840d-27b680a2e513
    |   \---795a223a-ca0c-4a63-8dc1-cc8967d1379c
    +---8
    |   +---80db8f0e-b4f5-48d0-af83-e589576a0631
    |   +---834f086a-b0b5-47b6-9727-548ccb876bdf
    |   +---8c8bf981-24b6-4ab8-ae53-92bdb2fce1cd
    |   +---8e3428a7-f63a-4576-a6f0-d4c9c3cb4d46
    |   \---8e414e7c-3ad6-4132-a1ff-018107d8f01e
    +---9
    |   +---900e049d-5927-40cf-80df-5b3fbdf6672e
    |   +---90b707e2-ddd6-451c-bbae-88c977686ec1
    |   +---919244e8-9568-4cea-a6f6-113dba63e21f
    |   \---9a09011a-9ca4-4b2d-8f8b-ffa6c128cc35
    +---a
    |   +---a18f5ad3-a9a7-40c2-9918-8d3504483266
    |   +---a23b5f63-0297-4772-a6d8-c808c4b61ba0
    |   +---a294c53d-9fa8-442e-b189-754d047dded3
    |   +---a7fe24db-3163-44ff-9382-af3404b607b1
    |   +---a9139650-57ef-4205-9147-a683057d975c
    |   +---a9ae7464-cf17-42fc-8200-d35eaf205289
    |   \---af80e537-5ceb-4676-b13d-956710752dbf
    +---b
    |   +---b842d551-3a01-4d83-abcf-67f213363bc2
    |   +---bc5f482e-897b-4264-8c58-9132747f1051
    |   \---bf8a677b-3687-41fc-8078-b973879a7315
    +---c
    |   +---c25d0fee-ae75-439c-90b4-49b8793ddf36
    |   +---c506c75d-dc4f-4743-818b-7cac35d79b95
    |   \---c9b85135-0030-426c-9146-2039eb0f27ee
    +---d
    |   +---d0424628-bb70-4714-a44f-e02e51184ff6
    |   +---d283787b-795d-4e72-bca9-95752d9f10b7
    |   +---d4292dd4-5689-4cf5-99a6-174f97f4c41b
    |   \---d918e6d5-1a34-49b1-8134-3d890d45d364
    +---e
    |   +---e1f0c851-aaa9-496e-b2d9-30607453215e
    |   +---edafcd97-1f51-466f-80f8-385f95f501d3
    |   \---ee2d8719-881a-4187-b604-c5cb9c2ca991
    \---f
        +---f0a77bdb-fc26-4d0d-8212-9c265e1e50a8
        +---f54553de-e334-47c1-997d-76f2999982e1
        +---f992a805-e6c4-4239-b2d5-7f91ea018c60
        +---fc627ddd-82d4-43e7-891b-1f9bcb0cceb7
        +---ff200544-b4c7-4a75-904d-63c8cee55f9d
        +---ff252500-59ed-4f61-94f0-adf577958b5f
        \---ff2e54a7-e235-4a65-a548-64b8772626d1
maintain-repository- Find content files in the S3 store that are not referenced any longer by an object in the database.

Find content files in the S3 store that are not referenced any longer by an object in the database.

yuuvis® Momentum stores content files separately from their metadata. The content files are indicated by a contentStreamId and can be stored in an S3 store. Each corresponding object with its metadata is stored in a database and contains a reference on the contentStreamId of its content file. If the object is deleted, the metadata are read from the database and deleted. The content file is searched afterwards by the contentStreamId that was read from the database before, and deleted. If an error occurs during this process, the object might be removed from the database but not the corresponding content file. Thus, over time, several content files might remain in the S3 store that are not referenced by an existing object. As of yuuvis® Momentum version 2020 Winter, it is possible to find those content files in the S3 store by means of the maintain-repository command provided by the commander service.

The command determines all content files in a specified S3 store and checks in the database whether they are referenced by an existing object or an old version of an object. Content files without any reference in the database are listed via contentStreamId and returned in a JSON structure.

These parameters can be given to the maintain-repository command:

Parameter Description

-r | --repositoryId <arg>

Specifies the ID of the repository that to be searched. If the specified repository is not an S3 store, an error is returned.

Example
maintain-repository -r s3repo
maintain-tenant-data-delete- Deletes all data belonging to a tenant of the core system, including all objects in the repository, database, Elasticsearch, audit entries and config files.

This command may be useful if all data of a tenant should be deleted. Before using this command, you should ensure that the tenant is already disabled for user login, to prevent any unexpected data manipulations while the deletion process is running. Please note that this operation cannot be undone and that there is no automatic data backup. Even objects under retention will be deleted. However, if binary content files are protected by an archive-internal retention, they cannot be deleted via this command.

While the command runs continuously, the deletion of DMS objects is performed step by step. Each day between the object creation date and the current date is separately processed. Then again, each day is split in a variable number of time periods, such that the amount of objects to be deleted in each period is approximately equal to the number of fetch-size. For each period, the command follows this procedure:

  • Process all current object versions:

    • Delete each repository item, i.e., binary content files. (individual requests)

    • Delete the objects in the Elasticsearch index. (batch request)

    • Delete all database rows. (batch request)

  • Process all old versions of DMS objects:

    • Delete each repository item, i.e., binary content files. (individual requests)

    • Delete all database rows. (batch request)

If one of the deletion sub-processes (in repository, search index or database) fails for a DMS object, the problem is logged and the deletion continues with the other sub-processes nevertheless.

After all time periods of a day are finished, all audit entries of this day are deleted. Then, the procedure is repeated for the next day until the current date has been processed. Depending on the number of objects for the tenant, this process can take a long time. While running the task, the process progress is continuously displayed including an estimated completion time.

After processing all days, as a last step, the tenant’s configuration is deleted.

The following parameters can be given to the maintain-tenant-data-delete command:

Parameter Argument Type Description Required Default

--tenant <arg>

string

Tenant for which all data should be deleted.

Example
maintain-tenant-data-delete --tenant default

yes

-

--target-directory <arg>

string

Target directory for result log.

Example
maintain-tenant-data-delete --target-directory C:\Users\myusername\ymtenantdeletionlog

no

-

--fetch-size <arg>

int

Fetch size, used to split days in time periods. Each period contains approximately as many elements as specified by fetch-size.

The value must be at least 100 and not bigger than 10,000.

Example
maintain-tenant-data-delete --fetch-size 500

no

1000

--what-if

boolean

Setting this flag will prevent the execution of the deletion. The process will be simulated in order to count all documents that would be deleted without this flag.

Example
maintain-tenant-data-delete --what-if

no

false

--skip-confirmation

boolean

Setting this flag will skip the initial warning that all data will be deleted.

Example
maintain-tenant-data-delete --skip-confirmation

no

false

In the following example, all objects of the tenant default will be deleted. Each day is split in time periods which contain approximately 500 objects.

Example
Lt. Commander>maintain-tenant-data-delete --tenant default --fetch-size 500
Running tenant delete job for 'default'

Any unexpected results will be continuously displayed while the process is running.

Database Commands

Check the data stock for consistency or execute global tasks that affect the entire system via commander functions called with the following commands.

dbs-reindex - Restore the entire Elasticsearch index from the database via Commander service.

Changes in the object structure might lead to differences between the index of Elasticsearch and the database. As of yuuvis® Momentum version 2020 Winter, it is possible to reindex Elasticsearch according to the database by means of the dbs-reindex command provided by the commander service.

The reindexing can be limited by a start date and an end date, and by specifying a tenant. Before the reindexing, execute the dbs-configure command to turn the simulation mode on/off.

These parameters can be given to the dbs-reindex command:

Parameter Description

-e | --end-date <arg>

Sets an end date. The argument is in format yyyy-MM-dd.

Example
dbs-reindex --end-date=2020-01-21

-s | --start-date <arg>

Sets a start date. The argument is in format yyyy-MM-dd.

Example
dbs-reindex -s 2019-01-21

-t | --tenant <arg>

Specifies the target tenant. If not specified, the command is executed for all tenants.

Example for tenant 'default'
dbs-reindex -t default

The following example code shows the commands together with the corresponding command line outputs for a non-simulation reindexing. The simulation mode is turned off (command dbs-configure) in line 16. In line 19, the reindexing is executed for the default tenant starting from 2020-01-01 and ending on 2022-01-01.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Lt. Commander>help dbs-configure


NAME
        dbs-configure - configure timeouts

SYNOPSYS
        dbs-configure [-s]
OPTIONS
        -s or --simulation
                turn simulation mode on/off
                [Optional, default = false]



Lt. Commander>dbs-configure
Running dbs-configure setting values simulation('false')
SessionState(simulation=false, reindexing=false)
Lt. Commander>dbs-reindex -t default -s 2020-01-01 -e 2022-01-01
Running dbs-reindex for 'default' from '2020-01-01' to '2022-01-01'
dbs-configure - Turn on/off the simulation mode for the reindexing command.

It is possible to reindex Elasticsearch according to the database by means of the dbs-reindex command provided by the commander service. Via the dbs-configure command, the reindxing can be configured to be executed in a simulation mode that does not manipulate any data. In order to actually apply the reindexing to the data, the simulation mode has to be turned off with the dbs-configure command.

These parameters can be given to the dbs-configure command:

Parameter Description

-s | --simulation

Turns the simulation mode on (true - parameter is set) or off (false - parameter is not set).

Example
dbs-configure --simulation

The following example code shows the commands together with the corresponding command line outputs for a non-simulation reindexing. The simulation mode is turned off in line 16. In line 19, the reindexing is executed for the default tenant starting from 2020-01-01 and ending on 2022-01-01.

Audit Commands

Check the data stock for consistency or execute global tasks that affect the entire system via commander functions called with the following commands.

audit-cleanup - Remove entries from the audit trail by means of the commander service.

It is possible to delete old audit trail entries by means of the audit-cleanup command provided by the commander service, together with the ./config/system/cleanupConfiguration.json configuration file.

The audit field in the JSON file contains details on the deletion of the audit trail entries using the following parameters:

Parameter Description

defaultCleanupAfterDays

An integer default value for the cleanupAfterDays parameter. It is valid for any action that is not listed in actions.

Parameter Description

actions

Contains a list of mappings of the minimum age of audit trail entry types and the corresponding cleanup timing.

comment

An optional string parameter for the purpose of help. The value is arbitrary and is not evaluated in the commander service.

action

The integer Core API code specifying the audit trail entry type. Only existing values are considered. Not existing values lead to ignoring of the mapping element.

cleanupAfterDays

The integer minimum age of audit trail entries with the history code action in days. Any entry of type action older than cleanupAfterDays will be deleted when the audit-cleanup command is executed.

Only values >= 0 are valid. If a negative value is set, audit trail entries of the corresponding type will never be deleted.

Example cleanupConfiguration.json
{
    "audit": {
        "defaultCleanupAfterDays": 10,
        "actions": [
            {
                "comment": "OBJECT_CREATED",
                "action": 100,
                "cleanupAfterDays": -1
            },
            {
                "comment": "DOCUMENT_ACCESSED",
                "action": 400,
                "cleanupAfterDays": 1
            }
        ]
    }
}

When the lifetime of the audit trail entries is exceeded, they are not automatically deleted. The deletion of entries takes place only as a result of the execution of the audit-cleanup command in the commander service AND if the specified lifetime is exceeded. When executed, the command reads the cleanupConfiguration.json file. If the file does not exist, the defaultCleanupAfterDays value is set to -1 and thus no entry will be deleted from the audit trail.

Finally, for the execution in the commander, the following parameters can be given to the audit-cleanup command:

Parameter Description

-t | --tenant

Specifies the target tenant. If not specified, the command is executed for all tenants.

Example for tenant 'default'
`audit-cleanup -t default

3. Practice Examples

The following example tutorials may help you to design your own solutions based on yuuvis Momentum core system. The example source code is available on gitHub.

3.1. Login to the Core API

To interact with the yuuvis® API, it is necessary to log in with a user account. The user accounts are managed by at least one external identity provider (such as Keycloak or the Active Directory Federation Service). It is possible to configure different identity providers for different tenants. Each user account belongs to exactly one tenant, which must be specified with each login.

Check out our graphical overview of the architecture which describes the basic use case flow for logging in to the core API.

3.1.1. Requirements

To work through this tutorial, the following is required:

  • Set-up yuuvis® API system (see Installation Guide)

  • A user with at least read permissions on a document type in the system (see tutorial for permissions)

  • Simple Maven project

  • Preconfigured yuuvis® API system with Keycloak as the identity provider

    • Keycloak contains a realm default

    • In the realm default, the Authentication service is registered as a client under the name enaio

    • The realm default contains a user clouduser with the password secret

3.1.2. Session Management

The login is done using request headers, which are passed during the first call of an API function. The calling HTTP client must have a Cookie Manager to enrich further requests with the session cookie (GWSESSIONID). This prevents the user from logging on again for each request. In the tutorial, the OkHttpClient by Square, Inc. is used to this. Therefore, the following block must be added to the Maven dependencies in the pom.xml of the project:

pom.xml
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.12.0</version>
</dependency>

<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-urlconnection</artifactId>
<version>3.12.0</version>
</dependency>

To activate Cookie Management in the OkHttpClient, you can do the following:

Activate Cookie Management in OkHttpClient
CookieJar cookieJar = new JavaNetCookieJar(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
OkHttpClient client = new OkHttpClient.Builder().cookieJar(cookieJar).build();

3.1.3. Secure Data Transmission with SSL

To use encrypted (HTTPS) endpoints with an OkHttpClient, it must be configured for the SSL encryption protocol. For this, it must also be capable of certificate treatment according to the X-509 standard. For this, the OkHttpClient receives a hostnameVerifier and a sslSocketFactory at initialization to check incoming certificates with the TLS handshake. In our example, we just keep building our X509TrustManager for the sslSocketFactory for demonstration purposes, so that certificates are almost always accepted. The following code creates an OkHttpClient that is both session- and SSL-enabled.

OkHttpClient with Session Handling and SSL
private OkHttpClient client = null;

// necessary to obtain access tokens via SSL
X509TrustManager trustManager = new X509TrustManager()
{
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {}
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
};


CookieJar cookieJar = new JavaNetCookieJar(new CookieManager(null, CookiePolicy.ACCEPT_ALL));

SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{this.trustManager}, new SecureRandom());

// create HTTP Client
this.client = new OkHttpClient.Builder()
.cookieJar(cookieJar)
.hostnameVerifier((s, sslSession) -> true)
.sslSocketFactory(sslContext.getSocketFactory(), this.trustManager)
.build();

3.1.4. Required System Data

To log in to the Core API, a client needs some information about the system. Of course, they first need valid credentials (username / password) of a user existing in the system. In addition, the Keycloak login client must be able to identify itself as an approved application, so it must know a registered clientId with an associated clientSecret. In addition, both pairs of credentials are only valid for a certain tenant whose name must also be known to the client for the requests. Finally, the client must also know the one accessible base URL of the Core API and the associated Keycloak identity provider.

Variables for the Login
private String userName = "clouduser";
private String userPwd = "secret";
private String userTenant = "default";
private String clientId = "clouduser";
private String clientSecret = "cd7e6ce4-781b-40db-af5f-e4106926e96c";  //client secret, obtainable through keycloak credentials tab of client matching client id and tenant
private String yuuvisBaseUrl= "http://10.10.6.242";             //Base URL of yuuvisclient
private String keycloakBaseUrl = "https://10.10.6.252:8443";   //Base URL of keycloak identity provider
Generating a Secret

To log in with an oAuth2 access token, the client must authenticate itself to Keycloak with its client secret. This secret is static and can be taken from the Keycloak interface. To do this, log on to the Keycloak interface with a technical user, select the tenant applicable to the client, select the correct client under "Clients" (here "Enaio") and take out the secret of the client under the "Credentials" tab.

3.1.5. Login Procedures

Login with Username and Password

The username, password, and associated tenant are passed as HTTP headers. The username and password must be encoded with Base64 in the same way as for classic Basic authentication. The headers are then sent to any Core API endpoint.

Login with Username and Password
byte[] credentials = "clouduser:secret".getBytes(StandardCharsets.UTF_8);
String authorization = "Basic " + Base64.getEncoder().encodeToString(credentials);

Headers headers = new Headers.Builder()
.add("Authorization", authorization)
.add("X-ID-TENANT-NAME", "default")
.build();
Login with an OAuth 2.0 Access Token

For this login procedure, the application must have received an access token from the identity provider from a third-party application (for example, a proxy). The access token and the associated tenant are passed as HTTP headers for login.

Keycloak can request an access token with the Password Credentials Grant Flow. The request must contain the user name, the user password, the client ID and the secret as parameters. Keycloak’s response contains a JSON object from which the access token and token type must be extracted. In the example, JsonPath is used for this.

Login with an OAuth 2.0 Access Token
String payload = "client_id=enaio&" +
"client_secret=4c5254363c1d&" +
"username=clouduser&" +
"password=secret&" +
"grant_type=password";

//retrieve access token from identity provider (Keycloak)
Request.Builder request = new Request.Builder()
.url(keycloakBaseUrl+"/auth/realms/default/protocol/openid-connect/token")
.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"), payload))
.build();

String responseJson = this.client.newCall(request).execute().body().string();

DocumentContext context = JsonPath.parse(responseJson);
String tokenType = context.read("token_type");
String accessToken = context.read("access_token");

Finally, the logon headers are created and sent to any Core API endpoint.

Creating Headers
Headers headers = new Headers.Builder()
.add("Authorization", tokenType + " " + accessToken)
.add("X-ID-TENANT-NAME", "default")
.build();
Login with the OAuth 2.0 Device Flow

With this logon procedure, the client application calls the system browser so that the user can log on to an HTML form. The OAuth 2.0 Device Flow is used for this purpose. The procedure is done in the following four steps:

  • Start the login process and read out the parameters Device Code, User Code, and Verification URI. The example uses JsonPath for this. The parameter values lose their validity after five minutes. In this time window, the user must have finished logging in to the browser.

    OAuth 2.0 Device Flow: Step 1
    Request.Builder startRequest = new Request.Builder().url(keycloakBaseUrl+"/tenant/default/loginDevice");
    
    String responseJson = this.client.newCall(startRequest.build()).execute().body().string();
    DocumentContext context = JsonPath.parse(responseJson);
    
    String deviceCode = context.read("device_code");
    String userCode = context.read("user_code");
    String verificationUri = context.read("verification_uri");
  • The Verification URI is opened with the User Code as a parameter in the system browser. The Authentication service then forwards to the login page of the identity provider, where the user can log in.

    OAuth 2.0 Device Flow: Step 2
    Desktop.getDesktop().browse(new URI(keycloakBaseUrl + verificationUri + "?user_code=" + userCode));
  • At regular intervals, the client application queries the Authentication service to see whether the user has successfully logged in. This is the case if the status request receives the return code OK (200). The response of the status request contains a JSON object from which the access token and the token type must be extracted. In the example, JsonPath is used for this.

    OAuth 2.0 Device Flow: Step 3
    String tokenType = null;
    String accessToken = null;
    
    for (int i = 1 ; i != 30 ; i++, Thread.sleep(2000))
    {
        Request.Builder pollingRequest = new Request.Builder().url(keycloakBaseUrl+"/auth/info/state?device_code=" + deviceCode);
    Response pollingResponse = this.client.newCall(pollingRequest.build()).execute();
    
        if (pollingResponse.code() != 200) continue;
    
        context = JsonPath.parse(pollingResponse.body().string());
        tokenType = context.read("token_type");
        accessToken = context.read("access_token");
    
        break;
    }
  • Finally, the logon headers are assembled and sent to any Core API endpoint.

    OAuth 2.0 Device Flow: Step 4
    Headers headers = new Headers.Builder()
    .add("Authorization", tokenType + " " + accessToken)
    .add("X-ID-TENANT-NAME", "default")
    .build();

3.1.6. Logout

After all necessary API operations have been performed, the session established by the logon can be closed.

Log Out of the Core API
Request.Builder logoutRequest = new Request.Builder().url(keycloakBaseUrl+"/logout");
this.client.newCall(logoutRequest.build()).execute();

3.1.7. Summary

This tutorial explains how an OkHttp3 Java client implements the different logon procedures for the Core API.

3.2. Importing Documents via Core API

This tutorial shows how documents can be imported into a yuuvis® API system via the Core API. During this tutorial, a short Java application will be developed that implements the HTTP requests for importing documents. We additionally provide a JavaScript version of this tutorial.

Check out our graphical overview of the architecture which describes the basic use case flow for importing documents.

3.2.1. Requirements

To work through this tutorial, the following is required:

  • Set-up yuuvis® API system (see Installation Guide)

  • A user with at least read permissions on a document type in the system (see tutorial for permissions)

  • Simple Maven project

3.2.2. Maven Configuration

Our Java client will submit its requests to the Core API using OkHttp 3.12 by Square, Inc. Therefore, the following block must be added to the Maven dependencies in the pom.xml of the project:

pom.xml
1
2
3
4
5
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.12.0</version>
</dependency>

Client Configuration To interact with the yuuvis® API system via the Core API, we use an OkHttp3 client to send HTTP requests and read their responses.

OkHttp3 Client and Variables
String baseUrl = "http://127.0.0.1"; //baseUrl of gateway: "http://&lt;host&gt;:&lt;port>"
String username = "clouduser";
String userpassword = "secret";
String tenant = "default";
String auth = java.util.Base64.getEncoder().encodeToString((username + ":" + userpassword).getBytes());

OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient client = builder.build();

For more information on setting up the OkHttp3 client with cookie handling, please refer to this Login Tutorial.

3.2.3. Importing a Single Document

To import a document using the Java client, we need the metadata and optionally the content of the document (depending on the schema definition, there are document types that may or must have content or must not have content).

The metadata when importing a document has the following format:

metaData.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
    "objects": [{
        "properties": {
            "objectTypeId": {
                "value": "document"
            },
            "Name": {
                "value": "test import"
            }
        },
        "contentStreams": [{
            "cid": "cid_63apple"
        }]
    }]
}

In our example, the schema contains an object type document with the Name property, which may or must have content. The content is referenced in the contentStreams object by specifying a cid (multipart content ID). In the example, the cid references a multipart content with content ID cid_63apple.

A content file can be in different file formats. It is recommended to specify the format correctly in the metadata and in the multipart request. If the content type is not specified, it is automatically determined during the content analysis. If the content type determination is not clear or the content analysis is switched off, the content type application/octet-stream is used.

In our example we have chosen a text file (Content-Type: text/plain).

Request

For an import, a POST request must be sent to the endpoint /api/dms/objects with a multipart body consisting of metadata and, if applicable, content of the object to be imported. To construct such a request, we use a MultipartBody.Builder(), which allows us to build the request body from several form parts as follows.

Building the Multipart Body with OkHttp3
1
2
3
4
5
6
7
8
9
RequestBody requestBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("data", "metaData.json",
            RequestBody.create(MediaType.parse("application/json; charset=utf-8"),
                new File("./src/main/resources/metaData.json")))
        .addFormDataPart("cid_63apple", "test.txt",
            RequestBody.create(MediaType.parse("text/plain; charset=utf-8"),
                new File("./src/main/resources/test.txt")))
        .build();

We use a Request.Builder() to create a request object with the multipart body, headers, and the URL. The following headers are necessary for the import because they contain user information of the user accessing the endpoint: Authorization header that contains the Base64-coded credentials of the user and an X-ID-TENANT-NAME header that contains the tenant name of the user. If the used OkHttp client supports cookie handling, the Authorization header can be omitted after the client’s first request, since the logon information is stored in a session cookie (see also Login Tutorial).

Building a POST Request for an Import
1
2
3
4
5
6
Request request = new Request.Builder()
        .header("Authorization", "Basic "+ auth)
        .header("X-ID-TENANT-NAME", tenant)
        .url(baseUrl + "/api/dms/objects") //baseUrl: "http://&lt;host&gt;:&lt;port>"
        .post(requestBody)
        .build();
Response

To display the response of the API to the console, we create an associated response object when the request is executed. Please note that an IOException can be thrown by the OkHttpClient when creating the response object.

Handling any IOException
1
2
3
4
5
6
try{
    Response response = client.newCall(request).execute();
    System.out.println(response.body().string());   //print to console
} catch (IOException e) {
    e.printStackTrace();
}

3.2.4. Importing Multiple Documents in Batch Mode

If multiple documents are to be imported at the same time, this can be done using the same endpoint of the Core API. Instead of a single object, the objects list consists of several metadata records. The individual content files of the objects then each require a unique cid as the name of the form-data parts in the multipart request. This cid is referenced in the associated metadata record in the contentStreams list, which allows metadata to be uniquely assigned to content.

metaDataBatch.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
    "objects": [{
        "properties": {
            "objectTypeId": {
                "value": "document"
            },
            "Name": {
                "value": "test import object 1"
            }
        },
        "contentStreams": [{
            "cid": "cid_63apple"
        }]
    },
    {
      "properties": {
            "objectTypeId": {
                "value": "document"
            },
            "Name": {
                "value": "test import object 2"
            }
        },
        "contentStreams": [{
            "cid": "cid_64apple"
        }]
    }]
}
Batch Request

In the multipart body, we create a separate FormDataPart for the content of each object, whose first parameter is the content ID (cid).

Building a POST Request for a Batch Import
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
RequestBody batchImportRequestBody = new MultipartBody
        .Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("data",
            "metaDataBatch.json",
            RequestBody.create(MediaType.parse("application/json; charset=utf-8"),
                new File("./src/main/resources/metaDataBatch.json")))
        .addFormDataPart("cid_63apple",
            "test1.txt",
            RequestBody.create(MediaType.parse("text/plain; charset=utf-8"),
                new File("./src/main/resources/test1.txt")))
        .addFormDataPart("cid_64apple",
            "test2.txt",
            RequestBody.create(MediaType.parse("text/plain; charset=utf-8"),
                new File("./src/main/resources/test2.txt")))
        .build();

The assembly of the request object is identical to the normal import.

Response of Batch Request

If successful, the response object contains a multi-element objects list that contains the metadata records of all objects imported in this batch import.

3.2.5. Referencing an Existing Binary Content File

To save storage in your repository, multiple documents can reference the same binary content file. Specify contentStreamId and repositoryId of the existing binary content file in the import request as shown in the following example.

The archivePath is only required if its value cannot be determined from the current request. For example, it is possible to configure a pathTemplate containing dynamic path elements like DATE in the application-storage.yml configuration file. Values for archivePath resulting from such dynamic path templated cannot be reconstructed for subsequently created objects that reference the same binary content.

metaData.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
    "objects": [{
        "properties": {
            "objectTypeId": {
                "value": "document"
            },
            "Name": {
                "value": "test import with reference on existing content"
            }
        },
        "contentStreams": [{
            "contentStreamId": "DB886B37-FEEF-11E9-BCEC-3FAD551A2B8A",
            "archivePath": "default/DOCUMENT/2024-03-21/86/B/",
            "repositoryId": "repo252"
        }]
    }]
}

A special case is the creation of compound documents and corresponding sub-documents.

3.2.6. Summary

In this tutorial an OkHttpClient with Cookie-Handling was used to import documents via the Core API, both in batch mode and individually.

A complete code example can be found in this git repository.

3.3. Retrieving Documents via Core API

In this tutorial, we will discuss various ways to retrieve objects via the Core API from the yuuvis® API system using an OkHttp3 Java client.

Check out our graphical overview of the architecture which describes the basic use case flow for retrieving content or metadata.

3.3.1. Requirements

To work through this tutorial, the following is required:

  • Set-up yuuvis® API system (see installation guide)

  • A user with at least read permissions on a document type in the system (see tutorial for permissions)

  • Simple Maven project

3.3.2. Maven Configuration

Our Java client will submit its requests to the Core API using OkHttp 3.12 by Square, Inc. Therefore, the following block must be added to the Maven dependencies in the pom.xml of the project:

pom.xml
1
2
3
4
5
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.12.0</version>
</dependency>

3.3.3. Client Configuration

To interact with the yuuvis® API system via the Core API, we use an OkHttp3 client to send HTTP requests and read their responses.

OkHttp3 Client and Variables
1
2
3
4
5
6
7
8
String baseUrl = "http://127.0.0.1"; //baseUrl of gateway: "http://&lt;host&gt;:&lt;port>"
String username = "clouduser";
String userpassword = "secret";
String tenant = "default";
String auth = java.util.Base64.getEncoder().encodeToString((username + ":" + userpassword).getBytes());

OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient client = builder.build();

For more information on setting up the OkHttp3 client with cookie handling, please refer to this login tutorial.

3.3.4. Retrieving Documents

To be able to access documents, they must exist in the system. A tutorial for importing documents can be found here.

Retrieving Documents via Object ID

The direct access to a document takes place via its object ID via GET request to the endpoint /api/dms/objects/{objectId}. The objectId serves as a unique identifier of a document and can be obtained from the response of the API call of an import (see Tutorial for updating documents: Determining the objectId after import).

Retrieving Metadata of an Object
1
2
3
4
5
6
7
8
9
10
11
String objectId = "1234567890"; //example-objectId

Request metadataRequest = new Request.Builder()
        .header("Authorization", "Basic " + auth)
        .header("X-ID-TENANT-NAME", tenant)
        .url(baseUrl+ "/api/dms/objects/" + objectId)
        .get().build();


Response metadataResponse = client.newCall(metadataRequest).execute();
String metadataResponseString = metadataResponse.body().string();

The API call response will contain the current version of the objects' metadata in JSON format.

To retrieve the content of an object, a GET request is sent to the endpoint /api/dms/objects/{objectId}/contents/file.

Retrieving Content of an Object
1
2
3
4
5
Request contentRequest = new Request.Builder()
        .header("Authorization", "Basic " + auth)
        .header("X-ID-TENANT-NAME", tenant)
        .url(baseUrl+ "/api/dms/objects/" + objectId + "/contents/file")
        .get().build();

If a specific version of the document is to be requested, the endpoint to be called for the documents' metadata changes to /api/dms/objects/{objectId}/versions/{versionNr} and for the documents' content to /api/dms/objects/{objectId}/versions/{versionNr}/contents/file. More about this topic can be found in the Updating Documents via Core API tutorial under Versioning.

Retrieving Documents via Search Endpoint

The Core API provides a search endpoint (/api/dms/objects/search) that can process search queries written in the proprietary Search Query Language. The search query is sent to the search endpoint in JSON format in the body of a POST request.

Query in JSON Format
{
    "query": {
        "maxItems": 50,
        "statement": "SELECT * FROM system:object WHERE CONTAINS('Europan') AND Name Like 'E%'",
        "skipCount": 0
    }
}

This example query searches for all objects of type enaio:object whose content contains the string Europan and whose value of property Name begins with the character E.

To create such a query object programmatically, a JSON library is needed to create the query JSON. We use org.json, so the following block must be added to the Maven dependencies in the pom.xml of the Java project:

pom.xml
1
2
3
4
5
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20180813</version>
</dependency>

Now we can implement a method createQueryJSON(String statement, int skipCount, int maxItems) that creates a query object and returns it as a string. We send the string to the search endpoint in the request body of a POST request:

Retrieving Documents via Search Endpoint
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static String createQueryJSON(String statement, int skipCount, int maxItems) {
    JSONObject queryObject = new JSONObject();
    JSONObject queryAttributes = new JSONObject();
    queryAttributes.put("statement", statement);
    queryAttributes.put("skipCount", skipCount);
    queryAttributes.put("maxItems", maxItems);
    queryObject.put("query", queryAttributes);

    return queryObject.toString();
}


String query = createQueryJSON("SELECT * FROM system:object WHERE CONTAINS('Europan') AND Name Like 'E%'", 0, 50);


Request attributeSearchRequest = new Request.Builder()
        .header("Authorization", "Basic " + auth)
        .header("X-ID-TENANT-NAME", tenant)
        .url(baseUrl + "/api/dms/objects/search")
        .post(RequestBody.create(MediaType.parse("application/json; charset=utf-8"), query))
        .build();
Response attributeSearchResponse = client.newCall(attributeSearchRequest).execute();
System.out.println(attributeSearchResponse.body().string());

The expected response is a list of DMS objects with metadata matching the search query, which can also be an empty list.

3.3.5. Summary

This tutorial showed how to use an OkHttpClient to retrieve documents via Core API.

A complete code example can be found in this Git repository.

3.4. Updating Documents via Core API

This tutorial demonstrates how to update documents in yuuvis® API with the Core API. The following example will result in a short Java application that implements the HTTP requests for updating a document.

Check out our graphical overview of the architecture which describes the basic use case flow for updating content or metadata.

3.4.1. Requirements

To work through this tutorial, the following is required:

  • Set-up yuuvis® API system (see Installation Guide)

  • A user with at least read permissions on a document type in the system (see tutorial for permissions)

  • Simple Maven project

3.4.2. Maven Configuration

Our Java client will submit its requests to the Core API using OkHttp 3.12 by Square, Inc. Therefore, the following block must be added to the Maven dependencies in the pom.xml of the project:

pom.xml
1
2
3
4
5
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.12.0</version>
</dependency>

3.4.3. Client Configuration

To interact with the yuuvis® API system via the Core API, we use an OkHttp3 client to send HTTP requests and read their responses.

OkHttp3 Client and Variables
1
2
3
4
5
6
7
8
String baseUrl = "http://127.0.0.1"; //baseUrl of gateway: "http://&lt;host&gt;:&lt;port>"
String username = "clouduser";
String userpassword = "secret";
String tenant = "default";
String auth = java.util.Base64.getEncoder().encodeToString((username + ":" + userpassword).getBytes());

OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient client = builder.build();

For more information on setting up the OkHttp3 client with cookie handling, please refer to this login tutorial.

The example client, which is created in this tutorial, is intended to exemplarily implement the possibilities of the DMS API for updating existing objects. For this purpose, the client needs the object ID of the existing object to be updated. We will update metadata and content of an object via the Core API and access older versions of the object.

3.4.4. Determining the Object ID after Import

The object ID of an object in the system remains consistent across all updates, so it is possible to pass the object ID of an existing object to the client. In our code example the client initially imports an object (tutorial here) to the system and extracts the objectId of the newly created object from the response. The Java library org.json can accomplish this and will be used in this example, so it needs to be added to dependencies of the maven project:

pom.xml
1
2
3
4
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
</dependency>

The extraction of the objectId from the answer can be realized with org.json as follows:

Extract ObjectId from Response
1
2
3
4
5
6
7
8
public static String parseObjectIdFromJsonResponse(String responseJson){
    JSONObject jsonObject = new JSONObject(responseJson);
    return jsonObject.getJSONArray("objects")
            .getJSONObject(0)
            .getJSONObject("properties")
            .getJSONObject("system:objectId")
            .getString("value");
}

3.4.5. Updating Documents

Update Metadata
POST Update Metadata (overwrite all)

To update the metadata of an existing object, a POST request containing the new metadata in the body must be sent to the endpoint (POST /api/dms/objects/{objectId}). Instead of using a multipart body, the new metadata is passed to the body as a string and designated as media type JSON.

Updating Metadata
1
2
3
4
5
6
7
Request updateMetadataRequest = new Request.Builder()
        .header("Authorization", "Basic "+ auth)
        .header("X-ID-TENANT-NAME", tenant)
        .url(baseUrl + "/api/dms/objects/" + objectId)
        .post(RequestBody.create(MediaType.parse("application/json; charset=utf-8"),
            new File("./src/main/resources/metaData2.json")))
        .build();

The response returns the full, modified metadata with a new version number.

PATCH Update Metadata (only provided properties)

Since a regular POST update overwrites all properties of an object type and can end up removing attributes if they are not resupplied, an alternative option for updating metadata is provided in the PATCH endpoint (PATCH /api/dms/objects/{objectId}). It allows users to update or add only those properties provided in the request body. Properties can also be removed using the PATCH endpoint by setting the value of an existing property to null.

Patch Metadata
1
2
3
4
5
6
7
Request patchMetadataRequest = new Request.Builder()
         .header("Authorization", auth)
         .header("X-ID-TENANT-NAME", tenant)
         .url(baseUrl + "/api/dms/objects/" + objectId)
         .patch(RequestBody.create(MediaType.parse("application/json; charset=utf-8"),
             new File("./src/main/resources/metadataPatch.json")))
         .build();

3.4.6. Update Content

To update the content of an existing object, a POST request must be sent to the endpoint /api/dms/objects/{objectId}/contents/file with the new content as a file in the body. The file name of the content file can be specified via the Content-Disposition header.

Update Content
1
2
3
4
5
6
7
8
Request updateContentRequest = new Request.Builder()
        .header("Authorization", "Basic "+ auth)
        .header("X-ID-TENANT-NAME", "default")
        .header("Content-Disposition", "attachment; filename=\"test2.txt\"")
        .url(baseUrl + "/api/dms/objects/" + objectId + "/contents/file")   //baseUrl: "http://&lt;host&gt;:&lt;port>"
        .post(RequestBody.create(MediaType.parse("text/plain; charset=utf-8"),
            new File("./src/main/resources/test2.txt")))
        .build();

3.4.7. Versioning

When updating content or metadata, a new version of the object is created each time. The endpoints for fetching metadata (/api/dms/objects/{objectId}) and content (/api/dms/objects/{objectId}/contents/file) always return the current version of an object. It is also possible to get an older version of the object. How to do this is described in the next section.

To retrieve metadata of a version, a GET request must be sent to the endpoint /api/dms/objects/{objectId}/versions/{versionNr}. The version number for each object starts at 1 and is incremented with each update.

Get Metadata of Version 1
1
2
3
4
5
Request versionMetadataRequest = new Request.Builder()
        .header("Authorization", "Basic "+ auth)
        .header("X-ID-TENANT-NAME", "default")
        .url(baseUrl+ "/api/dms/objects/" + objectId + "/versions/1")
        .get().build();

To retrieve the content of a version, a GET request must be sent to the endpoint /api/dms/objects/{objectId}/versions/{versionNr}/contents/file.

Get Content of Version 2
1
2
3
4
5
Request versionContentRequest = new Request.Builder()
        .header("Authorization", "Basic "+ auth)
        .header("X-ID-TENANT-NAME", "default")
        .url(baseUrl+ "/api/dms/objects/" + objectId + "/versions/2/contents/file")
        .get().build();

3.4.8. Summary

In this tutorial, we used an OkHttpClient with cookie handling to import an object, to update its metadata and content, and finally retrieve the revised versions via the version-related endpoints.

The complete code example can be found in the Git repository.

3.5. Deleting Documents via Core API

This tutorial explains how documents can be deleted using the Core API with the help of a Java client. This tutorial requires basic knowledge of importing documents using the Core API.

Check out our graphical overview of the architecture which describes the basic use case flow for deleting content.

3.5.1. Requirements

To work through this tutorial, the following is required:

Set-up yuuvis® API system (see Installation Guide) A user with read and delete permissions on a document type in the system (see tutorial for permissions) Simple Maven project

3.5.2. Maven Configuration

Our Java client will submit its requests to the Core API using OkHttp 3.12 by Square, Inc. Therefore, the following block must be added to the Maven dependencies in the pom.xml of the project:

pom.xml
1
2
3
4
5
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.12.0</version>
</dependency>

3.5.3. Client Configuration

To interact with the yuuvis® API system via the Core API, we use an OkHttp3 client to send HTTP requests and read their responses.

OkHttp3 Client and Variables
1
2
3
4
5
6
7
8
9
String baseUrl = "http://127.0.0.1"; //baseUrl of gateway: "http://&lt;host&gt;:&lt;port>"
String username = "clouduser";
String userpassword = "secret";
String tenant = "default";
String auth = java.util.Base64.getEncoder().encodeToString((username + ":" + userpassword).getBytes());

OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient client = builder.build();
For more information on setting up the OkHttp3 client with cookie handling, please refer to this Login Tutorial.

3.5.4. Deleting a Document

To delete a document from the system, a DELETE request must be sent to the endpoint /api/dms/objects/{objectId} for the corresponding object ID. This deletes the metadata record and, if present, the content file.

Deleting a Document
1
2
3
4
5
Request deleteRequest = new Request.Builder()
        .header("Authorization", "Basic "+ auth)
        .header("X-ID-TENANT-NAME", tenant)
        .url(baseUrl + "/api/dms/objects/" + objectId)  //baseUrl: "http://&lt;host&gt;:&lt;port>"
        .delete().build();

3.5.5. Deleting a Version of a Document

To delete a version of a document from the system, a DELETE request must be sent to the endpoint /api/dms/objects/{objectId}/versions/{versionNr}. The corresponding version number must exist for the document. If the specified version number indicates the current version of the document, the entire document including all associated versions will be deleted.

Deleting a Version of a Document
1
2
3
4
5
6
Request deleteVersionRequest = new Request.Builder()
        .header("X-ID-TENANT-NAME", "default")
        .header("Authorization", "Basic "+ auth)
        .url(baseUrl + "objects/"+objectId+"/versions/1")   //baseUrl: "http://&lt;host&gt;:&lt;port>"
        .delete().build();
Response deleteVersionResponse = client.newCall(deleteVersionRequest).execute();

3.5.6. Deleting a Document with Binary Content

During the deletion of documents with binary content, yuuvis® Momentum searches for other documents that might refer to the same binary content file. It is identified by the content stream properties contentStreamId and repositoryId. Current object versions are considered as well as older versions.

  • If there are NO further references on the binary content, the document’s metadata AND binary content are deleted.

  • If there is at least one reference on the binary content, ONLY the metadata of the requested object are deleted.

Thus, the binary content is available for all remaining documents (an document versions) that still refer to it.

3.5.7. Deleting Compound Documents

Deleting compound documents is a special case of deleting documents with binary content. The chapter Using Compound Documents describes what compound documents are and what to consider when deleting compound documents.

3.5.8. Summary

In this tutorial an OkHttpClient with cookie handling was used to delete an object or a certain version of the object.

The complete code example can be found in the Git repository.

3.6. Retrieving Document History Entries

This tutorial shows how we can use a Java application to make a request to the Core API of the yuuvis® API system to retrieve the history entries of a DMS document. In addition, it briefly describes which history entries are generated for a document.

3.6.1. Introduction

The history of a DMS document is used to trace what happened to the document from the creation of the document in the system, meaning the import, to the disappearance of the document from the system, the deletion. This also includes events such as updating or retrieving the document.

3.6.2. Requirements

To work through this tutorial, the following is required:

3.6.3. The History Entry

An entry in the history looks like this:

Structure of a History Entry
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
    "properties": {
        "system:objectId": {
            "value": 223439898
        },
        "system:objectTypeId": {
            "value": "system:audit"
        },
        "system:baseTypeId": {
            "value": "item"
        },
        "system:createdBy": {
            "value": "353c631e-6a61-4e89-9512-8d275c826ce5"
        },
        "system:tenant": {
            "value": "default"
        },
        "system:creationDate": {
            "value": "2018-12-21T12:23:34.510Z"
        },
        "description": {
            "value": ""
        },
        "action": {
            "value": 101
        },
        "detail": {
            "value": "CREATE_METADATA_WITH_CONTENT"
        },
        "referredObjectId": {
            "value": "d3241d76-0652-4ac8-ba6d-892d719a2a6d"
        },
        "traceid": {
            "value": "b279402aa9a2073b"
        },
        "system:versionNumber": {
            "value": 1
        }
    }
}

A history entry is structured like a map, i.e. the entry consists of key-value pairs, whereby a value can also be a key-value pair.

Each history entry has an objectId and a referencedObjectId. The referredObjectId is the object ID of the document for which the entry was written and the objectId is the object ID of the entry itself.

Furthermore there are properties like createdBy, detail or versionNumber, which indicate in which user context the entry was created, what happened and which version number the corresponding DMS document has after the protocolled action.

The time of the action (creationDate) and the associated trace ID (traceid) are also saved to ensure traceability.

3.6.4. The Client Application

We use a Java client to send a GET request to the Core API.

3.6.5. Maven Configuration

This example uses the OkHttpClient by Square, Inc. Therefore we add the following dependency to the file pom.xml:

pom.xml
1
2
3
4
5
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.12.0</version>
</dependency>

3.6.6. Client Configuration

To interact with the yuuvis® API system via the Core API, we use an OkHttp3 client to send HTTP requests and read their responses.

OkHttp3 Client and Variables
1
2
3
4
5
6
7
8
String baseUrl = "http://127.0.0.1"; //baseUrl of gateway: "http://&lt;host&gt;:&lt;port>"
String username = "clouduser";
String userpassword = "secret";
String tenant = "default";
String auth = java.util.Base64.getEncoder().encodeToString((username + ":" + userpassword).getBytes());

OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient client = builder.build();

For more information on setting up the OkHttp3 client with cookie handling, please refer to this Login Tutorial.

3.6.7. Retrieve History Entries of a Document

With a GET request to the URL /api/dms/objects/{objectId}/history we can retrieve the history of the DMS document with the object ID objectId. The objectId serves as the unique identification number of an object and can be retrieved from the API response during import, for example (see tutorial on updating documents).

Retrieve History Entries of a Document
1
2
3
4
5
6
7
8
String objectId = "1234567890"; //example-objectId

Request request = new Request.Builder()
    .header("Authorization", auth)
    .header("X-ID-TENANT-NAME", tenant)
    .url(baseUrl + "/api/dms/objects/" + objectId + "/history")
    .get()
    .build();

We can now execute the above request object with the OkHttpClient instance created at the beginning. Then we let the result be displayed as a string in the command line.

Execute Request
1
2
Response response = client.newCall(request).execute();
System.out.println(response.body().string());

The returned history for a DMS document is a list of all history entries. All history codes available in yuuvis® Momentum are listed and explained in the concept article on the Audit Trail.

3.6.8. Summary

In this article, we used the OkHttpClient to retrieve the history of a DMS document and output the result to the command line. If you want to use a client to send several requests to the system in the same user context, we recommend a session handling, such as described here.

The full implementation of this example can be found in this git repository.

3.7. Using Compound Documents

Concatenate multiple binary content files as byte arrays in one compound document. Create sub-documents that refer to specified ranges within the total byte array.

3.7.1. Introduction

Compound documents in yuuvis® Momentum are document objects with a byte array as binary content file. In the byte array, it is possible to concatenate the binary coding of multiple individual files. Sub-documents can be defined such that they refer exactly to the ranges within the byte array where the individual original files are located. A retrieval request for the content file of such sub-documents then returns exactly the binary coding of the individual original files. But also any other range or any combination of ranges can be referenced as content of sub-documents. A retrieval request for the content file of such sub-documents then returns the concatenation of the specified ranges.

In this tutorial, we provide an example scenario for the handling of compound documents and sub-documents.

3.7.2. Requirements

To work through this tutorial, the following is required:

  • Set-up yuuvis® Momentum system (see Installation Guide)

  • Configured user with appropriate permissions (in the example: clouduser:secret on tenant default)

  • Simple Maven project

3.7.3. Maven Configuration

Our Java client will submit its requests to the Core API using OkHttp 3.12 by Square, Inc. To build the metadata of a compound document and evaluate the responses of the Core API, it also requires a JSON library, with org.json selected in this tutorial. To work with these libraries, the following block must be added to the Maven dependencies in the pom.xml of the project:

pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
<dependencies>
    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>okhttp</artifactId>
        <version>3.12.0</version>
    </dependency>
        <dependency>
        <groupId>org.json</groupId>
               <artifactId>json</artifactId>
        <version>20180813</version>
        </dependency>
</dependencies>

3.7.4. Client Configuration

The basis for accessing the Core API is an OkHttp3 client that can issue HTTP requests against reachable URLs. Additionally, we need to define some variables that our OkHttp3 client will use to reach and authenticate at the Core API.

OkHttp3 Client and Variables
1
2
3
4
5
6
7
8
String baseUrl = "http://127.0.0.1"; //baseUrl of gateway: "http://&lt;host&gt;:&lt;port>"
String username = "clouduser";
String userpassword = "secret";
String tenant = "default";
String auth = java.util.Base64.getEncoder().encodeToString((username + ":" + userpassword).getBytes());

CookieJar cookieJar = new JavaNetCookieJar(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
OkHttpClient client = new OkHttpClient.Builder().cookieJar(cookieJar).build();

For more information on setting up the OkHttp3 client with cookie handling, see this tutorial on logging into the Core API.

3.7.5. Binary Content of the Compound Document

The binary content of a compound document must be a byte array. All individual files you want to concatenate have to be converted into this format. In the example code block below, FileUtils.readFileToByteArray(File file) is used to convert the contents of a file into a ByteArray (transforming it into binary code). If you want to reference the content of the individual original files lateron, you need to know their length within the byte array to determine their ranges.

convert individual example files
1
2
3
4
5
6
7
byte[] document1BA = FileUtils.readFileToByteArray(new File("./src/main/resources/test.txt"));
byte[] document2BA = FileUtils.readFileToByteArray(new File("./src/main/resources/test1.txt"));
byte[] document3BA = FileUtils.readFileToByteArray(new File("./src/main/resources/test2.txt"));

long document1BAlength = document1BA.length;
long document2BAlength = document2BA.length;
long document3BAlength = document3BA.length;

The converted individual files can easily be concatenated to an output stream as shown in the next example code block. Pay attention to set the offset correctly in order to not overwrite parts of individual contents. You should store the byte ranges that correspond to the individual original files. In the example, they are stored in the ranges array. Additionally, the original file names of the individual files are stored in the partialNames array. Those values can be used to provide a more convenient recognition of the referenced ranges in the sub-documents' metadata.

Building Content of a Compound Document
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//generate file for compound document content
File compoundFile = File.createTempFile("compound", ".bin");
OutputStream bos = new BufferedOutputStream(new FileOutputStream(compoundFile));

//partial document = Teildokument
String[] ranges = new String[3];                     //Byte ranges of the partial documents in the compound document
String[] partialNames = new String[3];        //Names of the partial documents

//write partial document bytestreams into binary compound file
long offset = 0;
String range1 = offset + "-" + (offset + document1BAlength - 1);
bos.write(document1BA);
ranges[0] = range1;
partialNames[0] = "test.txt";

offset += document1BAlength;
String range2 = offset + "-" + (offset + document2BAlength - 1);
bos.write(document2BA);
ranges[1] = range2;
partialNames[1] = "test1.txt";

offset += document2BAlength;
String range3 = (offset) + "-" + (offset + document3BAlength - 1);
bos.write(document3BA);
ranges[2] = range3;
partialNames[2] = "test2.txt";

IOUtils.closeQuietly(bos);

3.7.6. Metadata for the Object Creation

Creating a Compound Document

The import endpoint POST /api/dms/objects expects a multipart request body. Multiple objects can be created in yuuvis® Momentum with one request. Thus, it is possible to create the compound document with the concatenated byte array as content file and, in the same request, some sub-documents.

As shown in the example objects list below, the compound document is defined first. All following objects are sub-documents. They refer to the same cid like the compound document, but a range is additionally specified. Here, the ranges correspond to the individual original files and their original file names are noted in the metadata of the sub-documents.

Compound Document and Sub-documents
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
{
    "objects": [
        {
            "contentStreams": [
                {
                    "fileName": "compound.bin",
                    "mimeType": "application/octet-stream",
                    "cid": "cid_63apple"
                }
            ],
            "properties": {
                "objectTypeId": {
                    "value": "document"
                },
                "name": {
                    "value": "testCompound"
                }
            }
        },
        {
            "contentStreams": [
                {
                    "fileName": "compound.bin",
                    "range": "0-1244",
                    "mimeType": "text/plain",
                    "cid": "cid_63apple"
                }
            ],
            "properties": {
                "objectTypeId": {
                    "value": "document"
                },
                "name": {
                    "value": "test.txt"
                }
            }
        },
        {
            "contentStreams": [
                {
                    "fileName": "compound.bin",
                    "range": "1245-1338",
                    "mimeType": "text/plain",
                    "cid": "cid_63apple"
                }
            ],
            "properties": {
                "objectTypeId": {
                    "value": "document"
                },
                "name": {
                    "value": "test1.txt"
                }
            }
        },
        {
            "contentStreams": [
                {
                    "fileName": "compound.bin",
                    "range": "1339-2610",
                    "mimeType": "text/plain",
                    "cid": "cid_63apple"
                }
            ],
            "properties": {
                "objectTypeId": {
                    "value": "document"
                },
                "name": {
                    "value": "test2.txt"
                }
            }
        }
    ]
}
Creating Sub-Documents

It is also possible to create sub-documents of an already existing compound document. Do not assign a binary content file a second time, but reference the contentStreamId, repositoryId and archivePath where the binary content file of the compound document is stored. The archivePath is especially required if reconstruction is not possible with metadata information (e.g., if a pathTemplate containing dynamic path elements like DATE is configured in the archive profile). As you can see in the example, you can also specify a concatenation of multiple ranges.

Metadata for Subsequent Import of Subdocuments
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
    "objects": [
        {
            "contentStreams": [
                {
                    "contentStreamId": "8FF6DBAE-1969-11E9-83A4-DFA1C5E44BD0",
                    "repositoryId": "repo242",
                    "archivePath": "default/2023/01/06/",
                    "range": "1159-1365,0-45"
                    "mimeType": "text/plain"
                }
            ],
            "properties": {
                "objectTypeId": {
                    "value": "document"
                },
                "name": {
                    "value": "sub-concatenation.txt"
                }
            }
        }
    ]
}

3.7.7. Importing Compound Documents

Importing a compound document with the DMS API works in the same way as regular imports via POST of a multipart body with metadata and content to the endpoint /api/dms/objects. In the example, the compoundImportJsonString contains the metadata for the compound document and sub-documents as shown before.

Importing a Compound Document
1
2
3
4
5
6
7
8
9
10
11
12
13
14
RequestBody compoundImportRequestBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("data", "metaData.json", RequestBody.create(JSON, compoundImportJsonString))
        .addFormDataPart("cid_63apple", "compound.bin", RequestBody.create(OCTETSTREAM, compoundFile))
        .build();

Request compoundImportRequest = new Request.Builder()
        .header("Authorization", "Basic " + auth)
        .header("X-ID-TENANT-NAME", "default")
        .url(baseUrl + "objects")
        .post(compoundImportRequestBody)
        .build();

Response compoundImportResponse = client.newCall(compoundImportRequest).execute();

3.7.8. Importing Large Compound Documents

Importing very large compound documents together with the creation of many sub-documents (about 5000 or more) within one request can overload the Core API and cause some of the operations to fail. Therefore, it is recommended to stage such requests in several episodes: First, import the compound document itself as a single document and extract the contentStreamID and repositoryId from the response. From there, import the metadata of all sub-documents subsequently in a series of batch imports. Limit the amount of sub-documents per import to less than 5000 to avoid overloading.

When subsequently importing sub-documents, please note that the metadata (postSubDocumentImportJsonString in the example) must be sent in a multipart body as well, even if this multipart body consists of only one part.

Subsequent Import of a Sub-document
1
2
3
4
5
6
7
8
9
10
11
12
13
RequestBody postSubDocumentImportRequestBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("data", "metadata.json", RequestBody.create(JSON, postSubDocumentImportJsonString))
        .build();

Request postSubDocumentImportRequest = new Request.Builder()
        .header("Authorization", auth)
        .header("X-ID-TENANT-NAME", tenant)
        .url(baseUrl + "objects")
        .post(postSubDocumentImportRequestBody)
        .build();

Response postSubDocumentImportResponse = client.newCall(postSubDocumentImportRequest).execute();

3.7.9. Retrieving Sub-Documents

If you request the content of a compound document, you will get the total byte array. However, in most use cases, you want to retrieve a specific section of the total byte array. This is easily possible by retrieving a sub-document with a suitable range value that references the desired section in the total byte array (creation described above). You can retrieve its content by objectId (of the dub-document) as usual and you will get the corresponding section of the compound document’s content.

Retrieve the content file of the DMS object specified by 'objectId'
1
2
3
4
5
6
7
Request getContentOfSubDocumentRequest = new Request.Builder()
        .header("Authorization", auth)
        .header("X-ID-TENANT-NAME", tenant)
        .url(baseUrl + "objects/" + objectId + "/contents/file")
        .get().build();

Response getContentOfSubDocumentResponse = client.newCall(getContentOfSubDocumentRequest).execute();

See also the tutorial Retrieving Documents via Core API.

3.7.10. Deleting Compound Documents

If you request the deletion of a compound document, its metadata is deleted from the database. Thus, the DMS object itself does not exist in the system anymore. However, if at least one sub-document references a range within the former compound document’s binary content file, the entire original byte array remains in the binary storage. It is even possible to define new sub-documents with reference on the same repositoryId and contentStreamId. Only if you delete all sub-documents of an already deleted compound document, the binary content is deleted as well.

See also the tutorial Deleting Documents via Core API.

3.7.11. Summary

In this tutorial, we used an OkHttpClient to import and retrieve a compound document and several sub-documents through the Core API.

A complete code example can be found in this git repository.

3.8. Managing the Schema

This tutorial shows how to use the Core API to get the tenant-specific schema of the system, how to validate a schema, and how to bring in a new schema.

3.8.1. Introduction

The schema consists of the tenant-specific schema, the unchangeable system properties, and the global schema. It determines the attributes and properties that objects must or may have in the system. You can find out more about the structure of the schema here.

This tutorial deals with the administration of tenant-specific schemas. The global schema remains unchanged from the endpoints presented below.

A user can only manage the schema that belongs to the client to which he or she belongs. It is not possible to manage schemas of other clients. A user also requires the role 'YUUVIS_TENANT_ADMIN'.

The endpoints presented in the following example provide or expect a schema in XML format.

3.8.2. Requirements

To work through this tutorial, the following is required:

3.8.3. Maven Configuration

This example uses the OkHttpClient of the open source portal Square Open Source. For this, we add the following dependency to the file pom.xml:

pom.xml
1
2
3
4
5
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.12.0</version>
</dependency>

3.8.4. Client Configuration

To interact with the yuuvis® API system via the Core API, we use an OkHttp3 client to send HTTP requests and read their responses.

OkHttp3 Client and Variables
1
2
3
4
5
6
7
8
String baseUrl = "http://127.0.0.1"; //baseUrl of gateway: "http://&lt;host&gt;:&lt;port>"
String username = "clouduser";
String userpassword = "secret";
String tenant = "default";
String auth = java.util.Base64.getEncoder().encodeToString((username + ":" + userpassword).getBytes());

OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient client = builder.build();

For more information on setting up the OkHttp3 client with cookie handling, please refer to this login tutorial.

3.8.5. Retrieving the Schema

The active schema can be retrieved with a GET request to the URL /api/admin/schema. This schema contains only the tenant-specific, user-defined object types, properties, and so on. It does not contain any system types, meaning you can upload it as it is without the system behaving differently afterwards. Only the version number of the schema and the modification date would change. Underneath the tenant-specific schema lies a preconfigured global schema which can be altered only by authorized administrators via the URL /api/system/schema. To retrieve a complete schema consisting of the global schema and the additions specific to the tenant of the user that requests it, use /api/dms/schema.

Retrieving the Schema
1
2
3
4
5
6
Request getSchemaRequest = new Request.Builder()
        .header("Authorization", "Basic " + auth)
        .header("X-ID-TENANT-NAME", tenant)
        .url(baseUrl + "/api/admin/schema")
        .get()
        .build();

The OkHttpClient instance now makes it easy to write the schema to a file.

Write the Schema to a File
1
2
3
4
5
try(FileOutputStream fos = new FileOutputStream("activeSchema.xml")) {
    Response activeSchemaResponse = client.newCall(getSchemaRequest).execute();
    byte[] bytes = activeSchemaResponse.body().bytes();
    fos.write(bytes);
}

3.8.6. Validating a Schema

A POST request for the URL /api/admin/schema/validate can be used to verify that a schema is valid. This requires a schema; in the example, under the path ./schemaToValidate.xml. The schema is sent as a multi-part in the body of the request.

Validating a Schema
1
2
3
4
5
6
7
8
9
10
11
12
13
String filename = "./schemaToValidate.xml";

RequestBody requestBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("file", "schema.xml", RequestBody.create(MediaType.parse("application/xml; charset=utf-8"), new File(filename)))
        .build();

Request validateSchemaRequest = new Request.Builder()
        .header("Authorization", "Basic " + auth)
        .header("X-ID-TENANT-NAME", tenant)
        .url(baseUrl + "/api/admin/schema/validate")
        .post(requestBody)
        .build();

The response to this request contains an HTTP status code and the validation result in JSON format. You can simply output this to the console after the request was called using an OkHttpClient instance.

Console Output of the Validation Result
1
2
3
4
Response validationResponse = client.newCall(validateSchemaRequest).execute();
System.out.println(validationResponse.code());
String validationResponseAsString = validationResponse.body().string();
System.out.println(validationResponseAsString);

In the case of a valid schema, the response contains the HTTP status code 200 and the validation result is an empty list, meaning it does not contain any validation errors.

Result of a Successful Validation
1
2
3
{
    "validationErrors": []
}

If, however, the schema is not valid, the response contains the HTTP status code 422 and there is at least one validation error.

Result of an Unsuccessful Validation
1
2
3
4
5
{
    "validationErrors": [{
        "message": "Invalid property reference 'name' in type definition 'email'."
    }]
}

3.8.7. Importing a New Schema

A new schema can be imported with the POST request to the URL /api/admin/schema. The endpoint behaves similar to the validation endpoint, meaning the HTTP status code of the answer tells you if the schema is valid and the answer contains a validation result. The difference is that if the validation is successful, the schema is stored and activated in the system.

Importing a Schema
1
2
3
4
5
6
7
8
9
10
11
12
13
String filename = "./schemaToImport.xml";

RequestBody requestBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("file", "schema.xml", RequestBody.create(MediaType.parse("application/xml; charset=utf-8"), new File(filename)))
        .build();

Request validateSchemaRequest = new Request.Builder()
    .header("Authorization", "Basic " + auth)
        .header("X-ID-TENANT-NAME", tenant)
        .url(baseUrl + "/api/admin/schema")
        .post(requestBody)
        .build();

The further use of the request is analogous to the validation of a schema described in the previous section.

3.8.8. Changing the Schema

Typically, you rarely want to import a completely new schema. Often you only want to extend the active schema with object types or properties or make small changes. This can be done with the help of the three preset endpoints:

  1. Fetch the schema to be changed and save it locally in an XML file.

  2. Make the desired changes to the XML file and verify with the validation endpoint whether the new version of the schema is still valid.

  3. Import the changed, valid schema

3.8.9. Summary

This tutorial showed how to get the tenant-specific schema in XML format for editing, how to validate any schema and how to import a new schema.

The full implementations of these examples can be found in this Git repository.

For more information about creating your own Schema, please refer to the Schema concepts article.

3.9. Changing Object Structure during Lifecycle

This tutorial shows how to change the set of available metadata properties for individual DMS objects during their entire lifecycle. Classify objects at a later point in time, add or remove property groups at runtime by defining and referencing floating secondary object types (SOTs).

3.9.1. Requirements

To work through this tutorial, the following is required:

  • Set-up yuuvis® Momentum core system (see Installation Guide)

  • A user with read and write permissions on a document type in the system (see Access Management)

3.9.2. Example Use Case

Since a high variety of customized business processes can be set up for managing content, this tutorial shows one basic example to give you a better understanding of the idea behind the provided functionality. Let us imagine the following initial situation: we want to import documents and do not know the content types yet. At a later point in time, if the content type is known, we would like to add the needed group of properties for invoice, delivery slip and supplier metadata by using floating secondary object types.

Example scenario
Defining Document Object Types

Add a new document object type definition (document) with a single property (DateOfReceipt) to your schema to enable the import in general. To store objects with content, the objects' type must be a document type and the contentStreamAllowed attribute must specify that this type can or must have content (allowed or required).

Example excerpt from the schema
...
    <typeDocumentDefinition>
        <id>appSot:document</id>
        <baseId>system:document</baseId>
        <contentStreamAllowed>allowed</contentStreamAllowed>
        <propertyReference>appSot:DateOfReceipt</propertyReference>
    </typeDocumentDefinition>
...
Define Secondary Object Types

Add three new SOTs to your schema - each representing a group of properties used for specifying the content type in detail (INV invoice, DEL delivery slip and SUP supplier). At this point, it does not matter whether the SOT will be used later on by a document object type as static or floating.

Example excerpt from the schema
...
    <typeSecondaryDefinition>
        <id>appSot:INV</id>
        <baseId>system:secondary</baseId>
        <propertyReference>appSot:invoiceNo</propertyReference>
    </typeSecondaryDefinition>

    <typeSecondaryDefinition>
        <id>appSot:DEL</id>
        <baseId>system:secondary</baseId>
        <propertyReference>appSot:deliverySlipNo</propertyReference>
    </typeSecondaryDefinition>

    <typeSecondaryDefinition>
        <id>appSot:SUP</id>
        <baseId>system:secondary</baseId>
        <propertyReference>appSot:name</propertyReference>
        <propertyReference>appSot:address</propertyReference>
        <propertyReference>appSot:phone</propertyReference>
    </typeSecondaryDefinition>
...
Adding References to Secondary Object Types

Now, add three references to the secondary object types for your defined document object type (document). All three are floating references (static="false"), since they should only be used if the content type is known and the properties are useful and necessary.

Example excerpt from the schema
...
    <typeDocumentDefinition>
        <id>appSot:document</id>
        <baseId>system:document</baseId>
        <contentStreamAllowed>allowed</contentStreamAllowed>
        <secondaryObjectTypeId static="false">appSot:INV</secondaryObjectTypeId>
        <secondaryObjectTypeId static="false">appSot:DEL</secondaryObjectTypeId>
        <secondaryObjectTypeId static="false">appSot:SUP</secondaryObjectTypeId>
    </typeDocumentDefinition>
...
Importing New Documents

First of all, import your documents as a simple instance of document including the values for the date of receipt using the POST /api/dms/objects endpoint.

Example metadata for the import
{
    "objects": [{
        "properties": {
            "system:objectTypeId": {
                "value": "appSot:document"
            }
            "appSot:DateOfReceipt": {
                "value": "2020-10-07"
            }
        }
    }]
}
Adding Secondary Object Types
During the Lifecycle

If the content type is known, you update the DMS object’s metadata structure by assigning the necessary SOTs (POST /api/dms/objects/{objectId} or PATCH /api/dms/objects/{objectId}). Use the keyword add for a single secondary object type, or value with a comma separated list, e.g., ["INV","SUP"] for multiple ones. Note that by using the keyword value, the list of floating SOTs transferred will replace all existing ones. This includes the related properties and metadata values. If you want to keep the existing floating SOTs, you have to list them as well.

Example PATCH request body (assign a single SOT)
{
    "objects": [{
        "properties": {
            "system:secondaryObjecttypeIds": {
                "add": "INV"
            },
            "appSot:invoiceNo": {
                "value": "K0815-2020-1894834"
            }
        }
    }]
}
Example PATCH request body (assign multiple SOTs)
{
    "objects": [{
        "properties": {
            "system:secondaryObjecttypeIds": {
                "value": ["INV","SUP"]
            },
            "appSot:invoiceNo": {
                "value": "K0815-2020-1894834"
            },
            "appSot:name": {
                "value": "Supplier Smith"
            },
            "appSot:address": {
                "value": "7 Main Street, London"
            },
            "appSot:phone": {
                "value": "004420834029390"
            }
        }
    }]
}
Right at the Start of the Lifecycle (Import)

If you already know what content type you are going to import (e.g., an invoice), you can add one or more floating SOTs right away. Use the keyword value with a comma separated list, e.g., ["INV","SUP"] and the POST /api/dms/objects endpoint.

Example import metadata (assign multiple SOTs)
{
    "objects": [{
        "properties": {
            "system:objectTypeId": {
                "value": "appSot:document"
            }
            "system:secondaryObjectTypeIds": {
                "value": ["INV","SUP"]
            }
            "appSot:DateOfReceipt": {
                "value": "2020-10-07"
            }
        }
    }]
}
Removing Secondary Object Types

When a floating SOT is not needed any longer, you remove it from the DMS object using the update endpoints (POST /api/dms/objects/{objectId} or PATCH /api/dms/objects/{objectId}). All related properties and metadata values will be removed as well.

Example PATCH request body (remove SOT)
{
    "objects": [{
        "properties": {
            "system:secondaryobjecttypeids": {
                "remove": "INV"
            }
        }
    }]
}
Searching for Objects

You search for objects that use secondary object types by explicitly specifying them in the FROM clause:

select * from appSot:INV

The search result delivers the entire object and not only the properties of the specified secondary object type.

3.10. Tagging Objects for Processing

Based on tags, you set up complex stateful processing chains. This tutorial describes how tags can be added, displayed, and updated in an example context. For this purpose, a typical application will be discussed: An import management system, which is an example for a processing chain, where tags are a helpful tool to describe the current status of each object.

3.10.1. Introduction

In modern data processing chains, asynchronous operations become more and more popular. Concerning the administration of such complex procedures, a status measure is essential. The lifecycle of any object needs to be documented with a view to a general knowledge on the current state of progress, and in order to enable the resumption of interrupted processes. If the object status were located in the metadata, each pass through a multi-stage processing chain would create a completely new version of the whole object, which needs to be stored in addition to the previous one. In contrast, tags are treated separately. They always have a state and a traceId, which are a basis for external support as well as a possibility to control asynchronous operations. This additional information is stored together with the object, but independently of the metadata. Tags can only be assigned to the current version of an object. At the same time, their management and modification does not trigger the creation of a new version. The so assigned processing status reflects a concrete state of the object and serves as the basis for further transactions.

3.10.2. Requirements

This tutorial is dedicated to experienced users. Please find information on requirements, maven and client configuration in our Importing Documents via Core API tutorial, on which the variables' names are based. The handling of any IOException is demonstrated there, too.

3.10.3. Application Example – Import Management

The import management allows for subsequent object type classification that is independent of the actual import process. As a matter of fact, the initial step is a general search for recently created objects that have to be analyzed. Any object identified will be flagged with an integer tag analysis showing the current state of progress within the characterization process (waiting to be processed (1) → processing started (2) → processing finished (3) → metadata updated (4)).

Further tags will be assigned to the object in order to demonstrate the handling of multiple tags assigned to one object, to explain the tracing for tag operations and to illustrate the behavior of tags during metadata and content updates.

In this tutorial, the tag handling is explained by following one object with the arbitrary objectId=1234567812345678 through the processing chain of the import management. The code snippets can be executed in the same order as they are shown if the requirements are met and at least one document was imported. Replace the example objectId in the code snippets by the actual objectId of your imported document.

Example processing chain with a tag.
Adding Tags to Objects

A general search might deliver a long result list. In this example, one object is selected in order to demonstrate how to add a new tag. The selected object has the objectId=1234567812345678. An analysis tag is added with the current state value 1 (= waiting to be processed). For the import management, this step will be carried out for each individual result of the general search.

The string variables auth, tenant and baseUrl are defined in the client configuration.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
String objectId = "1234567812345678";
String tagName = "analysis";
String tagValue = "1";

RequestBody addTagBody = RequestBody.create(null, new byte[]{});

Request addTagRequest = new Request.Builder()
                    .header("Authorization", auth)
                    .header("X-ID-TENANT-NAME", tenant)
                    .url(baseUrl + "/api/dms/objects/" + objectId + "/tags/" + tagName + "/state/" + tagValue)
                    .post(addTagBody)
                    .build();

            Response addTagResponse = client.newCall(addTagRequest).execute();
            String addTagResponseString = addTagResponse.body().string();
            System.out.println(addTagResponseString);
Response
1
2
3
4
5
6
7
8
9
10
{"objects": [{
  "properties": {
    "system:tags": {
       "value": [
         ["analysis",1,"2021-06-30T15:19:25.370Z","0ff83b2d8c17b704"]
       ]
     }
   }
 }]
}

Endpoint details: POST /api/dms/objects/{objectId}/tags/{name}/state/{state}.

We add a second tag to the example object in order to demonstrate the handling of multiple tags. The procedure is exactly the same.

Adding tag 'testtag' in addition to tag 'analysis'.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
String objectId = "1234567812345678";
String tagName = "testtag";
String tagValue = "7";

RequestBody addTagBody = RequestBody.create(null, new byte[]{});

Request addTagRequest = new Request.Builder()
                    .header("Authorization", auth)
                    .header("X-ID-TENANT-NAME", tenant)
                    .url(baseUrl + "/api/dms/objects/" + objectId + "/tags/" + tagName + "/state/" + tagValue)
                    .post(addTagBody)
                    .build();

            Response addTagResponse = client.newCall(addTagRequest).execute();
            String addTagResponseString = addTagResponse.body().string();
            System.out.println(addTagResponseString);
Response
1
2
3
4
5
6
7
8
9
10
11
{"objects": [{
  "properties": {
    "system:tags": {
       "value": [
         ["analysis",1,"2021-06-30T15:19:25.370Z","0ff83b2d8c17b704"],
         ["testtag",7,"2021-06-30T15:19:26.700Z","4b2448d66e4d02eb"]
       ]
     }
   }
 }]
}
Showing Tags of Objects

To check the current state of the object processing, the tags of a specified object can be viewed. The response will contain the status information for all tags of the object with the given objectId. In particular, the example code below returns the analysis tag together with its state value 1 as well as the testtag tag together with its state value 7.

1
2
3
4
5
6
7
8
9
10
11
String objectId = "1234567812345678";

Request getTagRequest = new Request.Builder()
                    .header("Authorization", auth)
                    .header("X-ID-TENANT-NAME", tenant)
                    .url(baseUrl+ "/api/dms/objects/" + objectId + "/tags")
                    .get().build();

            Response tagResponse = client.newCall(getTagRequest).execute();
            String tagResponseString = tagResponse.body().string();
            System.out.println(tagResponseString);
Response
1
2
3
4
5
6
7
8
9
10
11
12
{"objects": [{
  "properties": {
     "system:tags": {
       "columnNames": ["name","state","creationDate","traceId"],
       "value": [
         ["analysis",1,"2021-06-30T15:19:25.370Z","0ff83b2d8c17b704"],
         ["testtag",7,"2021-06-30T15:19:26.700Z","4b2448d66e4d02eb"]
       ]
     }
   }
 }]
}

Endpoint details: GET /api/dms/objects/{objectId}/tags

Searching Objects and Updating Their Tags

At this point in the import management context, there are several objects in the system having a newly added analysis tag with the state 1. They are all waiting for a time-consuming processing step, but only one of them can be handled at the same time. In order to select one individual object for further processing, a search query is used, which returns a limited result list of objects having an analysis tag with the state 1 that was created/modified today or yesterday. The first result in this list is updated to state=2 which means processing started. In the code snippet of the Adding Tags to Objects section, only one object was flagged with the tag and thus the following code snippet will continue with exactly this object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
String statement = "SELECT * FROM document WHERE system:tags[analysis].(state=1 AND (creationDate=YESTERDAY() OR creationDate=TODAY()))";
String tagName = "analysis";
String newTagValue = "2";

Request queryTagRequest = new Request.Builder()
                    .header("Authorization", auth)
                    .header("X-ID-TENANT-NAME", tenant)
                    .url(baseUrl + "/api/dms/objects/tags/" + tagName + "/state/" + newTagValue + "?query=" + statement)
                    .post(RequestBody.create(null, new byte[0]))
                    .build();

            Response queryTagResponse = client.newCall(queryTagRequest).execute();
            String queryTagResponseString = queryTagResponse.body().string();
            System.out.println(queryTagResponseString);
Excerpt from the response body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{"objects": [{
  "properties": {
    "system:objectId": {
       "value": "1234567812345678"
     },
    ...
    "system:versionNumber": {
       "value": 1
    },
    ...
    ...
    "system:tags": {
       "value": [
         ["analysis",2,"2021-06-30T15:19:27.950Z","0ff83b2d8c17b704"],
         ["testtag",7,"2021-06-30T15:19:26.700Z","4b2448d66e4d02eb"]
       ]
     },
     ...
   },
   ...
 }]
}

Endpoint details: POST /api/dms/objects/tags/{name}/state/{state}?query=<SQL>

Updating Tags of Objects

As soon as the processing of the object is finished, the tag should be updated as well. The code below will change the status value of the analysis tag to 3 (= processing finished).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
String objectId = "1234567812345678";
String tagName = "analysis";
String newTagValue = "3";

Request updateTagRequest = new Request.Builder()
                    .header("Authorization", auth)
                    .header("X-ID-TENANT-NAME", tenant)
                    .url(baseUrl + "/api/dms/objects/" + objectId + "/tags/" + tagName + "/state/" + newTagValue + "?overwrite=true")
                    .post(RequestBody.create(null, new byte[0]))
                    .build();

            Response updateTagResponse = client.newCall(updateTagRequest).execute();
            String updateTagResponseString = updateTagResponse.body().string();
            System.out.println(updateTagResponseString);
Response
1
2
3
4
5
6
7
8
9
10
11
12
{"objects": [{
  "properties": {
     "system:tags": {
       "columnNames": ["name","state","creationDate","traceId"],
       "value": [
         ["analysis",3,"2021-06-30T15:19:28.530Z","faa0cdae5008d7e0"],
         ["testtag",7,"2021-06-30T15:19:26.700Z","4b2448d66e4d02eb"]
       ]
     }
   }
 }]
}
Adding Tags with Specified 'traceId'

In order to label multiple tag operations to associate them with one overall process, the traceId can be specified. In the code block below, the tracingprocess tag with state value 1 is added to our example object specified by its objectId. Additionally, a string traceId is defined in line 4. The traceId is passed to the endpoint in the request header in line 9. It will be set as value for the traceId of the new tag tracingprocess.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
String objectId = "1234567812345678";
String tagName = "tracingprocess";
String tagValue = "1";
String traceId = "1122334455667788";

Request addTagRequest = new Request.Builder()
                    .header("Authorization", auth)
                    .header("X-ID-TENANT-NAME", tenant)
                    .header("X-B3-TraceId", traceId)
                    .url(baseUrl + "/api/dms/objects/" + objectId + "/tags/" + tagName + "/state/" + tagValue)
                    .post(RequestBody.create(null, new byte[0]))
                    .build();

            Response addTagResponse = client.newCall(addTagRequest).execute();
            String addTagResponseString = addTagResponse.body().string();
            System.out.println(addTagResponseString);
Response
1
2
3
4
5
6
7
8
9
10
11
12
13
{"objects": [{
  "properties": {
     "system:tags": {
       "columnNames": ["name","state","creationDate","traceId"],
       "value": [
         ["analysis",3,"2021-06-30T15:19:28.530Z","faa0cdae5008d7e0"],
         ["testtag",7,"2021-06-30T15:19:26.700Z","4b2448d66e4d02eb"],
         ["tracingprocess",1,"2021-06-30T15:19:30.250Z","1122334455667788"]
       ]
     }
   }
 }]
}

Endpoint details: POST /api/dms/objects/{objectId}/tags/{name}/state/{state}

Updating Tags with Specified 'traceId'

Similar as in Adding Tags with Specified 'traceId', also in a tag update request, the query parameter traceIdMustMatch=true can be set if a traceId is specified in the header. The update operation will be performed only if the values are matching. Thus, the tag can only be updated if the previous traceId is known to the caller. Furthermore, the update operation will appear with the same traceId in the audit trail and can thus be summarized with the tag creation operation in one overall process trace.

The code block below shows an update request for the tracingprocess tag to the state value 2. Since the traceId specified in line 4 and referenced in line 9 matches the current traceId of the tracingprocess tag, the update will be successful. Of course, the traceId will remain the same after the tag update.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
String objectId = "1234567812345678";
String tagName = "tracingprocess";
String newTagValue = "2";
String traceId = "1122334455667788";

Request updateTagRequest = new Request.Builder()
                    .header("Authorization", auth)
                    .header("X-ID-TENANT-NAME", tenant)
                    .header("X-B3-TraceId", traceId)
                    .url(baseUrl + "/api/dms/objects/" + objectId + "/tags/" + tagName + "/state/" + newTagValue + "?overwrite=true&traceIdMustMatch=true")
                    .post(RequestBody.create(null, new byte[0]))
                    .build();

            Response updateTagResponse = client.newCall(updateTagRequest).execute();
            String updateTagResponseString = updateTagResponse.body().string();
            System.out.println(updateTagResponseString);
Response
1
2
3
4
5
6
7
8
9
10
11
12
13
{"objects": [{
  "properties": {
     "system:tags": {
       "columnNames": ["name","state","creationDate","traceId"],
       "value": [
         ["analysis",3,"2021-06-30T15:19:28.530Z","faa0cdae5008d7e0"],
         ["testtag",7,"2021-06-30T15:19:26.700Z","4b2448d66e4d02eb"],
         ["tracingprocess",2,"2021-06-30T15:19:30.780Z","1122334455667788"]
       ]
     }
   }
 }]
}

Endpoint details: POST /api/dms/objects/{objectId}/tags/{name}/state/{state}?overwrite=true

Deleting Tags with Specified 'traceId'

The deletion of a tag can be requested with the appended query parameter traceIdMustMatch=true or without. If not specified, the default traceIdMustMatch=false will be set and the current traceId of the corresponding tag will not be checked.

The code block shows a deletion call with traceIdMustMatch=true. The traceId in the header will be compared with the current traceId of the tag tracingprocess. If the values are matching, the tag is deleted.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
String objectId = "1234567812345678";
String tagName = "tracingprocess";
String traceId = "1122334455667788";

Request deleteTagRequest = new Request.Builder()
                    .header("Authorization", auth)
                    .header("X-ID-TENANT-NAME", tenant)
                    .header("X-B3-TraceId", traceId)
                    .url(baseUrl + "/api/dms/objects/"+ objectId + "/tags/" + tagName + "?traceIdMustMatch=true")
                    .delete().build();

            Response deleteTagResponse = client.newCall(deleteTagRequest).execute();

            if(deleteTagResponse.code() == 200) System.out.println("Successfully deleted.");
            else System.out.println("Error while deleting: " + deleteTagResponse.code());

Endpoint details: DELETE /api/dms/objects/{objectId}/tags/{name}

Tag Behavior in PATCH Metadata Update

In this section the behavior of tags during PATCH metadata update calls is demonstrated. To learn about requesting the call itself, please refer to the Updating Documents via Core API tutorial.

In a PATCH update, only the properties referenced in the request body will be modified. Although the tags do not belong to the metadata, they can be modified like metadata and together with the metadata in one call. The tag information is stored in table format. Thus, like for metadata table properties, the entire table will be replaced during the PATCH update. Consequently, tags can be added, updated or removed from the object. The code block shows an example request body that updates the state of the analysis tag to value 4 (= metadata updated) and adds the new tag contentprocessing:resistant. The suffix resistant indicates that the tag persists during updates of the binary content file assigned to the corresponding object. From the PATCH request body, only name and state of the tags are read. The tag properties creationDate and traceId are automatically determined by the system. The traceId of each tag will have the value of the system:traceId metadata property. In our example request body, the table row for the testtag tag is missing and will thus not appear in the new tag table anymore.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
  "objects": [{
    "properties": {
      "Name": {
        "value": "Test 3"
      },
      "system:tags": {
        "value": [
          ["analysis",4],
          ["contentprocessing:resistant",13]
        ]
      }
    }
  }]
}
Excerpt from the response body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{"objects": [{
  "properties": {
    "system:objectId": {
       "value": "1234567812345678"
     },
    ...
    "system:versionNumber": {
       "value": 2
    },
    ...
    "system:traceId": {
      "value": "118343a3fbc940e6"
    },
    "system:tags": {
       "value": [
         ["analysis",4,"2021-06-30T15:19:32.560Z","118343a3fbc940e6"],
         ["contentprocessing:resistant",13,"2021-06-30T15:19:32.560Z","118343a3fbc940e6"]
       ]
     },
     "Name": {
        "value": "Test 3"
      },
   },
   ...
 }]
}

Endpoint details: PATCH /api/dms/objects/{objectId}

Content Update

See how to prepare a call for the update of the binary content file in the Updating Documents via Core API tutorial. The content update creates a new version of the object and deletes all the assigned tags that are not resistant tags.

From our example object, the tag analysis is removed, but the resistant tag contentprocessing:resistant is kept for the new object version. The values of the tag properties remain unchanged. The code block below shows an excerpt of the response including the system:tags tag table after the update of the binary content file.

Excerpt from the response body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{"objects": [{
  "properties": {
    "system:objectId": {
       "value": "1234567812345678"
     },
    ...
    "system:versionNumber": {
       "value": 3
    },
    ...
    ...
    "system:tags": {
       "value": [
         ["contentprocessing:resistant",13,"2021-06-30T15:19:32.560Z","118343a3fbc940e6"]
       ]
     },
     "Name": {
        "value": "Test 3"
      },
   },
   ...
 }]
}

Endpoint details: POST /api/dms/objects/{objectId}/contents/file

POST Metadata Update

See how to prepare a POST update of the metadata in the Updating Documents via Core API tutorial. The update replaces all the metadata of the object with the values specified in the request body. If a property is missing in the request body, it will be removed from the object (except automatically determined system properties). Also the entire table with the tag information has to be explicitly specified as already described in the Tag Behavior in PATCH Metadata Update section. If the system:tags table is not specified in the request body, all tags will be removed from the object.

The code block below shows an example request body where no tags are specified. Thus, the analysis tag and especially also the contentprocessing:resistant tag are deleted.

Excerpt from the response body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{"objects": [{
  "properties": {
    "system:objectId": {
       "value": "1234567812345678"
     },
    ...
    "system:versionNumber": {
       "value": 4
    },
    ...
    "system:tags": {
       "value": null
     },
     "Name": {
        "value": "Test 2"
      },
   },
   ...
 }]
}

3.10.4. Summary

This tutorial illustrated the tag handling supported by yuuvis® Momentum in the example context of a simplified import management system. For control and administration of the status of individual objects within a process chain, tags are the means of choice.

Code examples in gitHub

3.11. Setting and Querying Structured Data

This example tutorial provides explanations and code examples to get an idea on how to define and specify structured data properties and on how to query them.

3.11.1. Introduction

yuuvis® Momentum offers a property type for the storage of structured data in JSON format. Thus, it is possible to store interleaved data structures in a queryable way without defining each single sub-property in the schema. The structured data properties should NOT be considered to replace the concept of a well-defined schema. They should be used only if the handling of objects' metadata via the conventional property definitions is not reasonable. Especially, if the structure of metadata and/or the availability of properties differs a lot for the individual object instances, the schema might grow to a really long list of scarcely used properties. This can be avoided by the usage of a property field that can store a JSON structure as value. In this tutorial, the bibliographic information of media in a library is considered an example use case. For this purpose, the set of information for each medium is provided in JSON structure following the concept of BibJSON.

Code examples in GitHub.

3.11.2. Requirements

This tutorial is dedicated to experienced users. Please find information on requirements, maven and client configuration in our Importing Documents via Core API tutorial. The handling of any IOException is demonstrated there, too.

3.11.3. Definition in the Schema

In the context of the library example, the below displayed app schema is used. It contains two property definitions and one object type definition referencing the properties. The first property bibjsonsample:bibjson has the property type structureddata. Its id matches the expression expected for the validation and the cardinality is single which is the only accepted value.

This property will be used for the storage of the BibJSON structure containing the bibliographic information of the corresponding medium. The second property bibjsonsample:locations allows for the assignment of a list of strings indicating storage locations if a printed version is available for the corresponding medium. In the object type definition of bibjsonsample:medium, both properties are referenced. Additionally, a binary content file can be assigned if necessary as defined in line 25 with the value allowed for the contentStreamAllowed attribute.

Example Schema
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="utf-8"?>
<schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://optimal-systems.org/ns/dmscloud/schema/v5.0/dmsCloud-schema.xsd">

    <propertyStructuredDataDefinition>
        <id>bibjsonsample:bibjson</id>
        <description>field for the BibJSON structure identifying and describing the medium</description>
        <propertyType>structureddata</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStructuredDataDefinition>
    <propertyStringDefinition>
        <id>bibjsonsample:locations</id>
        <description>field for storage locations of printed versions of the medium</description>
        <propertyType>string</propertyType>
        <cardinality>multi</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <typeDocumentDefinition>
        <id>bibjsonsample:medium</id>
        <baseId>system:document</baseId>
        <propertyReference>bibjsonsample:bibjson</propertyReference>
        <propertyReference>bibjsonsample:locations</propertyReference>
        <contentStreamAllowed>allowed</contentStreamAllowed>
    </typeDocumentDefinition>

</schema>

The schema for the bibjsonsample app is imported via the POST /api/system/apps/{app}/schema endpoint.

More details and further examples on schema handling are provided in the following tutorial: Managing the Schema

3.11.4. Specifying Values during Import

Two example objects will be created as instances of the abbBibjsonsample:medium object type. Both of them are assigned a BibJSON value for the appbibjsonsample:bibjson property.

For the individual sub-values of the structured data property, the system can identify integers, booleans and strings. The successfully executed import returns the entire set of metadata for each object, enriched with the system properties.

The first example object is a book. The bibliographic information stored in the appBibjsonsample:bibjson property contains one integer value specified in line 21. All other sub-values are stored as strings. In addition to the appBibjsonsample:bibjson property, two storage locations for printed versions are specified.

Import Request for a Book
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
  "objects": [{
    "properties": {
      "objectTypeId": {
        "value": "appBibjsonsample:medium"
      },
      "appBibjsonsample:bibjson": {
        "value": {
          "type": "book",
          "title": "My Book Title",
          "author": [
            {"name": "Heinrich Schuetzel"},
            {"name": "Maximilian Sturz"}
          ],
          "year": "1995",
          "owner": "My Library",
          "id": "ID_of_book",
          "url": "http://mylibrary.com/ebooks/36513466534",
          "publisher": "Example Verlag Mustershagen",
          "edition": {
            "number": 2,
            "language": "English"
          },
          "identifier":[
            {
              "id": "0002-9327",
              "type": "issn"
            }
          ]
        }
      },
      "appBibjsonsample:locations": {
        "value": [
          "central library, CN-3214-5324",
          "branch library east, 43-654b"
        ]
      }
    }
  }]
}
Import Request for a Book
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
{
    "objects": [
        {
            "properties": {
                "system:objectId": {
                    "value": "aab2b4d9-e829-45dd-981a-2f19a688592d"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:objectTypeId": {
                    "value": "appBibjsonsample:medium"
                },
                "system:createdBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:creationDate": {
                    "value": "2021-06-14T13:10:52.280Z"
                },
                "system:lastModifiedBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:lastModificationDate": {
                    "value": "2021-06-14T13:10:52.280Z"
                },
                "system:versionNumber": {
                    "value": 1
                },
                "system:tenant": {
                    "value": "default"
                },
                "system:traceId": {
                    "value": "5681d3bddb4279de"
                },
                "appBibjsonsample:bibjson": {
                    "value": {
                        "type": "book",
                        "title": "My Book Title",
                        "author": [
                            {
                                "name": "Heinrich Schuetzel"
                            },
                            {
                                "name": "Maximilian Sturz"
                            }
                        ],
                        "year": "1995",
                        "owner": "My Library",
                        "id": "ID_of_book",
                        "url": "http://mylibrary.com/ebooks/36513466534",
                        "publisher": "Example Verlag Mustershagen",
                        "edition": {
                            "number": 2,
                            "language": "English"
                        },
                        "identifier": [
                            {
                                "id": "0002-9327",
                                "type": "issn"
                            }
                        ]
                    }
                },
                "appBibjsonsample:locations": {
                    "value": [
                        "central library, CN-3214-5324",
                        "branch library east, 43-654b"
                    ]
                }
            }
        }
    ]
}

The second example object is a collection of articles without corresponding printed versions. The structure of the JSON value for the appBibjsonsample:bibjson property looks completely different.

Import Request for a Collection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
{
    "objects": [
        {
            "properties": {
                "system:objectId": {
                    "value": "3d4a67be-3341-4317-bb57-c48ea7ab0a1a"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:objectTypeId": {
                    "value": "appBibjsonsample:medium"
                },
                "system:createdBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:creationDate": {
                    "value": "2021-06-14T13:11:57.770Z"
                },
                "system:lastModifiedBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:lastModificationDate": {
                    "value": "2021-06-14T13:11:57.770Z"
                },
                "system:versionNumber": {
                    "value": 1
                },
                "system:tenant": {
                    "value": "default"
                },
                "system:traceId": {
                    "value": "22839c5775801e9c"
                },
                "appBibjsonsample:bibjson": {
                    "value": {
                        "metadata": {
                            "collection": "ym_concepts",
                            "label": "yuuvis(R) Momentum Core Concepts",
                            "description": "Documentation for yuuvis(R) Momentum Core in a structured, theoretical way, with links to the tutorial section.",
                            "id": "ID_of_collection",
                            "owner": "OS",
                            "created": "2020-06-09T15:04:12.944Z",
                            "modified": "2021-06-10T11:05:17.166Z",
                            "source": "https://help.optimal-systems.com/yuuvis_develop/display/YMY/x/-4BkAg",
                            "records": 2
                        },
                        "records": [
                            {
                                "collection": "ym_concepts",
                                "type": "article",
                                "title": "Schema - Defining Object Types",
                                "id": "ID_of_schema_article",
                                "link": "https://help.optimal-systems.com/yuuvis_develop/display/YMY/x/AYFkAg",
                                "author": [
                                    {
                                        "name": "Heinrich Schuetzel"
                                    },
                                    {
                                        "name": "George Trader"
                                    },
                                    {
                                        "name": "Johann Fluss"
                                    }
                                ],
                                "created": "2020-06-09T15:04:12.944Z",
                                "modified": "2021-06-10T08:53:23.532Z"
                            },
                            {
                                "collection": "ym_concepts",
                                "type": "article",
                                "title": "Search Query Language",
                                "id": "ID_of_query_article",
                                "link": "https://help.optimal-systems.com/yuuvis_develop/display/YMY/x/gIFkAg",
                                "author": [
                                    {
                                        "name": "Andrea Schumann"
                                    },
                                    {
                                        "name": "Franz Lissner"
                                    },
                                    {
                                        "name": "Hans Kammer"
                                    },
                                    {
                                        "name": "Johann Fluss"
                                    }
                                ],
                                "created": "2020-06-16T14:03:01.833Z",
                                "modified": "2021-06-02T09:54:12.643Z"
                            }
                        ]
                    }
                }
            }
        }
    ]
}

3.11.5. Search Queries

The individual sub-values within the JSON value for the appBibjsonsample:bibjson property are queryable.

In this chapter, some example search queries are explained.

Example 1

This query statement requests a search for all objects of type appBibjsonsample:medium. The full set of metadata will be returned for each of them. In the example context of this tutorial, only two objects match the query: The book and the collection that were imported before.

SELECT * FROM appBibjsonsample:medium
Request Body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
{
    "objects": [
        {
            "properties": {
                "system:traceId": {
                    "value": "5681d3bddb4279de"
                },
                "system:objectTypeId": {
                    "value": "appBibjsonsample:medium"
                },
                "appBibjsonsample:bibjson": {
                    "value": {
                        "type": "book",
                        "title": "My Book Title",
                        "author": [
                            {
                                "name": "Heinrich Schuetzel"
                            },
                            {
                                "name": "Maximilian Sturz"
                            }
                        ],
                        "year": "1995",
                        "owner": "My Library",
                        "id": "ID_of_book",
                        "url": "http://mylibrary.com/ebooks/36513466534",
                        "publisher": "Example Verlag Mustershagen",
                        "edition": {
                            "number": 2,
                            "language": "English"
                        },
                        "identifier": [
                            {
                                "id": "0002-9327",
                                "type": "issn"
                            }
                        ]
                    }
                },
                "system:versionNumber": {
                    "value": 1
                },
                "system:createdBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:creationDate": {
                    "value": "2021-06-14T13:10:52.280Z"
                },
                "system:lastModificationDate": {
                    "value": "2021-06-14T13:10:52.280Z"
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:tenant": {
                    "value": "default"
                },
                "appBibjsonsample:locations": {
                    "value": [
                        "central library, CN-3214-5324",
                        "branch library east, 43-654b"
                    ]
                },
                "system:lastModifiedBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:objectId": {
                    "value": "aab2b4d9-e829-45dd-981a-2f19a688592d"
                }
            }
        },
        {
            "properties": {
                "system:traceId": {
                    "value": "22839c5775801e9c"
                },
                "system:objectTypeId": {
                    "value": "appBibjsonsample:medium"
                },
                "appBibjsonsample:bibjson": {
                    "value": {
                        "metadata": {
                            "collection": "ym_concepts",
                            "label": "yuuvis(R) Momentum Core Concepts",
                            "description": "Documentation for yuuvis(R) Momentum Core in a structured, theoretical way, with links to the tutorial section.",
                            "id": "ID_of_collection",
                            "owner": "OS",
                            "created": "2020-06-09T15:04:12.944Z",
                            "modified": "2021-06-10T11:05:17.166Z",
                            "source": "https://help.optimal-systems.com/yuuvis_develop/display/YMY/x/-4BkAg",
                            "records": 2
                        },
                        "records": [
                            {
                                "collection": "ym_concepts",
                                "type": "article",
                                "title": "Schema - Defining Object Types",
                                "id": "ID_of_schema_article",
                                "link": "https://help.optimal-systems.com/yuuvis_develop/display/YMY/x/AYFkAg",
                                "author": [
                                    {
                                        "name": "Heinrich Schuetzel"
                                    },
                                    {
                                        "name": "George Trader"
                                    },
                                    {
                                        "name": "Johann Fluss"
                                    }
                                ],
                                "created": "2020-06-09T15:04:12.944Z",
                                "modified": "2021-06-10T08:53:23.532Z"
                            },
                            {
                                "collection": "ym_concepts",
                                "type": "article",
                                "title": "Search Query Language",
                                "id": "ID_of_query_article",
                                "link": "https://help.optimal-systems.com/yuuvis_develop/display/YMY/x/gIFkAg",
                                "author": [
                                    {
                                        "name": "Andrea Schumann"
                                    },
                                    {
                                        "name": "Franz Lissner"
                                    },
                                    {
                                        "name": "Hans Kammer"
                                    },
                                    {
                                        "name": "Johann Fluss"
                                    }
                                ],
                                "created": "2020-06-16T14:03:01.833Z",
                                "modified": "2021-06-02T09:54:12.643Z"
                            }
                        ]
                    }
                },
                "system:lastModificationDate": {
                    "value": "2021-06-14T13:11:57.770Z"
                },
                "system:versionNumber": {
                    "value": 1
                },
                "system:baseTypeId": {
                    "value": "system:document"
                },
                "system:tenant": {
                    "value": "default"
                },
                "system:createdBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:creationDate": {
                    "value": "2021-06-14T13:11:57.770Z"
                },
                "system:lastModifiedBy": {
                    "value": "275c826c-6a61-4e89-9512-8d935a1631e5"
                },
                "system:objectId": {
                    "value": "3d4a67be-3341-4317-bb57-c48ea7ab0a1a"
                }
            }
        }
    ],
    "numItems": 2,
    "hasMoreItems": false,
    "totalNumItems": 2
}
Example 2

In order to return only the bibliographic information in the result list of the search request, select the appBibjsonsample:bibjson property.

SELECT appBibjsonsample:bibjson FROM appBibjsonsample:medium
Request Body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
{
    "objects": [
        {
            "properties": {
                "appBibjsonsample:bibjson": {
                    "value": {
                        "type": "book",
                        "title": "My Book Title",
                        "author": [
                            {
                                "name": "Heinrich Schuetzel"
                            },
                            {
                                "name": "Maximilian Sturz"
                            }
                        ],
                        "year": "1995",
                        "owner": "My Library",
                        "id": "ID_of_book",
                        "url": "http://mylibrary.com/ebooks/36513466534",
                        "publisher": "Example Verlag Mustershagen",
                        "edition": {
                            "number": 2,
                            "language": "English"
                        },
                        "identifier": [
                            {
                                "id": "0002-9327",
                                "type": "issn"
                            }
                        ]
                    }
                }
            }
        },
        {
            "properties": {
                "appBibjsonsample:bibjson": {
                    "value": {
                        "metadata": {
                            "collection": "ym_concepts",
                            "label": "yuuvis(R) Momentum Core Concepts",
                            "description": "Documentation for yuuvis(R) Momentum Core in a structured, theoretical way, with links to the tutorial section.",
                            "id": "ID_of_collection",
                            "owner": "OS",
                            "created": "2020-06-09T15:04:12.944Z",
                            "modified": "2021-06-10T11:05:17.166Z",
                            "source": "https://help.optimal-systems.com/yuuvis_develop/display/YMY/x/-4BkAg",
                            "records": 2
                        },
                        "records": [
                            {
                                "collection": "ym_concepts",
                                "type": "article",
                                "title": "Schema - Defining Object Types",
                                "id": "ID_of_schema_article",
                                "link": "https://help.optimal-systems.com/yuuvis_develop/display/YMY/x/AYFkAg",
                                "author": [
                                    {
                                        "name": "Heinrich Schuetzel"
                                    },
                                    {
                                        "name": "George Trader"
                                    },
                                    {
                                        "name": "Johann Fluss"
                                    }
                                ],
                                "created": "2020-06-09T15:04:12.944Z",
                                "modified": "2021-06-10T08:53:23.532Z"
                            },
                            {
                                "collection": "ym_concepts",
                                "type": "article",
                                "title": "Search Query Language",
                                "id": "ID_of_query_article",
                                "link": "https://help.optimal-systems.com/yuuvis_develop/display/YMY/x/gIFkAg",
                                "author": [
                                    {
                                        "name": "Andrea Schumann"
                                    },
                                    {
                                        "name": "Franz Lissner"
                                    },
                                    {
                                        "name": "Hans Kammer"
                                    },
                                    {
                                        "name": "Johann Fluss"
                                    }
                                ],
                                "created": "2020-06-16T14:03:01.833Z",
                                "modified": "2021-06-02T09:54:12.643Z"
                            }
                        ]
                    }
                }
            }
        }
    ],
    "numItems": 2,
    "hasMoreItems": false,
    "totalNumItems": 2
}
Example 3

It is even possible to return specified sub-values of the JSON structure stored in the appBibjsonsample:bibjson property. If you specify an index within a list, the values for the list elements with lower indices will be replaced by null in the return statement as can be seen in line 9.

SELECT appBibjsonsample:bibjson.title,appBibjsonsample:bibjson.author[1].name,appBibjsonsample:bibjson.metadata.id FROM appBibjsonsample:medium
Request Body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
    "objects": [
        {
            "properties": {
                "appBibjsonsample:bibjson": {
                    "value": {
                        "title": "My Book Title",
                        "author": [
                            null,
                            {
                                "name": "Maximilian Sturz"
                            }
                        ]
                    }
                }
            }
        },
        {
            "properties": {
                "appBibjsonsample:bibjson": {
                    "value": {
                        "metadata": {
                            "id": "ID_of_collection"
                        }
                    }
                }
            }
        }
    ],
    "numItems": 2,
    "hasMoreItems": false,
    "totalNumItems": 2
}
Example 4

If you know the path of the sub-value within the JSON you want to query, you can directly specify it. The example query configures a search for a specific medium identified by its bibliographic ID.

SELECT appBibjsonsample:bibjson.title FROM appBibjsonsample:medium WHERE appBibjsonsample:bibjson.id = 'ID_of_book'
Request Body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
    "objects": [
        {
            "properties": {
                "appBibjsonsample:bibjson": {
                    "value": {
                        "title": "My Book Title",
                        "author": [
                            null,
                            {
                                "name": "Maximilian Sturz"
                            }
                        ]
                    }
                }
            }
        }
    ],
    "numItems": 1,
    "hasMoreItems": false,
    "totalNumItems": 1
}
Example 5

If you want to search for an object with a specific sub-value but unknown path, a * wildcard can be used. Each object containing the string ID_of_schema_article as a sub-value for the appBibjsonsample:bibjson property will match the query.

SELECT appBibjsonsample:bibjson.metadata.id FROM appBibjsonsample:medium WHERE appBibjsonsample:bibjson.* = 'ID_of_schema_article'
Request Body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
    "objects": [
        {
            "properties": {
                "appBibjsonsample:bibjson": {
                    "value": {
                        "metadata": {
                            "id": "ID_of_collection"
                        }
                    }
                }
            }
        }
    ],
    "numItems": 1,
    "hasMoreItems": false,
    "totalNumItems": 1
}
Example 6

The * wildcard can also be used instead of a specific index within a list. Thus, the condition will be checked for each list entry. Furthermore, full-text search with CONTAINS is possible in case of string sub-values.

SELECT appBibjsonsample:bibjson.title FROM appBibjsonsample:medium WHERE appBibjsonsample:bibjson.author[*].name CONTAINS('Sturz')
Request Body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
    "objects": [
        {
            "properties": {
                "appBibjsonsample:bibjson": {
                    "value": {
                        "title": "My Book Title"
                    }
                }
            }
        }
    ],
    "numItems": 1,
    "hasMoreItems": false,
    "totalNumItems": 1
}
Example 7

Use .. in order to replace unknown parts of a path. The query below specifies a search for objects where the appBibjsonsample:bibjson property contains Schuetzel in the value for the author[*].name key which can be located at any hierarchical level within the JSON. Furthermore, only key-value mappings for keys named id will be displayed in the response body.

SELECT appBibjsonsample:bibjson..id FROM appBibjsonsample:medium WHERE appBibjsonsample:bibjson..author[*].name CONTAINS('Schuetzel')
Request Body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
    "objects": [
        {
            "properties": {
                "appBibjsonsample:bibjson": {
                    "value": {
                        "id": "ID_of_book",
                        "identifier": [
                            {
                                "id": "0002-9327"
                            }
                        ]
                    }
                }
            }
        },
        {
            "properties": {
                "appBibjsonsample:bibjson": {
                    "value": {
                        "metadata": {
                            "id": "ID_of_collection"
                        },
                        "records": [
                            {
                                "id": "ID_of_schema_article"
                            },
                            {
                                "id": "ID_of_query_article"
                            }
                        ]
                    }
                }
            }
        }
    ],
    "numItems": 2,
    "hasMoreItems": false,
    "totalNumItems": 2
}

3.11.6. Summary

The structureddata property type allows for the storage of interleaved data structures in a queryable way without defining each single sub-property in the schema. This tutorial gave some explanations on how to define such a property in the schema, how to set a value during object creation and how to address the individual sub-values in search queries, in the example context of a library.

Code examples in GitHub.

3.12. Overwriting the 'required' Property Attribute

This tutorial shows how to reference the same property definition in different object type definitions, in some of them as a required property and in others as a non-required property.

3.12.1. Introduction

The metadata structure of object types has to be defined in the schema. In this definition, properties are referenced that should be connected to the object type. Each property is in turn defined in the schema by the specification of its attributes. The properties can be referenced or not referenced in object type definitions, but their attributes are fixed and cannot be modified. The required attribute is the only exception as it can be overwritten by a propertyReference in object type definitions. This makes it possible to decide for each property individually whether it is required in every single object type definition or not. Since schema structures can even be changed at runtime, yuuvis® Momentum offers a high flexibility in terms of document lifecycle management.

3.12.2. Requirements

To work through this tutorial, the following is required:

3.12.3. Overwriting the 'required' Attribute of Properties

All property definitions in the schema need the specification of the required attribute. Its boolean value decides if the corresponding property is mandatory (true) or optional (false) for an object. However, the value of the required attribute can be overwritten by a propertyReference in object type definitions.

Property Definition

In an import management system, documents may be imported with less properties than they will have lateron in their lifecycle. A freshly imported object for example does not necessarily have an editor. Later in the document lifecycle, this information may be required. By overwriting the required attribute of the editor property, it is possible to use the same property throughout the entire lifecycle.

In the example code below, the editor property is defined. The required attribute of the editor property is set to true. If not overwritten by a propertyReference, the editor property will be mandatory for any object of a type containing the editor property in its definition.

Property definition
1
2
3
4
5
6
<propertyStringDefinition>
    <id>editor</id>
    <propertyType>string</propertyType>
    <cardinality>single</cardinality>
    <required>true</required>
</propertyStringDefinition>
Overwriting Using a Document Type Definition

In a document type definition, a propertyReference can be used to set a value for the required attribute of a property. This value can be different from the value specified in the property definition. In this case, the value of the required attribute will be specified in the document type definition.

Since the editor property should be optional for an imported1 document, the required attribute is set to false by means of a propertyReference.

Overwriting of the required attribute by document type definition
1
2
3
4
5
6
7
8
9
10
11
12
13
<propertyStringDefinition>
    <id>editor</id>
    <propertyType>string</propertyType>
    <cardinality>single</cardinality>
    <required>true</required>
</propertyStringDefinition>

<typeDocumentDefinition>
    <id>imported1</id>
    <baseId>system:document</baseId>
    <propertyReference required="false">editor</propertyReference>
    <contentStreamAllowed>allowed</contentStreamAllowed>
</typeDocumentDefinition>

Overwriting Using a Secondary Object Type Definition An alternative option to reference a property in an object type definition is to include a floating secondary object type. In the secondary object type definition, a propertyReference can be used to set a value for the required attribute for a property. The required attribute value specified in the original property definition is again overwritten.

In the example code below, the editor property is not included directly in the imported2 document type definition. But it is based on the non-static (floating) secondary object type noeditor. The definition of noeditor uses the editor property and sets its required attribute to false by means of a propertyReference. Thus, for documents of the type imported2, the editor property will be available and optional.

Overwriting of the required attribute by secondary object type definition
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<propertyStringDefinition>
    <id>editor</id>
    <propertyType>string</propertyType>
    <cardinality>single</cardinality>
    <required>true</required>
</propertyStringDefinition>

<typeDocumentDefinition>
    <id>imported2</id>
    <baseId>system:document</baseId>
    <contentStreamAllowed>allowed</contentStreamAllowed>
    <secondaryObjectTypeId static="false">noeditor</secondaryObjectTypeId>
</typeDocumentDefinition>

<typeSecondaryDefinition>
    <id>noeditor</id>
    <baseId>system:secondary</baseId>
    <propertyReference required="false">editor</propertyReference>
</typeSecondaryDefinition>
Handling Multiple Property References

In a document type definition, it is possible to set a value for the required attribute of a property, and additionally include multiple secondary object types specifying the required attribute for the same property as well. If at least one definition implies required=true, this attribute will be true for every document of the corresponding type. The value true dominates over false regardless of the location of the propertyReference.

In the example code below, a document type imported3 is defined. The editor property is included, but the required attribute is overwritten to false which makes the editor property optional. However, the two secondary object types noeditor and witheditor may have different values specified for the required attribute of the editor property.

Document type definition and secondary object type definitions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<propertyStringDefinition>
    <id>editor</id>
    <propertyType>string</propertyType>
    <cardinality>single</cardinality>
    <required>true</required>
</propertyStringDefinition>

<typeDocumentDefinition>
    <id>imported3</id>
    <baseId>system:document</baseId>
    <propertyReference required="false">editor</propertyReference>
    <contentStreamAllowed>allowed</contentStreamAllowed>
    <secondaryObjectTypeId static="false">noeditor</secondaryObjectTypeId>
    <secondaryObjectTypeId static="false">witheditor</secondaryObjectTypeId>
</typeDocumentDefinition>

<typeSecondaryDefinition>
    <id>noeditor</id>
    <baseId>system:secondary</baseId>
    <propertyReference required="false">editor</propertyReference>
</typeSecondaryDefinition>

<typeSecondaryDefinition>
    <id>witheditor</id>
    <baseId>system:secondary</baseId>
    <propertyReference>editor</propertyReference>
</typeSecondaryDefinition>

The definition of the secondary object type noeditor overwrites the required attribute of the editor property to false. This value equals the specification in the imported3 document type definition. In contrast, the definition of witheditor includes the editor property by means of a propertyReference but does not explicitly specify a value for the required attribute. This means that the value true from the property definition will be used for witheditor.

  • If a document of type imported3 has none of the two secondary object types, the editor property is optional.

  • If a document of type imported3 has the secondary object type noeditor, nothing changes. The editor property is still optional.

  • But if a document of type imported3 has the secondary object type witheditor, the property editor is mandatory in this object.

3.12.4. Summary

This tutorial gave an introduction into the possibilities provided by the option of overwriting the required attribute of properties. Since this topic plays a role in the handling of the schema, also the following pages might be interesting to you.

3.13. Preprocessing Metadata using Webhooks

An example Webhook consumer service set up using Java and Spring Boot.

3.13.1. Requirements

In this tutorial, we’ll create a Spring Boot Service using Java, meaning the requirements for the project are derived from Spring Boot. Thus, a JDK version 1.8 or later and Maven 3.2 or later are required.

3.13.2. Setting up the Consumer Service

To implement processing of incoming update metadata using our webhook service, we need to configure an endpoint within a controller class of our Example Webhook Service, in this instance ExampleRestController. The URL we define between the RequestMapping annotation of the controller class and the PostMapping annotation of the endpoint method will need to find its way into the system hook configuration of our yuuvis® Momentum system. We will also define a stub method for working with the incoming metadata, which we will call from within our endpoint method, the object map provided by the system hook.

Controller Class with Endpoint for Webhook Consumption
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RestController
@RequestMapping("/api/dms/request")
public class ExampleRestController
{
    @PostMapping(value = "/update/metadata", produces = {"application/json"})
    public Map<String, Object> updateDmsObjectMetadata(@RequestBody Map<String, Object> dmsApiObjectList,
                                                       @RequestHeader(value = "Authorization", required = true) String authorization)
    {
        doSomething(dmsApiObjectList, authorization);
        return dmsApiObjectList;
    }
    private void doSomething(Map<String, Object> dmsApiObjectList, String authorization)
    {
        // do something with the metadata
    }
}

3.13.3. Configuring the Webhook

To use the webhook service for the intended purpose of intercepting metadata when updating objects, we need to create a new entry in the Webhook list within our systems' systemHookConfiguration.json file (`\system\systemHookConfiguration.json). The url attribute must refer to the webhook service identifier (derived from the artifact ID in the services' maven file) and direct to one of the endpoints declared in the service.

The services responsible for the webhook execution need to be restarted after changing the systemHookConfiguration.json file. The corresponding services of each webhook are listed here. For the enrichment of metadata, the pertaining service would be the API-gateway.

Example SystemHookConfiguration.json
1
2
3
4
5
6
7
8
9
10
11
12
13
{
  "systemhooks": {
    "webhooks": [
      {
        "enable": true,
        "predicate": "spel:true",
        "type": "dms.request.update.metadata",
        "url": "<protocol>://<webhook service identifier>/api/dms/request/update/metadata",
        "useDiscovery": true
      }
    ]
  }
}

3.13.4. Summary

In this tutorial, a Java-based method for webhook consumption is outlined. The code presented, including the project structure and additional webhook management, can be found in github. More concrete example webhook use cases are described in the articles linked below.

3.14. Accessing Binary Content during an Import

Access binary content files via webhooks during the import process.

3.14.1. Introduction

If an object is imported to yuuvis® Momentum, a binary content file can be assigned in addition to the object’s metadata. The storage of the binary content file is managed by the repository service. Afterwards, the metadata are stored in a separate database and are indexed for search.

As soon as the object import process is finished, the binary content file can be accessed. Especially, it can be analysed in order to set some content-related metadata properties for the corresponding object. The metadata update is possible, i.e., via POST or PATCH /api/dms/objects/{objectId} and triggers the creation of a new object version. However, in some use cases, it might be necessary to set metadata properties depending on an analysis of the corresponding binary content file already for the first version of the imported object. For this purpose, the binary content file can be accessed from a webhook that is called after storing the content and before storing the metadata. This tutorial describes an example solution using an internal endpoint of the repository service.

3.14.2. Setting up the Webhook Service

The webhook entry point has to be located after storing the binary content file and before storing the metadata in the process chain of an object import. For this purpose, the type dms.request.objects.upsert.database-before is suitable.

The Preprocessing Metadata using Webhooks tutorial provides a general example on how to configure and set up your own webhook service. A more specific example controller class for a webhook service for our concrete use case is provided in the code block below. For each object imported with a binary content file, the MD5 digest of the corresponding content is calculated. Since an internal endpoint of the repository service has to be called, the webhook service must run within the yuuvis® Momentum Kubernetes cluster.

As defined in lines 2 and 5, the webhook service will be available via the URL /api/process/checkcontent. This endpoint accepts the import request body containing all of the objects' metadata, and the request headers (line 6).

Especially in the case of a batch import, it is necessary to iterate over the individual objects (line 13) as the repository can only retrieve the content of one object at a time. For each individual object, the existence of an assigned binary content file is checked (lines 17 and 19). The binary content file is retrieved from the repository (starting in line 28) and its MD5 digest is calculated (line 47). The value is printed to the console (line 55).

Depending on the MD5 digest value, it would be possible to manipulate the individual object’s metadata. However, in this example, the metadata remain unchanged. The objects from the request body are returned without any manipulation (line 66).

Calculate MD5-Digest of binary content before import
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
@RestController
@RequestMapping("/api")
public class WebhookRestController
{
    @PostMapping(value = "/process/checkcontent", produces = "application/json;charset=UTF-8", consumes = "application/json")
    public ResponseEntity<?> checkContent(@RequestBody final Map<String, Object> dmsApiObList, @RequestHeader HttpHeaders incomingHeaders) throws Exception
    {
        try
        {
            String authorization = incomingHeaders.getFirst(HttpHeaders.AUTHORIZATION);
            List<Map<String, Object>> apiObjectList = (List<Map<String, Object>>)dmsApiObList.get("objects");

            for (Map<String, Object> apiObject : apiObjectList)
            {
                String objectId = (String)getMap(getMap(apiObject, "properties"), "system:objectId").get("value");

                boolean hasContent = apiObject.get("contentStreams") != null && ((List)apiObject.get("contentStreams")).size() > 0;

                if (hasContent)
                {
                    Map<String, Object> requestObject = new LinkedHashMap<>();
                    LinkedList<Map<String, Object>> requestList = new LinkedList<>();
                    requestList.add(apiObject);
                    requestObject.put("objects", requestList);

                    // @formatter:off
                    String md5Digest =
                        restTemplate.execute(
                            "http://repository/api/dms/objects/" + objectId,
                            HttpMethod.POST,
                            (ClientHttpRequest requestCallback) -> {
                              if (StringUtils.hasLength(authorization))
                              {
                                requestCallback.getHeaders().add(HttpHeaders.AUTHORIZATION, authorization);
                              }
                              requestCallback.getHeaders().setContentType(MediaType.APPLICATION_JSON);
                              requestCallback.getBody().write(this.objectMapper.writeValueAsString(requestObject).getBytes("UTF-8"));
                            },
                            new ResponseExtractor<String>()
                            {
                                @Override
                                public String extractData(ClientHttpResponse response) throws IOException
                                {
                                    if (response.getStatusCode().is2xxSuccessful())
                                    {
                                        // calculate MD5 Hash
                                        return DigestUtils.md5DigestAsHex(response.getBody());
                                    }
                                    throw new IllegalStateException("error in getting content: " + response.getRawStatusCode() + " " + response.getStatusText());
                                }
                            }
                        );
                    // @formatter:on

                    System.out.println("for objectId[" + objectId + "] the md5-digest of content is[" + md5Digest + "]");
                }
            }
        }
        catch (Throwable e)
        {

            return new ResponseEntity<>(e.getMessage(), HttpStatus.UNPROCESSABLE_ENTITY);
        }

        // just return input no changes
        return new ResponseEntity<Map<String, Object>>(dmsApiObList, HttpStatus.OK);
    }
}

3.15. Handling PDF Compound Documents via Interceptors

Learn how to set up a Microservice that can fill the role of an interceptor of any of the available interceptor types. Java code examples of such microservices can also be found here.

3.15.1. Basic Microservice Setup

In this tutorial, we will implement a Spring Boot microservice for the interceptors' obligations that can easily be integrated into the yuuvis® Momentum infrastructure (kubernetes). Learn more about Spring Boot Applications in their official documentation. To integrate with kubernetes, some additional application files need to be implemented in the microservice.

One nice thing about microservices is that you can use any programming language you like—as long as it supports REST which ensures communication with the other services.
Necessary Microservice Application Files

In this tutorials' code project, we implement some of our suggestions for the architecture of yuuvis® Momentum-integrated microservice. The following classes provide no logic specific to interceptors, but are still essential for the microservice to operate.

3.15.2. Functional Implementation of each Interceptor Type

In the following sections, an arbitrary practical example for each of the three interceptor types is provided for demonstrational purposes. At the end of the article, you will find a link to the Git Repository that houses the complete code project for your inspiration.

Type 'getContent'

Imagine the following situation: A large PDF file consisting of several sub-documents is stored in the system. When one specific document is requested, the respective pages should be extracted and returned as a separate PDF file. A good way to achieve this is using an interceptor, i.e., a service that runs in the background listening for its cue. When it occurs, the interceptor is called by the yuuvis® API system and performs its specific task, thereby rerouting the standard flow of the application.

Creating the 'getContent' REST Controller

Finally, we will need to create a REST endpoint to the service. A REST controller class will handle HTTP requests, producing the REST endpoint.

A traditional MVC controller and a RESTful web service controller in Spring differ significantly regarding the creation of the HTTP response body: In the traditional Model View Controller (MVC) paradigm, the controller would use a view technology in order to render an HTML version of the data and return a view object to be displayed. In Spring, however, the controller creates and returns a new instance of the resource representation class instead which will be written to the HTTP response as JSON.

Create the class PdfPageSelectorRestController and annotate it as @RestController. This will turn the class into a REST controller whose methods return domain objects instead of views (short for @Controller and @ResponseBody).

Rest Controller for the PDF Page Selector getContent Interceptor
@RestController
@RequestMapping("/api")
public class PdfPageSelectorRestController
{
    @Autowired
    private PdfPageSelectorService pdfPageSelectorService;

    @PostMapping(value = "/dms/objects/{objectId}", headers =   "content-type=application/json")
    public void getContentByPostRequest(@RequestBody Map<String, Object> dmsApiObjectList, @PathVariable("objectId") String objectId,
                                        @RequestHeader(value = "Authorization", required =false) String authorization,
                                        HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException
    {
        servletResponse.setContentType(MediaType.APPLICATION_PDF_VALUE);
        pdfPageSelectorService.extract(servletResponse.getOutputStream(), dmsApiObjectList, objectId, authorization);
    }
}

The controller sets the media type of response to PDF and calls the extract method of the PDFPageSelectorService.

Modelling a Sub-Document

As a document is identified by its start and end page, the domain object simply represents these two page numbers.

Pages.java Class Describing a Sub-Document of a PDF Document

public class Pages

{

    private int startPage;
    private int endPage;

    public Pages(int startPage, int endPage)
    {
        this.startPage = startPage;
        this.endPage = endPage;
    }
    //omitted getter/setter methods
}
Creating the Page Extractor

This is the core of the service. Create the class PdfPageSelectorService and annotate it as @Service. This indicates that it holds the business logic and will communicate with the repository layer.

The extract method first gets the page boundaries, i.e., start and end page numbers, from the input by simply removing the page: prefix and splitting the string at the - character:

Creating Sub-Document Instances from Compatible Documents
if (range.startsWith("page:"))
{
    ((Map<String, Object>)contentSreamObject.get(0)).remove("range");
    String[] bounds = range.substring("page:".length()).split("-");
    int startPage = Integer.parseInt(bounds[0]);
    int endPage = Integer.parseInt(bounds[1]);

    return new Pages(startPage, endPage);
}

Next, it calls the repository via the REST template and sends a POST request with all object data.

Retrieving the Document from the yuuvis® Repository
restTemplate.execute(repositoryUrl + "/" + objectId, HttpMethod.POST, (ClientHttpRequest requestCallback) ->
  {
    if (StringUtils.hasLength(authorization))
    {
        // delegate auth header
        requestCallback.getHeaders().add(HttpHeaders.AUTHORIZATION, authorization);
    }
    requestCallback.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_PDF));
    requestCallback.getHeaders().setContentType(MediaType.APPLICATION_JSON);
    requestCallback.getBody().write(this.objectMapper.writeValueAsString(requestObjects).getBytes("UTF-8"));
  },
new StreamResponseExtractor(outputStream, pages.getStartPage(), pages.getEndPage()));
Extracting Content from a PDF

The StreamResponseExtractor then extracts the pages of the sub-document from the streamed PDF (using PDFBox) and writes them to a new PDF file. The PDFBox functionality is wrapped in the PdfTools helper class.

The advantage of streaming is that large files do not need to be copied first but can be handled on the fly. This is not required though: You could just as well get the file from the repository first and store it locally before processing.

Creating the Sub-Document Using PdfTools
public static void extractPageFromStream(InputStream inputStream, int startPage, int endPage, OutputStream outputStream)
    {
        try
        {
            Splitter splitter = new Splitter();
            splitter.setStartPage(startPage);
            splitter.setEndPage(endPage);
            splitter.setSplitAtPage(endPage - startPage + 1);

            try (PDDocument document = PDDocument.load(inputStream))
            {
                List<PDDocument> documents = splitter.split(document);

                if (documents.size() != 1)
                {
                    throw new IllegalArgumentException("cannot split document, wrong number of split parts");
                }
                try (PDDocument doc = documents.get(0))
                {
                    PdfTools.writeDocument(doc, outputStream);
                }
            }
        }
        catch (Exception e)
        {
            LOGGER.info(ExceptionUtils.getMessage(e));
            throw new IllegalArgumentException(ExceptionUtils.getMessage(e));
        }
    }

    private static void writeDocument(PDDocument doc, OutputStream outputStream) throws IOException
    {
        try (COSWriter writer = new COSWriter(outputStream))
        {
            writer.write(doc);
        }
    }
Interceptor 'getContent' Configuration

Create the interceptorConfiguration.json file, add the following configuration (either JavaScript or SpEL) and save it to the configuration server, either by updating the git repository with the new state, or, in systems running the 'native' profile on the config service, simply changing the configuration file in the file-system of the config service itself.

You only need one configuration—whether you prefer JavaScript or SpEL is up to you.

When configuring a getContent interceptor, we can infer the objects' metadata from the predicate.

Condition in JS
{
  "interceptors" : [
    {
      "type" : "getContent",
      "predicate" : "js:function process(dmsApiObject){return dmsApiObject[\"contentStreams\"][0][\"range\"]!=null && dmsApiObject[\"contentStreams\"][0][\"range\"].startsWith(\"page:\")}",
      "url" : "http://examplewebhook/api/dms/objects/{system:objectId}",
      "useDiscovery" : false
    }
  ]
}
Condition in SpEL
{
  "interceptors" : [
    {
      "type" : "getContent",
      "predicate" : "spel:contentStreams[0]['range'] != null ? contentStreams[0]['range'] matches '(?i)^page:.*' : false",
      "url" : "http://examplewebhook/api/dms/objects/{system:objectId}",
      "useDiscovery" : false
    }
  ]
}

Finally, restart the API Service to apply the new configuration to the system.

Whenever we need to handle documents containing critical information during their development within a content management system, we need to ensure that the accessibility of such documents is restricted for all users without a specific authorization for those documents. To implement such a mechanism in our yuuvis® system, we can make use of the search interceptor type together with a system tag that will need to be set on all documents.

Creating the search REST Controller

The REST controller offering the endpoint for the interceptor mechanism follows in the footsteps of the PdfPageSelectorRestController, barring the absence of the objectId in the URL and the changed response content type.

Search Interceptor Rest Controller Class
@RestController
@RequestMapping("/api")
public class QueryByTagFilterRestController {
@Autowired
private QueryFilterService queryFilterService;

    @PostMapping(value = "/dms/objects/search", headers = "content-type=application/json")
    public void searchByPostedQuery(@RequestBody Map<String, Object> incomingQuery,
                                    @RequestHeader(value = "Authorization", required = false) String auth,
                                    HttpServletRequest servletRequest,
                                    HttpServletResponse servletResponse) throws IOException {
        servletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
        queryFilterService.filterQueryByTag(servletResponse.getOutputStream(), incomingQuery, auth);
    }
}
Enriching an Incoming Query Object
Enriching an Incoming Query
public Map<String, Object> enrichQueryByTagFilter(Map<String, Object> incomingQuery){
        Map<String, Object> queryMap = (Map<String, Object>)incomingQuery.get("query");
        String statement = String.valueOf(queryMap.get("statement"));
        String filteredStatement = "";
        if (statement.contains("WHERE")){
            filteredStatement = statement + " AND system:tags[\"test\"].state > 1";
        } else {
            filteredStatement = statement + " WHERE system:tags[\"test\"].state > 1";
        }
        queryMap.replace("statement", filteredStatement);
        incomingQuery.replace("query", queryMap);

        return incomingQuery;
    }

Essentially, we will enrich each incoming query from less authorized users on the search service using the interceptor, adding a filtering statement excluding documents where the state of our test tag does not indicate the information can be released systemwide. This means the documents we would want to exclude from the users' visibility need to have the test tag with a state value lower than 3. Increasing the state beyond this number will result in the filter to no longer apply, thereby making the document public to all users affected by the interceptor predicate. Please be aware that this Interceptor configuration may break more complex queries, such as those ordering results at the end of the statement, due to out of place WHERE clauses.

Interceptor 'search' Configuration

Search interceptors receive a JSON denoting the querying users' authorization details, including the granted permissions/roles of the user.

SpEL search Interceptor Configuration
{
      "type" : "search",
      "predicate" : "spel:!grantedAuthorities.contains('SOME_NEEDED_ROLE')",
      "url" : "http://exampleinterceptor/api/dms/objects/search",
      "useDiscovery" : true
}
Type 'updateDmsObject'

The last of the available interceptor types enters the stage whenever anyone tries to update an object matching the predicate declared in the interceptor configuration. The Interceptor can modify the incoming update metadata, while also having access to the current version of the object’s metadata.

Creating the 'updateDmsObject' REST Controller

Again, the Rest Controller class will not diverge much from the previous two interceptor types, keeping the object ID path variable of the getContent type and the JSON Request Content Type parameter of the search interceptor type.

updateDmsObject REST Controller Class
@RestController
@RequestMapping("/api")
public class UpdateEnricherRestController {
@Autowired
private UpdateEnricherService updateEnricherService;

    @PostMapping(value = "/dms/objects/{objectId}/update", headers = "content-type=application/json")
    public void enrichedUpdate(@RequestBody Map<String, Object> dmsApiObjectList,
                               @PathVariable("objectId") String objectId,
                               @RequestHeader(value = "Authorization", required = false) String auth,
                               HttpServletRequest servletRequest,
                               HttpServletResponse servletResponse) throws IOException {
        servletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
        updateEnricherService.enrichMetadata(servletResponse.getOutputStream(), dmsApiObjectList, objectId, auth);
    }
}
Manipulating Incoming Metadata

We can use our interceptor, for instance, to increment a property tracking the amount of edits of a certain property commited on an object. We can modify the incoming update metadata within the interceptor service to implement this logic in a very flexible manner, allowing for complex interactions with tertiary systems for the metadata enrichment.

Method for Enriching Incoming Update Metadata
public Map<String, Object> enrichMetadataTag(Map<String, Object> incomingMetadata){
        List<Map<String, Object>> list = (List<Map<String, Object>>)incomingMetadata.get("objects");
        Map<String, Object> dmsApiObject = list.get(0);
        Map<String, Object> propertyMap = (Map<String, Object>)dmsApiObject.get("properties");
        Map<String, Object> testStringMap = (Map<String, Object>)propertyMap.get("appInterceptor:testString1");
        String oldValue = testStringMap.get("value").toString();
        testStringMap.replace("value", (oldValue+ " (enriched value)"));
        return incomingMetadata;
    }

In this demonstration, we opt to enrich a metadata property value present in the body of the update request. We assume that the update already tries to modify the value. That way we can obtain the proposed new value for the property from the propertyMap within the incomingMetadata object. If we wanted to modify this value even if it was not present in the update body, we simply need to inject the property into the same property map, as it will be treated as overwriting metadata when forwarding the enriched metadata to the repository service in the next step.

Interceptor 'updateDmsObject' Configuration

Similarly to the getContent interceptor type, the updateDmsObject interceptor predicates are based on the current version of the objects' metadata. We use the predicate to verify the document that is meant to be updated is of the specific object type handled by our interceptor.

SpEL 'updateDmsObject' Interceptor Configuration
{
      "type" : "updateDmsObject",
      "predicate" : spel:contentStreams != null && contentStreams.size() > 0 && properties['system:objectTypeId'] == "appInterceptor:exampleDoc",
      "url" : "http://exampleinterceptor/api/dms/objects/{system:objectId}/update",
      "useDiscovery" : true
}

3.15.3. Summary

Your service is complete! Find the complete code project described in this tutorial in this GitHub Repository.

4. Client Development

The following services, APIs and libraries can be installed in addition to the core system. They allow to quickly build your own client application. An example client as reference implementation is available as well.

4.1. Web API

The Web API gateway is a collection of endpoints provided by the api-web service. It provides:

  • The core system’s DMS functionality in a different format

  • client-specific resources management (forms, localization, icons, catalogs, …​)

  • Integration possibilities for Business Process Management via bpm-engine service

  • User information retrieval from a specific database via userservice

  • User information retrieval from the used identity provider via tenant-management service

4.1.1. Endpoints

admin-controller
GET /api-web/api/admin/dms/catalogs - Retrieve the names of all catalogs available within the tenant.
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Retrieves the technical names of all catalogs grouped in lists depending on their global, app-specific or tenant-specific storage location.

Tenant-specific catalogs are retrieved only for the active tenant.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

500

Internal Server Error

Request Example

https://<host>/api-web/api/admin/dms/catalogs

no request body

Response Example

200 OK

Response Body
{
  "personalfile": [
    "appPersonalfile:class"
  ],
  "global": [
    "germancountry",
    "contracts",
    "germancountries",
    "globalnotice",
    "currency",
    "class",
    "clubs",
    "food",
  ],
  "invoice": [
    "appInvoice:type"
  ],
  "mytenant": [
    "germancountry",
    "contracts",
    "tenMytenant:My catalog",
    "germancountries",
    "globalnotice",
    "currency",
    "class",
    "appInvoice:type",
    "tenMytenant:processstatus",
    "appPersonalfile:class"
  ]
}
GET /api-web/api/admin/dms/catalogs/{qname} - Retrieve a specified catalog.
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Retrieves the catalog specified by its technical name of either global/app-specific or tenant-specific origin.

Behind the technical name, add the query parameter global=false (global=true) for a tenant-specific (app-specific or global) catalog. The endpoint returns null if no catalog with qname is available in the tenant-specific (app-specific or global) resource.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

401

Unauthorized

404

Not Found

Request Example

https://<host>/api-web/api/admin/dms/catalogs/appInvoice:type?global=true

no request body

Response Example

200 OK

Response Body
{
  "tenant": "mytenant",
  "readonly": false,
  "entries": [
    {
      "name": "Employment contract",
      "disabled": false
    },
    {
      "name": "Rental agreement",
      "disabled": false
    },
    {
      "name": "User contract",
      "disabled": false
    },
    {
      "name": "Purchase contract",
      "disabled": true
    }
  ]
}
POST /api-web/api/admin/dms/catalogs/{qname} - Create or replace a specified catalog.
As of Version

2021 Summer

Request Method

POST

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Updates the catalog specified by its technical name within the tenant-specific resources.

The new catalog data are passed in the JSON request body.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

Request Example

https://<host>/api-web/api/admin/dms/catalogs/tenMytenant:processstatus

Request Body
{
  "tenant": "mytenant",
  "readonly": false,
  "entries": [
    {
      "name": "Employment contract",
      "disabled": false
    },
    {
      "name": "Rental agreement",
      "disabled": false
    },
    {
      "name": "User contract",
      "disabled": false
    },
    {
      "name": "Purchase contract",
      "disabled": true
    }
  ]
}
Response Example

200 OK

Response Body
{
  "errors": [],
  "valid": true
}
PATCH /api-web/api/admin/dms/catalogs/{qname} - Update a specified catalog.
As of Version

2021 Summer

Request Method

PATCH

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Updates the existing tenant-specific catalog identified by its name qname, with the data passed in JSON format in the request body.

In the response body, the modified catalog will be returned.

If no tenant-specific catalog with name qname is available, an error will be thrown.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

403

Forbidden

404

Not Found

500

Internal Server Error

Request Example

https://<host>/api-web/api/admin/dms/catalogs/tenMytenant:contracts

Request Body
[
  {
    "op": "replace",
    "path": "/entries/1/name",
    "value": "Rental agreement"
  },
  {
    "op": "remove",
    "path": "/entries/3"
  },
  {
    "op": "add",
    "path": "/entries/-",
    "value": {
      "name": "Purchase contract",
      "disabled": true
    }
  }
]
Response Example

200 OK

Response Body
{
  "tenant": "mytenant",
  "readonly": false,
  "entries": [
    {
      "name": "Employment contract",
      "disabled": false
    },
    {
      "name": "Rental agreement",
      "disabled": false
    },
    {
      "name": "User contract",
      "disabled": false
    },
    {
      "name": "Purchase contract",
      "disabled": true
    }
  ]
}
deprecated as of 2023 Winter: GET /api-web/api/admin/dms/forms/{objecttype} - Retrieve a non-enriched metadata form for a specified object type.
Deprecated as of 2023 Winter. Please use GET /api-web/api/resources/forms/{type}.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the non-enriched form by object type ID objecttype and optional query parameters situation and sots (secondary object types) for the active tenant.

Behind the object type ID, add the query parameter situation=CREATE (situation=EDIT) to retrieve the CREATE (EDIT) form. Default is EDIT. Furthermore, add sots=<objectTypeId> in order to specify a secondary object type of which properties should be included in the retrieved form. The sots query parameter can be added multiple times for different secondary object types.

Returns null if there is no designed form model for the given object type.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/api-web/api/admin/dms/forms/tenMytenant:qadocscripts?situation=EDIT&sots=examplesot1&sot=examplesot2

no request body

Response Example

200 OK

Response Body
{
  "name": "tenMytenant:qadocscripts",
  "situation": "EDIT",
  "script": "any valid script",
  "elements": [
    {
      "name": "core",
      "type": "o2mGroup",
      "layout": {
        "align": "column"
      },
      "elements": [
        {
          "name": "appClient:clienttitle",
          "type": "string",
          "rows": 1
        },
        {
          "name": "appClient:clientdescription",
          "type": "string",
          "rows": 1
        }
      ]
    },
    {
      "name": "data",
      "type": "o2mGroupStack",
      "elements": [
        {
          "type": "o2mGroup",
          "layout": {
            "align": "column"
          },
          "elements": [
            {
              "type": "o2mGroup",
              "layout": {
                "align": "row"
              },
              "elements": [
                {
                  "type": "o2mGroup",
                  "layout": {
                    "align": "row"
                  },
                  "elements": [
                    {
                      "name": "tenMytenant:strsingle",
                      "type": "string",
                      "rows": 1
                    },
                    {
                      "name": "tenMytenant:strsinglemail",
                      "type": "string",
                      "rows": 1
                    }
                  ]
                },
                {
                  "type": "o2mGroup",
                  "layout": {
                    "align": "row"
                  },
                  "elements": [
                    {
                      "name": "tenMytenant:intsingle",
                      "type": "integer"
                    },
                    {
                      "name": "tenMytenant:intsingledigit",
                      "type": "integer"
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
deprecated as of 2023 Winter: POST /api-web/api/admin/dms/forms/{objecttype} - Create or update a non-enriched metadata form for a specified object type.
Deprecated as of 2023 Winter. Please use POST /api-web/api/resources/forms/{type}.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Retrieves the non-enriched form by object type ID objecttype and optional query parameters situation and sots (secondary object types) for the active tenant.

Behind the object type ID, add the query parameter situation=CREATE (situation=EDIT) to retrieve the CREATE (EDIT) form. Default is EDIT. Furthermore, add sots=<objectTypeId> in order to specify a secondary object type of which properties should be included in the retrieved form. The sots query parameter can be added multiple times for different secondary object types.

Returns null if there is no designed form model for the given object type.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/api-web/api/admin/dms/forms/tenMytenant:qadocscripts?situation=EDIT&sots=examplesot1&sot=examplesot2

no request body

Response Example

200 OK

Response Body
{
  "name": "tenMytenant:qadocscripts",
  "situation": "EDIT",
  "script": "any valid script",
  "elements": [
    {
      "name": "core",
      "type": "o2mGroup",
      "layout": {
        "align": "column"
      },
      "elements": [
        {
          "name": "appClient:clienttitle",
          "type": "string",
          "rows": 1
        },
        {
          "name": "appClient:clientdescription",
          "type": "string",
          "rows": 1
        }
      ]
    },
    {
      "name": "data",
      "type": "o2mGroupStack",
      "elements": [
        {
          "type": "o2mGroup",
          "layout": {
            "align": "column"
          },
          "elements": [
            {
              "type": "o2mGroup",
              "layout": {
                "align": "row"
              },
              "elements": [
                {
                  "type": "o2mGroup",
                  "layout": {
                    "align": "row"
                  },
                  "elements": [
                    {
                      "name": "tenMytenant:strsingle",
                      "type": "string",
                      "rows": 1
                    },
                    {
                      "name": "tenMytenant:strsinglemail",
                      "type": "string",
                      "rows": 1
                    }
                  ]
                },
                {
                  "type": "o2mGroup",
                  "layout": {
                    "align": "row"
                  },
                  "elements": [
                    {
                      "name": "tenMytenant:intsingle",
                      "type": "integer"
                    },
                    {
                      "name": "tenMytenant:intsingledigit",
                      "type": "integer"
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
deprecated as of 2023 Winter: GET /api-web/api/admin/resources/config/{name} - Retrieve a specified tenant-specific configuration file.
Deprecated as of 2023 Winter. Please use GET /api-web/api/resources/config/{name}.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Retrieves the tenant-specific configuration file specified by name.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

deprecated as of 2023 Winter: POST /api-web/api/admin/resources/config/{name} - Create or update a specified tenant-specific configuration file.
Deprecated as of 2023 Winter. Please use POST /api-web/api/resources/config/{name}.
As of Version

2020 Autumn

Request Method

POST

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Creates or updates the tenant-specific configuration file specified by name with the data passed in JSON format in the request body.

Response HTTP status codes:

HTTP status code Meaning

201

CREATED

401

Unauthorized

deprecated as of 2023 Winter: GET /api-web/api/admin/icons/{path} - Retrieve a specified tenant-specific icon.
Deprecated as of 2023 Winter. Please use GET /api-web/api/resources/icons/{path}.
As of Version

2020 Winter

Request Method

GET

Response Format

SVG

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Retrieves a tenant-specific icon resource specified by path as SVG image.

Such icon endpoints are also available in the resource-controller and system-controller. They are intended to serve for the configuration of object type icons. Use the technical name of the corresponding object type as value for path.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

deprecated as of 2023 Winter: POST /api-web/api/admin/icons/{path} - Create or update a specified tenant-specific icon.
Deprecated as of 2023 Winter. Please use POST /api-web/api/resources/icons/{type}.
As of Version

2020 Winter

Request Method

POST

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Creates or updates the tenant-specific icon specified by path with the data passed as SVG image in a multipart request body.

Such icon endpoints are also available in the resource-controller and system-controller. They are intended to serve for the configuration of object type icons. Use the technical name of the corresponding object type as value for path, e.g. tenMytenant:invoice or appMyapp:contract.

Response HTTP status codes:

HTTP status code Meaning

201

CREATED

400

No icon was specified.

401

Unauthorized

deprecated as of 2023 Winter: GET /api-web/api/admin/resources/text - Retrieve the tenant-specific localized text resources for a specified locale.
Deprecated as of 2023 Winter. Please use GET /api-web/api/resources/text.
As of Version

2020 Winter

Request Method

GET

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Retrieves tenant-specific localized text resources for the Accept-Language specified in the request header formatted in ISO norm (e.g., de, en, es, fr, …​)

The response body is a JSON structure where each technical term as a key is mapped to a string value that will occur as a localized term in the graphical user interface.

Each technical term consists of a field identification (e.g., twosteptest_proc:test_table) followed by either _label or _description in order to be displayed as field label or field description in the graphical user interface.

If a technical term is mapped to null, localization has not yet been applied. The field identification will be displayed as field label in the graphical user interface. A description will not be provided.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/api-web/api/admin/resources/text

no request body

Response Example

200 OK

Response Body
{
  "tenExample:betreff_label": "Subject",
  "tenExample:betreff_description": null,
  "tenExample:strsingle_label": "String",
  "tenExample:strsingle_description": "unlimited",
  "tenExample:strregextime_label": "Time",
  "tenExample:strregextime_description": "Time format is 24 hours with hh:mm",
  "tenExample:strcataloggermancountries_label": "German countries",
  "tenExample:strcataloggermancountries_description": "single-field",
  "tenExample:strcataloggermancountriesro_label": "German countries",
  "tenExample:strcataloggermancountriesro_description": "single-field, read-only",
  "tenExample:intsingle_label": "Integer",
  "tenExample:intsingle_description": "unlimited",
  "tenExample:intsingledigit_label": "Integer",
  "tenExample:intsingledigit_description": "digit grouping",
  "tenExample:decsingle_label": "Decimal",
  "tenExample:decsingle_description": "unlimited",
  "tenExample:decsingledigit_label": "Decimal",
  "tenExample:decsingledigit_description": "digit grouping",
  "tenExample:datetimesingle_label": "Date & time",
  "tenExample:datetimesingle_description": "unlimited",
  "tenExample:datetimesinglerequired_label": "Date & time",
  "tenExample:datetimesinglerequired_description": "mandatory",
  "tenExample:datesingle_label": "Date2",
  "tenExample:datesingle_description": "unlimited",
  "tenExample:datesinglerequired_label": "Date1",
  "tenExample:datesinglerequired_description": "mandatory",
  "tenExample:booleanrequiredtrue_label": "Boolean",
  "tenExample:booleanrequiredtrue_description": "mandatory",
  "tenExample:booleannull_label": "Boolean Tri-State",
  "tenExample:booleannull_description": "Null allowed",
  "tenExample:extract2_label": "Extract & map",
  "tenExample:tablesimplefields_label": "Simple fields",
  "tenExample:tablesimplefields_description": "Table with simple fields",
  "tenExample:tableclassifications_label": "Fields with classifications",
  "tenExample:tableclassifications_description": "Table with classification fields",
  "tenExample:strorganizationsingle_label": "User/Group",
  "tenExample:strorganizationmulti_label": "Users/Groups",
  "tenExample:strcatalogfruitsmulti_label": "Fruits",
  "tenExample:strcatalogfruitmulti_description": "Apple,Banana,Pear,Plum,Pineapple (multi)",
  "tenExample:tablenotice_label": "Notice",
  "tenExample:tablecreatedate_label": "Date",
  "tenExample:tableuser_label": "User",
  "tenExample:tablereadonly_label": "Write protection",
  "tenExample:tablenumber_label": "Number",
  "tenExample:tablenumberdigit_label": "Digit-number",
  "tenExample:tabledistance_label": "Distance",
  "tenExample:tabledistancedigit_label": "Digit-distance",
  "tenExample:tablecreatedatetime_label": "Datetime",
  "tenExample:tableemail_label": "Email",
  "tenExample:tableurl_label": "URL",
  "tenExample:tablephone_label": "Phone",
  "tenExample:tablecatalog_label": "Catalog",
  "tenExample:tablereference_label": "Reference",
  "tenExample:simpleFields_label": "Simple Fields",
  "tenExample:classifications_label": "Classifications",
  "tenExample:number_label": "Number",
  "tenExample:number_description": "Will be filled via script",
  "tenExample:createdate_label": "Created",
  "tenExample:createdate_description": "Will be filled via script as well",
  "tenExample:notice_label": "Notice",
  "tenExample:notice_description": "To be filled by user",
  "tenExample:probability_label": "Probability",
  "tenExample:probability_description": "To be filled by user as well",
  "tenExample:readonly_label": "Read-only",
  "tenExample:readonly_description": "It's still unclear who will do it ...",
  "tenExample:required_label": "Mandatory fields",
  "tenExample:notrequired_label": "Without obligation",
  "tenExample:tableGroup_label": "Table group",
  "tenExample:tableFilling_label": "Table filling",
  "tenExample:process_label": "Approval process",
  "tenExample:process:0_label": "Draft in work",
  "tenExample:process:1_label": "Draft in review",
  "tenExample:process:2_label": "Draft in rework",
  "tenExample:process:3_label": "Document ready",
  "tenExample:process:4_label": "Approved",
  "tenExample:process:5_label": "Rejected",
  "tenExample:datetimemulti_label": "Date & time ",
  "tenExample:datetimemulti_description": "unlimited",
  "tenExample:strcatalogfruitmulti_label": "Fruits",
  "tenExample:strcatalogfruitsmulti_description": "Apple,Banana,Pear,Plum,Pineapple (multi)",
  "tenExample:Table Group_label": "My group",
  "twosteptest_proc_label": "Two step process",
  "twosteptest_proc:2nd_task": "Second task",
  "twosteptest_proc:simplefields_label": "Simple fields",
  "twosteptest_proc:complexfields_label": "Complex fields",
  "twosteptest_proc:datetime_label": "Date & time",
  "twosteptest_proc:date_label": "Date only",
  "twosteptest_proc:boolean_label": "boolean",
  "twosteptest_proc:integer_label": "Integer",
  "twosteptest_proc:decimal_label": "Decimal",
  "twosteptest_proc:string_label": "String",
  "twosteptest_proc:stringmultirow_label": "Multi-row string ",
  "twosteptest_proc:email_label": "Email",
  "twosteptest_proc:phone_label": "Phone",
  "twosteptest_proc:url_label": "URL",
  "twosteptest_proc:user_label": "User",
  "twosteptest_proc:reference_label": "Reference",
  "twosteptest_proc:catalogcustom_label": "Custom catalog",
  "twosteptest_proc:test_table_label": "Notices",
  "twosteptest_proc:test_table_description": "List of notices",
  "twosteptest_proc:column_string_label": "Notice",
  "twosteptest_proc:column_date_label": "Date",
  "twosteptest_proc:column_user_label": "User",
  "twosteptest_proc:column_boolean_label": "Editable",
  "userGroupAssignment:user_label": "User",
  "userGroupAssignment:user_description": "Assign the user who should ...",
  "userGroupAssignment:comment_label": "Comment",
  "userGroupAssignment:comment_description": "Tell the user what to do .."
}
deprecated as of 2023 Winter: POST /api-web/api/admin/resources/text/{locale} - Create or update the tenant-specific localized text resources for the specified locale.
Deprecated as of 2023 Winter. Please use POST /api-web/api/resources/text/{locale}.
As of Version

2020 Winter

Request Method

POST

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Creates or updates the tenant-specific localized text resources for the active tenant and the specified locale formatted in ISO norm, e.g., de, en, es, fr, …​.

The request body is a JSON structure where each technical term as a key is mapped to a string value that will occur as a localized term in the graphical user interface.

Each technical term consists of a field identification (e.g., twosteptest_proc:test_table) followed by either _label or _description in order to be displayed as field label or field description in the graphical user interface.

If a technical term is mapped to null, localization has not yet been applied. The field identification will be displayed as field label in the graphical user interface. A description will not be provided.

Response HTTP status codes:

HTTP status code Meaning

201

CREATED

400

No text resources were specified.

401

Unauthorized

Request Example

https://<host>/api-web/api/admin/resources/text/en

Request Body
{
  "tenExample:betreff_label": "Subject",
  "tenExample:betreff_description": null,
  "tenExample:strsingle_label": "String",
  "tenExample:strsingle_description": "unlimited",
  "tenExample:strregextime_label": "Time",
  "tenExample:strregextime_description": "Time format is 24 hours with hh:mm",
  "tenExample:strcataloggermancountries_label": "German countries",
  "tenExample:strcataloggermancountries_description": "single-field",
  "tenExample:strcataloggermancountriesro_label": "German countries",
  "tenExample:strcataloggermancountriesro_description": "single-field, read-only",
  "tenExample:intsingle_label": "Integer",
  "tenExample:intsingle_description": "unlimited",
  "tenExample:intsingledigit_label": "Integer",
  "tenExample:intsingledigit_description": "digit grouping",
  "tenExample:decsingle_label": "Decimal",
  "tenExample:decsingle_description": "unlimited",
  "tenExample:decsingledigit_label": "Decimal",
  "tenExample:decsingledigit_description": "digit grouping",
  "tenExample:datetimesingle_label": "Date & time",
  "tenExample:datetimesingle_description": "unlimited",
  "tenExample:datetimesinglerequired_label": "Date & time",
  "tenExample:datetimesinglerequired_description": "mandatory",
  "tenExample:datesingle_label": "Date2",
  "tenExample:datesingle_description": "unlimited",
  "tenExample:datesinglerequired_label": "Date1",
  "tenExample:datesinglerequired_description": "mandatory",
  "tenExample:booleanrequiredtrue_label": "Boolean",
  "tenExample:booleanrequiredtrue_description": "mandatory",
  "tenExample:booleannull_label": "Boolean Tri-State",
  "tenExample:booleannull_description": "Null allowed",
  "tenExample:extract2_label": "Extract & map",
  "tenExample:tablesimplefields_label": "Simple fields",
  "tenExample:tablesimplefields_description": "Table with simple fields",
  "tenExample:tableclassifications_label": "Fields with classifications",
  "tenExample:tableclassifications_description": "Table with classification fields",
  "tenExample:strorganizationsingle_label": "User/Group",
  "tenExample:strorganizationmulti_label": "Users/Groups",
  "tenExample:strcatalogfruitsmulti_label": "Fruits",
  "tenExample:strcatalogfruitmulti_description": "Apple,Banana,Pear,Plum,Pineapple (multi)",
  "tenExample:tablenotice_label": "Notice",
  "tenExample:tablecreatedate_label": "Date",
  "tenExample:tableuser_label": "User",
  "tenExample:tablereadonly_label": "Write protection",
  "tenExample:tablenumber_label": "Number",
  "tenExample:tablenumberdigit_label": "Digit-number",
  "tenExample:tabledistance_label": "Distance",
  "tenExample:tabledistancedigit_label": "Digit-distance",
  "tenExample:tablecreatedatetime_label": "Datetime",
  "tenExample:tableemail_label": "Email",
  "tenExample:tableurl_label": "URL",
  "tenExample:tablephone_label": "Phone",
  "tenExample:tablecatalog_label": "Catalog",
  "tenExample:tablereference_label": "Reference",
  "tenExample:simpleFields_label": "Simple Fields",
  "tenExample:classifications_label": "Classifications",
  "tenExample:number_label": "Number",
  "tenExample:number_description": "Will be filled via script",
  "tenExample:createdate_label": "Created",
  "tenExample:createdate_description": "Will be filled via script as well",
  "tenExample:notice_label": "Notice",
  "tenExample:notice_description": "To be filled by user",
  "tenExample:probability_label": "Probability",
  "tenExample:probability_description": "To be filled by user as well",
  "tenExample:readonly_label": "Read-only",
  "tenExample:readonly_description": "It's still unclear who will do it ...",
  "tenExample:required_label": "Mandatory fields",
  "tenExample:notrequired_label": "Without obligation",
  "tenExample:tableGroup_label": "Table group",
  "tenExample:tableFilling_label": "Table filling",
  "tenExample:process_label": "Approval process",
  "tenExample:process:0_label": "Draft in work",
  "tenExample:process:1_label": "Draft in review",
  "tenExample:process:2_label": "Draft in rework",
  "tenExample:process:3_label": "Document ready",
  "tenExample:process:4_label": "Approved",
  "tenExample:process:5_label": "Rejected",
  "tenExample:datetimemulti_label": "Date & time ",
  "tenExample:datetimemulti_description": "unlimited",
  "tenExample:strcatalogfruitmulti_label": "Fruits",
  "tenExample:strcatalogfruitsmulti_description": "Apple,Banana,Pear,Plum,Pineapple (multi)",
  "tenExample:Table Group_label": "My group",
  "twosteptest_proc_label": "Two step process",
  "twosteptest_proc:2nd_task": "Second task",
  "twosteptest_proc:simplefields_label": "Simple fields",
  "twosteptest_proc:complexfields_label": "Complex fields",
  "twosteptest_proc:datetime_label": "Date & time",
  "twosteptest_proc:date_label": "Date only",
  "twosteptest_proc:boolean_label": "boolean",
  "twosteptest_proc:integer_label": "Integer",
  "twosteptest_proc:decimal_label": "Decimal",
  "twosteptest_proc:string_label": "String",
  "twosteptest_proc:stringmultirow_label": "Multi-row string ",
  "twosteptest_proc:email_label": "Email",
  "twosteptest_proc:phone_label": "Phone",
  "twosteptest_proc:url_label": "URL",
  "twosteptest_proc:user_label": "User",
  "twosteptest_proc:reference_label": "Reference",
  "twosteptest_proc:catalogcustom_label": "Custom catalog",
  "twosteptest_proc:test_table_label": "Notices",
  "twosteptest_proc:test_table_description": "List of notices",
  "twosteptest_proc:column_string_label": "Notice",
  "twosteptest_proc:column_date_label": "Date",
  "twosteptest_proc:column_user_label": "User",
  "twosteptest_proc:column_boolean_label": "Editable",
  "userGroupAssignment:user_label": "User",
  "userGroupAssignment:user_description": "Assign the user who should ...",
  "userGroupAssignment:comment_label": "Comment",
  "userGroupAssignment:comment_description": "Tell the user what to do .."
}
Response Example

201 CREATED

no response body

GET /api-web/api/admin/resources/text/languages - Retrieve a list of all used locales of the tenant.
As of Version

2020 Winter

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Retrieves a list of all used languages for resources of the active tenant.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

https://<host>/api-web/api/admin/resources/text/languages

no request body

Response Example

200 OK

Response Body
[
  "fr",
  "en",
  "it",
  "pt",
  "es",
  "de",
  "ru",
  "sv"
]
bpm-controller
The bpm-engine API is required.
GET /api-web/api/bpm/inbox - Retrieve the tasks for the logged-in user.
As of Version

2023 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the tasks for the logged-in user.

Optional query parameters:

Parameter Type Description

visibleTo

string

isCompleted

boolean

includeProcessVariables

boolean

businessKey

string

processDefinitionKey

string

processInstanceId

string

page

integer($int32)

size

integer($int32)

sort

string

id

string

name

string

assignee

string

owner

string

createdBefore

string

createdAfter

string

completedBefore

string

completedAfter

string

briefRepresentation

boolean

Indicates whether to provide additional information in response.

Default: true

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Indicates a parameter was passed in the wrong format. The status-message contains additional information.

401

Unauthorized

Request Example

https://<host>/api-web/api/bpm/inbox

no request body

Response Example

200 OK

Response Body
{
  "objects": [
    {
      "initiator": {
        "id": "string",
        "title": "string"
      },
      "processDefinition": {
        "id": "string",
        "idPrefix": "string",
        "name": "string",
        "description": "string"
      },
      "attachments": [
        "string"
      ],
      "subject": "string",
      "variables": [
        {
          "name": "string",
          "type": "string",
          "value": {},
          "scope": "string"
        }
      ],
      "createTime": "string",
      "formKey": "string",
      "parentTaskId": "string",
      "name": "string",
      "description": "string",
      "id": "string",
      "suspended": true,
      "claimTime": "string"
    }
  ],
  "hasMoreItems": true,
  "totalNumItems": 0,
  "numItems": 0
}
GET /api-web/api/bpm/process-definitions - Retrieve the process definitions the logged-in user is allowed to use.
As of Version

2023 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the process definitions a user is allowed to use to start a process.

This Web API request uses the internal bpm-engine request GET /bpm-engine/api/process-definitions.

Optional query parameters:

Parameter Type Description

latest

boolean

Returns only the latest process definition versions.

Default: true

page

integer($int32)

Result page you want to retrieve (0…N). Default is 0 which means the first page.

Default: 0

size

integer($int32)

Number of objects per page.

Default: 20

Response HTTP status codes:

HTTP status code Meaning

200

OK

403

Forbidden

Request Example

https://<host>/api-web/api/bpm/process-definitions?latest=true&page=0&size=3

no request body

Response Example

200 OK

Response Body
{
  "objects": [
    {
      "id": "dms-lite-adhoc:1:9689a57f-2cf7-11ec-84cf-867d35831bc9",
      "category": "http://www.flowable.org/processdef",
      "key": "dms-lite-adhoc",
      "name": "DMS Lite Adhoc Workflow v1",
      "description": "DMS Lite Ad-Hoc Workflow",
      "version": 1,
      "global": false,
      "startFormDefined": true,
      "suspended": false
    },
    {
      "id": "dms-lite-standard:1:889414e6-ff4e-11eb-97f3-86f2decdc2b4",
      "category": "http://www.flowable.org/processdef",
      "key": "dms-lite-standard",
      "name": "DMS Lite Standard Workflow",
      "description": "DMS Lite Taskflow",
      "version": 1,
      "global": false,
      "startFormDefined": false,
      "suspended": false
    },
    {
      "id": "dms-lite-taskflow:1:9689a57e-2cf7-11ec-84cf-867d35831bc9",
      "category": "http://www.flowable.org/processdef",
      "key": "dms-lite-taskflow",
      "name": "DMS Lite Taskflow",
      "description": "DMS Lite Taskflow",
      "version": 1,
      "global": false,
      "startFormDefined": false,
      "suspended": false
    }
  ],
  "numItems": 3,
  "totalNumItems": 3,
  "hasMoreItems": false
}
GET /api-web/api/bpm/processes - Retrieve the processes for the logged-in user.
As of Version

2023 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the processes for the logged-in user.

Optional query parameters:

Parameter Type Description

includeProcessVariables

boolean

Include process variables in the result.

businessKey

string

Only return process instances with the given businessKey.

isCompleted

boolean

processDefinitionKey

string

Only return process instances with the given process definition key.

page

integer($int32)

Result page you want to retrieve (0…N). Default is 0 which means the first page.

size

integer($int32)

Number of process objects per page.

sort

string

Sorting of results either ascending (asc) or descending (desc). Default sort order is ascending.

processInstanceId

string

processDefinitionId

string

nameLikeIgnoreCase

string

startedBy

string

startedBefore

string

startedAfter

string

finishedBefore

string

finishedAfter

string

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Indicates a parameter was passed in the wrong format. The status-message contains additional information.

Request Example

https://<host>/api-web/api/bpm/processes?businessKey=examplekey&includeProcessVariables=true&processDefinitionKey=follow-up

no request body

Response Example

200 OK

Response Body
{
  "objects": [
    {
      "id": "string",
      "subject": "string",
      "attachments": [
        "string"
      ],
      "processDefinition": {
        "id": "string",
        "idPrefix": "string",
        "name": "string",
        "description": "string"
      },
      "variables": [
        {
          "name": "string",
          "type": "string",
          "value": {},
          "scope": "string"
        }
      ],
      "startUserId": "string",
      "startActivityId": "string",
      "durationInMillis": 0,
      "name": "string",
      "businessKey": "string",
      "startTime": "string",
      "endTime": "string",
      "endActivityId": "string",
      "deleteReason": "string",
      "suspended": true
    }
  ]
}
POST /api-web/api/bpm/processes - Start a process.
As of Version

2023 Autumn

Request Method

POST

Response Format

JSON

Description

Start a process.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

https://<host>/api-web/api/bpm/processes

Request Body
{
  "processDefinitionKey": "string",
  "businessKey": "string",
  "name": "string",
  "variables": [
    {
      "name": "string",
      "type": "string",
      "value": {},
      "scope": "string"
    }
  ],
  "attachments": [
    "string"
  ],
  "subject": "string"
}
Response Example

200 OK

Response Body
{
  "objects": [
    {
      "id": "string",
      "subject": "string",
      "attachments": [
        "string"
      ],
      "processDefinition": {
        "id": "string",
        "idPrefix": "string",
        "name": "string",
        "description": "string"
      },
      "variables": [
        {
          "name": "string",
          "type": "string",
          "value": {},
          "scope": "string"
        }
      ],
      "startUserId": "string",
      "startActivityId": "string",
      "durationInMillis": 0,
      "name": "string",
      "businessKey": "string",
      "startTime": "string",
      "endTime": "string",
      "endActivityId": "string",
      "deleteReason": "string",
      "suspended": true
    }
  ]
}
DELETE /api-web/api/bpm/processes/{processInstanceId} - Delete the specified process instance.
As of Version

2020 Autumn

Request Method

DELETE

Response Format

HTTP status code

Description

Deletes the process instance specified by its processInstanceId.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad request

403

Forbidden

404

Not found

409

Conflict

422

Unprocessable entity

Request Example

https://<host>/api-web/api/bpm/processes/af678-34280fe-3bc

no request body

Response Example

200 OK

no response body

GET /api-web/api/bpm/processes/{processInstanceId}/history - Retrieve the specified process' history.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the history for the specified process instance.

Optional query parameters:

Parameter Type Description

includeComments

boolean

Indicates whether comments are included in response.

Default: false

Response HTTP status codes:

HTTP status code Meaning

200

OK

403

Forbidden

404

Not found

Request Example

https://<host>/api-web/api/bpm/processes/af678-34280fe-3bc/history

no request body

Response Example

200 OK

Response Body
{
  "tasks": [
    {
      "assignee": {
        "id": "string",
        "title": "string"
      },
      "owner": {
        "id": "string",
        "title": "string"
      },
      "initiator": {
        "id": "string",
        "title": "string"
      },
      "processDefinition": {
        "id": "string",
        "idPrefix": "string",
        "name": "string",
        "description": "string"
      },
      "attachments": [
        "string"
      ],
      "subject": "string",
      "formKey": "string",
      "variables": [
        {
          "name": "string",
          "type": "string",
          "value": {},
          "scope": "string"
        }
      ],
      "resolvedValues": {
        "additionalProp1": "string",
        "additionalProp2": "string",
        "additionalProp3": "string"
      },
      "taskForm": {
        "additionalProp1": {},
        "additionalProp2": {},
        "additionalProp3": {}
      },
      "taskMessages": [
        {}
      ]
    }
  ],
  "comments": [
    {
      "id": "string",
      "author": {
        "id": "string",
        "title": "string"
      },
      "message": "string",
      "time": "string",
      "processInstanceId": "string",
      "taskId": "string"
    }
  ]
}
GET /api-web/api/bpm/tasks - Retrieve the tasks for the logged-in user.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the tasks for the logged-in user.

Optional query parameters:

Parameter Type Description

includeProcessVariables

boolean

businessKey

string

processDefinitionKey

string

processInstanceId

string

page

integer($int32)

size

integer($int32)

sort

string

id

string

name

string

assignee

string

owner

string

createdBefore

string

createdAfter

string

completedBefore

string

completedAfter

string

visibleTo

string

isCompleted

boolean

briefRepresentation

boolean

Indicates whether to provide additional information in response.

Default: true

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Indicates a parameter was passed in the wrong format. The status-message contains additional information.

401

Unauthorized

Request Example

https://<host>/api-web/api/bpm/tasks

no request body

Response Example

200 OK

Response Body
{
  "objects": [
    {
      "initiator": {
        "id": "string",
        "title": "string"
      },
      "processDefinition": {
        "id": "string",
        "idPrefix": "string",
        "name": "string",
        "description": "string"
      },
      "attachments": [
        "string"
      ],
      "subject": "string",
      "variables": [
        {
          "name": "string",
          "type": "string",
          "value": {},
          "scope": "string"
        }
      ],
      "createTime": "string",
      "formKey": "string",
      "parentTaskId": "string",
      "name": "string",
      "description": "string",
      "id": "string",
      "suspended": true,
      "claimTime": "string"
    }
  ],
  "hasMoreItems": true,
  "totalNumItems": 0,
  "numItems": 0
}
GET /api-web/api/bpm/tasks/{taskId} - Retrieve the specified task.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the tasks for the logged-in user.

Optional query parameters:

Parameter Type Description

includeProcessVariables

boolean

Indicates whether process variables are included in response.

Default: false

briefRepresentation

boolean

Indicates whether to provide additional information in response.

Default: false

Response HTTP status codes:

HTTP status code Meaning

200

OK

404

Not found

Request Example

https://<host>/api-web/api/bpm/tasks/4345abc-acb3485739-ef3

no request body

Response Example

200 OK

Response Body
{
  "assignee": {
    "id": "string",
    "title": "string"
  },
  "owner": {
    "id": "string",
    "title": "string"
  },
  "initiator": {
    "id": "string",
    "title": "string"
  },
  "processDefinition": {
    "id": "string",
    "idPrefix": "string",
    "name": "string",
    "description": "string"
  },
  "attachments": [
    "string"
  ],
  "subject": "string",
  "variables": [
    {
      "name": "string",
      "type": "string",
      "value": {},
      "scope": "string"
    }
  ],
  "createTime": "string",
  "formKey": "string",
  "parentTaskId": "string",
  "name": "string",
  "description": "string",
  "id": "string",
  "suspended": true,
  "claimTime": "string"
}
PUT /api-web/api/bpm/tasks/{taskId} - Execute an action on the specified task.
As of Version

2020 Autumn

Request Method

PUT

Response Format

JSON

Description

Updates a task specified by its taskId. The task action is defined in JSON format in the request body.

Response HTTP status codes:

HTTP status code Meaning

200

Indicates the action was executed.

400

Indicates the action cannot be performed due to a conflict. Either the task was updates simultaneously or the task was claimed by another user, in case of the claim action.

404

Indicates the requested task was not found.

Request Example

https://<host>/api-web/api/bpm/tasks/4345abc-acb3485739-ef3

Response Body
{
  "action": "save",
  "attachments": [
    "string"
  ],
  "subject": "string",
  "variables": [
    {
      "name": "string",
      "type": "string",
      "value": {},
      "scope": "string"
    }
  ]
}
Response Example

200 OK

Response Body
{
  "assignee": {
    "id": "string",
    "title": "string"
  },
  "owner": {
    "id": "string",
    "title": "string"
  },
  "initiator": {
    "id": "string",
    "title": "string"
  },
  "processDefinition": {
    "id": "string",
    "idPrefix": "string",
    "name": "string",
    "description": "string"
  },
  "attachments": [
    "string"
  ],
  "subject": "string",
  "variables": [
    {
      "name": "string",
      "type": "string",
      "value": {},
      "scope": "string"
    }
  ],
  "createTime": "string",
  "formKey": "string",
  "parentTaskId": "string",
  "name": "string",
  "description": "string",
  "id": "string",
  "suspended": true,
  "claimTime": "string"
}
POST /api-web/api/bpm/tasks/{taskId}/candidates - Update task candidates.
As of Version

2024 Spring

Request Method

POST

Response Format

JSON

Description

Extends the list of candidates for the running task specified by taskId. The new candidates are specified in the JSON request body directly via their user ID or indirectly via roles.

Response HTTP status codes:

HTTP status code Meaning

204

The task was found and the list of candidates was updated.

401

The calling user is not authorized.

403

The user is not allowed to add candidates to the task.

404

The requested task was not found.

Request Header

Content-Type: application/json

Request Example

https://<host>/bpm-engine/api/tasks/187/candidates

Request body
{
  "users": [
    "string"
  ],
  "roles": [
    "string"
  ]
}
Response Example

204 OK

Response Body
{
  "assignee": {
    "id": "string",
    "title": "string"
  },
  "owner": {
    "id": "string",
    "title": "string"
  },
  "initiator": {
    "id": "string",
    "title": "string"
  },
  "processDefinition": {
    "id": "string",
    "idPrefix": "string",
    "name": "string",
    "description": "string"
  },
  "attachments": [
    "string"
  ],
  "subject": "string",
  "variables": [
    {
      "name": "string",
      "type": "string",
      "value": {}
    }
  ],
  "createTime": "string",
  "formKey": "string",
  "parentTaskId": "string",
  "name": "string",
  "description": "string",
  "id": "string",
  "suspended": true,
  "claimTime": "string"
}
POST /api-web/api/bpm/tasks/{taskId}/comment - Create a comment for the specified task.
As of Version

2023 Autumn

Request Method

POST

Response Format

JSON

Description

Creates a comment for the task specified by taskId. Send the message as string in the request body.

Response HTTP status codes:

HTTP status code Meaning

201

Indicates the comment was created and the result is returned.

400

Indicates the comment is missing from the request.

404

Indicates the requested task was not found.

Request Example

https://<host>/api-web/api/bpm/tasks/4345abc-acb3485739-ef3/comment

Request Body
This is the example message.
Response Example

201 CREATED

Response Body
{
  "id": "string",
  "author": "string",
  "message": "This is the example message.",
  "time": "string",
  "processInstanceId": "string",
  "taskId": "4345abc-acb3485739-ef3"
}
dms-controller

These endpoints are accessible for any authenticated user in the default configuration. Most of them internally call the core API.

GET /api-web/api/dms/catalogs/{qname} - Retrieve a specified catalog.
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Description

Retrieves the catalog specified by its name qname.

The tenant-specific resource will be checked first. If a catalog with name qname is available, it will be returned. Otherwise the global resource will be checked. If there is a catalog with name qname, it will be returned. The endpoint returns null if no catalog with qname was found in both global and tenant-specific resource.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/api-web/api/dms/catalogs/contracts

no request body

Response Example

200 OK

Response Body
{
  "tenant": "mytenant",
  "readonly": false,
  "entries": [
    {
      "name": "Employment contract",
      "disabled": false
    },
    {
      "name": "Rental agreement",
      "disabled": false
    },
    {
      "name": "User contract",
      "disabled": false
    },
    {
      "name": "Purchase contract",
      "disabled": true
    }
  ]
}
POST /api-web/api/dms/catalogs/{qname} - Create or update the specified catalog for the active tenant.
As of Version

2021 Summer

Request Method

POST

Response Format

JSON

Description

Updates the tenant-specific catalog specified by its technical name qname with the data passed in the request body in JSON format.

If no tenant-specific catalog with the specified technical name is available, it will be created.

Response HTTP status codes:

HTTP status code Meaning

201

OK

400

Bad request

401

Unauthorized

403

Forbidden

Request Example

https://<host>/api-web/api/dms/catalogs/contracts

Request Body
{
  "tenant": "mytenant",
  "readonly": false,
  "entries": [
    {
      "name": "Employment contract",
      "disabled": false
    },
    {
      "name": "Rental agreement",
      "disabled": false
    },
    {
      "name": "User contract",
      "disabled": false
    },
    {
      "name": "Purchase contract",
      "disabled": true
    }
  ]
}
Response Example

200 OK

Response Body
{
  "errors": [],
  "valid": true
}
PATCH /api-web/api/dms/catalogs/{qname} - Update the specified catalog for the active tenant.
As of Version

2021 Summer

Request Method

PATCH

Response Format

JSON

Description

Updates the existing tenant-specific catalog identified by its name qname or creates a modified copy of an existing global catalog, with the data passed in JSON format in the request body.

The tenant-specific resource will be checked first. If a catalog with name qname is available, it will be updated. Otherwise the global resource will be checked. If there is a catalog with name qname, it will be copied to the tenant-specific resource. This copy will be updated.

In the response body, the modified tenant-specific catalog will be returned.

If no catalog with name qname is available in both tenant-specific and global resources, an error will be thrown.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

403

Forbidden

404

Not found

500

Internal Server Error

Request Example

https://<host>/api-web/api/dms/catalogs/contracts

Request Body
[
  {
    "op": "replace",
    "path": "/entries/1/name",
    "value": "Rental agreement"
  },
  {
    "op": "remove",
    "path": "/entries/3"
  },
  {
    "op": "add",
    "path": "/entries/-",
    "value": {
      "name": "Purchase contract",
      "disabled": true
    }
  }
]
Response Example

200 OK

Response Body
{
  "tenant": "mytenant",
  "readonly": false,
  "entries": [
    {
      "name": "Employment contract",
      "disabled": false
    },
    {
      "name": "Rental agreement",
      "disabled": false
    },
    {
      "name": "User contract",
      "disabled": false
    },
    {
      "name": "Purchase contract",
      "disabled": true
    }
  ]
}
GET /api-web/api/dms/catalogs/{qname}/validate - Get the entries that are already used.
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Description

Checks if entries of the catalog specified by qname are already in use. Returns an empty list if no catalog entries are used.

Optional query parameters:

Parameter Type Description

entries

list of strings

List of entry names to be validated.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

https://<host>/api-web/api/dms/catalogs/contracts/validate

no request body

Response Example

200 OK

Response Body
[
  "string"
]
GET /api-web/api/dms/forms/{objecttype} - Retrieve a metadata form for the specified object type.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the default form for the object type specified by object type ID objecttype and optional query parameters situation and sots (secondary object types) for the active tenant.

Returns null if there is no designed form model for the given object type and situation.

Behind the object type ID, add the query parameter situation=CREATE (situation=EDIT) to retrieve the CREATE (EDIT) form. Default is EDIT. Furthermore, add sots=<objectTypeId> in order to specify a secondary object type of which properties should be included in the retrieved form. If the SOT is defined in an app or tenant schema, the objectTypeId has to contain the corresponding prefix, e.g., tenMytenant:mysot1 or appMyapp:mysot1. The sots query parameter can be added multiple times for different secondary object types.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/api-web/api/dms/forms/tenMytenant:qadocscripts?situation=EDIT&sots=examplesot1&sot=examplesot2

no request body

Response Example

200 OK

Response Body
{
  "name": "tenMytenant:qadocscripts",
  "situation": "EDIT",
  "script": "any valid script",
  "elements": [
    {
      "name": "core",
      "type": "o2mGroup",
      "layout": {
        "align": "column"
      },
      "elements": [
        {
          "name": "appClient:clienttitle",
          "type": "string",
          "rows": 1
        },
        {
          "name": "appClient:clientdescription",
          "type": "string",
          "rows": 1
        }
      ]
    },
    {
      "name": "data",
      "type": "o2mGroupStack",
      "elements": [
        {
          "type": "o2mGroup",
          "layout": {
            "align": "column"
          },
          "elements": [
            {
              "type": "o2mGroup",
              "layout": {
                "align": "row"
              },
              "elements": [
                {
                  "type": "o2mGroup",
                  "layout": {
                    "align": "row"
                  },
                  "elements": [
                    {
                      "name": "tenMytenant:strsingle",
                      "type": "string",
                      "rows": 1
                    },
                    {
                      "name": "tenMytenant:strsinglemail",
                      "type": "string",
                      "rows": 1
                    }
                  ]
                },
                {
                  "type": "o2mGroup",
                  "layout": {
                    "align": "row"
                  },
                  "elements": [
                    {
                      "name": "tenMytenant:intsingle",
                      "type": "integer"
                    },
                    {
                      "name": "tenMytenant:intsingledigit",
                      "type": "integer"
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
POST /api-web/api/dms/objects - Create a DMS object.
As of Version

2020 Autumn

Request Method

POST

Response Format

JSON

Description

Creates a DMS object with the data passed in the multipart request body including the metadata in JSON structure and optionally a binary content file.

The metadata of the created object are returned in the response body.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example
POST /api-web/dms/objects HTTP/1.1
Accept: application/json, application/*+json
Content-Type: multipart/form-data;boundary=Jn3QCX9rHAFQaofW6vsdoz5CsD5_P0PZhH
Content-Length: 83258
Host: 127.0.0.1:7400

--Jn3QCX9rHAFQaofW6vsdoz5CsD5_P0PZhH
Content-Disposition: form-data; name="data"; filename="blob"
Content-Type: application/json;charset=UTF-8

{
    "system:objectTypeId": "appPersonalfile:pfdocumentdlm",
    "system:tags": [["appclient:dlm:prepare",0]]
}


--Jn3QCX9rHAFQaofW6vsdoz5CsD5_P0PZhH
Content-Disposition: form-data; name="files"; filename="JPG_Test-min.jpg"
Content-Type: image/jpeg

--Jn3QCX9rHAFQaofW6vsdoz5CsD5_P0PZhH
Response Example

200 OK

Response Body
{
  "objects": [
    {
      "properties": {
        "system:objectId": {
          "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-05T12:22:41.820Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 31
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-05T12:22:55.900Z",
              "5a7a096a8c517759"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appPersonalfile:pfsubject": {
          "value": "Meeting A"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "test note"
        },
        "appClient:clientdescription": {
          "value": "test 0001"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    },
    {
      "properties": {
        "system:objectId": {
          "value": "12345678-90ab-cdef-1234-567890ab"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-07T12:32:37.500Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 26
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-07T12:32:49.790Z",
              "78d6e14d5b3d8a2e"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "patch test"
        },
        "appClient:clientdescription": {
          "value": "note 123"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    }
  ],
  "numItems": null,
  "hasMoreItems": null,
  "totalNumItems": null
}
DELETE /api-web/api/dms/objects - Delete multiple DMS objects.
As of Version

2023 Winter

Request Method

DELETE

Response Format

JSON

Description

Deletes multiple DMS objects specified by their system:objectId in the JSON request body. The processing is internally handled synchronously.

The number of DMS objects per request is limited to 100.

Optional query parameters:

Parameter Type Description

greedy

boolean

If true (default), the deletion process continues even if one or more DMS objects cannot be deleted. It deletes as many DMS objects as possible.

If false, the entire request fails if one object cannot be deleted.

Response HTTP status codes:

HTTP status code Meaning

207

Multi-Status

Request Example

https://<host>/api-web/api/dms/objects?greedy=true

Request Body
[
  "string"
]
Response Example

207 Multi-Status

Response Body

JSON list of processed objects with their metadata before the deletion

PATCH /api-web/api/dms/objects - Update the metadata of multiple DMS objects.
As of Version

2023 Winter

Request Method

PATCH

Response Format

JSON

Description

Updates the metadata of all DMS objects specified by their system:objectId in the JSON request body. Only the properties specified in the request body and some automatically determined system properties are updated. All further properties remain unchanged.

A (non-required) property value can be removed by sending null as new value.

If even one object could not be updated, the whole request fails.

The number of DMS objects per request is limited to 100.

Response HTTP status codes:

HTTP status code Meaning

200

OK

Request Example

https://<host>/api-web/api/dms/objects

Request Body
{
   "patches":
   [
      {
         "id": "cdc7095f-a5ce-486d-92a7-6d0955d969ee",
         "data": {
            "appClient:clientdescription": "test 0001",
            "appPersonalfile:pfsubject": "Meeting A"
         }
     },
     {
         "id": "12345678-90ab-cdef-1234-567890ab",
         "data": {
             "appClient:clientdescription": "note 123",
             "appPersonalfile:pfsubject":   "null"
         }
     }
   ]
}
Response Example

200 OK

Response Body
{
  "objects": [
    {
      "properties": {
        "system:objectId": {
          "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-05T12:22:41.820Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 31
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-05T12:22:55.900Z",
              "5a7a096a8c517759"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appPersonalfile:pfsubject": {
          "value": "Meeting A"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "test note"
        },
        "appClient:clientdescription": {
          "value": "test 0001"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    },
    {
      "properties": {
        "system:objectId": {
          "value": "12345678-90ab-cdef-1234-567890ab"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-07T12:32:37.500Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 26
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-07T12:32:49.790Z",
              "78d6e14d5b3d8a2e"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "patch test"
        },
        "appClient:clientdescription": {
          "value": "note 123"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    }
  ],
  "numItems": null,
  "hasMoreItems": null,
  "totalNumItems": null
}
GET /api-web/api/dms/objects/{id} - Get the metadata of the specified DMS object.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the metadata of the DMS object specified by its object ID id.

Optional query parameters:

Parameter Type Description

includePermissions

boolean

Should permissions be included.

Default: true

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/api-web/api/dms/objects/4711-44321-666777888

no request body

Response Example

200 OK

Response Body
{
  "objects": [
    {
      "properties": {
        "system:objectId": {
          "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-05T12:22:41.820Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 31
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-05T12:22:55.900Z",
              "5a7a096a8c517759"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appPersonalfile:pfsubject": {
          "value": "Meeting A"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "test note"
        },
        "appClient:clientdescription": {
          "value": "test 0001"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    },
    {
      "properties": {
        "system:objectId": {
          "value": "12345678-90ab-cdef-1234-567890ab"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-07T12:32:37.500Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 26
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-07T12:32:49.790Z",
              "78d6e14d5b3d8a2e"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "patch test"
        },
        "appClient:clientdescription": {
          "value": "note 123"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    }
  ],
  "numItems": null,
  "hasMoreItems": null,
  "totalNumItems": null
}
DELETE /api-web/api/dms/objects/{id} - Delete the specified object.
As of Version

2020 Autumn

Request Method

DELETE

Response Format

JSON

Description

Deletes the DMS object specified by its object ID id.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad request

403

Forbidden

404

Not found

409

Conflict

422

Unprocessable entity

Request Example

https://<host>/api-web/api/dms/objects/4711-44321-666777888

no request body

Response Example

200 OK

no response body

PATCH /api-web/api/dms/objects/{id} - Update the specified DMS object.
As of Version

2020 Autumn

Request Method

PATCH

Response Format

JSON

Description

Updates the metadata and/or tags of an existing DMS object specified by its object ID id with the data passed JSON format in the request body.

Internally, the core API endpoint PATCH /api/dms/objects/{objectId} is called. Thus, only those properties that are part of the request body are changed. Properties that are missing in the request body are not changed by the update.

The modified DMS object is returned in the response body in JSON format.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example
Request Body
{
  "additionalProp1": {},
  "additionalProp2": {},
  "additionalProp3": {}
}
Response Example

200 OK

Response Body
{
  "objects": [
    {
      "properties": {
        "system:objectId": {
          "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-05T12:22:41.820Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 31
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-05T12:22:55.900Z",
              "5a7a096a8c517759"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appPersonalfile:pfsubject": {
          "value": "Meeting A"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "test note"
        },
        "appClient:clientdescription": {
          "value": "test 0001"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    },
    {
      "properties": {
        "system:objectId": {
          "value": "12345678-90ab-cdef-1234-567890ab"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-07T12:32:37.500Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 26
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-07T12:32:49.790Z",
              "78d6e14d5b3d8a2e"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "patch test"
        },
        "appClient:clientdescription": {
          "value": "note 123"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    }
  ],
  "numItems": null,
  "hasMoreItems": null,
  "totalNumItems": null
}
GET /api-web/api/dms/objects/{id}/contents/file - Retrieve the binary content file of the specified object.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the binary content file assigned to the object specified by its object ID id.

Optional query parameters:

Parameter Type Description

version

integer($int32)

The version of the DMS object.

asdownload

boolean

If set to true, the content disposition header response value is set to attachment. This should trigger a download by the browser.

Default: true

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/api-web/api/dms/objects/4711-44321-666777888/contents/file

no request body

Response Example

200 OK

Response Body
[
  "string"
]
POST /api-web/api/objects/{id}/contents/file - Update the binary content file of the specified object.
As of Version

2020 Autumn

Request Method

POST

Response Format

JSON

Description

Updates the binary content file assigned to the object specified by its object ID id with the file passed in the request body.

The response body contains the metadata of the corresponding object.

Response HTTP status codes:

HTTP status code Meaning

200

OK

304

Not Modified

401

Unauthorized

422

Unprocessable entity

Request Example

https://<host>/api-web/api/dms/objects/234df-aca4-fe423/contents/file

Request Body
[
  "string"
]
Response Example

200 OK

Response Body
{
  "objects": [
    {
      "properties": {
        "system:objectId": {
          "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-05T12:22:41.820Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 31
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-05T12:22:55.900Z",
              "5a7a096a8c517759"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appPersonalfile:pfsubject": {
          "value": "Meeting A"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "test note"
        },
        "appClient:clientdescription": {
          "value": "test 0001"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    },
    {
      "properties": {
        "system:objectId": {
          "value": "12345678-90ab-cdef-1234-567890ab"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-07T12:32:37.500Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 26
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-07T12:32:49.790Z",
              "78d6e14d5b3d8a2e"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "patch test"
        },
        "appClient:clientdescription": {
          "value": "note 123"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    }
  ],
  "numItems": null,
  "hasMoreItems": null,
  "totalNumItems": null
}
GET /api-web/api/dms/objects/{id}/versions - Retrieve the metadata of all versions of the specified DMS object.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the metadata of all versions of the DMS object specified by its object ID id.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/api-web/api/dms/objects/4711-44321-666777888/versions

no request body

Response Example

200 OK

Response Body
{
  "objects": [
    {
      "properties": {
        "system:objectId": {
          "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-05T12:22:41.820Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 31
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-05T12:22:55.900Z",
              "5a7a096a8c517759"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appPersonalfile:pfsubject": {
          "value": "Meeting A"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "test note"
        },
        "appClient:clientdescription": {
          "value": "test 0001"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    },
    {
      "properties": {
        "system:objectId": {
          "value": "12345678-90ab-cdef-1234-567890ab"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-07T12:32:37.500Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 26
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-07T12:32:49.790Z",
              "78d6e14d5b3d8a2e"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "patch test"
        },
        "appClient:clientdescription": {
          "value": "note 123"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    }
  ],
  "numItems": null,
  "hasMoreItems": null,
  "totalNumItems": null
}
GET /api-web/api/dms/objects/{id}/versions/{version} - Retrieve the metadata of the specified DMS object version.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the metadata of the version version of the DMS object specified by its object ID id.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/api-web/api/dms/objects/4711-44321-666777888/versions/2

no request body

Response Example

200 OK

Response Body
{
  "objects": [
    {
      "properties": {
        "system:objectId": {
          "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-05T12:22:41.820Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 31
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-05T12:22:55.900Z",
              "5a7a096a8c517759"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appPersonalfile:pfsubject": {
          "value": "Meeting A"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "test note"
        },
        "appClient:clientdescription": {
          "value": "test 0001"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    },
    {
      "properties": {
        "system:objectId": {
          "value": "12345678-90ab-cdef-1234-567890ab"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-07T12:32:37.500Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 26
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-07T12:32:49.790Z",
              "78d6e14d5b3d8a2e"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "patch test"
        },
        "appClient:clientdescription": {
          "value": "note 123"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    }
  ],
  "numItems": null,
  "hasMoreItems": null,
  "totalNumItems": null
}
POST /api-web/api/dms/objects/{objectId}/versions/{versionNr}/actions/restore - Restore the specified old version of the DMS object.
As of Version

2022 Spring

Request Method

POST

Response Format

JSON

Description

Restores the older version version of the DMS object specified by its object ID id.

Optional query parameters:

Parameter Type Description

restoreParentId

boolean

Indicates whether to keep the current value for the system:parentId property of the child object even after restoring an old version.

Default: true

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/api-web/api/dms/objects/4711-44321-666777888/versions/2/actions/restore

no request body

Response Example

200 OK

Response Body
{
  "objects": [
    {
      "properties": {
        "system:objectId": {
          "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-05T12:22:41.820Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 31
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-05T12:22:55.900Z",
              "5a7a096a8c517759"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appPersonalfile:pfsubject": {
          "value": "Meeting A"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "test note"
        },
        "appClient:clientdescription": {
          "value": "test 0001"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    },
    {
      "properties": {
        "system:objectId": {
          "value": "12345678-90ab-cdef-1234-567890ab"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-07T12:32:37.500Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 26
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-07T12:32:49.790Z",
              "78d6e14d5b3d8a2e"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "patch test"
        },
        "appClient:clientdescription": {
          "value": "note 123"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    }
  ],
  "numItems": null,
  "hasMoreItems": null,
  "totalNumItems": null
}
POST /api-web/api/dms/objects/export - Search DMS objects and retrieve the result list as CSV.
As of Version

2022 Winter

Request Method

POST

Response Format

CSV

Description

Retrieves a list of DMS objects matching the search query passed in the request body in CSV format.

Datetime properties are formatted as ISO standard. Decimals are formatted corresponding to the locale for the currently logged-in user that is specified in the request header. If no locale is specified for the request, en is used as default.

Further formatting can be configured in the api-web-prod.yml configuration file.

The query JSON in the request body has to match the format for search via Web API gateway.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

https://<host>/api-web/api/dms/objects/export

Request Body
{
  "fields": [
    "string"
  ],
  "types": [
    "string"
  ],
  "lots": [
    "string"
  ],
  "term": "string",
  "filters": [
    {
      "lo": "string",
      "f": "string",
      "v1": {},
      "v2": {},
      "o": "string",
      "useNot": false
    }
  ],
  "tableFilters": [
    {
      "table": "string",
      "row": 0,
      "columnFilters": [
        {
          "lo": "string",
          "f": "string",
          "v1": {},
          "v2": {},
          "o": "string",
          "useNot": false
        }
      ],
      "lo": "string",
      "useNot": false
    }
  ],
  "aggs": [
    "string"
  ],
  "scope": "string",
  "sort": [
    {
      "order": "string"
    }
  ],
  "from": 0,
  "size": 20
}
Response Example

200 OK

text/csv in the response body

POST /api-web/api/dms/objects/search - Search DMS objects.
As of Version

2020 Autumn

Request Method

POST

Response Format

JSON

Description

Retrieves a list of DMS objects matching the search query passed in the request body in JSON format.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

https://<host>/api-web/api/dms/objects/search

Request Body
{
  "fields": [
    "string"
  ],
  "types": [
    "string"
  ],
  "lots": [
    "string"
  ],
  "term": "string",
  "filters": [
    {
      "lo": "string",
      "f": "string",
      "v1": {},
      "v2": {},
      "o": "string",
      "useNot": false
    }
  ],
  "tableFilters": [
    {
      "table": "string",
      "row": 0,
      "columnFilters": [
        {
          "lo": "string",
          "f": "string",
          "v1": {},
          "v2": {},
          "o": "string",
          "useNot": false
        }
      ],
      "lo": "string",
      "useNot": false
    }
  ],
  "aggs": [
    "string"
  ],
  "scope": "string",
  "sort": [
    {
      "order": "string"
    }
  ],
  "from": 0,
  "size": 20
}
Response Example

200 OK

Response Body
{
  "objects": [
    {
      "properties": {
        "system:objectId": {
          "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-05T12:22:41.820Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 31
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-05T12:22:55.900Z",
              "5a7a096a8c517759"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appPersonalfile:pfsubject": {
          "value": "Meeting A"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "test note"
        },
        "appClient:clientdescription": {
          "value": "test 0001"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    },
    {
      "properties": {
        "system:objectId": {
          "value": "12345678-90ab-cdef-1234-567890ab"
        },
        "system:baseTypeId": {
          "value": "system:document"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:secondaryObjectTypeIds": {
          "value": [
            "appClientsystem:leadingType",
            "appClient:clientdefaults",
            "appPersonalfile:pfsicknotesot"
          ]
        },
        "system:createdBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:creationDate": {
          "value": "2023-09-07T12:32:37.500Z"
        },
        "system:lastModifiedBy": {
          "value": "85b6c5ef-7e87-4e71-bbba-4148a042c7c4",
          "title": "Root, Test (root)"
        },
        "system:lastModificationDate": {
          "value": "2023-09-08T07:40:10.470Z"
        },
        "system:versionNumber": {
          "value": 26
        },
        "system:tenant": {
          "value": "testyuuvis"
        },
        "system:traceId": {
          "value": "97a35859dbb4c436"
        },
        "system:tags": {
          "value": [
            [
              "appclient:dlm:prepare",
              1,
              "2023-09-07T12:32:49.790Z",
              "78d6e14d5b3d8a2e"
            ]
          ]
        },
        "system:parentId": {
          "value": "a91c4029-2572-4649-a315-35a501d7b610"
        },
        "system:parentObjectTypeId": {
          "value": "appPersonalfile:pfpersonalfile"
        },
        "appClientsystem:leadingTypeId": {
          "value": "appPersonalfile:pfsicknotesot"
        },
        "appClient:clienttitle": {
          "value": "patch test"
        },
        "appClient:clientdescription": {
          "value": "note 123"
        },
        "appPersonalfile:pfdays": {
          "value": 2
        },
        "appPersonalfile:pfsickcertificate": {
          "value": false
        },
        "appPersonalfile:pfhalfday": {
          "value": false
        },
        "appPersonalfile:pfcompensation": {
          "value": false
        }
      }
    }
  ],
  "numItems": null,
  "hasMoreItems": null,
  "totalNumItems": null
}
GET /api-web/api/dms/permissions - Retrieve the available object types the logged-in user can use.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the object types that are available for the individual actions on DMS objects for the currently logged-in user. Available actions are:

  • CREATE

  • WRITE

  • READ

  • DELETE

With this information, client applications can present a selection list of object types that are relevant for the logged-in user. Thus, users will see only those object types that are available to them. Those selection lists may differ for the individual actions.

The response body is a JSON structure listing all object types for the corresponding action as shown in the example below.

The object type IDs are defined in a corresponding schema.

The permissions are assigned to users via roles.

Internally, the endpoint calls the search service’s endpoint GET /search/api/search/dsl/check.

+ Response HTTP status codes:

+

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

https://<host>/api-web/api/dms/permissions

no request body

Response Example

200 OK

Response Body
{
  "CREATE": {
    "folderTypeIds": [
      "appPersonalfile:pfpersonalfile"
    ],
    "secondaryObjectTypeIds": [
      "system:secondary",
      "emailsot",
      "appClientsystem:leadingType",
      "tenKolibri:qadocdossiersot"
    ],
    "objectTypeIds": [
      "email",
      "appClient:minidoc",
      "appPersonalfile:pfdocument",
      "tenKolibri:preobject"
    ]
  },
  "READ": {
    "folderTypeIds": [
      "appPersonalfile:pfpersonalfile",
      "appPhotoarchive:paphotoalbum"
    ],
    "secondaryObjectTypeIds": [
      "system:secondary",
      "system:rmDestructionRetention",
      "emailsot",
      "emailextension",
      "appClientsystem:leadingType",
      "tenKolibri:qadocdossiersot",
      "tenKolibri:qadoccatalogssot",
      "tenKolibri:qadoccontentrequiredsot",
      "tenKolibri:qadocscriptssot"
    ],
    "objectTypeIds": [
      "doctableofnotices",
      "email",
      "preemail",
      "appClient:minidoc",
      "appPersonalfile:pfidphoto",
      "appPersonalfile:pfdocument",
      "appPersonalfile:pfsicknote",
      "appPersonalfile:pfvacancy",
      "appPersonalfile:pfdocumentdlm",
      "tenKolibri:qadoccatalogs",
      "tenKolibri:qadocscripts",
      "tenKolibri:qadocscriptsmulti",
      "tenKolibri:preobject"
    ]
  },
  "WRITE": {
    "folderTypeIds": [
      "appPersonalfile:pfpersonalfile"
    ],
    "secondaryObjectTypeIds": [
      "system:secondary",
      "emailsot",
      "appClientsystem:leadingType",
      "tenKolibri:qadocdossiersot"
    ],
    "objectTypeIds": [
      "doctableofnotices",
      "email",
      "appClient:minidoc",
      "appPersonalfile:pfdocument",
      "tenKolibri:preobject"
    ]
  },
  "DELETE": {
    "folderTypeIds": [
      "tenKolibri:qadossier"
    ],
    "secondaryObjectTypeIds": [
      "tenKolibri:qadocscriptssot"
    ],
    "objectTypeIds": [
      "doctableofnotices",
      "tenKolibri:preobject"
    ]
  }
}
POST /api-web/api/dms/schema/refresh - Refresh a schema.
As of Version

2023 Autumn

Request Method

POST

Response Format

HTTP status code

Description

Refresh the global schema, the tenant schema or an app schema.

Optional query parameters:

Parameter Type Description

global

boolean

Should global schema be refreshed.

Default: true

app

string

The name of the app which schema should be refreshed.

tenant

string

The name of the tenant which schema should be refreshed.

Request Example

https://<host>/api-web/api/dms/schema/refresh

no request body

Response Example

200 OK

no response body

idm-controller

Endpoints of the Web API gateway for user information and role retrieval.

The tenant-management API is required.
GET /api-web/api/idm/roles - Retrieve the roles from the connected identity provider.
As of Version

2023 Spring

Request Method

GET

Response Format

JSON

Description

Retrieves all roles of the tenant. The relult list can be filtered by a search string. Technical roles are always filtered out.

Optional query parameters:

Parameter Type Description

search

string

A string contained in role name or description.

tenant

string

Tenant name to retrieve roles for a different tenant. Can only be used by users with the YUUVIS_SYSTEM_INTEGRATOR role, otherwise ignored.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

https://<host>/api-web/api/idm/roles?search=test

no request body

Response Example

200 OK

Response Body
[
  {
    "name": "TEST_ROLE",
    "description": "Example role"
  },
  {
    "name": "EXAMPLE_ROLE",
    "description": "Role containing word test in its description"
  }
]
POST /api-web/api/idm/roles - Create a role in Keycloak.
As of Version

2023 Autumn

Request Method

POST

Response Format

JSON

Required Permission

YUUVIS_SYSTEM_INTEGRATOR or YUUVIS_TENANT_ADMIN role

Description

Create a role in the connected identity provider.

Only available if Keycloak is used as identity provider.
The role is not introduced in a yuuvis® Momentum role set.

Optional query parameters:

Parameter Type Description

tenant

string

Tenant name to create a role for a different tenant. Can only be used by users with the YUUVIS_SYSTEM_INTEGRATOR role, otherwise ignored.

Response HTTP status codes:

HTTP status code Meaning

201

Created

401

Unauthorized

Request Example

https://<host>/api-web/api/idm/roles

Request Body
{
  "name": "TEST_ROLE",
  "description": "Example role"
}
Response Example

200 OK

Response Body
{
  "errors": [],
  "valid": true
}
DELETE /api-web/api/idm/roles/{role-name} - Delete a role in Keycloak.
As of Version

2023 Autumn

Request Method

DELETE

Response Format

HTTP status code

Required Permission

YUUVIS_SYSTEM_INTEGRATOR or YUUVIS_TENANT_ADMIN role

Description

Delete a role in the connected identity provider.

Only available if Keycloak is used as identity provider.
The role is not deleted in a yuuvis® Momentum role set.

Optional query parameters:

Parameter Type Description

tenant

string

Tenant name if role shoud be deleted for a different tenant. Can only be used by users with the YUUVIS_SYSTEM_INTEGRATOR role, otherwise ignored.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

https://<host>/api-web/api/idm/roles/TEST_ROLE

no request body

Response Example

200 OK

no response body

GET /api-web/api/idm/users - Retrieve tenant users from the identity provider.
As of Version

2023 Spring

Request Method

GET

Response Format

JSON

Description

Retrieves all users of the tenant. The result list can be filtered by applying conditions that have to be matched.

The conditions are specified via the following optional query parameters.

Users with technical roles are always filtered out.

Optional query parameters:

Parameter Type Description

search

string

Retrieve only users for which the specified string is contained in user name, first name, last name or e-mail.

excludeMe

boolean

onlyActive

boolean

If true, the currently logged-in user is excluded from the result list. (default: true)

roles

list of strings

Retrieve only users that have at least one of the provided roles.

page

integer

Result page you want to retrieve (0…N). Default is 0 which means the first page.

size

integer($int32)

Limit the number of users per page. (default: 20)

sort

list of strings

Sorting of results either ascending (asc) or descending (desc). Default sort order is ascending.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

https://<host>/api-web/api/idm/users

no request body

Response Example

200 OK

Response Body
[
  {
    "username": "string",
    "id": "string",
    "foreignid": "string",
    "type": "string",
    "title": "string",
    "email": "string",
    "firstname": "string",
    "lastname": "string",
    "domain": "string",
    "tenant": "string",
    "authorities": [
      "string"
    ],
    "substituteOf": [
      "string"
    ],
    "accountNonExpired": true,
    "accountNonLocked": true,
    "credentialsNonExpired": true,
    "enabled": true,
    "displayName": "string"
  }
]
GET /api-web/api/idm/users/{userId} - Retrieve attributes of the specified user.
As of Version

2023 Spring

Request Method

GET

Response Format

JSON

Description

Retrieves user-specific data for the user specified by userId. Technical roles are always filtered out.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

https://<host>/api-web/api/idm/users/string

no request body

Response Example

200 OK

Response Body
{
  "username": "string",
  "id": "string",
  "foreignid": "string",
  "type": "string",
  "title": "string",
  "email": "string",
  "firstname": "string",
  "lastname": "string",
  "domain": "string",
  "tenant": "string",
  "authorities": [
    "string"
  ],
  "substituteOf": [
    "string"
  ],
  "accountNonExpired": true,
  "accountNonLocked": true,
  "credentialsNonExpired": true,
  "enabled": true,
  "displayName": "string"
}
GET /api-web/api/idm/whoami - Retrieve attributes of the logged-in user.
As of Version

2023 Spring

Request Method

GET

Response Format

JSON

Description

Returns a result list configuration by type.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

https://<host>/api-web/api/idm/users/whoami

no request body

Response Example

200 OK

Response Body
{
  "username": "string",
  "id": "string",
  "foreignid": "string",
  "type": "string",
  "title": "string",
  "email": "string",
  "firstname": "string",
  "lastname": "string",
  "domain": "string",
  "tenant": "string",
  "authorities": [
    "string"
  ],
  "substituteOf": [
    "string"
  ],
  "accountNonExpired": true,
  "accountNonLocked": true,
  "credentialsNonExpired": true,
  "enabled": true,
  "displayName": "string"
}
resource-controller

Endpoints of the Web API gateway for resource files management.

GET /api-web/api/resources/config/{name} - Retrieve the specified configuration.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Description

Modified behavior as of 2023 Winter. For the configuration specified by name, the endpoint retrieves the

  • global configuration file,

  • tenant-specific configuration file,

  • app-specific configuration file OR

  • merged configuration file for the active tenant.

The merged configuration file is composed of tenant-specific, app-specific and global configurations.

The actual target configuration is specified via query parameters.

Optional query parameters:

Parameter Type Description

raw

boolean

If false or unspecified, the merged client configuration will be used.

If true, an unmerged configuration is retrieved.

filter

string

Filter for merged config (Only available if NOT raw and user is YUUVIS_SYSTEM_INTEGRATOR)

  • If not specified, tenant AND global resource (AND resolved resource, if specified) are retrieved.

  • If filter=global, only the global resource is retrieved.

  • If filter=tenant, only the tenant-specific resource is retrieved.

  • If filter=resolved, only 1 resource based on hierarchy (resolved OR tenant OR global) is retrieved.

tenant

string

Tenant name (Only use if raw is set)

app

string

App (Only use if raw is set)

Response HTTP status codes:

HTTP status code Meaning

200

OK

404

Not found

Request Example

https://<host>/api-web/api/resources/config/main-config

no request body

Response Example

200 OK

Response Body
{
  "tenant": {
    "core": {
      "apiBase": {
        "core": "/api",
        "api-web": "/api-web/api",
        "predict": "/predict-api",
        "viewer": "/viewer",
        "logout": "/logout",
        "oauth": "/oauth"
      },
      "gridOptions": {
        "pageSize": 50,
        "pageSizeOptions": [
          13,
          23,
          33
        ],
        "rowHeight": 70,
        "rowHeightOptions": [
          23,
          33,
          43
        ]
      },
      "languages": [
        {
          "iso": "de",
          "label": "Deutsch"
        },
        {
          "iso": "de-CH",
          "label": "Deutsch (Schweiz)"
        },
        {
          "iso": "en",
          "label": "English",
          "fallback": true
        }
      ],
      "logging": {
        "level": "debug"
      },
      "features": {
        "dashboardWorkspaces": true
      }
    },
    "client": {
      "docu": {
        "link": "https://help.optimal-systems.com/yuuvis_develop/display/YMY/Adding+Documentation",
        "language": [
          "de",
          "en"
        ]
      }
    }
  }
}
POST /api-web/api/resources/config/{name} - Update the specified configuration file.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Required Permission

Available for users with the roles configured in api-web.technical-roles in the api-web-prod.yml configuration file. Default: YUUVIS_SYSTEM_INTEGRATOR and YUUVIS_TENANT_ADMIN.

Description

Creates or updates the client configuration file specified by name with the data passed in JSON format in the request body. If no query parameter is set, the corresponding global configuration file is created/updated.

Optional query parameters:

Parameter Type Description

tenant

string

Update the tenant-specific configuration instead of the global one. In the default configuration, only available for users with the YUUVIS_TENANT_ADMIN role.

app

string

Update the app-specific configuration instead of the global one. In the default configuration, only available for users with the YUUVIS_SYSTEM_INTEGRATOR role.

Response HTTP status codes:

HTTP status code Meaning

201

CREATED

DELETE /api-web/api/resources/config/{name} - Delete the specified configuration file.
As of Version

2023 Winter

Request Method

DELETE

Response Format

JSON

Required Permission

Available for users with the roles configured in api-web.technical-roles in the api-web-prod.yml configuration file. Default: YUUVIS_SYSTEM_INTEGRATOR and YUUVIS_TENANT_ADMIN.

Description

Deletes the client configuration file specified by name with the data passed in JSON format in the request body. If no query parameter is set, the corresponding global configuration file is deleted.

Optional query parameters:

Parameter Type Description

tenant

string

Delete the tenant-specific configuration instead of the global one. In the default configuration, only available for users with the YUUVIS_SYSTEM_INTEGRATOR role.

app

string

Delete the app-specific configuration instead of the global one. In the default configuration, only available for users with the YUUVIS_SYSTEM_INTEGRATOR role.

Response HTTP status codes:

HTTP status code Meaning

200

OK

404

Configuration resource not found

GET /api-web/api/resources/forms/{type} - Retrieve the metadata form for the specified object type.
As of Version

2023 Winter

Request Method

GET

Response Format

JSON

Description

Retrieves the non-enriched form by object type ID type and optional query parameters situation and sots (secondary object types).

Behind the object type ID, add the query parameter situation=CREATE (situation=EDIT) to retrieve the CREATE (EDIT) form. Default is EDIT. Furthermore, add sots=<objectTypeId> in order to specify a secondary object type of which properties should be included in the retrieved form. The sots query parameter can be added multiple times for different secondary object types.

Returns null if there is no designed form model for the given object type.

Optional query parameters:

Parameter Type Description

situation

string

Create or edit a form. (default: EDIT)

sots

list of strings

List of the secondary object types

Response HTTP status codes:

HTTP status code Meaning

200

OK

404

Not found

Request Example

https://<host>/api-web/api/resources/forms/qadocscripts?situation=EDIT&sots=examplesot1&sot=examplesot2

no request body

Response Example

200 OK

Response Body
{
  "name": "tenMytenant:qadocscripts",
  "situation": "EDIT",
  "script": "any valid script",
  "elements": [
    {
      "name": "core",
      "type": "o2mGroup",
      "layout": {
        "align": "column"
      },
      "elements": [
        {
          "name": "appClient:clienttitle",
          "type": "string",
          "rows": 1
        },
        {
          "name": "appClient:clientdescription",
          "type": "string",
          "rows": 1
        }
      ]
    },
    {
      "name": "data",
      "type": "o2mGroupStack",
      "elements": [
        {
          "type": "o2mGroup",
          "layout": {
            "align": "column"
          },
          "elements": [
            {
              "type": "o2mGroup",
              "layout": {
                "align": "row"
              },
              "elements": [
                {
                  "type": "o2mGroup",
                  "layout": {
                    "align": "row"
                  },
                  "elements": [
                    {
                      "name": "tenMytenant:strsingle",
                      "type": "string",
                      "rows": 1
                    },
                    {
                      "name": "tenMytenant:strsinglemail",
                      "type": "string",
                      "rows": 1
                    }
                  ]
                },
                {
                  "type": "o2mGroup",
                  "layout": {
                    "align": "row"
                  },
                  "elements": [
                    {
                      "name": "tenMytenant:intsingle",
                      "type": "integer"
                    },
                    {
                      "name": "tenMytenant:intsingledigit",
                      "type": "integer"
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
POST /api-web/api/resources/forms/{type} - Update the metadata form for the specified object type.
As of version

2023 Winter

Request Method

POST

Response Format

JSON

Required Permission

Available for users with the roles configured in api-web.technical-roles in the api-web-prod.yml configuration file. Default: YUUVIS_SYSTEM_INTEGRATOR and YUUVIS_TENANT_ADMIN

Description

Saves non-enriched form. Specify the fully qualified name of the form’s object type in the type path parameter.

Optional query parameters:

Parameter Type Description

sots

array[string]

List of the secondary object types

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

500

Internal Server Error

Request Example

https://<host>/api-web/api/resources/forms/tenKolibri:email

Request Body
{
  "name": "tenMytenant:qadocscripts",
  "situation": "EDIT",
  "script": "any valid script",
  "elements": [
    {
      "name": "core",
      "type": "o2mGroup",
      "layout": {
        "align": "column"
      },
      "elements": [
        {
          "name": "appClient:clienttitle",
          "type": "string",
          "rows": 1
        },
        {
          "name": "appClient:clientdescription",
          "type": "string",
          "rows": 1
        }
      ]
    },
    {
      "name": "data",
      "type": "o2mGroupStack",
      "elements": [
        {
          "type": "o2mGroup",
          "layout": {
            "align": "column"
          },
          "elements": [
            {
              "type": "o2mGroup",
              "layout": {
                "align": "row"
              },
              "elements": [
                {
                  "type": "o2mGroup",
                  "layout": {
                    "align": "row"
                  },
                  "elements": [
                    {
                      "name": "tenMytenant:strsingle",
                      "type": "string",
                      "rows": 1
                    },
                    {
                      "name": "tenMytenant:strsinglemail",
                      "type": "string",
                      "rows": 1
                    }
                  ]
                },
                {
                  "type": "o2mGroup",
                  "layout": {
                    "align": "row"
                  },
                  "elements": [
                    {
                      "name": "tenMytenant:intsingle",
                      "type": "integer"
                    },
                    {
                      "name": "tenMytenant:intsingledigit",
                      "type": "integer"
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
Response Example

200 OK

Response Body
{
  "errors": [],
  "valid": true
}
DELETE /api-web/api/resources/forms/{type} - Delete the metadata form for the specified object type.
As of version

2023 Winter

Request Method

DELETE

Response Format

JSON

Required Permission

Available for users with the roles configured in api-web.technical-roles in the api-web-prod.yml configuration file. Default: YUUVIS_SYSTEM_INTEGRATOR and YUUVIS_TENANT_ADMIN

Description

Deletes non-enriched form. Specify the fully qualified name of the form’s object type in the type path parameter.

Optional query parameters:

Parameter Type Description

sots

array[string]

List of the secondary object types

Response HTTP status codes:

HTTP status code Meaning

200

OK

404

Form resource not found.

Request Example

https://<host>/api-web/api/resources/forms/tenKolibri:email

no request body

Response Example

200 OK

GET /api-web/api/resources/icons/{type} - Retrieve the specified icon.
As of Version

2020 Autumn

Request Method

GET

Response Format

SVG

Description

Retrieves the SVG image used as icon for the specified object type ID type.

Optional query parameters:

Parameter Type Description

fallback

string

In case for the object type referenced by the type path parameter, no icon is available. The fallback icon is retrieved. It is referenced by object type ID as well.

Response HTTP status codes:

HTTP status code Meaning

200

OK

404

Not found

Request Example

https://<host>/api-web/api/resources/icons/tenKolibri:email?fallback=appInvoice:document

POST /api-web/api/resources/icons/{type} - Update the specified icon.
As of version

2023 Winter

Request Method

POST

Response Format

HTTP status code

Required Permission

Available for users with the roles configured in api-web.technical-roles in the api-web-prod.yml configuration file. Default: YUUVIS_SYSTEM_INTEGRATOR and YUUVIS_TENANT_ADMIN

Description

This request updates the icon for the object type specified by its object type ID type.

Response HTTP status codes:

HTTP status code Meaning

201

CREATED

400

No icon was specified.

Request Example

https://<host>/api-web/api/resources/icons/tenKolibri:email

Request Body
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
  <path d="M15 3H5a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2V9l-6-6m4 16H5V5h9v5h5m-2 4H7v-2h10m-3 5H7v-2h7"/>
</svg>
Response Example

201 CREATED

DELETE /api-web/api/resources/icons/{type} - Delete the specified icon.
As of version

2023 Winter

Request Method

DELETE

Response Format

HTTP status code

Required Permission

Available for users with the roles configured in api-web.technical-roles in the api-web-prod.yml configuration file. Default: YUUVIS_SYSTEM_INTEGRATOR and YUUVIS_TENANT_ADMIN

Description

This request updates the icon for the object type specified by its object type ID type.

Response HTTP status codes:

HTTP status code Meaning

201

OK

404

No icon was found.

Request Example

https://<host>/api-web/api/resources/icons/tenKolibri:email

no request body

Response Example

200 OK

GET /api-web/api/resources/text - Retrieve the localized text resources for a specified locale.
As of Version

2020 Autumn

Request Method

GET

Response Format

HTTP status code

Description

Modified behavior as of 2023 Winter.

Retrieves localized text resources for the Accept-Language specified in the request header formatted in ISO norm (e.g., de, en, es, fr, …​). Depending on optional query parameters, the endpoint retrieves the

  • global localization file (raw=true),

  • tenant-specific localization file (raw=true&tenant=myfirsttenant),

  • app-specific localization file (raw=true&app=myexampleapp) OR

  • merged localization file for the active tenant (raw=false).

The merged localization file is composed of tenant-specific, app-specific and global localizations.

Optional query parameters:

Parameter Type Description

raw

boolean

If false or unspecified, the merged localization for the active tenant will be retrieved.

If true, an unmerged configuration is retrieved.

tenant

string

Only available if raw is set. Specify a tenant name for which you want to retrieve the tenant-specific localization file.

app

string

Only available if raw is set. Specify an app name for which you want to retrieve the app-specific localization file.

The response body is a JSON structure where each technical term as a key is mapped to a string value that will occur as a localized term in the graphical user interface.

Each technical term consists of a field identification (e.g., twosteptest_proc:test_table) followed by either _label or _description in order to be displayed as field label or field description in the graphical user interface.

If a technical term is mapped to null, localization has not yet been applied. The field identification will be displayed as field label in the graphical user interface. A description will not be provided.

Response HTTP status codes:

HTTP status code Meaning

200

OK

Request Example

https://<host>/api-web/api/resources/text/en

no request body

Response Example

200 OK

Response Body
{
  "tenExample:betreff_label": "Subject",
  "tenExample:betreff_description": null,
  "tenExample:strsingle_label": "String",
  "tenExample:strsingle_description": "unlimited",
  "tenExample:strregextime_label": "Time",
  "tenExample:strregextime_description": "Time format is 24 hours with hh:mm",
  "tenExample:strcataloggermancountries_label": "German countries",
  "tenExample:strcataloggermancountries_description": "single-field",
  "tenExample:strcataloggermancountriesro_label": "German countries",
  "tenExample:strcataloggermancountriesro_description": "single-field, read-only",
  "tenExample:intsingle_label": "Integer",
  "tenExample:intsingle_description": "unlimited",
  "tenExample:intsingledigit_label": "Integer",
  "tenExample:intsingledigit_description": "digit grouping",
  "tenExample:decsingle_label": "Decimal",
  "tenExample:decsingle_description": "unlimited",
  "tenExample:decsingledigit_label": "Decimal",
  "tenExample:decsingledigit_description": "digit grouping",
  "tenExample:datetimesingle_label": "Date & time",
  "tenExample:datetimesingle_description": "unlimited",
  "tenExample:datetimesinglerequired_label": "Date & time",
  "tenExample:datetimesinglerequired_description": "mandatory",
  "tenExample:datesingle_label": "Date2",
  "tenExample:datesingle_description": "unlimited",
  "tenExample:datesinglerequired_label": "Date1",
  "tenExample:datesinglerequired_description": "mandatory",
  "tenExample:booleanrequiredtrue_label": "Boolean",
  "tenExample:booleanrequiredtrue_description": "mandatory",
  "tenExample:booleannull_label": "Boolean Tri-State",
  "tenExample:booleannull_description": "Null allowed",
  "tenExample:extract2_label": "Extract & map",
  "tenExample:tablesimplefields_label": "Simple fields",
  "tenExample:tablesimplefields_description": "Table with simple fields",
  "tenExample:tableclassifications_label": "Fields with classifications",
  "tenExample:tableclassifications_description": "Table with classification fields",
  "tenExample:strorganizationsingle_label": "User/Group",
  "tenExample:strorganizationmulti_label": "Users/Groups",
  "tenExample:strcatalogfruitsmulti_label": "Fruits",
  "tenExample:strcatalogfruitmulti_description": "Apple,Banana,Pear,Plum,Pineapple (multi)",
  "tenExample:tablenotice_label": "Notice",
  "tenExample:tablecreatedate_label": "Date",
  "tenExample:tableuser_label": "User",
  "tenExample:tablereadonly_label": "Write protection",
  "tenExample:tablenumber_label": "Number",
  "tenExample:tablenumberdigit_label": "Digit-number",
  "tenExample:tabledistance_label": "Distance",
  "tenExample:tabledistancedigit_label": "Digit-distance",
  "tenExample:tablecreatedatetime_label": "Datetime",
  "tenExample:tableemail_label": "Email",
  "tenExample:tableurl_label": "URL",
  "tenExample:tablephone_label": "Phone",
  "tenExample:tablecatalog_label": "Catalog",
  "tenExample:tablereference_label": "Reference",
  "tenExample:simpleFields_label": "Simple Fields",
  "tenExample:classifications_label": "Classifications",
  "tenExample:number_label": "Number",
  "tenExample:number_description": "Will be filled via script",
  "tenExample:createdate_label": "Created",
  "tenExample:createdate_description": "Will be filled via script as well",
  "tenExample:notice_label": "Notice",
  "tenExample:notice_description": "To be filled by user",
  "tenExample:probability_label": "Probability",
  "tenExample:probability_description": "To be filled by user as well",
  "tenExample:readonly_label": "Read-only",
  "tenExample:readonly_description": "It's still unclear who will do it ...",
  "tenExample:required_label": "Mandatory fields",
  "tenExample:notrequired_label": "Without obligation",
  "tenExample:tableGroup_label": "Table group",
  "tenExample:tableFilling_label": "Table filling",
  "tenExample:process_label": "Approval process",
  "tenExample:process:0_label": "Draft in work",
  "tenExample:process:1_label": "Draft in review",
  "tenExample:process:2_label": "Draft in rework",
  "tenExample:process:3_label": "Document ready",
  "tenExample:process:4_label": "Approved",
  "tenExample:process:5_label": "Rejected",
  "tenExample:datetimemulti_label": "Date & time ",
  "tenExample:datetimemulti_description": "unlimited",
  "tenExample:strcatalogfruitmulti_label": "Fruits",
  "tenExample:strcatalogfruitsmulti_description": "Apple,Banana,Pear,Plum,Pineapple (multi)",
  "tenExample:Table Group_label": "My group",
  "twosteptest_proc_label": "Two step process",
  "twosteptest_proc:2nd_task": "Second task",
  "twosteptest_proc:simplefields_label": "Simple fields",
  "twosteptest_proc:complexfields_label": "Complex fields",
  "twosteptest_proc:datetime_label": "Date & time",
  "twosteptest_proc:date_label": "Date only",
  "twosteptest_proc:boolean_label": "boolean",
  "twosteptest_proc:integer_label": "Integer",
  "twosteptest_proc:decimal_label": "Decimal",
  "twosteptest_proc:string_label": "String",
  "twosteptest_proc:stringmultirow_label": "Multi-row string ",
  "twosteptest_proc:email_label": "Email",
  "twosteptest_proc:phone_label": "Phone",
  "twosteptest_proc:url_label": "URL",
  "twosteptest_proc:user_label": "User",
  "twosteptest_proc:reference_label": "Reference",
  "twosteptest_proc:catalogcustom_label": "Custom catalog",
  "twosteptest_proc:test_table_label": "Notices",
  "twosteptest_proc:test_table_description": "List of notices",
  "twosteptest_proc:column_string_label": "Notice",
  "twosteptest_proc:column_date_label": "Date",
  "twosteptest_proc:column_user_label": "User",
  "twosteptest_proc:column_boolean_label": "Editable",
  "userGroupAssignment:user_label": "User",
  "userGroupAssignment:user_description": "Assign the user who should ...",
  "userGroupAssignment:comment_label": "Comment",
  "userGroupAssignment:comment_description": "Tell the user what to do .."
}
POST /api-web/api/resources/text/{locale} - Update the localized text resources for a specified locale.
As of version

2023 Winter

Request Method

POST

Response Format

HTTP status code

Required Permission

Available for users with the roles configured in api-web.technical-roles in the api-web-prod.yml configuration file. Default: YUUVIS_SYSTEM_INTEGRATOR and YUUVIS_TENANT_ADMIN

Description

This request updates a localized text resource for the specified locale. Additionally, via query parameter, the request can be executed EITHER for a specific tenant OR a specific app.

Optional query parameters:

Parameter Type Description

tenant

string

Tenant

app

string

App

Only one of the two query parameters can be set per request.

Response HTTP status codes:

HTTP status code Meaning

201

CREATED

400

No text resources were specified.

Request Example

https://<host>/api-web/api/resources/text/de

Request Body
{
  "system:baseTypeId_label": "Basistype ID",
  "system:objectTypeId_label": "Object-type ID",
  "system:createdBy_label": "Creator",
  "system:creationDate_label": "Created on",
  "system:lastModifiedBy_label": "Editor",
  "system:lastModificationDate_label": "Edited on",
  "system:versionNumber_label": "Version",
  "system:contentStreamLength_label": "File size",
  "system:contentStreamMimeType_label": "File type",
  "system:contentStreamFileName_label": "File name",
  "system:contentStreamId_label": "Content ID",
  "system:contentStreamRange_label": "Content range",
  "system:contentStreamRepositoryId_label": "Content stream repository",
  "system:digest_label": "Digest",
  "system:archivePath_label": "Archive path",
  "system:rmExpirationDate_label": "Retention date",
  "system:rmStartOfRetention_label": "Retention start",
  "system:rmDestructionDate_label": "Destruction date",
  "system:rmDestructionRetention_label": "Retention",
  "system:parentVersionNumber_label": "Folder version",
  "follow-up_label": "Follow-up",
  "follow-up_description": "This is a reminder to react on this object.",
  "review_label": "Review",
  "twosteptest_proc_label": "Two step process",
  "twosteptest_proc_description": "This little process tests task forms",
  "1st_task_label": "First task",
  "1st_task_description": "With this first task, a draft is to be prepared.",
  "2nd_task_label": "Second task",
  "2nd_task_description": "With this second task, the design is to be reviewed.",
  "appClient_label": "Client standards",
  "appClient:minidoc_label": "Smallest document",
  "appClient:minidoc_description": "01 Across all",
  "appClient:clientdefaults_label": "Object header",
  "appClient:clienttitle_label": "Name",
  "appClient:clientdescription_label": "Description",
  "appClientsystem:leadingType_label": "Leading object-type",
  "appClientsystem:leadingTypeId_label": "Type",
  "appClient:titledescription_label": "Name & Description",
  "appAcl:aclowner_label": "Access list",
  "appAcl:acl_label": "Access list",
  "appEmail_label": "Email (exchange)",
  "appEmail:email_label": "Email (exchange)",
  "appEmail:email_description": "01 Across all",
  "appEmail:from_label": "from",
  "appEmail:to_label": "to",
  "appEmail:cc_label": "cc",
  "appEmail:bcc_label": "bcc",
  "appEmail:subject_label": "Subject",
  "appEmail:attachmentcount_label": "Attachments",
  "appEmail:attachmentnames_label": "Attachment names",
  "appEmail:received_label": "Receive date",
  "appEmail:exchangeid_label": "Exchange ID",
  "appEmail:messageid_label": "Message ID",
  "appEmail:mode_label": "Mode",
  "appEmail:maildigest_label": "Email digest",
  "appEmail:meta_label": "Meta",
  "appEmail:datagroup_label": "Email data",
  "appInvoice_label": "Invoice processing",
  "appInvoice:zipreinvoice_label": "Invoice (general)",
  "appInvoice:zipreinvoice_description": "07 Invoice Management",
  "appInvoice:ziinvoicesot_label": "Invoice (ZUGFeRD)",
  "appInvoice:ziinvoicesot_description": "07 Invoice Management",
  "appInvoice:ziId_label": "Document ID",
  "appInvoice:ziName_label": "Document name",
  "appInvoice:ziTypeCode_label": "Type code",
  "appInvoice:ziPaymentReference_label": "Payment reference",
  "appInvoice:ziIssueDateTime_label": "Issue date",
  "appInvoice:ziDeliveryOccurence_label": "Delivery occurence",
  "appInvoice:ziDeliveryNoteId_label": "Delivery note ID",
  "appInvoice:ziDeliveryNoteDate_label": "Delivery note date",
  "appInvoice:ziOrderNoteId_label": "Order number",
  "appInvoice:ziOrderNoteDate_label": "Order date",
  "appInvoice:ziNotes_label": "Notes",
  "appInvoice:ziSellerId_label": "Seller ID",
  "appclient:dlm:prepare:0_label": "prepared",
  "appclient:dlm:prepare:1_label": "finished",
  "doctableofnotices_label": "DocTabelOfNotice",
  "tablecatalog_label": "Static catalog",
  "tablecreatedate_label": "Date",
  "tablecreatedatetime_label": "DateTime",
  "tabledistance_label": "Distance",
  "tabledistancedigit_label": "Distance digit",
  "tableemail_label": "Email",
  "tablenotice_label": "Notice",
  "tablenumber_label": "Number",
  "tablenumberdigit_label": "Number digit",
  "tableofnotices_label": "Table of notices",
  "tablephone_label": "Phone",
  "tablereadonly_label": "Boolean",
  "tablereference_label": "Reference",
  "tableurl_label": "URL",
  "tableuser_label": "User",
  "doctableofnotices_description": "01 Across all",
  "Table Group_label": "Meine Gruppe",
  "system:secondary_bale": "Alle sekundären Documente",
  "appInvoice:ziBuyerCity_label_label": "Stadt",
  "system:objectId_description": null,
  "system:baseTypeId_description": null,
  "system:objectTypeId_description": null,
  "system:secondaryObjectTypeIds_description": null,
  "system:createdBy_description": null,
  "system:creationDate_description": null,
  "system:lastModifiedBy_description": null,
  "system:lastModificationDate_description": null,
  "system:parentId_description": null,
  "system:parentObjectTypeId_description": null,
  "system:versionNumber_description": null,
  "system:tenant_description": null,
  "system:traceId_description": null,
  "system:tags_description": null,
  "system:contentStreamLength_description": null,
  "system:contentStreamMimeType_description": null,
  "system:contentStreamFileName_description": null,
  "system:contentStreamId_description": null,
  "system:contentStreamRange_description": null,
  "system:contentStreamRepositoryId_description": null,
  "system:digest_description": null,
  "system:archivePath_description": null,
  "system:rmExpirationDate_description": null,
  "system:rmStartOfRetention_description": null,
  "system:rmDestructionDate_description": null,
  "testsubject_label": null,
  "testsubject_description": null,
  "from_description": null,
  "to_description": null,
  "cc_description": null,
  "subject_description": null,
  "attachmentcount_description": null,
  "hasattachment_description": null,
  "attachmentnames_description": null,
  "received_description": null,
  "extract_label": "extract",
  "extract_description": null,
  "notice_description": null,
  "tableofnotices_description": null,
  "appClientcatalogs:catalogname_label": "Catalog name",
  "appClientcatalogs:catalogname_description": null,
  "appClientcatalogs:catalogvalue_label": "Catalog value",
  "appClientcatalogs:catalogvalue_description": null,
  "appClientcatalogs:active_label": "active",
  "appClientcatalogs_label": "Catalogs",
  "appClientcatalogs:active_description": null,
  "appClientcatalogs:catalogs_label": "Catalogs",
  "appClientcatalogs:catalogs_description": "01 Across all",
  "appClientcatalogs:lables_label": null,
  "appClientcatalogs:lables_description": null,
  "appClientcatalogs:labels_label": "Labels"
}
Response Example

201 CREATED

no response body

DELETE /api-web/api/resources/text/{locale} - Delete the localized text resources for a specified locale.
As of version

2023 Winter

Request Method

DELETE

Response Format

HTTP status code

Required Permission

Available for users with the roles configured in api-web.technical-roles in the api-web-prod.yml configuration file. Default: YUUVIS_SYSTEM_INTEGRATOR and YUUVIS_TENANT_ADMIN

Description

This request deletes a localized text resource for the specified locale. Additionally, via query parameter, the request can be executed EITHER for a specific tenant OR a specific app.

Optional query parameters:

Parameter Type Description

tenant

string

Tenant

app

string

App

Only one of the two query parameters can be set per request.

Response HTTP status codes:

HTTP status code Meaning

200

OK

404

No text resources were found.

Request Example

https://<host>/api-web/api/resources/text/de

no request body

Response Example

200 OK

PATCH /api-web/api/resources/text/{locale} - Update parts of the localized text resources for a specified locale.
As of Version

2024 Summer

Request Method

PATCH

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN and YUUVIS_SYSTEM_INTEGRATOR roles.

Description

Updates the localization resource specified by locale with the data in the JSON request body. Only the keys specified in the request body are updated. All further keys remain unchanged.

Optional query parameters:

tenant string Specify a tenant name for which you want to update the tenant-specific localization file.

app

string

Specify an app name for which you want to update the app-specific localization file.

If neither app nor tenant is specified, the global localization file will be updated.

Response HTTP status codes:

HTTP status code Meaning

202

Accepted

400

No text resources were specified.

404

No text resources were found for update.

Request Example

https://<host>/api-web/api/resources/text/en

Request Body
{
  "tenExample:betreff_label": "Subject",
  "tenExample:strregextime_label": "Time",
  "tenExample:strregextime_description": "Time format is 24 hours with hh:mm",
  "tenExample:strcataloggermancountries_label": "German countries"
}
Response Example

200 OK

Response Body
{
  "tenExample:betreff_label": "Subject",
  "tenExample:betreff_description": null,
  "tenExample:strsingle_label": "String",
  "tenExample:strsingle_description": "unlimited",
  "tenExample:strregextime_label": "Time",
  "tenExample:strregextime_description": "Time format is 24 hours with hh:mm",
  "tenExample:strcataloggermancountries_label": "German countries",
  "tenExample:strcataloggermancountries_description": "single-field",
  "tenExample:strcataloggermancountriesro_label": "German countries",
  "tenExample:strcataloggermancountriesro_description": "single-field, read-only",
  "tenExample:intsingle_label": "Integer",
  "tenExample:intsingle_description": "unlimited",
  "tenExample:intsingledigit_label": "Integer",
  "tenExample:intsingledigit_description": "digit grouping",
  "tenExample:decsingle_label": "Decimal",
  "tenExample:decsingle_description": "unlimited",
  "tenExample:decsingledigit_label": "Decimal",
  "tenExample:decsingledigit_description": "digit grouping",
  "tenExample:datetimesingle_label": "Date & time",
  "tenExample:datetimesingle_description": "unlimited",
  "tenExample:datetimesinglerequired_label": "Date & time",
  "tenExample:datetimesinglerequired_description": "mandatory",
  "tenExample:datesingle_label": "Date2",
  "tenExample:datesingle_description": "unlimited",
  "tenExample:datesinglerequired_label": "Date1",
  "tenExample:datesinglerequired_description": "mandatory",
  "tenExample:booleanrequiredtrue_label": "Boolean",
  "tenExample:booleanrequiredtrue_description": "mandatory",
  "tenExample:booleannull_label": "Boolean Tri-State",
  "tenExample:booleannull_description": "Null allowed",
  "tenExample:extract2_label": "Extract & map",
  "tenExample:tablesimplefields_label": "Simple fields",
  "tenExample:tablesimplefields_description": "Table with simple fields",
  "tenExample:tableclassifications_label": "Fields with classifications",
  "tenExample:tableclassifications_description": "Table with classification fields",
  "tenExample:strorganizationsingle_label": "User/Group",
  "tenExample:strorganizationmulti_label": "Users/Groups",
  "tenExample:strcatalogfruitsmulti_label": "Fruits",
  "tenExample:strcatalogfruitmulti_description": "Apple,Banana,Pear,Plum,Pineapple (multi)",
  "tenExample:tablenotice_label": "Notice",
  "tenExample:tablecreatedate_label": "Date",
  "tenExample:tableuser_label": "User",
  "tenExample:tablereadonly_label": "Write protection",
  "tenExample:tablenumber_label": "Number",
  "tenExample:tablenumberdigit_label": "Digit-number",
  "tenExample:tabledistance_label": "Distance",
  "tenExample:tabledistancedigit_label": "Digit-distance",
  "tenExample:tablecreatedatetime_label": "Datetime",
  "tenExample:tableemail_label": "Email",
  "tenExample:tableurl_label": "URL",
  "tenExample:tablephone_label": "Phone",
  "tenExample:tablecatalog_label": "Catalog",
  "tenExample:tablereference_label": "Reference",
  "tenExample:simpleFields_label": "Simple Fields",
  "tenExample:classifications_label": "Classifications",
  "tenExample:number_label": "Number",
  "tenExample:number_description": "Will be filled via script",
  "tenExample:createdate_label": "Created",
  "tenExample:createdate_description": "Will be filled via script as well",
  "tenExample:notice_label": "Notice",
  "tenExample:notice_description": "To be filled by user",
  "tenExample:probability_label": "Probability",
  "tenExample:probability_description": "To be filled by user as well",
  "tenExample:readonly_label": "Read-only",
  "tenExample:readonly_description": "It's still unclear who will do it ...",
  "tenExample:required_label": "Mandatory fields",
  "tenExample:notrequired_label": "Without obligation",
  "tenExample:tableGroup_label": "Table group",
  "tenExample:tableFilling_label": "Table filling",
  "tenExample:process_label": "Approval process",
  "tenExample:process:0_label": "Draft in work",
  "tenExample:process:1_label": "Draft in review",
  "tenExample:process:2_label": "Draft in rework",
  "tenExample:process:3_label": "Document ready",
  "tenExample:process:4_label": "Approved",
  "tenExample:process:5_label": "Rejected",
  "tenExample:datetimemulti_label": "Date & time ",
  "tenExample:datetimemulti_description": "unlimited",
  "tenExample:strcatalogfruitmulti_label": "Fruits",
  "tenExample:strcatalogfruitsmulti_description": "Apple,Banana,Pear,Plum,Pineapple (multi)",
  "tenExample:Table Group_label": "My group",
  "twosteptest_proc_label": "Two step process",
  "twosteptest_proc:2nd_task": "Second task",
  "twosteptest_proc:simplefields_label": "Simple fields",
  "twosteptest_proc:complexfields_label": "Complex fields",
  "twosteptest_proc:datetime_label": "Date & time",
  "twosteptest_proc:date_label": "Date only",
  "twosteptest_proc:boolean_label": "boolean",
  "twosteptest_proc:integer_label": "Integer",
  "twosteptest_proc:decimal_label": "Decimal",
  "twosteptest_proc:string_label": "String",
  "twosteptest_proc:stringmultirow_label": "Multi-row string ",
  "twosteptest_proc:email_label": "Email",
  "twosteptest_proc:phone_label": "Phone",
  "twosteptest_proc:url_label": "URL",
  "twosteptest_proc:user_label": "User",
  "twosteptest_proc:reference_label": "Reference",
  "twosteptest_proc:catalogcustom_label": "Custom catalog",
  "twosteptest_proc:test_table_label": "Notices",
  "twosteptest_proc:test_table_description": "List of notices",
  "twosteptest_proc:column_string_label": "Notice",
  "twosteptest_proc:column_date_label": "Date",
  "twosteptest_proc:column_user_label": "User",
  "twosteptest_proc:column_boolean_label": "Editable",
  "userGroupAssignment:user_label": "User",
  "userGroupAssignment:user_description": "Assign the user who should ...",
  "userGroupAssignment:comment_label": "Comment",
  "userGroupAssignment:comment_description": "Tell the user what to do .."
}
system-controller

Endpoints of the Web API gateway for the management of global configuration data, accessible with the role specified for /api-web/api/system/** endpoints in the authentication-prod.yml configuration file.

The endpoints are used by yuuvis® architect. If you want to use this service, do not change the default access condition that is matched with the YUUVIS_SYSTEM_INTEGRATOR role.
GET /api-web/api/system/dms/catalogs - Retrieve all catalog names.
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Retrieves the technical names of all catalogs grouped in lists depending on their global, app-specific or tenant-specific storage location.

Optional query parameters:

Parameter Type Description

tenant

string

Retrieve only the catalogs available for the specified tenant.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

500

Internal Server Error

Request Example

https://<host>/api-web/api/system/dms/catalogs

no request body

Response Example

200 OK

Response Body
{
  "personalfile": [
    "appPersonalfile:class"
  ],
  "global": [
    "germancountry",
    "contracts",
    "germancountries",
    "globalnotice",
    "currency",
    "class",
    "clubs",
    "food",
  ],
  "invoice": [
    "appInvoice:type"
  ],
  "mytenant": [
    "germancountry",
    "contracts",
    "tenMytenant:My catalog",
    "germancountries",
    "globalnotice",
    "currency",
    "class",
    "appInvoice:type",
    "tenMytenant:processstatus",
    "appPersonalfile:class"
  ]
}
GET /api-web/api/system/dms/catalogs/{qname} - Retrieve the specified catalog.
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Retrieves the global or app-specific catalog specified by its name qname

The endpoint returns null if no catalog with qname was found in both global and app-specific resource.

Optional query parameters:

Parameter Type Description

tenant

string

Retrieve the tenant-specific catalog instead of the global or app-specific one.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not Found

Request Example

https://<host>/api-web/api/system/dms/catalogs/appInvoice:type

no request body

Response Example

200 OK

Response Body
{
  "tenant": "mytenant",
  "readonly": false,
  "entries": [
    {
      "name": "Employment contract",
      "disabled": false
    },
    {
      "name": "Rental agreement",
      "disabled": false
    },
    {
      "name": "User contract",
      "disabled": false
    },
    {
      "name": "Purchase contract",
      "disabled": true
    }
  ]
}
POST /api-web/api/system/dms/catalogs/{qname} - Create or update the specified catalog.
As of Version

2021 Summer

Request Method

POST

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Updates the global or app-specific catalog identified by its name qname with the data passed in JSON format in the request body.

If no global or app-specific catalog with name qname is available, it will be created.

The response body is a JSON structure with the list errors containing possibly occured error messages, and the boolean valid that is true for a successfully validated JSON in the request body.

Optional query parameters:

Parameter Type Description

tenant

string

Update the tenant-specific catalog instead of the global or app-specific one.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

401

Unauthorized

403

Forbidden

Request Example

https://<host>/api-web/api/system/dms/catalogs/processstatus?tenant=mytenant

Request Body
{
  "tenant": "mytenant",
  "readonly": false,
  "entries": [
    {
      "name": "Employment contract",
      "disabled": false
    },
    {
      "name": "Rental agreement",
      "disabled": false
    },
    {
      "name": "User contract",
      "disabled": false
    },
    {
      "name": "Purchase contract",
      "disabled": true
    }
  ]
}
Response Example

200 OK

Response Body
{
  "errors": [],
  "valid": true
}
PATCH /api-web/api/system/dms/catalogs/{qname} - Update the specified catalog.
As of Version

2021 Summer

Request Method

PATCH

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Updates the existing global or app-specific catalog identified by its name qname, with the data passed in JSON format in the request body.

In the response body, the modified catalog will be returned.

If no global or app-specific catalog with name qname is available, an error will be thrown.

Optional query parameters:

Parameter Type Description

tenant

string

Update the tenant-specific catalog instead of the global or app-specific one.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

403

Forbidden

404

Not Found

500

Internal Server Error

Request Example

https://<host>/api-web/api/system/dms/catalogs/contracts?tenant=mytenant

Request Body
[
  {
    "op": "replace",
    "path": "/entries/1/name",
    "value": "Rental agreement"
  },
  {
    "op": "remove",
    "path": "/entries/3"
  },
  {
    "op": "add",
    "path": "/entries/-",
    "value": {
      "name": "Purchase contract",
      "disabled": true
    }
  }
]
Response Example

200 OK

Response Body
{
  "tenant": "mytenant",
  "readonly": false,
  "entries": [
    {
      "name": "Employment contract",
      "disabled": false
    },
    {
      "name": "Rental agreement",
      "disabled": false
    },
    {
      "name": "User contract",
      "disabled": false
    },
    {
      "name": "Purchase contract",
      "disabled": true
    }
  ]
}
deprecated as of 2023 Winter: GET /api-web/api/system/dms/forms/{objecttype} - Retrieve a metadata form for the specified object type.
Deprecated as of 2023 Winter. Please use GET /api-web/api/resources/forms/{type}.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Retrieves the global or app-specific non-enriched form by object type ID objecttype and optional query parameters situation and sots (secondary object types).

Behind the object type ID, add the query parameter situation=CREATE (situation=EDIT) to retrieve the CREATE (EDIT) form. Default is EDIT. Furthermore, add sots=<objectTypeId> in order to specify a secondary object type of which properties should be included in the retrieved form. The sots query parameter can be added multiple times for different secondary object types.

Returns null if there is no designed form model for the given object type.

Optional query parameters:

Parameter Type Description

situation

string

The situation the form is used. (default: EDIT)

sots

list of strings

List of the secondary object types

tenant

string

Retrieve the tenant-specific form instead of the global one.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/api-web/api/system/dms/forms/qadocscripts?tenant=mytenant&situation=EDIT&sots=examplesot1&sot=examplesot2

no request body

Response Example

200 OK

Response Body
{
  "name": "tenMytenant:qadocscripts",
  "situation": "EDIT",
  "script": "any valid script",
  "elements": [
    {
      "name": "core",
      "type": "o2mGroup",
      "layout": {
        "align": "column"
      },
      "elements": [
        {
          "name": "appClient:clienttitle",
          "type": "string",
          "rows": 1
        },
        {
          "name": "appClient:clientdescription",
          "type": "string",
          "rows": 1
        }
      ]
    },
    {
      "name": "data",
      "type": "o2mGroupStack",
      "elements": [
        {
          "type": "o2mGroup",
          "layout": {
            "align": "column"
          },
          "elements": [
            {
              "type": "o2mGroup",
              "layout": {
                "align": "row"
              },
              "elements": [
                {
                  "type": "o2mGroup",
                  "layout": {
                    "align": "row"
                  },
                  "elements": [
                    {
                      "name": "tenMytenant:strsingle",
                      "type": "string",
                      "rows": 1
                    },
                    {
                      "name": "tenMytenant:strsinglemail",
                      "type": "string",
                      "rows": 1
                    }
                  ]
                },
                {
                  "type": "o2mGroup",
                  "layout": {
                    "align": "row"
                  },
                  "elements": [
                    {
                      "name": "tenMytenant:intsingle",
                      "type": "integer"
                    },
                    {
                      "name": "tenMytenant:intsingledigit",
                      "type": "integer"
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
deprecated as of 2023 Winter: POST /api-web/api/system/dms/forms/{objecttype} - Update a metadata form for the specified object type.
Deprecated as of 2023 Winter. Please use POST /api-web/api/resources/forms/{type}.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Retrieves the global or app-specific non-enriched form by object type ID objecttype and optional query parameters situation and sots (secondary object types).

Behind the object type ID, add the query parameter sots=<objectTypeId> in order to specify a secondary object type of which properties should be included in the retrieved form. The sots query parameter can be added multiple times for different secondary object types, separated by & characters.

Optional query parameters:

Parameter Type Description

situation

string

The situation the form is used. (default: EDIT)

sots

list of strings

List of the secondary object types. Individual values are separated by a & character.

tenant

string

Update the tenant-specific form instead of the global or app-specific one.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/api-web/api/system/dms/forms/qadocscripts?tenant=mytenant&situation=EDIT&sots=examplesot1&sot=examplesot2

no request body

Response Example

200 OK

Response Body
{
  "name": "tenMytenant:qadocscripts",
  "situation": "EDIT",
  "script": "any valid script",
  "elements": [
    {
      "name": "core",
      "type": "o2mGroup",
      "layout": {
        "align": "column"
      },
      "elements": [
        {
          "name": "appClient:clienttitle",
          "type": "string",
          "rows": 1
        },
        {
          "name": "appClient:clientdescription",
          "type": "string",
          "rows": 1
        }
      ]
    },
    {
      "name": "data",
      "type": "o2mGroupStack",
      "elements": [
        {
          "type": "o2mGroup",
          "layout": {
            "align": "column"
          },
          "elements": [
            {
              "type": "o2mGroup",
              "layout": {
                "align": "row"
              },
              "elements": [
                {
                  "type": "o2mGroup",
                  "layout": {
                    "align": "row"
                  },
                  "elements": [
                    {
                      "name": "tenMytenant:strsingle",
                      "type": "string",
                      "rows": 1
                    },
                    {
                      "name": "tenMytenant:strsinglemail",
                      "type": "string",
                      "rows": 1
                    }
                  ]
                },
                {
                  "type": "o2mGroup",
                  "layout": {
                    "align": "row"
                  },
                  "elements": [
                    {
                      "name": "tenMytenant:intsingle",
                      "type": "integer"
                    },
                    {
                      "name": "tenMytenant:intsingledigit",
                      "type": "integer"
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
deprecated as of 2023 Winter: GET /api-web/api/system/resources/config/{name} - Retrieve the specified configuration.
Deprecated as of 2023 Winter. Please use GET /api-web/api/resources/config/{name}.
As of Version

2020 Autumn

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Retrieves the global configuration file specified by name.

Optional query parameters:

Parameter Type Description

tenant

string

Retrieve the tenant-specific configuration instead of the global one.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

deprecated as of 2023 Winter: POST /api-web/api/system/resources/config/{name} - Update the specified configuration.
Deprecated as of 2023 Winter. Please use POST /api-web/api/resources/config/{name}.
As of Version

2020 Autumn

Request Method

POST

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Creates or updates the global configuration file specified by name with the data passed in JSON format in the request body.

Optional query parameters:

Parameter Type Description

tenant

string

Update the tenant-specific configuration instead of the global one.

Response HTTP status codes:

HTTP status code Meaning

201

CREATED

401

Unauthorized

deprecated as of 2023 Winter: GET /api-web/api/system/resources/icons/{path} - Retrieve a specified icon.
Deprecated as of 2023 Winter. Please use GET /api-web/api/resources/icons/{path}.
As of Version

2020 Winter

Request Method

GET

Response Format

SVG

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Retrieves a global, app-specific, or tenant-specific icon resource specified by path as SVG image.

Such icon endpoints are also available in the admin-controller and system-controller. They are intended to serve for the configuration of object type icons. Use the technical name of the corresponding object type as value for path.

Optional query parameters:

Parameter Type Description

tenant

string

Retrieve the tenant-specific icon instead of the global one.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

deprecated as of 2023 Winter: POST /api-web/api/system/resources/icons/{path} - Update a specified icon
Deprecated as of 2023 Winter. Please use POST /api-web/api/resources/icons/{type}.
As of Version

2020 Winter

Request Method

POST

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Creates or updates the global or app-specific icon resource specified by path with the data passed as SVG image in a multipart request body.

Such icon endpoints are also available in the admin-controller and resource-controller. They are intended to serve for the configuration of object type icons. Use the technical name of the corresponding object type as a value for path, e.g. tenMytenant:Invoice or appMyapp:Contract.

These defined icons are global ones. If not other icons are saved via the admin endpoint for the specific tenant the global icons are delivered with the corresponding resources endpoint.

Optional query parameters:

Parameter Type Description

tenant

string

Update the tenant-specific icon instead of the global one.

Response HTTP status codes:

HTTP status code Meaning

201

CREATED

400

No icon was specified.

401

Unauthorized

deprecated as of 2023 Winter: GET /api-web/api/system/resources/text - Retrieve localized text resources.
Deprecated as of 2023 Winter. Please use GET /api-web/api/resources/text.
As of Version

2020 Winter

Request Method

GET

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Retrieves global localized text resources for the Accept-Language specified in the request header formatted in ISO norm (e.g., de, en, es, fr, …​)

The response body is a JSON structure where each technical term as a key is mapped to a string value that will occur as a localized term in the graphical user interface.

Each technical term consists of a field identification (e.g., twosteptest_proc:test_table) followed by either _label or _description in order to be displayed as field label or field description in the graphical user interface.

If a technical term is mapped to null, localization has not yet been applied. The field identification will be displayed as field label in the graphical user interface. A description will not be provided.

Optional query parameters:

Parameter Type Description

tenant

string

Retrieve the tenant-specific text resources instead of the global one.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

https://<host>/api-web/api/system/resources/text

no request body

Response Example

200 OK

Response Body
{
  "system:baseTypeId_label": "Basistype ID",
  "system:objectTypeId_label": "Object-type ID",
  "system:createdBy_label": "Creator",
  "system:creationDate_label": "Created on",
  "system:lastModifiedBy_label": "Editor",
  "system:lastModificationDate_label": "Edited on",
  "system:versionNumber_label": "Version",
  "system:contentStreamLength_label": "File size",
  "system:contentStreamMimeType_label": "File type",
  "system:contentStreamFileName_label": "File name",
  "system:contentStreamId_label": "Content ID",
  "system:contentStreamRange_label": "Content range",
  "system:contentStreamRepositoryId_label": "Content stream repository",
  "system:digest_label": "Digest",
  "system:archivePath_label": "Archive path",
  "system:rmExpirationDate_label": "Retention date",
  "system:rmStartOfRetention_label": "Retention start",
  "system:rmDestructionDate_label": "Destruction date",
  "system:rmDestructionRetention_label": "Retention",
  "system:parentVersionNumber_label": "Folder version",
  "follow-up_label": "Follow-up",
  "follow-up_description": "This is a reminder to react on this object.",
  "review_label": "Review",
  "twosteptest_proc_label": "Two step process",
  "twosteptest_proc_description": "This little process tests task forms",
  "1st_task_label": "First task",
  "1st_task_description": "With this first task, a draft is to be prepared.",
  "2nd_task_label": "Second task",
  "2nd_task_description": "With this second task, the design is to be reviewed.",
  "appClient_label": "Client standards",
  "appClient:minidoc_label": "Smallest document",
  "appClient:minidoc_description": "01 Across all",
  "appClient:clientdefaults_label": "Object header",
  "appClient:clienttitle_label": "Name",
  "appClient:clientdescription_label": "Description",
  "appClientsystem:leadingType_label": "Leading object-type",
  "appClientsystem:leadingTypeId_label": "Type",
  "appClient:titledescription_label": "Name & Description",
  "appAcl:aclowner_label": "Access list",
  "appAcl:acl_label": "Access list",
  "appEmail_label": "Email (exchange)",
  "appEmail:email_label": "Email (exchange)",
  "appEmail:email_description": "01 Across all",
  "appEmail:from_label": "from",
  "appEmail:to_label": "to",
  "appEmail:cc_label": "cc",
  "appEmail:bcc_label": "bcc",
  "appEmail:subject_label": "Subject",
  "appEmail:attachmentcount_label": "Attachments",
  "appEmail:attachmentnames_label": "Attachment names",
  "appEmail:received_label": "Receive date",
  "appEmail:exchangeid_label": "Exchange ID",
  "appEmail:messageid_label": "Message ID",
  "appEmail:mode_label": "Mode",
  "appEmail:maildigest_label": "Email digest",
  "appEmail:meta_label": "Meta",
  "appEmail:datagroup_label": "Email data",
  "appInvoice_label": "Invoice processing",
  "appInvoice:zipreinvoice_label": "Invoice (general)",
  "appInvoice:zipreinvoice_description": "07 Invoice Management",
  "appInvoice:ziinvoicesot_label": "Invoice (ZUGFeRD)",
  "appInvoice:ziinvoicesot_description": "07 Invoice Management",
  "appInvoice:ziId_label": "Document ID",
  "appInvoice:ziName_label": "Document name",
  "appInvoice:ziTypeCode_label": "Type code",
  "appInvoice:ziPaymentReference_label": "Payment reference",
  "appInvoice:ziIssueDateTime_label": "Issue date",
  "appInvoice:ziDeliveryOccurence_label": "Delivery occurence",
  "appInvoice:ziDeliveryNoteId_label": "Delivery note ID",
  "appInvoice:ziDeliveryNoteDate_label": "Delivery note date",
  "appInvoice:ziOrderNoteId_label": "Order number",
  "appInvoice:ziOrderNoteDate_label": "Order date",
  "appInvoice:ziNotes_label": "Notes",
  "appInvoice:ziSellerId_label": "Seller ID",
  "appclient:dlm:prepare:0_label": "prepared",
  "appclient:dlm:prepare:1_label": "finished",
  "doctableofnotices_label": "DocTabelOfNotice",
  "tablecatalog_label": "Static catalog",
  "tablecreatedate_label": "Date",
  "tablecreatedatetime_label": "DateTime",
  "tabledistance_label": "Distance",
  "tabledistancedigit_label": "Distance digit",
  "tableemail_label": "Email",
  "tablenotice_label": "Notice",
  "tablenumber_label": "Number",
  "tablenumberdigit_label": "Number digit",
  "tableofnotices_label": "Table of notices",
  "tablephone_label": "Phone",
  "tablereadonly_label": "Boolean",
  "tablereference_label": "Reference",
  "tableurl_label": "URL",
  "tableuser_label": "User",
  "doctableofnotices_description": "01 Across all",
  "Table Group_label": "Meine Gruppe",
  "system:secondary_bale": "Alle sekundären Documente",
  "appInvoice:ziBuyerCity_label_label": "Stadt",
  "system:objectId_description": null,
  "system:baseTypeId_description": null,
  "system:objectTypeId_description": null,
  "system:secondaryObjectTypeIds_description": null,
  "system:createdBy_description": null,
  "system:creationDate_description": null,
  "system:lastModifiedBy_description": null,
  "system:lastModificationDate_description": null,
  "system:parentId_description": null,
  "system:parentObjectTypeId_description": null,
  "system:versionNumber_description": null,
  "system:tenant_description": null,
  "system:traceId_description": null,
  "system:tags_description": null,
  "system:contentStreamLength_description": null,
  "system:contentStreamMimeType_description": null,
  "system:contentStreamFileName_description": null,
  "system:contentStreamId_description": null,
  "system:contentStreamRange_description": null,
  "system:contentStreamRepositoryId_description": null,
  "system:digest_description": null,
  "system:archivePath_description": null,
  "system:rmExpirationDate_description": null,
  "system:rmStartOfRetention_description": null,
  "system:rmDestructionDate_description": null,
  "testsubject_label": null,
  "testsubject_description": null,
  "from_description": null,
  "to_description": null,
  "cc_description": null,
  "subject_description": null,
  "attachmentcount_description": null,
  "hasattachment_description": null,
  "attachmentnames_description": null,
  "received_description": null,
  "extract_label": "extract",
  "extract_description": null,
  "notice_description": null,
  "tableofnotices_description": null,
  "appClientcatalogs:catalogname_label": "Catalog name",
  "appClientcatalogs:catalogname_description": null,
  "appClientcatalogs:catalogvalue_label": "Catalog value",
  "appClientcatalogs:catalogvalue_description": null,
  "appClientcatalogs:active_label": "active",
  "appClientcatalogs_label": "Catalogs",
  "appClientcatalogs:active_description": null,
  "appClientcatalogs:catalogs_label": "Catalogs",
  "appClientcatalogs:catalogs_description": "01 Across all",
  "appClientcatalogs:lables_label": null,
  "appClientcatalogs:lables_description": null,
  "appClientcatalogs:labels_label": "Labels"
}
deprecated as of 2023 Winter: POST /api-web/api/system/resources/text/{locale} - Update localized text resources for the specified language.
Deprecated as of 2023 Winter. Please use POST /api-web/api/resources/text/{locale}.
As of Version

2020 Winter

Request Method

POST

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Creates or updates the global localized text resources for the active tenant and the specified locale formatted in ISO norm, e.g., de, en, es, fr, …​.

The request body is a JSON structure where each technical term as a key is mapped to a string value that will occur as a localized term in the graphical user interface.

Each technical term consists of a field identification (e.g., twosteptest_proc:test_table) followed by either _label or _description in order to be displayed as field label or field description in the graphical user interface.

If a technical term is mapped to null, localization has not yet been applied. The field identification will be displayed as field label in the graphical user interface. A description will not be provided.

Optional query parameters:

Parameter Type Description

tenant

string

Update the tenant-specific localized text resources instead of the global one.

Response HTTP status codes:

HTTP status code Meaning

201

CREATED

400

No text resources were specified.

401

Unauthorized

Request Example

https://<host>/api-web/api/system/resources/text/en

Request Body
{
  "system:baseTypeId_label": "Basistype ID",
  "system:objectTypeId_label": "Object-type ID",
  "system:createdBy_label": "Creator",
  "system:creationDate_label": "Created on",
  "system:lastModifiedBy_label": "Editor",
  "system:lastModificationDate_label": "Edited on",
  "system:versionNumber_label": "Version",
  "system:contentStreamLength_label": "File size",
  "system:contentStreamMimeType_label": "File type",
  "system:contentStreamFileName_label": "File name",
  "system:contentStreamId_label": "Content ID",
  "system:contentStreamRange_label": "Content range",
  "system:contentStreamRepositoryId_label": "Content stream repository",
  "system:digest_label": "Digest",
  "system:archivePath_label": "Archive path",
  "system:rmExpirationDate_label": "Retention date",
  "system:rmStartOfRetention_label": "Retention start",
  "system:rmDestructionDate_label": "Destruction date",
  "system:rmDestructionRetention_label": "Retention",
  "system:parentVersionNumber_label": "Folder version",
  "follow-up_label": "Follow-up",
  "follow-up_description": "This is a reminder to react on this object.",
  "review_label": "Review",
  "twosteptest_proc_label": "Two step process",
  "twosteptest_proc_description": "This little process tests task forms",
  "1st_task_label": "First task",
  "1st_task_description": "With this first task, a draft is to be prepared.",
  "2nd_task_label": "Second task",
  "2nd_task_description": "With this second task, the design is to be reviewed.",
  "appClient_label": "Client standards",
  "appClient:minidoc_label": "Smallest document",
  "appClient:minidoc_description": "01 Across all",
  "appClient:clientdefaults_label": "Object header",
  "appClient:clienttitle_label": "Name",
  "appClient:clientdescription_label": "Description",
  "appClientsystem:leadingType_label": "Leading object-type",
  "appClientsystem:leadingTypeId_label": "Type",
  "appClient:titledescription_label": "Name & Description",
  "appAcl:aclowner_label": "Access list",
  "appAcl:acl_label": "Access list",
  "appEmail_label": "Email (exchange)",
  "appEmail:email_label": "Email (exchange)",
  "appEmail:email_description": "01 Across all",
  "appEmail:from_label": "from",
  "appEmail:to_label": "to",
  "appEmail:cc_label": "cc",
  "appEmail:bcc_label": "bcc",
  "appEmail:subject_label": "Subject",
  "appEmail:attachmentcount_label": "Attachments",
  "appEmail:attachmentnames_label": "Attachment names",
  "appEmail:received_label": "Receive date",
  "appEmail:exchangeid_label": "Exchange ID",
  "appEmail:messageid_label": "Message ID",
  "appEmail:mode_label": "Mode",
  "appEmail:maildigest_label": "Email digest",
  "appEmail:meta_label": "Meta",
  "appEmail:datagroup_label": "Email data",
  "appInvoice_label": "Invoice processing",
  "appInvoice:zipreinvoice_label": "Invoice (general)",
  "appInvoice:zipreinvoice_description": "07 Invoice Management",
  "appInvoice:ziinvoicesot_label": "Invoice (ZUGFeRD)",
  "appInvoice:ziinvoicesot_description": "07 Invoice Management",
  "appInvoice:ziId_label": "Document ID",
  "appInvoice:ziName_label": "Document name",
  "appInvoice:ziTypeCode_label": "Type code",
  "appInvoice:ziPaymentReference_label": "Payment reference",
  "appInvoice:ziIssueDateTime_label": "Issue date",
  "appInvoice:ziDeliveryOccurence_label": "Delivery occurence",
  "appInvoice:ziDeliveryNoteId_label": "Delivery note ID",
  "appInvoice:ziDeliveryNoteDate_label": "Delivery note date",
  "appInvoice:ziOrderNoteId_label": "Order number",
  "appInvoice:ziOrderNoteDate_label": "Order date",
  "appInvoice:ziNotes_label": "Notes",
  "appInvoice:ziSellerId_label": "Seller ID",
  "appclient:dlm:prepare:0_label": "prepared",
  "appclient:dlm:prepare:1_label": "finished",
  "doctableofnotices_label": "DocTabelOfNotice",
  "tablecatalog_label": "Static catalog",
  "tablecreatedate_label": "Date",
  "tablecreatedatetime_label": "DateTime",
  "tabledistance_label": "Distance",
  "tabledistancedigit_label": "Distance digit",
  "tableemail_label": "Email",
  "tablenotice_label": "Notice",
  "tablenumber_label": "Number",
  "tablenumberdigit_label": "Number digit",
  "tableofnotices_label": "Table of notices",
  "tablephone_label": "Phone",
  "tablereadonly_label": "Boolean",
  "tablereference_label": "Reference",
  "tableurl_label": "URL",
  "tableuser_label": "User",
  "doctableofnotices_description": "01 Across all",
  "Table Group_label": "Meine Gruppe",
  "system:secondary_bale": "Alle sekundären Documente",
  "appInvoice:ziBuyerCity_label_label": "Stadt",
  "system:objectId_description": null,
  "system:baseTypeId_description": null,
  "system:objectTypeId_description": null,
  "system:secondaryObjectTypeIds_description": null,
  "system:createdBy_description": null,
  "system:creationDate_description": null,
  "system:lastModifiedBy_description": null,
  "system:lastModificationDate_description": null,
  "system:parentId_description": null,
  "system:parentObjectTypeId_description": null,
  "system:versionNumber_description": null,
  "system:tenant_description": null,
  "system:traceId_description": null,
  "system:tags_description": null,
  "system:contentStreamLength_description": null,
  "system:contentStreamMimeType_description": null,
  "system:contentStreamFileName_description": null,
  "system:contentStreamId_description": null,
  "system:contentStreamRange_description": null,
  "system:contentStreamRepositoryId_description": null,
  "system:digest_description": null,
  "system:archivePath_description": null,
  "system:rmExpirationDate_description": null,
  "system:rmStartOfRetention_description": null,
  "system:rmDestructionDate_description": null,
  "testsubject_label": null,
  "testsubject_description": null,
  "from_description": null,
  "to_description": null,
  "cc_description": null,
  "subject_description": null,
  "attachmentcount_description": null,
  "hasattachment_description": null,
  "attachmentnames_description": null,
  "received_description": null,
  "extract_label": "extract",
  "extract_description": null,
  "notice_description": null,
  "tableofnotices_description": null,
  "appClientcatalogs:catalogname_label": "Catalog name",
  "appClientcatalogs:catalogname_description": null,
  "appClientcatalogs:catalogvalue_label": "Catalog value",
  "appClientcatalogs:catalogvalue_description": null,
  "appClientcatalogs:active_label": "active",
  "appClientcatalogs_label": "Catalogs",
  "appClientcatalogs:active_description": null,
  "appClientcatalogs:catalogs_label": "Catalogs",
  "appClientcatalogs:catalogs_description": "01 Across all",
  "appClientcatalogs:lables_label": null,
  "appClientcatalogs:lables_description": null,
  "appClientcatalogs:labels_label": "Labels"
}
Response Example

201 CREATED

no response body

GET /api-web/api/system/resources/text/languages - Retrieve a list of supported languages.
As of Version

2020 Winter

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Retrieves a list of all supported languages for global resources.

Optional query parameters:

Parameter Type Description

tenant

string

Retrieve the supported languages for the specified tenant instead of the global ones.

Response HTTP status codes:

HTTP status code Meaning

200

OK

201

OK

401

Unauthorized

Request Example

https://<host>/api-web/api/system/resources/text/languages

no request body

Response Example

200 OK

Response Body
[
  "fr",
  "en",
  "it",
  "pt",
  "es",
  "de",
  "ru",
  "sv"
]
user-controller

Endpoints for user settings management, accessible for any authenticated user.

The userservice API is required.
GET /api-web/api/users/config/result/{type} - Retrieve the result list configuration for the logged-in user.
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Description

Returns a result list configuration by type.

Optional query parameters:

Parameter Type Description

sots

list of string

List of secondary object types.

fallback

string

Name of the fallback object type.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad request

401

Unauthorized

Request Example

https://<host>/api-web/api/users/config/result/mytype

no request body

Response Example

200 OK

Response Body
{
  "type": "string",
  "isDefault": true,
  "columns": [
    {
      "id": "string",
      "sort": {
        "order": "string"
      },
      "pinned": true
    }
  ]
}
POST /api-web/api/users/config/result/{type} - Update the result list configuration for the logged-in user.
As of Version

2021 Summer

Request Method

POST

Response Format

HTTP status code

Description

Updates a result list configuration by type.

Optional query parameters:

Parameter Type Description

sots

list of string

List of secondary object types.

Response HTTP status codes:

HTTP status code Meaning

200

OK

Request Example

https://<host>/api-web/api/users/config/result/mytype

Request Body
{
  "type": "string",
  "isDefault": true,
  "columns": [
    {
      "id": "string",
      "sort": {
        "order": "string"
      },
      "pinned": true
    }
  ]
}
Response Example

200 OK

no response body

GET /api-web/api/users/settings - Retrieve settings for the logged-in user.
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Description

Retrieves the general settings of the requested user.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

https://<host>/api-web/api/users/settings

no request body

Response Example

200 OK

Response Body
{
  "locale": "string"
}
POST /api-web/api/users/settings -Update settings for the logged-in user.
As of Version

2021 Summer

Request Method

GET

Response Format

HTTP status code

Description

Saves a general settings for the user.

Response HTTP status codes:

HTTP status code Meaning

200

OK

Request Example

https://<host>/api-web/api/users/settings

Request Body
{
  "locale": "string"
}
Response Example

200 OK

no response body

GET /api-web/api/users/settings/{section} - Retrieve the specified settings section for the logged-in user.
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Description

Retrieves the settings of the requested user matching the section name.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

POST /api-web/api/users/settings/{section} - Update the specified settings section for the logged-in user.
As of Version

2021 Summer

Request Method

POST

Response Format

HTTP status code

Description

Saves a settings for the user by a section.

Response HTTP status codes:

HTTP status code Meaning

200

OK

Parameters in Search Requests

The search endpoint POST /api-web/api/dms/objects/search of the Web API gateway accepts a JSON request body with specific parameters in a specific structure. The following optional parameters can be specified.

Parameter Type Description

Offset and Size of Result List

If the parameters should be included in the request, they have to be specified at the beginning of the JSON structure.

example
"from": <integer>,
"size": <integer>

from

integer

The optional parameter from sets the offset for the result list, default is 0.

size

integer

The optional parameter size allows you to configure the maximum amount of hits to be returned, default is 20.

Full-text Search Term

term

string

The parameter is used to request a full-text search.

example
"term": "<query string>"

If the specified query string consists of multiple words, it is parsed into a series of individual words connected by operators. Per default, individual words are connected by AND. For example, the query string capital of Hungary is translated to the following request to the core system:

SELECT * FROM type where CONTAINS('capital AND of AND Hungary')
The Web-API Gateway uses the placeholders ? (for a single character) and * (for any string) instead of the usual SQL placeholders.

For each object in the result list, the score is provided as object property. The results are sorted by their score values unless otherwise specified via sort parameter.

scope

string

As of 2023 Winter. Specifies whether to search in text renditions or string metadata or both. Available values: metadata, content, all

Sorting

sort

map of strings

The parameter arranges the result list in ascending (asc) or descending (desc) sort order of the specified field. It must be inserted in the upper part of the request body.

example
"sort": {
  "field" : "<field>",
  "order" : "<sort order>"
}

Default sorting:

  • If a term parameter is specified (full-text search), the results are ordered by score.

  • If no term parameter is specified, the results are ordered by the system:creationDate property.

Properties in Result List

fields

list of strings

Defines the objects' properties to be displayed in the result list.

example
"fields":
 [
     "<field1>",
     "<field2>",
     ...
]

Conditions on Metadata

filters

JSON

Contains conditions for filtering the result list based on the objects' metadata. The structure and subparameters are described below.

tableFilters

JSON

Contains conditions for filtering by a table property. Its structure is similar to the filters section as described below.

Aggregation

aggs

list strings

Specify a list of one or more property IDs (combined by OR) for which an aggregation is to be calculated.

"aggs": [
  "<field>"
]

Secondary Object Type(s)

sots

A list of secondary object types combined by OR. At least one of these secondary object types must be assigned to the DMS objects to be included in the result list.

"sots": [
  "<object type1>",
  "<object type2>",
  ...
]

lots

A list of leading object types combined by OR. Exactly one of these leading object types must be assigned to the DMS objects to be included in the result list.

"lots": [
  "<object type1>",
  "<object type2>",
  ...
]
Filtering

The subparameter lo is used to combine several logical conditions (default value: AND). If there is only one logical condition or the conditions are combined by AND, the subparameter lo can be omitted.

Each entry in the filters subparameter list configures a condition by means of the following subparameters:

  • Via the subparameter f, the ID of a property can be specified. The value of this property should match the condition.

  • The subparameter o describes the relationship between the subparameter f and the value to compare v. The list of allowed comparison operators is given below.

    If o is not specified, the default operator contains is used. In the main.json configuration file, the default operator con be changed to in (default up to 2023 Autumn).

  • The subparameter v contains the values to compare. The following types of comparing values are possible:

    Type Example

    string

    "Meier"

    numeric

    50

    date/datetime

    "2016-01-01T00:00:00.000Z"

    logical

    "true", "false"

    Regardless of the type, it is possible to use a null value to indicate that the corresponding property does not have any value.

  • The subparameter useNot reverses the meaning of the preceding logical comparison. While, e.g.,

    "f": "system:versionNumber",
    "eq": 1,
    "v": 1

    returns all objects with version number 1, the additional subparameter

    "notUse": "true"

    ensures that all objects are returned that do NOT have this version number.

Available Comparison Operators:

Operator Description Example

eq

Returns objects with values that are equal to v1.

"f": "appPersonalfile:name",
"o": "eq",
"v1": "idpic"

in

Returns objects that match at least one of the provided values (value has to be an array), i.e., list of terms combined by OR.

An array of values to compare must be specified.

Default comparison operator up to 2023 Autumn. Can be configured in main.json as of 2023 Winter.

"f": "appPersonalfile:employee",
"o": "in",
"v1":[
  "Applicant",
  "Manager"
]

gt

Returns objects with values greater than v1.

"f": "system:creationDate",
"o": "gt",
"v1": "2016-01-01T00:00:00.000Z"

gte

Returns objects with values greater than or equal to v1.

similar to gt

lt

Returns objects with values less than v1.

similar to gt

lte

Returns objects with values less than or equal to v1.

similar to gt

gtlt

Returns objects with values within the specified interval: greater than v1 and less than v2.

"f": "system:creationDate",
"o": "gtelte",
"v1": "2016-01-01T00:00:00.000Z",
"v2": "2016-01-10T00:00:00.000Z

gtelte

Returns objects with values within the specified interval: greater than or equal to v1 and less than or equal to v2.

similar to gtlt

gtlte

Returns objects with values within the specified interval: greater than v1 and less than or equal to v2.

similar to gtlt

gtelt

Returns objects with values within the specified interval: greater than or equal to v1 and less than v2.

similar to gtlt

like

Used to search for a specific pattern with wildcards.

The ? character represents a single character, the * character represents multiple characters.

A maximum number of 10 * and ? characters are allowed in one like expression.

"f": "system:tenant",
"v1": "??Tenant",
"o": "like"

contains

As of 2023 Autumn. Performs full-text search for the specified field.

Default comparison operator as of 2023 Winter. Can be configured in main.json.

{
  "f": "appClient:clientdescription",
  "v1": "test",
  "o": "contains"
}
Filters Structure
"filters":
 [  {
    "lo": "<logical operator>",
    "filters":
    [
       {
       "f": "<field1>",
       "v1": <comparing value1>,
       "o": "<comparison operator1>",
       "useNot": <"true" or "false">
       },
       {
       "f": "<field2>",
       "v2": <comparing value2>,
       "o": "<comparison operator2>"
       }
       ...
    ]
    }
 ]

As of 2022 Winter, the tableFilters section can be specified. Its structure is similar to the filters section as shown in the following example code. Specify the ID of the table property to which you want to apply conditions as value for table. In the columnFilters list, specify the individual conditions that are connected with a logical AND. Thus, they have to be matched in the SAME TABLE ROW.

Example query with two conditions on one table row
{
     "size": 50,
     "lots": ["appMyapp:invoice"],
     "fields": [
         "appClient:clienttitle",
         "system:objectId",
         "appMyapp:accountassignment"
     ],
     "tableFilters": [
         {
             "table": "appMyapp:accountassignment",
             "columnFilters": [
                 {
                     "f": "account",
                     "o": "eq",
                     "v1": "123456"
                 } ,
                 {
                     "f": "grossamount",
                     "o": "gt",
                     "v1": "1000"
                 }
             ]
         }
     ]
}
Example Request and Response

The following code blocks show an example request body using all parameters described above and a corresponding example response body.

Each search request for DMS objects always returns a list of DMS objects called objects. If only one object matches the search query, the result is a single-element list. If no object matches the query, the response body contains an empty objects list.

Request Body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
curl -X 'POST' \
  'https://kolibri.enaioci.net/api-web/api/dms/objects/search' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "from": 4,
  "size": 10,
  "term": "Martin",
  "sort":  [
    {
      "field" : "system:versionNumber",
      "order" : "desc"
    }
  ],
  "fields":
  [
    "system:createdBy",
    "system:creationDate",
    "system:objectTypeId",
    "system:versionNumber"
  ],
  "types": [
    "appPersonalfile:dossier"
  ],
  "filters":
  [
    {
    "lo": "OR",
    "filters":
      [
        {
          "f": "system:versionNumber",
          "v1": 1,
          "o": "eq",
          "useNot": true
        },
        {
          "f": "system:tenant",
          "v1": "kolibri",
          "o": "eq"
        }
      ]
    },
    {
      "f": "system:creationDate",
      "o": "gtelte",
      "v1": "2010-01-01T00:00:00.000Z",
      "v2": "2021-01-10T00:00:00.000Z"
    },
    {
      "f": "system:lastModifiedBy",
      "v1": "?685*",
      "o": "like"
    }
  ],
  "aggs":  [
    "appClientsystem:leadingTypeId"
  ],
  "sots":  [
    "appClient:clientdefaults"
  ],
  "lots":  [
    "appClientsystem:leadingTypeId"
  ]
}'
Response Body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
{
  "objects": [
    {
      "properties": {
        "system:createdBy": {
          "title": "Schubert, Martin",
          "value": "2612df3a-1cf8-4da3-968c-0a4a10b48921"        },
        "system:creationDate": {
          "value": "2020-11-16T10:23:56.740Z"
        },
        "system:objectTypeId": {
          "value": "tenKolibri:qadoctableofnotices"
        },
        "system:versionNumber": {
          "value": 14
        }
      }
    },
    {
      "properties": {
        "system:createdBy": {
          "title": "Schubert, Martin",
          "value": "2612df3a-1cf8-4da3-968c-0a4a10b48921"        },
        "system:creationDate": {
          "value": "2020-09-02T13:03:25.680Z"
        },
        "system:objectTypeId": {
          "value": "appPersonalfile:pfdocumentdlm"
        },
        "system:versionNumber": {
          "value": 10
        }
      }
    },
    {
      "properties": {
        "system:createdBy": {
          "title": "Wayne, Bruce",
          "value": "e823c59a-e073-40e1-af0a-e95e08a8e36c"
        },
        "system:creationDate": {
          "value": "2020-10-22T10:49:24.290Z"
        },
        "system:objectTypeId": {
          "value": "appEmail:email"
        },
        "system:versionNumber": {
          "value": 9
        }
      }
    },
    {
      "properties": {
        "system:createdBy": {
          "title": "Lauterbach, Ralf",
          "value": "0b09ef34-2954-451c-9ebc-a898020bd004"
        },
        "system:creationDate": {
          "value": "2020-07-22T11:08:03.870Z"
        },
        "system:objectTypeId": {
          "value": "appClient:minidoc"
        },
        "system:versionNumber": {
          "value": 8
        }
      }
    },
    {
      "properties": {
        "system:createdBy": {
          "title": "Miller, Brad",
          "value": "a2f7e1aa-ff42-4140-b9ec-5de4cc61f1a5"
        },
        "system:creationDate": {
          "value": "2020-12-17T08:30:26.380Z"
        },
        "system:objectTypeId": {
          "value": "tenKolibri:qadoctableofnotices"
        },
        "system:versionNumber": {
          "value": 8
        }
      }
    },
    {
      "properties": {
        "system:createdBy": {
          "title": "Schubert, Martin",
          "value": "2612df3a-1cf8-4da3-968c-0a4a10b48921"
        },
        "system:creationDate": {
          "value": "2020-02-13T18:48:03.860Z"
        },
        "system:objectTypeId": {
          "value": "appPhotoarchive:paphoto"
        },
        "system:versionNumber": {
          "value": 8
        }
      }
    },
  ],
  "numItems": 5,
  "hasMoreItems": true,
  "totalNumItems": 160
}

4.1.3. Localization Management

The schema definition contains technical names for fields and object types. These fields are not really "readable" for users. To provide users with more meaningful terms in any language they may need, you have to create the respective language files. With the installation of the system, some global default settings are given for English and German language regarding the internal system fields.

The JSON-format for labels

The localization is in JSON format and contains key-value pairs. The key is the technical name of an object type or a field ending with _label and _description. The value is displayed by the client instead of the technical names referenced in the key.

Example Localization file for 'en'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
{
  "system:folder_label": "All folders",
  "system:folder_description" : "01 Across all",
  "system:document_label": "All Documents",
  "system:document_description": "01 Across all",
  "system:secondary_bale": "All secondary documents",
  "system:secondary_description": "01 Across all",
  "system:baseTypeId_label": "Basistype ID",
  "system:objectTypeId_label": "Object type ID",
  "system:secondaryObjectTypeIds_label": "Characteristics",
  "system:parentObjectTypeId_label": "Folder type",
  "system:objectId_label": "Object ID",
  "system:parentId_label": "Folder ID",
  "system:createdBy_label": "Creator",
  "system:creationDate_label": "Created on",
  "system:lastModifiedBy_label": "Editor",
  "system:lastModificationDate_label": "Edited on",
  "system:versionNumber_label": "Version",
  "system:acl_label": "Access list",
  "system:tenant_label": "Tenant",
  "system:traceId_label": "Trace ID",
  "system:tags_label": "Tags",
  "system:contentStreamLength_label": "File size",
  "system:contentStreamMimeType_label": "File type",
  "system:contentStreamFileName_label": "File name",
  "system:contentStreamId_label": "Content ID",
  "system:contentStreamRange_label": "Content range",
  "system:contentStreamRepositoryId_label": "Content stream repository",
  "system:digest_label": "Digest",
  "system:archivePath_label": "Archive path",
  "system:rmExpirationDate_label": "Retention date",
  "system:rmStartOfRetention_label": "Retention start",
  "system:rmDestructionDate_label": "Destruction date",
  "system:rmDestructionRetention_label": "Retention",
  "system:parentVersionNumber_label": "Folder version",
  "follow-up_label": "Follow-up",
  "expiryDateTime_label": "Follup-up date",
  "businessKey_label": "Object",
  "whatAbout_label": "Subject",
  "startTime_label": "Start time",
  "task_label": "Reminder",
  "type_label": "Type",
  "undefined_label": "",
  "document_label": "Document",
  "document_description": "01 Across all",
  "appClient_label": "Client standards",
  "appClient:minidoc_label": "Smallest document",
  "appClient:minidoc_description": "01 Across all",
  "appClient:clientdefaults_label": "Object header",
  "appClient:clienttitle_label": "Title",
  "appClient:clientdescription_label": "Description",
  "appClientsystem:leadingType_label": "Type",
  "appClientsystem:leadingTypeId_label": "Type"
}
Example Localization file for 'de'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
{
  "system:folder_label": "Alle Ordner",
  "system:folder_description": "01 Übergreifend",
  "system:document_label": "Alle Dokumente",
  "system:document_description": "01 Übergreifend",
  "system:secondary_label": "Alle sekundären Dokumente",
  "system:secondary_description": "01 Übergreifend",
  "system:baseTypeId_label": "Basistyp",
  "system:objectTypeId_label": "Typ",
  "system:secondaryObjectTypeIds_label": "Characteristika",
  "system:parentObjectTypeId_label": "Ordnertyp",
  "system:objectId_label": "Objekt-ID",
  "system:parentId_label": "Ordner-ID",
  "system:createdBy_label": "Ersteller",
  "system:creationDate_label": "Erstellt am",
  "system:lastModifiedBy_label": "Bearbeiter",
  "system:lastModificationDate_label": "Bearbeitet am",
  "system:versionNumber_label": "Version",
  "system:acl_label": "Zugriffsliste",
  "system:tenant_label": "Mandant",
  "system:traceId_label": "Trace-ID",
  "system:tags_label": "Tags",
  "system:contentStreamLength_label": "Dateigröße",
  "system:contentStreamMimeType_label": "Dateityp",
  "system:contentStreamFileName_label": "Dateiname",
  "system:contentStreamId_label": "Dateistrom-ID",
  "system:contentStreamRange_label": "Dateistrombereich",
  "system:contentStreamRepositoryId_label": "Dateistrom-Repository",
  "system:digest_label": "Digest",
  "system:archivePath_label": "Archivpfad",
  "system:rmExpirationDate_label": "Aufbewahrungsdatum",
  "system:rmStartOfRetention_label": "Aufbewahrungsstart",
  "system:rmDestructionDate_label": "Aussonderungsdatum",
  "system:rmDestructionRetention_label": "Aufbewahrung",
  "system:parentVersionNumber_label": "Ordner-Version",
  "follow-up_label": "Wiedervorlage",
  "expiryDateTime_label": "Wiedervorlagedatum",
  "businessKey_label": "Objekt",
  "whatAbout_label": "Betreff",
  "startTime_label": "Startzeitpunkt",
  "task_label": "Erinnerung Wiedervorlage",
  "type_label": "Type",
  "undefined_label": "",
  "document_label": "Dokument",
  "document_description": "01 Übergreifend",
  "appClient_label": "Client-Standards",
  "appClient:minidoc_label": "Kleinstes Dokument",
  "appClient:minidoc_description": "01 Übergreifend",
  "appClient:clientdefaults_label": "Objektkopf",
  "appClient:clienttitle_label": "Titel",
  "appClient:clientdescription_label": "Beschreibung",
  "appClientsystem:leadingType_label": "Typ",
  "appClientsystem:leadingTypeId_label": "Typ"
}

For object types, the _description is used to group them in the object type selection dialog, e.g., for search or creation:

Example object type selection dialog.

Recommendation: Group all extending object types in a group names 'Extension'. This may help the user in differentiating in object types that can be used for instantiating an object and those that can extend an existing object.

For field names, the _description is shown below the form field.

Example metadata form.
Adjusting Localization Procedures
Saving Labels and Descriptions
  1. Open the resource-controller.

  2. Click the URL ..api/resource/text/{locale} to open the management form.

  3. Click Try it out.

  4. Copy the JSON-formatted data into the resource input field and enter the DIN value for the corresponding language, e.g., de for Deutsch, and en for English.

  5. If you want to update the labels for a tenant that you are not logged in to, provide a tenant name as a parameter. In the default configuration, this option is available only for users with the role YUUVIS_SYSTEM_INTEGRATOR.

  6. If you want to update the app text resources, provide the app name as a parameter.

  7. Click Execute to save the data.

  8. Check the response message area to make sure that the data really has been saved as described.

Reading all Labels and Descriptions
  1. Open the resource-controller.

  2. Click on the URL ../resources/text to open the management form.

  3. Click Try it out.

  4. Type the DIN value for the corresponding language, e.g., de for Deutsch, and en for English.

  5. You will get merged text. As default you will get global and app text resources merged with tenant resources for the requested locale with fallback to the default locale that is configured for api-web.

  6. Only users with the role YUUVIS_SYSTEM_INTEGRATOR can request the resources for a tenant that they are not logged-in to. If the raw parameter is true, the fallback to the default locale is not possible.

  7. Click Execute to display all key-value pairs for labels and descriptions in the Response Body.

4.1.4. Icon Management

In order to enhance the user experience of your client, you can configure icons for the different object types that will be displayed together with objects instantiated of the corresponding types. The icons are stored via the core system’s configservice either in the global or in the tenant-specific resources. The corresponding endpoints are Web API Gateway Endpoints and thus also available via Swagger UI. The icons are expected as SVG files not larger than 512 KB.

The endpoint GET /api-web/api/system/resources/icon/{path} retrieves the icon resource if available. If not available, a fallback icon can be returned.

Each icon is introduced into the system together with an object type ID to identify it in retrieval calls. The retrieval (GET) endpoint expects an object type ID and returns the corresponding icon (if available). If the specified object type ID is not available in the corresponding resource(s), a default icon will be returned. Alternatively, a fallback icon can be specified in addition to the desired icon. If the fallback icon was not found, the default icon will be returned.

Icons in yuuvis® client as reference implementation

The icons are not configured automatically during the installation process, but have to be introduced manually afterwards. Use the technical names of object types as keys for the icon identification. For the fallback icons, the following three keys are available:

key for fallback icon object types for which the fallback is configured

system:folder

all folder object types

system:document

all document object types without floating secondary object types referenced in the schema definition

system:dlm

all document object types with floating secondary object types referenced in the schema definition

We recommend to use the icons of material icons as they will blend in with the design of all the other icons used in our client framework. A basic set of icons is already included in the framework library, which is delivered together with the reference client.

Managing Icons via Swagger UI
Saving Icons
  1. Open the resource-controller.

  2. Click on the endpoint POST /api-web/resources/icon/{type} to open the management form.

  3. Only users with the role YUUVIS_SYSTEM_INTEGRATOR can update or add icons for a tenant that they are not logged in to.

  4. Click Try it out

  5. Select a file for the icon. It must be an SVG file and not larger than 512 KByte.

  6. Enter the fully qualified technical name of an object type, e.g., email or tenKolibri:invoice.

  7. Click Execute to save the data.

  8. Check the response message area to make sure that the data really has been saved as described.

4.1.5. Configuration of 'api-web' Service

It is possible to specify configuration parameters in a file called api-web-prod.yml that is located in the Git root directory like the profile-related configuration files used by the core services.

The following parameters can be specified:

Parameter Description Default

csv

Section of parameters for the export of search result lists via the endpoint POST /api-web/api/dms/objects/export.

delimiter

Separator between individual values.

;

encoding

Used encoding.

UTF-8

batchSize

Maximum number of objects to be included in the exported result list.

100

writeBOM

(as of 2023 Spring) Boolean value that specifies if byte order mark should be used (true) or not (false). If true, emojis and German umlauts can be displayed correctly.

true is only supported for UTF-8 encoding.

false

api-web.technical-roles

Comma-separated list of strings that specify the names of the roles that should be considered as technical roles. As such, they are filtered out, e.g., by the endpoints GET /api-web/api/idm/users and GET /api-web/api/idm/users/{userId}.

YUUVIS_SYSTEM_INTEGRATOR

api-web.default-locale

An ISO language code that specifies the default locale for requests to the Web-API gateway.

en

api-web.user-label-templates

(as of 2023 Spring) List of templates for creating display name for users instead of user IDs.

If you want to avoid the userId to appear in your client application, you can display the value of one or multiple of the following user attributes instead:

  • id

  • email

  • username

  • firstname

  • lastname

Configure a template with comma-separated references on those attributes as shown in the example below. If you list multiple templates, the first one for which all referenced attributes are available will be used. If all configured templates contain at least one attribute for which no value is available for the corresponding user, the default applies.

Example configuration
api-web.user-label-templates:
- "%{lastname}, %{firstname} (%{username})"
- "%{firstname} (%{username})"
- "%{lastname} (%{username})"
- "%{username}"

corresponding ID value

4.1.6. Client-side SOT Handling via 'sothook' Service

The sothook service is connected to yuuvis® Momentum via two webhooks. As an implementation for proper handling of an object’s lifecycle, it is required for the operation of the Web API.

Configuration
k8s-service
apiVersion: v1
kind: Service
metadata:
  labels:
    app: yuuvis
    yuuvis: "true"
    name: sothook
  name: sothook
  namespace: yuuvis
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 10779
  selector:
    name: sothook
  type: ClusterI
k8s-deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: yuuvis
  labels:
    app: yuuvis
    name: sothook
  name: sothook
spec:
  replicas: 1
  selector:
     matchLabels:
      name: sothook
  template:
    metadata:
      labels:
        app: yuuvis
        name: sothook
    spec:
      initContainers:
      - name: init-sothook
        image: busybox
        command: ["sh", "-c", "until wget -q --spider http://configservice/manage/health; do echo waiting for configservice; sleep 11; done;"]
        imagePullPolicy: IfNotPresent
      containers:
      - name: sothook
        image: docker.yuuvis.org/yuuvis/sandbox/sot-hook:1.0.0-RC01
        imagePullPolicy: Always
        env:
        - name: JAVA_OPTS
          value: -Xmx256m
        - name: SPRING_PROFILES_ACTIVE
          value: prod,kubernetes
        - name: SPRING_CLOUD_CONFIG_URI
          value: "http://configservice/config"
        ports:
        - containerPort: 10779
      restartPolicy: Always
      imagePullSecrets:
      - name: flexsecret

In the cluster, the app/clientsystem/systemHookConfiguration.json file must be adapted in the configservice - in the webhook array, these two entries must be added:

webhook array entries
{
    "enable": true,
    "predicate": "spel:T(java.util.List).of(100,101).contains(options['action']) && properties['system:secondaryObjectTypeIds'] != null && properties['system:secondaryObjectTypeIds']['value'].contains('appClientsystem:leadingType')",
    "type": "dms.request.objects.upsert.database-before",
    "url": "http://sothook/api/dms/request/import/databasebefore",
    "useDiscovery": true
},
{
    "enable": true,
    "predicate": "spel:T(java.util.List).of(300).contains(options['action']) && properties['system:secondaryObjectTypeIds'] != null && properties['system:secondaryObjectTypeIds']['value'].contains('appClientsystem:leadingType')",
    "type": "dms.request.objects.upsert.database-before",
    "url": "http://sothook/api/dms/request/updatemetadata/databasebefore",
    "useDiscovery": true
}

Deprecated (valid up to version 2022 Summer): In the cluster, the system/systemHookConfiguration.json file must be adapted in the configservice - in the webhook array, these two entries must be added:

webhook array entries (up to version 2022 Summer)
{
        "enable": true,
        "predicate": "spel:(options==null || options['currentVersion']==null)",
        "type": "dms.request.import.storage.before",
        "url": "http://sothook/api/dms/request/import",
        "useDiscovery": true
      },
      {
        "enable": true,
        "predicate": "spel:options!=null && options['currentVersion']!=null && options['currentVersion']['properties']['system:secondaryObjectTypeIds'] != null && options['currentVersion']['properties']['system:secondaryObjectTypeIds']['value'].contains('appClientsystem:leadingType')",
        "type": "dms.request.update.metadata",
        "url": "http://sothook/api/dms/request/update/metadata",
        "useDiscovery": true
    }

4.2. User Profile API

This API is provided by the userservice. It allows accessing and managing custom user information, settings and content.If the path parameter userId is specified in a request URL, the corresponding endpoint operates on the data of the user specified by this ID. In order to work with the data of the currently authorized user, the path alias /me can be used instead of /users/{userId}. For example, a GET /api/me request leads to the same result as calling the GET /api/users/{userId} endpoint.

Accessing or managing the data of users other than the currently authorized user may require administrative rights (as configured in the service parameter app.security.admin-role). If the service is accessed with administrative rights, no further checks on existence of users are performed. This allows more flexibility to users and apps with admin rights. For instance, it is possible to remove the data of users stored by userservice that have left the system and are no longer in the security system, or to prepare data for users that are about to be added to the system.

4.2.1. Endpoints

User Contents Endpoints

Manage custom content (for example, profile pictures). This service stores and delivers content stream and the mime-type of stored content items.

GET /userservice/api/users/{userId}/contents - Retrieve a list of all existing contents stored by the specified user.
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Description

Retrieve a list of all existing contents stored by the user specified by userId.

Optional query parameters:

Parameter Type Description

page

integer

Result page you want to retrieve (0…N). Default is 0 which means the first page.

size

integer($int32)

Limit the number of users per page. (default: 20)

sort

list of strings

Sorting of results either ascending (asc) or descending (desc). Default sort order is ascending. Multiple sort criteria are supported.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

403

Forbidden

Request Example

https://<host>/userservice/api/users/12345678-abcd-ef90-b620-0e92d5b7140c/contents?page=0&size=50&sort=desc

no request body

Response Example

200 OK

Response Body
{
  "objects": [
    {
      "id": "myapp.layout"
    }
  ],
  "numItems": 50,
  "totalNumItems": 1234,
  "hasMoreItems": true
}
DELETE /userservice/api/users/{userId}/contents - Delete all existing contents stored by the specified user.
As of Version

2021 Summer

Request Method

GET

Response Format

HTTP status code

Description

Deletes all existing contents stored for the user specified by userId.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

403

Forbidden

Request Example

https://<host>/userservice/api/users/12345678-abcd-ef90-b620-0e92d5b7140c/contents

no request body

Response Example

200 OK

no response body

GET /userservice/api/users/{userId}/contents/{contentId} - Retrieve the specified content for the specified user.
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Description

Retrieves the content specified by contentId that is stored for the user specified by userId.

Response HTTP status codes:

HTTP status code Meaning

200

OK

204

No content found that matches the identifier

401

Unauthorized

403

Forbidden

POST /userservice/api/users/{userId}/contents - Update the specified content for the specified user.
As of Version

2021 Summer

Request Method

POST

Response Format

HTTP status code

Description

Saves the content specified by contentId that is stored for the user specified by userId.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

403

Forbidden

DELETE /userservice/api/users/{userId}/contents - Delete the specified content for the specified user.
As of Version

2021 Summer

Request Method

DELETE

Response Format

HTTP status code

Description

Deletes the content specified by contentId that is stored for the user specified by userId.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

403

Forbidden

HEAD /userservice/api/users/{userId}/contents - Retrieve the specified content for the specified user.
As of Version

2021 Summer

Request Method

HEAD

Response Format

HTTP status code

Description

Retrieves the content specified by contentId that is stored for the user specified by userId.

Response HTTP status codes:

HTTP status code Meaning

200

OK

204

No content found that matches the identifier

401

Unauthorized

403

Forbidden

User Settings Endpoints

Manage custom settings (for example, layout settings) in form of JSON documents.

GET /userservice/api/users/{userId}/settings - Retrieve all settings for the specified user.
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Description

Retrieves a list of all existing settings on the user specified by userId.

Optional query parameters:

Parameter Type Description

page

integer

Result page you want to retrieve (0…N). Default is 0 which means the first page.

size

integer($int32)

Limit the number of users per page. (default: 20)

sort

list of strings

Sorting of results either ascending (asc) or descending (desc). Default sort order is ascending. Multiple sort criteria are supported.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/userservice/api/users/12345678-abcd-ef90-b620-0e92d5b7140c/contents?page=0&size=50&sort=desc

no request body

Response Example

200 OK

Response Body
{
  "objects": [
    {
      "id": "myapp.layout"
    }
  ],
  "numItems": 50,
  "totalNumItems": 1234,
  "hasMoreItems": true
}
DELETE /userservice/api/users/{userId}/settings - Delete all settings for the specified user.
As of Version

2021 Summer

Request Method

DELETE

Response Format

JSON

Description

Deletes all existing settings on the user specified by userId.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/userservice/api/users/12345678-abcd-ef90-b620-0e92d5b7140c/settings

no request body

Response Example

200 OK

no response body

GET /userservice/api/users/{userId}/settings/{settingId} - Retrieve the specified settings section for the specified user.
As of Version

2021 Summer

Request Method

GET

Response Format

JSON

Description

Retrieves the set of settings specified by settingId that is stored for the user specified by userId.

Response HTTP status codes:

HTTP status code Meaning

200

OK

204

No settings found that matches the identifier

401

Unauthorized

403

Forbidden

POST /userservice/api/users/{userId}/settings/{settingId} - Update the specified settings section for the specified user.
As of Version

2021 Summer

Request Method

POST

Response Format

HTTP status code

Description

Saves the settings section specified by settingsId that are stored for the user specified by userId.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

403

Forbidden

DELETE /userservice/api/users/{userId}/settings/{settingId} - Delete the specified settings section for the specified user.
As of Version

2021 Summer

Request Method

DELETE

Response Format

HTTP status code

Description

Deletes the settings section specified by settingsId that are stored for the user specified by userId.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

403

Forbidden

HEAD /userservice/api/users/{userId}/settings/{settingId} - Retrieve the specified settings section for the specified user.
As of Version

2021 Summer

Request Method

HEAD

Response Format

JSON

Description

Retrieves the set of settings specified by settingId that is stored for the user specified by userId.

Response HTTP status codes:

HTTP status code Meaning

200

OK

204

No settings found that matches the identifier

401

Unauthorized

403

Forbidden

4.2.2. Configuration

Database Connection

The userservice users the database connection that is configured via environment variables as described in the installation guide.

Service Configuration

The following parameters are part of the service configuration:

Parameter Description

app.security.admin-role

References the role (by name) that provides administrative rights and may be used in userservice, e.g. to access or manage data of other users.

app.userdata.content.max-data-per-user

Defines the maximum storage space available for all contents of one user.

app.userdata.content.max-file-size

Defines the maximum storage space for one single content item.

app.userdata.setting.max-data-per-user

Defines the maximum storage space available for all settings of one user.

app.userdata.setting.max-file-size

Defines the maximum storage space for one single setting item.

The following spring properties are ready configured for the installation and should be left unchanged to ensure that the userservice parameters are effective. Otherwise, it would cause unintended behavior.

  • spring.servlet.multipart.max-file-size

  • spring.servlet.multipart.max-request-size

Docker Deployment

Within the docker environment, the userservice will run in two separate docker containers.

Instead of deploying docker containers manually, we strongly recommend to use docker-compose. With docker-compose you can easily manage one or several deployments on your docker host, without copy-pasting docker commands manually. You will find pre-defined service stacks for connecting to different databases in our repository.

Running 'userservice' for Testing

Depending on the database you want to connect to the userservice, choose the correct deployment commands.

Deployment via docker-compose for PostgreSQL

Start the service with a PostgreSQL database for testing purposes with following steps:

  • In a console supporting docker, go to project docker directory.

  • Build a docker-compose image with docker-compose -f docker-compose-postgres.yml build.

  • Start this image with docker-compose -f docker-compose-postgres.yml up.

Deployment via docker-compose for Microsoft SQL Server

Start the service with a Microsoft SQL Server database for testing purposes with following steps:

  • In a console supporting docker, go to project docker directory.

  • Build a docker-compose image with docker-compose -f docker-compose-mssql.yml build.

  • Start this image with docker-compose -f docker-compose-mssql.yml up.

Deployment via docker-compose for CockroachDB

Start the service with a CockroachDB for testing purposes with following steps:

  • In a console supporting docker, go to project docker directory.

  • Build a docker-compose image with docker-compose -f docker-compose-cockroach.yml build.

  • Start this image with docker-compose -f docker-compose-cockroach.yml up.

4.3. Content Viewer API

The yuuvis® Momentum viewer service offers to display several common file types directly within a yuuvis® Momentum client application. It serves within the yuuvis® Momentum reference client and can readily be integrated in a custom client. It is designed to allow for easy integration of further viewers in addition to the free ones included already.

Currently, the Web API gateway offers several endpoints.

As of 2021 Autumn, it is possible to authenticate via bearer token to the viewer service. Especially, a preview for binary content files can be retrieved.

4.3.1. Supported Types

All following formats are supported by the viewer service. Some others like Microsoft Office files are supported by the rendition service or potentially the dashlet365 service if available.

For unsupported file types, the viewer service sends an error page with download link, allowing for the content to be downloaded and viewed by an external application.

Audio and Video

The audio and video files are natively played by the browser with HTML5 video tag (that is a subject of the HTML5 video specification). All played files are streamed to prevent unnecessary data downloads. The autoplay is set to false.

Example audio viewer configuration
1
2
3
4
5
6
7
8
9
10
11
[

  {

    "mimeType": ["audio/mp3", "audio/webm", "audio/ogg", "audio/mpeg", "video/mp4", "video/webm", "video/ogg", "application/ogg"],

    "viewer": "api/video/?path=${path}&mimeType=${mimeType}&fileExtension=${fileExtension}&lang=${lang}&theme=${theme}&accentColor=${accentColor}"

  }

]
Image

All supported image mimeTypes are rendered in the standard HTML img tag. The image viewer provides additional features like full screen, zoom, and rotate.

Specific Information for TIF/TIFF images
  • All images are automatically transformed as base64 encoded images.

  • The dimensions are limited to a maximum of 8K resolution to improve performance and prevent errors on extremely large TIFF files.

Example image viewer configuration
1
2
3
4
5
6
7
8
9
10
11
[

  {

    "mimeType": ["image/tiff", "image/jpeg", "image/png", "image/apng", "image/gif", "image/svg+xml", "image/webp"],

    "viewer": "api/img/?path=${path}&mimeType=${mimeType}&fileExtension=${fileExtension}&lang=${lang}&theme=${theme}&accentColor=${accentColor}"

  }

]
E-mail

All supported e-mail mimeTypes are rendered by a custom e-mail HTML viewer. The EML files are parsed by a mailparser, MSG files are parsed by a custom parser inspired by MSGReader. The e-mail viewer provides additional features like attachment preview and download.

Example e-mail viewer configuration
1
2
3
4
5
6
7
8
9
10
11
[

  {

    "mimeType": ["message/rfc822", "application/vnd.ms-outlook"],

    "viewer": "api/mail/?path=${path}&mimeType=${mimeType}&fileExtension=${fileExtension}&lang=${lang}&theme=${theme}&accentColor=${accentColor}"

  }

]
Text (JSON, XML, markdown, java, HTML, …)

All supported text mimeTypes are rendered by the 3rd party monaco viewer. The monaco viewer provides additional features like language formatting, line numbers, and text search.

Example text viewer configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
[

  {

    "mimeType": ["application/json"],

    "viewer": "api/monaco/?path=${path}&mimeType=${mimeType}&fileExtension=${fileExtension}&lang=${lang}&theme=${theme}&accentColor=${accentColor}&language=javascript"

  },

  {

    "mimeType": ["text/plain"],

    "viewer": "api/monaco/?path=${path}&mimeType=${mimeType}&fileExtension=${fileExtension}&lang=${lang}&theme=${theme}&accentColor=${accentColor}&language=plaintext"

  },

  {

    "mimeType": ["text/xml",

                "application/xml"],

    "viewer": "api/monaco/?path=${path}&mimeType=${mimeType}&fileExtension=${fileExtension}&lang=${lang}&theme=${theme}&accentColor=${accentColor}&language=xml"

  },

  {

    "mimeType": ["text/java"],

    "viewer": "api/monaco/?path=${path}&mimeType=${mimeType}&fileExtension=${fileExtension}&lang=${lang}&theme=${theme}&accentColor=${accentColor}&language=java"

  },

  {

    "mimeType": ["text/javascript",

                "application/javascript"],

    "viewer": "api/monaco/?path=${path}&mimeType=${mimeType}&fileExtension=${fileExtension}&lang=${lang}&theme=${theme}&accentColor=${accentColor}&language=javascript"

  },

  {

    "mimeType": ["text/html"],

    "viewer": "api/monaco/?path=${path}&mimeType=${mimeType}&fileExtension=${fileExtension}&lang=${lang}&theme=${theme}&accentColor=${accentColor}&language=html"

  },

  {

    "mimeType": ["text/markdown",

                "text/x-web-markdown",

                "text/x-markdown"],

    "viewer": "api/monaco/?path=${path}&mimeType=${mimeType}&fileExtension=${fileExtension}&lang=${lang}&theme=${theme}&accentColor=${accentColor}&language=markdown"

  }

]
PDF and Microsoft Office

All supported PDF and MS Office mimeTypes are rendered by the 3rd party component PDF.js which is a Mozilla project. The MS Office files are transformed to PDF via rendition service. The PDF viewer provides additional features like formatting, lazy loading, and text search.

The ranging support provided by PDF.js is supported by the Web API Gateway as well.

Search Term Highlighting

The full-text search provided by yuuvis® Momentum is insensitive to diacritics whereas the viewer service’s PDF preview is sensitive to diacritics. Thus, the found search term is not highlighted in the preview if it differs from the entered search term in diacritics.

Example PDF and MS Office viewer configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
[

  {

    "mimeType": [

        "application/pdf"

    ],

    "viewer": "api/pdf/web/viewer.html?file=&path=${path}&mimeType=${mimeType}&fileExtension=${fileExtension}&lang=${lang}&theme=${theme}&accentColor=${accentColor}"

    },

    {

    "mimeType": [

        "application/msword",

        "application/vnd.ms-excel",

        "application/vnd.ms-powerpoint",

        "application/vnd.openxmlformats-officedocument.wordprocessingml.document",

        "application/vnd.openxmlformats-officedocument.wordprocessingml.template",

        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",

        "application/vnd.openxmlformats-officedocument.spreadsheetml.template",

        "application/vnd.openxmlformats-officedocument.presentationml.presentation",

        "application/vnd.openxmlformats-officedocument.presentationml.template",

        "application/vnd.openxmlformats-officedocument.presentationml.slideshow",

        "application/vnd.ms-word.document.macroEnabled.12",

        "application/vnd.ms-word.template.macroEnabled.12",

        "application/vnd.ms-excel.sheet.macroEnabled.12",

        "application/vnd.ms-excel.template.macroEnabled.12",

        "application/vnd.ms-excel.addin.macroEnabled.12",

        "application/vnd.ms-excel.sheet.binary.macroEnabled.12",

        "application/vnd.ms-powerpoint.addin.macroEnabled.12",

        "application/vnd.ms-powerpoint.presentation.macroEnabled.12",

        "application/vnd.ms-powerpoint.template.macroEnabled.12",

        "application/vnd.ms-powerpoint.slideshow.macroEnabled.12"

    ],

    "viewer": "api/pdf/web/viewer.html?file=&path=${path}&pathPdf=${pathPdf}&mimeType=${mimeType}&fileExtension=${fileExtension}&lang=${lang}&theme=${theme}&accentColor=${accentColor}"

   }

]

4.3.2. Customizing

The viewer service can be extended as described in this section.

Localization

The viewer service offers a few strings with information for your users. You can change these or add some more language strings by setting them up in the translation section of the plug-in file that can be uploaded for use in the client.

Setting the localization strings in the plug-in file of the client
{

  "translations": {

    "en": {

       "yuv.viewer.not.authorized": "Not authorized to preview file.",

       "yuv.viewer.not.found": "File not found.",

       "yuv.viewer.not.supported": "Format not supported.",

       "yuv.viewer.not.supported.download.content": "Unable to display format. You can click this link to download the file."

    },

    "de": {

       "yuv.viewer.not.authorized": "Fehlende Authorisierung zur Anzeige der Datei.",

       "yuv.viewer.not.found": "Datei nicht gefunden.",

       "yuv.viewer.not.supported": "Dieses Format ist nicht unterstützt.",

       "yuv.viewer.not.supported.download.content": "Dieses Format kann nicht angezeigt werden. Ein Klick auf den Link lädt die Datei herunter."

    }

  }

}
The 'viewer' Service API

For the viewer to process a request, a path pointing to the file to be displayed must be accessible. The mimeType or fileExtension should be provided as well.

default viewers
api/video/?path=${path}&mimeType...
api/img/?path=${path}&mimeType...
api/mail/?path=${path}&mimeType...
api/monaco/?path=${path}&mimeType...
api/pdf/web/viewer.html?file=&path=${path}&mimeType...

The following parameters are available:

Parameter Type Description

path

string

the direct path from where the file can be loaded (required)

mimeType

string

the file’s mimeType (optional)

fileExtension

string

the file’s name extension (optional)

lang

string

sets the document locale to the html tag (default is en).

theme

string

sets class dark to the body (default = '').

accentColor

string

sets the accent color as css variable to the html tag (default = '').

default viewer parameters
URL/?path=${path}&mimeType=${mimeType}&fileExtension{fileExtension}&lang=${lang}&theme=${theme}&accentColor=${accentColor}
Custom Viewer Configuration

The viewer service configuration can be extended by adding a few lines to the plug-in configuration. Custom viewers can be implemented as static HTML files (in assets folder) or as custom microservice (for example dashlet365).

Custom viewer for JSON files (loaded from 'assets' folder)
1
2
3
4
5
6
7
8
9
10
11
12
13
"viewers": [

  {

    "mimeType": ["application/json"],

    "fileExtension": ["json"],

    "viewer": "assets/json-viewer/?path=${path}&mimeType=${mimeType}&fileExtension=${fileExtension}&lang=${lang}&theme=${theme}&accentColor=${accentColor}&language=javascript"

  }

]
  • mimeType may also be a string array, containing multiple mime types.

  • fileExtension is not mandatory. Provide only if mimeType is ambiguous.

  • viewer represents URL (string or function that returns string) that will be loaded in preview (iframe)

Additionally, the provided parameters will be passed to the custom viewer.

Native browser viewer for json files
1
2
3
4
5
6
7
8
9
10
11
12
13
"viewers": [

  {

    "mimeType": ["application/json"],

    "fileExtension": ["json"],

    "viewer": "() => parameters.path"

  }

]
Custom viewer for MS Office files (Office 365 support via 'dashlet365' service)
"viewers": [

  {

    "mimeType": [

            "application/msword",

            "application/vnd.ms-excel",

            "application/vnd.ms-powerpoint",

            "application/vnd.openxmlformats-officedocument",

            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",

            "application/vnd.openxmlformats-officedocument.wordprocessingml.template",

            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",

            "application/vnd.openxmlformats-officedocument.spreadsheetml.template",

            "application/vnd.openxmlformats-officedocument.presentationml.presentation",

            "application/vnd.openxmlformats-officedocument.presentationml.template",

            "application/vnd.openxmlformats-officedocument.presentationml.slideshow"

        ],

        "viewer": "() => { var edit = api.session.user.hasRole('YUUVIS_DEFAULT') && !location.pathname.match('/versions/');            return '/dashlet365/?id=${id}' + (edit ? '' : '_' + dmsObject.version) + '&version=${version}&mimeType=${mimeType}&path=${path}&fileExtension=${fileExtension}&locale=${lang}&allowedExtensions=doc,docx,xls,xlsx,ppt,pptx&editMode=' + edit + '&displayName=' + api.session.user.get().firstname;        }"

  }

]

4.4. Office 365 Integration

4.4.1. Function

Viewing Mode

Binary content files of the Microsoft Office file types and many others can be displayed in viewing mode. The preview is provided via the VIEWER Service in combination with a specific dashlet that is automatically installed via a Helm chart.

In viewing mode, no dedicated authentication license is required for Microsoft Office 365.

Editing Mode

If you have an authentication license for Microsoft Office 365, you have the possibility to edit binary content files of the types DOCX, PPTX, and XLSX directly in your yuuvis® Momentum client application. Changes are saved in a new version of the binary content file and a new object version is created in yuuvis® Momentum.

The editing mode is available for all users with a write permission on the corresponding object. In order to avoid the creation of offline copies, the binary content file that is edited via the OFFICE365 service never leaves the yuuvis® Momentum system during the processing. Thus, it is not possible to open it in a desktop editor directly from the web application. However, it is possible to download the binary content to your local file system from the client and open it from there in a desktop editor.

4.4.2. Certification

Our Office 365 integration is certified by Microsoft for our Software as a Service solution that is hosted by us. Customers with a self-hosted yuuvis® Momentum solution have to obtain their own certification for the Office 365 integration if needed.

4.4.3. Installation and Configuration

The service is installed and automatically configured by means of the client Helm chart. In its values.yaml file, specify user name and password for Microsoft Office 365 via the parameters yuuvis.client.office364.officeUser and yuuvis.client.office365.officePassword.

In order to integrate the Office 365 functionality in a client application based on the developer libraries, set up a plug-in configuration.

4.5. Developer Libraries

We offer the following developer libraries, which may be used when developing a custom client application in Angular.

  • The core library provides a set of services to interact with a yuuvis® Momentum backend.

  • The framework library provides yuuvis® developers with a collection of UI components, like hit lists, to create their own client applications.

  • The command-palette library provides support features for the navigation by keyboard.

  • As of 2022 Autumn, the widget-grid and widget-grid-widgets libraries allow for the creation of a custom dashboard.

4.5.1. Library Documentation

A documentation generated from the source code itself is provided at https://yuuvis-cc.yuuvis.org/. Notice the drop-down for switching between both documentations.

4.5.2. Library Installation

The developer libraries are open source, available on NPM. With @yuuvis/project we also provide schematics to be used with Angular CLI. It will support developers by integrating the libraries into their project: www.npmjs.com/package/@yuuvis/project

It is also possible to install the libraries separately:

  • Install the core library: www.npmjs.com/package/@yuuvis/core

  • Install the framework library: www.npmjs.com/package/@yuuvis/framework

Furthermore, the following libraries can be installed:

  • The command-palette library can be installed to enable further support of navigation by keyboard: www.npmjs.com/package/@yuuvis/command-palette

  • The widget-grid library can be installed for creating custom dashboards. Widgets can be registered and afterwards configured by the users: www.npmjs.com/package/@yuuvis/widget-grid

    The feature is still in a testing phase. We preserve to apply any changes to its functionality.
  • The widget-grid-widgets library contains a set of suitable widgets to be used with the widget-grid library: www.npmjs.com/package/@yuuvis/widget-grid-widgets

    The feature is still in a testing phase. We preserve to apply any changes to its functionality.
Installation Steps
  • First, you need to install the npm module.

    • For the core library:

      npm install @yuuvis/core --save
    • For the framework library (the command installs the core library as well):

      npm install @yuuvis/framework --save
  • Import YuvCoreModule to use @yuuvis/core in your Angular project. You have to import YuvCoreModule.forRoot() in the root NgModule of your application.

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { YuvCoreModule } from '@yuuvis/core';
    
    @NgModule({
      imports: [BrowserModule, YuvCoreModule.forRoot()],
      bootstrap: [AppComponent]
    })
    export class AppModule
  • Configure YuvCoreModule via assets/default/config/main.json configuration file. By default it looks like this:

        "core": {
          "apiBase": {
            "core": "/api",
            "api-web": "/api-web/api"
          },
          "languages": [
            {
              "iso": "de",
              "label": "Deutsch"
            },
            {
              "iso": "en",
              "label": "English",
              "fallback": true
            }
          ],
          "logging": {
            "level": "debug"
  • Configure translations set up by a translations module provided by the core library that can be used within your application. This module will be bound to the language a user has set up on the yuuvis® Momentum backend. In order to be able to initialize this module, translation files are required. By default, they are supposed to be located at assets/default/i18n/. In this directory, you provide a file for each supported language (en.json, de.json, …​). If you do not need translations, just provide empty files.

    You are able to change the default directory for the configuration by providing different locations to the module config when you import YuvCoreModule or YuvFrameworkModule:

    Example import 'YuvCoreModule'
    @NgModule({
      imports: [
        YuvCoreModule.forRoot({
          main: ['assets/my-custom-path/config/main.json'],
          translations: ['assets/my-custom-path/i18n/']
        })
      ],
      bootstrap: [AppComponent]
    })
    export class AppModule
    Example import 'YuvFrameworkModule'
    @NgModule({
          imports: [
            YuvFrameworkModule.forRoot({
              main: ['assets/my-custom-path/config/main.json'],
              translations: ['assets/my-custom-path/i18n/']
            })
          ],
          bootstrap: [AppComponent]
        })
    export class AppModule
  • Use the libraries:

    • Core library: Import the services you want to use into your components:

      import { UserService } from '@yuuvis/core';
      
      @Component({
        selector: 'app-root',
        templateUrl: './app.component.html',
        styleUrls: ['./app.component.scss']
      })
      export class AppComponent {
        constructor(private userService: UserService) {}
    • Framework library: Import the components you want to use into your components.

Troubleshooting

Ensure that your project is running on a supported Angular version. If you are not yet on Angular 9, update your project:

ng update @angular/cli@^9 @angular/core@^9

You may also want to update your global Angular CLI to version 9:

npm uninstall -g @angular/cli
npm cache verify
# if npm version is < 5 then use `npm cache clean`
npm install -g @angular/cli@latest

4.5.3. Client outside the yuuvis® Momentum Cluster

By default, client applications built with @yuuvis/core library are supposed to be deployed inside the yuuvis® Momentum cluster. As a main advantage, there is no responsibility for the library to handle the authentication process. Users authenticate directly via the authentication service.

As of yuuvis® Momentum version 2021 Autumn, the @yuuvis/core library allows for the built of clients that can be deployed outside the yuuvis® Momentum cluster. Such clients authenticate via OpenID Connect to the authentication service and can thus be hosted fully independently. They can even be configured to support switching between different yuuvis® Momentum clusters. Users select the cluster to which they want to connect.

An example project is provided on GitHub.

The following configuration steps are required to allow for the client deployment outside a yuuvis® Momentum cluster.

Setting up Keycloak

Configure a client inside your Keycloak Realm that will be used to trigger login.

Client ID: 'spa-client' // choose your own name
Client Protocol: 'openid-connect'
Access Type: 'public'
Valid Redirect URIs: // match your environment
Web Origins: '+' // means: everything that's also invalid redirect uris

#Advanced Settings
Proof Key for Code Exchange Code Challenge Method: 'S256'
Setting up Projects

Choose one of the following ways to setup your project.

Setup via Module Configuration

During the import of YuvCoreModule or YuvFrameworkModule, specify the following configuration:

// app.module.ts

imports: [
    YuvCoreModule.forRoot({
      // ... other config values
      oidc: {
        host: "https://kolibri.enaioci.net",
        tenant: "kolibri",
        issuer: "https://kc001.auth.enaioci.net/auth/realms/kolibri",
        clientId: "spa-client",
      }
    })
  ],
Setup via Dynamic Initialization

In case you do not know about the OIDC properties when your application starts (the OIDC profile needs to be loaded or users select one of several profiles), you can just import YuvCoreModule without OIDC config. The @yuuvis/core library will try the default initialization as if the client were deployed within a yuuvis® Momentum cluster. This will cause some console errors which can be ignored.

Once you are ready to specify the OIDC configuration, you can re-trigger the initialization of the library’s core module:

export class AppComponent {
  static OIDC = 'app.oidc.config';

  constructor(@Inject(CORE_CONFIG) private coreConfig: CoreConfig, private coreInit: CoreInit) {}

  login(target: OpenIdConfig) {
    this.coreConfig.oidc = {
      host: 'https://kolibri.enaioci.net',
      tenant: 'kolibri',
      issuer: 'https://kc001.auth.enaioci.net/auth/realms/kolibri',
      clientId: 'spa-client'
    };
    localStorage.setItem(AppComponent.OIDC, JSON.stringify(this.coreConfig.oidc));
    this.coreInit.initialize();
  }

  logout(removeOIDC = false) {
    removeOIDC && localStorage.removeItem(AppComponent.OIDC);
    this.userService.logout();
  }
}
// app.module.ts

imports: [
    YuvCoreModule.forRoot({
      oidc: JSON.parse(localStorage.getItem(AppComponent.OIDC) || '{}'),
    })
  ],

4.5.4. Customizing the Main Configuration

The default values for the main configuration of the settings are provided in the main.json file. Users with the appropriate permissions can download the main.json file, modify it and upload it again in order to apply new values to the main configuration. The settings will be applied to all users of the users' tenant.

To customize the main configuration, follow these steps:

  • Retrieve the currently applied main.json file via the Web-API Gateway endpoints GET /api-web/api/admin/resources/config/{name} or GET /api-web/api/resources/config/{name} with main-config as value for the name path parameter.

  • Modify the main.json file as described below.

  • Import the modified main.json file via the Web-API Gateway endpoint POST /api-web/api/admin/resources/config/{name} again with main-config as value for the name path parameter.

  • Refresh the client in your browser. The new settings will be applied.

The following code block shows the default main.json file defining the main configuration after installation. The individual parameters and their possible values are listed and described in the table below.

Settings in the main.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
  "core": {
    "apiBase": {
      "core": "/api",
      "api-web": "/api-web/api",
      "predict": "/predict-api",
      "viewer": "/viewer",
      "logout": "/logout",
      "oauth": "/oauth"
    },
    "languages": [
      {
        "iso": "de",
        "label": "Deutsch"
      },
      {
        "iso": "en",
        "label": "English",
        "fallback": true
      }
    ],
    "logging": {
      "level": "debug"
    }
  }
}
We recommend to configure only those parameters in your tentant-specific main.json that differ from the standard ones to reduce possible issues when updating the system.
Parameters in the 'main.json' file
Section Sub-Section / Key Key Example Value Description

core

apiBase

core

/api

Do not change these settings!

These values are required for the connection to yuuvis® Momentum core and client services.

api-web

/api-web

custom

/custom

languages

iso

en

This is the list of languages from which the users can choose in the reference client. Each list entry contains:

  • the internal identification string iso,

  • the string label shown in the reference client to identify the language and

  • the boolean fallback deciding if the language is used for the

  • first-time login of a new user.

Only one language in the list can have the value true for fallback.

For several languages, the specific date, time and number formats are automatically used.

label

English

fallback

true

logging

level

debug

Logging levels:

  • debug logs all issues

  • error logs only errors

  • warn logs only errors and warnings

  • info logs errors, warnings and infos

  • otherwise logs are disabled

permissions (as of 2022 Spring)

advancedUserRole

YUUVIS_SYSTEM_INTEGRATOR

YUUVIS_TENANT_ADMIN

(default)

Name of the role that enables the display of the following administrative information which are hidden for other users:

  • In object views:

    • tags that are not specified in the object type definition

    • history entries corresponding to a read action

  • In the BPM processes list My processes:

    • all BPM process variables

retentionManagerRole

YUUVIS_MANAGE_SETTINGS (default)

Name of the role that enables to modify the standard configurations of filters and hit lists. The configurations will be applied to all users within the tenant.

manageSettingsRole (as of 2022 Summer)

YUUVIS_MANAGE_SETTINGS (default)

Name of the role that enables the retention management view and allows to set or extend the expiration date for individual document objects.

clientdefaults (as of 2022 Spring)

titleProperty

appClient:clienttitle (default)

ID of an existing property that is referenced in all document or folder object type definitions (either directly or via SOT). This property will correspond to the Name field in the client that is available for all object types.

descriptionProperty

appClient:clientdescription (default)

ID of an existing property that is referenced in all document or folder object type definitions (either directly or via SOT). This property will correspond to the Description field in the client that is available for all object types.

app

inboxPageSize

100 (default)

(as of 2022 Summer)

Maximum number of tasks per page in the client’s Inbox view.

processesPageSize

100 (default)

Maximum number of processes per page in the client’s My follow-ups and My processes views.

strictSearchFilter

false (default)

Enable (true) or disable (false) the possibility for strict search - using IN operator. Default is full-text search - using CONTAINS operator.

searchQueryScope

all (default)

Search with specific term will be limited to scope: all, metadata, content.

features

dashboardWorkspaces

false (default)

(as of 2022 Winter)

Enable (true) or disable (false) the possibility for users to individually customize their dashboard.

gridOptions?

(as of 2023 Spring)

Configuration for the hit list grid that will be used as default for client users who did not save their own hit list configuration.

rowHeight

50 (default)

Row height in pixel.

pageSize

70 (default)

Maximum number of results within one page of the hit list.

client

docu

link

https://help.optimal-systems.com/yuuvis_develop/display/YMY/Adding+Documentation (default)

Any valid URL, optionally containing the placeholder ###userLang###.

The given URL can be called from two places within the client:

  • via the Documentation link provided in the About yuuvis® client menu item accessible via the main menu

  • via the ? icon in the title bar of the client

language

["en","de"]

List of languages in which the documentation portal is available. Depending on the language set in the reference client, the corresponding iso value is used in the URL instead of the placeholder userLang.

objectDetailsTabs

["summary", "indexdata", "preview", "history"] (default)

Specify the order of tabs or exclude any tabs in the Object Details view.

taskDetailsTabs

["summary", "history", "attachments", "comments"] (default)

As of 2023 Winter. Specify the order of tabs or exclude any of tabs in Task Details view (Inbox page).

processDetailsTabs

["summary", "history", "attachments", "comments"] (default)

As of 2023 Winter. Specify the order of tabs or exclude any of tabs in Process Details view (My Processes page).

Configuring Additional Client Languages

The developer libraries are provided by default with German and English as the application languages. However, the client can be extended with custom language files.

Users with the appropriate permissions can download the <iso>.json file for any language, modify it and upload it again in order to apply new values to the language configuration. The settings will be applied to all users of the users' tenant or to the users of all tenants.

To display an additional language, it needs to be enabled in the main.json configuration file via core.languages.

4.5.5. Schema Rules for Library-based Client

Secondary Object Type Classifications

This chapter relies on knowledge about the usage of Secondary Object Types (SOTs). Here, we consider only SOTs that are referenced as floating (FSOT). Those FSOTs can be assigned to objects during their lifecycle and removed again as well. Thus, additional metadata properties can be assigned to objects at any time, independent of the creation process. Clients based on our developer libraries use this concept to allow for a multi-step object creation process. It is possible to create objects having a general object type with only a few properties. After creation, either the user or a classification job analyses the object (and its binary content file if available) and selects a suitable FSOT that lets the object appear with a leading object type describing the business scope (invoice, delivery note, order, …​) and/or inserts appropriate properties.

To ensure proper functioning of form modeling, FSOTs must not be referenced in multiple object type definitions (see below).

By adding a specific classification attribute to their definition, it is possible to induce a particular behavior in your client. The following table introduces the classifications of SOTs you can use in your schemata.

Term Short Value for 'classification' Description

Primary floating secondary object type

PFSOT

appClient:primary

With respect to the above-mentioned import process, users can manually select the leading object type for a new object. Technically, the client application assigns a PFSOT that provides properties to identify this specific leading object type (invoice, delivery note, order, …​).

Required floating secondary object type

RFSOT

appClient:required

If you want to define some sets of properties that should be required for multiple PFSOTs, you can use RFSOTs instead of directly referencing the individual properties in the PFSOTs several times. In case users assign a PFSOT, all RFSOTs are assigned as well and provide their properties, e.g., client-specific defaults with title and description.

Especially the RFSOTs appClient:clientdefaults and appClientsystem:leadingType have to be defined, classified and referenced in each object type used in a library-based client. Find more information below.

Extendable floating secondary object type

EFSOT

-

While RFSOTs are automatically assigned together with a PFSOT, EFSOTs can be assigned later on if necessary. Examples are general address data, e-mail address data, and approval process attributes.

System floating secondary object type

SFSOT

systemsot

This classification suppresses the listing of the corresponding SOT for users of your client that do not have any administrative roles. The SFSOTs are not displayed in the Characteristics field in your client, but are listed in the classification[systemsot] field in the Advanced information section of the Summary aspect area.

E.g., the RFSOTs appClient:clientdefaults and appClientsystem:leadingType are additionally classified as SFSOTs.

-

-

appClient:extension:remove:false

If the FSOT is assigned to an object, it cannot be removed by a user via the client application.

Classifications available for all Object Types

This chapter relies on knowledge about the definition of object types. By specifying one of the following values for the classification attribute, it is possible to induce a particular behavior in your client.

Value for 'classification' Description

appClient:create:false

The object type is not available to users in the object creation dialog.

appClient:search:false

The object type is not available in the filter options for searches and hit lists.

prediction:classify

Only available for document object types referencing at least one PFSOT and if the client application is combined with AI functionality.

If set, the client application requests the PREDICT-API Endpoints for predictions while creating a new object with a binary content file. In the second step of the object creation dialog, a list of suitable PFSOTs including a percentage value describing the match quality is displayed for the users.

tag[<name>,<value1>,<value2>,…​]

E.g.:

  • tag[myttagname,0,1]

  • tag[anothertagname,0,10,20,30]

Document lifecycle management is provided via tags that can be assigned, modified or removed at runtime for any object independently on the schema. However, they are displayed in the client only if they are specified in the corresponding object type definition. If specified, the tags can be used for filtering and can be displayed in hit lists.

If specified in an SOT definition, the corresponding tag field in the client is available for all objects having the SOT assigned.

The tag name and values to be displayed in the client can be localized via keys of the following format: mytagname, mytagname:0, mytagname:1, …​

As of 2022 Spring, the tag name (and value where appropriate) is displayed in tag-specific history entries as well.

appClient:icon[myIconId]

(as of 2022 Summer)

Specify the ID of a globally stored icon in order to display it for the corresponding object type defined in the global schema or in any app or tenant schema.

Default 'client' and 'clientsystem' App Schemata

A library-based client is handled via two apps called client and clientsystem in yuuvis® Momentum. Both apps have their own app schema. They have to contain the definition of the following two RFSOTs that have to be referenced in all object type definitions:

  • appClient:clientdefaults – This SOT contains the properties clienttitle and clientdescription and appends them to each object to which it is assigned. Thus, all objects with a PFSOT have those two properties which makes them perfect for use in mixed hit lists.

  • appClientsystem:leadingType – This SOT contains the property leadingTypeId and appends it to each object to which it is assigned. It identifies the PFSOT from the client application’s point of view.

Per default, the app schemata already contain these two RFSOTs after installation.

Default 'client' app schema
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/">
    <propertyStringDefinition>
        <id>clienttitle</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>true</required>
        <maxLength>200</maxLength>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>clientdescription</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>true</required>
        <maxLength>200</maxLength>
    </propertyStringDefinition>
    <typeDocumentDefinition>
        <id>minidoc</id>
        <baseId>system:document</baseId>
        <contentStreamAllowed>allowed</contentStreamAllowed>
        <secondaryObjectTypeId>appClientsystem:leadingType</secondaryObjectTypeId>
        <secondaryObjectTypeId>appClient:clientdefaults</secondaryObjectTypeId>
    </typeDocumentDefinition>
    <typeSecondaryDefinition>
        <id>clientdefaults</id>
        <description>contains title and description fields mainly for mixed hit list and object header</description>
        <baseId>system:secondary</baseId>
        <propertyReference>clienttitle</propertyReference>
        <propertyReference>clientdescription</propertyReference>
        <classification>appClient:required</classification>
        <classification>appClient:create:false</classification>
    </typeSecondaryDefinition>
</schema>
Default 'clientsystem' app schema
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/">
    <propertyStringDefinition>
        <id>leadingTypeId</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <typeSecondaryDefinition>
        <id>leadingType</id>
        <description>contains the field that supports a better use of FSOTs</description>
        <baseId>system:secondary</baseId>
        <propertyReference>leadingTypeId</propertyReference>
        <classification>appClient:create:false</classification>
        <classification>appClient:search:false</classification>
    </typeSecondaryDefinition>
</schema>

Impact of appClient:clientdefaults:

  • provides the two properties clienttitle and clientdescription which are used in mixed hit lists to identify objects by Name and Description as well as in the header of the object details.

Impact of appClientsystem:leadingType:

  • Provides the property appClientsystem:leadingTypeId

  • The value for this property is set via a webhook (see SOTHOOK) as soon as a PFSOT is assigned to an object.

  • Based on the value specified in this property, the client application identifies the leading object type and displays a corresponding icon.

  • Furthermore, it is possible to configure permissions for individual leading object types by specifying conditions for the appClientsystem:leadingTypeId in your role set. An example role is shown in the following code block.

    <role>
            <name>contract_read</name>
            <permission>
                   <action>read</action>
                   <condition>appClientsystem:leadingTypeId = 'appMyapp:contract'</condition>
            </permission>
    </role>
  • The appClient:leadingType object type cannot be used for searching and the appClient:leadingTypeId field cannot be used in forms.

Example 'minidoc' Object Type

The default client schema contains the minidoc example object type, which only references the two RFSOTs appClient:clientdefaults and appClientsystem:leadingType. In the English default localization, it is offered as Smallest document in the Restrict to object types dialog.

After selecting the Smallest document object type, a binary content file can be added to the object. This is possible because the contentStreamAllowed property is set to allowed in the minidoc object type definition. Then, the Create form is displayed in which the new object’s metadata have to be entered. Here, the two referenced properties clienttitle and clientdescription are available. Per default, their labels are Title and Description.

The creation of the new object is completed by clicking the Create object button. Any binary content files added to the object will then be imported to the yuuvis® Momentum system.

Configuring the Content Preview for the Creation Dialog

In yuuvis® Momentum, the binary content file assigned to an object can be accessed as soon as the object creation is finished successfully. If a preview of the binary content file should be displayed for users, the corresponding object has to exist already. However, you might want to provide a preview of the binary content file already within the object creation dialog. For this purpose, at first, your client application has to create the object with the desired binary content file assigned to it. A generic document object type can be used. If this process is automatized by the client application, the user dialog for object creation can now display the content preview to make the users' decision for a PFSOT and/or the corresponding property values easier.

In the following example code block, a generic document object type preemail and a characterizing PFSOT emailsot are defined. The preemail object type is not offered to users in the object creation dialog. It does not reference any properties directly, but it references the appClientsystem:leadingType, appClient:clientdefaults and emailsot SOTs. The emailsot PFSOT references the properties users may need to handle e-mail objects.

Example for using FSOTs
<typeDocumentDefinition>
    <id>preemail</id>
    <description>...</description>
    <baseId>system:document</baseId>
    <classification>appClient:search:false</classification>
    <classification>appClient:create:false</classification>
    <contentStreamAllowed>required</contentStreamAllowed>
    <secondaryObjectTypeId>appClientSystem:leadingType</secondaryObjectTypeId>
    <secondaryObjectTypeId static="false">appClient:clientdefaults</secondaryObjectTypeId>
    <secondaryObjectTypeId static="false">emailsot</secondaryObjectTypeId>
</typeDocumentDefinition>
<typeSecondaryDefinition>
    <id>emailsot</id>
    <baseId>system:secondary</baseId>
    <propertyReference>from</propertyReference>
    <propertyReference>to</propertyReference>
    <propertyReference>cc</propertyReference>
    <propertyReference>subject</propertyReference>
    <propertyReference>hasattachment</propertyReference>
    <propertyReference>attachmentnames</propertyReference>
    <propertyReference>received</propertyReference>
    <classification>appClient:primary</classification>
</typeSecondaryDefinition>

The client application automatically uses the preemail type to create the object after users have selected a binary content file. In a second step in the object creation dialog, the content preview is displayed to the users who can now read it in order to specify the properties provided by the emailsot PFSOT. The following screenshot shows an example for a CREATE form modeled in yuuvis® architect on the left, next to a content preview on the right. The data specified in this form is extracted from the e-mail file. The next section describes how to model and script this automatic metadata extraction.

Property Classifications

You can use the following values for the classification attribute in property definitions of the suitable types to control the form field behavior in your client application. The corresponding controls can be added to the Summary aspect area, edit and create forms, hit lists, and filters.

Value for 'classification' Property type Description

email

string

An e-mail icon is displayed beside the form field. A click on the icon opens the locally installed e-mail client with the e-mail address specified.

The entered value is validated via an internal browser function. Valid addresses have to match the standard.

Values like "Mike Johnson" <mike.johnson@mycompany.com> result in case rendering problems. Use only mike.johnson@mycompany.com instead.

url

string

A URL icon is displayed beside the form field. A click on the icon opens the specified URL in a browser.

The entered value is validated via an internal browser function. Valid addresses have to match the standard.

phone

string

A phone icon is displayed beside the form field. A click on the icon opens the specified number in the available phone application. In Chrome, a connected Android phone can be used.

No validation takes place.

id:organization (as of 2022 Spring)

id:organization[APPROVER1,APPROVER2] (as of 2022 Summer)

id:organization[APPROVER1,APPROVER2,username1] (as of 2023 Spring)

string

Useful for properties that store a user ID and appear with the corresponding user name. As soon as users start typing in the form field, a selection list with user names is provided for which the entered term was found in the user name, name, surname or e-mail address. If users select one of them, the corresponding user ID is stored as property value while the user name is shown in the form as a chip.

If roles are specified, only user names of users having at least one of those roles are offered for the corresponding form field.

id:reference[]

id:reference[myObjectTypeId,…​]

string

Useful for properties that store an object type ID or an object ID and appear with the corresponding object type or object name. As soon as users start typing in the form field, a selection list with matching object type or object names is provided. If users select one of them, the corresponding object type ID or object ID is stored while the name is shown in the form as a chip. If no name is available, the ID is displayed instead.

For object ID property fields, an Anchor icon is additionally displayed beside the form field. A click on this icon opens the referenced object.

For object type ID property fields, it is possible to limit the object types that are offered to users in the selection list. For this purpose, specify all object type IDs to be considered in the classification attribute. An empty list allows all object types. Note: It is not possible to specify base types (system:object, system:folder, system:documents).

catalog[new,draft,review,released,rejected]

string

Configuration of a static catalog. Users can only select the values specified in the list. Only one language is supported here.

Pattern to be used in the global schema: dynamic:catalog[myObjecttype,readonly]

Pattern to be used in an app schema: dynamic:catalog[appMyapp:myObjecttype,readonly]

Pattern to be used in a tenant schema: dynamic:catalog[tenMytenant:myObjecttype,readonly]

string

Configuration of a dynamic catalog that can be maintained per tenant. Users can only select the values specified in the list. Users with the YUUVIS_MANAGE_SETTINGS role can deactivate and remove values or add new values if the optional parameter readonly is NOT set. Only one language is supported here.

The catalog values are stored separately for each tenant.

It is possible to set up standard values for each catalog using a specific system controller endpoint of the Web-API Gateway. If no tenant-specific variant has been saved so far, the standard values are used.

custom:catalog[myURL]

string

Retrieves the catalog values from a custom microservice that is called via the specified URL. The URL can be absolute (e.g., https://mydomain/myservice/myfunction?myparameter=mycatalogname) or relative (e.g., /myservice/myfunction?myparameter=mycatalogname).

If an absolute URL is used, ensure to handle CORS issues.

The internal token with the user information is transferred to the microservice. The language set by the user can be read from the header. The response format must have the following JSON structure:

{
  "entries": [
    {"name": "Bill", "disabled": "false"},
    {"name": "Ted", "disabled": "false"}
  ];
}

digit

number

Numbers are rendered with a delimiter, e.g., 123,456,789.35. Otherwise, no digital grouping is used, e.g., 123456789.35.

sortable

table

Enables the user to sort table rows manually by drag & drop.

switch

boolean

Values are represented by a switch with the available positions true (right position), false (left position) and null (middle position).

Per default (if switch is not specified), the values for boolean properties are displayed as checkboxes. A null value is represented as crossed-out box.

appClient:standardform:hidden

any type

The property is not displayed in any standard form by the client application.

appClient:summary:hidden (as of 2022 Summer)

any type

The property is not displayed in the summary aspect area of objects displayed by the client application.

4.5.6. Preview of Content Files

In addition to forms containing the metadata of a DMS object, a preview of the binary content file assigned to it can be displayed. In a client application based on our developer libraries, the content preview is retrieved either via the VIEWER Service or PDF renditions.

It is also possible to compare previews for two different binary content files. They can either belong to two different DMS objects or to two different versions of the same object.

Supported Formats

The content preview can be displayed if the file type of the binary content file is supported.

  • If possible, the VIEWER service is always used.

  • If the format is not supported by the VIEWER service, a PDF rendition is requested and displayed if the format is supported.

    A PDF rendition can only be retrieved for binary content files assigned to the current version of a DMS object. This means that only the preview of the current version will be displayed, when comparing different versions of a DMS object containing a content file whose format is not supported by the VIEWER Service, but only by the PDF rendition.

If the format is neither supported by VIEWER nor rendition service, no content preview can be displayed.

4.5.7. Maintaining Dynamic Catalogs

In some metadata fields, you may want to provide a selection list of possible values from which the users have to choose. Those lists are configured via so-called catalogs. In their schema definition, they can be configured to be editable or not directly in your client for users with the proper authorization. A change in the schema definition is not required in order to modify the available values for the so-called dynamic catalogs.

Dynamic catalogs are introduced into the Web-API gateway with version 2021 Summer.

We use the term catalog from a technical perspective and the term list from the user’s perspective.
The catalog values (corresponding to list elements) cannot be localized.
The list elements cannot be manipulated by client form scripting.
Defining Dynamic Catalogs

A property can be classified in the schema definition to be displayed as a dynamic catalog in your client by setting the value dynamic:catalog[<catalog name>] for the attribute classification. Per default, the catalog name will be used as display name in your client. It can be localized in order to replace the display name. We recommend using naming conventions as described below which make it easy to distinguish between tenant-specific and global catalogs.

The catalog values are saved in a JSON file in the config server beside the corresponding schema configuration.

Catalogs can be set as readonly via Web-API gateway. Thus, the catalog values cannot be modified via the dms-controller endpoints of the Web-API gateway. Since the client uses the dms-controller endpoints, the corresponding selection list elements in the client will also not be editable. Changes can be applied only via the system-controller endpoints in case of global catalogs and via the admin-controller endpoints in case of tenant-specific catalogs. This catalog management is also possible via yuuvis® architect.

In order to avoid empty selection lists in your client, we recommend to create the JSON configuration of the catalog first and introduce the definition into the schema afterwards.

Tenant-Specific Dynamic Catalogs

If only one specific tenant will use a dynamic catalog, it is recommended to configure this catalog as a tenant-specific property. Its technical name should follow the naming convention ten<tenantname>:<catalogname>. A user with access to the Admin Endpoints and admin-controller Endpoints (default: user with the YUUVIS_TENANT_ADMIN role) is required.

The catalog values are saved in the config server beside the tenant schema configuration.

In the following code block, an example schema definition of the example string property contract is displayed. The property is classified in line 6 to be a dynamic catalog which is displayed as a selection list with the technical name tenMytenant:contracts in your client. Initially, the list of values offered to users will be empty.

Schema excerpt example of a field of type string of classification dynamic catalog
1
2
3
4
5
6
7
<propertyStringDefinition>
    <id>contract</id>
    <propertyType>string</propertyType>
    <cardinality>single</cardinality>
    <required>false</required>
    <classification>dynamic:catalog[tenMytenant:contracts]</classification>
</propertyStringDefinition>

If the example schema is uploaded as a tenant schema via the POST /api/admin/schema endpoint by a user of the example tenant mytenant, the property contract will be available only in the specific tenant mytenant. After restarting your client, the users will get an empty selection list for the field called tenMytenant:contracts.

Global Dynamic Catalogs

If the dynamic catalog should be available to all tenants, it has to be configured as global property. This means that the property definition classified as dynamic catalog has to belong either to the system schema or to an app schema. Its values are stored in the config server besides the global schema or the corresponding app schema.

For catalogs in an app schema, we recommend the naming convention app<appname>:<catalogname>. For global catalogs, we recommend to use no special prefix but only the catalog name <catalogname>.

Also global dynamic catalogs can be defined to be editable for users with the advancedUserRole (default: users with the YUUVIS_MANAGE_SETTINGS role). If the modified catalog values are saved, a tenant-specific copy of the global JSON configuration is saved besides the tenant schema together with the values of tenant-specific catalogs. Whenever a global catalog is retrieved via the Web-API gateway, the tenant-specific copy will be returned for that tenant. If no tenant-specific copy exists, the global configuration is returned. This might happen if the global catalog is not editable or no changes were applied to the global catalog within the active tenant.

Not-Editable Global Catalogs

Users user with access to the System Endpoints and system-controller Endpoints (default: users with the YUUVIS_SYSTEM_INTEGRATOR role) can set up global catalogs with initial standard elements and set the catalogs to readonly.

In this case, you should only use standard values that are suitable for all tenants.

The following code block shows an example property definition cut from an example app schema. If the example schema is uploaded as an app schema via the POST /api/system/apps/{app}/schema endpoint for the example app myapplication, the property contract will not only be available for the specific app myapplication, but to all tenants using this app. After restarting your client, the users will get an empty selection list for the field called appMyapplication:contracts.

Schema excerpt example of a field of type string of classification dynamic catalog
<propertyStringDefinition>
    <id>contract</id>
    <propertyType>string</propertyType>
    <cardinality>single</cardinality>
    <required>false</required>
    <classification>dynamic:catalog[appMyapplication:contracts]</classification>
</propertyStringDefinition>

The following code block shows an example property definition cut from an example system schema. If the example schema is uploaded as system schema via the POST /api/system/schema endpoint , the property contract will be available in all tenants and for all applications. After restarting your client, the users will get an empty selection list for the field called contracts.

Schema excerpt example of a field of type string of classification dynamic catalog
<propertyStringDefinition>
    <id>contract</id>
    <propertyType>string</propertyType>
    <cardinality>single</cardinality>
    <required>false</required>
    <classification>dynamic:catalog[contracts]</classification>
</propertyStringDefinition>
Editable Global Catalogs

If the catalog parameter readonly is not set, users with the advancedUserRole (default: users with the YUUVIS_MANAGE_SETTINGS role) can change the list elements in your client. With the first update of such a catalog, a new catalog with the same technical name (without additional tenant-specific prefix) is saved for that tenant.

Changes of the global catalog saved via system-controller do not affect the copy.
Editing Catalog Values

The following actions are supported for editable catalogs/selection lists:

  • Create a new list element.

  • Remove a list element. A warning is given if this element is used by an object.

  • Disable a list element. Such elements are offered for search but not while creating or editing an object.

Editing via Client

Users with the advancedUserRole (default: users with the YUUVIS_MANAGE_SETTINGS role) can maintain pick lists that are based on a property classified as a dynamic catalog without the readonly parameter.

The edit dialog can be opened by clicking the pencil icon next to the field. The screenshot below shows the edit dialog for the example selection list contracts where the four values Employment contract, Rental agreement, User contract, and Purchase contract were already added.

Editing via Web-API Gateway

admin-controller

Users with access to the admin-controller Endpoints (default: user with the YUUVIS_TENANT_ADMIN role) are offered the maintenance actions also in read-only catalogs via the Web-API Gateway GET and POST endpoints https://<domain>/api-web/admin/catalogs/tenMytenant:contracts.

The following example shows a tenant-specific list of four elements stored for the tenant mytenant:

Example for a tenant-specific dynamic catalog
{
  "tenant": "Mytenant",
  "readonly" true,
  "entries": [
    {
      "name": "Employment contract",
      "disabled": false
    },
    {
      "name": "Rental agreement",
      "disabled": false
    },
    {
      "name": "User contract",
      "disabled": false
    },
    {
      "name": "Purchase contract",
      "disabled": false
    }
  ]
}

system-controller

In case of global catalogs, the Web-API Gateway system-controller endpoints GET and POST are used. In the default configuration, the role YUUVIS_SYSTEM_INTEGRATOR is required.

Global catalogs without an appschemaname are saved in the config service beside the system schema configuration. Otherwise, the catalogs are saved besides the app schema configurations.

dms-controller

The client uses the Web-API Gateway dms-controller endpoints that require per default the YUUVIS_MANAGE_SETTINGS role in case of POST and PATCH requests:

Swagger UI

There is a Swagger UI that supports you in using the mentioned endpoints: https://<domain>/api-web/swagger-ui.html. The screenshot below displays a part of the Web-API Gateway Swagger UI showing the first endpoints of the admin-controller.

4.5.8. Styling

If you are creating a new application intended to handle specific data of the yuuvis® backends and you only need the CSS files, you can use the npm package: https://www.npmjs.com/package/@yuuvis/styles.

Shortly, we will publish a website that shows all styles used as an example application on https://yuuvis-cc.yuuvis.org/

Changing the Appearance of Form Controls As with most of the components of the @yuuvis/framework, you are able to overwrite styling using CSS. To globally change the look and feel of components, we recommend to create a new *.scss file that you import in your project’s styles.scss (Make sure to place the import after the imported styles from @yuuvis/framework). The following code snippet changes the position of labels in forms:

1
2
3
4
5
6
7
8
9
10
11
yuv-object-form .yuv-form-input:not(.checkbox) .fe-wrapper {
  > label {
    order: 0;
  }
  > .control {
    order: 1;
  }
  > .tag {
    order: 2;
  }
}

You could also position the labels at the top of the input:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
yuv-object-form .yuv-form-input:not(.checkbox) .fe-wrapper {
  display: grid;
  grid-template-rows: auto 1fr;
  grid-template-columns: auto 1fr;
  grid-template-areas:
    'label tag'
    'fe fe';

  > label {
    grid-area: label;
  }
  > .control {
    grid-area: fe;
  }
  > .tag {
    grid-area: tag;
  }
}

4.5.9. Customizing the Dashboard

Feature in ALPHA Phase
As of version 2022 Winter, the feature is still in a testing phase. We preserve the right to apply any changes to its functionality.

The @yuuvis/widget-grid developer library allows users to individually customize the client’s dashboard according to their preferences.

A demo application shows how to configure widgets and how to use them to provide saved searches for the client user. Example code on gitHub.

Library Installation and Activation

Install and configure the @yuuvis/widget-grid and @yuuvis/widget-grid-widgets libraries with the widgets you want to enable for your users.

To enable the usage of a customizable dashboard in your client application, set the dashboardWorkspaces parameter to true in the main.json configuration file.

Users can now choose between the default dashboard and an individually designed custom dashboard via the client’s settings menu.

Configuring Workspaces

Users can configure multiple layouts for their dashboard and save them as so-called workspaces. To switch between workspaces, click the buttons with the workspace names in the bottom left corner.

Create a new workspace via the + Plus icon in the bottom left corner or edit the activated workspace via the Pencil icon in the bottom right corner. You can now

  • add new widgets via the + Plus icon in the bottom right corner,

  • change size and position of individual widgets by mouse actions

  • delete individual widgets or

  • edit individual widgets.

The edit mode for individual widgets depends on the widget type.

The custom dashboard configuration is stored via USERSERVICE and is thus available on any device in which users might log-in. However, users can activate the usage of the default dashboard or the customizable dashboard depending on their used device.

Widget Types

The following widget types are provided as default by the libraries. You can easily extend the list with your own widgets according to your needs. Just create a component and register it.

  • Hit list or count tile

    • Display search results for a configured query.

  • Stored query

    • Configure the search conditions you frequently need.

    • Specify the object type first if needed. A form with the corresponding metadata fields will open.

    • Specify conditions using the metadata fields if needed.

    • Specify a term for full-text search if needed.

    • Click Next to continue.

    • From the list of metadata fields presented on the left side, select the fields you want to fill via dashboard widget.

    • Click Next to continue.

    • Define the sorting to be applied to hit lists resulting from search requests coming from this widget.

    • Tick the total hits checkbox to display the number of hits as a preview on the dashboard before opening the hit list view.

  • Chart

  • Quick search

    • Display a search bar on your dashboard.

  • A picture

    • Add any image to your dashboard.

  • To do list

    • Display a checkbox list.

  • Summation

    • Specify a number-type metadata property available in one or more object types. All objects with this property will be searched and the values are totaled.

    • Additionally, you can apply conditions to the objects that should be included into the summation.

    • In the template field, you can add a measuring unit that will be always displayed with the calculated total number on the custom dashboard.

4.5.10. Form Scripting

If you configure custom forms for objects, you can additionally use executable scripts to, e.g., validate data, change data, change field properties - such as "read-only" or "mandatory" - and show context-related messages. Form-related scripts enhance your options by adding further functionalities to support your use cases and processes the best.

In yuuvis® Momentum client, you can use executable scripts to:

  • validate data

  • change data, for example by calculating a value based on other values

  • change field properties, such as read-only and visibility

  • show context-related messages.

Some things to note about script properties:

  • Client scripts in yuuvis® Momentum architect are written in JavaScript (ECMAScript).

  • Client scripts execute in the user’s browser using the browser’s native JavaScript runtime.

  • You can define client scripts by object type and form situation.

When field data changes are made using a script (i.e., without user action) when loading the form, the Save option is not available. In contrast, you can disable fields to protect against user changes.
Script Scope

The relevant object is given to each client script under the name 'scope.' This object provides the API so the scripts can access the object fields and their properties.

Properties of scope:

Name Description

api

Supplies access to the plug-in API, with 'session' (user information), 'dms' (object details, search via DMS-Service), 'http' (connection to any service), 'config', 'util' (helper functions) and 'agent' properties.

data

Supplies all object fields defined in the object or process activity. The fields offer read-only access using the technical name. Available for releases 2017-09-27 (3.22.x) or later.

model

Supplies the flattened form model and all object fields defined on the form. The fields can be accessed with the technical name. The form groups cannot be accessed in this way.

situation

Supplies the current form model situation. Scripts can respond to the relevant situation. Possible values are 'CREATE' (create), 'SEARCH' (search) and 'EDIT' (edit index data).

objectId

Supplies the ID of the current DMS object if available (available since version 6.4).

scope.data

A value of a system property of an object can be read using scope.data['system:<property name>']. These are some of the available system properties. You can find more in the browser console when looking for the currently loaded form script and hovering over 'scope' and looking for section 'data':

Name Description

system:objectId

Unique ID of the object

system:objectTypeID

Technical name of the object type, e.g., 'tenMytenant:customer'

system:baseTypeId

Specifies whether an object is of type 'folder' or 'document'

system:creationDate

The date and time of cration in the format 'yyyy-mm-ddThh-mm-ss.xxxZ'

system:createdBy

The title of the user that created the object in the format <name>,<surname> (<loginname>)

system:lastModificationDate

The date and time of last modification in the format 'yyyy-mm-ddThh-mm-ss.xxxZ'

system:lastModifiedBy

The title of the last user that edited the object in the format <name>,<surname> (<loginname>)

system:versionNumber

Current version number of the object

system:secondaryObjectTypeIds

This array lists all secondary object types that are part of the current object instance

system:tenant

The tenant name as used when created

system:traceId

Trace ID of the object (todo: write about the meaning)

system:parentId

This ID is given if a document object is filed into a folder.

Evaluate on data and getUser()
1
2
3
4
// assign the current objectId to a reference field and the current userId to an organisation field:
scope.model['tenMytenant:reference'].value = scope.data['system:objectId'];
scope.model['tenMytenant:user'].value = scope.api.session.getUser().id;
For scope.api please refer to "Client Scripting API".
scope.situation

For object types, you can create a default form to be used for the CREATE, EDIT and SEARCH situations. In each situation, any included scripts are active. If a general form is used, but different data management is necessary, it is possible to check which situation is given. For example, how to deactivate a form script to be used in the 'SEARCH' situation.

Check situation
1
2
if( scope.situation == 'CREATE' ) return;      // another situation value is EDIT
// ... additional script code
scope.model

This section describes how to access all form elements of objects or processes.

General object field properties

The following table describes object field properties that can be accessed with 'scope.model'.

Column "Binding"

  1. RO (ReadOnly): ReadOnly properties can only be read. Changes to the values of RO properties do not affect the interface.

  2. RW (ReadWrite): ReadWrite properties can also be written. Changes to the values of RW properties affect the interface.

Each field has the following properties:

Name Description Binding

name

The normalized name of the fields. Normalized means the simple field name is lower case. The name must not contain special characters except one ':'. This name is used to map the fields to the 'model.'

RO*

label

The display name of the type in the current user locale. Used as a field identifier.

RO

description

A field description. Can be used in tooltips for example.

RO

type

Describes the data type of the field. The possible values here are documented in the description of field data types. Other field attributes may exist, depending on the data type.

RO

readonly

If the read-only property is set to 'true,' the user cannot change the field value.

RW**

required

Flags a field as mandatory. If this property is set, the user must make an entry.

RW

value

The current value of the field.

RW

cardinality

In case of 'multi' instead of 'single' (equal 'undefined') a list of values can be maintained. A JavaScript array is then always expected in 'value.'

Not every data type supports the 'multiselect' property.

RO

*RO (ReadOnly): ReadOnly properties can only be read. Value changes of RO properties do not affect the interface.

**RW (ReadWrite): ReadWrite properties can also be written. Value changes of RW properties affect the interface.

The following example validates dynamic field properties for required fields and write permissions.

Example: onChange handler for form validation and user input
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// Abbreviate with 'm' in the FormModel of the scope.
// You could just use 'scope.model' everywhere instead of 'm'.
var m = scope.model;
// We want to know if the active state changes
// To do so, we register an onchange handler function
m['tenMytenant:aktiv'].onchange=updateActiveState;
// The logic should also run when there are changes in the area, since we want to
// control the error state of the script here.
m['tenMytenant:area'].onchange=updateActiveState;
// When the weekly hours change, we want to know this for our calculation
m['tenMytenant:weekhours'].onchange=updateWeekdays;

// Here is the logic implementation for what happens when the active state changes

function updateActiveState() {

  // Employee initials + status + employee number are required fields,
  // when the employee is active.
  m['tenMytenant:emplshort'].required      = active;
  m['tenMytenant:status'].required         = active;
  m['tenMytenant:personnelno'].required     = active;

  // The regulations cannot be changed as long as the employee is active.
  m['tenMytenant:unbefristet'].readonly        = active;
  m['tenMytenant:zielvereinbarung'].readonly   = active;
  m['tenMytenant:altersvorsorge'].readonly     = active;

  // Example for a deliberately set validation error with relevant error message
  // take into account that the error message will be offered for non read-only fields!
  if( active && (!m['tenMytenant:area'].value || m['tenMytenant:area'].value=='') ) {
    m['tenMytenant:area'].error = {msg:'Ein aktiver Mitarbeiter muss einem Bereich zugeordnet sein.'};
  } else {
    // If the validation error does not occur, we may have to reset a previously set error:
    if (scope.user) {
        m['tenMytenant:area'].error = null;
    }
    m['tenMytenant:aea'].error = null;
  }
}
// Here we calculate the weekdays
function updateWeekdays() {
    m['tenMytenant:weekdays'].value=m['tenMytenant:weekdays'].value / 8;
}

// Since the active/not active logic should already apply during form initialization,
// we call the function here.
updateActiveState();
Data types

The following table gives an overview of the possible data types per field. The JavaScript data type lists what is expected as the 'value' of an element.

If the 'multiselect' property is set, then the JavaScript data type is an array of the data type.

Name Description JavaScript data type Multi-selection

STRING

Any text. See also datatype: STRING.

String

Yes

NUMBER

Number and floating point number. See also datatype: NUMBER.

Number

Yes

BOOLEAN

Simple 'on/off' or 'true/false' value.

Boolean

No

DATETIME

A date or a date with time value.

Date

Yes

ORGANIZATION

A string field for saving user IDs. The title of the user is shown, or the ID if no title exists.

String

Yes

ID

A string field for saving object IDs. The IDs can be restricted to the specified object types defined in the classification tag 'id:reference[object type 1, object type 2, …​]. The title of the object is shown, or the ID if no title exists, or '!' if the object cannot be accessed. String Yes CATALOG A string field for saving elements of a given array in the classification tag 'catalog[value1, value2, …​]' String Yes TABLE A table with columns of the above data types

Table

No

STRING

For fields of type 'string' the following properties are given:

Name Description Binding

maxlen

The maximum number of characters permitted as a value in this field.

RO

minlen

The minimum number of characters permitted as a value in this field. RO

classification

*RO (ReadOnly): ReadOnly properties can only be read. Changes to values of RO properties do not affect the interface.

**RW (ReadWrite): ReadWrite properties can also be written. Changes to values of RW properties affect the interface.

NUMBERS

For fields of type integer and decimal the following properties are given:

Name Description Binding

maxvalue

The maximum number permitted as a value in this field.

RO

minvalue

The minimum number permitted as a value in this field.

RO

classification

If 'digital' is set the numbers are formatted with a thousand separator, e.g. for Din EN 1,569,345.43 and DE 1.569.345,43

RO

*RO (ReadOnly): ReadOnly properties can only be read. Changes to values of RO properties do not affect the interface.

**RW (ReadWrite): ReadWrite properties can also be written. Changes to values of RW properties affect the interface.

DATE

Sample Script: Specifying a date in the future

When determining a deadline for working on the next process step, you want to make sure the date is not in the past.

Example: Validate a date in the future
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var m=scope.model;
// The name of the date field is Deadline
var deadline=m['myTenant:deadline'];


// Register the onchange handler
deadline.onchange=updateDeadlineState;


// Next is the logic for what we want to happen if the state changes
function updateDeadlineState() {

  if( isBeforeToday( deadline.value ) ) {
    deadline.error = {msg:'Please select a date in the future.'};
  } else {
    // If the validation error does not occur, we may have to delete a previously-set error
    deadline.error = null;
  }
}
function isBeforeToday( pDate ) {

  // Todo: rework not available moment to a different function:
    var date = new Date();
    var today = moment(date).startOf('day');
    return moment(pDate).isBefore(today);

}
DATETIME

Important to know:

1
2
3
4
5
6
// allowed:
scope.model['tenMytenant:datetime'].value = new Date()
scope.model['tenMytenant:datetime'].value = moment().toDate()

// not allowed, sets the date one day into the past after save:
scope.model['tenMytenant:datetime'].value = moment();
TABLE

As of version 2.4, tables are supported.

Expects a JavaScript 'Object Array' as a 'value.' The properties of each object are defined by the column elements of the table. See the following example.

Example: Manipulating table data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* Example script: Manipulating table data based on index data change.
*/
// Add change listener to field 'myTenant:number'
scope.model.['myTenant:number'].onchange=function() {

    // The current user input on field with the internal name 'myTenant:number'
    var num = scope.model.['myTenant:number'].value;

    // Shortcut to access the table
    var table = scope.model.['myTenant:changes'];

    if(num>0 ) {
        // If 'myTenant:number' is set (greater than 0) we automatically fill the table
        if( !table.readonly ) {
            // The user may not modify the table
            table.readonly=true
        }
    } else {
        // If 'myTenant:number' is not set (less than 0) we let the user fill the table
        if( table.readonly ) {
            // The user may modify the table
            table.readonly=false
        }
    }
    // automatically fills the table if 'myTenant:number' is greater than 0
    // and add num rows to the table
    if(num>0) {
        // Clean up the table by setting a empty array
        table.value.length=0;   // changes of a single cell must be done in an array variable first,
                                // and then this array has to be pushed back to the table.
        for( i=0; i<num; i++ ) {
            // For each 'myTenant:number' add a row
            // Each row is an object defined by the internal names of the column elements.
            table.value.push(
                {
                    'myTenant:accepted': i%2,                              // Boolean
                    'myTenant:created': new Date() ,        // Date
                    'myTenant:activedate': new Date(),     // Another date
                    'myTenant:author': 'Marie Curie '+i,                       // String: Author name with i postfix
                    'myTenant:prio': i+.42,                                    // Decimal
                    'myTenant:company' : 'OSVH'                                // Codesystem - the 'data' values must be used.
                }
            )
        } // end for num
    } // end if num>0
}

Callback for tables:

Name Description

onrowedit

This callback is called when the user starts to edit a table row. Like 'onchange,' the first parameter contains the field element (the table itself). The second parameter contains a 'row' object, which describes the row the user wants to edit.

The 'row' object

The 'row' object is transferred as the second parameter during the 'onrowedit' callback for table fields.

Name Description Binding

index

Row index: '-1' for newly created rows. The first row has the value '0'.

RO*

copyEnabled

Controls whether the "Copy and create as new row" function is enabled. You can only edit this synchronously inside the onrowedit.

RW**

deleteEnabled

Controls whether the "Delete row" feature is enabled. You can only edit this synchronously inside the onrowedit.

RW

saveEnabled

Controls whether the "Save row" feature is enabled. You can only edit this synchronously inside the onrowedit.

RW

persisted

Is 'false' if the edited file was newly created. The property remains 'false' for new rows until the index data is saved. You can use this property to differentiate between a row that has been saved or newly created by the user during the current index data editing.

RO

model

Provides access to the model of the current row. With this model, the script can access and modify the values and element properties of the current row.

RW

*RO (ReadOnly): ReadOnly properties can only be read. Value changes of RO properties do not affect the interface.

**RW (ReadWrite): ReadWrite properties can also be written. Value changes of RW properties affect the interface.

See how the 'row' object is used in the following example.

Example: Table row scripting (onrowedit)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Example for row edit
// The 'scope.model.['myTenant:notices']' element is a table type with a few columns.
// This example script tries to achieve that only new rows can be edited. New rows are rows that the user has not saved yet.
scope.model.['myTenant:notices'].onrowedit=function(table,row) {
// 'table' is the element, the callback event was triggered.
// In this case the same as scope.model.notices. 'row' is the row object.

    // Show some information as a toast notification - just for demonstration
    scope.api.util.notifier.info("Editing table row","A row at index "+row.index+" is being edited.");

    // First we check whether the row is a new, not yet persisted, row, or an existing row
    if(!row.persisted) {
        // This is a row created by the user.
        // He is allowed to change it. So all table columns are set to be editable
        // by setting all row fields' readonly property (the column elements) to false.
        Object.keys(row.model).forEach( function(e) { e.readonly=false });

        // Delete/save is enabled by default, but the user is not allowed to copy the existing row as a new one.
        // So we switch off the copy function.
        row.copyEnabled = false;
    } else {
        // This is an already-saved row, so cell values are no longer editable, we have set them all to read only.
        Object.keys(row.model).forEach( function(e) { e.readonly=true });

        // Copy/delete/save are all disabled. The user can only 'cancel' the row editing. Nothing else.
        row.copyEnabled = false;
        row.deleteEnabled = false;
        row.saveEnabled = false;
    }
}
onChange handler for table cells

You define table rows in the form model (scope.model). Here you can set properties for each row. When the user edits a row, the system creates a temporary copy of the table elements. This copy can be accessed by a form script using the second parameter in the onchange Handler. Changes to the model are immediately visible in the table editing dialog. Changes to the properties of rowmodel are discarded when row editing has ended.

Example: onChange handler for a table cell
1
2
3
4
5
6
7
scope.model.['myTenant:mytable'].onrowedit = function(table, row){
// On this element we register a value change handler
row.model.['myTenant:number'].onchange = function(el, rowmodel) {
// The rowmodel provides access to the other elements
rowmodel.['myTenant:number'].readonly = ( el.value == 42 );
}
}
Manipulating row cells when one cell has been changed
1
2
3
4
5
6
7
8
9
var countries = scope.model.['myTenant:addresslist'].onrowedit=function(table,row){
row.model.['myTenant:country'].onchange=function() {
if(row.model.['myTenant:country'].value === 'Germany'){
row.model.['myTenant:zip'].required=true;       // depending on value of country set a zip code as mandatory
} else {
row.model.['myTenant:zip'].required=false;
}
}
}
Manipulating multiple row cells

If we deal with more complex table value manipulation, we need to create a copy of the values. Once the values are written, the table is populated and changes will be lost. Once all the cell manipulations are done, we can assign the manipulated values to the table values.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// see Manipulating table data
...
let tableCopy = JSON.parse(JSON.stringify(['myTenant:mytable'].value)); //create a copy
for ( i = 0; i < num; i++ ) {
if (i === 0) {
tableCopy[i].['myTenant:accepted'] = !i%2,                               // Boolean
tableCopy[i].['myTenant:created'] = new Date(),    // Date
tableCopy[i].['myTenant:activedate'] = new Date(), // Another date
tableCopy[i].['myTenant:author'] = 'Pierre Curie '+i,                    // String: Author name with i postfix
            tableCopy[i].['myTenant:prio'] = i+.00,                                  // Decimal
tableCopy[i].['myTenant:company'] = 'OSVH'                               // Catalog values must be used.
} else {
// For each number add a row
// Each row is an object defined by the internal names of the column elements.
tableCopy.push({
'myTenant:accepted': i%2,                              // Boolean
'myTenant:created': new Date(),    // Date
'myTenant:activedate': new Date(), // Another date
'myTenant:author': 'Marie Curie '+i,                   // String: Author name with i postfix
                'myTenant:prio': i+.42,                                // Decimal
'myTenant:company': 'OSVH'                             // String: Element of a catalog
});
}
// do even more fancy data manipulations
} // end for num
table.value = tableCopy;
...
// see Manipulating table data
scope.api.<more>

Please refer to the Client Scripting API documentation for more features you may use for specific requirements like notifying users, getting information about the current user, or calling other services via http.

4.5.11. Client Scripting

This article describes the Client Scripting API used to develop custom clients as well as client-side form scripts. For more information on building custom clients, refer to the client API documentation.

scope.api

The API is available by using scope.api.<more>

scope.api.router

Please note that this function is not supported in the form scripts.

scope.api.router.get() returns the Angular router.

Example:

scope.api.router.navigate('/versions/edfd46a3-daa9-4192-8223-2cc6d4847314?version=2') leads the application to open the 'version' state with this object ID focussing version 2.

scope.api.events

Please note that this function is not supported in the form scripts

Events can be triggered by a component. Listening components can then react.

Type of events

There are several client-specific events. The most common ones are bundled in the const "yuvEvent."

Inside a form script they are bundled in the "scope.api.events.yuuvisEventType" const .

Type Description Data

LOGOUT

on logout

CLIENT_LOCALE_CHANGED

the client locale has changed

ISO locale string

DMS_OBJECT_DELETED

a DMS object was deleted

the deleted DMS object

DMS_OBJECT_UPDATED

a DMS object was updated (index data, content, subscription, …​)

the updated DMS object

DMS_OBJECTS_MOVED

DMS objects were moved to another folder object

the moved DMS objects

DIALOG_STACK_CHANGED

the dialog stack has changed

an object with ID and active status of the dialog

scope.api.events.trigger()

Please note that this function is not supported in the form scripts.

With this function, you can trigger an event of a type mentioned above.

Parameter Type Description

type

string

type of the event

data

any

(optional) data associated with the event

Example
1
scope.api.events.trigger(DMS_OBJECT_UPDATED, dmsObject);

scope.api.events.on()

With this function, you can listen to events of the type mentioned above.

Parameter Type Description

type

string

type of the event

Returns an Observable containing type and data.

Example
scope.api.events.on(scope.api.events.yuuvisEventType.DMS_OBJECT_UPDATED).subscribe(event => {
let dmsObject = event.data;
let eventType = event.type;
});
scope.api.session

Currently, only the following session function is available.

scope.api.session.getUser() (user information)

The function scope.api.session.getUser() returns the user object, in which the following properties about the currently logged-in user are available. They are read-only.

Name Description

id

System ID given by the identity service

username

Login name

firstname

First name

lastname

Last name

title

Displayed name in the format of lastname, firstname

email

E-mail address authorities String array with the roles for which the user is authorized

userSettings.locale

Application language in ISO code (de, en, …​) as configured in the client settings

Sample script:

Aktueller Benutzer
1
2
3
4
5
6
// Write information for the current user in a model value
// The model value must be a STRING type.
var u=scope.api.session.getUser();
scope.model['tenMytenant:text'].value=
'- Login name               \n'+u.name+'\n'+
'- Roles                    \n'+u.authorities.join()+'\n'+
scope.api.util

A list of helper functions follows:

scope.api.util.notifier (display messages)

This helper can be used to display messages in the form of a toaster.

Functions:

Name Description Color since version

success(message[,title])

Displays a success message

Green

3.3

error(message[,title])

Displays an error message

Red

3.3

info(message[,title])

Displays an informational message

Gray

3.3

warning(message[,title])

Displays a warning message

Orange

4.1

Example: Messages
1
2
3
4
5
6
7
8
scope.model['tenMytenant:unlimited'].onchange=function() {
if( scope.model['tenMytenant:unlimited'].value ) {
scope.api.util.notifier.success(
scope.model['tenMytenant:firstname'].value +' ' + ...',        // Message
'Personal information changed'                                  // optional: use a short title
);
}
}

The success message is displayed in green.

scope.api.util.encodeFileName

Please note that this function is not supported in the form scripts

Encodes a file name safe for sending characters beyond ASCII-7bit using quoted printable encoding.

More information to come.

scope.api.http

You can use HTTP requests to get data from any service of the system, including custom microservices, which are part of the yuuvis® Momentum microservice infrastructure.

The following standard functions are supported: get, post, put and delete.

If you want a format different from JSON, you have to add a third parameter {responseType: 'arraybuffer' | 'blob' | 'json' | 'text'}.

scope.api.http.get

This function works with a mandatory parameter for the url and a second optional one that controls whether to use the core-api endpoints instead of those of the API-WEB (web-api gateway) which is the primary one for the client.

Example for get
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// http.get example: request for extraction data and map value of key to field:
var objectId = scope.data['system:objectId'];
scope.model['extract'].onchange=getextraction;     // idea: if boolean field gets checked, request for JSON-formatted extraction data

// extraction service delivers an object with JSON-based data
function getextraction(){
if (scope.model['extract'].value){
var httprequest='/dms/objects/'+objectId+'/contents/renditions/extract';    // call the extraction service
scope.api.http.get(httprequest,'core').then(
function(result) {
scope.model['tenKolibri:subject'].value = [result.data['OS:Subject']];   // map the value to field
},
function(error) {
scope.api.util.notifier.error('Failed to get extraction data', 'Error');
}
)
}
}
scope.api.http.del

The following script deletes an object:

Example for del
1
2
3
4
5
6
7
8
9
10
11
12
// how to delete an object
var objectId = '7B683C8E19BD492198F6A262D14EF43F';

// use the web-api gateway endpoint:
scope.api.http.del('/dms/' + objectId).then(
function(result) {
scope.api.util.notifier.info('Succeded to delete object: ' + objectId, 'Success');
},
function(error) {
scope.api.util.notifier.error('Failed to delete object ' + objectId, 'Error');
}
);
scope.api.http.post

The following example creates a follow-up for the current object:

Example for post
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function httppost() {
var  objectId1 = scope.data['system:objectId'];

   var inst = {
    "processDefinitionKey":"follow-up",
    "name":"follow-up",
    "businessKey":objectId1,
    "returnVariables":true,
    "variables": [
       {
         "name":"expiryDateTime",
         "value":"2020-10-24T09:57:00"
       },
       {
        "name":"whatAbout",
        "value":"some reminder"
       },
       {
        "name":"documentId",
        "value":objectId1
       }
    ]
 };

    scope.api.http.post('/bpm/process/instances', inst).then(
    function(result){
        scope.api.util.notifier.info('A follow-up for the following object is created: ' + objectId1, 'Success');
    },
    function(error){
        scope.api.util.notifier.error('A follow-up for the following object could not be created ' + objectId1, 'Error');
        console.log({error});
    }
)
scope.api.dms

This section describes the read access to object information.

scope.api.dms.getObject()

Loads a DMS object from the backend

Parameter Type Description

id

string

The id of the DMS object to be fetched.

version

string

optional: retrieve a specific version of the DMS object.

1
2
3
4
5
6
7
8
9
10
11
12
// example: get object of a given ID
var objectId = '7B683C8E19BD492198F6A262D14EF43F';
scope.api.dms.getObject(objectId).then(
function(result) {
scope.api.util.notifier.info(result.title, 'Title of Object');
// index-values can be found in result.data
// example: result.data.companyname
},
function(error) {
scope.api.util.notifier.error(''+error, 'An error occured');
}
);

4.5.12. Extending Clients with Plug-ins

The PluginsService provided by the framework library allows for extending clients with custom HTML code via a configuration file (s. API documentation for detailed information). The corresponding configuration file is managed via the Web-API Gateway endpoints. It is a simple and fast procedure without the necessity of rebuilding and deployment.

Endpoints for Plug-in Configuration Management

The Web-API gateway provides separate endpoints for the management of tenant-specific and global configuration files. This applies to the plug-in configuration files as well. Use plugin-config as value for the path parameter name. Import an empty JSON file to remove the configuration.

Global:

  • GET /api-web/api/system/resources/config/{name} - Retrieves the global configuration file specified by name.

  • POST /api-web/api/system/resources/config/{name}` - Updates the global configuration file specified by name with the data passed in JSON format in the request body.

Tenant-specific:

  • GET /api-web/api/admin/resources/config/{name} - Retrieves the tenant-specific configuration file specified by name.

  • POST /api-web/api/admin/resources/config/{name} - Updates a tenant-specific configuration file specified by name with the data passed in JSON format in the request body.

Structure of the Configuration File

The configuration file is in JSON format. The disabled key controls whether the client will use the defined plug-ins or not. The load function is executed once the client is loaded. The following example shows how to disable plug-ins for users with specific roles and how to change the application theme via custom styles. The other sections are described below.

Example for adding a new state to the client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"disabled": "() => !api.session.user.hasRole('YUUVIS_TENANT_ADMIN')",
"load": "() => api.util.styles('body, body.dark { --color-accent-rgb: 131, 108, 172; --color-accent: rgb(var(--color-accent-rgb)); --theme-logo-width: 50px; --theme-background: url(https://images.unsplash.com/photo-1460411794035-42aac080490a?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=1950&amp;q=80); --theme-logo: url(https://images.unsplash.com/photo-1460411794035-42aac080490a?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=50&amp;q=80); --theme-logo-big: url(https://images.unsplash.com/photo-1460411794035-42aac080490a?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=250&amp;q=80); }', '_pluginStyles')",
"links": [],
"states": [],
"actions": [],
"viewers": [],
"extensions": [],
"triggers": [],
"translations": {
    "en": {},
    "de": {}
   }
}

Detailed descriptions of the properties can be found in the documentation (s. PluginConfigList interface in framework library).

Configured links with a path and label can be hooked into the main menu or the settings menu. The label must be configured in the translations section as shown below.

Example for adding a new item to the main menu
1
2
3
4
5
6
7
8
9
10
{
  "links": [
    {
       "id": "yuv.custom.link.home_yuuvis",
       "label": "yuv.custom.action.home_yuuvis.label",
       "path": "https://help.optimal-systems.com/yuuvis/home_yuuvis_en.html",
       "matchHook": "yuv-sidebar-navigation|yuv-sidebar-settings"
    }
  ]
}

Detailed descriptions of the properties can be found in the documentation (s. PluginLinkConfig interface in framework library).

Plug-in States

States are new views with their own URL that are mostly reached by clicking a main menu item (see Extend Links). The following example shows how to integrate the user management view of yuuvis® architect as a new view into the client. This view can be opened via a new main menu item 'User management.' This item is offered if the user has the YUUVIS_TENANT_ADMIN role.

Example for adding a new state to the client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
    "states": [
        {
          "id": "yuv.custom.state.architect.users",
          "label": "yuv.custom.state.architect.users",
          "path": "architect/users",
          "matchHook": "yuv-sidebar-navigation",
          "canActivate": "(currentRoute, currentState) => {return this.session.getUser().authorities.includes('YUUVIS_TENANT_ADMIN');}",
          "canDeactivate": "(component, currentRoute, currentState, nextState) => true",
          "plugin": {
            "src": "https://kolibri.enaioci.net/architect/users",
            "html": "<style>iframe[src=\"https://kolibri.enaioci.net/architect/users\"] {display: block; height: calc(100% + 50px); margin-top: -50px;}</style>"
          }
        }
      ],
      "translations": {
        "en": {
          "yuv.custom.state.architect.users": "User management"
        },
        "de": {
          "yuv.custom.state.architect.users": "Benutzermanagement"
        }
      }
}

Detailed descriptions of the properties can be found in the documentation (s. PluginStateConfig interface in framework library).

Plug-in Actions

In general, object actions that are listed in the actions menu provide specific functions that manipulate the focused object, e.g., Download, Manage follow-ups, Open versions, …​ in yuuvis® client as reference implementation. If you want to include all original actions, use "" instead of listing them individually. Note that the position of the listed actions (or the "" if all actions are specified) within the script is irrelevant. The following example shows the implementation of an action that lets you navigate to the dashboard.

Example for adding a new action to the object actions menu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
  "actions": [
         "yuv-download-action",
         "yuv-delete-action",
         "yuv-upload-action",
         "yuv-move-action",
         {
         "id": "yuv.custom.action.home_yuuvis.list",
         "label": "yuv.custom.action.home_yuuvis.list",
         "description": "yuv.custom.action.home_yuuvis.description",
         "icon": "",
         "isExecutable": "(item) => item.id",
         "header": "yuv.custom.action.home_yuuvis.label",
         "subActionComponents": [
         {
             "id": "yuv.custom.action.home_yuuvis.sub.simple",
             "label": "yuv.custom.action.home_yuuvis.simple",
             "description": "yuv.custom.action.home_yuuvis.description",
             "priority": 0,
             "icon": "",
             "group": "common",
             "range": "MULTI_SELECT",
             "isExecutable": "(item) => item.id",
             "run": "(selection) => this.router.navigate(['dashboard'])"
         }]
       }
 ]
}

Detailed descriptions of the properties can be found in the documentation (s. PluginActionConfig interface framework library).

Plug-in Viewers

The Preview of the document file can be customized via a custom viewer configuration. The following example shows how to:

  • redirect of office files to external service (Office 365 viewer)

  • redirect of javascript and json files to monaco editor (line 18)

  • redirect of text files to monaco editor (line 19)

  • redirect of audio and video files to a custom video viewer (line 20)

  • redirect of xml files to monaco editor (line 21)

  • redirect of images to a custom image viewer (line 22)

  • redirect of text and audio and video files to a native html viewer (line 23)

  • customize the viewer path for each file (line 24)

Example for adding a new aspect to the object details
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"viewers": [
      {
        "mimeType": [
          "application/msword",
          "application/vnd.ms-excel",
          "application/vnd.ms-powerpoint",
          "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
          "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
          "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
          "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
          "application/vnd.openxmlformats-officedocument.presentationml.presentation",
          "application/vnd.openxmlformats-officedocument.presentationml.template",
          "application/vnd.openxmlformats-officedocument.presentationml.slideshow"
        ],
        "viewer": "externals/office?path=${path}#locale=${locale}&direction=${direction}&theme=${theme}&accentColor=${accentColor}&fileName=${fileName}&fileExtension=${fileExtension}"
      },
      {"fileExtension": ["js", "json"], "viewer": "assets/_default/monaco/index.html?file=${file}&lang=${lang}"},
      {"mimeType": ["text/plain"], "viewer": "assets/_default/monaco/index.html?file=${file}&lang=${lang}¶ms={\"lineNumbers\":\"off\"}"},
      {"mimeType": ["audio/mp3", "video/mp4"], "viewer": "assets/_default/video/index.html?file=${path}&lang=${lang}"},
      {"mimeType": ["text/xml"], "viewer": "assets/_default/monaco/index.html?language=xml&responseType=xml&file=${file}&lang=${lang}"},
      {"mimeType": ["image/jpeg", "image/png", "image/x-ms-bmp"], "viewer": "assets/_default/image/index.html?file=${file}&lang=${lang}"},
      {"mimeType": ["text/plain", "audio/mp3", "video/mp4"], "viewer": "() => parameters.path"},
      {"mimeType": "*", "type": "extend", "viewer": "() => parameters.mimeType === "text/plain" ? parameters.viewer + '&extend'" : parameters.defaultViewer},
]
}

Detailed descriptions of the properties can be found in the documentation (s. PluginViewerConfig interface in framework library).

Plug-in Extensions

The standard aspects of the object details offer general views of the data of the object: an Overview of all metadata with the possibility to edit the custom Metadata, a Preview of the document file and a History of system events. If you need more views of data that are residing in other services, you can add more such aspects. Custom extensions are also available for the Content Preview or Search Filter Panel. The following example shows:

  • Tab component – how to load a custom html page via iframe (line 4)

  • Tab component – custom html code and styles rendition (line 10)

  • Tab component – a custom component rendition (line 20)

  • Content preview – custom buttons to select the next/previous grid row (line 30)

  • Search filter panel – a custom filter with the dynamic values CURRENT_USER and TODAY (line 39)

  • Search filter panel – a custom filter group generated from a static catalog (line 68)

  • Search filter panel – a custom filter group generated from a dynamic catalog (line 79)

  • Search filter panel – custom filter groups generated from all available catalogs (line 90)

  • Search filter panel – a custom filter with a dynamic date range - next 28 days (TODAY,TODAY+27) (line 103)

Example for adding a new aspect to the object details
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
{
"extensions": [
    {
      "id": "yuv.custom.extension.home_yuuvis",
      "label": "yuv.custom.extension.home_yuuvis.label",
      "matchHook": "yuv-result|yuv-object",
      "plugin": { "src" : "https://help.optimal-systems.com/yuuvis/home_yuuvis_en.html" }
    },
    {
      "id": "yuv.custom.extension.home_yuuvis.complex",
      "label": "yuv.custom.extension.home_yuuvis.description",
      "matchHook": "yuv-result|yuv-object",
      "plugin": {
        "html": "<a href='https://help.optimal-systems.com/yuuvis/home_yuuvis_en.html'> yuuvis Home </a> <button onclick=\"api.router.navigate(['dashboard'])\">Go to dashboard</button>",
        "styles": ["a {color: red;}"],
        "styleUrls": []
      }
    },
    {
      "id": "yuv.custom.extension.quickfinder",
      "label": "yuv.custom.extension.home_yuuvis.description",
      "matchHook": "yuv-result|yuv-object",
      "plugin": {
        "component": "yuv-quickfinder",
        "inputs": { "autofocus": true, "allowedTargetTypes": ["appPersonalfile:pfpersonalfile"]},
        "outputs": { "objectSelect": "(selection) => { parent.selection = selection; }"}
      }
    },
    {
      "id": "yuv.custom.extension.content.preview.navigation",
      "label": "yuv.custom.extension.content.preview.navigation",
      "matchHook": "yuv-content-preview",
      "plugin": {
        "html": "() => { window._selectRow = (next) => { var el = api.util.$('.ag-center-cols-viewport .ag-row-selected')[next ? 'nextSibling' : 'previousSibling']; el && el.click();}; return '<div class=\"preview-navigation\"><button onclick=\"_selectRow()\">⇦</button><button onclick=\"_selectRow(true)\">⇨</button></div>';}",
        "styles": ["{ flex: 1; }", ".preview-navigation { display: flex; justify-content: center; margin: 0 4px; }", ".preview-navigation button { padding: 1px 4px; }"]
      }
    },
    {
      "id": "yuv.custom.extension.search.filter.createdBy.me",
      "label": "yuv.custom.extension.search.filter.createdBy.me",
      "matchHook": "yuv-search-result",
      "plugin": {
        "component": "SearchFilterGroup",
        "inputs": {
          "skipCount": false,
          "skipTranslate": false,
          "query": [
            {
              "lo": "OR",
              "filters": [
                {
                  "f": "system:createdBy",
                  "o": "eq",
                  "v1": "$CURRENT_USER$|eq"
                },
                {
                  "f": "system:creationDate",
                  "o": "lte",
                  "v1": "$TODAY$|lte"
                }
              ]
            }
          ]
        }
      }
    },
    {
      "id": "yuv.custom.extension.search.filter.catalog.static",
      "label": "yuv.custom.extension.search.filter.catalog.static",
      "matchHook": "yuv-search-result",
      "plugin": {
        "component": "PluginSearchComponent",
        "inputs": {
          "init": "() => {return component.catalogToSelectableGroup('tenKolibri:strcatalogaddress');}"
        }
      }
    },
    {
      "id": "yuv.custom.extension.search.filter.catalog.dynamic",
      "label": "yuv.custom.extension.search.filter.catalog.dynamic",
      "matchHook": "yuv-search-result",
      "plugin": {
        "component": "PluginSearchComponent",
        "inputs": {
          "init": "() => {return component.catalogToSelectableGroup('tenKolibri:strcataloggermancountries', component.loadCatalogOptions('tenKolibri:germancountries').then(countries => countries));}"
        }
      }
    },
    {
      "id": "yuv.custom.extension.search.filter.catalog.all",
      "label": "yuv.custom.extension.search.filter.catalog.all",
      "matchHook": "yuv-search-result",
      "plugin": {
        "component": "PluginSearchComponent",
        "inputs": {
           "maxHeight": 300,
           "hideZeroCount": true,
           "init": "() => {return component.getAvailableCatalogs().map(f => component.catalogToSelectableGroup(f.id));}"
        }
      }
    },
    {
      "id": "yuv.custom.extension.search.filter.date.future",
      "label": "yuv.custom.extension.search.filter.date.future",
      "matchHook": "yuv-search-result",
      "plugin": {
        "component": "PluginSearchComponent",
        "inputs": {
          "init": "() => {return component.toSelectable(component.extension, { array: [new SearchFilter('system:lastModificationDate', SearchFilter.OPERATOR.EQUAL, '$TODAY$,$TODAY$+27|eq')]});}"
        }
      }
    }
]
}

Detailed descriptions of the properties can be found in the documentation (s. PluginExtensionConfig interface in framework library).

Plug-in Triggers

Form controls support users in entering data in formats such as strings, numbers, dates, booleans, or more specific ones such as e-mail addresses, users or references to other objects. If you need more such specific controls, you can extend the form controls as shown in the following example:

  • paste the copied text to input via trigger (line 4)

  • custom value picker for input via dialog (line 12)

  • customize the reference component behavior to search for specific values (line 31)

  • custom dynamic date for date filter (line 37)

Example for adding a custom functionality to the form field controls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
{
"triggers": [
    {
      "id": "yuv.custom.trigger.paste.clipboard",
      "label": "yuv.custom.trigger.paste.clipboard",
      "matchHook": "yuv-*",
      "icon": "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" aria-hidden=\"true\" focusable=\"false\" width=\"1em\" height=\"1em\" preserveAspectRatio=\"xMidYMid meet\" viewBox=\"0 0 24 24\"><path opacity=\".3\" d=\"M17 7H7V4H5v16h14V4h-2z\" fill=\"white\"/><path d=\"M19 2h-4.18C14.4.84 13.3 0 12 0S9.6.84 9.18 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1s-1-.45-1-1s.45-1 1-1zm7 18H5V4h2v3h10V4h2v16z\" fill=\"#626262\"/></svg>",
      "isExecutable": "(component) => component.parent.formControlName",
      "run": "(component) => {var _this = this; navigator.clipboard.readText().then((v) => v && _this.form.modelChange(component.parent.formControlName, {name: 'value', newValue: v}))}"
    },
    {
      "id": "yuv.custom.trigger.quickfinder",
      "label": "yuv.custom.trigger.quickfinder",
      "matchHook": "yuv-*",
      "icon": "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" aria-hidden=\"true\" focusable=\"false\" width=\"1em\" height=\"1em\" preserveAspectRatio=\"xMidYMid meet\" viewBox=\"0 0 24 24\"><path opacity=\".3\" d=\"M17 7H7V4H5v16h14V4h-2z\" fill=\"hotpink\"/><path d=\"M19 2h-4.18C14.4.84 13.3 0 12 0S9.6.84 9.18 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1s-1-.45-1-1s.45-1 1-1zm7 18H5V4h2v3h10V4h2v16z\" fill=\"#626262\"/></svg>",
      "group": "visible",
      "buttons": {},
      "plugin": {
        "component": "yuv-quickfinder",
        "inputs": { "autofocus": true, "allowedTargetTypes": ["appPersonalfile:pfpersonalfile"]},
        "outputs": { "objectSelect": "(selection) => { parent.selection = selection; }"},
        "popoverConfig": {
          "height": "30%",
          "width": "50%"
        }
      },
      "isExecutable": "() => parent.formControlName === 'appClient:clienttitle'",
      "run": "() => { parent.selection = {}; trigger.openPopover().afterClosed().subscribe((result) => { result && api.form.modelChange('appClient:clientdescription', { name: 'value', newValue: parent.selection.description || '' }); });}"
    },
    {
      "id": "yuv.custom.trigger.reference",
      "matchHook": "yuv-reference",
      "isExecutable": "() => parent.formControlName === null",
      "run": "() => { var ref = parent.childComponent; ref.descriptionField = 'system:objectId'; ref.allowedTargetTypes = ['appClient:minidoc']; ref.objectTypeFields = ['system:createdBy']; ref.searchFnc = (term) => { var ids = [api.form.getValue('appClient:clienttitle')]; ref.filters = ids && ids[0] ? [{'f':'appClient:clienttitle','o':'in','v1': ids}] : []; return Object.assign({term : '*{0}*'.replace('{0}', term)}, ref.queryJson);}; ref.objectSelect.subscribe(() => { var v = (parent.childComponent.innerValue || [])[0]; var val = (v && v.data && v.data.get('appClient:clienttitle')) || ''; api.form.setValue('appClient:clientdescription', val); });}"
    },
    {
      "id": "yuv.custom.trigger.filter.variable.date",
      "label": "yuv.custom.trigger.filter.variable.date",
      "matchHook": "yuv-datetime-range",
      "group": "hidden",
      "isExecutable": "(component) => { return component.parent && component.parent.formControlName; }",
      "run": "(component) => { component.parent.dateVariables = [{offset: 3, value: '$TODAY$,$TODAY$+2'}].concat(component.parent.dateVariables); }"
    }
  ]
}

Detailed descriptions of the properties can be found in the documentation (s. PluginTriggerConfig interface in framework library).

Plug-in Translations

In case you need to extend translations with new keys, please specify translations for each language in your system.

Example for adding a custom functionality to the form field controls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
  "translations": {
    "en": {
      "yuv.custom.action.home_yuuvis.label": "yuuvis Home",
      "yuv.custom.action.home_yuuvis.description": "yuuvis Description",
      "yuv.custom.action.home_yuuvis.simple": "yuuvis Home simple",
      "yuv.custom.action.home_yuuvis.component": "yuuvis Home component",
      "yuv.custom.action.home_yuuvis.component.full": "yuuvis Home component full",
      "yuv.custom.action.home_yuuvis.link": "yuuvis Home link",
      "yuv.custom.action.home_yuuvis.list": "yuuvis Home list",
      "yuv.custom.trigger.paste.clipboard": "Paste clipboard",
      "yuv.custom.trigger.paste.selection": "Paste selection",
      "yuv.custom.trigger.paste.suggestion": "Paste suggestion"
    },
    "de": {
      "yuv.custom.action.home_yuuvis.label": "yuuvis Home DE",
      "yuv.custom.action.home_yuuvis.description": "yuuvis Description DE",
      "yuv.custom.action.home_yuuvis.simple": "yuuvis Home simple DE",
      "yuv.custom.action.home_yuuvis.component": "yuuvis Home component DE",
      "yuv.custom.action.home_yuuvis.component.full": "yuuvis Home component full DE",
      "yuv.custom.action.home_yuuvis.link": "yuuvis Home link DE",
      "yuv.custom.action.home_yuuvis.list": "yuuvis Home list DE",
      "yuv.custom.trigger.paste.clipboard": "Paste clipboard DE",
      "yuv.custom.trigger.paste.selection": "Paste selection DE",
      "yuv.custom.trigger.paste.suggestion": "Paste suggestion"
    }
  }
}
Activating the Extension Feature and Importing Your Plug-in Configuration

To import a configuration file with your extensions (plug-ins), follow these steps:

  • Open the client and open the settings.

  • Click On in the Plug-in Configuration. This feature is offered to all users with the YUUVIS_SYSTEM_INTEGRATOR role.

  • Click Import.

The file is uploaded to the configservice so that all clients can use these extensions as well.

Removing the Configuration

Import an empty JSON file to remove the configuration.

Use Case Example

The following code block configures an action where a start form for a workflow process is offered.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "id": "yuv.custom.action.taskflow.id",
  "label": "yuv.custom.action.taskflow.label",
  "description": "yuv.custom.action.taskflow.description",
  "priority": 1,
  "icon": "<svg height=\"24\" viewBox=\"0 0 24 24\" width=\"24\" xmlns=\"http://www.w3.org/2000/svg\"> <path d=\"M0 0h24v24H0V0z\" fill=\"none\"></path> <path d=\"M4 10h12v2H4zM4 6h12v2H4zM4 14h8v2H4zM14 14v6l5-3z\"></path> </svg>",
  "group": "further",
  "range": "MULTI_SELECT",
  "isExecutable": "(item) => item.id",
  "buttons": {
    "finish": "yuv.custom.action.workflow.start"
  },
  "plugin": {
    "component": "yuv-object-form",
    "inputs": {
      "__initOptions": "() => this.http.get(`/resources/config/taskflow-startform`, 'api-web').then((res) => {component.cmp.options = {formModel: res.data.tenant, disabled: false}})",
      "__init": "() =>parent.finished.subscribe((event) => {var selection = parent.selection;var cmp = component.cmp;var vars = [{ name: 'title', type: 'string', value: cmp.formData.title || '' },{ name: 'taskStatus', type: 'string', value: 'Open' },{ name: 'comment', type: 'string', value: cmp.formData.comment },{name: 'nextAssignee',type: 'string',value: cmp.formData.nextAssignee}];if (cmp.formData.expiryDatetime) {vars.push({name: 'expiryDatetime',type: 'date',value: cmp.formData.expiryDatetime,})}this.http.post('/bpm/processes',{businessKey: selection[0].id,name: selection[0].title || selection[0].id,processDefinitionKey: 'dms-lite-taskflow',attachments: selection.map((s) => s.id),subject: selection[0].title,variables: vars,},'api-web').then(() =>this.util.notifier.success(this.util.translate('yuv.custom.action.taskflow.success')))})"
    },
    "outputs": {
      "statusChanged": "(status) => { parent.disabled = status.invalid; }"
    }
  }
},

The configured action retrieves the taskflow-startform form from the configuration resources. The framework component yuv-object-form offers the form via the object action menu:

The form displays the localized fields corresponding to the Flowable process variables: title (The task), expiryDatetime (Due until), comment (Comment for the next assignee) and nextAssignee (Next assignee).

The taskStatus variable that is internally used for process management is not displayed.

The expiryDatetime variable can be saved only by calling the dms-lite-taskflow process if a value is set. Thus, it is possible to prohibit setting a null value for the datetime variable which is not allowed in Flowable.

4.5.13. BPM Plug-in

The BPM Engine in yuuvis® Momentum is provided by the BPM-ENGINE service based on the workflow functionality of the open-source software Flowable. In yuuvis® client as reference implementation, it can be integrated in order to support process and task management via the browser application.

Administrators can model process models (process-definitions in Flowable nomenclature) with the help of a Flowable modeler, pack them and export them as applications, and deploy the applications to the BPM-ENGINE service in yuuvis® Momentum. Once deployed in such a manner, a process definition can be instantiated and executed in the BPM Engine. If process instances running in the bpm engine contain user tasks, they will be available in the Inbox of the user to whom they were assigned.

The following information is intended to support administrators to set up Flowable processes that are supported by the reference client.

Processes and Tasks in the Reference Client

yuuvis® client as reference implementation offers three specific views that allow users to handle processes based on Flowable:

  • Users can create follow-ups for each object via the action menu. The My follow-ups view lists all active follow-ups with their follow-up date.

  • The Inbox view lists all user tasks that are intended for the authenticated user, such as reminder tasks of follow-up processes that have reached their follow-up date.

  • As of version 2021 Autumn, all tasks of processes the currently logged-in user is assigned to are listed as well.

  • As of version 2021 Autumn, the new My processes view lists all processes started by the logged-in user.

Recommendations

  • If you start a process related to a document, the ID of the document should be saved in the process variable documentId. The reference client uses this variable to retrieve and display object details.

  • When starting a process, specify a meaningful value for the process property name since it will be shown in the Process column in the My processes view.

  • When modeling a workflow, specify meaningful names for Tasks, since they will be shown in the Task column in the Inbox view.

Inbox

As of version 2021 Autumn, besides the follow-up tasks, the inbox lists all other BPM tasks as well. The following properties are displayed:

Column in yuuvis® client Technical details Description

Type

If the process parameter processDefinitionName is Follow-up, then Follow-up. Otherwise Task.

As of 2021 Winter, an icon is displayed. If the process parameter processDefinition.idPrefix is follow-up, then a bell is shown and the tooltip shows Follow-up. Otherwise, a general process icon is shown and a tooltip with the localized prefix. If no localization is configured, the technical prefix is displayed.

The description that was entered while creating the follow-up.

Task

Task name

The time the follow-up (process) was created.

as of 2021 Winter: Subject

Web-API Gateway parameter subject, represented as Flowable string variable subject

Set while creating the process or during the process while saving the Flowable process variable appClientsystem_subject of type string

Received

as of 2021 Winter: Received on

Task CreateTime

The date and time the task was created.

The value corresponds to the due date that was entered while creating the follow-up.

As of version 2021 Winter, the inbox offers a task details area with the aspects Task, History, and Attachments (not on the following screenshot).

The following screenshot shows the three possible elements of the aspect Task:

  • A static task description is shown if the task name (here: 2nd_task_dynform) that is set in the Flowable process model has a description representation in the localization for the language the user has set. Use the key <task name>_description for the task description and <task name>_title for localizing the task name itself.

  • Dynamic messages if the Flowable variable appClientsystem_taskMessages of type JSON have been saved. Message can be plane text lines or as unformatted lists. Colors are given by a level parameter. More details are given here: (link will come soon).

  • A static or dynamic form. The static form is set via Flowable formKey and a form model that was saved with this name. The dynamic form can be set by saving the Flowable variable appClientsystem_taskMessages of type JSON.

My processes

As of version 2021 Autumn, all processes including follow-ups are listed as soon as they are started by the user. The following properties are affected:

Column in yuuvis® client Technical details Description

Type

Process-definition parameter processDefinitionName

As of 2021 Winter, an icon is displayed. If the process parameter processDefinition.idPrefix is follow-up, then a bell is shown and the tooltip shows Follow-up. Otherwise, a general process icon is shown and a tooltip with the localized prefix. If no localization is configured, the technical prefix is displayed.

Process definition name

Process (not available anymore as of version 2021)

Process-instance parameter name (as set when starting the process instance)

Process instance name (e.g., a case number)

Created on

Process-instance parameter startTime

The time the process was created.

Status

Derived from the process-instance parameters completed and suspended

The status of the process can be running, suspended, or completed.

The status is given in the user’s language.

My follow-ups

This view lists the follow-up processes with the following specific properties:

Column in yuuvis® client Corresponding Counterpart in BPM Engine Description

Description (not available anymore as of version 2021)

Process variable whatAbout

The description that was entered while creating the follow-up.

as of 2021 Winter: Subject

Web-API Gateway parameter subject, represented as Flowable string variable subject

Set while creating the process.

Created on

Process parameter startTime

The time the follow-up (process) was created.

Follow-up date

Process variable expiryDateTime

The due date that was entered while creating the follow-up.

Status

Derived from process parameters endTime and suspended

Possible values for Status are running, completed and suspended.

Starting a Process for an Object via a Plug-in Action

The object actions can be extended with a plug-in action that can be offered in the MORE ACTIONS action group. The following example shows the Two step process action, which starts a process based on the twosteptest_proc process model (mapped to Flowable processDefinitionKey) for a single marked object or for multiple selected objects.

As of 2021 Winter, the objects are displayed in the attachment task of the task details for a selected task in the Inbox.

To provide the example Two step process action in a client, import the client plug-in configuration file shown below. To be able to import a settings file, users need an administrative role.

The twosteptest_proc process model has to be deployed to the Flowable BPM Engine.

Plug-in Configuration for an Example 'Two step pocess'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{
  "disabled": false,
  "actions": [
    {
      "id": "yuv.custom.action.two.step.multi.label",
      "label": "yuv.custom.action.two.step.multi.label",
      "description": "yuv.custom.action.two.step.multi.description",
      "priority": 0,
      "icon": "<svg height=\"24\" viewBox=\"0 0 24 24\" width=\"24\" xmlns=\"http://www.w3.org/2000/svg\"> <path d=\"M0 0h24v24H0V0z\" fill=\"none\"></path> <path d=\"M4 10h12v2H4zM4 6h12v2H4zM4 14h8v2H4zM14 14v6l5-3z\"></path> </svg>",
      "group": "further",
      "range": "MULTI_SELECT",
      "isExecutable": "(item) => item.id",
      "run": "(selection) => this.http.post('/bpm/processes', {businessKey: selection[0].id, name: selection[0].title || selection[0].id, processDefinitionKey: 'twosteptest_proc', attachments: selection.map((s) => s.id), subject: selection[0].title, variables: [{ name: 'myVariable', type: 'string', value: 'Lorem ipsum' }]},'api-web').then(() => this.util.notifier.success(this.util.translate('yuv.custom.action.two.step.multi.success')))"
    },
    "yuv-download-action",
    "yuv-delete-action",
    "yuv-delete",
    "yuv-upload",
    "yuv-upload-action",
    "yuv-move-action",
    "yuv-move",
    "yuv-follow-up-action",
    "yuv-follow-up",
    "yuv-reference-action",
    "yuv-open-context-action",
    "yuv-open-versions-action",
    "yuv-clipboard-action",
    "yuv-clipboard-link-action"
  ],
  "translations": {
    "en": {
      "yuv.custom.action.two.step.multi.label": "Two step process",
      "yuv.custom.action.two.step.multi.description": "Starts simple process with two steps, also for many objects",
      "yuv.custom.action.two.step.multi.success": "Process has started"
    },
    "de": {
      "yuv.custom.action.two.step.multi.label": "Zweischritteprozess",
      "yuv.custom.action.two.step.multi.description": "Startet einen einfachen Prozess mit zwei Schritten, auch für mehrere Prozesse",
      "yuv.custom.action.two.step.multi.success": "Prozess wurde gestartet"
    }
  }
}
Handling of Task Forms

As of version 2021 Winter, the Inbox view displays tasks in task forms that can be configured in order to provide a specific form for a specific Flowable task. The configuration can be done via following steps:

  • Display the task in the Flowable process modeler and write a technical name into the property FormKey.

  • Define your configuration in a JSON file as shown below.

  • Save this form using the configuration endpoint in the admin-controller or system-controller of the Web-API Gateway. Use the value of FormKey for the path parameter name of the configuration. POST /api-web/api/admin/resources/config/{name} or` POST /api-web/api/system/resources/config/{name}`

The client is calling this configuration file using the corresponding endpoint of the resource-controller of the Web-API Gateway.

Structure of the JSON Configuration File

The JSON format for task forms is the same as used for the object forms. Thus, the complete feature set is supported here as well. The expandable code block below shows an example configuration.

The Flowable variable names are specified as values for the key name. We recommend user task names with a prefix (in the example: 'xyz') for easier localization.

If the variable has not been used in the process before the form is called, the given values are saved to these variables after saving the form.

The property types used in forms for yuuvis® Momentum objects can be used for the Flowable variable types as well. Only the yuuvis® property type decimal is mapped to the Flowable variable type double, and the yuuvis® property type datetime is mapped to the Flowable variable type date.

The yuuvis® table properties are saved as in a variable of type JSON.

All other attributes given in this example are mostly self-explanatory.

Example Configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
{
  "name": "twosteptest_proc:1st_task",
  "situation": "EDIT",
  "script": "",
  "elements": [
    {
      "name": "core",
      "type": "o2mGroup",
      "elements": [
        {
          "type": "o2mGroup",
          "layout": {
              "align": "row"
          },
          "elements": [
           {
              "type": "o2mGroup",
              "name": "xyzSimplefields",
              "layout": {
                  "align": "column"
              },
              "elements": [
                {
                  "name": "xyzDatetime",
                  "type": "datetime",
                  "required": false,
                  "cardinality": "single",
                  "readonly": false
                },
                {
                  "name": "xyzDate",
                  "type": "datetime",
                  "required": false,
                  "cardinality": "single",
                  "readonly": false,
                  "resolution": "date"
                },
                {
                  "name": "xyzInteger",
                  "type": "integer",
                  "required": false,
                  "cardinality": "single",
                  "readonly": false                },
                {
                  "name": "xyzDecimal",
                  "type": "decimal",
                  "required": false,
                  "cardinality": "single",
                  "readonly": false
                },
                {
                  "name": "xyzString",
                  "type": "string",
                  "required": false,
                  "rows": 1,
                  "readonly": false                },
                {
                  "name": "xyzStringmultirow",
                  "type": "string",
                  "required": false,
                  "rows": 3,
                  "readonly": false
                }
              ]
            },
            {
              "type": "o2mGroup",
              "name": "xyzComplexfields",
              "layout": {
                  "align": "column"
              },
              "elements": [
                {
                  "name": "xyzEmail",
                  "type": "string",
                  "cardinality": "single",
                  "readonly": false,
                  "classifications": ["email"]
                },
                {
                  "name": "xyzUrl",
                  "type": "string",
                  "required": false,
                  "readonly": false,
                  "classifications": ["url"]
                },
                {
                  "name": "xyzPhone",
                  "type": "string",
                  "required": false,
                  "readonly": false,
                  "classifications": ["phone"]
                },
                {
                  "name": "xyzUser",
                  "type": "string",
                  "required": false,
                  "cardinality": "single",
                  "readonly": false,
                  "classifications": ["id:organization"]
                },
                {
                  "name": "xyzReference",
                  "type": "string",
                  "required": false,
                  "cardinality": "single",
                  "readonly": false,
                  "classifications": ["id:reference[]"],
                  "label": "Reference"
                },
                {
                  "name": "xyzCatalogcustom",
                  "type": "string",
                  "required": false,
                  "cardinality": "single",
                  "readonly": false,
                  "classifications": ["custom:catalog[/api-web/api/dms/catalogs/tenMytenant:processstatus]"],
                  "label": "Catalog status"
                },
                {
                  "name": "xyzBroc:boolean",
                  "type": "boolean",
                  "required": false,
                  "readonly": false,
                  "label": "Boolean"
                }
              ]
            }
          ]
        },
        {
          "name": "xyzTest_table",
          "type": "table",
          "required": false,
          "readonly": false,
          "label": "Notices",
          "description": "List of notices",
          "classifications": "sortable",
          "elements": [
            {
              "name": "xyzColumn_string",
              "type": "string",
              "required": false,
              "cardinality": "single",
              "readonly": false,
              "label": "String"
            },
            {
              "name": "xyzColumn_date",
              "type": "datetime",
              "required": false,
              "cardinality": "single",
              "readonly": false,
              "label": "Date"
            },
            {
              "name": "xyzColumn_user",
              "type": "string",
              "required": false,
              "cardinality": "single",
              "classifications": ["id:organization"],
              "readonly": false,
              "label": "User"
            },
            {
              "name": "xyzColumn_boolean",
              "type": "boolean",
              "required": false,
              "cardinality": "single",
              "readonly": false,
              "label": "Boolean"
            }
          ]
        }
      ]
    },
    {
      "name": "data",
      "type": "o2mGroupStack",
      "elements": [],
          "layout": { "align": "column" },
          "label": "Table group"
    }
  ]
}
The key-value pair "classifications": ["sortable"] allows the user to sort the table rows manually by drag & drop.

The following client-specific Flowable variables are available:

Task parameter (Web API Gateway GET tasks) Example format Flowable variable name Example format
subject - The client-specific task parameter subject is presented in the Subject column of the Inbox.
Description

The parameter can be set using the Web-API Gateway GET/PUT endpoints for tasks or the corresponding BPM-API endpoints for setting the variable appClientsystem_subject.

Example format

"subject": "My subject"

Flowable Variable

appClientsystem_subject

Flowable example format
{
  "action": "save",
  "variables": [
    {
      "name": "appClientsystem_subject",
      "type": "string",
      "value": "My subject"
    }
attachments - Used for the tasks' Attachments aspect area of the Inbox.
Description

The value is an array of object GUIDs. The title of the corresponding objects is displayed in the list of attachments for users.

The parameter can be set using the Web-API Gateway GET/PUT endpoints for tasks or the corresponding BPM-API endpoints for setting the variable appClientsystem_attachment.

Example format

"attachments": ["GUID1","GUID2", "GUID2"]

Flowable Variable

appClientsystem_attachments

Flowable Example Format
{
  "action": "save",
  "variables": [
    {
      "name": "appClientsystem_attachments",
      "type": "json",
      "value": [
          "GUID1",
          "GUID2"
      ]
    }
taskMessages - Used to present necessary information for working on this particular task on the top of the Task aspect area in the Inbox.
Description

The level parameter specifies the formatting of the corresponding messages. The following values are available:

level description

without level

The message is rendered in the normal format

info

The text is rendered in the accent color

error

Text is rendered in Red

warning

Text is rendered in Orange

If the message is a localization key, the key will be translated (see messageError in the example). The keys do not need an appended _label as required for the name for a form field.

'"Type": "ul" can be used to render messages with this setting in a list.

The value specified for taskMessages is retrieved by the GET tasks endpoint of the Web-API Gateway and can only be set by via the Flowable variable appClientsystem_taskMessages. Example format:: Example code for the GET task’s response of the Web-API Gateway:

+

"taskMessages": [
  {
    "message": "messageWithoutColor"
  },
  {
    "level": "error",
    "message": "messageError",
    "type": "ul"
  },
  {
    "level": "warning",
    "message": "messageWarning",
    "type": "ul"
  },
  {
    "level": "info",
    "message": "messageError"
  },
  {
    "message": "Not translated message"
  }
]
Flowable Variable

appClientsystem_taskMessages

Flowable Example format

Example code for setting the Flowable variable appClientsystem_taskMessages via BPM-API PUT tasks:

{
  "action": "save",
  "variables": [
    {
      "name": "appClientsystem_taskMessages",
      "type": "json",
      "value": [
        {
          "message": "messageWithoutColor"
        },
        {
          "level": "error",
          "message": "messageError",
          "type": "ul"
        },
        {
          "level": "warning",
          "message": "messageWarning",
          "type": "ul"
        },
        {
          "level": "info",
          "message": "messageError"
        },
        {
          "message": "Not translated message"
        }
      ]
    }
  ]
}
taskForm - Used to specify user-relevant properties to be displayed in the task form.
Description

Each property is specified by its name. The attributes of this property determine the style of the form field.

Form fields can be handled either by

  • listing the relevant properties in schemaProperties or

  • configuring a more complex form with form model syntax in a model.

If name does not have a representation in the schema, it will be ignored.

Example format

Example code for the GET tasks response of the Web-API Gateway using schemaProperties:

"taskForm": {
    "schemaProperties": [
      "tenMytenant:strsingle",
      "tenMytenant:datesingle"
    ]

Example code for the GET tasks response of the Web-API Gateway using a form model:

"taskForm": {
    "model": {
            "name": "twosteptest_proc:2nd_task",
            "situation": "EDIT",
            "script": "",
            "elements": [
              {
                "name": "core",
                "type": "o2mGroup",
                "elements": [
                  {
                    "type": "o2mGroup",
                    "layout": {
                        "align": "row"
                    },
                    "elements": [
                    {
                        "type": "o2mGroup",
                        "name": "twosteptest_proc:simplefields",
                        "layout": {
                            "align": "column"
                        },
                        "elements": [
                          {
                            "name": "twosteptest_proc:date",
                            "labelkey": "Date",
                            "type": "datetime",
                            "required": false,
                            "cardinality": "single",
                            "readonly": false,
                            "resolution": "date"
                          },
                          {
                            "name": "twosteptest_proc:string",
                            "type": "string",
                            "cardinality": "single",
                            "required": false,
                            "rows": 1,
                            "readonly": false
                          }
                        ]
                      }
                    ]
                  }
                ]
              }
            ]
     ]
Flowable Variable

appClientsystem_taskForm

Flowable Example format

Example code for setting the Flowable variable appClientsystem_taskForm via BPM-API PUT tasks using schemaProperties:

{
  "action": "save",
  "variables": [
    {
      "name": "appClientsystem_taskForm",
      "type": "json",
      "value": {
        "schemaProperties": [
          "tenMytenant:strsingle",
          "tenMytenant:datesingle"
        ]
      }
    }
  ]
}

Example code for saving the Flowable variable appClientsystem_taskForm via BPM-API PUT tasks using a form model:

{
  "action": "save",
  "variables": [
    {
      "name": "appClientsystem_taskForm",
      "type": "json",
      "value": {
        "model":
          {
            "name": "twosteptest_proc:2nd_task",
            "situation": "EDIT",
            "script": "",
            "elements": [
              {
                "name": "core",
                "type": "o2mGroup",
                "elements": [
                  {
                    "type": "o2mGroup",
                    "layout": {
                        "align": "row"
                    },
                    "elements": [
                    {
                        "type": "o2mGroup",
                        "name": "twosteptest_proc:simplefields",
                        "layout": {
                            "align": "column"
                        },
                        "elements": [
                          {
                            "name": "twosteptest_proc:date",
                            "labelkey": "Date",
                            "type": "datetime",
                            "required": false,
                            "cardinality": "single",
                            "readonly": false,
                            "resolution": "date"
                          },
                          {
                            "name": "twosteptest_proc:string",
                            "type": "string",
                            "cardinality": "single",
                            "required": false,
                            "rows": 1,
                            "readonly": false
                          }
                        ]
                      }
                    ]
                  }
                ]
              }
            ]
          }
      }
    }
  ]
}

The code clock below shows an example for the Flowable representation of a yuuvis table property. Tables are only shown up in a form where the types of the column properties are added as seen above.

{
  "name": "twosteptest_proc:test_table",
  "type": "json",
  "value": [
    {
      "twosteptest_proc:column_string": "abc",
      "twosteptest_proc:column_date": "2021-09-07T17:31Z",
      "twosteptest_proc:column_user": "2685df3a-1cf8-4da3-968c-0a4a10b48921",
      "twosteptest_proc:column_boolean": true
    }
  ],
  "scope": "global"
},
Start Forms for Starting Processes

As of version 2021 Winter, a plug-in action is available that allows to start a process via a start form as shown in the example screenshot. If all form fields are filled with valid values, the Start button is enabled. Both form fields User and Comment are required variables for starting a process. The code block below shows the corresponding plug-in configuration offering a start form with the name taskform in the object action view (displayed after a click on the object action Test process with role assignment).

Example Plugin Configuration Start Form
{
  "disabled": false,
  "actions": [
    {
      "id": "yuv.custom.action.userGroupAssignment.multi.label",
      "label": "yuv.custom.action.userGroupAssignment.multi.label",
      "description": "yuv.custom.action.userGroupAssignment.multi.description",
      "priority": 1,
      "icon": "<svg height=\"24\" viewBox=\"0 0 24 24\" width=\"24\" xmlns=\"http://www.w3.org/2000/svg\"> <path d=\"M0 0h24v24H0V0z\" fill=\"none\"></path> <path d=\"M4 10h12v2H4zM4 6h12v2H4zM4 14h8v2H4zM14 14v6l5-3z\"></path> </svg>",
      "group": "further",
      "range": "MULTI_SELECT",
      "isExecutable": "(item) => item.id",
      "buttons": {
        "finish": "yuv.custom.action.userGroupAssignment.multi.start"
      },
      "plugin": {
        "component": "yuv-object-form",
        "inputs": {
          "__initOptions": "this.http.get(`/resources/config/taskform`, 'api-web').then((res) => {component.cmp.options = {formModel: res.data.tenant, disabled: false}})",
          "__init": "() => parent.finished.subscribe((event) => { var selection = parent.selection; var cmp = component.cmp; this.http.post('/bpm/processes',{businessKey: selection[0].id,name: selection[0].title || selection[0].id,processDefinitionKey: 'userGroupAssignment',attachments: selection.map((s) => s.id),subject: selection[0].title,variables: [{ name: 'user', type: 'string', value: cmp.formData.user || '' },{ name: 'comment', type: 'string', value: cmp.formData.comment || '' },{ name: 'nextUserAssignee', type: 'string', value: 'fakeUserId' },{ name: 'nextGroupAssignee', type: 'string', value: 'YUUVIS_MANAGE_SETTINGS' }]},'api-web').then(() => this.util.notifier.success(this.util.translate('yuv.custom.action.userGroupAssignment.multi.success')))})"
        },
        "outputs": {
          "statusChanged": "(status) => { parent.disabled = status.invalid; }"
        }
      }
    },
    "*"
  ],
  "translations": {
    "en": {
      "yuv.custom.action.userGroupAssignment.multi.label": "Test process with role assignment",
      "yuv.custom.action.userGroupAssignment.multi.description": "Starts a process with two tasks. Second task assigned to YUUVIS_MANAGE_SETTINGS",
      "yuv.custom.action.userGroupAssignment.multi.success": "Process has started"
    }
  }
}

The following code block shows the form definition for the plug-in action example displayed above:

Definition Example
{
  "description": "This form is used during process start and both task of process userGroupAssignment",
  "name": "taskform",
  "situation": "EDIT",
  "elements": [
    {
      "name": "core",
      "type": "o2mGroup",
      "elements": [
        {
          "name": "user",
          "labelkey": "userGroupAssignment:user",
          "type": "string",
          "cardinality": "single",
          "required": true,
          "readonly": false,
          "classifications": ["id:organization"]
        },
        {
          "name": "comment",
          "labelkey": "userGroupAssignment:comment",
          "type": "string",
          "required": true,
          "readonly": false,
          "rows": 3
        }
      ],
      "layout": {
        "align": "column"
      }
    },
    {
      "name": "data",
      "label": "data",
      "type": "o2mGroupStack",
      "elements": []
    }
  ]
}

As of version 2021 Winter, the value multi is supported as an alternative for the value single of the property cardinality in order to configure a multi-value field:

  • If the cardinality of a field is single, its type is mapped to the type of the Flowable variable with the same name.

  • If the cardinality of a field is multi, the Flowable variable type is set to JSON and its values are listed in the specified JSON structure.

Custom Confirm Actions

As of version 2022 Spring, it is possible to configure custom confirm actions for BPM tasks. These custom confirm actions trigger optional forms that give users the possibility to provide further data that is relevant only for this particular outcome. The so-called outcomes can be configured in static BPM form files as well as in dynamic ones:

Outcomes configuration
{
  "model":
  {
    ...
  },
  "outcomes": [
    {
      "name": "taskflow_finish",
      "variable": "status",
      "value": "close"
    },
    {
      "name": "taskflow_forward",
      "secondary": true,
      "variable": "status",
      "value": "open",
      "model": "taskflow-form-forward"
    }
  ]
}

The outcomes list contains custom task confirm actions that will be displayed as buttons in the UI instead of the standard confirm button. The order of the buttons is from right to left. The buttons are displayed in the accent color per default. The outcomes section can be used in dynamic action forms as well.

Parameter Description

name

Technical name of the custom confirm action that is used as label for the button to be displayed in the client if not localized.

variable

The name of the Flowable variable for which the specified value is saved after the user has clicked the button. The variable can be used to control the process flow.

value

The value of the Flowable variable.

secondary

If false (default), the button is shown in the accent color.

If true, the button is NOT shown in the accent color.

model

Specify the technical name of a defined BPM form or a complete valid form model. This form will only be shown if users click the corresponding custom confirm action.

4.5.14. Office 365 Plug-in

The functionality provided by the OFFICE365 and DASHLET services is integrated via plug-in configuration in combination with the VIEWER Service in a library-based client. A general explanation of plug-in configurations is provided in a separate article and should be read carefully before addressing a specific use case like the integration of Office 365.

As soon as the plug-in configuration is applied, the VIEWER service provides an Office 365 preview for binary content files of Microsoft Office file types. If users have a write permission for the corresponding object, the object actions menu offers the Edit action that opens the binary content file in the edit mode in a new browser tab. Saving changes triggers the creation of a new object version.

In order to collaborate, multiple users can edit the same binary content file at the same time. The changes are saved after the last user has closed the session. Thus, only one update is applied to the binary content file.

The following information is intended to support administrators to configure the system for the Office 365 functionalities to be integrated in client applications based on our developer libraries.

Plug-in Configuration

The following plug-in configuration enables all functionalities of the Office 365 integration. It consists of an event listener (line 3), viewers (lines 4-30) and actions (lines 31-87) plug-ins. Before applying the plug-in configuration, replace <host> by your domain (line 28) and adjust the permissions according to your roles (e.g., replace the YUUVIS_DEFAULT role by a suitable custom role).

The event listener (line 3) triggers a refresh of the running client application after an update of the plug-in configuration.

In the viewers plug-in configuration section, the binary content file types are listed (lines 16-26) for which the VIEWER service should provide the preview via a specified dashlet.

In the actions plug-in configuration section, two actions are defined:

  • Editing of an existing Microsoft Office content file and storing the modified file as a new version (lines 32-42).

  • Opening a new Microsoft Office file, editing it and replacing the previous content file by the new one (lines 43-86). The following sub actions are specified for the Microsoft Office file types for which file creation is offered:

    • Microsoft Word file (lines 55-63)

    • Microsoft Excel file (lines 66-74)

    • Microsoft PowerPoint file (lines 77-85)

Plug-in configuration for Office 365 integration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
{
  "disabled": false,
  "load": "() => window.addEventListener('message', (e) => { console.log(e); if(!e || !e.data || !e.data.match || !e.data.match('MessageId'))  return; var data = JSON.parse(e.data); data && (data.MessageId === 'Host_PostmessageObjectUpdating' || data.MessageId === 'Host_PostmessageObjectConverted') && setTimeout(() => {var btn = api.util.$('.yuv-object-details .refresh-button'); btn && btn.click()}, 3500)})",
  "viewers": [
    {
      "mimeType": [
        "application/octet-stream"
      ],
      "fileExtension": [
        "nes"
      ],
      "viewer": "externals/x-nes?path=${path}#locale=${lang}&direction=${direction}&theme=${theme}&accentColor=${accentColor}"
    },
    {
      "mimeType": [
        "application/msword",
        "application/vnd.ms-excel",
        "application/vnd.ms-powerpoint",
        "application/vnd.openxmlformats-officedocument",
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
        "application/vnd.openxmlformats-officedocument.presentationml.presentation",
        "application/vnd.openxmlformats-officedocument.presentationml.template",
        "application/vnd.openxmlformats-officedocument.presentationml.slideshow"
      ],
      "viewer": "() => {parameters.path = parameters.path.replace('http://localhost:4400','https://&lt;host>'); var edit = api.session.user.hasRole('YUUVIS_DEFAULT') && !location.pathname.match('/versions/'); return '/dashlet365/?id=${id}' + (edit ? '' : '_' + dmsObject.version) + '&version=${version}&mimeType=${mimeType}&path=${path}&fileExtension=${fileExtension}&locale=${lang}&allowedExtensions=doc,docx,xls,xlsx,ppt,pptx&editMode=' + edit + '&displayName=' + api.session.user.get().firstname;}"
    }
  ],
  "actions": [
    {
      "id": "yuv.custom.action.office.edit.label",
      "label": "yuv.custom.action.office.edit.label",
      "description": "yuv.custom.action.office.edit.description",
      "priority": 0,
      "icon": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z\"/></svg>",
      "group": "further",
      "range": "SINGLE_SELECT",
      "isExecutable": "(item) => item.id && api.session.user.hasRole('YUUVIS_DEFAULT') && !location.pathname.match('/versions/') && api.content.viewer() && api.content.viewer().location.pathname === '/dashlet365/'",
      "run": "(selection) => api.content.viewer().postMessage(JSON.stringify({MessageId:'UI_Edit'}))"
    },
    {
      "id": "yuv.custom.action.office.new.label",
      "label": "yuv.custom.action.office.new.label",
      "description": "yuv.custom.action.office.new.description",
      "priority": 0,
      "icon": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z\"/></svg>",
      "group": "further",
      "range": "SINGLE_SELECT",
      "isExecutable": "(item) => item.id && api.session.user.hasRole('YUUVIS_DEFAULT') && !location.pathname.match('/versions/')",
      "header": "yuv.custom.action.office.new.label",
      "subActionComponents": [
        {
          "id": "yuv.custom.action.office.word.label",
          "label": "yuv.custom.action.office.word.label",
          "description": "yuv.custom.action.office.word.description",
          "priority": 0,
          "icon": "<svg width=\"512px\" height=\"512px\" viewBox=\"-64 0 512 512\" xmlns=\"http://www.w3.org/2000/svg\"&gt;<path d=\"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm220.1-208c-5.7 0-10.6 4-11.7 9.5-20.6 97.7-20.4 95.4-21 103.5-.2-1.2-.4-2.6-.7-4.3-.8-5.1.3.2-23.6-99.5-1.3-5.4-6.1-9.2-11.7-9.2h-13.3c-5.5 0-10.3 3.8-11.7 9.1-24.4 99-24 96.2-24.8 103.7-.1-1.1-.2-2.5-.5-4.2-.7-5.2-14.1-73.3-19.1-99-1.1-5.6-6-9.7-11.8-9.7h-16.8c-7.8 0-13.5 7.3-11.7 14.8 8 32.6 26.7 109.5 33.2 136 1.3 5.4 6.1 9.1 11.7 9.1h25.2c5.5 0 10.3-3.7 11.6-9.1l17.9-71.4c1.5-6.2 2.5-12 3-17.3l2.9 17.3c.1.4 12.6 50.5 17.9 71.4 1.3 5.3 6.1 9.1 11.6 9.1h24.7c5.5 0 10.3-3.7 11.6-9.1 20.8-81.9 30.2-119 34.5-136 1.9-7.6-3.8-14.9-11.6-14.9h-15.8z\"/></svg>",
          "group": "common",
          "range": "SINGLE_SELECT",
          "isExecutable": "(item) => item.id",
          "run": "(selection) => { var item = selection[0]; var user = api.session.user.get(); var uri = '/dashlet365/?id=' + item.id + '&version=' + item.version + '&fileExtension=docx&locale=' + user.userSettings.locale + '&editMode=true&displayName=' + encodeURIComponent(user.firstname) + '&action=editnew&mimeTypeGroup=WORD&conversion=none'; var w = window.open(uri); w.addEventListener('beforeunload', () => window.postMessage(JSON.stringify({MessageId:'Host_PostmessageObjectUpdating', Values: {osid: item.id}}))); }"
        },
        {
          "id": "yuv.custom.action.office.excel.label",
          "label": "yuv.custom.action.office.excel.label",
          "description": "yuv.custom.action.office.excel.description",
          "priority": 0,
          "icon": "<svg width=\"512px\" height=\"512px\" viewBox=\"-64 0 512 512\" xmlns=\"http://www.w3.org/2000/svg\"&gt;<path d=\"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm212-240h-28.8c-4.4 0-8.4 2.4-10.5 6.3-18 33.1-22.2 42.4-28.6 57.7-13.9-29.1-6.9-17.3-28.6-57.7-2.1-3.9-6.2-6.3-10.6-6.3H124c-9.3 0-15 10-10.4 18l46.3 78-46.3 78c-4.7 8 1.1 18 10.4 18h28.9c4.4 0 8.4-2.4 10.5-6.3 21.7-40 23-45 28.6-57.7 14.9 30.2 5.9 15.9 28.6 57.7 2.1 3.9 6.2 6.3 10.6 6.3H260c9.3 0 15-10 10.4-18L224 320c.7-1.1 30.3-50.5 46.3-78 4.7-8-1.1-18-10.3-18z\"/></svg>",
          "group": "common",
          "range": "SINGLE_SELECT",
          "isExecutable": "(item) => item.id",
          "run": "(selection) => { var item = selection[0]; var user = api.session.user.get(); var uri = '/dashlet365/?id=' + item.id + '&version=' + item.version + '&fileExtension=xlsx&locale=' + user.userSettings.locale + '&editMode=true&displayName=' + encodeURIComponent(user.firstname) + '&action=editnew&mimeTypeGroup=EXCEL&conversion=none'; var w = window.open(uri); w.addEventListener('beforeunload', () => window.postMessage(JSON.stringify({MessageId:'Host_PostmessageObjectUpdating', Values: {osid: item.id}}))); }"
        },
        {
          "id": "yuv.custom.action.office.powerpoint.label",
          "label": "yuv.custom.action.office.powerpoint.label",
          "description": "yuv.custom.action.office.powerpoint.description",
          "priority": 0,
          "icon": "<svg width=\"512px\" height=\"512px\" viewBox=\"-64 0 512 512\" xmlns=\"http://www.w3.org/2000/svg\"&gt;<path d=\"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm72-60V236c0-6.6 5.4-12 12-12h69.2c36.7 0 62.8 27 62.8 66.3 0 74.3-68.7 66.5-95.5 66.5V404c0 6.6-5.4 12-12 12H132c-6.6 0-12-5.4-12-12zm48.5-87.4h23c7.9 0 13.9-2.4 18.1-7.2 8.5-9.8 8.4-28.5.1-37.8-4.1-4.6-9.9-7-17.4-7h-23.9v52z\"/></svg>",
          "group": "common",
          "range": "SINGLE_SELECT",
          "isExecutable": "(item) => item.id",
          "run": "(selection) => { var item = selection[0]; var user = api.session.user.get(); var uri = '/dashlet365/?id=' + item.id + '&version=' + item.version + '&fileExtension=pptx&locale=' + user.userSettings.locale + '&editMode=true&displayName=' + encodeURIComponent(user.firstname) + '&action=editnew&mimeTypeGroup=POWERPOINT&conversion=none'; var w = window.open(uri); w.addEventListener('beforeunload', () => window.postMessage(JSON.stringify({MessageId:'Host_PostmessageObjectUpdating', Values: {osid: item.id}}))); }"
        }
      ]
    }
}

4.5.15. AI Plug-in

The Artificial Intelligence Platform is a set of APIs and tools that enable customers to set up and use AI functionalities by themselves, with low costs and high performance. Customers can export their own documents, train models using different algorithms provided by OPTIMAL SYSTEMS GmbH, evaluate trained models, and deploy them to make predictions. Every part of the AI Platform can be deployed on-premises or in the cloud.

The following information is intended to support administrators to configure the system for the AI functionalities to be integrated in client applications based on our developer libraries.

Classification in Object Type Definitions

The object types to be considered for analysis and predictions via the AI services have to be classified with the classification attribute:

<classification>prediction:classify</classification>

Set this attribute for all desired object types in their schema definition.

Inference Schema

The inference schema is a JSON configuration file defining the object types that will be available for the classification as well as the properties for which the metadata extraction should be done.

In order to use the Artificial Intelligence Platform with a client application based on our client libraries (e.g., yuuvis® client as reference implementation), objectTypeId has to be defined as a concatenation of app name and SOTs separated by pipes as can be seen in the example provided here.

4.6. Reference Client

yuuvis® Momentum client as reference implementation is an Angular application comprising multiple components. Each of these components implements a specific area of the client application using the functionality provided by the developer libraries.

In the header area, you will find the yuuvis® Momentum bar with icons for the most frequently used features.

Main menu icon

Main menu

yuuvis® icon

If you left-click the yuuvis® icon while pressing Ctrl, a new tab will open with another dashboard in your browser. If you left-click the yuuvis® icon in the hit list, folder, or object view, the dashboard will appear again.

Create icon

Create object

Search icon

Search (not displayed in the Dashboard view)

Settings menu icon

Settings menu

4.6.1. Dashboard

In the middle of the dashboard, you will find the multi-part search input field.

In the footer area, the objects that you recently created or edited are displayed in the form of a tile row. Click the Recently created or Recently edited buttons below the tile row to select which objects you want to view. If you click the More…​ button to the right of the objects listed in the footer area, the listed objects are displayed in a hit list.

4.6.2. Navigation by Keyboard

To make all functions and actions in yuuvis® Momentum client as reference application easily accessible, most of the commands can be called without using a mouse. To navigate through the application by keyboard, open the Quick access command palette at any time by pressing the Ctrl key twice. Then, start typing a string to find the command you are looking for.

Examples:

  • 'navigate' shows a list of all application views. Select an item from the list to open the respective view.

  • 'create' shows a list of possible create commands. One for each object type. Select an item from the list to create an object of the respective type. To find a specific create command, enter the name of the object type into the search field (e.g., si results in Create: Sick note, Create: Document (classified), etc.).

  • A full-text search of all DMS objects can be requested with ?<key word>.

4.6.3. Menus

Main Menu

You can access the main menu using the Main menu icon on the yuuvis® Momentum bar. You can access the following areas via the main menu:

  • Dashboard

  • Create object

  • In-tray

  • Inbox

  • My follow-ups

  • My processes

  • Retention management (as of 2022 Summer, only for users with specific authorization)

  • Settings

  • About

Object Actions Menu

Various actions are available for editing documents and folders via this menu, depending on the context and your permissions. It is available in different areas, such as in hit lists, in the folder view, and in the object view, via the Actions menu icon Object actions icon.

The suggested actions and processes always refer to the selected object(s). If you select several objects in an object list (such as a hit list) and then click the Object actions icon in the object list area, you can apply an action or a process to several objects.

Replace document file icon

Add as new version

Adds a document file to the selected object in a hit list or in a folder view. Adding a document file automatically creates a new document version.

Copy to clipboard icon

Copy to clipboard

Copies links from one or more selected objects to your operating system’s clipboard.

Delete icon

Delete

Deletes the selected object. Deleted items cannot be restored.

Download document file icon

Download document file

Downloads the document file of one or more selected objects to the local file system in the original format.

Follow-up icon

Manage follow-up

Creates follow-ups for a selected object or opens the dialog for modifying, deleting or confirming follow-ups.

Move icon

Move

Changes the parent folder of an object. It is also possible to remove the current parent folder so that the object will no longer have any parent objects.

icon baseline inventory black 48dp

As of 2022 Summer. Only for users with specific authorization.

Set retention time

Set an expiration date. Available for objects of document object types referencing the system:rmDestructionRetention secondary object type for which the retention time was specified so far.

Extend retention time

Replace the expiration date by a later date. Available for objects of document object types referencing the system:rmDestructionRetention secondary object type for which retention is already specified.

Open in context icon

Open in the folder/Open

Opens the selected object’s parent folder view. The object view will be opened for document files without a parent folder.

Show references icon

Show references

Displays an overview of the objects that reference the selected object.

Versions icon

Show versions

Opens an overview of all versions of the selected object. You can select two versions in the version list to compare them side by side. The action is not offered if the selected object only has one version (see Object Versions).

Set as current version This action is available when a Version view is displayed.

In an additional section MORE ACTIONS, plug-in actions can be available if configured by an administrator.

Settings Menu

Configure the main settings of your yuuvis® Momentum client. Open the settings menu by clicking the Settings menu icon Settings menu icon in the yuuvis® Momentum bar and select Settings from the dropdown menu. Alternatively, you can also open the settings menu via the Main menu.

The following information and configuration settings are available in the settings menu:

  • Language

    You can use the English and German buttons to control the language display of the general user interface elements and the object types, menus, fields, and catalogs specifically configured for your company.

  • Permissions

    The Roles dropdown menu displays the roles that are assigned to the currently logged in user.

  • Layout

    Customize the design of the client layout to your personal preference. * *Theme, Accent color and Dashboard background image

    + Choose between a light/dark/high contrast design, set an accent color, and upload a background image. This setting is stored on your device, meaning you can work on different devices with different layouts.

    • Dashboard type (as of 2022 Winter)

      Choose between the default dashboard layout and a customizable dashboard layout.

    • Export, Import and Reset

      You can also export the layout settings for use in other clients by clicking the Export button. Similarly, you can transfer the layout settings from other clients to yours by clicking the Import button. Click the Reset button to delete all of your individual layout settings.

  • Configuration

    Edit Hit lists, Search filters and Cache.

4.6.4. Hit List Configuration Menu

You can modify the hit lists' appearance and save it. You can configure a hit list for each individual object type as well as for mixed hit lists (hit lists with more than one object type). Run a search request for an object type and open the Configuration icon Configuration menu in the hit list if you want to configure the appearance of the hit list for this object type. Follow the same steps to configure mixed hit lists.

You can adjust the following in the configuration menu:

  • the columns that are shown/hidden in a hit list,

  • the order in which columns are displayed, and

  • the columns that are to be pinned or sorted.

Click Save to save the changes, or Cancel to discard them. Click Reset to default to restore the original configuration.

The saved hit list configuration is applied to each new hit list of the configured object type.

Filter Configuration Menu

This menu provides a graphical interface to configure your filters. It is accessible via the filter panel in the hit list view or via the Settings menu. All users can configure user-defined filters that are only available to themselves.

Users with the YUUVIS_MANAGE_SETTINGS role can additionally configure default filters that are available to all users across the entire system (via the Settings menu).

The configuration menu consists of the following areas:

  • Header area

    • The header area displays the object types for which you configure a filter.

    • You can configure cross-context filters or filters limited to one object type.

  • Filter list

    • The filter list shows you the available default filters and the filters you have configured.

    • Custom-configured filters are highlighted in bold in the list.

    • The filter list is divided into the areas Custom filters, Activated filters, and Deactivated filters.

  • Configuration area

    • The configuration area displays the configuration of the filter you have selected in the filter list.

    • This is where you can also configure your own filters.

You can create the following types of filters:

  • Object-specific filters

    • Only valid for a specific object type.

    • Only the filter fields of the corresponding object type are available in addition to the basic data filter fields.

  • Cross-context filters

    • Applicable to several or all object types.

    • Different filter fields will appear depending on which object types are contained in the object list in which you open the filter configuration menu.

To organize filter display in the filter panel, you can activate and deactivate the default and saved filters. Deactivated filters will then no longer be displayed in the filter panel. These settings apply to the filter panels of all object lists.

You can also delete filters you have created and saved. Default filters cannot be deleted.

Catalog Edit Menu

Catalogs are used to offer a selection list of predefined values for metadata fields in an object’s Metadata aspect area.

You require the YUUVIS_MANAGE_SETTINGS role to be able to edit catalogs in the client. To edit a catalog click the Pencil icon Pencil icon (if available). The catalog edit menu opens in which the following features are available:

Add entry

You can create new catalog entries using the entry field in the header area of the edit menu.

Remove icon

Delete a catalog entry by clicking the Remove icon. If you delete a catalog entry in the catalog edit menu, the catalog values can then not be deleted in metadata forms. Catalog values orphaned by deletion are marked red in the metadata form and by a red Remove icon.

Blank checkbox icon / Ticked check box

This checkbox allows you to control whether a catalog entry is displayed in the metadata form or not.

Sort feature icon

If you click this icon, you can drag and drop the line of the catalog entry to where you want it to be in the list of catalog entries.

4.6.5. Object Aspects

Objects contain various information that are displayed in units called object aspects. They are summarized in a form with a header area and multiple tabs containing the individual object aspects.

The header area contains a title and description (if available) and the following icons:

Message icon Mail icon Personal file icon Document icon Text document Folder icon Personal details icon Personal contract icon …​

Visualizes the object type.

Refresh icon

Refresh the object aspects.

Actions menu icon

Object actions menu.

The layout of the object areas can be customized. If you have changed the number and the width of the aspect areas, these changes will be saved automatically when you switch views.

Split aspect icon

Split aspect. The view splits and several aspect areas are displayed next to each other. You can use the separator bar between the aspect areas to adjust the size of the displayed areas.

Undock

Only available for the Content aspect. Open the content preview in a separate browser window.

Close icon

The aspect area will revert back to normal. The following object aspects are available.

Summary Aspect Area

Displays the object properties (basic metadata, type metadata and tags) of an object, such as name, editor, number of versions, file size, etc. The information is divided into the areas Basic metadata, Type metadata, and Advanced information.

If more than one version of a document exists, you can also click the highlighted version number to access the version view.

Metadata Aspect Area

The Metadata aspect area offers the option of editing the type metadata of the selected object, provided that you have the appropriate rights.

History Aspect Area

The History aspect area provides a view of the creation process as well as the editing and usage history of an object. It contains a chronological list of who made which changes to the content or type metadata of an object and when. The output (download and read) of an object is also logged in this aspect area. You can filter the events of the editing history, if needed. The entries in the history also contain links to the versions of the document. You can open the version view by clicking one of these links.

The entries in the history can be filtered by

  • limiting the date to a time period using the operators (>, <, =, -), or

  • specifying a type of action by ticking the corresponding checkboxes. Clicking a group name will select all history entries of this group.

For users to be able to see READ events in the object history, i.e., whether an object was only viewed, they must be assigned the YUUVIS_MANAGE_SETTINGS role.

Content Aspect Area

The Content aspect area offers a content preview of the selected object. Different content previews are used depending on the file type of the document file, based on the VIEWER service or PDF rendition as described in Preview of Binary Content Files.

4.6.6. The Version View

If type metadata is modified or the content file is edited, replaced, moved, or deleted, then new versions of the object are created. The older versions are retained. All versions of an object can be managed in the version view.

There are a number of ways to open the version view:

  • Via the object actions menu, if the selected document has more than one version

  • In the object area via the link on the version number in the Summary aspect area.

  • Via the links on the version numbers in the History aspect area.

The version view shows a list of all versions. Select a version to display its version-specific object information in the object aspect area as described above. If two versions are selected in the list, you can compare them in the tabs Changes to metadata and Changes to content where you have a number of actions available for a visual comparison.

If the content preview is provided as a PDF rendition, it is only available for the current version.

The slider in the center helps you find the differences. If you move your mouse over the slider, a dropdown menu will offer you more comparison options.

Slider icon

Drag the slider left and right to resize the images.

Circle icon

Displays both images instantly.

Circle icon|Circle icon

Layers both images on top of each other so that you can use the sliders to display one image and then the other.

Crossed circles icon

Only displayed when both images are superimposed. Clicking the icon reverts the view back to normal.

An older version can be set as the current version. To do this, select the desired version and select Versions icon Set as current version from the object actions menu. The version view is automatically refreshed by this action.

4.6.7. Creating Objects

You require the YUUVIS_CREATE_OBJECT role to be able to create objects.

You can create objects (folders and documents) in stages. This procedure is especially useful if you create a lot of objects in a short period of time that you do not want to complete until later.

Creating Documents

The following options are available for you to create documents:

  • via the yuuvis® Momentum bar

  • via the Main menu

  • via drag and drop

The following information is relevant for any document creation.

Parent Folders:

If you want to create a document, the first thing you have to decide is if you want to define a folder as parent object. For this purpose, you first need to display the folder object you want to specify as parent for your new document. Once you have opened the right folder, you can create one or more documents as child objects in the folder via the yuuvis® Momentum bar or by drag and drop.

The new document will not have a parent object

  • if you did not open a folder before creation, for example, if you are on the dashboard, in hit lists, in a document’s object view, or

  • if you created it via the Main menu.

Document Object Types:

You can find out which document object types are available for you in the object creation dialog. One of the basic properties of all document types is that they may or may not contain a binary content file.

A distinction is also made between the following object types, particularly with regard to the creation process:

  • Simple object types

    • Simple object types are the fastest way to create documents.

    • The object type is assigned when the object type is selected.

    • The main difference to other object types is that you do not get a preview of the uploaded file during the creation process.

  • Variable object type with fixed object type assignment

    • This object type offers you a preview of the uploaded file during the creation process.

    • This gives you the chance to double-check that the object type you selected matches your file.

  • Variable object type with subsequent object type assignment

    • For this object type, you can assign the object type after the creation process.

    • In the first step of the creation process, only a small amount of general type metadata is entered and the document is created.

    • You can assign the final object type at a later point, depending on the configuration of the variable object type.

Artificial intelligence can be used to create documents with variable object types regardless of how your yuuvis® Momentum system and individual object types are configured. The AI helps you to automatically classify your documents by showing you a suggestion list during object type assignment. This list contains a weighting based on machine learning.

Upload Status:

If you upload files, you can check their upload status in the yuuvis® Momentum bar. Click the Upload status icon to view the names and statuses of the files uploaded in a menu. A green tick behind an entry indicates that the upload process was successful. Click the Remove icon to remove entries from the list to get a better overview. The Upload status icon will no longer be displayed once all of the entries have been removed from the list.

Cancelling the Creation Process:

There are several ways to cancel the creation process:

  • Click Cancel during the creation process. In the form that opens you can:

    • delete the object (Remove object button). The incomplete object is permanently deleted. The files uploaded and/or type metadata entered up to that point will be lost.

    • place the file in the in-tray (File in in-tray button). The incomplete object, including all type metadata entered and/or all files uploaded up to this point, is placed in the in-tray. You can continue and complete the creation process at a later time.

  • Click the yuuvis® logo in the yuuvis® Momentum bar, which is part of the main menu, or an entry in the Settings menu during the creation process. Click OK in the form that opens to permanently delete the incomplete object. The files uploaded and/or type metadata entered up to that point will be lost.

Filing E-mails and Attachments:

There are many ways and options available to file e-mails and e-mail attachments. You can file e-mails together with their attachments or file the e-mails and attachments separately. You can upload e-mails from the local file system or drag and drop them.

You will need to keep a few things in mind when filing e-mails directly from an e-mail program via drag and drop. Whether or not it is possible to drag and drop e-mails from an e-mail program directly into the client depends on the e-mail program and the browser you are using. For example, the drag-and-drop filing of e-mails from Microsoft Outlook is supported if the client is running in a Google Chrome browser. In this case, the e-mail is filed in yuuvis® Momentum in the same file format (*.msg) in which it is transferred from Microsoft Outlook. Filing an e-mail in the MSG file format has one distinct disadvantage in that the content preview will differ slightly from the filed e-mail.

If you are working with a different browser, Firefox for example, and would like to file e-mails via drag and drop, then it is best to use the Outlook Add-In for Drag & Drop from OPTIMAL SYSTEMS. It enables drag-and-drop filing, ensuring that e-mails that are dropped onto the client are transferred as EML files so that the content preview generates a more accurate view of the filed e-mail. If you are interested in this add-in, please contact your partner at OPTIMAL SYSTEMS.

Save e-mail attachments in the local file system before uploading them to yuuvis® Momentum. The next steps required to file e-mail attachments from the local file system are similar to those used to create documents in the client. The use of drag and drop to file attachments stored in the local file system is also supported.

Creating Folders

Folders can be created via the yuuvis® Momentum bar as well as via the Main menu. You cannot create a folder inside another folder.

You cannot change a folder’s type after it has been created. If you want to change the folder type during creation, you can return to the object type selection by clicking in the breadcrumb trail in the header area of the form.

If you want to cancel the creation process and leave the form, click an icon on the yuuvis® Momentum bar.

4.6.8. Editing Objects

You require the YUUVIS_CREATE_OBJECT role to be able to edit objects.

4.6.9. In-tray – Assigning Final Object Types

The functionality is based on floating secondary object types. You can assign those object types to incomplete objects after the creation process.

In the first step of the creation process, only a small amount of general type metadata is entered and the object is created. You can assign the final object type at a later point, depending on the configuration of the secondary object type.

All incomplete objects are listed in the Main menu in the in-tray. If you want an object to be displayed in the in-tray, assign the appclient:dlm:prepare tag with value 0. Replace the value with 1 as soon as you are finished with the desired manual adjustments for the object. As the tag is specified in some object type definitions in the client’s schema, it can be set via metadata form.

If you select an object in the list of incomplete objects in the in-tray, its object aspects will be displayed. You can see which additional options are available for the selected object by the buttons displayed in the Metadata aspect area:

  • Assign object type button: You can assign a final object type to the object.

  • Extend button: You can extend and reduce the type metadata of the object.

If the Assign object type button is displayed in the Metadata aspect area, then you can assign an object type to the object. You can only assign an object type to an object once and this cannot be changed. After you have assigned an object type to an incomplete object, the Assign object type button will no longer be displayed and the object will be removed from the list of incomplete objects.

Adding or Replacing Binary Content Files

You can replace binary content files assigned to document objects with a new file, for example if a copy of the file was modified outside of yuuvis® Momentum and you would like to overwrite the file in yuuvis® Momentum with the new version. To do this, you have to upload the new file from your local file system to yuuvis® Momentum and add it to the document object as a new version.

The following options are available for you to add document files:

  • Use the Add as new version function in the object actions menu.

  • Drag and drop.

If you want to add the binary content file of another object, then you will need to first download this file to your local file system using the object actions menu before you can add it to another object as a binary content file.

Editing Metadata

Entries for type metadata are made and maintained via fields in metadata forms. You can enter type metadata both during and after object creation in the Metadata aspect area. For variable object types, you can also extend or reduce the metadata at any time. When an object is created, the object type is determined and the metadata form is filled out.

For documents, the Metadata aspect is displayed in hit lists and folder views (if a folder is specified as parent object), for example, if you have selected the corresponding document.

For folders, you can also display the Metadata aspect area in hit lists if you have selected the corresponding folder. In the folder view, you must click the folder name in the header of the structure area to display the Metadata aspect area.

Metadata Form Fields:

The form fields are configured by the administrator. Notices are shown if entries in fields and references between fields do not match these specifications.

Only integers from -231 to 231-1 (i.e., from -2,147,483,648 to 2,147,483,647) may be entered in the metadata form. Entries that fall outside this range will cause rounding or other errors.

Catalog fields

Catalog entry. Selection from a suggestion list after one character has been entered or via the catalog. For hierarchical catalogs with entries in layers, the administrator configures whether the entries for all layers are accepted or only the entry for the lowest layer. Free inputs are not accepted.

If a Pencil icon Pencil icon is displayed, you can open the catalog item in the catalog edit menu.

Catalog values marked in red are catalog values that can no longer be assigned to a catalog entry due to adjustments made to the catalog. Click on the red Remove icon Remove icon to delete them.

Checkboxes

Checkboxes either have the status 'active' or 'not active'. On an administrative level, the additional status 'neutral' can also be integrated.

Switches

Alternative visualization of checkboxes with an intuitive representation of the 'neutral' value, i. e., null.

Screenshot switch left = false

Screenshot switch centered = null

Screenshot switch right = right

Date fields

Date. Free input or via the Calendar icon Calendar icon.

The format of the date varies based on the user’s language settings. If you click in a date field, the date format to be entered will be displayed.

German: DD.MM.YYYY

English: MM/DD/YYYY

E-mail fields

E-mail addresses must be entered in full and contain the @ character. Placeholders and so on are not supported. E-mail addresses are not case sensitive. To enter multiple e-mail addresses, press Enter to confirm your entry.

Click the E-mail icon E-mail icon to create an e-mail with this address in the local e-mail application.

ID fields

User or group. Selection from a suggestion list after two characters have been entered.

Free inputs are not accepted.

Mandatory fields

Mandatory fields must be completed. They are indicated by an asterisk.

Numerical fields

Digits. The maximum number of digits and decimal places is defined.

Tables

Entry via a dialog. New rows are added at the bottom. Double-clicking a row opens the dialog for editing or deleting the row. The content of metadata tables can be exported as a *.csv file.

Telephone fields

To enter multiple telephone numbers, press Enter to confirm your entry.

URL fields

Addresses in URL fields must begin with the protocol information, e.g., http://, https://. Web addresses must be entered in full. Placeholders and so on are not supported. Web addresses are not case sensitive. To enter multiple web addresses, press Enter to confirm your entry.

The URL can be opened in the browser by clicking the www icon www icon.

Tables in Metadata Forms:

The following customization options and functions are available for tables in metadata forms:

  • Sort by column: If you click the header of a column, the table will be sorted by the contents of the column. Clicking the header again undoes the sorting. Tables in metadata forms can only be sorted by the content of a column.

  • Optimal column width: If you click the right column separator of a column, the column will be adjusted to the optimal width.

  • Edit table row: The table is opened in a new form with an input area in full view to make editing easier. The row you have clicked is also highlighted in the opened form. The values of this row are already entered in the form for editing or for adding a new row.

  • Align table columns: All columns in the table will be adjusted to the optimal width.

  • Open table: The table is opened in a new form in full view to make editing easier. If you select a row in the opened form, the input area for editing the row is also displayed.

  • Export spreadsheet data to CSV file: The table will be exported in CSV file format.

    • Text fields are in output in quotation marks (e.g., "abc").

    • Date and time fields are output in ISO format 8601.

    • Decimal numbers are formatted in the language the user has specified.

    • Values from reference fields are output as object IDs.

    • Values from users are output as user IDs.

    • Boolean values are output as FALSE and TRUE or empty/NULL.

  • Insert new row: The table is opened in a new form with an input area in full view to make editing easier.

Prepopulated Metadata Fields:

Certain fields in metadata forms may already be prepopulated when objects are created. The administrator defines which fields are prepopulated. These fields are specifically indicated in the metadata forms when objects are created. Manually entered data has priority, i.e., it overwrites automatically imported data in case of conflict. There is a distinction made between two types of prepopulated metadata fields:

  • Object type-specific prepopulated data

    Metadata fields that are yielded by the object type’s configuration can be prepopulated depending on the object type. This can be prepopulated data from free text inputs, catalogs, scripts, or additional components. Metadata fields that are prepopulated by the object type definition are indicated by a df during the creation process.

  • Extracted prepopulated data

    Specific pieces of data from the metadata of the files (such as title, creation date, author, etc.) can be automatically extracted and written to the metadata, depending on the configuration of your yuuvis® Momentum system, when uploading files. Object type-specific prepopulated data will be overwritten during this process. Metadata fields that extract data from the metadata of uploaded files are indicated by an ex during the creation process.

Object-specific and extracted prepopulated data is transferred as follows:

  • If both a default value and an extraction are defined for a field, then the data for the extraction (if available) is transferred during the creation of an object in yuuvis® Momentum client; otherwise the default value is transferred to the metadata form.

  • No extracted data will be shown in the metadata fields indicated as such for files to be filed as a batch. If you enter information in these fields, it will overwrite all extracted data. If you do not enter anything in these fields, all of the extracted data (if available) will be transferred; if not available, the default value will be transferred to the metadata form.

  • If the document file is later replaced, the extraction will be repeated. Existing data in fields configured for a mapping will be replaced or – if no new value is found – removed.

References:

In metadata forms, the metadata of another object can be transferred into certain fields, which are known as reference fields. These fields reference the ID of certain objects and therefore are retained even if the referenced object is renamed or moved. The administrator configures reference fields, and they are set up as multi-fields to hold several values.

References that have been set up are displayed both in hit lists and in the Summary and Metadata aspect areas. They are indicated in hit lists and in the aspect areas with a Reference icon Reference icon. Click the icon to quickly open the referenced object(s). If you hold down the Ctrl key while clicking, the location of the referenced object will be displayed in a new tab.

You can create and remove references in the Metadata aspect area.

If a referencing object is located in a folder, you can jump to the filing location of the referenced object by double-clicking the list entry. If the object clicked is located in the main directory, the object view of the referencing object will open.

If a user does not have any rights to a referencing object, it will not be displayed for this user. If a user has read access to a referencing object, but not to the folder in which the object was filed, then the user is only offered the object view for the object.

4.6.10. Searching

You can start search requests on any page. The search dialog is available for this purpose on the dashboard and in the yuuvis® Momentum bar. The following options are available and can also be combined:

Drop-down icon

A drop-down menu to the left of the search input field to limit your search to selected object types.

Search term

Full-text search for terms that you think might occur in the objects you are looking for. Searches the contents of document files as well as the string fields within metadata of objects. Note that number and date fields are not taken into account in the full-text search.

Filter icon

Define search conditions. Search for specific properties of objects, such as

  • basic metadata (creator, editor, created on, version, file size/type, etc.)

  • type metadata (title, description, subject, first/last name, etc.)

  • tags (status of an object within a technical process)

Select the property and specify the value by which you want to filter. For properties with resolved user IDs as values, a preview of available users is displayed after typing the first letters. To display all users, type **.

The Filter panel in the Hit list view uses predefined filters. In addition, filter criteria can also be changed in the search field in the yuuvis® Momentum bar. These settings are not saved and are only available for the current session.

Search icon

Run the search request.

The search combines all search terms and all limitations on object properties and object types with AND by default. Object types are combined in the search with OR. In the search dialog, you can change the logical operator of multiple search terms or criteria to OR and/or create nested searches.

4.6.11. Hit List View

The results of a search are displayed in a hit list of all objects that were found. The hit list view is divided into the areas described below. You can sort, filter, and configure the hit list. Search results are sorted lexicographically. This means that sorting is case-sensitive and special characters are accounted for. Depending on the configuration, the hit list will contain several columns with basic metadata, type metadata, tags, such as type, title, description, editor, etc. The view of a hit list always corresponds to the hit list configuration of the selected object type.

Header Area

Download document file icon

Export the hit list with the displayed columns as CSV file. Datetime values will be formatted in ISO standard whereas decimals will be formatted corresponding to the localization of the logged-in user.

If you want to display the exported file in MS Excel, please use CSV import with UTF-8 encoding (or the configured encoding).

Settings icon

Hit list configuration menu. You can add or remove columns via the Hit list configuration menu in the header of the hit list.

Refresh icon

Refresh the hit list.

Actions menu icon

Object actions menu. If multiple objects are selected, the action will be applied to all of them.

Filter Panel

In the filter panel, you can control the display of the objects shown in a hit list. You can limit the number of objects shown in the hit list by using filters. You can find the filters in the filter panel next to the object list. Click the Double chevron icon Double chevron icon to expand the filter panel if it is collapsed.

In the filter panel, you can use both default filters that are available to every user throughout the system and your own filters that you have configured yourself via the filter configuration menu. How many filters are available and which depends on the object types that are displayed in an object list.

You activate a filter by clicking the checkbox next to it. The numbers in front of the checkboxes indicate how many documents in the hit list match the specific filter criterion.

You can expand and collapse the sections in the list of filters by clicking the Minus icon Minus or Plus icon Plus icons. In the footer of the filter panel, you can toggle between different layouts for the display of the filters (flat list, grouped), or expand and collapse the filter panel. The filter panel’s layout settings are saved when you exit the view. The next time you open the same view, the same layout settings will be displayed.

Hit List Area

Hit List

The hit list presents the results of a search request in a table per default. It contains several columns containing basic metadata, type metadata, and tags with information such as object type, title, description, editor, etc.

The appearance of this table can vastly differ, depending on the search, configuration of object types, or configuration of the hit list. This means that the view of a hit list always corresponds to the hit list configuration of the object type currently selected in the hit list.

You can make the following changes directly in a hit list:

  • Adjust column widths by moving the column divider or by double-clicking the column divider (creates the optimal column width). The change of column width will also affect other hit lists, provided that you use the same columns there, too. If you have changed column widths, these changes will be saved automatically when you switch views. In addition, these settings apply to all users who use the same browser as you.

  • Adjust column sorting:

    • You can sort the hit list by a column by clicking its header. Clicking the column header repeatedly will change the sort direction or undo it.

    • You can sort a hit list by several columns by holding the Ctrl key. Numbers and small arrows in the column headers indicate the sort order.

    • Columns with labels (for example, columns with user names) cannot be sorted.

    • If you have sorted a hit list by clicking the column headers and then open the hit list configuration menu, this sorting will be transferred to the hit list configuration menu and can be saved there.

If you select an object in the hit list, the object aspects will be displayed on the right-hand side of the screen. You can open the folder view, or the object view if a document does not have a parent folder, by double-clicking an item in the hit list.

Selecting and Focusing

We distinguish between selected and focused elements:

  • Selected elements:

    • The row of selected elements is highlighted.

    • Multiple rows can be selected.

  • Focused elements:

    • Only one element out of all selected elements can be focused.

    • The icon is highlighted again at the beginning of the row.

    • For focused elements, the object aspects are displayed in the object area.

You can use the mouse to select further elements by additionally holding down the Ctrl key or the Shift key while clicking these elements. If you hold down the Shift key when clicking the mouse, all the rows between the row you have clicked and the row with the most recent focusing are selected, but the focus remains on the first row. If you hold down the Ctrl key when clicking the mouse, the row you have clicked is highlighted in addition to the existing selections. The focus still remains on the first row. When you position the cursor on another selected row and click the right mouse button, this row is focused.

Click the mouse on the selected row while holding down the Ctrl key to remove the selection again.

Copying

The copy to clipboard operation is supported in all grids (result list, metadata table) and can be applied in the following ways:

Key combination Selection

Ctrl+C

Single cell

Ctrl+Alt+C

Single cell and the corresponding column header

Ctrl+Shift+C

Selected rows

Ctrl+Shift+Alt+C

Selected rows and all column headers

To indicate that copying the selection was successful, the selected cells/rows are highlighted in the accent color for a few seconds. This is the default setting, which the administrator can adjust accordingly.

Footer

The number of hits is shown in the footer of the hit list. In the footer of the hit list, you can also choose between the display layouts, scroll through the hit list or go to the start or end.

Table icon

Table layout

Gallery icon

Gallery layout

List icon

List layout

Previous icon / Next icon

Previous/next page of the hit list

First page icon / Last page icon

First/last page of the hit list

Object Area

The object area is displayed to the right of the hit list area when you select an element from the hit list. It shows all object aspects of the selected object. To hide the object area, click the element in the hit list again while holding the Ctrl key.

4.6.12. Business Process Management

Processes are created based on at least one object, which is stored as an attachment in the process.

In the default configuration, users can start a follow-up process for an object via Manage follow-us provided by the object actions menu. If an administrator configures further types of business processes in addition to follow-up processes, they can be started for individual objects via the respective object action under MORE ACTIONS in the object actions menu.

Each process contains tasks that must be completed by users.

There are three specific views that allow users to handle processes:

  • The Inbox view lists all tasks of processes the currently logged-in user is assigned to, such as reminder tasks for follow-up processes that have reached their follow-up date.

  • The My follow-ups view lists all active follow-up processes that you created via the object actions menu.

  • The My processes view lists all processes started by the logged-in user.

In the individual views, the process/task list can be sorted by individual columns as already described for hit lists. Furthermore, it is possible to filter by specifying a term that should be matched by the subject of each displayed process/task.

The number of displayed processes/tasks is limited to 100 in the individual views in the default configuration. The configuration can be customized by specifying other values in the main.json configuration file.

Inbox View

The Inbox shows an overview of all the tasks a user is assigned to. The view of the Inbox can be toggled between a list view and a table view using the corresponding buttons at the bottom right.

In the Table view, the following columns are displayed: Type, Task, Subject, Received on and Due on. In the Type column, the Processes icon Processes icon represents tasks of custom processes and the Notification icon Notification icon represents follow-ups. The sort order can be changed by clicking on the header of the corresponding column. The position of columns can be rearranged within the table by drag and drop of individual columns. A red entry in the Due on column indicates that this task is overdue.

In the List view, Type (icon only), Subject and Task are displayed on the left-hand side, and the due date on the right-hand side. Sorting the inbox items or repositioning the information is not possible.

Tasks can be opened for editing by clicking on the respective task in the Inbox view. On the right-hand side, the task details will open, in which you can edit the task. After editing, the task can be further processed using the buttons at the bottom of the task details.

To process tasks, different buttons are available depending on the nature of the task. Standard follow-ups with the entry “Review” in the Task column only offer the option Confirm. For custom processes, Delegate, Forward, and other custom buttons are available as well as individual entries in the Task column, depending on the process model.

In the Inbox, attachments can be added to the task or deleted from it while the process is running. Attachments are displayed in the Attachments task aspect in the task details for every task. The document highlighted in the accent color is the focused attachment for which object details are displayed. Note that the first attachment cannot be deleted.

My follow-ups View

Follow-up processes can be created for both folder and document objects. They act as processing reminders, for example. You can only create one follow-up for each object via the object actions menu. Once you have created a follow-up, it will be displayed in the My follow-ups view provided via the main menu until the due date of the follow-up is reached. Here you can edit or delete all active follow-ups (i.e., follow-ups for which time has not yet expired).

When the due date of a follow-up is reached, the object to be followed up is also displayed in the Inbox provided via the main menu. By confirming the follow-up, you can remove expired follow-ups from both the Inbox and the My follow-ups view.

My processes View

If you started a process, it appears in the My processes view. In addition to the filter option by a query term, the predefined filters All, Running and Completed are available.

By selecting a process in the task list, the users can open the process details view with the Summary, Progress, Comments and Attachments aspect areas.

4.6.13. Retention Management View

Only for users with specific authorization: The Retention management view is accessible via the Main menu as of product version 2022 Winter LTS. A hit list view displays all objects with a system:rmExpirationDate property. The functional icons in the header area are already described for the hit list view.

The first column of the hit list contains a colored label that indicates whether the expiration date is already exceeded or not. A time is specified that tells users by how long the expiration date is already exceeded or how long it is until the expiration date is reached. If the time is longer than 12 months, it is indicated in years (e.g., 1.5 year(s) means one year and six months).

The predefined filters are:

  • having any expiration date (All),

  • having an expiration date within the next month (Next month) or

  • having an expired expiration date (To be removed).

By clicking an object in the hit list, you open the object aspects for this object.

The destruction date is displayed if specified, but is not evaluated.

4.6.14. Linking your Documentation

You can set up a hyperlink in the About yuuvis® area as well as on the yuuvis® Momentum bar to link to your own documentation of your custom solution. The corresponding URL is configured in the main.json configuration file.

5. Administration Tools

5.1. Tenant Management API

The Tenant Management API is a collection of endpoints provided by the tenant-management service. It is responsable for the retrieval of information from the connected identity provider for Web-API Gateway, clients and business process management (if configured). Thus, you can connect any identity provider working with OAuth2.

In combination with Keycloak, it additionally provides the tenant and user management functionality used by yuuvis® architect.

5.1.1. Endpoints

admin-controller

These endpoints can be used for role, group and user management in Keycloak within the own tenant. Administrative tenant-specific information can be retrieved as well.

The access to the endpoints has to be limited to administrative users as specified with the permission for /tenant-management/api/admin/** endpoints in the authentication-prod.yml configuration file.

If you use yuuvis® architect, do not change the default access condition that is matched with the YUUVIS_TENANT_ADMIN role.

As of 2022 Autumn, in the default configuration, users with the YUUVIS_MANAGE_SETTINGS role are allowed to manage users of their own tenant as well. They have access to all endpoints /tenant-management/api/admin/users/**. However, the following operations are not allowed for them:

  • Assigning the YUUVIS_TENANT_ADMIN or YUUVIS_SYSTEM_INTEGRATOR roles.

  • Editing the data of users having the YUUVIS_TENANT_ADMIN or YUUVIS_SYSTEM_INTEGRATOR role.

  • Deleting users having the YUUVIS_TENANT_ADMIN or YUUVIS_SYSTEM_INTEGRATOR role.

GET /tenant-management/api/admin/groups - Retrieve a list of groups.
As of Version

2021 Autumn

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Retrieves all groups with the assigned roles and members for the tenant.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example
curl -X 'GET' \
  'https://examplehost.net/tenant-management/api/admin/groups' \
  -H 'accept: application/json'
Response Example
[
  {
    "id": "fa854da5-004a-5187-9cc6-3b5c5bc2c728",
    "name": "HR-Manager",
    "realmRoles": [
      "EMAIL_WITHOUT_ACL"
    ],
    "members": [
      "gustav"
    ]
  },
  {
    "id": "dab12224-4e4a-5e23-06e8-ffd3ed17cff7",
    "name": "QA-Manager",
    "realmRoles": [
      "QA_MANAGER"
    ],
   "members": [
     "susanne",
     "gustav"
   ]
  }
]
POST /tenant-management/api/admin/groups - Create or add a top level realm group.
As of Version

2021 Autumn

Request Method

POST

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Creates a new group for the tenant with the properties specified in the JSON request body.

In the response, the group ID is returned again in JSON format.

The only required parameter is name for the group name. If roles should be assigned the given realmRoles must exist.

Response HTTP status codes:

HTTP status code Meaning

201

CREATED

401

Unauthorized

409

Conflict

Request Example

POST /tenant-management/api/admin/groups HTTP/1.1

{
    "id": "fa854da5-004a-5187-9cc6-3b5c5bc2c728",
    "name": "HR-Manager",
    "realmRoles": [
      "EMAIL_WITHOUT_ACL"
    ],
    "members": [
      "gustav"
    ]
}
Response Example

201 CREATED

GET /tenant-management/api/admin/groups/{id} - Retrieve representation of a group.
As of Version

2021 Autumn

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Retrieves the group specified by id with the assigned roles and members for the tenant.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

GET /tenant-management/api/admin/groups/fa854da5-004a-5187-9cc6-3b5c5bc2c728 HTTP/1.1

no request body

Response Example

200 OK

Response Body
{
    "id": "fa854da5-004a-5187-9cc6-3b5c5bc2c728",
    "name": "HR-Manager",
    "realmRoles": [
      "EMAIL_WITHOUT_ACL"
    ],
    "members": [
      "gustav"
    ]
}
PUT /tenant-management/api/admin/groups/{id} - Update a group.
As of Version

2021 Autumn

Request Method

PUT

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Updates the data of the group specified by id with the data passed in the request body in JSON format.

This endpoint does not allow for adding the role YUUVIS_SYSTEM_INTEGRATOR to a group. If this role is passed as an entry of the realmRoles list, the endpoint will return an error.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

PUT /tenant-management/api/admin/groups/a99a0bb1-2345-6c77-8901-22dee3f4a567 HTTP/1.1

Request Body
{
    "id": "fa854da5-004a-5187-9cc6-3b5c5bc2c728",
    "name": "HR-Manager",
    "realmRoles": [
      "EMAIL_WITHOUT_ACL"
    ],
    "members": [
      "gustav"
    ]
}
Response Example

200 OK

DELETE /tenant-management/api/admin/groups/{id} - Delete a group.
As of Version

2021 Autumn

Request Method

DELETE

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Deletes the group specified by id.

Response HTTP status codes:

HTTP status code Meaning

204

No content

401

Unauthorized

404

Not found

409

Conflict

500

Internal Server Error

Request Example

/tenant-management/api/admin/groups/a99a0bb1-2345-6c77-8901-22dee3f4a567

no request body

Response Example

200 NO CONTENT

no response body

GET /tenant-management/api/admin/roles - Retrieve all roles.
As of Version

2020 Winter

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Gets all roles.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

500

Internal Server Error

Request Example

GET /tenant-management/api/admin/roles HTTP/1.1

no request body

Response Example

200 OK

Response Body
{
  "name": "TEST_ROLE",
  "description": "Example role"
}
POST /tenant-management/api/admin/roles - Create a role.
As of Version

2020 Winter

Request Method

POST

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Creates a new role for the tenant with the properties specified in the JSON request body.

The only required parameters are name for the role and its description.

Response HTTP status codes:

HTTP status code Meaning

201

CREATED

401

Unauthorized

500

Internal Server Error

Request Example

POST /tenant-management/api/admin/roles HTTP/1.1

Request Body
{
  "name": "TEST_ROLE",
  "description": "Example role"
}
Response Example

201 CREATED

Response Body
{
  "errors": [],
  "valid": true
}
DELETE /tenant-management/api/admin/roles/{role-name} - Delete a role.
As of Version

2021 Autumn

Request Method

DELETE

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Deletes the role specified by name.

Response HTTP status codes:

HTTP status code Meaning

204

No content

401

Unauthorized

404

Not found

409

Conflict

500

Internal Server Error

Request Example

/tenant-management/api/admin/role/myrole

no request body

Response Example

200 OK

no response body

GET /tenant-management/api/admin/tenant - Retrieve the top-level representation of the tenant.
As of Version

2020 Winter

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Retrieves the tenant data as given in the Keycloak identity provider for the tenant of the calling user.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

GET /tenant-management/api/admin/tenant HTTP/1.1

no request body

Response Example

200 OK

Response Body
{
  "name": "My Name",
  "description": "My Tenant",
  "displayNameHTML": "This is a HTML formatted display name",
  "adminPassword": "changeme",
  "adminEmail": "mrexample@examplemail.net",
  "adminFirstName": "Johann",
  "adminLastName": "Fluss",
  "enabled": true,
  "emailSettings": {
    "host": "string",
    "from": "string",
    "username": "string",
    "password": "string",
    "fromDisplayName": "string",
    "port": 0,
    "enableAuthentication": true,
    "enableSSL": true,
    "enableStartTLS": true
  },
  "clientSettings": {
    "redirectUris": [
      "string"
    ],
    "postLogoutRedirectUri": "string"
  },
  "systems": {
    "ips": true,
    "yuuvis": true
  }
}
PATCH /tenant-management/api/admin/tenant - Update the tenant.
As of Version

2023 Autumn

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Updates the tenant data in the Keycloak identity provider for the tenant of the calling user.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

403

Forbidden

500

Internal Server Error

Request Example

PATCH /tenant-management/api/admin/tenant HTTP/1.1

Request Body
[
  {"op":"replace",
    "path": "/displayNameHTML",
    "value" : "This is a HTML formatted display name"
  },
  {"op":"replace",
    "path": "/description",
    "value" : "My Tenant"
  },
  {
  "op": "replace",
    "path": "/emailSettings/port",
    "value": 200
  },
  {"op":"replace",
    "path": "/enabled",
    "value" : false
  }
]
Response Example

200 OK

Response Body
{
  "name": "My Name",
  "description": "My Tenant",
  "displayNameHTML": "This is a HTML formatted display name",
  "adminPassword": "changeme",
  "adminEmail": "mrexample@examplemail.net",
  "adminFirstName": "Johann",
  "adminLastName": "Fluss",
  "enabled": true,
  "emailSettings": {
    "host": "string",
    "from": "string",
    "username": "string",
    "password": "string",
    "fromDisplayName": "string",
    "port": 0,
    "enableAuthentication": true,
    "enableSSL": true,
    "enableStartTLS": true
  },
  "clientSettings": {
    "redirectUris": [
      "string"
    ],
    "postLogoutRedirectUri": "string"
  },
  "systems": {
    "ips": true,
    "yuuvis": true
  }
}
GET /tenant-management/api/admin/users - Retrieve a list of users.
As of Version

2020 Winter

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN and YUUVIS_MANAGE_SETTINGS (as of 2022 Autumn) roles.

Description

Retrieves a list of all users within the tenant.

As 2021 Autumn, the list can be filtered by applying query parameters.

Optional query parameters:

Parameter Type Description

search

string

Retrieve only users for which the specified string is contained in user name, first name, last name or e-mail.

first

integer($int32)

Skip the first users in the result list. Return only users with index equal or larger than the specified value.

max

integer($int32)

Return only the specified number of users.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

GET /tenant-management/api/admin/users HTTP/1.1

no request body

Response Example

200 OK

Response Body
[
  {
    "id": "406b5a28-7a8b-4c36-a569-df7bff480375",
    "firstName": "Heinrich",
    "lastName": "Schuetzel",
    "roles": [
      "YUUVIS_SYSTEM_INTEGRATOR",
      "YUUVIS_DEFAULT",
      "YUUVIS_TENANT_ADMIN",
      "HR_MANAGER",
      "YUUVIS_CREATE_OBJECT",
      "YUUVIS_MANAGE_SETTINGS"
    ],
    "username": "newuser5",
    "enabled": true,
    "createdTimestamp": 1622122631393
  },
  {
    "id": "320c67d0-b88b-4e99-852a-b938f4b38cd7",
    "email": "kammer@segelreisen.de",
    "firstName": "Hannes",
    "lastName": "Kammer",
    "roles": [
      "YUUVIS_SYSTEM_INTEGRATOR",
      "YUUVIS_DEFAULT",
      "YUUVIS_TENANT_ADMIN",
      "YUUVIS_CREATE_OBJECT",
      "YUUVIS_MANAGE_SETTINGS",
      "YUUVIS_AI_PIPELINE",
      "COMPLIANCE_MANAGER",
      "YUUVIS_AI_PREDICT"
    ],
    "groups": [
      "onlyoffice"
    ],
    "username": "kammer",
    "enabled": true,
    "createdTimestamp": 1591957723730
  },
  {
    "id": "a6f5e1aa-ff42-4140-b9ec-5de4cc61f1a9",
    "email": "schwimmer@segelreisen.de",
    "firstName": "Klaus",
    "lastName": "Schwimmer",
    "roles": [
      "YUUVIS_SYSTEM_INTEGRATOR",
      "YUUVIS_DEFAULT",
      "INVOICE_MANAGER",
      "YUUVIS_TENANT_ADMIN",
      "HR_MANAGER",
      "YUUVIS_AIINVOICE",
      "EMAIL_WITHOUT_ACL",
      "QA_MEMBER_AREA2",
      "uma_authorization",
      "YUUVIS_CREATE_OBJECT",
      "TEAMS_MANAGER",
      "PHOTOARCHIVE_MANAGER",
      "YUUVIS_MANAGE_SETTINGS",
      "QA_MANAGER",
      "ACL_ALL_USERS",
      "YUUVIS_AI_PIPELINE",
      "QA_MEMBER_AREA1",
      "COMPLIANCE_MANAGER",
      "YUUVIS_AI_PREDICT",
      "offline_access"
    ],
    "username": "klaus",
    "enabled": true,
    "createdTimestamp": 1606820894094
  }
]
POST /tenant-management/api/admin/users - Create a user.
As of Version

2020 Winter

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN and YUUVIS_MANAGE_SETTINGS (as of 2022 Autumn) roles.

Description

Creates a new user in the tenant with the given properties.

The properties for the new user are passed in JSON format. In the response, the user including its ID is returned again in JSON format.

The only required parameter is username, but specifying the email parameter is recommended. The specified e-mail address is used to invite users after they have been created and in case they have forgotten their password. If no SMTP parameters are set for a new user, no invitation e-mail can be sent. The currently logged-in user will be informed.

It is not allowed to assign the YUUVIS_SYSTEM_INTEGRATOR default role to new users.

As of 2022 Autumn, in the default configuration, users with the YUUVIS_MANAGE_SETTINGS role are allowed to use the endpoint as well. However, they are not allowed to assign the roles YUUVIS_TENANT_ADMIN or YUUVIS_SYSTEM_INTEGRATOR.

It is recommended to deactivate users instead of deleting them. Their usernames might be required for compliance reasons.

New users are created with the Keycloak settings shown in the screenshot below. The first actions newly created users have to carry out are specified under Required User Actions. In this configuration, these are Update Password and Update Profile. Hence, new users have to register by setting a password and other user data. The URL to the registration page is specified in the e-mail invitation.

Keycloak settings screenshot

yuuvis® Momentum client as reference implementation displays the user’s name in the following format: lastName, firstName (username).

Optional query parameters:

Parameter Type Description

withInvitation

boolean

Weather an invitation should be sent on creation. (default: false)

temporaryPassword

boolean

Weather the password should be changed after the first login. (default: true)

Response HTTP status codes:

HTTP status code Meaning

201

CREATED

401

Unauthorized

409

Conflict

At least one of the following situations occurred:

  • The username is not unique.

  • The email address is not unique.

  • The email address or password must be set.

  • The role {ROLE_NAME} was not found.

  • The group {GROUP_NAME} was not found.

Request Example

GET /tenant-management/api/admin/users HTTP/1.1

Request Body
{
  "id": "string",
  "email": "string",
  "firstName": "string",
  "lastName": "string",
  "roles": [
    "string"
  ],
  "groups": [
    "string"
  ],
  "username": "string",
  "password": "string",
  "enabled": true,
  "createdTimestamp": 0
}
Response Example

201 CREATED

Response Body
{
  "id": "a00a0bb1-1234-5c66-7890-00fbb1c1a222"
}
GET /tenant-management/api/admin/users/{id} - Retrieve representation of a user.
As of Version

2020 Winter

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN and YUUVIS_MANAGE_SETTINGS (as of 2022 Autumn) roles.

Description

Retrieves the data of the user specified by id.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

GET /tenant-management/api/admin/users/a69a0eb6-3662-4c00-8096-38fbb2c4a922 HTTP/1.1

no request body

Response Example

200 OK

Response Body
{
  "id": "string",
  "email": "string",
  "firstName": "string",
  "lastName": "string",
  "roles": [
    "string"
  ],
  "groups": [
    "string"
  ],
  "username": "string",
  "password": "string",
  "enabled": true,
  "createdTimestamp": 0
}
PUT /tenant-management/api/admin/users/{id} - Update a user.
As of Version

2020 Winter

Request Method

PUT

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN and YUUVIS_MANAGE_SETTINGS (as of 2022 Autumn) roles.

Description

Updates the data of the user specified by id with the data passed in the request body in JSON format.

As of version 2021 Autumn, this endpoint does not allow for the assignment of the YUUVIS_SYSTEM_INTEGRATOR role to a user. If this role is passed as an entry of the roles list, the endpoint will return an error.

As of version 2022 Summer, the deactivation of users leads to an invalidation of all their active sessions (if the enabled property is changed to false).

As of 2022 Autumn, in the default configuration, users with the YUUVIS_MANAGE_SETTINGS role are allowed to use the endpoint as well. However, they are not allowed to assign the roles YUUVIS_TENANT_ADMIN or YUUVIS_SYSTEM_INTEGRATOR or to update the data of users with at least one of those roles.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

409

Conflict

At least one of the following situations occurred:

  • The username is not unique.

  • The email address is not unique.

  • The email address or password must be set.

  • The role {ROLE_NAME} was not found.

  • The group {GROUP_NAME} was not found.

Request Example

PUT /tenant-management/api/admin/users/a99a0bb1-2345-6c77-8901-22dee3f4a567 HTTP/1.1

Request Body
{
  "id": "string",
  "email": "string",
  "firstName": "string",
  "lastName": "string",
  "roles": [
    "string"
  ],
  "groups": [
    "string"
  ],
  "username": "string",
  "password": "string",
  "enabled": true,
  "createdTimestamp": 0
}
Response Example

200 OK

DELETE /tenant-management/api/admin/users/{id} - Delete a user.
As of Version

2020 Winter

Request Method

DELETE

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN and YUUVIS_MANAGE_SETTINGS (as of 2022 Autumn) roles.

Description

Deletes the user specified by id.

As of 2022 Summer, all active sessions of the deleted user are invalidated.

As of version 2022 Autumn, in the default access authorization configuration, users with the YUUVIS_MANAGE_SETTINGS roles are allowed to use the endpoint as well. However, they are not allowed to delete users with the YUUVIS_TENANT_ADMIN or YUUVIS_SYSTEM_INTEGRATOR role assigned.

Response HTTP status codes:

HTTP status code Meaning

204

No content

401

Unauthorized

404

Not found

409

Conflict

422

Unprocessable Entity

Request Example

/tenant-management/api/admin/users/a99a0bb1-2345-6c77-8901-22dee3f4a567

no request body

Response Example

204 No content

Response Body
{
  "reason": "string",
  "deleted": true
}
GET /tenant-management/api/admin/users/count - Retrieve amount of users.
As of Version

2020 Winter

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN and YUUVIS_MANAGE_SETTINGS (as of 2022 Autumn) roles.

Description

Retrieves the number of all users of the tenant.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

GET /tenant-management/api/admin/users HTTP/1.1

no request body

Response Example

200 OK

42

idm-controller

The endpoints of the Identity Management Controller (idm-controller) provide an interface for retrieving user and role information from the connected identity provider.

In the default configuration, the endpoints are available for any user logged-in to yuuvis® Momentum.

GET /tenant-management/api/idm/me - Retrieve representation of the current user.
As of Version

2021 Winter

Request Method

GET

Response Format

JSON

Required Permission

The endpoint is available for every logged-in user.

Description

Retrieves the representation of the currently logged-in user.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/tenant-management/api/idm/me

no request body

Response Example

200 OK

Response Body
{
  "id": "string",
  "email": "string",
  "firstName": "string",
  "lastName": "string",
  "roles": [
    "string"
  ],
  "groups": [
    "string"
  ],
  "username": "string",
  "password": "string",
  "enabled": true,
  "createdTimestamp": 0
}
GET /tenant-management/api/idm/roles - Retrieve all roles.
As of Version

2022 Spring

Request Method

GET

Response Format

JSON

Required Permission

The endpoint is available for every logged-in user.

Description

Gets all roles of the tenant of the requesting user.

Optional query parameters:

Parameter Type Description

search

string

A string contained in role name or description.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

500

Internal Server Error

Request Example

https://<host>/tenant-management/api/idm/roles?search=test

no request body

Response Example

200 OK

Response Body
[
  {
    "name": "TEST_ROLE",
    "description": "Example role"
  },
  {
    "name": "EXAMPLE_ROLE",
    "description": "Role containing word test in its description"
  }
]
GET /tenant-management/api/idm/roles/{role}/users - Retrieve users that have the given role.
As of Version

2021 Winter

Request Method

GET

Response Format

JSON

Required Permission

The endpoint is available for every logged-in user.

Description

Retrieves a list of users that have the specified role assigned to them.

Optional query parameters:

Parameter Type Description

briefRepresentation

boolean

  • If true (default), the following parameters will be returned for each user: id, email, firstName, lastName, username, enabled, createdTimestamp.

  • If false, the following parameters will be additionally included: roles, groups.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

Request Example

https://<host>/tenant-management/api/idm/roles/YUUVIS_TENANT_ADMIN/users?briefRepresentation=false

no request body

Response Example

200 OK

Response Body
[
  {
    "id": "406b5a28-7a8b-4c36-a569-df7bff480375",
    "firstName": "Heinrich",
    "lastName": "Schuetzel",
    "roles": [
      "YUUVIS_SYSTEM_INTEGRATOR",
      "YUUVIS_DEFAULT",
      "YUUVIS_TENANT_ADMIN",
      "HR_MANAGER",
      "YUUVIS_CREATE_OBJECT",
      "YUUVIS_MANAGE_SETTINGS"
    ],
    "username": "newuser5",
    "enabled": true,
    "createdTimestamp": 1622122631393
  },
  {
    "id": "320c67d0-b88b-4e99-852a-b938f4b38cd7",
    "email": "kammer@segelreisen.de",
    "firstName": "Hannes",
    "lastName": "Kammer",
    "roles": [
      "YUUVIS_SYSTEM_INTEGRATOR",
      "YUUVIS_DEFAULT",
      "YUUVIS_TENANT_ADMIN",
      "YUUVIS_CREATE_OBJECT",
      "YUUVIS_MANAGE_SETTINGS",
      "YUUVIS_AI_PIPELINE",
      "COMPLIANCE_MANAGER",
      "YUUVIS_AI_PREDICT"
    ],
    "groups": [
      "onlyoffice"
    ],
    "username": "kammer",
    "enabled": true,
    "createdTimestamp": 1591957723730
  },
  {
    "id": "a6f5e1aa-ff42-4140-b9ec-5de4cc61f1a9",
    "email": "schwimmer@segelreisen.de",
    "firstName": "Klaus",
    "lastName": "Schwimmer",
    "roles": [
      "YUUVIS_SYSTEM_INTEGRATOR",
      "YUUVIS_DEFAULT",
      "INVOICE_MANAGER",
      "YUUVIS_TENANT_ADMIN",
      "HR_MANAGER",
      "YUUVIS_AIINVOICE",
      "EMAIL_WITHOUT_ACL",
      "QA_MEMBER_AREA2",
      "uma_authorization",
      "YUUVIS_CREATE_OBJECT",
      "TEAMS_MANAGER",
      "PHOTOARCHIVE_MANAGER",
      "YUUVIS_MANAGE_SETTINGS",
      "QA_MANAGER",
      "ACL_ALL_USERS",
      "YUUVIS_AI_PIPELINE",
      "QA_MEMBER_AREA1",
      "COMPLIANCE_MANAGER",
      "YUUVIS_AI_PREDICT",
      "offline_access"
    ],
    "username": "klaus",
    "enabled": true,
    "createdTimestamp": 1606820894094
  }
]
GET /tenant-management/api/idm/users - Retrieve a list of users, filtered according to query parameters.
As of Version

2021 Winter

Request Method

GET

Response Format

JSON

Required Permission

The endpoint is available for every logged-in user.

Description

Retrieves a list of all users within the same tenant as the currently logged-in user.

Each user in the result list will be represented with all user account parameters available via Tenant Management API.

Required query parameter:

Parameter Type Description

pageable

JSON

Example
{
  "page": 0,
  "size": 1,
  "sort": [
    "string"
  ]
}

Optional query parameters:

Parameter Type Description

search

string

Retrieve only users for which the specified string is contained in user name, first name, last name or e-mail.

briefRepresentation

boolean

  • If true (default), the following parameters will be returned for each user: id, email, firstName, lastName, username, enabled, createdTimestamp.

  • If false, the following parameters will be additionally included: roles, groups.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example
Response Example

200 OK

Response Body
{
  "objects": [
    {
      "id": "string",
      "email": "string",
      "firstName": "string",
      "lastName": "string",
      "roles": [
        "string"
      ],
      "groups": [
        "string"
      ],
      "username": "string",
      "password": "string",
      "enabled": true,
      "createdTimestamp": 0
    }
  ],
  "numItems": 50,
  "totalNumItems": 1234,
  "hasMoreItems": true
}
GET /tenant-management/api/idm/users/{id} - Retrieve representation of the specified user.
As of Version

2021 Winter

Request Method

GET

Response Format

JSON

Required Permission

The endpoint is available for every logged-in user.

Description

Retrieves the representation of the user specified by id. Only users within the tenant of the logged-in user are available.

The response body contains all user account properties available via Tenant Management API.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Request Example

https://<host>/tenant-management/api/idm/users/string

no request body

Response Example

200 OK

Response Body
{
  "id": "string",
  "email": "string",
  "firstName": "string",
  "lastName": "string",
  "roles": [
    "string"
  ],
  "groups": [
    "string"
  ],
  "username": "string",
  "password": "string",
  "enabled": true,
  "createdTimestamp": 0
}
system-controller

These endpoints can be used for role, group and user management for any tenant within the system and to create and delete tenants in Keycloak.

The access to the endpoints has to be limited to administrative users as specified with the permission for /tenant-management/api/system/** endpoints in the authentication-prod.yml configuration file.

If you use yuuvis® architect, do not change the default access condition that is matched with the YUUVIS_SYSTEM_INTEGRATOR role.

GET /tenant-management/api/system/profile - Retrieve the tenant creation profile.
As of Version

2020 Winter

Request Method

GET

Response Format

JSON

Description

Updates the tenant creation profile that is used while creating a tenant of a customer with all the information that should be set up, e.g., additional roles, users, schema and client settings. Each SaaS application has its own tenant creation profile.

Optional query parameters:

Parameter Type Description

name

String

The name of the tenant creation profile. Should be specified only if multiple profiles are used.

Response HTTP status codes:

HTTP status code Meaning

200

OK

401

Unauthorized

404

Not found

Response Example
{
  "user": {
    "withInvitation": true,
    "users": [
      {
        "id": "string",
        "email": "string",
        "firstName": "string",
        "lastName": "string",
        "roles": [
          "string"
        ],
        "groups": [
          "string"
        ],
        "username": "string",
        "password": "string",
        "enabled": true,
        "createdTimestamp": 0,
        "temporaryPassword": true
      }
    ]
  },
  "roles": [
    {
      "name": "string",
      "description": "string"
    }
  ],
  "groups": [
    {
      "id": "string",
      "name": "string",
      "realmRoles": [
        "string"
      ],
      "members": [
        "string"
      ]
    }
  ],
  "email": {
    "host": "string",
    "from": "string",
    "username": "string",
    "password": "string",
    "fromDisplayName": "string",
    "port": 0,
    "enableAuthentication": true,
    "enableSSL": true,
    "enableStartTLS": true
  },
  "general": {
    "displayNameHTML": "string",
    "customMicroservice": "string",
    "customMicroserviceOnDelete": "string",
    "defaultLocale": "string",
    "supportedLocales": [
      "string"
    ]
  },
  "client": {
    "redirectUris": [
      "string"
    ],
    "postLogoutRedirectUri": "string"
  }
}
POST /tenant-management/api/system/profile - Update the tenant creation profile.
As of Version

2020 Winter

Request Method

POST

Response Format

HTTP status code

Description

Updates the tenant creation profile that is used while creating a tenant of a customer with all the information that should be set up, e.g., additional roles, users, schema and client settings. Each SaaS application has its own tenant creation profile. All available parameters are described here.

Optional query parameters:

Parameter Type Description

name

String

The name of the tenant creation profile. Should be specified only if multiple profiles are used.

Response HTTP status codes:

HTTP status code Meaning

200 OK

Successful, the tenant with the specified name has been created.

401 UNAUTHORIZED

The call was unauthorized.

Request Example

POST /tenant-management/api/system/profile HTTP/1.1

Request Body
{
  "user": {
    "withInvitation": true,
    "users": [
      {
        "id": "string",
        "email": "string",
        "firstName": "string",
        "lastName": "string",
        "roles": [
          "string"
        ],
        "groups": [
          "string"
        ],
        "username": "string",
        "password": "string",
        "enabled": true,
        "createdTimestamp": 0,
        "temporaryPassword": true
      }
    ]
  },
  "roles": [
    {
      "name": "string",
      "description": "string"
    }
  ],
  "groups": [
    {
      "id": "string",
      "name": "string",
      "realmRoles": [
        "string"
      ],
      "members": [
        "string"
      ]
    }
  ],
  "email": {
    "host": "string",
    "from": "string",
    "username": "string",
    "password": "string",
    "fromDisplayName": "string",
    "port": 0,
    "enableAuthentication": true,
    "enableSSL": true,
    "enableStartTLS": true
  },
  "general": {
    "displayNameHTML": "string",
    "customMicroservice": "string",
    "customMicroserviceOnDelete": "string",
    "defaultLocale": "string",
    "supportedLocales": [
      "string"
    ]
  },
  "client": {
    "redirectUris": [
      "string"
    ],
    "postLogoutRedirectUri": "string"
  }
}
GET /tenant-management/api/system/tenants - Retrieve the top-level representation of all realms.
As of Version

2020 Winter

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Retrieves the top-level representation of all realms. It will not include nested information like User and Client representations. Reads the list of all tenants.

Optional query parameters:

Parameter Type Description

withSystems

boolean

If true, the systems property section is included for each tenant in the response JSON. If false (default), the systems properties section is not displayed.

For each tenant, the following properties are included in the JSON response body:

Property Type Description

name

string

Tenant name.

description

string

Only displayed if available.

enabled

boolean

If true, the tenant is activated. Users can log in.

systems

Section of parameters displayed only if withSystems=true.

ips

boolean

If true, the tenant is configured in the identity provider.

yuuvis

boolean

If true, the tenant is configured in yuuvis® Momentum.

Response HTTP status codes:

HTTP status code Meaning

200 OK

Successful, the data of all tenants have been read.

401 UNAUTHORIZED

The call was unauthorized.

Request Example

GET /tenant-management/api/system/tenants?withSystems=true

Response Example
Response Body
[
  {
    "name": "string777",
    "enabled": false,
    "systems": {
      "ips": true,
      "yuuvis": false
    }
  },
  {
    "name": "technicaltenant",
    "description": "tenant userd by specific services",
    "enabled": false,
    "systems": {
      "ips": true,
      "yuuvis": false
    }
  },
  {
    "name": "e2e",
    "description": "End-To-End Test System",
    "enabled": true,
    "systems": {
      "ips": true,
      "yuuvis": true
    }
  }
]
POST /tenant-management/api/system/tenants - Create a tenant.
As of Version

2020 Winter

Request Method

POST

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Creates a new tenant with the values for the corresponding parameters specified in JSON format. Required settings for Keycloak and yuuvis® Momentum core are passed as well as custom (= product application) settings.

A Keycloak realm with a name and description is created together with the initial default technical user admin that you can use as a proxy user in your portal for tenant management. The values for name and description can be displayed in the Keycloak Admin Console as Realm Name and Display name as shown in the first screenshot below.

The parameters available for defining Keycloak settings are described in the here. These parameters determine the settings for each further tenant that will be created.

name and description are mandatory.

The adminPassword can be set for the default user admin. The admin user has to be used to create any additional users for the tenant using the user management in yuuvis® architect.

If adminEmail is specified and the smtp e-mail service parameters are set up, an e-mail invitation is sent to this address. Users have to change the password and edit their profile data.

If no e-mail address is specified, you can use a (secure) communication channel of your choice to inform your admin user about how to log in to yuuvis® architect and manage users.

In an additional system parameter section, you can specify following parameters:

  • ips - Boolean value. If true, the tenant is created in the identity provider (only supported for Keycloak).

  • yuuvis - Boolean value. If true, the tenant is added to the application-oauth2.yml configuration file of the core system.

In the yuuvis® Momentum system, a tenant with the same name will be created as well. No further configurations are set up. For additional configurations like tenant schema or extensions of the role set, a custom microservice can be configured in the profile. It will be called after each tenant creation process and add the defined extending configurations.

After creating a new yuuvis® tenant, the newly created admin user can be used to access the system using the core API, yuuvis® architect, or yuuvis® Momentum client as reference implementation.

Optional query parameters:

Parameter Type Description

profile

String

The name of the tenant creation profile that should be used for the new tenant. Should be specified only if multiple profiles are available. It is obsolete if less than two tenant creation profiles are available.

Response HTTP status codes:

HTTP status code Meaning

201 CREATED

Successful, the tenant with the name has been created.

400 BAD REQUEST

No valid instance for new realm <tenantname> found.

401 UNAUTHORIZED

The call was unauthorized.

Request Example
Request Example
{
  "name": "My Name",
  "description": "My Tenant",
  "displayNameHTML": "This is a HTML formatted display name",
  "adminPassword": "changeme",
  "adminEmail": "mrexample@examplemail.net",
  "adminFirstName": "Johann",
  "adminLastName": "Fluss",
  "enabled": true,
  "emailSettings": {
    "host": "string",
    "from": "string",
    "username": "string",
    "password": "string",
    "fromDisplayName": "string",
    "port": 0,
    "enableAuthentication": true,
    "enableSSL": true,
    "enableStartTLS": true
  },
  "clientSettings": {
    "redirectUris": [
      "string"
    ],
    "postLogoutRedirectUri": "string"
  },
  "systems": {
    "ips": true,
    "yuuvis": true
  }
}
Response Example

201 CREATED

no response body

GET /tenant-management/api/tenants/{tenant} - Retrieves the top-level representation of the Keycloak realm specified by tenant.
As of Version

2020 Winter

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Retrieves the top-level representation of the Keycloak realm specified by tenant. It will not include nested information like User and Client representations. Reads the tenant data of the specified tenant.

Optional query parameters:

Parameter Type Description

withSystems

boolean

If true, the systems property section is included for each tenant in the response JSON. If false (default), the systems properties section is not displayed.

Response HTTP status codes:

HTTP status code Meaning

200 OK

Successful, the data of the specified tenant has been read.

401 UNAUTHORIZED

The call was unauthorized.

404 NOT FOUND

The specified tenant was not found.

Request Example

GET /tenant-management/api/system/tenants/myMandant1 HTTP/1.1

no request body

Response Example

200 OK

Response Body
{
  "value": {},
  "filters": {}
}
DELETE /tenant-management/api/system/tenants/{tenant} - Delete the specified tenant.
As of Version

2020 Winter

Request Method

DELETE

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

The tenant is only deleted if no DMS objects are stored. If the tenant does not contain any DMS object, all client-side configurations are deleted. The configuration files saved via the configservice like tenant schema, forms, localization files, and catalogs are deleted as well. In case the configservice is not available, those configuration files remain and have to be deleted manually later on.

All users of the deleted tenant are deleted as well. If they have active sessions, they are invalidated (as of 2022 Summer).

This endpoint is still under development. Its behavior might change with the next release.

Response HTTP status codes:

HTTP status code Meaning

204 NO CONTENT

Successful, the specified tenant has been deleted.

401 UNAUTHORIZED

The call was unauthorized.

404 NOT FOUND

The specified tenant was not found.

Request Example

/tenant-management/api/system/tenants/myTenant

Response Example

204 NO CONTENT

Response Body
{
  "reason": "string",
  "deleted": true
}
PATCH /tenant-management/api/system/tenants/{tenant} - Update a specified tenant.
As of Version

2021 Summer

Request Method

POST

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Update a new tenant with the values for the corresponding parameters specified in JSON format.

The PATCH request body is expected to be in JSONPath format.

The following properties can be updated:

  • Keycloak realm Display Name (request property is displayNameHTML)

  • HTML Display Name (request property is description)

  • As of version 2021 Autumn: Activation/Deactivation of the tenant (request property enabled)

  • As of version 2021 Autumn: Any property of the e-mail settings (request property emailSettings/<property>)

Response HTTP status codes:

HTTP status code Meaning

200 OK

Successful, the tenant with the name has been updated.

401 UNAUTHORIZED

The call was unauthorized.

Request Example

PATCH /tenant-management/api/system/tenants/myTenant HTTP/1.1

Request Body
[
  {"op":"replace",
    "path": "/displayNameHTML",
    "value" : "This is a HTML formatted display name"
  },
  {"op":"replace",
    "path": "/description",
    "value" : "My Tenant"
  },
  {
  "op": "replace",
    "path": "/emailSettings/port",
    "value": 200
  },
  {"op":"replace",
    "path": "/enabled",
    "value" : false
  }
]
Response Example

200 OK

Response Body
{
  "name": "My Name",
  "description": "My Tenant",
  "displayNameHTML": "This is a HTML formatted display name",
  "adminPassword": "changeme",
  "adminEmail": "mrexample@examplemail.net",
  "adminFirstName": "Johann",
  "adminLastName": "Fluss",
  "enabled": true,
  "emailSettings": {
    "host": "string",
    "from": "string",
    "username": "string",
    "password": "string",
    "fromDisplayName": "string",
    "port": 0,
    "enableAuthentication": true,
    "enableSSL": true,
    "enableStartTLS": true
  },
  "clientSettings": {
    "redirectUris": [
      "string"
    ],
    "postLogoutRedirectUri": "string"
  },
  "systems": {
    "ips": true,
    "yuuvis": true
  }
}
GET /tenant-management/api/system/tenants/{tenant}/groups - Retrieve all groups of a specified tenant.
As of Version

2021 Autumn

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Retrieves all groups of the specified tenant with the assigned roles and members.

Response HTTP status codes:

HTTP status code Meaning

200 OK

Successful, all roles of the specified tenant have been read.

401 UNAUTHORIZED

The call was unauthorized.

Request Example

GET /tenant-management/api/system/tenants/myTenant/groups HTTP/1.1

no request body

Response Example
Response Body
[
  {
    "id": "fa854da5-004a-5187-9cc6-3b5c5bc2c728",
    "name": "HR-Manager",
    "realmRoles": [
      "EMAIL_WITHOUT_ACL"
    ],
    "members": [
      "gustav"
    ]
  },
  {
    "id": "dab12224-4e4a-5e23-06e8-ffd3ed17cff7",
    "name": "QA-Manager",
    "realmRoles": [
      "QA_MANAGER"
    ],
   "members": [
     "susanne",
     "gustav"
   ]
  }
]
POST /tenant-management/api/system/tenants/{tenant}/groups - Create a group.
As of Version

2021 Autumn

Request Method

POST

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Creates a new group with the given properties for the specified tenant.

The properties for the new group are passed in JSON format. In the response body, the group ID is returned again in JSON format.

The only required parameter is name for the group name. If roles should be assigned, the specified realmRoles must exist.

Response HTTP status codes:

HTTP status code Meaning

201 CREATED

Successful, the user has been created with the specified properties.

401 UNAUTHORIZED

The call was unauthorized.

Request Example

POST /tenant-management/api/system/tenants/{mytenant}/groups HTTP/1.1

Request Body
{
    "id": "fa854da5-004a-5187-9cc6-3b5c5bc2c728",
    "name": "HR-Manager",
    "realmRoles": [
      "EMAIL_WITHOUT_ACL"
    ],
    "members": [
      "gustav"
    ]
}
Response Example

201 CREATED

Response Body
{
  "id": "a00a0bb1-1234-5c66-7890-00fbb1c1a222"
}
PUT /tenant-management/api/system/tenants/{tenant}/groups/{id} - Update a specified group.
As of Version

2021 Autumn

Request Method

PUT

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Updates the data of the group specified by id that is given for the specified tenant.

Response HTTP status codes:

HTTP status code Meaning

200 OK

Successful, the data for the specified group have been updated.

401 UNAUTHORIZED

The call was unauthorized.

Request Example

PUT /tenant-management/api/system/tenants/{tenant}/groups/a99a0bb1-2345-6c77-8901-22dee3f4a567 HTTP/1.1

Request Body
{
    "id": "fa854da5-004a-5187-9cc6-3b5c5bc2c728",
    "name": "HR-Manager",
    "realmRoles": [
      "EMAIL_WITHOUT_ACL"
    ],
    "members": [
      "gustav"
    ]
}
Response Example

200 OK

DELETE /tenant-management/api/system/tenants/{tenant}/groups/{id} - Delete a specified group.
As of Version

2021 Autumn

Request Method

DELETE

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Deletes the group specified by id in the specified tenant.

Response HTTP status codes:

HTTP status code Meaning

204 NO CONTENT

Successful, the specified group has been deleted.

401 UNAUTHORIZED

The call was unauthorized.

404 NOT FOUND

The specified group was not found.

Request Example

/tenant-management/api/system/tenants/mytenant/group/a99a0bb1-2345-6c77-8901-22dee3f4a567

Response Example

204 NO CONTENT

no response body

GET /tenant-management/api/system/tenants/{tenant}/roles - Retrieve all roles of a specified tenant.
As of Version

2020 Winter

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Gets all roles of the specified tenant.

Optional query parameters:

Parameter Type Description

search

string

The result list contains only roles that contain the specified string in their name or decription value.

Response HTTP status codes:

HTTP status code Meaning

200 OK

Successful, all roles of the specified tenant have been read.

401 UNAUTHORIZED

The call was unauthorized.

Request Example

GET /tenant-management/api/system/tenants/myTenant/roles HTTP/1.1

Response Example
Response Body
[
  {
    "name": "TEST_ROLE",
    "description": "Example role"
  },
  {
    "name": "EXAMPLE_ROLE",
    "description": "Role containing word test in its description"
  }
]
POST /tenant-management/api/system/tenants/{tenant}/roles - Create a role.
As of Version

2021 Autumn

Request Method

POST

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Creates a new role for the specified tenant with the properties specified in JSON format in the request body.

The properties for the new role are passed in JSON format.

The only required parameters are name for the role and its description.

Response HTTP status codes:

HTTP status code Meaning

201 CREATED

Successful, the role has been created with the specified properties.

401 UNAUTHORIZED

The call was unauthorized.

Request Example

POST /tenant-management/api/system/tenants/mytenant/roles HTTP/1.1

Request Body
{
  "name": "TEST_ROLE",
  "description": "Example role"
}
Response Example

201 CREATED

Response Body
{
  "errors": [],
  "valid": true
}
DELETE /tenant-management/api/system/tenants/{tenant}/roles/{role-name} - Delete a specified role.
As of Version

2021 Autumn

Request Method

DELETE

Response Format

HTTP status code

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Deletes the role specified by name for the specified tenant.

Response HTTP status codes:

HTTP status code Meaning

204 NO CONTENT

Successful, the specified role has been deleted

401 UNAUTHORIZED

The call was unauthorized.

404 NOT FOUND

The specified role was not found.

Request Example

/tenant-management/api/system/tenants/mytenant/role/myrole

Response Example

204 NO CONTENT

no response body

GET /tenant-management/api/system/tenants/{tenant}/users - Retrieve all users of a specified tenant.
As of Version

2020 Winter

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Retrieves a list of all users of the specified tenant. As 2021 Autumn, the list can be filtered by applying query parameters.

Optional query parameters:

Parameter Type Description

search

string

Retrieve only users for which the specified string is contained in user name, first name, last name or e-mail.

first

integer($int32)

Skip the first users in the result list. Return only users with index equal or larger than the specified value.

max

integer($int32)

Return only the specified number of users.

Response HTTP status codes:

HTTP status code Meaning

200 OK

Successful, the data of all users of the specified tenant have been read.

401 UNAUTHORIZED

The call was unauthorized.

Request Example

GET /tenant-management/api/system/tenants/myTenant/users HTTP/1.1

or

GET /tenant-management/api/system/tenants/myTenant/users?first=1&max=5&search=test

Response Example

200 OK

Response Body
[
  {
    "id": "406b5a28-7a8b-4c36-a569-df7bff480375",
    "firstName": "Heinrich",
    "lastName": "Schuetzel",
    "roles": [
      "YUUVIS_SYSTEM_INTEGRATOR",
      "YUUVIS_DEFAULT",
      "YUUVIS_TENANT_ADMIN",
      "HR_MANAGER",
      "YUUVIS_CREATE_OBJECT",
      "YUUVIS_MANAGE_SETTINGS"
    ],
    "username": "newuser5",
    "enabled": true,
    "createdTimestamp": 1622122631393
  },
  {
    "id": "320c67d0-b88b-4e99-852a-b938f4b38cd7",
    "email": "kammer@segelreisen.de",
    "firstName": "Hannes",
    "lastName": "Kammer",
    "roles": [
      "YUUVIS_SYSTEM_INTEGRATOR",
      "YUUVIS_DEFAULT",
      "YUUVIS_TENANT_ADMIN",
      "YUUVIS_CREATE_OBJECT",
      "YUUVIS_MANAGE_SETTINGS",
      "YUUVIS_AI_PIPELINE",
      "COMPLIANCE_MANAGER",
      "YUUVIS_AI_PREDICT"
    ],
    "groups": [
      "onlyoffice"
    ],
    "username": "kammer",
    "enabled": true,
    "createdTimestamp": 1591957723730
  },
  {
    "id": "a6f5e1aa-ff42-4140-b9ec-5de4cc61f1a9",
    "email": "schwimmer@segelreisen.de",
    "firstName": "Klaus",
    "lastName": "Schwimmer",
    "roles": [
      "YUUVIS_SYSTEM_INTEGRATOR",
      "YUUVIS_DEFAULT",
      "INVOICE_MANAGER",
      "YUUVIS_TENANT_ADMIN",
      "HR_MANAGER",
      "YUUVIS_AIINVOICE",
      "EMAIL_WITHOUT_ACL",
      "QA_MEMBER_AREA2",
      "uma_authorization",
      "YUUVIS_CREATE_OBJECT",
      "TEAMS_MANAGER",
      "PHOTOARCHIVE_MANAGER",
      "YUUVIS_MANAGE_SETTINGS",
      "QA_MANAGER",
      "ACL_ALL_USERS",
      "YUUVIS_AI_PIPELINE",
      "QA_MEMBER_AREA1",
      "COMPLIANCE_MANAGER",
      "YUUVIS_AI_PREDICT",
      "offline_access"
    ],
    "username": "klaus",
    "enabled": true,
    "createdTimestamp": 1606820894094
  }
]
POST /tenant-management/api/system/tenants/{tenant}/users - Create a user.
As of Version

2020 Winter

Request Method

POST

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Creates a new user with the given properties for the specified tenant.

The properties for the new user are passed in JSON format. In the response, the user ID is returned again in JSON format.

The only required parameter is username, but specifying the email parameter is recommended. The specified e-mail address is used to invite users after they have been created and in case they have forgotten their password. If no SMTP parameters are set for a new user, no invitation e-mail can be sent. The currently logged-in user will be informed.

It is recommended to deactivate users instead of deleting them. Their user names might be required for compliance reasons.

New users are created with the Keycloak settings shown in the screenshot below. The first actions newly created users have to carry out are specified under Required User Actions. In this configuration, these are Update Password and Update Profile. Hence, new users have to register by setting a password and other user data. The URL to the registration page is specified in the e-mail invitation.

Keycloak settings screenshot

yuuvis® Momentum client as reference implementation displays the user’s name in the following format: lastName, firstName (username).

Optional query parameters:

Parameter Type Description

withInvitation

boolean

Weather an invitation should be sent on creation. (default: false)

temporaryPassword

boolean

Weather the password should be change after the first login. (default: true)

Response HTTP status codes:

HTTP status code Meaning

201 CREATED

Successful, the user with the specified properties has been created.

401 UNAUTHORIZED

The call was unauthorized.

409 CONFLICT

At least one of the following situations occurred:

  • The username is not unique.

  • The email address is not unique.

  • The email address or password must be set.

  • The role {ROLE_NAME} was not found.

  • The group {GROUP_NAME} was not found.

Request Example

POST /tenant-management/api/system/tenants/{tenant}/users?withInvitation=true HTTP/1.1

Request Body
{
  "email": "example@exampleprovider.de",
  "username": "mrexample",
  "firstName": "Examplename",
  "lastName": "Examplesurname",
  "roles": ["role1","role2"],
  "groups": ["group3","group1","group5"],
  "enabled": true,
  "password": "asecurepassword"
}
Response Example

201 CREATED

Response Body
{
  "id": "a00a0bb1-1234-5c66-7890-00fbb1c1a222"
}
GET /tenant-management/api/system/tenants/{tenant}/users/{id} - Retrieve a specified user.
As of Version

2020 Winter

Request Method

GET

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Retrieves the data of the user specified by tenant and id.

Response HTTP status codes:

HTTP status code Meaning

200 OK

Successful, the data of the specified user of the specified tenant has been read.

401 UNAUTHORIZED

The call was unauthorized.

Request Example

GET /tenant-management/api/admin/tenant/users/a99a0bb1-2345-6c77-8901-22dee3f4a567 HTTP/1.1

Response Example

200 OK

Response Body
{
  "id": "string",
  "email": "string",
  "firstName": "string",
  "lastName": "string",
  "roles": [
    "string"
  ],
  "groups": [
    "string"
  ],
  "username": "string",
  "password": "string",
  "enabled": true,
  "createdTimestamp": 0
}
PUT /tenant-management/api/system/tenants/{tenant}/users/{id} - Update a specified user.
As of Version

2020 Winter

Request Method

POST

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Update the data of the user specified by tenant and id.

The properties for the new user are passed in JSON format.

The specified e-mail address is used in case users have forgotten their password.

It is recommended to deactivate users instead of deleting them. Their user names might be required for compliance reasons.

yuuvis® Momentum client as reference implementation displays the user’s name in the following format: lastName, firstName (username).

As of version 2022 Summer, the deactivation of users leads to an invalidation of all their active sessions (if the enabled property is changed to false).

Response HTTP status codes:

HTTP status code Meaning

200 OK

Successful, the data of the user with the specified tenant and id have been updated.

401 UNAUTHORIZED

The call was unauthorized.

404 NOT FOUND

The user with the id was not found.

409 CONFLICT

At least one of the following situations occurred:

  • The username is not unique.

  • The email address is not unique.

  • The email address or password must be set.

  • The role {ROLE_NAME} was not found.

  • The group {GROUP_NAME} was not found.

Request Example

PUT /tenant-management/api/admin/tenants/myTenant/users/a69a0eb6-3662-4c00-8096-38fbb2c4a922 HTTP/1.1

Request Body
{
  "id": "string",
  "email": "string",
  "firstName": "string",
  "lastName": "string",
  "roles": [
    "string"
  ],
  "groups": [
    "string"
  ],
  "username": "string",
  "password": "string",
  "enabled": true,
  "createdTimestamp": 0
}
Response Example

200 OK

no response body

DELETE /tenant-management/api/system/tenants/{tenant}/users/{id} - Delete a specified user.
As of Version

2.4

Request Method

DELETE

Response Format

JSON

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Deletes the user specified by id of the specified tenant.

As of 2022 Summer, all active sessions of the deleted user are invalidated.

Response HTTP status codes:

HTTP status code Meaning

204 NO CONTENT

Successful, the specified user has been deleted.

401 UNAUTHORIZED

The call was unauthorized.

404 NOT FOUND

The specified user was not found.

Request Example

/tenant-management/api/system/tenants/myTenant/users/a99a0bb1-2345-6c77-8901-22dee3f4a567

Response Example

204 NO CONTENT

Response Body
{
  "reason": "string",
  "deleted": true
}
GET /tenant-management/api/system/tenants/{tenant}/users/count - Request the number of users within the specified tenant.
As of Version

2020 Winter

Request Method

GET

Response Format

TXT

Required Permission

Available if listed in authorization.accesses in authentication-prod.yml and the specified access condition is matched. In the default configuration, access is granted via the YUUVIS_SYSTEM_INTEGRATOR role.

Description

Retrieves the number of all users of the specified tenant.

Response HTTP status codes:

HTTP status code Meaning

200 OK

Successful, the number of users has been requested from Keycloak.

401 UNAUTHORIZED

The call was unauthorized.

Request Example

GET /tenant-management/api/system/tenants/myTenant/users/count HTTP/1.1

Response Example

200 OK

Response Body
23

5.1.2. Tenant Creation Profile

The tenant management API allows for the creation of new tenants in a customer’s yuuvis® Momentum system. All information for the initial configuration of the new tenant are stored in the tenant creation profile, e.g. additional roles, initial users, schema and client settings. Each yuuvis® Momentum cluster has its own tenant creation profile. The tenant creation profile is stored, retrieved and updated in JSON format.

As of 2024 Summer, it is possible to store multiple tenant creation profiles. They are identified by a name query parameter. During each tenant creation process, the administrator can select the desired pre-configured settings.

An admin user is created for each tenant that is used for the initial tenant administration. Per default, this user gets all global default roles except YUUVIS_SYSTEM_INTEGRATOR. The Credentials and E-mails will be specified during tenant creation. The users specified in the tenant creation profile are created in addition to this admin user.

The tenant creation profile does not belong the the configuration profiles of yuuvis® core. It is an independent file that follows its own concept and is managed only via the Tenant Management API.

Placeholders

It is possible to use placeholders within the tenant creation profile that will be replaced by values determined from the parameters of each tenant creation call. The syntax to incorporate them is ${varName}. The following placeholders are available:

Placeholder Name Description

DISPLAY_TENANT_NAME

The Keycloak Realm Display Name of the tenant as specified in the creation call.

TENANT_NAME

The Keycloak Realm Name of the tenant as specified in the creation call.

The profile can be read and set via the following endpoints:

  • GET /tenant-management/api/system/profile returns the currently active profile.

  • POST /tenant-management/api/system/profile applies a new profile to the cluster.

Parameters

The following table gives an overview of the parameters available within the profile and their usage. The parameters in the section general are displayed also in the Keycloak GUI, realm setting Themes.

Parameter Required Values Description

general.displayNameHTML

No (but recommended)

<div class=\"yuv-brand-logo\">${DISPLAY_TENANT_NAME}</div>

<div class=\"yuv-brand-logo ymc\">${DISPLAY_TENANT_NAME}</div>

Sets the left hand side of the login page’s icon and title. If not specified, the Keycloak realm HTML Display name will be set by default to <div class="yuv-brand-logo">${DISPLAY_TENANT_NAME}</div>.

general.customMicroservice

No

URL

The URL of a custom microservice endpoint that will be called in each process of a tenant creation via the Tenant Management API. Thus, custom tenant preparations are supported.

A POST request will be sent to the specified URL during each tenant creation process. The request contains a header and body:

  • Header: The JSON Web Token the creation endpoint was called with. Since this must be done by a user with access to the system-controller endpoints (default: users with YUUVIS_SYSTEM_INTEGRATOR role), you can use its rights to further prepare the tenant (e.g., create a user with tenant administration rights who can apply a tenant-specific schema)

  • Body: The tenant name as string.

The call is asynchronous, the tenant creation does not wait for a response from the microservice.

general.customMicroserviceOnDelete

No

URL

Define the URL of the custom microservice that should be asynchronously called after deleting a tenant to remove additional custom settings.

general.supportedLocales[]

No

List of ISO language terms e.g. ["en","de","es"]

Defines which languages a user can select in the login dialogue of Keycloak. The default locales are en for English and de for German. Find more available locales in the Keycloak documentation.

general.defaultLocale

No

ISO language term, e.g., "en"

Determines the language of the invitation e-mails that will be sent to each user created during the tenant creation.

client.redirectUris[] (as of 2022 Winter)

No

List of URIs, e.g. ["https://example.com/*"]

URIs used in Keycloak Client creation to set Valid redirect URIs.

Default URI (baseURL+"/*") will always be added to this list, only use this to set additional redirect URIs

postLogoutRedirectUri

themes

No

JSON mapping

Set theming parameters as described in the Keycloak documentation.

Example:

"themes": {
    "login": "eca",
    "account": "yuuvis",
    "admin": "yuuvis",
    "email": "eca"
}

email.host

If using e-mail

URL

The SMTP server to be configured in the Keycloak realm (e.g., for sending invitation e-mails).

email.port

No

Integer

The port of the SMTP server. Default is 25.

email.fromDisplayName

No

String

The display name of the e-mail sender for administrative emails.

email.from

If using e-mail

eMail address

The sender of the administrative e-mails.

email.enableSSL

No

Boolean

Determines if SSL is enabled (true) or disabled (false). Default is false.

email.enableStartTLS

No

Boolean

Determines if TLS is enabled (true) or disabled (false). Default is false.

email.enableAuthentication

No

Boolean

Determines if the SMTP server requires authentication.

email.username

If using e-mail with authentication

String

The user name for authentication against the SMTP server.

email.password

If using e-mail with with authentication

String

The password for authentication against the SMTP server.

roles[]

No

List of key value pairs with the following parameters.

Section that allows to add custom roles (in addition to the pre-defined role set) which will be available within each new tenant. The roles are specified by their name and a description.

role

No

String

The name of a role to be added to the tenant. The following roles are created per tenant by default:

  • YUUVIS_DEFAULT (full access to every object via default role set)

  • YUUVIS_MANAGE_SETTINGS (save result list column and filter configurations as standard)

  • YUUVIS_TENANT_ADMIN (update schema, rolse set, manage users, …​ for the tenant)

  • YUUVIS_SYSTEM_INTEGRATOR (update global schemata and role sets for the system, create tenants)

  • YUUVIS_MULTI_TENANT (easily switch between accounts in different tenants)

description

No

String

The description of a role to be added to the tenant.

groups[]

No

As of 2021 Autumn, not yet supported by yuuvis® architect.

Specify groups that will be created in the tenant with the listed roles assigned to them.

user.users[]

If additional users shall be created

List of key value pairs with the following parameters.

If a tenant is created via Tenant Management API, a first user admin is always included. Here you can define additional initial users that will be set up in each tenant created. For each of them, the following configuration parameters are available.

username

If additional user is to be created

String

The user name of the user to be created.

email

If additional user is to be created, with e-mail invitation

String

The e-mail address of the user to be created.

firstName

No

String

The first name of the user to be created.

lastName

No

String

The last name of the user to be created.

roles[]

No

List of Strings

The list of roles the user should be assigned to.

password

If additional user is to be created, without e-mail invitation

String

The user password of the user to be created. It will be stored encrypted.

Not necessary when inviting users via e-mail.

Note: The password policy must be met, see corresponding description of this tenant management API endpoint:

POST /tenant-management/api/system/tenants

enabled

Boolean

Enable (true) or disable (false) the user to be created. In most cases true is recommended.

temporaryPassword

Boolean

If you want to set up technical users that should not be forced to change their passwords while logging in for the first time, set false. The default is true.

user.withInvitation

Boolean

Determines if new users should be invited via e-mail. If true, you do not need to set a password during user creation.

The default value is false.

Profile Structure

The following code block shows an example profile.

Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
{
"general":{
"displayNameHTML": "<div class=\"yuv-brand-logo\">${DISPLAY_TENANT_NAME}</div>",
"customMicroservice": "https://myCustomMicroserviceURL",
"supportedLocales": ["en","de","es"],
"defaultLocale": "es"
},

    "client": {
        "redirectUris": [ "https://example.com/*" ]
    },

    "email": {
        "host": "myemailservice.com",
        "port": 25,
        "fromDisplayName": "mySenderShowName",
        "from": "my.sender@address.tld",
        "enableSSL": true,
        "enableStartTLS": true,
        "enableAuthentication": true,
        "username": "emailserviceuser",
        "password": "PaswordWith8Characters1Uppercase1SpecialNoUserName"
    },

    "roles": [
        {
        "role": "Role 1",
        "description": "Description of Role 1"
        }, ...
    ],

    "user": {
        "users": [
            {
                "username": "yauser",
                "email": "yauser@example.tld",
                "firstName": "yaFirstName",
                "lastName": "yaLastName",
                "roles": ["YUUVIS_DEFAULT"],
                "password": "PasswordWith8Characters1Uppercase1SpecialNoUserName",
                "temporaryPassword": false,
                "enabled": true
            },
            ...
        ],
        "withInvitation": true
    }
}

5.1.3. User Management via Endpoints

The Tenant Management API provided by the tenant-management service offers endpoints for user management via Keycloak. In order to scale the identity management, the keycloak-proxy service can be used for the connection of multiple Keycloak instances. The endpoints of the Tenant Management API are called by the architect services.

This article describes the handling and representation formats of data for individual user accounts as retrieved and expected by the Tenant Management Endpoints.

Further functionality is provided by our userservice.

User Management Endpoints

The following endpoints of the Tenant Management API are available for User Management purposes:

Endpoints Required User Role in Default Configuration Purpose

GET/POST/PUT/DELETE

/tenant-management/api/system/tenants/{tenant}/users*

YUUVIS_SYSTEM_INTEGRATOR

operations on any tenant in the system

GET/POST/PUT/DELETE

/tenant-management/api/admin/users*

YUUVIS_TENANT_ADMIN

operations on the own tenant

GET

/tenant-management/api/idm/users*

The endpoints are available for every logged-in user.

operations on the own tenant

All endpoints for user management via the Tenant Management API are available via the Swagger UI: https://<host>/tenant-management/swagger-ui.html.

The POST and PUT endpoints allow for the deactivation of users. In object histories, the user names of deactivated users are still displayed. In the client framework components, these usernames are still reserved by the Web API Gateway as the users still exist in the corresponding tenant. In order to reuse the user name of a deactivated user for a new user, you may append -disabled to the original user name. Thus, the deactivated user can still be identified in the object history and the user name can be reused at the same time.

5.1.4. User Account Properties

The following properties for user accounts can be managed via the Tenant Management API.

Property Type in Creation Request Bodies in Update Request Bodies in Response Bodies Description

id

string

Ignored.

Ignored.

Included.

The ID of the user for identification in the identity management system and in yuuvis® Momentum.

email

string

Required if invitation via e-mail is desired.

Optional, unchanged if not specified.

Included if available.

The e-mail address of the user.

firstName

string

Optional.

Optional, unchanged if not specified.

Included if available.

The first name of the user.

lastName

string

Optional.

Optional, unchanged if not specified.

Included if available.

The last name of the user.

roles

list of string role names

Optional.

Optional, unchanged if not specified.

Note that changes can also be applied by assigning/removing groups.

Included if available. Includes roles assigned via groups if available.

A list of roles defined in the identity management system that are assigned to the user.

groups

list of string group names

Optional.

Optional, removed from data set if not specified.

Included if available.

A list of groups defined in the identity management system in which the assigned user is a member.

username

string

Required.

Optional, unchanged if not specified.

Included.

The user name of the user.

enabled

boolean

Optional, default: true.

Optional, unchanged if not specified.

Included.

Specifies whether the user is allowed to log in (true) or not (false).

createdTimestamp

unix time stamp

Ignored.

Ignored.

Included.

Date and time of user creation in the identity provider.

5.1.5. User Account Data Sets

For each user account represented in a request or response body, its properties are specified in JSON format. The order of the individual properties within one data set is arbitrary.

The following code block shows an example for a result list including the data sets of several user accounts. Such result list can be retrieved, e.g., by the GET /tenant-management/api/idm/users endpoint.

[
  {
    "id": "406b5a28-7a8b-4c36-a569-df7bff480375",
    "firstName": "Heinrich",
    "lastName": "Schuetzel",
    "roles": [
      "YUUVIS_SYSTEM_INTEGRATOR",
      "YUUVIS_DEFAULT",
      "YUUVIS_TENANT_ADMIN",
      "HR_MANAGER",
      "YUUVIS_CREATE_OBJECT",
      "YUUVIS_MANAGE_SETTINGS"
    ],
    "username": "newuser5",
    "enabled": true,
    "createdTimestamp": 1622122631393
  },
  {
    "id": "320c67d0-b88b-4e99-852a-b938f4b38cd7",
    "email": "kammer@segelreisen.de",
    "firstName": "Hannes",
    "lastName": "Kammer",
    "roles": [
      "YUUVIS_SYSTEM_INTEGRATOR",
      "YUUVIS_DEFAULT",
      "YUUVIS_TENANT_ADMIN",
      "YUUVIS_CREATE_OBJECT",
      "YUUVIS_MANAGE_SETTINGS",
      "YUUVIS_AI_PIPELINE",
      "COMPLIANCE_MANAGER",
      "YUUVIS_AI_PREDICT"
    ],
    "groups": [
      "onlyoffice"
    ],
    "username": "kammer",
    "enabled": true,
    "createdTimestamp": 1591957723730
  },
  {
    "id": "a6f5e1aa-ff42-4140-b9ec-5de4cc61f1a9",
    "email": "schwimmer@segelreisen.de",
    "firstName": "Klaus",
    "lastName": "Schwimmer",
    "roles": [
      "YUUVIS_SYSTEM_INTEGRATOR",
      "YUUVIS_DEFAULT",
      "INVOICE_MANAGER",
      "YUUVIS_TENANT_ADMIN",
      "HR_MANAGER",
      "YUUVIS_AIINVOICE",
      "EMAIL_WITHOUT_ACL",
      "QA_MEMBER_AREA2",
      "uma_authorization",
      "YUUVIS_CREATE_OBJECT",
      "TEAMS_MANAGER",
      "PHOTOARCHIVE_MANAGER",
      "YUUVIS_MANAGE_SETTINGS",
      "QA_MANAGER",
      "ACL_ALL_USERS",
      "YUUVIS_AI_PIPELINE",
      "QA_MEMBER_AREA1",
      "COMPLIANCE_MANAGER",
      "YUUVIS_AI_PREDICT",
      "offline_access"
    ],
    "username": "klaus",
    "enabled": true,
    "createdTimestamp": 1606820894094
  }
]

5.1.6. Configuration

Working with Keycloak
  • First, create an initial Keycloak realm. Then create a user with the YUUVS_SYSTEM_INTEGRATOR role within this realm.

  • Users calling endpoints of the system controller need the YUUVIS_SYSTEM_INTEGRATOR role.

  • Users calling endpoints of the admin controller need the YUUVIS_TENANT_ADMIN role and must be a member of the Keycloak realm that is created when creating a yuuvis® Momentum tenant.

  • Before creating the first tenant, the profile has to be saved via POST /tenant-management/api/system/profile by a user with the YUUVS_SYSTEM_INTEGRATOR role.

Working with any Identity Provider via OAuth2

As of 2022 Spring, the service can be configured such that the idm-controller endpoints retrieve their information from a custom IDM proxy. This proxy can be used to connect other identity providers than Keycloak for reading purposes. An example proxy service is available as a beta version on request.
Note: If the service is not combined with Keycloak, all endpoints not belonging to the idm-controller are not available and return a 404 error.

In order to connect such a custom IDM proxy, create a tenant-management-prod.yml configuration file with the following parameters:

idm:
  custom:
    enabled: true
    base-url: http://IDM_HOST:port

The handling of profile-related configuration files is described for the core system.

5.2. yuuvis® architect

yuuvis® architect provides a support tool with a graphical user interface for client administrators. Based on the framework library, metadata forms of their client’s graphical user interface can be modeled. Furthermore, users can be added or removed from the respective tenant and language settings can be customized.

After installing the client services, yuuvis® architect can be accessed via the following URL: https://<domain>/architect.

yuuvis® architect works with the default roles.

5.2.1. Dashboard and Menus

The yuuvis® architect dashboard shows the most important application information at a glance.

Header Area

In the header area, you will find the yuuvis® Momentum bar with icons for the most frequently used features, such as the main menu icon and the yuuvis® icon on the left, and the settings menu icon with the current user’s initials on the right. Click the icons to go to the corresponding linked areas.

As of version 2021 Autumn: If you have the role YUUVIS_MULTI_TENANT, you will find Switch tenant in the drop down menu after clicking the settings menu icon. Click this option to log out from the current tenant and log in to a different tenant.

Whenever you left-click the yuuvis® icon, the dashboard will appear again.

If you left-click the yuuvis® icon while pressing Ctrl, a new tab will open with another yuuvis® architect dashboard in your browser.

Middle Area

In the middle of the dashboard, you will find tiles for the different views of yuuvis® architect. Click a tile to open one of them.

The Main Menu

Via the main menu you can access important areas and features such as the dashboard and the settings menu. You can access the main menu using the main menu icon on the yuuvis® Momentum bar.

You can access the following areas via the main menu:

  • Dashboard: Open the dashboard of yuuvis® Momentum client.

  • Localization: Open the localization customizing view.

  • Form modeling: Open the form modeling view.

  • User management: Open the user management view.

  • Settings: Open the settings menu, where you can configure the language settings and yuuvis® architect’s appearance.

  • About yuuvis® architect: This area provides you with information on the software manufacturer and versions. The licenses of the software components used are displayed in the Licensing notes area.

The Settings Menu

Use the settings menu to configure the settings of your yuuvis® architect. Open the settings menu by clicking the settings icon in the header area and select Settings from the dropdown menu. Alternatively, you can also open the settings menu via the main menu.

The following information and configuration settings are available in the settings menu:

  • Language: You can use the buttons to control the language display of the general user interface elements and the object types, menus, fields, and catalogs displayed in your yuuvis® architect session.

  • Roles: The drop-down menu indicates the user roles that were assigned to you. User roles and group access rights to object types and program functions are explained here.

  • Layout: In the Layout settings area, you can customize the design of the yuuvis® architect appearance to your personal preferences. Here, you can choose between a light and a dark theme, set an accent color, and upload a background image for yuuvis® architect. These settings are stored on your device, meaning you can work on different devices with different designs.

    You can also reuse the layout settings in your client by clicking the Export button. Similarly, you can transfer the layout settings from other clients to yours by clicking the Import button. Click the Reset button to delete all of your individual layout settings in your yuuvis® architect.

  • Configuration: In the Cache settings area, you can empty the application cache of your device by clicking the button. Tick or untick the checkboxes to determine whether the entire cache should be emptied or only certain data, such as the system cache or layout settings, should be deleted. The deletion is device-dependent. This means that only the settings of the device on which the deletion is performed are reset.

    • System: Reloads all system configurations, such as the schema. If the schema was modified, the updated version will be imported in yuuvis® architect.

    • Layout: Resets the area width in the different views and the column width, for example, for the technical names list in the localization view.

5.2.2. Rights and Roles

Rights management in yuuvis® architect is based on the default roles. It is not yet possible to configure yuuvis® architect to enable access via custom roles.

Depending on the description of the position and tasks, employees work with different data, functions, and tools. User rights for access to data, functions, and applications in accordance with the employees’ fields of duties and responsibility are grouped into roles in the client application and yuuvis® architect. In this way, users with the same fields of duties and responsibility also have the same rights in the system.

Users can view the roles assigned them via their settings.

Roles for Users and Administrators

The following roles can be assigned to users of yuuvis® Momentum client as reference implementation and yuuvis® architect in order to manage their permissions. Users can view the roles assigned to them in the settings menu.

Role Permissions in yuuvis® Momentum client as reference implementation Permissions in yuuvis® architect

YUUVIS_DEFAULT

Users have full access to all objects.

no impact

YUUVIS_MANAGE_SETTINGS

Users are allowed to customize the global standard configurations for hit lists and filters in the settings menu. Those standards will be the default settings for (new) users that have not saved their own user-specific standard configurations so far.

As of 2022 Autumn, users can manage other users of their own tenant but cannot assign the roles YUUVIS_TENANT_ADMIN or YUUVIS_SYSTEM_INTEGRATOR to them. Furthermore, users with one of those two roles cannot be edited or deleted.

YUUVIS_SYSTEM_INTEGRATOR

Administrative object information is provided to users in the metadata forms of any object in the system.

Users can modify metadata forms in the metadata aspect area for any object type defined in the global system schema or in an app-specific schema.

Users can customize the localization of the labels associated with object types defined in the global system schema or in an app-specific schema.

Users can add or delete users of their own tenant and assign roles to them.

YUUVIS_TENANT_ADMIN

Administrative object information is provided to users in the metadata forms of any object in the system.

Users can modify metadata forms in the metadata aspect area for any object type defined in the tenant-specific schema.

Users can customize the localization of the labels associated with object types defined in the tenant-specific schema.

Users can add or delete users of their own tenant and assign roles to them.

YUUVIS_MULTI_TENANT

Users with accounts in multiple tenants can easily switch between their tenants via Switch tenant instead of a conventional logout.

Users with accounts in multiple tenants can easily switch between their tenants via Switch tenant instead of a conventional logout.

Custom Roles

The roles listed above are provided as default for yuuvis® Momentum client as reference implementation and yuuvis® architect. yuuvis® Momentum allows for the definition of custom roles as well. But be aware that you will not be able to use yuuvis® architect. Instead, you can build your own administrative tool based on the API-WEB Service (Web-API Gateway).

5.2.3. Object Types

Any business object handled in your client has an object type. The available object types are defined in the yuuvis® Momentum schema as document, folder or secondary object type. This article gives an introduction into the basics of the yuuvis® Momentum schema and the particularities for yuuvis® Momentum client and yuuvis® architect.

The yuuvis® Momentum Schema

yuuvis® Momentum uses schemata to ensure a valid and consistent data structure for the metadata of stored business objects. The metadata consists of properties. Some predefined system properties are automatically assigned to all objects during their creation. Further properties can be defined in a schema.

The individual properties can be referenced in object type definitions. If you create a business object, you will select one of those object types. It determines the set of properties that will be available for business objects.

Schemata are configuration files containing property and object type definitions.

  • All tenants can refer to the global system schema.

    → yuuvis® architect allows its management only for users with the YUUVIS_SYSTEM_INTEGRATOR role.

  • Additionally, each tenant can configure an own tenant schema. All properties and object types defined in a tenant schema are not available in other tenants.

    → yuuvis® architect allows its management for users with the YUUVIS_TENANT_ADMIN role.

  • An app schema contains property and object type definitions that will be available in all tenants for which the concrete app is enabled.

    → yuuvis® architect allows its management only for users with the YUUVIS_SYSTEM_INTEGRATOR role.

The roles used by yuuvis® architect are not defined in the schema but in a tool-specific role set. This role set is also the default library-based clients. However, yuuvis® Momentum allows you to define your own role set. If you do so, you will not be able to use yuuvis® architect.
Floating Secondary Object Types in yuuvis® architect

In contrast to SSOTs, FSOTs can be handled in a flexible way during the import or at runtime for already existing documents or folders with an update. The concept of FSOTs fits the import behavior where files are imported as documents of a general document object type with no or only a few defined metadata properties. After creation, a classification job analyses the document and assigns specific FSOTs to that document providing the typical properties of a specific business object like an invoice, a delivery note, an order, etc.

In order to be able to assign an FSOT, it has to be referenced as floating in the corresponding document (or folder) object type definition.

An FSOT must not be referenced by more than one object type to assure valid form modeling.

The operating principle of yuuvis® architect is based on a classification of the SOTs. FSOTs referenced in a document or folder object type definition can be given a classification appClient:primary or appClient:required.

Classification 'primary'

With respect to the above-mentioned import process, the user can specify business types for an object manually by means of assigning an FSOT. Here, you can only choose a primary-classified floating secondary object type (PFSOT), characterized by the appClient:primary classification. All of them need to be referenced as floating in the corresponding object type definition in the schema. After importing an object with the general object type, exactly one of those PFSOTs can be selected. Thus, the business type of the object will be determined by assigning its metadata: a specific business type name like invoice, order, etc. and a corresponding description.

During runtime, only one PFSOT can be assigned to an instantiated object.

Whenever one of the referenced PFSOTs is assigned, all RFSOTs referenced in the same object type definition are assigned at the same time.

Classification 'required'

Business objects may need more metadata properties than provided by the initial general object type together with the user-selected PFSOT. With the classification appClient:required, the required-classified floating secondary object types (RFSOTs) are defined. Their metadata properties are assigned automatically together with the assignment of any PFSOT if they are referenced in the same document or folder object type definition. The assignment of multiple RFSOTs is allowed.

Extending Types without Classification

In the schema, SOTs can be defined without any classification appClient:primary or appClient:required. Nevertheless, they can be referenced as FSOTs in an object type definition. Thus, they allow for the user to assign additional metadata independently of other SOTs. They can also be assigned or removed later on if necessary. Examples are general address data, e-mail address data, and approval process attributes.

Types for Business Objects

Any business object in the yuuvis® system needs an object type – either a document or a folder object type. The document or folder object type can reference SSOTs. Thus, any instance of the document or folder object type is provided with a set of metadata coming from the final object type definition and a set of metadata coming from the referenced SSOT.

The assignment of a PFSOT makes an object appear with a specific business pseudo-type determined by the properties of the PFSOT. Since all referenced RFSOTs are assigned at the same time, the object now has a fixed set of metadata containing the properties of the original general object type from the creation, of the assigned PFSOT and of the assigned RFSOTs. This set of metadata will be the same for any object to which the corresponding PFSOT is assigned. Thus, you can consider them as pseudo-types you can choose for your business objects. They are identified by the title property of the PFSOTs.

Instantiated documents or folders of both categories can be extended at runtime by assigning extending FSOTs.

Tags

Tags make it possible to flag the current state of an instantiated object within a process chain in the backend.

In order to display their values in your client, they need to be introduced into your schema as well. Indeed, they are introduced in a specific object type definition. Their names and expected values are set in this definition.

So once introduced, the name and expected values of a tag will appear as technical names in the localization view for users who have the permission to manage the comprising object type.

5.2.4. Localization

The Localization tile is available on the dashboard for users with the YUUVIS_TENANT_ADMIN or YUUVIS_SYSTEM_INTEGRATOR roles.

In your client, forms are used to present the properties of your business objects. yuuvis® architect allows you to customize the labels of the individual property fields and thus replace technical names in the forms, filters and hit list columns.

The structure of the metadata forms for the client cannot be customized via localization, but by means of the Form Modeling view of yuuvis® architect.

Customizing Labels

yuuvis® Momentum client reference implementation includes a default label configuration for the languages English and German. Any technical name you may have defined additionally will have no corresponding language-specific label. If you select a language other than English or German, no labels are predefined at all. In your client, the technical names will be displayed instead.

The following instructions will help you to either customize the default labels or define your own labels.

  • Click the Localization tile to open the view for the label customizing. Alternatively, click the menu button on the top left and select Localization.

  • Select one or two languages on the right side of the top bar.

  • Find a list with the columns Technical name, and for each language Label and Description. All technical names are displayed that correspond to a specific property field available in your client and that are enabled for customizing based on your roles.

  • Add or edit labels and/or descriptions in your language for any technical name in the list. The description is used to group object types in the Create object and Restrict to object types dialogs. Object types with the same description are displayed in the same group.

  • Save your changes or Reset to the last saved configuration and discard all changes.

  • Sort the list by a column by clicking its header. Clicking the column header repeatedly will invert the sort direction.

  • Find a tree of object types in the Filter technical names by: area on the left next to the list. The structure represents the schema structure and contains all types of business objects and extending types you are allowed to customize. Additionally, the # Tags filter provides all technical names identifying names and values of process tags that you are allowed to customize.

  • Click on a node or leaf in the tree to limit the listed technical names by showing only the technical names associated with the selected filter.

  • Click repeatedly on the same filter to remove it and display the entire list of technical names.

New technical names cannot be added in the localization view of yuuvis® architect. They appear automatically in the list after applying changes to the metadata structure directly via the schema or via the Form Modeling view of yuuvis® architect.

The technical names are automatically extracted from the active schema definition. If new definitions are added, the corresponding technical names will appear in the list of available technical names. However with the version 2020 Winter of yuuvis® architect, if schema definitions are deleted, the technical names are not removed from the localizations list. So far, it is not possible to delete the corresponding localization entries that have been saved before. This feature will be available as of version 2021 Summer.
Customizing Language Files

As of version 2021 Summer, the labels can be localized alternatively via language files. To change the language file you have two options: a) make changes online in your browser or b) download the language file, make changes offline and upload the edited file to the server.

a) Online editing

  • To change a label or description for an object type, double-click on the corresponding field and enter your change. Click Save to save your change or Reset to reset.

b) Offline editing

  • Download the language file for the selected language by clicking the corresponding Export icon on the right side of the title bar.

  • Modify the file locally in an editor of your choice.

  • If you want to reuse the file for a different language, rename it consistent with the convention <ISO>.json, e.g., fr.json for French.

  • If you want to reuse the file for a different tenant, the prefixes of tenant-specific labels have to be adjusted.

  • Upload your custom language file by clicking the corresponding Datei, laden Symbol Import icon on the right side of the title bar and selecting the file from the Explorer window.

  • After you have selected the language file, the Import validation dialog opens in which you can check your changes before uploading them. In the left column of the Import validation dialog, the technical names of all object types that have been added to the language file are displayed. In the right column of the Import validation dialog, the technical names of all object types that have been deleted from the language file are displayed. If only the labels and descriptions of object types have been changed, but no technical names, the left column of the Import validation dialog will remain empty.

  • Click OK to upload your local language file to the server.

  • To complete the offline editing, click Save. The values on the server will then be overwritten by the values from your local language file.

yuuvis® Momentum library-based clients support a number of languages.

Sublocales, like German for Switzerland (de-CH), are not supported in yuuvis® architect.

5.2.5. Form Modeling

The Form modeling tile is available on the dashboard for users with the YUUVIS_TENANT_ADMIN or YUUVIS_SYSTEM_INTEGRATOR roles.

You can model the Metadata aspect area in CREATE and EDIT forms that are offered in your client to view and edit metadata. It also possible to combine the form modeling with situation-specific scripts. To check the current layout during modeling, yuuvis® architect provides a form preview presenting the modeled metadata form as it will appear in your client.

The labels displayed in the metadata forms for the client cannot be customized in the form modeler, but by means of the Localization view in yuuvis® architect.

Modeling Forms for Metadata

In your client, the properties of your business objects are presented in different aspect areas. The properties provided by document an folder object types themselves are displayed in the summary aspect area that cannot be customized in yuuvis® architect. However, the properties provided by assigned secondary object types are displayed in the metadata aspect area which can indeed be customized. For each type of your business objects, you can customize separate forms in yuuvis® architect for the Create and Edit working scenarios. For example, you can hide fields from an edit form that are only necessary to create an object. The corresponding form is provided to the user in yuuvis® client accordingly.

You can use default forms if you do not want to create custom forms. These forms are generally sufficient for technical data transfers.

Depending on your roles, you have different permissions. You can model only the metadata forms for which you are authorized by your roles. With the YUUVIS_TENANT_ADMIN role only object types defined in the tenant schema will appear in the architect. With the YUUVIS_SYSTEM_INTEGRATOR role only object types defined in the global system and app schema will appear in the architect.

In general, metadata aspect area forms consist of a form model with arranged groups of fields and optionally a script for manipulating field values. The following instructions will help you to customize the forms displaying metadata in your client for the edit and create situations.

  • Click the Form modeling tile to open the form modeling view. Alternatively, click the menu button on the top left and select Form modeling.

  • In the column Select object type, find a tree to navigate through all object types for which you have the permission to model the metadata forms. In this view, you cannot distinguish pseudo-types determined by primary-classified floating secondary object types from document (or forlder) object types.

    Node Content Required Role

    Application

    Further nodes are displayed, each of them corresponds to one specific application with its own app schema.

    Each node contains types defined in the specific app-schema:

    • Document and folder object types.

    • Pseudo-types determined by a primary-classified floating secondary object type.

    YUUVIS_SYSTEM_INTEGRATOR

    Extending Types

    Floating secondary object types without the classification primary or required defined in

    • the system schema,

    • the app schema or

    • the own tenant schema.

    For system and app schema: YUUVIS_SYSTEM_INTEGRATOR

    For tenant schema: YUUVIS_TENANT_ADMIN

    System

    Types defined in the system schema:

    • Document and folder object types.

    • Pseudo-types determined by a primary-classified floating secondary object type.

    YUUVIS_SYSTEM_INTEGRATOR

    Tenant

    Types defined in the own tenant schema:

    • Document and folder object types.

    • Pseudo-types determined by a primary-classified floating secondary object type.

    YUUVIS_TENANT_ADMIN

  • Click either EDIT in order to customize the edit form or CREATE in order to customize the create form displayed in your client. In case you have saved a model for the EDIT situation but not the CREATE situation, you are asked whether to reuse the EDIT model for CREATE.

The browser window is now divided in 3 areas: On the left a building set area, the Model tree and the Layout area. After clicking on a field in the Model tree or Layout area, an additional Properties area is opened on the right-hand side.

Building Set Area

The left-hand area shows the selected type and the form situation (EDIT or CREATE) you are currently modifying. Below, you can find a list of all available elements you can use to build your metadata aspect area form. On the top, there are two structuring elements: Group and GroupStack. Below, metadata properties are listed that are always assigned to the selected object type via secondary object types. All these properties will be assigned to each object of this business object type, independently of the form of presentation.

The properties are characterized by their names that are displayed in the form, by their data types in italic (-string-, -boolean- etc.) and by their schema-intern property IDs in lower-case letters below.

If a property is displayed in grey letters, it is already part of the metadata form for your client.

If a property is displayed in white letters, it is currently not part of your form presenting the metadata in your client. You can drag and drop the property into the Model tree area.

Properties provided by the document or folder object type itself are not available for form modeling. However, they are always assigned to all instances of the corresponding object type and are provided in the Summary aspect area in the client.
Model Tree Area

In this area you define the structure of your metadata aspect area form. By means of drag and drop, you add elements from the building set on the left. You can arrange the form elements using drag and drop to design groups and GroupStacks of properties. Click x to delete unwanted GroupStacks, Groups, and properties from the form. Properties, groups and GroupStacks can be rearranged by drag and drop within a form.

By default, form layouts are organized into a Main Area for the most important metadata and a Data Area. This layout structure is optional. You may only use the Main Area. Later in time, the Data Area should be used for grouping the metadata in the Summary aspect of the object details in yuuvis® Momentum client.

All Groups and GroupStacks in the model tree can be collapsed or expanded for a better overview.

You can use the Import and Export buttons in order to download your form model as JSON file and import it again later on. The file can only be used for the specific object type. During import, the file is validated and specific errors are reported.

The Clear model button removes all properties from the Model tree together with allmost all Groups and GroupStacks. Only the Main Area Group and the Data Area GroupStack remain.

Click Save to save your form and apply it to your client.

Group:

  • Groups combine properties and group them visually. Properties whose contents are related, can thus be logically combined (e.g., a person’s name, contact details, and postal address, etc.) like in an address book entry. The corresponding fields in the form are visually grouped by means of background color and layout.

  • Elements within a group are arranged vertically by default. In order to arrange them horizontally, go to the Properties area and select Row instead of Column.

  • For example, you can arrange a person’s first and last name next to each other in the first row in an address book entry and place the contact details below in a block with full lines.

  • In the Properties area, you can give groups a unique technical name for identification. This technical name is required in order to display a label for the Group in your form. Customize the labels via Localization. If not specified in the corresponding localization configuration, the technical name will be displayed in the metadata form.

GroupStack:

  • GroupsStacks combine several groups. Groups combined via GroupStack are shown as tabs within the GroupStack area. The name of the Groups in a GroupStack is shown as title of the tabs.

  • The Data Area is per default an empty GroupStack. Thus, no property fields can be arranged here outside of groups.

Layout Area

In this area you can see the properties as fields displayed in their Groups and GroupStacks. The arrangement corresponds to the structure defined in the Model tree. If you select an element in the Model tree, it will be highlighted in the Layout. The highlighting of elements within a GroupStack will be visible only if the corresponding tab is selected.

The Layout area displays an overview of the structure and does not distinguish between arrangement in rows or columns.

Via Open form preview you can have a look at your model to see what it will look like in your client.

Via Open script you can open a scripting window providing further form modeling possibilities. Thus, yuuvis® architect makes it possible to assign situation-specific scripts to the current form. As a scripting support, IntelliSense is available: Click Copy to clipboard in the left corner to select a technical field name. Add the selected string surrounded with the correct syntax to your script at the position of your cursor via Ctrl+V.

Properties Area

After clicking any element in the Model tree or Layout area, an additional Properties area is opened on the right-hand side. Information on the selected element is provided here.

On the top, the name and element type are displayed in a first block.

The second block below differs for different types of elements:

  • For a single property field, you can tick or untick the checkbox Read-only in order to define the behavior in the client. For a string property, you can modify the number of Lines that will be provided for the property field in the client.

    Under Schema, you can see the attributes of the schema property definition for the selected property.

  • For a table property, you see a Read-only checkbox together with the Schema attributes of the property definition, too. Additionally, an overview of the available columns is provided. They are named with their technical names and their types (string etc.). By clicking one of them, you can define for each individual column the number of Lines for each entry and for the entries to be Read-only or not. By drag and drop, you can change the order of the columns or move them between Columns used and Columns not used. Thus, you can include or exclude columns from the metadata form.

  • For a Group, you can select either Row or Column as Layout for the arrangement of the included property fields. Except for the Main Area, you can define a unique technical name for the identification of the Group. This technical name is required in order to display a label for the Group in your form. Customize the labels via Localization.

  • For a GroupStack, no second information block is displayed.

5.2.6. User Management

Users with the YUUVIS_MANAGE_SETTINGS or YUUVIS_TENANT_ADMIN or YUUVIS_SYSTEM_INTEGRATOR roles see the User management tile on the dashboard.

This view of yuuvis® architect provides a graphical interface for administrative users in order to manage users belonging to their tenant. Individual users can be edited or deleted and users can be added. New users will be invited via e-mail to set up their passwords.

The functionality is provided by the admin endpoints of the Tenant Management API.

List of Users

A click on the User management tile on the Dashboard opens a new state that lists all users of your client belonging to your own tenant. Each row corresponds to one user. The list is displayed with the following columns:

Column name Description

Active

Ticked users are activated and can log in. An unticked and thus deactivated user will not be able to log in.

User name

User name for the login of the user. The field is mandatory.

First name

First name of the user.

Last name

Last name of the user.

E-mail

E-mail address of the user. By clicking the entry, a new e-mail will be opened in your local e-mail client with the specified e-mail address as recipient.

Roles

The roles assigned to the user. You can add or remove roles.

ID

Unique user ID automatically set by the yuuvis® Momentum system.

Sort the list by a column by clicking its header. Clicking the column header repeatedly will invert the sort direction.

Filter the list by clicking the icon in any column header and typing your search term.

Adding New Users

In order to add a new user to your tenant, click the Add user button on the right in the top bar. The New user area will open and display a blank form asking for the data of the user to be added. Mandatory fields are User name, E-mail and Roles, where you can select one or several of the roles provided in the dropdown catalog. By clicking the letter icon in the E-Mail field, a new e-mail will be opened in your local e-mail client with the specified e-mail address as recipient.

Click Save to add the user to your tenant.

The user will receive an invitation e-mail guiding them to the registration page. The invitation is valid for 12 hours.

Editing User Data

In the list of users, click on the row of the user for which you want to edit the data. The Properties area will open with the data of the selected row arranged in a form. You can edit the values for First name, Last name and E-Mail, assign additional roles or remove roles, and activate or deactivate the user via the Active checkbox. The user’s password is not displayed and can only be changed by the corresponding user.

Click Save to apply your changes. The data of the user will be updated in the list.

Deleting Users

In the list of users, click on the row of the user you want to delete. The Properties area will open where you can find the Delete button. Confirm with OK in the pop-up window. The user will be removed from the list.

5.2.7. Catalog Management

The Catalog management tile is available on the dashboard for users with the YUUVIS_TENANT_ADMIN or YUUVIS_SYSTEM_INTEGRATOR roles.

Selection lists with pre-defined entries can be used in forms for the properties of your business objects in your client. These selection lists are provided by so-called dynamic catalogs of the Web-API Gateway. Thus, yuuvis® architect allows you to create and modify dynamic catalogs leading to changes in the selection lists displayed in your client.

Dynamic Catalogs

Users with the YUUVIS_TENANT_ADMIN role can create and edit tenant-specific catalogs and set them to Read-only. Catalogs that are set to Read-only implement non-editable selection lists in your client.

Additionally, tenant administrators can create a tenant-specific copy of global or app-specific catalogs that are not set to Read-only. Each copy can be managed as a tenant-specific catalog. Your client will display the selection list configured in the tenant-specific copy of the global catalog. Changes of the original global catalog do not affect the tenant-specific copy and thus also not the selection list displayed in your client.

Users with the YUUVIS_SYSTEM_INTEGRATOR role can create and edit global and app-specific catalogs that are available in every tenant and set them to Read-only. Global or app-specific catalogs that are set to Read-only cannot be copied to a tenant-specific resource.

Start managing catalogs as follows:

  • Click the Catalog management tile to open the catalog management view. Alternatively, click the menu button on the top left and select Catalog management.

  • In the Catalogs column on the left, find a tree to navigate though all catalogs available for users of your tenant. Catalogs under System and App are available in each tenant whereas catalogs under Tenant are available only for users within the corresponding tenant.

  • You can either edit existing catalogs or create new catalogs.

Editing Catalogs

The following instructions will help you to customize the selection lists in your client by managing the catalogs.

  • Select a catalog. A new area is opened displaying the data for the selected catalog.

  • If you have the appropriate permissions, you can edit the catalog and its entries.

  • As a YUUVIS_TENANT_ADMIN you cannot edit global or app-specific catalogs. Instead, the Create tenant copy button allows you to copy the catalog to your tenant resource and edit it as a tenant-specific catalog.

  • Edit the catalog:

    • Decide whether the catalog should be Read-only or not by ticking or not ticking the checkbox.

    • Specify values for the catalog that will be the entries available in the selection list in your client. Enter each of them in the field New entry and confirm with Add. The values cannot be localized.

    • Disable a value by unticking its checkbox.

    • Delete a value by clicking the x icon.

    • Check the Preview sub-area on the right and see what the selection list will look like in your client.

  • Save the modified catalog.

Creating Catalogs

The following instructions will help you to create a new selection list in your client by creating a catalog.

  • You can create catalogs in each resource where you can see a + icon behind the name of the node in the tree. Users with the YUUVIS_SYSTEM_INTEGRATOR role will see a + icon behind the System node and behind the individual child nodes of App. Users with the YUUVIS_TENANT_ADMIN role will see the + icon next to their tenant’s node.

  • Click the + icon next to the node where you want to create the new catalog. The New catalog area will be opened.

  • Enter the technical name for your catalog in the Catalog name field. You can localize it afterwards via Localization.

  • Use the editing options described above.

  • Save the catalog.

5.2.8. Schema Management

Beta Version
As of yuuvis® Momentum release 2022 Summer, the Schema management is available as a beta version.

The Schema management tile is available on the dashboard for users with the YUUVIS_TENANT_ADMIN or YUUVIS_SYSTEM_INTEGRATOR roles.

You can use this graphical user interface provided by yuuvis® architect to define object types and their properties for the business objects in your client application. The object types and properties are defined in schema structures.

Depending on the roles assigned to the currently logged-in user, it is possible to manage the global schema, app schemata and/or tenant schemata as described below.

The schema management provided by yuuvis® architect uses the corresponding endpoints provided by the Core API and the Web-API Gateway.

The structure of the metadata forms that present the properties of your business objects in your client can be customized by means of the Form Modeling view of yuuvis® architect.

Before you start working on your schemata, it is important to define how the available types of schemata as well as properties and object types will best depict your business use case. Especially as a system integrator with access to the global schema as well as to all tenant and app schemata, you are responsible for the creation and management of a complex configuration with multiple schemata that can refer to each other. With this definition in mind, you can create and edit your schemata.
Selecting/Creating a Schema

Select the schema file you want to read or edit from the Schema selection list on the left side of the Schema management view of yuuvis® architect. Depending on your role, you have read and/or edit permissions:

Icon Scope Required Roles for Read Access Required Role for Edit Actions

system

YUUVIS_SYSTEM_INTEGRATOR or YUUVIS_TENANT_ADMIN

YUUVIS_SYSTEM_INTEGRATOR

app

YUUVIS_SYSTEM_INTEGRATOR or YUUVIS_TENANT_ADMIN

YUUVIS_SYSTEM_INTEGRATOR

tenant

YUUVIS_SYSTEM_INTEGRATOR or YUUVIS_TENANT_ADMIN

YUUVIS_SYSTEM_INTEGRATOR or YUUVIS_TENANT_ADMIN

The namespace of the individual schemata indicates their concrete scope: either the entire system, a specific app or a specific tenant.

To create a new app schema, use the endpoint POST /api/system/apps/{app}/schema.

As of 2022 Autumn, a new app schema can be created via the + Plus icon in the top bar of the Schema selection list.

Importing an External Schema File

Import an external XML file from a local directory by clicking Import in the bottom left corner.

Managing Classifications

Classifications can be set for object types and properties in their definition. All available classifications that trigger a specific behavior in a library-based client are described here.

Furthermore, it is possible to specify one or more custom classifications. If you specify a custom classification value, do not use the semicolon character as it is internally used as separator.

Display Modes

yuuvis® architect offers two different display modes.

  • The Model mode allows to manage schemata via a graphical user interface.

  • The XML mode displays the selected schema file in XML format.

Click the Model and XML buttons on the top right to toggle between the two views.

Using the Model Mode

After selecting a schema file, the scope of the schema (the tenant name, the app name or system) is displayed in the header of the left side bar. Below, you can switch between the two tabs Object types and Metadata to display the IDs of object types or metadata definitions that are part of the selected schema file. The object type IDs are grouped by base type (Document, Folder, and Secondary (extensions)) whereas the metadata IDs are grouped by metadata type (e.g., DateTime, Integer, String, …​).

If no draft is available for the selected schema file, you can either copy the schema version currently used by yuuvis® Momentum or start with an empty schema file to create a new draft.

Creating/Editing Object Type Definitions:

  • Select the Object types tab on the left side. If your selected schema already contains object type definitions, they are arranged in a selection list grouped by the corresponding base type Document, Folder, or Secondary (extensions).

    • Create: Click the + Plus icon next to the schema namespace and choose one of the following object type definitions to be created: Document, Folder, and Secondary (extensions).

      To add another object type definition to an already existing base type group, click the + Plus icon next to the corresponding base type.

    • Edit: Display the defined object types by opening the selection list of the corresponding base type Document, Folder, or Secondary (extensions). Click the object type ID of the definition you want to edit.

  • The base type is displayed in the header of the form view providing an object type configuration form, and the object type ID if specified.

  • Attributes marked with * are required.

  • The properties referenced in the Metadata field area are part of the metadata.

    • To add a property, click the + icon. The Metadata field view is displayed on the right.

    • Create a new property by clicking the + icon in the header of the Metadata field view.

    • Edit a property by clicking the pencil icon.

    • Click a property in the Metadata field view to add it to or remove it from the Metadata field area of the object type view.

  • For document and folder object type definitions: The Used secondary object types area displays all secondary object types by their IDs that are referenced in the document or folder object type definition.

  • Click Apply to introduce your changes into the draft you are currently working on.

Creating/Editing Metadata Definitions:

  • Select the Metadata tab on the left side. If your selected schema already contains metadata definitions, they are arranged in a selection list of the corresponding metadata types (e.g., DateTime, Integer, String, …​).

    • Create: Click the + Plus icon next to the schema namespace and select the type of metadata to be created. To add another metadata definition to an already existing type group, click the + Plus icon next to the corresponding type.

    • Edit: Display the defined object types by opening the selection list of the corresponding metadata types (e.g., DateTime, Integer, String, …​). Click the metadata ID of the definition you want to edit.

  • The metadata type is displayed in the header of the form view providing a metadata configuration form, and the metadata ID if specified.

  • Attributes marked with * are required.

  • Click Apply to introduce your changes into the draft you are currently working on.

Using the XML Mode

After selecting a schema file, the two views DEPLOYED Schema and DRAFT Schema are displayed. Both of them present a schema in its XML structure.

By clicking the arrows in the right sidebar, you can compare the deployed and draft schemata in the Schema Diff view.

DEPLOYED Schema View:

  • The current version of the selected schema file is displayed. This version is currently used by yuuvis® Momentum. Editing is not possible.

  • Click Export to save a local copy of the displayed XML file.

DRAFT Schema View:

  • This view displays the draft version for the selected schema file. You can edit and save it to continue your work at a later time.

  • Click Import to load an XML file from a local directory.

  • Click Export to save a local copy of the displayed XML file.

Schema Diff View:

  • The deployed schema on the left is compared to the draft schema on the right. Differences are highlighted.

Saving and Deploying a Draft

Via Validate, it is possible to check whether your draft fulfills all requirements for a valid schema.

Click Deploy to replace the schema version currently used by yuuvis® Momentum by your draft schema. The draft is automatically validated. Thus, the process can only be successful if your draft is valid.

Click Save draft to store your current working status. The draft is not validated.

5.2.9. Access Rights Management

The Access rights management tile is available on the dashboard for users with the YUUVIS_TENANT_ADMIN or YUUVIS_SYSTEM_INTEGRATOR roles.

You can use this graphical user interface provided by yuuvis® architect to manage roles and the rights they will grant in your client application. The roles are defined in role set structures.

Depending on the roles assigned to the currently logged-in user, it is possible to manage the global role set, app role sets and/or tenant role sets as described below.

Selecting a Role Set

Select the role set file you want to read or edit from the Select role set selection list on the left side of the Access rights management view of yuuvis® architect. Depending on your roles, you have read and/or edit permissions:

Icon Scope Required Roles for Read Access Required Role for Edit Actions

system

YUUVIS_SYSTEM_INTEGRATOR or YUUVIS_TENANT_ADMIN

YUUVIS_SYSTEM_INTEGRATOR

app

YUUVIS_SYSTEM_INTEGRATOR or YUUVIS_TENANT_ADMIN

YUUVIS_SYSTEM_INTEGRATOR

tenant

YUUVIS_SYSTEM_INTEGRATOR or YUUVIS_TENANT_ADMIN

YUUVIS_SYSTEM_INTEGRATOR or YUUVIS_TENANT_ADMIN

The namespace of the individual role sets indicates their concrete scope: either the entire system, a specific app or a specific tenant.

To create a new app role set, use the endpoint POST /api/system/apps/{app}/permissions.
Display Modes

yuuvis® architect offers two different display modes.

  • The Model mode allows to manage role sets via a graphical user interface.

  • The XML mode displays the selected role set file in XML format.

Click the Model and XML buttons on the top right to toggle between the two views.

Using the Model Mode

After selecting a role set file, the scope of the role set (the tenant name, the app name or system) is displayed in the header of the main area.

Creating a Role:

  • Click the + Plus icon in the header of the Select a role sidebar. Specify a name for the new role.

Editing Roles:

  • Select an existing role in the Select a role selection list on the left side. If your selected role set already contains roles, they are arranged in the Select a role selection list.

  • The role name is displayed next to the role set’s scope in the header of the form view providing a role set configuration form.

  • Attributes marked with * are required.

  • The following fields can be configured:

    • Name of the role.

    • Permissions for the handling of DMS objects the role will grant to the users if assigned. Available values are create, read, write, delete.

    • condition to limit the specified permissions to specific object types.

  • Click Save role to introduce your changes into the draft you are currently working on.

Using the XML Mode

After selecting a role set file, the two views Deployed role set and Draft role set are displayed. Both of them present a role set in its XML structure.

Deployed role set View:

  • The current version of the selected role set file is displayed. This version is currently used by yuuvis® Momentum. Editing is not possible.

  • Click Export to save a local copy of the displayed XML file.

Draft role set View:

  • This view displays the draft version for the selected role set file. You can edit and save it to continue your work at a later time.

  • Click Import to load an XML file from a local directory.

  • Click Export to save a local copy of the displayed XML file.

Saving and Deploying a Draft

Via Validate, it is possible to check whether your draft fulfills all requirements for a valid role set.

Click Deploy to replace the role set version currently used by yuuvis® Momentum by your draft role set. The draft is automatically validated. Thus, the process can only be successful if your draft is valid.

Click Save draft to store your current working status. The draft is not validated.

5.2.10. Process Management (BPM)

The Process management (BPM) tile is available on the dashboard for users with the YUUVIS_TENANT_ADMIN role.

Processes/Tasks List View

Select the corresponding tab to display either the Processes list view or the Tasks list view (as of 2023 Autumn).

The lists can be sorted by the values of those properties by clicking the corresponding column header. Furthermore, it is possible to filter by specific values for the individual process properties. The value can be specified

  • via input field for string properties

  • via calendar for datetime properties or

  • via selection list for the Status.

It is possible to specify filter values for multiple properties. Internally, the conditions will be concatenated via a logical AND operator.

Processes Tab

All processes within in the currently active tenant are listed. For each process, the properties ID, Process definition key, Name, Started by, Start time, End time, Status and Business key are displayed.

Hereby, the Started by column displays Lastname, Firstname (username) like in a client application instead of the userId. The format is configurable. Filtering is possible by typing the user’s name whereas it is internally resolved and treated as userId. Admin users are not searchable.

Tasks Tab

As of 2023 Autumn: All tasks within the currently active tenant are listed. For each task, the properties ID, Name, Status, Editor, Owner, Creation time and End time are displayed.

Hereby, the Editor and Owner columns display Lastname, Firstname (username) like in a client application instead of the userId. The format is configurable. Filtering is possible by typing the user’s name whereas it is internally resolved and treated as userId. Admin users are not searchable.

Process Details View

Click a specific process instance in the processes list to display the corresponding process details. Multi-selection is possible.

The details of the selected process are displayed in the aspects Summary, Tasks and Progress.

As of 2023 Summer, the process details view’s top bar contains the Delete process and Refresh buttons.

Summary Aspect Area

The Summary aspect area contains the metadata of the selected process instance:

  • Status (Running or Completed)

  • ID

  • Process definition key

  • Name

  • Started by

  • Start time

  • End time (if already completed)

  • Business key

  • Process variables (if available) in a table with the columns Name, Type and Value

The process variables (if available) can be edited.

  • Boolean values can be changed from true to false or vice versa.

  • String values can be replaced by a different string value with a length up to 4000 characters.

  • Dates can be changed via calendar icon.

  • JSON values can be replaced by a different valid JSON structure.

  • Integer and double values can be edited to integer and double values.

  • Variables without type (null value variables) cannot be edited as their type is unknown.

Tasks Aspect Area

All tasks belonging to the selected process instances are listed. To sort the list by their individual values for the task properties, click the corresponding column header.

Progress Aspect Area

This aspect area displays the history of the selected process instance.

Task Details View

Click a specific task instance in the task list to display the corresponding task details. Multi-selection is possible.

The details of the selected process are displayed in the aspects Summary and Editor history.

The task details view’s top bar contains the Refresh button and, if the task is currently assigned to the logged-in user, the Unassign button.

Summary Aspect Area

The Summary aspect area contains the metadata of the selected process instance:

  • Status (Running or Completed)

  • Editor

  • Owner

  • Task ID

  • Task definition key

  • Form key

  • Process ID

  • Name

  • Creation time

  • End time (if already completed)

Task Editor History Aspect Area

An Assignments list contains information on user assignments and unassignments, delegations and resolving of the task.

5.3. Monitoring via Prometheus and Grafana

Display the current status and capacity of the services within your yuuvis® Momentum cluster via Grafana Web UI.

As of version 2021 Autumn, this monitoring solution allows the observation of your yuuvis® Momentum Kubernetes Cluster. The integrated Grafana Web UI serves for visualization of resource consumption and network traffic for yuuvis® services or their individual pods.

5.3.1. Helm Chart 'monitoring'

The monitoring Helm chart includes Prometheus for the collection and processing of the service-specific status information, and Grafana providing a graphical user interface which displays the results provided by Prometheus. Furthermore, a Kubernetes NodePort service is installed that manages the port for the monitoring and thus allows for the access to the monitoring displayed in Grafana via web browser.

Each service within the yuuvis namespace can be monitored.

The Grafana UI can be accessed in the web browser via the port of the NodePort service:

http://<host>:3000

There are two dashboards for the Grafana UI installed via the monitoring Helm chart:

Dashboard File Name Description

momentum-application-instances-(pods).json

Dashboard for inspection of single pods in a yuuvis® Momentum cluster. Displays the status information of the individual pods, e.g., their memory or CPU consumption.

momentum-applications-(services).json

Dashboard for inspection of services in a yuuvis® Momentum cluster. For services using multiple pods, the results of all pods of that service are summarized. Network traffic like error messages, response times, logs etc. can thus be displayed.

To import one of them into Grafana UI, click the Dashboards icon in the left corner and select Manage. Then, click the Import button and select a dashboard.

If you want to save a custom dashboard, click the Share icon in the top bar, switch to the Export tab and activate Export for sharing externally in order to store your dashboard in an importable format. If you now click Save to file, the exported file can be stored in the correct format.

5.3.2. Installation and Configuration

Before deploying the monitoring Helm chart during an installation or upgrade, adjust the following parameters in the values.yaml configuration file.

Parameter Description Default Value

prometheus

Configuration parameters for Prometheus.

-

prometheusSpec.retention

Storage time for log data collected by the Prometheus operator.

10d

grafana

Configuration parameters for Grafana.

-

adminPassword

Password for login to Grafana UI.

Has to be replaced by a secure custom password.

changeme

service.enabled

Boolean value specifying whether the Kubernetes NodePort service for the browser access of monitoring is activated (true) or deactivated (false).

If set to false, monitoring is accessible only via port forwarding to port 3000.

true

6. Business Process Management

6.1. BPM Engine API

6.1.1. Concept

In order to establish a standardized approach when working with such a large amount of documents, companies that use DMS systems need to establish and enforce business rules for their processing. For instance, an employee must know which steps are to be performed with an invoice document in order to pay an invoice to a third party, while still complying with bookkeeping rules of the company. The business rules also include multiple technical steps that should be performed by the employee in order to comply with these business rules as well as with the legal norms. For instance, a paid invoice must be marked as such in order to avoid double payment of it, and the retention time of it should be set, to prevent deletion within the time period defined by the law. All this puts a considerable cognitive load onto employees working with documents, since they have to execute their primary task of processing the invoice, while keeping the status of the document up to date (how far has the payment process progressed and what has been done so far) and setting such purely technical fields on the document.

yuuvis® Momentum is a powerful DMS system that can handle hundreds of millions of documents with ease—whether they are of numerous types, spread over multiple tenants or used by hundreds or thousands of users. In order to efficiently adopt and enforce the business rules, a considerable automation is necessary to be able to support the employees who work on the documents. And that is why we integrate the yuuvis® Momentum DMS with a workflow functionality in form of a BPM Engine. The DMS stores and manages the documents, and BPM Engine implements the business rules that define how documents are processed in a company. Implementing the business rules as workflows is not only an automation capability, but also a great opportunity for companies to document their business rules.

Why Flowable?

In order to support the workflows in yuuvis® Momentum, we have decided to integrate Flowable engine in it, for the following reasons:

  • it supports the BPMN 2.0 modeling notation, and has a visual modeler

  • it is highly extensible and supports numerous ways of integration with third-party systems

  • it has an active developer and user community

  • it has detailed documentation for all its components and technical interfaces

  • it has been proven in numerous projects and for various purposes

  • it is a freely available, open source workflow engine, accessible to any yuuvis® Momentum solution developer in case some details of implementation require detailed investigation

Integration Overview

The BPM engine is deployed within the Kubernetes cluster, next to other yuuvis® Momentum services. It exposes a detailed REST interface that is accessible from the cluster. The administration console uses this interface to manage models and processes running within the engine. The REST interface of the engine is not exposed to external clients, but can be accessed only through system gateway (that authenticates and authorizes incoming requests) and Web-API gateway. Flowable REST interface that is accessible within the cluster includes not only process-instance relevant endpoints that are of interest to clients, but also considerable number of endpoints that are used for management purposes. For this reason, the Web-API exposes only those endpoints that are relevant to external clients (that may be yuuvis® Momentum client, its customization or a custom client), such as endpoints for starting a process, or an endpoint that lists the currently active tasks of a user. The engine contains a custom IDM connector for Keycloak with which it can access users and their roles.

Both the BPM engine and Web-API Gateway REST interfaces are documented using Open-API and can be explored and tested via Swagger-UI.

The engine supports multitenancy. Each request coming from the Web-API Gateway will contain the tenant information in the JWT token and the processes and models are divided into tenants based on this information.

In case that REST interface of the engine is accessed from within the cluster, the caller has to ensure that either a correct yuuvis® Momentum JWT token is sent with the request or that the tenant ID is passed as a parameter of the endpoint call.

6.1.2. Endpoints

These endpoints allow the management of workflow processes and tasks.

Manage Process Definitions
GET /bpm-engine/api/process-definitions - Retrieve a list of process definitions.
As of Version

2021 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves a list of process definitions matching the conditions defined in various query parameters.

Optional query parameters:

Parameter Type Description

category

string

Only return process definitions with the given category.

categoryLike

string

Specify a string that has to match the category and that can contain % characters as placeholders for an arbitrary number of unknown characters.

categoryNotEquals

string

Only return process definitions which do not have the given category.

key

string

Only return process definitions with the given key.

keyLike

string

Specify a string that has to match the key and that can contain % characters as placeholders for an arbitrary number of unknown characters.

name

string

Only return process definitions with the given name.

nameLike

string

Specify a string that has to match the name and that can contain % characters as placeholders for an arbitrary number of unknown characters.

version

integer

Only return process definitions with the given version.

latest

boolean

Only return the latest process definition versions. Can only be used together with key and keyLike parameters. Combination with any other parameters will result in an error with HTTP status code 400.

suspended

boolean

If true, only suspended process definitions are returned. If false, only active process definitions (which are not suspended) are returned.

startableByUser

string

A valid user ID. Only return process definitions which user specified by the ID is authorized to start.

page

integer($int32)

Result page you want to retrieve (0…N). Default is 0 which means the first page.

size

integer($int32)

Number of objects per page.

sort

string

Sorting of results either ascending (asc) or descending (desc). Default sort order is ascending.

Response HTTP status codes:

HTTP status code Meaning

200

Request was successful and the process definitions are returned.

400

A parameter was passed in the wrong format or latest is used with parameters other than key and keyLike. The status message contains additional information.

401

The calling user is not authorized.

Request Header

Content-Type: application/json

Request Example

https://<host>/bpm-engine/api/process-definitions/?page=0&size=50&sort=desc&version=1

Response Example
{
  "objects": [
    {
      "id": "follow-up:1:00000000-0000-0000-0000-000000000000",
      "category": "examplecategory",
      "key": "follow-up",
      "name": "Follow-up",
      "description": "Follow up any document (NOTE: The start-form enforces 1 parameter (expiryDateTime) and 1 optional parameter (whatAbout))",
      "version": 1,
      "global": false,
      "startFormDefined": true,
      "suspended": false
    },
    {
      "id": "onesteptest_proc:1:00000000-0000-0000-0000-000000000001",
      "category": "exampleprocess",
      "key": "onesteptest_proc",
      "name": "One step test process",
      "description": null,
      "version": 1,
      "global": false,
      "startFormDefined": false,
      "suspended": false
    },
    {
      "id": "twosteptest_proc:1:00000000-0000-0000-0000-000000000002",
      "category": "exampleprocess",
      "key": "twosteptest_proc",
      "name": "Process-definition-name: Two step test process",
      "description": "This is description from model editor (high level, not the visual editor of process). The first step goes to initiator, second to no one (can be played with id-links). There is one form reference (get group id) in the first task.",
      "version": 1,
      "global": false,
      "startFormDefined": false,
      "suspended": false
    }
  ],
  "numItems": 3,
  "totalNumItems": 3,
  "hasMoreItems": false
}
GET /bpm-engine/api/process-definitions/{processDefinitionID} - Retrieve a process definition by ID.
As of Version

2021 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the process definitions specified by processDefinitionId.

Response HTTP status codes:

HTTP status code Meaning

200

The process definition was found and returned.

401

The calling user is not authorized.

404

The requested process specified by processDefinitionId was not found.

Request Header

Content-Type: application/json

Request Example

https://<host>/bpm-engine/api/process-definitions/onesteptest_proc:1:00000000-0000-0000-0000-000000000001

Response Example
{
  "id": "onesteptest_proc:1:00000000-0000-0000-0000-000000000001",
  "category": "exampleprocess",
  "key": "onesteptest_proc",
  "name": "One step test process",
  "description": null,
  "version": 1,
  "global": false,
  "startFormDefined": false,
  "suspended": false
}
Manage Process Instances
GET /bpm-engine/api/processes - Retrieve all processes for the user
As of Version

2021 Autumn

Request Method

GET

Response Format

JSON

Description

This endpoint returns a list of processes from the same tenant as the user.

A user without admin rights can only see processes that he has started himself.

A user with admin rights can see all processes from the user’s tenant. An admin user can also filter for processes started by a given user using the parameter startedBy.

With default filter parameters the list of processes contains completed and not completed(running) processes.

Optional query parameters:

Parameter Type Description

processInstanceId

string

Only return process instances with the given id.

name

string

Only return process instances with the given name.

nameLike

string

Only return process instances with a name like the given name.

nameLikeIgnoreCase

string

Only return process instances with a name like the given name ignoring case.

processDefinitionKey

string

Only return process instances with the given process definition key.

processDefinitionId

string

Only return process instances with the given process definition ID.

processDefinitionCategory

string

Only return process instances with the given process definition category.

processDefinitionVersion

integer

Only return process instances with the given process definition version.

businessKey

string

Only return process instances with the given businessKey.

businessKeyLike

string

Specify a string that has to match the businessKey and that can contain % characters as placeholders for an arbitrary number of unknown characters.

startedAfter

date-time

Only return process instances started after the given date.

startedBefore

date-time

Only return process instances started before the given date.

finishedAfter

date-time

Only return process instances ended after the given date.

finishedBefore

date-time

Only return process instances ended before the given date.

startedBy

string

Only return process instances started by the given user specified by userId. The result depends on the permissions of the currently logged-in user:

  • If startedBy is not specified and

    • the user has admin access, all processes are returned.

    • the user has no admin access, user gets only the own processes.

  • If startedBy is specified and

    • the user has admin access, all processes started by the specified user are returned.

    • the user has no admin access, only the own userId is allowed as value for startedBy. A request with a different userId as value for startedBy returns an error.

involvedUser

string

Only return process instances in which the given user is involved.

superProcessInstanceId

string

Only return process instances which have the given super process instance ID (for processes that have a call activity).

excludeSubprocesses

boolean

Return only process instances which are not sub-processes.

includeProcessVariables

boolean

Include process variables in the result.

isCompleted

boolean

If true, only completed processes are returned. If false, only running processes are returned. If not specified, both completed und running processes are returned.

page

integer($int32)

Result page you want to retrieve (0…N). Default is 0 which means the first page.

size

integer($int32)

Number of objects per page.

sort

string

Sorting of results either ascending (asc) or descending (desc). Default sort order is ascending.

Response HTTP status codes:

HTTP status code Meaning

200

Request was successful and the process definitions are returned.

400

A parameter was passed in the wrong format or latest is used with parameters other than key and keyLike. The status message contains additional information.

401

The calling user is not authorized.

Request Header

Content-Type: application/json

Request Example

https://<host>/bpm-engine/api/processes?page=0&size=1

Response Example
{
  "objects": [
    {
      "id": "00000000-0000-0000-0000-000000000000",
      "name": "testProcessInstanceName",
      "businessKey": "testBusinessKey",
      "processDefinitionId": "twosteptest_proc:4:8dc694a2-10b1-11ec-99ef-027ea5eeae02",
      "processDefinitionName": "Two tasks test process",
      "processDefinitionDescription": "Process shall be started with Web-API Gateway variable subject to be shown in the same column of the inbox and with . Both tasks to initiator.",
      "startUserId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
      "startTime": "2021-11-01T12:28:46.363Z",
      "deleteReason": null,
      "endActivityId": null,
      "startActivityId": "startEvent1",
      "durationInMillis": null,
      "endTime": null,
      "suspended": false,
      "variables": []
    }
  ],
  "numItems": 1,
  "totalNumItems": 1,
  "hasMoreItems": false
}
POST /bpm-engine/api/processes - Start a process
As of Version

2021 Autumn

Request Method

POST

Response Format

JSON

Description

Starts a process specified in a JSON structure in the request body.

Response HTTP status codes:

HTTP status code Meaning

200, 201

Request was successful and the process instance was created.

400

Either the process definition was not found or an invalid variable was passed. Status description contains additional information about the error.

401

The calling user is not authorized.

Request Header

Content-Type: application/json

Request Example

https://<host>/bpm-engine/api/processes

Request Body
{
  "businessKey": "myBusinessKey",
  "name": "myProcessInstanceName",
  "processDefinitionKey": "oneTaskProcess",
  "variables": [
    {
      "name": "myVariable",
      "scope": "myScope",
      "type": "myType",
      "value": "test",
      "valueUrl": "http://...."
    }
  ]
}
Response Example
{
  "hasMoreItems": true,
  "numItems": 50,
  "objects": [
    {
      "businessKey": "myBusinessKey",
      "completed": true,
      "id": 187,
      "name": "myProcessInstanceName",
      "processDefinitionDescription": "A process definition description",
      "processDefinitionId": "oneTaskProcess:1:00000000-0000-0000-0000-000000000000",
      "processDefinitionName": "A process definition name",
      "startTime": "2018-04-17T10:17:43.902+0000",
      "startUserId": "user0001",
      "suspended": true,
      "variables": [
        {
          "name": "myVariable",
          "scope": "myScope",
          "type": "myType",
          "value": "test",
          "valueUrl": "http://...."
        }
      ]
    }
  ]
}
DELETE /bpm-engine/api/processes - Delete multiple processes.
As of Version

2023 Autumn

Request Method

DELETE

Response Format

HTTP status code

Description

Batch delete a list of process instances. If one of the provided process instance id is not found, then no processes will be deleted. Process instances ids have to be provided as list of id strings in the request body.

Response HTTP status codes:

HTTP status code Meaning

200

Indicates the process instances were found and deleted. Response body is left empty intentionally.

401

Indicates the calling user is not authorized.

403

Indicates the calling user is not allowed to use this endpoint.

404

Indicates at least one of the requested process instances was not found.

GET /bpm-engine/api/processes/{processInstanceId} - Retrieve a process instance
As of Version

2021 Autumn

Request Method

POST

Response Format

JSON

Description

Retrieves the process instance specified by processInstanceId.

Optional query parameters:

Parameter Type Description

includeProcessVariables

boolean

Indication to include process variables in the result. Default is false.

Response HTTP status codes:

HTTP status code Meaning

200

The process instance was found and returned.

401

The calling user is not authorized.

404

The requested process instance specified by processInstanceId was not found.

Request Header

Content-Type: application/json

Request Example

https://<host>/bpm-engine/api/processes/187

Response Example
{

  "businessKey": "myBusinessKey",
  "completed": true,
  "id": 187,
  "name": "myProcessInstanceName",
  "processDefinitionDescription": "A process definition description",
  "processDefinitionId": "oneTaskProcess:1:00000000-0000-0000-0000-000000000000",
  "processDefinitionName": "A process definition name",
  "startTime": "2018-04-17T10:17:43.902+0000",
  "startUserId": "user0001",
  "suspended": true,
  "variables": [
    {
      "name": "myVariable",
      "scope": "myScope",
      "type": "myType",
      "value": "test",
      "valueUrl": "http://...."
    }
  ]
}
DELETE /bpm-engine/api/processes/{processInstanceId} - Delete a process instance
As of Version

2021 Autumn

Request Method

DELETE

Response Format

HTTP status code

Description

Deletes the process instance specified by processInstanceId.

Response HTTP status codes:

HTTP status code Meaning

200

The process instance was found and deleted.

401

The calling user is not authorized.

404

The requested process instance specified by processInstanceId was not found.

Request Header

Content-Type: application/json

Request Example

https://<host>/bpm-engine/api/processes/187

Response Example

200

POST /bpm-engine/api/processes/{processInstanceId}/evaluate - Evaluate a script on a process instance
As of Version

2024 Summer

Request Method

POST

Response Format

HTTP status code

Required Permission

Available if the authenticated user has the admin role configured in bpm.engine.app.admin-access-role. In the default configuration, access is granted via the YUUVIS_TENANT_ADMIN role.

Description

Evaluates the script in the request body on a running process instance. Process variables can be changed by such a script. Supported script languages:

  • Javascript

  • Groovy

REQUIRED query parameters:

Parameter Type Description

scriptLanguage

String

Specifies the language of the script that is sent in the request body.

Available values:

  • groovy

  • javascript (default)

Response HTTP status codes:

HTTP status code Meaning

200

The script was successfully evaluated.

401

The calling user is not authorized.

403

The calling user is not allowed to use this endpoint.

404

The requested process was not found.

409

The script evaluation failed.

GET /bpm-engine/api/processes/{processInstanceId}/history - Retrieve the history of a process instance
As of Version

2021 Winter

Request Method

GET

Response Format

JSON

Description

Retrieves the history of the process instance specified by processInstanceId.

Optional query parameters:

Parameter Type Description

includeIdentityLinks

boolean

Decides whether the identityLinks list is included (true) in the individual tasks' history or not (false). Default is false.

includeComments

boolean

Decides whether the Comments list is included (true) in the process history or not (false). Default is false.

Response HTTP status codes:

HTTP status code Meaning

200

The process instance history was found and returned.

400

Bad request.

403

Forbidden.

404

The requested process instance specified by processInstanceId was not found.

409

Conflict.

415

Unsupported media type.

500

Internal server error.

Each error is thrown in the response body in JSON format containing an error message and an exception string.

Request Header

Content-Type: application/json

Request Example

https://<host>/bpm-engine/api/processes/00000000-0000-0000-0000-000000000000/history

Response Example
{
  "tasks": [
    {
      "id": "00000000-0000-0000-0000-000000000123",
      "name": "1st_task",
      "description": "In this case, you have to do several things as they are:\n1. subtask\n2. subtask",
      "assignee": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
      "owner": null,
      "createTime": "2021-11-01T12:28:46.388Z",
      "claimTime": null,
      "endTime": null,
      "identityLinks": [
        {
          "candidates": {
            "users": [],
            "roles": []
          },
          "assignmentHistory": [
            {
              "type": "ASSIGNMENT",
              "assignee": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
              "timestamp": "2021-11-01T12:28:46.447Z"
            }
          ]
        }
      ]
    }
  ],
  "comments": [
    {
      "id": "00000001-0001-0001-0001-000000000001",
      "author": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
      "message": "This is the first example comment for the first task.",
      "time": "2021-11-02T13:05:29.099Z",
      "processInstanceId": "00000000-0000-0000-0000-000000000000",
      "taskId": "00000000-0000-0000-0000-000000000123"
    }
  ]
}
PUT /bpm-engine/api/processes/{processInstanceId}/variables - Update process variables.
As of Version

2024 Spring

Request Method

PUT

Response Format

HTTP status code

Description

Saves a list of variables for a running process. If a variable does not exist yet, it will be created in the process scope.

The following types are available for variables:

  • boolean

  • string

  • datetime

  • JSON

Response HTTP status codes:

HTTP status code Meaning

200

Request was successful and the process variables were saved.

401

The calling user is not authorized.

403

The calling user is not allowed to use the endpoint.

404

The requested process instance was not found.

Request Example

https://<host>/bpm-engine/api/processes/187/variables

Request Body
{
  "variables": [
    {
      "name": "myVariable",
      "scope": "myScope",
      "type": "myType",
      "value": "test",
      "valueUrl": "http://...."
    }
  ]
}
Response Example

200 OK

Manage Tasks
GET /bpm-engine/api/tasks - Retrieve a list of tasks
As of Version

2021 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves a list of tasks of the currently active user that are matching the conditions defined in various query parameters.

If the currently logged-in user has administrative rights, all active tasks within the tenant are retrieved. Use the visibleTo query parameter to specify any user.

Optional query parameters:

Parameter Type Description

id

string

Only return the task with the given id.

name

string

Only return process instances with the given name.

nameLike

string

Specify a string that has to match the name and that can contain % characters as placeholders for an arbitrary number of unknown characters.

description

string

Only return tasks with the given description.

processInstanceId

string

Only return tasks which are part of the process instance with the given ID.

processInstanceIdWithChildren

string

Only return tasks which are part of the process instance and its children with the given ID.

processInstanceBusinessKey

string

Only return tasks which are part of the process instance with the given business key.

processInstanceBusinessKeyLike

string

Specify a string that has to match the processInstanceBusinessKey and that can contain % characters as placeholders for an arbitrary number of unknown characters.

processDefinitionId

string

Only return process instances with the given process definition ID.

processDefinitionKey

string

Only return process instances with the given process definition key.

processDefinitionKeyLike

string

Specify a string that has to match the processDefinitionKey and that can contain % characters as placeholders for an arbitrary number of unknown characters.

Only return tasks which are part of a process instance which has a process definition with a key matching the given value.

processDefinitionName

string

Only return tasks which are part of a process instance which has a process definition with the given name.

processDefinitionNameLike

string

Specify a string that has to match the processDefinitionName and that can contain % characters as placeholders for an arbitrary number of unknown characters.

Only return tasks which are part of a process instance which has a process definition with a name matching the given value.

Only return tasks which are part of the process instance which has a business key matching the given value.

createdAfter

string

Only return tasks which have been created after the given date.

createdBefore

string

Only return tasks which have been created before the given date.

createdOn

string

Only return tasks which have been created on the given date.

completedAfter

date-time

Only return tasks which are completed after the given date.

completedBefore

date-time

Only return tasks which are completed before the given date.

dueAfter

string

Only return tasks which are due after the given date.

dueBefore

string

Only return tasks which are due before the given date.

dueOn

string

Only return tasks which are due on the given date.

withoutDueDate

boolean

Only return tasks which do not have a due date. The property is ignored if the value is false.

scopeDefinitionId

string

Only return tasks with the given scopeDefinitionId.

scopeId

string

Only return tasks with the given scopeId.

scopeType

string

Only return tasks with the given scopeType.

owner

string

Only return tasks with the given owner id.

includeProcessVariables

boolean

Include process variables in the result.

isAssigned

boolean

As of 2023 Spring.

If isAssigned=true, the endpoint retrieves only tasks that are assigned to the currently logged-in user.

If isAssigend=false, the endpoint retrieves only tasks without an assignee for which the currently logged-in user is a candidate user.

If isAssigned is not specified in the request URL, the endpoint retrieves tasks that are assigned to the currently logged-in user as well as tasks without an assignee for which the currently logged-in user is a candidate user.

visibleTo

string

As of 2023 Autumn: Only return tasks visible to this user.

isCompleted

boolean

As of 2023 Autumn: If true, only completed tasks are returned. If false, only running tasks are returned. If not specified, both completed and running tasks are returned.

page

integer($int32)

Results page you want to retrieve (0…N). Default is 0 which means the first page.

size

integer($int32)

sort

string

Number of objects per page.

filter

string

(up to 2022 Winter) Allows to filter the result. By default, all tasks that are assigned to the current user, have been claimed by the current user or are waiting to be claimed by the current user (candidate user or groups) will be returned.

assignee

string

up to 2023 Summer

Response HTTP status codes:

HTTP status code Meaning

200

The request was successful and the tasks are returned.

401

The calling user is not authorized.

404

A parameter was passed in the wrong format. The status message contains additional information.

Request Example

https://<host>/bpm-engine/api/tasks?page=0&size=1

no request body

Response Example

200 OK

Response Body
{
  "objects": [
    {
      "id": "187",
      "name": "1st_task",
      "description": "In this case, you have to do several things as they are:\n1. subtask\n2. subtask",
      "assignee": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
      "owner": aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa5,
      "createTime": "2021-11-01T12:28:46.388Z",
      "endTime": "2023-12-02T13:39:57.499Z",
      "claimTime": "2021-11-01T13:29:47.389Z",
      "processDefinitionId": "twosteptest_proc:4:8dc694a2-10b1-11ec-99ef-027ea5eeae02",
      "processInstanceId": "00000000-0000-0000-0000-000000000000",
      "parentTaskId": null,
      "formKey": "twosteptest_proc:1st_task",
      "taskDefinitionKey": "sid-4CAF2A19-B303-46C6-A7C0-2F506F1613D4",
      "delegationState": "pending",
      "suspended": true,
      "variables": [
        {
          "name": "whatabout",
          "type": "string",
          "value": "testValue",
          "scope": "global"
        },
        {
          "name": "initiator",
          "type": "string",
          "value": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa5",
          "scope": "global"
        }
      ]
    }
  ],
  "numItems": 1,
  "totalNumItems": 1,
  "hasMoreItems": false
}
GET /bpm-engine/api/tasks/{taskId} - Retrieve a task by ID
As of Version

2021 Autumn

Request Method

GET

Response Format

JSON

Description

Retrieves the task specified by taskId.

Optional query parameters:

Parameter Type Description

includeProcessVariables

boolean

Indication to include process variables in the result. Default is false.

Response HTTP status codes:

HTTP status code Meaning

200

The task was found and returned.

401

The calling user is not authorized.

404

The requested task was not found.

Request Header

Content-Type: application/json

Request Example

https://<host>/bpm-engine/api/tasks/187

Response Example
{
   "id": "187",
   "name": "1st_task",
   "description": "In this case, you have to do several things as they are:\n1. subtask\n2. subtask",
   "assignee": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
   "owner": aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa5,
   "createTime": "2021-11-01T12:28:46.388Z",
   "claimTime": "2021-11-01T13:29:47.389Z",
   "processDefinitionId": "twosteptest_proc:4:8dc694a2-10b1-11ec-99ef-027ea5eeae02",
   "processInstanceId": "00000000-0000-0000-0000-000000000000",
   "parentTaskId": null,
   "formKey": "twosteptest_proc:1st_task",
   "taskDefinitionKey": "sid-4CAF2A19-B303-46C6-A7C0-2F506F1613D4",
   "delegationState": "pending",
   "suspended": true,
   "variables": [
     {
       "name": "whatabout",
       "type": "string",
       "value": "testValue",
       "scope": "global"
     },
     {
       "name": "initiator",
       "type": "string",
       "value": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa5",
       "scope": "global"
     }
   ]
}
POST /bpm-engine/api/tasks/{taskId} - Perform an action on a task
As of Version

2021 Autumn

Request Method

POST

Response Format

JSON

Description

Performs an action defined in the request body on the task specified by taskId.

In addition to the complete action and in contrast to the corresponding underlying Flowable task actions, the following actions allow to apply changes to variables as well:

  • delegate

  • resolve

    The specified values for the variables are updated even if the final resolving process fails.

Response HTTP status codes:

HTTP status code Meaning

200

The request was successful and the task is returned.

400

An invalid variable has been passed. Status description contains additional information about the error.

401

The calling user is not authorized.

404

The requested task was not found.

Request Header

Content-Type: application/json

Request Example

https://<host>/bpm-engine/api/tasks/8

Request Body
{
  "action": "claim",
  "assignee": "userWhoClaims",
  "variables": [
    {
      "name": "myVariable",
      "scope": "myScope",
      "type": "myType",
      "value": "test",
      "valueUrl": "http://...."
    }
  ]
}
Response Example
{
  "assignee": "userWhoClaims",
  "claimTime": "2018-04-17T10:17:43.902+0000",
  "createTime": "2013-04-17T10:17:43.902+0000",
  "description": "Task description",
  "formKey": "myKey",
  "id": 8,
  "name": "My task",
  "parentTaskId": "null",
  "processDefinitionId": 123,
  "processInstanceId": 123,
  "suspended": true,
  "variables": [
    {
      "name": "myVariable",
      "scope": "myScope",
      "type": "myType",
      "value": "test",
      "valueUrl": "http://...."
    }
  ]
}
GET /bpm-engine/api/tasks/{taskId}/candidates - Retrieve candidates
As of Version

2024 Spring

Request Method

GET

Response Format

JSON

Description

Retrieves the list of candidates for the task specified by taskId.

Response HTTP status codes:

HTTP status code Meaning

200

The task was found and the list of candidates returned.

401

The calling user is not authorized.

404

The requested task was not found.

Request Header

Content-Type: application/json

Request Example

https://<host>/bpm-engine/api/tasks/187/candidates

Response Example
{
  "users": [
    "string"
  ],
  "roles": [
    "string"
  ]
}
PUT /bpm-engine/api/tasks/{taskId}/candidates - Add candidates
As of Version

2024 Spring

Request Method

PUT

Response Format

JSON

Description

Extends the list of candidates for the task specified by taskId. The new candidates are specified in the JSON request body directly via their user ID or indirectly via roles.

Response HTTP status codes:

HTTP status code Meaning

204

The task was found and the list of candidates was updated.

401

The calling user is not authorized.

403

The user is not allowed to add candidates to the task.

404

The requested task was not found.

Request Header

Content-Type: application/json

Request Example

https://<host>/bpm-engine/api/tasks/187/candidates

Request body
{
  "users": [
    "string"
  ],
  "roles": [
    "string"
  ]
}
Response Example

204 OK

POST /bpm-engine/api/tasks/{taskId}/candidates - Replace candidates
As of Version

2024 Spring

Request Method

POST

Response Format

JSON

Description

Sets a list of users (specified by its IDs) and/or roles (specified by its names) as the candidates of a running task.

Current candidates of this task will be overwritten with the new ones, but users or roles will only be affected if you pass a value as the corresponding JSON object.

Example:

  • Only pass a user list but no roles list with the following input:

    {
        "users": [
            "cb6e5625-caef-4825-9eb3-6cd1310354e6"
        ]
    }
  • Only the user candidates will be overwritten. The role candidates won’t be affected at all.

If you pass an empty array, all candidates of this type will be removed.

Response HTTP status codes:

HTTP status code Meaning

204

The task was found and the list of candidates was updated.

401

The calling user is not authorized.

403

The user is not allowed to add candidates to the task.

404

The requested task was not found.

Request Header

Content-Type: application/json

Request Example

https://<host>/bpm-engine/api/tasks/187/candidates

Request body
{
  "users": [
    "string"
  ],
  "roles": [
    "string"
  ]
}
Response Example

204 OK

DELETE /bpm-engine/api/tasks/{taskId}/candidates - Delete candidates
As of Version

2024 Spring

Request Method

DELETE

Response Format

JSON

Description

Deletes a list of users (specified by its IDs) and/or roles (specified by its names) from the candidates of a running task.

Response HTTP status codes:

HTTP status code Meaning

204

The task was found and the corresponding candidates were deleted.

401

The calling user is not authorized.

403

The user is not allowed to add candidates to the task.

404

The requested task was not found.

Request Header

Content-Type: application/json

Request Example

https://<host>/bpm-engine/api/tasks/187/candidates

Request body
{
  "users": [
    "string"
  ],
  "roles": [
    "string"
  ]
}
Response Example

204 OK

POST /bpm-engine/api/tasks/{taskId}/comment - Create a comment
As of Version

2021 Autumn

Request Method

POST

Response Format

JSON

Description

Creates a comment with the message specified in the plain text request body for the task specified by taskId. It will be included in the process instance’s history.

Response HTTP status codes:

HTTP status code Meaning

201

The request was successful and the comment is returned.

400

The request body is missing.

404

The requested task was not found.

Request Header

Content-Type: text/plain

Request Example

https://<host>/bpm-engine/api/tasks/00000000-0000-0000-0000-000000000123

Request Body
Test comment number 2.
Response Example
{
  "id": "00000001-0001-0001-0001-000000000001",
  "author": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
  "message": "Test comment number 2.",
  "time": "2021-11-09T13:53:20.339Z",
  "processInstanceId": "00000000-0000-0000-0000-000000000000",
  "taskId": "00000000-0000-0000-0000-000000000123"
}

6.1.3. Modeling and Deployment of Process Definitions

The process definitions for BPM Engine are modeled locally via Flowable UI and deployed to the BPM Engine afterwards. For the deployment, the internal API of the BPM Engine itself has to be used. It can be made available for authorized users via configuration of the authentication service or via port forwarding.

Process Definition

The process modeling requires the local installation of Flowable UI. A detailed description of the installation and usage is provided in the Flowable documentation.

By means of the Flowable UI, create your process definitions and group them in an application.

As of version 2021 Winter, Flowable Http tasks can call internal yuuvis® Momentum endpoints. In order to add the yuuvis® Momentum authentication headers that are required for internal requests, set the placeholder Authorization: %%YuuvisSystemInternal%% for the Request header configuration parameter. If HTTP task is used to call external methods, this option should not be used. Other headers can be added as desired and required via the modeler.

Publish your application including your new versions of process definitions and export it in BAR or ZIP format.

The BAR format is the primary format for deployment that includes Flowable-specific pre-defined forms (not supported by a library-based client) that will be deployed in the BPM Engine. This may be of interest for custom clients that are using and supporting forms in Flowable format. Unfortunately, this format is a pure deployment format and cannot be imported back to Flowable modeler.

The ZIP format will be also accepted by BPM Engine, and can be reimported to a Flowable modeler as well. The Flowable-specific forms are included but will not be deployed by the Flowable BPM Engine.

Process Deployment

The exported application from the Flowable UI has to be imported to BPM Engine via its internal API. The corresponding endpoints can be configured in the file authentication-prod.yml to be accessible via Swagger UI for users with a specified administrative role. In productive systems, the internal API should not be accessible for yuuvis® Momentum users. Instead, you can use the internal REST interface of BMP Engine via port forwarding. Thus, the Swagger UI can be used only by Kubernetes administrators. Alternatively, you can also use a different tool of your preference, such as cURL.

Deployment via Swagger UI

In order to use the internal BPM Engine endpoints via Swagger UI, the following configuration is required to be added in the configuration file authentication-prod.yml under authorization.accesses. The access will be managed by the authentication service and has to be limited to users with a specified administrative role.

1
2
3
- endpoints: /bpm-engine/swagger-ui.html,/bpm-engine/swagger-ui/**,/bpm-engine/v2/api-docs/**,/bpm-engine/v3/api-docs/**
- endpoints: /bpm-engine/internal/**
  access: hasAuthority('<role>')

If the configuration is applied and the logged-in user is authorized, the Swagger UI is available via the URL https://<host>/bpm-engine/swagger-ui.hmtl.

  • Select the Internal Flowable App REST API from the dropdown menu in the top bar.

  • In the App Deployments section, click the POST /app-repository/deployments endpoint.

  • Click Try it out.

  • Type the ID of the tenant to which you want to deploy the new process definitions.

  • Select the exported Flowable application from your file system.

  • Execute the API call.

It is also possible to use the internal REST interface of the BPM Engine for the deployment of new process definitions without enabling user web access. Since those endpoints are accessible only for services within the yuuvis® Momentum cluster, port forwarding is required for the access to the Kubernetes pod for the bpm-engine service.

Deployment via cURL

If Swagger is not activated in a system, process definitions can be deployed by other means, such as for instance cURL. The same access configuration rules apply as described before. In the following steps, replace the <*> terms by your specific values.

  • Create a deployment. The following command deploys the exported Flowable application to the BPM Engine instance.

    curl -u <username>:<password> -F 'upload=@\"<PATH TO THE APPLICATION .zip OR .bar FILE>"' -X POST "https://<HOSTNAME>/bpm-engine/internal/process-api/repository/deployments?tenantId=<tenantId WHERE THE APPLICATION IS TO BE DEPLOYED>" -H "accept: application/json" -H "Content-Type: multipart/form-data" -H "X-ID-TENANT-NAME: <tenantId WHERE THE APPLICATION IS TO BE DEPLOYED>"
  • Retrieve the deployments in order to check whether the deployment was successful.

    curl -u <username>:<password> -X GET "https://<HOSTNAME>/bpm-engine/internal/process-api/repository/deployments?tenantId=<tenantID WHERE APPLICATION WAS DEPLOYED>" -H "accept: application/json" -H "X-ID-TENANT-NAME: <tenantID WHERE APPLICATION WAS DEPLOYED>"
  • List the deployed process definitions. The command retrieves a list of your available process definitions.

    curl -X GET "https://<HOSTNAME>/bpm-engine/internal/process-api/repository/process-definitions?tenantId=<tenantID WHERE APPLICATION WAS DEPLOYED>" -H "accept: application/json" -H "X-ID-TENANT-NAME: <tenantID WHERE APPLICATION WAS DEPLOYED>"
  • From the retrieved list of process definitions, choose one process definition you want to use to instantiate a process. For the process creation, you can specify the process definition by its ID. Note that if you specify the ID of an older version of a process definition, this old version will be used for the instantiation of your process.

    Alternatively, you can refer to a process definition by specifying its processDefinitionKey as shown in the command below. In this case, the current version of process definition will always be used for the process instantiation.

    curl -u <username>:<password> -X POST "https://<HOSTNAME>/bpm-engine/internal/process-api/runtime/process-instances" -H "accept: application/json" -H "Content-Type: application/json" -d "\{ \"businessKey\": \"myBusinessKey\", \"name\": \"myProcessInstanceName\", \"processDefinitionKey\": \"<PROCESS DEF KEY TO BE STARTED>\", \"returnVariables\": true, \"tenantId\": \"<tenantID WHERE APPLICATION WAS DEPLOYED>\"}" -H "X-ID-TENANT-NAME: <tenantID WHERE APPLICATION WAS DEPLOYED>"
Custom Functionality Extension

As of version 2022 Winter, it is possible to add custom functionality to process definitions that is not supported by Flowable, e.g., notifying a logger. The custom extension is integrated as delegation in service tasks or event listeners.

As of 2023 Winter, scripts can be written in Groovy or JavaScript as well.

Dependency

Create a new project. Inject the flowable-engine dependency.

<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-engine</artifactId>
<version>6.8.2</version>
<scope>provided</scope>
</dependency>
Java Implementation

The class with your custom extension has to implement the JavaDelegate Flowable interface as shown in the example below.

package my.company;

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;

import java.util.logging.Logger;

public class LoggerDelegate implements JavaDelegate {

    private static final Logger log = Logger.getLogger(LoggerDelegate.class.getName());

    public void execute(DelegateExecution execution) {
        log.info("\n\n  ... LoggerDelegate invoked by "
          + "processInstanceId=" + execution.getProcessInstanceId()
          + ", processInstanceBusinessKey=" + execution.getProcessInstanceBusinessKey()
          + ", processDefinitionId=" + execution.getProcessDefinitionId()
          + ", activityId=" + execution.getCurrentActivityId()
          + ", flowElementId='" + execution.getCurrentFlowElement().getId() + "'"
          + ", flowElementName='" + execution.getCurrentFlowElement().getName() + "'"
          + ", executionId=" + execution.getId()
          + " \n\n");
    }
}
Extension of 'bpm-engine' Image

Compile your project and copy the JAR into the /yuuvis/libs bpm-engine library folder.

You can use your custom Java class in your process definitions now.

6.1.4. Handling of Process Instances and Tasks

A process can be instantiated based on a process definition that refers to a process model created via Flowable Modeler UI and deployed to the BPM-ENGINE service. Especially, the concrete tasks included in the process instance are determined by the process model referenced via the process definition. See the Flowable Documentation.

The follow-up process model is included as an example in our installations. It is supported by yuuvis® Momentum client as reference implementation and is also compatible with our developer libraries.

Creating Process Instances

Processes instances are created by starting a process based on a specified process definition. All deployed and thus available process definitions can be retrieved via the GET /bpm-engine/api/process-definitions endpoint. Reference one of the listed process definition objects for your concrete process instance creation by its key. Use the value for the processDefinitionKey in the request body for POST /bpm-engine/api/processes.

The (first) task included in the process instance is now available for the assignee (if already pre-defined) or all referenced candidate users.

Retrieving Process Instances

Users can only retrieve process instances that they have started themselves.

There are two endpoints available:

  • GET /bpm-engine/api/processes - Retrieves a list of processes of the currently active user that are matching the conditions defined in various query parameters.

  • GET /bpm-engine/api/processes/{processInstanceId} - Retrieves the process instance specified by processInstanceId.

Working on Tasks
Retrieving Tasks

Users can only retrieve tasks that are assigned to them or for which they are a candidate user.

There are two endpoints available:

  • GET /bpm-engine/api/tasks - Retrieves a list of tasks of the currently active user that are matching the conditions defined in various query parameters.

  • GET /bpm-engine/api/tasks/{taskId} - Retrieves the task specified by taskId.

Responsibilities
  • Assignee

    • Only the assignee of a task can take an action on it. An exception is the complete action as described below.

  • Candidate Users

    • In order to specify multiple users that should be able to take an action on a specific task, those users can be set as so-called candidate users. It is possible to assign candidate groups as well by specifying a role. Each user with this role will be a candidate user for the corresponding task.

    • All candidate users are allowed to claim the task and thereby assign it to themselves. As soon as the task is assigned to one of them, it will no longer be available for all other candidate users until the assignee returns it to them. All candidate users are allowed to complete the task without assigning it to themselves when no assignee is specified.

  • Owner

    • When the first assignee delegates the task to another user, the first assignee becomes the owner. The owner is not overwritten if further delegations are applied to the task. Whenever a subsequent assignee resolves the task, the owner will be set as assignee again. Thus, the owner is responsible for the task completion.

Users can take an action on a task specified by its ID via the POST /bpm-engine/api/tasks/{taskId} endpoint. In the request body, the type of action is set as value for the action property. The following actions are available for the user(s) with the corresponding responsibility.

Value for 'action' Responsibility Effect on the Task

complete

assignee, candidate users

  • The values for the task variables specified in the request body are updated.

  • The updated task will be a historic task. No further action can be taken on it.

claim

if assignee is null: candidate users

  • The first candidate user who claims the task becomes the assignee.

if assignee is not null: assignee

  • The assignee can return the task to all candidate users by setting the assignee property back to null.

delegate

assignee

  • The user specified in the request body replaces the previous assignee. The original assignee is set as owner of the task.

  • The task property delegationState is updated.

resolve

assignee (if appointed via delegation)

  • The previous assignee who called the delegation will again be assignee.

  • The task property delegationState is updated.

Each action that is applied to a task triggers the creation of a new identity link referring to the acting user in the individual task’s history, e.g.:

{
     "type": "assignee",
     "userId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
     "groupId": null,
     "timestamp": "2021-11-01T12:28:46.447Z"
}
Comments

In order to add messages to a task, comments can be created and assigned via the POST /bpm-engine/api/tasks/{taskId}/comment endpoint. They will be included in the process history in a separate section. The following code block shows an example comment visualising the corresponding stored data set.

{
     "id": "00000001-0001-0001-0001-000000000001",
     "author": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
     "message": "This is the first example comment for the first task.",
     "time": "2021-11-02T13:05:29.099Z",
     "processInstanceId": "00000000-0000-0000-0000-000000000000",
     "taskId": "00000000-0000-0000-0000-000000000123"
}
Process Instance History

The process history is available for active tasks as well as for completed tasks. It can be retrieved via the GET /bpm-engine/api/processes/{processInstanceId}/history endpoint.

The response body is a JSON structure containing the following properties.

Parameter Description

tasks

List of data sets, one for each task within the process. Each data set contains the following parameters:

id

ID of the task instance.

name

Task name.

description

Task description.

assignee

User ID of the current assignee. If the task is currently not assigned to a user, the value is null.

owner

User ID of the owner.

createTime

Date and time of task creation.

claimTime

Date and time of last claim action on the task. If the task has not been claimed so far, the value is null.

endTime

Date and time of task completion (action complete). If the task has not been claimed so far, the value is null.

identityLinks

List of identity links stored for the corresponding task.

type

Type of identity link, e.g., candidate.

userId

ID of the user to which the identity link refers. If multiple users are involved, the value is null.

groupId

Role that defines the group of users to which the identity link refers. If only one user is involved, the value is null.

timestamp

Date and time of identity link creation.

comments

List of data sets, one for each comment that has been assigned to the process.

id

ID of the comment.

author

User ID of the user who assigned the comment to the process.

message

Comment message.

time

Date and time of the comment’s assignment.

processInstanceId

ID of the process instance containing the task to which the comment was assigned.

taskId

ID of the task instance to which the comment was assigned.

6.1.5. Configuration

Database Connection of 'bpm-engine'

The bpm-engine service users the database connection that is configured via environment variables as described in the installation guide.

Setting up Identity Management for 'bpm-engine'

The BPM-ENGINE service is based on the workflow functionality of the open source software Flowable. The service is connected to Keycloak in order to obtain information on users and their roles present in the tenant. The Business Process Management can be used only if yuuvis® Momentum uses Keycloak as identity provider and role management system.

Flowable and Keycloak

If Keycloak is used as identity provider and role management system, users are registered as members of realms (corresponding to yuuvis® Momentum tenants) with defined roles assigned to them. Furthermore, users can be assigned to groups which can build a hierarchical structure.

The Keycloak realms and users are directly mapped to tenants and users in Flowable and thus in the BPM-ENGINE. The Keycloak groups are not mapped to Flowable. Keycloak supports the hierarchical group structure that is unique for every tenant. Hierarchical group structures are not supported in Flowable and in addition, since the group structure is unique for every tenant, it would not be possible to develop a model that is valid in multiple tenants and that assigns a user task to a specific group (such as "bookkeepers"). To resolve both of these integration issues, we map the users' Keycloak roles to Flowable groups. Since roles form a flat structure and can be assigned to users from different tenants, they correspond to the groups of users as defined in Flowable.

Once correctly configured, the Groups and Users interface in Flowable REST will provide information on users and groups within the BPM-ENGINE. However, it is not possible to edit users or groups via the BPM-ENGINE service. This has to be done in Keycloak.

Configuration for 'bpm-engine' Service

Following service configuration parameters are available.

Parameter Description Default Value

bpm.engine

Section of parameters defining BPM-internal settings.

app

Section of parameters related to the BPM-ENGINE service.

global-tenant

Specifies the master Flowable tenant which has access to all other tenants.

As of version 2021 Autumn: If access to all tenants should be enabled also via bpm-admin-ui service, the same tenant has to be set for the parameter bpm.admin.app.default-user-authentication.user.tenant.

'master'

admin-access-role

Specifies the role granting the permission to access all tenants.

Users with the specified role furthermore have admin rights for processes and are thus able to manage all processes (not only their own ones, as it is the case for "normal" users).

As of version 2021 Autumn: If access to all tenants should be enabled also via bpm-admin-ui service, the same role has to be included in the list defined for the parameter bpm.admin.app.default-user-authentication.user.privileges.

'YUUVIS_TENANT_ADMIN'

idm

Section of parameters for the connection of an identity provider.

keycloak

Section of parameters only required if Keycloak is used as identity provider.

enabled

Boolean value that specifies if BPM Engine connects to Keycloak/keycloak-proxy service (true) or to a different identity provider (false).

If true, the parameter bpm.engine.idm.custom.enabled must be false.

true

server

URL of the Keycloak server that should be used for authentication.

admin

Section of parameters specifying the access credentials for the technical user account used by the bpm-engine service in order to authenticate in Keycloak.

n/a

username

Username for technical user account.

password

Password for technical user account.

custom

Section of parameters only required if Keycloak is not used as identity provider.

enabled

Boolean value that specifies if BPM Engine connects to Keycloak/keycloak-proxy service (false) or to a different identity provider (true).

If true, the parameter bpm.engine.idm.keycloak.enabled must be false.

false

base-url

URL to the identity provider or to the idm-controller of the tenant-management service.

'http://tenant-management/api/idm'

Up to version 2022 Summer, BPM Engine has to be configured as follows. Especially, the conversion of the Keycloak roles into Flowable groups can be customized via the keycloak.idm.groups.role-filter parameter.

Parameter Description Default Value

keycloak

Section of parameters defining the connection of the bpm-engine service to Keycloak.

server

URL of the Keycloak server that should be used for authentication.

"http://localhost:8000/auth"

admin

Section of parameters specifying the access credentials for the technical user account used by the bpm-engine service in order to authenticate in Keycloak.

n/a

username

username for technical user account

password

password for technical user account

idm

Section of parameters defining conversion configurations for the connection between Keycloak and the bpm-engine service.

groups

Section of parameters dealing with the conversion of Keycloak roles into BPM-ENGINE groups.

-

role-filter

Contains a regular expression that filters the roles from Keycloak such that only those Keycloak roles that match the condition are visible to the bpm-engine service.

Example: With the filter ^(YUUVIS)(.*) only roles with names starting with YUUVIS will be visible to the bpm-engine service.

"^(.+)"

6.2. BPM Admin UI

The BPM-ADMIN-UI service is a frontend application enabling the management of models, processes, tasks, and jobs via an administrative graphical user interface.

This service is not yet included in yuuvis® Momentum installations but is available only on request. Alternatively, you can use the Flowable REST API in order to directly call the endpoints of the BPM-ENGINE service.

6.2.1. Configuration

Once logged in to the BMP Admin UI, users have the permission to manage all models and processes of all tenants. Therefore, the protection against unauthorized access has to be ensured. Per default, this security is achieved by granting access only within the Kubernetes cluster of yuuvis® Momentum. Users can access the system only from their local workstations via Kubernetes port forwarding within the Kubernetes cluster. However, the BPM Admin UI can be configured such that authentication is possible via other authentication gateways with appropriate access credentials.

Parameters

The parameters for the connection between BPM-ENGINE service and BPM-ADMIN-UI service are listed in the section bpm.admin.app.default-user-authentication of the configuration profile.

Parameter Description Default Value

enabled

Boolean value that activates or deactivates the default authentication for the bpm-admin-ui service.

true

user

Section of parameters defining the access credentials and permissions of the technical user account used for the default authentication.

id

Defines the id of the default user that will be written to appropriate logs. It does not have to exist in Keycloak since no subsequent authorization is performed.

"sysadmin"

tenant

Defines the Flowable tenant that can be accessed by the bpm-admin-ui service. By default it is set to the master tenant which has access to all tenants.

If access to all tenants is needed, this parameter should be the same as the configuration parameter user.tenant bpm.engine.app.global-tenant for the bpm-engine service.

'master'

privileges

The roles that will be used to identify the bpm-engine technical user to access the bpm-engine. The list shall match the roles defined in bpm.engine.app.admin-access-role of the bpm-engine service. In addition to this required list entry, further groups can be added.

['YUUVIS_SYSTEM_INTEGRATOR', 'YUUVIS_TENANT_ADMIN', 'YUUVIS_DEFAULT']

as of 2021 Winter: ['YUUVIS_SYSTEM_INTEGRATOR']

Setting Options via User Interface

After accessing the BPM Admin as the graphical user interface provided by the bpm-admin-ui service, the URL of the BPM Engine can be changed. This might be necessary if deployment has multiple BPM Engine instances within the same cluster. However, in most cases this is not needed since by default there is one instance of BPM Engine and the BPM Admin will connect to it by default. Only process-engine is supported at the moment, since it is deployed with yuuvis® Momentum by default. Other engines cannot be managed and a toast error will occur.

When searching and managing the processes, the BPM Admin user may use a filter for tenant ids to improve the search results. Only requests affecting the specified tenant will be available. The filter must be set if the parameter bpm.admin.app.default-user-authentication.user.tenant specifies a single tenant not having access to other tenants. By default, both BPM Engine and BPM Admin services are configured such that administration of all tenants is possible.

7. SAP® Integration

Combine yuuvis® Momentum with SAP.

There are separate services for the different SAP® interfaces:

  • The basic integration functionality is provided by the repositorymanager service.

  • The repositorymanager-cmis service (or rmcmis spring application) can be used to connect to SAP® via CMIS interface.

  • The repositorymanager-ilm service (or rmilm spring application) can be used to connect to SAP® via ILM controller.

7.1. Concept

The repositorymanager service establishes the connection between SAP® and the yuuvis® Momentum system and organizes and manages storage and retrieval of documents in both yuuvis® Momentum and SAP.

The SAP® object types are mapped to yuuvis® Momentum object types that are defined in the repositorymanager app schema. The access to yuuvis® Momentum is managed via a technical user account that has full access to objects of types defined in the repositorymanager app schema.

Each tenant can have a single ILM repository and several ArchiveLink repositories (if needed), since ArchiveLink model includes the ContentRepository field.

7.1.1. Inserting a Document in yuuvis® Momentum by Barcode Upload

The Document and its Data

If a document is inserted into the yuuvis® Momentum system, the corresponding document will be given a barcode and an ArchiveLink version (AL version) is created. The barcode is specified during the capture process (e.g., a barcode label is applied to a document).

The barcode links the document with a business process until the SAP® system has linked an SAP® business object to the document ID.

At this point it is not yet allowed to set the 'Barcode sent to R3' document flag. All other index data of the document and components need to be already filled in, in particular the unique DocID.

In regular intervals, yuuvis® Momentum REPOSITORYMANAGER determines all documents that have a barcode and no BarcodesenttoR3 flag. For these documents, an entry will be inserted in the barcode file, which is written in the configured Work/Barcode directory.

Reporting the Document to the SAP® System

By calling the WriteBarcodeFile function, the REPOSITORYMANAGER service determines in cyclic intervals all barcodes and document IDs that have not yet been reported to the SAP® system. The corresponding values of the documents to be reported are written to a file in the Work\Barcode directory by the REPOSITORYMANAGER service. This file’s content may look as follows:

<Barcode1> FI <Document-ID1> 20090623 FAX
<Barcode2> FI <Document-ID2> 20090623 FAX
<Barcode3> FI <Document-ID3> 20090623 FAX

Barcode values cannot contain any spaces because they are used as separators here.

The BarcodesenttoR3 field’s value is set to true to flag the processed documents. This field will be created in the REPOSITORYMANAGER service when reporting the barcode to the SAP® system.

This ensures that unsuccessfully processed documents are NOT processed again and again to avoid system overload.

The processing results are documented in KGS-success and KGS-error-file as usual. In case of error, manual correction is required.

To simplify error tracking and handling, it is possible to extend the schema by adding an optional barcodeProcessingError field.

Referencing a Document in the SAP® System

When the barcode is reported to SAP, the document ID and the barcode are entered in the SAP® table BDS_BAR_EX for open external barcodes. This table includes all externally captured documents that own a barcode and are therefore identified by a document ID, but could not have been internally assigned to an SAP® object and a business process respectively in the SAP® system.

Barcode files are exchanged in the <WorkingDirectory> in the barcode subdirectory. If the exchange file was processed correctly by the content server, the barcodes are entered in the <WorkingDirectory>\barcode\successful\yyyymmdd.txt file. If barcodes were not processed correctly, they are entered in the <WorkingDirectory>\barcode\error\yyyymmdd.txt file.

A maximum of 5,000 barcodes can be reported in a reporting interval.

Linking a Document to an SAP® Object

In the SAP® system, a business process (SAP® object) can be assigned to a document. For example, the booking of a payment transaction. During this process, the barcode of a business transaction will be filed together with the SAP® object ID in the SAP® table BDS_BAR_IN of open internal barcodes.

The document ID is referenced with the barcode in the SAP® table for the open external barcodes and the barcode is referenced with an SAP® object ID in the table for the open internal barcodes. Thus, the SAP® object ID and the document ID can be linked. This is done automatically. The SAP® object ID and document ID are added to the SAP® link table TOAXX taking into account the repository. This completes the linking of a yuuvis® Momentum document to an SAP® process. After linking, the barcode is no longer known to the SAP® system and can only be searched in the yuuvis® Momentum system.

Data Flow Diagram

The following diagram depicts the data flow of when a document is given to the SAP® system.

Data Flow Diagram

7.1.2. Archiving of Data from the SAP® System

Receipts (documents), print lists, and reorg data (data backups) may be stored. In this case, the document ID is transferred to the yuuvis® Momentum system. Barcodes are not transferred here.

If an ILM-Object contains a link to an ArchiveLink object, the REPOSITORYMANAGER service ensures the following:

  • If a legal hold or a retention date is specified for the ILM-object, these metadata are propagated to the linked ArchiveLink object itself.

  • Same behavior in case of lifting the legal hold.

An ArchiveLink object with a legal hold and/or with a retention date lying in the future are prevented from being deleted by ArchiveLink directly.

7.2. Basic 'repositorymanager' Service

7.2.1. Installation

Deployment

The repositorymanager service is delivered as docker container image.

As of 2022 Summer, the installation via Helm chart is possible as well.

For the deployment to the yuuvis® Momentum cluster, you need a deployment and a service script as shown in the example code blocks below. The parameters have to be adjusted according to your own cluster. However, please use the /working-dir path for the PersistentVolumeClaim.

Example 'rm_service.yml'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Service
metadata:
  namespace: $NAMESPACE
  labels:
    app: yuuvis
    name: repositorymanager
    yuuvis: "true"
  name: repositorymanager
spec:
  ports:
    - name: "http"
      port: 80
      targetPort: 8010
  type: ClusterIP
  selector:
    name: repositorymanager
Example 'rm_deployment.yml'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-repositorymanager
  namespace: $NAMESPACE
spec:
  storageClassName: local-path
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: $NAMESPACE
  labels:
    app: yuuvis
    name: repositorymanager
  name: repositorymanager
spec:
  replicas: 1
  selector:
    matchLabels:
      name: repositorymanager
  template:
    metadata:
      labels:
        name: repositorymanager
    spec:
      containers:
        - name: repositorymanager
          image: docker.optimal-systems.org/team-kookaburra/$CI_PROJECT_NAME:commit-$CI_COMMIT_SHORT_SHA
          imagePullPolicy: Always
          env:
            - name: JAVA_OPTS
              value: -Xmx128m
            - name: SPRING_CLOUD_CONFIG_URI
              value: "http://configservice/config"
            - name: SPRING_PROFILES_ACTIVE
              value: prod,docker,kubernetes
          ports:
            - containerPort: 8010
          volumeMounts:
            - name: storage
              mountPath: /working-dir
      volumes:
        - name: storage
          persistentVolumeClaim:
            claimName: data-repositorymanager
      restartPolicy: Always
      imagePullSecrets:
        - name: osgitlab
Configuring the Kubernetes Cluster

The repositorymanager service has to be accessible for the SAP® system which is running outside the yuuvis® Momentum Kubernetes cluster. We recommend the usage of a loadbalancer of your cloud provider or the implementation of an Ingress controller. Alternatively, you could open the corresponding node port for the connection to the SAP® system.

The following two sections provide an example configuration for both, the access via Ingress and via Node Port.

If your tests fail due to problems with the ILM protocol, please disable CORS

  • by configuring nginx.ingress.kubernetes.io/enable-cors: "false" in case you use Ingress controller or

  • in the loadbalancer of your cloud provider.

Access via NGINX Ingress Controller

The following steps result in a configuration where the REPOSITORY-MANAGER service is accessible via NGINX Ingress controller from outside the Kubernetes cluster.

  • Add the Helm repositories for the NGINX Ingress controller and for a certificate manager for automated TLS certificate management:

    helm repo add nginx-stable https://helm.nginx.com/stable
    helm repo add jetstack https://charts.jetstack.io
    helm repo update
  • Install the certificate manager and the Ingress:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    helm install \
      cert-manager jetstack/cert-manager \
      --namespace cert-manager \
      --create-namespace \
      --version v1.8.0 \
      --set installCRDs=true
    
    helm install nginx-ingress nginx-stable/nginx-ingress --set rbac.create=true
    
    # Validate that nginx is running
    kubectl get pods --all-namespaces -l app=nginx-ingress-nginx-ingress
  • Add the following ingress-repositorymanager.yaml file to the templates folder of the repositorymanager Helm chart. Adjust the values according to your installation.

    Example 'ingress-repositorymanager.yaml' configuration
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: repositorymanager.yourdns.net # Change value
    spec:
      secretName: repositorymanager-yourdns-net-cert # Change value
      dnsNames:
        - repositorymanager.yourdns.net # Change value
      issuerRef:
        group: cert-manager.io
        name: letsencrypt-prod
        kind: ClusterIssuer
    ---
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        cert-manager.io/cluster-issuer: letsencrypt-prod
        ingress.kubernetes.io/ssl-redirect: "true"
        meta.helm.sh/release-name: repositorymanager
        meta.helm.sh/release-namespace: repositorymanagerwinter # Change value
        nginx.ingress.kubernetes.io/enable-cors: "false"
        nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
        nginx.ingress.kubernetes.io/rewrite-target: /
      name: repositorymanager-ingress
    spec:
      rules:
        - host: repositorymanager.yourdns.net # Change value
          http:
            paths:
              - backend:
                  service:
                    name: repositorymanager
                    port:
                      number: 80
                path: /
                pathType: ImplementationSpecific
      tls:
      - hosts:
          - repositorymanager.yourdns.net # Change value
        secretName: repositorymanager-yourdns-net-cert # Change value

If you want to operate multiple instances of repositorymanager service, they have to run in separate namespaces each of them with an own Ingress controller.

Access via Node Port

The following steps result in a configuration where the repositorymanager service is exposed via Node Port to be accessible from outside the Kubernetes cluster.

Expose the repositorymanager service via a Kubernetes Node port to the local network. In the example configuration shown in the code block below, the repositorymanager service will be accessible in the local network by the IP address CLUSTER_IP:30036.

Example Kubernetes cluster configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
kind: Service
apiVersion: v1
metadata:
 name: repositorymanager
 namespace: yuuvis
   app: yuuvis
   name: repositorymanager
   yuuvis: 'true'
spec:
 ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 8010
    nodePort: 30036 # This should be unique value in range 30000-32767
 selector:
   name: repositorymanager
 type: NodePort
Configuring the Cluster Firewall

The REPOSITORYMANAGER service, more precisely the barcode functionality, needs access directly from the pod where it is connected to the SAP® system. For this reason, a firewall entry needs to be added on cluster level to allow communication to the SAP® system.

Provide the IP:port info of the SAP® system that will have an RFC connection for the barcode functionality to work properly to the cluster administrator. The configurations have to be carried out on the KGS Administration Page that can be accessed via the following address: http://<host>/repositorymanager/cs/

The default port is 8010, the user name is admin, and the password is admin.

After logging in, you can change the login credentials via OSGi > Configuration > Application Framework Management Console:

Cluster Firewall Configuration
Adjusting the Service Configuration

In case of a standard installation, the service configuration parameters are specified in the corresponding application.yml file and are set to reasonable defaults. Those default values can be overwritten by specifying different values in the repositorymanager-prod.yml configuration file. Especially, the parameters configuring the ActiveMQ connection have to be adjusted:

  • spring.activemq.broker-url

  • spring.activemq.user

  • spring.activemq.password

KGS/CS-Admins should limit the free access to SAP® systems to ensure that only relevant SAP® systems can store data for a certain tenant.

Parameters of the repositorymanager-prod.yml configuration file:

Property Type Description Example value Default value

repository-manager.barcode.default-docType

String

Default SAP® document type that is used if there is no barcode mapping for the yuuvis® Momentum content type (see repository-manager.barcode.cntType2docType).

TIF

TIF

repository-manager.barcode.cntType2docType

String

List of entries for mapping the barcode document type, separated by pipe characters. Entries consist of: yuuvis® Momentum content type, equals sign, SAP® document type.

For each yuuvis® Momentum content type missing in the mapping list, the SAP® document type repository-manager.barcode.cntType2docType is used.

Image/TIFF=FAX|application/pdf=PDF

Image/TIFF=FAX|application/pdf=PDF

core.api.url

String

Public URL of the yuuvis® Momentum authentication service.

http://<yourserver>:<port>

http://127.0.0.1:7301/

core.api.username

String

Username of the technical user for the REPOSITORYMANAGER service’s access to yuuvis® Momentum.

The technical user requires full access rights to the objects.

sap

root

core.api.password

String

Password of the technical user for the REPOSITORYMANAGER service’s access to yuuvis® Momentum.

optimal1

optimal

core.api.tenant

String

Tenant of the technical user for the REPOSITORYMANAGER service’s access to yuuvis® Momentum.

default

default

spring.activemq.broker-url

String

IP address and port used by ActiveMQ.

tcp://<yourserver>:<port>

tcp://127.0.0.1:61616

spring.activemq.user

String

User name for ActiveMQ access.

admin

admin

spring.activemq.password

String

Password for ActiveMQ access.

admin

admin

The following code block shows an example configuration.

Example 'repositorymanager-prod.yml' configuration file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
repository-manager:
  barcode:
    cntType2docType: Image/TIFF=FAX|application/pdf=PDF
    default-docType: TIF

core:
  api:
    url: https://client.con.yuuvis.org
    username: root
    password: optimal
    tenant: default

spring:
  activemq:
    broker-url: tcp://repositorymanager-mq:61616
    user: admin
    password: admin
Multiple Instances of the 'repositorymanager' Service

If you use an Ingress controller, just create additional instances in separate namespaces with an own Ingress controller for each of them.

The following example deployment process is intended to explain the usage of multiple REPOSITORYMANAGER service instances exposed via Node port.

To achieve multi-tenancy, an independent instance of the REPOSITORYMANAGER service needs to be deployed for each individual tenant. The same service artifact can be used. In general, the following principles apply:

  • Each instance should have its own ActiveMQ pod, distributed as separate image.

  • Each pair of REPOSITORYMANAGER service and ActiveMQ instances should be deployed into its own namespace, have its own ports and profile configuration (default is prod).

  • Each pair of REPOSITORYMANAGER service and ActiveMQ must have its own tenant.

Namespaces, service ports and profiles should be specified in the deployment script. The following sections describe the required configuration steps. All scripts are applied via the command:

kubectl apply - f <filename>
Preparation

Decide on the namespace, and node ports to be used (one port for the REPOSITORYMANAGER service and two ports for the repositorymanager-mq service) as well as the profile in which the application will run (this determines the naming of the configuration file). For this example, the namespace will be repositorymanager-1, the ports are 30000 for the REPOSITORYMANAGER service, 30001 and 30002 for the ActiveMQ and the profile will be instance1. The cluster should use the repositorymanager app schema. The tenant to be used by the REPOSITORYMANAGER service should be created and configured to use it as described above for the configuration of a single instance.

Namespace

Create the namespace using the following YML script:

namespace script
1
2
3
4
apiVersion: v1
kind: Namespace
metadata:
  name: repositorymanager-1 # This is an example value that has to be replaced by the name of your namespace you want to use for the additional repositorymanager service instance.
ActiveMQ Service

Deploy the repositorymanager-mq pod for ActiveMQ using the following two YML scripts:

MQ deployment script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: repositorymanager-1 # Change value to the namespace specified in the namespace script before.
  name: repositorymanager-mq
  labels:
    app: yuuvis
    name: repositorymanager-mq
spec:
  replicas: 1
  selector:
    matchLabels:
      name: repositorymanager-mq
  template:
    metadata:
      labels:
        name: repositorymanager-mq
    spec:
      containers:
        - image: docker.yuuvis.org/<image> # Change value
          name: repositorymanager-mq
          imagePullPolicy: Always
      restartPolicy: Always
      imagePullSecrets:
        - name: changeme # Change value
This is an example script which requires the a specific secret to be present in the same namespace. Different clusters might require some changes.
MQ service script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: Service
metadata:
  namespace: repositorymanager-1
  name: repositorymanager-mq
  labels:
    app: yuuvis
    name: repositorymanager-mq
spec:
  selector:
    name: repositorymanager-mq
  ports:
    - name: dashboard
      port: 8161
      nodePort: 30001
    - name: openwire
      port: 61616
      nodePort: 30002
  type: NodePort
The ActiveMQ service exposes two ports, one to access the web admin page, internally on port 8161 and externally on 30001, the other to access the ActiveMQ itself, internally on port 61616 and externally on 30002.
Deployment of 'repositorymanager' Service

Deploy the repositorymanager service using the following two YML scripts:

Service deployment script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-repositorymanager
  namespace: repositorymanager-1
spec:
  storageClassName: local-path
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: repositorymanager-1
  labels:
    app: yuuvis
    name: repositorymanager
  name: repositorymanager
spec:
  replicas: 1
  selector:
    matchLabels:
      name: repositorymanager
  template:
    metadata:
      labels:
        name: repositorymanager
    spec:
      containers:
        - name: repositorymanager
          image: docker.optimal-systems.org/team-kookaburra/repositorymanager-momentum:commit-2d346b0e
          imagePullPolicy: Always
          env:
            - name: JAVA_OPTS
              value: -Xmx128m
            - name: SPRING_CLOUD_CONFIG_URI
              value: "http://configservice.yuuvis/config"
            - name: SPRING_PROFILES_ACTIVE
              value: instance1,docker,kubernetes
          ports:
            - containerPort: 8010
          volumeMounts:
            - name: storage
              mountPath: /working-dir
      volumes:
        - name: storage
          persistentVolumeClaim:
            claimName: data-repositorymanager
      restartPolicy: Always
      imagePullSecrets:
        - name: osgitlab
This script uses the image from OS GitLab which requires the osgitlab secret to be present in the same namespace. Different clusters might require some changes. Additionally, the environment parameter SPRING_CLOUD_CONFIG_URI should point to the configservice of the specific cluster. The SPRING_PROFILES_ACTIVE environment variable should contain the docker and kubernetes profiles as well as the service profile dedicated to that instance, in this case instance1.
service script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: Service
metadata:
  namespace: repositorymanager-1
  labels:
    app: yuuvis
    name: repositorymanager
    yuuvis: "true"
  name: repositorymanager
spec:
  ports:
    - name: "http"
      port: 80
      targetPort: 8010
      nodePort: 30000
  type: NodePort
  selector:
    name: repositorymanager
The REPOSITORYMANAGER service exposes one port to allow internal access via port 8010 and external access via port 30000.
Configuration via 'configservice'

Use the configservice of the cluster to create the repositorymanager-instance1.yml file. This file contains the configuration for the service instance running with the profile instance1.

The following code block shows an example for the configuration:

repositorymanager-instance1.yml
1
2
3
4
5
6
7
8
9
10
core:
  api:
    url: http://client.yuuvis
    username: root
    password: optimal
    tenant: instance1tenant

spring:
  activemq:
    broker-url: tcp://repositorymanager-mq:61616

The tenant name as well as credentials to access the yuuvis® Momentum system are provided as well as the URLs to access the system and ActiveMQ.

Once the configuration is created, the REPOSITORYMANAGER service should be restarted to apply the changes.

Access

Once the service is deployed and configured, a reverse proxy should be created to allow two-way communication between the REPOSITORYMANAGER service and SAP. This will also allow access to the KGS admin panel for service configuration.

7.2.2. Configuration

After installing the repositorymanager service, further configurations of yuuvis® Momentum and the SAP® system are required.

Configuring the App Schema

The REPOSITORYMANAGER service requires the repositorymanager app schema shown in the code block below. It is imported to yuuvis® Momentum via the endpoint POST /api/system/apps/{app}/schema.

The app schema contains the document object type definitions archiveLinkComponent and ilmObject.

Properties of 'archiveLinkComponent'

Objects of type archiveLinkComponent will be used both for documents (logical placeholders) and components (actual documents with content). It contains metadata related to ArchiveLink documents and ArchiveLink components.

Property Type Description

Creationdate

String

Date of creation

Creationtime

String

Time of creation

Datelastmodification

String

Date of the last modification

Timelastmodification

String

Time of the last modification

Contentrepository

String

Name of the content repository. Maximum length is 30 characters.

ArchiveLinkversion

String

ArchiveLink log version number (e.g., 0046)

Documentprotection

String

Document protection: user-defined combination of the r (read), c (create), u (update), and d (delete) operations defined in the ArchiveLink ACL (AccessControlList). If SAP® does not provide information when a document is created, the default value as defined in the KGS configuration interface will be valid (normally rcud: i.e., the document is protected from all operations). DocID String Document ID that unambiguously identifies the SAP® document.

Legalholdlock

String

Specifies that the document has to be retained due to legal reasons (legal hold), thus preventing the document or its components from being deleted.

This property was introduced with component version 7.0. It is enabled for specific scenarios only.

Expirationdate

String

Retention period for the document and its components.

This property was introduced with component version 7.0. It is enabled for specific scenarios only.

Barcode

String

Temporary unique ID that can be used to assign a document object located in yuuvis® Momentum to a business transaction in the SAP® system.

BarcodesenttoR3

Boolean

This document flag indicates whether the barcode and thus the document have already been reported to SAP.

BarcodeProcessingError

Boolean

Will be set to true in case KGS reports an error.

CompID

String

Component ID (data for multi-page TIFF files or data, data1, data2, etc. for single-page TIFF files)

Contenttype

String

MIME type (image/tiff or application/pdf, for example)

Filename

String

File name of the source file. As this name is always filed through Apache Tomcat’s working directory, the name is always a temporary file name.

Applicationversion

String

Version number of the application (e.g., 1.0)

Charset

String

Character set

Compressionstring

String

Compression with gzip is performed by the content server for components with a size that exceeds the adjustable threshold value CompressionSize. This offers advantages for storing, especially for storing print lists that have an uncompressed size bigger than 2 GB. By this compression, they are usually reduced to 10% of the original size.

With this administrative information, the content server is able to determine the uncompressed size of the component and which compression parameters have been used.

Properties of 'ilmObject'

The objects of type ilmObject have the common ILM properties (URL and properties table), as well as a content length property and a type property.

Property

Type

Description

type

string

Specifies the ILM object type. Available values:

  • collection (set 0 for contentlength)

  • resource

contentlength

integer

Content size in Bytes

0 for ILM collections

properties

table

Table with name and value columns of type string

url

string

URL of the ILM object

Combination with Library-based Client

If a client application for yuuvis® Momentum is used that is based on our developer libraries, the IDs of properties and object types should be localized.

An example key-value mapping is shown in the following code block.

Example localization for library-based clients
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
    "appRepositorymanager:Contentrepository_label": "Content Repository",
    "appRepositorymanager:ArchiveLinkversion_label": "Archive Link Version",
    "appRepositorymanager:Documentprotection_label": "Document Protection",
    "appRepositorymanager:DocID_label": "Document ID",
    "appRepositorymanager:Creationdate_label": "Creation Date",
    "appRepositorymanager:Creationtime_label": "Creation Time",
    "appRepositorymanager:Datelastmodification_label": "Last Modified Date",
    "appRepositorymanager:Timelastmodification_label": "Last Modified Time",
    "appRepositorymanager:Legalholdlock_label": "Legal Hold Lock",
    "appRepositorymanager:Expirationdate_label": "Expiration Date",
    "appRepositorymanager:Barcode_label": "Barcode",
    "appRepositorymanager:BarcodesenttoR3_label": "Barcode Sent to R3",
    "appRepositorymanager:BarcodeProcessingError_label": "Barcode Processig Error",
    "appRepositorymanager:CompID_label": "Component ID",
    "appRepositorymanager:Contenttype_label": "Content Type",
    "appRepositorymanager:Filename_label": "File Name",
    "appRepositorymanager:Applicationversion_label": "Application Version",
    "appRepositorymanager:Charset_label": "Chartset",
    "appRepositorymanager:Compressionstring_label": "Compression String",
    "appRepositorymanager:archiveLinkComponent_label": "ArchiveLink object type",
    "appRepositorymanager:archiveLinkComponent_description": "Type used for ArchiveLink documents and components",
    "appRepositorymanager:timestampProperties_label": "Timestamp properties",
    "appRepositorymanager:componentProperties_label": "Component properties",
    "appRepositorymanager:documentProperties_label": "Document properties",
    "appRepositorymanager:type_label": "Type",
    "appRepositorymanager:url_label": "URL",
    "appRepositorymanager:properties_label": "Properties",
    "appRepositorymanager:contentlength_label": "Content Length",
    "appRepositorymanager:ilmObject_label": "ILM object type",
    "appRepositorymanager:ilmObject_description": "Type used for ILM collections and resources"
}
Configuration of the KGS SAP® Connector

Open the KGS Administration Page as described in the installation guide for the REPOSITORYMANAGER service. Go to Main > KGS SAP® Connector.

An SAP® connector is required for the RFC configuration later on.

In the Configuration Editor, configure a debug level between 0 and 4. For productive systems, value 0 is usually set.

The barcode scenario is set up with the following steps.

  • Create a bridge connection via Main > KGS SAP Connector > Bridge Status > Generate Bridge.

    Create Bridge
  • Create a connection via Main > KGS SAP Connector > Add config.

    Add Brigde
  • Edit the connection via Main > KGS SAP Connector > Edit. The following information needs to be entered: Description, SAP AS Host, SAP System Number, SAP Client, SAP User, SAP User Password, SAP Language

    Edit Bridge
  • Configure the repositories via Main > Contentserver4ArchiveLink > Edit and adjust the values in the following tabs:

    • License - Specify the KGS-license key.

    • Barcode - Tick the Enable Barcode checkbox.

    • Protocol - For normal work mode, untick all checkboxes.

    • Common - Adjust only the debug level if necessary.

    • Security

      • Configure the default security level for the communication between SAP® and embedded tomcat:

        0

        certificate is not used

        1

        certificate is used, but not validated

        2

        certificate is used and validated

        We recommend level 2 for productive systems.

      • Specify the clients that should be allowed to change the certificate via Allowed CSAdmin Clients. Avoid the use of a wildcard. Specify only the needed IP addresses instead.

    • RFC - Choose one of the connections you configured before.

    • Components - Usually no changes needed. In case you see a need, please contact your OS or KGS consultant.

    • Backend - Usually no changes needed. In case you see a need, please contact your OS or KGS consultant.

    • Content - Usually no changes needed. In case you see a need, please contact your OS or KGS consultant.

    • Index Export - If barcode upload is used, the time period for requesting new barcodes can be adjusted here. Please ensure that the period in productive systems is long enough to avoid overlapping runs (1800 s recommended).

    • ILM - Set ILM for the ILM Repository. Enter the user name and password of an existing SAP® account that should be used for the connection.

  • Assign a configuration at repository level or global level via Main > ContentServer4ArchiveLink > Edit > RFC > RFC Connection Name. The barcode configuration you create will be assigned. To use barcode synchronization from multiple SAP® systems, remove any global barcode configuration and use the configuration at repository level instead.

    • Repository level:

      Assign Configuration
    • Global level:

      Assign Global Configuration
  • Enable barcode via Main > ContentServer4ArchiveLink > Edit Configuration > Barcode > Enable barcode.

    Enable Configuration
  • Define the barcode timer via Main > ContentServer4ArchiveLink > Edit Configuration > Index Export > BarcodeTimer. Recommended: 60 (seconds)

    Timer Configuration
  • SAPMimeExtensionLookup needs to be enabled to be able to correctly assign file formats to document types. Enable SAPMimeExtensionLookup via Main > ContentServer4ArchiveLink > Edit Configuration > Common > SAPMimeExtensionLookup

    SAPMimeExtensionLookup
KGS Logging

In the default configuration, KGS a log is created once per day. The log files are stored with a retention time of 365 days.

Configuration of the SAP® System

To connect the SAP® system with the HTTP content server and make all necessary settings, we recommend following the SAP® guidelines using the SPRO transaction under Netware > Application Server > Basis Services > ArchiveLink.

To customize the interface for print lists and outbound documents, we recommend attending the SAP® course BIT615. To file reorg data, we recommend attending the SAP® course BIT660.

The main transactions required to establish a connection are listed below:

Transaction OAC0 defines one or several repositories.

This and all further activities within the SAP® system have to be carried out by the SAP® system administrator or another authorized user of the customer.

These activities include:

  • For the first time:

    • Creation of a communication user (SU01) with the corresponding authorizations (SAP_BC_ENDUSER, SAP_BC_SRV_ARL_ADMIN, SAP_BC_SRV_ARL_USER, SAP_BC_SRV_COM_ADMIN)

    • ArchiveLink: maintenance of basic settings (OAG1)

    • Creation of number range intervals (OANR) for print lists

    • Create log (OAA3) or import prepared transports from OPTIMAL SYSTEMS with the log.

    • Creation of an archive device (name ARCH) as output device (SPAD), assignment of the SAP ArchiveLink archiver, hostspool access method (I: archiver)

  • One or several times; depending on how many content repositories have to be defined:

    • Creation of a content repository (OAC0)

      DocArea

      ArchiveLink

      Filing method

      HTTP content server

      Log

      OPTIMALA

      Version no.

      0046 or 0047

      http script

      cs/contentserver

      Output device

      ARCH

      HTTP server

      name or IP address of the server on which yuuvis® Momentum REPOSITORYMANAGER is running

      Port number

      The port used to access yuuvis® Momentum REPOSITORYMANAGER (default: 8010).

    • After successful configuration of yuuvis® Momentum REPOSITORYMANAGER, the certificate (OAC0/CSADMIN) has to be sent and activated for each repository.

      Configuration

7.3. CMIS Interface

As of version 2024 Spring.

The repositorymanager-cmis service is an implementation of the CMIS standard. It is a microservice solution for connecting to SAP® S/4 and SAP® BTP, and implements a set of interfaces required by SAP®.

An SAP® system communicates via the WEB with the assigned CMIS service via the Business Technology Platform (BTP) provided by SAP.

The following services and required methods of the CMIS interface are supported. Support of further methods cannot be guaranteed and might change in the future.

CMIS service Methods

repository

  • getRepositoryInfo

  • getRepositoryInfos

  • getTypeDefinition

  • getTypeChilderen

  • createType

  • updateType

  • deleteType

discovery

query

versioning

  • checkIn

  • checkOut

  • cancelCheckOut

navigation

  • getChildren

  • getObjectParents

object

  • createFolder

  • createDocument

  • createItem

  • deleteObject

  • deleteTree

  • getAllowableActions

  • getObject

  • moveObject

  • getProperties

  • updateProperties

  • getContentStream

  • appendContentStream

7.3.1. Configuration

Configuring the App Schema

Download the XML file and apply it as app schema for the cmis app. Enable the app for each tenant that should be able to use it.

The schema contains only property definitions and secondary object type definitions (SOTs). Some of them define general CMIS types, others are specific for SAP.

As : and _ characters are not allowed in type IDs, the repositorymanager-cmis service replaces them by 0 and 1 respectively. Thus, the resulting CMIS-specific SOTs are:

SOT Description Properties

base

Contains common properties of all CMIS objects.

  • repository

  • parent

  • type

  • name

  • description

  • path

  • createdBy

  • lastModifiedBy

cmis0folder

Represents a CMIS folder.

-

cmis0item

Represents a CMIS item.

-

cmis0document

Represents a CMIS document. It has properties used for versioning.

  • versionLabel

  • versionSeriesCheckedOutBy

cmis0secondary

The base type for all CMIS secondary types.

-

cmis0rm1hold

Used by SAP® to set holds on a document.

  • rm1holdIds

All other types in the schema start with sapBo and represent SAP® business objects.

Service Configuration of 'repositorymanager-cmis'

The repositorymanager-cmis service internally uses rmcmis as spring application name. As the service runs with the prod profile, it loads the rmcmis-prod.yml configuration file that can contain the following parameters:

Parameter Type Description Example value

repositorymanager-cmis.auth.username

String

Username that the CMIS client needs to access yuuvis® Momentum.

exampleuser

repositorymanager-cmis.auth.password

String

Password that the CMIS client needs to use.

changeme

repositorymanager-cmis.yuuvis.api-url

String

URL of the yuuvis core API. Default: http://api.

https://api.testtenant

repositorymanager-cmis.yuuvis.config-url

String

URL of the yuuvis config service. Default: http://configservice.

https://configservice.mynamespace

repositorymanager-cmis.yuuvis.technical.gateway

String

URL of the yuuvis® Momentum to be used by the technical user.

https://myhost.net

repositorymanager-cmis.yuuvis.technical.tenant

String

Tenant of the technical user that repositorymanager-cmis service will use to fetch the app schema

testtenant

repositorymanager-cmis.yuuvis.technical.username

String

Username of the technical user that repositorymanager-cmis service will use to fetch the app schema

adminuser

repositorymanager-cmis.yuuvis.technical.password

String

Password of the technical user that repositorymanager-cmis service will use to fetch app schema

changeme

virus-scan.host

String

Host where ClamAV is deployed. Most likely it will be a pod in the same namespace. If deployment is in a different namespace, include the full path to it.

clam-virus-scan.mynamespace

virus-scan.port

Int

Port on which ClamAV is exposed.

3310

virus-scan.platform

String

Platform on which ClamAV is deployed. Valid values are windows and unix.

unix

logging.level.com.os.services.ilm

String

Configuration parameter provided by Spring Boot frameworks, enables configuring service log level. Exact format of the property is given in the sample configuration file in the attachment of this page. Default: INFO.

DEBUG

Access Configuration

For the repositorymanager-cmis service, a cross-tenant service account is required. Its credentials are configured in the service’s deployment during installation.

Ingress Setup

As requests from SAP® to yuuvis® Momentum do not contain the tenant, the ingress must be configured such that it enriches those requests with the X-ID-TENANT-NAME header.

The tenant header is only added if /repositorymanager/ is part of the endpoint URL. This URL should be adjusted to the naming of the gateway-route (see Gateway section).

Example with request coming from 'sapcmis' tenant
nginx.ingress.kubernetes.io/configuration-snippet: |
  add_header set-cookie 'tenant=sapcmis; Path=/; SameSite=Lax';
  access_by_lua_block
  {
    if string.find(ngx.var.request_uri,"/repositorymanager/") ~= nil then ngx.req.set_header("X-ID-TENANT-NAME", "sapcmis") end
  }

The ingress controller should be configured to target the authentication service within the cluster.

Endpoint Configuration

The repositorymanager-cmis service’s internal endpoints are accessible via https://<ingress-url>/repositorymanager/* paths. They have to be added to the authorization.accesses list in the authentication-prod.yml configuration file.

Identity Provider Configuration

In the identity provider used by yuuvis® Momentum for authentication, enable requests to the ingress controller URL. For example, if Keycloak is used, set Redirect URIs and Web origins.

Storage Configuration

Each tenant that uses the CMIS interface needs an own storage configuration. On the Git server that manages all yuuvis® Momentum configuration files, create a repositories.json file for each of those tenants.

Use the cluster-internal endpoint POST /system/api/resources/{resourceName}/path/{pathName} with the following path parameter values:

  • repositories.json as value for resourceName

  • |tenant|sapcmis|apps|rmcmis value for pathName (for the sapcmis example tenant)

The request body contains the JSON configuration file as shown in the following example:

Example 'repositories.json'
{
  "repository-names": "Repo1,Repo2,Repo3"
}

7.3.3. Logging

All tenant-specific logs are prefixed with tenant[{tenantName}].

7.4. Implementation of SAP® ILM Protocol

As of version 2024 Summer.

To use the SAP® ILM functionality, connect to the SAP® ILM controller via repositorymanager-ilm service.

Please check the supported SAP® versions.

Using retention propagation
If retention propagation functionality is desired (i.e. propagating retention to ArchiveLink documents), the repositorymanager-ilm service has to be combined with repositorymanager service with enabled ArchiveLink functionality.

7.4.1. Configuration

App Schema

The repositorymanager-ilm service requires the app schema for the repositorymanager app.

Parameters

The repositorymanager-ilm service internally uses rmilm as spring application name. As the service runs with the prod profile, it loads the rmilm-prod.yml configuration file that can contain the following parameters:

Property Type Description Example value

repositorymanager-ilm.controller.prefix

String

ILM controller prefix which determines the path /<value>/ilm to be used by SAP®.

Default is cs wich leads to the path /cs/ilm

cs

repositorymanager-ilm.yuuvis.api-url

String

URI of the yuuvis® Momentum API gateway.

Default is http://api. It can be used if the repositorymanager-ilm service is deployed in the same namespace.

http://api.myapinamespace

Ingress Setup

As requests from SAP® to yuuvis® Momentum do not contain the tenant, the ingress has to be configured such that it enriches those requests with the X-ID-TENANT-NAME header.

Example with request coming from 'sapilm' tenant
nginx.ingress.kubernetes.io/configuration-snippet: |
    add_header set-cookie 'tenant=sapilm; Path=/; SameSite=Lax';
    access_by_lua_block
    {
        if string.find(ngx.var.request_uri,"/cs/ilm") ~= nil then ngx.req.set_header("X-ID-TENANT-NAME", "sapilm") end
    }

The ingress controller should be configured to target the authentication service within the cluster.

Endpoint Configuration

The repositorymanager-ilm service’s internal endpoints are accessible via /repositorymanager-ilm/* paths. They have to be added to the authorization.accesses list in the authentication-prod.yml configuration file.

As the connection uses WebDAV, the HTTP methods used by WebDAV have to be added as for controlling access to external services via authentication service.

Identity Provider Configuration

In the identity provider that is used by yuuvis® Momentum for authentication, enable requests to the ingress controller URL. For example, if Keycloak is used, set Redirect URIs and Web origins.

7.4.3. Logging

All tenant-specific logs are prefixed with tenant[{tenantName}].

8. AI Platform

The Artificial Intelligence Platform is a set of APIs and tools that enable customers to set up and use AI functionalities by themselves, yet with low costs and high performance.

Customers can provide their own documents, train models using different algorithms provided by OPTIMAL SYSTEMS GmbH, evaluate trained models, and deploy to make predictions.

Every part of the AI Platform can be deployed on-premises or in the cloud.

8.1. Platform Overview

Artificial Intelligence Platform Overview

The artificial intelligence (AI) platform consists of two services.

  • The kairos-api service for the operation of the machine learning (ML) pipeline that provides models and

  • the predict-api service for actual AI predictions based on the models.

The kairos-api service can be connected to any document management system. In this documentation, only the combination with yuuvis® Momentum is considered. The models created and trained by the ML pipeline can be deployed to any Kubernetes cluster and used by any custom service.

The predict-api service is a solution for the usage of pipeline-built models. It is used to integrate the AI functionality into the developer libraries for yuuvis® Momentum client applications.

8.2. API for AI Features

The predict-api service provides the API for the retrieval of AI predictions. It calls the appropriate machine learning models, improves and validates results returned by the ML models, and finally creates responses for the calling party according to rules set in the inference schema.

The endpoints of the predict-api service are provided in an own API that can be called by client applications.

  • Document Classification:

    • In the context of the AI platform, classification means the determination of suitable typification classes fitting for an object based on its full-text or PDF rendition. For one object, one prediction is provided that contains mappings of classes and their corresponding relevance probability as well as a reference on the object in yuuvis® Momentum via objectId.

    • Instead of the class names used internally in the predict-api service, the prediction response bodies provide the object types as referenced in the inference schema.

  • Metadata Extraction:

    • The predict-api service can analyze the PDF rendition of binary content files assigned to objects in yuuvis® Momentum to extract specific metadata. Based on the models trained via kairos-api service, predictions for values of specific object properties can be determined. The object properties must be listed in the inference schema where conditions for the values and settings for the prediction responses are also specified.

8.2.1. Endpoints of 'predict-api'

The endpoints allow for the development of client applications with integrated AI functionality.

All endpoints are available via the Swagger UI https://<host>/predict-api/swagger-ui.html.

Object Classification
GET /predict-api/api/classification/{objectId} - Retrieve classification prediction for a single object
As of Version

2022 Winter

Request Method

GET

Response Format

JSON

Request Header

Content-Type: application/json

X-ID-TENANT-NAME: tenant_name

Description

Retrieves a classification prediction for a single object identified by its objectId.

The object type IDs will be returned as defined in the inference schema along with their probability in percentage (level of confidence) in the properties section of the JSON response body.

The response JSON further contains the predictionId that should be used for giving feedback to the predict-api service on the quality of received predictions, as well as the system:objectId that was specified in the request URL.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/classification/da20c2fb-8071-45e9-b4bf-2af376cdf9b7

no request body

Response Example
{
    "predictions": [{
        "properties": {
            "appImpulse:receiptsot|appImpulse:receiptType|Rechnung" : {
                "probability": 85.45
            },
            "appImpulse:receiptsot|appImpulse:receiptType|Order": {
                "probability": 12.35
            },
            "appImpulse:hrsot|appImpulse:hrType|Bewerbung": {
                "probability": 1.20
            },
            "Class4": {
                "probability": 0.98
            },
            "Class5": {
                "probability": 0.02
            }
        },
        "system:objectId": "da20c2fb-8071-45e9-b4bf-2af376cdf9b6",
        "predictionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    }]
}
POST /predict-api/api/classification - Retrieve classification prediction for multiple objects
As of Version

2022 Winter

Request Method

POST

Response Format

HTTP status code

Request Header

Content-Type: application/json

X-ID-TENANT-NAME: tenant_name

Description

Retrieves classification predictions for multiple objects identified by their objectId specified in the JSON request body.

The endpoint will return a JSON structure containing a list of predictions, one for each objectId. Each individual prediction sub-structure is structured as already described for the endpoint GET /predict-api/api/classification/{objectId}.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/classification

{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": "da20c2fb-8071-45e9-b4bf-2af376cdf9b6"
            }
        }
    },
    {
        "properties": {
            "system:objectId": {
                "value": "r6s5c2fb-1234-88e9-b4bf-2af376cdf7y7"
            }
        }
    }]
}
Response Example
{
    "predictions": [{
        "properties": {
            "Class1": {
                "probability": 98.45
            },
            "Class2": {
                "probability": 12.77
            },
            "Class3": {
                "probability": 1.38
            },
            "Class4": {
                "probability": 0.99
            },
            "Class5": {
                "probability": 0.02
            }
        },
        "system:objectId": "da20c2fb-8071-45e9-b4bf-2af376cdf9b6",
        "predictionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    },
    {
        "properties": {
            "Class1": {
                "probability": 81.23
            },
            "Class2": {
                "probability": 10.42
            },
            "Class3": {
                "probability": 2.97
            },
            "Class4": {
                "probability": 0.86
            },
            "Class5": {
                "probability": 0.01
            }
        },
        "system:objectId": "r6s5c2fb-1234-88e9-b4bf-2af376cdf7y7",
        "predictionId": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
    }]
}
POST /predict-api/api/classification/feedback - Send classification feedback to Model Serving
As of Version

2022 Winter

Request Method

POST

Response Format

HTTP status code

Request Header

Content-Type: application/json

X-ID-TENANT-NAME: tenant_name

Description

Sends feedback to the ML Pipeline informing about the user decision for one of the object types suggested in a prediction.

After the classification is done and the predicted document types are shown to the user, the user decides which one is the correct type and stores it. It is important to inform the ML Pipeline about this decision so it can be analyzed by Data scientists and that they can improve future models behavior.

In the JSON request body, the following parameters are expected:

Parameter Description

predictionId

ID returned by the classification retrieval endpoints.

feedbackData.objectTypeId.value

ID of the object type selected by the user.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Request is bad.

403

Forbidden

404

Specified predictionId was not found.

415

Unsupported Media Type

500

Internal Server Error: Error while storing feedback.

Request Example

/predict-api/api/classification/feedback

{
   "properties": {
      "predictionId": {
          "value":"3fa85f64-5717-4562-b3fc-2c963f66afa6"
      },
      "feedbackData":{
          "objectTypeId": {
              "value": "Rechnung"
          }
      }
   }
}
Response Example

(1) Successful

200 OK

(2) Not successful

400 Bad Request

{
    "statusCode": 400,
    "timestamp": "2020-12-25T09:42:33.386+00:00",
    "message": "JSON parse error: Unrecognized field \"objectTyyyyypeId\" (class com.os.ai.predict.domain.classification.ClassificationFeedbackRequestData), not marked as ignorable..."
}
POST /predict-api/api/classification/file - Retrieve classification prediction for PDF
As of Version

2022 Winter

Request Method

POST

Response Format

JSON

Request Header

Content-Type: application/json

X-ID-TENANT-NAME: tenant_name

Description

Retrieves classification predictions based on a PDF file. The file should be, e.g. a PDF rendition of a binary content file.

The endpoint will return a JSON structure containing a list of predictions with one entry that is structured as described for the endpoint GET /predict-api/api/classification/{objectId}.

In this scenario, the document is not located in yuuvis® Momentum, so there is no objectId and yuuvis® Momentum features are not used.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/classification/file

Request Body

Binary content of PDF document

Response Example
Response Body
{
    "predictions": [{
        "properties": {
            "Class1": {
                "probability": 98.45
            },
            "Class2": {
                "probability": 12.77
            },
            "Class3": {
                "probability": 1.38
            },
            "Class4": {
                "probability": 0.99
            },
            "Class5": {
                "probability": 0.02
            }
        },
        "predictionId": "3fa85f64-5717-4562-b3fc-2c963f66afa7",
        "system:objectId":  {}
    }]
}
Metadata Extraction
GET /predict-api/api/extraction/{objectId} - Retrieve extraction prediction for a single object
As of Version

2022 Winter

Request Method

GET

Response Format

JSON

Request Header

Content-Type: application/json

X-ID-TENANT-NAME: tenant_name

Description

Retrieves a metadata extraction prediction for the binary content file of a single object identified by its objectId.

The property IDs will be returned according to the inference schema along with their probability in percentage (level of confidence) in the properties section of the JSON response body. The properties page and boundingBox (coordinates on the page) describe the location within the binary content file where the decisive information was identified.

The response JSON further contains the predictionId that should be used for giving feedback to the predict-api service on the quality of received predictions, as well as the system:objectId that was specified in the request URL.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/extraction/da20c2fb-8071-45e9-b4bf-2af376cdf9b6

no request body

Response Example
Response Body
{
    "predictions": [{
        "properties": {
            "appAIInvoice:aiiCompanyName": [
                {
                    "value": "Lufthansa",
                    "probability": 99.24,
                    "boundingBox": [
                        403,
                        729,
                        61,
                        14
                    ],
                    "page": 0
                },
                {
                    "value": "AKG Thermotechnik International GmbH & Co.KG",
                    "probability": 93.24,
                    "boundingBox": [
                        413,
                        224,
                        93,
                        14
                    ],
                    "page": 1
                }
            ],
            "appAIInvoice:aiiIssueDate": [
                {
                    "value": "2018-01-26",
                    "probability": 85.12,
                    "boundingBox": [
                        213,
                        234,
                        76,
                        14
                    ],
                    "page": 1
                }
            ]
        },
        "system:objectId": "da20c2fb-8071-45e9-b4bf-2af376cdf9b6",
        "predictionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    }]
}
POST /predict-api/api/extraction - Retrieve extraction prediction for multiple objects
As of Version

2022 Winter

Request Method

POST

Response Format

JSON

Request Header

Content-Type: application/json

X-ID-TENANT-NAME: tenant_name

Description

Retrieves metadata extraction predictions for the binary content files of multiple objects identified by their objectId specified in the JSON request body.

The endpoint will return a JSON structure containing a list of predictions, one for each objectId. Each individual prediction sub-structure is structured as described for the endpoint GET /predict-api/api/extraction/{objectId}.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/extraction

Request Body
{
    "objects": [{
        "properties": {
            "system:objectId": {
                "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
            }
        }
    },
    {
        "properties": {
            "system:objectId": {
                "value": "da20c2fb-8071-45e9-b4bf-2af376cdf9b6"
            }
        }
    }]

}
Response Example
Response Body
{
    "predictions": [{
        "properties": {
            "appAIInvoice:aiiCompanyName": [
                {
                    "value": "Lufthansa",
                    "probability": 99.24,
                    "boundingBox": [
                        403,
                        729,
                        61,
                        14
                    ],
                    "page": 0
                },
                {
                    "value": "AKG Thermotechnik International GmbH & Co.KG",
                    "probability": 93.24,
                    "boundingBox": [
                        413,
                        224,
                        93,
                        14
                    ],
                    "page": 1
                }
            ],
            "appAIInvoice:aiiIssueDate": [
                {
                    "value": "2018-01-26",
                    "probability": 85.12,
                    "boundingBox": [
                        213,
                        234,
                        76,
                        14
                    ],
                    "page": 1
                }
            ]
        },
        "system:objectId": {
            "value": "cdc7095f-a5ce-486d-92a7-6d0955d969ee"
        },
        "predictionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    },
    {
        "properties": {
            "appAIInvoice:aiiCompanyName": {
                "value": "Mercedes",
                "probability": 83.11
            },
            "appAIInvoice:aiiIssuedDate": {
                "value": "2009-10-12",
                "probability": 97.14,
                "boundingBox": [
                    313,
                    424,
                    73,
                    14
                ],
                "page": 0
            }
        },
        "system:objectId": {
            "value": "da20c2fb-8071-45e9-b4bf-2af376cdf9b6"
        },
        "predictionId": "r6s5c2fb-1234-88e9-b4bf-2af376cdf7y7"
    }]
}
POST /predict-api/api/extraction/feedback - Send extraction feedback to Model Serving
As of Version

2022 Winter

Request Method

GET

Response Format

HTTP status code

Request Header

Content-Type: application/json

X-ID-TENANT-NAME: tenant_name

Description

Sends feedback to the ML Pipeline informing about the user decision for one of the property values suggested in a prediction.

After metadata extraction is done and the predicted property values are shown to the user, the user decides on the validity of those data by accepting them or changing the shown values. It is important to inform the ML Pipeline about this decision so it can be analyzed by data scientists and that they can improve future models behavior.

In the JSON request body, the following parameters are expected:

Parameter Description

predictionId

ID returned by the extraction retrieval endpoints.

feedbackData

Values for all properties the user was able to modify after retrieving the prediction (e.g., aiInvoiceNumber, aiCompanyName, aiAmount, aiIssuedDate):

value

value selected/entered by the user

boundingBox

Optional, coordinates of the selected value on the page within the binary content file

page

Optional, page number where the value was found within the binary content file

Response HTTP status codes:

HTTP status code Meaning

200 OK

Feedback is logged successfully.

400 Bad request

Request is bad.

403 Forbidden

404 Not Found

Specified predictionId was not found.

415 Unsupported Media Type

500 Internal Server Error

Error while storing feedback.

If an error is thrown, a JSON structure is returned as response body.

Request Example

/predict-api/api/extraction/feedback

{
    "properties": {
        "predictionId": {
            "value":"3fa85f64-5717-4562-b3fc-2c963f66afa6"
        },
        "feedbackData": [
            {
                "propertyName": "aiInvoiceNumber",
                "value": "RWTÜV",
                "boundingBox":[123, 222, 33, 14],
                "page": 1
            },
            {
                "propertyName": "aiCompanyName",
                "value": "CompanyName"
            },
            {
                "propertyName": "aiAmount",
                "value": "234.44"
            },
            {
                "propertyName": "aiIssuedDate",
                "value": "10.4.2020"
            }
        ]
    }
}
Response Example

(1) Successful

200 OK

(2) Not successful

400 Bad Request

{
    "statusCode": 400,
    "timestamp": "2020-12-25T09:42:33.386+00:00",
    "message": "JSON parse error: Unrecognized field \"aiCompanssyName\" (class com.os.ai.predict.domain.extraction.ExtractionFeedbackRequestData), not marked as ignorable..."
}
POST /predict-api/api/extraction/file - Retrieve extraction prediction for PDF
As of Version

2022 Winter

Request Method

POST

Response Format

JSON

Request Header

Content-Type: application/json

X-ID-TENANT-NAME: tenant_name

Description

Retrieves an extraction prediction based on a PDF file that is passed in the request body.

The endpoint will return a JSON structure containing a list of predictions with one prediction that is structured as already described for the endpoint GET /predict-api/api/extraction/{objectId}.

In this scenario, the document is not located in yuuvis® Momentum, so there is no objectId and yuuvis® Momentum features are not used.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/extraction/file

Request Body

Binary content of PDF document

Response Example
Response Body
{
    "predictions": [{
        "properties": {
            "appAIInvoice:aiiCompanyName": [
                {
                    "value": "Lufthansa",
                    "probability": 99.24,
                    "boundingBox": [
                        403,
                        729,
                        61,
                        14
                    ],
                    "page": 0
                },
                {
                    "value": "AKG Thermotechnik International GmbH & Co.KG",
                    "probability": 93.24,
                    "boundingBox": [
                        413,
                        224,
                        93,
                        14
                    ],
                    "page": 1
                }
            ],
            "appAIInvoice:aiiIssueDate": [
                {
                    "value": "2018-01-26",
                    "probability": 85.12,
                    "boundingBox": [
                        213,
                        234,
                        76,
                        14
                    ],
                    "page": 1
                }
            ]
        },
        "system:objectId":  {},
        "predictionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    }]
}
Dictionary Management
GET /predict-api/api/admin/dictionaries/{dictionaryId} - Retrieve all records
As of Version

2022 Winter

Request Method

GET

Response Format

JSON

Description

Retrieves all record from the Elasticsearch dictionary identified by its dictionaryId.

Parameters in the JSON response body:

Parameter Type Description

id

string

Unique elasticsearch record identifier

companyName

string

Name of already known company that will be used for comparison with the one extracted by the model

fullAddress

string

Address of that company

tenant

string

Tenant for which this company name is valid

Response HTTP status codes:

+

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/admin/dictionaries/company_name_dictionary

Response Example

200 OK

Response Body
[
    {
        "id": "55c3270e-0d10-4222-a458-c9b0030dedcc",
        "companyName": "TestCompany1",
        "fullAddress": "testAddress1",
        "tenant": "tenant1"
    },
    {
        "id": "d519e595-1c10-4bdc-a850-efdf44d5ce69",
        "companyName": "TestCompany2",
        "fullAddress": "testAddress2",
        "tenant": "tenant1"
    }
]
DELETE /predict-api/api/admin/dictionaries/{dictionaryId} - Delete all records
As of Version

2022 Winter

Request Method

DELETE

Response Format

HTTP status code

Description

Deletes the records in the Elasticsearch dictionary identified by its dictionaryId. Dictionary represents elasticsearch index.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/admin/dictionaries/company_name_dictionary

Response Example

200 OK

POST /predict-api/api/admin/dictionaries/{dictionaryId}/batchupdate - Create or update multiple records
As of Version

2022 Winter

Request Method

POST

Response Format

JSON

Description

Saves the records specified in a CSV file in the Elasticsearch dictionary identified by its dictionaryId.

CSV file should contain 3 columns in this order (id, companyName, fullAddress) and values separated by ;.

Tenant information is taken directly from the logged in user.

Parameters in the JSON response body:

Parameter Type Description

id

string

Unique elasticsearch record identifier

companyName

string

Name of already known company that will be used for comparison with the one extracted by the model

fullAddress

string

Address of that company

tenant

string

Tenant for which this company name is valid

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/admin/dictionaries/company_name_dictionary/batchupdate

CSV file as input

text/csv in the request body header

Response Example

200 OK

Response Body
[
    {
        "id": "55c3270e-0d10-4222-a458-c9b0030dedcc",
        "companyName": "TestCompany1",
        "fullAddress": "testAddress1",
        "tenant": "tenant1"
    },
    {
        "id": "d519e595-1c10-4bdc-a850-efdf44d5ce69",
        "companyName": "TestCompany2",
        "fullAddress": "testAddress2",
        "tenant": "tenant1"
    }
]
POST /predict-api/api/admin/dictionaries/{dictionaryId}/entries - Create single record
As of Version

2022 Winter

Request Method

POST

Response Format

JSON

Description

Saves a record specified in the JSON request body in the Elasticsearch dictionary identified by its dictionaryId.

id is automatically generated and tenant information is taken from currently logged in user.

Parameters in the JSON request body:

Parameter Type Description

companyName

string

Name of already known company that will be used for comparison with the one extracted by the model

fullAddress

string

Address of that company

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/admin/dictionaries/company_name_dictionary/entries

Request body
{
  "companyName": "string",
  "fullAddress": "string"
}
Response Example

200 OK

Response Body
{
    "id": "55c3270e-0d10-4222-a458-c9b0030dedcc",
    "companyName": "TestCompany1",
    "fullAddress": "testAddress1",
    "tenant": "tenant1"
}
POST /predict-api/api/admin/dictionaries/{dictionaryId}/entries/{entryId} - Update specified record
As of Version

2022 Winter

Request Method

POST

Response Format

JSON

Description

Update a record specified by its entryId with the data passed in the JSON request body in the Elasticsearch dictionary identified by its dictionaryId.

If the record with specified entryId does not exist, a new one will be created.

Parameters in the JSON request body:

Parameter Type Description

companyName

string

Name of already known company that will be used for comparison with the one extracted by the model

fullAddress

string

Address of that company

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/admin/dictionaries/company_name_dictionary/entries/1

Request body
{
  "companyName": "string",
  "fullAddress": "string"
}
Response Example

200 OK

Response Body
{
    "id": "1",
    "companyName": "TestCompany1",
    "fullAddress": "testAddress1",
    "tenant": "tenant1"
}
DELETE /predict-api/api/admin/dictionaries/{dictionaryId}/entries/{entryId} - Delete specified record
As of Version

2023 Winter

Request Method

DELETE

Response Format

JSON

Description

Deletes a record specified by its entryId from the Elasticsearch dictionary identified by its dictionaryId.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/admin/dictionaries/company_name_dictionary/entries/1

Response Example

200 OK

Model Performance Metrics

Calculation of performances for different models.

POST /predict-api/api/admin/history/models/{modelid}/performance - Retrieve tenant model performance.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Description

Retrieves the tenant model performances specified by parameters. System context models used for the currently active tenant are also valid.

Parameters in the JSON request body:

Parameter Type Description

startDate

LocalDateTime

Desired start date for getting records from the database

endDate

LocalDateTime

Desired end date for getting records from the database

Parameters in the JSON response body:

Parameter Type Description

confusionMatrix

Object

Description can be found on the towards data science Website.

averageResponseTime

int

Average of all response times relevant for the model that is checked

accuracy,precision,recall,fmeasure

int

Description can be found on the towards data science Website.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/admin/history/models/model_1_Id/performance

Request body
{
  "startDate": "2021-04-01T12:18:04.512527",
  "endDate": "2021-04-01T19:18:04.512527"
}
Response Example

200 OK

Response Body
{
    "accuracy": 1.0,
    "precision": 0.0,
    "recall": 0.0,
    "confusionMatrix": {
        "TP": 0,
        "FP": 0,
        "TN": 6,
        "FN": 0
    },
    "averageResponseTime": 3771.0,
    "fmeasure": 0.0
}
POST /predict-api/api/system/history/models/{modelid}/performance - Retrieve system model performance.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Description

Retrieves the system model performances specified by parameters.

Parameters in the JSON request body:

Parameter Type Description

startDate

LocalDateTime

Desired start date for getting records from the database

endDate

LocalDateTime

Desired end date for getting records from the database

Parameters in the JSON response body:

Parameter Type Description

confusionMatrix

Object

Description can be found on the towards data science Website.

averageResponseTime

int

Average of all response times relevant for the model that is checked

accuracy,precision,recall,fmeasure

int

Description can be found on the towards data science Website.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/system/history/models/model_1_Id/performance

Request body
{
  "startDate": "2021-04-01T12:18:04.512527",
  "endDate": "2021-04-01T19:18:04.512527"
}
Response Example

200 OK

Response Body
{
    "accuracy": 1.0,
    "precision": 0.0,
    "recall": 0.0,
    "confusionMatrix": {
        "TP": 0,
        "FP": 0,
        "TN": 6,
        "FN": 0
    },
    "averageResponseTime": 3771.0,
    "fmeasure": 0.0
}
History Logs
GET /predict-api/api/admin/history/models - Retrieve information on tenant models
As of Version

2022 Winter

Request Method

GET

Response Format

JSON

Description

Retrieve information on models that are already used by the currently active tenant.

System context models used for that tenant are also valid.

Parameters in the JSON response body:

Parameter Type Description

modelRunId

string

Unique model identifier set in property file of Predict-API

modelOriginType

string

Model type (TENANT or SYSTEM)

modelUsageType

string

Purpose type (extraction or classification)

Response HTTP status codes:

+

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/admin/history/models

Response Example

200 OK

Response Body
[
    {
        "modelRunId": "string",
        "modelOriginType": "string",
        "modelUsageType": "string",
    }
]
POST /predict-api/api/admin/history/models/{modelId}/performance-logs - Retrieve history request logs of the current tenant
As of Version

2022 Winter

Request Method

POST

Response Format

HTTP status code

Description

Retrieves the tenant history request logs by the parameters specified in the JSON request body for the model identified by modelId.

The model must have already been used in the current tenant. System context models used for that tenant are also valid.

Parameters in the JSON request body:

Parameter Type Description

startDate

LocalDateTime

Desired start date for getting records from the database

endDate

LocalDateTime

Desired end date for getting records from the database

documentId

String

UUID that represents the document’s objectId

Parameters in the JSON response body:

Parameter Type Description

uuid

long

Object unique identifier

documentId

String

This represents objectId of the document

modelRequest

String

Request that is used to call this model

modelResponse

String

Response returned by the model

predictions

String

Response returned by Predict-API for that request

modelsResponseInfo

String

Map of information about the model called in this specific request (Model label and information about the model – model type, request time, model identifier)

responseTime

long

Response time in total

predictionType

long

Type of the prediction – extraction or classification

sot

String

List of secondary object types used for this request

feedbackData

String

Feedback data in string format

tenant

String

Tenant name

isActive

Boolean

Flag if the record is relevant or not (softly deleted)

createdDate

LocalDateTime

Creation date of request

createdBy

String

Who created the request

lastModifiedDate

LocalDateTime

Date on which the request was last updated

lastModifiedBy

String

Who last updated the request

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/admin/history/models/model_1_Id/performance-logs

Request body
{
  "startDate": "2021-04-01T12:18:04.512527",
  "endDate": "2021-04-01T19:18:04.512527",
  "documentId": "string"
}
Response Example

200 OK

Response Body
[
    {
        "id": "long"
        "uuid": "UUID"
        "documentId": "string"
        "modelRequest": "string"
        "modelResponse": "string"
        "predictions": "string"
        "modelsResponseInfo": "string"
        "responseTime": "long"
        "predictionType": "string"
        "sots": "string"
        "feedbackData": "string"
        "tenant": "string"
        "isActive": true
        "createdDate": "localDateTime"
        "createdBy": "string"
        "lastModifiedDate": "localDateTime"
        "lastModifiedBy": "string"

    }
]
GET /predict-api/api/system/history/models - Retrieve information on system context models
As of Version

2022 Winter

Request Method

GET

Response Format

JSON

Description

Retrieves information on the system context models already used in any tenant.

Parameters in the JSON response body:

Parameter Type Description

modelRunId

string

Unique model identifier set in property file of Predict-API

modelOriginType

string

Model type (TENANT or SYSTEM)

modelUsageType

string

Purpose type (extraction or classification)

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/system/history/models

Response Example

200 OK

Response Body
[
    {
        "modelRunId": "string",
        "modelOriginType": "string",
        "modelUsageType": "string",
    }
]
POST /predict-api/api/system/history/models/{modelId}/performance-logs - Retrieve history logs of system context
As of Version

2022 Winter

Request Method

POST

Response Format

HTTP status code

Description

Retrieve the history request logs of system context by the parameters specified in the JSON request body for the model identified by modelId.

The model must have already been used in any tenant.

Parameters in the JSON request body:

Parameter Type Description

startDate

LocalDateTime

Desired start date for getting records from the database

endDate

LocalDateTime

Desired end date for getting records from the database

documentId

String

UUID that represents the document’s objectId

Parameters in the JSON response body:

Parameter Type Description

uuid

long

Object unique identifier

documentId

String

This represents objectId of the document

modelRequest

String

Request that is used to call this model

modelResponse

String

Response returned by the model

predictions

String

Response returned by Predict-API for that request

modelsResponseInfo

String

Map of information about the model called in this specific request (Model label and information about the model – model type, request time, model identifier)

responseTime

long

Response time in total

predictionType

long

Prediction type (extraction or classification)

sot

String

List of secondary object types used for this request

feedbackData

String

Feedback data in string format

tenant

String

Tenant name

isActive

Boolean

Flag if the record is relevant or not (softly deleted)

createdDate

LocalDateTime

Creation date of request

createdBy

String

Who created the request

lastModifiedDate

LocalDateTime

Date on which the request was last updated

lastModifiedBy

String

Who updated the request

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/predict-api/api/system/history/models/model_1_Id/performance-logs

Request body
{
  "startDate": "2021-04-01T12:18:04.512527",
  "endDate": "2021-04-01T19:18:04.512527",
  "documentId": "string"
}
Response Example

200 OK

Response Body
[
    {
        "id": "long"
        "uuid": "UUID"
        "documentId": "string"
        "modelRequest": "string"
        "modelResponse": "string"
        "predictions": "string"
        "modelsResponseInfo": "string"
        "responseTime": "long"
        "predictionType": "string"
        "sots": "string"
        "feedbackData": "string"
        "tenant": "string"
        "isActive": true
        "createdDate": "localDateTime"
        "createdBy": "string"
        "lastModifiedDate": "localDateTime"
        "lastModifiedBy": "string"

    }
]

8.2.2. Requirements

The predict-api service is a Java Spring Microservice intended for use in Kubernetes and in combination with kairos-api service. To find details on infrastructure requirements for the AI Platform components, see requirements and dependencies. If you want to use them for the AI integration in a client application based on our client libraries (e.g., yuuvis® client as reference implementation), also the requirements of the involved services must be considered.

8.2.3. Configuration

The inference schema needs to be defined according to your client application and deployed via the API of the kairos-api service.

Default timeout value for the inference schema (if timeout is not set) can be configured with:

predict-api:
  config:
    default-timeout: 20

The endpoints of the predict-api service are available for users with the YUUVIS_AI_PREDICT role in the default configuration. Also, the admin and system roles can be customized for /admin/* and /system/* endpoints. The roles can be replaced by a custom role via the following configuration:

predict-api:
  user:
    authority:
      api: YUUVIS_AI_PREDICT
      admin: YUUVIS_TENANT_ADMIN
      system: YUUVIS_SYSTEM_INTEGRATOR

To handle models provided by the kairos-api service, the following configuration parameters are required. Models can be specified per tenant if tenant specific model is trained. Alternatively, default services can be used.

predict-api:
  extraction:
    label-to-model-info-map-per-tenant:
      tenant1:
        TRANSFORMERS:
          - http://transformers.ml-infrastructure:5000
          - tenant1ModelTransformers
          - ML_FLOW
        RULE_BASED:
          - http://extraction-rule-based.ml-infrastructure:5000
          - tenant1ModelRuleBased
          - ML_FLOW
      default:
        TRANSFORMERS:
          - http://transformers-default.ml-infrastructure:5000
          - defaultModelTransformers
          - ML_FLOW
        RULE_BASED:
          - http://extraction-rule-based-default.ml-infrastructure:5000
          - defaultModelRuleBased
          - ML_FLOW

Furthermore, a list of labels for individual models is required as shown in the example below.

The specified labels are processed with the corresponding model. In the example, INVOICE_ISSUER_NAME and INVOICE_RECEIVER_NAME are processed via the transformers model and via the rule-based-name model. This allows the most suitable approach to be selected for each purpose.

issuer-receiver-name-labels should specify labels used for company name extraction.

If a model should not be used, remove all entries from the corresponding labels list.

predict-api:
  extraction:
    transformers-labels:
      - INVOICE_TOTAL_AMOUNT
      - INVOICE_BASE_AMOUNT
      - INVOICE_ISSUE_DATE
      - INVOICE_NUMBER
      - INVOICE_ISSUER_NAME
      - INVOICE_RECEIVER_NAME
    rule-based-labels:
      - INVOICE_IBAN_NUMBER
      - TAX_AMOUNT
      - INVOICE_CURRENCY
      - TAX_NUMBER_ISSUING_COMPANY
      - TAX_NUMBER_RECEIVING_COMPANY
      - INVOICE_SWIFTBIC_NUMBER
    issuer-receiver-name-labels:
      - INVOICE_ISSUER_NAME
      - INVOICE_RECEIVER_NAME

Negative class for extraction models needs to fit the one in the trained models and can be configured with:

predict-api:
  negative-class: O

Company name similarity postprocessing and database logging can be enabled/disabled with:

predict-api:
  company-name-similarity:
    enabled: false
  db-logs:
    enabled: true

If amount calculation postprocessing is enabled, labels for amounts should be specified in property file.

predict-api:
  extraction:
    amount-calculation-labels:
      default:
        TOTAL_AMOUNT: INVOICE_TOTAL_AMOUNT
        BASE_AMOUNT:
        TAX_AMOUNT: TAX_AMOUNT
      default:
        TOTAL_AMOUNT: INVOICE_TOTAL_AMOUNT
        BASE_AMOUNT: INVOICE_BASE_AMOUNT
        TAX_AMOUNT: TAX_AMOUNT

Classification properties are specified as follows:

  • URL to classification model service,

  • classification model identifier,

  • threshold that represents the limit to show prediction classes with certainty level above that value,

  • model label name

  • and flag that is used to specify which approach is used in classification model (if set to true – transformers approach is used, if false – old tfidf approach is used)

predict-api:
  classification:
    url: http://classification.ml-infrastructure:5000
    runId: defaultClassificationRunId
    threshold: 0.50
    label: CLASSIFICATION
    useTransformers: true

The PDF converter component is used to extract information from a pdf document and convert it to a format that is suitable as model input.

predict-api:
  pdf-converter:
    url: http://pdf-converter.ml-infrastructure:5000

8.3. API for ML Pipeline

The machine learning (ML) pipeline is a processing chain with multiple jobs as shown in the overview image.

  • Preprocessing of DMS objects including metadata and binary content. Documents exported from external systems and their metadata can be used as well (e.g., 5,000 invoices received from different partners/suppliers). The data are managed on an S3 storage.

  • Training of a new model based on the now suitable formatted data. The training can be repeated with the change set of parameters to increase model performance.

  • Creation of a docker image for the model and deployment to any Kubernetes cluster.

The individual jobs are managed via kairos-api endpoints.

Furthermore, the kairos-api service is responsible for configuring the inference schema, that is in turn used by predict-api to call the appropriate machine learning models for an object type.

8.3.1. Endpoints of 'kairos-api' Service

All endpoints are available via the Swagger UI https://<host>/kairos-api/swagger-ui.html.

Inference Schema Management
GET /kairos-api/api/admin/schema - Get Inference Schema for Tenant
As of Version

2022 Winter

Request Method

GET

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Retrieves the tenants' current inference schema.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/schema

no request body

Response Example
Response Body
{
  "tenant": "string",
  "classification": {
    "timeout": 10,
    "enabled": true,
    "aiClassifierId": "string",
    "objectTypes": [
      {
        "objectTypeId": "string",
        "aiObjectTypeId": "string"
      }
    ]
  },
  "extraction": {
    "timeout": 10,
    "enabled": true,
    "objects": [
      {
        "objectTypeId": "string",
        "enabled": true,
        "timeout": 12,
        "propertyReference": [
          {
            "propertyId": "string",
            "aiPropertyId": "string",
            "allowedValues": [
              "string"
            ],
            "pattern": "string",
            "validationService": "string",
            "maxNumberOfPredictions": 3
          }
        ]
      }
    ]
  }
}
POST /kairos-api/api/admin/schema - Update Inference Schema for Tenant
As of Version

2022 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Updates the tenants' inference schema.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/schema

Input is a JSON file with content explained in the inference schema.

GET /kairos-api/api/system/schema - Get Global Inference Schema
As of Version

2022 Winter

Request Method

GET

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Retrieves the global inference schema.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/system/schema

no request body

Response Example
Response Body
{
  "classification": {
    "timeout": 10,
    "enabled": true,
    "aiClassifierId": "string",
    "objectTypes": [
      {
        "objectTypeId": "string",
        "aiObjectTypeId": "string"
      }
    ]
  },
  "extraction": {
    "timeout": 10,
    "enabled": true,
    "objects": [
      {
        "objectTypeId": "string",
        "enabled": true,
        "timeout": 12,
        "propertyReference": [
          {
            "propertyId": "string",
            "aiPropertyId": "string",
            "allowedValues": [
              "string"
            ],
            "pattern": "string",
            "validationService": "string",
            "maxNumberOfPredictions": 3
          }
        ]
      }
    ]
  }
}
POST /kairos-api/api/system/schema - Update Global Inference Schema
As of Version

2022 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Updates the global inference schema.

The global inference schema is available for all tenants. It will be used by tenants which do not have their inference schema.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/system/schema

Input is a JSON file with content explained in the inference schema.

Building and Deploying Docker Images
POST /kairos-api/api/admin/models/build-image - Build and push a model docker image.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Creates a Kubernetes job that builds a model docker image and pushes it to a specified docker image registry. Response is UUID of the created Kubernetes job.

Parameters in the JSON response body:

Parameter Type Description

dockerImage

String

Docker image tag that you want to use for the model that you are building. Must match the regular expression (^[a-zA-Z0-9_.-]+(/[a-zA-Z0-9_.-]+)+(:[a-zA-Z0-9_.-]+)?$)

artifactLocation

String

Location on S3 storage where model artifacts to be used for image build are located. Must match the regular expression (s3://([a-z0-9][a-z0-9\-.]{1,61}[a-z0-9])/(.+)$)

dockerImagePushSecretName

String

Name of the Kubernetes secret where to push the image with credentials for listed repository in dockerImage parameter. Secret should be present in the cluster.

artifactLocationSecretName

String

Kubernetes secret with credentials to S3 storage where listed artifacts are located.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/models/build-image

Request body
{
  "dockerImage": "...",
  "artifactLocation": "s3://...",
  "dockerImagePushSecretName": "string",
  "artifactLocationSecretName": "string"
}
Response Example

200 OK

Response Body
{
  "jobUuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
GET /kairos-api/api/admin/models/build-image/history - Get all image build jobs.
As of Version

2023 Winter

Request Method

GET

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Gets all image build job details to check their status. Paging and sorting (by start or end time) can be adjusted via query parameters. The result contains:

  • running image build operations including their start time,

  • finished image build operations including their start and end time, as well as their execution summary, and

  • interrupted image build operations, including their start time and end (interruption) time.

Optional query parameters:

Parameter Type Description

page

int

Default is 0.

size

int

Default is 10.

sort

string

Allowed values are:

  • createdDate

  • endedDate

  • created date/DESC (default)

Response object explained in GET /kairos-api/api/admin/models/build-image/history/{uuid}.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/models/build-image/history?page=0&size=1&sort=string

Response Example

200 OK

Response Body
{
  "content": [
    {
      "uuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "jobType": "string",
      "jobStatus": "string",
      "executionSummary": "string",
      "endedDate": "2023-11-13T15:45:33.976Z",
      "createdDate": "2023-11-13T15:45:33.976Z",
      "createdBy": "string",
      "lastModifiedDate": "2023-11-13T15:45:33.976Z",
      "lastModifiedBy": "string",
      "isActive": true,
      "tenant": "string",
      "runId": "string"
    }
  ],
  "totalElements": 1,
  "totalPages": 0,
  "last": true
}
GET /kairos-api/api/admin/models/build-image/history/{jobUuid} - Get specific image build job by UUID.
As of Version

2023 Winter

Request Method

GET

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Gets specific image build job details by UUID.

Parameters in the JSON response body:

Parameter Type Description

uuid

UUID

Unique record identifier

jobType

string

Job type = IMAGE_BUILD

jobStatus

string

Job Status - IS_RUNNING, COMPLETE, FAILED, INTERRUPTED

executionSummary

string

Execution summary description

createdDate

LocalDateTime

Date when request is created

createdBy

String

Information who created the request

lastModifiedDate

LocalDateTime

Date on which the request was last updated

lastModifiedBy

String

Information who updated the request

isActive

Boolean

Flag if the record is relevant or not (softly deleted)

tenant

String

Tenant name

runId

String

runId of the training pipeline

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/models/build-image/history/3fa85f64-5717-4562-b3fc-2c963f66afa6

Response Example

200 OK

Response Body
{
  "uuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "jobType": "string",
  "jobStatus": "string",
  "executionSummary": "string",
  "endedDate": "2023-11-13T19:08:21.291Z",
  "createdDate": "2023-11-13T19:08:21.292Z",
  "createdBy": "string",
  "lastModifiedDate": "2023-11-13T19:08:21.292Z",
  "lastModifiedBy": "string",
  "isActive": true,
  "tenant": "string",
  "runId": "string"
}
POST /kairos-api/api/admin/models/build-image/interrupt/{jobUuid} - Interrupt/Delete image build and push job by UUID of the job.
As of Version

2023 Winter

Request Method

POST

Response Format

HTTP status code

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Interrupts/Deletes image build and push job by UUID of the job.

There is no automated cleanup of preprocessing results that were saved to the S3 bucket. Administrators can maintain those results according to their needs.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/models/build-image/interrupt/3fa85f64-5717-4562-b3fc-2c963f66afa6

Response Example

200 OK

POST /kairos-api/api/admin/models/deploy - Deploy model to Kubernetes cluster.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

The endpoint deploys a model that is dockerized and located at the docker image registry that is specified in the JSON request body to the Kubernetes cluster. The image will be run after the proper deployment and Kubernetes service creation.

Parameters in the JSON request body:

Parameter Type Description

modelName

string

The name of the model (deployment and service). Must match the regular expression (^[a-z0-9]([-a-z0-9]*[a-z0-9])?$). The number of characters is limited to 255 (RFC 1123 standard).

dockerImage

string

Docker image tag. Must match the regular expression (^[a-zA-Z0-9_.-]+(/[a-zA-Z0-9_.-]+)+(:[a-zA-Z0-9_.-]+)?$)

imagePullSecret

string

Image pull secret that will be used to pull image from the docker image registry. Should already be present in the cluster.

numberOfReplicas

int

Number of replicas. Default is 1.

memoryLimits

string

Memory limit for Kubernetes container. Use Mi or Gi as measure.

memoryRequests

string

Memory requests for Kubernetes container. Use Mi or Gi as measure.

containerPort

int

Port inside the model. Values are available in a range between 1 and 65535. Default is 8080.

environmentVariables

JSON key-value mapping

Environment variables that should be used for the model.

shouldAddToleration

boolean

Decides if toleration is used to place the container on a specific Node inside the cluster (true) or not (false). Default is false.

If true, a Node with following taint is required:

tolerations:
- key: "dedicated"
  operator: "Exists"
  effect: "NoSchedule"
nodeSelector:
  dedicated: machinelearning

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/models/deploy

Request body
{
  "modelName": "a3m45j7...",
  "dockerImage": "container-registry/image:tag",
  "imagePullSecret": "string",
  "numberOfReplicas": 1,
  "memoryLimits": "10Gi",
  "memoryRequests": "8Gi",
  "containerPort": 65535,
  "environmentVariables": {
    "additionalProp1": "string",
    "additionalProp2": "string",
    "additionalProp3": "string"
  },
  "shouldAddToleration": true
}
Response Example

200 OK

Response Body
{
  "status": "string"
}
POST /kairos-api/api/admin/models/health - Check model availability.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Checks the health of the model specified with Kubernetes service name in the JSON request body by sending a ping request to the corresponding Kubernetes pod.

Parameters in the JSON request body:

Parameter Type Description

modelName

string

The name of the model Kubernetes service. Must match the regular expression (^[a-z0-9]([-a-z0-9]*[a-z0-9])?$). The number of characters is limited to 255 (RFC 1123 standard).

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/models/health

Request body
{
  "modelName": "model1"
}
Response Example

200 OK

Response Body
{
  "status": "string"
}
POST /kairos-api/api/admin/models/undeploy - Undeploy/Delete model from Kubernetes cluster.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Undeploys/Deletes a model’s deployment and pod from the Kubernetes cluster.

Parameters in the JSON request body:

Parameter Type Description

modelName

string

The name of the model (deployment and service). Must match the regular expression (^[a-z0-9]([-a-z0-9]*[a-z0-9])?$). The number of characters is limited to 255 (RFC 1123 standard).

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/models/undeploy

Request body
{
  "modelName": "string"
}
Response Example

200 OK

Response Body
{
  "status": "string"
}
Preprocessing Operations

Manage preprocessing of raw data to convert them into a suitable format for the training. The preprocessing is performed by individual Kubernetes jobs.

POST /kairos-api/api/admin/preprocessing - Start a preprocessing job.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Starts a preprocessing job that converts raw data into a suitable format for training processes.

Configuration parameters should be set in the property file of a service. For details, see configuration description of preprocessing service.

The data are read from and written to the configured S3 repository.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/models/preprocessing

Response Example

200 OK

Response Body
{
  "jobUuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
GET /kairos-api/api/admin/preprocessing/history - Get all preprocessing jobs.
As of Version

2023 Winter

Request Method

GET

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Gets all preprocessing job details to check their status. Paging and sorting (by start or end time) can be adjusted via query parameters. The result contains:

  • running preprocessing operations including their start time,

  • finished preprocessing operations including their start and end time, as well as their execution summary, and

  • interrupted preprocessing operations, including their start time and end (interruption) time.

Optional query parameters:

Parameter Type Description

page

int

Default is 0.

size

int

Default is 10.

sort

string

Allowed values are:

  • createdDate

  • endedDate

  • created date/DESC (default)

Response object explained in GET /kairos-api/api/admin/models/build-image/history/{uuid}. Only type is different - PREPROCESSING

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/models/preprocessing/history?page=0&size=1&sort=string

Response Example

200 OK

Response Body
{
  "content": [
    {
      "uuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "jobType": "string",
      "jobStatus": "string",
      "executionSummary": "string",
      "endedDate": "2023-11-13T17:39:54.727Z",
      "createdDate": "2023-11-13T17:39:54.727Z",
      "createdBy": "string",
      "lastModifiedDate": "2023-11-13T17:39:54.727Z",
      "lastModifiedBy": "string",
      "isActive": true,
      "tenant": "string",
      "runId": "string"
    }
  ],
  "totalElements": 1,
  "totalPages": 0,
  "last": true
}
GET /kairos-api/api/admin/preprocessing/history/{jobUuid} - Get specific preprocessing job by UUID.
As of Version

2023 Winter

Request Method

GET

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Gets specific preprocessing job details by UUID.

Response object explained in GET /kairos-api/api/admin/models/build-image/history/{uuid}. Only type is different - PREPROCESSING

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/models/preprocessing/history/3fa85f64-5717-4562-b3fc-2c963f66afa6

Response Example

200 OK

Response Body
{
  "uuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "jobType": "string",
  "jobStatus": "string",
  "executionSummary": "string",
  "endedDate": "2023-11-13T17:51:01.807Z",
  "createdDate": "2023-11-13T17:51:01.807Z",
  "createdBy": "string",
  "lastModifiedDate": "2023-11-13T17:51:01.807Z",
  "lastModifiedBy": "string",
  "isActive": true,
  "tenant": "string",
  "runId": "string"
}
POST /kairos-api/api/admin/preprocessing/interrupt/{jobUuid} - Interrupt/Delete preprocessing job by its UUID.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Interrupts/Deletes preprocessing job by its UUID.

There is no cleanup of preprocessing results that were saved to the corresponding bucket in the S3 repository. Repository administrators can maintain those results according to their needs.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/models/preprocessing/interrupt/3fa85f64-5717-4562-b3fc-2c963f66afa6

Response Example

200 OK

Training of Models
POST /kairos-api/api/admin/training - Start the training of a model.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Starts the pipeline training job in Kubernetes.

Configuration parameters should be set in the property file of a service. For details, see configuration description of training service.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/training

Response Example

200 OK

Response Body
{
  "jobUuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
GET /kairos-api/api/admin/training/history - Get all training jobs.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Gets all training job details to check their status. Paging and sorting (by start or end time) can be adjusted via query parameters. The result contains:

  • running training operations including their start time,

  • finished training operations including their start and end time, as well as their execution summary, and

  • interrupted training operations, including their start time and end (interruption) time.

Optional query parameters:

Parameter Type Description

page

int

Default is 0.

size

int

Default is 10.

sort

string

Allowed values are:

  • createdDate

  • endedDate

  • created date/DESC (default)

Response object explained in GET /kairos-api/api/admin/models/build-image/history/{uuid}. Only type is different - TRAINING

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/training/history?page=0&size=1&sort=string

Response Example

200 OK

Response Body
{
  "content": [
    {
      "uuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "jobType": "string",
      "jobStatus": "string",
      "executionSummary": "string",
      "endedDate": "2023-11-13T18:06:27.260Z",
      "createdDate": "2023-11-13T18:06:27.260Z",
      "createdBy": "string",
      "lastModifiedDate": "2023-11-13T18:06:27.260Z",
      "lastModifiedBy": "string",
      "isActive": true,
      "tenant": "string",
      "runId": "string"
    }
  ],
  "totalElements": 1,
  "totalPages": 0,
  "last": true
}
GET /kairos-api/api/admin/training/history/{jobUuid} - Get specific training job by UUID.
As of Version

2023 Winter

Request Method

GET

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Gets specific training job details by UUID.

Response object explained in GET /kairos-api/api/admin/models/build-image/history/{uuid}. Only type is different - TRAINING

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/models/training/history/3fa85f64-5717-4562-b3fc-2c963f66afa6

Response Example

200 OK

Response Body
{
  "uuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "jobType": "string",
  "jobStatus": "string",
  "executionSummary": "string",
  "endedDate": "2023-11-13T18:17:03.193Z",
  "createdDate": "2023-11-13T18:17:03.193Z",
  "createdBy": "string",
  "lastModifiedDate": "2023-11-13T18:17:03.194Z",
  "lastModifiedBy": "string",
  "isActive": true,
  "tenant": "string",
  "runId": "string"
}
POST /kairos-api/api/admin/training/interrupt/{jobUuid} - Interrupt/Delete training job by the job’s UUID.
As of Version

2023 Winter

Request Method

POST

Response Format

HTTP status code

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Interrupts/Deletes training job by UUID of the job.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/training/interrupt/3fa85f64-5717-4562-b3fc-2c963f66afa6

Response Example

200 OK

Experiments
POST /kairos-api/api/admin/experiments/create - Create experiment.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Creates the MLflow experiment. It returns experiment id of created experiment in MLflow tracking server.

Parameters in the JSON request body:

Parameter Type Description

name

string

Name of the new experiment in MLflow

artifactLocation

string

If you want to override the default artifact location

tags

Object

Custom tags to set on MLflow experiment

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/experiments/create

Request body
{
  "name": "string",
  "artifactLocation": "string",
  "tags": [
    {
      "key": "string",
      "value": "string"
    }
  ]
}
Response Example

200 OK

Response Body
{
    "experiment_id": "17"
}
POST /kairos-api/api/admin/experiments/delete - Delete experiment.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Deletes experiments from MLflow tracking server.

Request parameter is experiment id from MLflowW

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/experiments/delete

Request body
{
  "experiment_id": "1"
}
Response Example

200 OK

no response body

POST /kairos-api/api/admin/experiments/search - Search experiments.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Searches experiments in MLflow tracking server.

Request and response property descriptions can be found on the MLflow Documentation Website. Default values for maxResults is 1000 and for viewType is ALL.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/experiments/search

Request body
{
  "maxResults": 10,
  "pageToken": "string",
  "filter": "string",
  "orderBy": [
    "string"
  ],
  "viewType": "ACTIVE_ONLY"
}
Response Example

200 OK

Response Body
{
  "experiments": [
    {
      "experimentId": "string",
      "name": "string",
      "artifactLocation": "string",
      "lifecycleStage": "string",
      "lastUpdateTime": 2018-01-26T15:21:170Z,
      "creationTime": 2018-01-26T15:21:170Z,
      "tags": [
        {
          "key": "string",
          "value": "string"
        }
      ]
    }
  ],
  "nextPageToken": "string"
}
Information on Models
POST /kairos-api/api/admin/models/search - List registered models.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Lists registered models from MLflow tracking server. The response description can be found on the MLflow Documentation Website.

Parameters in the JSON request body:

Parameter Type Description

name

int

Filter by registered model name.

version

int

Filter by registered model version.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/models/search

Request body
{
  "name": "string",
  "version": "string"
}
Response Example

200 OK

Response Body
{
  "registeredModels": [
    {
      "name": "string",
      "creationTimestamp": 2018-01-26T15:21:170Z,
      "lastUpdateTimestamp": 2018-01-26T15:21:170Z,
      "latestVersions": [
        {
          "name": "string",
          "version": "string",
          "creationTimestamp": 2018-01-26T15:21:170Z,
          "lastUpdatedTimestamp": 2018-01-26T15:21:170Z,
          "userId": "string",
          "currentStage": "string",
          "description": "string",
          "source": "string",
          "runId": "string",
          "status": "READY",
          "statusMessage": "string",
          "tags": [
            {
              "key": "string",
              "value": "string"
            }
          ],
          "runLink": "string"
        }
      ]
    }
  ],
  "nextPageToken": "string"
}
Information on Jobs
GET /kairos-api/api/admin/runs/get/{jobUuid} - Get run information by job UUID.
As of Version

2023 Winter

Request Method

GET

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Gets MLflow run information by job UUID. Based on that UUID you are getting runId from your database and collecting the run details from MLflow tracking server.

Response object is explained on the MLflow Documentation Website.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/runs/get/3fa85f64-5717-4562-b3fc-2c963f66afa6

Response Example

200 OK

Response Body
{
  "run": {
    "info": {
      "runId": "string",
      "runName": "string",
      "experimentId": "string",
      "status": "RUNNING",
      "startTime": 2018-01-26T15:21:170Z,
      "endTime": 2018-01-26T15:29:170Z,
      "artifactUri": "string",
      "lifecycleStage": "string"
    },
    "data": {
      "metrics": [
        {
          "key": "string",
          "value": 0,
          "timestamp": 0,
          "step": 0
        }
      ],
      "params": [
        {
          "key": "string",
          "value": "string"
        }
      ],
      "tags": [
        {
          "key": "string",
          "value": "string"
        }
      ]
    },
    "inputs": {
      "datasetInputs": [
        {
          "tags": [
            {
              "key": "string",
              "value": "string"
            }
          ],
          "dataset": {
            "name": "string",
            "digest": "string",
            "sourceType": "string",
            "source": "string",
            "schema": "string",
            "profile": "string"
          }
        }
      ]
    }
  }
}
POST /kairos-api/api/admin/runs/search - Search runs in MLflow tracking server.
As of Version

2023 Winter

Request Method

POST

Response Format

JSON

Request Header

X-ID-TENANT-NAME: tenant_name

Description

Searches runs in MLflow tracking server.

Request and response property descriptions can be found on the MLflow Documentation Website.

Response HTTP status codes:

HTTP status code Meaning

200

OK

400

Bad Request

403

Forbidden

404

Not Found

415

Unsupported Media Type

500

Internal Server Error

Request Example

/kairos-api/api/admin/runs/search

Request body
{
  "experimentIds": [
    "string"
  ],
  "maxResults": 10,
  "pageToken": "string",
  "filter": "string",
  "orderBy": [
    "string"
  ],
  "runViewType": "ACTIVE_ONLY"
}
Response Example

200 OK

Response Body
{
  "runs": [
    {
      "info": {
        "runId": "string",
        "runName": "string",
        "experimentId": "string",
        "status": "RUNNING",
        "startTime": 2018-01-26T15:21:170Z,
        "endTime": 2018-01-26T15:29:170Z,
        "artifactUri": "string",
        "lifecycleStage": "string"
      },
      "data": {
        "metrics": [
          {
            "key": "string",
            "value": 0,
            "timestamp": 0,
            "step": 0
          }
        ],
        "params": [
          {
            "key": "string",
            "value": "string"
          }
        ],
        "tags": [
          {
            "key": "string",
            "value": "string"
          }
        ]
      },
      "inputs": {
        "datasetInputs": [
          {
            "tags": [
              {
                "key": "string",
                "value": "string"
              }
            ],
            "dataset": {
              "name": "string",
              "digest": "string",
              "sourceType": "string",
              "source": "string",
              "schema": "string",
              "profile": "string"
            }
          }
        ]
      }
    }
  ],
  "nextPageToken": "string"
}

8.3.2. Inference Schema

The inference schema is a JSON configuration file defining the object types that will be available for the classification as well as the properties for which the metadata extraction should be done. At the same time, each internal aiObjectTypeId for classification gets a corresponding objectTypeId and each aiPropertyId for metadata extraction gets a corresponding propertyId. They will be used in the response bodies of the classification and extraction endpoints to be compatible with the connected client application.

The inference schema also defines timeouts, allowed values, patterns that should be met, whether the particular mapping is enabled or disabled, etc.

The inference schema can be defined for a specific tenant or for the whole instance. A tenant-specific inference schema will override the global inference schema.

Example for an inference schema
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
{
    "tenant" : "ACME Inc.",
    "classification" : {
        "enabled" : true,
        "timeout" : 2,
        "aiClassifierId" : "DOCUMENT_CLASSIFICATION",
        "objectTypes": [
            {
                "objectTypeId" : "invoiceIn",
                "aiObjectTypeId" : "AI_INVOICE"
            },
            {
                "objectTypeId" : "invoiceOut",
                "aiObjectTypeId" : "AI_INVOICE"
            },
            {
                "objectTypeId" : "creditMemoIn",
                "aiObjectTypeId" : "AI_CREDIT_MEMO"
            },
            {
                "objectTypeId" : "creditMemoOut",
                "aiObjectTypeId" : "AI_CREDIT_MEMO"
            }
        ]
    },
    "extraction" : {
        "enabled" : true,
        "timeout" : 5,
        "objects" : [
            {
                "objectTypeId" : "invoiceIn",
                "enabled" : true,
                "timeout" : 10,
                "propertyReference" : [
                    {
                        "propertyId" : "companyName",
                        "aiPropertyId" : "AI_INVOICE_COMPANY_NAME",
                        "allowedValues" : ["Lufthansa", "KLM", "Swiss"],
                        "pattern" : "/^[a-z]|\\d?[a-zA-Z0-9]?[a-zA-Z0-9\\s&@.]+$",
                        "maxNumberOfPredictions" : 5
                    },
                    {
                        "propertyId" : "baseAmount",
                        "aiPropertyId" : "AI_BASE_AMOUNT",
                        "pattern" : "^[0-9]*[.][0-9]*$",
                        "maxNumberOfPredictions" : 1
                    },
                    {
                        "propertyId" : "totalAmount",
                        "aiPropertyId" : "AI_INVOICE_TOTAL_AMOUNT",
                        "pattern" : "^[0-9]*[.][0-9]*$",
                        "maxNumberOfPredictions" : 1
                    },
                    {
                        "propertyId" : "invoiceDate",
                        "aiPropertyId" : "AI_INVOICE_DATE",
                        "pattern" : "^[0-9]*[.][0-9]*$",
                        "maxNumberOfPredictions" : 1
                    }

                ]
            },
            {
                "objectTypeId" : "invoiceOut",
                "enabled" : true,
                "timeout" : 10,
                "propertyReference" : [
                    {
                        "propertyId" : "companyName",
                        "aiPropertyId" : "AI_INVOICE_COMPANY_NAME",
                        "allowedValues" : ["Lufthansa", "KLM", "Swiss"],
                        "pattern" : "/^[a-z]|\\d?[a-zA-Z0-9]?[a-zA-Z0-9\\s&@.]+$",
                        "maxNumberOfPredictions" : 5
                    },
                    {
                        "propertyId" : "totalAmount",
                        "aiPropertyId" : "AI_INVOICE_TOTAL_AMOUNT",
                        "pattern" : "^[0-9]*[.][0-9]*$",
                        "maxNumberOfPredictions" : 1
                    }
                ]
            },
            {
                "objectTypeId" : "creditMemoIn",
                "enabled" : true,
                "timeout" : 10,
                "propertyReference" : [
                    {
                        "propertyId" : "companyName",
                        "aiPropertyId" : "AI_CREDIT_MEMO_TOTAL_AMOUNT",
                        "allowedValues" : ["Lufthansa", "KLM", "Swiss"],
                        "pattern" : "/^[a-z]|\\d?[a-zA-Z0-9]?[a-zA-Z0-9\\s&@.]+$",
                        "maxNumberOfPredictions" : 5
                    },
                    {
                        "propertyId" : "totalAmount",
                        "aiPropertyId" : "AI_CREDIT_MEMO_TOTAL_AMOUNT",
                        "pattern" : "^[0-9]*[.][0-9]*$",
                        "maxNumberOfPredictions" : 1
                    }
                ]
            },
            {
                "objectTypeId" : "creditMemoOut",
                "enabled" : true,
                "timeout" : 10,
                "propertyReference" : [
                    {
                        "propertyId" : "companyName",
                        "aiPropertyId" : "AI_CREDIT_MEMO_TOTAL_AMOUNT",
                        "allowedValues" : ["Lufthansa", "KLM", "Swiss"],
                        "pattern" : "/^[a-z]|\\d?[a-zA-Z0-9]?[a-zA-Z0-9\\s&@.]+$",
                        "maxNumberOfPredictions" : 5
                    },
                    {
                        "propertyId" : "totalAmount",
                        "aiPropertyId" : "AI_CREDIT_MEMO_TOTAL_AMOUNT",
                        "pattern" : "^[0-9]*[.][0-9]*$",
                        "maxNumberOfPredictions" : 1
                    }
                ]
            }
        ]
    }
}

The following parameters are available in the inference schema:

Parameter Description

tenant

Tenant for which the inference schema will be applied.

classification

Section of parameters for classification processes.

enabled

Boolean value specifying whether the document classification is activated (true) or deactivated (false).

timeout

Time limit for the determination of a classification prediction in seconds.

An error will be thrown if the calculation process could not be finished before the timeout was reached.

aiClassifierId

ID in the AI platform dictionary defining the model that will be used for the classification process.

objectTypes

A list of mappings, each of them containing the following keys. This list defines the object types that are available for the classification prediction.

objectTypeId

The identification of an object type as it will appear in prediction response bodies. You can define a concatenation of several secondary object type IDs, catalog values, etc. that can be interpreted by your client application to show the prediction results in a proper format.

aiObjectTypeId

ID of the internal class label on which the model is trained.

extraction

Section of parameters for metadata extraction processes.

enabled

Boolean value specifying whether the metadata extraction is activated (true) or deactivated (false).

timeout

Time limit for the determination of extraction predictions in seconds.

The result will be returned even if the calculation process is still running for some models. Those models will be excluded from the response.

objects

List of mappings for the individual object types containing the following keys. This list defines the object types for which metadata extraction will be available.

objectTypeId

The ID of the object type as it will be referenced within each object’s metadata in the property system:secondaryObjectTypeIds. This property must already be set during the object creation in yuuvis® Momentum and is thus always assigned to any object to be processed. The available secondary object types are defined in the yuuvis® Momentum schema.

enabled

Boolean value specifying whether the metadata extraction is activated (true) or deactivated (false) for the specific object type.

Ignored if extraction.enabled is set to false.

timeout

Optional time limit in seconds overwriting extraction.timeout for the determination of extraction predictions for properties belonging to the object type specified by objectTypeId.

The result will be returned even if the calculation process is still running for some models. Those models will be excluded from the response.

propertyReference

A list of mappings, each of them containing the following keys. This list defines the properties for which metadata should be extracted for an object of type objectTypeId.

propertyId

The identification of a property as it will appear in prediction response bodies. You can define a concatenation of several secondary object type IDs, catalog values etc. that can be interpreted by your client application to show the prediction results in proper format.

aiPropertyId

ID of the internal property label on which the model is trained.

allowedValues

Optional limitation of the prediction response: List of values for the property specified by propertyId. Only values specified in this list are allowed as prediction results of the metadata extraction.

pattern

Optional limitation of the prediction response: Condition for values for the property specified by propertyId. Only values matching the condition are allowed as prediction results of the metadata extraction.

maxNumberOfPredictions

Optional parameter: An integer value defining the maximum number of values included in the prediction response for the property propertyId.

If not specified, the default value 1 will be used.

To use the Artificial Intelligence Platform with a client application based on our client libraries (e.g., yuuvis® client as a reference implementation), objectTypeId can be defined as a concatenation of app name and SOTs separated by pipes as can be seen in the following example:

Inference schema for the combination with yuuvis® Momentum 'client' service
{
    "tenant" : "os__papi",
    "classification" : {
        "enabled" : true,
        "timeout" : 10,
        "aiClassifierId" : "DOCUMENT_CLASSIFICATION",
        "objectTypes": [
            {
                "objectTypeId" : "appImpulse:hrdocsot|appImpulse:hrDocumentType|Bescheinigung",
                "aiObjectTypeId" : "appImpulse:contractsot"
            },
            {
                "objectTypeId" : "appImpulse:receiptsot",
                "aiObjectTypeId" : "appImpulse:hrdocsot"
            },
            {
                "objectTypeId" : "appImpulse:contractsot|appImpulse:contractType|Arbeitsvertrag",
                "aiObjectTypeId" : "appImpulse:receiptsot"
            },
            {
                "objectTypeId" : "appImpulse:hrdocsot|appImpulse:hrDocumentType|Arbeitsvertrag",
                "aiObjectTypeId" : "appImpulse:basedocumentsot"
            }
        ]
    }
}

8.3.3. Requirements

Serving and platform management components are dockerized and can be deployed to any infrastructure that supports Docker/Kubernetes — on-premises or in the cloud.

To support the customers that have sensitive data and do not want their documents to leave their on-premises systems, the model training can be executed in their own infrastructure and once the models are dockerized, they can be used on-premises or in the cloud, according to customers' needs.

For details on infrastructure requirements, see requirements and dependencies.

8.3.4. Configuration

Service-specific Parameters
Parameter Description Default Value

kairos-api.user.authority.api

Authority (role) user needs to access kairos-api's endpoints with /api suffix.

YUUVIS_AI_PREDICT

kairos-api.user.authority.admin

Authority (role) user needs to access kairos-api's endpoints with /admin suffix.

YUUVIS_TENANT_ADMIN

kairos-api.user.authority.system

Authority (role) user needs to access kairos-api's endpoints with /system suffix.

YUUVIS_SYSTEM_INTEGRATOR

kairos-api.config.inference-schema.name

Name of the file in Git where inference schema is located. The file is read/updated via configservice.

ai-inference-schema.json

kairos-api.yuuvis.client.url

URL of the yuuvis® client application, used by predict-api for communication with core API

http://api

kairos-api.mlflow.client.url

URL where MLflow TS instance is located

http://mlflow-tracking-server.ml-infrastructure:5000

Preprocessing Service Parameters

When starting a preprocessing job via POST /kairos-api/api/admin/preprocessing the service is triggered to create an instance of the job from an image provided by configuration. If the specified namespace (e.g., ml-infrastructure) does not exist, it is created.

Kubernetes properties
kairos-api:
  k8s:
    namespace: ml-infrastructure
    preprocessing:
      image: docker.optimal-systems.org/team-owl/preprocessing-service:0.0.1
      image-pull-secret: preprocessing-service-registry-token
      env:
        secrets:
          S3_CONFIG_DICT_KAIROS: aws-preprocessing-details
        variables:
          SOURCE_DIR: "s3:/test/pdfs/"
          TARGET_DIR: "s3:/mlflow/pkl/"
          METADATA_DIR: "s3:/test/metadata/"
          REPORT_DIR: "s3:/mlflow/reports/"
          REPORT_NAME: "test-kairos-api"
          NUM_WORKERS: 1
          SKIP: true
          SYNCHRONIZE_DIRS: true
    job:
     ttl-seconds-after-finished: 120

Explanations and hints:

  • The image to be used for each started job is configured by image tag, image pull secret and credentials.

  • The namespace indicates where the preprocessing jobs should be located within the cluster.

  • Also, env variables for the preprocessing service can be listed in env.variables section.

  • The env variables that represent security concerns such as AWS credentials can be read from secrets. Configure them in the env.secret section.

    The secret contains an env variable with the same name but encrypted.
  • The parameter ttl-seconds-after-finished is recommended to be set. It represents the number of seconds that Kubernetes leaves the job in the cluster for our manual analyses. If this time is expired, the job will be deleted from the cluster.

  • The job watcher component monitors jobs within the namespace and reacts to events on jobs. The following event handlers are available: onAdd, onUpdate, and onDelete.

Training Service Parameters

The namespace and ttl-seconds-after-finish parameters are shared.

A job watcher will track the training jobs as well.

For more details on Kubernetes-related parameters, see configuration description of preprocessing service.

Kubernetes properties
kairos-api:
  k8s:
    namespace: ml-infrastructure
    training:
      image: docker.optimal-systems.org/team-owl/kairos/transformers_extraction_train
      image-pull-secret: kairos-registry-token
      env:
        secrets:
          S3_CONFIG_DICT_KAIROS: aws-training-details
          KAIROS_API_DB_USERNAME: kairosapidb-secret
          KAIROS_API_DB_PASSWORD: kairosapidb-secret
        variables:
          MLFLOW_TRACKING_URI: "http://mlflow-tracking-server:5000"
          MLFLOW_EXPERIMENT_ID: 0
          IN_DATA_DIR: "s3:/data/pkl/"
          MAX_EPOCHS: 1
          TRAIN_BS: 32
          VALID_BS: 32
          TRAINING_LABELS: "{'matchers':{'INVOICE_RECEIVER_NAME':{'matcher':{'name':'MultiTokenTextMatcher','args':{'threshold':0.6}}},'INVOICE_ISSUER_NAME':{'matcher':{'name':'MultiTokenTextMatcher','args':{'threshold':0.6}}},'INVOICE_NUMBER':{'matcher':{'name':'MultiTokenTextMatcher','args':{'threshold':0.7}}},'INVOICE_ISSUE_DATE':{'matcher':{'name':'MultiTokenDateMatcher','args':{'max_iter_words':5,'date_formats':['%Y%m%d','%Y%m%d000000']}}},'INVOICE_TOTAL_AMOUNT':{'matcher':{'name':'DecimalMatcher'}},'INVOICE_BASE_AMOUNT':{'matcher':{'name':'DecimalMatcher'}}}}"
          DOCLOAD_NUM_WORKERS: 3
          DATASET_NUM_WORKERS: 3
          KAIROS_API_DB_HOST: "postgres.infrastructure:5432"
          KAIROS_API_DB_NAME: kairosapidb
    job:
      ttl-seconds-after-finished: 120
  • The image used here is used for model training. It is configured with image tag, image pull secret, and the URL to the MLflow tracking service that is internally used to run and log the training jobs.

  • An experiment can be configured under which the training will run.

  • The minio directory for storing the dataset is configured via bucket and folder as well as credentials to the minio instance.

  • Labels for the transformers-based training and some other training-related parameters are available.

  • The env variables can be read from secret (critical data - AWS credentials) or directly.

  • The run ID is set to be UUID that is created during writing the job information in the database. kairos-api handles it as environment variable RUN_ID.

Model Build Parameters

The job for model docker image build uses kaniko for which most configuration parameters are set.

However, the S3_ENDPOINT parameter can be used to customize the location of the minio instance for storing the model artifacts.

kaniko-build:
  image: gcr.io/kaniko-project/executor:latest
  env:
    variables:
      DEBUG: true
      S3_FORCE_PATH_STYLE: true
      S3_ENDPOINT: "http://mlflow-minio.infrastructure:9000"
Database Schema

The kairos-api service uses its own database. It is initialized with the installation of a separate Helm chart with ConfigMap to create a valid database and user for our service and to grant all privileges to that user.

The database table job_details is populated with information about the jobs. The status of each individual job is stored in the table as well. Following states are available: IS_RUNNING, COMPLETE, FAILED, INTERRUPTED.

Columns of the job_details table:

Column Name Type

id

BIGINT

created_date

DATETIME

created_by

VARCHAR(255)

last_modified_date

DATETIME

last_modified_by

VARCHAR(255)

is_active

BOOLEAN

tenant

VARCHAR(255)

job_type

VARCHAR(255)

job_status

VARCHAR(255)

execution_summary

VARCHAR(255)

ended_date

DATETIME

uuid

UUID

run_id

VARCHAR(255)

9. E-mail Archive

9.1. Introduction

This e-mail archive solution manages indexing and storing of e-mails in yuuvis® Momentum that were sent or received via an external e-mail provider. This compliant storage of e-mails is based on international regulations regarding privacy and data protection.

The e-mail archive can handle journaling reports or conventional e-mails. They are stored in yuuvis® Momentum as individual DMS objects with corresponding metadata as well as an internal text rendition for full-text search.

The service is designed to work primarily with Microsoft Exchange Online. It is also possible to connect other e-mail providers using SMTP. However, this documentation describes configurations and functionality for using of MS Exchange Online.

9.2. Architecture and Function

The e-mail archive contains three different services. The massmtp and masmailbox services are responsible for e-mail communication and the masstoragemomentum service is responsible for storing mail messages in yuuvis® Momentum.

There are three different formats of e-mail retrieval from the e-mail provider:

  • conventional e-mails

  • Microsoft Exchange Online journal reports

  • non-deliverable reports

One of these formats is selected in the connection configuration of each individual mailbox. The concrete configuration parameters differ for a connection via massmtp or masmailbox service as described in the configuration section.

9.3. Journaling

An e-mail imported as journal report corresponds to exactly one DMS object in yuuvis® Momentum. It consists of metadata and binary content.

In the metadata, a participants property is filled with a list of all e-mail addresses that are involved. This property simplifies the definition of proper access rights. Which addresses are actually added to the property depends on the journaling mode used.

9.3.1. Journal and Alternate Mode

This mode uses the masmailbox service.

The journaling mailboxes have to be listed in mas-mailbox.journaling.mailboxes.

Each e-mail that is successfully stored in yuuvis® Momentum is permanently deleted from the corresponding mailbox.

The participants property is filled with a list of all e-mail addresses that are involved as FROM, TO, CC or BCC.

The determined e-mail addresses are resolved as follows:

  • Mailing lists and mail-enabled security groups are split in their individual member addresses.

  • If secondary addresses are used for configured domains, they are turned to primary addresses (domain list and access to graph API required, find details in the configuration section).

9.3.2. Normal Mode

This mode uses the masmailbox service.

The participants property is filled with a list of all e-mail addresses that are involved as FROM, TO or CC.

The e-mail address resolving rules are the same as for the journal mode.

9.3.3. Journaling without Exchange Online

This mode uses SMTP via massmpt service.

The type of accepted messages is configured via mas-smtp.message-mode.

The bundled SMTP server can be bound to a configurable port and can work with or without TLS. The service extracts MailMessage objects from the received e-mails and provides them for storing in yuuvis® Momentum.

To avoid spam in yuuvis® Momentum, the processing can be limited to a list of allowed receivers as well as allowed senders.

The participants property is filled with a list of all e-mail addresses that are involved as FROM, TO, CC or BCC.

The determined e-mails are not resolved. Mailing lists and secondary addresses are kept as they are.

9.4. Mailbox Archiving

This mode uses the masmailbox service.

The mailboxes to be archived have to be listed in mas-mailbox.archiving.mailboxes.

The service tags the e-mails within the mailboxes. Thus, the mailbox user can trace which e-mails are already stored in yuuvis® Momentum.

When an e-mail is imported via mailbox archiving, a separate DMS object is created for each e-mail address involved as FROM, TO, CC or BCC. Each duplicate refers to the same binary content but has its own metadata. This allows the individual users to apply changes to the metadata of their own objects according to their wishes. For example, users can 'move' their e-mail objects in their own private folders without affecting the objects of other involved users.

The participants property contains only the configured mailbox’s address. None of the e-mail addresses that are involved as FROM, TO, CC or BCC are included.

9.5. Deduplication

It is rather common that e-mail addresses are included in multiple mailing lists. As it is possible that two or more of those mailing lists are connected as mailboxes to the e-mail archive, users would find their e-mails twice or more in yuuvis® Momentum. To avoid this duplication, the e-mail archive behaves as follows.

Incoming e-mail Already existing e-mail Impact on the existing e-mail

Journal e-mail

Journal e-mail

The metadata of the existing e-mail is replaced by the metadata of incoming e-mail.

Archive e-mail

Archive e-mail

  • If both e-mails should be stored for the same user, the existing metadata are replaced by the metadata of incoming email.

  • If the incoming and the existing e-mail should be stored for different users, the incoming e-mail is created as a new DMS object but refers to the already existing binary content.

Journal e-mail

Archive e-mail

The incoming e-mail is created as a new DMS object but refers to the already existing binary content.

The user for which the e-mail already exists is removed from participants of the new e-mail.

Archive e-mail

Journal e-mail

The incoming e-mail is created as a new DMS object but refers to the already existing binary content.

The user for which the e-mail already exists is removed from participants of the existing e-mail.

9.5.1. Access Management

During the login, an app-specific webhook adds the user’s e-mail addresses as connectedEmails parameter to the abac section of the internal JSON web token (JWT).

The user’s roles grant the permissions to retrieve/update an e-mail DMS object in yuuvis® Momentum.

9.7. Installation

The e-mail archive solution can be installed via Helm chart.

9.8. Configuration

9.8.1. Schema 'mailarchiving'

The e-mail requires the following app schema. It must be imported into the yuuvis® Momentum system and the mailarchiving app must be activated for the tenant.

App schema for 'mailarchiving' app
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/">
    <!-- access control -->
    <propertyStringDefinition>
        <id>appMailarchiving:participants</id>
        <propertyType>string</propertyType>
        <cardinality>multi</cardinality>
        <required>false</required>
    </propertyStringDefinition>

    <!-- grouping properties -->
    <propertyStringDefinition>
        <id>appMailarchiving:user</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>true</required>
    </propertyStringDefinition>

    <!-- report properties -->
    <propertyTableDefinition>
        <id>appMailarchiving:reportInfo</id>
        <propertyType>table</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
        <propertyStringDefinition>
            <id>reportId</id>
            <propertyType>string</propertyType>
            <cardinality>single</cardinality>
            <required>false</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>reportChannel</id>
            <propertyType>string</propertyType>
            <cardinality>single</cardinality>
            <required>false</required>
        </propertyStringDefinition>
        <propertyDateTimeDefinition>
            <id>reportTime</id>
            <propertyType>datetime</propertyType>
            <cardinality>single</cardinality>
            <required>false</required>
        </propertyDateTimeDefinition>
    </propertyTableDefinition>
    <propertyStringDefinition>
        <id>appMailarchiving:reportRecipients</id>
        <propertyType>string</propertyType>
        <cardinality>multi</cardinality>
        <required>false</required>
    </propertyStringDefinition>

    <!-- message properties -->
    <propertyDateTimeDefinition>
        <id>appMailarchiving:messageReceivedTime</id>
        <propertyType>datetime</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyDateTimeDefinition>
    <propertyIntegerDefinition>
        <id>appMailarchiving:messageSize</id>
        <propertyType>integer</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
        <minValue>0</minValue>
    </propertyIntegerDefinition>
    <propertyStringDefinition>
        <id>appMailarchiving:messageBody</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>appMailarchiving:messagePriority</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>appMailarchiving:messagePrivacy</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <propertyBooleanDefinition>
        <id>appMailarchiving:messageHasAttachments</id>
        <propertyType>boolean</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyBooleanDefinition>
    <propertyStringDefinition>
        <id>appMailarchiving:messageHeaders</id>
        <propertyType>string</propertyType>
        <cardinality>multi</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>appMailarchiving:messageDigest</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>

    <!-- mailbox properties -->
    <propertyStringDefinition>
        <id>appMailarchiving:mailboxName</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>appMailarchiving:mailboxMessageId</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>appMailarchiving:mailboxFolder</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>appMailarchiving:mailboxCategory</id>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyStringDefinition>

        <!-- secondary object types for report, message and mailbox -->
    <typeSecondaryDefinition>
        <id>appMailarchiving:reportData</id>
        <baseId>system:secondary</baseId>
        <propertyReference>appMailarchiving:reportInfo</propertyReference>
        <propertyReference>appMailarchiving:reportRecipients</propertyReference>
    </typeSecondaryDefinition>
    <typeSecondaryDefinition>
        <id>appMailarchiving:messageData</id>
        <baseId>system:secondary</baseId>
        <propertyReference>appMailarchiving:messageReceivedTime</propertyReference>
        <propertyReference>appMailarchiving:messageSize</propertyReference>
        <propertyReference>appMailarchiving:messageBody</propertyReference>
        <propertyReference>appMailarchiving:messagePriority</propertyReference>
        <propertyReference>appMailarchiving:messagePrivacy</propertyReference>
        <propertyReference>appMailarchiving:messageHasAttachments</propertyReference>
        <propertyReference>appMailarchiving:messageHeaders</propertyReference>
        <propertyReference>appMailarchiving:messageDigest</propertyReference>
        <propertyReference>appMailarchiving:user</propertyReference>
        <propertyReference>appMailarchiving:participants</propertyReference>
    </typeSecondaryDefinition>
    <typeSecondaryDefinition>
        <id>appMailarchiving:mailboxData</id>
        <baseId>system:secondary</baseId>
        <propertyReference>appMailarchiving:mailboxName</propertyReference>
        <propertyReference>appMailarchiving:mailboxMessageId</propertyReference>
        <propertyReference>appMailarchiving:mailboxFolder</propertyReference>
        <propertyReference>appMailarchiving:mailboxCategory</propertyReference>
    </typeSecondaryDefinition>
</schema>

9.8.2. Apps

The following two apps must be enabled for all tenants that use the e-mail archive:

The e-mail archive uses object types from both app schemata.

  • The secondary types (SOTs) appSystemmail:email and appMailarchiving:messageData are assigned to every stored e-mail object.

  • If the e-mail is a journal report, it additionally gets the appMailarchiving:reportData SOT.

  • If the e-mail is retrieved from a mailbox, it additionally gets the appMailarchiving:mailboxData SOT.

9.8.3. Role Set

It is possible to define your own roles according to your needs.

To use the e-mail archive’s default roles, set the following role set for the mailarchiving app via POST /api/system/apps/mailarchiving/permissions.

Default role set for 'mailarchiving' app
<roleSet xmlns="http://optimal-systems.org/ns/dmscloud/roleset/">
    <role>
        <name>ROLE_MAILARCHIVING_ALL</name>
        <permission>
            <action>create</action>
            <action>read</action>
            <action>delete</action>
            <action>write</action>
            <condition>system:secondaryObjectTypeIds in ('appMailarchiving:messageData')</condition>
        </permission>
    </role>
                <role>
        <name>ROLE_MAILARCHIVING_JOURNALING</name>
        <permission>
            <action>read</action>
            <condition>system:secondaryObjectTypeIds in ('appMailarchiving:messageData') and appMailarchiving:user in ('Journaling')</condition>
        </permission>
    </role>
    <role>
        <name>ROLE_MAILARCHIVING_OWN</name>
        <permission>
            <action>read</action>
            <condition>system:secondaryObjectTypeIds in ('appMailarchiving:messageData') and appMailarchiving:participants IN @abac.mailboxes</condition>
        </permission>
    </role>
</roleSet>

Assigning the default roles to users grants the following permissions:

  • ROLE_MAILARCHIVING_ALL grants all permissions on DMS objects having the appMailarchiving:messageData SOT.

  • ROLE_MAILARCHIVING_JOURNALING grants the read permission on DMS objects having the appMailarchiving:messageData SOT and Journaling as value for appMailarchiving:user.

  • ROLE_MAILARCHIVING_OWN grants the read permission on DMS objects having the appMailarchiving:messageData SOT and one of the actual user’s e-mail addresses is included in the appMailarchiving:participants.

9.8.4. Webhook

The e-mail archive uses a specific user.info webhook to enrich the user information in the internal JSON web token with an abac section containing the corresponding user’s e-mail addresses. The enrichment is only done for users with the roles listed in mas-storage-momentum.user-info.roles.

The e-mail archive’s webhook retrieves the user’s e-mail addresses from two data sources:

  • yuuvis® Momentum userservice

  • Azure AD via Graph API (if access is configured)

To configure the webhook, go through the following steps:

  • Retrieve the global systemHookConfiguration.json via GET /api/system/systemhooks.

  • Copy the URL of the user.info webhook and paste the value to the mas-storage-momentum.user-info.url parameter.

  • In the global systemHookConfiguration.json, replace the user.info webhook configuration by the following configuration and apply it via POST /api/system/systemhooks.

    Webhook configuration
    {
      "enable": true,
      "predicate" : "spel:true",
      "type": "user.info",
      "url": "http://mailarchiving-storage.mailarchiving/api/abac/${tenant}/${userId}",
      "useDiscovery" : false
    }

9.8.5. Common Configuration Parameters

The following parameters are configured in the application-mas.yml configuration file that can be read by all services with activated mas profile. In the default configuration, this applies to masstoragemomentum and masmailbox.

Encryption of values
All values within the configuration file can be encrypted. This is especially recommended for credentials.
Parameter Type Description Example value

mas.mailbox-related-storage.folder-name-config.domains

Comma-separated string values

Domains that are part of Active Directory are used to resolve user mails, for each mail that is part of configured domains. If empty, no user mail resolving will be invoked.

Read by masstoragemomentum service.

osdevtest.de, opt-syst.com

mas.mailbox-related-storage.folder-name-config.property

String

Configuration parameter used to determine a value for a single user mail from the Active Directory account. This value is used to populate appMailarchiving:user property of the DMS e-mail object in yuuvis® Momentum which is further used to resolve user access. If the value cannot be determined from the Active Directory, the user’s e-mail address will be used.

Possible values are:

  • USERNAME (default)

  • SAM_ACCOUNT_NAME

  • LAST_NAME

  • FIRST_NAME

  • DISPLAY_NAME

Read by masstoragemomentum service.

mas.exchange-online.access.client-id

String

Application authentication parameter for the Azure portal.

Read by masstoragemomentum and masmailbox services.

mas.exchange-online.access.tenant-id

String

Application authentication parameter on Azure portal.

Read by masstoragemomentum and masmailbox services.

mas.exchange-online.access.secret

String

Application authentication parameter on Azure portal.

Read by masstoragemomentum and masmailbox services.

9.8.6. Configuration of 'masmailbox' Service

In addition to the common configuration parameters, the masmailbox service uses the following service-specific parameters. They are configured either during the installation or later in the masmailbox-prod.yml configuration file in Git.

Parameter Type Description Example value

mas.exchange-online.access.page-size

Integer

Maximum number of messages in one batch request to the mailbox. The next batch is requested as soon as the processing of the previous one is completed. Thus, the larger the batch size, the higher the performance but the higher the delay of some individual messages.

Value should not be greater than 999. Default is 999 (recommended).

999

mas-mailbox.health-cache-duration

Integer

Expensive health check operations of resolving mailboxes against A.D. are cached. This parameter represents health cache duration in hours. Default is 6.

6

mas-mailbox.journaling.mailboxes

List of mailbox configurations

Each list entry requires the following parameters:

  • mailbox- Backup mailbox which will be used if needed. If no value is set, the service will conclude that no backup mailbox is needed.

  • read-folder - Backup mailbox folder from which the service should extract messages.

  • message-mode - Kind of messages to be read from the backup mailbox. If backup mailbox stores journal reports, value should be JOURNAL. If backup mailbox stores NDR (non-delivery reports), value should be ALTERNATE. If backup mailbox stores conventional e-mails, value should be NORMAL. Details here.

The value is case-sensitive.
journaling:
  mailboxes:
    - mailbox: root@myprovider.de
      read-folder: Inbox
      message-mode: ALTERNATE
    - mailbox: optimal@myprovider.de
      read-folder: Posteingang
      message-mode: JOURNAL

mas-mailbox.categories.archived

String

A note that is assigned to all successfully archived e-mails in the mailbox to inform the mailbox user. Default is Archived.

Archived

mas-mailbox.categories.error

String

A note that is assigned to all e-mails in the mailbox for which the archiving failed to inform the mailbox user. Default is Error.

Error

mas-mailbox.archiving.mailboxes

List of Strings

List of primary mailboxes, shared mailboxes and distribution lists for mailbox archiving. Details here.

- devtest@osdevtest.de
- distribMail@osdevtest.de

mas-mailbox.archiving.groups

List of Strings

Active Directory groups of type 'Distibution group' for archiving

- Team group
- Developers group

mas-mailbox.archiving.whitelist

Comma-separated string values

Folders within the mailboxes from which the service should read the e-mails for archiving.

The value is case-sensitive.

Inbox, Sent

mas-mailbox.archiving.blacklist

Comma-separated string values

Folders within the mailboxes that should be skipped (means not archived).

The value is case-sensitive.

Outbox, Personal

9.8.7. Configuration of 'masstoragemomentum' Service

In addition to the common configuration parameters, the masstoragemomentum service uses the following service-specific parameters. They are configured either during the installation or later in the masstoragemomentum-prod.yml configuration file in Git.

Parameter Type Description Example value

mas-storage-momentum.dms.url

Boolean

URI of the DMS that should receive requests from storage service.

https://myfirsttenant.mycluster.net

mas-storage-momentum.dms.username

String

Username for yuuvis® Momentum authentication.

root

mas-storage-momentum.dms.password

String

Password for yuuvis® Momentum authentication.

changeme

mas-storage-momentum.dms.tenant

String

Tenant in yuuvis® Momentum.

myfirsttenant

mas-storage-momentum.user-info.mailbox-mapping

Structure of mailbox-mappings

Property contains multiple mailbox mappings. The yuuvis® Momentum user with the e-mail defined as key gets access to mails from the mapped mailboxes. The key part of configuration (i.e. mail address in square brackets and quotes) needs to be the same as in yuuvis® Momentum.

mas-storage-momentum.user-info.url

String

Original URL for retrieval of user roles via user.info webhook. In systems without e-mail archive, the URL is set in the systemWebHooksConfiguration.json configuration file.

"http://system.mynamespace/api/userinfo/${tenant}/${userId}"

mas-storage-momentum.user-info.roles

Structure of listed role per line starting with the dash (see Value example column for clarification).

Represents a user role for which the abac section should be added to JWT during login process.

Default:

- ROLE_MAILARCHIVING_OWN
- ROLE_MAILARCHIVING_OWN
- ROLE_MAILARCHIVING_USER

9.8.8. Configuration of 'massmtp' Service

In addition to the common configuration parameters, the massmtp service uses the following service-specific parameters. They are configured either during the installation or later in the massmtp-prod.yml configuration file in Git.

Parameter Type Description Example value

mas-smtp.port

Integer

Port on which SMTP will listen for the incoming messages. Must be greater than 1024. Default is 25000.

25000

mas-smtp.base-auth.username

String

Username for SMTP authentication.

smtpUser

mas-smtp.base-auth.password

String

Password for SMTP authentication.

smtpUserPassword

mas-smtp.tls.require-tls

Boolean

Value should be set to true if TLS is required for SMTP to receive messages. Default is false.

true

mas-smtp.tls.key-store-file

String

In case TLS is required, this property should contain the path to the file with the SSL certification.

<absolute file path>

mas-smtp.tls.key-store-pass

String

In case TLS is required, this property should contain the password for the key-store-file.

passSample

mas-smtp.tls.key-store-type

String

In case TLS is required, this property should contain the value for key store type. Default is PKCS12

JKS

mas-smtp.restrictions.allowed-senders

String

List of comma-separated entries that represent allowed senders for incoming SMTP messages. If empty, all senders will be allowed.

Please check if the e-mail provider replaces the original e-mail address with the mailbox address for the archived messages.

optimal@os.de, systems@mail.com

mas-smtp.restrictions.allowed-recipients

String

List of comma-separated entries that represent allowed recipients for incoming SMTP messages. If empty, all recipients will be allowed.

Please check if the e-mail provider replaces the original e-mail address with the mailbox address for the archived messages.

systems@mail.com, optimal@os.de

mas-smtp.message-mode

String

Determines which kind of messages will be received via SMTP channel. Available values:

  • JOURNAL (default) - receive journal reports

  • ALTERNATE - receive NDR (non-delivery reports)

  • NORMAL - receive conventional e-mails

JOURNAL

9.9. Maintenance

9.9.1. Health Checks

Calling the health check endpoint GET <service>/manage/health for the individual services triggers multiple health checks for the corresponding components. The response JSON contains the following service-specific information.

Health Check for 'masstoragemomentum'
Parameter Response Example for status UP Response Example for status DOWN

DMS Health Check

dms.details.productLine

"yuuvis Momentum"

-----

dms.details.dmsVersion

"4.13.8"

-----

dms.details.systemVersion

"yuuvis Momentum - 2021 Winter"

-----

dms.details.http-statuscode

-----

<error message>

Schema Health Check

schema.details.emailObjectModel

"ObjectModel available."

-----

http-statuscode

-----

<error message>

User Directory Health Check

userDirectory.details.user-directory-status

"All domains are correctly configured."

"Misconfigured domains are: example-domain.org"

Health Check for 'massmtp'
Parameter Response Example for status UP Response Example for status DOWN

SMTP Health Check

smtp.details.port

25000

-----

smtp.details.tls

true / false

-----

smtp.details.missing key-store-file

-----

"TLS keyStore file not configured"

smtp.details.missing key-store-pass

-----

"TLS keyStore passphrase not configured"

Health Check for 'masmailbox'
(Example) Parameter Response Example for status UP Response Example for status DOWN

Mailbox Archiving Health Check

mailboxArchiving.details.example@mailbox.com

"Archiving mailbox successfully reached"

"Unable to find archiving mailbox"

mailboxArchiving.details.exampleGroup

"Archiving group successfully reached"

"Unable to find archiving group"

mailboxArchiving.details.archiving-mailbox-status

"Archiving mailboxes are not configured for use."

-----

mailboxArchiving.details.timestamp

"2023-06-26T16:36:12.766570200"

-----

Mailbox Journaling Health Check

mailboxJournaling.details.example1@mailbox.com

"Journaling mailbox successfully reached"

"No read folder defined for mailbox"

mailboxJournaling.details.example2@mailbox.com

"Journaling mailbox successfully reached"

"Journaling mailbox or folder is not correctly configured or could not be reached"

mailboxJournaling.details.journaling-mailbox-status

"Journaling mailboxes are not configured for use."

-----

mailboxjournaling.details.timestamp

"2023-06-26T16:36:12.766570200"

-----

9.9.2. Logs

The logs of the individual services can be accessed via the following commands.

  • Check the pod number of the service for which you need the log:

    kubectl get pods -n 'pod_namespace'
  • Get the logs of the corresponding pod:

    kubectl -n 'pod_namespace' logs 'pod_name'
  • To export the logs to a file, add the following additional parameters:

    kubectl -n 'pod_namespace' logs 'pod_name' > filename.log

Alternatively, a 3rd-party tool like, e.g., OpenLens can be used to manage pods and access logs:

  • Open OpenLens and connect to the cluster.

  • Select the Workloads tab on the left.

  • Select Pods from the expanded Workloads tab.

  • Find the pod that starts with the service name.

  • Select the Settings Icon of the pod and select Logs.

  • Optional: Export the logs by clicking Download on the bottom right.

9.10. Metrics

The metrics can be accessed via the services' ports using the endpoint https://<ip>:<port>/manage/metrics.

For example, the number of stored e-mails can be retrieved via https://<ip>:<port>/manage/metrics/storage_messages_processed_total.

Internal Endpoint
This endpoint is available only for services within the yuuvis® Momentum cluster. Never expose it for public access in the authentication-prod.yml configuration file.

Within the yuuvis ® Momentum cluster, this endpoint can be called by monitoring tools such as Prometheus. The cluster admin can extend the prometheus configuration as shown in the following example.

scrape_configs:

  - job_name: "masstorage"
    scrape_interval: 15s
    metrics_path: '/manage/prometheus'
    static_configs:
      - targets: ["localhost:8130"]

  - job_name: "massmtp"
    scrape_interval: 15s
    metrics_path: '/manage/prometheus'
    static_configs:
      - targets: ["localhost:8120"]

  - job_name: "masmailbox"
    scrape_interval: 15s
    metrics_path: '/manage/prometheus'
    static_configs:
      - targets: ["localhost:8110"]

10. Release Information

10.1. Version Maintenance

yuuvis® Momentum is released in a release train strategy, with one release per quarter. The releases are labelled with a year and season, e.g., 2023 Spring, 2023 Summer, 2023 Autumn etc. In the regular maintenance package, a one-year long-term support (LTS) release is included.

10.1.1. Regular Maintenance

Every Winter release will always be treated as a regular LTS release and will be maintained for the duration of one year and one quarter, until the next Winter release is available, which then supersedes the previous LTS release. There are no further features added in an LTS version during the maintenance period. For example, 2022 Winter will be the regular LTS version, and will be supported for an additional quarter after 2023 Winter is released, which is until 2024 Spring. During this time, new features will be made available in releases 2023 Spring, 2023 Summer, 2023 Autumn and ultimately 2024 Winter which will then become the new regular LTS release.

All releases between two Winter releases (Spring, Summer and Autumn) will supersede each other sequentially in the order of their release. For example, release 2023 Spring will be maintained until release 2023 Summer (three months). After 2023 Summer is released, 2023 Spring will not be maintained anymore, and all fixes will be available in the 2023 Summer version only.

10.1.2. Updates and Compatibility

Update is possible and guaranteed:

  • Between two successive regular LTS releases, for example 2022 Winter to 2023 Winter. We furthermore require that all hotfixes are applied to the previous regular LTS before the update.

  • Between all releases from the release train of the same year, for example 2023 Spring to 2023 Summer or 2023 Autumn.

We make no further statements about version compatibility of different releases. We expect furthermore that releases are installed completely and do not allow mixing of components from different releases. The individual components within a release will respect and follow the semantic versioning, where major component version denotes API breaking changes.

10.2. Requirements and Dependencies

yuuvis® Momentum is a product with a lot of variety for customers. The core services can be combined with different third-party software products, selected by the customers according to their needs.

The systems listed have been tested in the listed versions together with the current release in the OPTIMAL SYSTEMS release tests and their compatibility has been ensured.

yuuvis® Momentum uses standardized interfaces and integration technologies, meaning that yuuvis® Momentum also works with a wide range of older or more recent versions of the systems listed and with other unlisted systems. OPTIMAL SYSTEMS does not guarantee compatibility for systems not listed in the system requirements and performs its services subject to restrictions (in particular, no damage repair) in accordance with the prevailing maintenance contracts. In addition, OPTIMAL SYSTEMS guarantees compatibility with a listed system up until the date that the manufacturer guarantees regular (for example, not extended, expanded, individually agreed) support.
The system requirements describe the infrastructure needed for a productive yuuvis® Momentum system to provide adequate operational performance. This information is a set of non-binding guidelines. OPTIMAL SYSTEMS can only give a guarantee for a specific system environment on the basis of a customized hardware constellation.

10.2.1. Core

Kubernetes

Kubernetes is required for installation and operation of yuuvis® Momentum instances. The versions listed below are supported.

Kubernetes Version

1.19

1.20

1.21

1.22

1.23

1.24

1.25

1.26

1.27

1.28

1.29

1.30

Helm

Deployments for yuuvis® Momentum are offered via Helm charts and thus require the installation of Helm. The supported versions are listed below.

Helm Versions

3.2.4

Databases

yuuvis® Momentum requires a relational database instance to store and manage metadata and content files. Many software products are available and can be combined with yuuvis® Momentum. We highly recommend providing yuuvis® Momentum with an exclusive database to ensure performance.

The system requirements for the individual manufacturers must be observed for operation of the relevant database system.

yuuvis® Momentum supports the following databases:

Database Management System Version

PostgreSQL

14.x

15.x

16.x

CockroachDB

19.2.1 - 20.2 and 21.1

Microsoft SQL Server

2012 (32- and 64-bit)

2014 (32- and 64-bit)

2016 (32- and 64-bit)

2017 (32- and 64-bit)

2017 (32- and 64-bit)

2019 (32- and 64-bit)

SSL connection or configuration adjustment is required. Find details here.
Search Engine

yuuvis® Momentum works together with the open source search engine Elasticsearch. The following versions are tested with the current yuuvis® Momentum release.

Elasticsearch Versions

7.17.x (as of 2023 Autumn)

7.16.x

7.9.x

7.3.x

In order to operate Elasticsearch together with yuuvis® Momentum, the following plugins are additionally required. Please install a version that is supported by your Elasticsearch version.

  • Intrafind Linguistic Plugin

  • ICU Analysis Plugin

Redis

In order to ensure synchrony in internal processes of yuuvis® Momentum, an in-memory data structure store is required. Our tested recommendation is Redis.

Redis Versions

6.x

7.x

Messaging Systems

yuuvis® Momentum uses the OASIS Advanced Message Queuing Protocoll (AMQP) Version 1.0 for internal messaging. The messaging systems of the corresponding versions listed below are tested with yuuvis® Momentum. Since RabbitMQ does not support AMQP Version 1.0, an additional plugin is required.

Messaging System Versions Additional Required Plugin

ActiveMQ

5.15.4

-

RabbitMQ

3.8.9 - 3.12

rabbitmq_amqp1_0

Git

We strongly recommend to use Git as config store for yuuvis® Momentum, that acts as a version control system at the same time. In general, any git server should be sufficient. However, we tested the git servers listed below with the corresponding versions.

Git Server Minimum Required Version

Gogs

0.11.91

Gitea

1.12.0

GitLab

11.10.8

Identity Provider

For operation of yuuvis® Momentum, an authentication provider is required. In general, any authentication provider supporting the OAuth 2.0 protocol can be combined with yuuvis® Momentum. However, we perform all our tests with Keycloak. The supported versions are listed below.

Keycloak Versions

7.0.0

10.0.2

11.0.2

15.0.2

19.0.2

22.0.2 (as of 2023 Autumn)

23.0.6 (as of 2024 Spring)

24.0.2 (2023 Winter - 2024 Summer)

Storage

S3 Store

yuuvis® Momentum is working with an S3 directory that has to be connected via a service supporting the S3 protocol. All our tests are performed with MinIO, that can operate as store and as protocol service at the same time. It can also be used to connect an S3 store of a different provider to yuuvis® Momentum.

MinIO Versions

RELEASE.2020-10-18T21-54-12Z

Optional: Further Supported Archive Drivers

The repository Service allows to connect additional archives. The following archive drivers are supported. The configuration parameters have to be specified in the application-storage.yml configuration file.

Provider Version Supported Protocols Archive-Internal Retention

Cloudian HyperStore

7.2

s3-based

supported

Dell EMC ECS (Elastic Cloud Storage)

DellECM-ECS-CE-3.7

S3 REST API

supported

NetApp

file system-based

supported

Azure Blob Storage

REST API

supported

Google Cloud Storage

REST API

supported

File System

not supported

The following archives are connected via archive service. As most of the drivers are now directly available via repository service, they are labeled as deprecated for the archive service. We recommend the drivers of the repository service if they are available, as they are faster and no additional archive service is required.

The configuration parameters have to be specified in the application-storage.yml configuration file as well.

Provider Version Supported Protocols Archive-Internal Retention

Hitachi Content Platform

7.3.0.6

s3-based

supported

deprecated: iTernity Compliant Archive Software (iCAS)

3.7

iCAS

supported

deprecated: Cloudian HyperStore

7.2

s3-based

supported

deprecated: Dell EMC ECS (Elastic Cloud Storage)

DellECM-ECS-CE-3.7

S3 REST API

supported

deprecated: NetApp

file system-based

supported

deprecated: Azure Blob Storage

REST API

supported

10.2.2. Client Development

Developer Libraries
yuuvis® Momentum Services

In addition to the yuuvis® Momentum core services, the developer libraries require further services. Please check their third-party requirements.

  • Web-API Gateway (API-WEB)

  • VIEWER Service

  • BPM-ENGINE Service (only for process and task management)

  • TENANT-MANAGEMENT Service (only idm-controller endpoints)

yuuvis® Momentum client as reference implementation uses the full functionality of the developer libraries. Thus, all listed services are required.
Web API
yuuvis® Momentum Services

In addition to the yuuvis® Momentum core services, the Web-API Gateway requires further services. Please check their third-party requirements.

  • USERSERVICE

  • SOTHOOK

  • BPM-ENGINE Service

  • TENANT-MANAGEMENT Service (only idm-controller endpoints)

yuuvis® architect
yuuvis® Momentum Services

In addition to the yuuvis® Momentum core services, yuuvis® architect requires further services. Please check their third-party requirements.

Content Viewer API
yuuvis® Momentum Services

In addition to the yuuvis® Momentum core services, the VIEWER Service requires further services.

  • office365 Service (only for Office 365 integration)

Office 365 Integration

To integrate the Microsoft Office 365 editing functionality, you need an authentication license for the Microsoft Office 365 Platform.

The viewing functionality of Microsoft Office 365 is available without a dedicated license.

User Profile API
Database

For operation of the userservice, a database is required. The same database systems as for the core services are supported.

10.2.3. Administration Tools

Tenant Management API
Identity Management Provider

In order to operate the idm-controller of the Tenant Management API, the service requires an authentication provider supporting OAuth2, e.g., Keycloak. If you do not use Keycloak, you need to implement a custom proxy that converts the request formats. An example implementation is available on request as a beta version.

In order to operate also the admin- and system-controller of Tenant Management API, Keycloak is required as identity management provider. The supported versions are listed below.

Keycloak Versions

11.0.2 (up to 2021 Winter)

15.0.2 (2022 Spring, 2022 Autumn)

19.0.2 (2022 Winter - 2023 Summer)

22.0.2 (2023 Autumn)

24.0.2 (2023 Winter - 2024 Summer)

Service 'keycloak-proxy'
Keycloak

The service supports only Keycloak as authentication provider. The supported versions are listed below.

Keycloak Versions

11.0.2 (up to 2021 Winter)

15.0.2 (2022 Spring, 2022 Autumn)

19.0.2 (2022 Winter - 2023 Summer)

22.0.2 (2023 Autumn)

24.0.2 (2023 Winter - 2024 Summer)

10.2.4. Business Process Management

BPM Engine API
Database

For operation of the BPM Engine, a database is required. Following providers and versions are supported:

Database Management System Version

PostgreSQL

9.4 - 11.10.0

Microsoft SQL Server

2012 (32- and 64-bit)

2014 (32- and 64-bit)

2016 (32- and 64-bit)

2017 (32- and 64-bit)

As of 2021 Winter: 2019 (32- and 64-bit)

Identity Management Provider

The BPM Engine needs access to the identity provider that is used for the yuuvis® Momentum cluster. The identity provider has to support the Custom IDM API shown below (e.g., Keycloak). If you want to use an identity provider that does not support the Custom IDM API, the TENANT-MANAGEMENT Service is required.

Custom IDM API
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
openapi: 3.0.1
info:
  title: Custom IDM API
  version: v1.0
paths:
  /roles:
    get:
      tags:
        - Roles
      description: Get all roles
      operationId: getRoles
      responses:
        '200':
          description: Indicates request was successful and the roles are returned.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CustomIdmRoleResponse'
  /roles/{roleId}/users:
    get:
      tags:
        - Roles
      description: Get all users with given role.
      operationId: getRoleMembers
      parameters:
        - name: roleId
          in: path
          description: Identifier of the role
          required: true
          schema:
            type: string
          example: YUUVIS_TENANT_ADMIN
      responses:
        '200':
          description: Indicates request was successful and the members are returned.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CustomIdmUserResponse'
  /users:
    get:
      tags:
        - Users
      description: Get all users
      operationId: getUsers
      parameters:
        - name: page
          in: query
          description: Zero-based page index (0..N)
          schema:
            type: integer
            default: 0
        - name: size
          in: query
          description: The size of the page to be returned
          schema:
            type: integer
            default: 20
        - name: sort
          in: query
          description: 'Sorting criteria in the format: property(,asc|desc). Default sort order is ascending. Multiple sort criteria are supported.'
          schema:
            type: array
            items:
              type: string
      responses:
        '200':
          description: Indicates request was successful and the users are returned.
          content:
            application/json:
              schema:
                type: object
                title: PageResponse
                properties:
                  objects:
                    type: array
                    items:
                      $ref: '#/components/schemas/CustomIdmUserResponse'
                  numItems:
                    type: integer
                    format: int32
                    example: 50
                  totalNumItems:
                    type: integer
                    format: int64
                    example: 1234
                  hasMoreItems:
                    type: boolean
                    example: true
  /users/{userId}:
    get:
      tags:
        - Users
      description: Get an user
      operationId: getUserById
      parameters:
        - name: userId
          in: path
          description: Identifier of the user
          required: true
          schema:
            type: string
          example: YUUVIS_TENANT_ADMIN
      responses:
        '200':
          description: Indicates request was successful and the user is returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CustomIdmUserResponse'
components:
  schemas:
    CustomIdmRoleResponse:
      type: object
      properties:
        name:
          type: string
    CustomIdmUserResponse:
      type: object
      properties:
        id:
          type: string
        username:
          type: string
        firstName:
          type: string
        lastName:
          type: string
        email:
          type: string
        roles:
          type: array
          items:
            type: string

10.2.5. AI Platform

Database

The AI Platform requires a SQL database to log model metrics. While PostGreSQL is our most frequently tested database driver, multiple other solutions have been proven to work with the platform.

Database Management System Version

PostGreSQL

9.4 - 11.10.0

Microsoft SQL

2012, 2014, 2016, 2017, 2019

CockroachDB

20.2, 21.1

Elasticsearch

The predict-api service can infer models that make use of Elasticsearch backend to improve prediction quality.

Elasticsearch Version

7.16.3

10.2.6. SAP® Integration

Requirements of 'repositorymanager'
  • ActiveMQ

  • Space for PersistentVolumeClaim

Requirements of 'repositorymanager-cmis'
SAP® compatibility
  • SAP® S/4HANA CLOUD, PUBLIC EDITION and all subsequent releases

  • SAP® Basis release 752

Storage
Antivirus Engine
  • The installation of the repositorymanager-cmis service contains ClamAV as default.

Requirements of 'repositorymanager-ilm'
SAP® compatibility
  • SAP® NetWeaver 7.5

  • SAP® S/4HANA 2020 and all subsequent releases

Instance of 'repositorymanager' serivce

For retention propagation, an instance of the repositorymangager service with enabled ArchiveLink functionality is required.

10.2.7. E-mail Archive

E-Mail Provider

The service requires an e-mail provider. The following systems are supported:

  • Microsoft Exchange Online

  • Every system using the SMTP protocol

Further 3rd Party Requirements

In some specific use cases, the following 3rd party software is required:

  • In case the mailbox is pulling from MS Exchange Online: Graph API is required

  • In case premium journaling for MS Exchange 2016/2019 is used: CAL enterprise license is required

Recommended 3rd Party Software
  • Prometheus – used for scraping and graphical visualization of operation data

  • Grafana – can be used for a more elaborated visualization of operation data

10.3. Installation Guide

This installation guide will help you to install yuuvis® Momentum via Helm charts to operate it in a Kubernetes cluster. We assume readers are familiar with Kubernetes and Helm commands. Start with Helm charts for testing purposes and replace default third-party software according to your preferences.

Each yuuvis® Momentum installation contains the core services provided in the yuuvis Helm chart. Most of our optional additional services are available via separate Helm charts as well.

After the installation, we recommend testing your system, e.g., with Postman.

10.3.1. Requirements

Check the requirements and recommendations of third-party software in order to set up a productive yuuvis® Momentum system.

10.3.2. Installation

  • Clone the yuuvis-api-helm-charts repository as working directory (see Docker Images).

  • Adjust the values.yaml configuration files in all Helm charts you want to install.

    • Add your credentials for the docker.yuuvis.org registry. Replace all changeme default passwords.

      For any questions about credentials please contact our support department.

    • If you want to operate multiple instances of individual services within your Kubernetes cluster, you can enable the PodDisruptionBudget for those services via the pdb parameters. After the installation, the corresponding <service>-pdb.yaml Kubernetes configuration files ensure that NOT all instances of the corresponding service are shut down at the same time, e.g., for service updates.

      • Set a minimum number of instances for pdb.minAvailable that always have to be kept running,

        OR

      • set a maximum number of instances for pdb.maxUnavailable that are allowed to be shut down at the same time. Set pdb.minAvailable: null.

    Ensure that your resulting minimum number of running instances is lower than the total number of instances. Otherwise, it is not possible to restart the corresponding service at all.
    • If you want to specify a Kubernetes node where to operate your yuuvis® Momentum services, you can use the nodeSelector configuration parameter for the individual services.

All yuuvis® Momentum services reach out to the configservice on startup to retrieve their configuration files, which results in a short delay before that services are fully operable. The yuuvis chart configures the authentication and organization services for OAuth2 with the tenant myfirsttenant (in the default configuration).

Helm Chart 'infrastructure'

The infrastructure Helm chart provides third-party software that can be combined with yuuvis® Momentum in order to build a test system. You should replace those components according to your preferences and needs in your productive system:

Infrastructure Component Function

PostgreSQL

database service

Elasticsearch

search engine

Minio

object storage

Gitea

self-hosted Git service

RabbitMQ

message broker

Keycloak

identity and access management service

Redis

in-memory data structure store

In order to install and use the set of third-party software provided in the infrastructure Helm chart, follow these steps:

  • Add the required Helm repositories:

    helm repo add minio https://charts.min.io/
    helm repo add bitnami https://charts.bitnami.com/bitnami
    helm repo add gitea-charts https://dl.gitea.io/charts/
    helm repo add codecentric https://codecentric.github.io/helm-charts/
  • Update the Infrastructure dependencies:

    cd infrastructure
    helm dep up
    helm repo add stable https://charts.helm.sh/stable
    cd ..
  • Adjust the values.yaml file:

    • Adjust the docker registry credentials.

    • Specify the address of your yuuvis® Momentum cluster by setting your CLUSTER_IP or your authentication service’s LOAD_BALANCER_IP for the parameter yuuvis.authentication.ip.

    • Optionally change passwords.

    • Optionally change the used storage classes.

  • Install the infrastructure services. Naming the chart during installation is necessary as each service would otherwise receive a default prefix from Kubernetes, making it difficult for the yuuvis® Momentum services to interact with them later. This also enables us to rollback our installation.

    kubectl create namespace infrastructure
    helm install infrastructure ./infrastructure --namespace infrastructure
  • Wait until the jobs are done.

    kubectl get jobs -n infrastructure

    There are two jobs preparing the git server and the Keycloak environment that need to be completed.

    NAME                              COMPLETIONS   DURATION   AGE
    gogsrepo-init                     1/1           83s        8m4s
    keycloak-create-selfsigned-cert   1/1           8m4s       8m4s
  • Run the following command to see if the infrastructure chart was deployed (STATUS DEPLOYED).

     helm list --namespace infrastructure
Helm Chart 'yuuvis'
  • Adjust the values.yaml file:

    • Adjust the docker registry credentials.

    • If you are using Keycloak as identity provider, specify its address by setting your CLUSTER_IP or your Keycloak’s LOAD_BALANCER_IP for the parameter yuuvis.keycloak.address.

    • In the section initjob, use the parameter createrealm to activate (true, default) or deactivate (false) the creation of an initial tenant including an administrative user. This user will have all default roles. If you do not change the default configuration, a tenant myfirsttenant with a user root will be created in Keycloak.

    • If you change createrealm to false, configure your tenant(s) in the oauth2 section or after the installation in the application-oauth2.yml configuration file in your git repository.

  • Navigate to the root Helm chart directory within the cloned repository.

  • Install the Helm chart. Naming this chart prevents randomization of service identifiers and gives us the ability to rollback all associated services.

    kubectl create namespace yuuvis
    helm install yuuvis ./yuuvis --namespace yuuvis
  • Wait for the pods to be ready:

    kubectl get po -n yuuvis
Helm Chart 'client'
  • Adjust the docker registry credentials.

  • Check the profiles to be activated for the userservice in the yuuvis.client.userservice.profiles. During the deployment, they will be set as value for the SPRING_PROFILES_ACTIVE environment variable.

    • Use dbsprostgres (default), dbsmssql OR dbscockroach to specify the database type.

    • Use swagger to enable the creation of a Swagger UI.

  • Adjust the database credentials yuuvis.client.userservice.database.address, yuuvis.client.userservice.database.user and yuuvis.client.userservice.database.password. During the deployment, they will be set as values for the environment variables DB_HOST, DB_USER and DB_USER.

  • Install the Helm chart:

    helm install client ./client --namespace yuuvis
  • Wait for the pods to be ready:

    kubectl get po -n yuuvis

    The installation of the client Helm chart will change the app-specific systemHookConfiguration.json for the clientsystem app. Services referring to this configuration will only read it once at startup. Thus, the corresponding services must be restarted to apply the new configuration. For example, restart the API Gateway via:

    kubectl rollout restart deployment api -n yuuvis
  • To enable users to create objects, define a suitable role and assign it to them.

Helm Chart 'bpm'
  • Adjust the docker registry credentials.

  • Check the profiles to be activated for the bpm-engine service in the yuuvis.bpm.engine.profiles. During the deployment, they will be set as value for the SPRING_PROFILES_ACTIVE environment variable.

    • Use dbsprostgres (default) OR dbsmssql to specify the database type.

    • Use swagger to enable the creation of a Swagger UI.

    • Use oauth2 to enable the usage of the authentication parameters in the application-oauth2.yml configuration file.

  • Adjust the database credentials yuuvis.bpm.engine.database.address, yuuvis.bpm.engine.database.user and yuuvis.bpm.engine.database.password. During the deployment, they will be set as values for the environment variables db.host, db.user and db.pwd.

  • Install the Helm chart:

    kubectl get po -n yuuvis
    helm install bpm ./bpm --namespace yuuvis
Helm Chart 'rendition'
  • Install the Helm chart:

    kubectl get po -n yuuvis
    helm install rendition ./rendition --namespace yuuvis
Helm Chart 'repositorymanager'

This Helm chart installs the repositorymanager service. It is a connector that provides a solution for ArchiveLink and ILM protocols of SAP.

It is possible to have more than one instance of the repositorymanager service. To use that possibility, the repositorymanager service will not be part of yuuvis namespace. Every instance has to be created in a new namespace.

CORS Ingress

For the communication with SAP® protocols, please disable CORS e.g. via nginx.ingress.kubernetes.io/enable-cors: "false". If you use a cloud provider, you should disable it there.

  • Adjust the docker registry credentials and the chart’s values.yaml configuration file.

  • Install the Helm chart:

    • Check if the core services in the yuuvis namespace are running:

      kubectl get po -n yuuvis
    • Create a new namespace for every repositorymanager instance, e.g. xxxxx

      kubectl create namespace xxxxx
    • Ensure that the correct values are set in the values.yml (credentials, ports, profile, tenant…​)

      helm install repositorymanager ./repositorymanager --namespace xxxxx
Helm Chart 'repositorymanagerilm'

This Helm chart installs the repositorymanager-ilm service. It is a connector to the SAP® via ILM protocol.

  • Adjust the docker registry credentials and repositorymanager-ilm service configuration parameters in the chart’s values.yaml configuration file.

  • Install the Helm chart:

    • Check if the core services in the yuuvis namespace are running:

      kubectl get po -n yuuvis
    • Create a new namespace for every repositorymanager-ilm service instance, e.g. repositorymanagerilm

      kubectl create namespace repositorymanagerilm
    • Ensure that the correct values are set in the values.yml (docker credentials and image version, profile, tenant…​)

      helm install repositorymanagerilm ./repositorymanagerilm --namespace repositorymanagerilm
Helm Chart 'repositorymanagercmis'

This Helm chart installs the repositorymanager-cmis service. It is a connector to SAP® via CMIS interface.

  • Adjust the docker registry credentials and repositorymanager-cmis service configuration parameters in the chart’s values.yaml configuration file.

  • Install the Helm chart:

    • Check if the core services in the yuuvis namespace are running:

      kubectl get po -n yuuvis
    • Create a new namespace for every repositorymanager-cmis service instance, e.g. repositorymanagercmis

      kubectl create namespace repositorymanagercmis
    • Ensure that the correct values are set in the values.yml (docker credentials and image version, profile, tenant…​)

    • Especially, configure the credentials for the cross-tenant service account that should be used by the repositorymanager-cmis service

      repositorymanager-cmis:
        yuuvis:
          technical:
            gateway: https://myhost.net
            tenant: testtenant
            username: testuser
            password: changeme
    • Start the actual installation process.

      helm install repositorymanagercmis ./repositorymanagercmis --namespace repositorymanagercmis
Helm Chart 'mailarchiving'

The Helm chart contains the following services for installation:

The Helm charts are constructed in such a way that each service can be independently installed. The installation of mailarchivingstorage is required. It creates an application-mas.yml configuration file. It will be read by the masstoragemomentum service and by the masmailbox service as well (if mailarchivingmailbox is installed as described below).

In addition to mailarchivinstorage, you can install mailarchivingsmtp and/or mailarchivingmailbox according to your needs.

Installation steps:

  • Install the mailarchivingstorage Helm chart:

    • Change the needed values in the mailarchiving/mailarchivingstorage/values.yml file. Detailed information on configuration parameters are available in the service description section.

      Using 'masmailbox'
      If you want masmailbox to run, ensure that correct Exchange Online Access credentials are added. This precondition is not needed for running massmtp.
    • Start the installation.

      # Check if yuuvis core services running (namespace yuuvis is example, yuuvis core services can be in namespace with another name)
      kubectl get po -n yuuvis
      
      # For every instance create new namespace e.g. xxxxx
      kubectl create namespace xxxxx
      
      # Make sure correct values are set in values.yml (credentials, ports, profile, tenant...)
      helm install mailarchivingstorage ./mailarchiving/mailarchivingstorage --namespace xxxxx
  • Optional: Install the mailarchivingsmtp Helm chart:

    • Change needed values in mailarchiving/mailarchivingsmtp/values.yml

    • Start the installation.

      # Check if yuuvis core services running (namespace yuuvis is example, yuuvis core services can be in namespace with another name)
      kubectl get po -n yuuvis
      
      # Check if storage service running in xxxxx namespace
      kubectl get po -n xxxxx
      
      # Make sure correct values are set in values.yml (credentials, ports, profile, tenant...)
      helm install mailarchivingsmtp ./mailarchiving/mailarchivingsmtp --namespace xxxxx
  • If wanted: Install the mailarchivingmailbox Helm chart

    • Please change needed values in mailarchiving/mailarchivingmailbox/values.yml

    • Start the installation.

      # Check if yuuvis core services running (namespace yuuvis is example, yuuvis core services can be in namespace with another name)
      kubectl get po -n yuuvis
      
      # Check if storage service running in xxxxx namespace
      kubectl get po -n xxxxx
      
      # Make sure correct values are set in values.yml (credentials, ports, profile, tenant...)
      helm install mailarchivingmailbox ./mailarchiving/mailarchivingmailbox --namespace xxxxx

10.3.3. Deinstallation

Helm does not delete persistent volumes. Those data have to be deleted manually.
Helm Chart 'infrastructure'
  • The rollback of the installation is possible via:

    helm uninstall infrastructure --namespace infrastructure
  • After uninstalling, run the following two commands:

    kubectl delete clusterrole create-selfsigned-cert
    kubectl delete clusterrolebinding create-selfsigned-cert
Helm Chart 'monitoring'
  • The rollback of the installation is possible via:

    helm uninstall monitoring --namespace monitoring
    helm uninstall prometheus-operator --namespace infrastructure
  • Delete the final setup for monitoring via:

    kubectl delete servicemonitor --all -n infrastructure and kubectl delete prometheusrule --all -n infrastructure
Helm Chart 'yuuvis'
  • The rollback of all associated services is possible via:

    helm uninstall yuuvis --namespace yuuvis

10.4. Update Guide

When updating your yuuvis® Momentum installation, manual configuration changes are required for some services.

After adjusting the configurations, the version update can be done via Helm.

We provide a detailed update guide for the following Update processes:

  • from version 2024 Spring to version 2024 Summer

For updates from other versions to 2024 Summer, we recommend to update version by version. Please refer to the individual breaking changes and configuration requirements on your own responsibility.

10.4.1. From 2024 Spring to 2024 Summer

Handling the Breaking Changes
The following breaking changes are incompatible changes, and therefore you need to be aware of them and take action accordingly.
Infrastructure
Identity Provider
Support of Keycloak 24

Keycloak 24 is now supported as identity provider. The following services require the new version:

Core
DMS Objects
Text Rendition via Lifecycle

As the full-text indexing is now managed via lifecycle, the following services are obsolete and no longer part of yuuvis® Momentum installations:

  • controller service

  • textextractor service

Instead, the renditiontextworker service is installed. This change requires the following configuration steps:

  • Create a cross-tenant service account for the renditiontextworker service.

  • Configure its credentials via environment variables for the renditiontextworker service:

    • YUUVIS_TENANT - The tenant in which the cross-tenant service account is created.

    • YUUVIS_USER - The username of the cross-tenant service account.

    • YUUVIS_PASSWORD - The password of the cross-tenant service account.

  • Optional: The values can be protected in a Kubernetes secret.

  • Optional: If you want to store the calculated text renditions in the rendition repository, set the parameter rendition.store.text: true in a service-specific YAML configuration file, e.g. renditiontextworker-prod.yml.

  • Adjust the global system hook configuration:

    • Remove the AMQP hook that connects the lc.textextraction queue:

      Previous 'systemhookconfiguration.json'
      {
          "systemhooks": {
              "amqp": [
                  ...
                  {
                      "bulkSize": 10,
                      "enable": true,
                      "password": "secret",
                      "predicate": "spel:(contentStreams != null && contentStreams.size() > 0 && contentStreams[0]['range'] != null && contentStreams[0]['range'].length() > 0) ? true : false",
                      "queue": "lc.textextraction",
                      "type": "object.insert.document",
                      "url": "10.10.6.243:5674",
                      "user": "clouduser"
                  }
                  ...
              ],
              "lifecycle": [...],
              "webhooks": [...]
          }
      }
    • Add the following lifecycle hook configuration:

      New 'systemhookconfiguration.json'
      {
          "systemhooks": {
              "amqp": [...],
              "lifecycle": [
                  ...
                  {
                      "type" : "dms.request.objects.upsert.database-before",
                      "enable" : true,
                      "predicate" : "spel:contentStreams != null && contentStreams.size() > 0 && contentStreams[0]['range'] != null",
                      "tagname": "system:ren:text",
                      "tagstate": 1
                  }
                  ...
              ],
              "webhooks": [...]
          }
      }
Enabling specific new Features
SAP® Integration
'repositorymanager' Service
Configuration handling
  • Before updating the repositorymanager service, check the webapp/cs configuration directory. Delete all configuration folders that should be replaced by the default configuration.

  • If a default configuration folders is missing in the webapps/cs directory (e.g., conf, META-INF, WEB-INF) during the version update, it is added with the default configuration settings.

  • Especially, if the KGS version after the update will not be compatible with the version before the update, delete the WEB-INF folder before the update. Otherwise the incompatible configuration is kept and has to be manually adjusted.

SAP® ILM Controller
Activation of SAP® ILM Controller
Requirements
repositorymanager service version 4 with enabled ILM functionality is required.
  • Check current configuration

    • In the cluster that contains your repositorymanager 4, open the repositorymanager-prod.yaml configuration file.

    • Note the tenant for which the service is configured (core.api.tenant property).

  • Installation of 'repositorymanager-ilm'

    • Install the new service via Helm chart in the same cluster.

    • Adjust the rmilm-prod.yml configuration file as shown below.

    • Check if an ingress controller with correct tenant information is created for the repositorymanger-ilm service. Both services repositorymanger-ilm and repositorymanager have to use the same tenant.

    • If the yuuvis® Momentum api gateway uses a different namespace than repositorymanager-ilm, set the value in the repositorymanager-ilm.yuuvis.api-url property.

  • Configure Connection in the SAP

    • Deprecated configuration:

      The Target Host is the ingress configuration that directly exposes the service. The path prefix is cs/ilm. Username and password used for this connection are the username and password configured in the KGS.

      Screenshot showing the KGS configuration section with *Technical Settings* tab.
      Screenshot showing the KGS configuration section with *Logon&Security* tab.
    • New configuration:

      The Target Host is the ingress that contains information on the tenant used by the repositorymanager-ilm service (in this example sapilm).

      The path prefix now also contains repositorymanager-ilm service`s URL as used by the ingress, followed by /cs/ilm.

      Username and password for Basic Authentication can be any user within the tenant that has read/write rights on the repositorymanager app.

      Screenshot showing the KGS configuration section with *Technical Settings* tab.
      Screenshot showing the KGS configuration section with *Logon&Security* tab.
Update the Helm Charts
  • All Helm charts except the infrastructure chart can be updated to a new version via:

    helm upgrade -n <namespace> <chart name> <chart location>

    For the concrete individual charts this means:

    helm upgrade -n yuuvis yuuvis yuuvis
    helm upgrade -n yuuvis bpm bpm
    helm upgrade -n yuuvis client client
    helm upgrade -n yuuvis rendition rendition
  • The third-party infrastructure components have to be updated via individual docker images:

    • Use our current Docker image for Elasticsearch as it includes the required plug-ins.

    • Optionally, use our Keycloak Docker image.

    • Updates for all further third-party components are within the customer’s responsibility.

10.5. Docker Images

The services are available at: http://docker.yuuvis.org/yuuvis/

10.5.2. Core Services

Service Name tag - product v. 2024 Summer

Gateway

API

api-gateway:4.19.2

Basic Core Services

authentication

authentication:4.19.2

SYSTEM

system:4.19.2

repository

repository:4.19.2

registry

registry:4.19.2

index

index:4.19.2

search

search:4.19.2

contentanalyzer

contentanalyzer:4.19.2

Archive Services

archive

archiveservice:4.19.2

Rendition Services

controller

controller:4.19.2

renditiontextworker

textextraction-worker-service:2.10.2

rendition

renditionservice:2.10.2

rendition-repository

rendition-repository:2.1.1

Structural Services

Rollback Administration

commander*

commander:4.19.2

Infrastructure

elasticsearch

2023-08-07

Test and Example Infrastructure

KEYCLOAK

keycloak:24.0.2-stable1

\* service of special interest for DevOps | ** obsolete when using Kubernetes

10.5.3. Additional Services

Service Name tag - product v. 2024 Summer

Client Services

API-WEB

api-web:1.19.2

CLIENT

client:5.5.1

ARCHITECT

architect:2.4.0

VIEWERSERVICE

viewerservice:3.0.10

USERSERVICE

userservice:1.13.2

SOTHOOK

sothook:4.19.0

OFFICE365

provider-client:2.0.2

DASHLET

dashlet-microservice:2.0.1

PROVIDER

provider:3.0.0

HOST

wopi-host:3.0.0

SCHEDULER

provider-scheduler:3.0.0

ADMIN

provider-admin:3.0.1

Tenant Management Services

TENANT-MANAGEMENT

tenant-management:1.16.3

METRICS

metricsservice:1.4.2

KEYCLOAK-PROXY

keycloak-proxy:24.0.0

Business Process Management (BPM)

BPM-ENGINE

bpm-engine:0.14.2

BPM-ADMIN-UI

bpm-admin:0.9.1

AI Integration

PDF-CONVERTER

kairos/pdf-converter:1.4.1

PREDICT-API

kairos/predict-api:2.1.0

KAIROS-API

kairos/kairos-api:2.1.0

SAP Integration

REPOSITORYMANAGER

repositorymanager:4.3.3

REPOSITORYMANAGER-MQ

repositorymanager-mq:1.2.1

REPOSITORYMANAGER-CMIS

repositorymanager-cmis:5.0.0

REPOSITORYMANAGER-ILM

repositorymanager-ilm:5.0.0

Mailarchiving Integration

STORAGE

mailarchiving-storage:2.1.6

SMTP

mailarchiving-smtp:2.1.6

MAILBOX

mailarchiving-mailbox:2.1.6

10.6. Standard Ports and Profiles

10.6.1. Core Services

Name Function Configuration Profiles Standard Ports

Gateway

api

API gateway

prod, redis, kubernetes, metrics

7450-7459

Basic Core Services

authentication

user authentication, session management

prod, oauth2, redis, kubernetes, metrics

80

system

schema management

prod, redis, kubernetes, metrics

7400

repository

management of the binary storage

prod, storage, redis, kubernetes, metrics

7500-7509

registry

management of object metadata in the relational database

prod, jpapostgres, dbs, redis, kubernetes, metrics

7510-7519

index

indexing in Elasticsearch

prod, es, kubernetes, redis, metrics

7291-7300

search

processing of queries

prod, es, kubernetes, metrics

7221-7230

contentanalyzer

synchronous full-text extraction and determination of the MIME type

prod, kubernetes, metrics

7430-7439

Archive Services

deprecated: archive

connector for storage solutions

prod, storage

7530-7539

Rendition Services

renditiontextworker

As of 2024 Summer: asynchronous full-text extraction

prod

rendition

generation of renditions of submitted documents

prod

7341

Rollback Administration

commander

command tool for rollbacks

prod, dbs, es

7412

10.6.2. Additional Services

Name Function Configuration Profiles Standard Ports

Client Services

api-web

web-api gateway, bundling of higher-level functions in one client API, adds more features like custom forms, localization, and object type icons to the system.

prod

7550

client

reference client based on core and framework libraries that can be used for custom client development

prod

80

architect

supports custom form modeling including form scripts, localization of technical names, and user management.

prod

80

viewerservice

offers client-side viewing capability for certain file types

prod

80

userservice

stores user settings and caches user information

dbspostgres

8080

sothook

fills the property appClientsystem:leadingTypeId used by client development libraries.

prod

10779

Tenant Management

tenant-management

tenant management API with endpoints for maintaining tenants and their users

prod, oauth2

8080

deprecated: `metrics`

provides tenant specific metrics. The tenant management API offers exposed endpoints of this service.

-

8080

Business Process Management (BPM)

bpm-engine

Flowable-based BPM engine

dbspostgres,swagger,oauth2

8080

bpm-admin-ui

admin user interface for the BPM engine

-

8080

E-Mail Archive (as of 2024 Spring)

masmailbox

Receiving messages from alternate mailboxes.

prod, mas, docker, kubernetes

8110

massmtp

SMTP server.

prod, docker, kubernetes

8120

masstoragemomentum

SMTP server.

prod, mas, docker, kubernetes

8130

Auto ML Platform (beta version - not yet included in installations)

kairos-api

-

-

-

ML Training Pipeline

-

-

-

predict-api

-

-

-

10.7. Changelog and Bugfixes

The following tables contain technical information on processed tasks during the development of product version 2024 Summer.

10.7.1. Changelog

Click to show.
Key Summary Description

AI-1963

Include tax percentage in prediction result

Predict-API returns only tax amount as part of the response. Even if tax percentage is returned from rule_based model.

  • Include tax percentage in prediction response

AI-1972

Reverse Charge

As a user of the invoice compliance check service, I would like to be able to know if the invoice I received falls under the reverse charge regulation to be able to handle it properly

Acceptance criteria:

  • Check if the invoice mentions "Reverse Charge" or "Reverse Charge Verfahren" prominently.

  • Check if the invoice has a 0% tax rate

  • Verify if the supplier’s VAT ID is provided but no VAT amount is charged.

  • Ensure that the recipient’s VAT ID is also mentioned.

  • Include the result of the check in the response of the endpoint.

AI-2011

Include Supply date in Predict API

Incude Supply date in Predict-API response

AI-2024

Add tax exemption in Predict API response

As a predict API user, I want to recieve the response of the tax exemption model to be able to provide input to the ICC

Acceptance criteria:

  • Predict API response includes tax exemption

BUD-2971

Tenant Management-API is upgraded to Keycloak 24

As a system operator I want to use keycloak in version 24.

Acceptance criteria:

  • The Upgrade to keycloak version 24 is successfully implemented.

  • The keycloak themes are adopted for the docker image with version 24

BUD-3012

Tenant Management API supports several profiles

As a system integrator, I would like to be supported in creating tenants via profiles that are different so that I can save time through automation.

The profiles are different e. g. in regards to the e-mail and theming settings.

Acceptance criteria:

  • Profile should be extended by themes section:

"themes":

{ "login": "eca", "account": "yuuvis", "admin": "yuuvis", "email": "eca"} * TM should support several profiles

BUD-3015

Patch method for API-web to add text resources

As an editor of text resources, I would like to be supported in the ability to add text resources through API-Web.

Acceptance criteria:

  • There is a patch method for API-web

  • The patch method is available in the global, app and tenant contexts

  • This patch method is tested and documented.

BUD-3054

Reserved SQL words should be escaped

As an administrator I would like to use SQL reserved keywords when creating names in schema etc. without breaking the functionality.

Acceptance creteria:

  • SQL reserved keywords can be used and are escaped in queries

ERA-9961

It is possible to execute scripts on a running process instance

As a model developer, I would like to execute scripts in context of a running process instance, to be able to change the state of variables in process, or to test the scripts that I am currently developing.

Acceptance criteria:

  • There is an endpoint that allows tenant administrator to execute a script in context of a running process

  • Tenant administrator role is defined by configuration parameter bpm.engine.app.admin-access-role

  • Per default, the tenant administrator shall have the role 'YUUVIS_TENANT_ADMIN'

  • It is possible to choose the scripting language: groovy or javascript

  • Script can change the state of the process variables

OKTO-5220

Consistent use of options for webhooks

Options are used in many processes (e.g. metadata update). Some are important for webhooks (e.g. "action"), others were originally developed for internal purposes ("preserve_missing_properties", "waitForSearchConsistency").

As a developer, I would like to find a standardised use of the options for all webhooks in order to enable better integration.

Acceptance criteria:

  • A positive list is used for all webhooks of options that can be included

  • Is firmly anchored in the services

  • The names of the options remain as before

  • Options changed by the WebHook are replaced by the original ones

  • Exception: changing the deletion code to an update code

  • The response WebHooks receive the same options as the request WebHooks

  • The AMQP WebHooks receive the same options as the request WebHooks

  • The options are documented for the Lifecycle WebHooks

OKTO-5260

Switching the controller for asynchronous text completion to tags

As a system integrator, I would like to be able to better understand and individualise the post-completion text. To do this, the post-completion text should be converted to tags in order to be able to use the existing query and control options.

Acceptance criteria:

  • The subsequent extraction of text takes place via tags

  • The relevant hooks are customised

  • The subsequent extraction of text via messaging is deactivated

  • The relevant services are no longer delivered

OKTO-5676

Repository encryption

As a system integrator, I need the option of storing certain data in encrypted form on the storage medium in order to comply with legal requirements.

Acceptance criteria:

  • The hash value is always calculated from the unencrypted document and is therefore independent of the storage location

  • Whether the data is stored in encrypted form can be configured individually for each file

  • The data is encrypted by yuuvis Momentum and not by the storage provider first

  • The key to be used can be configured

  • The configuration of the key can be set by the environment in order to keep the configurations free of critical data

  • Only the storage providers in the repository are supported

OKTO-5713

Partial upload of files for a better upload of large documents

As an API user, I would like to have the option of uploading large files in packets in order to facilitate uploads in the event of unstable or slow connections.

Acceptance criteria:

  • A separate API is available for uploading partial files

  • The API is harmonised with the DMS API for enaio, but does not currently have to be supported by it

  • No additional versions of the document are created if it is uploaded in parts

OKTO-5967

Direct connection of the google cloud storage to yMomentum

As a system integrator, I would like to be able to store data in google cloud directly via the repository service, without having to go through Minio or the archive service, in order to achieve a faster and less error-prone connection.

Currently, google cloud storage can be connected to yMomentum via Minio as an S3 proxy. In the first case, the Minio proxy, which has been discontinued by the manufacturer, is also required. In the second case, the archive driver writes additional information to the medium that is not required for the simple storage of data.

Acceptance criteria:

  • The google cloud storage blob storage can be configured and used directly via the repository service to yMomentum

  • No hop via the archive service is necessary

  • There is a way to access the data previously stored via Minio

  • It is configurable whether additional data is stored on the blob storage, as is the case with archiving

OKTO-6005

Support of WebDav HTTP methods in the core

As a developer, I would like to be able to provide an extension within the system that uses the WebDAV verbs in order to use the authentication methods of the system and not have to implement them myself.

Acceptance criteria:

  • The HTTP verbs can be passed through the authentication service

  • It is documented how these HTTP verbs can be configured

OKTO-6017

Tables in responses always have columnNames

As an API user, I would like the column names of the tables to always be returned in order to have standardised access to the data.

Current behaviour:

  • In the current version, the COLUMN name is always returned

  • In old versions and the response of updates, these are only returned if they were also written

Acceptance criteria:

  • The COLUMN names are always returned. If these are missing in the stored data, they are added by the system. This can result in the column names of old data not being correct after a change to the schema. This can only occur with data that was written before this change.

  • When writing data to the database, the column names are always enriched if they are not specified.

  • If there are no more column names for assignment (e.g. table has been removed from the schema), empty column names are returned Nils Vormum: please check whether empty strings are currently permitted

OKTO-6063

Direct connection to iCas (iTernity) from Repository

Currently, when objects are stored via the iTernity driver, they are always stored via the archive service. Additional information is also stored at this point, which is not the case when storing via the repository.

As a system integrator, I would like to be able to store data on the iTernity without the additional archive data also being stored. The driver for iTernity should also be transferred to the repository.

Acceptance criteria:

  • The ArchiveService is not changed

  • The repository can write directly to iTernity

  • The repository can also use the archive options

10.7.2. Bugfixlog

Click to show.
Key Description Support Calls

AI-1962

Fix multiple points parsing exception

AI-1998

Model Image build failing with mlflow version 2.3.x

BUD-2969

Misleading error message text

BUD-3003

PDFs with form fields cause browser-warning when focus is changed

BUD-3004

API-web memory issue

BUD-3017

Versions for signed documents cannot be displayed

00066962

BUD-3036

Missing situation parameter in deleteForm endpoint

BUD-3037

Client framework / quick search component issue

BUD-3051

Column configuration icon is not displayed in the client when a folder is opened

00067544

BUD-3055

If you try to select a user from a filter list which has a scrollbar with the arrow keys it does not scroll to the selected item

00067785 CIM-5885

BUD-3068

Search in tables does not work

BUD-3070

Question regarding the query of a folder regarding the number of contained folders and documents

00067516 CIM-5588

BUD-3075

History tab is not available

BUD-3078

Users are not displayed

BUD-3079

Backend respondns 422 when opening filters

DB-8290

After Hotfix 21, XML instead of JSON is sent to webhooks with dms.request.objects.upsert.storage-before

OKTO-5942

Application returns 401 Unauthorized error

OKTO-5945

NPE for incorrect configuration in the application-storage.yml for evaluating the repository

OKTO-5961

After Spring Boot update: Multipart parser modifies the content of certain PDF documents

OKTO-5973

Auth-Svc: OPTIONS requests are not routed

OKTO-5976

Auth-Svc: Since the Spring Boot Update, expiry dates are entered in internal JWTs with an accuracy of milliseconds. The services expect values accurate to the second.

OKTO-5978

Auth-Svc: Gibt man einen unbekannten Mandant per API-Aufruf mit, dann bekommt man Status 500

OKTO-5985

Error 422 encountered while loading Folders menu

OKTO-5987

Hits disappear when using the highlight function

OKTO-5995

Search IndexOutOfBoundsException: Index 0 outside the limits for length 0

OKTO-6009

NPE for schema validation with verbose=true

10.7.3. Hotfixes

2024 Summer
06 - 05 Sep 2024
Hotfixes for
component version date

api-gateway

4.19.2

04.09.2024

authentication

4.19.2

04.09.2024

archiveservice

4.19.2

04.09.2024

commander

4.19.2

04.09.2024

index

4.19.2

04.09.2024

registry

4.19.2

04.09.2024

repository

4.19.2

04.09.2024

search

4.19.2

04.09.2024

system

4.19.2

04.09.2024

Solved tickets
ticket number description component support call

OKTO-6078

Commander: During post-indexing, the tag: system:ren:text is also set with the status 1

yuuvis MOMENTUM core

05 - 29 Jul 2024
Hotfixes for
component version date

tenant-management

1.16.3

26.07.2024

Solved tickets
ticket number description component support call

DB-8441

Tenant-management: get tenant data broken

yuuvis Momentum tenant-management

04 - 16 Jul 2024
Hotfixes for
component version date

api-web

1.19.2

03.07.2024

Solved tickets
ticket number description component support call

DB-8395

Issue with handling emoji characters

yuuvis Momentum api-web

CIM-5351, 00070289

03 - 01 Jul 2024
Hotfixes for
component version date

rendition-repository

2.1.1

28.06.2024

renditionservice

2.10.2

28.06.2024

textextraction-worker-service

2.10.2

28.06.2024

Solved tickets
ticket number description component support call

DB-8392

Rendition repository cannot updateObjectToHashTable

yuuvis MOMENTUM rendition-plus

02 - 20 Jun 2024
Hotfixes for
component version date

provider-admin

3.0.1

12.06.2024

Solved tickets
ticket number description component support call

DB-8347

Admin portal can not be accessed

yuuvis MOMENTUM Office 365 service

00069565, CIM-6027

01 - 17 Jun 2024
Hotfixes for
component version date

api-web

1.19.1

14.06.2024

client

5.5.1

14.06.2024

Solved tickets
ticket number description component support call

DB-8300

can not fetch app specific resource

yuuvis MOMENTUM client, yuuvis MOMENTUM web-api-gateway

10.8. New Features

Here you will find some of the new release’s highlights. Check out the Change Log for further information on all changes.

10.8.1. 2024 Summer

Released on 11 JUN 2024.

Infrastructure
Identity Provider
Support of Keycloak 24

Keycloak 24 is now supported as identity provider.

Breaking Change
Please note that some services require Keycloak version 24.
Core
Architecture
Continued: Merging Groups of Core Services

As already started with product version 2024 Spring, the performance and scalability is improved by merging individual services. As a next step, all archive drivers provided by the archive service are now provided by the repository service as well. This means, the drivers for iCas and Hitachi Content Platforms are now available as well. The archive service is now obsolete.

Furthermore, the contentanalyzer service is merged into the repository service as well.

Services up to 2024 Spring Service that provides functions of both as of 2024 Summer
  • repository

  • archive

  • contentanalyzer

repository

DMS Objects
Text Rendition via Lifecycle

The asynchronous full-text creation is now integrated in the document lifecycle management and controlled by tagging. Thus, it is possible to adjust the processing for custom solutions. Furthermore, the text renditions can now be stored in the rendition repository like PDF and slide renditions.

Breaking Change

The textextractor and controller services are removed from the core system and replaced by the new renditiontextworker service. Find the configuration changes in the Breaking Changes list.

Partial Upload of Large Content Files

The import of DMS objects with large binary content files might be very slow and often leads to timeouts. It is now possible to partially upload the binary content. This means that the actual upload of the binary content is separated from the creation of the DMS object. Furthermore, the content is partially uploaded in pieces. Thus, the upload process is split in sub-processes that can be restarted separately in case of a failure.

The process is controlled via a new set of DMS endpoints.

Webhooks
Standardized Set of Options

The DMS objects passing through the individual system hook entry points contain a standardized set of options that contain processing-related information.

Trace ID Header for Webhooks

The requests sent to the available webhooks contain the X-B3-TraceId header now.

This header is NOT available for the webhooks of type user.info.
Binary Storage Connection
New Archive Driver for Google Cloud

The repository service provides a new archive driver that allows connecting google cloud storage. The configuration parameters are specified in the application-storage.yml configuration file.

Repository Encryption

The repository service can apply an encryption to binary content files before storing them. Thus, storage administrators cannot open and read the stored binary content files. The encryption can be activated in the storage.repositories section in the application-storage.yml configuration file.

As encryption impairs the performance of your system, only use it when necessary. Especially range requests for sections of very large content files might be slow. The entire content has to be decrypted before the requested range can be retrieved.
Administration Tools
Tenant Management API
Theming and Specialization of Tenant Creation Profiles

To allow for more specific configuration settings, it is now possible to store multiple tenant creation profiles. They are identified by a name query parameter that is now available for the following endpoints:

Furthermore, the new themes parameter section is available in tenant creation profiles.

Client Development
Web API
PATCH Update for Localization Resources

The new endpoint PATCH /api-web/api/resources/text/{locale} allows updating the localization of some particular keys in the corresponding localization resource file.

Business Process Management
BPM Engine
Evaluation of Scripts on Process Instances

The new endpoint POST /bpm-engine/api/processes/{processInstanceId}/evaluate allows evaluating Javascript or Groovy scripts on a running process instance.

SAP® Integration
Repositorymanager
New configuration handling

After an update of the repositorymanager service, the previous configuration stored in the webapp/cs directory can be reused now.

ILM Controller
New Interface for SAP® ILM

The new repositorymanager-ilm service can connect to the SAP® ILM interface.

10.8.2. 2024 Spring

Released on 21 MAR 2024.

Infrastructure
Identity Provider

Subsequently added with 2024 Summer:

Support of Keycloak 24

Keycloak 24 is now supported as identity provider.

Breaking Change
Please note that some services require Keycloak version 24.
Core
Architecture
Merging Groups of Core Services

To improve scalability and performance, some groups of two or three services are merged into one. The lower number of services reduces the number of cluster-internal calls as well as the minimum resources for smallest yuuvis® Momentum installations. For example, merging the audit service into the registry service halves the number of database connections.

Moreover, most archive drivers provided by the archive service are now provided by the repository service as well. Using the drivers in the repository service increases the performance especially for very large binary content files and mass imports. It furthermore allows to disable the additional archiving of metadata in the binary storage.

The requests to the API and cluster-internal API are NOT affected. The Kubernetes cluster is configured such that all previous individual services' names are still available and requests are redirected to an instance of the new merged service.

Breaking Change

Customers who do not use the preconfigured Helm charts for installation/update but directly refer to the individual services' Docker images have to adapt their processes to the new core architecture.

The following services are merged:

Services up to 2023 Winter Merged into Service as of 2024 Spring
  • system

  • configservice

  • organization

system

  • audit

  • registry

registry

  • repository

  • archive

repository (not yet completed, to be continued in version 2024 Summer)

Binary Storage Connection
New Driver for Hitachi Content Platform Archives

The driver for Hitachi Content Platform as binary storage is updated and renamed.

Breaking Change
  • previous driver name: hcp_s3

  • new driver name: hcp-s3

Please note the retention options for those storages as well. Retention times cannot be subsequently extended in Hitachi Content Platform archives. If a binary content file is stored with a retention time (either via configured defaultRetentionInDays or via object property system:rmExpirationDate), this time is fixed in the archive metadata during the entire storage time.

Subsequently added with 2024 Summer:

Connecting Azure directly to 'repository' service

The two archive drivers for Azure storages are both supported by the repository service now. As this connection does not require an additional step via archive service, it reduces the processing time and used resources for content-related requests.

The feature is described in the documentation starting with product version 2024 Summer for azure_blobstore and azure_objectretention.

DMS Objects
Metadata Extraction for E-mails

During the import of e-mails, their file type (EML or MSG) can be determined and specific metadata can be automatically extracted.

Lifecycle Hooks

The lifecycle hooks are a new and easy way to automatically add tags to DMS objects during object creation or update processes. Thus, for tagging automation, it is not anymore required to create a custom service and connect it via webhook.

Separated Permission for Tagging

A tag action is now available for configuring permissions in role sets. It allows to configure roles for service accounts that grant editing rights for tags but not for metadata or content. Thus, custom services can control asynchronous processing chains in the document lifecycle.

In combination with the read permission, the tag permission allows the usage of the following endpoints:

Rendition for 256-bit Encrypted PDF

It is now possible to retrieve renditions for binary content files of 256-bit encrypted PDF format.

Keys within Structured Data Properties

Structured data properties accept JSON values with keys containing capital letters. The keys must now match the regular expression [a-zA-Z][a-zA-Z0-9]* similar to the convention for type IDs.

Update Metadata and Content

The endpoint POST /api/dms/objects/{objectId} supports multipart request bodies to update metadata and content within one request.

Breaking Change
If your system uses webhooks triggered by update actions, you need to adjust your predicate. Details here.
Search
Case-insensitive Metadata Search

It is now possible to specify case-insensitive search conditions on string metadata.

Client Development
Web API
New Endpoint for Updating Task Candidates

The process variables of an existing process instance can be updated via the new endpoint POST /api-web/api/tasks/{taskId}/candidates.

Administration Tools
Tenant Management API
Replaced Metrics Endpoints

The core API offers metrics endpoints with the information but improved processing as of 2023 Summer. The METRICS service is no longer used and can be removed from installation. Thus, the following metrics endpoints of the Tenant Management API are deprecated and will not be available anymore in product version 2023 Winter:

  • GET /tenant-management/api/system/tenants/{tenant}/metrics

  • GET /tenant-management/api/admin/metrics

Breaking Change
in product version 2023 Winter
yuuvis® architect
Task Editor History Aspect Area

The new Editor history aspect area within the task details view contains information on user assignments and unassignments, delegations and resolving of the task.

Editing Process Variables

In the Summary aspect area within the process details view, the process variables can be edited (if available) for running processes.

E-Mail Archive
New
New E-mail Archive

A new solution for e-mail archiving is now available. It supports journaling as well as mailbox archiving. Communication is possible via SMTP and/or Graph API.

Business Process Management
BPM Engine
New Endpoints for Candidates Management

The following new endpoints are provided by the BMP Engine:

New Endpoint for Updating Process Variables

The process variables of an existing process instance can be updated via the new endpoint PUT /bpm-engine/api/processes/{processInstanceId}/variables.

SAP® Integration
CMIS Interface
New CMIS Interface for SAP® connection

The new repositorymanager-cmis service can connect to SAP® via CMIS interface.

10.8.3. 2023 Winter

Released on 04 DEC 2023.

Infrastructure
Identity Provider

Subsequently added with 2024 Summer:

Support of Keycloak 24

Keycloak 24 is now supported as identity provider.

Breaking Change
Please note that some services require Keycloak version 24.
Core
Core API
Batch Update with 'greedy' Parameter

The greedy query parameter is now available for the PATCH /api/dms/objects endpoint. It allows to update as many requested DMS objects as possible even if one or more of them cannot be processed.

Breaking Change
The response format is changed even if greedy is not assigned to the request URL. This breaking change affects also webhooks that are triggered after a successful update process.
Configuration of 'authentication' Service

The authentication service is now scalable in the default configuration and always requires the redis profile.

Furthermore, custom services to be accessible via authentication service only need to be registered via URL (and permissions if necessary) in the authorization.accesses section of the authentication-prod.yml configuration file.

Storage

Subsequently added with 2024 Summer:

Connecting Azure directly to 'repository' service

The two archive drivers for Azure storages are both supported by the repository service now. As this connection does not require an additional step via archive service, it reduces the processing time and used resources for content-related requests.

The feature is described in the documentation starting with product version 2024 Summer for azure_blobstore and azure_objectretention.

Client Development
Web API
App Form and Icon Paths

The app-specific forms and icons are managed with a new path structure.

Breaking Change
Please note the required manual actions described in the breaking changes.
Batch Update For DMS Objects

The new endpoint PATCH /api-web/api/dms/objects allows to update the metadata of multiple DMS objects with one request.

Batch Deletion For DMS Objects

The new endpoint DELETE /api-web/api/dms/objects deletes multiple DMS objects with one request.

Improved Resources Management supporting Apps

The resource-controller is now responsible for the entire resources management that is available via Web API. Its endpoints allow for app-specific resource management as well. Meanwhile, the /api-web/api/admin/resources/* and /api-web/api/system/resources/* endpoints are deprecated.

Reduction of Header Size for Web API

As already introduced for the core services with product version 2023 Autumn, also the Web API supports keeping user roles and other project-specific information in an internal cache instead of transporting them via internal JWT now.

Searching in Table Rows

The search via Web API allows to specify filters to search for query terms appearing in the same table row.

Relaxed Admin Role Filtering

Users with the role YUUVIS_TEANANT_ADMINISTRATOR are NOT ANYMORE excluded from result lists in the default configuration.

Deletion of Client Resources

The following new endpoints of the Web API allow for the deletion of corresponding client-specific resources:

Developer Libraries
Full-text Search Configuration

The main.json allows to configure two parameters to adjust the Web API’s full-text search behavior.

Administration Tools
Tenant Management API
Reduction of Header Size for Tenant Management API

As already introduced for the core services with product version 2023 Autumn, also the Tenant Management API supports keeping user roles and other project-specific information in an internal cache instead of transporting them via internal JWT now.

Properties for the Initial Admin User

During a new tenant creation via POST /tenant-management/api/system/tenants endpoint, first name and last name can be passed as further properties to the initial admin user.

yuuvis® architect
Form Modeling for Table Properties

The form modeling supports table properties now.

Filters for Tasks

Filters can be applied to the tasks list now.

Permissions Management

The new Permissions Management view of yuuvis® architect provides an administrative graphical user interface for role set creation and modification.

Reassigning Tasks

It is possible to specify a new responsible user for tasks that were unassigned before.

Business Process Management
BPM Engine
Scripting Languages for Modelling

It is now possible to use scripts in Groovy or Javascript languages for modelling.

Reduction of Header Size for BPM Engine

As already introduced for the core services with product version 2023 Autumn, also BPM Engine supports keeping user roles and other project-specific information in an internal cache instead of transporting them via internal JWT now.

Available Query Parameters for Task Lists

The following query parameters are now available for GET /bpm-engine/api/tasks allows to specify filters to search for query terms appearing in the same table row.

  • nameLikeIgnoreCase

  • businessKeyLike

  • createdBefore

  • createdAfter

  • completedBefore

  • completedAfter

  • isCompleted

  • visibleTo

AI Platform
API for Machine Learning Pipeline
New 'kairos-api' Endpoints

The kairos-api service for management of the machine learning pipeline offers the following new endpoints:

10.8.4. 2023 Autumn

Released on 22 AUG 2023.

Infrastructure
Identity Provider
Support of Keycloak Version 22

Customers using Keycloak as identity provider for yuuvis® Momentum can now update to Keycloak version 22.

Breaking Change
  • The update of Keycloak requires configuration adjustment.

  • The core system does not necessarily need an update of the Keycloak version. In contrast, the following services do not support previous Keycloak versions:

    • tenant-management

    • keycloak-proxy

Search Engine
Support of Elasticsearch 7.17.x

yuuvis® Momentum supports Elasticsearch version 7.17.x now. A docker image including the required plugins is available.

Core
Schema
Schema Label

A new label string field can be specified in a schema XML file. It can be used to specify a project-specific schema versioning information.

Tenant Separation
Support of multiple Elasticsearch Instances

To realize high performance while the workload increases, it is now possible to configure multiple Elasticsearch instances in the application-es.yml configuration file. Furthermore, the connection to Elasticsearch can now be secured by username and password.

Breaking Change
The configuration structure is changed. Even if you continue using only one Elasticsearch instance, you need to adjust your application-es.yml configuration file.
Selection of Repository by Condition

It is now possible to configure a predicate for each repository in the application-storage.yml configuration file to realize, e.g., a tenant-specific storage for binary content files. Thus, the used repository can be selected not only for each single content file during the import but also by configured conditions.

Document Lifecycle
Audit Entry for Deletion of an Object Version

The deletion of an object version is now documented in the audit trail with a specific audit entry.

Search
Full-text in Search Results

It is possible to display the text rendition for individual DMS objects in result lists if available. The search query term is highlighted. Client applications, e.g., may display a full-text excerpt that contains the search term in result lists of full-text search queries. Thus, the users can better evaluate the relevance of individual search results.

SUM() Function for Search Queries

The new SUM() function for search queries allows to retrieve the sum of integer property values in a single result.

Access Management
Reduction of Header Size

In order to reduce the header size for requests to the API gateway, it is possible to keep user roles and other project-specific information in an internal cache instead of transporting them via internal JWT. The feature can be activated by setting authorization.cacheUserAttributes: true in the authentication-prod.ym configuration file.

The feature is NOT yet supported by BPM und client development components of yuuvis® Momentum.
Storage
Archive Driver for Azure using Object Retention

The new archive driver azure_objectretention allows storing binary content files with retention times specified by the metadata of the corresponding DMS objects.

Object Lock Configuration for S3 and Azure Archives

For the archive drivers s3, ecs-s3 and azure_objectretention, the retention mode can be configured in the application-storage.yml configuration file. Thus, you can decide to allow the manipulation of objects under retention by an archive administrator or not.

Custom Extensions
Extending the Core API

It is possible to add custom endpoints to the API provided via api gateway. The api gateway forwards the requests to the configured custom URL including the assigned JWT.

It ist NOT possible to overwrite existing endpoints of the api gateway.

Client Development
Web API Gateway
Web API Full-text Search on Specified Field

The Web API query language provides a search operator to force the search for the field to be a full-text search, even if it contains wildcards. Thus, these searches are case-insensitive and wildcard-capable.

Administration Tools
Tenant Management API
Replaced Metrics Endpoints

The core API offers metrics endpoints with the information but improved processing as of 2023 Summer. The METRICS service is no longer used and can be removed from installation. Thus, the following metrics endpoints of the Tenant Management API are deprecated and will not be available anymore in product version 2023 Winter:

  • GET /tenant-management/api/system/tenants/{tenant}/metrics

  • GET /tenant-management/api/admin/metrics

Breaking Change
in product version 2023 Winter
yuuvis® architect
New Tasks List View

The Process Management (BPM) part of yuuvis® architect offers a tasks list view in addition to the processes list view for tenant administrators.

Business Process Management (BPM)
BPM Engine API
Options for Task Lists

The endpoint for the retrieval of task lists GET /bpm-engine/api/tasks accepts two new query parameters.

  • isCompleted filters running and/or completed tasks.

  • visibleTo allows to display only the tasks that are visible for a specified user.

Furthermore, the task’s metadata contain the ` endTime` property.

10.8.5. 2023 Summer

Core
Schema
Extended Schema Validation

The response of the endpoints for update or validation of a schema is extended with an additional changes section. It informs about differences between the current schema and the schema in the request body, and about the consequences for already existing DMS objects.

Contents and Renditions
Slide Renditions for E-Mail formats MSG and EML

It is now possible to retrieve a slide rendition for binary content files of MSG or EML e-mail formats.

Slide Renditions for Image formats PBM and JNG

It is now possible to retrieve a slide rendition for binary content files of PBM and JNG image formats.

Improved Text Extraction from large MS Office Content Files

The text extraction via contentanalyzer service is improved, especially for the handling of large binary content files of Microsoft Office file types. The length of extracted full-text is now limited by a configurable parameter. Thus, overloads and downtimes of the contentanalyzer service due to huge content files with much text can be avoided.

Mime Type Determination for Office 365 File Types

The contentanalyzer service can now determine the mime types for the file types of the current Microsoft Office 365 integration.

Document Lifecycle
Deletion of Binary Content

A new endpoint allows to remove the binary content of a DMS object. A new version without content is created while the previous content is still assigned to the previous object version.

Parameter 'waitForSearchConsistency' for Deletion Endpoints

The boolean query parameter waitForSearchConsistency is now available for the following endpoints:

  • DELETE /api/dms/objects/{objectId}

  • DELETE /api/dms/objects

If the parameter is set to false, the success response of the corresponding endpoint does not wait for the update of the search index. Thus, the waiting time for the response is far shorter. However, search requests sent immediately after the change request may be processed before the search index is updated and thus may deliver recently deleted objects.

Access Management
Attribute-based Access Control

In the definition of roles, it is now possible to specify conditions on project-specific user attributes that are provided in a separate section of the internal JWT. The additional user attributes have to be provided via user.info webhook.

At the same time, the boolean parameters accountNonExpired, accountNonLocked, credentialsNonExpired and enabled are removed from the JWT as they were unused.

Storage
Support of Azure Blob Storage

Azure Blob Storage can be connected via archive service. The configuration is specified in the application-storage.yml configuration file.

Database
Metrics Endpoints for DMS Object Count

The metrics endpoints GET /api/system/tenants/{tenant}/metrics/{metric} and GET /api/admin/metrics/{metric} can now provide the number of DMS objects within one specific tenant. In addition, the number of folder objects is provided separately. The information might be used for billing purposes as well as for an emptiness check before removing a tenant from the system.

Database Connections Optimizations

In the context of resources optimization measures, the number of database connections within the cluster is reduced. The individual services do not use their own database connection pools anymore. Instead, the connections are centralized now. The new default configuration is documented here: application-dbs.yml.

This feature has been subsequently added to yuuvis® Momentum product versions 2023 Spring and 2022 Winter LTS as well.
Client Development
Web API
Representation of User Attributes

It is possible to configure the representation of user attributes in order to replace IDs by more user-friendly strings like username, first name or last name.

Parameter 'scope' for Search Queries

The scope parameter can be used to execute a search request on either metadata only or full-text rendition of content only or on both.

Administration Tools
Tenant Management API
Log-out Process Improvement

The log-out process is improved by a new redirection configuration in application-oauth2.yml.

yuuvis® architect
Process Management

It is now possible to delete or refresh process instances via yuuvis® architect.

10.9. Breaking Changes

The following Breaking Changes are incompatible changes we had to deploy into operation, and therefore you—as a yuuvis® user—need to be aware of them and take action accordingly.

10.9.1. 2024 Summer

Infrastructure
Identity Provider
Support of Keycloak 24

Keycloak 24 is now supported as identity provider. The following services require the new version:

Core
DMS Objects
Text Rendition via Lifecycle

As the full-text indexing is now managed via lifecycle, the following services are obsolete and no longer part of yuuvis® Momentum installations:

  • controller service

  • textextractor service

Instead, the renditiontextworker service is installed. This change requires the following configuration steps:

  • Create a cross-tenant service account for the renditiontextworker service.

  • Configure its credentials via environment variables for the renditiontextworker service:

    • YUUVIS_TENANT - The tenant in which the cross-tenant service account is created.

    • YUUVIS_USER - The username of the cross-tenant service account.

    • YUUVIS_PASSWORD - The password of the cross-tenant service account.

  • Optional: The values can be protected in a Kubernetes secret.

  • Optional: If you want to store the calculated text renditions in the rendition repository, set the parameter rendition.store.text: true in a service-specific YAML configuration file, e.g. renditiontextworker-prod.yml.

  • Adjust the global system hook configuration:

    • Remove the AMQP hook that connects the lc.textextraction queue:

      Previous 'systemhookconfiguration.json'
      {
          "systemhooks": {
              "amqp": [
                  ...
                  {
                      "bulkSize": 10,
                      "enable": true,
                      "password": "secret",
                      "predicate": "spel:(contentStreams != null && contentStreams.size() > 0 && contentStreams[0]['range'] != null && contentStreams[0]['range'].length() > 0) ? true : false",
                      "queue": "lc.textextraction",
                      "type": "object.insert.document",
                      "url": "10.10.6.243:5674",
                      "user": "clouduser"
                  }
                  ...
              ],
              "lifecycle": [...],
              "webhooks": [...]
          }
      }
    • Add the following lifecycle hook configuration:

      New 'systemhookconfiguration.json'
      {
          "systemhooks": {
              "amqp": [...],
              "lifecycle": [
                  ...
                  {
                      "type" : "dms.request.objects.upsert.database-before",
                      "enable" : true,
                      "predicate" : "spel:contentStreams != null && contentStreams.size() > 0 && contentStreams[0]['range'] != null",
                      "tagname": "system:ren:text",
                      "tagstate": 1
                  }
                  ...
              ],
              "webhooks": [...]
          }
      }

10.9.2. 2024 Spring

Infrastructure
Identity Provider

Subsequently added with 2024 Summer:

Support of Keycloak 24

Keycloak 24 is now supported as identity provider. The following services require the new version:

Core
Operations und DMS Objects
Update Metadata and Content

The endpoint POST /api/dms/objects/{objectId} supports multipart request bodies to update metadata and content within one request. It triggers the creation of an audit entry 302 (OBJECT_METADATA_DOCUMENT_CHANGED). If your system uses webhooks triggered by updates, you need to add the new action code to the predicate in the webhook configuration. Webhooks of the following types are affected: * dms.request.objects.upsert.storage-before * dms.request.objects.upsert.database-before * dms.response.objects * dms.response.objects.update

Action: Adjust your predicate values as shown in the following example:

previous 'predicate'
"predicate" : "spel:T(java.util.List).of(300).contains(options['action']) && ...
new 'predicate'
"predicate" : "spel:T(java.util.List).of(300,302).contains(options['action']) && ...
Architecture
Merging Groups of Core Services

To improve scalability and performance, some groups of two or three services are merged into one. The lower number of services reduces the number of cluster-internal calls as well as the minimum resources for smallest yuuvis® Momentum installations.

The requests to the API and cluster-internal API are NOT affected. The Kubernetes cluster is configured such that all previous individual services' names are still available and requests are redirected to an instance of the new merged service.

Customers who do not use the preconfigured Helm charts for installation/update but directly refer to the individual services' Docker images have to adapt their processes to the new core architecture.

The following services are merged:

Services up to 2023 Winter Merged into Service as of 2024 Spring
  • system

  • configservice

  • organization

system

  • audit

  • registry

registry

  • search

  • index

search

  • repository

  • archive

repository

Binary Storage Connection
New Driver for Hitachi Content Platform Archives

The driver for Hitachi Content Platform as binary storage is updated and renamed.

  • previous driver name: hcp_s3

  • new driver name: hcp-s3

Please note the retention options for those storages as well. Retention times cannot be subsequently extended in Hitachi Content Platform archives. If a binary content file is stored with a retention time (either via configured defaultRetentionInDays or via object property system:rmExpirationDate), this time is fixed in the archive metadata during the entire storage time.

Business Process Management
BPM Engine API
New Format for Identity Links

The identityLinks section of the POST /bpm-engine/api/processes/{processInstanceId}/history endpoint’s JSON response has a new structure.

Administration Tools
Tenant Management API
Replaced Metrics Endpoints

The core API offers metrics endpoints with the information but improved processing as of 2023 Summer. Thus, the metrics endpoints of the Tenant Management API are deprecated already as of product version 2023 Autumn and will be now finally removed.
Action: Use the core API’s metrics endpoints instead.

10.9.3. 2023 Winter

Infrastructure
Identity Provider

Subsequently added with 2024 Summer:

Support of Keycloak 24

Keycloak 24 is now supported as identity provider. The following services require the new version:

Core
DMS Endpoints and Webhooks
Batch Update with 'greedy' Parameter

The response of the PATCH /api/dms/objects is changed due to the introduction of the greedy query parameter.

HTTP status code 2023 Winter HTTP status codes up to 2023 Autumn
  • 207 Multi-Status

The response always returns this HTTP status code. However, the JSON response body contains the HTTP status codes for the processing of each individual object. Those sub-requests can be successful or failed.

  • 404 Not Found – One object was not found.

  • 403 Forbidden – The user has no write permission for one object.

  • 422 Unprocessable Entity – A validation error occurred for one object.

  • 200 Ok – All objects are successfully updated.

The new behavior affects webhooks of the following types as well. Their individual entry points are now passed by ALL batch updates (not only purely successful batch updates anymore). The object lists contain the HTTP status codes resulting from the sub-requests mentioned above.

Client Development
Web API
App Form and Icon Paths

The paths for app forms and app icons have been changed. Please back up the app forms and app icons before updating the system to 2023 Winter and reimport them after the update is complete.

Business Process Management
BPM Engine API
Rename Available Database Profiles

The bpm-engine service requires exactly one database profile. The available profiles are renamed as follows:

New profile name as of 2023 Winter Previous profile name

dbspostgres

postgres

dbsmssql

mssql

If you do not replace the corresponding profile name in the active profiles for the service, it uses a local database and all workflow-related data are stored only during runtime.

Action: In the bpm-engine service’s Kubernetes deployment file, find the active profiles that are listed under the SPRING_PROFILES_ACTIVE environment variable. Replace the profile name, e.g., postgres by dbspostgres.

10.9.4. 2023 Autumn

Infrastructure
Identity Provider
Support of Keycloak Version 22

Keycloak version 22 requires the scope configuration parameter. It has to be configured in the application-oauth2.yml configuration file.

The infrastructure Helm chart for yuuvis® Momentum 2023 Autumn contains Keycloak version 22.

The update to the Keycloak 22 is optional for the core system, but MANDATORY for tenant-management service and keycloak-proxy service.
Core
Search Engine Connection
Support of multiple Elasticsearch Instances

To realize high performance while the workload increases, it is now possible to configure multiple Elasticsearch instances. Furthermore, the connection to Elasticsearch can now be secured by username and password.

Action: To continue using the same Elasticsearch instance for all tenants, replace the spring.data.elasticsearch parameters as shown in the example below in your application-es.yml configuration in the Git root directory.

  • The spring.datasource parameters used up to product version 2023 Summer:

    spring.data.elasticsearch.cluster-name: 'my-es-cluster'
    spring.data.elasticsearch.cluster-nodes: '12.23.5.678:9012'
    spring.data.elasticsearch.repositories.enabled: true
  • The new configuration structure used as of product version 2023 Autumn:

    storage:
        searchdatabases:
          database1:
            datasource: dbsource1
            predicate: 'spel:true'
            default: true
    
        searchdatasources:
          dbsource1:
            urls: '12.23.5.678:9012'
            index: 'exampleindex'

To use different Elasticsearch instances for individual tenants, please read the documentation of the application-es.yml configuration file.

Client Development
User Profile API
Rename Available Database Profiles

The userservice requires exactly one database profile. The available profiles are renamed as follows:

New profile name as of 2023 Autumn Previous profile name

dbspostgres

postgres

dbsmssql

mssql

dbscockroach

cockroach

If you do not replace it in the active profiles for the service, it uses a local database and all userservice-related data are stored only during runtime.

Action: In the userservice's Kubernetes deployment file, find the active profiles that are listed under the SPRING_PROFILES_ACTIVE environment variable. Replace the profile name, e.g., postgres by dbspostgres.

10.9.5. 2023 Spring

Core
Metrics
New Metrics Endpoints

The audit service requires a Redis connection now. If you use the Helm charts for your version update, your configuration is automatically adjusted and thus you do not need the following action.
Action: Restart the audit service with the redis profile.

DMS Endpoints
Batch Deletion with 'greedy' Parameter

The DELETE /api/dms/objects endpoint’s response is different even in the default request with greedy=false.

New behavior Previous behavior

The HTTP status code is always 207 in case of a proper request now.

Distinction between defined HTTP status codes 200, 403, 404, 409.

The response body contains the DMS objects (completed as far as possible) that were referenced by objectId in the request body. The options section contains the system:deletionResult that specifies success or failure of the individual objects' deletion.

No response body in case of successful deletion of all referenced objects. Error in JSON format as soon as one object could not be deleted.

The entry points for the webhooks dms.request.objects.delete, dms.response.objects and dms.response.objects.delete are reached with the complete objects list even if some referenced objects cannot be deleted.

The entry points for the dms.request.objects.delete, dms.response.objects and dms.response.objects.delete are NOT reached as soon as at least one referenced object cannot be deleted.

Client Development
Web API
New idm-controller

The following endpoints were moved from the user-controller to the new idm-controller. They are scheduled to be permanently removed with the next product version.

Endpoint in user-controller up to 2022 Winter Endpoint in idm-controller as of 2023 Spring

GET /api-web/api/users/users

GET /api-web/api/idm/users

GET /api-web/api/users/{userId}

GET /api-web/api/idm/users/{userId}

GET /api-web/api/users/whoami

GET /api-web/api/idm/whoami

Action:

Update the access configuration for the individual endpoints of the Web-API gateway in the authentication-prod.yml configuration file. The example code block shows the new default configuration for new installations.

### api-web
  - endpoints: /api-web/swagger-ui.html,/api-web/swagger-ui/**,/api-web/**/v3/api-docs/**
  - endpoints: /api-web/api/system/**
    access: hasAuthority('YUUVIS_SYSTEM_INTEGRATOR')
  - endpoints: /api-web/api/admin/**
    access: hasAuthority('YUUVIS_TENANT_ADMIN')
  - endpoints: /api-web/api/dms/**,/api-web/api/bpm/**,/api-web/api/resources/**,/api-web/api/users/**,/api-web/api/idm/**
Business Process Management (BPM)
BPM Engine API
Filtering of Task Lists

The GET /bpm-engine/api/tasks endpoint for the retrieval of a task list now accepts the boolean query parameter isAssigned instead of filter.

Action: Adjust your requests considering following behavior:

  • If isAssigned=true, the endpoint retrieves only tasks that are assigned to the currently logged-in user.

  • If isAssigend=false, the endpoint retrieves only tasks without an assignee for which the currently logged-in user is a candidate user.

  • If isAssigned is not specified in the request URL, the endpoint retrieves tasks that are assigned to the currently logged-in user as well as tasks without an assignee for which the currently logged-in user is a candidate user.

10.9.6. 2022 Winter (LTS)

Infrastructure
Identity Provider
Support of Keycloak Version 19

To use Keycloak version 19, it is required to manually adjust the endSessionUri parameter for each tenant in the application-oauth2.yml configuration file.
Action: In each tenant configuration, remove the redirect URI from the URL as shown below for the testyuuvis example tenant.

up to Keycloak version 15:
endSessionUri: http://${keycloak.host}/auth/realms/testyuuvis/protocol/openid-connect/logout?redirect_uri=${redir}
for Keyclaoak version 19:
endSessionUri: http://${keycloak.host}/auth/realms/testyuuvis/protocol/openid-connect/logout
Core
Database Connection
Tenant-specific Database Configuration

It is now possible to configure different databases to be used for storing metadata of individual tenants. Configurations for previous product versions are not supported anymore. The spring.datasource parameters in the application-dbs.yml configuration file are ignored.

Action: If you use the TENANT-MANAGEMENT service in your installation, apply the breaking change for the METRICS service configuration first. Afterwards, apply the new configuration to the core services as described here. To continue using the same database for all tenants, replace the spring.datasource parameters as shown in the example below in your application-dbs.yml configuration in the Git root directory.

The spring.datasource parameters used up to product version 2022 Autumn:
spring.datasource.url: jdbc:postgresql://abc/def
spring.datasource.username: yuuvis
spring.datasource.password: changeme123
spring.datasource.driver-class-name: org.postgresql.Driver
The new configuration structure used as of product version 2022 Winter:
storage:
    databases:
        defaultdb:
            datasource: defaultds
            predicate: 'spel:false'
            default: true
    datasources:
        defaultds:
            url: 'jdbc:postgresql://abc/def'
            username: yuuvis
            password: changeme123
            driver-class-name: 'org.postgresql.Driver'

To use different databases for individual tenants, please read the documentation of the application-dbs.yml configuration file.

Administration Tools
Tenant Management API
METRICS service database

As the METRICS service still uses only one database for the data of all tenants, it uses an own configuration file with its own database connection parameters now.

Actions:
  • Create a copy of the previoulsy used application-dbs.yml configuration file and save it as application-dbstmp.yml configuration file. The file should now contain the spring.datasource parameters as shown in the following example.

spring.datasource.url: jdbc:postgresql://abc/def
spring.datasource.username: yuuvis
spring.datasource.password: changeme123
spring.datasource.driver-class-name: org.postgresql.Driver
  • In the METRICS service deployment, replace the dbs profile by the dbstmp profile.

  • Continue with the database reconfiguration of the core services.

Client Development
Developer Libraries
Task Properties in Inbox

The inbox provided by the @yuuvis/core library uses the briefRepresentation parameter of the Web-API gateway bpm-controller endpoints as described below. Thus, the retrieved tasks are presented with a reduced data set to the users of a client application.
Action: If you want to display the full property set of tasks, set disableBriefRepresentation for the inbox service.

Web API
bpm-controller Endpoints

The optional query parameter briefRepresentation is available for the task retrieval endpoints. Per default, the response will contain only a reduced data set in order to reduce the processing time.
Action: In order to keep the behavior of the previous versions, set the query parameter briefRepresentation=false for each request to the corresponding endpoint.

10.9.7. 2022 Autumn

Client Development
Developer Libraries
Angular Version Update

The client libraries use Angular 14 now. In case you extended your client with further (third party) libraries, please ensure that they are compatible with Angular 14.
Action: If necessary, update your external libraries to a version that supports Angular 14.

Subsequently added with 2022 Winter:

Task Properties in Inbox

The inbox provided by the @yuuvis/core library uses the briefRepresentation parameter of the Web-API gateway bpm-controller endpoints as described below. Thus, the retrieved tasks are presented with a reduced data set to the users of a client application.
Action: If you want to display the full property set of tasks, set disableBriefRepresentation for the inbox service.

Web API

Subsequently added with 2022 Winter:

bpm-controller Endpoints

The optional query parameter briefRepresentation is available for the task retrieval endpoints. Per default, the response will contain only a reduced data set in order to reduce the processing time.
Action: In order to keep the behavior of the previous versions, set the query parameter briefRepresentation=false for each request to the corresponding endpoint.

Administration Tools
Tenant Management API
idm-controller Endpoints

The optional query parameter briefRepresentation is available for the endpoint GET /tenant-management/api/idm/users. Per default, the response will contain only a reduced data set in order to reduce the processing time. Especially, roles and groups of the listed users are not included in the default response anymore.
Action: In order to keep the behavior of the previous versions, set the query parameter briefRepresentation=false for each request to the endpoint.

10.9.8. 2022 Summer

Core
Access Management
Validation of Internal JSON Web Tokens

The internal endpoint of the authentication service for the validation of internal JSON Web Tokens (JWTs) is now available via a different URL.
>> GET /jwt/verify
Action: Custom microservices that called the endpoint /authentication/jwt/verify have to use the URL http://authentication-internal/jwt/verify instead.

10.9.9. 2022 Spring

Core
Git Connection
Performance Optimization for configservice

Local and remote resources on the git server are synchronized now at regular intervals of 5 minutes. Thus, changes applied directly to the remote resources on the git server are NOT available until the regular synchronization process is passed. The resources are always cached. The availability of the git server is not checked anymore in case of resource retrieval requests. It is no longer possible to set the parameter fail-if-git-not-available=true.

Furthermore, the Helm charts create a persistent volume claim for each configservice instance that will be used for service initialization after a service restart.

In case multiple instances of the configservice are running, the synchronization of the individual local resources is done at regular intervals of 5 minutes as well. Thus, requests for resources that have been modified less than 5 minutes ago might lead to the retrieval of a deprecated version of those resources. Resources created less than 5 minutes ago might be not available.

Client Development
Developer Libraries
Object Creation Permissions

The permission to create new objects is now enabled via a create permission within one of the roles defined via a role set. The YUUVIS_CREATE_OBJECT role does no longer allow object creation. You need to adjust your corresponding role set accordingly.

Action: Update your roles as described here. Use the following condition:

<condition>system:objectTypeId = 'appClient:minidoc' AND system.secondaryjectTypeIds = 'appClient:minidoc'</condition>
Web API
New Swagger UI Version for Web-API Gateway

The new Swagger version is available under a new URL.
Action: Adjust the endpoint URL pattern in authentication-prod.yml configuration file has follows:

...
### api-web
- endpoints: /api-web/swagger-ui.html,/api-web/swagger-ui/**,/api-web/**/v3/api-docs/**
...
...
User Profile API
Migration of User Information Endpoints.

The user information endpoints GET /userservice/api/users and GET /userservice/api/users/{userId} are not available anymore.
Action: Use the endpoints GET /api-web/api/users/users and GET /api-web/api/users/{userId} instead.

Administration Tools
Tenant Management API
New Swagger UI Version

The new Swagger version is available under a new URL.
Action: Adjust the endpoint URL pattern in authentication-prod.yml configuration file has follows:

...
### tenant-management
- endpoints: /tenant-management/swagger-ui.html,/tenant-management/swagger-ui/**,/tenant-management/**/v3/api-docs/**
...
...

10.9.10. 2021 Winter

Core
Git Connection

Subsequently added with 2022 Spring:

Performance Optimization for configservice

Local and remote resources on the git server are synchronized now at regular intervals of 5 minutes. Thus, changes applied directly to the remote resources on the git server are NOT available until the regular synchronization process is passed. The resources are always cached. The availability of the git server is not checked anymore in case of resource retrieval requests. It is no longer possible to set the parameter fail-if-git-not-available=true.

Furthermore, the Helm charts create a persistent volume claim for each configservice instance that will be used for service initialization after a service restart.

In case multiple instances of the configservice are running, the synchronization of the individual local resources is done at regular intervals of 5 minutes as well. Thus, requests for resources that have been modified less than 5 minutes ago might lead to the retrieval of a deprecated version of those resources. Resources created less than 5 minutes ago might be not available.

Client Development
Developer Libraries
BPM Integration in Clients

In order to provide the new features in client applications, the BPM process model follow-up has been updated. Process instances based on the previous version of the follow-up process model are not anymore supported. They are displayed without subject and attachments.

Action: You can delete those process instances via the client application or via the corresponding Web-API Gateway endpoint.

Management of Configuration Files
  • In order to unify the management of standard configurations, the standard column and filter configurations are now managed via the Web-API Gateway and no longer via the USERSERVICE.

  • All client-specific configuration files like main, plug-in or language configuration are managed via the Web-API Gateway as well.

Action: If standard column or filter configurations are already stored in your system via the USERSERVICE, they need to be imported again via the corresponding Web-API Gateway endpoint.

10.9.11. 2021 Autumn

Core
Access Management
Token Handling for Custom Services

The internal tokens (JWT) created by the authentication Service are now signed.

Actions:

  • If you are working with Java custom services using the annotation com.os.services.core.security.EnableServiceSecurity from the library services-security, you need to update the library to version 5.7.0.

  • If you are working with Java custom services using the library com.nimbusds:nimbus-jose-jwt for parsing of incoming JWTs, you have to use the class com.nimbusds.jwt.SignedJWT instead of the class com.nimbusds.jwt.PlainJWT.

Object Creation Permissions

In role sets, permissions can now be set for the creation of objects by introducing the action create. So far, the object creation was enabled together with the edit permission via the action write. Additionally, the role YUUVIS_CREATE_OBJECT had to be assigned to users in order to enable object creation via API Gateway. As of now, this role does not affect the functionality of the API Gateway and is not part of the global default role set anymore.

Actions:

  • In each of your existing role sets, add <action>create</action> to each permission including a write action that should allow for object creation further on. If the permission includes a condition, ensure that no CONTAINS statement is involved. Use the endpoints for managing permissions.

  • Remove the following lines from section # API-endpoints in authorization.accesses in the configuration file authentication-prod.yml:

    - endpoints: /api/dms/objects
      method: POST
      access: hasAuthority('YUUVIS_CREATE_OBJECT')
Administration Tools
Tenant Management API
Assignment of the System Integrator Role

In previous versions, the endpoint POST /tenant-management/api/admin/users that is accessible with the role YUUVIS_TENANT_ADMIN allowed for the assignment of the role YUUVIS_SYSTEM_INTEGRATOR to other users. This is not possible anymore. Only the endpoint POST /tenant-management/api/system/tenants/{tenant}/users that is accessible with the role YUUVIS_SYSTEM_INTEGRATOR allows for the assignment of the role YUUVIS_SYSTEM_INTEGRATOR to other users.

Client Development
Developer Libraries
No Printing via 'ContentPreviewComponent'

The ContentPreviewComponent provided by the framework library does not allow for printing anymore. Users have to download the binary content files and print them from their local drives.

10.9.12. 2021 Summer

Client Development
Web API
URLs

The endpoint URLs have been changed to match the structure of other service-specific endpoint URLs. The new URLs are used by yuuvis® client as reference implementation and yuuvis® architect.

The endpoints are grouped consistent with the Web-API Gateway Swagger-UI. The changes are highlighted in bold letters in the new URL.

Action: If you are already referencing one of the following endpoints in your applications, please update the corresponding URLs.

HTTP Method Deprecated URL New URL

admin-controller

GET

/api-web/admin/resources/text

/api-web/api/admin/resources/text

POST

/api-web/admin/resources/text/{locale}

/api-web/api/admin/resources/text/{locale}

GET

/api-web/admin/resources/icon/{path}

/api-web/api/admin/resources/icons/{path}

POST

/api-web/admin/icon/{path}

/api-web/api/ admin/resources/icons/{path}

GET

/api-web/admin/resources/config

/api-web/api/admin/resources/config

POST

/api-web/admin/resources/config

/api-web/api/admin/resources/config

GET

/api-web/admin/form/{objecttype}

/api-web/api/admin/dms/forms/{objecttype}

POST

/api-web/admin/form/{objecttype}

/api-web/api/admin/dms/forms/{objecttype}

GET

/api-web/admin/form/{objecttype}

/api-web/api/admin/dms/forms/{objecttype}

GET

/api-web/admin/catalogs/{name}

/api-web/api/admin/dms/catalogs/{qname}

POST

/api-web/admin/catalogs/{name}

/api-web/api/admin/dms/catalogs/{qname}

bpm-controller

GET

/api-web/bpm/process/instances

/api-web/api/bpm/process/instances

POST

/api-web/bpm/process/instances

/api-web/api/bpm/process/instances

DELETE

/api-web/bpm/process/instances/{processInstanceId}

/api-web/api/bpm/process/instances/{processInstanceId}

GET

/api-web/bpm/process/instances

/api-web/api/bpm/process/instances

GET

/api-web/bpm/tasks

/api-web/api/bpm/tasks

POST

/api-web/bpm/tasks/{taskId}

/api-web/api/bpm/tasks/{taskId}

dms-controller

POST

/api-web/dms/search

/api-web/api/dms/objects/search

GET

/api-web/dms/{id}

/api-web/api/dms/objects/{id}

GET

/api-web/dms/{id}/versions/{version}

/api-web/api/dms/objects/{id}/versions/{version}

GET

/api-web/dms/{id}/versions

/api-web/api/dms/objects/{id}/versions

GET

/api-web/dms/{id}/content

/api-web/api/dms/objects/{id}/contents/file

GET

/api-web/dms/{id}/content

/api-web/api/dms/objects/{id}/contents/file

POST

/api-web/dms/update/{id}/content

/api-web/api/dms/objects/{id}/contents/file

POST

/api-web/dms/create

/api-web/api/dms/objects

PATCH

/api-web/dms/update/{id}

/api-web/api/dms/objects/{id}

DELETE

/api-web/dms/delete/{id}

/api-web/api/dms/objects/{id}

GET

/api-web/dms/form/{objecttype}

/api-web/api/dms/forms/{objecttype}

GET

/api-web/dms/catalogs/{qname}

/api-web/api/dms/catalogs/{qname}

POST

/api-web/dms/catalogs/{qname}

/api-web/api/dms/catalogs/{qname}

PATCH

/api-web/dms/catalogs/{qname}

/api-web api/dms/catalogs/{qname}

GET

/api-web/dms/catalogs/{qname}/validate

/api-web/api/dms/catalogs/{qname}/validate

resource-controller

GET

/api-web/resources/text

/api-web/api/resources/text

GET

/api-web/resources/icon/{path}

/api-web/api/resources/icons/{path}

GET

/api-web/resources/config

/api-web/api/resources/config

system-controller

GET

`/api-web/system/resources/text

/api-web/api/system/resources/text

POST

/api-web/system/resources/text/{locale}

/api-web/api/system/resources/text/{locale}

GET

/api-web/system/resources/icon/{path}

/api-web/api/system/resources/icons/{path}

POST

/api-web/system/icon/{path}

/api-web/api/system/resources/icons/{path}

GET

/api-web/system/resources/config

/api-web/api/system/resources/config

POST

/api-web/system/resources/config

/api-web/api/system/resources/config

GET

/api-web/system/form/{objecttype}

/api-web/api/system/dms/forms/{objecttype}

POST

/api-web/system/form/{objecttype}

/api-web/api/system/dms/forms/{objecttype}

GET

/api-web/system/form/{objecttype}

/api-web/api/system/dms/forms/{objecttype}

GET

/api-web/system/catalogs/{name}

/api-web/api/system/dms/catalogs/{qname}

POST

/api-web/system/catalogs/{name}

/api-web/api/system/dms/catalogs/{qname}

user-controller

GET, POST

/api-web/users*

/api-web/api/users*

Appendix A: FAQ

Find here answers to frequently asked questions (FAQ) on yuuvis® Momentum.

A.1. DMS Schemata

Is it possible to change the object type of an already existing object?

No, it is not. The object type has to be specified in the object creation request by the system:objectTypeId property and cannot be modified later on. However, the concept of secondary object types (SOTs) might satisfy your needs. Those object types cannot be used to instantiate any object, but to assign or remove additional properties at runtime. Thus, it is possible to specify a generic object type with only few properties during the object creation and assign a characterizing SOT by a metadata update at any time. In case you want to build a client application based on our developer libraries, such characterizing SOTs have to be defined as primary SOTs.

Why are some objects displayed on the first and second result page?

The request for the second result page in yuuvis® Momentum internally requests a new search with the same query condition. From the new result list, the second page is calculated and provided to you. If, e.g., some objects matching the query condition are created after you retrieved the first and before you retrieved the second page, some objects from the first page might now appear later in the total result list. Thus, they reappear on the second result page.

A.3. Troubleshooting

Why is the database locked sometimes after a service startup?

During the startup of services with database access, Liquibase locks the data tables by writing a specific entry in the DATABASECHANGELOGLOCK table. If the startup is cancelled for any reason, this entry might remain. In this case the services with a database connection (e.g. audit, registry and rendition-repository services) fail to start and will repeatedly log warnings containing waiting for changelog lock.

Example log:

INFO [audit,,] 8 --- [ main] liquibase.lockservice : Waiting for changelog lock....

The database has to be unlocked as described in the Liquibase documentation.

What can I do if updating/deleting an object takes longer than its locking time?

The api gateway, registry service or repository lock the affected DMS objects during the processing time of the following requests:

  • update of metadata or content

  • moving content

  • object creation with reference to a binary content file that is already stored in yuuvis® Momentum

  • object deletion

  • creation, update or deletion of tags.

Thus, multiple parallel manipulations on the same object or content are prevented. However, the locking time for each process is limited to 600 s in the default configuration. If some update or deletion processes exceed this time, you have the possibility to configure a higher value by specifying the lock.leasetime parameter for the above mentioned services.

We strongly recommend to look for the origin of the slow processing instead of increasing the locking time. In most cases, your issues indicate a problem with your search index, your database or a binary storage (e.g., one of them might be almost full). Especially for productive systems, it is important to fix the actual problem.
Why is the header size of my cluster-internal requests too large?

The calls within the yuuvis® Momentum cluster can have multiple headers assigned to themselves. The sum of them is limited to a maximum total header size of 8 KB. If your header size exceeds this limit, try the following steps:

  • Find the origin of the large amount of data in your headers and reduce it as much as you can. In most cases, the internal json web token (JWT) is unnecessarily large and can be reduced.

    • Optimize your role set such that users only need a few roles to get all their required permissions.

    • Use short role names.

    • If you use the abac section in your JWT, keep the content as small as possible as well.

  • If you cannot further reduce your header size and still exceed the limit, cache the user attributes. The most critical JWT sections are outsourced and thus the header size is reduced.

  • Only as a last resort, increase the maximum header size. Set server.max-http-request-header-size for all services within your cluster to your desired value.

    The larger your headers, the slower is the processing of all requests within your cluster. Make a serious attempt to reduce the header size below the default limit of 8 KB using the means described above before increasing the maximum header size.

Appendix B: Glossary

AMQP Hook

Special system hooks used to generate messages for messaging systems using Advanced Message Queuing Protocol 1.0 (AMQP) as encoding scheme. The generation of messages is triggered by specific operations under configured conditions.

Audit configuration

The configuration possibilities for the audit service.

Audit service

The service of yuuvis® Momentum core that is responsible for audit trail and metrics management.

Audit trail

A documentation of the actions that have been applied to a specific DMS object. The values are stored in a separate database table.

Compound document

DMS objects with binary content consisting of concatenated byte arrays. Sub-documents can be created that reference a specified range within the compound document’s content instead of importing the actual data again.

Content digest

A property of each binary content stored in the content stream properties section of the DMS object(s) to which the content is assigned. The hex-encoded value is calculated by the repository service during the import or update of binary content files via Secure Hash Algorithm (SHA256). Thus, it can be used, e.g., to compare content files of different DMS objects or versions.

Document

A DMS object instantiated of a document object type. It consists of metadata and, if configured in the object type definition, it can contain a binary content file.

Document object type

Defined object type with base type system:document.

Endpoint

An URL to request a specific operation via yuuvis® Momentum REST API.

Folder

A DMS object instantiated of a folder object type. It consists of metadata and CANNOT have a binary content file assigned to itself.

Folder object type

Defined object type with base type system:folder.

History
  1. In the context of DMS objects: see audit trail.

  2. In the context of workflow / business process management: The process instance history gives an overview of all comments and tasks contained in the process instance and their current processing state.

Interceptor

The interceptors allow for project-specific extensions of the yuuvis® Momentum standard process flows by redirection to an alternative processing flow. The alternative process can entirely replace the standard one from this position on or resume the standard process at a specified position.

Metadata

Information stored in a JSON structure as defined in a schema that identifies and characterizes a DMS object in yuuvis® Momentum and makes it queryable. A fixed set of pre-defined system properties is assigned to all DMS objects. Further properties can be assigned if valid with respect to the applied tenant schema.

Multipart body

For transferring data of several types (e.g. a binary file along with a JSON object) in a single request you typically use multipart body. This type of request combines one or more sets of data, separated by boundaries, into a single body.

Object
  1. DMS object: An instance of a defined document or folder object type.

  2. In the context of workflow / business process management via BPM Engine API or Web API:

    1. A task or process definition containing pre-defined Flowable parameters.

    2. A task or process instantiated from a task or process definition containing values for the configured properties.

Object type

The identification of a specific XML (or JSON) structure that defines which properties are available/required for DMS object instances in a specific business use case.

Rendition

An alternative representation (plain text, PDF or thumbnail) of a binary content file to be used, e.g., for full-text search or content preview.

Retention

A protection of the binary content file from being modified or deleted before a specified expiration date is reached.

Schema

The schema is the data model defining the object types and property types. Any DMS object’s metadata validation is based on the schema.

Secondary object type

An abstract object type that cannot be directly instantiated during the creation of DMS objects. It is used as reusable group of properties defined in a schema that belong together in business situations. For example, properties related to e-mail management could be sender and receiver. Those property groups can be referenced in multiple object type definitions.

System hook

A custom extension of the yuuvis® Momentum core functionality. At specific entry points of some processing flows, messages can be generated (AMQP hooks) or the current data can be sent to a custom service (webhooks). After the custom extension, the standard process flow is resumed.

Tag

A tag describes the status of an object within a process chain independently of the object’s metadata. Thus, the usage of tags needs no definition in the schema and does not trigger the creation of new DMS object versions.

Tenant

An isolated part within the yuuvis® Momentum system with the possibility to configure an own schema, role set and further configurations. Each yuuvis® Momentum user belongs to exactly one tenant. Each DMS object is stored for exactly one tenant as well. Users have access only to the DMS objects within their own tenant.

Webhook

System hooks that extend the standard processing flow by an HTTP call if a configured condition is matched.

Feedback Contact and Impressum

We hope this growing portal serves you well and invite you to submit requests or suggestions to us.