From b98047a659828dad8d782b03195b152567797b1b Mon Sep 17 00:00:00 2001 From: markostreich Date: Fri, 12 Apr 2024 12:10:09 +0200 Subject: [PATCH] 1401 enhance process config with incident notification addresses (#1545) * 1401 enhance process config with incident notification adresses * 1401 mock super class * #1401 unittest incident notification adresses * 1401 JavaDoc * 1401 documentation * repair broken footnotes * Update digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/engine/incidents/IncidentNotifierHandler.java Co-authored-by: Simon Hirtreiter * 1401 refactor incident noditifaction properties * 1401 refactor properties --------- Co-authored-by: Simon Hirtreiter --- .../engine/incidents/BaseIncidentHandler.java | 10 ++ .../IncidentNotificationProperties.java | 17 +++ .../incidents/IncidentNotifierHandler.java | 126 +++++++++++------- .../config/domain/model/ProcessConfig.java | 14 +- .../src/main/resources/application.yml | 6 +- .../Test/TestIncident.processconfig.json | 42 ++++++ .../IncidentNotifierHandlerTest.java | 121 +++++++++++++++++ .../resources/dummy/Test.processconfig.json | 42 ++++++ .../src/main/resources/application.yml | 2 +- .../architecture/system-integration.md | 6 +- docs/src/modeling/processes/config/README.md | 8 +- stack/local-docker.env | 1 + 12 files changed, 334 insertions(+), 61 deletions(-) create mode 100644 digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/engine/incidents/BaseIncidentHandler.java create mode 100644 digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/engine/incidents/IncidentNotificationProperties.java create mode 100644 digiwf-engine/digiwf-engine-service/src/main/resources/prozesse/archive/Test/TestIncident.processconfig.json create mode 100644 digiwf-engine/digiwf-engine-service/src/test/java/de/muenchen/oss/digiwf/engine/incidents/IncidentNotifierHandlerTest.java create mode 100644 digiwf-engine/digiwf-engine-service/src/test/resources/dummy/Test.processconfig.json diff --git a/digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/engine/incidents/BaseIncidentHandler.java b/digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/engine/incidents/BaseIncidentHandler.java new file mode 100644 index 0000000000..4d60f97496 --- /dev/null +++ b/digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/engine/incidents/BaseIncidentHandler.java @@ -0,0 +1,10 @@ +package de.muenchen.oss.digiwf.engine.incidents; + +import org.camunda.bpm.engine.impl.incident.DefaultIncidentHandler; + +public class BaseIncidentHandler extends DefaultIncidentHandler { + + public BaseIncidentHandler() { + super("failedJob"); + } +} diff --git a/digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/engine/incidents/IncidentNotificationProperties.java b/digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/engine/incidents/IncidentNotificationProperties.java new file mode 100644 index 0000000000..b7655b3331 --- /dev/null +++ b/digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/engine/incidents/IncidentNotificationProperties.java @@ -0,0 +1,17 @@ +package de.muenchen.oss.digiwf.engine.incidents; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@Data +@ConfigurationProperties(prefix = "digiwf.incident") +public class IncidentNotificationProperties { + + private String cockpitUrl; + + private String environment; + + private String fromAddress; + + private String toAddress; +} diff --git a/digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/engine/incidents/IncidentNotifierHandler.java b/digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/engine/incidents/IncidentNotifierHandler.java index 27d9c60337..f8acaa882e 100644 --- a/digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/engine/incidents/IncidentNotifierHandler.java +++ b/digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/engine/incidents/IncidentNotifierHandler.java @@ -6,24 +6,26 @@ import de.muenchen.oss.digiwf.email.api.DigiwfEmailApi; import de.muenchen.oss.digiwf.email.model.Mail; +import de.muenchen.oss.digiwf.process.config.domain.model.ProcessConfig; +import de.muenchen.oss.digiwf.process.config.domain.service.ProcessConfigService; import jakarta.mail.MessagingException; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.val; import org.apache.logging.log4j.util.Strings; import org.camunda.bpm.engine.RepositoryService; -import org.camunda.bpm.engine.impl.incident.DefaultIncidentHandler; +import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.impl.incident.IncidentContext; import org.camunda.bpm.engine.impl.persistence.entity.IncidentEntity; import org.camunda.bpm.engine.repository.ProcessDefinition; import org.camunda.bpm.engine.runtime.Incident; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; +import org.jetbrains.annotations.NotNull; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import java.util.Map; - /** * Handler getting active in case of incidents and can react e.g. by sending an information mail. * @@ -31,67 +33,60 @@ */ @Slf4j @Component -public class IncidentNotifierHandler extends DefaultIncidentHandler { - - @Autowired - private DigiwfEmailApi digiwfEmailApi; +@RequiredArgsConstructor(onConstructor_ = { @Lazy }) +@EnableConfigurationProperties(IncidentNotificationProperties.class) +public class IncidentNotifierHandler extends BaseIncidentHandler { - @Autowired - @Lazy - private RepositoryService repositoryService; + private final RepositoryService repositoryService; - @Value("${digiwf.incident.cockpitUrl:#{null}}") - private String cockpitUrl; + private final RuntimeService runtimeService; - @Value("${digiwf.incident.fromAddress:#{null}}") - private String fromAddress; + private final DigiwfEmailApi digiwfEmailApi; - @Value("${digiwf.incident.toAddress:#{null}}") - private String toAddress; + private final ProcessConfigService processConfigService; - @Value("${digiwf.incident.environment:#{null}}") - private String environment; - - public IncidentNotifierHandler() { - super("failedJob"); - } + private final IncidentNotificationProperties incidentNotificationProperties; @Override public Incident handleIncident(final IncidentContext context, final String message) { log.warn("Incident occurred"); - final IncidentEntity incidentEntity = (IncidentEntity) super.handleIncident(context, message); + final IncidentEntity incidentEntity = superHandleIncident(context, message); + + val processInstanceId = incidentEntity.getProcessInstanceId(); + val rootProcessInstanceId = runtimeService + .createProcessInstanceQuery() + .processInstanceId(processInstanceId) + .singleResult() + .getRootProcessInstanceId(); + + val rootProcessDefinitionId = runtimeService + .createProcessInstanceQuery() + .processInstanceId(rootProcessInstanceId) + .singleResult() + .getProcessDefinitionId(); + val processConfig = processConfigService.getProcessConfig(rootProcessDefinitionId.split(":")[0]); + + var notificationAddresses = processConfig.orElse(new ProcessConfig()).getIncidentNotificationAddresses(); - if (Strings.isEmpty(this.toAddress)) { - log.debug("Notification on incidents if not configured"); + if (Strings.isEmpty(notificationAddresses)) notificationAddresses = incidentNotificationProperties.getToAddress(); + + if (Strings.isEmpty(notificationAddresses)) { + log.debug("Notification on incidents is not configured"); return incidentEntity; } try { String processName = this.getProcessName(incidentEntity.getProcessDefinitionId()); - val link = this.cockpitUrl + - "camunda/app/cockpit/default/#/process-instance/" + - incidentEntity.getProcessInstanceId() + - "/runtime"; - final String emailText = processName.isBlank() ? - "In der Anwendung ist ein Incident aufgetreten." : - "In der Anwendung ist ein Incident aufgetreten (Prozessname: " + processName + ")."; - - final Map emailContent = Map.of( - "%%body_top%%", emailText, - "%%body_bottom%%", "Mit freundlichen Grüßen
Ihr DigiWF-Team", - "%%button_link%%", link, - "%%button_text%%", "Fehler im Cockpit anzeigen", - "%%footer%%", "DigiWF 2.0
IT-Referat der Stadt München" - ); + final Map emailContent = getEMailContent(incidentEntity, processName); final String templatePath = "bausteine/mail/templatewithlink/mail-template.tpl"; final String emailBody = this.digiwfEmailApi.getEmailBodyFromTemplate(templatePath, emailContent); final Mail mail = Mail.builder() - .receivers(this.toAddress) - .subject(this.environment + ": Incident aufgetreten") + .receivers(notificationAddresses) + .subject(incidentNotificationProperties.getEnvironment() + ": Incident aufgetreten") .body(emailBody) .htmlBody(true) - .replyTo(this.fromAddress) + .replyTo(incidentNotificationProperties.getFromAddress()) .build(); this.digiwfEmailApi.sendMailWithDefaultLogo(mail); } catch (final MessagingException error) { @@ -101,22 +96,51 @@ public Incident handleIncident(final IncidentContext context, final String messa return incidentEntity; } - private String getProcessName(String processDefinitionId){ + /** + * Retrieves the email content for the incident notification email. This includes the process name, a link to the incident in the Camunda Cockpit, and a + * predefined email template. + * + * @param incidentEntity The IncidentEntity representing the incident. + * @param processName The name of the process associated with the incident. + * @return A Map containing the email content key-value pairs. + */ + @NotNull + private Map getEMailContent(final IncidentEntity incidentEntity, final String processName) { + val link = incidentNotificationProperties.getCockpitUrl() + + "camunda/app/cockpit/default/#/process-instance/" + + incidentEntity.getProcessInstanceId() + + "/runtime"; + final String emailText = processName.isBlank() ? + "In der Anwendung ist ein Incident aufgetreten." : + "In der Anwendung ist ein Incident aufgetreten (Prozessname: " + processName + ")."; + + return Map.of( + "%%body_top%%", emailText, + "%%body_bottom%%", "Mit freundlichen Grüßen
Ihr DigiWF-Team", + "%%button_link%%", link, + "%%button_text%%", "Fehler im Cockpit anzeigen", + "%%footer%%", "DigiWF 2.0
IT-Referat der Stadt München" + ); + } + + private String getProcessName(String processDefinitionId) { String processName = ""; try { ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult(); - if(procDef.getName() != null && !procDef.getName().isBlank()) { + if (procDef.getName() != null && !procDef.getName().isBlank()) { processName = procDef.getName(); - } - else { - if(procDef.getKey() != null && !procDef.getKey().isBlank()){ + } else { + if (procDef.getKey() != null && !procDef.getKey().isBlank()) { processName = procDef.getKey(); } } - } - catch (Exception ex){ + } catch (Exception ex) { log.warn("Reading ProcessDefinition failed: {}", ex.getMessage()); } return processName; } + + IncidentEntity superHandleIncident(final IncidentContext context, final String message) { + return (IncidentEntity) super.handleIncident(context, message); + } } diff --git a/digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/process/config/domain/model/ProcessConfig.java b/digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/process/config/domain/model/ProcessConfig.java index 18b5bd5005..1ab9769caf 100644 --- a/digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/process/config/domain/model/ProcessConfig.java +++ b/digiwf-engine/digiwf-engine-service/src/main/java/de/muenchen/oss/digiwf/process/config/domain/model/ProcessConfig.java @@ -24,11 +24,19 @@ @NoArgsConstructor public class ProcessConfig { - public static final String INSTANCE_FILE_PATHS_READONLY = "app_instance_file_paths_readonly"; public static final String INSTANCE_FILE_PATHS = "app_instance_file_paths"; public static final String INSTANCE_SCHEMA_KEY = "app_instance_schema_key"; + /** + * This constant holds the configuration key for email addresses that should be notified in case of an incident. + * These addresses are used to send out alerts or notifications when an incident occurs within the application. + *

+ * The expected format for the email addresses is a comma-separated list of valid email addresses. + * Example: "admin@example.com,support@example.com" + */ + public static final String INCIDENT_NOTIFICATION_ADDRESSES = "app_incident_notification_addresses"; + /** * key of the process config. */ @@ -91,4 +99,8 @@ public String getInstanceSchemaKey() { return this.getConfig(INSTANCE_SCHEMA_KEY); } + public String getIncidentNotificationAddresses() { + return this.getConfig(INCIDENT_NOTIFICATION_ADDRESSES); + } + } diff --git a/digiwf-engine/digiwf-engine-service/src/main/resources/application.yml b/digiwf-engine/digiwf-engine-service/src/main/resources/application.yml index f7b7c6a835..4cba8bd227 100644 --- a/digiwf-engine/digiwf-engine-service/src/main/resources/application.yml +++ b/digiwf-engine/digiwf-engine-service/src/main/resources/application.yml @@ -161,10 +161,10 @@ digiwf: autodeployBausteine: true whitelist: '^[\w\s\?\!\#\: \.§\%\/\(\);:,@\u20AC\-\''\u00C0-\u017F]*$' incident: - cockpiturl: ${COCKPIT_URL} + cockpit-url: ${COCKPIT_URL} environment: ${DIGIWF_ENV} - fromaddress: itm.digiwf@muenchen.de - toaddress: itm.digiwf@muenchen.de + from-address: noreply@muenchen.de + to-address: itm.digiwf@muenchen.de jsonschema: autodeploy: true mail: diff --git a/digiwf-engine/digiwf-engine-service/src/main/resources/prozesse/archive/Test/TestIncident.processconfig.json b/digiwf-engine/digiwf-engine-service/src/main/resources/prozesse/archive/Test/TestIncident.processconfig.json new file mode 100644 index 0000000000..363f26f28b --- /dev/null +++ b/digiwf-engine/digiwf-engine-service/src/main/resources/prozesse/archive/Test/TestIncident.processconfig.json @@ -0,0 +1,42 @@ +{ + "key": "TestProcessIncident", + "statusConfig": [ + { + "key": "Offen", + "label": "Offen", + "position": 1 + }, + { + "key": "inBear", + "label": "In Bearbeitung", + "position": 2 + }, + { + "key": "abgeschlossen", + "label": "Abgeschlossen", + "position": 3 + } + ], + "configs": [ + { + "key": "app_file_paths_readonly", + "value": "Documents/test4;Documents/test5;Documents/test6" + }, + { + "key": "app_file_paths", + "value": "Documents/test1;Documents/test2;Documents/test3" + }, + { + "key": "app_instance_file_paths", + "value": "Documents" + }, + { + "key": "app_instance_schema_key", + "value": "TestIncident_Start_V01" + }, + { + "key": "app_incident_notification_addresses", + "value": "itm.digiwf@muenchen.de" + } + ] +} \ No newline at end of file diff --git a/digiwf-engine/digiwf-engine-service/src/test/java/de/muenchen/oss/digiwf/engine/incidents/IncidentNotifierHandlerTest.java b/digiwf-engine/digiwf-engine-service/src/test/java/de/muenchen/oss/digiwf/engine/incidents/IncidentNotifierHandlerTest.java new file mode 100644 index 0000000000..9ba0b9f651 --- /dev/null +++ b/digiwf-engine/digiwf-engine-service/src/test/java/de/muenchen/oss/digiwf/engine/incidents/IncidentNotifierHandlerTest.java @@ -0,0 +1,121 @@ +package de.muenchen.oss.digiwf.engine.incidents; + +import de.muenchen.oss.digiwf.email.api.DigiwfEmailApi; +import de.muenchen.oss.digiwf.email.model.Mail; +import de.muenchen.oss.digiwf.process.config.domain.mapper.ProcessConfigMapper; +import de.muenchen.oss.digiwf.process.config.domain.model.ProcessConfig; +import de.muenchen.oss.digiwf.process.config.domain.service.ProcessConfigService; +import de.muenchen.oss.digiwf.process.config.infrastructure.entity.ProcessConfigEntity; +import jakarta.mail.MessagingException; +import org.camunda.bpm.engine.RepositoryService; +import org.camunda.bpm.engine.RuntimeService; +import org.camunda.bpm.engine.impl.incident.IncidentContext; +import org.camunda.bpm.engine.impl.persistence.entity.IncidentEntity; +import org.camunda.bpm.engine.repository.ProcessDefinition; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.*; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class IncidentNotifierHandlerTest { + + private static final String CONFIG_KEY = "TestProcessConfig"; + + @Mock + private DigiwfEmailApi digiwfEmailApi; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private RuntimeService runtimeService; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private RepositoryService repositoryService; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private ProcessConfigService processConfigService; + + @Mock + private IncidentNotificationProperties incidentNotificationProperties; + + @Captor + private ArgumentCaptor incidentEntityCaptor; + + @InjectMocks + @Spy() + private IncidentNotifierHandlerMock incidentNotifierHandler; + + /** + * Tests incident notifications for configured email addresses. + * + * @throws IOException In case there is an issue with reading a file on the file system. + * @throws MessagingException In case there is an issue with sending an e-mail to the notification receivers. + */ + @Test + void testIncidentNotifications() throws IOException, MessagingException { + + // Setup + final IncidentContext incidentContext = mock(IncidentContext.class); + final IncidentEntity incidentEntity = mock(IncidentEntity.class); + when(incidentEntity.getProcessInstanceId()).thenReturn(""); + when(runtimeService + .createProcessInstanceQuery() + .processInstanceId(anyString()) + .singleResult() + .getRootProcessInstanceId()) + .thenReturn("rootProcessInstanceId"); + when(runtimeService + .createProcessInstanceQuery() + .processInstanceId(anyString()) + .singleResult() + .getProcessDefinitionId()) + .thenReturn(CONFIG_KEY + ":v42:12345"); + ProcessConfig.builder() + .key("processDefinitionId"); + final String configContent = Files.readString(Paths.get("src/test/resources/dummy/Test.processconfig.json")); + final ProcessConfigEntity processConfigEntity = ProcessConfigEntity.builder() + .version("v1") + .key(CONFIG_KEY) + .config(configContent) + .build(); + final ProcessConfig processConfig = new ProcessConfigMapper().map(processConfigEntity); + when(processConfigService.getProcessConfig(anyString())).thenReturn(Optional.of(processConfig)); + when(incidentNotifierHandler.superHandleIncident(any(), anyString())).thenReturn(incidentEntity); + when(incidentNotificationProperties.getCockpitUrl()).thenReturn("cockpiturl"); + when(incidentNotificationProperties.getEnvironment()).thenReturn("environment"); + when(incidentNotificationProperties.getFromAddress()).thenReturn("from@address.org"); + ProcessDefinition processDefinitionMock = Mockito.mock(ProcessDefinition.class); + when(repositoryService.createProcessDefinitionQuery().processDefinitionId(anyString()).singleResult()).thenReturn(processDefinitionMock); + + // Execute + incidentNotifierHandler.handleIncident(incidentContext, "Incident message"); + + // Assert that an email was sent with the correct receivers. + verify(digiwfEmailApi, times(1)).sendMailWithDefaultLogo(incidentEntityCaptor.capture()); + final Mail mail = incidentEntityCaptor.getValue(); + assertThat(mail.getReceivers()).isEqualTo(processConfig.getIncidentNotificationAddresses()); + } + + private static class IncidentNotifierHandlerMock extends IncidentNotifierHandler { + + public IncidentNotifierHandlerMock(RepositoryService repositoryService, RuntimeService runtimeService, DigiwfEmailApi digiwfEmailApi, + ProcessConfigService processConfigService, IncidentNotificationProperties incidentNotificationProperties) { + super(repositoryService, runtimeService, digiwfEmailApi, processConfigService, incidentNotificationProperties); + } + + // Workaround: If a static method is in the chain, Mockito will not mock method calls of superclasses. + @Override + IncidentEntity superHandleIncident(final IncidentContext context, final String message) { + return null; + } + } +} + diff --git a/digiwf-engine/digiwf-engine-service/src/test/resources/dummy/Test.processconfig.json b/digiwf-engine/digiwf-engine-service/src/test/resources/dummy/Test.processconfig.json new file mode 100644 index 0000000000..6e8ddde9f5 --- /dev/null +++ b/digiwf-engine/digiwf-engine-service/src/test/resources/dummy/Test.processconfig.json @@ -0,0 +1,42 @@ +{ + "key": "TestProcessConfig", + "statusConfig": [ + { + "key": "Offen", + "label": "Offen", + "position": 1 + }, + { + "key": "inBear", + "label": "In Bearbeitung", + "position": 2 + }, + { + "key": "abgeschlossen", + "label": "Abgeschlossen", + "position": 3 + } + ], + "configs": [ + { + "key": "app_file_paths_readonly", + "value": "Documents42/test42" + }, + { + "key": "app_file_paths", + "value": "Documents42/test42" + }, + { + "key": "app_instance_file_paths", + "value": "Documents42" + }, + { + "key": "app_instance_schema_key", + "value": "TestIncident_Start_V01" + }, + { + "key": "app_incident_notification_addresses", + "value": "itm.digiwf@muenchen.de" + } + ] +} \ No newline at end of file diff --git a/digiwf-integrations/digiwf-email-integration/digiwf-email-integration-service/src/main/resources/application.yml b/digiwf-integrations/digiwf-email-integration/digiwf-email-integration-service/src/main/resources/application.yml index 4f8a53be17..3484b3d67a 100644 --- a/digiwf-integrations/digiwf-email-integration/digiwf-email-integration-service/src/main/resources/application.yml +++ b/digiwf-integrations/digiwf-email-integration/digiwf-email-integration-service/src/main/resources/application.yml @@ -45,7 +45,7 @@ io: muenchendigital: digiwf: mail: - fromAddress: ${MAIL_USERNAME:digiwf@muenchen.de} + fromAddress: ${MAIL_USERNAME:itm.digiwf@muenchen.de} metrics: totalMailCounterName: "digiwf.email.integration.send_mail.total" failureCounterName: "digiwf.email.integration.send_mail.failure" diff --git a/docs/src/documentation/architecture/system-integration.md b/docs/src/documentation/architecture/system-integration.md index b350630748..33e41c4f43 100644 --- a/docs/src/documentation/architecture/system-integration.md +++ b/docs/src/documentation/architecture/system-integration.md @@ -56,8 +56,6 @@ im `digiwf-s3-integration-client-starter` enthalten, sodass im Idealfall nichts Mail-Server anzubinden. Man erstellt lediglich ein Spring-Boot-Projekt (z. B. über [^3]), bindet die Starter ein und kann mit der richtigen Konfiguration sofort arbeiten. -[^1]: -Siehe [https://docs.camunda.io/docs/components/modeler/desktop-modeler/element-templates/about-templates/](https://docs.camunda.io/docs/components/modeler/desktop-modeler/element-templates/about-templates/) -[^2]: -Siehe [https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using.build-systems.starters](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using.build-systems.starters) +[^1]: Siehe [https://docs.camunda.io/docs/components/modeler/desktop-modeler/element-templates/about-templates/](https://docs.camunda.io/docs/components/modeler/desktop-modeler/element-templates/about-templates/) +[^2]: Siehe [https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using.build-systems.starters](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using.build-systems.starters) [^3]: Siehe [https://start.spring.io/](https://start.spring.io/) \ No newline at end of file diff --git a/docs/src/modeling/processes/config/README.md b/docs/src/modeling/processes/config/README.md index 82737192e6..8a21c56e2a 100644 --- a/docs/src/modeling/processes/config/README.md +++ b/docs/src/modeling/processes/config/README.md @@ -59,6 +59,10 @@ wie Notepad++ oder Visual Studio Code zurückzugreifen. "key": "app_file_paths", "value": "writabledocs" } + { + "key": "app_incident_notification_addresses", + "value": "myFirstNotificationAddress@muenchen.de, mySecondNotificationAddress@muenchen.de" + } ] } @@ -93,4 +97,6 @@ In den configs können zudem DigiWF-spezifische Einstellungen angegeben werden: - **app_instance_file_paths_readonly:** Die Dateipfade, die in der Prozessinstanzübersicht (Meine Vorgänge) gelesen werden können. - **app_instance_file_paths:** Die Dateipfade, auf die in der Prozessinstanzübersicht (Meine Vorgänge) geschrieben - werden kann. \ No newline at end of file + werden kann. +- **app_incident_notification_addresses:** Eine Liste von E-Mail-Adressen, die im Falle eines Incidents benachrichtigt + werden sollen. \ No newline at end of file diff --git a/stack/local-docker.env b/stack/local-docker.env index 9f79e73efd..fce135f3fa 100644 --- a/stack/local-docker.env +++ b/stack/local-docker.env @@ -8,6 +8,7 @@ ENGINE_SERVER_PORT=39146 ENGINE_REST_SERVER_PORT=8089 TASKSERVICE_SERVER_PORT=37568 GATEWAY_SERVER_PORT=8083 +COCKPIT_URL=${DIGIWF_FRONTEND_URL}/ S3_INTEGRATION_SERVER_PORT=8086 MUCS_DMS_INTEGRATION_SERVER_PORT=8087