To get an overview about new functionality, read the Release Notes. To learn about the necessary actions to update Livingdocs to release-2025-01, read on.

Attention: If you skipped one or more releases, please also check the release-notes of the skipped ones.

Webinar

System Requirements

Suggested

NameVersion
Node22
NPM10
Postgres16
Elasticsearch
OpenSearch
8.x
v2.3.0
Redis7
Livingdocs Server Docker Imagelivingdocs/server-base:22
Livingdocs Editor Docker Imagelivingdocs/editor-base:22
Browser SupportEdge >= 92, Firefox >= 90, Chrome >= 92, Safari >= 15.4, iOS Safari >= 15.4, Opera >= 78

Minimal

NameVersion
Node20.18
NPM10
Postgres13
Elasticsearch
OpenSearch
7.x
1
Redis6.2
Livingdocs Server Docker Imagelivingdocs/server-base:20:7
Livingdocs Editor Docker Imagelivingdocs/editor-base:20:7
Browser SupportEdge >= 92, Firefox >= 90, Chrome >= 92, Safari >= 15.4, iOS Safari >= 15.4, Opera >= 78

Deployment

Before the deployment

No prior preparations are required before rolling out this release.

After the deployment

No post-deployment steps are required after rolling out this release.

Rollback

No steps are required to roll back this release.

Breaking Changes 🔥

server Operations

Migrate the Postgres Database 🔥

No migrations were introduced in this release.

editor/server Operations

Drop support for Node.js 18 🔥

  • 🔥 Drop Node.js v18. Only Node.js v20.18.1 and newer are supported.

How to migrate your project to Node.js 22:

  • Change the content of the .nvmrc in your project root to 22
  • Change the engines.node declaration in the package.json to >=22
  • Change the Dockerfile of the server to livingdocs/server-base:22
  • Change the Dockerfile of the editor to livingdocs/editor-base:22

Server PR: Drop support for Node.js 18 Editor PR: Drop support for Node.js 18

server Dashboards

Angular dashboard cards 🔥

As part of our ongoing migration from Angular to Vue, we have removed support for Angular dashboard cards. Please consider using the newly introduced task screens or our provided upstream task dashboard cards instead. If these do not meet your requirements, migrate your custom dashboard cards to Vue.

Editor PR: Angular dashboard cards

server Dashboard

Dashboard type dashboard 🔥

Support for dashboards of type dashboard has been removed. Please migrate your dashboards of type dashboard to dashboards of type tableDashboard.

Server PR: Dashboard type dashboard Editor PR: Dashboard type dashboard

server Integrations

Comyan upload without targetMediaType and metadata mapping 🔥

It’s no longer possible to use the Comyan integration without providing a targetMediaType and a Comyan metadata mapping config in that media type definition. Please provide targetMediaType in Comyan integration settings and comyanExtraction in the media type. In the project configuration:

{
  settings: {
    integrations: {
      comyan: {
        targetMediaType: 'image'
      },
      mediaTypes: [
        {
          type: 'mediaImage',
          handle: 'image',
          comyanExtraction: {
            mappings: []
          }
        }
      ]
    }
  }
}

Server PR: Comyan upload without targetMediaType and metadata mapping

server Integrations

Comyan built-in postPublishHookAsync 🔥

The built-in postPublishHookAsync used for comyan usage reporting is no longer automatically registered in the upstream code. The registration of the postPublishHookAsync hook has to be defined in the downstream. If you are using the Comyan integration, please make sure to register the postPublishHookAsync in your project.

To disable the reporting from Livingdocs add the following to the configuration:

integrations: {
  comyan: {
    allowed: true,
    registerHooks: false
  }
}

To enable the same behavior as before configure the following in the downstream:

liServer.registerInitializedHook(() => {
  const {reportDocumentVersion} = liServer.features.api('li-comyan')
  liServer.registerPublicationServerHooks({postPublishHookAsync: reportDocumentVersion})
})

Additonally this opens up flexibility to customize when comyan usage is reported for example only registering for a certain project and execute it for desired contentTypes:

liServer.registerInitializedHook(() => {
  const {reportDocumentVersion} = liServer.features.api('li-comyan')
  liServer.registerPublicationHooks({
    projectHandle: 'myproject',
    postPublishHookAsync ({documentVersion}) {
      if (documentVersion.contentType !== 'article') return
      return reportDocumentVersion({documentVersion})
    }
  })
})

