diff --git a/CHANGELOG.md b/CHANGELOG.md
index 99740055b..02ef01c46 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,10 @@
# Changelog
All notable changes to this project will be documented in this file.
+## [9.6.0]
+### Added
+- customer-data-platform (CDP) module for the customer profiles ingestion
+
## [9.5.0]
### Added
- investment service intraday generation and ingestion function
diff --git a/pom.xml b/pom.xml
index 723ca3abe..5591a11e8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
pom
Stream :: Services
@@ -34,6 +34,7 @@
stream-contacts
stream-loans
stream-audiences
+ stream-cdp
stream-compositions
stream-plan-manager
stream-customer-profile
diff --git a/stream-access-control/access-control-core/pom.xml b/stream-access-control/access-control-core/pom.xml
index 5304fba13..b374b451d 100644
--- a/stream-access-control/access-control-core/pom.xml
+++ b/stream-access-control/access-control-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-access-control
- 9.5.1
+ 9.6.0
access-control-core
diff --git a/stream-access-control/pom.xml b/stream-access-control/pom.xml
index 6f0a96d20..e4ba6bb4d 100644
--- a/stream-access-control/pom.xml
+++ b/stream-access-control/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-access-control
diff --git a/stream-approvals/approvals-bootstrap-task/pom.xml b/stream-approvals/approvals-bootstrap-task/pom.xml
index 84af24aab..9b18c9930 100644
--- a/stream-approvals/approvals-bootstrap-task/pom.xml
+++ b/stream-approvals/approvals-bootstrap-task/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-task-starter-parent
- 9.5.1
+ 9.6.0
../../stream-sdk/stream-starter-parents/stream-task-starter-parent
diff --git a/stream-approvals/approvals-core/pom.xml b/stream-approvals/approvals-core/pom.xml
index c61b60c88..daa89af62 100644
--- a/stream-approvals/approvals-core/pom.xml
+++ b/stream-approvals/approvals-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-approvals
- 9.5.1
+ 9.6.0
approvals-core
diff --git a/stream-approvals/pom.xml b/stream-approvals/pom.xml
index 2567dc962..bbeedc806 100644
--- a/stream-approvals/pom.xml
+++ b/stream-approvals/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-approvals
diff --git a/stream-audiences/audiences-core/pom.xml b/stream-audiences/audiences-core/pom.xml
index 3779e1808..13507c7ec 100644
--- a/stream-audiences/audiences-core/pom.xml
+++ b/stream-audiences/audiences-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-audiences
- 9.5.1
+ 9.6.0
audiences-core
diff --git a/stream-audiences/pom.xml b/stream-audiences/pom.xml
index 9e756c222..dfa9ff126 100644
--- a/stream-audiences/pom.xml
+++ b/stream-audiences/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-audiences
diff --git a/stream-cdp/README.md b/stream-cdp/README.md
new file mode 100644
index 000000000..c87c39c9e
--- /dev/null
+++ b/stream-cdp/README.md
@@ -0,0 +1,6 @@
+# Stream Audiences Integration
+The goal of this module is to enable ingestion of Customers into Retail Customers and Business Customers segments.
+
+The ingestion is done through an HTTP call towards `User Segments Collector` service.
+
+`UserKindSegmentationSaga` (responsible for triggering the ingestion towards the collector) is triggered from `LegalEntitySaga`
\ No newline at end of file
diff --git a/stream-cdp/cdp-core/pom.xml b/stream-cdp/cdp-core/pom.xml
new file mode 100644
index 000000000..ff5681db6
--- /dev/null
+++ b/stream-cdp/cdp-core/pom.xml
@@ -0,0 +1,42 @@
+
+
+ 4.0.0
+
+
+ com.backbase.stream
+ stream-cdp
+ 9.6.0
+
+
+ cdp-core
+ jar
+ Stream :: CDP Core
+
+
+ true
+
+
+
+
+ com.backbase.stream
+ stream-dbs-clients
+ ${project.version}
+
+
+ com.backbase.stream
+ stream-worker
+ ${project.version}
+
+
+ io.projectreactor
+ reactor-test
+ test
+
+
+ com.backbase.buildingblocks
+ service-sdk-starter-test
+ test
+
+
+
+
diff --git a/stream-cdp/cdp-core/src/main/java/com/backbase/stream/cdp/CdpSaga.java b/stream-cdp/cdp-core/src/main/java/com/backbase/stream/cdp/CdpSaga.java
new file mode 100644
index 000000000..ed03316b5
--- /dev/null
+++ b/stream-cdp/cdp-core/src/main/java/com/backbase/stream/cdp/CdpSaga.java
@@ -0,0 +1,69 @@
+package com.backbase.stream.cdp;
+
+import com.backbase.cdp.ingestion.api.service.v1.CdpApi;
+import com.backbase.stream.configuration.CdpProperties;
+import com.backbase.stream.worker.StreamTaskExecutor;
+import com.backbase.stream.worker.exception.StreamTaskException;
+import lombok.extern.slf4j.Slf4j;
+import reactor.core.publisher.Mono;
+
+@Slf4j
+public class CdpSaga implements StreamTaskExecutor {
+
+ public static final String ENTITY = "CdpProfile";
+ public static final String INGEST = "ingest";
+ public static final String SUCCESS = "success";
+ public static final String ERROR = "error";
+ public static final String INGESTED_SUCCESSFULLY = "Customer ingested successfully";
+ public static final String FAILED_TO_INGEST = "Failed to ingest Customer";
+
+ private final CdpApi cdpServiceApi;
+ private final CdpProperties cdpProperties;
+
+ public CdpSaga(
+ CdpApi cdpServiceApi,
+ CdpProperties cdpProperties
+ ) {
+ this.cdpServiceApi = cdpServiceApi;
+ this.cdpProperties = cdpProperties;
+ }
+
+ @Override
+ public Mono executeTask(CdpTask streamTask) {
+
+ var request = streamTask.getCdpEvents();
+
+ return cdpServiceApi.ingestEvents(request)
+ .then(Mono.fromCallable(() -> {
+ streamTask.info(ENTITY, INGEST, SUCCESS, null,
+ request.getCdpEvents().getFirst().getSourceId(), INGESTED_SUCCESSFULLY);
+ return streamTask;
+ }))
+ .onErrorResume(throwable -> {
+ streamTask.error(ENTITY, INGEST, ERROR, null,
+ request.getCdpEvents().getFirst().getSourceId(), FAILED_TO_INGEST);
+ return Mono.error(new StreamTaskException(streamTask, throwable, FAILED_TO_INGEST));
+ });
+ }
+
+ @Override
+ public Mono rollBack(CdpTask streamTask) {
+ return null;
+ }
+
+ public boolean isEnabled() {
+ if (cdpProperties == null) {
+ return false;
+ }
+
+ return cdpProperties.enabled();
+ }
+
+ public String getDefaultCustomerCategory() {
+ if (!isEnabled()) {
+ return null;
+ }
+
+ return cdpProperties.defaultCustomerCategory();
+ }
+}
diff --git a/stream-cdp/cdp-core/src/main/java/com/backbase/stream/cdp/CdpTask.java b/stream-cdp/cdp-core/src/main/java/com/backbase/stream/cdp/CdpTask.java
new file mode 100644
index 000000000..dacc8c1a2
--- /dev/null
+++ b/stream-cdp/cdp-core/src/main/java/com/backbase/stream/cdp/CdpTask.java
@@ -0,0 +1,16 @@
+package com.backbase.stream.cdp;
+
+import com.backbase.cdp.ingestion.api.service.v1.model.CdpEvents;
+import com.backbase.stream.worker.model.StreamTask;
+import lombok.Data;
+
+@Data
+public class CdpTask extends StreamTask {
+
+ private CdpEvents cdpEvents;
+
+ @Override
+ public String getName() {
+ return "cdpProfilesIngestionTask";
+ }
+}
diff --git a/stream-cdp/cdp-core/src/main/java/com/backbase/stream/configuration/CdpConfiguration.java b/stream-cdp/cdp-core/src/main/java/com/backbase/stream/configuration/CdpConfiguration.java
new file mode 100644
index 000000000..a5c95b4dc
--- /dev/null
+++ b/stream-cdp/cdp-core/src/main/java/com/backbase/stream/configuration/CdpConfiguration.java
@@ -0,0 +1,22 @@
+package com.backbase.stream.configuration;
+
+
+import com.backbase.cdp.ingestion.api.service.v1.CdpApi;
+import com.backbase.stream.cdp.CdpSaga;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@EnableConfigurationProperties({CdpProperties.class})
+@Configuration
+public class CdpConfiguration {
+
+ @Bean
+ public CdpSaga cdpSaga(
+ CdpApi cdpServiceApi,
+ CdpProperties cdpProperties
+ ) {
+ return new CdpSaga(cdpServiceApi, cdpProperties);
+ }
+
+}
diff --git a/stream-cdp/cdp-core/src/main/java/com/backbase/stream/configuration/CdpProperties.java b/stream-cdp/cdp-core/src/main/java/com/backbase/stream/configuration/CdpProperties.java
new file mode 100644
index 000000000..bbe340e1f
--- /dev/null
+++ b/stream-cdp/cdp-core/src/main/java/com/backbase/stream/configuration/CdpProperties.java
@@ -0,0 +1,11 @@
+package com.backbase.stream.configuration;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@ConfigurationProperties(prefix = "backbase.stream.cdp")
+public record CdpProperties(
+ boolean enabled,
+ String defaultCustomerCategory
+) {
+
+}
diff --git a/stream-cdp/cdp-core/src/main/java/com/backbase/stream/package-info.java b/stream-cdp/cdp-core/src/main/java/com/backbase/stream/package-info.java
new file mode 100644
index 000000000..831c97c86
--- /dev/null
+++ b/stream-cdp/cdp-core/src/main/java/com/backbase/stream/package-info.java
@@ -0,0 +1 @@
+package com.backbase.stream;
\ No newline at end of file
diff --git a/stream-cdp/cdp-core/src/test/java/com/backbase/stream/cdp/CdpSagaTest.java b/stream-cdp/cdp-core/src/test/java/com/backbase/stream/cdp/CdpSagaTest.java
new file mode 100644
index 000000000..a8a80b59c
--- /dev/null
+++ b/stream-cdp/cdp-core/src/test/java/com/backbase/stream/cdp/CdpSagaTest.java
@@ -0,0 +1,102 @@
+package com.backbase.stream.cdp;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.backbase.cdp.ingestion.api.service.v1.CdpApi;
+import com.backbase.cdp.ingestion.api.service.v1.model.CdpEvent;
+import com.backbase.cdp.ingestion.api.service.v1.model.CdpEvents;
+import com.backbase.stream.configuration.CdpProperties;
+import java.util.Map;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import reactor.core.publisher.Mono;
+
+@ExtendWith(MockitoExtension.class)
+class CdpSagaTest {
+
+ @Mock
+ private CdpApi cdpServiceApi;
+
+ @Mock
+ private CdpProperties userKindSegmentationProperties;
+
+ @InjectMocks
+ private CdpSaga cdpSaga;
+
+ @Test
+ void testExecuteTask() {
+ var task = createTask();
+ when(cdpServiceApi.ingestEvents(any())).thenReturn(Mono.empty());
+
+ cdpSaga.executeTask(task).block();
+
+ verify(cdpServiceApi).ingestEvents(any());
+ }
+
+ @Test
+ void testExecuteTaskFailure() {
+ var task = createTask();
+ when(cdpServiceApi.ingestEvents(any()))
+ .thenReturn(Mono.error(new RuntimeException("Ingestion failed")));
+
+ try {
+ cdpSaga.executeTask(task).block();
+ } catch (Exception e) {
+ assertThat(e.getCause().getMessage()).isEqualTo("Ingestion failed");
+ }
+
+ verify(cdpServiceApi).ingestEvents(any());
+ }
+
+ @Test
+ void isDisabledByDefault() {
+ var saga = new CdpSaga(
+ cdpServiceApi,
+ null
+ );
+
+ assertThat(saga.isEnabled()).isFalse();
+ }
+
+ @Test
+ void defaultCustomerCategoryIsNullWhenSagaIsDisabled() {
+ when(userKindSegmentationProperties.enabled()).thenReturn(false);
+
+ assertThat(cdpSaga.getDefaultCustomerCategory()).isNull();
+ }
+
+ @Test
+ void rollbackReturnsNull() {
+ assertThat(cdpSaga.rollBack(createTask())).isNull();
+ }
+
+ @Test
+ void returnsDefaultCustomerCategoryFromProperties() {
+ when(userKindSegmentationProperties.enabled()).thenReturn(true);
+ when(userKindSegmentationProperties.defaultCustomerCategory()).thenReturn("RETAIL");
+
+ assertThat(cdpSaga.getDefaultCustomerCategory()).isEqualTo("RETAIL");
+ }
+
+ private CdpTask createTask() {
+ var task = new CdpTask();
+ task.setCdpEvents(
+ new CdpEvents()
+ .addCdpEventsItem(new CdpEvent()
+ .eventType("ProfileCreatedEvent")
+ .eventId(UUID.randomUUID().toString())
+ .sourceSystem("BACKBASE")
+ .sourceType("USER_ID")
+ .sourceId("internal-id")
+ .data(Map.of()))
+ );
+ return task;
+ }
+}
\ No newline at end of file
diff --git a/stream-cdp/cdp-core/src/test/java/com/backbase/stream/cdp/CdpTaskTest.java b/stream-cdp/cdp-core/src/test/java/com/backbase/stream/cdp/CdpTaskTest.java
new file mode 100644
index 000000000..8beb2bfc2
--- /dev/null
+++ b/stream-cdp/cdp-core/src/test/java/com/backbase/stream/cdp/CdpTaskTest.java
@@ -0,0 +1,15 @@
+package com.backbase.stream.cdp;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class CdpTaskTest {
+
+ @Test
+ void testCdpTask() {
+ CdpTask cdpTask = new CdpTask();
+ assertThat(cdpTask.getName()).isEqualTo("cdpProfilesIngestionTask");
+ }
+
+}
diff --git a/stream-cdp/cdp-core/src/test/java/com/backbase/stream/configuration/CdpConfigurationTest.java b/stream-cdp/cdp-core/src/test/java/com/backbase/stream/configuration/CdpConfigurationTest.java
new file mode 100644
index 000000000..22161b981
--- /dev/null
+++ b/stream-cdp/cdp-core/src/test/java/com/backbase/stream/configuration/CdpConfigurationTest.java
@@ -0,0 +1,51 @@
+package com.backbase.stream.configuration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.backbase.cdp.ingestion.api.service.v1.CdpApi;
+import com.backbase.stream.cdp.CdpSaga;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+
+class CdpConfigurationTest {
+
+ @Test
+ void testCdpSagaBeanCreation() {
+ // Arrange: create mocks
+ CdpApi cdpApi = Mockito.mock(CdpApi.class);
+ CdpProperties cdpProperties = new CdpProperties(true, "RETAIL");
+
+ // Use a test configuration to inject mocks
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+ context.registerBean(CdpApi.class, () -> cdpApi);
+ context.registerBean(CdpProperties.class, () -> cdpProperties);
+ context.register(CdpConfiguration.class);
+ context.refresh();
+
+ // Act: get the bean
+ CdpSaga cdpSaga = context.getBean(CdpSaga.class);
+
+ // Assert
+ assertThat(cdpSaga).isNotNull().isInstanceOf(CdpSaga.class);
+ context.close();
+ }
+
+ @Test
+ void testCdpSagaBeanCreation_withRecordProperties() {
+ // Arrange: create mocks
+ CdpApi cdpApi = Mockito.mock(CdpApi.class);
+ // Provide required constructor args for record
+ CdpProperties cdpProperties = new CdpProperties(false, "BUSINESS");
+
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+ context.registerBean(CdpApi.class, () -> cdpApi);
+ context.registerBean(CdpProperties.class, () -> cdpProperties);
+ context.register(CdpConfiguration.class);
+ context.refresh();
+
+ CdpSaga cdpSaga = context.getBean(CdpSaga.class);
+ assertThat(cdpSaga).isNotNull().isInstanceOf(CdpSaga.class);
+ context.close();
+ }
+}
diff --git a/stream-cdp/cdp-core/src/test/java/com/backbase/stream/configuration/CdpPropertiesTest.java b/stream-cdp/cdp-core/src/test/java/com/backbase/stream/configuration/CdpPropertiesTest.java
new file mode 100644
index 000000000..fdd253de3
--- /dev/null
+++ b/stream-cdp/cdp-core/src/test/java/com/backbase/stream/configuration/CdpPropertiesTest.java
@@ -0,0 +1,16 @@
+package com.backbase.stream.configuration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class CdpPropertiesTest {
+
+ @Test
+ void testProperties() {
+ CdpProperties properties = new CdpProperties(true, "testCategory");
+
+ assertThat(properties.enabled()).isTrue();
+ assertThat(properties.defaultCustomerCategory()).isEqualTo("testCategory");
+ }
+}
diff --git a/stream-cdp/pom.xml b/stream-cdp/pom.xml
new file mode 100644
index 000000000..e10bfd3e2
--- /dev/null
+++ b/stream-cdp/pom.xml
@@ -0,0 +1,20 @@
+
+
+ 4.0.0
+
+
+ com.backbase.stream
+ stream-services
+ 9.6.0
+
+
+ stream-cdp
+
+ pom
+ Stream :: CDP
+
+
+ cdp-core
+
+
+
diff --git a/stream-compositions/api/cursors-api/pom.xml b/stream-compositions/api/cursors-api/pom.xml
index 1fefc94b8..79b991d05 100644
--- a/stream-compositions/api/cursors-api/pom.xml
+++ b/stream-compositions/api/cursors-api/pom.xml
@@ -5,7 +5,7 @@
api
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
cursors-api
diff --git a/stream-compositions/api/cursors-api/transaction-cursor-api/pom.xml b/stream-compositions/api/cursors-api/transaction-cursor-api/pom.xml
index f587b2097..12ad8a8b4 100644
--- a/stream-compositions/api/cursors-api/transaction-cursor-api/pom.xml
+++ b/stream-compositions/api/cursors-api/transaction-cursor-api/pom.xml
@@ -5,7 +5,7 @@
cursors-api
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
4.0.0
diff --git a/stream-compositions/api/integrations-api/legal-entity-integration-api/pom.xml b/stream-compositions/api/integrations-api/legal-entity-integration-api/pom.xml
index f01683572..c0063dedb 100644
--- a/stream-compositions/api/integrations-api/legal-entity-integration-api/pom.xml
+++ b/stream-compositions/api/integrations-api/legal-entity-integration-api/pom.xml
@@ -6,7 +6,7 @@
integrations-api
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.api
diff --git a/stream-compositions/api/integrations-api/payment-order-integration-api/pom.xml b/stream-compositions/api/integrations-api/payment-order-integration-api/pom.xml
index 444645667..09133d5e0 100644
--- a/stream-compositions/api/integrations-api/payment-order-integration-api/pom.xml
+++ b/stream-compositions/api/integrations-api/payment-order-integration-api/pom.xml
@@ -6,7 +6,7 @@
integrations-api
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.api
diff --git a/stream-compositions/api/integrations-api/pom.xml b/stream-compositions/api/integrations-api/pom.xml
index 5a64fc340..ecc13de5d 100644
--- a/stream-compositions/api/integrations-api/pom.xml
+++ b/stream-compositions/api/integrations-api/pom.xml
@@ -6,7 +6,7 @@
api
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
integrations-api
diff --git a/stream-compositions/api/integrations-api/product-catalog-integration-api/pom.xml b/stream-compositions/api/integrations-api/product-catalog-integration-api/pom.xml
index 1e9424baf..07c92b9ed 100644
--- a/stream-compositions/api/integrations-api/product-catalog-integration-api/pom.xml
+++ b/stream-compositions/api/integrations-api/product-catalog-integration-api/pom.xml
@@ -6,7 +6,7 @@
integrations-api
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.api
diff --git a/stream-compositions/api/integrations-api/product-integration-api/pom.xml b/stream-compositions/api/integrations-api/product-integration-api/pom.xml
index 40974425d..b6acae63f 100644
--- a/stream-compositions/api/integrations-api/product-integration-api/pom.xml
+++ b/stream-compositions/api/integrations-api/product-integration-api/pom.xml
@@ -6,7 +6,7 @@
integrations-api
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.api
diff --git a/stream-compositions/api/integrations-api/transaction-integration-api/pom.xml b/stream-compositions/api/integrations-api/transaction-integration-api/pom.xml
index 48bd65ec7..abde27f50 100644
--- a/stream-compositions/api/integrations-api/transaction-integration-api/pom.xml
+++ b/stream-compositions/api/integrations-api/transaction-integration-api/pom.xml
@@ -6,7 +6,7 @@
integrations-api
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.api
diff --git a/stream-compositions/api/pom.xml b/stream-compositions/api/pom.xml
index ff9581fa5..1fbd7ee1d 100644
--- a/stream-compositions/api/pom.xml
+++ b/stream-compositions/api/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions
diff --git a/stream-compositions/api/service-api/legal-entity-composition-api/pom.xml b/stream-compositions/api/service-api/legal-entity-composition-api/pom.xml
index bb34b7cae..aef1da2d1 100644
--- a/stream-compositions/api/service-api/legal-entity-composition-api/pom.xml
+++ b/stream-compositions/api/service-api/legal-entity-composition-api/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream.compositions
service-api
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.api
diff --git a/stream-compositions/api/service-api/payment-order-composition-api/pom.xml b/stream-compositions/api/service-api/payment-order-composition-api/pom.xml
index 5fa599783..609aefe69 100644
--- a/stream-compositions/api/service-api/payment-order-composition-api/pom.xml
+++ b/stream-compositions/api/service-api/payment-order-composition-api/pom.xml
@@ -6,7 +6,7 @@
service-api
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.api
diff --git a/stream-compositions/api/service-api/pom.xml b/stream-compositions/api/service-api/pom.xml
index a4a30c715..1a2d0a83d 100644
--- a/stream-compositions/api/service-api/pom.xml
+++ b/stream-compositions/api/service-api/pom.xml
@@ -6,7 +6,7 @@
com.backbase.stream.compositions
api
- 9.5.1
+ 9.6.0
service-api
diff --git a/stream-compositions/api/service-api/product-catalog-composition-api/pom.xml b/stream-compositions/api/service-api/product-catalog-composition-api/pom.xml
index f34792d8b..cb31c7064 100644
--- a/stream-compositions/api/service-api/product-catalog-composition-api/pom.xml
+++ b/stream-compositions/api/service-api/product-catalog-composition-api/pom.xml
@@ -6,7 +6,7 @@
service-api
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.api
diff --git a/stream-compositions/api/service-api/product-composition-api/pom.xml b/stream-compositions/api/service-api/product-composition-api/pom.xml
index 432976233..adef570a7 100644
--- a/stream-compositions/api/service-api/product-composition-api/pom.xml
+++ b/stream-compositions/api/service-api/product-composition-api/pom.xml
@@ -6,7 +6,7 @@
service-api
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.api
diff --git a/stream-compositions/api/service-api/transaction-composition-api/pom.xml b/stream-compositions/api/service-api/transaction-composition-api/pom.xml
index 70a74a98b..d0777b8c8 100644
--- a/stream-compositions/api/service-api/transaction-composition-api/pom.xml
+++ b/stream-compositions/api/service-api/transaction-composition-api/pom.xml
@@ -6,7 +6,7 @@
service-api
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.api
diff --git a/stream-compositions/cursors/pom.xml b/stream-compositions/cursors/pom.xml
index bf133ee51..40b9ecea0 100644
--- a/stream-compositions/cursors/pom.xml
+++ b/stream-compositions/cursors/pom.xml
@@ -5,7 +5,7 @@
stream-compositions
com.backbase.stream
- 9.5.1
+ 9.6.0
4.0.0
diff --git a/stream-compositions/cursors/transaction-cursor/pom.xml b/stream-compositions/cursors/transaction-cursor/pom.xml
index 4804a95e6..62e461471 100644
--- a/stream-compositions/cursors/transaction-cursor/pom.xml
+++ b/stream-compositions/cursors/transaction-cursor/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream.compositions
cursors
- 9.5.1
+ 9.6.0
4.0.0
diff --git a/stream-compositions/events/grandcentral/pom.xml b/stream-compositions/events/grandcentral/pom.xml
index bae6d955b..981ecc85e 100644
--- a/stream-compositions/events/grandcentral/pom.xml
+++ b/stream-compositions/events/grandcentral/pom.xml
@@ -5,7 +5,7 @@
events
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.events
diff --git a/stream-compositions/events/legal-entity-egress/pom.xml b/stream-compositions/events/legal-entity-egress/pom.xml
index b3bc4fc9f..f17efd8f5 100644
--- a/stream-compositions/events/legal-entity-egress/pom.xml
+++ b/stream-compositions/events/legal-entity-egress/pom.xml
@@ -5,7 +5,7 @@
events
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.events
diff --git a/stream-compositions/events/legal-entity-ingress/pom.xml b/stream-compositions/events/legal-entity-ingress/pom.xml
index e7242bab6..fee0a0dc4 100644
--- a/stream-compositions/events/legal-entity-ingress/pom.xml
+++ b/stream-compositions/events/legal-entity-ingress/pom.xml
@@ -5,7 +5,7 @@
events
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.events
diff --git a/stream-compositions/events/pom.xml b/stream-compositions/events/pom.xml
index 7ac3d1c78..ed67fc334 100644
--- a/stream-compositions/events/pom.xml
+++ b/stream-compositions/events/pom.xml
@@ -6,7 +6,7 @@
com.backbase.stream
stream-compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions
diff --git a/stream-compositions/events/product-catalog-egress/pom.xml b/stream-compositions/events/product-catalog-egress/pom.xml
index 5b9867019..06a34a197 100644
--- a/stream-compositions/events/product-catalog-egress/pom.xml
+++ b/stream-compositions/events/product-catalog-egress/pom.xml
@@ -5,7 +5,7 @@
events
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.events
diff --git a/stream-compositions/events/product-catalog-ingress/pom.xml b/stream-compositions/events/product-catalog-ingress/pom.xml
index 30d6c9fac..7e4b5dc4d 100644
--- a/stream-compositions/events/product-catalog-ingress/pom.xml
+++ b/stream-compositions/events/product-catalog-ingress/pom.xml
@@ -5,7 +5,7 @@
events
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.events
diff --git a/stream-compositions/events/product-egress/pom.xml b/stream-compositions/events/product-egress/pom.xml
index b3dc20510..efa61d6f3 100644
--- a/stream-compositions/events/product-egress/pom.xml
+++ b/stream-compositions/events/product-egress/pom.xml
@@ -5,7 +5,7 @@
events
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.events
diff --git a/stream-compositions/events/product-ingress/pom.xml b/stream-compositions/events/product-ingress/pom.xml
index 696a2f803..6ffe789af 100644
--- a/stream-compositions/events/product-ingress/pom.xml
+++ b/stream-compositions/events/product-ingress/pom.xml
@@ -5,7 +5,7 @@
events
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.events
diff --git a/stream-compositions/events/transaction-egress/pom.xml b/stream-compositions/events/transaction-egress/pom.xml
index 09bcb681f..323f1c2a1 100644
--- a/stream-compositions/events/transaction-egress/pom.xml
+++ b/stream-compositions/events/transaction-egress/pom.xml
@@ -5,7 +5,7 @@
events
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.events
diff --git a/stream-compositions/events/transaction-ingress/pom.xml b/stream-compositions/events/transaction-ingress/pom.xml
index 5ad48a060..aea0dcb66 100644
--- a/stream-compositions/events/transaction-ingress/pom.xml
+++ b/stream-compositions/events/transaction-ingress/pom.xml
@@ -5,7 +5,7 @@
events
com.backbase.stream.compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions.events
diff --git a/stream-compositions/pom.xml b/stream-compositions/pom.xml
index 2daf0d172..969a18657 100644
--- a/stream-compositions/pom.xml
+++ b/stream-compositions/pom.xml
@@ -7,13 +7,13 @@
com.backbase.stream
stream-starter
- 9.5.1
+ 9.6.0
../stream-sdk/stream-starter
com.backbase.stream
stream-compositions
- 9.5.1
+ 9.6.0
pom
Stream :: Compositions
diff --git a/stream-compositions/services/legal-entity-composition-service/pom.xml b/stream-compositions/services/legal-entity-composition-service/pom.xml
index ad5d530d2..636565e86 100644
--- a/stream-compositions/services/legal-entity-composition-service/pom.xml
+++ b/stream-compositions/services/legal-entity-composition-service/pom.xml
@@ -7,7 +7,7 @@
com.backbase.stream.compositions
services
- 9.5.1
+ 9.6.0
legal-entity-composition-service
diff --git a/stream-compositions/services/payment-order-composition-service/pom.xml b/stream-compositions/services/payment-order-composition-service/pom.xml
index 5169ba450..3860580da 100644
--- a/stream-compositions/services/payment-order-composition-service/pom.xml
+++ b/stream-compositions/services/payment-order-composition-service/pom.xml
@@ -6,7 +6,7 @@
com.backbase.stream.compositions
services
- 9.5.1
+ 9.6.0
payment-order-composition-service
diff --git a/stream-compositions/services/pom.xml b/stream-compositions/services/pom.xml
index e1525092b..8a8ac9908 100644
--- a/stream-compositions/services/pom.xml
+++ b/stream-compositions/services/pom.xml
@@ -6,7 +6,7 @@
com.backbase.stream
stream-compositions
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions
diff --git a/stream-compositions/services/product-catalog-composition-service/pom.xml b/stream-compositions/services/product-catalog-composition-service/pom.xml
index f5f10e710..bef4df81c 100644
--- a/stream-compositions/services/product-catalog-composition-service/pom.xml
+++ b/stream-compositions/services/product-catalog-composition-service/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream.compositions
services
- 9.5.1
+ 9.6.0
product-catalog-composition-service
diff --git a/stream-compositions/services/product-composition-service/pom.xml b/stream-compositions/services/product-composition-service/pom.xml
index 78a8e977a..ae633d3a2 100644
--- a/stream-compositions/services/product-composition-service/pom.xml
+++ b/stream-compositions/services/product-composition-service/pom.xml
@@ -7,7 +7,7 @@
com.backbase.stream.compositions
services
- 9.5.1
+ 9.6.0
product-composition-service
diff --git a/stream-compositions/services/transaction-composition-service/pom.xml b/stream-compositions/services/transaction-composition-service/pom.xml
index b0cd1b164..65a310733 100644
--- a/stream-compositions/services/transaction-composition-service/pom.xml
+++ b/stream-compositions/services/transaction-composition-service/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream.compositions
services
- 9.5.1
+ 9.6.0
transaction-composition-service
diff --git a/stream-compositions/test-utils/pom.xml b/stream-compositions/test-utils/pom.xml
index 2e3efa433..c82f08a83 100644
--- a/stream-compositions/test-utils/pom.xml
+++ b/stream-compositions/test-utils/pom.xml
@@ -6,7 +6,7 @@
stream-compositions
com.backbase.stream
- 9.5.1
+ 9.6.0
com.backbase.stream.compositions
diff --git a/stream-contacts/contacts-core/pom.xml b/stream-contacts/contacts-core/pom.xml
index b1d365f00..314b35bc0 100644
--- a/stream-contacts/contacts-core/pom.xml
+++ b/stream-contacts/contacts-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-contacts
- 9.5.1
+ 9.6.0
contacts-core
diff --git a/stream-contacts/pom.xml b/stream-contacts/pom.xml
index 84e4ef306..dc653f25e 100644
--- a/stream-contacts/pom.xml
+++ b/stream-contacts/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-contacts
diff --git a/stream-cursor/cursor-core/pom.xml b/stream-cursor/cursor-core/pom.xml
index 31f8a2685..18cff867f 100644
--- a/stream-cursor/cursor-core/pom.xml
+++ b/stream-cursor/cursor-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-cursor
- 9.5.1
+ 9.6.0
cursor-core
diff --git a/stream-cursor/cursor-http/pom.xml b/stream-cursor/cursor-http/pom.xml
index 92e17f709..4e74fdd6e 100644
--- a/stream-cursor/cursor-http/pom.xml
+++ b/stream-cursor/cursor-http/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-http-starter-parent
- 9.5.1
+ 9.6.0
../../stream-sdk/stream-starter-parents/stream-http-starter-parent
diff --git a/stream-cursor/cursor-publishers/pom.xml b/stream-cursor/cursor-publishers/pom.xml
index 9c5b339db..375ff5a8c 100644
--- a/stream-cursor/cursor-publishers/pom.xml
+++ b/stream-cursor/cursor-publishers/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-cursor
- 9.5.1
+ 9.6.0
cursor-publishers
diff --git a/stream-cursor/cursor-store/pom.xml b/stream-cursor/cursor-store/pom.xml
index 20acbd710..f7b02efce 100644
--- a/stream-cursor/cursor-store/pom.xml
+++ b/stream-cursor/cursor-store/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-cursor
- 9.5.1
+ 9.6.0
cursor-store
diff --git a/stream-cursor/pom.xml b/stream-cursor/pom.xml
index 971762600..d7a85cb3e 100644
--- a/stream-cursor/pom.xml
+++ b/stream-cursor/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-cursor
diff --git a/stream-customer-profile/customer-profile-core/pom.xml b/stream-customer-profile/customer-profile-core/pom.xml
index 898a19ee0..586e4a8af 100644
--- a/stream-customer-profile/customer-profile-core/pom.xml
+++ b/stream-customer-profile/customer-profile-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-customer-profile
- 9.5.1
+ 9.6.0
customer-profile-core
diff --git a/stream-customer-profile/pom.xml b/stream-customer-profile/pom.xml
index c758b1515..7c15da7ea 100644
--- a/stream-customer-profile/pom.xml
+++ b/stream-customer-profile/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-customer-profile
diff --git a/stream-dbs-clients/pom.xml b/stream-dbs-clients/pom.xml
index a604aa11f..b4efc00d7 100644
--- a/stream-dbs-clients/pom.xml
+++ b/stream-dbs-clients/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-dbs-clients
@@ -745,6 +745,60 @@
+
+ boat-validation-cdp-spec
+
+ validate
+
+ generate-sources
+
+ ${project.basedir}/src/main/openapi/cdp-ingestion-service-api-v1.0.0-beta.yaml
+ true
+
+
+
+ generate-cdp-ingestion-service-api-code
+
+ generate-webclient-embedded
+
+ generate-sources
+
+ REFACTOR_ALLOF_WITH_PROPERTIES_ONLY=true
+ ${project.basedir}/src/main/openapi/cdp-ingestion-service-api-v1.0.0-beta.yaml
+ com.backbase.cdp.ingestion.api.service.v1
+ com.backbase.cdp.ingestion.api.service.v1.model
+
+ false
+
+
+
+
+ boat-validation-cdp-profiles-spec
+
+ validate
+
+ generate-sources
+
+ ${project.basedir}/src/main/openapi/cdp-profiles-service-api-v1.0.0-beta.yaml
+ true
+
+
+
+ generate-cdp-profiles-service-api-code
+
+ generate-webclient-embedded
+
+ generate-sources
+
+ REFACTOR_ALLOF_WITH_PROPERTIES_ONLY=true
+ ${project.basedir}/src/main/openapi/cdp-profiles-service-api-v1.0.0-beta.yaml
+ com.backbase.cdp.profiles.api.service.v1
+ com.backbase.cdp.profiles.api.service.v1.model
+
+ false
+
+
+
generate-plan-manager-service-api-code
diff --git a/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CdpIngestionClientConfig.java b/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CdpIngestionClientConfig.java
new file mode 100644
index 000000000..0b28a9ac4
--- /dev/null
+++ b/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CdpIngestionClientConfig.java
@@ -0,0 +1,35 @@
+package com.backbase.stream.clients.config;
+
+import com.backbase.cdp.ingestion.api.service.ApiClient;
+import com.backbase.cdp.ingestion.api.service.v1.CdpApi;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.text.DateFormat;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConfigurationProperties("backbase.communication.services.cdp-ingestion")
+public class CdpIngestionClientConfig extends CompositeApiClientConfig {
+
+ public static final String CDP_INGESTION_SERVICE_ID = "cdp-ingestion";
+
+ public CdpIngestionClientConfig() {
+ super(CDP_INGESTION_SERVICE_ID);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public ApiClient cdpIngestionApiClient(ObjectMapper objectMapper, DateFormat dateFormat) {
+ return new ApiClient(getWebClient(), objectMapper, dateFormat)
+ .setBasePath(createBasePath());
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public CdpApi cdpIngestionServiceApi(ApiClient apiClient) {
+ return new CdpApi(apiClient);
+ }
+
+}
diff --git a/stream-dbs-clients/src/main/openapi/cdp-ingestion-service-api-v1.0.0-beta.yaml b/stream-dbs-clients/src/main/openapi/cdp-ingestion-service-api-v1.0.0-beta.yaml
new file mode 100644
index 000000000..d7ceb3fa9
--- /dev/null
+++ b/stream-dbs-clients/src/main/openapi/cdp-ingestion-service-api-v1.0.0-beta.yaml
@@ -0,0 +1,1955 @@
+openapi: 3.0.3
+info:
+ title: CDP Ingestion Service API Spec
+ description: Specs for CDP Ingestion Service API
+ version: 1.0.0-beta
+ x-icon: credit_card
+servers:
+- url: http://localhost:8080
+ description: prism mock server
+tags:
+- name: cdp
+paths:
+ /service-api/v1/ingestEvents:
+ post:
+ tags:
+ - cdp
+ summary: Ingest multiple CDP events
+ description: Accepts and processes multiple CDP events for bulk ingestion into
+ the platform
+ operationId: ingestEvents
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/CdpEvents"
+ examples:
+ cdpEvents:
+ $ref: "#/components/examples/CdpEventsExample"
+ value: null
+ required: true
+ responses:
+ "200":
+ description: Events successfully processed
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/BulkIngestionSuccessResponse"
+ examples:
+ bulkSuccess:
+ $ref: "#/components/examples/BulkIngestionSuccessExample"
+ value: null
+ "400":
+ description: |
+ The server cannot or will not process the request due to something that is perceived to be a client error.
+ For example, invalid event structure or missing required fields.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/BadRequestError"
+ examples:
+ badRequestError:
+ $ref: "#/components/examples/BadRequestExample"
+ value: null
+ "401":
+ description: Request lacks valid authentication credentials for the target
+ resource.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UnauthorizedError"
+ examples:
+ unauthorizedError:
+ $ref: "#/components/examples/UnauthorizedExample"
+ value: null
+ "404":
+ description: Not found.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/error"
+ example:
+ $ref: "#/components/examples/not-found-error"
+ "500":
+ description: Internal server error occurred while processing the event
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/InternalServerError"
+ examples:
+ internalServerError:
+ $ref: "#/components/examples/InternalServerErrorExample"
+ value: null
+ x-BbAccessControl: false
+ /service-api/v1/validation/event-types/{eventType}/rules:
+ get:
+ tags:
+ - validation
+ summary: Get validation rules
+ description: Retrieves validation rules for a specific event type
+ operationId: getValidationRules
+ parameters:
+ - name: eventType
+ in: path
+ description: Event type to get rules for
+ required: true
+ style: simple
+ explode: false
+ schema:
+ maxLength: 100
+ type: string
+ responses:
+ "200":
+ description: Successfully retrieved validation rules
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: "#/components/schemas/ValidationRule"
+ "401":
+ description: Request lacks valid authentication credentials
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UnauthorizedError"
+ examples:
+ unauthorizedError:
+ $ref: "#/components/examples/UnauthorizedExample"
+ value: null
+ "500":
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/InternalServerError"
+ examples:
+ internalServerError:
+ $ref: "#/components/examples/InternalServerErrorExample"
+ value: null
+ x-BbAccessControl: false
+ post:
+ tags:
+ - validation
+ summary: Create validation rules
+ description: Creates one or more validation rules for validating CDP events
+ operationId: createValidationRules
+ parameters:
+ - name: eventType
+ in: path
+ description: Event type these rules apply to
+ required: true
+ style: simple
+ explode: false
+ schema:
+ maxLength: 100
+ type: string
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ValidationRule"
+ examples:
+ validationRule:
+ $ref: "#/components/examples/ValidationRuleExample"
+ value: null
+ required: true
+ responses:
+ "201":
+ description: Validation rule successfully created
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ValidationRule"
+ examples:
+ validationRule:
+ $ref: "#/components/examples/ValidationRuleExample"
+ value: null
+ "400":
+ description: Bad request - invalid schema format or duplicate schema
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/SchemaValidationError"
+ examples:
+ schemaValidationError:
+ $ref: "#/components/examples/SchemaValidationErrorExample"
+ value: null
+ "401":
+ description: Request lacks valid authentication credentials
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UnauthorizedError"
+ examples:
+ unauthorizedError:
+ $ref: "#/components/examples/UnauthorizedExample"
+ value: null
+ "500":
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/InternalServerError"
+ examples:
+ internalServerError:
+ $ref: "#/components/examples/InternalServerErrorExample"
+ value: null
+ x-BbAccessControl: false
+ /service-api/v1/validation/event-types/{eventType}/rules/{uuid}:
+ put:
+ tags:
+ - validation
+ summary: Update validation rule
+ description: Updates an existing validation rule
+ operationId: updateValidationRule
+ parameters:
+ - name: eventType
+ in: path
+ description: Event type this rule applies to
+ required: true
+ style: simple
+ explode: false
+ schema:
+ maxLength: 100
+ type: string
+ - name: uuid
+ in: path
+ description: Validation rule UUID
+ required: true
+ style: simple
+ explode: false
+ schema:
+ type: string
+ format: uuid
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ValidationRule"
+ required: true
+ responses:
+ "200":
+ description: Validation rule successfully updated
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ValidationRule"
+ "400":
+ description: Bad request - invalid validation rule data
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/BadRequestError"
+ examples:
+ badRequestError:
+ $ref: "#/components/examples/BadRequestExample"
+ value: null
+ "401":
+ description: Request lacks valid authentication credentials
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UnauthorizedError"
+ examples:
+ unauthorizedError:
+ $ref: "#/components/examples/UnauthorizedExample"
+ value: null
+ "404":
+ description: Validation rule not found
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/NotFoundError"
+ "500":
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/InternalServerError"
+ examples:
+ internalServerError:
+ $ref: "#/components/examples/InternalServerErrorExample"
+ value: null
+ x-BbAccessControl: false
+ delete:
+ tags:
+ - validation
+ summary: Delete validation rule
+ description: Deletes a validation rule by its UUID
+ operationId: deleteValidationRule
+ parameters:
+ - name: eventType
+ in: path
+ description: Event type this rule applies to
+ required: true
+ style: simple
+ explode: false
+ schema:
+ maxLength: 100
+ type: string
+ - name: uuid
+ in: path
+ description: Validation rule UUID
+ required: true
+ style: simple
+ explode: false
+ schema:
+ type: string
+ format: uuid
+ responses:
+ "204":
+ description: Validation rule successfully deleted
+ "401":
+ description: Request lacks valid authentication credentials
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UnauthorizedError"
+ examples:
+ unauthorizedError:
+ $ref: "#/components/examples/UnauthorizedExample"
+ value: null
+ "404":
+ description: Validation rule not found
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/NotFoundError"
+ "500":
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/InternalServerError"
+ examples:
+ internalServerError:
+ $ref: "#/components/examples/InternalServerErrorExample"
+ value: null
+ x-BbAccessControl: false
+ /service-api/v1/validation/event-types:
+ get:
+ tags:
+ - validation
+ summary: Get all event types
+ description: Retrieves all available event types
+ operationId: getAllEventTypes
+ responses:
+ "200":
+ description: Successfully retrieved event types
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: "#/components/schemas/EventType"
+ "401":
+ description: Request lacks valid authentication credentials
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UnauthorizedError"
+ examples:
+ unauthorizedError:
+ $ref: "#/components/examples/UnauthorizedExample"
+ value: null
+ "500":
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/InternalServerError"
+ examples:
+ internalServerError:
+ $ref: "#/components/examples/InternalServerErrorExample"
+ value: null
+ x-BbAccessControl: false
+ post:
+ tags:
+ - validation
+ summary: Create a new event type
+ description: Creates a new event type for CDP events
+ operationId: createEventType
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/EventType"
+ required: true
+ responses:
+ "201":
+ description: Event type successfully created
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/EventType"
+ "400":
+ description: Bad request - invalid event type data
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/BadRequestError"
+ examples:
+ badRequestError:
+ $ref: "#/components/examples/BadRequestExample"
+ value: null
+ "401":
+ description: Request lacks valid authentication credentials
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UnauthorizedError"
+ examples:
+ unauthorizedError:
+ $ref: "#/components/examples/UnauthorizedExample"
+ value: null
+ "500":
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/InternalServerError"
+ examples:
+ internalServerError:
+ $ref: "#/components/examples/InternalServerErrorExample"
+ value: null
+ x-BbAccessControl: false
+ /service-api/v1/validation/event-types/{eventType}:
+ delete:
+ tags:
+ - validation
+ summary: Delete the event type
+ description: Deletes the event type
+ operationId: deleteEventType
+ parameters:
+ - name: eventType
+ in: path
+ description: Event type to delete
+ required: true
+ style: simple
+ explode: false
+ schema:
+ maxLength: 100
+ type: string
+ responses:
+ "204":
+ description: Event type successfully deleted
+ "401":
+ description: Request lacks valid authentication credentials
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UnauthorizedError"
+ examples:
+ unauthorizedError:
+ $ref: "#/components/examples/UnauthorizedExample"
+ value: null
+ "404":
+ description: Event type configuration not found
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/NotFoundError"
+ "500":
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/InternalServerError"
+ examples:
+ internalServerError:
+ $ref: "#/components/examples/InternalServerErrorExample"
+ value: null
+ x-BbAccessControl: false
+ /service-api/v1/validation/event-types/{eventType}/configuration:
+ get:
+ tags:
+ - validation
+ summary: Get configuration for an event type
+ description: Retrieves the configuration for a specific event type (1-to-1 relationship)
+ operationId: getEventTypeConfiguration
+ parameters:
+ - name: eventType
+ in: path
+ description: Event type to get configuration for
+ required: true
+ style: simple
+ explode: false
+ schema:
+ maxLength: 100
+ type: string
+ responses:
+ "200":
+ description: Successfully retrieved event type configuration
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/EventTypeConfiguration"
+ examples:
+ eventTypeConfiguration:
+ $ref: "#/components/examples/EventTypeConfigurationExample"
+ value: null
+ "404":
+ description: Configuration not found for this event type
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/NotFoundError"
+ "401":
+ description: Request lacks valid authentication credentials
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UnauthorizedError"
+ examples:
+ unauthorizedError:
+ $ref: "#/components/examples/UnauthorizedExample"
+ value: null
+ "500":
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/InternalServerError"
+ examples:
+ internalServerError:
+ $ref: "#/components/examples/InternalServerErrorExample"
+ value: null
+ x-BbAccessControl: false
+ put:
+ tags:
+ - validation
+ summary: Create or update configuration for an event type
+ description: Creates or updates the configuration for a specific event type
+ (1-to-1 relationship)
+ operationId: createOrUpdateEventTypeConfiguration
+ parameters:
+ - name: eventType
+ in: path
+ description: Event type to configure
+ required: true
+ style: simple
+ explode: false
+ schema:
+ maxLength: 100
+ type: string
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/EventTypeConfiguration"
+ required: true
+ responses:
+ "200":
+ description: Event type configuration successfully updated
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/EventTypeConfiguration"
+ examples:
+ eventTypeConfiguration:
+ $ref: "#/components/examples/EventTypeConfigurationExample"
+ value: null
+ "201":
+ description: Event type configuration successfully created
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/EventTypeConfiguration"
+ examples:
+ eventTypeConfiguration:
+ $ref: "#/components/examples/EventTypeConfigurationExample"
+ value: null
+ "400":
+ description: Bad request - invalid configuration data
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/BadRequestError"
+ examples:
+ badRequestError:
+ $ref: "#/components/examples/BadRequestExample"
+ value: null
+ "401":
+ description: Request lacks valid authentication credentials
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UnauthorizedError"
+ examples:
+ unauthorizedError:
+ $ref: "#/components/examples/UnauthorizedExample"
+ value: null
+ "500":
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/InternalServerError"
+ examples:
+ internalServerError:
+ $ref: "#/components/examples/InternalServerErrorExample"
+ value: null
+ x-BbAccessControl: false
+ delete:
+ tags:
+ - validation
+ summary: Delete configuration for an event type
+ description: Deletes the configuration for a specific event type
+ operationId: deleteEventTypeConfiguration
+ parameters:
+ - name: eventType
+ in: path
+ description: Event type
+ required: true
+ style: simple
+ explode: false
+ schema:
+ maxLength: 100
+ type: string
+ responses:
+ "204":
+ description: Event type configuration successfully deleted
+ "401":
+ description: Request lacks valid authentication credentials
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UnauthorizedError"
+ examples:
+ unauthorizedError:
+ $ref: "#/components/examples/UnauthorizedExample"
+ value: null
+ "404":
+ description: Event type configuration not found
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/NotFoundError"
+ "500":
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/InternalServerError"
+ examples:
+ internalServerError:
+ $ref: "#/components/examples/InternalServerErrorExample"
+ value: null
+ x-BbAccessControl: false
+components:
+ schemas:
+ CdpEvent:
+ required:
+ - data
+ - eventId
+ - eventType
+ - sourceId
+ - sourceSystem
+ - sourceType
+ type: object
+ properties:
+ eventId:
+ type: string
+ description: Unique identifier of the event in the source system
+ example: 12345678-1234-5678-9012-123456789012
+ eventType:
+ type: string
+ description: Type of the event - used for event validation and processing
+ definitions
+ example: login
+ timestamp:
+ type: string
+ description: Time when event was emitted by the source system
+ format: date-time
+ example: 2023-09-16T10:30:00Z
+ sourceSystem:
+ type: string
+ description: "System where the event originated (e.g., web_app, mobile_app)"
+ example: mobile_app
+ sourceType:
+ type: string
+ description: "Identifies the type of the source entity. Examples: USER_ID,\
+ \ CUSTOMER_ID, ACCOUNT_ID, DATA_GROUP_ID"
+ example: USER_ID
+ sourceId:
+ type: string
+ description: The id of the entity in the source system
+ example: user-123456
+ sessionId:
+ type: string
+ description: "ID of the user session (for web originated events, mostly)"
+ example: session-789012
+ cdpCustomerId:
+ type: string
+ description: Provided if the source system is aware of the CDP customer
+ profile id
+ example: cdp_789
+ data:
+ type: object
+ additionalProperties: true
+ description: "The main entity Map to provide the information\
+ \ for CDP"
+ context:
+ type: object
+ additionalProperties: true
+ description: Map of String and Object to store any information on the context
+ metadata:
+ type: object
+ properties:
+ schemaVersion:
+ type: string
+ description: Event schema version
+ source:
+ type: string
+ description: The name of the event's service origin
+ correlationId:
+ type: string
+ description: Correlation ID for tracing across services
+ traceId:
+ type: string
+ description: Trace ID for distributed tracing
+ processedBy:
+ type: array
+ description: List of services that processed the event
+ items:
+ type: string
+ sourceIp:
+ type: string
+ description: Source IP address (for web/mobile events)
+ userAgent:
+ type: string
+ description: User agent (for web/mobile events)
+ additionalProperties: false
+ description: Event metadata from source system
+ CdpEvents:
+ required:
+ - cdpEvents
+ type: object
+ properties:
+ cdpEvents:
+ maxItems: 100
+ minItems: 1
+ type: array
+ description: Array of CDP events to be processed
+ example:
+ - eventId: 123e4567-e89b-12d3-a456-426614174000
+ eventType: USER_ACTION
+ timestamp: 2024-06-10T12:34:56Z
+ sourceSystem: webApp
+ sourceType: USER_ID
+ sourceId: user_001
+ sessionId: session_abc123
+ cdpCustomerId: null
+ data:
+ action: login
+ device: Chrome
+ location:
+ country: US
+ city: New York
+ context: null
+ metadata:
+ schemaVersion: 2.1.0
+ source: webApp
+ correlationId: corr-123e4567-e89b-12d3
+ traceId: trace-123e4567-e89b-12d3
+ processedBy: []
+ sourceIp: 192.168.1.1
+ userAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
+ - eventId: 456e7890-e12b-34d5-b789-567890123456
+ eventType: TRANSACTION
+ timestamp: 2024-06-10T12:35:30Z
+ sourceSystem: mobileApp
+ sourceType: USER_ID
+ sourceId: user_001
+ sessionId: session_abc123
+ cdpCustomerId: cdp_customer_001
+ data:
+ action: payment
+ amount: 150.0
+ currency: USD
+ merchant: Amazon
+ context:
+ deviceType: mobile
+ appVersion: 2.1.0
+ metadata:
+ schemaVersion: 2.1.0
+ source: mobileApp
+ correlationId: corr-456e7890-e12b-34d5
+ traceId: trace-456e7890-e12b-34d5
+ processedBy: []
+ sourceIp: 10.0.0.5
+ userAgent: MobileApp/2.1.0 (iOS 15.0)
+ items:
+ $ref: "#/components/schemas/cdp-event"
+ IngestionSuccessResponse:
+ required:
+ - eventId
+ - status
+ type: object
+ properties:
+ status:
+ type: string
+ description: Status of the ingestion request
+ example: SUCCESS
+ enum:
+ - SUCCESS
+ eventId:
+ type: string
+ description: The ID of the ingested event
+ format: uuid
+ example: 12345678-1234-5678-9012-123456789012
+ message:
+ type: string
+ description: Optional success message
+ example: Event successfully ingested
+ timestamp:
+ type: string
+ description: When the event was processed (ISO 8601 format)
+ format: date-time
+ example: 2023-09-16T10:30:01.5Z
+ BulkIngestionSuccessResponse:
+ required:
+ - processedEvents
+ - status
+ - totalEvents
+ type: object
+ properties:
+ status:
+ type: string
+ description: Status of the bulk ingestion request
+ example: SUCCESS
+ enum:
+ - SUCCESS
+ - PARTIAL_SUCCESS
+ totalEvents:
+ minimum: 1
+ type: integer
+ description: Total number of events received
+ example: 3
+ processedEvents:
+ minimum: 0
+ type: integer
+ description: Number of events successfully processed
+ example: 3
+ failedEvents:
+ minimum: 0
+ type: integer
+ description: Number of events that failed processing
+ example: 0
+ errors:
+ type: array
+ description: List of errors for failed events (if any)
+ example: []
+ items:
+ type: object
+ properties:
+ eventId:
+ type: string
+ description: ID of the event that failed
+ error:
+ type: string
+ description: Error message
+ errorCode:
+ type: string
+ description: Error code
+ message:
+ type: string
+ description: Optional success message
+ example: All events successfully ingested
+ timestamp:
+ type: string
+ description: When the bulk processing was completed (ISO 8601 format)
+ format: date-time
+ example: 2024-06-10T12:36:05.5Z
+ ValidationRule:
+ required:
+ - errorMessage
+ - fieldPath
+ - ruleName
+ - validationConfig
+ - validationType
+ type: object
+ properties:
+ id:
+ type: string
+ description: Unique identifier for the validation rule
+ format: uuid
+ readOnly: true
+ example: 123e4567-e89b-12d3-a456-426614174000
+ ruleName:
+ maxLength: 200
+ minLength: 1
+ type: string
+ description: Name of the validation rule
+ example: User ID Required
+ validationType:
+ $ref: "#/components/schemas/validation-type"
+ fieldPath:
+ maxLength: 500
+ minLength: 1
+ type: string
+ description: JSONPath to the field to validate
+ example: $.data.userId
+ validationConfig:
+ type: object
+ additionalProperties: true
+ description: Configuration object for the validation rule
+ example:
+ required: true
+ errorMessage:
+ maxLength: 500
+ minLength: 1
+ type: string
+ description: Error message to return when validation fails
+ example: User ID is required
+ SchemaValidationError:
+ required:
+ - message
+ type: object
+ properties:
+ message:
+ type: string
+ description: High-level error message
+ example: Invalid JSON schema format
+ ruleName:
+ type: string
+ description: Name of the validation rule that failed
+ example: ProfileCreatedEvent Schema v1.0
+ details:
+ type: array
+ description: Detailed validation errors for specific fields
+ items:
+ type: object
+ properties:
+ field:
+ type: string
+ description: The field path where the error occurred
+ example: properties.userId.type
+ error:
+ type: string
+ description: Specific error message for this field
+ example: "Invalid type: should be 'string'"
+ example:
+ message: Invalid JSON schema format
+ ruleName: ProfileCreatedEvent Schema v1.0
+ details:
+ - field: properties.userId.type
+ error: "Invalid type: should be 'string'"
+ - field: required
+ error: Missing required field 'email'
+ EventType:
+ required:
+ - eventType
+ type: object
+ properties:
+ id:
+ type: string
+ description: Unique UUID identifier for the event type
+ format: uuid
+ readOnly: true
+ example: 550e8400-e29b-41d4-a716-446655440000
+ eventType:
+ maxLength: 100
+ minLength: 1
+ type: string
+ description: The event type identifier
+ example: login
+ displayName:
+ maxLength: 200
+ type: string
+ description: Human-readable display name for the event type
+ example: User Login Event
+ description:
+ type: string
+ description: Description of the event type
+ example: Event triggered when a user successfully logs into the system
+ EventTypeAction:
+ required:
+ - actionName
+ - eventType
+ type: object
+ properties:
+ id:
+ type: string
+ description: Unique UUID identifier for the event type action
+ format: uuid
+ readOnly: true
+ example: 660e8400-e29b-41d4-a716-446655440001
+ eventType:
+ maxLength: 100
+ minLength: 1
+ type: string
+ description: The event type this action applies to
+ example: ProfileCreatedEvent
+ actionName:
+ maxLength: 200
+ minLength: 1
+ type: string
+ description: Name of the action to be performed
+ example: Identity Resolution
+ description:
+ maxLength: 500
+ type: string
+ description: Description of what this action does
+ example: Enrich event with identity resolution data
+ actionConfig:
+ type: object
+ additionalProperties: true
+ description: |
+ Configuration parameters for the event type processing.
+ Contains two main sections:
+ - profilesMatchingQueryString: Elasticsearch query object to find target profiles
+ - actions: Map of action names to enabled/disabled flags
+ example:
+ profilesMatchingQueryString:
+ term:
+ externalIds.id.keyword: '%s'
+ actions:
+ save-event: true
+ create-profile: true
+ update-segments: true
+ send-notification: false
+ EventTypeConfiguration:
+ required:
+ - eventType
+ type: object
+ properties:
+ id:
+ type: string
+ description: Unique UUID identifier for the event type configuration
+ format: uuid
+ readOnly: true
+ example: 660e8400-e29b-41d4-a716-446655440001
+ eventType:
+ maxLength: 100
+ minLength: 1
+ type: string
+ description: The event type this configuration applies to
+ example: ProfileCreatedEvent
+ profilesMatchingQuery:
+ type: object
+ additionalProperties: true
+ description: |
+ Elasticsearch query object to find target profiles for this event type.
+ This query determines which user profiles this event should be applied to.
+ example:
+ term:
+ externalIds.id.keyword: '%s'
+ eventConfig:
+ type: object
+ additionalProperties: true
+ description: |
+ Configuration for event enrichment actions.
+ Contains map of action names to enabled/disabled flags.
+ example:
+ actions:
+ save-event: true
+ create-profile: true
+ update-segments: true
+ send-notification: false
+ example:
+ $ref: ../examples/event-type-configuration.json
+ ValidationType:
+ type: string
+ description: Type of validation to perform
+ enum:
+ - SCHEMA_VALIDATION
+ x-enum-descriptions:
+ - Validates the entire data object against a JSON Schema
+ BadRequestError:
+ title: BadRequestError
+ required:
+ - key
+ - message
+ type: object
+ properties:
+ message:
+ minLength: 1
+ type: string
+ description: Any further information
+ key:
+ minLength: 1
+ type: string
+ description: Error summary
+ errors:
+ type: array
+ description: Detailed error information
+ items:
+ $ref: "#/components/schemas/error-item"
+ UnauthorizedError:
+ title: UnauthorizedError
+ required:
+ - key
+ - message
+ type: object
+ properties:
+ message:
+ minLength: 1
+ type: string
+ description: Any further information
+ key:
+ minLength: 1
+ type: string
+ description: Error summary
+ errors:
+ type: array
+ description: Detailed error information
+ items:
+ $ref: "#/components/schemas/error-item"
+ NotFoundError:
+ title: NotFoundError
+ required:
+ - key
+ - message
+ type: object
+ properties:
+ message:
+ minLength: 1
+ type: string
+ description: Any further information
+ key:
+ minLength: 1
+ type: string
+ description: Error summary
+ errors:
+ type: array
+ description: Detailed error information
+ items:
+ $ref: "#/components/schemas/error-item"
+ InternalServerError:
+ title: SimpleError
+ type: object
+ properties:
+ message:
+ minLength: 1
+ type: string
+ description: Any further information
+ key:
+ minLength: 1
+ type: string
+ description: Error summary
+ ErrorItem:
+ title: ErrorItem
+ required:
+ - key
+ - message
+ type: object
+ properties:
+ message:
+ minLength: 1
+ type: string
+ description: Any further information.
+ key:
+ minLength: 1
+ type: string
+ description: "{capability-name}.api.{api-key-name}. For generated validation\
+ \ errors this is the path in the document the error resolves to. e.g.\
+ \ object name + '.' + field"
+ context:
+ title: Context
+ type: object
+ additionalProperties:
+ type: string
+ description: Context can be anything used to construct localised messages.
+ error:
+ title: Error
+ required:
+ - key
+ - message
+ type: object
+ properties:
+ message:
+ minLength: 1
+ type: string
+ description: Any further information
+ key:
+ minLength: 1
+ type: string
+ description: Error summary
+ errors:
+ type: array
+ description: Detailed error information
+ items:
+ $ref: "#/components/schemas/error-item"
+ cdp-event:
+ required:
+ - data
+ - eventId
+ - eventType
+ - sourceId
+ - sourceSystem
+ - sourceType
+ type: object
+ properties:
+ eventId:
+ type: string
+ description: Unique identifier of the event in the source system
+ example: 12345678-1234-5678-9012-123456789012
+ eventType:
+ type: string
+ description: Type of the event - used for event validation and processing
+ definitions
+ example: login
+ timestamp:
+ type: string
+ description: Time when event was emitted by the source system
+ format: date-time
+ example: 2023-09-16T10:30:00Z
+ sourceSystem:
+ type: string
+ description: "System where the event originated (e.g., web_app, mobile_app)"
+ example: mobile_app
+ sourceType:
+ type: string
+ description: "Identifies the type of the source entity. Examples: USER_ID,\
+ \ CUSTOMER_ID, ACCOUNT_ID, DATA_GROUP_ID"
+ example: USER_ID
+ sourceId:
+ type: string
+ description: The id of the entity in the source system
+ example: user-123456
+ sessionId:
+ type: string
+ description: "ID of the user session (for web originated events, mostly)"
+ example: session-789012
+ cdpCustomerId:
+ type: string
+ description: Provided if the source system is aware of the CDP customer
+ profile id
+ example: cdp_789
+ data:
+ type: object
+ additionalProperties: true
+ description: "The main entity Map to provide the information\
+ \ for CDP"
+ context:
+ type: object
+ additionalProperties: true
+ description: Map of String and Object to store any information on the context
+ metadata:
+ type: object
+ properties:
+ schemaVersion:
+ type: string
+ description: Event schema version
+ source:
+ type: string
+ description: The name of the event's service origin
+ correlationId:
+ type: string
+ description: Correlation ID for tracing across services
+ traceId:
+ type: string
+ description: Trace ID for distributed tracing
+ processedBy:
+ type: array
+ description: List of services that processed the event
+ items:
+ type: string
+ sourceIp:
+ type: string
+ description: Source IP address (for web/mobile events)
+ userAgent:
+ type: string
+ description: User agent (for web/mobile events)
+ additionalProperties: false
+ description: Event metadata from source system
+ cdp-events:
+ required:
+ - cdpEvents
+ type: object
+ properties:
+ cdpEvents:
+ maxItems: 100
+ minItems: 1
+ type: array
+ description: Array of CDP events to be processed
+ example:
+ - eventId: 123e4567-e89b-12d3-a456-426614174000
+ eventType: USER_ACTION
+ timestamp: 2024-06-10T12:34:56Z
+ sourceSystem: webApp
+ sourceType: USER_ID
+ sourceId: user_001
+ sessionId: session_abc123
+ cdpCustomerId: null
+ data:
+ action: login
+ device: Chrome
+ location:
+ country: US
+ city: New York
+ context: null
+ metadata:
+ schemaVersion: 2.1.0
+ source: webApp
+ correlationId: corr-123e4567-e89b-12d3
+ traceId: trace-123e4567-e89b-12d3
+ processedBy: []
+ sourceIp: 192.168.1.1
+ userAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
+ - eventId: 456e7890-e12b-34d5-b789-567890123456
+ eventType: TRANSACTION
+ timestamp: 2024-06-10T12:35:30Z
+ sourceSystem: mobileApp
+ sourceType: USER_ID
+ sourceId: user_001
+ sessionId: session_abc123
+ cdpCustomerId: cdp_customer_001
+ data:
+ action: payment
+ amount: 150.0
+ currency: USD
+ merchant: Amazon
+ context:
+ deviceType: mobile
+ appVersion: 2.1.0
+ metadata:
+ schemaVersion: 2.1.0
+ source: mobileApp
+ correlationId: corr-456e7890-e12b-34d5
+ traceId: trace-456e7890-e12b-34d5
+ processedBy: []
+ sourceIp: 10.0.0.5
+ userAgent: MobileApp/2.1.0 (iOS 15.0)
+ items:
+ $ref: "#/components/schemas/cdp-event"
+ ingestion-success-response:
+ required:
+ - eventId
+ - status
+ type: object
+ properties:
+ status:
+ type: string
+ description: Status of the ingestion request
+ example: SUCCESS
+ enum:
+ - SUCCESS
+ eventId:
+ type: string
+ description: The ID of the ingested event
+ format: uuid
+ example: 12345678-1234-5678-9012-123456789012
+ message:
+ type: string
+ description: Optional success message
+ example: Event successfully ingested
+ timestamp:
+ type: string
+ description: When the event was processed (ISO 8601 format)
+ format: date-time
+ example: 2023-09-16T10:30:01.5Z
+ bulk-ingestion-success-response:
+ required:
+ - processedEvents
+ - status
+ - totalEvents
+ type: object
+ properties:
+ status:
+ type: string
+ description: Status of the bulk ingestion request
+ example: SUCCESS
+ enum:
+ - SUCCESS
+ - PARTIAL_SUCCESS
+ totalEvents:
+ minimum: 1
+ type: integer
+ description: Total number of events received
+ example: 3
+ processedEvents:
+ minimum: 0
+ type: integer
+ description: Number of events successfully processed
+ example: 3
+ failedEvents:
+ minimum: 0
+ type: integer
+ description: Number of events that failed processing
+ example: 0
+ errors:
+ type: array
+ description: List of errors for failed events (if any)
+ example: []
+ items:
+ type: object
+ properties:
+ eventId:
+ type: string
+ description: ID of the event that failed
+ error:
+ type: string
+ description: Error message
+ errorCode:
+ type: string
+ description: Error code
+ message:
+ type: string
+ description: Optional success message
+ example: All events successfully ingested
+ timestamp:
+ type: string
+ description: When the bulk processing was completed (ISO 8601 format)
+ format: date-time
+ example: 2024-06-10T12:36:05.5Z
+ validation-rule:
+ required:
+ - errorMessage
+ - fieldPath
+ - ruleName
+ - validationConfig
+ - validationType
+ type: object
+ properties:
+ id:
+ type: string
+ description: Unique identifier for the validation rule
+ format: uuid
+ readOnly: true
+ example: 123e4567-e89b-12d3-a456-426614174000
+ ruleName:
+ maxLength: 200
+ minLength: 1
+ type: string
+ description: Name of the validation rule
+ example: User ID Required
+ validationType:
+ $ref: "#/components/schemas/validation-type"
+ fieldPath:
+ maxLength: 500
+ minLength: 1
+ type: string
+ description: JSONPath to the field to validate
+ example: $.data.userId
+ validationConfig:
+ type: object
+ additionalProperties: true
+ description: Configuration object for the validation rule
+ example:
+ required: true
+ errorMessage:
+ maxLength: 500
+ minLength: 1
+ type: string
+ description: Error message to return when validation fails
+ example: User ID is required
+ schema-validation-error:
+ required:
+ - message
+ type: object
+ properties:
+ message:
+ type: string
+ description: High-level error message
+ example: Invalid JSON schema format
+ ruleName:
+ type: string
+ description: Name of the validation rule that failed
+ example: ProfileCreatedEvent Schema v1.0
+ details:
+ type: array
+ description: Detailed validation errors for specific fields
+ items:
+ type: object
+ properties:
+ field:
+ type: string
+ description: The field path where the error occurred
+ example: properties.userId.type
+ error:
+ type: string
+ description: Specific error message for this field
+ example: "Invalid type: should be 'string'"
+ example:
+ message: Invalid JSON schema format
+ ruleName: ProfileCreatedEvent Schema v1.0
+ details:
+ - field: properties.userId.type
+ error: "Invalid type: should be 'string'"
+ - field: required
+ error: Missing required field 'email'
+ event-type:
+ required:
+ - eventType
+ type: object
+ properties:
+ id:
+ type: string
+ description: Unique UUID identifier for the event type
+ format: uuid
+ readOnly: true
+ example: 550e8400-e29b-41d4-a716-446655440000
+ eventType:
+ maxLength: 100
+ minLength: 1
+ type: string
+ description: The event type identifier
+ example: login
+ displayName:
+ maxLength: 200
+ type: string
+ description: Human-readable display name for the event type
+ example: User Login Event
+ description:
+ type: string
+ description: Description of the event type
+ example: Event triggered when a user successfully logs into the system
+ event-type-action:
+ required:
+ - actionName
+ - eventType
+ type: object
+ properties:
+ id:
+ type: string
+ description: Unique UUID identifier for the event type action
+ format: uuid
+ readOnly: true
+ example: 660e8400-e29b-41d4-a716-446655440001
+ eventType:
+ maxLength: 100
+ minLength: 1
+ type: string
+ description: The event type this action applies to
+ example: ProfileCreatedEvent
+ actionName:
+ maxLength: 200
+ minLength: 1
+ type: string
+ description: Name of the action to be performed
+ example: Identity Resolution
+ description:
+ maxLength: 500
+ type: string
+ description: Description of what this action does
+ example: Enrich event with identity resolution data
+ actionConfig:
+ type: object
+ additionalProperties: true
+ description: |
+ Configuration parameters for the event type processing.
+ Contains two main sections:
+ - profilesMatchingQueryString: Elasticsearch query object to find target profiles
+ - actions: Map of action names to enabled/disabled flags
+ example:
+ profilesMatchingQueryString:
+ term:
+ externalIds.id.keyword: '%s'
+ actions:
+ save-event: true
+ create-profile: true
+ update-segments: true
+ send-notification: false
+ event-type-configuration:
+ required:
+ - eventType
+ type: object
+ properties:
+ id:
+ type: string
+ description: Unique UUID identifier for the event type configuration
+ format: uuid
+ readOnly: true
+ example: 660e8400-e29b-41d4-a716-446655440001
+ eventType:
+ maxLength: 100
+ minLength: 1
+ type: string
+ description: The event type this configuration applies to
+ example: ProfileCreatedEvent
+ profilesMatchingQuery:
+ type: object
+ additionalProperties: true
+ description: |
+ Elasticsearch query object to find target profiles for this event type.
+ This query determines which user profiles this event should be applied to.
+ example:
+ term:
+ externalIds.id.keyword: '%s'
+ eventConfig:
+ type: object
+ additionalProperties: true
+ description: |
+ Configuration for event enrichment actions.
+ Contains map of action names to enabled/disabled flags.
+ example:
+ actions:
+ save-event: true
+ create-profile: true
+ update-segments: true
+ send-notification: false
+ example:
+ $ref: ../examples/event-type-configuration.json
+ validation-type:
+ type: string
+ description: Type of validation to perform
+ enum:
+ - SCHEMA_VALIDATION
+ x-enum-descriptions:
+ - Validates the entire data object against a JSON Schema
+ bad-request-error:
+ title: BadRequestError
+ required:
+ - key
+ - message
+ type: object
+ properties:
+ message:
+ minLength: 1
+ type: string
+ description: Any further information
+ key:
+ minLength: 1
+ type: string
+ description: Error summary
+ errors:
+ type: array
+ description: Detailed error information
+ items:
+ $ref: "#/components/schemas/error-item"
+ unauthorized-error:
+ title: UnauthorizedError
+ required:
+ - key
+ - message
+ type: object
+ properties:
+ message:
+ minLength: 1
+ type: string
+ description: Any further information
+ key:
+ minLength: 1
+ type: string
+ description: Error summary
+ errors:
+ type: array
+ description: Detailed error information
+ items:
+ $ref: "#/components/schemas/error-item"
+ not-found-error:
+ title: NotFoundError
+ required:
+ - key
+ - message
+ type: object
+ properties:
+ message:
+ minLength: 1
+ type: string
+ description: Any further information
+ key:
+ minLength: 1
+ type: string
+ description: Error summary
+ errors:
+ type: array
+ description: Detailed error information
+ items:
+ $ref: "#/components/schemas/error-item"
+ simple-error:
+ title: SimpleError
+ type: object
+ properties:
+ message:
+ minLength: 1
+ type: string
+ description: Any further information
+ key:
+ minLength: 1
+ type: string
+ description: Error summary
+ error-item:
+ title: ErrorItem
+ required:
+ - key
+ - message
+ type: object
+ properties:
+ message:
+ minLength: 1
+ type: string
+ description: Any further information.
+ key:
+ minLength: 1
+ type: string
+ description: "{capability-name}.api.{api-key-name}. For generated validation\
+ \ errors this is the path in the document the error resolves to. e.g.\
+ \ object name + '.' + field"
+ context:
+ title: Context
+ type: object
+ additionalProperties:
+ type: string
+ description: Context can be anything used to construct localised messages.
+ responses:
+ "404NotFound":
+ description: Not found.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/error"
+ example:
+ $ref: "#/components/examples/not-found-error"
+ examples:
+ ValidationRuleExample:
+ summary: ValidationRuleExample
+ value:
+ id: 550e8400-e29b-41d4-a716-446655440001
+ ruleName: ProfileCreatedEvent Schema v1.0
+ validationType: SCHEMA_VALIDATION
+ fieldPath: data
+ errorMessage: Event data must conform to ProfileCreatedEvent schema
+ validationConfig:
+ $schema: http://json-schema.org/draft-07/schema#
+ type: object
+ required:
+ - userId
+ - email
+ properties:
+ userId:
+ type: string
+ minLength: 1
+ email:
+ type: string
+ format: email
+ ValidationRulesListExample:
+ summary: ValidationRulesListExample
+ value:
+ value:
+ - id: 550e8400-e29b-41d4-a716-446655440001
+ ruleName: ProfileCreatedEvent Schema v1.0
+ validationType: SCHEMA_VALIDATION
+ fieldPath: data
+ errorMessage: Event data must conform to ProfileCreatedEvent schema
+ validationConfig:
+ $schema: http://json-schema.org/draft-07/schema#
+ type: object
+ required:
+ - userId
+ - email
+ properties:
+ userId:
+ type: string
+ minLength: 1
+ email:
+ type: string
+ format: email
+ SchemaValidationErrorExample:
+ summary: SchemaValidationErrorExample
+ value:
+ message: Invalid JSON schema format
+ ruleName: ProfileCreatedEvent Schema v1.0
+ details:
+ - field: properties.userId.type
+ error: "Invalid type: should be 'string'"
+ - field: required
+ error: Missing required field 'email'
+ EventTypeExample:
+ summary: EventTypeExample
+ value:
+ id: 770e8400-e29b-41d4-a716-446655440001
+ eventType: ProfileCreatedEvent
+ description: Event triggered when a new user profile is created in the system
+ version: 1.0.0
+ active: true
+ EventTypesListExample:
+ summary: EventTypesListExample
+ value:
+ value:
+ - id: 770e8400-e29b-41d4-a716-446655440001
+ eventType: ProfileCreatedEvent
+ description: Event triggered when a new user profile is created
+ version: 1.0.0
+ active: true
+ - id: 880e8400-e29b-41d4-a716-446655440002
+ eventType: InteractionCapturedEvent
+ description: Event triggered when a user interaction is captured
+ version: 1.0.0
+ active: true
+ EventTypeConfigurationExample:
+ summary: EventTypeConfigurationExample
+ value:
+ id: 660e8400-e29b-41d4-a716-446655440001
+ eventType: ProfileCreatedEvent
+ description: Configuration for profile creation event processing
+ profilesMatchingQuery:
+ term:
+ externalIds.id.keyword: '%s'
+ eventConfig:
+ actions:
+ save-event: true
+ create-profile: true
+ update-segments: true
+ send-notification: false
+ CdpEventExample:
+ summary: CdpEventExample
+ value:
+ eventId: 12345678-1234-5678-9012-123456789012
+ eventType: USER_ACTION
+ timestamp: 2023-09-16T10:30:00.000Z
+ sourceSystem: mobile_app
+ sourceType: USER_ID
+ sourceId: user-123456
+ sessionId: session-789012
+ cdpCustomerId: null
+ data:
+ action: login
+ page: /dashboard
+ location:
+ country: US
+ city: New York
+ latitude: 40.7128
+ longitude: -74.006
+ customProperties:
+ campaign_id: summer_promo_2023
+ ab_test_variant: variant_b
+ context: null
+ metadata:
+ schemaVersion: 2.1.0
+ source: mobile_app
+ correlationId: corr-12345678-1234-5678
+ traceId: trace-12345678-1234-5678
+ processedBy: []
+ sourceIp: 192.168.1.100
+ userAgent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X)
+ CdpEventsExample:
+ summary: CdpEventsExample
+ value:
+ cdpEvents:
+ - eventId: 123e4567-e89b-12d3-a456-426614174000
+ eventType: USER_ACTION
+ timestamp: 2024-06-10T12:34:56Z
+ sourceSystem: webApp
+ sourceType: USER_ID
+ sourceId: user_001
+ sessionId: session_abc123
+ cdpCustomerId: null
+ data:
+ action: login
+ page: /dashboard
+ location:
+ country: US
+ city: New York
+ latitude: 40.7128
+ longitude: -74.006
+ context: null
+ metadata:
+ schemaVersion: 2.1.0
+ source: webApp
+ correlationId: corr-123e4567-e89b-12d3
+ traceId: trace-123e4567-e89b-12d3
+ processedBy: []
+ sourceIp: 192.168.1.1
+ userAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
+ - eventId: 456e7890-e12b-34d5-b789-567890123456
+ eventType: TRANSACTION
+ timestamp: 2024-06-10T12:35:30Z
+ sourceSystem: mobileApp
+ sourceType: USER_ID
+ sourceId: user_001
+ sessionId: session_abc123
+ cdpCustomerId: cdp_customer_001
+ data:
+ action: payment
+ amount: 150.0
+ currency: USD
+ merchant: Amazon
+ paymentMethod: credit_card
+ context:
+ deviceType: mobile
+ appVersion: 2.1.0
+ metadata:
+ schemaVersion: 2.1.0
+ source: mobileApp
+ correlationId: corr-456e7890-e12b-34d5
+ traceId: trace-456e7890-e12b-34d5
+ processedBy: []
+ sourceIp: 10.0.0.5
+ userAgent: MobileApp/2.1.0 (iOS 15.0)
+ - eventId: 789e0123-e45f-67g8-c901-234567890123
+ eventType: PAGE_VIEW
+ timestamp: 2024-06-10T12:36:00Z
+ sourceSystem: webApp
+ sourceType: USER_ID
+ sourceId: user_002
+ sessionId: session_def456
+ cdpCustomerId: null
+ data:
+ action: page_view
+ page: /products/electronics
+ duration: 45
+ referrer: https://google.com
+ context: null
+ metadata:
+ schemaVersion: 2.1.0
+ source: webApp
+ correlationId: corr-789e0123-e45f-67g8
+ traceId: trace-789e0123-e45f-67g8
+ processedBy: []
+ sourceIp: 192.168.1.2
+ userAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
+ IngestionSuccessExample:
+ summary: IngestionSuccessExample
+ value:
+ status: SUCCESS
+ eventId: 12345678-1234-5678-9012-123456789012
+ message: Event successfully ingested
+ timestamp: 2023-09-16T10:30:01.500Z
+ BulkIngestionSuccessExample:
+ summary: BulkIngestionSuccessExample
+ value:
+ status: SUCCESS
+ totalEvents: 3
+ processedEvents: 3
+ failedEvents: 0
+ errors: []
+ message: All 3 events successfully ingested
+ timestamp: 2024-06-10T12:36:05.500Z
+ BadRequestExample:
+ summary: BadRequestExample
+ value:
+ message: Bad Request
+ key: REQUEST_ERROR
+ errors:
+ - message: "Value Exceeded. Must be between {min} and {max}."
+ key: common.api.shoesize
+ context:
+ max: "50"
+ min: "1"
+ UnauthorizedExample:
+ summary: UnauthorizedExample
+ value:
+ message: Access to requested resource denied.
+ key: UNAUTHORIZED_ERROR
+ errors:
+ - message: Resource access denied due to invalid credentials.
+ key: common.api.token
+ context:
+ accessToken: expired
+ ErrorItemExample:
+ summary: ErrorItemExample
+ value:
+ message: "Value Exceeded. Must be between {min} and {max}."
+ key: common.api.shoesize
+ context:
+ max: "50"
+ min: "1"
+ InternalServerErrorExample:
+ summary: InternalServerErrorExample
+ value:
+ message: Description of error
+ key: SERVER_ERROR
+ not-found-error:
+ summary: not-found-error
+ value:
+ message: Resource not found.
+ key: NOT_FOUND_ERROR
+ errors:
+ - message: "Unable to find the requested resource: {resource}."
+ key: common.api.resource
+ context:
+ resource: aResource
diff --git a/stream-dbs-clients/src/main/openapi/cdp-profiles-service-api-v1.0.0-beta.yaml b/stream-dbs-clients/src/main/openapi/cdp-profiles-service-api-v1.0.0-beta.yaml
new file mode 100644
index 000000000..0a2e95cde
--- /dev/null
+++ b/stream-dbs-clients/src/main/openapi/cdp-profiles-service-api-v1.0.0-beta.yaml
@@ -0,0 +1,1092 @@
+openapi: 3.0.3
+info:
+ title: CDP Profile Service - Service API
+ description: |
+ This internal service API is used to manage customer profiles, including personal information, addresses, and product holdings.
+ version: 1.0.0-beta
+ x-api-domain: customer-management
+ x-api-service: customer-data-platform
+servers:
+- url: http://localhost:8080
+tags:
+- name: Profiles
+ description: Internal operations related to customer profiles.
+paths:
+ /service-api/v1/profiles:
+ get:
+ tags:
+ - Profiles
+ summary: Fetch all customer profiles
+ operationId: getProfiles
+ parameters:
+ - name: page
+ in: query
+ description: "The page number to retrieve, starting at 0."
+ required: false
+ style: form
+ explode: true
+ schema:
+ minimum: 0
+ type: integer
+ default: 0
+ - name: size
+ in: query
+ description: The number of events to return per page.
+ required: false
+ style: form
+ explode: true
+ schema:
+ maximum: 20
+ minimum: 1
+ type: integer
+ default: 10
+ - name: sortDirection
+ in: query
+ description: The direction to sort by.
+ required: false
+ style: form
+ explode: true
+ schema:
+ type: string
+ default: asc
+ enum:
+ - asc
+ - desc
+ responses:
+ "200":
+ description: Customer profiles retrieved successfully.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/paged-customer-profile-response"
+ "404":
+ description: Customer profiles can't be retrieved.
+ post:
+ tags:
+ - Profiles
+ summary: Create a customer profile
+ operationId: createProfile
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/customer-profile-create-request"
+ required: true
+ responses:
+ "201":
+ description: Profile created successfully.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/customer-profile"
+ "400":
+ description: Invalid input provided.
+ /service-api/v1/profiles/{id}:
+ get:
+ tags:
+ - Profiles
+ summary: Get a customer profile by ID
+ operationId: getProfile
+ parameters:
+ - name: id
+ in: path
+ description: The unique identifier for the customer.
+ required: true
+ style: simple
+ explode: false
+ schema:
+ type: string
+ example: 4b3488af-a244-40ee-bc74-d7d8699fcc03
+ responses:
+ "200":
+ description: Customer profile retrieved successfully.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/customer-profile"
+ "404":
+ description: Customer profile not found.
+ delete:
+ tags:
+ - Profiles
+ summary: Delete a customer profile
+ operationId: deleteProfile
+ parameters:
+ - name: id
+ in: path
+ description: The unique identifier for the customer to delete.
+ required: true
+ style: simple
+ explode: false
+ schema:
+ type: string
+ responses:
+ "202":
+ description: Profile deletion request accepted and will be processed asynchronously.
+ patch:
+ tags:
+ - Profiles
+ summary: Update a customer profile
+ operationId: updateProfile
+ parameters:
+ - name: id
+ in: path
+ description: The unique identifier for the customer to update.
+ required: true
+ style: simple
+ explode: false
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/customer-profile-update-request"
+ required: true
+ responses:
+ "200":
+ description: Profile updated successfully.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/customer-profile"
+ "400":
+ description: Invalid input provided.
+ "404":
+ description: Profile not found.
+ /service-api/v1/profiles/merge:
+ post:
+ tags:
+ - Profiles
+ summary: Merge two customer profiles
+ operationId: mergeProfiles
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/merge-profile-request"
+ required: true
+ responses:
+ "200":
+ description: Profiles merged successfully.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/customer-profile"
+ "400":
+ description: Invalid merge request.
+ /service-api/v1/profiles/external/{id}:
+ get:
+ tags:
+ - Profiles
+ summary: Get customers profile by ID
+ operationId: getProfileByExternalId
+ parameters:
+ - name: id
+ in: path
+ description: Identifier for the customer.
+ required: true
+ style: simple
+ explode: false
+ schema:
+ type: string
+ example: 4b3488af-a244-40ee-bc74-d7d8699fcc03
+ - name: page
+ in: query
+ description: "The page number to retrieve, starting at 0."
+ required: false
+ style: form
+ explode: true
+ schema:
+ minimum: 0
+ type: integer
+ default: 0
+ - name: size
+ in: query
+ description: The number of events to return per page.
+ required: false
+ style: form
+ explode: true
+ schema:
+ maximum: 20
+ minimum: 1
+ type: integer
+ default: 10
+ responses:
+ "200":
+ description: Customer profiles retrieved successfully.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/paged-customer-profile-response"
+ "404":
+ description: Customer profile not found.
+ delete:
+ tags:
+ - Profiles
+ summary: Delete a customer profile
+ operationId: deleteProfileByExternalId
+ parameters:
+ - name: id
+ in: path
+ description: The unique identifier for the customer to delete.
+ required: true
+ style: simple
+ explode: false
+ schema:
+ type: string
+ responses:
+ "204":
+ description: Customer profile deleted successfully.
+ "404":
+ description: Customer profile not found.
+ patch:
+ tags:
+ - Profiles
+ summary: Update a customer profile
+ operationId: updateProfileByExternalId
+ parameters:
+ - name: id
+ in: path
+ description: The unique identifier for the customer to update.
+ required: true
+ style: simple
+ explode: false
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/customer-profile-update"
+ required: true
+ responses:
+ "200":
+ description: Customer profile updated successfully.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/customer-profile"
+ "404":
+ description: Customer profile not found.
+ /service-api/v1/profiles/{cdpCustomerId}/events:
+ get:
+ tags:
+ - Profiles
+ summary: Fetch all events for customer
+ description: |
+ Fetch all the events.
+ operationId: getEventsByCdpCustomerId
+ parameters:
+ - name: cdpCustomerId
+ in: path
+ description: The unique identifier for the event.
+ required: true
+ style: simple
+ explode: false
+ schema:
+ type: string
+ example: 4b3488af-a244-40ee-bc74-d7d8699fcc03
+ - name: page
+ in: query
+ description: "The page number to retrieve, starting at 0."
+ required: false
+ style: form
+ explode: true
+ schema:
+ type: integer
+ default: 0
+ - name: size
+ in: query
+ description: The number of events to return per page.
+ required: false
+ style: form
+ explode: true
+ schema:
+ type: integer
+ default: 20
+ - name: sortDirection
+ in: query
+ description: The direction to sort by.
+ required: false
+ style: form
+ explode: true
+ schema:
+ type: string
+ default: asc
+ enum:
+ - asc
+ - desc
+ responses:
+ "200":
+ description: A paginated list of matching events.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/paged-event-entity-response"
+ /service-api/v1/events/counts:
+ get:
+ tags:
+ - Events
+ summary: Count events by types and date range
+ description: Returns a dictionary of event counts for the specified types within
+ a given time period.
+ operationId: countEventsByTypes
+ parameters:
+ - name: eventTypes
+ in: query
+ description: A list of event types to count (maximum 15 types).
+ required: true
+ style: form
+ explode: true
+ schema:
+ maxItems: 15
+ minItems: 1
+ type: array
+ items:
+ type: string
+ - name: segmentCodes
+ in: query
+ description: A list of segmentCodes to filter events (maximum 15 types).
+ required: false
+ style: form
+ explode: true
+ schema:
+ maxItems: 15
+ minItems: 0
+ type: array
+ items:
+ type: string
+ - name: fromDate
+ in: query
+ description: Start date-time (ISO 8601) for the search range.
+ required: true
+ style: form
+ explode: true
+ schema:
+ type: string
+ format: date-time
+ - name: toDate
+ in: query
+ description: End date-time (ISO 8601) for the search range.
+ required: true
+ style: form
+ explode: true
+ schema:
+ type: string
+ format: date-time
+ responses:
+ "200":
+ description: Event counts retrieved successfully.
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties:
+ type: integer
+ format: int64
+ description: A map where key is the eventType and value is the count.
+ example:
+ LOGIN_ATTEMPT: 150
+ PAYMENT_SUCCESS: 45
+ PROFILE_UPDATE: 12
+ "400":
+ description: Invalid input parameters.
+components:
+ schemas:
+ paged-customer-profile-response:
+ title: Paged Customer Profile Response
+ type: object
+ properties:
+ content:
+ type: array
+ description: The list of customer profiles for the current page.
+ items:
+ $ref: "#/components/schemas/customer-profile"
+ page:
+ type: integer
+ description: The current page number.
+ size:
+ type: integer
+ description: The number of items per page.
+ totalElements:
+ type: integer
+ description: The total number of profiles available.
+ description: A paginated response containing a list of customer profiles.
+ customer-profile-create-request:
+ title: CustomerProfileCreateRequest
+ required:
+ - externalIds
+ - profileStatus
+ - profileType
+ type: object
+ properties:
+ externalIds:
+ type: array
+ items:
+ $ref: "#/components/schemas/external-id"
+ organizationInfo:
+ $ref: "#/components/schemas/organization-info"
+ personalInfo:
+ $ref: "#/components/schemas/personal-info"
+ deliveryChannels:
+ type: array
+ items:
+ $ref: "#/components/schemas/delivery-channel"
+ addresses:
+ type: array
+ items:
+ $ref: "#/components/schemas/address"
+ profileExtendedData:
+ $ref: "#/components/schemas/profile-extended-data"
+ cardProductHoldings:
+ type: array
+ items:
+ $ref: "#/components/schemas/card-product-holding"
+ productHoldings:
+ type: array
+ items:
+ $ref: "#/components/schemas/product-holding"
+ preferences:
+ type: object
+ additionalProperties:
+ type: object
+ complianceInfo:
+ type: object
+ additionalProperties:
+ type: object
+ segments:
+ type: array
+ items:
+ $ref: "#/components/schemas/segment"
+ profileStatus:
+ type: string
+ description: The status of the profile.
+ example: ACTIVE
+ profileType:
+ type: string
+ enum:
+ - ORGANIZATION
+ - PERSON
+ - EMPLOYEE
+ description: Request body for creating a new customer profile.
+ customer-profile:
+ title: CustomerProfile
+ required:
+ - externalIds
+ - profileStatus
+ - profileType
+ type: object
+ properties:
+ cdpCustomerId:
+ type: string
+ description: Unique identifier for the customer profile in the CDP.
+ example: 4b3488af-a244-40ee-bc74-d7d8699fcc03
+ externalIds:
+ type: array
+ items:
+ $ref: "#/components/schemas/external-id"
+ organizationInfo:
+ $ref: "#/components/schemas/organization-info"
+ personalInfo:
+ $ref: "#/components/schemas/personal-info"
+ deliveryChannels:
+ type: array
+ items:
+ $ref: "#/components/schemas/delivery-channel"
+ addresses:
+ type: array
+ items:
+ $ref: "#/components/schemas/address"
+ profileExtendedData:
+ $ref: "#/components/schemas/profile-extended-data"
+ cardProductHoldings:
+ type: array
+ items:
+ $ref: "#/components/schemas/card-product-holding"
+ productHoldings:
+ type: array
+ items:
+ $ref: "#/components/schemas/product-holding"
+ financialSummary:
+ type: object
+ additionalProperties:
+ type: object
+ description: Aggregated financial data related to the customer profile.
+ behavioralMetrics:
+ type: object
+ additionalProperties:
+ type: object
+ description: Aggregated financial data related to the customer profile.
+ inferredAttributes:
+ type: object
+ additionalProperties:
+ type: object
+ description: Aggregated financial data related to the customer profile.
+ preferences:
+ type: object
+ additionalProperties:
+ type: object
+ description: Aggregated financial data related to the customer profile.
+ complianceInfo:
+ type: object
+ additionalProperties:
+ type: object
+ description: Aggregated financial data related to the customer profile.
+ segments:
+ type: array
+ items:
+ $ref: "#/components/schemas/segment"
+ segmentCodes:
+ type: array
+ description: A list of customer segment codes that this profile belongs
+ to.
+ example:
+ - segment1
+ - segment2
+ - segment10
+ items:
+ type: string
+ profileStatus:
+ type: string
+ description: The status of the profile.
+ example: ACTIVE
+ profileType:
+ type: string
+ enum:
+ - ORGANIZATION
+ - PERSON
+ - EMPLOYEE
+ lastUpdated:
+ type: string
+ format: date-time
+ example: 2025-05-20T18:32:56Z
+ createdAt:
+ type: string
+ format: date-time
+ example: 2024-05-20T18:32:56Z
+ version:
+ type: integer
+ format: int64
+ example: 56
+ description: A complete customer profile data model.
+ customer-profile-update-request:
+ title: CustomerProfileUpdateRequest
+ type: object
+ properties:
+ organizationInfo:
+ $ref: "#/components/schemas/organization-info"
+ personalInfo:
+ $ref: "#/components/schemas/personal-info"
+ deliveryChannels:
+ type: array
+ items:
+ $ref: "#/components/schemas/delivery-channel"
+ addresses:
+ type: array
+ items:
+ $ref: "#/components/schemas/address"
+ profileExtendedData:
+ $ref: "#/components/schemas/profile-extended-data"
+ cardProductHoldings:
+ type: array
+ items:
+ $ref: "#/components/schemas/card-product-holding"
+ productHoldings:
+ type: array
+ items:
+ $ref: "#/components/schemas/product-holding"
+ preferences:
+ type: object
+ additionalProperties:
+ type: object
+ complianceInfo:
+ type: object
+ additionalProperties:
+ type: object
+ segments:
+ type: array
+ items:
+ $ref: "#/components/schemas/segment"
+ profileStatus:
+ type: string
+ description: The status of the profile.
+ example: ACTIVE
+ description: Request body for updating an existing customer profile.
+ merge-profile-request:
+ title: Merge Profile Request
+ type: object
+ description: Request containing a list of profile IDs to be merged into a single
+ profile.
+ customer-profile-update:
+ title: Customer Profile Update
+ type: object
+ description: The request body for updating a customer profile using a PATCH
+ operation.
+ paged-event-entity-response:
+ title: Paged Event Entity Response
+ type: object
+ properties:
+ content:
+ type: array
+ description: The list of event entities for the current page.
+ items:
+ $ref: "#/components/schemas/event-entity"
+ page:
+ type: integer
+ description: The current page number.
+ size:
+ type: integer
+ description: The number of items per page.
+ totalElements:
+ type: integer
+ description: The total number of events available.
+ description: A paginated response containing a list of event entities.
+ external-id:
+ title: ExternalId
+ required:
+ - id
+ - source
+ - type
+ type: object
+ properties:
+ source:
+ type: string
+ description: "The source system of the identifier (e.g., BACKBASE, CORE)."
+ example: BACKBASE
+ id:
+ type: string
+ example: 3a3488af-a244-40ee-bc74-d7d8699fcc01
+ type:
+ type: string
+ description: "The type of identifier (e.g., USER_ID)."
+ example: USER_ID
+ verified:
+ type: boolean
+ description: Indicates if the identifier has been verified.
+ example: true
+ organization-info:
+ title: OrganizationInfo
+ type: object
+ properties:
+ name:
+ type: string
+ description: the name of the organization
+ legalStructure:
+ type: string
+ description: the legal structure of the organization
+ type:
+ type: string
+ description: the type of the organization
+ sector:
+ type: string
+ description: "the business sector of the organisation, according to ISO20022\
+ \ standards"
+ email:
+ type: string
+ description: Primary email address
+ format: email
+ example: johndoe@gmail.com
+ phone:
+ type: string
+ description: Primary phone number
+ example: "+380671234567"
+ address:
+ $ref: "#/components/schemas/address"
+ establishmentDate:
+ type: string
+ description: the date when the organisation was established
+ format: date
+ description: filled in only if this profile stands for the organization
+ personal-info:
+ title: PersonalInfo
+ type: object
+ properties:
+ firstName:
+ type: string
+ example: John
+ lastName:
+ type: string
+ example: Doe
+ middleName:
+ type: string
+ example: Sebastian
+ fullName:
+ type: string
+ example: John Doe
+ email:
+ type: string
+ description: Primary email address
+ format: email
+ example: johndoe@gmail.com
+ phone:
+ type: string
+ description: Primary phone number
+ example: "+380671234567"
+ address:
+ $ref: "#/components/schemas/address"
+ dateOfBirth:
+ type: string
+ format: date
+ example: 1986-06-14
+ gender:
+ type: string
+ example: MALE
+ enum:
+ - MALE
+ - FEMALE
+ - NON-BINARY
+ preferredLocale:
+ type: string
+ example: en_US
+ nationality:
+ type: string
+ example: Ukrainian
+ maritalStatus:
+ type: string
+ example: married
+ occupation:
+ type: string
+ example: software development
+ employer:
+ type: string
+ example: "185726526739063089"
+ employerName:
+ type: string
+ example: Backbase
+ delivery-channel:
+ title: DeliveryChannel
+ required:
+ - type
+ - value
+ type: object
+ properties:
+ type:
+ type: string
+ example: EMAIL
+ enum:
+ - EMAIL
+ - PHONE
+ - APP
+ - PUSH
+ - SMS
+ - SOCIAL
+ - OTHER
+ value:
+ type: string
+ example: johndoe@gmail.com
+ verified:
+ type: boolean
+ example: true
+ optIn:
+ type: boolean
+ example: true
+ primary:
+ type: boolean
+ example: true
+ address:
+ title: Address
+ type: object
+ properties:
+ street1:
+ type: string
+ example: "Park Lane, ave"
+ street2:
+ type: string
+ city:
+ type: string
+ example: New York
+ state:
+ type: string
+ example: New York
+ postalCode:
+ type: string
+ example: "12345"
+ country:
+ type: string
+ example: US
+ type:
+ type: string
+ example: HOME
+ primary:
+ type: boolean
+ example: true
+ description: Address schema
+ profile-extended-data:
+ title: ProfileExtendedData
+ type: object
+ additionalProperties:
+ type: object
+ description: A map for storing arbitrary key-value pairs of extended profile
+ data.
+ example:
+ loyaltyMemberId: L-12345
+ lastLoginPlatform: iOS
+ isPremiumCustomer: true
+ customPreferences:
+ theme: dark
+ notifications: daily
+ card-product-holding:
+ title: CardProductHolding
+ required:
+ - accountId
+ - productKind
+ - productType
+ type: object
+ properties:
+ externalIds:
+ type: array
+ description: External identifiers associated with the card product
+ items:
+ $ref: "#/components/schemas/external-id"
+ cardNumberLast4:
+ type: string
+ description: "Type of product (e.g., 'currentAccount', 'termDeposit', 'loan',\
+ \ 'creditCard')"
+ cardType:
+ type: string
+ description: "Type of product (e.g., 'currentAccount', 'termDeposit', 'loan',\
+ \ 'creditCard')"
+ cardIssuer:
+ type: string
+ description: "Primary identifier for the product (account ID, loan ID, card\
+ \ ID)"
+ validThrough:
+ type: string
+ description: Date when the product was opened/created
+ format: date
+ metadata:
+ type: object
+ additionalProperties:
+ type: object
+ description: any additional information for the product holding
+ description: Details of a credit or debit card product held by the customer.
+ product-holding:
+ title: ProductHolding
+ required:
+ - externalIds
+ - productKind
+ - productType
+ type: object
+ properties:
+ externalIds:
+ type: array
+ description: "External identifiers for the product holding (e.g., account\
+ \ number, IBAN)"
+ items:
+ $ref: "#/components/schemas/external-id"
+ productKind:
+ type: string
+ description: "Type of product (e.g., 'currentAccount', 'termDeposit', 'loan',\
+ \ 'creditCard')"
+ example: loans
+ productType:
+ type: string
+ description: "Type of product (e.g., 'currentAccount', 'termDeposit', 'loan',\
+ \ 'creditCard')"
+ example: Mortgage
+ accountNumberMasked:
+ type: string
+ description: Masked account number for display purposes
+ example: NL?? ABNA 0417 XXXX
+ currency:
+ type: string
+ description: Currency code (ISO 4217)
+ example: USD
+ openingDate:
+ type: string
+ description: Date when the product was opened/created
+ format: date
+ example: 2024-03-17
+ status:
+ type: string
+ example: ACTIVE
+ balance:
+ type: number
+ description: "Current balance (for accounts), outstanding balance (for loans),\
+ \ principal (for TDs)"
+ format: decimal
+ example: 15068.78
+ interestRate:
+ type: number
+ description: Interest rate (if applicable)
+ format: decimal
+ example: 22.5
+ linkedAccountId:
+ type: string
+ description: For cards/overdrafts linked to an account
+ creditLimit:
+ type: number
+ description: Credit limit for credit cards/overdrafts
+ format: decimal
+ example: 1000
+ availableCredit:
+ type: number
+ description: Available credit (for credit products)
+ format: decimal
+ example: 1000
+ expiryDate:
+ type: string
+ description: Expiry date for cards
+ format: date
+ example: 2027-05-01
+ maturityDate:
+ type: string
+ description: Maturity date for term deposits/loans
+ format: date
+ example: 2027-05-20
+ productName:
+ type: string
+ description: Product name as displayed to customer
+ productCode:
+ type: string
+ description: Internal product code
+ originatingBranch:
+ type: string
+ description: Branch or channel where product was opened
+ metadata:
+ type: object
+ additionalProperties:
+ type: object
+ description: any additional information for the product holding
+ description: "Details of a product holding (account, loan, card, etc.) for a\
+ \ customer"
+ segment:
+ title: Segment
+ required:
+ - assignedAt
+ - code
+ - id
+ - name
+ type: object
+ properties:
+ id:
+ type: string
+ code:
+ type: string
+ description: "unique programmatic code for the segment (e.g., 'RFM_CHAMPION_CUSTOMER')"
+ name:
+ type: string
+ description: human-readable name of the segment
+ assignedAt:
+ type: string
+ description: timestamp when the segment was assigned to the customer
+ format: date-time
+ additional:
+ type: object
+ additionalProperties:
+ type: string
+ description: A customer segment data model.
+ event-entity:
+ title: EventEntity
+ type: object
+ properties:
+ eventId:
+ type: string
+ description: The unique identifier for the event.
+ example: evt_a1b2c3d4e5f6
+ eventType:
+ type: string
+ description: "The type of the event (e.g., 'user.login', 'transaction.completed')."
+ example: user.login
+ timestamp:
+ type: string
+ description: The ISO 8601 timestamp of when the event occurred.
+ format: date-time
+ example: 2025-10-09T08:32:49Z
+ sourceSystem:
+ type: string
+ description: "The system that originated the event (e.g., 'WebApp', 'MobileApp')."
+ example: WebApp
+ sourceType:
+ type: string
+ description: "The type of the source entity (e.g., 'user', 'account')."
+ example: user
+ sourceId:
+ type: string
+ description: The ID of the source entity.
+ example: usr_f6e5d4c3b2a1
+ sessionId:
+ type: string
+ description: The session identifier associated with the event.
+ example: sess_9876543210
+ cdpCustomerId:
+ type: string
+ description: The Customer Data Platform unique identifier for the customer.
+ example: cdp_xyz987abc654
+ data:
+ type: object
+ additionalProperties:
+ type: object
+ description: A flexible map containing the primary event payload.
+ example:
+ loginMethod: password
+ successful: true
+ context:
+ type: object
+ additionalProperties:
+ type: object
+ description: A flexible map containing contextual information about the
+ event.
+ example:
+ deviceType: mobile
+ location: "Kraków, PL"
+ metadata:
+ $ref: "#/components/schemas/event-metadata"
+ description: Represents a generic event captured by the system.
+ event-metadata:
+ title: EventMetadata
+ type: object
+ properties:
+ schemaVersion:
+ type: string
+ description: The version of the event schema.
+ example: 1.2.0
+ source:
+ type: string
+ description: The specific source.
+ traceId:
+ type: string
+ description: The distributed tracing identifier.
+ example: trace_1122334455
+ ingestedAt:
+ type: string
+ description: The ISO 8601 timestamp of when the event was ingested by the
+ system.
+ format: date-time
+ example: 2025-10-09T08:32:50.123Z
+ processingStatus:
+ type: string
+ description: The current processing status of the event.
+ example: PROCESSED
+ processedBy:
+ type: array
+ description: A list of services or processors that have handled this event.
+ example:
+ - ingestion-service
+ - profile-builder
+ items:
+ type: string
+ sourceIp:
+ type: string
+ description: The IP address from which the event originated.
+ format: ipv4
+ example: 198.51.100.14
+ userAgent:
+ type: string
+ description: The user agent string of the client that generated the event.
+ example: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,\
+ \ like Gecko) Chrome/125.0.0.0 Safari/537.36"
+ correlationId:
+ type: string
+ description: An ID to correlate events across different systems.
+ example: corr_aabbccddeeff
+ additionalProperties:
+ type: object
+ additionalProperties:
+ type: string
+ description: A map for any other arbitrary metadata properties.
+ example:
+ data_center: europe-west3
+ description: Metadata associated with the processing and ingestion of the event.
+ examples: {}
diff --git a/stream-investment/investment-core/pom.xml b/stream-investment/investment-core/pom.xml
index 24a832ea2..0afc14948 100644
--- a/stream-investment/investment-core/pom.xml
+++ b/stream-investment/investment-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-investment
- 9.5.1
+ 9.6.0
investment-core
diff --git a/stream-investment/pom.xml b/stream-investment/pom.xml
index 04786c0b4..f5d54ff3a 100644
--- a/stream-investment/pom.xml
+++ b/stream-investment/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-investment
diff --git a/stream-legal-entity/legal-entity-bootstrap-task/pom.xml b/stream-legal-entity/legal-entity-bootstrap-task/pom.xml
index 56ded57ce..b2d709b53 100644
--- a/stream-legal-entity/legal-entity-bootstrap-task/pom.xml
+++ b/stream-legal-entity/legal-entity-bootstrap-task/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-task-starter-parent
- 9.5.1
+ 9.6.0
../../stream-sdk/stream-starter-parents/stream-task-starter-parent
diff --git a/stream-legal-entity/legal-entity-core/pom.xml b/stream-legal-entity/legal-entity-core/pom.xml
index ac1bf44c1..1154ec059 100644
--- a/stream-legal-entity/legal-entity-core/pom.xml
+++ b/stream-legal-entity/legal-entity-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-legal-entity
- 9.5.1
+ 9.6.0
legal-entity-core
@@ -34,6 +34,13 @@
compile
+
+ com.backbase.stream
+ cdp-core
+ ${project.version}
+ compile
+
+
com.backbase.stream
contacts-core
diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java
index b896ee1cf..a9f5c27ae 100644
--- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java
+++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java
@@ -10,6 +10,8 @@
import com.backbase.audiences.collector.api.service.v1.model.CustomerOnboardedRequest;
import com.backbase.audiences.collector.api.service.v1.model.CustomerOnboardedRequest.UserKindEnum;
+import com.backbase.cdp.ingestion.api.service.v1.model.CdpEvent;
+import com.backbase.cdp.ingestion.api.service.v1.model.CdpEvents;
import com.backbase.dbs.contact.api.service.v2.model.AccessContextScope;
import com.backbase.dbs.contact.api.service.v2.model.ContactsBulkPostRequestBody;
import com.backbase.dbs.contact.api.service.v2.model.ExternalAccessContext;
@@ -23,6 +25,8 @@
import com.backbase.dbs.user.profile.api.service.v2.model.CreateUserProfile;
import com.backbase.stream.audiences.UserKindSegmentationSaga;
import com.backbase.stream.audiences.UserKindSegmentationTask;
+import com.backbase.stream.cdp.CdpSaga;
+import com.backbase.stream.cdp.CdpTask;
import com.backbase.stream.configuration.LegalEntitySagaConfigurationProperties;
import com.backbase.stream.contact.ContactsSaga;
import com.backbase.stream.contact.ContactsTask;
@@ -45,6 +49,7 @@
import com.backbase.stream.mapper.LegalEntityV2toV1Mapper;
import com.backbase.stream.mapper.ServiceAgreementV2ToV1Mapper;
import com.backbase.stream.mapper.UserProfileMapper;
+import com.backbase.stream.mapper.UserToCdpEventMapper;
import com.backbase.stream.product.utils.StreamUtils;
import com.backbase.stream.service.AccessGroupService;
import com.backbase.stream.service.CustomerProfileService;
@@ -80,6 +85,7 @@ public class LegalEntitySagaV2 extends HelperProcessor implements StreamTaskExec
private final UserProfileMapper userProfileMapper = Mappers.getMapper(UserProfileMapper.class);
private final LegalEntityV2toV1Mapper leV2Mapper = Mappers.getMapper(LegalEntityV2toV1Mapper.class);
private final ServiceAgreementV2ToV1Mapper saV2Mapper = Mappers.getMapper(ServiceAgreementV2ToV1Mapper.class);
+ private final UserToCdpEventMapper cdpEventMapper = Mappers.getMapper(UserToCdpEventMapper.class);
private final LegalEntityService legalEntityService;
private final UserService userService;
@@ -90,6 +96,7 @@ public class LegalEntitySagaV2 extends HelperProcessor implements StreamTaskExec
private final CustomerAccessGroupSaga customerAccessGroupSaga;
private final LegalEntitySagaConfigurationProperties legalEntitySagaConfigurationProperties;
private final UserKindSegmentationSaga userKindSegmentationSaga;
+ private final CdpSaga cdpSaga;
private final CustomerProfileService customerProfileService;
private static final ExternalContactMapper externalContactMapper = ExternalContactMapper.INSTANCE;
@@ -104,6 +111,7 @@ public LegalEntitySagaV2(
CustomerAccessGroupSaga customerAccessGroupSaga,
LegalEntitySagaConfigurationProperties legalEntitySagaConfigurationProperties,
UserKindSegmentationSaga userKindSegmentationSaga,
+ CdpSaga cdpSaga,
CustomerProfileService customerProfileService) {
this.legalEntityService = legalEntityService;
this.userService = userService;
@@ -114,6 +122,7 @@ public LegalEntitySagaV2(
this.customerAccessGroupSaga = customerAccessGroupSaga;
this.legalEntitySagaConfigurationProperties = legalEntitySagaConfigurationProperties;
this.userKindSegmentationSaga = userKindSegmentationSaga;
+ this.cdpSaga = cdpSaga;
this.customerProfileService = customerProfileService;
}
@@ -125,6 +134,7 @@ public Mono executeTask(@SpanTag(value = "streamTask") LegalE
.flatMap(this::setupAdministrators)
.flatMap(this::setupUsers)
.flatMap(this::processAudiencesSegmentation)
+ .flatMap(this::processCdpProfilesIngestion)
.flatMap(this::setupLimits)
.flatMap(this::postLegalEntityContacts)
.flatMap(this::processSubsidiaries)
@@ -185,6 +195,37 @@ private Mono processAudiencesSegmentation(LegalEntityTaskV2 s
.then(Mono.just(streamTask));
}
+ private Mono processCdpProfilesIngestion(LegalEntityTaskV2 streamTask) {
+ if (!cdpSaga.isEnabled()) {
+ log.info("Skipping cdp profiles ingestion - feature is disabled.");
+ return Mono.just(streamTask);
+ }
+
+ var le = streamTask.getData();
+
+ if (le.getLegalEntityType() != LegalEntityType.CUSTOMER) {
+ return Mono.just(streamTask);
+ }
+
+ if (isNull(le.getInternalId())) {
+ return Mono.just(streamTask);
+ }
+
+ log.info("Ingesting customers of LE {} into CDP", le.getExternalId());
+
+ return Flux.fromStream(StreamUtils.nullableCollectionToStream(le.getUsers()))
+ .filter(user -> nonNull(user.getInternalId()))
+ .map(user -> {
+ var task = new CdpTask();
+ CdpEvent cdpEvent = cdpEventMapper.mapUserToCdpEvent(
+ le.getInternalId(), le.getExternalId(), le.getCustomerCategory(), user);
+ task.setCdpEvents(new CdpEvents().addCdpEventsItem(cdpEvent));
+ return task;
+ })
+ .flatMap(cdpSaga::executeTask)
+ .then(Mono.just(streamTask));
+ }
+
private UserKindEnum customerCategoryToUserKind(CustomerCategory customerCategory) {
return switch (customerCategory) {
case RETAIL -> UserKindEnum.RETAILCUSTOMER;
diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java
index 52fb8ba2c..c102be357 100644
--- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java
+++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java
@@ -7,6 +7,7 @@
import com.backbase.stream.LegalEntityUnitOfWorkExecutor;
import com.backbase.stream.ServiceAgreementSagaV2;
import com.backbase.stream.audiences.UserKindSegmentationSaga;
+import com.backbase.stream.cdp.CdpSaga;
import com.backbase.stream.contact.ContactsSaga;
import com.backbase.stream.legalentity.repository.LegalEntityUnitOfWorkRepository;
import com.backbase.stream.limit.LimitsSaga;
@@ -80,8 +81,8 @@ public LegalEntitySagaV2 reactiveLegalEntitySagaV2(LegalEntityService legalEntit
CustomerAccessGroupSaga customerAccessGroupSaga,
LegalEntitySagaConfigurationProperties sinkConfigurationProperties,
UserKindSegmentationSaga userKindSegmentationSaga,
- CustomerProfileService customerProfileService
- ) {
+ CdpSaga cdpSaga,
+ CustomerProfileService customerProfileService) {
return new LegalEntitySagaV2(
legalEntityService,
userService,
@@ -92,6 +93,7 @@ public LegalEntitySagaV2 reactiveLegalEntitySagaV2(LegalEntityService legalEntit
customerAccessGroupSaga,
sinkConfigurationProperties,
userKindSegmentationSaga,
+ cdpSaga,
customerProfileService
);
}
diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/mapper/UserToCdpEventMapper.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/mapper/UserToCdpEventMapper.java
new file mode 100644
index 000000000..fa599b7f6
--- /dev/null
+++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/mapper/UserToCdpEventMapper.java
@@ -0,0 +1,378 @@
+package com.backbase.stream.mapper;
+
+import static java.util.Objects.isNull;
+import static java.util.Objects.nonNull;
+import static org.mapstruct.ReportingPolicy.ERROR;
+
+import com.backbase.cdp.ingestion.api.service.v1.model.CdpEvent;
+import com.backbase.cdp.ingestion.api.service.v1.model.CdpEventMetadata;
+import com.backbase.cdp.profiles.api.service.v1.model.Address;
+import com.backbase.cdp.profiles.api.service.v1.model.CustomerProfile;
+import com.backbase.cdp.profiles.api.service.v1.model.DeliveryChannel;
+import com.backbase.cdp.profiles.api.service.v1.model.ExternalId;
+import com.backbase.cdp.profiles.api.service.v1.model.PersonalInfo;
+import com.backbase.stream.legalentity.model.CustomerCategory;
+import com.backbase.stream.legalentity.model.EmailAddress;
+import com.backbase.stream.legalentity.model.Multivalued;
+import com.backbase.stream.legalentity.model.PhoneNumber;
+import com.backbase.stream.legalentity.model.User;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import java.time.LocalDate;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+@Mapper(componentModel = "spring", unmappedTargetPolicy = ERROR)
+public interface UserToCdpEventMapper {
+
+ String PROFILE_CREATED_EVENT = "ProfileCreatedEvent";
+
+ String SOURCE_BACKBASE = "BACKBASE";
+ String SOURCE_CORE_BANKING_SYSTEM = "CORE_SYSTEM";
+
+ String TYPE_USER_ID = "USER_ID";
+ String TYPE_CUSTOMER_ID = "CUSTOMER_ID";
+
+ @Mapping(target = "eventId", expression = "java(generateEventId())")
+ @Mapping(target = "timestamp", expression = "java(generateEventTimestamp())")
+ @Mapping(target = "sessionId", ignore = true)
+ @Mapping(target = "cdpCustomerId", ignore = true)
+ @Mapping(target = "context", ignore = true)
+ @Mapping(target = "metadata", expression = "java(generateEventMetadata(\"stream-services\"))")
+ @Mapping(target = "eventType", constant = PROFILE_CREATED_EVENT)
+ @Mapping(target = "sourceSystem", constant = SOURCE_BACKBASE)
+ @Mapping(target = "sourceType", constant = TYPE_USER_ID)
+ @Mapping(target = "sourceId", expression = "java(user.getInternalId())")
+ @Mapping(target = "data", expression = "java(mapEntityToData(mapGetUserProfileToCdpCustomerProfile(" +
+ "legalEntityInternalId, legalEntityExternalId, customerCategory, user)))")
+ CdpEvent mapUserToCdpEvent(String legalEntityInternalId,
+ String legalEntityExternalId,
+ CustomerCategory customerCategory,
+ User user);
+
+ default List convertPostalAddresses(User user) {
+ List addresses = new ArrayList<>();
+ if (nonNull(user.getUserProfile()) && nonNull(user.getUserProfile().getAddresses())) {
+ addresses = user.getUserProfile().getAddresses()
+ .stream()
+ .map(this::mapPostalAddress)
+ .toList();
+ }
+ return addresses;
+ }
+
+ default List convertElectronicAddressesAndPhoneNumbers(User user) {
+ List contactDetails = new ArrayList<>();
+ if (nonNull(user.getEmailAddress())) {
+ contactDetails.add(mapEmailAddress(user.getEmailAddress()));
+ }
+ if (nonNull(user.getMobileNumber())) {
+ contactDetails.add(mapPhoneAddress(user.getMobileNumber()));
+ }
+ List electronicAddresses = new ArrayList<>();
+ List phoneNumbers = new ArrayList<>();
+ if (nonNull(user.getUserProfile())) {
+ if (nonNull(user.getUserProfile().getAdditionalEmails())) {
+ electronicAddresses.addAll(user.getUserProfile().getAdditionalEmails());
+ }
+ if (nonNull(user.getUserProfile().getAdditionalPhoneNumbers())) {
+ phoneNumbers.addAll(user.getUserProfile().getAdditionalPhoneNumbers());
+ }
+ }
+ contactDetails.addAll(electronicAddresses
+ .stream().map(this::mapElectronicAddress)
+ .toList());
+ contactDetails.addAll(phoneNumbers
+ .stream().map(this::mapPhoneAddress)
+ .toList());
+ return contactDetails;
+ }
+
+ @Mapping(target = "street1", source = "streetAddress")
+ @Mapping(target = "city", source = "locality")
+ @Mapping(target = "country", source = "country")
+ @Mapping(target = "postalCode", source = "postalCode")
+ @Mapping(target = "primary", source = "primary")
+ @Mapping(target = "type", source = "type")
+ @Mapping(target = "street2", ignore = true)
+ @Mapping(target = "state", ignore = true)
+ Address mapPostalAddress(com.backbase.stream.legalentity.model.Address postalAddress);
+
+ @Mapping(target = "type",
+ expression = "java(com.backbase.cdp.profiles.api.service.v1.model.DeliveryChannel.TypeEnum.EMAIL)")
+ @Mapping(target = "value", source = "value")
+ @Mapping(target = "primary", source = "primary")
+ @Mapping(target = "verified", constant = "true")
+ @Mapping(target = "optIn", ignore = true)
+ DeliveryChannel mapElectronicAddress(Multivalued electronicAddress);
+
+ @Mapping(target = "type",
+ expression = "java(com.backbase.cdp.profiles.api.service.v1.model.DeliveryChannel.TypeEnum.PHONE)")
+ @Mapping(target = "value", source = "value")
+ @Mapping(target = "primary", source = "primary")
+ @Mapping(target = "verified", constant = "true")
+ @Mapping(target = "optIn", ignore = true)
+ DeliveryChannel mapPhoneAddress(Multivalued phoneAddress);
+
+ @Mapping(target = "firstName", expression = "java(mapFirstName(user))")
+ @Mapping(target = "lastName", expression = "java(mapLastName(user))")
+ @Mapping(target = "middleName", expression = "java(mapMiddleName(user))")
+ @Mapping(target = "fullName", ignore = true)
+ @Mapping(target = "email", expression = "java(getPrimaryEmail(user))")
+ @Mapping(target = "phone", expression = "java(getPrimaryPhone(user))")
+ @Mapping(target = "address", expression = "java(getPrimaryAddress(convertPostalAddresses(user)))")
+ @Mapping(target = "dateOfBirth", expression = "java(mapDateOfBirth(user))")
+ @Mapping(target = "gender", expression = "java(mapGender(user))")
+ @Mapping(target = "preferredLocale", expression = "java(mapLocale(user))")
+ @Mapping(target = "nationality", expression = "java(mapNationality(user))")
+ @Mapping(target = "maritalStatus", source = "user.userProfile.personalInformation.maritalStatus")
+ @Mapping(target = "occupation", ignore = true)
+ @Mapping(target = "employer", source = "user.userProfile.personalInformation.employer")
+ @Mapping(target = "employerName", ignore = true)
+ PersonalInfo mapPersonalInfo(User user);
+
+ @Mapping(target = "cdpCustomerId", ignore = true)
+ @Mapping(target = "externalIds", expression = "java(mapUserToExternalIds(" +
+ "user, legalEntityInternalId, legalEntityExternalId))")
+ @Mapping(target = "personalInfo", expression = "java(mapPersonalInfo(user))")
+ @Mapping(target = "deliveryChannels", expression = "java(convertElectronicAddressesAndPhoneNumbers(user))")
+ @Mapping(target = "productHoldings", ignore = true)
+ @Mapping(target = "financialSummary", ignore = true)
+ @Mapping(target = "behavioralMetrics", ignore = true)
+ @Mapping(target = "inferredAttributes", ignore = true)
+ @Mapping(target = "preferences", ignore = true)
+ @Mapping(target = "complianceInfo", ignore = true)
+ @Mapping(target = "addresses", expression = "java(convertPostalAddresses(user))")
+ @Mapping(target = "segments", ignore = true)
+ @Mapping(target = "segmentCodes", ignore = true)
+ @Mapping(target = "organizationInfo", ignore = true)
+ @Mapping(target = "profileExtendedData", ignore = true)
+ @Mapping(target = "cardProductHoldings", ignore = true)
+ @Mapping(target = "profileStatus", expression = "java(mapUserStatus(user))")
+ @Mapping(target = "profileType", expression = "java(mapProfileType(customerCategory))")
+ @Mapping(target = "lastUpdated", ignore = true)
+ @Mapping(target = "createdAt", ignore = true)
+ @Mapping(target = "version", constant = "0L")
+ CustomerProfile mapGetUserProfileToCdpCustomerProfile(String legalEntityInternalId,
+ String legalEntityExternalId,
+ CustomerCategory customerCategory,
+ User user);
+
+ default CustomerProfile.ProfileTypeEnum mapProfileType(CustomerCategory customerCategory) {
+ if (isNull(customerCategory)) {
+ return CustomerProfile.ProfileTypeEnum.PERSON;
+ }
+ return customerCategory.equals(CustomerCategory.RETAIL)
+ ? CustomerProfile.ProfileTypeEnum.PERSON
+ : CustomerProfile.ProfileTypeEnum.EMPLOYEE;
+ }
+
+ default String mapUserStatus(User user) {
+ if (isNull(user)
+ || isNull(user.getUserProfile())
+ || isNull(user.getUserProfile().getActive())) {
+ return "ACTIVE";
+ }
+ return Boolean.TRUE.equals(user.getUserProfile().getActive()) ? "ACTIVE" : "INACTIVE";
+ }
+
+ default String mapNationality(User user) {
+ if (isNull(user)
+ || isNull(user.getUserProfile())
+ || isNull(user.getUserProfile().getPersonalInformation())
+ || isNull(user.getUserProfile().getPersonalInformation().getNationalities())
+ || user.getUserProfile().getPersonalInformation().getNationalities().isEmpty()) {
+ return null;
+ }
+ return user.getUserProfile().getPersonalInformation().getNationalities().getFirst();
+ }
+
+ default String getPrimaryEmail(User user) {
+ if (nonNull(user.getEmailAddress())) {
+ return user.getEmailAddress().getAddress();
+ } else if (nonNull(user.getUserProfile()) && nonNull(user.getUserProfile().getAdditionalEmails())) {
+ return getPrimaryValueFromMultiValued(user.getUserProfile().getAdditionalEmails());
+ }
+ return null;
+ }
+
+ default String getPrimaryPhone(User user) {
+ if (nonNull(user.getMobileNumber())) {
+ return user.getMobileNumber().getNumber();
+ } else if (nonNull(user.getUserProfile()) && nonNull(user.getUserProfile().getAdditionalPhoneNumbers())) {
+ return getPrimaryValueFromMultiValued(user.getUserProfile().getAdditionalPhoneNumbers());
+ }
+ return null;
+ }
+
+ default String getPrimaryValueFromMultiValued(List addresses) {
+ if (addresses == null || addresses.isEmpty()) {
+ return null;
+ }
+ return addresses.stream()
+ .filter(address -> address.getPrimary() != null && address.getPrimary())
+ .findFirst()
+ .orElse(addresses.getFirst())
+ .getValue();
+ }
+
+ default PersonalInfo.GenderEnum mapGender(User user) {
+ if (isNull(user)
+ || isNull(user.getUserProfile())
+ || isNull(user.getUserProfile().getPersonalInformation())
+ || isNull(user.getUserProfile().getPersonalInformation().getGender())
+ || user.getUserProfile().getPersonalInformation().getGender().isEmpty()) {
+ return null;
+ }
+ return mapStringToGender(user.getUserProfile().getPersonalInformation().getGender());
+ }
+
+ default String mapLocale(User user) {
+ if (isNull(user)
+ || isNull(user.getUserProfile())
+ || isNull(user.getUserProfile().getLocale())) {
+ return null;
+ }
+ return user.getUserProfile().getLocale();
+ }
+
+ default String mapFirstName(User user) {
+ if (isNull(user)
+ || isNull(user.getUserProfile())
+ || isNull(user.getUserProfile().getName())
+ || isNull(user.getUserProfile().getName().getGivenName())) {
+ return null;
+ }
+ return user.getUserProfile().getName().getGivenName();
+ }
+
+ default String mapLastName(User user) {
+ if (isNull(user)
+ || isNull(user.getUserProfile())
+ || isNull(user.getUserProfile().getName())
+ || isNull(user.getUserProfile().getName().getFamilyName())) {
+ return null;
+ }
+ return user.getUserProfile().getName().getFamilyName();
+ }
+
+ default String mapMiddleName(User user) {
+ if (isNull(user)
+ || isNull(user.getUserProfile())
+ || isNull(user.getUserProfile().getName())
+ || isNull(user.getUserProfile().getName().getMiddleName())) {
+ return null;
+ }
+ return user.getUserProfile().getName().getMiddleName();
+ }
+
+ default LocalDate mapDateOfBirth(User user) {
+ if (isNull(user) || isNull(user.getUserProfile()) || isNull(user.getUserProfile().getPersonalInformation())
+ || isNull(user.getUserProfile().getPersonalInformation().getDateOfBirth())) {
+ return null;
+ }
+ String dateOfBirth = user.getUserProfile().getPersonalInformation().getDateOfBirth();
+ if (isNull(dateOfBirth) || dateOfBirth.isEmpty()) {
+ return null;
+ }
+ return LocalDate.parse(dateOfBirth);
+ }
+
+ @Mapping(target = "type",
+ expression = "java(com.backbase.cdp.profiles.api.service.v1.model.DeliveryChannel.TypeEnum.PHONE)")
+ @Mapping(target = "value", source = "number")
+ @Mapping(target = "primary", source = "primary")
+ @Mapping(target = "verified", constant = "true")
+ @Mapping(target = "optIn", ignore = true)
+ DeliveryChannel mapPhoneAddress(PhoneNumber phoneAddress);
+
+ @Mapping(target = "type",
+ expression = "java(com.backbase.cdp.profiles.api.service.v1.model.DeliveryChannel.TypeEnum.EMAIL)")
+ @Mapping(target = "value", source = "address")
+ @Mapping(target = "primary", source = "primary")
+ @Mapping(target = "verified", constant = "true")
+ @Mapping(target = "optIn", ignore = true)
+ DeliveryChannel mapEmailAddress(EmailAddress emailAddress);
+
+ default Address getPrimaryAddress(List addresses) {
+ if (addresses == null || addresses.isEmpty()) {
+ return null;
+ }
+ return addresses.stream()
+ .filter(address -> address.getPrimary() != null && address.getPrimary())
+ .findFirst()
+ .orElse(addresses.getFirst());
+ }
+
+ default PersonalInfo.GenderEnum mapStringToGender(String gender) {
+ if (gender == null || gender.isEmpty()) {
+ return null;
+ }
+ try {
+ return PersonalInfo.GenderEnum.fromValue(gender.toUpperCase());
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ default Map mapEntityToData(Object entity) {
+ ObjectMapper mapper = new ObjectMapper()
+ .registerModule(new JavaTimeModule())
+ .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ return mapper.convertValue(entity, new TypeReference<>() {});
+ }
+
+ default String generateEventId() {
+ return java.util.UUID.randomUUID().toString();
+ }
+
+ default OffsetDateTime generateEventTimestamp() {
+ return OffsetDateTime.now(ZoneOffset.UTC);
+ }
+
+ default CdpEventMetadata generateEventMetadata(String eventSource) {
+ return new CdpEventMetadata()
+ .processedBy(List.of("stream-services"))
+ .schemaVersion("1")
+ .source(eventSource);
+ }
+
+ default List mapUserToExternalIds(User user, String legalEntityInternalId, String legalEntityExternalId) {
+ List externalIds = new ArrayList<>();
+ externalIds.add(new ExternalId()
+ .source(SOURCE_CORE_BANKING_SYSTEM)
+ .type(TYPE_USER_ID)
+ .id(user.getExternalId())
+ .verified(true));
+ if (nonNull(user.getInternalId())) {
+ externalIds.add(new ExternalId()
+ .source(SOURCE_BACKBASE)
+ .type(TYPE_USER_ID)
+ .id(user.getInternalId())
+ .verified(true));
+ }
+ if (nonNull(legalEntityInternalId)) {
+ externalIds.add(new ExternalId()
+ .source(SOURCE_BACKBASE)
+ .type(TYPE_CUSTOMER_ID)
+ .id(legalEntityInternalId)
+ .verified(true));
+ }
+ if (nonNull(legalEntityExternalId)) {
+ externalIds.add(new ExternalId()
+ .source(SOURCE_CORE_BANKING_SYSTEM)
+ .type(TYPE_CUSTOMER_ID)
+ .id(legalEntityExternalId)
+ .verified(true));
+ }
+ return externalIds;
+ }
+
+}
diff --git a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaV2Test.java b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaV2Test.java
index 8e3030da3..a1db08b70 100644
--- a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaV2Test.java
+++ b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaV2Test.java
@@ -1,17 +1,21 @@
package com.backbase.stream;
import static com.backbase.stream.FixtureUtils.reflectiveAlphaFixtureMonkey;
+import static com.backbase.stream.mapper.UserToCdpEventMapper.PROFILE_CREATED_EVENT;
import static com.backbase.stream.service.UserService.REMOVED_PREFIX;
import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import com.backbase.cdp.ingestion.api.service.v1.model.CdpEvent;
import com.backbase.customerprofile.api.integration.v1.model.PartyResponseUpsertDto;
import com.backbase.dbs.contact.api.service.v2.model.AccessContextScope;
import com.backbase.dbs.contact.api.service.v2.model.ContactsBulkPostRequestBody;
@@ -23,20 +27,28 @@
import com.backbase.dbs.user.api.service.v2.model.Realm;
import com.backbase.stream.audiences.UserKindSegmentationSaga;
import com.backbase.stream.audiences.UserKindSegmentationTask;
+import com.backbase.stream.cdp.CdpSaga;
+import com.backbase.stream.cdp.CdpTask;
import com.backbase.stream.configuration.LegalEntitySagaConfigurationProperties;
import com.backbase.stream.contact.ContactsSaga;
import com.backbase.stream.contact.ContactsTask;
+import com.backbase.stream.legalentity.model.Address;
import com.backbase.stream.legalentity.model.CustomerCategory;
+import com.backbase.stream.legalentity.model.EmailAddress;
import com.backbase.stream.legalentity.model.ExternalAccountInformation;
import com.backbase.stream.legalentity.model.ExternalContact;
import com.backbase.stream.legalentity.model.LegalEntity;
import com.backbase.stream.legalentity.model.LegalEntityType;
import com.backbase.stream.legalentity.model.LegalEntityV2;
+import com.backbase.stream.legalentity.model.Name;
import com.backbase.stream.legalentity.model.Party;
+import com.backbase.stream.legalentity.model.PersonalInformation;
+import com.backbase.stream.legalentity.model.PhoneNumber;
import com.backbase.stream.legalentity.model.SavingsAccount;
import com.backbase.stream.legalentity.model.ServiceAgreement;
import com.backbase.stream.legalentity.model.ServiceAgreementV2;
import com.backbase.stream.legalentity.model.User;
+import com.backbase.stream.legalentity.model.UserProfile;
import com.backbase.stream.mapper.LegalEntityV2toV1Mapper;
import com.backbase.stream.mapper.ServiceAgreementV2ToV1Mapper;
import com.backbase.stream.service.AccessGroupService;
@@ -49,6 +61,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.UUID;
import java.util.stream.Stream;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -57,6 +70,7 @@
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mapstruct.factory.Mappers;
+import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
@@ -92,6 +106,9 @@ class LegalEntitySagaV2Test {
@Mock
private UserKindSegmentationSaga userKindSegmentationSaga;
+ @Mock
+ private CdpSaga cdpSaga;
+
@Mock
private CustomerProfileService customerProfileService;
@@ -356,19 +373,46 @@ void updateUserName() {
Assertions.assertNotNull(result);
Assertions.assertNotNull(result.getData().getUsers());
- Assertions.assertNotNull(result.getData().getUsers().get(0));
+ Assertions.assertNotNull(result.getData().getUsers().getFirst());
Assertions.assertEquals(newRegularUser.getFullName(),
- result.getData().getUsers().get(0).getFullName());
+ result.getData().getUsers().getFirst().getFullName());
}
void getMockLegalEntity() {
- regularUser = new User().internalId("someRegularUserInId")
- .externalId(regularUserExId);
+ String userInternalId = UUID.randomUUID().toString();
+ regularUser = new User().internalId(userInternalId)
+ .externalId(regularUserExId)
+ .fullName("User Full Name")
+ .userProfile(new UserProfile()
+ .userId(userInternalId)
+ .externalId(regularUserExId)
+ .name(new Name()
+ .familyName("User")
+ .givenName("Name")
+ .middleName("Full")
+ .formatted("Full Name User"))
+ .active(true)
+ .addresses(List.of(new Address()
+ .streetAddress("Some street 1")
+ .locality("Some city")
+ .postalCode("02147")
+ .country("Some country")))
+ .personalInformation(new PersonalInformation()
+ .dateOfBirth("1990-01-01")
+ .employer("BACKBASE")
+ .gender("male")
+ .maritalStatus("single")))
+ .legalEntityId(leInternalId)
+ .emailAddress(new EmailAddress("home", "home", regularUserExId.concat("@domain.com")))
+ .mobileNumber(new PhoneNumber("home", "home", "1234567890"));
User adminUser = new User().internalId("someAdminInId").externalId(adminExId);
ServiceAgreement sa = new ServiceAgreement().creatorLegalEntity(leExternalId);
legalEntityV2 = new LegalEntityV2()
.internalId(leInternalId)
.externalId(leExternalId)
+ .legalEntityType(LegalEntityType.CUSTOMER)
+ .name("le-name")
+ .customerCategory(CustomerCategory.RETAIL)
.parties(fixtureMonkey.giveMe(Party.class, PARTY_SIZE))
.addAdministratorsItem(adminUser)
.parentExternalId(leParentExternalId)
@@ -412,7 +456,7 @@ void test_PostLegalContacts() {
legalEntityV2.setContacts(Collections.singletonList(contact));
result = legalEntitySaga.executeTask(task).block();
Assertions.assertNotNull(result);
- Assertions.assertEquals(leExternalId, result.getData().getContacts().get(0).getExternalId());
+ Assertions.assertEquals(leExternalId, result.getData().getContacts().getFirst().getExternalId());
}
@Test
@@ -540,6 +584,48 @@ void whenUserKindSegmentationIsEnabledAndNoCustomerCategoryCanBeDeterminedReturn
);
}
+ @Test
+ void cdpIsDisabled() {
+ getMockLegalEntity();
+
+ when(cdpSaga.isEnabled()).thenReturn(false);
+
+ when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn(
+ Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class)));
+
+ legalEntitySaga.executeTask(mockLegalEntityTask(legalEntityV2)).block();
+
+ verify(cdpSaga, never()).executeTask(Mockito.any());
+ }
+
+ @Test
+ void cdpIsEnabledTestMappings() {
+ ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CdpTask.class);
+ getMockLegalEntity();
+
+ when(cdpSaga.isEnabled()).thenReturn(true);
+ when(legalEntitySagaConfigurationProperties.isUserProfileEnabled()).thenReturn(false);
+
+ legalEntityV2.setLegalEntityType(LegalEntityType.CUSTOMER);
+
+ when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn(
+ Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class)));
+
+ when(cdpSaga.executeTask(any())).thenReturn(
+ Mono.just(Mockito.mock(com.backbase.stream.cdp.CdpTask.class)));
+
+ legalEntitySaga.executeTask(mockLegalEntityTask(legalEntityV2)).block();
+
+ verify(cdpSaga, atLeastOnce()).executeTask(Mockito.any());
+ verify(cdpSaga).executeTask(argumentCaptor.capture());
+ CdpTask capturedCdpTask = argumentCaptor.getValue();
+ assertThat(capturedCdpTask).isNotNull();
+ assertThat(capturedCdpTask.getCdpEvents()).isNotNull();
+ assertThat(capturedCdpTask.getCdpEvents().getCdpEvents()).isNotNull().hasSize(1);
+ CdpEvent cdpEvent = capturedCdpTask.getCdpEvents().getCdpEvents().getFirst();
+ assertThat(cdpEvent.getEventType()).isEqualTo(PROFILE_CREATED_EVENT);
+ }
+
@Test
void testSetupParties_IfPartyFound_ThenUpsertParty() {
getMockLegalEntity();
@@ -590,7 +676,7 @@ void upster_error(Exception ex, String error) {
// Then
verify(legalEntityService).getLegalEntityByExternalId(any());
- org.assertj.core.api.Assertions.assertThat(stEx)
+ assertThat(stEx)
.isNotNull()
.extracting(e -> e.getTask().getHistory().get(1).getErrorMessage())
.isEqualTo(error);
diff --git a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/mapper/UserToCdpEventMapperTest.java b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/mapper/UserToCdpEventMapperTest.java
new file mode 100644
index 000000000..366bcafb9
--- /dev/null
+++ b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/mapper/UserToCdpEventMapperTest.java
@@ -0,0 +1,212 @@
+package com.backbase.stream.mapper;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.backbase.cdp.ingestion.api.service.v1.model.CdpEvent;
+import com.backbase.cdp.profiles.api.service.v1.model.CustomerProfile;
+import com.backbase.cdp.profiles.api.service.v1.model.ExternalId;
+import com.backbase.stream.legalentity.model.Address;
+import com.backbase.stream.legalentity.model.CustomerCategory;
+import com.backbase.stream.legalentity.model.EmailAddress;
+import com.backbase.stream.legalentity.model.Multivalued;
+import com.backbase.stream.legalentity.model.PersonalInformation;
+import com.backbase.stream.legalentity.model.PhoneNumber;
+import com.backbase.stream.legalentity.model.User;
+import com.backbase.stream.legalentity.model.UserProfile;
+import java.time.LocalDate;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mapstruct.factory.Mappers;
+
+class UserToCdpEventMapperTest {
+
+ private UserToCdpEventMapper mapper;
+
+ @BeforeEach
+ void setUp() {
+ mapper = Mappers.getMapper(UserToCdpEventMapper.class);
+ }
+
+ @Test
+ void testMapUserToCdpEvent_basicFields() {
+ User user = new User();
+ user.setInternalId("int-1");
+ user.setExternalId("ext-1");
+ user.setEmailAddress(new EmailAddress().address("test@email.com").primary(true));
+ user.setMobileNumber(new PhoneNumber().number("123456789").primary(true));
+ user.setUserProfile(new UserProfile());
+ CustomerCategory category = CustomerCategory.RETAIL;
+ CdpEvent event = mapper.mapUserToCdpEvent("leIntId", "leExtId", category, user);
+ assertThat(event).isNotNull();
+ assertThat(event.getEventType()).isEqualTo(UserToCdpEventMapper.PROFILE_CREATED_EVENT);
+ assertThat(event.getSourceSystem()).isEqualTo(UserToCdpEventMapper.SOURCE_BACKBASE);
+ assertThat(event.getSourceType()).isEqualTo(UserToCdpEventMapper.TYPE_USER_ID);
+ assertThat(event.getSourceId()).isEqualTo("int-1");
+ assertThat(event.getEventId()).isNotNull();
+ assertThat(event.getTimestamp()).isNotNull();
+ assertThat(event.getMetadata()).isNotNull();
+ assertThat(event.getMetadata().getProcessedBy()).isNotNull().contains("stream-services");
+ assertThat(event.getMetadata().getSchemaVersion()).isEqualTo("1");
+ assertThat(event.getMetadata().getSource()).isEqualTo("stream-services");
+ assertThat(event.getData()).isNotNull();
+ }
+
+ @Test
+ void testConvertPostalAddresses_handlesNulls() {
+ User user = new User();
+ assertThat(mapper.convertPostalAddresses(user)).isNotNull().isEmpty();
+ }
+
+ @Test
+ void testGetPrimaryValueFromMultiValued_prefersPrimary() {
+ Multivalued m1 = new Multivalued().value("a").primary(false);
+ Multivalued m2 = new Multivalued().value("b").primary(true);
+ List list = List.of(m1, m2);
+ assertThat(mapper.getPrimaryValueFromMultiValued(list)).isEqualTo("b");
+ }
+
+ @Test
+ void shouldProperlyMapProfileTypeTest() {
+ CustomerProfile.ProfileTypeEnum profileType = mapper.mapProfileType(CustomerCategory.BUSINESS);
+ assertThat(profileType).isEqualTo(CustomerProfile.ProfileTypeEnum.EMPLOYEE);
+ }
+
+ @Test
+ void testGetPrimaryValueFromMultiValued_fallbackToFirst() {
+ Multivalued m1 = new Multivalued().value("a").primary(false);
+ Multivalued m2 = new Multivalued().value("b").primary(false);
+ List list = List.of(m1, m2);
+ assertThat(mapper.getPrimaryValueFromMultiValued(list)).isEqualTo("a");
+ }
+
+ @Test
+ void testMapUserStatus_nulls() {
+ assertThat(mapper.mapUserStatus(null)).isEqualTo("ACTIVE");
+ User user = new User();
+ assertThat(mapper.mapUserStatus(user)).isEqualTo("ACTIVE");
+ user.setUserProfile(new UserProfile());
+ assertThat(mapper.mapUserStatus(user)).isEqualTo("ACTIVE");
+ }
+
+ @Test
+ void testMapUserStatus_inactive() {
+ User user = new User();
+ UserProfile profile = new UserProfile();
+ profile.setActive(false);
+ user.setUserProfile(profile);
+ assertThat(mapper.mapUserStatus(user)).isEqualTo("INACTIVE");
+ }
+
+ @Test
+ void testMapDateOfBirth_handlesNullsAndEmpty() {
+ User user = new User();
+ assertThat(mapper.mapDateOfBirth(user)).isNull();
+ UserProfile profile = new UserProfile();
+ user.setUserProfile(profile);
+ assertThat(mapper.mapDateOfBirth(user)).isNull();
+ profile.setPersonalInformation(new PersonalInformation());
+ assertThat(mapper.mapDateOfBirth(user)).isNull();
+ profile.getPersonalInformation().setDateOfBirth("");
+ assertThat(mapper.mapDateOfBirth(user)).isNull();
+ }
+
+ @Test
+ void testMapDateOfBirth_valid() {
+ User user = new User();
+ UserProfile profile = new UserProfile();
+ PersonalInformation pi = new PersonalInformation();
+ pi.setDateOfBirth("2000-01-01");
+ profile.setPersonalInformation(pi);
+ user.setUserProfile(profile);
+ assertThat(mapper.mapDateOfBirth(user)).isEqualTo(LocalDate.of(2000, 1, 1));
+ }
+
+ @Test
+ void testMapUserToExternalIds_allFields() {
+ User user = new User();
+ user.setInternalId("int");
+ user.setExternalId("ext");
+ List ids = mapper.mapUserToExternalIds(user, "leInt", "leExt");
+ assertThat(ids).hasSize(4);
+ }
+
+ @Test
+ void testMapUserToExternalIds_handlesNulls() {
+ User user = new User();
+ List ids = mapper.mapUserToExternalIds(user, null, null);
+ assertThat(ids).isEmpty();
+ user.setInternalId("int");
+ ids = mapper.mapUserToExternalIds(user, null, null);
+ assertThat(ids).hasSize(1);
+ }
+
+ @Test
+ void testPhoneAddressMultiValuedMapping() {
+ Multivalued phone = new Multivalued().value("+123456789").primary(false);
+ var deliveryChannel = mapper.mapPhoneAddress(phone);
+ assertThat(deliveryChannel).isNotNull();
+ assertThat(deliveryChannel.getPrimary()).isFalse();
+ assertThat(deliveryChannel.getValue()).isEqualTo("+123456789");
+ }
+
+ @Test
+ void testElectronicAddressMapping() {
+ Multivalued email = new Multivalued().value("test@address.com").primary(true);
+ var deliveryChannel = mapper.mapElectronicAddress(email);
+ assertThat(deliveryChannel).isNotNull();
+ assertThat(deliveryChannel.getPrimary()).isTrue();
+ assertThat(deliveryChannel.getValue()).isEqualTo("test@address.com");
+ }
+
+ @Test
+ void testPrimaryEmailMapping() {
+ EmailAddress email = new EmailAddress().address("test@address.com").primary(true);
+ var deliveryChannel = mapper.mapEmailAddress(email);
+ assertThat(deliveryChannel).isNotNull();
+ assertThat(deliveryChannel.getPrimary()).isTrue();
+ assertThat(deliveryChannel.getValue()).isEqualTo("test@address.com");
+ }
+
+ @Test
+ void testPhoneAddressMapping() {
+ PhoneNumber phone = new PhoneNumber().number("987654321").primary(true);
+ var deliveryChannel = mapper.mapPhoneAddress(phone);
+ assertThat(deliveryChannel).isNotNull();
+ assertThat(deliveryChannel.getPrimary()).isTrue();
+ assertThat(deliveryChannel.getValue()).isEqualTo("987654321");
+ }
+
+ @Test
+ void testPostalAddressMappingWhenNull() {
+ User user = new User();
+ var addresses = mapper.convertPostalAddresses(user);
+ assertThat(addresses).isNotNull().isEmpty();
+ }
+
+ @Test
+ void testPostalAddressMapping() {
+ UserProfile userProfile = new UserProfile();
+ userProfile.setAddresses(List.of(new Address()
+ .streetAddress("123 Main St")
+ .locality("Anytown")
+ .region("CA")
+ .postalCode("12345")
+ .country("USA")
+ .primary(true)
+ , new Address()
+ .streetAddress("124 Main St")
+ .locality("Sometown")
+ .region("Alberta")
+ .postalCode("54321")
+ .country("Canada")
+ .primary(true)
+ ));
+ User user = new User();
+ user.setUserProfile(userProfile);
+ var addresses = mapper.convertPostalAddresses(user);
+ assertThat(addresses).isNotNull().hasSize(2);
+ assertThat(addresses.stream().map(com.backbase.cdp.profiles.api.service.v1.model.Address::getStreet1))
+ .containsExactlyInAnyOrder("123 Main St", "124 Main St");
+ }
+}
diff --git a/stream-legal-entity/legal-entity-http/pom.xml b/stream-legal-entity/legal-entity-http/pom.xml
index 0f4fc6f3c..fa2f35924 100644
--- a/stream-legal-entity/legal-entity-http/pom.xml
+++ b/stream-legal-entity/legal-entity-http/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-http-starter-parent
- 9.5.1
+ 9.6.0
../../stream-sdk/stream-starter-parents/stream-http-starter-parent
diff --git a/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java b/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java
index 81b5b1757..341bdb80e 100644
--- a/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java
+++ b/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java
@@ -21,6 +21,7 @@
import com.backbase.loan.inbound.api.service.v2.LoansApi;
import com.backbase.stream.CustomerAccessGroupSaga;
import com.backbase.stream.audiences.UserKindSegmentationSaga;
+import com.backbase.stream.cdp.CdpSaga;
import com.backbase.stream.clients.config.CustomerProfileClientConfig;
import com.backbase.stream.config.LegalEntityHttpConfiguration;
import com.backbase.stream.configuration.LegalEntitySagaConfiguration;
@@ -126,6 +127,9 @@ class ServiceAgreementControllerTest {
@MockitoBean
private UserKindSegmentationSaga userKindSegmentationSaga;
+ @MockitoBean
+ private CdpSaga cdpSaga;
+
@MockitoBean
private PlansService plansService;
diff --git a/stream-legal-entity/pom.xml b/stream-legal-entity/pom.xml
index 0dec1aac3..e88a5d003 100644
--- a/stream-legal-entity/pom.xml
+++ b/stream-legal-entity/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-legal-entity
diff --git a/stream-limits/limits-core/pom.xml b/stream-limits/limits-core/pom.xml
index f039f9939..254213240 100644
--- a/stream-limits/limits-core/pom.xml
+++ b/stream-limits/limits-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-limits
- 9.5.1
+ 9.6.0
limits-core
diff --git a/stream-limits/pom.xml b/stream-limits/pom.xml
index 3050bc565..ed4c9c5c0 100644
--- a/stream-limits/pom.xml
+++ b/stream-limits/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-limits
diff --git a/stream-loans/loans-core/pom.xml b/stream-loans/loans-core/pom.xml
index 716ba27c5..8b5b48cd7 100644
--- a/stream-loans/loans-core/pom.xml
+++ b/stream-loans/loans-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-loans
- 9.5.1
+ 9.6.0
loans-core
diff --git a/stream-loans/pom.xml b/stream-loans/pom.xml
index fc7de247b..c4a7a7f69 100644
--- a/stream-loans/pom.xml
+++ b/stream-loans/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-loans
diff --git a/stream-models/approval-model/pom.xml b/stream-models/approval-model/pom.xml
index 0678e9ca9..bd24fa04f 100644
--- a/stream-models/approval-model/pom.xml
+++ b/stream-models/approval-model/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-models
- 9.5.1
+ 9.6.0
approval-model
diff --git a/stream-models/legal-entity-model/pom.xml b/stream-models/legal-entity-model/pom.xml
index 80ad72b2c..feb1202dd 100644
--- a/stream-models/legal-entity-model/pom.xml
+++ b/stream-models/legal-entity-model/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-models
- 9.5.1
+ 9.6.0
legal-entity-model
diff --git a/stream-models/pom.xml b/stream-models/pom.xml
index 5f3cdefcc..eef047ba2 100644
--- a/stream-models/pom.xml
+++ b/stream-models/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-models
diff --git a/stream-models/portfolio-model/pom.xml b/stream-models/portfolio-model/pom.xml
index 33c5407c2..dd47d72c4 100644
--- a/stream-models/portfolio-model/pom.xml
+++ b/stream-models/portfolio-model/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-models
- 9.5.1
+ 9.6.0
portfolio-model
diff --git a/stream-models/product-catalog-model/pom.xml b/stream-models/product-catalog-model/pom.xml
index fa9c1db46..36a48ebe1 100644
--- a/stream-models/product-catalog-model/pom.xml
+++ b/stream-models/product-catalog-model/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-models
- 9.5.1
+ 9.6.0
product-catalog-model
diff --git a/stream-payment-order/payment-order-core/pom.xml b/stream-payment-order/payment-order-core/pom.xml
index c541595b0..cc05b5eb1 100644
--- a/stream-payment-order/payment-order-core/pom.xml
+++ b/stream-payment-order/payment-order-core/pom.xml
@@ -6,7 +6,7 @@
com.backbase.stream
stream-payment-order
- 9.5.1
+ 9.6.0
payment-order-core
diff --git a/stream-payment-order/pom.xml b/stream-payment-order/pom.xml
index 3f8031cfe..742bcb56b 100644
--- a/stream-payment-order/pom.xml
+++ b/stream-payment-order/pom.xml
@@ -6,7 +6,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-payment-order
diff --git a/stream-plan-manager/plan-manager-core/pom.xml b/stream-plan-manager/plan-manager-core/pom.xml
index e73090e95..a006e4d8d 100644
--- a/stream-plan-manager/plan-manager-core/pom.xml
+++ b/stream-plan-manager/plan-manager-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-plan-manager
- 9.5.1
+ 9.6.0
plan-manager-core
diff --git a/stream-plan-manager/pom.xml b/stream-plan-manager/pom.xml
index 1dc1b4efe..88b60283a 100644
--- a/stream-plan-manager/pom.xml
+++ b/stream-plan-manager/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-plan-manager
diff --git a/stream-portfolio/pom.xml b/stream-portfolio/pom.xml
index dd63f601f..947516869 100644
--- a/stream-portfolio/pom.xml
+++ b/stream-portfolio/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-portfolio
diff --git a/stream-portfolio/portfolio-bootstrap-task/pom.xml b/stream-portfolio/portfolio-bootstrap-task/pom.xml
index 18f23e3d9..99d89e76c 100644
--- a/stream-portfolio/portfolio-bootstrap-task/pom.xml
+++ b/stream-portfolio/portfolio-bootstrap-task/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-task-starter-parent
- 9.5.1
+ 9.6.0
../../stream-sdk/stream-starter-parents/stream-task-starter-parent
diff --git a/stream-portfolio/portfolio-core/pom.xml b/stream-portfolio/portfolio-core/pom.xml
index aa3581f2a..c719be402 100644
--- a/stream-portfolio/portfolio-core/pom.xml
+++ b/stream-portfolio/portfolio-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-portfolio
- 9.5.1
+ 9.6.0
portfolio-core
diff --git a/stream-portfolio/portfolio-http/pom.xml b/stream-portfolio/portfolio-http/pom.xml
index d15631140..b52d7d1c6 100644
--- a/stream-portfolio/portfolio-http/pom.xml
+++ b/stream-portfolio/portfolio-http/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-http-starter-parent
- 9.5.1
+ 9.6.0
../../stream-sdk/stream-starter-parents/stream-http-starter-parent
diff --git a/stream-product-catalog/pom.xml b/stream-product-catalog/pom.xml
index 24ee11a4b..66a0fbe9e 100644
--- a/stream-product-catalog/pom.xml
+++ b/stream-product-catalog/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-product-catalog
diff --git a/stream-product-catalog/product-catalog-core/pom.xml b/stream-product-catalog/product-catalog-core/pom.xml
index ff3c6bb2f..caa9ba64c 100644
--- a/stream-product-catalog/product-catalog-core/pom.xml
+++ b/stream-product-catalog/product-catalog-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-product-catalog
- 9.5.1
+ 9.6.0
product-catalog-core
diff --git a/stream-product-catalog/product-catalog-http/pom.xml b/stream-product-catalog/product-catalog-http/pom.xml
index 0890af6e3..ded880d1c 100644
--- a/stream-product-catalog/product-catalog-http/pom.xml
+++ b/stream-product-catalog/product-catalog-http/pom.xml
@@ -6,7 +6,7 @@
com.backbase.stream
stream-http-starter-parent
- 9.5.1
+ 9.6.0
../../stream-sdk/stream-starter-parents/stream-http-starter-parent
diff --git a/stream-product-catalog/product-catalog-task/pom.xml b/stream-product-catalog/product-catalog-task/pom.xml
index 6ed319a64..fcb8f8182 100644
--- a/stream-product-catalog/product-catalog-task/pom.xml
+++ b/stream-product-catalog/product-catalog-task/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-task-starter-parent
- 9.5.1
+ 9.6.0
../../stream-sdk/stream-starter-parents/stream-task-starter-parent
diff --git a/stream-product/pom.xml b/stream-product/pom.xml
index 5de8ee75d..d5d7d8444 100644
--- a/stream-product/pom.xml
+++ b/stream-product/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-product
diff --git a/stream-product/product-core/pom.xml b/stream-product/product-core/pom.xml
index 55a954474..e86d1bb91 100644
--- a/stream-product/product-core/pom.xml
+++ b/stream-product/product-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-product
- 9.5.1
+ 9.6.0
product-core
diff --git a/stream-product/product-ingestion-saga/pom.xml b/stream-product/product-ingestion-saga/pom.xml
index 3d51deb14..47a91db12 100644
--- a/stream-product/product-ingestion-saga/pom.xml
+++ b/stream-product/product-ingestion-saga/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-product
- 9.5.1
+ 9.6.0
product-ingestion-saga
diff --git a/stream-sdk/pom.xml b/stream-sdk/pom.xml
index 39c1f2943..993a85731 100644
--- a/stream-sdk/pom.xml
+++ b/stream-sdk/pom.xml
@@ -4,7 +4,7 @@
com.backbase.stream
stream-sdk
- 9.5.1
+ 9.6.0
pom
Stream :: SDK
diff --git a/stream-sdk/stream-parent/pom.xml b/stream-sdk/stream-parent/pom.xml
index 5bf1fb5b8..3969b9b6f 100644
--- a/stream-sdk/stream-parent/pom.xml
+++ b/stream-sdk/stream-parent/pom.xml
@@ -11,7 +11,7 @@
com.backbase.stream
stream-parent
- 9.5.1
+ 9.6.0
pom
Stream :: SDK :: Parent
Parent for all Stream SDK modules
diff --git a/stream-sdk/stream-parent/stream-context-propagation/pom.xml b/stream-sdk/stream-parent/stream-context-propagation/pom.xml
index 81fa2a029..b19a009c3 100644
--- a/stream-sdk/stream-parent/stream-context-propagation/pom.xml
+++ b/stream-sdk/stream-parent/stream-context-propagation/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-parent
- 9.5.1
+ 9.6.0
stream-context-propagation
diff --git a/stream-sdk/stream-parent/stream-dbs-web-client/pom.xml b/stream-sdk/stream-parent/stream-dbs-web-client/pom.xml
index a131b57f9..a94659b8b 100644
--- a/stream-sdk/stream-parent/stream-dbs-web-client/pom.xml
+++ b/stream-sdk/stream-parent/stream-dbs-web-client/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-parent
- 9.5.1
+ 9.6.0
stream-dbs-web-client
diff --git a/stream-sdk/stream-parent/stream-openapi-support/pom.xml b/stream-sdk/stream-parent/stream-openapi-support/pom.xml
index c05182ecc..78ad2e993 100644
--- a/stream-sdk/stream-parent/stream-openapi-support/pom.xml
+++ b/stream-sdk/stream-parent/stream-openapi-support/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-parent
- 9.5.1
+ 9.6.0
stream-openapi-support
diff --git a/stream-sdk/stream-parent/stream-test-support/pom.xml b/stream-sdk/stream-parent/stream-test-support/pom.xml
index e3dd067dd..9ded1b622 100644
--- a/stream-sdk/stream-parent/stream-test-support/pom.xml
+++ b/stream-sdk/stream-parent/stream-test-support/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-parent
- 9.5.1
+ 9.6.0
stream-test-support
diff --git a/stream-sdk/stream-parent/stream-worker/pom.xml b/stream-sdk/stream-parent/stream-worker/pom.xml
index c471a6b21..16021eff7 100644
--- a/stream-sdk/stream-parent/stream-worker/pom.xml
+++ b/stream-sdk/stream-parent/stream-worker/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-parent
- 9.5.1
+ 9.6.0
stream-worker
diff --git a/stream-sdk/stream-starter-parents/pom.xml b/stream-sdk/stream-starter-parents/pom.xml
index 016bd051f..231d07e7d 100644
--- a/stream-sdk/stream-starter-parents/pom.xml
+++ b/stream-sdk/stream-starter-parents/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-parent
- 9.5.1
+ 9.6.0
../stream-parent
diff --git a/stream-sdk/stream-starter-parents/stream-http-starter-parent/pom.xml b/stream-sdk/stream-starter-parents/stream-http-starter-parent/pom.xml
index d98fe53f7..666be655b 100644
--- a/stream-sdk/stream-starter-parents/stream-http-starter-parent/pom.xml
+++ b/stream-sdk/stream-starter-parents/stream-http-starter-parent/pom.xml
@@ -6,13 +6,13 @@
com.backbase.stream
stream-starter
- 9.5.1
+ 9.6.0
../../stream-starter
com.backbase.stream
stream-http-starter-parent
- 9.5.1
+ 9.6.0
pom
Stream :: SDK :: HTTP Services Starter
Parent for Stream HTTP Services
diff --git a/stream-sdk/stream-starter-parents/stream-task-starter-parent/pom.xml b/stream-sdk/stream-starter-parents/stream-task-starter-parent/pom.xml
index d040f27ab..30ad2d577 100644
--- a/stream-sdk/stream-starter-parents/stream-task-starter-parent/pom.xml
+++ b/stream-sdk/stream-starter-parents/stream-task-starter-parent/pom.xml
@@ -5,13 +5,13 @@
com.backbase.stream
stream-starter
- 9.5.1
+ 9.6.0
../../stream-starter
com.backbase.stream
stream-task-starter-parent
- 9.5.1
+ 9.6.0
pom
Stream :: SDK :: Task Starter
Parent for Stream Executable Tasks
diff --git a/stream-sdk/stream-starter/pom.xml b/stream-sdk/stream-starter/pom.xml
index f98040dcd..05c700182 100644
--- a/stream-sdk/stream-starter/pom.xml
+++ b/stream-sdk/stream-starter/pom.xml
@@ -10,7 +10,7 @@
com.backbase.stream
stream-starter
Stream :: SDK :: stream-starter
- 9.5.1
+ 9.6.0
pom
diff --git a/stream-transactions/pom.xml b/stream-transactions/pom.xml
index ef3d81a92..e64307a40 100644
--- a/stream-transactions/pom.xml
+++ b/stream-transactions/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-services
- 9.5.1
+ 9.6.0
stream-transactions
diff --git a/stream-transactions/transactions-core/pom.xml b/stream-transactions/transactions-core/pom.xml
index c764efcd8..945be2423 100644
--- a/stream-transactions/transactions-core/pom.xml
+++ b/stream-transactions/transactions-core/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-transactions
- 9.5.1
+ 9.6.0
transactions-core
diff --git a/stream-transactions/transactions-item-writer/pom.xml b/stream-transactions/transactions-item-writer/pom.xml
index d49aa5e92..6d5d86e82 100644
--- a/stream-transactions/transactions-item-writer/pom.xml
+++ b/stream-transactions/transactions-item-writer/pom.xml
@@ -5,7 +5,7 @@
com.backbase.stream
stream-parent
- 9.5.1
+ 9.6.0
../../stream-sdk/stream-parent