Server PR: Remove Comyan usage reporting registration

server Dependencies

Migrate to Express v5 🔥

The Livingdocs Server is now using Express v5.

  • In case you have custom route declarations, please make sure they conform to the Express v5 conventions. You can find the migration guide here: https://expressjs.com/en/guide/migrating-5.html
  • There’s nothing to change if there are no custom route declarations in a project.

The following changes affect the livingdocs server and maybe also downstreams:

  • Wildcards in routes have a new syntax. Unsupported routes now throw an error during server start. /designs/:name/:version/:file(*) -> /designs/:name/:version/*file req.params.file will result in an array with the path segments.
  {
  -  path: '/custom/api/assets/:file(*)',
  +  path: '/custom/api/assets/*file',
     method: 'get',
     title: 'Retrieve the files',
     action: (req, res) {
       const file = fileStream({
  -      file: req.params.file
  +      file: req.params.file.join('/')
       })
  
       return pipeline(file, res)
     }
  }  

Server PR: Migrate to Express v5

server Metadata Plugins

Stricter Validation of Metadata Plugin Indexing Keys 🔥

Indexing keys of metadata plugins must contain only alphabetic characters (a-z, A-Z) and dots (.). Please update all indexing keys in your custom metadata plugins that do not fulfil this requirement.

indexing: {
  enabled: true,
  behavior: [
    {
      type: 'keyword',
+     key: 'reference.id',
-     key: 'reference__id',
      getValue (val) { return val.reference?.id }
    }
  ]
}

Server PR: Stricter Validation of Metadata Plugin Indexing Keys

server Metadata Plugins

Legacy base filter syntax in li-document-search 🔥

Base filters in metadata plugin li-document-search no longer support the legacy filter syntax. Downstreams which define the baseFilters using the old syntax, need to migrate them to the new Search DSL.

Server PR: Legacy base filter syntax in li-document-search

Deprecations

editor Design

Sass @import declarations are deprecated

In the Livingdocs editor, it is possible to declare an additional stylesheet. This can be done using an environment variable, such as:

CUSTOM_STYLE_PATH_AFTER=./path/to/custom.scss

When this variable is set, the editor uses the specified custom Sass/CSS file.

If your project defines such a custom stylesheet, you are likely using @import declarations within it. However, a recent Sass update has deprecated the @import syntax. To prevent warnings and ensure compatibility, these @import statements need to be migrated.

Migration Guide

Follow these guidelines to migrate your @import statements:

  1. For files exposing variables, replace @import with @use:

    @use "~styles/settings/defaults";
    
    .custom-style {
      // Use variables from the imported file, prefixed by the file name
      z-index: defaults.$z-index-modal;
    }
    

    This replaces the previous approach:

    @import "~styles/settings/defaults";
    
    .custom-style {
      z-index: $z-index-modal;
    }
    

    Note: The @use directive automatically namespaces variables with the file name (e.g., defaults.$variableName), which helps avoid naming conflicts.

  2. For other cases, replace @import with @forward:

    @forward "~styles/settings/defaults";
    

    Use @forward to re-export the contents of a file without directly consuming them in the current file.

Why This Change?

The Sass team deprecated @import because it does not enforce proper scoping, leading to potential variable and mixin conflicts in larger projects. The new directives @use and @forward are designed to ensure better modularity and maintainability in your stylesheets.

For more details, refer to the Sass official documentation on deprecating @import.

server Configuration

Rename blacklist and whitelist to denylist and allowlist ⚠️

server Server Configuration

Multi channel configuration ⚠️

Features

editor Content Management
server Conditions

Brand Conditions 🎁

To support country- or brand-specific content, we are introducing a new component condition: the brands condition. This allows downstreams to configure a set of brands, from which one or more can be selected on components to define for which brands a component should be included. This condition works alongside the already existing dateTime condition.

Brands component condition
  1. To configure the new brands condition, downstreams need to first define a set of brands in the Project Config.
    brands: [
      {
        handle: 'brand1',
        label: 'Example Brand 1',
        iconUrl: 'https://example.com/brand1.svg',
        isDefault: true
      },
      {
        handle: 'brand2',
        label: 'Example Brand 2',
        iconUrl: 'https://example.com/brand2.svg'
      }
    ]
    
  2. Then, the brands condition can be enabled for specific components in the content type configuration.
    components: [
      {
        name: 'title',
        conditions: ['brands']
      }
    ]
    
  3. When requesting a document through the Composition API or any other endpoint, conditions are automatically evaluated according to the provided componentConditions property. If no brand is provided, the default brand will be used instead. A document can only be requested for a single brand at a time.
    POST {{server}}/api/beta/composition/1
    
    {
      "componentConditions": {
        "brand": "brand2"
      }
    }
    

For more information, please refer to our conditional components documentation.

Visibility Mode

With the introduction of the brands condition, we are renaming ‘Timeline Mode’ to ‘Visibility Mode’ to better reflect its new use case. Its purpose remains the same: allowing users to preview a document for a specific brand and at a specific date time.

Before release-2025-01:

Timeline mode action

release-2025-01 and after:

Visibility mode action

API

The brands condition is supported by all API endpoints where the existing dateTime component condition is supported:

  • GET /api/v1/documents/:documentId/latestPublication
  • GET /api/v1/documents/latestPublications
  • GET /api/v1/documents/:documentId/latestPublication/renditions/:renditionHandles
  • GET /api/v1/publications/search
  • GET /api/v1/document-lists/:id
  • GET /api/beta/documents/:documentId/latestDraft
  • GET /api/beta/documents/:documentId/latestPublication
  • GET /api/beta/documents/latestPublications
  • POST /api/beta/composition/:documentId

Along with these endpoints, the related Public API methods also support the new brands condition:

  • publicApi.getLatestPublication({ignoreComponentConditions, componentConditions})
  • publicApi.getLatestPublications({ignoreComponentConditions, componentConditions})
  • publicApi.getRenditions({ignoreComponentConditions, componentConditions})
  • publicApi.searchPublications({ignoreComponentConditions, componentConditions})
  • publicApi.getDocumentList({ignoreComponentConditions, componentConditions})
  • publicApi.getLatestDraftBeta({ignoreComponentConditions, componentConditions})
  • publicApi.getLatestDraftsBeta({ignoreComponentConditions, componentConditions})
server Page Management

Page Management: References in Base Filters

To enhance page management workflows, we are introducing support for variables in base filters of li-teaser and li-document-search.

For example, consider a news site where articles are categorized using a topic metadata property. Each topic has a corresponding page, which also has the same topic metadata property. Specialized teaser components based on li-teaser and li-document-search will then automatically use the topic from the page to display articles of the same topic, eliminating the need to manually select the topic for each teaser component through the user interface.

With variables, these components can now reference other properties to dynamically adjust their base filter, such as:

  • Metadata properties of the document containing the component
  • The brand for which the document is requested

Metadata Properties

For example, consider the following base filter:

baseFilters: [
  {key: 'metadata.topic.reference.id', termVariable: 'metadata.topic.reference.id'}
]

This base filter matches all documents that share the same topic metadata property (a reference to a dedicated topic data record) which is also selected for the page in which the teaser component is currently included.

Metadata properties are accessed using the same syntax as the indexing behavior of the underlying metadata plugin. In the example above, the metadata property is of type li-document-reference. To extract the IDs from this property, the postfix reference.id is appended. This corresponds to the indexing behavior of li-document-reference, specifically its key.

indexing: {
  enabled: true,
  behavior: [{
    type: 'keyword',
    key: 'reference.id',
    getValue (val) { return val.reference?.id }
  }]
}

Metadata properties do not need to be indexed to be referenced by a term variable (such as topic on the topic page in this example).

If a referenced metadata property is empty, the term variable will be excluded from the query. Therefore, we recommend to always pair such terms with an additional superset term as a fallback. For example:

baseFilters: [
  {key: 'contentType', term: 'article'},
  // This will be excluded if metadata property topic is empty
  {key: 'metadata.topic.reference.id', termVariable: 'metadata.topic.reference.id'}
]

Brand Component Conditions

In addition to metadata properties, you can reference the brand for which the document is requested using the componentConditions.brand term variable. This enables you to load teasers relevant to a specific brand.

For example, if articles are categorized by a brand metadata property, you can filter them using the following base filter:

baseFilters: [
  {key: 'metadata.brand', termVariable: 'componentConditions.brand'}
]

If no brand is provided in a request, componentConditions.brand uses the default brand as configured in the Project Config.

For more details, refer to our term variable documentation.

server Metadata

User needs plugin 🎁

The User Needs metadata plugin integrates the User Needs Model 2.0 into Livingdocs, allowing newsrooms to categorize articles based on audience-focused interests.
By assigning one of eight user-need categories during content creation or editing, teams can better align with audience preferences, boost engagement, and optimize content placement.

How to use User Needs in Livingdocs:

  • Select them in the dashboard, in the metadata panel of the editor or in the creation-flow panel
  • Edit them in the dashboard in the metadata panel
  • Enable User Needs as filter in the dashboard to streamline content analysis.

For instructions on how to set it up, refer to the li-user-needs documentation.

User Needs in Dashboard and in Metadata
editor Integrations

PEIQ integration 🎁

You can now upload images directly from PEIQ via drag & drop into our system, making your workflow more efficient and straightforward.

To set it up, add the following configuration to your project settings:

// project config
{
  settings: {
    integrations: {
      peiq: {
        enabled: true,
        targetMediaType: 'image',
        apiEndpoint: '...',
        apiToken: {
          $secretRef: {
            name: 'peiq-local'
          }
        }
      }
    }
  }
}

To enable the import of metadata directly from PEIQ, we provide an extraction mapping feature. This allows you to define how PEIQ fields correspond to specific metadata properties:

// project config
{
  mediaTypes: [
    {
      handle: 'image',
      // ...
      peiqExtraction: {
        mappings: [
          {field: 'name', metadataPropertyName: 'title'},
          // ...
        ]
      }
    }
  ]
}
editor Document Preview

Document preview auto-reload 🎁

server Metadata

System metadata plugins 🎁

server Configuration

Product Usage Analytics 🎁

In order to drive the continuous improvement of Livingdocs in a user-centered way, usage data and patterns can greatly improve our perspective and point us to pain points worth interviewing users about. Livingdocs tracks certain user interactions along with some context data and sends it to PostHog, a cloud service to store, process and visualize such data.

It is opt-in, and we are very cautious to respect the privacy of our users. More details can be found in the project config settings docs.

Vulnerability Patches

We are constantly patching module vulnerabilities for the Livingdocs Server and Livingdocs Editor as module fixes are available. Below is a list of all patched vulnerabilities included in the release.

Livingdocs Server

This release we have patched the following vulnerabilities in the Livingdocs Server:

No known vulnerabilities. 🎉

Livingdocs Editor

This release we have patched the following vulnerabilities in the Livingdocs Editor:

  • TBD

We are aware of the following vulnerabilities in the Livingdocs Editor:

  • CVE-2023-44270 vulnerability in postcss, it affects linters using PostCSS to parse external Cascading Style Sheets (CSS). It is not exploitable in the editor as we don’t load untrusted external CSS at build time.
  • CVE-2023-26116, CVE-2023-26118, CVE-2023-26117, CVE-2022-25869, CVE-2022-25844 are all AngularJS vulnerabilities that don’t have a patch available. We are working on removing all AngularJS from our code and vulnerabilities will go away when we complete the transition to Vue.js.

Patches

Here is a list of all patches after the release has been announced.

Livingdocs Server Patches

  • v267.1.3: fix(li-system-date): Make the new li-system-date and li-system-datetime validations more strict
  • v267.1.2: fix(deps): update dependency @livingdocs/framework from 32.1.1 to v32.1.2
  • v267.1.1: fix(channels): Deprecate Multi-Channel Setups (LIDEP048)

Livingdocs Editor Patches

  • v114.13.4: fix: remove nzz publish control behavior

  • v114.13.3: fix(confirm button): Angular version

  • v114.13.2: fix(deps): update dependency @livingdocs/framework from 32.1.1 to v32.1.2

  • v114.13.1: fix(teaser-manager): Reduce include resolve requests


    Icon Legend

    • Breaking changes: 🔥
    • Feature: 🎁
    • Bugfix: 🪲
    • Chore: 🔧