Compare commits

..

No commits in common. "master" and "dynamixs-ai-1.0.1" have entirely different histories.

214 changed files with 82125 additions and 12617 deletions

6
.env
View file

@ -1,6 +0,0 @@
# Docker Config
PROJECT_PREFIX=dynamixs-ai-super-office
# LLM Config
LLM_API_ENDPOINT=https://api.llama.cpp.imixs.com/
LLM_API_KEY=7fdb663fa87ea16731c1e0ece8ad3214e358423eabf2403188110c731ce07321

View file

@ -1,7 +1,13 @@
FROM ghcr.io/dynamixs-ai/ai-platform:latest
#FROM imixs/imixs-office-workflow:5.1.5-wildfly-29.0.1.Final-jdk17
FROM imixs/imixs-office-workflow:5.1.6-SNAPSHOT-wildfly-29.0.1.Final-jdk17
# Debug
# Setup configuration
#COPY ./docker/configuration/wildfly/standalone-debug.xml /opt/jboss/wildfly/standalone/configuration/
# Deploy artefact
RUN rm -r /opt/jboss/wildfly/standalone/deployments/*
# Deploy artefact
COPY ./target/*.war /opt/jboss/wildfly/standalone/deployments/
ADD ./dynamixs-ai-app/target/dynamixs-ai*.war /opt/jboss/wildfly/standalone/deployments/

View file

@ -1,5 +1,5 @@
FROM ghcr.io/dynamixs-ai/ai-platform:latest
#FROM imixs/imixs-office-workflow:5.1.5-wildfly-29.0.1.Final-jdk17
FROM imixs/imixs-office-workflow:5.1.6-SNAPSHOT-wildfly-29.0.1.Final-jdk17
# Deploy artefact
RUN rm -r /opt/jboss/wildfly/standalone/deployments/*
COPY ./target/*.war /opt/jboss/wildfly/standalone/deployments/

View file

@ -1,9 +1,5 @@
# Dynamixs AI
Dies ist das interne Super Office von Dynamixs.ai
Wir verwenden OIDC / Keyclaok für die Anmeldung
This repository contains the source code as also build scripts to setup an Dynamixs AI instance.
**Topics**

View file

@ -0,0 +1,130 @@
/****************************************************************************
* Copyright (c) 2022-2025 Imixs Software Solutions GmbH and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* This Source Code may also be made available under the terms of the
* GNU General Public License, version 2 or later (GPL-2.0-or-later),
* which is available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
****************************************************************************/
package ai.dynamixs.cognition;
import static org.imixs.workflow.engine.AsyncEventSchedulerConfig.ASYNCEVENT_PROCESSOR_DEADLOCK;
import static org.imixs.workflow.engine.AsyncEventSchedulerConfig.ASYNCEVENT_PROCESSOR_ENABLED;
import static org.imixs.workflow.engine.AsyncEventSchedulerConfig.ASYNCEVENT_PROCESSOR_INITIALDELAY;
import static org.imixs.workflow.engine.AsyncEventSchedulerConfig.ASYNCEVENT_PROCESSOR_INTERVAL;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.imixs.workflow.engine.AsyncEventService;
import org.imixs.workflow.engine.EventLogService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import jakarta.annotation.security.DeclareRoles;
import jakarta.annotation.security.RunAs;
import jakarta.ejb.Singleton;
import jakarta.ejb.Startup;
import jakarta.ejb.Timeout;
import jakarta.ejb.Timer;
import jakarta.ejb.TimerConfig;
import jakarta.ejb.TimerService;
import jakarta.inject.Inject;
/**
* The CognitoEventScheduler starts a scheduler service to process cognition
* events in an asynchronous way by calling the CognitoEventService.
* <p>
* The Scheduler runs on a non-persistent ejb timer with the same interval
* settings as the AsyncEventProcessor
* <p>
* Configuration is read from the environment variables
* 'ASYNCEVENT_PROCESSOR_INTERVAL' and an optional delay defined by
* 'ASYNCEVENT_PROCESSOR_INITIALDELAY'. To enable the processor
* 'ASYNCEVENT_PROCESSOR_ENABLED' must be set to true (default=false).
* 'ASYNCEVENT_PROCESSOR_DEADLOCK' deadlock timeout
* <p>
* In a clustered environment this timer runs in each cluster member that
* contains the EJB. So this means the non-persistent EJB Timer scales
* horizontal within a clustered environment – e.g. a Kubernetes cluster.
*
* @see AsyncEventService
* @version 1.1
* @author rsoika
*
*/
@DeclareRoles({ "org.imixs.ACCESSLEVEL.MANAGERACCESS" })
@RunAs("org.imixs.ACCESSLEVEL.MANAGERACCESS")
@Startup
@Singleton
public class CognitoEventScheduler {
// enabled
@Inject
@ConfigProperty(name = ASYNCEVENT_PROCESSOR_ENABLED, defaultValue = "false")
boolean enabled;
// timeout interval in ms
@Inject
@ConfigProperty(name = ASYNCEVENT_PROCESSOR_INTERVAL, defaultValue = "1000")
long interval;
// initial delay in ms
@Inject
@ConfigProperty(name = ASYNCEVENT_PROCESSOR_INITIALDELAY, defaultValue = "0")
long initialDelay;
// deadlock timeout interval in ms
@Inject
@ConfigProperty(name = ASYNCEVENT_PROCESSOR_DEADLOCK, defaultValue = "60000")
long deadLockInterval;
private static final Logger logger = Logger.getLogger(CognitoEventScheduler.class.getName());
@Resource
TimerService timerService;
@Inject
CognitoEventService cognitoEventService;
@Inject
EventLogService eventLogService;
@PostConstruct
public void init() {
if (enabled) {
// Registering a non-persistent Timer Service.
final TimerConfig timerConfig = new TimerConfig();
timerConfig.setInfo("Dynamixs AI CognitoEventScheduler");
timerConfig.setPersistent(false);
timerService.createIntervalTimer(initialDelay, interval, timerConfig);
logger.log(Level.INFO, "├── ✅ Started CognitoEventScheduler - initalDelay={0} inverval={1}",
new Object[] { initialDelay, interval });
}
}
/**
* The method delegates the event processing to the stateless ejb
* AsyncEventProcessor.
* <p>
* Before processing the eventLog the method releases possible dead locks first.
* Both methods are running in separate transactions
*
*/
@Timeout
public void run(Timer timer) {
eventLogService.releaseDeadLocks(deadLockInterval,
CognitoEventService.EVENTLOG_TOPIC_COGNITO_PROMPT,
CognitoEventService.EVENTLOG_TOPIC_COGNITO_CACHE);
cognitoEventService.processEventLog();
}
}

View file

@ -0,0 +1,243 @@
/****************************************************************************
* Copyright (c) 2022-2025 Imixs Software Solutions GmbH and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* This Source Code may also be made available under the terms of the
* GNU General Public License, version 2 or later (GPL-2.0-or-later),
* which is available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
****************************************************************************/
package ai.dynamixs.cognition;
import java.util.List;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.imixs.ai.ImixsAIContextHandler;
import org.imixs.ai.workflow.OpenAIAPIConnector;
import org.imixs.ai.workflow.OpenAIAPIService;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.AsyncEventScheduler;
import org.imixs.workflow.engine.EventLogService;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.engine.jpa.EventLog;
import org.imixs.workflow.exceptions.AdapterException;
import org.imixs.workflow.exceptions.PluginException;
import jakarta.annotation.security.DeclareRoles;
import jakarta.annotation.security.RunAs;
import jakarta.ejb.LocalBean;
import jakarta.ejb.Stateless;
import jakarta.ejb.TransactionAttribute;
import jakarta.ejb.TransactionAttributeType;
import jakarta.inject.Inject;
import jakarta.persistence.OptimisticLockException;
/**
* The CognitoEventService is responsible to process Dynamixs-AI Cognito events
* in an asynchronous batch process. The CognitoEventService automatically
* lookup eventLog entries of the topic "rag.event.*". The RAGEventService is
* called only by the RAGEventScheduler which is implementing a
* ManagedScheduledExecutorService.
* <p>
* The CognitoEventService reacts on events from the following types:
* <ul>
* <li>cognito.event.prompt - resoles the llm prompt based on the given workitem
* and creates a cache event</li>
* <li>cognito.event.cache - indicates that this entry is still cached in the
* event log database</li>
* </ul>
* The processor look up the workItem by the $uniqueId.
* <p>
* To prevent concurrent processes to handle the same workitems the batch
* process uses a Optimistic lock strategy. After fetching new event log entries
* the processor updates the eventLog entry in a new transaction and set the
* topic to 'batch.process.lock'. After that update we can be sure that no other
* process is dealing with these entries. After completing the processing step
* the eventlog entry will be removed.
* <p>
* To avoid ad deadlock the processor set an expiration time on the lock, so the
* lock will be auto-released after 1 minute (batch.processor.deadlock).
*
* @see AsyncEventScheduler
* @version 1.0
* @author rsoika
*
*/
@DeclareRoles({ "org.imixs.ACCESSLEVEL.MANAGERACCESS" })
@RunAs("org.imixs.ACCESSLEVEL.MANAGERACCESS")
@Stateless
@LocalBean
public class CognitoEventService {
public static final String EVENTLOG_TOPIC_COGNITO_PROMPT = "cognito.event.prompt";
public static final String EVENTLOG_TOPIC_COGNITO_CACHE = "cognito.event.cache";
public static final String ITEM_PROMPT_DEFINITION = "prompt.definition";
private static final Logger logger = Logger.getLogger(CognitoEventService.class.getName());
@Inject
EventLogService eventLogService;
@Inject
private WorkflowService workflowService;
@Inject
private OpenAIAPIService llmService;
@Inject
ImixsAIContextHandler imixsAIContextHandler;
@Inject
CognitoLockHandler cognitoLockHandler;
@Inject
@ConfigProperty(name = OpenAIAPIConnector.ENV_LLM_SERVICE_ENDPOINT)
Optional<String> serviceEndpoint;
/**
* The method lookups for cognito prompt event log entries and updates the ....
* information
* <p>
* Each eventLogEntry provides optional a prompt template
*
*/
@TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
public void processEventLog() {
long l = System.currentTimeMillis();
// test for new event log entries by timeout...
List<EventLog> events = eventLogService.findEventsByTimeout(100,
CognitoEventService.EVENTLOG_TOPIC_COGNITO_PROMPT, CognitoEventService.EVENTLOG_TOPIC_COGNITO_CACHE);
if (events.size() > 0) {
logger.log(Level.INFO, "├── 🔃 processing {0} Cognito events....", events.size());
// do we know the endpoint?
if (!serviceEndpoint.isPresent()) {
logger.log(Level.WARNING,
"├── ⚠️ Missing environment var 'llm.service.endpoint' - can not process cognito events!");
return;
}
for (EventLog eventLogEntry : events) {
try {
boolean llmAPIDebug = true;
logger.log(Level.INFO,
"│ ├── Event: " + eventLogEntry.getTopic() + " - " + eventLogEntry.getRef());
// first try to lock the eventLog entry....
if (eventLogService.lock(eventLogEntry)) {
// Index / Update event?
ItemCollection workitem = workflowService.getWorkItem(eventLogEntry.getRef());
if (workitem == null) {
logger.log(Level.WARNING, "│ ├── ⚠️ unable to read workitem: " + eventLogEntry.getRef());
eventLogService.removeEvent(eventLogEntry.getId());
continue;
}
ItemCollection promptItemCol = new ItemCollection(eventLogEntry.getData());
switch (eventLogEntry.getTopic()) {
case CognitoEventService.EVENTLOG_TOPIC_COGNITO_PROMPT + ".lock":
// load the promptDefinition from the event data object
String promptTemplate = promptItemCol.getItemValueString(ITEM_PROMPT_DEFINITION);
imixsAIContextHandler.setWorkItem(workitem);
imixsAIContextHandler.addPromptDefinition(promptTemplate);
String llmPrompt = imixsAIContextHandler.toString();
// if we have a prompt we call the llm api endpoint
if (llmPrompt != null && !llmPrompt.isBlank()) {
String llmAPIEndpoint = serviceEndpoint.get();
// postPromptCompletion
// JsonObject jsonPrompt =
// llmService.buildJsonPromptObjectV1(imixsAIContextHandler);
String completionResult = llmService.postPromptCompletion(imixsAIContextHandler,
llmAPIEndpoint);
// process the ai.result....
if (llmAPIDebug) {
logger.info("===> Completion Result: ");
logger.info(completionResult);
}
String resultMessage = llmService.processPromptResult(completionResult, "", workitem);
// if the workitem is not locked we can safety update the $workflowabstarct
if (!cognitoLockHandler.isLocked(workitem.getUniqueID())) {
logger.log(Level.INFO,
"│ ├── ✓ workitem not locked - updating $workflowabstract...");
workitem.setItemValue("$workflowabstract", resultMessage);
workflowService.getDocumentService().save(workitem);
} else {
// workitem is still in edit mode - so we create a cache event that just stores
// the result. This is an async caching mechanism for the front end.
logger.log(Level.INFO,
"│ ├── ⚐ workitem locked - create COGNITO_CACHE event...");
promptItemCol.setItemValue("$workflowabstract", resultMessage);
// create a new event
eventLogService.createEvent(CognitoEventService.EVENTLOG_TOPIC_COGNITO_CACHE,
workitem.getUniqueID(),
promptItemCol);
}
} else {
logger.finest(
"......no prompt definition found for " + workitem.getUniqueID());
}
// finally remove the event log entry...
eventLogService.removeEvent(eventLogEntry.getId());
break;
case CognitoEventService.EVENTLOG_TOPIC_COGNITO_CACHE + ".lock":
logger.log(Level.INFO,
"│ ├── process COGNITO_CACHE event...");
if (!cognitoLockHandler.isLocked(workitem.getUniqueID())) {
logger.log(Level.INFO,
"│ ├── ✓ workitem not locked - updating $workflowabstract...");
// ItemCollection promptItemCol = new ItemCollection(eventLogEntry.getData());
String resultMessage = promptItemCol.getItemValueString("$workflowabstract");
workitem.setItemValue("$workflowabstract", resultMessage);
workflowService.getDocumentService().save(workitem);
// finally remove the event log entry...
eventLogService.removeEvent(eventLogEntry.getId());
} else {
// repeat event until workitem is unlocked
eventLogService.unlock((eventLogEntry));
}
break;
default:
// no op
}
}
} catch (OptimisticLockException e) {
// lock was not possible - continue....
logger.log(Level.INFO, "│ ├── ⚠️ unable to lock AsyncEvent: {0}", e.getMessage());
} catch (PluginException | AdapterException e) {
logger.log(Level.WARNING, e.getErrorCode() + " - " + e.getMessage());
// remove the event log entry...
eventLogService.removeEvent(eventLogEntry.getId());
}
}
logger.log(Level.INFO, "├── ✅ {0} CognitoEvents processed in {1}ms",
new Object[] { events.size(), System.currentTimeMillis() - l });
}
}
}

View file

@ -0,0 +1,274 @@
/****************************************************************************
* Copyright (c) 2022-2025 Imixs Software Solutions GmbH and others.
* https://www.imixs.com
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* This Source Code may also be made available under the terms of the
* GNU General Public License, version 2 or later (GPL-2.0-or-later),
* which is available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
****************************************************************************/
package ai.dynamixs.cognition;
import java.time.Instant;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.faces.data.WorkflowEvent;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.interceptor.Interceptor;
/**
* The CognitoLockHandler is an application scoped CDI bean that holds a list of
* workitem uniqueIds currently in edit mode. This caching mechanism is used by
* the {@code CognitoEventService} to avoid optimistic lock exceptions.
* <p>
* The IDs are stored in the lock cache. The CognitoEventService looks up an ID
* in this cache before updating a workitem in a safe way.
* <p>
* It may happen that a user switches into edit mode
* ({@link WorkflowEvent#DOCUMENT_CHANGED}) without updating the workitem. For
* this reason a locked ID will be released after {@value #LOCK_TIMEOUT_SECONDS}
* seconds automatically.
* <p>
* <strong>Thread Safety:</strong> This implementation uses a
* {@link ConcurrentHashMap} to ensure thread-safe operations in a
* multi-user-environment where the same workitem can be opened by different
* users in parallel.
*
* @author rsoika
* @version 1.0
*/
@ApplicationScoped
public class CognitoLockHandler {
private static final Logger logger = Logger.getLogger(CognitoLockHandler.class.getName());
/**
* Lock timeout in seconds. After this duration, a lock is considered stale and
* will be automatically released.
*/
public static final long LOCK_TIMEOUT_SECONDS = 120;
/**
* Thread-safe cache storing workitem uniqueIds mapped to their lock timestamp.
* The timestamp is used to determine if a lock has expired.
*/
private final Map<String, Instant> lockCache = new ConcurrentHashMap<>();
/**
* WorkflowEvent listener that manages the lock cache based on document
* lifecycle events.
* <p>
* <ul>
* <li>{@link WorkflowEvent#DOCUMENT_CHANGED}: Adds the workitem's uniqueID to
* the lock cache (lock operation)</li>
* <li>{@link WorkflowEvent#DOCUMENT_AFTER_SAVE}: Removes the workitem's
* uniqueID from the lock cache (unlock operation)</li>
* </ul>
* <p>
* This observer is executed with {@link Interceptor.Priority#LIBRARY_BEFORE}
* priority to ensure it runs before other observers.
*
* @param workflowEvent the workflow event containing the workitem and event
* type
* @throws PluginException if an error occurs during event processing
*/
public void onWorkflowEvent(@Observes WorkflowEvent workflowEvent)
throws PluginException {
int eventType = workflowEvent.getEventType();
String uniqueId = extractUniqueId(workflowEvent);
if (uniqueId == null || uniqueId.isEmpty()) {
logger.log(Level.FINE, "Skipping lock operation - workitem has no uniqueId");
return;
}
// Lock the workitem when user enters edit mode
if (WorkflowEvent.WORKITEM_CHANGED == eventType) {
lock(uniqueId);
logger.log(Level.INFO, "Workitem locked: uniqueId={0}, active locks={1}",
new Object[] { uniqueId, lockCache.size() });
}
// Unlock the workitem after successful save
if (WorkflowEvent.WORKITEM_AFTER_PROCESS == eventType) {
boolean wasLocked = unlock(uniqueId);
if (wasLocked) {
logger.log(Level.INFO, "Workitem unlocked after process: uniqueId={0}, remaining locks={1}",
new Object[] { uniqueId, lockCache.size() });
} else {
logger.log(Level.INFO, "Workitem was not locked (possibly expired): uniqueId={0}",
uniqueId);
}
}
}
/**
* Checks if the given workitem uniqueID is currently locked (in edit mode).
* <p>
* This method also performs cleanup of stale locks. If the lock for the given
* ID has exceeded the timeout ({@value #LOCK_TIMEOUT_SECONDS} seconds), it will
* be automatically removed and this method returns {@code false}.
*
* @param id the unique identifier of the workitem to check
* @return {@code true} if the workitem is currently locked and the lock has not
* expired, {@code false} otherwise
*/
public boolean isLocked(String id) {
if (id == null || id.isEmpty()) {
logger.log(Level.FINE, "isLocked called with null or empty id - returning false");
return false;
}
Instant lockTimestamp = lockCache.get(id);
if (lockTimestamp == null) {
logger.log(Level.FINE, "Workitem not locked: uniqueId={0}", id);
return false;
}
// Check if lock has expired
if (isLockExpired(lockTimestamp)) {
logger.log(Level.INFO, "Lock expired and removed: uniqueId={0}, locked since={1}",
new Object[] { id, lockTimestamp });
lockCache.remove(id);
return false;
}
long lockedSeconds = java.time.Duration.between(lockTimestamp, Instant.now()).getSeconds();
logger.log(Level.FINE, "Workitem is locked: uniqueId={0}, locked for {1}s",
new Object[] { id, lockedSeconds });
return true;
}
/**
* Adds a workitem uniqueID to the lock cache with the current timestamp.
* <p>
* If the ID is already in the cache, the timestamp will be updated (lock
* refresh).
*
* @param id the unique identifier of the workitem to lock
*/
public void lock(String id) {
if (id == null || id.isEmpty()) {
logger.log(Level.WARNING, "Attempted to lock with null or empty id - operation ignored");
return;
}
Instant previousLock = lockCache.put(id, Instant.now());
if (previousLock != null) {
logger.log(Level.FINE, "Lock refreshed: uniqueId={0}, previous lock from={1}",
new Object[] { id, previousLock });
} else {
logger.log(Level.FINE, "New lock created: uniqueId={0}", id);
}
// Opportunistic cleanup of expired locks
cleanupExpiredLocks();
}
/**
* Removes a workitem uniqueID from the lock cache.
*
* @param id the unique identifier of the workitem to unlock
* @return {@code true} if the workitem was locked and is now unlocked,
* {@code false} if the workitem was not locked
*/
public boolean unlock(String id) {
if (id == null || id.isEmpty()) {
logger.log(Level.WARNING, "Attempted to unlock with null or empty id - operation ignored");
return false;
}
Instant removed = lockCache.remove(id);
if (removed != null) {
long lockedDuration = java.time.Duration.between(removed, Instant.now()).getSeconds();
logger.log(Level.FINE, "Lock removed: uniqueId={0}, was locked for {1}s",
new Object[] { id, lockedDuration });
return true;
}
return false;
}
/**
* Returns the current number of active locks in the cache.
* <p>
* <strong>Note:</strong> This count may include expired locks that have not yet
* been cleaned up.
*
* @return the number of entries in the lock cache
*/
public int getLockCount() {
return lockCache.size();
}
/**
* Removes all expired locks from the cache.
* <p>
* This method is called opportunistically during lock operations to prevent
* unbounded cache growth.
*/
public void cleanupExpiredLocks() {
int initialSize = lockCache.size();
lockCache.entrySet().removeIf(entry -> {
boolean expired = isLockExpired(entry.getValue());
if (expired) {
logger.log(Level.FINE, "Cleaning up expired lock: uniqueId={0}, locked since={1}",
new Object[] { entry.getKey(), entry.getValue() });
}
return expired;
});
int removed = initialSize - lockCache.size();
if (removed > 0) {
logger.log(Level.INFO, "Expired locks cleanup completed: removed={0}, remaining={1}",
new Object[] { removed, lockCache.size() });
}
}
/**
* Checks if a lock timestamp has exceeded the timeout threshold.
*
* @param lockTimestamp the timestamp when the lock was created
* @return {@code true} if the lock is expired, {@code false} otherwise
*/
private boolean isLockExpired(Instant lockTimestamp) {
return lockTimestamp.plusSeconds(LOCK_TIMEOUT_SECONDS).isBefore(Instant.now());
}
/**
* Extracts the uniqueId from the workitem contained in the workflow event.
*
* @param workflowEvent the workflow event
* @return the uniqueId of the workitem, or {@code null} if not available
*/
private String extractUniqueId(WorkflowEvent workflowEvent) {
if (workflowEvent == null || workflowEvent.getWorkitem() == null) {
logger.log(Level.WARNING, "WorkflowEvent or workitem is null - cannot extract uniqueId");
return null;
}
String uniqueId = workflowEvent.getWorkitem().getUniqueID();
if (uniqueId == null || uniqueId.isEmpty()) {
logger.log(Level.FINE, "Workitem has no uniqueId (possibly a new document)");
}
return uniqueId;
}
}

View file

@ -0,0 +1,139 @@
/****************************************************************************
* Copyright (c) 2022-2025 Imixs Software Solutions GmbH and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* This Source Code may also be made available under the terms of the
* GNU General Public License, version 2 or later (GPL-2.0-or-later),
* which is available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
****************************************************************************/
package ai.dynamixs.cognition;
import java.util.List;
import java.util.logging.Logger;
import org.imixs.ai.workflow.ImixsAIPromptService;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.EventLogService;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.exceptions.PluginException;
import ai.dynamixs.ChronicleTextBuilder;
import jakarta.inject.Inject;
/**
* The CognitoPlugin is a generic plugin to generate an cognito.create.event.
* This event is processed by the `CognitoEventService` to generate an AI based
* workflow abstract
* <p>
* The plugin can be activated by the following workflow result tag
*
* <pre>
{@code
<dynamixs-ai name="COGNITO" />
}
* </pre>
* <p>
* The embedded tag 'debug' is optional
*
* <p>
* The prompt definition is either loaded from the corresponding BPMN event
* (DataObject) or generated as generic default template in case that no
* PromptDefinition is assigned to the current event.
*
*
* @author rsoika
*
*/
public class CognitoPlugin extends org.imixs.ai.rag.workflow.RAGIndexPlugin {
private static final Logger logger = Logger.getLogger(CognitoPlugin.class.getName());
@Inject
private WorkflowService workflowService;
@Inject
private EventLogService eventLogService;
@Inject
private ImixsAIPromptService imixsAIPromptService;
@Override
public ItemCollection run(ItemCollection workitem, ItemCollection event) throws PluginException {
// do only run on type = workitem!
if (!workitem.getType().equals("workitem")) {
// no op!
return workitem;
}
// read optional configuration form the model or imixs.properties....
List<ItemCollection> cognitoAIDefinitions = workflowService.evalWorkflowResultXML(event, "dynamixs-ai",
"COGNITO", workitem, false);
// COGNITO Mode?
if (cognitoAIDefinitions != null && cognitoAIDefinitions.size() > 0) {
logger.info("├── running Dynamixs.AI Cognito Plugin");
// test if the event provides a Prompt template!
String promptTemplate = imixsAIPromptService.loadPromptTemplateByModelElement(event);
if (promptTemplate != null && !promptTemplate.isBlank()) {
logger.info("│ ├── loaded custom cognito prompt template from event");
} else {
promptTemplate = buildDefaultPromptTemplate(workitem);
logger.info("│ ├── created default cognito prompt template");
}
// we create a data object that holds the template
ItemCollection promptItemCol = new ItemCollection();
promptItemCol.setItemValue("category", "cognition");
promptItemCol.setItemValue(CognitoEventService.ITEM_PROMPT_DEFINITION, promptTemplate);
eventLogService.createEvent(CognitoEventService.EVENTLOG_TOPIC_COGNITO_PROMPT, workitem.getUniqueID(),
promptItemCol);
}
return workitem;
}
/**
* This method generates a generic prompt definition including a prompt template
* including the workflow chronicle data.
*
* @param workitem
* @return
*/
private String buildDefaultPromptTemplate(ItemCollection workitem) {
// generate default template
ChronicleTextBuilder chronicleTextBuilder = new ChronicleTextBuilder(workitem);
String promptTemplate = chronicleTextBuilder.build();
String result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + //
"<PromptDefinition>\n" + //
"\t<prompt_options>{\"n_predict\": 2048, \"temperature\": 0.2, \"top_p\": 0.9}</prompt_options>\n" + //
"\n" + //
" <prompt role=\"system\"><![CDATA[\n" + //
"You are a process analyst. A workflow has just been completed.\n" + //
"\n" + //
"Create a brief project insight:\n" + //
"- What specifically happened? (Include relevant names from people, companies, products when mentioned.)\n"
+ //
"- Is there anything unusual or important to remember for the future? (Pay attention to user comments - they often contain important warnings or decisions.)\n"
+ //
"\n" + //
"No general advice. Only project-specific facts and insights.]]>\n" + //
" </prompt>\n" + //
" <prompt role=\"user\"><![CDATA[\n" + promptTemplate + "]]>\n" + //
" </prompt>\n" + //
"\n" + //
"</PromptDefinition> ";
return result;
}
}

View file

@ -0,0 +1,175 @@
package ai.dynamixs;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.imixs.ai.ImixsAIContextHandler;
import org.imixs.ai.workflow.ImixsAIPromptService;
import org.imixs.ai.workflow.OpenAIAPIService;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.ConditionalExpressionEvent;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.exceptions.AdapterException;
import org.imixs.workflow.exceptions.PluginException;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.json.JsonObject;
import jakarta.transaction.TransactionScoped;
/**
* The ConditionalAIAdapter reacts on CDI Events of type BPMNConditionEvent and
* evaluates a condition against an LLM
* <p>
* The Adapter defines a Default Expression template for LLMs. The BPMN
* Configuration must only include the user prompt. See the following example:
* <p>
*
* <pre>
* {@code
<imixs-ai name="CONDITION">
<debug>true</debug>
<endpoint><propertyvalue>llm.service.endpoint</propertyvalue></endpoint>
<result-item>my.condition</result-item>
<prompt><![CDATA[
Is Germany an EU member country? ]]>
</prompt>
</imixs-ai>
* }
* </pre>
*
* Caching: The ConditionalAIAdapter implements a caching mechnaism. The adapter
* class stores the hash value in to the item <result-item>.hash to avoid
* duplicate calls against the llm with the same prompt in one processing cycle!
*/
@TransactionScoped
public class ConditionalAIAdapter implements Serializable {
private static final Logger logger = Logger.getLogger(ConditionalAIAdapter.class.getName());
// Transaction-scoped cache - survives across multiple eval() calls
private Map<Long, String> promptResultCache = new HashMap<>();
@Inject
protected WorkflowService workflowService;
@Inject
protected ImixsAIPromptService imixsAIPromptService;
@Inject
protected OpenAIAPIService llmService;
@Inject
ImixsAIContextHandler imixsAIContextHandler;
public static String DEFAULT_EXPRESSION_TEMPLATE = "<imixs-ai name=\"CONDITION\">\n" + //
" <debug>true</debug>\n" + //
" <endpoint><propertyvalue>llm.service.endpoint</propertyvalue></endpoint>\n" + //
" <result-event>BOOLEAN</result-event>\n" + //
" <PromptDefinition>\n" + //
" <prompt_options>{\"n_predict\": 16, \"temperature\": 0 }</prompt_options>\n" + //
" <prompt role=\"system\"><![CDATA[\n" + //
" Evaluate the following condition to 'true' or 'false'. Do only answer with 'true' or 'false'. Do not add any additional context into your answer.]]>\n"
+ //
" </prompt>\n" + //
" </PromptDefinition>\n" + //
"</imixs-ai>";
/**
* Test method
*
* @param conditionEvent
* @throws PluginException
* @throws AdapterException
*/
public void onConditionEvent(@Observes ConditionalExpressionEvent conditionalEvent)
throws PluginException, AdapterException {
// run only if we have a prompt definition
String condition = conditionalEvent.getCondition();
if (condition != null && condition.contains("<imixs-ai")) {
long l = System.currentTimeMillis();
List<ItemCollection> llmConditionDefinitions;
boolean llmAPIDebug = false;
condition = condition.trim();
llmConditionDefinitions = workflowService.evalXMLExpressionList(
conditionalEvent.getCondition(), "imixs-ai", "CONDITION", conditionalEvent.getWorkitem(), true);
for (ItemCollection promptDefinition : llmConditionDefinitions) {
String llmAPIEndpoint = imixsAIPromptService.parseLLMEndpointByBPMN(promptDefinition);
String userPrompt = promptDefinition.getItemValueString("prompt");
if ("true".equalsIgnoreCase(promptDefinition.getItemValueString("debug"))) {
llmAPIDebug = true;
}
if (llmAPIDebug) {
logger.info("├── evaluate conditional expression");
}
// set DEFAULT_EXPRESSION_TEMPLATE.
imixsAIContextHandler.setWorkItem(conditionalEvent.getWorkitem());
imixsAIContextHandler.addPromptDefinition(DEFAULT_EXPRESSION_TEMPLATE);
// add the user prompt!
imixsAIContextHandler.addMessage(ImixsAIContextHandler.ROLE_USER, userPrompt,
workflowService.getSessionContext().getCallerPrincipal().getName(), null);
// POST PromptCompletion
JsonObject jsonPrompt = imixsAIContextHandler.getOpenAIMessageObject();
if (llmAPIDebug) {
logger.info("│ ├── conditional prompt:");
logger.info(jsonPrompt.toString());
}
// Caching:
// if jsonPrompt (hash) was already stored, we do not call the LLM
long hashPrompt = jsonPrompt.hashCode();
// Check transaction-scoped cache
if (promptResultCache.containsKey(hashPrompt)) {
if (llmAPIDebug) {
logger.info("│ ├── reuse cached result from transaction cache - hash=" + hashPrompt);
logger.info("└── ✓ evaluation time: " + (System.currentTimeMillis() - l) + "ms");
}
conditionalEvent.setCondition(promptResultCache.get(hashPrompt));
return;
}
String completionResult = llmService.postPromptCompletion(imixsAIContextHandler, llmAPIEndpoint);
if (llmAPIDebug) {
logger.info("│ ├── ⚙ Completion Request conditional expression...");
}
String conditionalExpressionResult = llmService.processPromptResult(completionResult, "BOOLEAN",
conditionalEvent.getWorkitem());
// store the result message
if (conditionalExpressionResult != null && !conditionalExpressionResult.isBlank()) {
// trim result
conditionalExpressionResult = conditionalExpressionResult.trim().toLowerCase();
if (!"true".equals(conditionalExpressionResult) && !"false".equals(conditionalExpressionResult)) {
logger.warning(
"│ ├── ⚠ Unexpected conditional expression result: " + conditionalExpressionResult);
throw new PluginException(OpenAIAPIService.class.getSimpleName(),
OpenAIAPIService.ERROR_PROMPT_INFERENCE,
"Conditional expression should result into 'true' or 'false' only");
}
if (llmAPIDebug) {
logger.info("│ ├── ⚐ Conditional expression result: " + conditionalExpressionResult);
}
boolean booleanExpressionResult = Boolean.parseBoolean(conditionalExpressionResult.trim());
// Store in transaction-scoped cache
promptResultCache.put(hashPrompt, "" + booleanExpressionResult);
conditionalEvent.setCondition("" + booleanExpressionResult);
logger.info("└── ✓ evaluation time: " + (System.currentTimeMillis() - l) + "ms");
}
}
}
}
}

View file

@ -1,24 +0,0 @@
#!/bin/bash
############################################################
# The Dynamixs.AI Developer Script
# start, build, hot, setup, deploy
#
############################################################
strip_dash() {
echo "$1" | sed 's/^-//'
}
echo " _ _ _ _ "
echo " __| | _____ _(_) | |__ ___| |_ __"
echo " / _\` |/ _ \\ \\ / / | | '_ \\ / _ \\ | \'_ \\"
echo "| (_| | __/\ V /| | | | | | __/ | |_) |"
echo " \__,_|\___| \_/ |_| |_| |_|\___|_| .__/ "
echo " |_| "
echo " Dynamixs.AI Build Script..."
echo "_________________________________________"
# Update git
git pull
mvn clean install -DskipTests -Pimixs-cloud

29
devi
View file

@ -1,11 +1,12 @@
#!/bin/bash
############################################################
# The Dynamixs.AI Developer Script
# The Imixs Developer Script
# start, build, hot, setup, deploy
#
############################################################
# Funktion zum Entfernen des '-' Zeichens von einem Parameter
strip_dash() {
echo "$1" | sed 's/^-//'
}
@ -23,31 +24,23 @@ strip_dash() {
if [[ "$(strip_dash $1)" == "setup" ]]; then
echo " Dev Setup..."
sudo chmod -R 777 docker/deployments/
echo " starting dev environment..."
echo " starting dev enrvionment..."
mvn clean install -Pdebug
cp ./*-app/target/*.war ./docker/deployments/
docker compose -f ./docker-compose-dev.yaml up
docker compose -f ./docker/docker-compose-dev.yaml up
fi
if [[ "$(strip_dash $1)" == "start" ]]; then
echo " Start Dev Environment..."
docker compose -f ./docker-compose.yaml up
fi
if [[ "$(strip_dash $1)" == "dev" ]]; then
echo " Start Dev Environment..."
mvn clean install -DskipTests -Pdebug
docker compose -f ./docker-compose-dev.yaml up
docker compose -f ./docker/docker-compose-dev.yaml up
fi
if [[ "$(strip_dash $1)" == "docker" ]]; then
echo " Build Docker image..."
mvn clean install -DskipTests -Pdocker
echo " Buld Docker Image..."
mvn clean install -Pdocker
fi
if [[ "$(strip_dash $1)" == "build" ]]; then
echo " Build and Autodeploy..."
mvn clean install -DskipTests
@ -65,6 +58,11 @@ if [[ "$(strip_dash $1)" == "hot" ]]; then
cd ..
fi
if [[ "$(strip_dash $1)" == "deploy" ]]; then
echo " Deploy to Imixs-Cloud..."
mvn clean install -Pimixs-cloud -DskipTests
fi
# Überprüfen, ob keine Parameter übergeben wurden - standard build
if [[ $# -eq 0 ]]; then
@ -72,10 +70,11 @@ if [[ $# -eq 0 ]]; then
echo " Run with ./dev.sh -XXX"
echo " "
echo " -start : start Docker Containers"
echo " -dev : start the Docker dev environment"
echo " -build : build application and redeploy"
echo " -hot : Manik Hotdeploy"
echo " -docker : build the Docker image"
echo " -test : run tests"
echo " -deploy: Imixs-Cloud Deployment starten "
echo " -setup : setup dev environment - rebuild docker containers "
echo "_________________________________________"
echo " "

View file

@ -3,18 +3,18 @@ services:
# PostgreSQL
#######################
db:
image: postgres:17.4
image: postgres:9.6.1
environment:
POSTGRES_PASSWORD: adminadmin
POSTGRES_DB: office
volumes:
- dbdata:/var/lib/postgresql/data
- dbdata-hai:/var/lib/postgresql/data
#######################
# Dynamixs AI
#######################
app:
image: imixs/dynamixs-super-office
image: imixs/dynamixs-ai
depends_on:
- db
environment:
@ -44,8 +44,10 @@ services:
WOPI_HOST_ENDPOINT: "http://app:8080/api/wopi/"
COLLABORA_CONVERTER_URL: "http://collabora:9980/lool/convert-to/"
# LLM Integration
LLM_CONFIG_FILE: /opt/jboss/imixs-llm.xml
# Imixs-AI
# Optional configured via imixs.properties
LLM_SERVICE_ENDPOINT: ${LLM_API_ENDPOINT}
LLM_SERVICE_ENDPOINT_APIKEY: ${LLM_API_KEY}
# Cassandra Embeddings
EMBEDDINGS_CLUSTER_CONTACTPOINTS: "cassandra"
@ -56,20 +58,21 @@ services:
- "9990:9990"
- "8787:8787"
volumes:
- ./docker/deployments:/opt/jboss/wildfly/standalone/deployments/
- ./docker/keys/imixs-llm.xml:/opt/jboss/imixs-llm.xml
#- ./import_examples:/opt/jboss/import_examples/
- ./deployments:/opt/jboss/wildfly/standalone/deployments/
- ./import_examples:/opt/jboss/import_examples/
# Mapping the host ip to the container
# This setting is used for local testing only
# Wildfly can access the keycloak server via the external host address
# extra_hosts:
# - "keycloak.imixs.local:host-gateway"
extra_hosts:
- "keycloak.imixs.local:host-gateway"
#######################
# Tika OCR Service
#######################
tika:
#image: imixs/tika
#image: apache/tika:1.24.1-full
image: apache/tika:3.2.0.0-full
environment:
TZ: "Europe/Berlin"
@ -111,17 +114,40 @@ services:
- password=adminadmin
- extra_params=--o:ssl.enable=false
- aliasgroup1=http://app:8080
# volumes:
# - ./configuration/collabora/fonts:/usr/share/fonts/truetype/more/
# - ./configuration/collabora/fonts:/opt/cool/systemplate/usr/share/fonts/truetype/more/
#######################
# Imixs Admin Client
#######################
# imixsadmin:
# image: imixs/imixs-admin
# ports:
# - "8888:8080"
imixsadmin:
image: imixs/imixs-admin
ports:
- "8888:8080"
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./configuration/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheusdata:/prometheus/
grafana:
image: grafana/grafana:10.4.0 # Aktuelle stabile Version
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin # Standardpasswort setzen
volumes:
- grafana-storage:/var/lib/grafana # Persistente Daten
#networks:
# - monitoring
volumes:
dbdata:
name: ${PROJECT_PREFIX}-dbdata
dbdata-hai:
dbkeycloak:
cassandra_data:
name: ${PROJECT_PREFIX}-cassandra_data
prometheusdata:
grafana-storage:

View file

@ -0,0 +1,172 @@
services:
#######################
# PostgreSQL
#######################
db:
image: postgres:9.6.1
environment:
POSTGRES_PASSWORD: adminadmin
POSTGRES_DB: office
volumes:
- dbdata-hai:/var/lib/postgresql/data
#######################
# Dynamixs AI
#######################
app:
image: imixs/dynamixs-ai
depends_on:
- db
environment:
JAVA_OPTS: "-Dnashorn.args=--no-deprecation-warning"
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "adminadmin"
POSTGRES_CONNECTION: "jdbc:postgresql://db/office"
TZ: "Europe/Berlin"
LANG: "en_US.UTF-8"
MAILGATEWAY: "localhost"
ASYNCEVENT_PROCESSOR_ENABLED: "true"
ASYNCEVENT_PROCESSOR_INITIALDELAY: "30000"
OCR_SERVICE_ENDPOINT: "http://tika:9998/tika"
OCR_SERVICE_MODE: "MODEL"
#OCR_STRATEGY: "NO_OCR, OCR_ONLY, OCR_AND_TEXT_EXTRACTION, AUTO (default)"
OCR_STRATEGY: "AUTO"
# Collabora integration
WOPI_PUBLIC_ENDPOINT: "http://localhost:9980"
WOPI_DISCOVERY_ENDPOINT: "http://collabora:9980/hosting/discovery"
WOPI_HOST_ENDPOINT: "http://imixs-documents:8080/api/wopi/"
COLLABORA_CONVERTER_URL: "http://collabora:9980/lool/convert-to/"
# Imixs-Archive
# ARCHIVE_SERVICE_ENDPOINT: "http://imixs-archive:8080/api"
# Imixs-AI
# Optional configured via imixs.properties
LLM_SERVICE_ENDPOINT: "https://llama.cpp.imixs.com/"
LLM_SERVICE_ENDPOINT_USER: "admin"
LLM_SERVICE_ENDPOINT_PASSWORD: "imixs4.null"
# Cassandra Embeddings
EMBEDDINGS_CLUSTER_CONTACTPOINTS: "cassandra"
EMBEDDINGS_CLUSTER_KEYSPACE: "embeddings"
# OIDC
OIDCCONFIG_PROVIDERURI: "http://keycloak.imixs.local:8084/realms/dynamixsai/.well-known/openid-configuration"
OIDCCONFIG_CLIENTID: "imixs"
OIDCCONFIG_CLIENTSECRET: "aSuEXUeD7bARAlX8o3fLagSYbIagBrrM"
OIDCCONFIG_REDIRECTURI: "http://localhost:8080/callback"
#OIDCCONFIG_SCOPE: "openid profile email"
#OIDCCONFIG_CLAIM_CALLERNAME: "preferred_username"
#OIDCCONFIG_CLAIM_ROLES: "groups"
ports:
- "8080:8080"
- "9990:9990"
- "8787:8787"
volumes:
- ./deployments:/opt/jboss/wildfly/standalone/deployments/
- ./import_examples:/opt/jboss/import_examples/
# Mapping the host ip to the container
# This setting is used for local testing only
# Wildfly can access the keycloak server via the external host address
extra_hosts:
- "keycloak.imixs.local:host-gateway"
#######################
# Tika OCR Service
#######################
tika:
#image: imixs/tika
image: apache/tika:1.24.1-full
environment:
TZ: "Europe/Berlin"
ports:
- "9998:9998"
#######################
# Cassandra
#######################
cassandra:
image: cassandra:5.0.4
container_name: cassandra
mem_limit: 2G # Mindestens 2 GB RAM für Cassandra 5.x
mem_reservation: 1G # Reserviert 1 GB
environment:
- TZ="Europe/Berlin"
- JVM_OPTS=-Xms1G -Xmx1G # Heap auf 1 GB begrenzen
- CASSANDRA_CLUSTER_NAME=dynamixsAiCluster
- CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch
- CASSANDRA_DC=datacenter1
- CASSANDRA_RACK=rack1
ports:
- "9042:9042" # CQL-Port
- "7000:7000" # Inter-Node-Kommunikation
- "7001:7001" # TLS-fähige Inter-Node-Kommunikation
- "7199:7199" # JMX-Port
volumes:
- cassandra_data:/var/lib/cassandra
#######################
# collabora Office Online
#######################
collabora:
image: collabora/code:23.05.0.5.1
#expose:
# - 9980
ports:
- "9980:9980"
environment:
- username=admin
- password=adminadmin
- extra_params=--o:ssl.enable=false
- aliasgroup1=http://app:8080
volumes:
- ./configuration/collabora/fonts:/usr/share/fonts/truetype/more/
- ./configuration/collabora/fonts:/opt/cool/systemplate/usr/share/fonts/truetype/more/
#######################
# Imixs Admin Client
#######################
# imixsadmin:
# image: imixs/imixs-admin
# ports:
# - "8888:8080"
##################################
# Keycloak SQL Server
##################################
dbkeycloak:
image: postgres:15
environment:
POSTGRES_PASSWORD: adminadmin
POSTGRES_USER: keycloak
POSTGRES_DB: keycloak
volumes:
- dbkeycloak:/var/lib/postgresql/data
##################################
# Keycloak Server
##################################
keycloak:
#image: quay.io/keycloak/keycloak:23.0.5
image: quay.io/keycloak/keycloak:26.2.4
command:
- start-dev
environment:
- KEYCLOAK_ADMIN=admin
- KEYCLOAK_ADMIN_PASSWORD=adminadmin
- KC_DB=postgres
- KC_DB_URL=jdbc:postgresql://dbkeycloak:5432/keycloak
- KC_DB_USER=keycloak
- KC_DB_PASSWORD=adminadmin
volumes:
- /etc/localtime:/etc/localtime:ro
- ./configuration/keycloak/themes/:/opt/keycloak/themes/
ports:
- "8084:8080"
volumes:
dbdata-hai:
dbkeycloak:
cassandra_data:

View file

@ -0,0 +1,52 @@
version: "3.1"
services:
db:
image: postgres:9.6.1
environment:
POSTGRES_PASSWORD: adminadmin
POSTGRES_DB: office
volumes:
- dbdata:/var/lib/postgresql/data
app:
image: imixs/imixs-office-workflow
depends_on:
- db
environment:
TZ: "Europe/Berlin"
JAVA_OPTS: "-Dnashorn.args=--no-deprecation-warning"
MAILGATEWAY: "localhost"
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "adminadmin"
POSTGRES_CONNECTION: "jdbc:postgresql://db/office"
METRICS_ENABLED: "true"
ports:
- "8080:8080"
- "9990:9990"
- "8787:8787"
volumes:
- ./deployments:/opt/jboss/wildfly/standalone/deployments/
# imixsadmin:
# image: imixs/imixs-admin
# ports:
# - "8888:8080"
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheusdata:/prometheus/
grafana:
image: grafana/grafana:7.1.0
ports:
- "3000:3000"
volumes:
prometheusdata:
dbdata:

Binary file not shown.

View file

@ -0,0 +1,65 @@
#!/bin/bash
# Überprüfen, ob eine Eingabedatei angegeben wurde
if [ $# -ne 1 ]; then
echo "Verwendung: $0 input.csv"
exit 1
fi
input_file="$1"
output_file="${input_file%.*}_clean.csv"
# Temporäre Datei für die Verarbeitung
temp_file=$(mktemp)
# Verarbeitung:
# 1. Zuerst alle echten Zeilenumbrüche (die nicht in Anführungszeichen sind) markieren
# 2. Dann Newlines innerhalb von Anführungszeichen durch Leerzeichen ersetzen
# 3. HTML-Tags entfernen
# 4. Markierte Zeilenumbrüche wiederherstellen
awk '
BEGIN { FPAT = "([^;]*)|(\"[^\"]+\")"; OFS=";"; in_quotes=0 }
{
# Zeilen zusammenfügen, wenn sie unvollständig sind (nur für Sicherheit)
if (NR == 1) {
full_line = $0
} else {
full_line = full_line " " $0
}
# Überprüfen, ob die Zeile vollständig ist (gleich viele öffnende und schließende Anführungszeichen)
quotes = gsub(/"/, "&", full_line)
if (quotes % 2 == 0) {
# Zeile ist vollständig, jetzt verarbeiten
$0 = full_line
# Newlines in jedem Feld durch Leerzeichen ersetzen
for (i=1; i<=NF; i++) {
# HTML-Tags entfernen
gsub(/<[^>]*>/, "", $i)
# Newlines und mehrfache Leerzeichen bereinigen
gsub(/\n/, " ", $i)
gsub(/ +/, " ", $i)
# Feld trimmen
sub(/^[ \t]+/, "", $i)
sub(/[ \t]+$/, "", $i)
# Feld wieder in Anführungszeichen setzen, wenn es Semikolons oder Anführungszeichen enthält
if (($i ~ /;/ || $i ~ /"/) && $i !~ /^".*"$/) {
gsub(/"/, "\"\"", $i) # Escape existing quotes
$i = "\"" $i "\""
}
}
print
full_line = ""
}
}' "$input_file" > "$temp_file"
# Endgültige Bereinigung
mv "$temp_file" "$output_file"
echo "Bereinigte Datei wurde erstellt: $output_file"

View file

@ -0,0 +1,36 @@
id;customer.name;customer.address;customer.zip;customer.city;customer.phone;customer.email;customer.web;customer.country
1;TechSolutions GmbH;Musterstraße 123;10115;Berlin;+49 30 12345678;info@techsolutions.de;www.techsolutions.de;DE
2;Innovate AG;Hauptstraße 45;80335;München;+49 89 87654321;contact@innovate-ag.com;www.innovate-ag.com;AU
3;DataSystems Ltd.;Industriestraße 78;20095;Hamburg;+49 40 5559876;office@datasystems.de;www.datasystems.de;JP
4;WebCraft GmbH;Am Bahnhof 5;50667;Köln;+49 221 9876543;info@webcraft.de;www.webcraft.de;DE
5;CloudExperts AG;TechPark 12;70173;Stuttgart;+49 711 123457;support@cloudexperts.de;www.cloudexperts.de;DE
6;SoftwareHub GmbH;Friedrichstraße 33;60323;Frankfurt;+49 69 5551234;info@softwarehub.de;www.softwarehub.de;DE
7;DigitalWorks Ltd.;Königsallee 1;40212;Düsseldorf;+49 211 8765432;contact@digitalworks.de;www.digitalworks.de;DE
8;NetSolutions GmbH;Hansastraße 62;04109;Leipzig;+49 341 2345678;office@netsolutions.de;www.netsolutions.com;DE
9;CodeMasters AG;Rathausplatz 8;86150;Augsburg;+49 821 9876543;info@codemasters.de;www.codemasters.de;DE
10;FutureTech GmbH;Am Markt 3;38100;Braunschweig;+49 531 5559876;contact@futuretech.de;www.futuretech.de;DE
11;SmartSystems Ltd.;Ludwigstraße 15;97070;Würzburg;+49 931 1234567;support@smartsystems.de;www.smartsystems.de;CN
12;AppFactory GmbH;Poststraße 23;14467;Potsdam;+49 331 8765432;info@appfactory.de;www.appfactory.de;CN
13;DataLabs AG;Goethestraße 98;99084;Erfurt;+49 361 9876543;office@datalabs.de;www.datalabs.de;CN
14;WebInnovate GmbH;Schillerstraße 44;30159;Hannover;+49 511 5551234;contact@webinnovate.de;www.webinnovate.de;CN
15;CloudSystems Ltd.;Bahnhofstraße 77;66111;Saarbrücken;+49 681 2345678;info@cloudsystems.de;www.cloudsystems.de;CN
21;GlobalTech Solutions;124 Oxford Street;W1D 2HQ;London;+44 20 7123 4567;info@globaltech.co.uk;www.globaltech.co.uk;CN
22;InnovateX Ltd;78 Canary Wharf;E14 5AB;London;+44 20 7987 6543;contact@innovatex.com;www.innovatex.com;CN
23;DataDynamics Inc;446 Silicon Roundabout;EC2A 4NE;London;+44 20 7555 12345;office@datadynamics.com;www.datadynamics.com;FR
24;CloudSphere GmbH;TechPark Berlin 15;10115;Berlin;+49 30 9876 15432;info@cloudsphere.de;www.cloudsphere.de;FR
25;WebCraft International;200 Madison Ave;10016;New York;+1 212 555 7890;support@webcraft.com;www.webcraft.com;FR
26;DigitalFrontiers Pte Ltd;1 Raffles Place;048616;Singapore;+65 6123 4567;info@digitalfrontiers.sg;www.digitalfrontiers.sg;FR
27;TechNova SAS;55 Praspiekt Pieramozcau;75008;Misnk; 1 42 86 53 09;contact@technova.by;www.technova.by;BY
28;AppFactory Ltd;88 Kingsway;WC2B 6AA;London;+44 20 7123 9876;office@appfactory.io;www.appfactory.io;FR
29;GlobalData Systems;Level 25 One Canada Square;E14 5AB;London;+44 20 7987 1234;info@globaldata.com;www.globaldata.com;FR
210;SmartSolutions AG;Bahnhofstrasse 45;8001;Zurich;+41 44 234 56 78;contact@smartsolutions.ch;www.smartsolutions.ch;FR
211;InnovationHub Ltd;22 Shoreditch High Street;E1 6PE;London;+44 20 7555 8765;support@innovationhub.co.uk;www.innovationhub.co.uk;UK
212;CyberSecure Inc;500 5th Avenue;10110;New York;+1 212 867 5309;security@cybersecure.com;www.cybersecure.com;FR
213;TechBridge Tokyo;Shinjuku Center Building 1-25-1;163-0650;Tokyo;+81 3 5321 7890;info@techbridge.jp;www.techbridge.jp;JP
214;LondonDigital Agency;15 Covent Garden;WC2E 8BE;London;+44 20 7123 5555;hello@londondigital.com;www.londondigital.com;FR
215;GlobalInnovate Group;Tower 42; 25 Old Broad Street;EC2N 1HQ;London;+44 20 7987 9999;info@globalinnovate.com;www.globalinnovate.com;FR
216;DataCraft Sydney;1 Macquarie Place;2000;Sydney;+61 2 9123 4567;au@datacraft.com;www.datacraft.com;FR
217;EuroTech Solutions;Amsterdam Towers;1011 PN;Amsterdam;+31 20 765 4321;info@eurotech.nl;www.eurotech.nl;NL
218;LondonFinTech Labs;Level 39; One Canada Square;E14 5AB;London;+44 20 7555 4321;finance@londonfintech.com;www.londonfintech.com;UK
219;CloudMasters Inc;221 Main Street;94105;San Francisco;+1 415 555 1234;support@cloudmasters.com;www.cloudmasters.com;FR
220;TechVenture Capital;8 St. James's Square;SW1Y 4JU;London;+44 20 7123 7777;invest@techventure.com;www.techventure.com;FR
Can't render this file because it has a wrong number of fields in line 31.

View file

@ -0,0 +1,90 @@
ID;Name;Description;stock;price;category;subcategory;Lieferzeit;EAN
DEV001;Arduino Uno R3a;The Arduino Uno R3 is a foundational microcontroller board based on the ATmega328P. It features 14 digital I/O pins, 6 analog inputs, a 16 MHz quartz crystal, USB connectivity, and a power jack. Operating voltage is 5V. It is the ideal platform for beginners in electronics and coding, widely used for prototyping, DIY projects, automation, robotics, and educational purposes. It can be programmed using the Arduino IDE.;45;22.99;Microcontroller & Development Boards;Arduino Boards;2-3 Tage;7630049200016
DEV002;Raspberry Pi 4 Model B 4GB;The new high-performance single-board computer featuring a Broadcom BCM2711, quad-core Cortex-A72 (ARM v8) 64-bit SoC running at 1.5GHz and 4GB of LPDDR4-3200 SDRAM. Connectivity includes dual-band 2.4/5.0 GHz Wi-Fi, Bluetooth 5.0, Gigabit Ethernet, two USB 3.0 ports, and two micro-HDMI ports supporting dual 4K displays. Its primary use is as a low-cost desktop computer, network-attached storage (NAS) device, media center, or embedded system for industrial applications.;28;75.50;Microcontroller & Development Boards;Raspberry Pi Boards;5-7 Tage;1931000001047
DEV003;ESP32-WROOM-312 Development Board;A powerful Wi-Fi and Bluetooth-enabled microcontroller board with dual-core Xtensa LX6 processor. Features 4MB flash memory, 520KB SRAM, 34 GPIO pins, and supports various communication protocols like I2C, I2S, SPI, and UART. Ideal for IoT projects, smart home devices, and wireless applications requiring robust connectivity and processing power.;67;12.95;Microcontroller & Development Boards;ESP32/8266 Boards;3-5 Tage;8717478034021
DEV004;STM32F407VET6 Development Board;High-performance ARM Cortex-M4 based board with DSP and FPU instructions. Features 512KB flash, 192KB RAM, USB OTG, Ethernet, and multiple timers. Operating frequency up to 168MHz. Suitable for industrial control, motor control, audio processing, and advanced embedded applications requiring high computational power.;23;35.80;Microcontroller & Development Boards;Other Microcontrollers;7-10 Tage;6940541880018
DEV005;Arduino Motor Shield Rev3;Add-on shield designed to drive inductive loads such as relays, solenoids, DC and stepper motors. Features two channels that support 2A continuous current, screw terminals for easy connection, and built-in protection diodes. Perfect for robotics projects and automation systems when used with Arduino boards.;89;24.50;Microcontroller & Development Boards;Accessories;1-2 Tage;7630049200023
DEV006;Raspberry Pi 4 Official Case;Official protective case for Raspberry Pi 4 Model B with integrated GPIO access and dedicated slots for camera and display cables. Features a modular design with three plates for easy access to ports and components. Made from high-quality white plastic with colored accents.;156;8.99;Microcontroller & Development Boards;Accessories;1-2 Tage;1931000001054
DEV007;DHT22 AM2302 Digital Sensor;A pre-calibrated digital temperature and humidity sensor module. It provides a digital signal output and features a dedicated NTC for temperature measurement and a resistive humidity sensing element. Operating voltage: 3.3V - 6V. Measurement range: Humidity 0-100% RH, Temperature -40 to 80°C. Accuracy: ±2% RH and ±0.5°C. Typical applications include HVAC systems, weather stations, environmental monitoring, home automation, and data logging projects. It is easy to interface with Arduino, Raspberry Pi, and other microcontrollers.;120;9.95;Sensors & Modules;Temperature & Humidity Sensors;1-2 Tage;8591854063228
DEV008;HC-SR05 Ultrasonic Sensor;Ultrasonic distance measurement module with 2cm to 400cm non-contact range. Operating voltage: 5V DC. Provides excellent ranging accuracy with stable readings. Uses sonar principles to determine distance to objects. Ideal for obstacle avoidance robots, parking assistance systems, and liquid level measurement.;204;3.50;Sensors & Modules;Motion & Proximity Sensors;1-2 Tage;6943185501012
DEV009;PIR Motion Sensor HC-SR501;Passive infrared motion detection sensor with adjustable sensitivity and delay time. Detection range up to 7 meters with 120-degree detection angle. Operating voltage: 4.5-20V DC. Features low power consumption and reliable performance. Perfect for security systems, automatic lighting control, and energy-saving applications.;178;4.25;Sensors & Modules;Motion & Proximity Sensors;1-2 Tage;6943185501029
DEV010;BH1750 Digital Light Sensor;Digital ambient light sensor with I2C interface and 16-bit resolution. Measurement range: 1-65535 lux. Features low power consumption and high precision. No need for external components. Ideal for display backlight control in mobile devices, automatic brightness adjustment systems, and environmental light monitoring.;95;6.80;Sensors & Modules;Light, Color & Gesture Sensors;2-3 Tage;8591854063235
DEV011;APDS-9960 Gesture Sensor;Advanced gesture detection, proximity sensing, and ambient light sensor in one module. Features I2C interface with interrupt output. Can detect simple gestures (up, down, left, right) and measure proximity up to 20cm. Perfect for touchless interfaces, interactive displays, and smart home control.;63;15.75;Sensors & Modules;Light, Color & Gesture Sensors;3-5 Tage;8717478034038
DEV012;MQ-2 Gas Sensor Module;Semiconductor gas sensor for detecting LPG, propane, hydrogen, methane, alcohol, and smoke. Analog and digital output with adjustable sensitivity. Heating voltage: 5V±0.2V. Fast response and recovery time. Suitable for gas leak detection in home and industry, air quality monitoring, and safety systems.;112;8.45;Sensors & Modules;Gas, Air Quality & Pressure Sensors;2-3 Tage;6943185501036
DEV013;BMP2810 Barometric Pressure Sensor;High-precision digital barometric pressure and temperature sensor with I2C and SPI interfaces. Pressure range: 300-1100 hPa with ±1 hPa absolute accuracy. Temperature measurement with ±1.0°C accuracy. Low power consumption. Ideal for weather stations, altitude tracking, and indoor navigation.;87;9.20;Sensors & Modules;Gas, Air Quality & Pressure Sensors;2-3 Tage;8591854063242
DEV014;NEO-6M GPS Module;GPS receiver module with built-in EEPROM and ceramic antenna. Provides accurate positioning with 2.5m accuracy. Supports up to 5Hz update rate with NMEA protocol. Operating voltage: 3.3-5V. Features low power consumption and hot start capability. Perfect for navigation systems, tracking devices, and drones.;134;18.90;Sensors & Modules;GPS & Location Modules;3-5 Tage;8717478034045
DEV015;RC522 RFID Reader Module;RFID reader/writer operating at 13.56MHz with SPI interface. Reading distance up to 5cm. Supports ISO 14443A standard tags. Operating voltage: 2.5-3.3V. Ideal for access control systems, attendance tracking, payment systems, and interactive applications.;198;7.85;Sensors & Modules;RFID & NFC Modules;1-2 Tage;6943185501043
DEV016;37-in-1 Sensor Module Kit;Comprehensive sensor kit containing 37 most popular modules including temperature, humidity, motion, light, sound, and gas sensors. Comes with tutorial CD and connection diagrams. Perfect for beginners learning electronics and IoT programming. All modules are compatible with Arduino and Raspberry Pi.;45;89.99;Sensors & Modules;Sensor Kits;5-7 Tage;7630049200030
DEV017;SG90 Micro Servo Motor;TowerPro SG90 mini servo motor with 180-degree rotation range. Operating voltage: 4.8V. Stall torque: 1.8kg/cm. Comes with plastic gears and three-wire interface (power, ground, signal). Ideal for robotics, RC models, camera positioning, and small automation projects.;312;4.75;Actuators & Output;Motors;1-2 Tage;6940541880025
DEV018;28BYJ-48 Stepper Motor with Driver;Unipolar stepper motor with ULN2003 driver board. Step angle: 5.625° x 1/64 reduction ratio. Operating voltage: 5-12V DC. Provides precise position control without feedback. Perfect for 3D printers, CNC machines, automated curtains, and precision positioning systems.;167;12.50;Actuators & Output;Motors;2-3 Tage;8591854063259
DEV019;L298N Motor Driver Module;Dual H-bridge motor driver capable of driving two DC motors or one stepper motor. Operating voltage: 5-35V. Maximum current: 2A per channel. Features logic level conversion and heat sink. Ideal for robotics projects, motor control applications, and high-power driving needs.;98;8.95;Actuators & Output;Motor Drivers & Controllers;2-3 Tage;8717478034052
DEV020;5V Relay Module;Single channel relay module with optocoupler isolation. Operating voltage: 5V. Switching capacity: 10A 250V AC or 30V DC. Features status LED and standard interface for easy connection to microcontrollers. Perfect for controlling high-voltage appliances with low-voltage circuits.;245;3.25;Actuators & Output;Relays & Switches;1-2 Tage;6943185501050
DEV021;16x2 LCD Display with I2C;Blue backlight LCD display with 16 characters x 2 lines and I2C interface module. Operating voltage: 5V. Contrast adjustable. The I2C interface reduces required GPIO pins from 6 to 2. Ideal for displaying system status, sensor readings, and user interface information.;143;14.99;Actuators & Output;Displays;2-3 Tage;7630049200047
DEV022;0.96 inch OLED Display;128x64 pixel OLED display with SSD1306 driver and I2C/SPI interface. Features high contrast, wide viewing angle, and low power consumption. Operating voltage: 3.3-5V. Perfect for projects requiring compact, high-quality graphics display.;189;10.45;Actuators & Output;Displays;2-3 Tage;1931000001061
DEV023;5mm RGB LED Common Cathode;Diffused RGB LED with common cathode configuration. Operating voltage: 2.0-2.5V (Red), 3.0-3.4V (Green/Blue). Maximum current: 20mA per color. Provides full color spectrum mixing. Ideal for status indicators, mood lighting, and visual feedback in projects.;500;0.75;Actuators & Output;LEDs & Lighting;1-2 Tage;8591854063266
DEV024;Active Buzzer Module;5V active buzzer with built-in oscillator that produces continuous sound when powered. Operating voltage: 3.3-5V. Sound output: approximately 85dB. Easy to drive with microcontroller digital pin. Perfect for alarm systems, timers, and user notification applications.;287;2.10;Actuators & Output;Buzzers & Speakers;1-2 Tage;6943185501067
DEV025;1K Ohm Resistor Pack;Assortment of 100 pieces 1K ohm 1/4W metal film resistors with 1% tolerance. Temperature coefficient: 50ppm/°C. Perfect for pull-up/pull-down resistors, voltage dividers, and current limiting in various electronic circuits.;15;4.99;Components & Parts;Resistors, Capacitors, Potentiometers;1-2 Tage;8717478034069
DEV026;100uF Electrolytic Capacitor;Radial lead electrolytic capacitor with 25V voltage rating. Operating temperature: -40°C to +85°C. Low ESR and high ripple current capability. Ideal for power supply filtering, audio circuits, and general decoupling applications.;420;0.25;Components & Parts;Resistors, Capacitors, Potentiometers;1-2 Tage;6940541880032
DEV027;10K Ohm Linear Potentiometer;Rotary potentiometer with 10K ohm resistance and linear taper. Shaft length: 15mm. Power rating: 0.5W. Features smooth rotation and reliable performance. Perfect for volume control, brightness adjustment, and parameter tuning.;195;1.20;Components & Parts;Resistors, Capacitors, Potentiometers;1-2 Tage;8591854063273
DEV028;2N2222A NPN Transistor;General purpose NPN bipolar junction transistor in TO-92 package. Collector current: 800mA max. Collector-emitter voltage: 40V max. Gain bandwidth: 250MHz. Ideal for switching and amplification applications in various electronic circuits.;876;0.35;Components & Parts;Transistors & MOSFETs;1-2 Tage;7630049200054
DEV029;IRFZ44N N-Channel MOSFET;Power MOSFET with low on-resistance and fast switching speed. Drain-source voltage: 55V. Continuous drain current: 49A. TO-220 package. Perfect for motor control, power switching, and high-current applications.;321;2.15;Components & Parts;Transistors & MOSFETs;1-2 Tage;1931000001078
DEV030;1N4007 Rectifier Diode;General purpose rectifier diode with 1000V maximum repetitive reverse voltage and 1A average forward current. DO-41 package. Ideal for power supply rectification, reverse polarity protection, and general purpose switching.;650;0.15;Components & Parts;Diodes & LEDs;1-2 Tage;8717478034076
DEV031;5mm Green LED;Diffused green LED with 20mA forward current and 2.1V forward voltage. Viewing angle: 30 degrees. Luminous intensity: 5000-8000 mcd. Perfect for status indicators, panel lights, and visual feedback in electronic projects.;1200;0.20;Components & Parts;Diodes & LEDs;1-2 Tage;6943185501074
DEV032;6x6mm Tactile Switch;Momentary push button switch with through-hole mounting. Operating force: 160±50gf. Contact resistance: <50mΩ. Life expectancy: 100,000 cycles. Ideal for user input, reset buttons, and control interfaces.;890;0.10;Components & Parts;Buttons & Switches;1-2 Tage;8591854063280
DEV033;Toggle Switch SPDT;Single pole double throw toggle switch with on-on configuration. Rating: 6A 125V AC / 3A 250V AC. Panel mount design with nut and washer. Perfect for power switching, mode selection, and circuit configuration.;134;2.95;Components & Parts;Buttons & Switches;2-3 Tage;6940541880049
DEV034;Jumper Wires Male-to-Male;Bundle of 120 pieces 20cm male-to-male jumper wires in multiple colors. 0.1 pitch. Made with high-quality Dupont connectors. Perfect for breadboard connections, prototyping, and wiring Arduino projects.;45;6.99;Components & Parts;Wires, Cables & Connectors;1-2 Tage;7630049200061
DEV035;USB Type B Cable;1.5 meter USB 2.0 Type A to Type B cable with gold-plated connectors. Data transfer speed up to 480Mbps. 28AWG power conductors. Perfect for connecting Arduino boards, printers, and other devices with Type B接口.;178;7.50;Components & Parts;Wires, Cables & Connectors;1-2 Tage;1931000001085
DEV036;400-Point Solderless Breadboard;High-quality solderless breadboard with 400 tie points. Features two power rails and 63 rows of interconnected terminals. Adhesive backing for secure mounting. Maximum voltage: 300V. Ideal for circuit prototyping and testing.;67;8.25;Components & Parts;Breadboards & Prototyping;1-2 Tage;8717478034083
DEV037;Breadboard Jumper Wire Kit;Kit containing 140 pieces of pre-cut and stripped jumper wires in various lengths and colors. Includes male-to-male, male-to-female, and female-to-female types. Organized in convenient storage box. Perfect for breadboard prototyping.;92;12.99;Components & Parts;Breadboards & Prototyping;1-2 Tage;6943185501081
DEV038;12V 2A Power Supply;Switching power adapter with 12V DC output and 2A maximum current. Input: 100-240V AC. Comes with 5.5mm x 2.1mm barrel jack connector. Short circuit and overvoltage protection. Ideal for powering Arduino projects, LED strips, and various electronics.;58;14.95;Power & Battery;Power Supplies;3-5 Tage;8591854063297
DEV039;5V 3A USB Power Supply;High-current USB power supply with 5V 3A output. Features built-in USB Type-A port and overcurrent protection. Input: 100-240V AC. Perfect for powering Raspberry Pi, high-power USB devices, and charging applications.;47;11.50;Power & Battery;Power Supplies;2-3 Tage;6940541880056
DEV040;4xAA Battery Holder;Plastic battery holder for 4 AA batteries with series connection providing 6V output. Features wire leads with stripped ends and on/off switch. Secure battery closure. Perfect for portable projects and backup power.;124;3.75;Power & Battery;Battery Holders;1-2 Tage;7630049200078
DEV041;TP4056 Lithium Charger Module;Single cell lithium battery charging module with 1A maximum charge current. Features charging status indicators and protection circuits. Input: 5V USB. Supports 3.7V Li-ion and LiPo batteries. Perfect for portable projects.;216;4.25;Power & Battery;Charging Circuits;2-3 Tage;1931000001092
DEV042;LM2596 DC-DC Buck Converter;Adjustable step-down voltage regulator module with 3A maximum output current. Input voltage: 4.5-40V. Output voltage: 1.5-35V adjustable. Efficiency up to 92%. Features overheat and short circuit protection.;189;5.95;Power & Battery;Voltage Regulators & Converters;2-3 Tage;8717478034090
DEV043;60W Soldering Station;Temperature controlled soldering station with 60W power and adjustable temperature range 200-480°C. Features ceramic heating element, sleep mode, and digital display. Comes with soldering iron stand and sponge. Perfect for electronics repair and prototyping.;34;49.99;Tools & Equipment;Soldering Equipment;5-7 Tage;6943185501098
DEV044;Digital Multimeter DT9205A;3-1/2 digit digital multimeter with LCD display. Measures AC/DC voltage, current, resistance, capacitance, frequency, and temperature. Features diode test, continuity buzzer, and data hold. Comes with test leads and carrying case.;29;38.50;Tools & Equipment;Multimeters & Test Equipment;3-5 Tage;8591854063303
DEV045;65-Piece Screwdriver Set;Precision screwdriver set with 65 pieces including various Phillips, flat, Torx, and hex bits. Magnetic tips and comfortable handle. Organized in durable carrying case. Perfect for electronics repair, smartphone disassembly, and精密 work.;56;24.95;Tools & Equipment;Tool Kits;2-3 Tage;6940541880063
DEV046;Plastic Project Enclosure 160x100x60mm;Plastic electronic project box with dimensions 160x100x60mm. Features mounting posts for PCBs, ventilation slots, and removable lid. Material: ABS plastic. Perfect for housing electronic projects and prototypes.;78;9.75;Tools & Equipment;Enclosures & Boxes;3-5 Tage;7630049200085
DEV047;Arduino Nano Every;Compact board based on the ATMega4809 with 20MHz operating frequency. Features 48KB flash, 6KB SRAM, and 22 GPIO pins. Compatible with Arduino Nano footprint. Perfect for space-constrained projects requiring Arduino compatibility.;91;18.50;Microcontroller & Development Boards;Arduino Boards;3-5 Tage;7630049200092
DEV048;Raspberry Pi Pico W;Microcontroller board with RP2040 chip and wireless connectivity. Features 264KB SRAM, 2MB flash, and 30 GPIO pins. Supports MicroPython and C/C++. Built-in Wi-Fi and Bluetooth. Ideal for IoT projects and wireless applications.;167;9.95;Microcontroller & Development Boards;Raspberry Pi Boards;2-3 Tage;1931000001108
DEV049;ESP32-CAM Development Board;ESP32 module with OV2640 camera and microSD card slot. Features 4MB flash, 520KB SRAM, and supports Wi-Fi and Bluetooth. Provides video streaming and image capture capabilities. Perfect for security cameras and IoT vision applications.;124;15.75;Microcontroller & Development Boards;ESP32/8266 Boards;3-5 Tage;8717478034106
DEV050;ATtiny85 Development Board;Compact development board based on ATtiny85 microcontroller. Features 8KB flash, 512B SRAM, and 6 GPIO pins. Operating voltage: 5V. Perfect for simple projects requiring minimal I/O and small form factor.;205;6.25;Microcontroller & Development Boards;Other Microcontrollers;2-3 Tage;6943185501104
DEV051;Arduino Ethernet Shield;Network connectivity shield for Arduino with W5500 Ethernet controller. Supports TCP/IP protocols and provides SD card slot. Operating voltage: 5V. Perfect for network-connected projects and data logging.;76;32.99;Microcontroller & Development Boards;Accessories;4-6 Tage;8591854063310
DEV052;Raspberry Pi Official Power Supply;Official 15.3W USB-C power supply for Raspberry Pi 4. Output: 5.1V DC, 3A. Features noise filtering and overcurrent protection. Includes 1.5m USB-C cable. Ensures stable power for Raspberry Pi operation.;142;11.99;Microcontroller & Development Boards;Accessories;2-3 Tage;6940541880070
DEV053;DS18B20 Waterproof Temperature Sensor;Digital temperature sensor with 1-wire interface and waterproof stainless steel probe. Measurement range: -55°C to +125°C with ±0.5°C accuracy. 1-meter cable length. Perfect for liquid temperature measurement, environmental monitoring, and industrial applications.;188;8.95;Sensors & Modules;Temperature & Humidity Sensors;2-3 Tage;7630049200108
DEV054;HC-SR501 PIR Motion Sensor;Passive infrared motion detector with adjustable time and sensitivity. Detection range: 7 meters with 120° angle. Operating voltage: 4.5-20V DC. Features low power consumption. Ideal for security systems and automatic lighting.;156;4.50;Sensors & Modules;Motion & Proximity Sensors;1-2 Tage;1931000001115
DEV055;VL53L0X Laser Distance Sensor;Time-of-flight laser ranging sensor with 2m measurement range and 1mm resolution. I2C interface. Operating voltage: 2.6-3.5V. Features high accuracy and immune to ambient light. Perfect for gesture recognition and proximity sensing.;97;14.25;Sensors & Modules;Motion & Proximity Sensors;3-5 Tage;8717478034113
DEV056;TCS34725 Color Sensor;RGB color light sensor with IR filter and white LED. I2C interface with interrupt output. Provides clear, red, green, blue, and lux measurements. Perfect for color sorting, ambient light sensing, and display calibration.;84;13.75;Sensors & Modules;Light, Color & Gesture Sensors;2-3 Tage;6943185501111
DEV057;VCNL4040 Proximity Sensor;Integrated proximity and ambient light sensor with I2C interface. Proximity range: 0-200mm. Features interrupt function and low power consumption. Perfect for touchless interfaces and presence detection.;119;9.80;Sensors & Modules;Light, Color & Gesture Sensors;2-3 Tage;8591854063327
DEV058;MQ-135 Air Quality Sensor;Semiconductor sensor for detecting harmful gases like NH3, NOx, alcohol, benzene, and CO2. Analog output with adjustable sensitivity. Heating voltage: 5V±0.1V. Suitable for air quality monitoring and environmental detection.;145;7.25;Sensors & Modules;Gas, Air Quality & Pressure Sensors;2-3 Tage;6940541880087
DEV059;BME280 Environmental Sensor;Integrated environmental sensor measuring temperature, humidity, and barometric pressure. I2C/SPI interfaces. Operating voltage: 1.8-3.6V. Low power consumption. Ideal for weather stations and environmental monitoring.;132;14.50;Sensors & Modules;Gas, Air Quality & Pressure Sensors;3-5 Tage;7630049200115
DEV060;U-blox NEO-M8N GPS Module;High-performance GPS module with 72 channels and 2.5m accuracy. Supports GPS, GLONASS, and BeiDou systems. Update rate: up to 10Hz. Perfect for drones, navigation systems, and precision tracking.;89;26.95;Sensors & Modules;GPS & Location Modules;4-6 Tage;1931000001122
DEV061;PN532 NFC RFID Module;NFC/RFID reader/writer supporting ISO 14443A/B, ISO 18092, and FeliCa protocols. Operating frequency: 13.56MHz. Interfaces: I2C, SPI, HSU. Reading distance: up to 5cm. Ideal for contactless payment and access control.;107;18.75;Sensors & Modules;RFID & NFC Modules;3-5 Tage;8717478034120
DEV062;Arduino Sensor Kit;Complete sensor kit containing 37 modules compatible with Arduino. Includes tutorials and code examples. Covers basic to advanced sensors. Perfect for educational purposes and learning electronics.;68;79.99;Sensors & Modules;Sensor Kits;5-7 Tage;6943185501128
DEV063;NEMA 17 Stepper Motor;Bipolar stepper motor with 1.8° step angle and 42mm frame size. Holding torque: 40Ncm. Current: 1.2A per phase. 4-wire connection. Perfect for 3D printers, CNC machines, and precision positioning systems.;45;28.95;Actuators & Output;Motors;4-6 Tage;8591854063334
DEV064;L293D Motor Driver IC;Quadruple half-H driver for bidirectional DC motor control. Operating voltage: 4.5-36V. Output current: 600mA per channel. DIP-16 package. Perfect for controlling small motors and solenoids.;213;3.45;Actuators & Output;Motor Drivers & Controllers;1-2 Tage;6940541880094
DEV065;5V 4-Channel Relay Module;4-channel relay module with optocoupler isolation and status LEDs. Operating voltage: 5V. Switching capacity: 10A 250V AC per channel. Features screw terminals and standard control interface.;124;15.50;Actuators & Output;Relays & Switches;2-3 Tage;7630049200122
DEV066;20x4 LCD Display with I2C;Large LCD display with 20 characters x 4 lines and I2C interface. Blue backlight with adjustable contrast. Operating voltage: 5V. Perfect for projects requiring extensive text display.;87;19.95;Actuators & Output;Displays;3-5 Tage;1931000001139
DEV067;1.3 inch IPS LCD Display;1.3 inch IPS display with 240x240 resolution and ST7789 driver. SPI interface with 65K colors. Operating voltage: 3.3V. Features high brightness and wide viewing angle. Perfect for graphics and GUI applications.;134;16.75;Actuators & Output;Displays;3-5 Tage;8717478034137
DEV068;WS2812B RGB LED Strip;Addressable RGB LED strip with 30 LEDs per meter. Each LED individually controllable via single-wire protocol. Operating voltage: 5V. Perfect for decorative lighting, art installations, and visual effects.;78;18.50;Actuators & Output;LEDs & Lighting;2-3 Tage;6943185501135
DEV069;Piezo Buzzer Element;Passive piezo buzzer without internal oscillator. Requires external driver circuit. Operating voltage: 3-20V. Resonant frequency: 4kHz. Compact size. Ideal for custom tone generation and audio projects.;345;1.25;Actuators & Output;Buzzers & Speakers;1-2 Tage;8591854063341
DEV070;Assorted Resistor Kit;Comprehensive resistor kit with 1000 pieces covering values from 10 ohm to 1M ohm. 1/4W metal film with 1% tolerance. Organized in storage box with value labels. Perfect for electronics projects and repairs.;28;29.99;Components & Parts;Resistors, Capacitors, Potentiometers;2-3 Tage;6940541880100
DEV071;100nF Ceramic Capacitor;Multilayer ceramic capacitor with 100nF capacitance and 50V rating. X7R dielectric material. Through-hole design. Ideal for decoupling, filtering, and timing applications.;1200;0.15;Components & Parts;Resistors, Capacitors, Potentiometers;1-2 Tage;7630049200139
DEV072;200K Logarithmic Potentiometer;Audio taper potentiometer with 100K ohm resistance. Shaft length: 20mm. Power rating: 0.5W. Smooth rotation with logarithmic response. Perfect for volume controls and audio applications.;167;2.25;Components & Parts;Resistors, Capacitors, Potentiometers;1-2 Tage;1931000001146
DEV073;BC547 NPN Transistor;General purpose NPN transistor in TO-92 package. Collector current: 100mA max. Collector-emitter voltage: 45V. DC current gain: 110-800. Ideal for amplification and switching applications.;954;0.25;Components & Parts;Transistors & MOSFETs;1-2 Tage;8717478034144
DEV074;IRF540N N-Channel MOSFET;Power MOSFET with 100V drain-source voltage and 33A continuous drain current. Low on-resistance: 44mΩ. TO-220 package. Perfect for high-power switching and motor control applications.;189;3.75;Components & Parts;Transistors & MOSFETs;1-2 Tage;6943185501142
DEV075;1N4148 Switching Diode;Fast switching diode with 100V reverse voltage and 200mA forward current. Switching speed: 4ns. DO-35 package. Ideal for high-speed switching, protection circuits, and signal processing.;875;0.12;Components & Parts;Diodes & LEDs;1-2 Tage;8591854063358
DEV076;5mm Red LED;Standard red LED with 20mA forward current and 2.0V forward voltage. Viewing angle: 30 degrees. Luminous intensity: 2000-4000 mcd. Perfect for indicators and visual feedback.;1500;0.18;Components & Parts;Diodes & LEDs;1-2 Tage;6940541880117
DEV077;12mm Push Button Switch;Momentary push button switch with LED illumination. Operating voltage: 12V DC. Contact rating: 3A 125V AC. Panel mount design. Available in multiple colors. Perfect for control panels and user interfaces.;234;2.95;Components & Parts;Buttons & Switches;2-3 Tage;7630049200146
DEV078;DIP Switch 8 Position;8-position dual in-line package switch with through-hole mounting. Rating: 50mA 24V DC. Compact size. Ideal for configuration settings and mode selection in electronic circuits.;187;1.85;Components & Parts;Buttons & Switches;1-2 Tage;1931000001153
DEV079;Jumper Wires Female-to-Female;Bundle of 120 pieces 20cm female-to-female jumper wires in multiple colors. 0.1 pitch. High-quality Dupont connectors. Perfect for connecting modules and sensors to development boards.;67;6.99;Components & Parts;Wires, Cables & Connectors;1-2 Tage;8717478034151
DEV080;Micro USB Cable;1-meter Micro USB to USB Type-A cable with gold-plated connectors. Data transfer and charging capable. 28AWG power conductors. Perfect for connecting various electronic devices and charging.;245;5.50;Components & Parts;Wires, Cables & Connectors;1-2 Tage;6943185501159
DEV081;830-Point Breadboard;Large solderless breadboard with 830 tie points. Features four power rails and 63 rows of terminals. Adhesive backing. Maximum voltage: 300V. Ideal for complex circuit prototyping.;54;12.95;Components & Parts;Breadboards & Prototyping;2-3 Tage;8591854063365
DEV082;Breadboard Power Supply Module;3.3V/5V breadboard power supply module with USB input. Maximum output current: 700mA. Features LED indicators and on/off switch. Perfect for providing stable power to breadboard projects.;138;8.45;Components & Parts;Breadboards & Prototyping;2-3 Tage;6940541880124
DEV083;9V 1A Power Supply;Wall adapter with 9V DC output and 1A maximum current. Input: 100-240V AC. 5.5mm x 2.1mm barrel jack. Short circuit protection. Ideal for powering effects pedals and various electronics.;89;9.99;Power & Battery;Power Supplies;2-3 Tage;7630049200153
DEV084;USB-C Power Delivery Module;USB-C power delivery module with adjustable voltage output (5V, 9V, 12V, 15V, 20V). Maximum power: 100W. Features digital display and multiple protection circuits. Perfect for modern power requirements.;76;22.50;Power & Battery;Power Supplies;3-5 Tage;1931000001160
DEV085;18650 Battery Holder;Dual 18650 battery holder with series/parallel switch. Provides 3.7V (parallel) or 7.4V (series) output. Features built-in protection circuit and power switch. Perfect for lithium battery projects.;112;6.95;Power & Battery;Battery Holders;2-3 Tage;8717478034168
DEV086;TP5100 2A Lithium Charger;Dual lithium battery charger module with 2A maximum charge current. Supports 3.7V Li-ion and LiPo batteries. Input: 5-12V. Features charging status indicators. Perfect for high-capacity battery charging.;98;7.25;Power & Battery;Charging Circuits;2-3 Tage;6943185501166
DEV087;LM317 Adjustable Voltage Regulator;Adjustable linear voltage regulator with 1.5A output current. Output voltage: 1.25-37V. Features overcurrent and thermal protection. TO-220 package. Perfect for custom power supply designs.;167;2.95;Power & Battery;Voltage Regulators & Converters;1-2 Tage;8591854063372
DEV088;Temperature Controlled Soldering Iron;60W temperature controlled soldering iron with adjustable temperature 200-450°C. Features ceramic heater and quick heat-up time. Includes stand and spare tips. Perfect for basic soldering tasks.;45;35.99;Tools & Equipment;Soldering Equipment;3-5 Tage;6940541880131
DEV089;Auto-Ranging Multimeter;True RMS auto-ranging digital multimeter with 6000 counts. Measures AC/DC voltage, current, resistance, capacitance, frequency, and temperature. Features backlit display and data hold.;38;59.95;Tools & Equipment;Multimeters & Test Equipment;4-6 Tage;7630049200160
1 ID Name Description stock price category subcategory Lieferzeit EAN
2 DEV001 Arduino Uno R3a The Arduino Uno R3 is a foundational microcontroller board based on the ATmega328P. It features 14 digital I/O pins, 6 analog inputs, a 16 MHz quartz crystal, USB connectivity, and a power jack. Operating voltage is 5V. It is the ideal platform for beginners in electronics and coding, widely used for prototyping, DIY projects, automation, robotics, and educational purposes. It can be programmed using the Arduino IDE. 45 22.99 Microcontroller & Development Boards Arduino Boards 2-3 Tage 7630049200016
3 DEV002 Raspberry Pi 4 Model B 4GB The new high-performance single-board computer featuring a Broadcom BCM2711, quad-core Cortex-A72 (ARM v8) 64-bit SoC running at 1.5GHz and 4GB of LPDDR4-3200 SDRAM. Connectivity includes dual-band 2.4/5.0 GHz Wi-Fi, Bluetooth 5.0, Gigabit Ethernet, two USB 3.0 ports, and two micro-HDMI ports supporting dual 4K displays. Its primary use is as a low-cost desktop computer, network-attached storage (NAS) device, media center, or embedded system for industrial applications. 28 75.50 Microcontroller & Development Boards Raspberry Pi Boards 5-7 Tage 1931000001047
4 DEV003 ESP32-WROOM-312 Development Board A powerful Wi-Fi and Bluetooth-enabled microcontroller board with dual-core Xtensa LX6 processor. Features 4MB flash memory, 520KB SRAM, 34 GPIO pins, and supports various communication protocols like I2C, I2S, SPI, and UART. Ideal for IoT projects, smart home devices, and wireless applications requiring robust connectivity and processing power. 67 12.95 Microcontroller & Development Boards ESP32/8266 Boards 3-5 Tage 8717478034021
5 DEV004 STM32F407VET6 Development Board High-performance ARM Cortex-M4 based board with DSP and FPU instructions. Features 512KB flash, 192KB RAM, USB OTG, Ethernet, and multiple timers. Operating frequency up to 168MHz. Suitable for industrial control, motor control, audio processing, and advanced embedded applications requiring high computational power. 23 35.80 Microcontroller & Development Boards Other Microcontrollers 7-10 Tage 6940541880018
6 DEV005 Arduino Motor Shield Rev3 Add-on shield designed to drive inductive loads such as relays, solenoids, DC and stepper motors. Features two channels that support 2A continuous current, screw terminals for easy connection, and built-in protection diodes. Perfect for robotics projects and automation systems when used with Arduino boards. 89 24.50 Microcontroller & Development Boards Accessories 1-2 Tage 7630049200023
7 DEV006 Raspberry Pi 4 Official Case Official protective case for Raspberry Pi 4 Model B with integrated GPIO access and dedicated slots for camera and display cables. Features a modular design with three plates for easy access to ports and components. Made from high-quality white plastic with colored accents. 156 8.99 Microcontroller & Development Boards Accessories 1-2 Tage 1931000001054
8 DEV007 DHT22 AM2302 Digital Sensor A pre-calibrated digital temperature and humidity sensor module. It provides a digital signal output and features a dedicated NTC for temperature measurement and a resistive humidity sensing element. Operating voltage: 3.3V - 6V. Measurement range: Humidity 0-100% RH, Temperature -40 to 80°C. Accuracy: ±2% RH and ±0.5°C. Typical applications include HVAC systems, weather stations, environmental monitoring, home automation, and data logging projects. It is easy to interface with Arduino, Raspberry Pi, and other microcontrollers. 120 9.95 Sensors & Modules Temperature & Humidity Sensors 1-2 Tage 8591854063228
9 DEV008 HC-SR05 Ultrasonic Sensor Ultrasonic distance measurement module with 2cm to 400cm non-contact range. Operating voltage: 5V DC. Provides excellent ranging accuracy with stable readings. Uses sonar principles to determine distance to objects. Ideal for obstacle avoidance robots, parking assistance systems, and liquid level measurement. 204 3.50 Sensors & Modules Motion & Proximity Sensors 1-2 Tage 6943185501012
10 DEV009 PIR Motion Sensor HC-SR501 Passive infrared motion detection sensor with adjustable sensitivity and delay time. Detection range up to 7 meters with 120-degree detection angle. Operating voltage: 4.5-20V DC. Features low power consumption and reliable performance. Perfect for security systems, automatic lighting control, and energy-saving applications. 178 4.25 Sensors & Modules Motion & Proximity Sensors 1-2 Tage 6943185501029
11 DEV010 BH1750 Digital Light Sensor Digital ambient light sensor with I2C interface and 16-bit resolution. Measurement range: 1-65535 lux. Features low power consumption and high precision. No need for external components. Ideal for display backlight control in mobile devices, automatic brightness adjustment systems, and environmental light monitoring. 95 6.80 Sensors & Modules Light, Color & Gesture Sensors 2-3 Tage 8591854063235
12 DEV011 APDS-9960 Gesture Sensor Advanced gesture detection, proximity sensing, and ambient light sensor in one module. Features I2C interface with interrupt output. Can detect simple gestures (up, down, left, right) and measure proximity up to 20cm. Perfect for touchless interfaces, interactive displays, and smart home control. 63 15.75 Sensors & Modules Light, Color & Gesture Sensors 3-5 Tage 8717478034038
13 DEV012 MQ-2 Gas Sensor Module Semiconductor gas sensor for detecting LPG, propane, hydrogen, methane, alcohol, and smoke. Analog and digital output with adjustable sensitivity. Heating voltage: 5V±0.2V. Fast response and recovery time. Suitable for gas leak detection in home and industry, air quality monitoring, and safety systems. 112 8.45 Sensors & Modules Gas, Air Quality & Pressure Sensors 2-3 Tage 6943185501036
14 DEV013 BMP2810 Barometric Pressure Sensor High-precision digital barometric pressure and temperature sensor with I2C and SPI interfaces. Pressure range: 300-1100 hPa with ±1 hPa absolute accuracy. Temperature measurement with ±1.0°C accuracy. Low power consumption. Ideal for weather stations, altitude tracking, and indoor navigation. 87 9.20 Sensors & Modules Gas, Air Quality & Pressure Sensors 2-3 Tage 8591854063242
15 DEV014 NEO-6M GPS Module GPS receiver module with built-in EEPROM and ceramic antenna. Provides accurate positioning with 2.5m accuracy. Supports up to 5Hz update rate with NMEA protocol. Operating voltage: 3.3-5V. Features low power consumption and hot start capability. Perfect for navigation systems, tracking devices, and drones. 134 18.90 Sensors & Modules GPS & Location Modules 3-5 Tage 8717478034045
16 DEV015 RC522 RFID Reader Module RFID reader/writer operating at 13.56MHz with SPI interface. Reading distance up to 5cm. Supports ISO 14443A standard tags. Operating voltage: 2.5-3.3V. Ideal for access control systems, attendance tracking, payment systems, and interactive applications. 198 7.85 Sensors & Modules RFID & NFC Modules 1-2 Tage 6943185501043
17 DEV016 37-in-1 Sensor Module Kit Comprehensive sensor kit containing 37 most popular modules including temperature, humidity, motion, light, sound, and gas sensors. Comes with tutorial CD and connection diagrams. Perfect for beginners learning electronics and IoT programming. All modules are compatible with Arduino and Raspberry Pi. 45 89.99 Sensors & Modules Sensor Kits 5-7 Tage 7630049200030
18 DEV017 SG90 Micro Servo Motor TowerPro SG90 mini servo motor with 180-degree rotation range. Operating voltage: 4.8V. Stall torque: 1.8kg/cm. Comes with plastic gears and three-wire interface (power, ground, signal). Ideal for robotics, RC models, camera positioning, and small automation projects. 312 4.75 Actuators & Output Motors 1-2 Tage 6940541880025
19 DEV018 28BYJ-48 Stepper Motor with Driver Unipolar stepper motor with ULN2003 driver board. Step angle: 5.625° x 1/64 reduction ratio. Operating voltage: 5-12V DC. Provides precise position control without feedback. Perfect for 3D printers, CNC machines, automated curtains, and precision positioning systems. 167 12.50 Actuators & Output Motors 2-3 Tage 8591854063259
20 DEV019 L298N Motor Driver Module Dual H-bridge motor driver capable of driving two DC motors or one stepper motor. Operating voltage: 5-35V. Maximum current: 2A per channel. Features logic level conversion and heat sink. Ideal for robotics projects, motor control applications, and high-power driving needs. 98 8.95 Actuators & Output Motor Drivers & Controllers 2-3 Tage 8717478034052
21 DEV020 5V Relay Module Single channel relay module with optocoupler isolation. Operating voltage: 5V. Switching capacity: 10A 250V AC or 30V DC. Features status LED and standard interface for easy connection to microcontrollers. Perfect for controlling high-voltage appliances with low-voltage circuits. 245 3.25 Actuators & Output Relays & Switches 1-2 Tage 6943185501050
22 DEV021 16x2 LCD Display with I2C Blue backlight LCD display with 16 characters x 2 lines and I2C interface module. Operating voltage: 5V. Contrast adjustable. The I2C interface reduces required GPIO pins from 6 to 2. Ideal for displaying system status, sensor readings, and user interface information. 143 14.99 Actuators & Output Displays 2-3 Tage 7630049200047
23 DEV022 0.96 inch OLED Display 128x64 pixel OLED display with SSD1306 driver and I2C/SPI interface. Features high contrast, wide viewing angle, and low power consumption. Operating voltage: 3.3-5V. Perfect for projects requiring compact, high-quality graphics display. 189 10.45 Actuators & Output Displays 2-3 Tage 1931000001061
24 DEV023 5mm RGB LED Common Cathode Diffused RGB LED with common cathode configuration. Operating voltage: 2.0-2.5V (Red), 3.0-3.4V (Green/Blue). Maximum current: 20mA per color. Provides full color spectrum mixing. Ideal for status indicators, mood lighting, and visual feedback in projects. 500 0.75 Actuators & Output LEDs & Lighting 1-2 Tage 8591854063266
25 DEV024 Active Buzzer Module 5V active buzzer with built-in oscillator that produces continuous sound when powered. Operating voltage: 3.3-5V. Sound output: approximately 85dB. Easy to drive with microcontroller digital pin. Perfect for alarm systems, timers, and user notification applications. 287 2.10 Actuators & Output Buzzers & Speakers 1-2 Tage 6943185501067
26 DEV025 1K Ohm Resistor Pack Assortment of 100 pieces 1K ohm 1/4W metal film resistors with 1% tolerance. Temperature coefficient: 50ppm/°C. Perfect for pull-up/pull-down resistors, voltage dividers, and current limiting in various electronic circuits. 15 4.99 Components & Parts Resistors, Capacitors, Potentiometers 1-2 Tage 8717478034069
27 DEV026 100uF Electrolytic Capacitor Radial lead electrolytic capacitor with 25V voltage rating. Operating temperature: -40°C to +85°C. Low ESR and high ripple current capability. Ideal for power supply filtering, audio circuits, and general decoupling applications. 420 0.25 Components & Parts Resistors, Capacitors, Potentiometers 1-2 Tage 6940541880032
28 DEV027 10K Ohm Linear Potentiometer Rotary potentiometer with 10K ohm resistance and linear taper. Shaft length: 15mm. Power rating: 0.5W. Features smooth rotation and reliable performance. Perfect for volume control, brightness adjustment, and parameter tuning. 195 1.20 Components & Parts Resistors, Capacitors, Potentiometers 1-2 Tage 8591854063273
29 DEV028 2N2222A NPN Transistor General purpose NPN bipolar junction transistor in TO-92 package. Collector current: 800mA max. Collector-emitter voltage: 40V max. Gain bandwidth: 250MHz. Ideal for switching and amplification applications in various electronic circuits. 876 0.35 Components & Parts Transistors & MOSFETs 1-2 Tage 7630049200054
30 DEV029 IRFZ44N N-Channel MOSFET Power MOSFET with low on-resistance and fast switching speed. Drain-source voltage: 55V. Continuous drain current: 49A. TO-220 package. Perfect for motor control, power switching, and high-current applications. 321 2.15 Components & Parts Transistors & MOSFETs 1-2 Tage 1931000001078
31 DEV030 1N4007 Rectifier Diode General purpose rectifier diode with 1000V maximum repetitive reverse voltage and 1A average forward current. DO-41 package. Ideal for power supply rectification, reverse polarity protection, and general purpose switching. 650 0.15 Components & Parts Diodes & LEDs 1-2 Tage 8717478034076
32 DEV031 5mm Green LED Diffused green LED with 20mA forward current and 2.1V forward voltage. Viewing angle: 30 degrees. Luminous intensity: 5000-8000 mcd. Perfect for status indicators, panel lights, and visual feedback in electronic projects. 1200 0.20 Components & Parts Diodes & LEDs 1-2 Tage 6943185501074
33 DEV032 6x6mm Tactile Switch Momentary push button switch with through-hole mounting. Operating force: 160±50gf. Contact resistance: <50mΩ. Life expectancy: 100,000 cycles. Ideal for user input, reset buttons, and control interfaces. 890 0.10 Components & Parts Buttons & Switches 1-2 Tage 8591854063280
34 DEV033 Toggle Switch SPDT Single pole double throw toggle switch with on-on configuration. Rating: 6A 125V AC / 3A 250V AC. Panel mount design with nut and washer. Perfect for power switching, mode selection, and circuit configuration. 134 2.95 Components & Parts Buttons & Switches 2-3 Tage 6940541880049
35 DEV034 Jumper Wires Male-to-Male Bundle of 120 pieces 20cm male-to-male jumper wires in multiple colors. 0.1 pitch. Made with high-quality Dupont connectors. Perfect for breadboard connections, prototyping, and wiring Arduino projects. 45 6.99 Components & Parts Wires, Cables & Connectors 1-2 Tage 7630049200061
36 DEV035 USB Type B Cable 1.5 meter USB 2.0 Type A to Type B cable with gold-plated connectors. Data transfer speed up to 480Mbps. 28AWG power conductors. Perfect for connecting Arduino boards, printers, and other devices with Type B接口. 178 7.50 Components & Parts Wires, Cables & Connectors 1-2 Tage 1931000001085
37 DEV036 400-Point Solderless Breadboard High-quality solderless breadboard with 400 tie points. Features two power rails and 63 rows of interconnected terminals. Adhesive backing for secure mounting. Maximum voltage: 300V. Ideal for circuit prototyping and testing. 67 8.25 Components & Parts Breadboards & Prototyping 1-2 Tage 8717478034083
38 DEV037 Breadboard Jumper Wire Kit Kit containing 140 pieces of pre-cut and stripped jumper wires in various lengths and colors. Includes male-to-male, male-to-female, and female-to-female types. Organized in convenient storage box. Perfect for breadboard prototyping. 92 12.99 Components & Parts Breadboards & Prototyping 1-2 Tage 6943185501081
39 DEV038 12V 2A Power Supply Switching power adapter with 12V DC output and 2A maximum current. Input: 100-240V AC. Comes with 5.5mm x 2.1mm barrel jack connector. Short circuit and overvoltage protection. Ideal for powering Arduino projects, LED strips, and various electronics. 58 14.95 Power & Battery Power Supplies 3-5 Tage 8591854063297
40 DEV039 5V 3A USB Power Supply High-current USB power supply with 5V 3A output. Features built-in USB Type-A port and overcurrent protection. Input: 100-240V AC. Perfect for powering Raspberry Pi, high-power USB devices, and charging applications. 47 11.50 Power & Battery Power Supplies 2-3 Tage 6940541880056
41 DEV040 4xAA Battery Holder Plastic battery holder for 4 AA batteries with series connection providing 6V output. Features wire leads with stripped ends and on/off switch. Secure battery closure. Perfect for portable projects and backup power. 124 3.75 Power & Battery Battery Holders 1-2 Tage 7630049200078
42 DEV041 TP4056 Lithium Charger Module Single cell lithium battery charging module with 1A maximum charge current. Features charging status indicators and protection circuits. Input: 5V USB. Supports 3.7V Li-ion and LiPo batteries. Perfect for portable projects. 216 4.25 Power & Battery Charging Circuits 2-3 Tage 1931000001092
43 DEV042 LM2596 DC-DC Buck Converter Adjustable step-down voltage regulator module with 3A maximum output current. Input voltage: 4.5-40V. Output voltage: 1.5-35V adjustable. Efficiency up to 92%. Features overheat and short circuit protection. 189 5.95 Power & Battery Voltage Regulators & Converters 2-3 Tage 8717478034090
44 DEV043 60W Soldering Station Temperature controlled soldering station with 60W power and adjustable temperature range 200-480°C. Features ceramic heating element, sleep mode, and digital display. Comes with soldering iron stand and sponge. Perfect for electronics repair and prototyping. 34 49.99 Tools & Equipment Soldering Equipment 5-7 Tage 6943185501098
45 DEV044 Digital Multimeter DT9205A 3-1/2 digit digital multimeter with LCD display. Measures AC/DC voltage, current, resistance, capacitance, frequency, and temperature. Features diode test, continuity buzzer, and data hold. Comes with test leads and carrying case. 29 38.50 Tools & Equipment Multimeters & Test Equipment 3-5 Tage 8591854063303
46 DEV045 65-Piece Screwdriver Set Precision screwdriver set with 65 pieces including various Phillips, flat, Torx, and hex bits. Magnetic tips and comfortable handle. Organized in durable carrying case. Perfect for electronics repair, smartphone disassembly, and精密 work. 56 24.95 Tools & Equipment Tool Kits 2-3 Tage 6940541880063
47 DEV046 Plastic Project Enclosure 160x100x60mm Plastic electronic project box with dimensions 160x100x60mm. Features mounting posts for PCBs, ventilation slots, and removable lid. Material: ABS plastic. Perfect for housing electronic projects and prototypes. 78 9.75 Tools & Equipment Enclosures & Boxes 3-5 Tage 7630049200085
48 DEV047 Arduino Nano Every Compact board based on the ATMega4809 with 20MHz operating frequency. Features 48KB flash, 6KB SRAM, and 22 GPIO pins. Compatible with Arduino Nano footprint. Perfect for space-constrained projects requiring Arduino compatibility. 91 18.50 Microcontroller & Development Boards Arduino Boards 3-5 Tage 7630049200092
49 DEV048 Raspberry Pi Pico W Microcontroller board with RP2040 chip and wireless connectivity. Features 264KB SRAM, 2MB flash, and 30 GPIO pins. Supports MicroPython and C/C++. Built-in Wi-Fi and Bluetooth. Ideal for IoT projects and wireless applications. 167 9.95 Microcontroller & Development Boards Raspberry Pi Boards 2-3 Tage 1931000001108
50 DEV049 ESP32-CAM Development Board ESP32 module with OV2640 camera and microSD card slot. Features 4MB flash, 520KB SRAM, and supports Wi-Fi and Bluetooth. Provides video streaming and image capture capabilities. Perfect for security cameras and IoT vision applications. 124 15.75 Microcontroller & Development Boards ESP32/8266 Boards 3-5 Tage 8717478034106
51 DEV050 ATtiny85 Development Board Compact development board based on ATtiny85 microcontroller. Features 8KB flash, 512B SRAM, and 6 GPIO pins. Operating voltage: 5V. Perfect for simple projects requiring minimal I/O and small form factor. 205 6.25 Microcontroller & Development Boards Other Microcontrollers 2-3 Tage 6943185501104
52 DEV051 Arduino Ethernet Shield Network connectivity shield for Arduino with W5500 Ethernet controller. Supports TCP/IP protocols and provides SD card slot. Operating voltage: 5V. Perfect for network-connected projects and data logging. 76 32.99 Microcontroller & Development Boards Accessories 4-6 Tage 8591854063310
53 DEV052 Raspberry Pi Official Power Supply Official 15.3W USB-C power supply for Raspberry Pi 4. Output: 5.1V DC, 3A. Features noise filtering and overcurrent protection. Includes 1.5m USB-C cable. Ensures stable power for Raspberry Pi operation. 142 11.99 Microcontroller & Development Boards Accessories 2-3 Tage 6940541880070
54 DEV053 DS18B20 Waterproof Temperature Sensor Digital temperature sensor with 1-wire interface and waterproof stainless steel probe. Measurement range: -55°C to +125°C with ±0.5°C accuracy. 1-meter cable length. Perfect for liquid temperature measurement, environmental monitoring, and industrial applications. 188 8.95 Sensors & Modules Temperature & Humidity Sensors 2-3 Tage 7630049200108
55 DEV054 HC-SR501 PIR Motion Sensor Passive infrared motion detector with adjustable time and sensitivity. Detection range: 7 meters with 120° angle. Operating voltage: 4.5-20V DC. Features low power consumption. Ideal for security systems and automatic lighting. 156 4.50 Sensors & Modules Motion & Proximity Sensors 1-2 Tage 1931000001115
56 DEV055 VL53L0X Laser Distance Sensor Time-of-flight laser ranging sensor with 2m measurement range and 1mm resolution. I2C interface. Operating voltage: 2.6-3.5V. Features high accuracy and immune to ambient light. Perfect for gesture recognition and proximity sensing. 97 14.25 Sensors & Modules Motion & Proximity Sensors 3-5 Tage 8717478034113
57 DEV056 TCS34725 Color Sensor RGB color light sensor with IR filter and white LED. I2C interface with interrupt output. Provides clear, red, green, blue, and lux measurements. Perfect for color sorting, ambient light sensing, and display calibration. 84 13.75 Sensors & Modules Light, Color & Gesture Sensors 2-3 Tage 6943185501111
58 DEV057 VCNL4040 Proximity Sensor Integrated proximity and ambient light sensor with I2C interface. Proximity range: 0-200mm. Features interrupt function and low power consumption. Perfect for touchless interfaces and presence detection. 119 9.80 Sensors & Modules Light, Color & Gesture Sensors 2-3 Tage 8591854063327
59 DEV058 MQ-135 Air Quality Sensor Semiconductor sensor for detecting harmful gases like NH3, NOx, alcohol, benzene, and CO2. Analog output with adjustable sensitivity. Heating voltage: 5V±0.1V. Suitable for air quality monitoring and environmental detection. 145 7.25 Sensors & Modules Gas, Air Quality & Pressure Sensors 2-3 Tage 6940541880087
60 DEV059 BME280 Environmental Sensor Integrated environmental sensor measuring temperature, humidity, and barometric pressure. I2C/SPI interfaces. Operating voltage: 1.8-3.6V. Low power consumption. Ideal for weather stations and environmental monitoring. 132 14.50 Sensors & Modules Gas, Air Quality & Pressure Sensors 3-5 Tage 7630049200115
61 DEV060 U-blox NEO-M8N GPS Module High-performance GPS module with 72 channels and 2.5m accuracy. Supports GPS, GLONASS, and BeiDou systems. Update rate: up to 10Hz. Perfect for drones, navigation systems, and precision tracking. 89 26.95 Sensors & Modules GPS & Location Modules 4-6 Tage 1931000001122
62 DEV061 PN532 NFC RFID Module NFC/RFID reader/writer supporting ISO 14443A/B, ISO 18092, and FeliCa protocols. Operating frequency: 13.56MHz. Interfaces: I2C, SPI, HSU. Reading distance: up to 5cm. Ideal for contactless payment and access control. 107 18.75 Sensors & Modules RFID & NFC Modules 3-5 Tage 8717478034120
63 DEV062 Arduino Sensor Kit Complete sensor kit containing 37 modules compatible with Arduino. Includes tutorials and code examples. Covers basic to advanced sensors. Perfect for educational purposes and learning electronics. 68 79.99 Sensors & Modules Sensor Kits 5-7 Tage 6943185501128
64 DEV063 NEMA 17 Stepper Motor Bipolar stepper motor with 1.8° step angle and 42mm frame size. Holding torque: 40Ncm. Current: 1.2A per phase. 4-wire connection. Perfect for 3D printers, CNC machines, and precision positioning systems. 45 28.95 Actuators & Output Motors 4-6 Tage 8591854063334
65 DEV064 L293D Motor Driver IC Quadruple half-H driver for bidirectional DC motor control. Operating voltage: 4.5-36V. Output current: 600mA per channel. DIP-16 package. Perfect for controlling small motors and solenoids. 213 3.45 Actuators & Output Motor Drivers & Controllers 1-2 Tage 6940541880094
66 DEV065 5V 4-Channel Relay Module 4-channel relay module with optocoupler isolation and status LEDs. Operating voltage: 5V. Switching capacity: 10A 250V AC per channel. Features screw terminals and standard control interface. 124 15.50 Actuators & Output Relays & Switches 2-3 Tage 7630049200122
67 DEV066 20x4 LCD Display with I2C Large LCD display with 20 characters x 4 lines and I2C interface. Blue backlight with adjustable contrast. Operating voltage: 5V. Perfect for projects requiring extensive text display. 87 19.95 Actuators & Output Displays 3-5 Tage 1931000001139
68 DEV067 1.3 inch IPS LCD Display 1.3 inch IPS display with 240x240 resolution and ST7789 driver. SPI interface with 65K colors. Operating voltage: 3.3V. Features high brightness and wide viewing angle. Perfect for graphics and GUI applications. 134 16.75 Actuators & Output Displays 3-5 Tage 8717478034137
69 DEV068 WS2812B RGB LED Strip Addressable RGB LED strip with 30 LEDs per meter. Each LED individually controllable via single-wire protocol. Operating voltage: 5V. Perfect for decorative lighting, art installations, and visual effects. 78 18.50 Actuators & Output LEDs & Lighting 2-3 Tage 6943185501135
70 DEV069 Piezo Buzzer Element Passive piezo buzzer without internal oscillator. Requires external driver circuit. Operating voltage: 3-20V. Resonant frequency: 4kHz. Compact size. Ideal for custom tone generation and audio projects. 345 1.25 Actuators & Output Buzzers & Speakers 1-2 Tage 8591854063341
71 DEV070 Assorted Resistor Kit Comprehensive resistor kit with 1000 pieces covering values from 10 ohm to 1M ohm. 1/4W metal film with 1% tolerance. Organized in storage box with value labels. Perfect for electronics projects and repairs. 28 29.99 Components & Parts Resistors, Capacitors, Potentiometers 2-3 Tage 6940541880100
72 DEV071 100nF Ceramic Capacitor Multilayer ceramic capacitor with 100nF capacitance and 50V rating. X7R dielectric material. Through-hole design. Ideal for decoupling, filtering, and timing applications. 1200 0.15 Components & Parts Resistors, Capacitors, Potentiometers 1-2 Tage 7630049200139
73 DEV072 200K Logarithmic Potentiometer Audio taper potentiometer with 100K ohm resistance. Shaft length: 20mm. Power rating: 0.5W. Smooth rotation with logarithmic response. Perfect for volume controls and audio applications. 167 2.25 Components & Parts Resistors, Capacitors, Potentiometers 1-2 Tage 1931000001146
74 DEV073 BC547 NPN Transistor General purpose NPN transistor in TO-92 package. Collector current: 100mA max. Collector-emitter voltage: 45V. DC current gain: 110-800. Ideal for amplification and switching applications. 954 0.25 Components & Parts Transistors & MOSFETs 1-2 Tage 8717478034144
75 DEV074 IRF540N N-Channel MOSFET Power MOSFET with 100V drain-source voltage and 33A continuous drain current. Low on-resistance: 44mΩ. TO-220 package. Perfect for high-power switching and motor control applications. 189 3.75 Components & Parts Transistors & MOSFETs 1-2 Tage 6943185501142
76 DEV075 1N4148 Switching Diode Fast switching diode with 100V reverse voltage and 200mA forward current. Switching speed: 4ns. DO-35 package. Ideal for high-speed switching, protection circuits, and signal processing. 875 0.12 Components & Parts Diodes & LEDs 1-2 Tage 8591854063358
77 DEV076 5mm Red LED Standard red LED with 20mA forward current and 2.0V forward voltage. Viewing angle: 30 degrees. Luminous intensity: 2000-4000 mcd. Perfect for indicators and visual feedback. 1500 0.18 Components & Parts Diodes & LEDs 1-2 Tage 6940541880117
78 DEV077 12mm Push Button Switch Momentary push button switch with LED illumination. Operating voltage: 12V DC. Contact rating: 3A 125V AC. Panel mount design. Available in multiple colors. Perfect for control panels and user interfaces. 234 2.95 Components & Parts Buttons & Switches 2-3 Tage 7630049200146
79 DEV078 DIP Switch 8 Position 8-position dual in-line package switch with through-hole mounting. Rating: 50mA 24V DC. Compact size. Ideal for configuration settings and mode selection in electronic circuits. 187 1.85 Components & Parts Buttons & Switches 1-2 Tage 1931000001153
80 DEV079 Jumper Wires Female-to-Female Bundle of 120 pieces 20cm female-to-female jumper wires in multiple colors. 0.1 pitch. High-quality Dupont connectors. Perfect for connecting modules and sensors to development boards. 67 6.99 Components & Parts Wires, Cables & Connectors 1-2 Tage 8717478034151
81 DEV080 Micro USB Cable 1-meter Micro USB to USB Type-A cable with gold-plated connectors. Data transfer and charging capable. 28AWG power conductors. Perfect for connecting various electronic devices and charging. 245 5.50 Components & Parts Wires, Cables & Connectors 1-2 Tage 6943185501159
82 DEV081 830-Point Breadboard Large solderless breadboard with 830 tie points. Features four power rails and 63 rows of terminals. Adhesive backing. Maximum voltage: 300V. Ideal for complex circuit prototyping. 54 12.95 Components & Parts Breadboards & Prototyping 2-3 Tage 8591854063365
83 DEV082 Breadboard Power Supply Module 3.3V/5V breadboard power supply module with USB input. Maximum output current: 700mA. Features LED indicators and on/off switch. Perfect for providing stable power to breadboard projects. 138 8.45 Components & Parts Breadboards & Prototyping 2-3 Tage 6940541880124
84 DEV083 9V 1A Power Supply Wall adapter with 9V DC output and 1A maximum current. Input: 100-240V AC. 5.5mm x 2.1mm barrel jack. Short circuit protection. Ideal for powering effects pedals and various electronics. 89 9.99 Power & Battery Power Supplies 2-3 Tage 7630049200153
85 DEV084 USB-C Power Delivery Module USB-C power delivery module with adjustable voltage output (5V, 9V, 12V, 15V, 20V). Maximum power: 100W. Features digital display and multiple protection circuits. Perfect for modern power requirements. 76 22.50 Power & Battery Power Supplies 3-5 Tage 1931000001160
86 DEV085 18650 Battery Holder Dual 18650 battery holder with series/parallel switch. Provides 3.7V (parallel) or 7.4V (series) output. Features built-in protection circuit and power switch. Perfect for lithium battery projects. 112 6.95 Power & Battery Battery Holders 2-3 Tage 8717478034168
87 DEV086 TP5100 2A Lithium Charger Dual lithium battery charger module with 2A maximum charge current. Supports 3.7V Li-ion and LiPo batteries. Input: 5-12V. Features charging status indicators. Perfect for high-capacity battery charging. 98 7.25 Power & Battery Charging Circuits 2-3 Tage 6943185501166
88 DEV087 LM317 Adjustable Voltage Regulator Adjustable linear voltage regulator with 1.5A output current. Output voltage: 1.25-37V. Features overcurrent and thermal protection. TO-220 package. Perfect for custom power supply designs. 167 2.95 Power & Battery Voltage Regulators & Converters 1-2 Tage 8591854063372
89 DEV088 Temperature Controlled Soldering Iron 60W temperature controlled soldering iron with adjustable temperature 200-450°C. Features ceramic heater and quick heat-up time. Includes stand and spare tips. Perfect for basic soldering tasks. 45 35.99 Tools & Equipment Soldering Equipment 3-5 Tage 6940541880131
90 DEV089 Auto-Ranging Multimeter True RMS auto-ranging digital multimeter with 6000 counts. Measures AC/DC voltage, current, resistance, capacitance, frequency, and temperature. Features backlit display and data hold. 38 59.95 Tools & Equipment Multimeters & Test Equipment 4-6 Tage 7630049200160

File diff suppressed because it is too large Load diff

156
dynamixs-ai-a2a/pom.xml Normal file
View file

@ -0,0 +1,156 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>dynamixs-ai</artifactId>
<groupId>ai.dynamixs</groupId>
<version>1.0.1</version>
</parent>
<artifactId>dynamixs-ai-a2a</artifactId>
<packaging>jar</packaging>
<name>Dynamixs AI A2A Library</name>
<build>
<plugins>
<!-- use JDK settings for compiling -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.source}</source>
<target>${java.target}</target>
</configuration>
</plugin>
<!-- Testing JUnit 5 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<!-- issue #572
hack for:
https://stackoverflow.com/questions/75116023/unable-to-make-protected-final-java-lang-class-java-lang-classloader-defineclass
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>default-test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<argLine>
--add-opens java.base/java.lang=ALL-UNNAMED
</argLine>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Jakarta EE -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>${jakarta.version}</version>
<scope>provided</scope>
</dependency>
<!-- Microprofile -->
<dependency>
<groupId>org.eclipse.microprofile</groupId>
<artifactId>microprofile</artifactId>
<version>${microprofile.version}</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<!-- Imixs Workflow -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-core</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-engine</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-jax-rs</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-faces</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.parsson</groupId>
<artifactId>jakarta.json</artifactId>
<version>1.1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,448 @@
package ai.dynamixs.a2a;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import jakarta.json.Json;
import jakarta.json.JsonArray;
import jakarta.json.JsonArrayBuilder;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;
import jakarta.json.JsonString;
import jakarta.json.JsonValue;
/**
* Represents an A2A Skill Card based on Imixs-Workflow BPMN models.
*
* The skill ID follows the pattern: {modelVersion}_{taskId}_{eventId} This
* allows direct mapping to Imixs workflow execution parameters.
*
* Example: "office-de-2.0_100_10" represents: - Model Version: "office-de-2.0"
* - Task ID: 100 - Event ID: 10
*/
public class A2ASkillCard implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(A2ASkillCard.class.getSimpleName());
// A2A Standard Fields
private String id; // {modelVersion}_{taskId}_{eventId}
private String name; // Human-readable skill name
private String description; // Detailed description
private List<String> tags; // Categorization tags
private List<String> examples; // Example usage scenarios
private List<String> inputModes; // Supported input media types
private List<String> outputModes; // Supported output media types
private Map<String, Object> metadata; // Additional metadata
// Constructors
public A2ASkillCard() {
this.tags = new ArrayList<>();
this.examples = new ArrayList<>();
this.inputModes = new ArrayList<>();
this.outputModes = new ArrayList<>();
this.metadata = new HashMap<>();
}
/**
* Id is computed by version, task and event id "invoice-workflow-2.1_100_10"
*
* @param modelVersion
* @param taskID
* @param eventID
*/
public A2ASkillCard(String modelVersion, int taskID, int eventID) {
this();
this.id = createSkillId(modelVersion, taskID, eventID);
}
// Imixs-specific convenience methods for parsing skill ID
/**
* Extracts the model version from the skill ID
*
* @return model version (e.g., "office-de-2.0")
*/
public String getModelVersion() {
if (id == null || !id.contains("_")) {
throw new IllegalStateException("Invalid skill ID format: " + id);
}
return id.substring(0, id.lastIndexOf('_', id.lastIndexOf('_') - 1));
}
/**
* Extracts the task ID from the skill ID
*
* @return Imixs task ID as integer
*/
public int getTaskId() {
if (id == null || !id.contains("_")) {
throw new IllegalStateException("Invalid skill ID format: " + id);
}
String[] parts = id.split("_");
if (parts.length < 3) {
throw new IllegalStateException("Invalid skill ID format: " + id);
}
try {
return Integer.parseInt(parts[parts.length - 2]);
} catch (NumberFormatException e) {
throw new IllegalStateException("Invalid task ID in skill ID: " + id, e);
}
}
/**
* Extracts the event ID from the skill ID
*
* @return Imixs event ID as integer
*/
public int getEventId() {
if (id == null || !id.contains("_")) {
throw new IllegalStateException("Invalid skill ID format: " + id);
}
String[] parts = id.split("_");
if (parts.length < 3) {
throw new IllegalStateException("Invalid skill ID format: " + id);
}
try {
return Integer.parseInt(parts[parts.length - 1]);
} catch (NumberFormatException e) {
throw new IllegalStateException("Invalid event ID in skill ID: " + id, e);
}
}
/**
* Creates a skill ID from Imixs workflow components
*
* @param modelVersion the workflow model version
* @param taskId the task ID
* @param eventId the event ID
* @return formatted skill ID
*/
public static String createSkillId(String modelVersion, int taskId, int eventId) {
if (modelVersion == null || modelVersion.trim().isEmpty()) {
throw new IllegalArgumentException("Model version cannot be null or empty");
}
return String.format("%s_%d_%d", modelVersion, taskId, eventId);
}
// JSON Serialization
/**
* Converts this skill card to a Jakarta JSON object
*
* @return JsonObject representation of this skill card
*/
public JsonObject toJsonObject() {
JsonObjectBuilder builder = Json.createObjectBuilder()
.add("id", id != null ? id : "")
.add("name", name != null ? name : "")
.add("description", description != null ? description : "");
// Tags array
JsonArrayBuilder tagsBuilder = Json.createArrayBuilder();
if (tags != null) {
tags.forEach(tagsBuilder::add);
}
builder.add("tags", tagsBuilder.build());
// Examples array
JsonArrayBuilder examplesBuilder = Json.createArrayBuilder();
if (examples != null) {
examples.forEach(examplesBuilder::add);
}
builder.add("examples", examplesBuilder.build());
// Input modes array
JsonArrayBuilder inputModesBuilder = Json.createArrayBuilder();
if (inputModes != null) {
inputModes.forEach(inputModesBuilder::add);
}
builder.add("inputModes", inputModesBuilder.build());
// Output modes array
JsonArrayBuilder outputModesBuilder = Json.createArrayBuilder();
if (outputModes != null) {
outputModes.forEach(outputModesBuilder::add);
}
builder.add("outputModes", outputModesBuilder.build());
// Metadata object
if (metadata != null && !metadata.isEmpty()) {
JsonObjectBuilder metadataBuilder = Json.createObjectBuilder();
metadata.forEach((key, value) -> {
if (value instanceof String) {
metadataBuilder.add(key, (String) value);
} else if (value instanceof Number) {
metadataBuilder.add(key, ((Number) value).doubleValue());
} else if (value instanceof Boolean) {
metadataBuilder.add(key, (Boolean) value);
} else if (value != null) {
metadataBuilder.add(key, value.toString());
}
});
builder.add("metadata", metadataBuilder.build());
}
return builder.build();
}
/**
* Creates an A2ASkillCard from a JSON string
*
* @param jsonString JSON representation of a skill card
* @return A2ASkillCard instance
*/
// public static A2ASkillCard fromJsonString(String jsonString) {
// try (JsonReader reader = Json.createReader(new
// java.io.StringReader(jsonString))) {
// JsonObject jsonObject = reader.readObject();
// return fromJsonObject(jsonObject);
// } catch (Exception e) {
// logger.severe("Failed to parse A2ASkillCard from JSON: " + e.getMessage());
// throw new IllegalArgumentException("Invalid JSON format for A2ASkillCard",
// e);
// }
// }
/**
* Creates an A2ASkillCard from a JsonObject
*
* @param jsonObject JsonObject representation
* @return A2ASkillCard instance
*/
public static A2ASkillCard fromJsonObject(JsonObject jsonObject) {
A2ASkillCard skill = new A2ASkillCard();
// Basic fields
skill.setId(jsonObject.getString("id", ""));
skill.setName(jsonObject.getString("name", ""));
skill.setDescription(jsonObject.getString("description", ""));
// Arrays
if (jsonObject.containsKey("tags")) {
JsonArray tagsArray = jsonObject.getJsonArray("tags");
skill.setTags(jsonArrayToStringList(tagsArray));
}
if (jsonObject.containsKey("examples")) {
JsonArray examplesArray = jsonObject.getJsonArray("examples");
skill.setExamples(jsonArrayToStringList(examplesArray));
}
if (jsonObject.containsKey("inputModes")) {
JsonArray inputModesArray = jsonObject.getJsonArray("inputModes");
skill.setInputModes(jsonArrayToStringList(inputModesArray));
}
if (jsonObject.containsKey("outputModes")) {
JsonArray outputModesArray = jsonObject.getJsonArray("outputModes");
skill.setOutputModes(jsonArrayToStringList(outputModesArray));
}
// Metadata
if (jsonObject.containsKey("metadata")) {
JsonObject metadataObject = jsonObject.getJsonObject("metadata");
Map<String, Object> metadata = new HashMap<>();
metadataObject.forEach((key, value) -> {
switch (value.getValueType()) {
case STRING:
metadata.put(key, ((JsonString) value).getString());
break;
case NUMBER:
metadata.put(key, ((jakarta.json.JsonNumber) value).doubleValue());
break;
case TRUE:
metadata.put(key, Boolean.TRUE);
break;
case FALSE:
metadata.put(key, Boolean.FALSE);
break;
default:
metadata.put(key, value.toString());
}
});
skill.setMetadata(metadata);
}
return skill;
}
/**
* Helper method to convert JsonArray to List<String>
*/
private static List<String> jsonArrayToStringList(JsonArray jsonArray) {
List<String> list = new ArrayList<>();
for (JsonValue value : jsonArray) {
if (value.getValueType() == JsonValue.ValueType.STRING) {
list.add(((JsonString) value).getString());
} else {
list.add(value.toString());
}
}
return list;
}
// Validation
/**
* Validates this skill card for A2A compliance
*
* @return true if valid, false otherwise
*/
public boolean isValid() {
if (id == null || id.trim().isEmpty()) {
logger.warning("Skill card validation failed: missing ID");
return false;
}
if (name == null || name.trim().isEmpty()) {
logger.warning("Skill card validation failed: missing name");
return false;
}
if (description == null || description.trim().isEmpty()) {
logger.warning("Skill card validation failed: missing description");
return false;
}
// Validate skill ID format
try {
getModelVersion();
getTaskId();
getEventId();
} catch (Exception e) {
logger.warning("Skill card validation failed: invalid ID format: " + id);
return false;
}
return true;
}
// Getters and Setters
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags != null ? tags : new ArrayList<>();
}
public List<String> getExamples() {
return examples;
}
public void setExamples(List<String> examples) {
this.examples = examples != null ? examples : new ArrayList<>();
}
public List<String> getInputModes() {
return inputModes;
}
public void setInputModes(List<String> inputModes) {
this.inputModes = inputModes != null ? inputModes : new ArrayList<>();
}
public List<String> getOutputModes() {
return outputModes;
}
public void setOutputModes(List<String> outputModes) {
this.outputModes = outputModes != null ? outputModes : new ArrayList<>();
}
public Map<String, Object> getMetadata() {
return metadata;
}
public void setMetadata(Map<String, Object> metadata) {
this.metadata = metadata != null ? metadata : new HashMap<>();
}
// Convenience methods for metadata
/**
* Adds a metadata entry
*/
public void addMetadata(String key, Object value) {
if (metadata == null) {
metadata = new HashMap<>();
}
metadata.put(key, value);
}
/**
* Gets a metadata value as String
*/
public String getMetadataString(String key) {
Object value = metadata != null ? metadata.get(key) : null;
return value != null ? value.toString() : null;
}
/**
* Gets a metadata value as Boolean
*/
public Boolean getMetadataBoolean(String key) {
Object value = metadata != null ? metadata.get(key) : null;
if (value instanceof Boolean) {
return (Boolean) value;
}
return null;
}
// toString for debugging
@Override
public String toString() {
return String.format("A2ASkillCard{id='%s', name='%s', modelVersion='%s', taskId=%d, eventId=%d}",
id, name,
id != null ? getModelVersion() : "unknown",
id != null ? getTaskId() : -1,
id != null ? getEventId() : -1);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
A2ASkillCard that = (A2ASkillCard) obj;
return id != null ? id.equals(that.id) : that.id == null;
}
@Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
}

View file

@ -0,0 +1,436 @@
/*******************************************************************************
* Imixs Workflow
* Copyright (C) 2001, 2011 Imixs Software Solutions GmbH,
* http://www.imixs.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You can receive a copy of the GNU General Public
* License at http://www.gnu.org/licenses/gpl.html
*
* Project:
* http://www.imixs.org
* http://java.net/projects/imixs-workflow
*
* Contributors:
* Imixs Software Solutions GmbH - initial API and implementation
* Ralph Soika - Software Developer
*******************************************************************************/
package ai.dynamixs.a2a;
import java.io.Serializable;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.json.Json;
import jakarta.json.JsonArray;
import jakarta.json.JsonArrayBuilder;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriInfo;
/**
* The TextblockRestService provides methods to access the content of a textbock
* in various ways.
*
* @author rsoika
*
*/
@Named
@RequestScoped
@Path("/a2a/")
@Produces({ MediaType.TEXT_HTML, MediaType.APPLICATION_XHTML_XML, MediaType.TEXT_PLAIN })
public class A2ASkillCardRestService implements Serializable {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(A2ASkillCardRestService.class.getSimpleName());
@Context
UriInfo uriInfo;
@Inject
A2ASkillService a2aSkillService;
/**
* A2A Agent Card Discovery Endpoint According to RFC 8615 - Well-Known URIs
* URL: /.well-known/agent.json
*/
@GET
@Path("/.well-known/agent.json")
@Produces({ MediaType.APPLICATION_JSON })
public Response getAgentCard() {
try {
JsonObject agentCard = buildAgentCard();
return Response.ok(agentCard).build();
} catch (Exception e) {
logger.severe("Error creating agent card: " + e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(buildJsonRpcError(-32603, "Internal server error", null))
.build();
}
}
/**
* A2A JSON-RPC 2.0 Endpoint All A2A protocol methods are handled here URL:
* /a2a/v1 (as specified in Agent Card)
*/
@POST
@Path("/a2a/v1")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response handleJsonRpcRequest(JsonObject request) {
try {
// Validate JSON-RPC 2.0 structure
if (!isValidJsonRpcRequest(request)) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(buildJsonRpcError(-32600, "Invalid Request", null))
.build();
}
String method = request.getString("method");
Object id = request.get("id");
JsonObject params = request.getJsonObject("params");
// Route to appropriate A2A method
switch (method) {
case "message/send":
return handleMessageSend(id, params);
case "tasks/get":
return handleTasksGet(id, params);
case "tasks/cancel":
return handleTasksCancel(id, params);
case "agent/authenticatedExtendedCard":
return handleAuthenticatedExtendedCard(id, params);
default:
return Response.status(Response.Status.NOT_FOUND)
.entity(buildJsonRpcError(-32601, "Method not found", id))
.build();
}
} catch (Exception e) {
logger.severe("Error processing JSON-RPC request: " + e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(buildJsonRpcError(-32603, "Internal server error", null))
.build();
}
}
/**
* Builds the A2A compliant Agent Card
*/
private JsonObject buildAgentCard() {
// Security schemes for authentication
JsonObject securitySchemes = Json.createObjectBuilder()
.add("bearer", Json.createObjectBuilder()
.add("type", "http")
.add("scheme", "bearer")
.add("bearerFormat", "JWT")
.build())
.add("apiKey", Json.createObjectBuilder()
.add("type", "apiKey")
.add("in", "header")
.add("name", "X-API-Key")
.build())
.build();
// Security requirements
JsonArray security = Json.createArrayBuilder()
.add(Json.createObjectBuilder()
.add("bearer", Json.createArrayBuilder().build())
.build())
.build();
// Agent capabilities
JsonObject capabilities = Json.createObjectBuilder()
.add("streaming", false) // SSE not implemented yet
.add("pushNotifications", false) // Push notifications not implemented yet
.add("stateTransitionHistory", false)
.build();
// Agent provider information
JsonObject provider = Json.createObjectBuilder()
.add("organization", "Dynamixs.AI")
.add("url", "https://www.dynamixs.ai")
.build();
// Skills array
JsonArray skills = buildA2ASkills();
// Build complete A2A Agent Card
JsonObjectBuilder cardBuilder = Json.createObjectBuilder()
.add("name", "Dynamixs.AI Processing Agent")
.add("description",
"An agent for processing business documents and tasks.")
.add("url", getBaseUrl() + "a2a/v1") // JSON-RPC endpoint
.add("provider", provider)
.add("version", "1.0.0")
.add("documentationUrl", getBaseUrl() + "docs/a2a")
.add("capabilities", capabilities)
.add("securitySchemes", securitySchemes)
.add("security", security)
.add("defaultInputModes", Json.createArrayBuilder()
.add("text/plain")
.add("application/json")
.build())
.add("defaultOutputModes", Json.createArrayBuilder()
.add("text/plain")
.add("application/json")
.add("text/html")
.build())
.add("skills", skills)
.add("supportsAuthenticatedExtendedCard", false); // Simplified for now
return cardBuilder.build();
}
/**
* Builds A2A compliant skills array
*/
private JsonArray buildA2ASkills() {
logger.info("Starting to build A2A skills...");
List<A2ASkillCard> skills = a2aSkillService.parseModels();
logger.info("parseModels() returned " + (skills != null ? skills.size() : "null") + " skills");
if (skills != null) {
for (A2ASkillCard skill : skills) {
logger.info("Skill found: " + skill.getId() + " - Valid: " + skill.isValid());
if (!skill.isValid()) {
logger.warning("Invalid skill: " + skill);
}
}
}
List<A2ASkillCard> validSkills = skills.stream()
.filter(A2ASkillCard::isValid)
.collect(Collectors.toList());
logger.info("Valid skills after filtering: " + validSkills.size());
return validSkills.stream()
.map(A2ASkillCard::toJsonObject)
.collect(Json::createArrayBuilder,
JsonArrayBuilder::add,
JsonArrayBuilder::addAll)
.build();
}
/**
* Handle A2A message/send method
*/
private Response handleMessageSend(Object id, JsonObject params) {
try {
// Extract message from params
JsonObject message = params.getJsonObject("message");
if (message == null) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(buildJsonRpcError(-32602, "Invalid params: missing message",
id))
.build();
}
// Process the message and create a task
String taskId = generateTaskId();
String contextId = generateContextId();
// For demo: create a simple completed task
JsonObject task = Json.createObjectBuilder()
.add("id", taskId)
.add("contextId", contextId)
.add("status", Json.createObjectBuilder()
.add("state", "completed")
.add("timestamp", getCurrentTimestamp())
.build())
.add("artifacts", Json.createArrayBuilder()
.add(Json.createObjectBuilder()
.add("artifactId", generateArtifactId())
.add("name", "Processing Result")
.add("parts", Json.createArrayBuilder()
.add(Json.createObjectBuilder()
.add("kind", "text")
.add("text", "Task completed successfully. Message processed: "
+
message.getJsonArray(
"parts")
.getJsonObject(0)
.getString("text",
""))
.build())
.build())
.build())
.build())
.add("history", Json.createArrayBuilder()
.add(message)
.build())
.add("kind", "task")
.build();
// Return JSON-RPC success response
JsonObject response = Json.createObjectBuilder()
.add("jsonrpc", "2.0")
.add("id", id.toString())
.add("result", task)
.build();
return Response.ok(response).build();
} catch (Exception e) {
logger.severe("Error in message/send: " + e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(buildJsonRpcError(-32603, "Internal server error", id))
.build();
}
}
/**
* Handle A2A tasks/get method
*/
private Response handleTasksGet(Object id, JsonObject params) {
try {
String taskId = params.getString("id");
// For demo: return a mock task
JsonObject task = Json.createObjectBuilder()
.add("id", taskId)
.add("contextId", generateContextId())
.add("status", Json.createObjectBuilder()
.add("state", "completed")
.add("timestamp", getCurrentTimestamp())
.build())
.add("kind", "task")
.build();
JsonObject response = Json.createObjectBuilder()
.add("jsonrpc", "2.0")
.add("id", id.toString())
.add("result", task)
.build();
return Response.ok(response).build();
} catch (Exception e) {
logger.severe("Error in tasks/get: " + e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(buildJsonRpcError(-32001, "Task not found", id))
.build();
}
}
/**
* Handle A2A tasks/cancel method
*/
private Response handleTasksCancel(Object id, JsonObject params) {
try {
String taskId = params.getString("id");
JsonObject task = Json.createObjectBuilder()
.add("id", taskId)
.add("contextId", generateContextId())
.add("status", Json.createObjectBuilder()
.add("state", "canceled")
.add("timestamp", getCurrentTimestamp())
.build())
.add("kind", "task")
.build();
JsonObject response = Json.createObjectBuilder()
.add("jsonrpc", "2.0")
.add("id", id.toString())
.add("result", task)
.build();
return Response.ok(response).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(buildJsonRpcError(-32002, "Task cannot be canceled", id))
.build();
}
}
/**
* Handle authenticated extended card (not implemented)
*/
private Response handleAuthenticatedExtendedCard(Object id, JsonObject params) {
return Response.status(Response.Status.NOT_IMPLEMENTED)
.entity(buildJsonRpcError(-32004, "This operation is not supported", id))
.build();
}
/**
* Validates JSON-RPC 2.0 request structure
*/
private boolean isValidJsonRpcRequest(JsonObject request) {
return request.containsKey("jsonrpc") &&
"2.0".equals(request.getString("jsonrpc")) &&
request.containsKey("method") &&
request.containsKey("id");
}
/**
* Builds a JSON-RPC 2.0 error response
*/
private JsonObject buildJsonRpcError(int code, String message, Object id) {
JsonObjectBuilder errorBuilder = Json.createObjectBuilder()
.add("code", code)
.add("message", message);
JsonObjectBuilder responseBuilder = Json.createObjectBuilder()
.add("jsonrpc", "2.0")
.add("error", errorBuilder.build());
if (id != null) {
responseBuilder.add("id", id.toString());
} else {
responseBuilder.addNull("id");
}
return responseBuilder.build();
}
/**
* Helper methods for generating IDs and timestamps
*/
private String generateTaskId() {
return java.util.UUID.randomUUID().toString();
}
private String generateContextId() {
return java.util.UUID.randomUUID().toString();
}
private String generateArtifactId() {
return java.util.UUID.randomUUID().toString();
}
private String getCurrentTimestamp() {
return java.time.Instant.now().toString();
}
private String getBaseUrl() {
return uriInfo.getBaseUri().toString();
}
}

View file

@ -0,0 +1,152 @@
/*******************************************************************************
* Imixs Workflow
* Copyright (C) 2001, 2011 Imixs Software Solutions GmbH,
* http://www.imixs.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You can receive a copy of the GNU General Public
* License at http://www.gnu.org/licenses/gpl.html
*
* Project:
* http://www.imixs.org
* http://java.net/projects/imixs-workflow
*
* Contributors:
* Imixs Software Solutions GmbH - initial API and implementation
* Ralph Soika - Software Developer
*******************************************************************************/
package ai.dynamixs.a2a;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.ModelManager;
import org.imixs.workflow.engine.ModelService;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.exceptions.ModelException;
import org.imixs.workflow.exceptions.PluginException;
import org.openbpmn.bpmn.BPMNModel;
import jakarta.annotation.security.DeclareRoles;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ejb.LocalBean;
import jakarta.ejb.Stateless;
import jakarta.inject.Inject;
/**
* The A2ASkillService parses the model information to provide A2ASkillCards
*
* @author rsoika
*/
@DeclareRoles({ "org.imixs.ACCESSLEVEL.NOACCESS",
"org.imixs.ACCESSLEVEL.READERACCESS",
"org.imixs.ACCESSLEVEL.AUTHORACCESS",
"org.imixs.ACCESSLEVEL.EDITORACCESS",
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
@RolesAllowed({ "org.imixs.ACCESSLEVEL.NOACCESS",
"org.imixs.ACCESSLEVEL.READERACCESS",
"org.imixs.ACCESSLEVEL.AUTHORACCESS",
"org.imixs.ACCESSLEVEL.EDITORACCESS",
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
@Stateless
@LocalBean
public class A2ASkillService {
@Inject
ModelService modelService;
@Inject
WorkflowService workflowService;
private static Logger logger = Logger.getLogger(A2ASkillService.class
.getName());
/**
* This method iterates over all models and returns a list of skill card objects
*
* The method tests if a event has a <imixs-ai name="SKILL"> tag.
*
*/
public List<A2ASkillCard> parseModels() {
logger.log(Level.INFO, "├── 🔃 parsing A2A SkillCards....");
List<A2ASkillCard> result = new ArrayList<>();
ModelManager modelManager = new ModelManager(workflowService);
List<String> versions = modelService.getVersions();
try {
for (String version : versions) {
logger.log(Level.INFO, "│ ├── {0}", version);
BPMNModel model = modelManager.getModel(version);
Set<String> groups = modelManager.findAllGroupsByModel(model);
for (String group : groups) {
List<ItemCollection> tasks = modelManager.findTasks(model, group);
for (ItemCollection task : tasks) {
int taskID = task.getItemValueInteger("taskid");
List<ItemCollection> events = modelManager.findEventsByTask(model, taskID);
for (ItemCollection event : events) {
int eventID = event.getItemValueInteger("eventid");
// test if we have a <imixs-ai name="SKILL">
try {
List<ItemCollection> llmPromptDefinitions = workflowService.evalWorkflowResultXML(event,
"imixs-ai",
"SKILL", null, false);
// did we found a skill?
for (ItemCollection skillItemCol : llmPromptDefinitions) {
A2ASkillCard skillCard = new A2ASkillCard(version, taskID, eventID);
skillCard.setName(event.getItemValueString("name"));
skillCard.setDescription(skillItemCol.getItemValueString("description"));
String tags = skillItemCol.getItemValueString("tags");
if (tags != null && !tags.isBlank()) {
String[] parts = tags.split(",\\s*");
skillCard.setTags(Arrays.asList(parts));
}
skillCard.setExamples(skillItemCol.getItemValueList("example", String.class));
// skillCard.addMetadata("aea", versions);
if (skillCard.isValid()) {
result.add(skillCard);
}
}
} catch (PluginException e) {
// no match
}
}
}
}
}
} catch (ModelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
}

View file

@ -0,0 +1,30 @@
Imixs-Office-Workflow
Copyright (C) 2001-2018 Imixs Software Solutions GmbH,
http://www.imixs.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Project:
http://www.imixs.org
Contributors:
Imixs Software Solutions GmbH - initial API and implementation
Ralph Soika - Software Developer

View file

@ -0,0 +1,621 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd"
bean-discovery-mode="all" version="3.0">
</beans>

View file

@ -0,0 +1,10 @@
Imixs Workflow Technology
Copyright (C) 2010 Imixs Software Solutions GmbH,
http://www.imixs.com
Contributors:
Imixs Software Solutions GmbH - initial implementation
Ralph Soika

View file

@ -0,0 +1 @@
??

392
dynamixs-ai-app/pom.xml Normal file
View file

@ -0,0 +1,392 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>dynamixs-ai</artifactId>
<groupId>ai.dynamixs</groupId>
<version>1.0.1</version>
</parent>
<artifactId>dynamixs-ai-app</artifactId>
<packaging>war</packaging>
<name>Dynamixs AI Web App</name>
<profiles>
<profile>
<id>debug</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>install</phase>
<configuration>
<target>
<exec executable="docker">
<arg value="build" />
<arg value="-f" />
<arg value="../Dockerfile-debug" />
<arg value="-t" />
<arg value="imixs/${imixs-office.applicationname}" />
<arg value="./." />
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>imixs-cloud</id>
<!-- Imixs Security OIDC -->
<dependencies>
<dependency>
<groupId>org.imixs.security</groupId>
<artifactId>imixs-oidc</artifactId>
<version>${org.imixs.security.version}</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.imixs.security</groupId>
<artifactId>imixs-oidc-marty</artifactId>
<version>${org.imixs.security.version}</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>install</phase>
<configuration>
<target>
<exec executable="docker">
<arg value="build" />
<arg value="-t" />
<arg
value="imixs/${imixs-office.applicationname}:${project.version}" />
<arg value="../." />
</exec>
<exec executable="docker">
<arg value="tag" />
<arg
value="imixs/${imixs-office.applicationname}:${project.version}" />
<arg
value="${org.imixs.docker.registry}/imixs/${imixs-office.applicationname}:${project.version}" />
</exec>
<exec executable="docker">
<arg value="push" />
<arg
value="${org.imixs.docker.registry}/imixs/${imixs-office.applicationname}:${project.version}" />
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<resources>
<!-- enable resource filtering for multi language version -->
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<webResources>
<resource>
<filtering>true</filtering>
<!-- this is relative to the pom.xml directory -->
<directory>${custom.webResources}</directory>
<includes>
<include>**/WEB-INF/*</include>
<!-- include any other file types you want to filter -->
</includes>
</resource>
</webResources>
<workDirectory>target/overlay-war-folder</workDirectory>
<!-- We exclude libs form the parent WAR artifact -->
<overlays>
<overlay>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-office-workflow-app</artifactId>
<excludes>
<exclude>WEB-INF/lib/*.jar</exclude>
</excludes>
</overlay>
</overlays>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.imixs.maven</groupId>
<artifactId>manik-hotdeploy-maven-plugin</artifactId>
<version>2.0.0</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- List Source and Target folders for Autodeploy and Hotdeploy -->
<autodeployments>
<deployment>
<!-- wildcard deployment -->
<source>target/*.{war,ear,jar}</source>
<target>../docker/deployments/</target>
<unpack>true</unpack>
</deployment>
</autodeployments>
<hotdeployments>
<deployment>
<source>src/main/webapp</source>
<target>../docker/deployments/dynamixs-ai.war</target>
</deployment>
</hotdeployments>
</configuration>
</plugin>
</plugins>
<finalName>dynamixs-ai</finalName>
</build>
<dependencies>
<!-- Imixs Workflow -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-core</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-engine</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-jax-rs</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-faces</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-index-lucene</artifactId>
<version>${org.imixs.workflow.version}</version>
</dependency>
<!-- A2A -->
<dependency>
<groupId>ai.dynamixs</groupId>
<artifactId>dynamixs-ai-a2a</artifactId>
<type>jar</type>
<version>${project.version}</version>
</dependency>
<!-- MCP -->
<dependency>
<groupId>ai.dynamixs</groupId>
<artifactId>dynamixs-ai-mcp</artifactId>
<type>jar</type>
<version>${project.version}</version>
</dependency>
<!-- Marty -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-marty</artifactId>
</dependency>
<!-- Metrics -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-metrics-monitor</artifactId>
</dependency>
<!-- Imixs-Office-Workflow Overlay -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-office-workflow-app</artifactId>
<type>war</type>
<version>${org.imixs.office.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-office-workflow-util</artifactId>
<version>${org.imixs.office.version}</version>
</dependency>
<!-- Imixs-Archive -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-archive-api</artifactId>
<version>${org.imixs.archive.version}</version>
</dependency>
<!-- Imixs Data -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-data-groups</artifactId>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-data-views</artifactId>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-data-documents</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-data-importer</artifactId>
<scope>compile</scope>
</dependency>
<!-- -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>${apache.pdfbox.version}</version>
</dependency>
<!-- Imixs-AI -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-ai-rag</artifactId>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-ai-workflow</artifactId>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-ai-bpmn</artifactId>
</dependency>
<!-- Imixs-QR-Code -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-qrcode</artifactId>
</dependency>
<!-- Imixs-Wopi -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-wopi</artifactId>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-odf</artifactId>
</dependency>
<!-- Imixs Signature Feature -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-signature-api</artifactId>
<version>${org.imixs.signature.version}</version>
</dependency>
<!-- SEPA -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-sepa</artifactId>
</dependency>
<!-- DATEV -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-datev</artifactId>
</dependency>
<!-- POI Adapter -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-poi</artifactId>
</dependency>
<!-- OIDC
<dependency>
<groupId>org.imixs.security</groupId>
<artifactId>imixs-oidc</artifactId>
<version>3.0.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.imixs.security</groupId>
<artifactId>imixs-oidc-marty</artifactId>
<version>3.0.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
-->
</dependencies>
</project>

View file

@ -0,0 +1,546 @@
package ai.dynamixs;
/*******************************************************************************
* Imixs Workflow Technology
* Copyright (C) 2003, 2008 Imixs Software Solutions GmbH,
* http://www.imixs.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You can receive a copy of the GNU General Public
* License at http://www.gnu.org/licenses/gpl.html
*
* Contributors:
* Imixs Software Solutions GmbH - initial API and implementation
* Ralph Soika
*
*******************************************************************************/
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import org.imixs.ai.workflow.ImixsAIPromptEvent;
import org.imixs.workflow.FileData;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.ItemCollectionComparator;
import org.imixs.workflow.WorkflowKernel;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.engine.plugins.HistoryPlugin;
import org.imixs.workflow.exceptions.QueryException;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
/**
* The ChronicleTextBuilder is a CDI Bean observing the CDI event
* `ImixsAIPromptEvent` and replaces the placeholder {chronicle} with the
* chronicle data of the given workitem.
* <p>
* The class creates a text representation of all chronicle data for a given
* workitem.
* <p>
* The output format is structured by year and month:
*
* <pre>
* 2025
*
* December
* 27. Dec 2025 (14:37) - Ralph Soika
* Offer sent
* Products are out of stock now!
*
* 27. Dec 2025 (14:35) - imixs-workflow-service
* Retrieve Products
* Retrieve Address
* </pre>
*
* <p>
* Usage example:
*
* <pre>
* ChronicleTextBuilder builder = new ChronicleTextBuilder(workitem, locale);
* builder.setDmsController(dmsController);
* builder.setWorkitemLinkController(workitemLinkController);
* builder.setWorkitemService(workitemService);
* builder.setDocumentService(documentService);
* String chronicleText = builder.build();
* </pre>
*
* <p>
* The builder supports filtering by entry type (history, comment, dms,
* reference, version, imixs-ai).
*
* @author rsoika
*/
public class ChronicleTextBuilder implements Serializable {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(ChronicleTextBuilder.class.getName());
private ItemCollection workitem;
private Locale locale;
private String filterType;
// @Inject
// private WorkitemService workitemService;
@Inject
private DocumentService documentService;
// Internal data structures
private List<ChronicleEntry> chronicleEntries;
private Map<Integer, Set<Integer>> yearsMonths;
// Date formatters
private DateTimeFormatter dayFormatter;
private DateTimeFormatter timeFormatter;
private DateTimeFormatter monthFormatter;
/**
* Default constructor
*/
public ChronicleTextBuilder() {
this.locale = Locale.ENGLISH;
this.filterType = null;
this.chronicleEntries = new ArrayList<>();
this.yearsMonths = new HashMap<>();
// Initialize date formatters
this.dayFormatter = DateTimeFormatter.ofPattern("d. MMM yyyy", this.locale);
this.timeFormatter = DateTimeFormatter.ofPattern("HH:mm", this.locale);
this.monthFormatter = DateTimeFormatter.ofPattern("MMMM", this.locale);
}
/**
* Constructor with workitem and locale.
*
* @param workitem the workitem to build the chronicle for
* @param locale the locale for date formatting (e.g., Locale.ENGLISH,
* Locale.GERMAN)
*/
public ChronicleTextBuilder(ItemCollection workitem, Locale locale) {
this.workitem = workitem;
this.locale = locale != null ? locale : Locale.ENGLISH;
this.filterType = null;
this.chronicleEntries = new ArrayList<>();
this.yearsMonths = new HashMap<>();
// Initialize date formatters
this.dayFormatter = DateTimeFormatter.ofPattern("d. MMM yyyy", this.locale);
this.timeFormatter = DateTimeFormatter.ofPattern("HH:mm", this.locale);
this.monthFormatter = DateTimeFormatter.ofPattern("MMMM", this.locale);
}
/**
* Constructor with workitem only (uses English locale as default).
*
* @param workitem the workitem to build the chronicle for
*/
public ChronicleTextBuilder(ItemCollection workitem) {
this(workitem, Locale.ENGLISH);
}
/**
* This CDI class reacts on the CDI Event `ImixsAIPromptEvent` and replaces the
* placeholder {chronicle} with the chronicle data of the given workitem.
*
* @param event
*/
public void onEvent(@Observes ImixsAIPromptEvent event) {
if (event.getWorkitem() == null) {
return;
}
String prompt = event.getPromptTemplate();
if (prompt.contains("{chronicle}")) {
this.workitem = event.getWorkitem();
String result = build();
prompt = prompt.replace("{chronicle}", result);
// update the prompt tempalte
event.setPromptTemplate(prompt);
}
}
/**
* Sets a filter to include only entries of a specific type. Valid types:
* history, comment, dms, reference, version, imixs-ai
*
* @param filterType the type to filter by, or null to include all
* @return this builder for method chaining
*/
public ChronicleTextBuilder setFilter(String filterType) {
this.filterType = filterType;
return this;
}
/**
* Builds and returns the text representation of the chronicle.
*
* @return formatted chronicle text
*/
public String build() {
long startTime = System.currentTimeMillis();
if (workitem == null) {
return "";
}
// Collect all chronicle data
collectHistoryEntries();
collectCommentEntries();
collectDMSEntries();
collectVersionEntries();
// Sort entries by date (newest first)
Collections.sort(chronicleEntries, new ChronicleEntryComparator(false));
// Build the text output
String result = buildTextOutput();
logger.fine("ChronicleTextBuilder.build() completed in " + (System.currentTimeMillis() - startTime) + "ms");
return result;
}
/**
* Collects workflow history entries from the workitem.
*/
@SuppressWarnings("unchecked")
private void collectHistoryEntries() {
List<List<?>> history = null;
// Check for deprecated field 'txtworkflowhistory'
if (!workitem.hasItem(HistoryPlugin.ITEM_HISTORY_LOG)
&& workitem.hasItem("txtworkflowhistory")) {
history = workitem.getItemValue("txtworkflowhistory");
// Sort old history entries chronologically
Collections.sort(history, new Comparator<List<?>>() {
@Override
public int compare(List<?> entry1, List<?> entry2) {
Date date1 = (Date) entry1.get(0);
Date date2 = (Date) entry2.get(0);
return date1.compareTo(date2);
}
});
} else {
history = workitem.getItemValue(HistoryPlugin.ITEM_HISTORY_LOG);
}
// Reverse to get newest first
// Collections.reverse(history);
if (history.size() > 0 && history.get(0) instanceof List) {
for (List<?> entries : history) {
Date date = (Date) entries.get(0);
String message = (String) entries.get(1);
String user = (String) entries.get(2);
addEntry(date, user, message, "history");
}
}
}
/**
* Collects comment entries from the workitem.
*/
private void collectCommentEntries() {
List<Map<String, List<Object>>> comments = workitem.getItemValue("txtCommentLog");
for (Map<String, List<Object>> comment : comments) {
ItemCollection itemCol = new ItemCollection(comment);
Date date = itemCol.getItemValueDate("datcomment");
String message = itemCol.getItemValueString("txtcomment");
String user = itemCol.getItemValueString("nameditor");
addEntry(date, user, message, "comment");
}
}
/**
* Collects DMS (attachment) entries if dmsController is available.
*/
private void collectDMSEntries() {
List<FileData> fileDataList = workitem.getFileData();
for (FileData fileData : fileDataList) {
ItemCollection fileAttributes = new ItemCollection(fileData.getAttributes());
String content = fileAttributes.getItemValueString("text");
if (!content.isBlank()) {
String user = fileAttributes.getItemValueString("$creator");
Date date = fileAttributes.getItemValueDate("$created");
if (fileData.getAttribute("$modified") != null) {
date = fileAttributes.getItemValueDate("$modified");
}
if (date == null) {
date = new Date();
}
addEntry(date, user, "Attachment: " + fileData.getName() + "\n\n" + content + "\n\n", "dms");
}
}
}
/**
* Collects version entries if workitemService and documentService are
* available.
*/
private void collectVersionEntries() {
List<ItemCollection> versions = findAllVersions(workitem);
for (ItemCollection version : versions) {
// Skip current workitem
if (workitem.getUniqueID().equals(version.getUniqueID())) {
continue;
}
ItemCollection versionFull = documentService.load(version.getUniqueID());
Date date = version.getItemValueDate(WorkflowKernel.CREATED);
String message = version.getItemValueString("$WorkflowSummary");
String user = version.getItemValueString(WorkflowKernel.EDITOR);
if (!versionFull.getItemValueString("$uniqueIdSource").isEmpty()) {
if (versionFull.hasItem(WorkflowKernel.CREATED + ".version")) {
date = versionFull.getItemValueDate(WorkflowKernel.CREATED + ".version");
}
message = "Version (Branch): " + message;
} else {
message = "Version: " + message;
}
addEntry(date, user, message, "version");
}
}
/**
* Adds a chronicle entry to the internal list. Applies filter if set and
* updates the year/month index.
*/
private void addEntry(Date date, String user, String message, String type) {
if (date == null) {
return;
}
// Apply filter if set
if (filterType != null && !filterType.isEmpty() && !filterType.equals(type)) {
return;
}
// Truncate to minutes
LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
localDateTime = localDateTime.truncatedTo(ChronoUnit.MINUTES);
ChronicleEntry entry = new ChronicleEntry(localDateTime, user, message, type);
chronicleEntries.add(entry);
// Update year/month index
LocalDate localDate = localDateTime.toLocalDate();
int year = localDate.getYear();
int month = localDate.getMonthValue();
yearsMonths.computeIfAbsent(year, k -> new HashSet<>()).add(month);
}
/**
* Builds the formatted text output from collected entries.
*/
private String buildTextOutput() {
StringBuilder sb = new StringBuilder();
// Add title
sb.append(
"# " + workitem.getWorkflowGroup() + " : " + workitem.getItemValueString(WorkflowKernel.WORKFLOWSTATUS))
.append("\n\n");
// Get sorted years (descending)
List<Integer> years = new ArrayList<>(yearsMonths.keySet());
for (int i = 0; i < years.size(); i++) {
int year = years.get(i);
// Year header
// sb.append(year).append("\n\n");
// Get sorted months for this year (descending)
List<Integer> months = new ArrayList<>(yearsMonths.get(year));
for (int j = 0; j < months.size(); j++) {
int month = months.get(j);
// Get entries for this month
List<ChronicleEntry> monthEntries = getEntriesForMonth(year, month);
if (monthEntries.isEmpty()) {
continue;
}
// Month header
// String monthName = LocalDate.of(year, month, 1).format(monthFormatter);
// sb.append(monthName).append("\n\n");
// Group entries by user and timestamp
List<GroupedEntry> groupedEntries = groupEntries(monthEntries);
for (GroupedEntry grouped : groupedEntries) {
// Format: "27. Dec 2025 (14:37) - Ralph Soika"
String dayStr = grouped.dateTime.format(dayFormatter);
String timeStr = grouped.dateTime.format(timeFormatter);
sb.append("\n" + dayStr).append(" (").append(timeStr).append(") - ").append(grouped.user)
.append("\n");
// Add all messages for this group
for (String message : grouped.messages) {
sb.append(message).append("\n");
}
}
// Add spacing between months (but not after the last month of the last year)
if (j < months.size() - 1 || i < years.size() - 1) {
sb.append("\n");
}
}
}
return sb.toString().trim();
}
/**
* Returns all entries for a specific year and month.
*/
private List<ChronicleEntry> getEntriesForMonth(int year, int month) {
List<ChronicleEntry> result = new ArrayList<>();
for (ChronicleEntry entry : chronicleEntries) {
if (entry.dateTime.getYear() == year && entry.dateTime.getMonthValue() == month) {
result.add(entry);
}
}
return result;
}
/**
* Groups entries by user and timestamp (same minute). This consolidates
* multiple actions by the same user at the same time.
*/
private List<GroupedEntry> groupEntries(List<ChronicleEntry> entries) {
List<GroupedEntry> grouped = new ArrayList<>();
GroupedEntry current = null;
for (ChronicleEntry entry : entries) {
if (current == null ||
!current.user.equals(entry.user) ||
!current.dateTime.equals(entry.dateTime)) {
// Start a new group
current = new GroupedEntry(entry.dateTime, entry.user);
grouped.add(current);
}
current.messages.add(entry.message);
}
return grouped;
}
/**
* Internal class representing a single chronicle entry.
*/
private static class ChronicleEntry {
LocalDateTime dateTime;
String user;
String message;
String type;
ChronicleEntry(LocalDateTime dateTime, String user, String message, String type) {
this.dateTime = dateTime;
this.user = user != null ? user : "";
this.message = message != null ? message : "";
this.type = type;
}
}
/**
* Internal class for grouping entries by user and timestamp.
*/
private static class GroupedEntry {
LocalDateTime dateTime;
String user;
List<String> messages;
GroupedEntry(LocalDateTime dateTime, String user) {
this.dateTime = dateTime;
this.user = user;
this.messages = new ArrayList<>();
}
}
/**
* Comparator for sorting chronicle entries by date.
*/
private static class ChronicleEntryComparator implements Comparator<ChronicleEntry> {
private boolean descending;
ChronicleEntryComparator(boolean descending) {
this.descending = descending;
}
@Override
public int compare(ChronicleEntry e1, ChronicleEntry e2) {
int result = e1.dateTime.compareTo(e2.dateTime);
return descending ? -result : result;
}
}
/**
* This method finds all versions of a given workitem.
*
*/
private List<ItemCollection> findAllVersions(ItemCollection workitem) {
List<ItemCollection> versions = new ArrayList<ItemCollection>();
if (null == workitem)
return versions;
List<ItemCollection> col = null;
String sRefID = workitem.getItemValueString("$workitemId");
String refQuery = "( (type:\"workitem\" OR type:\"workitemarchive\" OR type:\"workitemversion\") AND $workitemid:\""
+ sRefID + "\")";
try {
col = documentService.findStubs(refQuery, 999, 0, WorkflowKernel.LASTEVENTDATE, true);
// sort by $modified
Collections.sort(col, new ItemCollectionComparator("$modified", true));
// Only return version list if more than one version was found!
if (col.size() > 1) {
for (ItemCollection aworkitem : col) {
versions.add(aworkitem);
}
}
} catch (QueryException e) {
logger.warning("findAllVersions - invalid query: " + e.getMessage());
}
return versions;
}
}

View file

@ -0,0 +1,175 @@
/****************************************************************************
* Copyright (c) 2022-2025 Imixs Software Solutions GmbH and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* This Source Code may also be made available under the terms of the
* GNU General Public License, version 2 or later (GPL-2.0-or-later),
* which is available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
****************************************************************************/
package ai.dynamixs;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.imixs.ai.rag.index.IndexService;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.WorkflowKernel;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.exceptions.AdapterException;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.exceptions.QueryException;
import jakarta.inject.Inject;
/**
* The OrderPlugin is a generic plugin for Order workflows.
* <p>
* The plugin collects a list of $uniqueids for the last 5 orders for the given
* customer.ref. The list is stored in the item `order.history.ref`
*
* <p>
* The plugin extends the default imixs-ai RAGIndexPlugin. In the mode INDEX
* this plugins generates a default prompt template.This is to simplify the
* models.
* <p>
*
* <pre>
{@code
<dynamixs-ai name="INDEX">
<debug>false</debug>
</dynamixs-ai>
}
* </pre>
* <p>
* The tag 'debug' is optional
*
*
* @author rsoika
*
*/
public class OrderPlugin extends org.imixs.ai.rag.workflow.RAGIndexPlugin {
private static final Logger logger = Logger.getLogger(OrderPlugin.class.getName());
public static final String LINK_PROPERTY = "$workitemref";
public static final int MAX_HISTORY_RESULT = 5;
@Inject
private WorkflowService workflowService;
@Inject
private IndexService ragService;
@Override
public ItemCollection run(ItemCollection workitem, ItemCollection event) throws PluginException {
// do not run on Snapshots!
if (workitem.getType().startsWith("snapshot-")) {
// no op!
return workitem;
}
logger.info("├── running Dynamixs.AI Order Plugin");
// Update History....
updateOrderHistory(workitem);
// read optional configuration form the model or imixs.properties....
List<ItemCollection> ragIndexDefinitions = workflowService.evalWorkflowResultXML(event, "dynamixs-ai",
IndexService.RAG_INDEX, workitem, false);
try {
// INDEX Mode?
if (ragIndexDefinitions != null && ragIndexDefinitions.size() > 0) {
// do we have a prompt template?
ItemCollection indexDefinition = ragIndexDefinitions.get(0);
String promptTemplate = indexDefinition.getItemValueString("promptTemplate");
if (promptTemplate.isBlank()) {
// generate default template
ChronicleTextBuilder chronicleTextBuilder = new ChronicleTextBuilder(workitem);
promptTemplate = chronicleTextBuilder.build();
workitem.setItemValue("ai.chronicle.summary", promptTemplate);
indexDefinition.setItemValue("promptTemplate", embedTemplate(promptTemplate));
loadPromptDefinition(indexDefinition, event);
ragService.indexWorkitem(indexDefinition, workitem);
}
}
} catch (AdapterException e) {
throw new PluginException(e);
}
return workitem;
}
/**
* This method updates the item `order.history.ref` with the latest 5 orders for
* the current customer
*
* @param workitem
*/
private void updateOrderHistory(ItemCollection workitem) {
workitem.removeItem("order.history.ref");
String customerRef = workitem.getItemValueString("customer.ref");
if (!customerRef.isEmpty()) {
// append customer ref to $workitemref
workitem.appendItemValueUnique("$workitemref", customerRef);
// collect all history orders....
String sQuery = "(";
sQuery = " (type:\"workitem\" OR type:\"workitemarchive\") AND (" + LINK_PROPERTY + ":\"" + customerRef
+ "\") AND ($workflowgroup:\"" + workitem.getWorkflowGroup() + "\")";
List<ItemCollection> orderHistory = null;
try {
orderHistory = workflowService.getDocumentService().findStubs(sQuery, MAX_HISTORY_RESULT, 0,
WorkflowKernel.LASTEVENTDATE, true);
} catch (QueryException e) {
e.printStackTrace();
}
if (orderHistory != null) {
List<String> orderHistoryRefList = new ArrayList<>();
for (ItemCollection order : orderHistory) {
if (!workitem.getUniqueID().equals(order.getUniqueID())) { // skip current id!
orderHistoryRefList.add(order.getUniqueID());
}
}
workitem.setItemValue("order.history.ref", orderHistoryRefList);
}
}
}
/**
* Embedds a prompt into a imixs prompt template
*
*
* @param prompt
* @return
*/
private String embedTemplate(String prompt) {
String template = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + //
"<PromptDefinition>\n" + //
" <prompt_options>{}</prompt_options>\n" + //
" <prompt><![CDATA[";
template = template + prompt;
template = template + "]]>\n" + //
"</prompt>\n" + //
"</PromptDefinition> ";
return template;
}
}

View file

@ -0,0 +1,171 @@
package ai.dynamixs.agent;
import java.io.Serializable;
import java.util.logging.Logger;
import org.imixs.ai.ImixsAIContextHandler;
import org.imixs.ai.workflow.ImixsAIToolCallEvent;
import org.imixs.ai.workflow.OpenAIAPIService;
import org.imixs.workflow.exceptions.ModelException;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.faces.data.WorkflowController;
import jakarta.enterprise.context.SessionScoped;
import jakarta.enterprise.event.Observes;
import jakarta.enterprise.event.Reception;
import jakarta.inject.Inject;
import jakarta.inject.Named;
@Named("aiAgentController")
@SessionScoped
public class AIAgentController implements Serializable {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(AIAgentController.class.getName());
@Inject
private OpenAIAPIService openAIAPIService;
@Inject
private ImixsAIContextHandler contextHandler;
@Inject
protected WorkflowController workflowController;
@Inject
protected SkillController skillController;
private String userMessage;
private String agentResponse;
private String redirectUrl;
private static final int MAX_ITERATIONS = 10; // prevent infinite loops
/**
* Starts the conversation scope and initializes the context.
*/
public void init() {
logger.info("├── Initialize AI Agent");
redirectUrl = null;
agentResponse = null;
contextHandler.init();
// Build system prompt with skill headers
try {
contextHandler.addSystemMessage(
"You are a workflow assistant in Imixs-Office-Workflow. " +
"When a user wants to start a process, call start_process with the " +
"matching modelversion and taskId from the list below.\n\n" +
"Do NOT explain what you are doing. Just call the tool directly.\n\n" +
skillController.getSkillHeaders());
// Register start_process function
contextHandler.addFunction(
"start_process",
"Starts a BPMN workflow process for the user",
"""
{
"type": "object",
"properties": {
"$modelversion": {
"type": "string",
"description": "The model version of the process"
},
"$taskid": {
"type": "integer",
"description": "The task ID of the initial task"
},
"process.ref": {
"type": "string",
"description": "The unique ID referring of the process"
}
},
"required": ["$modelversion", "$taskid", "process.ref"]
}
""");
} catch (PluginException e) {
logger.warning("Failed to init AIAgent: " + e.getMessage());
}
}
/**
* Main entry point for the frontend. Runs the agent loop and returns either a
* text response or a redirect URL.
*/
public String startChat() throws PluginException {
init();
logger.info("├── Starting new chat");
logger.info("│ ├── User Question: " + userMessage);
contextHandler.addQuestion(userMessage, null, null);
// Agent Loop
int iterations = 0;
while (iterations < MAX_ITERATIONS) {
iterations++;
String response = openAIAPIService.postPromptCompletion(
contextHandler, null, true);
// Tool call? → processToolCallResult handles CDI events
boolean wasToolCall = openAIAPIService.processToolCallResult(
response, contextHandler);
if (!wasToolCall) {
// Normal text response → done
agentResponse = openAIAPIService.processPromptResult(
response, null, null);
return null; // stay on current page
}
// Check if a tool call produced a redirect URL
if (redirectUrl != null) {
return redirectUrl; // JSF redirect
}
}
throw new PluginException(AIAgentController.class.getSimpleName(),
"AGENT_LOOP_ERROR", "Max iterations reached!");
}
public void onToolCall(@Observes(notifyObserver = Reception.IF_EXISTS) ImixsAIToolCallEvent event)
throws PluginException {
try {
if ("start_process".equals(event.getToolName())) {
String modelVersion = event.getArguments().getString("$modelversion");
int taskId = event.getArguments().getInt("$taskid");
String processRef = event.getArguments().getString("process.ref");
workflowController.create(modelVersion, taskId, processRef);
// Set redirect URL directly on this bean - startChat() will pick it up
this.redirectUrl = "/pages/workitems/workitem.xhtml?id="
+ workflowController.getWorkitem().getUniqueID()
+ "&faces-redirect=true";
event.setResult("New Process started: " + workflowController.getWorkitem().getUniqueID());
}
} catch (ModelException e) {
throw new PluginException(e.getErrorContext(), e.getErrorCode(), e.getMessage());
}
}
public void setRedirectUrl(String url) {
this.redirectUrl = url;
}
public String getUserMessage() {
return userMessage;
}
public void setUserMessage(String userMessage) {
this.userMessage = userMessage;
}
public String getAgentResponse() {
return agentResponse;
}
}

View file

@ -0,0 +1,155 @@
package ai.dynamixs.agent;
import java.util.regex.Pattern;
/**
* Utility class to convert HTML content into clean, LLM-friendly markup text.
*/
public class HtmlStripper {
// Precompiled patterns for performance
private static final Pattern P_SCRIPT_STYLE = Pattern.compile(
"<(script|style)[^>]*>[\\s\\S]*?</\\1>", Pattern.CASE_INSENSITIVE);
private static final Pattern P_HEADING = Pattern.compile(
"<h[1-5][^>]*>(.*?)</h[1-5]>", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
private static final Pattern P_STRONG = Pattern.compile(
"<(strong|b)[^>]*>(.*?)</(strong|b)>", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
private static final Pattern P_EM = Pattern.compile(
"<(em|i)[^>]*>(.*?)</(em|i)>", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
private static final Pattern P_LI = Pattern.compile(
"<li[^>]*>(.*?)</li>", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
private static final Pattern P_BLOCK = Pattern.compile(
"<(p|div|br|tr|blockquote|pre|ul|ol|table)[^>]*/?>",
Pattern.CASE_INSENSITIVE);
private static final Pattern P_CLOSE_BLOCK = Pattern.compile(
"</(p|div|tr|blockquote|pre|ul|ol|table)>",
Pattern.CASE_INSENSITIVE);
private static final Pattern P_TAGS = Pattern.compile("<[^>]+>");
private static final Pattern P_MULTI_NEWLINE = Pattern.compile("\\n{3,}");
private static final Pattern P_BLANK_LINE = Pattern.compile("(?m)^[ \\t]+$");
/**
* Converts an HTML string into clean, LLM-readable markdown-style text. Handles
* headings, bold/italic, lists, images, HTML entities and removes all remaining
* tags. Designed to be minimal and allocation-efficient.
*
* @param content raw HTML input (may be null)
* @return clean markup text, or empty string if input is null/blank
*/
public static String stripHtml(String content) {
if (content == null || content.isBlank()) {
return "";
}
String s = content;
// 1. Normalize line endings
s = s.replace("\r\n", "\n").replace("\r", "\n");
// 2. Remove script / style blocks entirely
s = P_SCRIPT_STYLE.matcher(s).replaceAll("");
// 3. Images → [Image: alt] or drop silently
// s = P_IMG.matcher(s).replaceAll("[Image: $1]");
// s = P_IMG_NO_ALT.matcher(s).replaceAll("");
// 4. Headings → Markdown headings
s = P_HEADING.matcher(s).replaceAll("\n**$1**\n");
// 5. Bold / Italic → Markdown
s = P_STRONG.matcher(s).replaceAll("**$2**");
s = P_EM.matcher(s).replaceAll("*$2*");
// 6. List items → Markdown bullets
s = P_LI.matcher(s).replaceAll("\n- $1");
// 7. Block-level elements → newlines
s = P_BLOCK.matcher(s).replaceAll("\n");
s = P_CLOSE_BLOCK.matcher(s).replaceAll("\n");
// 8. Strip all remaining tags
s = P_TAGS.matcher(s).replaceAll("");
// 9. Decode HTML entities
s = decodeEntities(s);
// 10. Clean up whitespace
s = P_BLANK_LINE.matcher(s).replaceAll("");
s = P_MULTI_NEWLINE.matcher(s).replaceAll("\n\n");
return s.strip();
}
/**
* Decodes common named and numeric HTML entities. Covers the full ISO-8859-1 /
* HTML4 named entity set plus numeric references.
*/
private static String decodeEntities(String s) {
// Use a simple regex-replace loop for correctness
s = decodeNumericEntities(s);
// Named entities – most frequent ones in German/English business docs
s = s
.replace("&nbsp;", " ")
.replace("&amp;", "&")
.replace("&lt;", "<")
.replace("&gt;", ">")
.replace("&quot;", "\"")
.replace("&apos;", "'")
.replace("&auml;", "ä").replace("&Auml;", "Ä")
.replace("&ouml;", "ö").replace("&Ouml;", "Ö")
.replace("&uuml;", "ü").replace("&Uuml;", "Ü")
.replace("&szlig;", "ß")
.replace("&eacute;", "é").replace("&Eacute;", "É")
.replace("&egrave;", "è").replace("&Egrave;", "È")
.replace("&ecirc;", "ê").replace("&Ecirc;", "Ê")
.replace("&agrave;", "à").replace("&Agrave;", "À")
.replace("&acirc;", "â").replace("&Acirc;", "Â")
.replace("&ocirc;", "ô").replace("&Ocirc;", "Ô")
.replace("&ucirc;", "û").replace("&Ucirc;", "Û")
.replace("&ccedil;", "ç").replace("&Ccedil;", "Ç")
.replace("&ntilde;", "ñ").replace("&Ntilde;", "Ñ")
.replace("&copy;", "©")
.replace("&reg;", "®")
.replace("&trade;", "™")
.replace("&mdash;", "—")
.replace("&ndash;", "–")
.replace("&hellip;", "…")
.replace("&laquo;", "«").replace("&raquo;", "»")
.replace("&bull;", "•")
.replace("&euro;", "€");
return s;
}
private static final Pattern P_DEC_ENTITY = Pattern.compile("&#(\\d+);");
private static final Pattern P_HEX_ENTITY = Pattern.compile("&#x([0-9a-fA-F]+);");
/**
* Replaces numeric HTML entities (decimal and hex) with their Unicode
* characters.
*/
private static String decodeNumericEntities(String s) {
// Hex
var m = P_HEX_ENTITY.matcher(s);
var sb = new StringBuilder(); // ← StringBuilder statt StringBuffer
while (m.find()) {
int cp = Integer.parseInt(m.group(1), 16);
m.appendReplacement(sb, new String(Character.toChars(cp)));
}
m.appendTail(sb);
s = sb.toString();
// Decimal
m = P_DEC_ENTITY.matcher(s);
sb = new StringBuilder(); // ← StringBuilder
while (m.find()) {
int cp = Integer.parseInt(m.group(1));
m.appendReplacement(sb, new String(Character.toChars(cp)));
}
m.appendTail(sb);
return sb.toString();
}
}

View file

@ -0,0 +1,160 @@
/*******************************************************************************
* Imixs Workflow
* Copyright (C) 2001, 2011 Imixs Software Solutions GmbH,
* http://www.imixs.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You can receive a copy of the GNU General Public
* License at http://www.gnu.org/licenses/gpl.html
*
* Project:
* http://www.imixs.org
* http://java.net/projects/imixs-workflow
*
* Contributors:
* Imixs Software Solutions GmbH - initial API and implementation
* Ralph Soika - Software Developer
*******************************************************************************/
package ai.dynamixs.agent;
import java.io.Serializable;
import java.util.List;
import org.imixs.marty.team.TeamController;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentEvent;
import org.imixs.workflow.office.model.ModelController;
import jakarta.annotation.Resource;
import jakarta.ejb.SessionContext;
import jakarta.enterprise.context.SessionScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
/**
* The SkillController is a CDI bean handling workflow skills from the current
* process models.
*
* @author rsoika
*/
@SessionScoped
public class SkillController implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
TeamController teamController;
@Inject
ModelController modelController;
@Resource
SessionContext ctx;
String skillHeaders = null;
/**
* This method refreshes the cache of skillHeaders
*
* @param event
*/
public void onDocumentEvent(@Observes DocumentEvent event) {
String type = event.getDocument().getType();
if ((type.startsWith("process") || type.startsWith("model"))
&& (event.getEventType() == DocumentEvent.ON_DOCUMENT_SAVE
|| event.getEventType() == DocumentEvent.ON_DOCUMENT_DELETE)) {
skillHeaders = null;
}
}
/**
* Return the current skill headers. The method supports a lazy loading
* mechanism.
*
* @return
*/
public String getSkillHeaders() {
loadSkillHeaders();
return skillHeaders;
}
/**
* Helper method to load the skill headers for all available processes and
* assigned workflows
*
* @return
*/
private void loadSkillHeaders() {
if (skillHeaders == null) {
StringBuilder skillHeaderBuilder = new StringBuilder();
skillHeaderBuilder.append("Available Workflow Processes:\n\n");
List<ItemCollection> processList = teamController.getProcessList();
for (ItemCollection process : processList) {
if (process.getTaskID() == 301 || teamController.isManagerOf(process.getUniqueID())) {
String processName = process.getItemValueString("name");
String processDescription = HtmlStripper
.stripHtml(process.getItemValueString("txtdescription"));
List<String> workflowList = process.getItemValueList("txtWorkflowList", String.class);
// Collect workflow entries first - skip process if none found
StringBuilder workflowEntries = new StringBuilder();
for (String group : workflowList) {
String modelVersion = modelController.getVersionByGroup(group);
List<ItemCollection> startTasks = modelController.findAllStartTasksByGroup(modelVersion, group);
if (!startTasks.isEmpty()) {
ItemCollection initialTask = startTasks.get(0);
int taskId = initialTask.getItemValueInteger("taskid");
String taskDescription = HtmlStripper.stripHtml(
modelController.getProcessDescriptionByInitialTask(initialTask, modelVersion,
group));
workflowEntries.append("- ").append(group).append(": ");
if (taskDescription != null && !taskDescription.isBlank()) {
workflowEntries.append(taskDescription);
} else if (processDescription != null && !processDescription.isBlank()) {
workflowEntries.append(processDescription);
}
workflowEntries.append(" (model: ").append(modelVersion)
.append(", taskid: ").append(taskId)
.append(", process.ref: ").append(process.getUniqueID())
.append(")\n");
}
}
// Only add process section if it has at least one workflow
if (workflowEntries.length() > 0) {
skillHeaderBuilder.append("[").append(processName).append("]");
if (processDescription != null && !processDescription.isBlank()) {
skillHeaderBuilder.append(" - ").append(processDescription);
}
skillHeaderBuilder.append("\n");
skillHeaderBuilder.append(workflowEntries);
skillHeaderBuilder.append("\n");
}
}
}
skillHeaders = skillHeaderBuilder.toString();
}
}
}

View file

@ -0,0 +1,2 @@
Manifest-Version: 1.0

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
version="3.0">
<!--
Imixs JPA definition Make sure that the imixs-workflow-jee library
version maches the version provided by the EAR/EJB
-->
<!-- eclipselink -->
<persistence-unit name="org.imixs.workflow.jpa" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>${imixs-office.jta-data-source}</jta-data-source>
<jar-file>lib/imixs-workflow-engine-${org.imixs.workflow.version}.jar</jar-file>
<jar-file>lib/imixs-marty-${org.imixs.marty.version}.jar</jar-file>
<properties>
<!-- target-database Auto MySQL PostgreSQL -->
<property name="eclipselink.target-database" value="Auto" />
<property name="eclipselink.ddl-generation" value="create-or-extend-tables" />
<property name="eclipselink.deploy-on-startup" value="true" />
<property name="eclipselink.logging.level" value="INFO" />
</properties>
</persistence-unit>
</persistence>

View file

@ -0,0 +1,7 @@
# Build Information
build.version=${project.version}
build.timestamp=${org.imixs.build.timestamp}
build.office.version=${org.imixs.office.version}
build.marty.version=${org.imixs.marty.version}
build.workflow.version=${org.imixs.workflow.version}
build.name=${imixs-office.applicationname}

View file

@ -0,0 +1,45 @@
##############################
# Imixs-Workflow
##############################
model.default.data=system-de-1.3.0.bpmn
lucence.indexDir=${imixs-office.IndexDir}
index.fields=txtsearchstring,txtSubject,txtname,txtEmail,txtUserName,namCreator,txtworkflowgroup,txtworkflowstatus,txtWorkflowAbstract,txtWorkflowSummary,txtworkflowhistory,txtspacename,txtprocessname,_subject,_description,_name,_projectnumber,_projectname,_ordernumber,_contractnumber,datDueDate,txtcommentlog,htmldescription,htmldocumentation,_childitems
index.fields.analyze=txtUsername
index.fields.noanalyze=type,$UniqueIDRef,$created,$modified,$ModelVersion,namCreator,$ProcessID,datDate,txtWorkflowGroup,txtemail, datdate, datfrom, datto, numsequencenumber,dms_count,
index.fields.store=process.name,txtProcessName,txtWorkflowImageURL
index.fields.category=space.name,space.ref
##############################
# Model Setup
##############################
setup.system.model=system-de-1.3
# Office Properties
BASIC.maxviewentries=10
##############################
# Marty Security
##############################
security.setup.mode=auto
security.userid.input.mode=LOWERCASE
security.email.unique=true
#security.userid.input.pattern=
# Profile - autoprocess event
profile.login.event=100
# Marty Mail Plugin
# mail.defaultSender=info@imixs.com
# Image reziser
image.fileExtension=jpg,gif
image.maxWidth=2048
dms.search=true

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd"
bean-discovery-mode="all" version="3.0">
</beans>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
version="2.2">
</faces-config>

View file

@ -0,0 +1,146 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">
<display-name>imixs-office-workflow</display-name>
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
<!-- -->
<context-param>
<param-name>jakarta.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>jakarta.faces.CONFIG_FILES</param-name>
<param-value>
/WEB-INF/faces-config-office.xml,
/WEB-INF/faces-config-custom.xml
</param-value>
</context-param>
<!-- project stage is computed by the maven profile settings -->
<context-param>
<param-name>jakarta.faces.PROJECT_STAGE</param-name>
<param-value>Production</param-value>
</context-param>
<!-- Session Timeout 180 = 3h -->
<session-config>
<session-timeout>60</session-timeout>
</session-config>
<!-- Facelets -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>0</load-on-startup>
<multipart-config>
<location>/tmp</location>
<!-- 20MB (20848820) *2MB (2097152)-->
<max-file-size>2097152</max-file-size>
<!-- 400MB (418018841) *20MB (20848820)-->
<max-request-size>20848820</max-request-size>
<file-size-threshold>1048576</file-size-threshold>
</multipart-config>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<!-- Error handling -->
<error-page>
<error-code>401</error-code>
<location>/loginerror.jsf</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/authorizationerror.html</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/error.jsf</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error.jsf</location>
</error-page>
<!-- Login Modul - Form-Login -->
<login-config>
<auth-method>FORM</auth-method>
<realm-name>imixsrealm</realm-name>
<form-login-config>
<form-login-page>/login.jsf</form-login-page>
<form-error-page>/loginerror.jsf</form-error-page>
</form-login-config>
</login-config>
<!-- Wildfly OIDC Login Module
Note: WEB-INF/oidc.yaml file is mandatory!
<login-config>
<auth-method>OIDC</auth-method>
</login-config>
-->
<!-- Security Roles -->
<security-constraint>
<display-name>Access Manager Security Constraint</display-name>
<web-resource-collection>
<web-resource-name>AUTHENTICATED_RESOURCE</web-resource-name>
<url-pattern>/pages/*</url-pattern>
<url-pattern>/api/workflow/*</url-pattern>
<url-pattern>/api/model/*</url-pattern>
<url-pattern>/api/documents/*</url-pattern>
<url-pattern>/api/report/*</url-pattern>
<url-pattern>/api/snapshot/*</url-pattern>
<url-pattern>/api/adminp/*</url-pattern>
<url-pattern>/api/eventlog/*</url-pattern>
<url-pattern>/api/logout</url-pattern>
<!-- exclude /api/metrics and /api/wopi -->
</web-resource-collection>
<auth-constraint>
<role-name>org.imixs.ACCESSLEVEL.READERACCESS</role-name>
<role-name>org.imixs.ACCESSLEVEL.AUTHORACCESS</role-name>
<role-name>org.imixs.ACCESSLEVEL.EDITORACCESS</role-name>
<role-name>org.imixs.ACCESSLEVEL.MANAGERACCESS</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>AUTHENTICATED_ADMIN_RESOURCE</web-resource-name>
<url-pattern>/pages/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>org.imixs.ACCESSLEVEL.MANAGERACCESS</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>org.imixs.ACCESSLEVEL.NOACCESS</role-name>
</security-role>
<security-role>
<role-name>org.imixs.ACCESSLEVEL.READERACCESS</role-name>
</security-role>
<security-role>
<role-name>org.imixs.ACCESSLEVEL.AUTHORACCESS</role-name>
</security-role>
<security-role>
<role-name>org.imixs.ACCESSLEVEL.EDITORACCESS</role-name>
</security-role>
<security-role>
<role-name>org.imixs.ACCESSLEVEL.MANAGERACCESS</role-name>
</security-role>
</web-app>

View file

@ -0,0 +1,63 @@
// custom scripts
/**
* This method renders $workflowabstarct as markup
*/
$(document).ready(function() {
});
function showTooltip(trigger) {
const tooltip = trigger.nextElementSibling;
const rect = trigger.getBoundingClientRect();
// Position relativ zum Viewport berechnen
tooltip.style.left = rect.left + 'px';
tooltip.style.top = (rect.bottom + 5) + 'px';
// Markdown nur einmal parsen (lazy loading)
const markdownContainer = tooltip.querySelector('.imixs-workflowabstract');
if (markdownContainer && !markdownContainer.dataset.parsed) {
const rawMarkdown = markdownContainer.textContent;
markdownContainer.innerHTML = marked.parse(rawMarkdown);
markdownContainer.dataset.parsed = 'true'; // Flag setzen
}
tooltip.classList.add('visible');
// Optional: Prüfen ob Tooltip aus dem Viewport ragt
const tooltipRect = tooltip.getBoundingClientRect();
if (tooltipRect.right > window.innerWidth) {
tooltip.style.left = (window.innerWidth - tooltipRect.width - 10) + 'px';
}
if (tooltipRect.bottom > window.innerHeight) {
tooltip.style.top = (rect.top - tooltipRect.height - 5) + 'px';
}
}
function hideTooltip(trigger) {
const tooltip = trigger.nextElementSibling;
tooltip.classList.remove('visible');
}
/**
* Helper method to trigger the workflowabstract element in the form
* @param {} trigger
*/
function toggleWorkflowAbstract(trigger) {
const content = trigger.nextElementSibling;
// Markdown nur einmal parsen (lazy loading)
const markdownContainer = content.querySelector('.imixs-markdown-output');
if (markdownContainer && !markdownContainer.dataset.parsed) {
const rawMarkdown = markdownContainer.textContent;
markdownContainer.innerHTML = marked.parse(rawMarkdown);
markdownContainer.dataset.parsed = 'true';
}
content.classList.toggle('hidden');
}

View file

@ -0,0 +1,116 @@
/* --- Custom Layout --- */
#imixs-header {
background-color: #599191;
}
#imixs-branding {
background-color: #599191;
background-image: url("./logo-01.png");
background-repeat: no-repeat;
background-position: 10px 15px;
background-size: 140px;
min-height: 120px;
color: #fff;
}
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default, .ui-button, html .ui-button.ui-state-disabled:hover, html .ui-button.ui-state-disabled:active {
border: 1px solid #599191;
background: #599191;
}
.imixsfileupload input[type="file"] + label {
background-color: #599191;
}
.imixsfileupload input[type="file"] + label:hover {
background-color: #62a2a2;
}
.ui-button:hover {
background: #62a2a2;
}
.imixs-workitem-chronicle-tabs ul li.active a {
color: #599191;
}
.imixsdatatable th {
background: #599191;
color: #fff;
border-left: 4px solid #599191;
border-bottom: 1px solid #599191;
}
.imixs-llm, .imixs-llm:focus, .imixs-date.imixs-llm, .imixs-date.imixs-llm:focus {
border: none !important;
border-bottom: 2px solid #faa732 !important;
box-shadow: none !important;
text-align: left !important;
border-radius: 0;
background-color: transparent !important;
}
/* Neues Abstract markup */
.tooltip-container {
position: relative;
display: inline-block;
}
.tooltip-trigger {
cursor: pointer;
color: #007bff;
}
.tooltip-content {
display: none;
position: fixed;
font-size: 0.85rem;
line-height: 1.75;
left: 0;
top: 100%;
z-index: 1200;
background: white;
border: 1px solid #ccc;
border-radius: 4px;
min-width: 420px;
max-width: 650px;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
background-color: #ffffff;
padding: 10px;
transition: opacity 0.5s ease-in-out, visibility 0.3s ease-in-out;
}
.tooltip-container:hover .tooltip-content {
display: block;
}
.imixs-workflowabstract-toggle-icon {
margin-left: auto;
align-self: flex-end;
cursor: pointer;
padding: 10px;
font-size: 1.25rem;
color: #599191;
}
.imixs-workflowabstract-content {
flex-basis: 100%;
padding: 0 15px;
border: 1px solid #599191;
margin: 0 15px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -0,0 +1,15 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:a="http://xmlns.jcp.org/jsf/passthrough"
xmlns:i="http://xmlns.jcp.org/jsf/composite/imixs">
<f:view>
<div class="toolbar agent">
<h:inputText a:data-id="nav_input_phrase" style="margin-right: 10px;" a:placeholder="What do you need?"
value="#{aiAgentController.userMessage}" />
<h:commandLink action="#{aiAgentController.startChat()}" a:data-id="nav_search_link"><span
class="typcn typcn-lightbulb" style="font-size:1.4em;"></span>
</h:commandLink>
</div>
</f:view>
</ui:composition>

View file

@ -0,0 +1,79 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:pt="http://xmlns.jcp.org/jsf/passthrough"
xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions" xmlns:marty="http://xmlns.jcp.org/jsf/composite/marty"
xmlns:i="http://xmlns.jcp.org/jsf/composite/imixs">
<!-- Build with link ? -->
<span class="imixs-icon tooltip-container" title=" ">
<span class="tooltip-trigger" onmouseenter="showTooltip(this)" onmouseleave="hideTooltip(this)">
<ui:fragment rendered="#{showlink}">
<h:link outcome="/pages/workitems/workitem">
<!-- typcn -->
<ui:fragment rendered="#{fn:startsWith(workitem.item['txtWorkflowImageURL'],'typcn')}">
<span class="imixs-typicon" data-typicon="#{workitem.item['txtWorkflowImageURL']}"></span>
</ui:fragment>
<!-- Image -->
<ui:fragment rendered="#{!fn:startsWith(workitem.item['txtWorkflowImageURL'],'typcn')}">
<h:graphicImage rendered="#{!empty workitem.item['txtWorkflowImageURL']}"
url="#{workitem.item['txtWorkflowImageURL']}" style="max-height: 24px; margin: 4px;">
</h:graphicImage>
<h:graphicImage rendered="#{empty workitem.item['txtWorkflowImageURL']}"
value="/layout/icons/vwicn070.png" style="max-height: 24px; margin: 4px;"></h:graphicImage>
</ui:fragment>
<f:param name="id" value="#{workitem.item['$uniqueid']}" />
</h:link>
</ui:fragment>
<!-- Build without link -->
<ui:fragment rendered="#{!showlink}">
<!-- typcn -->
<ui:fragment rendered="#{fn:startsWith(workitem.item['txtWorkflowImageURL'],'typcn')}">
<span class="imixs-typicon" data-typicon="#{workitem.item['txtWorkflowImageURL']}"></span>
</ui:fragment>
<!-- Image -->
<ui:fragment rendered="#{!fn:startsWith(workitem.item['txtWorkflowImageURL'],'typcn')}">
<h:graphicImage rendered="#{!empty workitem.item['txtWorkflowImageURL']}"
url="#{workitem.item['txtWorkflowImageURL']}" style="max-height: 24px; margin: 4px;">
</h:graphicImage>
<h:graphicImage rendered="#{empty workitem.item['txtWorkflowImageURL']}"
value="/layout/icons/vwicn070.png" style="max-height: 24px; margin: 4px;"></h:graphicImage>
</ui:fragment>
</ui:fragment>
</span>
<h:panelGroup class="tooltip-content">
<h:outputText value="#{message.created}: " style="font-weight:bold;" />
<h:outputText value="#{workitem.item['$created']}">
<f:convertDateTime timeZone="#{message.timeZone}" type="both" pattern="#{message.dateTimePattern}" />
</h:outputText>
<h:outputText value=" #{message.by} #{userController.getUserName(workitem.item['$creator'])}" />
<!-- Modified -->
<br />
<span>
<h:outputText style="font-weight: bold;" value="#{message.edited}: " />
<h:outputText value="#{workitem.item['$lasteventdate']}" style="font-weight: normal;">
<f:convertDateTime timeZone="#{message.timeZone}" pattern="#{message.dateTimePattern}" />
</h:outputText>
<h:outputText value=" #{message.by} #{userController.getUserName(workitem.item['$editor'])}" />
</span>
<hr />
<!-- Markup -->
<div class="imixs-workflowabstract">
<h:outputText styleClass="imixs-markdown-output" value="#{workitem.item['$WorkflowAbstract']}"
escape="false" />
</div>
</h:panelGroup>
</span>
</ui:composition>

View file

@ -0,0 +1,317 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:i="http://java.sun.com/jsf/composite/imixs" xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:pt="http://xmlns.jcp.org/jsf/passthrough" xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions"
xmlns:marty="http://java.sun.com/jsf/composite/marty" template="/layout/template.xhtml">
<ui:define name="content">
<f:view>
<script type="text/javascript">
/*<![CDATA[*/
$(document).ready(function () {
//$('.imixsdatatable').layoutImixsTable();
});
// This method refreshs the layout
function updateOptions(data) {
if (data.status === 'success') {
$('[id$=Optionlist]').imixsLayout();
/* var id='#'+data.source.id;
if (id.indexOf("input")>-1) {
$(id).focus();
} */
}
}
/*]]>*/
</script>
<h:form id="import_form_id">
<!-- ########## Error ########## -->
<ui:include src="/error_message.xhtml" />
<div class="imixs-form">
<div class="imixs-header">
<h1>Document Importer</h1>
</div>
<div class="imixs-body">
<div class="imixs-tabs">
<ul>
<li><a href="#tab-1">Timer Setting</a></li>
<li><a href="#tab-2">Data Sources</a></li>
</ul>
<!-- ### Timer ### -->
<div id="tab-1">
<div class="ui-state-highlight ui-corner-all"
style="margin-bottom: 10px; padding: .5em;">
<p><span class="typcn typcn-lightbulb"></span> Define a crontab to schedule the
import processor.</p>
</div>
<ui:include src="sub_scheduler_control.xhtml">
<ui:param name="schedulerController" value="#{documentImportController}" />
</ui:include>
</div>
<!-- ### SMTP ### -->
<div id="tab-2">
<div class="ui-state-highlight ui-corner-all"
style="margin-bottom: 10px; padding: .5em;">
<p><span class="typcn typcn-lightbulb"></span> Define a destination IMAP server and
assign mail addresses to specific workflow groups.</p>
</div>
<div class="imixs-form-panel">
<!-- ### Sources ### -->
<h:panelGroup layout="block" id="imapOptionlist"
binding="#{imapOptionlistContainer}">
<f:ajax onevent="updateOptions">
<table class="imixsdatatable" style="width: 100%;">
<thead>
<tr>
<th style="width: 10px;text-align: center;">Pos</th>
<th style="width: 100px;text-align: center;">Type</th>
<th style="">Workflowgroup</th>
<th style="">Modelversion</th>
<th style="">Task</th>
<th style="">Event</th>
<th style="width: 110px;">
<!-- delete -->
</th>
</tr>
</thead>
<tbody>
<ui:repeat var="source" value="#{documentImportController.sources}">
<tr>
<!-- pos -->
<td style=" text-align: center;">
<h:commandLink
actionListener="#{documentImportController.selectSource(source.item['index'])}">
#
<h:outputText value="#{source.item['index']}" />
<f:ajax render="#{imapOptionlistContainer.clientId}"
onevent="updateOptions" />
</h:commandLink>
</td>
<!-- type -->
<td style="text-align: center;">
<h:outputText value="#{source.item['type']}" />
</td>
<!-- Workflowgroup -->
<td>
<h:outputText value="#{source.item['workflowgroup']}" />
</td>
<td>
<h:outputText value="#{source.item['workflowmodel']}" />
</td>
<td>
<h:outputText value="#{source.item['task']}" />
</td>
<td>
<h:outputText value="#{source.item['event']}" />
</td>
<td>
<h:commandLink
actionListener="#{documentImportController.moveSourceDown(source.item['index'])}">
<span
class="typcn typcn-arrow-down-thick imixs-state-info"></span>
<f:ajax render="#{imapOptionlistContainer.clientId}"
onevent="updateOptions" />
</h:commandLink>
<h:commandLink
actionListener="#{documentImportController.moveSourceUp(source.item['index'])}">
<span
class="typcn typcn-arrow-up-thick imixs-state-info"></span>
<f:ajax render="#{imapOptionlistContainer.clientId}"
onevent="updateOptions" />
</h:commandLink>
<h:commandLink
actionListener="#{documentImportController.removeSource(source.item['index'])}">
<span
class="typcn typcn-trash imixs-state-info"></span>
<f:ajax render="#{imapOptionlistContainer.clientId}"
onevent="updateOptions" />
</h:commandLink>
</td>
</tr>
</ui:repeat>
</tbody>
</table>
<!-- add button -->
<h:commandButton value="#{message.add}"
actionListener="#{documentImportController.addSource()}">
<f:ajax render="#{imapOptionlistContainer.clientId}"
onevent="updateOptions" />
</h:commandButton>
<!-- ### Subform for selected source ### -->
<h:panelGroup layout="block"
rendered="#{! empty documentImportController.source}"
styleClass="imixs-form-panel">
<h3>Order ID #
<h:outputText
value="#{documentImportController.source.item['index']}" />
</h3>
<div class="imixs-form-section-3">
<dl>
<dt>Type</dt>
<dd>
<h:selectOneRadio
value="#{documentImportController.source.item['type']}">
<f:selectItem itemLabel="IMAP" itemValue="IMAP" />
<f:selectItem itemLabel="FTP" itemValue="FTP" />
<f:selectItem itemLabel="CSV" itemValue="CSV" />
</h:selectOneRadio>
</dd>
</dl>
<dl>
<dt>Workflowgroup</dt>
<dd>
<h:selectOneMenu
value="#{documentImportController.source.item['workflowgroup']}">
<f:selectItem itemLabel=" - " itemValue="" />
<c:forEach items="#{modelController.workflowGroups}"
var="group">
<f:selectItem itemLabel="#{group}"
itemValue="#{group}" />
</c:forEach>
</h:selectOneMenu>
</dd>
</dl>
</div>
<div class="imixs-form-section-3">
<dl>
<dt>Workflowmodel</dt>
<dd>
<h:inputText
value="#{documentImportController.source.item['workflowmodel']}" />
</dd>
</dl>
<dl>
<dt>Task ID</dt>
<dd>
<h:inputText
value="#{documentImportController.source.item['task']}" />
</dd>
</dl>
<dl>
<dt>Event ID</dt>
<dd>
<h:inputText
value="#{documentImportController.source.item['event']}" />
</dd>
</dl>
</div>
<hr />
<!-- IMAP -->
<div class="imixs-form-section-3">
<dl>
<dt>Server : Port</dt>
<dd>
<h:inputText style="width:80%;"
value="#{documentImportController.source.item['server']}">
</h:inputText> : <h:inputText style="width:15%;"
value="#{documentImportController.source.item['port']}">
</h:inputText>
</dd>
</dl>
<dl>
<dt>User</dt>
<dd>
<h:inputText required="false"
value="#{documentImportController.source.item['user']}">
</h:inputText>
</dd>
</dl>
<dl>
<dt>Password</dt>
<dd>
<h:inputSecret required="false" redisplay="true"
value="#{documentImportController.source.item['password']}">
</h:inputSecret>
</dd>
</dl>
</div>
<div class="imixs-form-section">
<dl>
<dt>Selector</dt>
<dd>
<h:inputText required="false"
value="#{documentImportController.source.item['selector']}">
</h:inputText>
<p class="small">A selector can be an optional regular
expression to be used to select a subset of data</p>
</dd>
</dl>
<dl>
<dt>Options</dt>
<dd>
<h:inputTextarea required="false"
style="height: 5em; width: 100%;"
value="#{documentImportController.source.item['options']}">
</h:inputTextarea>
<p class="small">You can apply custom properties here.
</p>
</dd>
</dl>
</div>
</h:panelGroup> <!-- end of source subform -->
</f:ajax>
</h:panelGroup>
</div>
</div>
</div>
</div>
<div class="imixs-footer">
<h:outputLabel value="#{message.modified}: " />
<h:outputText value="#{documentImportController.configuration.item['$modified']}">
<f:convertDateTime timeZone="#{message.timeZone}" type="both"
pattern="#{message.dateTimePattern}" />
</h:outputText>
<br />
<h:commandButton actionListener="#{documentImportController.saveConfiguration()}"
action="/pages/admin/document_import" value="#{message.save}">
</h:commandButton>
<h:commandButton value="#{message.close}" action="notes" />
</div>
</div>
</h:form>
</f:view>
</ui:define>
</ui:composition>

View file

@ -1,9 +1,6 @@
<f:subview xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:pt="http://xmlns.jcp.org/jsf/passthrough"
<f:subview xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core" xmlns:pt="http://xmlns.jcp.org/jsf/passthrough"
xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions">
<script type="text/javascript">
@ -22,27 +19,23 @@
<!-- **** General info ***** -->
<div class="imixs-form-panel">
<h:inputTextarea required="false"
converter="org.imixs.VectorConverter"
style="height: 8em; width: 100%;"
<h:inputTextarea required="false" converter="org.imixs.VectorConverter" style="height: 8em; width: 100%;"
value="#{schedulerController.configuration.itemList['_scheduler_definition']}">
</h:inputTextarea>
</div>
<!-- **** Timer Status ***** -->
<h:panelGroup layout="block" class="imixs-form-panel" id="status_panel">
<h:panelGroup layout="block" id="timer_details"
class="imixs-form-section">
<h:panelGroup layout="block" id="timer_details" class="imixs-form-section">
<h2>
<h:outputText id="timer_status"
value="Status ⇢ #{schedulerController.configuration.item['_scheduler_status']}" />
<h:panelGroup
rendered="#{! empty schedulerController.configuration.item['_scheduler_errormessage']}"
<h:panelGroup rendered="#{! empty schedulerController.configuration.item['_scheduler_errormessage']}"
class="small" style="color:red">
<br />Error: #{schedulerController.configuration.item['_scheduler_errormessage']}
</h:panelGroup>
</h:panelGroup>
</h2>
<h:panelGrid columns="2">
@ -51,26 +44,17 @@
<h:outputLabel value="ID: " />
</h:panelGroup>
<h:panelGroup>
<h:outputText
value="#{schedulerController.configuration.item['$UniqueID']}" />
<h:outputText value="#{schedulerController.configuration.item['$UniqueID']}" />
</h:panelGroup>
<h:outputLabel value="Schedule: " />
<h:outputText
value="#{schedulerController.configuration.item['Schedule']}" />
<h:outputText value="#{schedulerController.configuration.item['Schedule']}" />
<h:outputLabel value="Next Timeout: " />
<h:panelGroup>
<h:outputText
value="#{schedulerController.configuration.item['nextTimeout']}"
<h:outputText value="#{schedulerController.configuration.item['nextTimeout']}"
rendered="#{! empty schedulerController.configuration.item['nextTimeout']}">
<f:convertDateTime timeZone="#{message.timeZone}" type="both"
pattern="#{message.dateTimePattern}" />
</h:outputText>
<h:outputText value=" " />
</h:panelGroup>
@ -78,26 +62,17 @@
<h:outputLabel value="TimeRemaining: " />
<h:outputText
value="#{schedulerController.millisToShortDHMS(schedulerController.configuration.item['timeRemaining'])}" />
</h:panelGrid>
<h:outputLabel value="Last Run: " />
<h:panelGroup layout="block" class="ui-state-highlight ui-corner-all"
style="padding: .5em;">
<ui:fragment
rendered="#{! empty schedulerController.configuration.item['_scheduler_logmessage']}">
<ui:repeat var="logentry"
value="#{schedulerController.configuration.itemList['_scheduler_logmessage']}">
<h:outputText escape="false" value="#{logentry}" />
<br />
</ui:repeat>
style="padding: .5em;background: #f5f5f5;padding: 10px;height: 260px;overflow-y: auto;">
<ui:fragment rendered="#{! empty schedulerController.configuration.item['_scheduler_logmessage']}">
<pre style="font-family: 'Courier New', Courier, monospace;color: #111;line-height: 1.0rem;"> <ui:repeat var="logentry" value="#{schedulerController.configuration.itemList['_scheduler_logmessage']}">
<h:outputText escape="false" value="#{logentry}" /><br />
</ui:repeat></pre>
</ui:fragment>
<ui:fragment
rendered="#{empty schedulerController.configuration.item['_scheduler_logmessage']}">
No Data.
<ui:fragment rendered="#{empty schedulerController.configuration.item['_scheduler_logmessage']}">
No Data.
</ui:fragment>
</h:panelGroup>
@ -106,21 +81,16 @@
<!-- Timer Actions -->
<h:commandButton value="#{message.refresh}"
actionListener="#{schedulerController.refresh}">
<h:commandButton value="#{message.refresh}" actionListener="#{schedulerController.refresh}">
<f:ajax render="status_panel" onevent="updateStatustPanel" />
</h:commandButton>
<h:commandButton
actionListener="#{schedulerController.startScheduler}" value="start">
<h:commandButton actionListener="#{schedulerController.startScheduler}" value="start">
</h:commandButton>
<h:commandButton actionListener="#{schedulerController.stopScheduler}"
value="stop">
<h:commandButton actionListener="#{schedulerController.stopScheduler}" value="stop">
</h:commandButton>
<h:commandButton
actionListener="#{schedulerController.restartScheduler}"
value="restart">
<h:commandButton actionListener="#{schedulerController.restartScheduler}" value="restart">
</h:commandButton>

View file

@ -0,0 +1,107 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:pt="http://xmlns.jcp.org/jsf/passthrough"
xmlns:marty="http://xmlns.jcp.org/jsf/composite/marty" xmlns:i="http://xmlns.jcp.org/jsf/composite/imixs">
<div style="display: flex;">
<div style="flex:1;">
<h1>
<h:outputText value="#{workflowController.workitem.item['$workflowgroup']}" />
»
<h:outputText value=" #{workflowController.workitem.item['$workflowstatus']}" />
<!-- Display Deleted status -->
<h:outputText rendered="#{workflowController.workitem.item['type'] eq 'workitemdeleted'}"
value="- #{message.deleted}!" style="color:red;" />
</h1>
<!-- Workitem Info Header -->
<div class="imixs-form-header">
<!-- *** Image *** -->
<div class="image-block">
<ui:include src="/layout/workitem_icon.xhtml">
<ui:param name="workitem" value="#{workflowController.workitem}" />
<ui:param name="hidetooltip" value="#{true}" />
</ui:include>
</div>
<ui:remove><!-- *** Standard Info *** --></ui:remove>
<div class="content-block">
<h2>
<h:outputText escape="false"
rendered="#{empty workflowController.workitem.item['$WorkflowSummary']}"
value="#{message.new_workitem}" />
<h:outputText escape="false"
rendered="#{!empty workflowController.workitem.item['$WorkflowSummary']}"
value="#{workflowController.workitem.item['$WorkflowSummary']}" />
</h2>
<h:outputLabel value="#{message['process.title']}: " />
<h:link outcome="/pages/notes_board?processref=#{workflowController.workitem.item['process.Ref']}">
<h:outputText value="#{workflowController.workitem.item['Process.Name']}" />
</h:link>
<ui:remove><!-- *** Owners *** --></ui:remove>
<h:panelGroup styleClass="imixs-no-print" layout="block">
<ui:repeat value="#{workflowController.workitem.itemList['$owner']}" var="name">
<ui:param name="profile" value="#{userController.getProfile(name)}"></ui:param>
<ui:fragment rendered="#{! empty profile}">
<h:graphicImage styleClass="imixs-workitem-chronicle-usericon"
title="#{profile.item['txtusername']}"
rendered="#{! empty profile.item['txtusericon']}"
value="/api/snapshot/#{profile.item['$uniqueid']}/file/#{profile.item['txtusericon']}">
</h:graphicImage>
<!-- optional - user initials -->
<h:panelGroup layout="block" rendered="#{empty profile.item['txtusericon']}">
<h:outputText styleClass="imixs-workitem-chronicle-usericon"
title="#{profile.item['txtusername']}" value="#{profile.item['txtinitials']}" />
</h:panelGroup>
</ui:fragment>
</ui:repeat>
</h:panelGroup>
</div>
<!-- *** Comment Toggle *** -->
<div class="imixs-workflowabstract-toggle-icon" onclick="toggleWorkflowAbstract(this)">
<i class="fa-regular fa-comment-dots"></i>
</div>
<!-- Extra Content - volle Breite -->
<div class="imixs-workflowabstract-content hidden">
<h:outputText styleClass="imixs-markdown-output"
rendered="#{workflowController.workitem.taskID eq 1210}"
value="#{indexController.getContent(workflowController.workitem.uniqueID, 'CSDDD')}"
escape="false" />
<h:outputText styleClass="imixs-markdown-output"
rendered="#{workflowController.workitem.taskID ne 1210}"
value="#{indexController.getContent(workflowController.workitem.uniqueID, '')}"
escape="false" />
</div>
</div>
</div>
<!-- QR-Code displayed only if property 'qr-code.url.prafix' is filled -->
<ui:param name=" qrprafix" value="#{propertyController.getProperty('qr-code.url.prafix')}">
</ui:param>
<ui:fragment
rendered="#{(! empty workflowController.workitem.uniqueID) and (!userController.mobileUser) and (!empty qrprafix)}">
<div style="flex-grow: 1;"></div>
<div>
<a href="#" onclick="imixsOfficeWorkitem.printQRCode();">
<h:graphicImage styleClass="imixsQrCode"
url="/api/qr-code?size=130&amp;key=#{qrprafix}#{workflowController.workitem.uniqueID}">
</h:graphicImage>
</a>
</div>
</ui:fragment>
</div>
</ui:composition>

View file

@ -0,0 +1,140 @@
/****************************************************************************
* Copyright (c) 2022-2025 Imixs Software Solutions GmbH and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* This Source Code may also be made available under the terms of the
* GNU General Public License, version 2 or later (GPL-2.0-or-later),
* which is available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
****************************************************************************/
package ai.dynamixs.agent;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.Optional;
import org.imixs.ai.ImixsAIContextHandler;
import org.imixs.ai.workflow.OpenAIAPIConnector;
import org.imixs.ai.workflow.OpenAIAPIService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
/**
* Test class to test a function call
*
*
* @author rsoika
*/
@ExtendWith(MockitoExtension.class)
public class TestAgentCall {
private static final String MISTRAL_ENDPOINT = "https://api.llama.cpp.imixs.com/";
public static final String MISTRAL_API_KEY = "7fdb663fa87ea16731c1e0ece8ad3214e358423eabf2403188110c731ce07321";
private OpenAIAPIService service;
private OpenAIAPIConnector connector;
@BeforeEach
void setUp() throws Exception {
connector = new OpenAIAPIConnector();
connector.setServiceEndpointApiKey(Optional.of(MISTRAL_API_KEY));
connector.setServiceEndpointUser(Optional.empty());
connector.setServiceEndpointPassword(Optional.empty());
injectField(connector, "serviceTimeout", 30000);
injectField(connector, "serviceEndpoint", Optional.of(MISTRAL_ENDPOINT));
service = new OpenAIAPIService();
injectField(service, "openAIAPIConnector", connector);
}
@Test
void testHelloWorld() throws Exception {
// Build a simple "Hello World" prompt
ImixsAIContextHandler contextHandler = new ImixsAIContextHandler();
contextHandler.addQuestion("Say hello world!", null, null);
String response = service.postPromptCompletion(contextHandler, MISTRAL_ENDPOINT, true);
assertNotNull(response);
System.out.println("Response: " + response);
}
@Test
void testFunctionCalling() throws Exception {
ImixsAIContextHandler contextHandler = new ImixsAIContextHandler();
// Define system context
contextHandler.addSystemMessage("""
You are a workflow assistant integrated into the Imixs-Office-Workflow suite.
The following BPMN processes are available:
- urlaubsantrag: Vacation request process
- reisekostenabrechnung: Travel expense process
- eingangsrechnung: Incoming invoice process
When a user wants to start a process, always call the load_skill tool
with the matching process_id. Never ask the user for the process ID.
""");
// Define the load_skill function
contextHandler.addFunction(
"load_skill",
"Loads details about an available BPMN workflow process",
"""
{
"type": "object",
"properties": {
"process_id": {
"type": "string",
"description": "The ID of the BPMN process, e.g. urlaubsantrag"
}
},
"required": ["process_id"]
}
""");
contextHandler.addQuestion(
"I need next week off. Can you start the vacation request process?",
"tom.clancy", new Date());
// Print the full request JSON to verify it looks correct
System.out.println("Request: " + contextHandler.toString());
String response = service.postPromptCompletion(contextHandler, MISTRAL_ENDPOINT, true);
assertNotNull(response);
System.out.println("Response: " + response);
// Check if Mistral responded with a tool call
assertTrue(response.contains("load_skill"),
"Expected Mistral to call load_skill tool");
// Verify Mistral responded with a tool call
assertTrue(response.contains("\"finish_reason\":\"tool_calls\""));
assertTrue(response.contains("\"name\":\"load_skill\""));
assertTrue(response.contains("urlaubsantrag"));
}
private void injectField(Object target, String fieldName, Object value) throws Exception {
Class<?> clazz = target.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(target, value);
return;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
}

View file

@ -0,0 +1,583 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- origin at X=0.0 Y=0.0 --><bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:BPMN2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:ext="http://org.eclipse.bpmn2/ext" xmlns:imixs="http://www.imixs.org/bpmn2" xmlns:open-bpmn="http://open-bpmn.org/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exporter="org.eclipse.bpmn2.modeler.core" exporterVersion="1.5.4.RC1-v20220528-0836-B1" id="Definitions_1" targetNamespace="http://www.imixs.org/bpmn2">
<bpmn2:extensionElements>
<imixs:item name="txtworkflowmodelversion" type="xs:string">
<imixs:value><![CDATA[offer-en-1.0]]></imixs:value>
</imixs:item>
<imixs:item name="txtfieldmapping" type="xs:string">
<imixs:value><![CDATA[Creator|$Creator]]></imixs:value>
<imixs:value><![CDATA[Current Editor|$Editor]]></imixs:value>
<imixs:value><![CDATA[Owner|$owner]]></imixs:value>
<imixs:value><![CDATA[Process Manager|process.manager]]></imixs:value>
<imixs:value><![CDATA[Process Team|process.team]]></imixs:value>
<imixs:value><![CDATA[Process Assist|process.assist]]></imixs:value>
<imixs:value><![CDATA[Department Manager|space.manager]]></imixs:value>
<imixs:value><![CDATA[Department Team|space.team]]></imixs:value>
<imixs:value><![CDATA[Department Assist|space.assist]]></imixs:value>
</imixs:item>
<imixs:item name="txttimefieldmapping" type="xs:string">
<imixs:value><![CDATA[Liefertermin|order.delivery]]></imixs:value>
</imixs:item>
<imixs:item name="txtplugins" type="xs:string">
<imixs:value><![CDATA[org.imixs.workflow.office.plugins.WorkitemLinkPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.ai.rag.RAGIndexPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.ResultPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.RulePlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.profile.ProfilePlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.plugins.CommentPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.plugins.SequenceNumberPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.team.TeamPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.profile.DeputyPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.OwnerPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.HistoryPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.LogPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.ApplicationPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.profile.MailPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.IntervalPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.SplitAndJoinPlugin]]></imixs:value>
<imixs:value><![CDATA[ai.dynamixs.cognition.CognitoPlugin]]></imixs:value>
</imixs:item>
<open-bpmn:auto-align>true</open-bpmn:auto-align>
</bpmn2:extensionElements>
<bpmn2:collaboration id="Collaboration_1" name="Collaboration 1">
<bpmn2:participant id="Participant_1" name="Example" processRef="Process_1">
<bpmn2:documentation id="documentation_3xKpCQ"/>
</bpmn2:participant>
<bpmn2:participant id="participant_hnZfjA" name="Default Process" processRef="process_2"/>
</bpmn2:collaboration>
<bpmn2:process definitionalCollaborationRef="Collaboration_1" id="Process_1" isExecutable="false" name="Example" processType="Private">
<bpmn2:laneSet id="LaneSet_1" name="Lane Set 1">
<bpmn2:lane id="Lane_1" name="Team">
<bpmn2:documentation id="documentation_gvQWYQ"/>
<bpmn2:flowNodeRef>StartEvent_1</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>EndEvent_2</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_yrC2dw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_J0JjAg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_1FAZgA</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_cjoSqg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>gateway_SVo89A</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_5P6uhg</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_5RftUw" name="Contract Management">
<bpmn2:documentation id="documentation_AW2roA"/>
<bpmn2:flowNodeRef>task_0W5Llw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_0k30Ug</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_vJ0eNA</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_a0dlhQ" name="Contract Owner">
<bpmn2:documentation id="documentation_fATy7A"/>
<bpmn2:flowNodeRef>task_GgAr6w</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_zpkT5A</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_v7oUjw</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_A6bDCA" name="Sales">
<bpmn2:documentation id="documentation_l0BSxA"/>
</bpmn2:lane>
</bpmn2:laneSet>
<bpmn2:startEvent id="StartEvent_1" name="Start">
<bpmn2:documentation id="documentation_IUTaAQ"/>
<bpmn2:outgoing>sequenceFlow_mCJiSA</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:endEvent id="EndEvent_2" name="End">
<bpmn2:documentation id="documentation_mHDfBQ"/>
</bpmn2:endEvent>
<bpmn2:task id="task_yrC2dw" imixs:processid="2100" name="Contract Creation">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_BN3NHA"><![CDATA[Erstellung eines neuen Vertrags mit folgenden Pflichtfeldern: - **Vertragspartner** (Name, Adresse, Kontaktdaten, Vertragsnummer) - **Waren/Lieferungen** (Beschreibung, Menge, Einheit, Preis pro Einheit, Gesamtpreis, ggf. SKU/Artikelnummer) - **Lagerort** (falls relevant: Lagerstandort, Lagerverantwortlicher) - **Termine** (Liefertermin(e), Vertragslaufzeit, Fristen für Zahlungen/Meldungen) Optional: **Sonderbedingungen** (z. B. Rabatte, Penalties, Zahlungsmodalitäten).]]></bpmn2:documentation>
<bpmn2:incoming>sf-5</bpmn2:incoming>
<bpmn2:incoming>sequenceFlow_mCJiSA</bpmn2:incoming>
<bpmn2:outgoing>sf-8</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:task id="task_vJ0eNA" imixs:processid="2300" name="Approval by Management">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_6PFUVg"><![CDATA[Freigabe des Vertrags unter Berücksichtigung: - **Finanzielle Auswirkungen** (Budget, Liquidität, Forecast) - **Strategische Bedeutung** (Neukunde, Langfristpartner) - **Risikoanalyse** (Bonität des Partners, Marktrisiken)]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_4076SQ</bpmn2:incoming>
</bpmn2:task>
<bpmn2:task id="task_XQfsfg" imixs:processid="2400" name="Contract Execution">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_ds3A0w"><![CDATA[**Finaler Schritt zur Vertragsaktivierung:** - **Vertragsunterzeichnung** (digital/physisch) durch beide Parteien. - **Datenaktualisierung im System**: - **Vertragspartner** → CRM/ERP (z. B. SAP, Salesforce). - **Waren/Lieferungen** → Lagerverwaltung/Logistik (z. B. Warehouse-Management-System). - **Termine** → Kalender/Projektmanagement (z. B. Microsoft Project, Jira). - **Finanzen** → Buchhaltung (Rechnungslauf, Zahlungspläne). - **Lagerort** → Bei physischen Gütern: Einlagerung und Zuordnung (z. B. per Barcode).]]></bpmn2:documentation>
</bpmn2:task>
<bpmn2:task id="task_GgAr6w" imixs:processid="2900" name="Contract Completed">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_uK2mxw"><![CDATA[**Vertragsbeendigung:** - Kündigungsfristen einhalten. - **Liquidation**: - Offene Rechnungen prüfen (Zahlungseingang/Stornierung). - Lagerbestände bereinigen (Rücklieferung/Rücknahme). - **Dokumentation**: - Grund der Kündigung festhalten (für zukünftige Entscheidungen). - Vertrag aus dem System löschen.]]></bpmn2:documentation>
<bpmn2:outgoing>sf-44</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:task id="task_0W5Llw" imixs:processid="2990" name="Request/Contract Rejected">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_XDZRNw"><![CDATA[**Abgelehter Vertrag oder Anfrage:** - Grund für die Ablehnung dokumentieren (z. B. "Partner nicht solvent"). - Feedback an Initiator geben. - END]]></bpmn2:documentation>
<bpmn2:incoming>sf-4</bpmn2:incoming>
<bpmn2:incoming>sf-9</bpmn2:incoming>
<bpmn2:incoming>sf-45</bpmn2:incoming>
</bpmn2:task>
<bpmn2:intermediateCatchEvent id="event_5P6uhg" imixs:activityid="20" name="Reject Request">
<bpmn2:documentation id="documentation_FFCYJw"/>
<bpmn2:outgoing>sf-4</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_J0JjAg" imixs:activityid="10" name="Save Draft">
<bpmn2:documentation id="documentation_2D4qfg"/>
<bpmn2:outgoing>sf-5</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_cjoSqg" imixs:activityid="20" name="Submit for Review">
<bpmn2:documentation id="documentation_44KEYA"/>
<bpmn2:incoming>sf-6</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_4076SQ</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_1FAZgA" imixs:activityid="30" name="Cancel Request">
<bpmn2:documentation id="documentation_ysbsYg"/>
<bpmn2:incoming>sequenceFlow_Jp2oQQ</bpmn2:incoming>
<bpmn2:outgoing>sf-9</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_0k30Ug" imixs:activityid="10" name="Request Adjustments">
<bpmn2:documentation id="documentation_gmDYqA"/>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_Xdll0Q" imixs:activityid="20" name="Final Approval">
<bpmn2:documentation id="documentation_md4VQA"/>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_W0tDdA" imixs:activityid="30" name="Decline Approval">
<bpmn2:documentation id="documentation_mRacqQ"/>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_yurw7A" imixs:activityid="10" name="Completed">
<bpmn2:documentation id="documentation_sqwDNg"/>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_c4BtJg" imixs:activityid="20" name="Execution Failed">
<bpmn2:documentation id="documentation_thihzw"/>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_zpkT5A" imixs:activityid="20" name="Correction Needed">
<bpmn2:documentation id="documentation_iUtChg"/>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_v7oUjw" imixs:activityid="10" name="Termination Completed">
<bpmn2:documentation id="documentation_bwy4xQ"/>
<bpmn2:incoming>sf-44</bpmn2:incoming>
<bpmn2:outgoing>sf-45</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sf-4" sourceRef="event_5P6uhg" targetRef="task_0W5Llw">
<bpmn2:documentation id="documentation_rBwcmQ"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sf-5" sourceRef="event_J0JjAg" targetRef="task_yrC2dw">
<bpmn2:documentation id="documentation_QaeCdA"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sf-6" sourceRef="gateway_SVo89A" targetRef="event_cjoSqg">
<bpmn2:documentation id="documentation_BUeEdQ"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sf-8" sourceRef="task_yrC2dw" targetRef="gateway_SVo89A">
<bpmn2:documentation id="documentation_Sd5bvw"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sf-9" sourceRef="event_1FAZgA" targetRef="task_0W5Llw">
<bpmn2:documentation id="documentation_bJindA"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sf-44" sourceRef="task_GgAr6w" targetRef="event_v7oUjw">
<bpmn2:documentation id="documentation_to0tvg"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sf-45" sourceRef="event_v7oUjw" targetRef="task_0W5Llw">
<bpmn2:documentation id="documentation_CjUGog"/>
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_H7qtPg" imixs:activityid="20" name="Create Kundenauftrag">
<bpmn2:documentation id="documentation_w9TwIQ"/>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_mCJiSA" sourceRef="StartEvent_1" targetRef="task_yrC2dw">
<bpmn2:documentation id="documentation_rnZlMw"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_4076SQ" sourceRef="event_cjoSqg" targetRef="task_vJ0eNA">
<bpmn2:documentation id="documentation_2UZmwA"/>
</bpmn2:sequenceFlow>
<bpmn2:eventBasedGateway gatewayDirection="Diverging" id="gateway_SVo89A" name="">
<bpmn2:documentation id="documentation_C4eyaQ"/>
<bpmn2:incoming>sf-8</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_Jp2oQQ</bpmn2:outgoing>
<bpmn2:outgoing>sf-6</bpmn2:outgoing>
</bpmn2:eventBasedGateway>
<bpmn2:sequenceFlow id="sequenceFlow_Jp2oQQ" sourceRef="gateway_SVo89A" targetRef="event_1FAZgA">
<bpmn2:documentation id="documentation_Wzw9Yg"/>
</bpmn2:sequenceFlow>
</bpmn2:process>
<bpmn2:process id="process_2" name="Default Process" processType="Public">
<bpmn2:documentation id="documentation_imRbaw"/>
<bpmn2:extensionElements>
<open-bpmn:auto-align>true</open-bpmn:auto-align>
</bpmn2:extensionElements>
</bpmn2:process>
<bpmn2:signal id="signal_3" name="org.imixs.ai.workflow.OpenAIAPIAdapter"/>
<bpmn2:signal id="signal_4" name="org.imixs.ai.rag.RAGRetrievalAdapter"/>
<bpmn2:message id="message_1" name="Message 1">
<bpmn2:documentation id="documentation_lq3hSg"/>
</bpmn2:message>
<bpmn2:signal id="signal_5" name="org.imixs.ai.workflow.ImixsAIAssistantAdapter"/>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane bpmnElement="Collaboration_1" id="BPMNPlane_Process_1">
<bpmndi:BPMNShape bpmnElement="Participant_1" id="BPMNShape_Participant_1" isHorizontal="true">
<dc:Bounds height="2300.0" width="4430.0" x="130.0" y="90.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Lane_1" id="BPMNShape_Lane_1" isHorizontal="true">
<dc:Bounds height="420.25001525878906" width="4400.0" x="160.0" y="90.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="StartEvent_1" id="BPMNShape_StartEvent_1">
<dc:Bounds height="36.0" width="36.0" x="217.0" y="177.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_1" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="20.0" width="100.0" x="189.5" y="214.10797119140625"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_TextAnnotation_1">
<dc:Bounds height="73.0" width="131.0" x="130.0" y="581.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_30">
<dc:Bounds height="67.0" width="119.0" x="136.0" y="581.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="EndEvent_2" id="BPMNShape_EndEvent_2">
<dc:Bounds height="36.0" width="36.0" x="1027.0" y="197.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_110" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="20.0" width="100.0" x="1001.138671875" y="235.10791015625"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="participant_hnZfjA" id="BPMNShape_iHhp5Q">
<dc:Bounds height="210.0" width="800.0" x="0.0" y="0.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="message_1" id="BPMNShape_5X9D7w">
<dc:Bounds height="20.0" width="30.0" x="80.0" y="10.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_20MvBw">
<dc:Bounds height="20.0" width="100.0" x="45.86090087890625" y="37.66443634033203"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="lane_5RftUw" id="BPMNShape_Lane_EXH7Fg">
<dc:Bounds height="651.2500152587891" width="4400.0" x="160.0" y="510.25001525878906"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="lane_a0dlhQ" id="BPMNShape_Lane_lMjKqQ">
<dc:Bounds height="614.2500152587891" width="4400.0" x="160.0" y="1161.5000305175781"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="lane_A6bDCA" id="BPMNShape_Lane_ErklDA">
<dc:Bounds height="614.2500152587891" width="4400.0" x="160.0" y="1775.7500457763672"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_yrC2dw" id="BPMNShape_mtNu0w">
<dc:Bounds height="50.0" width="110.0" x="340.0" y="170.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_vJ0eNA" id="BPMNShape_VSjVPA">
<dc:Bounds height="50.0" width="110.0" x="980.0" y="670.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_XQfsfg" id="BPMNShape_Vk1kAw">
<dc:Bounds height="50.0" width="110.0" x="1540.0" y="1080.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_GgAr6w" id="BPMNShape_PSzHWw">
<dc:Bounds height="50.0" width="110.0" x="2260.0" y="1300.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_0W5Llw" id="BPMNShape_WjH04g">
<dc:Bounds height="50.0" width="110.0" x="2420.0" y="400.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_5P6uhg" id="BPMNShape_1ACHNw">
<dc:Bounds height="36.0" width="36.0" x="1227.0" y="397.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_IsYLwA">
<dc:Bounds height="20.0" width="100.0" x="1195.0" y="436.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_J0JjAg" id="BPMNShape_zrh0rg">
<dc:Bounds height="36.0" width="36.0" x="377.0" y="97.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_fwqgDg">
<dc:Bounds height="20.0" width="100.0" x="345.0" y="136.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_cjoSqg" id="BPMNShape_POp4IQ">
<dc:Bounds height="36.0" width="36.0" x="827.0" y="367.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_zhSm0g">
<dc:Bounds height="20.0" width="100.0" x="795.0" y="406.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_1FAZgA" id="BPMNShape_bSO6tQ">
<dc:Bounds height="36.0" width="36.0" x="897.0" y="177.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_gAvpBQ">
<dc:Bounds height="20.0" width="100.0" x="865.0" y="216.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_0k30Ug" id="BPMNShape_Zn0P3A">
<dc:Bounds height="36.0" width="36.0" x="757.0" y="667.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_umknQA">
<dc:Bounds height="20.0" width="100.0" x="725.0" y="706.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_Xdll0Q" id="BPMNShape_Eq39Kg">
<dc:Bounds height="36.0" width="36.0" x="1317.0" y="920.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_G1WeRA">
<dc:Bounds height="20.0" width="100.0" x="1285.0" y="959.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_W0tDdA" id="BPMNShape_5yHEow">
<dc:Bounds height="36.0" width="36.0" x="1407.0" y="857.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_HkKcBw">
<dc:Bounds height="20.0" width="100.0" x="1375.0" y="896.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_yurw7A" id="BPMNShape_rWONBg">
<dc:Bounds height="36.0" width="36.0" x="1887.0" y="1147.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_s0S0ng">
<dc:Bounds height="20.0" width="100.0" x="1855.0" y="1186.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_c4BtJg" id="BPMNShape_iclF5g">
<dc:Bounds height="36.0" width="36.0" x="1857.0" y="1047.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_Gi1kIA">
<dc:Bounds height="20.0" width="100.0" x="1825.0" y="1086.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_zpkT5A" id="BPMNShape_TbcBcA">
<dc:Bounds height="36.0" width="36.0" x="1487.0" y="1317.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_9UFuzg">
<dc:Bounds height="20.0" width="100.0" x="1455.0" y="1356.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_v7oUjw" id="BPMNShape_p2C5FA">
<dc:Bounds height="36.0" width="36.0" x="2727.0" y="1357.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_DFJutA">
<dc:Bounds height="20.0" width="100.0" x="2695.0" y="1396.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_H7qtPg" id="BPMNShape_zXH5Wg">
<dc:Bounds height="36.0" width="36.0" x="1317.0" y="1087.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_BcZSCQ">
<dc:Bounds height="20.0" width="100.0" x="1285.0" y="1126.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="gateway_SVo89A" id="BPMNShape_rffh8A">
<dc:Bounds height="50.0" width="50.0" x="600.0" y="170.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_eaxusQ">
<dc:Bounds height="20.0" width="100.0" x="575.0" y="223.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sf-4" id="BPMNEdge_oO9ZTA" sourceElement="BPMNShape_1ACHNw" targetElement="BPMNShape_WjH04g">
<di:waypoint x="1263.0" y="415.0"/>
<di:waypoint x="1267.0" y="415.0"/>
<di:waypoint x="1267.0" y="425.0"/>
<di:waypoint x="2420.0" y="425.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-5" id="BPMNEdge_GZrbVw" sourceElement="BPMNShape_zrh0rg" targetElement="BPMNShape_mtNu0w">
<di:waypoint x="395.0" y="133.0"/>
<di:waypoint x="395.0" y="170.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-6" id="BPMNEdge_SKcIKQ" sourceElement="BPMNShape_rffh8A" targetElement="BPMNShape_POp4IQ">
<di:waypoint x="625.0" y="220.0"/>
<di:waypoint x="625.0" y="385.0"/>
<di:waypoint x="827.0" y="385.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-8" id="BPMNEdge_J17Pgg" sourceElement="BPMNShape_mtNu0w" targetElement="BPMNShape_rffh8A">
<di:waypoint x="450.0" y="195.0"/>
<di:waypoint x="600.0" y="195.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-9" id="BPMNEdge_oJE2uQ" sourceElement="BPMNShape_bSO6tQ" targetElement="BPMNShape_WjH04g">
<di:waypoint x="933.0" y="195.0"/>
<di:waypoint x="1677.0" y="195.0"/>
<di:waypoint x="1677.0" y="425.0"/>
<di:waypoint x="2420.0" y="425.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-44" id="BPMNEdge_IzbEkA" sourceElement="BPMNShape_PSzHWw" targetElement="BPMNShape_p2C5FA">
<di:waypoint x="2370.0" y="1329.0"/>
<di:waypoint x="3230.0" y="1329.0"/>
<di:waypoint x="3230.0" y="1375.0"/>
<di:waypoint x="2763.0" y="1375.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-45" id="BPMNEdge_TxZz3A" sourceElement="BPMNShape_p2C5FA" targetElement="BPMNShape_WjH04g">
<di:waypoint x="2763.0" y="1375.0"/>
<di:waypoint x="3282.0" y="1375.0"/>
<di:waypoint x="2474.0" y="1375.0"/>
<di:waypoint x="2474.0" y="450.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_mCJiSA" id="BPMNEdge_m1mtfw" sourceElement="BPMNShape_StartEvent_1" targetElement="BPMNShape_mtNu0w">
<di:waypoint x="253.0" y="195.0"/>
<di:waypoint x="340.0" y="195.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_4076SQ" id="BPMNEdge_8zpyew" sourceElement="BPMNShape_POp4IQ" targetElement="BPMNShape_VSjVPA">
<di:waypoint x="863.0" y="385.0"/>
<di:waypoint x="917.0" y="385.0"/>
<di:waypoint x="917.0" y="695.0"/>
<di:waypoint x="980.0" y="695.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_Jp2oQQ" id="BPMNEdge_HivQDQ" sourceElement="BPMNShape_rffh8A" targetElement="BPMNShape_bSO6tQ">
<di:waypoint x="650.0" y="195.0"/>
<di:waypoint x="897.0" y="195.0"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
<bpmndi:BPMNLabelStyle id="BPMNLabelStyle_1">
<dc:Font name="arial" size="9.0"/>
</bpmndi:BPMNLabelStyle>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

View file

@ -0,0 +1,144 @@
START
|
|- [Task: 2000] **New Contract Request**
Team: **Contract Management**
Description:
Ein neuer Vertragsanfrag wird eingereicht (z. B. durch Vertrieb oder Einkauf). Grundlegende Daten wie Vertragstyp (Kauf/Verkauf/Leasing) und Verantwortlicher müssen erfasst werden.
|-- [Event: 10] **Forward to Contract Creation** --> [Task: 2100] **Contract Creation**
|-- [Event: 20] **Reject Request** --> [Task: 2990] **Request Rejected**
|
|- [Task: 2100] **Contract Creation**
Team: **Contract Management**
Description:
Erstellung eines neuen Vertrags mit folgenden Pflichtfeldern:
- **Vertragspartner** (Name, Adresse, Kontaktdaten, Vertragsnummer)
- **Waren/Lieferungen** (Beschreibung, Menge, Einheit, Preis pro Einheit, Gesamtpreis, ggf. SKU/Artikelnummer)
- **Lagerort** (falls relevant: Lagerstandort, Lagerverantwortlicher)
- **Termine** (Liefertermin(e), Vertragslaufzeit, Fristen für Zahlungen/Meldungen)
Optional: **Sonderbedingungen** (z. B. Rabatte, Penalties, Zahlungsmodalitäten).
|-- [Event: 10] **Save Draft** --> [Task: 2100] **Contract Creation** *(Iteration für Korrekturen)*
|-- [Event: 20] **Submit for Review** --> [Task: 2200] **Legal Review**
|-- [Event: 30] **Cancel Request** --> [Task: 2990] **Request Rejected**
|
|- [Task: 2200] **Legal Review**
Team: **Legal/Compliance**
Description:
Prüfung auf rechtliche Korrektheit und Vollständigkeit:
- Vertragsklauseln (AGB, Gewährleistungen, Haftung)
- Compliance mit internen Richtlinien (z. B. Risikobewertung bei neuen Partnern)
- Terminpläne (z. B. Prüfung von Fristen)
|-- [Event: 10] **Request Changes** --> [Task: 2100] **Contract Creation** *(Rückgabe zur Korrektur)*
|-- [Event: 20] **Approve Contract** --> [Task: 2300] **Approval by Management**
|-- [Event: 30] **Reject Contract** --> [Task: 2990] **Contract Rejected**
|
|- [Task: 2300] **Approval by Management**
Team: **Senior Management/Finance**
Description:
Freigabe des Vertrags unter Berücksichtigung:
- **Finanzielle Auswirkungen** (Budget, Liquidität, Forecast)
- **Strategische Bedeutung** (Neukunde, Langfristpartner)
- **Risikoanalyse** (Bonität des Partners, Marktrisiken)
|-- [Event: 10] **Request Adjustments** --> [Task: 2100] **Contract Creation** *(z. B. Preisanpassung)*
|-- [Event: 20] **Final Approval** --> [Task: 2400] **Contract Execution**
|-- [Event: 30] **Decline Approval** --> [Task: 2990] **Contract Rejected**
|
|- [Task: 2400] **Contract Execution**
Team: **Contract Management / Operations**
Description:
**Finaler Schritt zur Vertragsaktivierung:**
- **Vertragsunterzeichnung** (digital/physisch) durch beide Parteien.
- **Datenaktualisierung im System**:
- **Vertragspartner** → CRM/ERP (z. B. SAP, Salesforce).
- **Waren/Lieferungen** → Lagerverwaltung/Logistik (z. B. Warehouse-Management-System).
- **Termine** → Kalender/Projektmanagement (z. B. Microsoft Project, Jira).
- **Finanzen** → Buchhaltung (Rechnungslauf, Zahlungspläne).
- **Lagerort** → Bei physischen Gütern: Einlagerung und Zuordnung (z. B. per Barcode).
|-- [Event: 10] **Contract Signed** --> [Task: 2500] **Post-Contract Setup**
|-- [Event: 20] **Execution Failed** --> [Task: 2990] **Contract Rejected** *(z. B. Unterzeichnung gescheitert)*
|
|- [Task: 2500] **Post-Contract Setup**
Team: **Cross-Functional (Logistik, Sales, Finance)**
Description:
**Nachbereitung nach Vertragsunterzeichnung:**
- **Logistik**:
- Lagerbestände anpassen (bei Lieferverträgen).
- Lieferpläne erstellen (Termine, Routen, Verantwortliche).
- **Vertrieb**:
- Kundenkommunikation (Bestätigungsmail, nächste Schritte).
- **Finanzen**:
- Zahlungsbedingungen konfigurieren (z. B. Skonto, Raten).
- Budgetreservierungen freigeben.
- **Monitoring**:
- **KPIs** festlegen (z. B. Liefertreue, Zahlungseingänge).
- **Audit-Trail** für Nachverfolgung.
|-- [Event: 10] **Setup Completed** --> [Task: 2600] **Contract Active**
|-- [Event: 20] **Correction Needed** --> [Task: 2400] **Contract Execution** *(z. B. Lagerfehler korrigieren)*
|
|- [Task: 2600] **Contract Active**
Team: **Contract Owner (z. B. Account Manager)**
Description:
**Laufender Vertrag:**
- **Regelmäßige Überprüfungen**:
- Terminpläne (Lieferungen, Zahlungen, Kündigungsfristen).
- Performance des Partners (z. B. Lieferzuverlässigkeit).
- **Änderungsmanagement**:
- Anpassungen (z. B. Mengenänderungen, Preisanpassungen) müssen neu freigegeben werden (→ Rückkehr zu [Task: 2100]).
|-- [Event: 10] **Renewal Due** --> [Task: 2700] **Contract Renewal**
|-- [Event: 20] **Termination Requested** --> [Task: 2900] **Contract Termination**
|-- [Event: 30] **Escalation** --> [Task: 2800] **Contract Dispute**
|
|- [Task: 2700] **Contract Renewal**
Team: **Contract Management / Sales**
Description:
**Vertragsverlängerung/Anpassung:**
- Analyse der Vertragsperformance (z. B. Umsatz, Partnerzufriedenheit).
- Angebot für Verlängerung oder neue Bedingungen erstellen.
- Prozess wie [Task: 2100] **Contract Creation** wiederholen.
|-- [Event: 10] **Renewal Approved** --> [Task: 2600] **Contract Active**
|-- [Event: 20] **Renewal Rejected** --> [Task: 2900] **Contract Termination**
|
|- [Task: 2800] **Contract Dispute**
Team: **Legal / Dispute Resolution**
Description:
**Konfliktmanagement:**
- Ursache analysieren (z. B. nicht erfüllte Liefertermine, Preisstreitigkeiten).
- Mediation oder rechtliche Schritte einleiten.
- Bei Einigung: Anpassung des Vertrags ([Task: 2100]).
- Bei Scheitern: [Task: 2900] **Contract Termination**.
|-- [Event: 10] **Dispute Resolved** --> [Task: 2600] **Contract Active**
|-- [Event: 20] **Termination Due to Dispute** --> [Task: 2900] **Contract Termination**
|
|- [Task: 2900] **Contract Termination**
Team: **Contract Management / Legal**
Description:
**Vertragsbeendigung:**
- Kündigungsfristen einhalten.
- **Liquidation**:
- Offene Rechnungen prüfen (Zahlungseingang/Stornierung).
- Lagerbestände bereinigen (Rücklieferung/Rücknahme).
- **Dokumentation**:
- Grund der Kündigung festhalten (für zukünftige Entscheidungen).
- Vertrag aus dem System löschen.
|-- [Event: 10] **Termination Completed** --> [Task: 2990] **Process Ended**
|
|- [Task: 2990] **Request/Contract Rejected**
Team: **Contract Management**
Description:
**Abgelehter Vertrag oder Anfrage:**
- Grund für die Ablehnung dokumentieren (z. B. "Partner nicht solvent").
- Feedback an Initiator geben.
|-- [Event: 10] **Close Case** --> END
|
|- END
Description: **Workflow abgeschlossen** (Vertrag aktiv, beendet oder abgelehnt).

View file

@ -0,0 +1,820 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- origin at X=0.0 Y=0.0 --><bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:BPMN2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:ext="http://org.eclipse.bpmn2/ext" xmlns:imixs="http://www.imixs.org/bpmn2" xmlns:open-bpmn="http://open-bpmn.org/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exporter="org.eclipse.bpmn2.modeler.core" exporterVersion="1.5.4.RC1-v20220528-0836-B1" id="Definitions_1" targetNamespace="http://www.imixs.org/bpmn2">
<bpmn2:extensionElements>
<imixs:item name="txtworkflowmodelversion" type="xs:string">
<imixs:value><![CDATA[offer-en-1.0]]></imixs:value>
</imixs:item>
<imixs:item name="txtfieldmapping" type="xs:string">
<imixs:value><![CDATA[Creator|$Creator]]></imixs:value>
<imixs:value><![CDATA[Current Editor|$Editor]]></imixs:value>
<imixs:value><![CDATA[Owner|$owner]]></imixs:value>
<imixs:value><![CDATA[Process Manager|process.manager]]></imixs:value>
<imixs:value><![CDATA[Process Team|process.team]]></imixs:value>
<imixs:value><![CDATA[Process Assist|process.assist]]></imixs:value>
<imixs:value><![CDATA[Department Manager|space.manager]]></imixs:value>
<imixs:value><![CDATA[Department Team|space.team]]></imixs:value>
<imixs:value><![CDATA[Department Assist|space.assist]]></imixs:value>
</imixs:item>
<imixs:item name="txttimefieldmapping" type="xs:string">
<imixs:value><![CDATA[Liefertermin|order.delivery]]></imixs:value>
</imixs:item>
<imixs:item name="txtplugins" type="xs:string">
<imixs:value><![CDATA[org.imixs.workflow.office.plugins.WorkitemLinkPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.ai.rag.RAGIndexPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.ResultPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.RulePlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.profile.ProfilePlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.plugins.CommentPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.plugins.SequenceNumberPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.team.TeamPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.profile.DeputyPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.OwnerPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.HistoryPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.LogPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.ApplicationPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.profile.MailPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.IntervalPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.SplitAndJoinPlugin]]></imixs:value>
<imixs:value><![CDATA[ai.dynamixs.cognition.CognitoPlugin]]></imixs:value>
</imixs:item>
<open-bpmn:auto-align>true</open-bpmn:auto-align>
</bpmn2:extensionElements>
<bpmn2:collaboration id="Collaboration_1" name="Collaboration 1">
<bpmn2:participant id="Participant_1" name="Example" processRef="Process_1">
<bpmn2:documentation id="documentation_3xKpCQ"/>
</bpmn2:participant>
<bpmn2:participant id="participant_hnZfjA" name="Default Process" processRef="process_2"/>
</bpmn2:collaboration>
<bpmn2:process definitionalCollaborationRef="Collaboration_1" id="Process_1" isExecutable="false" name="Example" processType="Private">
<bpmn2:laneSet id="LaneSet_1" name="Lane Set 1">
<bpmn2:lane id="Lane_1" name="Team">
<bpmn2:documentation id="documentation_gvQWYQ"/>
<bpmn2:flowNodeRef>Task_2</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>StartEvent_1</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>EndEvent_2</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_vIjHLQ</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_DG70UA" name="Sales Operations">
<bpmn2:flowNodeRef>task_X3JEMQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_DsQHAA</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_UdE1FQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_RDx0tQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_hNqu8Q</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_0Uti6Q</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_00ytag" name="Finance / Legal">
<bpmn2:flowNodeRef>task_0qFkuw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_LsGwGw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_VDjbDQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_YIeVQg</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_4fHTYA" name="Pre-Sales / Engineers">
<bpmn2:flowNodeRef>task_q3AJTA</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_w7iCNQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_tPPF0w</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_aGk1Mw" name="Purchasing / Procurement">
<bpmn2:flowNodeRef>task_U17j4w</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_79P3wA" name="Logistics / Technical Support">
<bpmn2:flowNodeRef>task_dkvx9A</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_u6xa6w</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_zdkmmA" name="Finance">
<bpmn2:flowNodeRef>task_T7gMeg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_rukJhQ</bpmn2:flowNodeRef>
</bpmn2:lane>
</bpmn2:laneSet>
<bpmn2:startEvent id="StartEvent_1" name="Start">
<bpmn2:documentation id="documentation_IUTaAQ"/>
<bpmn2:outgoing>sequenceFlow_8NDJxA</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:task id="Task_2" imixs:processid="1000" name="Import">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="Documentation_2"/>
<bpmn2:incoming>sequenceFlow_khuDtw</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_Gj9mmA</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:endEvent id="EndEvent_2" name="End">
<bpmn2:documentation id="documentation_mHDfBQ"/>
<bpmn2:incoming>sequenceFlow_Gj9mmA</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:sequenceFlow id="sequenceFlow_8NDJxA" sourceRef="StartEvent_1" targetRef="event_vIjHLQ">
<bpmn2:documentation id="documentation_RKidfg"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_Gj9mmA" sourceRef="Task_2" targetRef="EndEvent_2">
<bpmn2:documentation id="documentation_V7pFuw"/>
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_vIjHLQ" imixs:activityid="10" name="Event-1">
<bpmn2:documentation id="documentation_e2Geig"/>
<bpmn2:incoming>sequenceFlow_8NDJxA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_khuDtw</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_khuDtw" sourceRef="event_vIjHLQ" targetRef="Task_2">
<bpmn2:documentation id="documentation_d1EdlQ"/>
</bpmn2:sequenceFlow>
<bpmn2:task id="task_X3JEMQ" imixs:processid="2000" name="Order Received">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_sesL1g"><![CDATA[A new purchase order from a Reseller has been received via EDI, Email or Portal. Initial check for completeness of SKU and quantities.]]></bpmn2:documentation>
<bpmn2:outgoing>sf-1</bpmn2:outgoing>
<bpmn2:incoming>sf-3</bpmn2:incoming>
</bpmn2:task>
<bpmn2:task id="task_0qFkuw" imixs:processid="2100" name="Credit &amp; Compliance Check">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_HNaSKw"><![CDATA[Verification of the Reseller's credit limit and export control compliance (especially for US-based cybersecurity vendors).]]></bpmn2:documentation>
<bpmn2:incoming>sf-2</bpmn2:incoming>
<bpmn2:outgoing>sf-4</bpmn2:outgoing>
<bpmn2:incoming>sf-6</bpmn2:incoming>
<bpmn2:outgoing>sf-7</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:task id="task_q3AJTA" imixs:processid="2200" name="Technical Validation">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_eH1H6Q"><![CDATA[VAD Service: Review if the ordered configuration/solution is technically sound and compatible (e.g., bundles, maintenance periods).]]></bpmn2:documentation>
<bpmn2:incoming>sf-5</bpmn2:incoming>
<bpmn2:outgoing>sf-9</bpmn2:outgoing>
<bpmn2:incoming>sf-11</bpmn2:incoming>
</bpmn2:task>
<bpmn2:task id="task_U17j4w" imixs:processid="2300" name="Vendor Ordering">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_5oT1YQ"><![CDATA[Order is placed at the Vendor (e.g., Fortinet, Check Point). Waiting for Vendor confirmation and license/hardware allocation. |-- [Event: 10] Confirmed by Vendor --> [Task: 2400] Delivery & Provisioning |-- [Event: 20] Delay Notification --> [Task: 2300] Vendor Ordering]]></bpmn2:documentation>
<bpmn2:incoming>sf-10</bpmn2:incoming>
</bpmn2:task>
<bpmn2:task id="task_dkvx9A" imixs:processid="2400" name="Delivery &amp; Provisioning">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_aNWqug"><![CDATA[Physical shipment of hardware or digital provisioning of license keys/cloud access to the Reseller.]]></bpmn2:documentation>
<bpmn2:outgoing>sf-12</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:task id="task_T7gMeg" imixs:processid="2500" name="Invoicing">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_ggUUuQ"><![CDATA[Final invoice is generated and sent to the Reseller. Update of ERP system records. |-- [Event: 10] Invoice Sent --> [Task: 2800] Completed]]></bpmn2:documentation>
<bpmn2:incoming>sf-13</bpmn2:incoming>
<bpmn2:incoming>sf-14</bpmn2:incoming>
</bpmn2:task>
<bpmn2:task id="task_DsQHAA" imixs:processid="2800" name="Completed">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_2wE86A"><![CDATA[Order successfully fulfilled and invoiced. |-- [Event: 10] Archive Order --> [Task: 2800] Completed]]></bpmn2:documentation>
</bpmn2:task>
<bpmn2:task id="task_UdE1FQ" imixs:processid="2900" name="Cancelled">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_aXvupw"><![CDATA[The order was cancelled due to commercial, technical, or compliance reasons. |-- [Event: 10] Inform Vendor & Reseller --> [Task: 2800] Completed |-- [Event: 30] Delete Record --> [Task: 2990] Deleted END]]></bpmn2:documentation>
<bpmn2:incoming>sf-8</bpmn2:incoming>
</bpmn2:task>
<bpmn2:task id="task_RDx0tQ" imixs:processid="2990" name="Deleted">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_WSBv0w"/>
</bpmn2:task>
<bpmn2:intermediateCatchEvent id="event_hNqu8Q" imixs:activityid="10" name="Validated">
<bpmn2:documentation id="documentation_HpkRIg"/>
<bpmn2:incoming>sf-1</bpmn2:incoming>
<bpmn2:outgoing>sf-2</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_0Uti6Q" imixs:activityid="20" name="Data Missing">
<bpmn2:documentation id="documentation_jke3RA"/>
<bpmn2:outgoing>sf-3</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_LsGwGw" imixs:activityid="10" name="Approved">
<bpmn2:documentation id="documentation_1Z7lLQ"/>
<bpmn2:incoming>sf-4</bpmn2:incoming>
<bpmn2:outgoing>sf-5</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_VDjbDQ" imixs:activityid="20" name="Hold">
<bpmn2:documentation id="documentation_c39vVA"/>
<bpmn2:outgoing>sf-6</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_YIeVQg" imixs:activityid="30" name="Rejected">
<bpmn2:documentation id="documentation_ezlA2Q"/>
<bpmn2:incoming>sf-7</bpmn2:incoming>
<bpmn2:outgoing>sf-8</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_w7iCNQ" imixs:activityid="10" name="Technical Clear">
<bpmn2:documentation id="documentation_L830uw"/>
<bpmn2:incoming>sf-9</bpmn2:incoming>
<bpmn2:outgoing>sf-10</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_tPPF0w" imixs:activityid="20" name="Adjustment Needed">
<bpmn2:documentation id="documentation_yfTMmg"/>
<bpmn2:outgoing>sf-11</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_u6xa6w" imixs:activityid="10" name="Fulfilled">
<bpmn2:documentation id="documentation_ffDPSg"/>
<bpmn2:incoming>sf-12</bpmn2:incoming>
<bpmn2:outgoing>sf-13</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_rukJhQ" imixs:activityid="10" name="Dispute">
<bpmn2:documentation id="documentation_J0NUmg"/>
<bpmn2:outgoing>sf-14</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sf-1" sourceRef="task_X3JEMQ" targetRef="event_hNqu8Q"/>
<bpmn2:sequenceFlow id="sf-2" sourceRef="event_hNqu8Q" targetRef="task_0qFkuw"/>
<bpmn2:sequenceFlow id="sf-3" sourceRef="event_0Uti6Q" targetRef="task_X3JEMQ"/>
<bpmn2:sequenceFlow id="sf-4" sourceRef="task_0qFkuw" targetRef="event_LsGwGw"/>
<bpmn2:sequenceFlow id="sf-5" sourceRef="event_LsGwGw" targetRef="task_q3AJTA"/>
<bpmn2:sequenceFlow id="sf-6" sourceRef="event_VDjbDQ" targetRef="task_0qFkuw"/>
<bpmn2:sequenceFlow id="sf-7" sourceRef="task_0qFkuw" targetRef="event_YIeVQg"/>
<bpmn2:sequenceFlow id="sf-8" sourceRef="event_YIeVQg" targetRef="task_UdE1FQ"/>
<bpmn2:sequenceFlow id="sf-9" sourceRef="task_q3AJTA" targetRef="event_w7iCNQ"/>
<bpmn2:sequenceFlow id="sf-10" sourceRef="event_w7iCNQ" targetRef="task_U17j4w"/>
<bpmn2:sequenceFlow id="sf-11" sourceRef="event_tPPF0w" targetRef="task_q3AJTA"/>
<bpmn2:sequenceFlow id="sf-12" sourceRef="task_dkvx9A" targetRef="event_u6xa6w"/>
<bpmn2:sequenceFlow id="sf-13" sourceRef="event_u6xa6w" targetRef="task_T7gMeg"/>
<bpmn2:sequenceFlow id="sf-14" sourceRef="event_rukJhQ" targetRef="task_T7gMeg"/>
</bpmn2:process>
<bpmn2:process id="process_2" name="Default Process" processType="Public">
<bpmn2:documentation id="documentation_imRbaw"/>
<bpmn2:extensionElements>
<open-bpmn:auto-align>true</open-bpmn:auto-align>
</bpmn2:extensionElements>
</bpmn2:process>
<bpmn2:signal id="signal_3" name="org.imixs.ai.workflow.OpenAIAPIAdapter"/>
<bpmn2:signal id="signal_4" name="org.imixs.ai.rag.RAGRetrievalAdapter"/>
<bpmn2:message id="message_1" name="Message 1">
<bpmn2:documentation id="documentation_lq3hSg"/>
</bpmn2:message>
<bpmn2:signal id="signal_5" name="org.imixs.ai.workflow.ImixsAIAssistantAdapter"/>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane bpmnElement="Collaboration_1" id="BPMNPlane_Process_1">
<bpmndi:BPMNShape bpmnElement="Participant_1" id="BPMNShape_Participant_1" isHorizontal="true">
<dc:Bounds height="1610.0" width="4430.0" x="130.0" y="90.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Lane_1" id="BPMNShape_Lane_1" isHorizontal="true">
<dc:Bounds height="230.0" width="4400.0" x="160.0" y="90.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="StartEvent_1" id="BPMNShape_StartEvent_1">
<dc:Bounds height="36.0" width="36.0" x="237.0" y="137.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_1" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="20.0" width="100.0" x="209.5" y="174.10797119140625"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_TextAnnotation_1">
<dc:Bounds height="73.0" width="131.0" x="130.0" y="581.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_30">
<dc:Bounds height="67.0" width="119.0" x="136.0" y="581.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Task_2" id="BPMNShape_Task_5">
<dc:Bounds height="50.0" width="110.0" x="490.0" y="130.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="EndEvent_2" id="BPMNShape_EndEvent_2">
<dc:Bounds height="36.0" width="36.0" x="697.0" y="137.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_110" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="20.0" width="100.0" x="671.138671875" y="175.10791015625"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="participant_hnZfjA" id="BPMNShape_iHhp5Q">
<dc:Bounds height="210.0" width="800.0" x="0.0" y="0.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="message_1" id="BPMNShape_5X9D7w">
<dc:Bounds height="20.0" width="30.0" x="80.0" y="10.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_20MvBw">
<dc:Bounds height="20.0" width="100.0" x="45.86090087890625" y="37.66443634033203"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_vIjHLQ" id="BPMNShape_U2OU0Q">
<dc:Bounds height="36.0" width="36.0" x="367.0" y="137.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_vd0n1w">
<dc:Bounds height="20.0" width="100.0" x="335.0" y="176.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_8NDJxA" id="BPMNEdge_5jeXwQ" sourceElement="BPMNShape_StartEvent_1" targetElement="BPMNShape_U2OU0Q">
<di:waypoint x="273.0" y="155.0"/>
<di:waypoint x="367.0" y="155.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_Gj9mmA" id="BPMNEdge_D8ZZAw" sourceElement="BPMNShape_Task_5" targetElement="BPMNShape_EndEvent_2">
<di:waypoint x="600.0" y="155.0"/>
<di:waypoint x="697.0" y="155.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_khuDtw" id="BPMNEdge_vHtmSA" sourceElement="BPMNShape_U2OU0Q" targetElement="BPMNShape_Task_5">
<di:waypoint x="403.0" y="155.0"/>
<di:waypoint x="490.0" y="155.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="lane_DG70UA" id="BPMNShape_Lane_jFYG6Q">
<dc:Bounds height="230.0" width="4400.0" x="160.0" y="320.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="lane_00ytag" id="BPMNShape_Lane_xhK1gw">
<dc:Bounds height="230.0" width="4400.0" x="160.0" y="550.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="lane_4fHTYA" id="BPMNShape_Lane_6GK7cA">
<dc:Bounds height="230.0" width="4400.0" x="160.0" y="780.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="lane_aGk1Mw" id="BPMNShape_Lane_tjmgKA">
<dc:Bounds height="230.0" width="4400.0" x="160.0" y="1010.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="lane_79P3wA" id="BPMNShape_Lane_pPNT5g">
<dc:Bounds height="230.0" width="4400.0" x="160.0" y="1240.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="lane_zdkmmA" id="BPMNShape_Lane_FtseBQ">
<dc:Bounds height="230.0" width="4400.0" x="160.0" y="1470.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_X3JEMQ" id="BPMNShape_jq7RHA">
<dc:Bounds height="50.0" width="110.0" x="300.0" y="390.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_0qFkuw" id="BPMNShape_3K2f0Q">
<dc:Bounds height="50.0" width="110.0" x="610.0" y="620.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_q3AJTA" id="BPMNShape_sUEenw">
<dc:Bounds height="50.0" width="110.0" x="920.0" y="850.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_U17j4w" id="BPMNShape_W8fe4Q">
<dc:Bounds height="50.0" width="110.0" x="1230.0" y="1080.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_dkvx9A" id="BPMNShape_ubdkUw">
<dc:Bounds height="50.0" width="110.0" x="1540.0" y="1310.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_T7gMeg" id="BPMNShape_hIOUAw">
<dc:Bounds height="50.0" width="110.0" x="1850.0" y="1540.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_DsQHAA" id="BPMNShape_Vn2fuQ">
<dc:Bounds height="50.0" width="110.0" x="2160.0" y="390.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_UdE1FQ" id="BPMNShape_QQ4bfw">
<dc:Bounds height="50.0" width="110.0" x="2470.0" y="390.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_RDx0tQ" id="BPMNShape_3XWFIw">
<dc:Bounds height="50.0" width="110.0" x="2780.0" y="390.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_hNqu8Q" id="BPMNShape_KOADdw">
<dc:Bounds height="36.0" width="36.0" x="337.0" y="460.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_BF0Ebw">
<dc:Bounds x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_0Uti6Q" id="BPMNShape_DcRdSQ">
<dc:Bounds height="36.0" width="36.0" x="387.0" y="460.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_t2gQcA">
<dc:Bounds x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_LsGwGw" id="BPMNShape_UiA5Yg">
<dc:Bounds height="36.0" width="36.0" x="647.0" y="690.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_ryMLDA">
<dc:Bounds x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_VDjbDQ" id="BPMNShape_xBD1vQ">
<dc:Bounds height="36.0" width="36.0" x="697.0" y="690.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_BSXHzQ">
<dc:Bounds x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_YIeVQg" id="BPMNShape_BgjXgw">
<dc:Bounds height="36.0" width="36.0" x="747.0" y="690.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_v8qOow">
<dc:Bounds x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_w7iCNQ" id="BPMNShape_qw6I8A">
<dc:Bounds height="36.0" width="36.0" x="957.0" y="920.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_y0gzLg">
<dc:Bounds x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_tPPF0w" id="BPMNShape_e93ltA">
<dc:Bounds height="36.0" width="36.0" x="1007.0" y="920.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_7bv15g">
<dc:Bounds x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_u6xa6w" id="BPMNShape_Zgddmw">
<dc:Bounds height="36.0" width="36.0" x="1577.0" y="1380.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_jnAdow">
<dc:Bounds x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_rukJhQ" id="BPMNShape_GQobtA">
<dc:Bounds height="36.0" width="36.0" x="1887.0" y="1610.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_BqocNw">
<dc:Bounds x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sf-1" id="BPMNEdge_6SOP2w" sourceElement="BPMNShape_jq7RHA" targetElement="BPMNShape_KOADdw">
<di:waypoint x="355.0" y="415.0"/>
<di:waypoint x="355.0" y="478.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-2" id="BPMNEdge_LM1Ncg" sourceElement="BPMNShape_KOADdw" targetElement="BPMNShape_3K2f0Q">
<di:waypoint x="355.0" y="478.0"/>
<di:waypoint x="665.0" y="645.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-3" id="BPMNEdge_JI0a9g" sourceElement="BPMNShape_DcRdSQ" targetElement="BPMNShape_jq7RHA">
<di:waypoint x="405.0" y="478.0"/>
<di:waypoint x="355.0" y="415.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-4" id="BPMNEdge_qQOQfA" sourceElement="BPMNShape_3K2f0Q" targetElement="BPMNShape_UiA5Yg">
<di:waypoint x="665.0" y="645.0"/>
<di:waypoint x="665.0" y="708.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-5" id="BPMNEdge_L6cT5A" sourceElement="BPMNShape_UiA5Yg" targetElement="BPMNShape_sUEenw">
<di:waypoint x="665.0" y="708.0"/>
<di:waypoint x="975.0" y="875.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-6" id="BPMNEdge_pTz0gg" sourceElement="BPMNShape_xBD1vQ" targetElement="BPMNShape_3K2f0Q">
<di:waypoint x="715.0" y="708.0"/>
<di:waypoint x="665.0" y="645.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-7" id="BPMNEdge_fcnNzw" sourceElement="BPMNShape_3K2f0Q" targetElement="BPMNShape_BgjXgw">
<di:waypoint x="665.0" y="645.0"/>
<di:waypoint x="765.0" y="708.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-8" id="BPMNEdge_oL0lZw" sourceElement="BPMNShape_BgjXgw" targetElement="BPMNShape_QQ4bfw">
<di:waypoint x="765.0" y="708.0"/>
<di:waypoint x="2525.0" y="415.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-9" id="BPMNEdge_y0BJxQ" sourceElement="BPMNShape_sUEenw" targetElement="BPMNShape_qw6I8A">
<di:waypoint x="975.0" y="875.0"/>
<di:waypoint x="975.0" y="938.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-10" id="BPMNEdge_e6L0iA" sourceElement="BPMNShape_qw6I8A" targetElement="BPMNShape_W8fe4Q">
<di:waypoint x="975.0" y="938.0"/>
<di:waypoint x="1285.0" y="1105.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-11" id="BPMNEdge_s8Telw" sourceElement="BPMNShape_e93ltA" targetElement="BPMNShape_sUEenw">
<di:waypoint x="1025.0" y="938.0"/>
<di:waypoint x="975.0" y="875.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-12" id="BPMNEdge_7D51VA" sourceElement="BPMNShape_ubdkUw" targetElement="BPMNShape_Zgddmw">
<di:waypoint x="1595.0" y="1335.0"/>
<di:waypoint x="1595.0" y="1398.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-13" id="BPMNEdge_kX1vjg" sourceElement="BPMNShape_Zgddmw" targetElement="BPMNShape_hIOUAw">
<di:waypoint x="1595.0" y="1398.0"/>
<di:waypoint x="1905.0" y="1565.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sf-14" id="BPMNEdge_lDS21g" sourceElement="BPMNShape_GQobtA" targetElement="BPMNShape_hIOUAw">
<di:waypoint x="1905.0" y="1628.0"/>
<di:waypoint x="1905.0" y="1565.0"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
<bpmndi:BPMNLabelStyle id="BPMNLabelStyle_1">
<dc:Font name="arial" size="9.0"/>
</bpmndi:BPMNLabelStyle>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

View file

@ -0,0 +1,64 @@
Ordermanagement
START
|
|- [Task: 2000] Order Received
| Team: Sales Operations
| Description:
| A new purchase order from a Reseller has been received via EDI, Email or Portal. Initial check for completeness of SKU and quantities.
| |-- [Event: 10] Validated (Order complete) --> [Task: 2100] Credit & Compliance Check
| |-- [Event: 20] Data Missing (Contact Reseller) --> [Task: 2000] Order Received
| |-- [Event: 30] Cancel Order --> [Task: 2900] Cancelled
|
|- [Task: 2100] Credit & Compliance Check
| Team: Finance / Legal
| Description:
| Verification of the Reseller's credit limit and export control compliance (especially for US-based cybersecurity vendors).
| |-- [Event: 10] Approved (Credit and Compliance OK) --> [Task: 2200] Technical Validation
| |-- [Event: 20] Hold (Credit limit exceeded) --> [Task: 2100] Credit & Compliance Check
| |-- [Event: 30] Rejected (Compliance risk) --> [Task: 2900] Cancelled
|
|- [Task: 2200] Technical Validation
| Team: Pre-Sales / Engineers
| Description:
| VAD Service: Review if the ordered configuration/solution is technically sound and compatible (e.g., bundles, maintenance periods).
| |-- [Event: 10] Technical Clear (Configuration valid) --> [Task: 2300] Vendor Ordering
| |-- [Event: 20] Adjustment Needed (Consult with Reseller) --> [Task: 2200] Technical Validation
| |-- [Event: 30] Reject Design --> [Task: 2900] Cancelled
|
|- [Task: 2300] Vendor Ordering
| Team: Purchasing / Procurement
| Description:
| Order is placed at the Vendor (e.g., Fortinet, Check Point). Waiting for Vendor confirmation and license/hardware allocation.
| |-- [Event: 10] Confirmed by Vendor --> [Task: 2400] Delivery & Provisioning
| |-- [Event: 20] Delay Notification --> [Task: 2300] Vendor Ordering
|
|- [Task: 2400] Delivery & Provisioning
| Team: Logistics / Technical Support
| Description:
| Physical shipment of hardware or digital provisioning of license keys/cloud access to the Reseller.
| |-- [Event: 10] Fulfilled (Delivery/Provisioning completed) --> [Task: 2500] Invoicing
| |-- [Event: 11] Partial Delivery --> [Task: 2400] Delivery & Provisioning
|
|- [Task: 2500] Invoicing
| Team: Finance
| Description:
| Final invoice is generated and sent to the Reseller. Update of ERP system records.
| |-- [Event: 10] Invoice Sent --> [Task: 2800] Completed
| |-- [Event: 20] Dispute (Correction required) --> [Task: 2500] Invoicing
|
|- [Task: 2800] Completed
| Team: Sales Operations
| Description:
| Order successfully fulfilled and invoiced.
| |-- [Event: 10] Archive Order --> [Task: 2800] Completed
|
|- [Task: 2900] Cancelled
| Team: Sales Operations
| Description:
| The order was cancelled due to commercial, technical, or compliance reasons.
| |-- [Event: 10] Inform Vendor & Reseller --> [Task: 2800] Completed
| |-- [Event: 30] Delete Record --> [Task: 2990] Deleted
|
END

View file

@ -0,0 +1,78 @@
Business Process: Risk Management
START
|
|- [Task: 1000] Risk Identification
| Team: Risk Owner (Operational Unit)
| Description:
| A potential risk has been identified within an operational unit. The Risk Owner captures basic data (Category, Description, Early Warning Indicators) to initiate the process in accordance with KonTraG.
| |-- [Event: 10] Submit Proposal (Forward to Central Risk Management) --> [Task: 1100] Validation
| |-- [Event: 20] Discard (Draft deleted) --> [Task: 1990] Deleted
|
|- [Task: 1100] Validation
| Team: Central Risk Management
| Description:
| Central function checks if the identified issued qualifies as a relevant risk or if it is a duplicate.
| |-- [Event: 10] Confirm Risk (Risk is valid, proceed to assessment) --> [Task: 1200] Gross Assessment
| |-- [Event: 20] Reject (Not a risk or duplicate) --> [Task: 1900] Archived
| |-- [Event: 30] Request Info (Send back to Owner for details) --> [Task: 1000] Risk Identification
|
|- [Task: 1200] Gross Assessment
| Team: Risk Owner (Operational Unit)
| Description:
| Quantitative assessment of the risk WITHOUT considering planned or existing measures. Impact and Probability are estimated to determine the Gross Risk Score.
| |-- [Event: 10] Save Gross Data (Proceed to Measure Definition) --> [Task: 1300] Measure Definition
|
|- [Task: 1300] Measure Definition
| Team: Risk Owner (Operational Unit)
| Description:
| Definition of risk mitigating measures (Avoid, Reduce, Transfer, Accept). Documentation of costs and responsibilities for these measures.
| |-- [Event: 10] Measures Defined (Proceed to Net Assessment) --> [Task: 1400] Net Assessment
| |-- [Event: 20] Update Assessment (Go back to Gross Assessment) --> [Task: 1200] Gross Assessment
|
|- [Task: 1400] Net Assessment
| Team: Risk Owner (Operational Unit)
| Description:
| Re-evaluation of Impact and Probability taking the defined measures into account (Residual Risk). Crucial for IDW PS 340 compliance.
| |-- [Event: 10] Submit for Aggregation (Forward to Central RM) --> [Task: 1500] Aggregation & Analysis
|
|- [Task: 1500] Aggregation & Analysis
| Team: Central Risk Management
| Description:
| The risk is analyzed in the context of the total risk portfolio (Risk Aggregation/Monte Carlo Simulation) to check against the company's Risk Bearing Capacity.
| |-- [Event: 10] Approve (Risk within appetite, standard monitoring) --> [Task: 1600] Monitoring
| |-- [Event: 20] Insufficient Mitigation (Measures not enough, send back) --> [Task: 1300] Measure Definition
| |-- [Event: 30] Critical Escalation (Threat to existence, forward to Board) --> [Task: 1550] Board Review
|
|- [Task: 1550] Board Review
| Team: Management Board / Risk Committee
| Description:
| High-level decision required. Risk exceeds risk bearing capacity or is a "bestandsgefährdendes Risiko" (§91 Abs. 2 AktG).
| |-- [Event: 10] Accept Risk (Special approval granted) --> [Task: 1600] Monitoring
| |-- [Event: 20] Demand Action (Force new measures) --> [Task: 1300] Measure Definition
|
|- [Task: 1600] Monitoring
| Team: Risk Owner (Operational Unit)
| Description:
| Continuous surveillance of the risk and the effectiveness of measures. Periodic review (e.g., quarterly).
| |-- [Event: 10] Report: No Change (Keep monitoring) --> [Task: 1600] Monitoring
| |-- [Event: 20] Risk Changed (Values or measures changed) --> [Task: 1200] Gross Assessment
| |-- [Event: 30] Risk Obsolete (Risk no longer exists) --> [Task: 1800] Closure Review
|
|- [Task: 1800] Closure Review
| Team: Central Risk Management
| Description:
| Final check if the risk can really be closed.
| |-- [Event: 10] Close Risk (Archive) --> [Task: 1900] Archived
| |-- [Event: 20] Deny Closure (Keep active) --> [Task: 1600] Monitoring
|
|- [Task: 1900] Archived
| Team: System
| Description:
| Risk is closed but kept for audit trails and historical data analysis.
| |-- [Event: 10] Reactivate --> [Task: 1100] Validation
|
END
|
|- [Task: 1990] Deleted
|

View file

@ -0,0 +1,319 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- origin at X=0.0 Y=0.0 --><bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:BPMN2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:ext="http://org.eclipse.bpmn2/ext" xmlns:imixs="http://www.imixs.org/bpmn2" xmlns:open-bpmn="http://open-bpmn.org/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exporter="org.eclipse.bpmn2.modeler.core" exporterVersion="1.5.4.RC1-v20220528-0836-B1" id="Definitions_1" targetNamespace="http://www.imixs.org/bpmn2">
<bpmn2:extensionElements>
<imixs:item name="txtworkflowmodelversion" type="xs:string">
<imixs:value><![CDATA[offer-en-1.0]]></imixs:value>
</imixs:item>
<imixs:item name="txtfieldmapping" type="xs:string">
<imixs:value><![CDATA[Creator|$Creator]]></imixs:value>
<imixs:value><![CDATA[Current Editor|$Editor]]></imixs:value>
<imixs:value><![CDATA[Owner|$owner]]></imixs:value>
<imixs:value><![CDATA[Process Manager|process.manager]]></imixs:value>
<imixs:value><![CDATA[Process Team|process.team]]></imixs:value>
<imixs:value><![CDATA[Process Assist|process.assist]]></imixs:value>
<imixs:value><![CDATA[Department Manager|space.manager]]></imixs:value>
<imixs:value><![CDATA[Department Team|space.team]]></imixs:value>
<imixs:value><![CDATA[Department Assist|space.assist]]></imixs:value>
</imixs:item>
<imixs:item name="txttimefieldmapping" type="xs:string">
<imixs:value><![CDATA[Liefertermin|order.delivery]]></imixs:value>
</imixs:item>
<imixs:item name="txtplugins" type="xs:string">
<imixs:value><![CDATA[org.imixs.workflow.office.plugins.WorkitemLinkPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.ai.rag.RAGIndexPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.ResultPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.RulePlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.profile.ProfilePlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.plugins.CommentPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.plugins.SequenceNumberPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.team.TeamPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.profile.DeputyPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.OwnerPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.HistoryPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.LogPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.ApplicationPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.profile.MailPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.IntervalPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.SplitAndJoinPlugin]]></imixs:value>
<imixs:value><![CDATA[ai.dynamixs.cognition.CognitoPlugin]]></imixs:value>
</imixs:item>
<open-bpmn:auto-align>true</open-bpmn:auto-align>
</bpmn2:extensionElements>
<bpmn2:collaboration id="Collaboration_1" name="Collaboration 1">
<bpmn2:participant id="Participant_1" name="Example" processRef="Process_1">
<bpmn2:documentation id="documentation_3xKpCQ"/>
</bpmn2:participant>
<bpmn2:participant id="participant_hnZfjA" name="Default Process" processRef="process_2"/>
</bpmn2:collaboration>
<bpmn2:process definitionalCollaborationRef="Collaboration_1" id="Process_1" isExecutable="false" name="Example" processType="Private">
<bpmn2:laneSet id="LaneSet_1" name="Lane Set 1">
<bpmn2:lane id="Lane_1" name="Team">
<bpmn2:documentation id="documentation_gvQWYQ"/>
<bpmn2:flowNodeRef>Task_2</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>StartEvent_1</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>EndEvent_2</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_vIjHLQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_HQd8AQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_6HJvNQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_HQ9VcQ</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_EQOgOg" name="Accounting"/>
<bpmn2:lane id="lane_2tdU0Q" name="Sales Team"/>
</bpmn2:laneSet>
<bpmn2:startEvent id="StartEvent_1" name="Start">
<bpmn2:documentation id="documentation_IUTaAQ"/>
<bpmn2:outgoing>sequenceFlow_8NDJxA</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:task id="Task_2" imixs:processid="1000" name="Import">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="Documentation_2"/>
<bpmn2:incoming>sequenceFlow_khuDtw</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_Gj9mmA</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:endEvent id="EndEvent_2" name="End">
<bpmn2:documentation id="documentation_mHDfBQ"/>
<bpmn2:incoming>sequenceFlow_Gj9mmA</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:sequenceFlow id="sequenceFlow_8NDJxA" sourceRef="StartEvent_1" targetRef="event_vIjHLQ">
<bpmn2:documentation id="documentation_RKidfg"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_Gj9mmA" sourceRef="Task_2" targetRef="EndEvent_2">
<bpmn2:documentation id="documentation_V7pFuw"/>
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_vIjHLQ" imixs:activityid="10" name="Event-1">
<bpmn2:documentation id="documentation_e2Geig"/>
<bpmn2:incoming>sequenceFlow_8NDJxA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_khuDtw</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_khuDtw" sourceRef="event_vIjHLQ" targetRef="Task_2">
<bpmn2:documentation id="documentation_d1EdlQ"/>
</bpmn2:sequenceFlow>
<bpmn2:task id="task_HQd8AQ" imixs:processid="1000" name="Task-2">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_z6PPww"/>
<bpmn2:outgoing>sequence-flow-1</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:intermediateCatchEvent id="event_6HJvNQ" imixs:activityid="10" name="Event-1">
<bpmn2:documentation id="documentation_PoRwdg"/>
<bpmn2:incoming>sequence-flow-1</bpmn2:incoming>
<bpmn2:outgoing>sequence-flow-2</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:task id="task_HQ9VcQ" imixs:processid="1100" name="Import">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_CdXjvg"/>
<bpmn2:incoming>sequence-flow-2</bpmn2:incoming>
</bpmn2:task>
<bpmn2:sequenceFlow id="sequence-flow-1" sourceRef="task_HQd8AQ" targetRef="event_6HJvNQ"/>
<bpmn2:sequenceFlow id="sequence-flow-2" sourceRef="event_6HJvNQ" targetRef="task_HQ9VcQ"/>
</bpmn2:process>
<bpmn2:process id="process_2" name="Default Process" processType="Public">
<bpmn2:documentation id="documentation_imRbaw"/>
<bpmn2:extensionElements>
<open-bpmn:auto-align>true</open-bpmn:auto-align>
</bpmn2:extensionElements>
</bpmn2:process>
<bpmn2:signal id="signal_3" name="org.imixs.ai.workflow.OpenAIAPIAdapter"/>
<bpmn2:signal id="signal_4" name="org.imixs.ai.rag.RAGRetrievalAdapter"/>
<bpmn2:message id="message_1" name="Message 1">
<bpmn2:documentation id="documentation_lq3hSg"/>
</bpmn2:message>
<bpmn2:signal id="signal_5" name="org.imixs.ai.workflow.ImixsAIAssistantAdapter"/>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane bpmnElement="Collaboration_1" id="BPMNPlane_Process_1">
<bpmndi:BPMNShape bpmnElement="Participant_1" id="BPMNShape_Participant_1" isHorizontal="true">
<dc:Bounds height="690.0" width="4430.0" x="130.0" y="90.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Lane_1" id="BPMNShape_Lane_1" isHorizontal="true">
<dc:Bounds height="230.0" width="4400.0" x="160.0" y="90.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="StartEvent_1" id="BPMNShape_StartEvent_1">
<dc:Bounds height="36.0" width="36.0" x="237.0" y="137.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_1" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="20.0" width="100.0" x="209.5" y="174.10797119140625"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_TextAnnotation_1">
<dc:Bounds height="73.0" width="131.0" x="130.0" y="581.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_30">
<dc:Bounds height="67.0" width="119.0" x="136.0" y="581.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Task_2" id="BPMNShape_Task_5">
<dc:Bounds height="50.0" width="110.0" x="490.0" y="130.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="EndEvent_2" id="BPMNShape_EndEvent_2">
<dc:Bounds height="36.0" width="36.0" x="697.0" y="137.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_110" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="20.0" width="100.0" x="671.138671875" y="175.10791015625"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="participant_hnZfjA" id="BPMNShape_iHhp5Q">
<dc:Bounds height="210.0" width="800.0" x="0.0" y="0.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="message_1" id="BPMNShape_5X9D7w">
<dc:Bounds height="20.0" width="30.0" x="80.0" y="10.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_20MvBw">
<dc:Bounds height="20.0" width="100.0" x="45.86090087890625" y="37.66443634033203"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_vIjHLQ" id="BPMNShape_U2OU0Q">
<dc:Bounds height="36.0" width="36.0" x="367.0" y="137.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_vd0n1w">
<dc:Bounds height="20.0" width="100.0" x="335.0" y="176.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_8NDJxA" id="BPMNEdge_5jeXwQ" sourceElement="BPMNShape_StartEvent_1" targetElement="BPMNShape_U2OU0Q">
<di:waypoint x="273.0" y="155.0"/>
<di:waypoint x="367.0" y="155.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_Gj9mmA" id="BPMNEdge_D8ZZAw" sourceElement="BPMNShape_Task_5" targetElement="BPMNShape_EndEvent_2">
<di:waypoint x="600.0" y="155.0"/>
<di:waypoint x="697.0" y="155.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_khuDtw" id="BPMNEdge_vHtmSA" sourceElement="BPMNShape_U2OU0Q" targetElement="BPMNShape_Task_5">
<di:waypoint x="403.0" y="155.0"/>
<di:waypoint x="490.0" y="155.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="lane_EQOgOg" id="BPMNShape_Lane_vbFCIg">
<dc:Bounds height="230.0" width="4400.0" x="160.0" y="320.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="lane_2tdU0Q" id="BPMNShape_Lane_AJQqiw">
<dc:Bounds height="230.0" width="4400.0" x="160.0" y="550.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_HQd8AQ" id="BPMNShape_SWNkXw">
<dc:Bounds height="50.0" width="110.0" x="150.0" y="200.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_6HJvNQ" id="BPMNShape_GCOCOA">
<dc:Bounds height="36.0" width="36.0" x="350.0" y="200.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_K3GzxA">
<dc:Bounds x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_HQ9VcQ" id="BPMNShape_0vb1vw">
<dc:Bounds height="50.0" width="110.0" x="450.0" y="200.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequence-flow-1" id="BPMNEdge_nhNbcg" sourceElement="BPMNShape_SWNkXw" targetElement="BPMNShape_GCOCOA">
<di:waypoint x="205.0" y="225.0"/>
<di:waypoint x="368.0" y="218.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequence-flow-2" id="BPMNEdge_NLlZ5g" sourceElement="BPMNShape_GCOCOA" targetElement="BPMNShape_0vb1vw">
<di:waypoint x="368.0" y="218.0"/>
<di:waypoint x="505.0" y="225.0"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
<bpmndi:BPMNLabelStyle id="BPMNLabelStyle_1">
<dc:Font name="arial" size="9.0"/>
</bpmndi:BPMNLabelStyle>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

View file

@ -0,0 +1,77 @@
Business Process: Risk Management Cycle (IDW PS 340)
START
|
|- [Task: 1000] Risk Identification
| Team: Risk Owner (Operational Unit)
| Description:
| A potential risk has been identified within an operational unit. The Risk Owner captures basic data (Category, Description, Early Warning Indicators) to initiate the process in accordance with KonTraG.
| |-- [Event: 10] Submit Proposal (Forward to Central Risk Management) --> [Task: 1100] Validation
| |-- [Event: 20] Discard (Draft deleted) --> [Task: 1990] Deleted
|
|- [Task: 1100] Validation
| Team: Central Risk Management
| Description:
| Central function checks if the identified issue qualifies as a relevant risk or if it is a duplicate.
| |-- [Event: 10] Confirm Risk (Risk is valid, proceed to assessment) --> [Task: 1200] Gross Assessment
| |-- [Event: 20] Reject (Not a risk or duplicate) --> [Task: 1900] Archived
| |-- [Event: 30] Request Info (Send back to Owner for details) --> [Task: 1000] Risk Identification
|
|- [Task: 1200] Gross Assessment
| Team: Risk Owner (Operational Unit)
| Description:
| Quantitative assessment of the risk WITHOUT considering planned or existing measures. Impact and Probability are estimated to determine the Gross Risk Score.
| |-- [Event: 10] Save Gross Data (Proceed to Measure Definition) --> [Task: 1300] Measure Definition
|
|- [Task: 1300] Measure Definition
| Team: Risk Owner (Operational Unit)
| Description:
| Definition of risk mitigating measures (Avoid, Reduce, Transfer, Accept). Documentation of costs and responsibilities for these measures.
| |-- [Event: 10] Measures Defined (Proceed to Net Assessment) --> [Task: 1400] Net Assessment
| |-- [Event: 20] Update Assessment (Go back to Gross Assessment) --> [Task: 1200] Gross Assessment
|
|- [Task: 1400] Net Assessment
| Team: Risk Owner (Operational Unit)
| Description:
| Re-evaluation of Impact and Probability taking the defined measures into account (Residual Risk). Crucial for IDW PS 340 compliance.
| |-- [Event: 10] Submit for Aggregation (Forward to Central RM) --> [Task: 1500] Aggregation & Analysis
|
|- [Task: 1500] Aggregation & Analysis
| Team: Central Risk Management
| Description:
| The risk is analyzed in the context of the total risk portfolio (Risk Aggregation/Monte Carlo Simulation) to check against the company's Risk Bearing Capacity.
| |-- [Event: 10] Approve (Risk within appetite, standard monitoring) --> [Task: 1600] Monitoring
| |-- [Event: 20] Insufficient Mitigation (Measures not enough, send back) --> [Task: 1300] Measure Definition
| |-- [Event: 30] Critical Escalation (Threat to existence, forward to Board) --> [Task: 1550] Board Review
|
|- [Task: 1550] Board Review
| Team: Management Board / Risk Committee
| Description:
| High-level decision required. Risk exceeds risk bearing capacity or is a "bestandsgefährdendes Risiko" (§91 Abs. 2 AktG).
| |-- [Event: 10] Accept Risk (Special approval granted) --> [Task: 1600] Monitoring
| |-- [Event: 20] Demand Action (Force new measures) --> [Task: 1300] Measure Definition
|
|- [Task: 1600] Monitoring
| Team: Risk Owner (Operational Unit)
| Description:
| Continuous surveillance of the risk and the effectiveness of measures. Periodic review (e.g., quarterly).
| |-- [Event: 10] Report: No Change (Keep monitoring) --> [Task: 1600] Monitoring
| |-- [Event: 20] Risk Changed (Values or measures changed) --> [Task: 1200] Gross Assessment
| |-- [Event: 30] Risk Obsolete (Risk no longer exists) --> [Task: 1800] Closure Review
|
|- [Task: 1800] Closure Review
| Team: Central Risk Management
| Description:
| Final check if the risk can really be closed.
| |-- [Event: 10] Close Risk (Archive) --> [Task: 1900] Archived
| |-- [Event: 20] Deny Closure (Keep active) --> [Task: 1600] Monitoring
|
|- [Task: 1900] Archived
| Team: System
| Description:
| Risk is closed but kept for audit trails and historical data analysis.
| |-- [Event: 10] Reactivate --> [Task: 1100] Validation
|
END
|
|- [Task: 1990] Deleted

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,197 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- origin at X=0.0 Y=0.0 --><bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:BPMN2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:ext="http://org.eclipse.bpmn2/ext" xmlns:imixs="http://www.imixs.org/bpmn2" xmlns:open-bpmn="http://open-bpmn.org/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exporter="org.eclipse.bpmn2.modeler.core" exporterVersion="1.5.4.RC1-v20220528-0836-B1" id="Definitions_1" targetNamespace="http://www.imixs.org/bpmn2">
<bpmn2:extensionElements>
<imixs:item name="txtworkflowmodelversion" type="xs:string">
<imixs:value><![CDATA[offer-en-1.0]]></imixs:value>
</imixs:item>
<imixs:item name="txtfieldmapping" type="xs:string">
<imixs:value><![CDATA[Creator|$Creator]]></imixs:value>
<imixs:value><![CDATA[Current Editor|$Editor]]></imixs:value>
<imixs:value><![CDATA[Owner|$owner]]></imixs:value>
<imixs:value><![CDATA[Process Manager|process.manager]]></imixs:value>
<imixs:value><![CDATA[Process Team|process.team]]></imixs:value>
<imixs:value><![CDATA[Process Assist|process.assist]]></imixs:value>
<imixs:value><![CDATA[Department Manager|space.manager]]></imixs:value>
<imixs:value><![CDATA[Department Team|space.team]]></imixs:value>
<imixs:value><![CDATA[Department Assist|space.assist]]></imixs:value>
</imixs:item>
<imixs:item name="txttimefieldmapping" type="xs:string">
<imixs:value><![CDATA[Liefertermin|order.delivery]]></imixs:value>
</imixs:item>
<imixs:item name="txtplugins" type="xs:string">
<imixs:value><![CDATA[org.imixs.workflow.office.plugins.WorkitemLinkPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.ai.rag.RAGIndexPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.ResultPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.RulePlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.profile.ProfilePlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.plugins.CommentPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.plugins.SequenceNumberPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.team.TeamPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.profile.DeputyPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.OwnerPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.HistoryPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.LogPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.ApplicationPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.marty.profile.MailPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.IntervalPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.SplitAndJoinPlugin]]></imixs:value>
<imixs:value><![CDATA[ai.dynamixs.cognition.CognitoPlugin]]></imixs:value>
</imixs:item>
<open-bpmn:auto-align>true</open-bpmn:auto-align>
</bpmn2:extensionElements>
<bpmn2:collaboration id="Collaboration_1" name="Collaboration 1">
<bpmn2:participant id="Participant_1" name="Example" processRef="Process_1">
<bpmn2:documentation id="documentation_3xKpCQ"/>
</bpmn2:participant>
<bpmn2:participant id="participant_hnZfjA" name="Default Process" processRef="process_2"/>
</bpmn2:collaboration>
<bpmn2:process definitionalCollaborationRef="Collaboration_1" id="Process_1" isExecutable="false" name="Example" processType="Private">
<bpmn2:laneSet id="LaneSet_1" name="Lane Set 1">
<bpmn2:lane id="Lane_1" name="Team">
<bpmn2:documentation id="documentation_gvQWYQ"/>
<bpmn2:flowNodeRef>Task_2</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>StartEvent_1</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>EndEvent_2</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_vIjHLQ</bpmn2:flowNodeRef>
</bpmn2:lane>
</bpmn2:laneSet>
<bpmn2:startEvent id="StartEvent_1" name="Start">
<bpmn2:documentation id="documentation_IUTaAQ"/>
<bpmn2:outgoing>sequenceFlow_8NDJxA</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:task id="Task_2" imixs:processid="1000" name="Import">
<bpmn2:extensionElements>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[form_basic]]></imixs:value>
</imixs:item>
<imixs:item name="txtname" type="xs:string">
<imixs:value><![CDATA[Rechnung erhalten]]></imixs:value>
</imixs:item>
<imixs:item name="txtimageurl" type="xs:string">
<imixs:value><![CDATA[typcn-business-card]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>request.subject</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:string">
<imixs:value><![CDATA[true]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitem]]></imixs:value>
</imixs:item>
<imixs:item name="namownershipnames" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddreadaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="namaddwriteaccess" type="xs:string">
<imixs:value/>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string">
<imixs:value><![CDATA[$Editor]]></imixs:value>
<imixs:value><![CDATA[process.assist]]></imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string">
<imixs:value><![CDATA[process.assist]]></imixs:value>
<imixs:value><![CDATA[process.team]]></imixs:value>
<imixs:value><![CDATA[process.manager]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="Documentation_2"/>
<bpmn2:incoming>sequenceFlow_khuDtw</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_Gj9mmA</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:endEvent id="EndEvent_2" name="End">
<bpmn2:documentation id="documentation_mHDfBQ"/>
<bpmn2:incoming>sequenceFlow_Gj9mmA</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:sequenceFlow id="sequenceFlow_8NDJxA" sourceRef="StartEvent_1" targetRef="event_vIjHLQ">
<bpmn2:documentation id="documentation_RKidfg"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_Gj9mmA" sourceRef="Task_2" targetRef="EndEvent_2">
<bpmn2:documentation id="documentation_V7pFuw"/>
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_vIjHLQ" imixs:activityid="10" name="Event-1">
<bpmn2:documentation id="documentation_e2Geig"/>
<bpmn2:incoming>sequenceFlow_8NDJxA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_khuDtw</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_khuDtw" sourceRef="event_vIjHLQ" targetRef="Task_2">
<bpmn2:documentation id="documentation_d1EdlQ"/>
</bpmn2:sequenceFlow>
</bpmn2:process>
<bpmn2:process id="process_2" name="Default Process" processType="Public">
<bpmn2:documentation id="documentation_imRbaw"/>
<bpmn2:extensionElements>
<open-bpmn:auto-align>true</open-bpmn:auto-align>
</bpmn2:extensionElements>
</bpmn2:process>
<bpmn2:signal id="signal_3" name="org.imixs.ai.workflow.OpenAIAPIAdapter"/>
<bpmn2:signal id="signal_4" name="org.imixs.ai.rag.RAGRetrievalAdapter"/>
<bpmn2:message id="message_1" name="Message 1">
<bpmn2:documentation id="documentation_lq3hSg"/>
</bpmn2:message>
<bpmn2:signal id="signal_5" name="org.imixs.ai.workflow.ImixsAIAssistantAdapter"/>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane bpmnElement="Collaboration_1" id="BPMNPlane_Process_1">
<bpmndi:BPMNShape bpmnElement="Participant_1" id="BPMNShape_Participant_1" isHorizontal="true">
<dc:Bounds height="230.0" width="4430.0" x="130.0" y="90.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Lane_1" id="BPMNShape_Lane_1" isHorizontal="true">
<dc:Bounds height="230.0" width="4400.0" x="160.0" y="90.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="StartEvent_1" id="BPMNShape_StartEvent_1">
<dc:Bounds height="36.0" width="36.0" x="237.0" y="137.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_1" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="20.0" width="100.0" x="209.5" y="174.10797119140625"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_TextAnnotation_1">
<dc:Bounds height="73.0" width="131.0" x="130.0" y="581.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_30">
<dc:Bounds height="67.0" width="119.0" x="136.0" y="581.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Task_2" id="BPMNShape_Task_5">
<dc:Bounds height="50.0" width="110.0" x="490.0" y="130.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="EndEvent_2" id="BPMNShape_EndEvent_2">
<dc:Bounds height="36.0" width="36.0" x="697.0" y="137.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_110" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="20.0" width="100.0" x="671.138671875" y="175.10791015625"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="participant_hnZfjA" id="BPMNShape_iHhp5Q">
<dc:Bounds height="210.0" width="800.0" x="0.0" y="0.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="message_1" id="BPMNShape_5X9D7w">
<dc:Bounds height="20.0" width="30.0" x="80.0" y="10.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_20MvBw">
<dc:Bounds height="20.0" width="100.0" x="45.86090087890625" y="37.66443634033203"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_vIjHLQ" id="BPMNShape_U2OU0Q">
<dc:Bounds height="36.0" width="36.0" x="367.0" y="137.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_vd0n1w">
<dc:Bounds height="20.0" width="100.0" x="335.0" y="176.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_8NDJxA" id="BPMNEdge_5jeXwQ" sourceElement="BPMNShape_StartEvent_1" targetElement="BPMNShape_U2OU0Q">
<di:waypoint x="273.0" y="155.0"/>
<di:waypoint x="367.0" y="155.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_Gj9mmA" id="BPMNEdge_D8ZZAw" sourceElement="BPMNShape_Task_5" targetElement="BPMNShape_EndEvent_2">
<di:waypoint x="600.0" y="155.0"/>
<di:waypoint x="697.0" y="155.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_khuDtw" id="BPMNEdge_vHtmSA" sourceElement="BPMNShape_U2OU0Q" targetElement="BPMNShape_Task_5">
<di:waypoint x="403.0" y="155.0"/>
<di:waypoint x="490.0" y="155.0"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
<bpmndi:BPMNLabelStyle id="BPMNLabelStyle_1">
<dc:Font name="arial" size="9.0"/>
</bpmndi:BPMNLabelStyle>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

View file

@ -0,0 +1,146 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:BPMN2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:imixs="http://www.imixs.org/bpmn2" xmlns:open-bpmn="http://open-bpmn.org/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exporter="org.openbpmn" exporterVersion="1.0.0" targetNamespace="http://open-bpmn.org">
<bpmn2:extensionElements>
<imixs:item name="txtworkflowmodelversion" type="xs:string">
<imixs:value><![CDATA[default-en-1.0]]></imixs:value>
</imixs:item>
<imixs:item name="txtplugins" type="xs:string">
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.RulePlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.SplitAndJoinPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.OwnerPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.ApproverPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.HistoryPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.ApplicationPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.IntervalPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.MailPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.ResultPlugin]]></imixs:value>
</imixs:item>
<imixs:item name="txtfieldmapping" type="xs:string">
<imixs:value><![CDATA[Creator|$creator]]></imixs:value>
<imixs:value><![CDATA[Owner|$owner]]></imixs:value>
<imixs:value><![CDATA[Editor|$editor]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:process id="process_1" name="Default Process" processType="Public">
<bpmn2:documentation id="documentation_dIsJlQ"/>
<bpmn2:extensionElements>
<open-bpmn:auto-align>true</open-bpmn:auto-align>
</bpmn2:extensionElements>
<bpmn2:task id="task_DzBmHg" imixs:processid="100" name="Approve">
<bpmn2:documentation id="documentation_Dz7pPQ"/>
<bpmn2:incoming>sequenceFlow_3VLCbQ</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_cE44xg</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:sequenceFlow id="sequenceFlow_3VLCbQ" sourceRef="event_BQQVcw" targetRef="task_DzBmHg">
<bpmn2:documentation id="documentation_Ib3jJg"/>
</bpmn2:sequenceFlow>
<bpmn2:task id="task_Qx2B4g" imixs:processid="200" name="Send">
<bpmn2:extensionElements/>
<bpmn2:documentation id="documentation_rvNWnQ"/>
<bpmn2:incoming>sequenceFlow_cE44xg</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_Sl9ddA</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:sequenceFlow id="sequenceFlow_cE44xg" sourceRef="task_DzBmHg" targetRef="task_Qx2B4g">
<bpmn2:documentation id="documentation_aElYrg"/>
</bpmn2:sequenceFlow>
<bpmn2:dataStoreReference id="dataStoreReference_7e3Lqw" name="Data Store">
<bpmn2:documentation id="documentation_7z4JLw"/>
</bpmn2:dataStoreReference>
<bpmn2:association id="association_iA0M8A" sourceRef="task_Qx2B4g" targetRef="dataStoreReference_7e3Lqw">
<bpmn2:documentation id="documentation_UrXC7A"/>
</bpmn2:association>
<bpmn2:dataObject id="dataObject_gtbRDw" imixs:datatype="prompt-data" name="Data">
<bpmn2:documentation id="documentation_0uxQUw"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<PromptDefinition>
<prompt_options>{}</prompt_options>
<prompt><![CDATA[<itemvalue>request.subject</itemvalue>
<FILECONTEXT>^.+\.eml$</FILECONTEXT>
]]]]><![CDATA[>
</prompt>
<loglevel>FINE</loglevel>
</PromptDefinition> ]]></bpmn2:documentation>
</bpmn2:dataObject>
<bpmn2:association id="association_lWHmDQ" sourceRef="task_DzBmHg" targetRef="dataObject_gtbRDw">
<bpmn2:documentation id="documentation_Fj4EFA"/>
</bpmn2:association>
<bpmn2:association id="association_pNef4Q" sourceRef="event_BQQVcw" targetRef="dataStoreReference_7e3Lqw">
<bpmn2:documentation id="documentation_pbD1Sw"/>
</bpmn2:association>
<bpmn2:startEvent id="event_BQQVcw" name="Start">
<bpmn2:documentation id="documentation_KSXkdw"/>
<bpmn2:outgoing>association_pNef4Q</bpmn2:outgoing>
<bpmn2:outgoing>sequenceFlow_3VLCbQ</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:endEvent id="event_uRSh7g" name="Completed">
<bpmn2:documentation id="documentation_uzqyIA"/>
<bpmn2:incoming>sequenceFlow_Sl9ddA</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:sequenceFlow id="sequenceFlow_Sl9ddA" sourceRef="task_Qx2B4g" targetRef="event_uRSh7g">
<bpmn2:documentation id="documentation_SpLy3Q"/>
</bpmn2:sequenceFlow>
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1" name="OpenBPMN Diagram">
<bpmndi:BPMNPlane bpmnElement="process_1" id="BPMNPlane_d1zbGg">
<bpmndi:BPMNShape bpmnElement="task_DzBmHg" id="BPMNShape_06Te5Q">
<dc:Bounds height="50.0" width="110.0" x="200.0" y="40.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_Qx2B4g" id="BPMNShape_yer4kw">
<dc:Bounds height="50.0" width="110.0" x="450.0" y="40.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="dataStoreReference_7e3Lqw" id="BPMNShape_xwZRRA">
<dc:Bounds height="50.0" width="50.0" x="520.0" y="180.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_RaeA2w">
<dc:Bounds height="20.0" width="100.0" x="495.0" y="230.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="dataObject_gtbRDw" id="BPMNShape_31X79A">
<dc:Bounds height="50.0" width="35.0" x="270.0" y="150.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_bCydww">
<dc:Bounds height="20.0" width="100.0" x="237.5" y="205.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_BQQVcw" id="BPMNShape_aIKvbQ">
<dc:Bounds height="36.0" width="36.0" x="57.0" y="47.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_b5BxyA">
<dc:Bounds height="20.0" width="100.0" x="25.0" y="86.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_uRSh7g" id="BPMNShape_pDh8Gw">
<dc:Bounds height="36.0" width="36.0" x="657.0" y="47.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_c4C4GQ">
<dc:Bounds height="20.0" width="100.0" x="625.0" y="86.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_3VLCbQ" id="BPMNEdge_lrjXGw" sourceElement="BPMNShape_aIKvbQ" targetElement="BPMNShape_06Te5Q">
<di:waypoint x="93.0" y="65.0"/>
<di:waypoint x="200.0" y="65.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_cE44xg" id="BPMNEdge_cZ0SNA" sourceElement="BPMNShape_06Te5Q" targetElement="BPMNShape_yer4kw">
<di:waypoint x="310.0" y="65.0"/>
<di:waypoint x="450.0" y="65.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="association_iA0M8A" id="BPMNEdge_xP9rlQ" sourceElement="BPMNShape_yer4kw" targetElement="BPMNShape_xwZRRA">
<di:waypoint x="504.0" y="90.0"/>
<di:waypoint x="504.0" y="137.0"/>
<di:waypoint x="540.0" y="137.0"/>
<di:waypoint x="540.0" y="180.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="association_lWHmDQ" id="BPMNEdge_kg3SHw" sourceElement="BPMNShape_06Te5Q" targetElement="BPMNShape_31X79A">
<di:waypoint x="254.0" y="90.0"/>
<di:waypoint x="254.0" y="174.0"/>
<di:waypoint x="270.0" y="174.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="association_pNef4Q" id="BPMNEdge_PH7UMQ" sourceElement="BPMNShape_aIKvbQ" targetElement="BPMNShape_xwZRRA">
<di:waypoint x="75.0" y="83.0"/>
<di:waypoint x="75.0" y="243.0"/>
<di:waypoint x="544.0" y="243.0"/>
<di:waypoint x="544.0" y="230.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_Sl9ddA" id="BPMNEdge_KkWFiA" sourceElement="BPMNShape_yer4kw" targetElement="BPMNShape_pDh8Gw">
<di:waypoint x="560.0" y="65.0"/>
<di:waypoint x="657.0" y="65.0"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 62 KiB

View file

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" class="sprotty-graph bpmnextension-imixs" height="818" id="bpmn-diagram_5_root_pTGI10VcLg3PlNVo" version="1.1" viewBox="0 0 815 545" width="1223">
<defs>
</defs>
<g transform="scale(1) translate(0,0)">
<g class="graph-content">
<g class="node task bpmnextension-imixs" id="bpmn-diagram_5_task_DzBmHg" transform="translate(200, 40)">
<defs>
<clipPath id="task_DzBmHg_clip_path">
<path d="M2,5q0,-3 3,-3h100q3,0 3,3v40q0,3 &#10; -3,3h-100q-3,0 -3,-3z "/>
</clipPath>
</defs>
<path class="sprotty-node" d="M0,5q0,-5 5,-5h100q5,0 5,5v40q0,5 &#10; -5,5h-100q-5,0 -5,-5z " style="fill: transparent; stroke: #00000024; stroke-width: 2px;"/>
<g class="extension">
<text style="fill: #00000024; font-family: sans-serif; font-size: 9.33333px; stroke: rgb(0, 0, 0); stroke-width: 0px;" transform="translate(3,46)">Id:
100</text>
</g>
<g class="bpmn-text-node" id="bpmn-diagram_5_task_DzBmHg_multiline" transform="translate(0, 8)">
<text class="sprotty-label" style="fill: #00000024; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 9.92188px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(55,0)">
<tspan dy="10" x="0">Approve </tspan>
</text>
</g>
</g>
<g class="node task bpmnextension-imixs" id="bpmn-diagram_5_task_Qx2B4g" transform="translate(450, 40)">
<defs>
<clipPath id="task_Qx2B4g_clip_path">
<path d="M2,5q0,-3 3,-3h100q3,0 3,3v40q0,3 &#10; -3,3h-100q-3,0 -3,-3z "/>
</clipPath>
</defs>
<path class="sprotty-node" d="M0,5q0,-5 5,-5h100q5,0 5,5v40q0,5 &#10; -5,5h-100q-5,0 -5,-5z " style="fill: transparent; stroke: #00000024; stroke-width: 2px;"/>
<g class="extension">
<text style="fill: #00000024; font-family: sans-serif; font-size: 9.33333px; stroke: rgb(0, 0, 0); stroke-width: 0px;" transform="translate(3,46)">Id:
200</text>
</g>
<g class="bpmn-text-node" id="bpmn-diagram_5_task_Qx2B4g_multiline" transform="translate(0, 8)">
<text class="sprotty-label" style="fill: #00000024; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 6.21875px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(55,0)">
<tspan dy="10" x="0">Send </tspan>
</text>
</g>
</g>
<g class="startEvent event" id="bpmn-diagram_5_event_BQQVcw" transform="translate(57, 47)">
<circle class="sprotty-node" cx="18" cy="18" r="18" style="fill: transparent; stroke: #00000024; stroke-width: 2px;"/>
<g class="symbol">
<path d="" style="fill: #00000024; stroke-width: 0px;" transform="scale(1.5),translate(4,4)"/>
</g>
</g>
<g class="BPMNLabel" id="bpmn-diagram_5_event_BQQVcw_bpmnlabel" transform="translate(25, 86)">
<rect class="sprotty-node" height="22" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="100" x="0" y="0"/>
<g class="comp sprotty-comp label-container" id="bpmn-diagram_5_1dabf9f7-0b63-4258-9ad2-4187f7af92c2" style="fill: rgba(0, 0, 0, 0); stroke: rgba(0, 0, 0, 0);" transform="translate(5, 5)">
<g class="bpmn-text-node" id="bpmn-diagram_5_event_BQQVcw_bpmnlabel_multiline">
<text class="sprotty-label" style="fill: #00000024; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 5.625px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(45,0)">
<tspan dy="10" x="0">Start </tspan>
</text>
</g>
</g>
</g>
<g class="endEvent event" id="bpmn-diagram_5_event_uRSh7g" transform="translate(657, 47)">
<circle class="sprotty-node" cx="18" cy="18" r="18" style="fill: transparent; stroke: #00000024; stroke-width: 3px;"/>
<g class="symbol">
<path d="" style="fill: #00000024; stroke-width: 0px;" transform="scale(1.5),translate(4,4)"/>
</g>
</g>
<g class="BPMNLabel" id="bpmn-diagram_5_event_uRSh7g_bpmnlabel" transform="translate(625, 86)">
<rect class="sprotty-node" height="22" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="100" x="0" y="0"/>
<g class="comp sprotty-comp label-container" id="bpmn-diagram_5_63a5fcfa-f28f-48d1-a957-e5d4e974b3e0" style="fill: rgba(0, 0, 0, 0); stroke: rgba(0, 0, 0, 0);" transform="translate(5, 5)">
<g class="bpmn-text-node" id="bpmn-diagram_5_event_uRSh7g_bpmnlabel_multiline">
<text class="sprotty-label" style="fill: #00000024; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 12.875px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(45,0)">
<tspan dy="10" x="0">Completed </tspan>
</text>
</g>
</g>
</g>
<g class="dataObject bpmnextension-imixs" id="bpmn-diagram_5_dataObject_gtbRDw" transform="translate(270, 150)">
<rect class="sprotty-node" height="50" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 144, 241); stroke-width: 0px;" width="35" x="0" y="0"/>
<g class="sprotty-icon" style="stroke-width: 2px;">
<path d="&#10; M 0,0 &#10; L 25,0&#10; L 35,10&#10; L 35,50&#10; L 0,50&#10; Z" fill="none" stroke="#00000024" stroke-width="1.5" style="fill: #00000024;"/>
<g class="symbol">
<path d="M6.25 9.016C6.66421 9.016 7 9.35089 7 9.76399V11.26C7 11.6731 6.66421 12.008 6.25 12.008C5.83579 12.008 5.5 11.6731 5.5 11.26V9.76399C5.5 9.35089 5.83579 9.016 6.25 9.016Z&#10; M10.5 9.76399C10.5 9.35089 10.1642 9.016 9.75 9.016C9.33579 9.016 9 9.35089 9 9.76399V11.26C9 11.6731 9.33579 12.008 9.75 12.008C10.1642 12.008 10.5 11.6731 10.5 11.26V9.76399Z&#10; M7.86079 1.80482C7.91028 1.8577 7.95663 1.91232 8 1.96856C8.04337 1.91232 8.08972 1.8577 8.13921 1.80482C8.82116 1.07611 9.87702 0.90832 11.0828 1.04194C12.3131 1.17827 13.2283 1.56829 13.8072 2.29916C14.3725 3.01276 14.5 3.90895 14.5 4.77735C14.5 5.34785 14.447 5.92141 14.2459 6.428L14.4135 7.26391L14.4798 7.29699C15.4115 7.76158 16 8.71126 16 9.7501V11.0107C16 11.2495 15.9143 11.4478 15.844 11.5763C15.7691 11.7131 15.6751 11.8368 15.5851 11.9416C15.4049 12.1512 15.181 12.3534 14.9801 12.5202C14.7751 12.6907 14.5728 12.8419 14.4235 12.9494C14.1842 13.1217 13.9389 13.2807 13.6826 13.4277C13.3756 13.6038 12.9344 13.8361 12.3867 14.0679C11.2956 14.5296 9.75604 15 8 15C6.24396 15 4.70442 14.5296 3.61334 14.0679C3.06559 13.8361 2.62435 13.6038 2.31739 13.4277C2.0611 13.2807 1.81581 13.1217 1.57651 12.9494C1.42716 12.8419 1.2249 12.6907 1.01986 12.5202C0.819 12.3534 0.595113 12.1512 0.414932 11.9416C0.3249 11.8368 0.230849 11.7131 0.156031 11.5763C0.0857453 11.4478 0 11.2495 1.90735e-06 11.0107L0 9.7501C0 8.71126 0.588507 7.76158 1.52017 7.29699L1.5865 7.26391L1.75413 6.42799C1.55295 5.9214 1.5 5.34785 1.5 4.77735C1.5 3.90895 1.62745 3.01276 2.19275 2.29916C2.77172 1.56829 3.68694 1.17827 4.91718 1.04194C6.12298 0.90832 7.17884 1.07611 7.86079 1.80482ZM3.0231 7.7282L3 7.8434V12.0931C3.02086 12.1053 3.04268 12.1179 3.06543 12.131C3.32878 12.2821 3.71567 12.4861 4.19916 12.6907C5.17058 13.1017 6.50604 13.504 8 13.504C9.49396 13.504 10.8294 13.1017 11.8008 12.6907C12.2843 12.4861 12.6712 12.2821 12.9346 12.131C12.9573 12.1179 12.9791 12.1053 13 12.0931V7.8434L12.9769 7.7282C12.4867 7.93728 11.9022 8.01867 11.25 8.01867C10.1037 8.01867 9.19051 7.69201 8.54033 7.03004C8.3213 6.80703 8.14352 6.55741 8 6.28924C7.85648 6.55741 7.6787 6.80703 7.45967 7.03004C6.80949 7.69201 5.89633 8.01867 4.75 8.01867C4.09776 8.01867 3.51325 7.93728 3.0231 7.7282ZM6.76421 2.82557C6.57116 2.61928 6.12702 2.41307 5.08282 2.52878C4.06306 2.64179 3.60328 2.93176 3.36975 3.22656C3.12255 3.53861 3 4.01374 3 4.77735C3 5.56754 3.12905 5.94499 3.3082 6.1441C3.47045 6.32443 3.82768 6.52267 4.75 6.52267C5.60367 6.52267 6.08903 6.28769 6.38811 5.98319C6.70349 5.66209 6.91507 5.1591 7.00579 4.43524C7.12274 3.50212 6.96805 3.04338 6.76421 2.82557ZM9.23579 2.82557C9.03195 3.04338 8.87726 3.50212 8.99421 4.43524C9.08493 5.1591 9.29651 5.66209 9.61189 5.98319C9.91097 6.28769 10.3963 6.52267 11.25 6.52267C12.1723 6.52267 12.5295 6.32443 12.6918 6.1441C12.871 5.94499 13 5.56754 13 4.77735C13 4.01374 12.8775 3.53861 12.6303 3.22656C12.3967 2.93176 11.9369 2.64179 10.9172 2.52878C9.87298 2.41307 9.42884 2.61928 9.23579 2.82557Z" style="fill: #00000024; stroke-width: 0px;" transform="scale(1.5),translate(4,8)"/>
</g>
</g>
</g>
<g class="BPMNLabel" id="bpmn-diagram_5_dataObject_gtbRDw_bpmnlabel" transform="translate(237.5, 205)">
<rect class="sprotty-node" height="22" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="100" x="0" y="0"/>
<g class="comp sprotty-comp label-container" id="bpmn-diagram_5_1fa04718-497b-43aa-9a90-d5ba73fe6ebc" style="fill: rgba(0, 0, 0, 0); stroke: rgba(0, 0, 0, 0);" transform="translate(5, 5)">
<g class="bpmn-text-node" id="bpmn-diagram_5_dataObject_gtbRDw_bpmnlabel_multiline">
<text class="sprotty-label" style="fill: #00000024; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 5.625px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(45,0)">
<tspan dy="10" x="0">Data </tspan>
</text>
</g>
</g>
</g>
<g class="dataStoreReference" id="bpmn-diagram_5_dataStoreReference_7e3Lqw" transform="translate(520, 180)">
<rect class="sprotty-node" height="50" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="50" x="0" y="0"/>
<g class="sprotty-icon" style="stroke-width: 2px;" transform="translate(0,10)">
<path d="M0 0 L0 30" fill="none" stroke="#00000024" stroke-width="1.5"/>
<path d="M50 0 L50 30" fill="none" stroke="#00000024" stroke-width="1.5"/>
<path d="M0 30 A25 8.5 0 0 0 50 30" fill="none" stroke="#00000024" stroke-width="1.5"/>
<path d="M0 15 A25 8.5 0 0 0 50 15" fill="none" stroke="#00000024" stroke-width="1.5"/>
<ellipse cx="25" cy="0" fill="none" rx="25" ry="8.5" stroke="#00000024" stroke-width="1.5"/>
</g>
</g>
<g class="BPMNLabel" id="bpmn-diagram_5_dataStoreReference_7e3Lqw_bpmnlabel" transform="translate(495, 230)">
<rect class="sprotty-node" height="22" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="100" x="0" y="0"/>
<g class="comp sprotty-comp label-container" id="bpmn-diagram_5_da9e09dd-e430-42ae-adbe-c2014dd27244" style="fill: rgba(0, 0, 0, 0); stroke: rgba(0, 0, 0, 0);" transform="translate(5, 5)">
<g class="bpmn-text-node" id="bpmn-diagram_5_dataStoreReference_7e3Lqw_bpmnlabel_multiline">
<text class="sprotty-label" style="fill: #00000024; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 12.7344px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(45,0)">
<tspan dy="10" x="0">Data Store </tspan>
</text>
</g>
</g>
</g>
<g class="sprotty-edge sequenceFlow bpmnedge" id="bpmn-diagram_5_sequenceFlow_3VLCbQ" style="fill: none; stroke: #00000024; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 93,65 L 200,65"/>
<path class="sprotty-edge arrow" d="M 1,0 L 14,-4 L 14,4 Z" style="fill: #00000024;" transform="rotate(180&#10; 200 65) translate(200 65&#10; )"/>
<path class="mouse-handle" d="M 93,65 L 200,65" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_sequenceFlow_3VLCbQ_bpmnlabel" style="fill: #00000024; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(146.5, 65) translate(0, -3)"/>
</g>
<g class="sprotty-edge sequenceFlow bpmnedge" id="bpmn-diagram_5_sequenceFlow_cE44xg" style="fill: none; stroke: #00000024; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 310,65 L 450,65"/>
<path class="sprotty-edge arrow" d="M 1,0 L 14,-4 L 14,4 Z" style="fill: #00000024;" transform="rotate(180&#10; 450 65) translate(450 65&#10; )"/>
<path class="mouse-handle" d="M 310,65 L 450,65" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_sequenceFlow_cE44xg_bpmnlabel" style="fill: #00000024; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(380, 65) translate(0, -3)"/>
</g>
<g class="sprotty-edge sequenceFlow bpmnedge" id="bpmn-diagram_5_sequenceFlow_Sl9ddA" style="fill: none; stroke: #00000024; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 560,65 L 657,65"/>
<path class="sprotty-edge arrow" d="M 1,0 L 14,-4 L 14,4 Z" style="fill: #00000024;" transform="rotate(180&#10; 657 65) translate(657 65&#10; )"/>
<path class="mouse-handle" d="M 560,65 L 657,65" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_sequenceFlow_Sl9ddA_bpmnlabel" style="fill: #00000024; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(608.5, 65) translate(0, -3)"/>
</g>
<g class="sprotty-edge association bpmnedge" id="bpmn-diagram_5_association_iA0M8A" style="fill: none; stroke: #00000024; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 504,90 L 504,127 Q 504,137 514,137 L 530,137 Q 540,137 540,147 L 540,180" style="stroke-dasharray: 4px, 4px;"/>
<path class="mouse-handle" d="M 504,90 L 504,127 Q 504,137 514,137 L 530,137 Q 540,137 540,147 L 540,180" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_association_iA0M8A_bpmnlabel" style="fill: #00000024; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(520, 137) translate(0, -3)"/>
</g>
<g class="sprotty-edge association bpmnedge" id="bpmn-diagram_5_association_lWHmDQ" style="fill: none; stroke: #00000024; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 254,90 L 254,166.8 Q 254,174 261.2,174 L 270,174" style="stroke-dasharray: 4px, 4px;"/>
<path class="mouse-handle" d="M 254,90 L 254,166.8 Q 254,174 261.2,174 L 270,174" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_association_lWHmDQ_bpmnlabel" style="fill: #00000024; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(254, 140) translate(-3, 0)"/>
</g>
<g class="sprotty-edge association bpmnedge" id="bpmn-diagram_5_association_pNef4Q" style="fill: none; stroke: #00000024; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 75,83 L 75,233 Q 75,243 85,243 L 538.1,243 Q 544,243 544,237.1 L 544,230" style="stroke-dasharray: 4px, 4px;"/>
<path class="mouse-handle" d="M 75,83 L 75,233 Q 75,243 85,243 L 538.1,243 Q 544,243 544,237.1 L 544,230" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_association_pNef4Q_bpmnlabel" style="fill: #00000024; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(236, 243) translate(0, -3)"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 17 KiB

View file

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" class="sprotty-graph bpmnextension-imixs" height="818" id="bpmn-diagram_5_root_pTGI10VcLg3PlNVo" version="1.1" viewBox="0 0 815 545" width="1223">
<defs>
</defs>
<g transform="scale(1) translate(0,0)">
<g class="graph-content">
<g class="node task bpmnextension-imixs" id="bpmn-diagram_5_task_DzBmHg" transform="translate(200, 40)">
<defs>
<clipPath id="task_DzBmHg_clip_path">
<path d="M2,5q0,-3 3,-3h100q3,0 3,3v40q0,3 &#10; -3,3h-100q-3,0 -3,-3z "/>
</clipPath>
</defs>
<path class="sprotty-node" d="M0,5q0,-5 5,-5h100q5,0 5,5v40q0,5 &#10; -5,5h-100q-5,0 -5,-5z " style="fill: transparent; stroke: #ffffff24; stroke-width: 2px;"/>
<g class="extension">
<text style="fill: #ffffff24; font-family: sans-serif; font-size: 9.33333px; stroke: rgb(0, 0, 0); stroke-width: 0px;" transform="translate(3,46)">Id:
100</text>
</g>
<g class="bpmn-text-node" id="bpmn-diagram_5_task_DzBmHg_multiline" transform="translate(0, 8)">
<text class="sprotty-label" style="fill: #ffffff24; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 9.92188px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(55,0)">
<tspan dy="10" x="0">Approve </tspan>
</text>
</g>
</g>
<g class="node task bpmnextension-imixs" id="bpmn-diagram_5_task_Qx2B4g" transform="translate(450, 40)">
<defs>
<clipPath id="task_Qx2B4g_clip_path">
<path d="M2,5q0,-3 3,-3h100q3,0 3,3v40q0,3 &#10; -3,3h-100q-3,0 -3,-3z "/>
</clipPath>
</defs>
<path class="sprotty-node" d="M0,5q0,-5 5,-5h100q5,0 5,5v40q0,5 &#10; -5,5h-100q-5,0 -5,-5z " style="fill: transparent; stroke: #ffffff24; stroke-width: 2px;"/>
<g class="extension">
<text style="fill: #ffffff24; font-family: sans-serif; font-size: 9.33333px; stroke: rgb(0, 0, 0); stroke-width: 0px;" transform="translate(3,46)">Id:
200</text>
</g>
<g class="bpmn-text-node" id="bpmn-diagram_5_task_Qx2B4g_multiline" transform="translate(0, 8)">
<text class="sprotty-label" style="fill: #ffffff24; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 6.21875px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(55,0)">
<tspan dy="10" x="0">Send </tspan>
</text>
</g>
</g>
<g class="startEvent event" id="bpmn-diagram_5_event_BQQVcw" transform="translate(57, 47)">
<circle class="sprotty-node" cx="18" cy="18" r="18" style="fill: transparent; stroke: #ffffff24; stroke-width: 2px;"/>
<g class="symbol">
<path d="" style="fill: #ffffff24; stroke-width: 0px;" transform="scale(1.5),translate(4,4)"/>
</g>
</g>
<g class="BPMNLabel" id="bpmn-diagram_5_event_BQQVcw_bpmnlabel" transform="translate(25, 86)">
<rect class="sprotty-node" height="22" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="100" x="0" y="0"/>
<g class="comp sprotty-comp label-container" id="bpmn-diagram_5_1dabf9f7-0b63-4258-9ad2-4187f7af92c2" style="fill: rgba(0, 0, 0, 0); stroke: rgba(0, 0, 0, 0);" transform="translate(5, 5)">
<g class="bpmn-text-node" id="bpmn-diagram_5_event_BQQVcw_bpmnlabel_multiline">
<text class="sprotty-label" style="fill: #ffffff24; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 5.625px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(45,0)">
<tspan dy="10" x="0">Start </tspan>
</text>
</g>
</g>
</g>
<g class="endEvent event" id="bpmn-diagram_5_event_uRSh7g" transform="translate(657, 47)">
<circle class="sprotty-node" cx="18" cy="18" r="18" style="fill: transparent; stroke: #ffffff24; stroke-width: 3px;"/>
<g class="symbol">
<path d="" style="fill: #ffffff24; stroke-width: 0px;" transform="scale(1.5),translate(4,4)"/>
</g>
</g>
<g class="BPMNLabel" id="bpmn-diagram_5_event_uRSh7g_bpmnlabel" transform="translate(625, 86)">
<rect class="sprotty-node" height="22" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="100" x="0" y="0"/>
<g class="comp sprotty-comp label-container" id="bpmn-diagram_5_63a5fcfa-f28f-48d1-a957-e5d4e974b3e0" style="fill: rgba(0, 0, 0, 0); stroke: rgba(0, 0, 0, 0);" transform="translate(5, 5)">
<g class="bpmn-text-node" id="bpmn-diagram_5_event_uRSh7g_bpmnlabel_multiline">
<text class="sprotty-label" style="fill: #ffffff24; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 12.875px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(45,0)">
<tspan dy="10" x="0">Completed </tspan>
</text>
</g>
</g>
</g>
<g class="dataObject bpmnextension-imixs" id="bpmn-diagram_5_dataObject_gtbRDw" transform="translate(270, 150)">
<rect class="sprotty-node" height="50" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 144, 241); stroke-width: 0px;" width="35" x="0" y="0"/>
<g class="sprotty-icon" style="stroke-width: 2px;">
<path d="&#10; M 0,0 &#10; L 25,0&#10; L 35,10&#10; L 35,50&#10; L 0,50&#10; Z" fill="none" stroke="#ffffff24" stroke-width="1.5" style="fill: #ffffff24;"/>
<g class="symbol">
<path d="M6.25 9.016C6.66421 9.016 7 9.35089 7 9.76399V11.26C7 11.6731 6.66421 12.008 6.25 12.008C5.83579 12.008 5.5 11.6731 5.5 11.26V9.76399C5.5 9.35089 5.83579 9.016 6.25 9.016Z&#10; M10.5 9.76399C10.5 9.35089 10.1642 9.016 9.75 9.016C9.33579 9.016 9 9.35089 9 9.76399V11.26C9 11.6731 9.33579 12.008 9.75 12.008C10.1642 12.008 10.5 11.6731 10.5 11.26V9.76399Z&#10; M7.86079 1.80482C7.91028 1.8577 7.95663 1.91232 8 1.96856C8.04337 1.91232 8.08972 1.8577 8.13921 1.80482C8.82116 1.07611 9.87702 0.90832 11.0828 1.04194C12.3131 1.17827 13.2283 1.56829 13.8072 2.29916C14.3725 3.01276 14.5 3.90895 14.5 4.77735C14.5 5.34785 14.447 5.92141 14.2459 6.428L14.4135 7.26391L14.4798 7.29699C15.4115 7.76158 16 8.71126 16 9.7501V11.0107C16 11.2495 15.9143 11.4478 15.844 11.5763C15.7691 11.7131 15.6751 11.8368 15.5851 11.9416C15.4049 12.1512 15.181 12.3534 14.9801 12.5202C14.7751 12.6907 14.5728 12.8419 14.4235 12.9494C14.1842 13.1217 13.9389 13.2807 13.6826 13.4277C13.3756 13.6038 12.9344 13.8361 12.3867 14.0679C11.2956 14.5296 9.75604 15 8 15C6.24396 15 4.70442 14.5296 3.61334 14.0679C3.06559 13.8361 2.62435 13.6038 2.31739 13.4277C2.0611 13.2807 1.81581 13.1217 1.57651 12.9494C1.42716 12.8419 1.2249 12.6907 1.01986 12.5202C0.819 12.3534 0.595113 12.1512 0.414932 11.9416C0.3249 11.8368 0.230849 11.7131 0.156031 11.5763C0.0857453 11.4478 0 11.2495 1.90735e-06 11.0107L0 9.7501C0 8.71126 0.588507 7.76158 1.52017 7.29699L1.5865 7.26391L1.75413 6.42799C1.55295 5.9214 1.5 5.34785 1.5 4.77735C1.5 3.90895 1.62745 3.01276 2.19275 2.29916C2.77172 1.56829 3.68694 1.17827 4.91718 1.04194C6.12298 0.90832 7.17884 1.07611 7.86079 1.80482ZM3.0231 7.7282L3 7.8434V12.0931C3.02086 12.1053 3.04268 12.1179 3.06543 12.131C3.32878 12.2821 3.71567 12.4861 4.19916 12.6907C5.17058 13.1017 6.50604 13.504 8 13.504C9.49396 13.504 10.8294 13.1017 11.8008 12.6907C12.2843 12.4861 12.6712 12.2821 12.9346 12.131C12.9573 12.1179 12.9791 12.1053 13 12.0931V7.8434L12.9769 7.7282C12.4867 7.93728 11.9022 8.01867 11.25 8.01867C10.1037 8.01867 9.19051 7.69201 8.54033 7.03004C8.3213 6.80703 8.14352 6.55741 8 6.28924C7.85648 6.55741 7.6787 6.80703 7.45967 7.03004C6.80949 7.69201 5.89633 8.01867 4.75 8.01867C4.09776 8.01867 3.51325 7.93728 3.0231 7.7282ZM6.76421 2.82557C6.57116 2.61928 6.12702 2.41307 5.08282 2.52878C4.06306 2.64179 3.60328 2.93176 3.36975 3.22656C3.12255 3.53861 3 4.01374 3 4.77735C3 5.56754 3.12905 5.94499 3.3082 6.1441C3.47045 6.32443 3.82768 6.52267 4.75 6.52267C5.60367 6.52267 6.08903 6.28769 6.38811 5.98319C6.70349 5.66209 6.91507 5.1591 7.00579 4.43524C7.12274 3.50212 6.96805 3.04338 6.76421 2.82557ZM9.23579 2.82557C9.03195 3.04338 8.87726 3.50212 8.99421 4.43524C9.08493 5.1591 9.29651 5.66209 9.61189 5.98319C9.91097 6.28769 10.3963 6.52267 11.25 6.52267C12.1723 6.52267 12.5295 6.32443 12.6918 6.1441C12.871 5.94499 13 5.56754 13 4.77735C13 4.01374 12.8775 3.53861 12.6303 3.22656C12.3967 2.93176 11.9369 2.64179 10.9172 2.52878C9.87298 2.41307 9.42884 2.61928 9.23579 2.82557Z" style="fill: #ffffff24; stroke-width: 0px;" transform="scale(1.5),translate(4,8)"/>
</g>
</g>
</g>
<g class="BPMNLabel" id="bpmn-diagram_5_dataObject_gtbRDw_bpmnlabel" transform="translate(237.5, 205)">
<rect class="sprotty-node" height="22" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="100" x="0" y="0"/>
<g class="comp sprotty-comp label-container" id="bpmn-diagram_5_1fa04718-497b-43aa-9a90-d5ba73fe6ebc" style="fill: rgba(0, 0, 0, 0); stroke: rgba(0, 0, 0, 0);" transform="translate(5, 5)">
<g class="bpmn-text-node" id="bpmn-diagram_5_dataObject_gtbRDw_bpmnlabel_multiline">
<text class="sprotty-label" style="fill: #ffffff24; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 5.625px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(45,0)">
<tspan dy="10" x="0">Data </tspan>
</text>
</g>
</g>
</g>
<g class="dataStoreReference" id="bpmn-diagram_5_dataStoreReference_7e3Lqw" transform="translate(520, 180)">
<rect class="sprotty-node" height="50" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="50" x="0" y="0"/>
<g class="sprotty-icon" style="stroke-width: 2px;" transform="translate(0,10)">
<path d="M0 0 L0 30" fill="none" stroke="#ffffff24" stroke-width="1.5"/>
<path d="M50 0 L50 30" fill="none" stroke="#ffffff24" stroke-width="1.5"/>
<path d="M0 30 A25 8.5 0 0 0 50 30" fill="none" stroke="#ffffff24" stroke-width="1.5"/>
<path d="M0 15 A25 8.5 0 0 0 50 15" fill="none" stroke="#ffffff24" stroke-width="1.5"/>
<ellipse cx="25" cy="0" fill="none" rx="25" ry="8.5" stroke="#ffffff24" stroke-width="1.5"/>
</g>
</g>
<g class="BPMNLabel" id="bpmn-diagram_5_dataStoreReference_7e3Lqw_bpmnlabel" transform="translate(495, 230)">
<rect class="sprotty-node" height="22" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="100" x="0" y="0"/>
<g class="comp sprotty-comp label-container" id="bpmn-diagram_5_da9e09dd-e430-42ae-adbe-c2014dd27244" style="fill: rgba(0, 0, 0, 0); stroke: rgba(0, 0, 0, 0);" transform="translate(5, 5)">
<g class="bpmn-text-node" id="bpmn-diagram_5_dataStoreReference_7e3Lqw_bpmnlabel_multiline">
<text class="sprotty-label" style="fill: #ffffff24; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 12.7344px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(45,0)">
<tspan dy="10" x="0">Data Store </tspan>
</text>
</g>
</g>
</g>
<g class="sprotty-edge sequenceFlow bpmnedge" id="bpmn-diagram_5_sequenceFlow_3VLCbQ" style="fill: none; stroke: #ffffff24; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 93,65 L 200,65"/>
<path class="sprotty-edge arrow" d="M 1,0 L 14,-4 L 14,4 Z" style="fill: #ffffff24;" transform="rotate(180&#10; 200 65) translate(200 65&#10; )"/>
<path class="mouse-handle" d="M 93,65 L 200,65" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_sequenceFlow_3VLCbQ_bpmnlabel" style="fill: #ffffff24; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(146.5, 65) translate(0, -3)"/>
</g>
<g class="sprotty-edge sequenceFlow bpmnedge" id="bpmn-diagram_5_sequenceFlow_cE44xg" style="fill: none; stroke: #ffffff24; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 310,65 L 450,65"/>
<path class="sprotty-edge arrow" d="M 1,0 L 14,-4 L 14,4 Z" style="fill: #ffffff24;" transform="rotate(180&#10; 450 65) translate(450 65&#10; )"/>
<path class="mouse-handle" d="M 310,65 L 450,65" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_sequenceFlow_cE44xg_bpmnlabel" style="fill: #ffffff24; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(380, 65) translate(0, -3)"/>
</g>
<g class="sprotty-edge sequenceFlow bpmnedge" id="bpmn-diagram_5_sequenceFlow_Sl9ddA" style="fill: none; stroke: #ffffff24; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 560,65 L 657,65"/>
<path class="sprotty-edge arrow" d="M 1,0 L 14,-4 L 14,4 Z" style="fill: #ffffff24;" transform="rotate(180&#10; 657 65) translate(657 65&#10; )"/>
<path class="mouse-handle" d="M 560,65 L 657,65" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_sequenceFlow_Sl9ddA_bpmnlabel" style="fill: #ffffff24; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(608.5, 65) translate(0, -3)"/>
</g>
<g class="sprotty-edge association bpmnedge" id="bpmn-diagram_5_association_iA0M8A" style="fill: none; stroke: #ffffff24; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 504,90 L 504,127 Q 504,137 514,137 L 530,137 Q 540,137 540,147 L 540,180" style="stroke-dasharray: 4px, 4px;"/>
<path class="mouse-handle" d="M 504,90 L 504,127 Q 504,137 514,137 L 530,137 Q 540,137 540,147 L 540,180" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_association_iA0M8A_bpmnlabel" style="fill: #ffffff24; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(520, 137) translate(0, -3)"/>
</g>
<g class="sprotty-edge association bpmnedge" id="bpmn-diagram_5_association_lWHmDQ" style="fill: none; stroke: #ffffff24; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 254,90 L 254,166.8 Q 254,174 261.2,174 L 270,174" style="stroke-dasharray: 4px, 4px;"/>
<path class="mouse-handle" d="M 254,90 L 254,166.8 Q 254,174 261.2,174 L 270,174" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_association_lWHmDQ_bpmnlabel" style="fill: #ffffff24; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(254, 140) translate(-3, 0)"/>
</g>
<g class="sprotty-edge association bpmnedge" id="bpmn-diagram_5_association_pNef4Q" style="fill: none; stroke: #ffffff24; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 75,83 L 75,233 Q 75,243 85,243 L 538.1,243 Q 544,243 544,237.1 L 544,230" style="stroke-dasharray: 4px, 4px;"/>
<path class="mouse-handle" d="M 75,83 L 75,233 Q 75,243 85,243 L 538.1,243 Q 544,243 544,237.1 L 544,230" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_association_pNef4Q_bpmnlabel" style="fill: #ffffff24; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(236, 243) translate(0, -3)"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 17 KiB

View file

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" class="sprotty-graph bpmnextension-imixs" height="818" id="bpmn-diagram_5_root_pTGI10VcLg3PlNVo" version="1.1" viewBox="0 0 815 545" width="1223">
<defs>
</defs>
<g transform="scale(1) translate(0,0)">
<g class="graph-content">
<g class="node task bpmnextension-imixs" id="bpmn-diagram_5_task_DzBmHg" transform="translate(200, 40)">
<defs>
<clipPath id="task_DzBmHg_clip_path">
<path d="M2,5q0,-3 3,-3h100q3,0 3,3v40q0,3 &#10; -3,3h-100q-3,0 -3,-3z "/>
</clipPath>
</defs>
<path class="sprotty-node" d="M0,5q0,-5 5,-5h100q5,0 5,5v40q0,5 &#10; -5,5h-100q-5,0 -5,-5z " style="fill: transparent; stroke: #ffffff0a; stroke-width: 2px;"/>
<g class="extension">
<text style="fill: #ffffff0a; font-family: sans-serif; font-size: 9.33333px; stroke: rgb(0, 0, 0); stroke-width: 0px;" transform="translate(3,46)">Id:
100</text>
</g>
<g class="bpmn-text-node" id="bpmn-diagram_5_task_DzBmHg_multiline" transform="translate(0, 8)">
<text class="sprotty-label" style="fill: #ffffff0a; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 9.92188px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(55,0)">
<tspan dy="10" x="0">Approve </tspan>
</text>
</g>
</g>
<g class="node task bpmnextension-imixs" id="bpmn-diagram_5_task_Qx2B4g" transform="translate(450, 40)">
<defs>
<clipPath id="task_Qx2B4g_clip_path">
<path d="M2,5q0,-3 3,-3h100q3,0 3,3v40q0,3 &#10; -3,3h-100q-3,0 -3,-3z "/>
</clipPath>
</defs>
<path class="sprotty-node" d="M0,5q0,-5 5,-5h100q5,0 5,5v40q0,5 &#10; -5,5h-100q-5,0 -5,-5z " style="fill: transparent; stroke: #ffffff0a; stroke-width: 2px;"/>
<g class="extension">
<text style="fill: #ffffff0a; font-family: sans-serif; font-size: 9.33333px; stroke: rgb(0, 0, 0); stroke-width: 0px;" transform="translate(3,46)">Id:
200</text>
</g>
<g class="bpmn-text-node" id="bpmn-diagram_5_task_Qx2B4g_multiline" transform="translate(0, 8)">
<text class="sprotty-label" style="fill: #ffffff0a; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 6.21875px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(55,0)">
<tspan dy="10" x="0">Send </tspan>
</text>
</g>
</g>
<g class="startEvent event" id="bpmn-diagram_5_event_BQQVcw" transform="translate(57, 47)">
<circle class="sprotty-node" cx="18" cy="18" r="18" style="fill: transparent; stroke: #ffffff0a; stroke-width: 2px;"/>
<g class="symbol">
<path d="" style="fill: #ffffff0a; stroke-width: 0px;" transform="scale(1.5),translate(4,4)"/>
</g>
</g>
<g class="BPMNLabel" id="bpmn-diagram_5_event_BQQVcw_bpmnlabel" transform="translate(25, 86)">
<rect class="sprotty-node" height="22" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="100" x="0" y="0"/>
<g class="comp sprotty-comp label-container" id="bpmn-diagram_5_1dabf9f7-0b63-4258-9ad2-4187f7af92c2" style="fill: rgba(0, 0, 0, 0); stroke: rgba(0, 0, 0, 0);" transform="translate(5, 5)">
<g class="bpmn-text-node" id="bpmn-diagram_5_event_BQQVcw_bpmnlabel_multiline">
<text class="sprotty-label" style="fill: #ffffff0a; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 5.625px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(45,0)">
<tspan dy="10" x="0">Start </tspan>
</text>
</g>
</g>
</g>
<g class="endEvent event" id="bpmn-diagram_5_event_uRSh7g" transform="translate(657, 47)">
<circle class="sprotty-node" cx="18" cy="18" r="18" style="fill: transparent; stroke: #ffffff0a; stroke-width: 3px;"/>
<g class="symbol">
<path d="" style="fill: #ffffff0a; stroke-width: 0px;" transform="scale(1.5),translate(4,4)"/>
</g>
</g>
<g class="BPMNLabel" id="bpmn-diagram_5_event_uRSh7g_bpmnlabel" transform="translate(625, 86)">
<rect class="sprotty-node" height="22" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="100" x="0" y="0"/>
<g class="comp sprotty-comp label-container" id="bpmn-diagram_5_63a5fcfa-f28f-48d1-a957-e5d4e974b3e0" style="fill: rgba(0, 0, 0, 0); stroke: rgba(0, 0, 0, 0);" transform="translate(5, 5)">
<g class="bpmn-text-node" id="bpmn-diagram_5_event_uRSh7g_bpmnlabel_multiline">
<text class="sprotty-label" style="fill: #ffffff0a; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 12.875px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(45,0)">
<tspan dy="10" x="0">Completed </tspan>
</text>
</g>
</g>
</g>
<g class="dataObject bpmnextension-imixs" id="bpmn-diagram_5_dataObject_gtbRDw" transform="translate(270, 150)">
<rect class="sprotty-node" height="50" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 144, 241); stroke-width: 0px;" width="35" x="0" y="0"/>
<g class="sprotty-icon" style="stroke-width: 2px;">
<path d="&#10; M 0,0 &#10; L 25,0&#10; L 35,10&#10; L 35,50&#10; L 0,50&#10; Z" fill="none" stroke="#ffffff0a" stroke-width="1.5" style="fill: #ffffff0a;"/>
<g class="symbol">
<path d="M6.25 9.016C6.66421 9.016 7 9.35089 7 9.76399V11.26C7 11.6731 6.66421 12.008 6.25 12.008C5.83579 12.008 5.5 11.6731 5.5 11.26V9.76399C5.5 9.35089 5.83579 9.016 6.25 9.016Z&#10; M10.5 9.76399C10.5 9.35089 10.1642 9.016 9.75 9.016C9.33579 9.016 9 9.35089 9 9.76399V11.26C9 11.6731 9.33579 12.008 9.75 12.008C10.1642 12.008 10.5 11.6731 10.5 11.26V9.76399Z&#10; M7.86079 1.80482C7.91028 1.8577 7.95663 1.91232 8 1.96856C8.04337 1.91232 8.08972 1.8577 8.13921 1.80482C8.82116 1.07611 9.87702 0.90832 11.0828 1.04194C12.3131 1.17827 13.2283 1.56829 13.8072 2.29916C14.3725 3.01276 14.5 3.90895 14.5 4.77735C14.5 5.34785 14.447 5.92141 14.2459 6.428L14.4135 7.26391L14.4798 7.29699C15.4115 7.76158 16 8.71126 16 9.7501V11.0107C16 11.2495 15.9143 11.4478 15.844 11.5763C15.7691 11.7131 15.6751 11.8368 15.5851 11.9416C15.4049 12.1512 15.181 12.3534 14.9801 12.5202C14.7751 12.6907 14.5728 12.8419 14.4235 12.9494C14.1842 13.1217 13.9389 13.2807 13.6826 13.4277C13.3756 13.6038 12.9344 13.8361 12.3867 14.0679C11.2956 14.5296 9.75604 15 8 15C6.24396 15 4.70442 14.5296 3.61334 14.0679C3.06559 13.8361 2.62435 13.6038 2.31739 13.4277C2.0611 13.2807 1.81581 13.1217 1.57651 12.9494C1.42716 12.8419 1.2249 12.6907 1.01986 12.5202C0.819 12.3534 0.595113 12.1512 0.414932 11.9416C0.3249 11.8368 0.230849 11.7131 0.156031 11.5763C0.0857453 11.4478 0 11.2495 1.90735e-06 11.0107L0 9.7501C0 8.71126 0.588507 7.76158 1.52017 7.29699L1.5865 7.26391L1.75413 6.42799C1.55295 5.9214 1.5 5.34785 1.5 4.77735C1.5 3.90895 1.62745 3.01276 2.19275 2.29916C2.77172 1.56829 3.68694 1.17827 4.91718 1.04194C6.12298 0.90832 7.17884 1.07611 7.86079 1.80482ZM3.0231 7.7282L3 7.8434V12.0931C3.02086 12.1053 3.04268 12.1179 3.06543 12.131C3.32878 12.2821 3.71567 12.4861 4.19916 12.6907C5.17058 13.1017 6.50604 13.504 8 13.504C9.49396 13.504 10.8294 13.1017 11.8008 12.6907C12.2843 12.4861 12.6712 12.2821 12.9346 12.131C12.9573 12.1179 12.9791 12.1053 13 12.0931V7.8434L12.9769 7.7282C12.4867 7.93728 11.9022 8.01867 11.25 8.01867C10.1037 8.01867 9.19051 7.69201 8.54033 7.03004C8.3213 6.80703 8.14352 6.55741 8 6.28924C7.85648 6.55741 7.6787 6.80703 7.45967 7.03004C6.80949 7.69201 5.89633 8.01867 4.75 8.01867C4.09776 8.01867 3.51325 7.93728 3.0231 7.7282ZM6.76421 2.82557C6.57116 2.61928 6.12702 2.41307 5.08282 2.52878C4.06306 2.64179 3.60328 2.93176 3.36975 3.22656C3.12255 3.53861 3 4.01374 3 4.77735C3 5.56754 3.12905 5.94499 3.3082 6.1441C3.47045 6.32443 3.82768 6.52267 4.75 6.52267C5.60367 6.52267 6.08903 6.28769 6.38811 5.98319C6.70349 5.66209 6.91507 5.1591 7.00579 4.43524C7.12274 3.50212 6.96805 3.04338 6.76421 2.82557ZM9.23579 2.82557C9.03195 3.04338 8.87726 3.50212 8.99421 4.43524C9.08493 5.1591 9.29651 5.66209 9.61189 5.98319C9.91097 6.28769 10.3963 6.52267 11.25 6.52267C12.1723 6.52267 12.5295 6.32443 12.6918 6.1441C12.871 5.94499 13 5.56754 13 4.77735C13 4.01374 12.8775 3.53861 12.6303 3.22656C12.3967 2.93176 11.9369 2.64179 10.9172 2.52878C9.87298 2.41307 9.42884 2.61928 9.23579 2.82557Z" style="fill: #ffffff0a; stroke-width: 0px;" transform="scale(1.5),translate(4,8)"/>
</g>
</g>
</g>
<g class="BPMNLabel" id="bpmn-diagram_5_dataObject_gtbRDw_bpmnlabel" transform="translate(237.5, 205)">
<rect class="sprotty-node" height="22" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="100" x="0" y="0"/>
<g class="comp sprotty-comp label-container" id="bpmn-diagram_5_1fa04718-497b-43aa-9a90-d5ba73fe6ebc" style="fill: rgba(0, 0, 0, 0); stroke: rgba(0, 0, 0, 0);" transform="translate(5, 5)">
<g class="bpmn-text-node" id="bpmn-diagram_5_dataObject_gtbRDw_bpmnlabel_multiline">
<text class="sprotty-label" style="fill: #ffffff0a; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 5.625px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(45,0)">
<tspan dy="10" x="0">Data </tspan>
</text>
</g>
</g>
</g>
<g class="dataStoreReference" id="bpmn-diagram_5_dataStoreReference_7e3Lqw" transform="translate(520, 180)">
<rect class="sprotty-node" height="50" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="50" x="0" y="0"/>
<g class="sprotty-icon" style="stroke-width: 2px;" transform="translate(0,10)">
<path d="M0 0 L0 30" fill="none" stroke="#ffffff0a" stroke-width="1.5"/>
<path d="M50 0 L50 30" fill="none" stroke="#ffffff0a" stroke-width="1.5"/>
<path d="M0 30 A25 8.5 0 0 0 50 30" fill="none" stroke="#ffffff0a" stroke-width="1.5"/>
<path d="M0 15 A25 8.5 0 0 0 50 15" fill="none" stroke="#ffffff0a" stroke-width="1.5"/>
<ellipse cx="25" cy="0" fill="none" rx="25" ry="8.5" stroke="#ffffff0a" stroke-width="1.5"/>
</g>
</g>
<g class="BPMNLabel" id="bpmn-diagram_5_dataStoreReference_7e3Lqw_bpmnlabel" transform="translate(495, 230)">
<rect class="sprotty-node" height="22" style="fill: rgba(0, 0, 0, 0); stroke: rgb(0, 0, 0); stroke-width: 0px;" width="100" x="0" y="0"/>
<g class="comp sprotty-comp label-container" id="bpmn-diagram_5_da9e09dd-e430-42ae-adbe-c2014dd27244" style="fill: rgba(0, 0, 0, 0); stroke: rgba(0, 0, 0, 0);" transform="translate(5, 5)">
<g class="bpmn-text-node" id="bpmn-diagram_5_dataStoreReference_7e3Lqw_bpmnlabel_multiline">
<text class="sprotty-label" style="fill: #ffffff0a; font-family: sans-serif; font-size: 10.6667px; perspective-origin: 12.7344px 6px; stroke: rgb(0, 0, 0); stroke-width: 0px; text-anchor: middle;" transform="translate(45,0)">
<tspan dy="10" x="0">Data Store </tspan>
</text>
</g>
</g>
</g>
<g class="sprotty-edge sequenceFlow bpmnedge" id="bpmn-diagram_5_sequenceFlow_3VLCbQ" style="fill: none; stroke: #ffffff0a; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 93,65 L 200,65"/>
<path class="sprotty-edge arrow" d="M 1,0 L 14,-4 L 14,4 Z" style="fill: #ffffff0a;" transform="rotate(180&#10; 200 65) translate(200 65&#10; )"/>
<path class="mouse-handle" d="M 93,65 L 200,65" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_sequenceFlow_3VLCbQ_bpmnlabel" style="fill: #ffffff0a; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(146.5, 65) translate(0, -3)"/>
</g>
<g class="sprotty-edge sequenceFlow bpmnedge" id="bpmn-diagram_5_sequenceFlow_cE44xg" style="fill: none; stroke: #ffffff0a; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 310,65 L 450,65"/>
<path class="sprotty-edge arrow" d="M 1,0 L 14,-4 L 14,4 Z" style="fill: #ffffff0a;" transform="rotate(180&#10; 450 65) translate(450 65&#10; )"/>
<path class="mouse-handle" d="M 310,65 L 450,65" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_sequenceFlow_cE44xg_bpmnlabel" style="fill: #ffffff0a; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(380, 65) translate(0, -3)"/>
</g>
<g class="sprotty-edge sequenceFlow bpmnedge" id="bpmn-diagram_5_sequenceFlow_Sl9ddA" style="fill: none; stroke: #ffffff0a; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 560,65 L 657,65"/>
<path class="sprotty-edge arrow" d="M 1,0 L 14,-4 L 14,4 Z" style="fill: #ffffff0a;" transform="rotate(180&#10; 657 65) translate(657 65&#10; )"/>
<path class="mouse-handle" d="M 560,65 L 657,65" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_sequenceFlow_Sl9ddA_bpmnlabel" style="fill: #ffffff0a; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(608.5, 65) translate(0, -3)"/>
</g>
<g class="sprotty-edge association bpmnedge" id="bpmn-diagram_5_association_iA0M8A" style="fill: none; stroke: #ffffff0a; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 504,90 L 504,127 Q 504,137 514,137 L 530,137 Q 540,137 540,147 L 540,180" style="stroke-dasharray: 4px, 4px;"/>
<path class="mouse-handle" d="M 504,90 L 504,127 Q 504,137 514,137 L 530,137 Q 540,137 540,147 L 540,180" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_association_iA0M8A_bpmnlabel" style="fill: #ffffff0a; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(520, 137) translate(0, -3)"/>
</g>
<g class="sprotty-edge association bpmnedge" id="bpmn-diagram_5_association_lWHmDQ" style="fill: none; stroke: #ffffff0a; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 254,90 L 254,166.8 Q 254,174 261.2,174 L 270,174" style="stroke-dasharray: 4px, 4px;"/>
<path class="mouse-handle" d="M 254,90 L 254,166.8 Q 254,174 261.2,174 L 270,174" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_association_lWHmDQ_bpmnlabel" style="fill: #ffffff0a; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(254, 140) translate(-3, 0)"/>
</g>
<g class="sprotty-edge association bpmnedge" id="bpmn-diagram_5_association_pNef4Q" style="fill: none; stroke: #ffffff0a; stroke-width: 1.5px;">
<path class="sprotty-edge line" d="M 75,83 L 75,233 Q 75,243 85,243 L 538.1,243 Q 544,243 544,237.1 L 544,230" style="stroke-dasharray: 4px, 4px;"/>
<path class="mouse-handle" d="M 75,83 L 75,233 Q 75,243 85,243 L 538.1,243 Q 544,243 544,237.1 L 544,230" style="stroke-width: 20; stroke: transparent; stroke-dasharray: none; stroke-dashoffset: 0;"/>
<text class="heading sprotty-label" id="bpmn-diagram_5_association_pNef4Q_bpmnlabel" style="fill: #ffffff0a; font-family: sans-serif; font-size: 10.6667px; stroke-width: 0px; text-align: center; text-anchor: middle;" transform="translate(236, 243) translate(0, -3)"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 17 KiB

View file

@ -0,0 +1,494 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DYNAMIXS.AI - Die TRUSTED Enterprise AI Platform</title>
<style>
/*
*************************************************
* CSS-GRUNDLAGEN (Zum schnellen Testen integriert) *
*************************************************
*/
:root {
--color-primary: #007bff;
/* Starkes Blau */
--color-secondary: #28a745;
/* Akzent Grün/Akzent */
--color-dark: #212529;
--color-light: #f8f9fa;
--font-family: 'Inter', sans-serif;
--section-padding: 80px 0;
}
body {
font-family: var(--font-family);
line-height: 1.6;
margin: 0;
padding-top: 60px;
/* Platz für die Fixed-Navigation */
color: var(--color-dark);
background-color: white;
}
h1,
h2,
h3 {
line-height: 1.2;
font-weight: 800;
margin-bottom: 20px;
}
a {
color: var(--color-primary);
text-decoration: none;
transition: color 0.3s;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
section {
padding: var(--section-padding);
scroll-margin-top: 60px;
/* Für smooth scrolling */
}
/* --- Navigation --- */
.header-nav {
position: fixed;
top: 0;
left: 0;
width: 100%;
background-color: white;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
z-index: 1000;
}
.nav-content {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px;
}
.logo {
font-size: 1.5em;
font-weight: bold;
color: var(--color-dark);
}
.nav-menu ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
}
.nav-menu ul li a {
padding: 10px 15px;
display: block;
font-weight: 600;
color: var(--color-dark);
}
.nav-menu ul li a:hover {
color: var(--color-primary);
}
/* --- CTAs --- */
.btn {
display: inline-block;
padding: 12px 25px;
margin-top: 10px;
border-radius: 5px;
text-transform: uppercase;
font-weight: 600;
transition: background-color 0.3s;
text-align: center;
}
.btn-primary {
background-color: var(--color-primary);
color: white;
}
.btn-primary:hover {
background-color: #0056b3;
}
.btn-secondary {
background-color: transparent;
color: var(--color-primary);
border: 2px solid var(--color-primary);
}
.btn-secondary:hover {
background-color: var(--color-primary);
color: white;
}
/* --- Sektion: Hero/Home --- */
#home {
background-color: var(--color-light);
text-align: center;
padding: 100px 0;
}
#home h1 {
font-size: 3em;
margin-bottom: 10px;
color: var(--color-dark);
}
#home .subtitle {
font-size: 1.5em;
font-weight: 400;
margin-bottom: 40px;
color: #6c757d;
}
.cta-group .btn {
margin: 0 10px;
}
/* --- Sektion: Problem (Kontrast-Sektion) --- */
#problem {
background-color: var(--color-dark);
color: white;
text-align: center;
}
#problem h2 {
color: white;
}
#problem ul {
list-style: none;
padding: 0;
display: flex;
justify-content: center;
gap: 40px;
flex-wrap: wrap;
}
#problem ul li {
max-width: 250px;
text-align: left;
padding: 20px;
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 8px;
}
/* --- Sektion: Features (Grid) --- */
.feature-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 40px;
margin-top: 40px;
}
.feature-card {
background-color: var(--color-light);
padding: 30px;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
}
.feature-card h3 {
color: var(--color-primary);
}
/* --- Sektion: Prozess (Linearer Ablauf) --- */
.process-step {
display: flex;
align-items: flex-start;
margin-bottom: 30px;
}
.step-number {
font-size: 2em;
font-weight: bold;
color: var(--color-secondary);
margin-right: 20px;
}
.step-content h3 {
margin-top: 0;
color: var(--color-primary);
}
/* --- Sektion: Ergebnisse (Metriken/Testimonials) --- */
.metric-grid {
display: flex;
justify-content: space-around;
text-align: center;
margin-top: 40px;
}
.metric strong {
display: block;
font-size: 3em;
color: var(--color-primary);
line-height: 1;
}
.testimonial-card {
background-color: var(--color-light);
padding: 30px;
border-left: 5px solid var(--color-secondary);
margin-top: 30px;
}
/* --- Footer --- */
footer {
background-color: var(--color-dark);
color: white;
padding: 40px 0;
text-align: center;
font-size: 0.9em;
}
footer a {
color: white;
margin: 0 10px;
}
/* --- Media Queries für Responsivität --- */
@media (max-width: 768px) {
.nav-menu ul {
display: none;
/* Mobile Navigation vereinfacht (Hamburger-Menü würde hier folgen) */
}
.nav-content {
justify-content: center;
}
body {
padding-top: 50px;
}
.header-nav {
height: 50px;
}
#home h1 {
font-size: 2.5em;
}
.metric-grid {
flex-direction: column;
gap: 30px;
}
.cta-group {
display: flex;
flex-direction: column;
gap: 10px;
}
}
</style>
</head>
<body>
<header class="header-nav">
<div class="container nav-content">
<div class="logo">DYNAMIXS.AI</div>
<nav class="nav-menu">
<ul>
<li><a href="#home">Start</a></li>
<li><a href="#plattform">Plattform</a></li>
<li><a href="#prozess">Prozess</a></li>
<li><a href="#ergebnisse">Erfolge</a></li>
<li><a href="#kontakt" class="btn btn-primary">Demo</a></li>
</ul>
</nav>
</div>
</header>
<section id="home" class="container">
<h1>Ihre Geschäftsprozesse sind einzigartig.<br>Unsere KI versteht sie.</h1>
<p class="subtitle">Die **TRUSTED Enterprise AI Platform** – Modellierung, Verbesserung und Automatisierung
Ihrer Prozesse, geerdet in Ihrer Business-Realität.</p>
<div class="cta-group">
<a href="#plattform" class="btn btn-primary">Platform kennenlernen</a>
<a href="#kontakt" class="btn btn-secondary">Experten sprechen</a>
</div>
</section>
<section id="problem">
<div class="container">
<h2>Warum KI allein nicht genug ist</h2>
<p>Ohne den Kontext Ihrer Abläufe bleibt KI eine Black Box. Die häufigsten Herausforderungen:</p>
<ul>
<li>
<i class="fas fa-sitemap"></i>
<h3>Verstreute Workflows</h3>
<p>Komplexe Abläufe sind über viele Systeme verteilt, Tools halten nicht Schritt.</p>
</li>
<li>
<i class="fas fa-database"></i>
<h3>Datensilos</h3>
<p>Wichtige Informationen sind isoliert, was Entscheidungen verlangsamt und die Zuverlässigkeit
mindert.</p>
</li>
<li>
<i class="fas fa-lock"></i>
<h3>Sicherheitsrisiken</h3>
<p>Compliance- und Sicherheitsauflagen limitieren den Einsatz externer, unkontrollierter KI.</p>
</li>
</ul>
</div>
</section>
<section id="plattform" class="container">
<h2>Was DYNAMIXS.AI **anders** macht</h2>
<p class="subtitle">Wir starten mit Ihrer Business-Realität. Die DYNAMIXS.AI Plattform ist Ihre **Process
Context Engine**:</p>
<p>Ihre Workflows, Regeln, Dokumente und das Expertenwissen Ihrer Teams werden zusammengeführt, um der KI den
notwendigen Kontext zu liefern. Dadurch wird KI **präzise, geschäftsreif und vertrauenswürdig**.</p>
<img src="placeholder-grafik-context-engine.svg" alt="Visuelle Darstellung der Process Context Engine"
style="width: 100%; max-width: 600px; display: block; margin: 40px auto;">
<a href="#features" class="btn btn-primary">Mehr zu AI Modeling</a>
</section>
<section id="features" class="container">
<h2>Drei Säulen für Ihren Erfolg</h2>
<div class="feature-grid">
<div class="feature-card">
<i class="fas fa-handshake fa-3x"></i>
<h3>Start mit Ihrer Geschäftsrealität</h3>
<p>Wir modellieren Prozesse, Daten und Regeln exakt so, wie sie existieren. Ihre individuelle Logik ist
die Basis für präzise KI-Aktionen.</p>
<a href="#">Mehr erfahren &rarr;</a>
</div>
<div class="feature-card">
<i class="fas fa-robot fa-3x"></i>
<h3>AI transformiert Ihre Prozesse</h3>
<p>Ihre Workflows bilden den Rahmen für KI-gesteuerte Entscheidungen: **Smart, Secure und Trusted.** Das
System lernt mit jedem Workflow.</p>
<a href="#">AI Modeling ansehen &rarr;</a>
</div>
<div class="feature-card">
<i class="fas fa-cogs fa-3x"></i>
<h3>Effiziente Anpassung mit Templates</h3>
<p>Vordefinierte Bausteine für Finance, HR und Logistik ermöglichen eine schnelle, kosteneffiziente
Implementierung in Stunden statt Wochen.</p>
<a href="#">Zur Template Library &rarr;</a>
</div>
</div>
</section>
<section id="prozess" class="container" style="background-color: var(--color-light);">
<h2>In 4 Schritten zur Trusted AI Platform</h2>
<p>Von der Vision zur Implementierung – schnell und strukturiert.</p>
<div class="process-flow">
<div class="process-step">
<div class="step-number">1</div>
<div class="step-content">
<h3>Capture your business reality</h3>
<p>Ihre Prozesse, Daten und Regeln werden in einem Living Model abgebildet.</p>
</div>
</div>
<div class="process-step">
<div class="step-number">2</div>
<div class="step-content">
<h3>Build the workflow model</h3>
<p>Eine erste lauffähige Version Ihres Systems ist innerhalb von Stunden einsatzbereit.</p>
</div>
</div>
<div class="process-step">
<div class="step-number">3</div>
<div class="step-content">
<h3>Customize with templates</h3>
<p>Fertige Komponenten verkürzen die Entwicklungszeit und beschleunigen die Implementierung.</p>
</div>
</div>
<div class="process-step">
<div class="step-number">4</div>
<div class="step-content">
<h3>Deploy, learn, improve</h3>
<p>Nach dem Live-Gang beginnt die kontinuierliche Optimierung durch gesammelte Prozessdaten.</p>
</div>
</div>
</div>
</section>
<section id="architektur" class="container">
<h2>Enterprise-Ready Architektur</h2>
<p>Ein Technologie-Stack, geformt durch zwei Jahrzehnte Enterprise-Projekte, auf den Sie sich verlassen können:
</p>
<ul>
<li>**Skalierbar:** Event-driven, BPMN-basiert, Cloud-native und API-first.</li>
<li>**Geschützt:** Daten sind verschlüsselt, auditierbar und DSGVO-konform.</li>
<li>**Bewährt:** Erfolgreich im Einsatz in Logistik, HR, Finance und Government.</li>
</ul>
<a href="#" class="btn btn-secondary">Architektur im Detail ansehen</a>
</section>
<section id="ergebnisse" class="container" style="background-color: var(--color-light);">
<h2>Messbare Erfolge in realen Unternehmen</h2>
<div class="metric-grid">
<div class="metric">
<strong>2</strong>
<p>Wochen bis zur vollen Integration in vielen Kundenfällen.</p>
</div>
<div class="metric">
<strong>5,000+</strong>
<p>Transaktionen und 95 Modelle bei einer Steuerberatung.</p>
</div>
<div class="metric">
<strong>2</strong>
<p>Stunden bis zum ersten lauffähigen Modell.</p>
</div>
</div>
<div class="testimonial-card">
<p>“Unglaublich, wie schnell wir unsere Geschäftsprozesse implementiert haben. Die Ergebnisse fließen direkt
in unser ERP.”</p>
<small>— Kunde, Finance</small>
</div>
<a href="#" class="btn btn-primary" style="margin-top: 40px;">Alle Erfolgsstories &rarr;</a>
</section>
<section id="kontakt" class="container" style="text-align: center;">
<h2>Ready to see how?</h2>
<p class="subtitle">Nutzen Sie das ungenutzte Intelligenzpotenzial Ihrer Workflows. Wir zeigen Ihnen, wie.</p>
<a href="#" class="btn btn-primary btn-lg" style="font-size: 1.2em;">Jetzt Beratungstermin vereinbaren</a>
<p style="margin-top: 20px;">Oder rufen Sie uns an: +49 (0) XXXX / XXXXXX</p>
</section>
<footer>
<div class="container">
<div class="logo">DYNAMIXS.AI</div>
<p>© 2025 DYNAMIXS.AI | Alle Rechte vorbehalten.</p>
<p>
<a href="#">Kontakt</a>
<a href="#">Legal / Impressum</a>
<a href="#">Datenschutz</a>
</p>
</div>
</footer>
</body>
</html>

156
dynamixs-ai-mcp/pom.xml Normal file
View file

@ -0,0 +1,156 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>dynamixs-ai</artifactId>
<groupId>ai.dynamixs</groupId>
<version>1.0.1</version>
</parent>
<artifactId>dynamixs-ai-mcp</artifactId>
<packaging>jar</packaging>
<name>Dynamixs AI MCP Server Library</name>
<build>
<plugins>
<!-- use JDK settings for compiling -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.source}</source>
<target>${java.target}</target>
</configuration>
</plugin>
<!-- Testing JUnit 5 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<!-- issue #572
hack for:
https://stackoverflow.com/questions/75116023/unable-to-make-protected-final-java-lang-class-java-lang-classloader-defineclass
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>default-test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<argLine>
--add-opens java.base/java.lang=ALL-UNNAMED
</argLine>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Jakarta EE -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>${jakarta.version}</version>
<scope>provided</scope>
</dependency>
<!-- Microprofile -->
<dependency>
<groupId>org.eclipse.microprofile</groupId>
<artifactId>microprofile</artifactId>
<version>${microprofile.version}</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<!-- Imixs Workflow -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-core</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-engine</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-jax-rs</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-faces</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.parsson</groupId>
<artifactId>jakarta.json</artifactId>
<version>1.1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,315 @@
package ai.dynamixs.mcp;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import jakarta.json.Json;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;
import jakarta.json.JsonString;
/**
* Represents an MCP Resource based on Imixs-Workflow BPMN models.
*
* MCP Resources represent entities that can be read by the MCP client. Each
* resource corresponds to a workflow task/event combination.
*/
public class MCPResource implements Serializable {
private static final long serialVersionUID = 1L;
// MCP Standard Fields
private String uri; // Resource URI
private String name; // Human-readable name
private String description; // Resource description
private String mimeType; // MIME type of the resource
private Map<String, Object> annotations; // Additional metadata
// Imixs-specific fields
private String modelVersion;
private int taskId;
private int eventId;
// Constructors
public MCPResource() {
this.annotations = new HashMap<>();
}
public MCPResource(String modelVersion, int taskId, int eventId) {
this();
this.modelVersion = modelVersion;
this.taskId = taskId;
this.eventId = eventId;
this.uri = createResourceUri(modelVersion, taskId, eventId);
}
/**
* Creates a resource URI from Imixs workflow components
*/
public static String createResourceUri(String modelVersion, int taskId, int eventId) {
if (modelVersion == null || modelVersion.trim().isEmpty()) {
throw new IllegalArgumentException("Model version cannot be null or empty");
}
return String.format("imixs://workflow/%s/%d/%d", modelVersion, taskId, eventId);
}
/**
* Parses model version from URI
*/
public String getModelVersionFromUri() {
if (uri == null || !uri.startsWith("imixs://workflow/")) {
throw new IllegalStateException("Invalid resource URI format: " + uri);
}
String path = uri.substring("imixs://workflow/".length());
String[] parts = path.split("/");
if (parts.length < 3) {
throw new IllegalStateException("Invalid resource URI format: " + uri);
}
return parts[0];
}
/**
* Parses task ID from URI
*/
public int getTaskIdFromUri() {
if (uri == null || !uri.startsWith("imixs://workflow/")) {
throw new IllegalStateException("Invalid resource URI format: " + uri);
}
String path = uri.substring("imixs://workflow/".length());
String[] parts = path.split("/");
if (parts.length < 3) {
throw new IllegalStateException("Invalid resource URI format: " + uri);
}
try {
return Integer.parseInt(parts[1]);
} catch (NumberFormatException e) {
throw new IllegalStateException("Invalid task ID in resource URI: " + uri, e);
}
}
/**
* Parses event ID from URI
*/
public int getEventIdFromUri() {
if (uri == null || !uri.startsWith("imixs://workflow/")) {
throw new IllegalStateException("Invalid resource URI format: " + uri);
}
String path = uri.substring("imixs://workflow/".length());
String[] parts = path.split("/");
if (parts.length < 3) {
throw new IllegalStateException("Invalid resource URI format: " + uri);
}
try {
return Integer.parseInt(parts[2]);
} catch (NumberFormatException e) {
throw new IllegalStateException("Invalid event ID in resource URI: " + uri, e);
}
}
/**
* Converts this resource to MCP JSON format
*/
public JsonObject toJsonObject() {
JsonObjectBuilder builder = Json.createObjectBuilder()
.add("uri", uri != null ? uri : "")
.add("name", name != null ? name : "")
.add("description", description != null ? description : "");
if (mimeType != null) {
builder.add("mimeType", mimeType);
}
// Annotations object
if (annotations != null && !annotations.isEmpty()) {
JsonObjectBuilder annotationsBuilder = Json.createObjectBuilder();
annotations.forEach((key, value) -> {
if (value instanceof String) {
annotationsBuilder.add(key, (String) value);
} else if (value instanceof Number) {
annotationsBuilder.add(key, ((Number) value).doubleValue());
} else if (value instanceof Boolean) {
annotationsBuilder.add(key, (Boolean) value);
} else if (value != null) {
annotationsBuilder.add(key, value.toString());
}
});
builder.add("annotations", annotationsBuilder.build());
}
return builder.build();
}
/**
* Creates an MCPResource from a JsonObject
*/
public static MCPResource fromJsonObject(JsonObject jsonObject) {
MCPResource resource = new MCPResource();
resource.setUri(jsonObject.getString("uri", ""));
resource.setName(jsonObject.getString("name", ""));
resource.setDescription(jsonObject.getString("description", ""));
if (jsonObject.containsKey("mimeType")) {
resource.setMimeType(jsonObject.getString("mimeType"));
}
// Annotations
if (jsonObject.containsKey("annotations")) {
JsonObject annotationsObject = jsonObject.getJsonObject("annotations");
Map<String, Object> annotations = new HashMap<>();
annotationsObject.forEach((key, value) -> {
switch (value.getValueType()) {
case STRING:
annotations.put(key, ((JsonString) value).getString());
break;
case NUMBER:
annotations.put(key, ((jakarta.json.JsonNumber) value).doubleValue());
break;
case TRUE:
annotations.put(key, Boolean.TRUE);
break;
case FALSE:
annotations.put(key, Boolean.FALSE);
break;
default:
annotations.put(key, value.toString());
}
});
resource.setAnnotations(annotations);
}
return resource;
}
/**
* Validates this resource for MCP compliance
*/
public boolean isValid() {
if (uri == null || uri.trim().isEmpty()) {
return false;
}
if (name == null || name.trim().isEmpty()) {
return false;
}
// Validate URI format
try {
getModelVersionFromUri();
getTaskIdFromUri();
getEventIdFromUri();
} catch (Exception e) {
return false;
}
return true;
}
// Getters and Setters
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
public Map<String, Object> getAnnotations() {
return annotations;
}
public void setAnnotations(Map<String, Object> annotations) {
this.annotations = annotations != null ? annotations : new HashMap<>();
}
public String getModelVersion() {
return modelVersion;
}
public void setModelVersion(String modelVersion) {
this.modelVersion = modelVersion;
}
public int getTaskId() {
return taskId;
}
public void setTaskId(int taskId) {
this.taskId = taskId;
}
public int getEventId() {
return eventId;
}
public void setEventId(int eventId) {
this.eventId = eventId;
}
// Convenience methods for annotations
public void addAnnotation(String key, Object value) {
if (annotations == null) {
annotations = new HashMap<>();
}
annotations.put(key, value);
}
public String getAnnotationString(String key) {
Object value = annotations != null ? annotations.get(key) : null;
return value != null ? value.toString() : null;
}
public Boolean getAnnotationBoolean(String key) {
Object value = annotations != null ? annotations.get(key) : null;
if (value instanceof Boolean) {
return (Boolean) value;
}
return null;
}
@Override
public String toString() {
return String.format("MCPResource{uri='%s', name='%s', modelVersion='%s', taskId=%d, eventId=%d}",
uri, name, modelVersion, taskId, eventId);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
MCPResource that = (MCPResource) obj;
return uri != null ? uri.equals(that.uri) : that.uri == null;
}
@Override
public int hashCode() {
return uri != null ? uri.hashCode() : 0;
}
}

View file

@ -0,0 +1,434 @@
/*******************************************************************************
* Imixs Workflow
* Copyright (C) 2001, 2011 Imixs Software Solutions GmbH,
* http://www.imixs.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You can receive a copy of the GNU General Public
* License at http://www.gnu.org/licenses/gpl.html
*
* Project:
* http://www.imixs.org
* http://java.net/projects/imixs-workflow
*
* Contributors:
* Imixs Software Solutions GmbH - initial API and implementation
* Ralph Soika - Software Developer
*******************************************************************************/
package ai.dynamixs.mcp;
import java.io.Serializable;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.imixs.workflow.ItemCollection;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.json.Json;
import jakarta.json.JsonArray;
import jakarta.json.JsonArrayBuilder;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriInfo;
/**
* The MCPRestService provides Model Context Protocol (MCP) endpoints for
* accessing workflow resources and tools.
*
* @author rsoika
*/
@Named
@RequestScoped
@Path("/mcp/")
@Produces({ MediaType.APPLICATION_JSON })
public class MCPRestService implements Serializable {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(MCPRestService.class.getSimpleName());
@Context
UriInfo uriInfo;
@Inject
MCPService mcpService;
/**
* MCP JSON-RPC 2.0 Endpoint All MCP protocol methods are handled here URL:
* /mcp/v1
*/
@POST
@Path("/v1")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response handleJsonRpcRequest(JsonObject request) {
try {
// Validate JSON-RPC 2.0 structure
if (!isValidJsonRpcRequest(request)) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(buildJsonRpcError(-32600, "Invalid Request", null))
.build();
}
String method = request.getString("method");
Object id = request.get("id");
JsonObject params = request.containsKey("params") ? request.getJsonObject("params") : null;
// Route to appropriate MCP method
switch (method) {
case "initialize":
return handleInitialize(id, params);
case "resources/list":
return handleResourcesList(id, params);
case "resources/read":
return handleResourcesRead(id, params);
case "tools/list":
return handleToolsList(id, params);
case "tools/call":
return handleToolsCall(id, params);
default:
return Response.status(Response.Status.NOT_FOUND)
.entity(buildJsonRpcError(-32601, "Method not found", id))
.build();
}
} catch (Exception e) {
logger.severe("Error processing MCP JSON-RPC request: " + e.getMessage());
e.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(buildJsonRpcError(-32603, "Internal server error", null))
.build();
}
}
/**
* Handle MCP initialize method
*/
private Response handleInitialize(Object id, JsonObject params) {
try {
// Build server capabilities
JsonObject capabilities = Json.createObjectBuilder()
.add("resources", Json.createObjectBuilder()
.add("subscribe", false)
.add("listChanged", false)
.build())
.add("tools", Json.createObjectBuilder().build())
.add("logging", Json.createObjectBuilder().build())
.build();
// Build server information
JsonObject serverInfo = Json.createObjectBuilder()
.add("name", "Dynamixs.AI MCP Server")
.add("version", "1.0.0")
.build();
JsonObject result = Json.createObjectBuilder()
.add("protocolVersion", "2024-11-05")
.add("capabilities", capabilities)
.add("serverInfo", serverInfo)
.build();
JsonObject response = Json.createObjectBuilder()
.add("jsonrpc", "2.0")
.add("id", id.toString())
.add("result", result)
.build();
return Response.ok(response).build();
} catch (Exception e) {
logger.severe("Error in initialize: " + e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(buildJsonRpcError(-32603, "Internal server error", id))
.build();
}
}
/**
* Handle MCP resources/list method
*/
private Response handleResourcesList(Object id, JsonObject params) {
try {
List<MCPResource> resources = mcpService.parseResources();
List<MCPResource> validResources = resources.stream()
.filter(MCPResource::isValid)
.collect(Collectors.toList());
JsonArray resourcesArray = validResources.stream()
.map(MCPResource::toJsonObject)
.collect(Json::createArrayBuilder,
JsonArrayBuilder::add,
JsonArrayBuilder::addAll)
.build();
JsonObject result = Json.createObjectBuilder()
.add("resources", resourcesArray)
.build();
JsonObject response = Json.createObjectBuilder()
.add("jsonrpc", "2.0")
.add("id", id.toString())
.add("result", result)
.build();
return Response.ok(response).build();
} catch (Exception e) {
logger.severe("Error in resources/list: " + e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(buildJsonRpcError(-32603, "Internal server error", id))
.build();
}
}
/**
* Handle MCP resources/read method
*/
private Response handleResourcesRead(Object id, JsonObject params) {
try {
if (params == null || !params.containsKey("uri")) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(buildJsonRpcError(-32602, "Invalid params: missing uri", id))
.build();
}
String uri = params.getString("uri");
String content = mcpService.readResource(uri);
JsonObject result = Json.createObjectBuilder()
.add("contents", Json.createArrayBuilder()
.add(Json.createObjectBuilder()
.add("uri", uri)
.add("mimeType", "text/plain")
.add("text", content)
.build())
.build())
.build();
JsonObject response = Json.createObjectBuilder()
.add("jsonrpc", "2.0")
.add("id", id.toString())
.add("result", result)
.build();
return Response.ok(response).build();
} catch (Exception e) {
logger.severe("Error in resources/read: " + e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(buildJsonRpcError(-32001, "Resource not found", id))
.build();
}
}
/**
* Handle MCP tools/list method
*/
private Response handleToolsList(Object id, JsonObject params) {
try {
List<MCPTool> tools = mcpService.parseTools();
List<MCPTool> validTools = tools.stream()
.filter(MCPTool::isValid)
.collect(Collectors.toList());
JsonArray toolsArray = validTools.stream()
.map(MCPTool::toJsonObject)
.collect(Json::createArrayBuilder,
JsonArrayBuilder::add,
JsonArrayBuilder::addAll)
.build();
JsonObject result = Json.createObjectBuilder()
.add("tools", toolsArray)
.build();
JsonObject response = Json.createObjectBuilder()
.add("jsonrpc", "2.0")
.add("id", id.toString())
.add("result", result)
.build();
return Response.ok(response).build();
} catch (Exception e) {
logger.severe("Error in tools/list: " + e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(buildJsonRpcError(-32603, "Internal server error", id))
.build();
}
}
/**
* Handle MCP tools/call method
*/
private Response handleToolsCall(Object id, JsonObject params) {
try {
if (params == null || !params.containsKey("name")) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(buildJsonRpcError(-32602, "Invalid params: missing name", id))
.build();
}
String toolName = params.getString("name");
JsonObject arguments = params.containsKey("arguments") ? params.getJsonObject("arguments")
: Json.createObjectBuilder().build();
// Convert JSON arguments to ItemCollection
ItemCollection workitem = jsonToItemCollection(arguments);
// Execute the tool
ItemCollection result = mcpService.executeTool(toolName, workitem);
// Convert result back to JSON
JsonObject toolResult = itemCollectionToJson(result);
// Build MCP response with content array
JsonObject mcpResult = Json.createObjectBuilder()
.add("content", Json.createArrayBuilder()
.add(Json.createObjectBuilder()
.add("type", "text")
.add("text", "Tool executed successfully. Result: " + toolResult.toString())
.build())
.build())
.add("isError", false)
.build();
JsonObject response = Json.createObjectBuilder()
.add("jsonrpc", "2.0")
.add("id", id.toString())
.add("result", mcpResult)
.build();
return Response.ok(response).build();
} catch (Exception e) {
logger.severe("Error in tools/call: " + e.getMessage());
// Return error content in MCP format
JsonObject errorResult = Json.createObjectBuilder()
.add("content", Json.createArrayBuilder()
.add(Json.createObjectBuilder()
.add("type", "text")
.add("text", "Tool execution failed: " + e.getMessage())
.build())
.build())
.add("isError", true)
.build();
JsonObject response = Json.createObjectBuilder()
.add("jsonrpc", "2.0")
.add("id", id.toString())
.add("result", errorResult)
.build();
return Response.ok(response).build();
}
}
/**
* Validates JSON-RPC 2.0 request structure
*/
private boolean isValidJsonRpcRequest(JsonObject request) {
return request.containsKey("jsonrpc") &&
"2.0".equals(request.getString("jsonrpc")) &&
request.containsKey("method") &&
request.containsKey("id");
}
/**
* Builds a JSON-RPC 2.0 error response
*/
private JsonObject buildJsonRpcError(int code, String message, Object id) {
JsonObjectBuilder errorBuilder = Json.createObjectBuilder()
.add("code", code)
.add("message", message);
JsonObjectBuilder responseBuilder = Json.createObjectBuilder()
.add("jsonrpc", "2.0")
.add("error", errorBuilder.build());
if (id != null) {
responseBuilder.add("id", id.toString());
} else {
responseBuilder.addNull("id");
}
return responseBuilder.build();
}
/**
* Converts a JSON object to an ItemCollection
*/
private ItemCollection jsonToItemCollection(JsonObject jsonObject) {
ItemCollection itemCol = new ItemCollection();
if (jsonObject.containsKey("workitem")) {
JsonObject workitem = jsonObject.getJsonObject("workitem");
workitem.forEach((key, value) -> {
switch (value.getValueType()) {
case STRING:
itemCol.setItemValue(key, ((jakarta.json.JsonString) value).getString());
break;
case NUMBER:
itemCol.setItemValue(key, ((jakarta.json.JsonNumber) value).intValue());
break;
case TRUE:
itemCol.setItemValue(key, Boolean.TRUE);
break;
case FALSE:
itemCol.setItemValue(key, Boolean.FALSE);
break;
default:
itemCol.setItemValue(key, value.toString());
}
});
}
return itemCol;
}
/**
* Converts an ItemCollection to a JSON object
*/
private JsonObject itemCollectionToJson(ItemCollection itemCol) {
JsonObjectBuilder builder = Json.createObjectBuilder();
for (String itemName : itemCol.getItemNames()) {
Object value = itemCol.getItemValue(itemName);
if (value instanceof String) {
builder.add(itemName, (String) value);
} else if (value instanceof Integer) {
builder.add(itemName, (Integer) value);
} else if (value instanceof Double) {
builder.add(itemName, (Double) value);
} else if (value instanceof Boolean) {
builder.add(itemName, (Boolean) value);
} else if (value != null) {
builder.add(itemName, value.toString());
}
}
return builder.build();
}
}

View file

@ -0,0 +1,273 @@
package ai.dynamixs.mcp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.ModelManager;
import org.imixs.workflow.engine.ModelService;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.exceptions.ModelException;
import org.imixs.workflow.exceptions.PluginException;
import org.openbpmn.bpmn.BPMNModel;
import jakarta.annotation.security.DeclareRoles;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ejb.LocalBean;
import jakarta.ejb.Stateless;
import jakarta.inject.Inject;
/**
* The MCPService parses the model information to provide MCP Resources and
* Tools
*
* @author rsoika
*/
@DeclareRoles({ "org.imixs.ACCESSLEVEL.NOACCESS",
"org.imixs.ACCESSLEVEL.READERACCESS",
"org.imixs.ACCESSLEVEL.AUTHORACCESS",
"org.imixs.ACCESSLEVEL.EDITORACCESS",
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
@RolesAllowed({ "org.imixs.ACCESSLEVEL.NOACCESS",
"org.imixs.ACCESSLEVEL.READERACCESS",
"org.imixs.ACCESSLEVEL.AUTHORACCESS",
"org.imixs.ACCESSLEVEL.EDITORACCESS",
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
@Stateless
@LocalBean
public class MCPService {
@Inject
ModelService modelService;
@Inject
WorkflowService workflowService;
private static Logger logger = Logger.getLogger(MCPService.class.getName());
/**
* This method iterates over all models and returns a list of MCP resources
*
* The method looks for events with <imixs-ai name="RESOURCE"> tag.
*/
public List<MCPResource> parseResources() {
logger.log(Level.INFO, "├── 🔃 parsing MCP Resources....");
List<MCPResource> result = new ArrayList<>();
ModelManager modelManager = new ModelManager(workflowService);
List<String> versions = modelService.getVersions();
try {
for (String version : versions) {
logger.log(Level.INFO, "│ ├── {0}", version);
BPMNModel model = modelManager.getModel(version);
Set<String> groups = modelManager.findAllGroupsByModel(model);
for (String group : groups) {
List<ItemCollection> tasks = modelManager.findTasks(model, group);
for (ItemCollection task : tasks) {
int taskID = task.getItemValueInteger("taskid");
List<ItemCollection> events = modelManager.findEventsByTask(model, taskID);
for (ItemCollection event : events) {
int eventID = event.getItemValueInteger("eventid");
// test if we have a <imixs-ai name="RESOURCE">
try {
List<ItemCollection> resourceDefinitions = workflowService.evalWorkflowResultXML(
event, "imixs-ai", "RESOURCE", null, false);
// did we found a resource?
for (ItemCollection resourceItemCol : resourceDefinitions) {
MCPResource resource = new MCPResource(version, taskID, eventID);
resource.setName(event.getItemValueString("name"));
resource.setDescription(resourceItemCol.getItemValueString("description"));
resource.setMimeType("text/plain");
// Add annotations
String tags = resourceItemCol.getItemValueString("tags");
if (tags != null && !tags.isBlank()) {
resource.addAnnotation("tags", tags);
}
String category = resourceItemCol.getItemValueString("category");
if (category != null && !category.isBlank()) {
resource.addAnnotation("category", category);
}
if (resource.isValid()) {
result.add(resource);
logger.log(Level.INFO, "│ │ ├── Resource: {0}", resource.getUri());
}
}
} catch (PluginException e) {
// no match
}
}
}
}
}
} catch (ModelException e) {
logger.log(Level.SEVERE, "Error parsing models for resources", e);
}
return result;
}
/**
* This method iterates over all models and returns a list of MCP tools
*
* The method looks for events with <imixs-ai name="TOOL"> tag.
*/
public List<MCPTool> parseTools() {
logger.log(Level.INFO, "├── 🔃 parsing MCP Tools....");
List<MCPTool> result = new ArrayList<>();
ModelManager modelManager = new ModelManager(workflowService);
List<String> versions = modelService.getVersions();
try {
for (String version : versions) {
logger.log(Level.INFO, "│ ├── {0}", version);
BPMNModel model = modelManager.getModel(version);
Set<String> groups = modelManager.findAllGroupsByModel(model);
for (String group : groups) {
List<ItemCollection> tasks = modelManager.findTasks(model, group);
for (ItemCollection task : tasks) {
int taskID = task.getItemValueInteger("taskid");
List<ItemCollection> events = modelManager.findEventsByTask(model, taskID);
for (ItemCollection event : events) {
int eventID = event.getItemValueInteger("eventid");
// test if we have a <imixs-ai name="TOOL">
try {
List<ItemCollection> toolDefinitions = workflowService.evalWorkflowResultXML(
event, "imixs-ai", "TOOL", null, false);
// did we found a tool?
for (ItemCollection toolItemCol : toolDefinitions) {
MCPTool tool = new MCPTool(version, taskID, eventID);
String toolName = version + "_" + taskID + "_" + eventID;// toolItemCol.getItemValueString("name");
if (toolName != null && !toolName.isBlank()) {
tool.setName(toolName);
}
tool.setDescription(toolItemCol.getItemValueString("description"));
String tags = toolItemCol.getItemValueString("tags");
if (tags != null && !tags.isBlank()) {
String[] parts = tags.split(",\\s*");
tool.setTags(Arrays.asList(parts));
}
tool.setExamples(toolItemCol.getItemValueList("example", String.class));
if (tool.isValid()) {
result.add(tool);
logger.log(Level.INFO, "│ │ ├── Tool: {0}", tool.getName());
}
}
} catch (PluginException e) {
// no match
}
}
}
}
}
} catch (ModelException e) {
logger.log(Level.SEVERE, "Error parsing models for tools", e);
}
return result;
}
/**
* Executes a workflow tool with the given arguments
*/
public ItemCollection executeTool(String toolName, ItemCollection workitem) throws Exception {
logger.log(Level.INFO, "├── 🔧 executing MCP Tool: {0}", toolName);
// Parse tool name to extract workflow parameters
MCPTool tool = new MCPTool();
tool.setName(toolName);
String modelVersion = tool.getModelVersionFromName();
int taskId = tool.getTaskIdFromName();
int eventId = tool.getEventIdFromName();
// Set workflow parameters
workitem.setItemValue("$modelversion", modelVersion);
workitem.setItemValue("$taskid", taskId);
workitem.setItemValue("$eventid", eventId);
// Process the workitem
ItemCollection result = workflowService.processWorkItem(workitem);
logger.log(Level.INFO, "│ └── Tool execution completed");
return result;
}
/**
* Reads the content of a resource
*/
public String readResource(String uri) throws Exception {
logger.log(Level.INFO, "├── 📖 reading MCP Resource: {0}", uri);
// Parse URI to extract workflow parameters
MCPResource resource = new MCPResource();
resource.setUri(uri);
String modelVersion = resource.getModelVersionFromUri();
int taskId = resource.getTaskIdFromUri();
int eventId = resource.getEventIdFromUri();
// Create a workitem to read the resource
ItemCollection workitem = new ItemCollection();
workitem.setItemValue("$modelversion", modelVersion);
workitem.setItemValue("$taskid", taskId);
workitem.setItemValue("$eventid", eventId);
// Get the event definition to extract resource content
ModelManager modelManager = new ModelManager(workflowService);
BPMNModel model = modelManager.getModel(modelVersion);
ItemCollection event = modelManager.findEventByID(model, taskId, eventId);
if (event == null) {
throw new Exception("Event not found: " + uri);
}
// Look for resource content in the event
try {
List<ItemCollection> resourceDefinitions = workflowService.evalWorkflowResultXML(
event, "imixs-ai", "RESOURCE", null, false);
if (!resourceDefinitions.isEmpty()) {
ItemCollection resourceDef = resourceDefinitions.get(0);
String content = resourceDef.getItemValueString("content");
if (content != null && !content.isBlank()) {
return content;
}
}
} catch (PluginException e) {
// no resource definition found
}
// Fallback: return event documentation
String documentation = event.getItemValueString("documentation");
if (documentation != null && !documentation.isBlank()) {
return documentation;
}
// Last fallback: return event name and description
return String.format("Event: %s\nDescription: %s",
event.getItemValueString("name"),
event.getItemValueString("description"));
}
}

View file

@ -0,0 +1,254 @@
package ai.dynamixs.mcp;
import java.io.Serializable;
import java.util.List;
import java.util.logging.Logger;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.json.Json;
import jakarta.json.JsonArrayBuilder;
import jakarta.json.JsonObject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriInfo;
/**
* Test endpoint for MCP server discovery and debugging Similar to A2A Agent
* Card but for MCP protocol
*
* @author rsoika
*/
@Named
@RequestScoped
@Path("/mcp/debug/")
@Produces({ MediaType.APPLICATION_JSON })
public class MCPTestEndpoint implements Serializable {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(MCPTestEndpoint.class.getSimpleName());
@Context
UriInfo uriInfo;
@Inject
MCPService mcpService;
/**
* MCP Server Information Endpoint (similar to A2A Agent Card) URL:
* /mcp/server-info
*/
@GET
@Path("/server-info")
public Response getServerInfo() {
try {
JsonObject serverInfo = buildServerInfo();
return Response.ok(serverInfo).build();
} catch (Exception e) {
logger.severe("Error creating MCP server info: " + e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(Json.createObjectBuilder()
.add("error", "Internal server error")
.add("message", e.getMessage())
.build())
.build();
}
}
/**
* Quick test endpoint to list all available resources URL: /mcp/test/resources
*/
@GET
@Path("/test/resources")
public Response testResources() {
try {
List<MCPResource> resources = mcpService.parseResources();
JsonArrayBuilder resourcesBuilder = Json.createArrayBuilder();
for (MCPResource resource : resources) {
if (resource.isValid()) {
resourcesBuilder.add(resource.toJsonObject());
}
}
JsonObject result = Json.createObjectBuilder()
.add("status", "success")
.add("count", resources.size())
.add("resources", resourcesBuilder.build())
.build();
return Response.ok(result).build();
} catch (Exception e) {
logger.severe("Error testing resources: " + e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(Json.createObjectBuilder()
.add("error", "Failed to parse resources")
.add("message", e.getMessage())
.build())
.build();
}
}
/**
* Quick test endpoint to list all available tools URL: /mcp/test/tools
*/
@GET
@Path("/test/tools")
public Response testTools() {
try {
List<MCPTool> tools = mcpService.parseTools();
JsonArrayBuilder toolsBuilder = Json.createArrayBuilder();
for (MCPTool tool : tools) {
if (tool.isValid()) {
toolsBuilder.add(tool.toJsonObject());
}
}
JsonObject result = Json.createObjectBuilder()
.add("status", "success")
.add("count", tools.size())
.add("tools", toolsBuilder.build())
.build();
return Response.ok(result).build();
} catch (Exception e) {
logger.severe("Error testing tools: " + e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(Json.createObjectBuilder()
.add("error", "Failed to parse tools")
.add("message", e.getMessage())
.build())
.build();
}
}
/**
* Health check endpoint URL: /mcp/health
*/
@GET
@Path("/health")
public Response healthCheck() {
try {
List<MCPResource> resources = mcpService.parseResources();
List<MCPTool> tools = mcpService.parseTools();
JsonObject health = Json.createObjectBuilder()
.add("status", "healthy")
.add("timestamp", java.time.Instant.now().toString())
.add("server", "Dynamixs.AI MCP Server")
.add("version", "1.0.0")
.add("protocol", "MCP 2024-11-05")
.add("endpoint", getBaseUrl() + "mcp/v1")
.add("resources_count", resources.size())
.add("tools_count", tools.size())
.build();
return Response.ok(health).build();
} catch (Exception e) {
logger.severe("Health check failed: " + e.getMessage());
return Response.status(Response.Status.SERVICE_UNAVAILABLE)
.entity(Json.createObjectBuilder()
.add("status", "unhealthy")
.add("error", e.getMessage())
.build())
.build();
}
}
/**
* Builds comprehensive server information (MCP equivalent of A2A Agent Card)
*/
private JsonObject buildServerInfo() {
List<MCPResource> resources = mcpService.parseResources();
List<MCPTool> tools = mcpService.parseTools();
// Server capabilities
JsonObject capabilities = Json.createObjectBuilder()
.add("resources", Json.createObjectBuilder()
.add("subscribe", false)
.add("listChanged", false)
.build())
.add("tools", Json.createObjectBuilder().build())
.add("logging", Json.createObjectBuilder().build())
.build();
// Protocol information
JsonObject protocol = Json.createObjectBuilder()
.add("name", "Model Context Protocol")
.add("version", "2024-11-05")
.add("transport", "HTTP/JSON-RPC 2.0")
.build();
// Server metadata
JsonObject server = Json.createObjectBuilder()
.add("name", "Dynamixs.AI MCP Server")
.add("version", "1.0.0")
.add("description", "MCP server for Imixs-Workflow BPM platform")
.add("vendor", "Dynamixs.AI")
.add("platform", "Jakarta EE 10 / Imixs-Workflow")
.build();
// Endpoints
JsonObject endpoints = Json.createObjectBuilder()
.add("jsonrpc", getBaseUrl() + "mcp/v1")
.add("health", getBaseUrl() + "mcp/health")
.add("server_info", getBaseUrl() + "mcp/server-info")
.add("test_resources", getBaseUrl() + "mcp/test/resources")
.add("test_tools", getBaseUrl() + "mcp/test/tools")
.build();
// Statistics
JsonObject statistics = Json.createObjectBuilder()
.add("resources_available", resources.size())
.add("tools_available", tools.size())
.add("last_updated", java.time.Instant.now().toString())
.build();
// Resource summary
JsonArrayBuilder resourceSummary = Json.createArrayBuilder();
for (MCPResource resource : resources) {
if (resource.isValid()) {
resourceSummary.add(Json.createObjectBuilder()
.add("uri", resource.getUri())
.add("name", resource.getName())
.add("mimeType", resource.getMimeType() != null ? resource.getMimeType() : "text/plain")
.build());
}
}
// Tool summary
JsonArrayBuilder toolSummary = Json.createArrayBuilder();
for (MCPTool tool : tools) {
if (tool.isValid()) {
toolSummary.add(Json.createObjectBuilder()
.add("name", tool.getName())
.add("description", tool.getDescription())
.build());
}
}
// Build complete server info
return Json.createObjectBuilder()
.add("protocol", protocol)
.add("server", server)
.add("capabilities", capabilities)
.add("endpoints", endpoints)
.add("statistics", statistics)
.add("resource_summary", resourceSummary.build())
.add("tool_summary", toolSummary.build())
.build();
}
private String getBaseUrl() {
return uriInfo.getBaseUri().toString();
}
}

View file

@ -0,0 +1,283 @@
package ai.dynamixs.mcp;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import jakarta.json.Json;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;
/**
* Represents an MCP Tool based on Imixs-Workflow BPMN models.
*
* MCP Tools represent functions that can be called by the MCP client. Each tool
* corresponds to a workflow task/event combination.
*/
public class MCPTool implements Serializable {
private static final long serialVersionUID = 1L;
// MCP Standard Fields
private String name; // Tool name/identifier
private String description; // Tool description
private JsonObject inputSchema; // JSON Schema for input parameters
// Imixs-specific fields
private String modelVersion;
private int taskId;
private int eventId;
private List<String> tags;
private List<String> examples;
// Constructors
public MCPTool() {
this.tags = new ArrayList<>();
this.examples = new ArrayList<>();
}
public MCPTool(String modelVersion, int taskId, int eventId) {
this();
this.modelVersion = modelVersion;
this.taskId = taskId;
this.eventId = eventId;
this.name = createToolName(modelVersion, taskId, eventId);
}
/**
* Creates a tool name from Imixs workflow components
*/
public static String createToolName(String modelVersion, int taskId, int eventId) {
if (modelVersion == null || modelVersion.trim().isEmpty()) {
throw new IllegalArgumentException("Model version cannot be null or empty");
}
return String.format("%s_%d_%d", modelVersion.replace("-", "_"), taskId, eventId);
}
/**
* Parses model version from tool name
*/
public String getModelVersionFromName() {
if (name == null || !name.contains("_")) {
throw new IllegalStateException("Invalid tool name format: " + name);
}
return name.substring(0, name.lastIndexOf('_', name.lastIndexOf('_') - 1)).replace("_", "-");
}
/**
* Parses task ID from tool name
*/
public int getTaskIdFromName() {
if (name == null || !name.contains("_")) {
throw new IllegalStateException("Invalid tool name format: " + name);
}
String[] parts = name.split("_");
if (parts.length < 3) {
throw new IllegalStateException("Invalid tool name format: " + name);
}
try {
return Integer.parseInt(parts[parts.length - 2]);
} catch (NumberFormatException e) {
throw new IllegalStateException("Invalid task ID in tool name: " + name, e);
}
}
/**
* Parses event ID from tool name
*/
public int getEventIdFromName() {
if (name == null || !name.contains("_")) {
throw new IllegalStateException("Invalid tool name format: " + name);
}
String[] parts = name.split("_");
if (parts.length < 3) {
throw new IllegalStateException("Invalid tool name format: " + name);
}
try {
return Integer.parseInt(parts[parts.length - 1]);
} catch (NumberFormatException e) {
throw new IllegalStateException("Invalid event ID in tool name: " + name, e);
}
}
/**
* Creates a default input schema for workflow tools
*/
public JsonObject createDefaultInputSchema() {
return Json.createObjectBuilder()
.add("type", "object")
.add("properties", Json.createObjectBuilder()
.add("workitem", Json.createObjectBuilder()
.add("type", "object")
.add("description", "Workflow item data")
.add("properties", Json.createObjectBuilder()
.add("$modelversion", Json.createObjectBuilder()
.add("type", "string")
.add("description", "Workflow model version")
.build())
.add("$taskid", Json.createObjectBuilder()
.add("type", "integer")
.add("description", "Task ID")
.build())
.add("$eventid", Json.createObjectBuilder()
.add("type", "integer")
.add("description", "Event ID")
.build())
.build())
.add("required", Json.createArrayBuilder()
.add("$modelversion")
.add("$taskid")
.add("$eventid")
.build())
.build())
.build())
.add("required", Json.createArrayBuilder()
.add("workitem")
.build())
.build();
}
/**
* Converts this tool to MCP JSON format
*/
public JsonObject toJsonObject() {
JsonObjectBuilder builder = Json.createObjectBuilder()
.add("name", name != null ? name : "")
.add("description", description != null ? description : "");
// Input schema
if (inputSchema != null) {
builder.add("inputSchema", inputSchema);
} else {
builder.add("inputSchema", createDefaultInputSchema());
}
return builder.build();
}
/**
* Creates an MCPTool from a JsonObject
*/
public static MCPTool fromJsonObject(JsonObject jsonObject) {
MCPTool tool = new MCPTool();
tool.setName(jsonObject.getString("name", ""));
tool.setDescription(jsonObject.getString("description", ""));
if (jsonObject.containsKey("inputSchema")) {
tool.setInputSchema(jsonObject.getJsonObject("inputSchema"));
}
return tool;
}
/**
* Validates this tool for MCP compliance
*/
public boolean isValid() {
if (name == null || name.trim().isEmpty()) {
return false;
}
if (description == null || description.trim().isEmpty()) {
return false;
}
// Validate tool name format
try {
getModelVersionFromName();
getTaskIdFromName();
getEventIdFromName();
} catch (Exception e) {
return false;
}
return true;
}
// Getters and Setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public JsonObject getInputSchema() {
return inputSchema;
}
public void setInputSchema(JsonObject inputSchema) {
this.inputSchema = inputSchema;
}
public String getModelVersion() {
return modelVersion;
}
public void setModelVersion(String modelVersion) {
this.modelVersion = modelVersion;
}
public int getTaskId() {
return taskId;
}
public void setTaskId(int taskId) {
this.taskId = taskId;
}
public int getEventId() {
return eventId;
}
public void setEventId(int eventId) {
this.eventId = eventId;
}
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags != null ? tags : new ArrayList<>();
}
public List<String> getExamples() {
return examples;
}
public void setExamples(List<String> examples) {
this.examples = examples != null ? examples : new ArrayList<>();
}
@Override
public String toString() {
return String.format("MCPTool{name='%s', description='%s', modelVersion='%s', taskId=%d, eventId=%d}",
name, description, modelVersion, taskId, eventId);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
MCPTool that = (MCPTool) obj;
return name != null ? name.equals(that.name) : that.name == null;
}
@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
}

View file

@ -0,0 +1,30 @@
Imixs-Office-Workflow
Copyright (C) 2001-2018 Imixs Software Solutions GmbH,
http://www.imixs.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Project:
http://www.imixs.org
Contributors:
Imixs Software Solutions GmbH - initial API and implementation
Ralph Soika - Software Developer

View file

@ -0,0 +1,621 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd"
bean-discovery-mode="all" version="3.0">
</beans>

View file

@ -0,0 +1,10 @@
Imixs Workflow Technology
Copyright (C) 2010 Imixs Software Solutions GmbH,
http://www.imixs.com
Contributors:
Imixs Software Solutions GmbH - initial implementation
Ralph Soika

View file

@ -0,0 +1 @@
??

View file

@ -1,13 +0,0 @@
#!/bin/bash
############################################################
# Push build into imixs-cloud repo
#
############################################################
# build
./build.sh
# push
docker tag imixs/dynamixs-super-office:latest registry.tikal.imixs.com/imixs/dynamixs-super-office:latest
docker push registry.tikal.imixs.com/imixs/dynamixs-super-office:latest

840
pom.xml
View file

@ -1,433 +1,475 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ai.dynamixs</groupId>
<artifactId>dynamixs-super-office</artifactId>
<packaging>war</packaging>
<name>Dynamixs Super Office</name>
<version>1.0.0</version>
<description>Dynamixs Super Office - Internal </description>
<organization>
<name>Imixs Software Solutions GmbH</name>
<url>http://www.imixs.com</url>
</organization>
<inceptionYear>2025</inceptionYear>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ai.dynamixs</groupId>
<artifactId>dynamixs-ai</artifactId>
<modules>
<module>dynamixs-ai-app</module>
<module>dynamixs-ai-a2a</module>
<module>dynamixs-ai-mcp</module>
</modules>
<packaging>pom</packaging>
<name>Dynamixs AI</name>
<version>1.0.1</version>
<description>Dynamixs AI - The Hyper AI collaboration platform for enterprise business. </description>
<organization>
<name>Imixs Software Solutions GmbH</name>
<url>http://www.imixs.com</url>
</organization>
<inceptionYear>2019</inceptionYear>
<developers>
<developer>
<id>rsoika</id>
<name>Ralph Soika</name>
<email>ralph.soika@imixs.com</email>
<url>http://blog.imixs.org/</url>
<organization>Imixs Software Solutions GmbH</organization>
<organizationUrl>http://www.imixs.com</organizationUrl>
<roles>
<role>developer</role>
<role>testing</role>
</roles>
<timezone>2</timezone>
</developer>
<developer>
<id>gaheinle</id>
<name>Gaby Heinle</name>
<email />
<url />
<organization>Imixs Software Solutions GmbH</organization>
<organizationUrl>http://www.imixs.com</organizationUrl>
<roles>
<role>developer</role>
<role>testing</role>
</roles>
<timezone>2</timezone>
</developer>
</developers>
<properties>
<java.source>17</java.source>
<java.target>17</java.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<properties>
<java.source>17</java.source>
<java.target>17</java.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Wildfly -->
<custom.webResources>src/main/webapp</custom.webResources>
<custom.unpackTypes>war</custom.unpackTypes>
<!-- Wildfly -->
<custom.webResources>src/main/webapp</custom.webResources>
<custom.unpackTypes>war</custom.unpackTypes>
<!-- =========================================================
STEP 2: Set the Dynamixs.AI platform version you target.
Ask your Dynamixs.AI partner contact for the current version.
========================================================= -->
<ai.dynamixs.version>1.0.4-SNAPSHOT</ai.dynamixs.version>
<org.imixs.workflow.version>6.2.10-SNAPSHOT</org.imixs.workflow.version>
<org.imixs.office.version>5.1.12-SNAPSHOT</org.imixs.office.version>
<org.imixs.data.version>1.0.5-SNAPSHOT</org.imixs.data.version>
<org.imixs.adapter.version>3.2.5</org.imixs.adapter.version>
<org.imixs.security.version>3.0.2</org.imixs.security.version>
<!-- Build Time -->
<org.imixs.build.timestamp>${maven.build.timestamp}</org.imixs.build.timestamp>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
<jakarta.faces.project_stage>Production</jakarta.faces.project_stage>
<!-- Jakarta EE -->
<jakarta.version>10.0.0</jakarta.version>
<microprofile.version>6.0</microprofile.version>
<!-- Dependency Versions -->
<jakarta.version>10.0.0</jakarta.version>
<microprofile.version>6.0</microprofile.version>
<!-- The final WAR name - this will be the context root on Wildfly -->
<custom.applicationname>dynamixs-super-office</custom.applicationname>
</properties>
<org.imixs.workflow.version>6.2.5-SNAPSHOT</org.imixs.workflow.version>
<org.imixs.office.version>5.1.6-SNAPSHOT</org.imixs.office.version>
<org.imixs.data.version>1.0.2-SNAPSHOT</org.imixs.data.version>
<org.imixs.archive.version>3.1.5-SNAPSHOT</org.imixs.archive.version>
<org.imixs.marty.version>5.1.0</org.imixs.marty.version>
<org.imixs.adapter.version>3.2.2-SNAPSHOT</org.imixs.adapter.version>
<org.imixs.ai.version>1.1.5-SNAPSHOT</org.imixs.ai.version>
<org.imixs.metrics.version>1.0.0-SNAPSHOT</org.imixs.metrics.version>
<org.imixs.signature.version>1.0.0</org.imixs.signature.version>
<org.imixs.melman.version>2.1.1-SNAPSHOT</org.imixs.melman.version>
<org.imixs.security.version>3.0.1-SNAPSHOT</org.imixs.security.version>
<net.sf.saxon.version>9.9.1-4</net.sf.saxon.version>
<apache.pdfbox.version>2.0.24</apache.pdfbox.version>
<!-- test dependencies -->
<junit.jupiter.version>5.9.2</junit.jupiter.version>
<mockito.version>5.8.0</mockito.version>
<!-- =========================================================
Repositories
- Imixs SNAPSHOT artifacts are on Sonatype (public)
- Dynamixs.AI artifacts are on GitHub Packages (partner access required)
========================================================= -->
<repositories>
<repository>
<id>oss-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>github-dynamixs</id>
<name>Dynamixs.AI GitHub Packages</name>
<url>https://maven.pkg.github.com/dynamixs-ai/dynamixs-platform-repo</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<imixs-office.applicationname>dynamixs-ai</imixs-office.applicationname>
<!-- Environment Settings -->
<imixs-office.contextroot>/</imixs-office.contextroot>
<imixs-office.realm>imixsrealm</imixs-office.realm>
<imixs-office.jta-data-source>jdbc/office</imixs-office.jta-data-source>
<imixs-office.IndexDir>lucene/office-workflow-index</imixs-office.IndexDir>
<imixs-mail-res-ref-name>java:/mail/org.imixs.workflow.mail</imixs-mail-res-ref-name>
<profiles>
<profile>
<id>docker</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>install</phase>
<configuration>
<target>
<exec executable="docker">
<arg value="build" />
<arg value="-t" />
<arg value="imixs/${custom.applicationname}" />
<arg value="./" />
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Wildfly unpack war -->
<custom.unpackTypes>war</custom.unpackTypes>
<jakarta.faces.project_stage>Production</jakarta.faces.project_stage>
</plugins>
</build>
</profile>
<org.imixs.docker.registry>registry.tikal.imixs.com</org.imixs.docker.registry>
<profile>
<id>debug</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>install</phase>
<configuration>
<target>
<exec executable="docker">
<arg value="build" />
<arg value="-f" />
<arg value="./Dockerfile-debug" />
<arg value="-t" />
<arg value="imixs/${custom.applicationname}" />
<arg value="./." />
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</properties>
<repositories>
<repository>
<id>oss-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<profile>
<id>imixs-cloud</id>
<!-- Imixs Security OIDC -->
<dependencies>
<dependency>
<groupId>org.imixs.security</groupId>
<artifactId>imixs-oidc</artifactId>
<version>${org.imixs.security.version}</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.imixs.security</groupId>
<artifactId>imixs-oidc-marty</artifactId>
<version>${org.imixs.security.version}</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>install</phase>
<configuration>
<target>
<exec executable="docker">
<arg value="build" />
<arg value="-t" />
<arg value="imixs/${custom.applicationname}" />
<arg value="./" />
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>
<!-- =========================================================
Dynamixs.AI Platform Core
Contains all platform services, CDI beans, REST endpoints,
AI integration and workflow engine extensions.
========================================================= -->
<dependency>
<groupId>ai.dynamixs</groupId>
<artifactId>dynamixs-platform-core</artifactId>
<version>${ai.dynamixs.version}</version>
</dependency>
<!-- =========================================================
Dynamixs.AI Platform UI - WAR Overlay Base
This is the base web application. Your files in
src/main/webapp/ will override files from this WAR.
========================================================= -->
<dependency>
<groupId>ai.dynamixs</groupId>
<artifactId>dynamixs-platform-ui</artifactId>
<version>${ai.dynamixs.version}</version>
<type>war</type>
<scope>runtime</scope>
</dependency>
<!-- =========================================================
STEP 3: Add your customer-specific dependencies here.
Examples: ERP connectors, custom REST clients, etc.
This code is owned by your customer - not by Dynamixs.AI.
========================================================= -->
<!--
<dependency>
<groupId>com.acme</groupId>
<artifactId>sap-connector</artifactId>
<version>1.0.0</version>
</dependency>
-->
<!-- Jakarta EE API - provided by Wildfly at runtime -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>${jakarta.version}</version>
<scope>provided</scope>
</dependency>
<!-- Microprofile - provided by Wildfly at runtime -->
<dependency>
<groupId>org.eclipse.microprofile</groupId>
<artifactId>microprofile</artifactId>
<version>${microprofile.version}</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<profiles>
<!-- Imixs Workflow -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-core</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-engine</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-jax-rs</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-faces</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
<scope>provided</scope>
</dependency>
<profile>
<id>debug</id>
</profile>
<profile>
<id>imixs-cloud</id>
</profile>
</profiles>
<build>
<resources>
<!-- enable resource filtering for multi language version -->
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<!-- use JDK settings for compiling -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.source}</source>
<target>${java.target}</target>
</configuration>
</plugin>
<!-- Testing JUnit 5 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<!-- Imixs-Office-Workflow Overlay -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-office-workflow-util</artifactId>
<version>${org.imixs.office.version}</version>
<scope>provided</scope>
</dependency>
<!-- issue #572
hack for:
https://stackoverflow.com/questions/75116023/unable-to-make-protected-final-java-lang-class-java-lang-classloader-defineclass
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>default-test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<argLine>
--add-opens java.base/java.lang=ALL-UNNAMED
</argLine>
</configuration>
</execution>
</executions>
</plugin>
<!-- SEPA -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-sepa</artifactId>
<version>${org.imixs.adapter.version}</version>
</dependency>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<!-- DATEV -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-datev</artifactId>
<version>${org.imixs.adapter.version}</version>
</dependency>
</plugins>
<finalName>dynamixs-ai</finalName>
</build>
<dependencyManagement>
<dependencies>
<!-- Jakarta EE -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>${jakarta.version}</version>
<scope>provided</scope>
</dependency>
<!-- Microprofile -->
<dependency>
<groupId>org.eclipse.microprofile</groupId>
<artifactId>microprofile</artifactId>
<version>${microprofile.version}</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<!-- Imixs Workflow -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-core</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-engine</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-jax-rs</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-faces</artifactId>
<type>jar</type>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-index-lucene</artifactId>
<version>${org.imixs.workflow.version}</version>
</dependency>
<!-- Marty -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-marty</artifactId>
<type>jar</type>
<version>${org.imixs.marty.version}</version>
</dependency>
<!-- POI Adapter -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-poi</artifactId>
<version>${org.imixs.adapter.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-odf</artifactId>
<version>${org.imixs.adapter.version}</version>
</dependency>
<!-- Imixs-Archive -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-archive-api</artifactId>
<version>${org.imixs.archive.version}</version>
</dependency>
<!-- Imixs Metrics-->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-metrics-monitor</artifactId>
<version>${org.imixs.metrics.version}</version>
</dependency>
<!-- -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>${apache.pdfbox.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-data-groups</artifactId>
<version>${org.imixs.data.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-data-views</artifactId>
<version>${org.imixs.data.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-data-documents</artifactId>
<version>${org.imixs.data.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-data-importer</artifactId>
<version>${org.imixs.data.version}</version>
<scope>provided</scope>
</dependency>
<!-- Imixs-AI -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-ai-rag</artifactId>
<version>${org.imixs.ai.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-ai-workflow</artifactId>
<version>${org.imixs.ai.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-ai-bpmn</artifactId>
<version>${org.imixs.ai.version}</version>
</dependency>
</dependencies>
<build>
<finalName>${custom.applicationname}</finalName>
<!-- Imixs-QR-Code -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-qrcode</artifactId>
<version>${org.imixs.adapter.version}</version>
</dependency>
<plugins>
<!-- Use JDK settings for compiling -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.source}</source>
<target>${java.target}</target>
</configuration>
</plugin>
<!-- WAR Overlay: dynamixs-platform-ui is the base layer.
Files in src/main/webapp/ take precedence and override
anything from the base WAR. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<webResources>
<resource>
<filtering>true</filtering>
<!-- this is relative to the pom.xml directory -->
<directory>${custom.webResources}</directory>
<includes>
<include>**/WEB-INF/*</include>
<!-- include any other file types you want to filter -->
</includes>
</resource>
</webResources>
<!-- Imixs-Wopi -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-wopi</artifactId>
<version>${org.imixs.adapter.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-odf</artifactId>
<version>${org.imixs.adapter.version}</version>
</dependency>
<!-- We exclude libs form the parent WAR artifact
<workDirectory>target/overlay-war-folder</workDirectory>
<overlays>
<overlay>
<groupId>ai.dynamixs</groupId>
<artifactId>dynamixs-platform-ui</artifactId>
<excludes>
<exclude>WEB-INF/lib/*.jar</exclude>
</excludes>
</overlay>
</overlays>
-->
</configuration>
</plugin>
<!-- Hot deployment to local Wildfly Docker instance -->
<plugin>
<groupId>org.imixs.maven</groupId>
<artifactId>manik-hotdeploy-maven-plugin</artifactId>
<version>2.0.0</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
<configuration>
<autodeployments>
<deployment>
<source>target/*.{war,ear,jar}</source>
<target>docker/deployments/</target>
<unpack>true</unpack>
</deployment>
</autodeployments>
<hotdeployments>
<deployment>
<source>src/main/webapp</source>
<target>docker/deployments/${custom.applicationname}.war</target>
</deployment>
</hotdeployments>
</configuration>
</plugin>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-melman</artifactId>
<version>${org.imixs.melman.version}</version>
<scope>compile</scope>
</dependency>
</plugins>
</build>
<!-- SEPA -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-sepa</artifactId>
<version>${org.imixs.adapter.version}</version>
</dependency>
<!-- DATEV -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-datev</artifactId>
<version>${org.imixs.adapter.version}</version>
</dependency>
<!-- POI Adapter -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-poi</artifactId>
<version>${org.imixs.adapter.version}</version>
</dependency>
<!-- Imixs Data -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-data-groups</artifactId>
<version>${org.imixs.data.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-data-views</artifactId>
<version>${org.imixs.data.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-data-documents</artifactId>
<version>${org.imixs.data.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-data-importer</artifactId>
<version>${org.imixs.data.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Jakarta EE -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>${jakarta.version}</version>
<scope>provided</scope>
</dependency>
<!-- Microprofile -->
<dependency>
<groupId>org.eclipse.microprofile</groupId>
<artifactId>microprofile</artifactId>
<version>${microprofile.version}</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<!-- Testing -->
<!-- JUnit 5 Dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<!-- Mockito Dependencies -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>org.eclipse.parsson</groupId>
<artifactId>jakarta.json</artifactId>
<version>1.1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
<!-- JSON-B Implementation for Tests -->
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>3.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.json</artifactId>
<version>2.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-jaxb</artifactId>
<version>3.1.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>3.1.5</version>
<scope>test</scope>
</dependency>
<!-- HTTP Client -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

File diff suppressed because one or more lines are too long

View file

@ -1,130 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY bdquo "" ><!ENTITY quot "" ><!ENTITY uuml "ü" ><!ENTITY auml "ä" ><!ENTITY ouml "ö" ><!ENTITY Uuml "Ü" ><!ENTITY Auml "Ä" ><!ENTITY Ouml "Ö" ><!ENTITY szlig "ß" ><!ENTITY nbsp " " ><!ENTITY lt "" >
<!ENTITY gt "" >]><xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output method="html" media-type="text/html" indent="no"
encoding="UTF-8" /> <xsl:decimal-format
name="euro" decimal-separator="," grouping-separator="." /> <xsl:variable
name="currenttime" select="current-dateTime()" /> <xsl:template
match="/"> <html> <head> <meta name="viewport"
content="width=device-width" /> <meta
http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Imixs
Software Solutions GmbH</title> <link
href="../../layout/css/imixs-basic.css" charset="UTF-8" type="text/css" rel="stylesheet" /> <link
href="../../layout/css/imixs-layout.css" charset="UTF-8" type="text/css" rel="stylesheet" /> <link
href="../../layout/css/office-theme-print.css" charset="UTF-8" type="text/css" rel="stylesheet"
/> <link
href="../../layout/css/custom.css" charset="UTF-8" type="text/css" rel="stylesheet" /> <link
href="../../custom-print.css" charset="UTF-8" type="text/css" rel="stylesheet" /> <style>
.toolbar.branding { font-size:1.75rem; } h2 { font-size:1.7em; } .small { font-size:65%; }
#imixs-content { padding:10px; } #header { background-color: #FFF; color: #333; border-bottom:
1px solid #333; padding:0; } .imixs-requirement { margin-top:20px; margin-bottom:40px; }
.imixs-requirement h4 { border-bottom: 1px solid #333; } .imixs-table { width: 100%;
margin-bottom:4em; } @media print { body {font-size:0.66em;} } </style> </head> <body> <!--
content --> <div
id="container"> <div id="imixs-content"> <!-- generate
Header --> <xsl:apply-templates
select="/data/document[normalize-space(item[@name = '$workflowgroup'
] /value) = 'Auftrag']" /> <!-- body -->
<xsl:apply-templates
select="/data/document[normalize-space(item[@name = '$workflowgroup']/value) = 'Requirement']" />
</div>
</div>
</body>
</html>
</xsl:template> <!--
Header Template -->
<xsl:template
match="/data/document[normalize-space(item[@name = '$workflowgroup']/value) = 'Auftrag']">
<div id="header">
<div id="imixs-servicenav">
<div class="toolbar branding" style="float:left;">
<span> Auftrag - <xsl:value-of select="item[@name='numsequencenumber']/value" />
</span>
</div>
<div style="font-size:12px;float:right"> DYNAMIXS.AI GmbH - <br /> Frei-Otto-Str. 4 -
80797 München <br /> Tel.: +49 (0)89 / 45 21 36-0 </div>
</div>
</div>
<div>
<h2>
<xsl:value-of select="item[@name='_subject']/value" />
</h2>
<h3>Requirements Completed: <xsl:value-of
select="format-dateTime($currenttime, '[D01].[M01].[Y0001]')"></xsl:value-of></h3>
</div>
</xsl:template> <!--
Body Template -->
<xsl:template
match="/data/document[normalize-space(item[@name = '$workflowgroup']/value) = 'Requirement']">
<xsl:variable name="eventDate" select="item[@name='$lasteventdate']/value" />
<xsl:variable name="effortPlaned" select="item[@name='_effort_planed']/value" />
<xsl:variable name="capacity" select="item[@name='_capacity']/value" />
<div class="imixs-requirement">
<h4>
<xsl:value-of select="item[@name='_subject']/value" />
<span class="small" style="float:right;"> Stand: <xsl:value-of
select="format-dateTime($eventDate, '[D01].[M01].[Y0001]')"></xsl:value-of>
</span>
</h4>
<p>
<xsl:value-of select="item[@name='_description']/value" disable-output-escaping="yes" />
</p>
</div> <!--
efforts -->
<table class="imixs-table">
<thead>
<tr>
<th style="width:10px;">Datum</th>
<th>Leistungsbezeichnung</th>
<th style="width:80px;">Stunden</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="item[@name='_childitems']/value">
<tr>
<td style="text-align: center;">
<xsl:value-of
select="format-dateTime(item[@name='datdate']/value, '[D01].[M01].[Y0001]')" />
</td>
<td>
<xsl:value-of select="item[@name='name']/value" />
</td>
<td style="text-align: right;">
<xsl:value-of select="item[@name='amount']/value" />
</td>
</tr>
</xsl:for-each> <!--
Summe -->
</tbody>
<tfoot>
<tr>
<td></td>
<td style="text-align: right;">
<strong>Summe:</strong>
</td>
<td style="text-align: right;">
<xsl:value-of select="item[@name='_capacity']/value" />
</td>
</tr>
<tr>
<td></td>
<td style="text-align: right;">
<strong>Plan:</strong>
</td>
<td style="text-align: right;">
<xsl:value-of select="item[@name='_effort_planed']/value" />
</td>
</tr>
<tr>
<td></td>
<td style="text-align: right;">
<strong>Prozent:</strong>
</td>
<td style="text-align: right;">
<xsl:value-of select="item[@name='_effort_div']/value" /> % </td>
</tr>
</tfoot>
</table>
</xsl:template>
</xsl:stylesheet>

File diff suppressed because one or more lines are too long

View file

@ -1,133 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY bdquo "" ><!ENTITY quot "" ><!ENTITY uuml "ü" ><!ENTITY auml "ä" ><!ENTITY ouml "ö" ><!ENTITY Uuml "Ü" ><!ENTITY Auml "Ä" >
<!ENTITY Ouml "Ö" ><!ENTITY szlig "ß" ><!ENTITY nbsp " " ><!ENTITY lt "" ><!ENTITY gt "" >
]>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output method="html" media-type="text/html" indent="no" encoding="UTF-8" />
<xsl:decimal-format name="euro" decimal-separator="," grouping-separator="." />
<xsl:variable name="currenttime" select="current-dateTime()" />
<xsl:template match="/">
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Imixs Software Solutions GmbH</title>
<link href="../../layout/css/imixs-basic.css" charset="UTF-8" type="text/css"
rel="stylesheet" />
<link href="../../layout/css/imixs-layout.css" charset="UTF-8" type="text/css"
rel="stylesheet" />
<link href="../../layout/css/office-theme-print.css" charset="UTF-8" type="text/css"
rel="stylesheet" />
<link href="../../layout/css/custom.css" charset="UTF-8" type="text/css"
rel="stylesheet" />
<link href="../../custom-print.css" charset="UTF-8" type="text/css" rel="stylesheet" />
<style> .toolbar.branding { font-size:1.75rem; } h2 { font-size:1.7em; } .small { font-size:65%; } #imixs-content { padding:10px; } #header { background-color: #FFF; color: #333; border-bottom: 1px solid #333; padding:0; } .imixs-requirement { margin-top:20px; margin-bottom:40px; } .imixs-requirement h4 { border-bottom: 1px solid #333; } .imixs-table { width: 100%; margin-bottom:4em; } @media print { body {font-size:0.66em;} } </style>
</head>
<body> <!-- content -->
<div id="container">
<div id="imixs-content"> <!-- generate Header -->
<xsl:apply-templates
select="/data/document[normalize-space(item[@name = '$workflowgroup']/value) = 'Auftrag']" /> <!--
body -->
<xsl:apply-templates
select="/data/document[normalize-space(item[@name = '$workflowgroup']/value) = 'Requirement']" />
</div>
</div>
</body>
</html>
</xsl:template> <!--
Header Template -->
<xsl:template
match="/data/document[normalize-space(item[@name = '$workflowgroup']/value) = 'Auftrag']">
<div id="header">
<div id="imixs-servicenav">
<div class="toolbar branding" style="float:left;">
<span> Auftrag - <xsl:value-of select="item[@name='numsequencenumber']/value" />
</span>
</div>
<div style="font-size:12px;float:right"> DYNAMIXS.AI GmbH - <br /> Frei-Otto-Str. 4
- 80797 München <br /> Tel.: +49 (0)89 / 45 21 36-0 </div>
</div>
</div> <div>
<h2>
<xsl:value-of select="item[@name='_subject']/value" />
</h2>
<h3>Requirements in Umsetzung: <xsl:value-of
select="format-dateTime($currenttime, '[D01].[M01].[Y0001]')"></xsl:value-of></h3>
</div>
</xsl:template> <!--
Body Template -->
<xsl:template
match="/data/document[normalize-space(item[@name = '$workflowgroup']/value) = 'Requirement']">
<xsl:variable name="eventDate" select="item[@name='$lasteventdate']/value" /> <xsl:variable
name="effortPlaned" select="item[@name='_effort_planed']/value" /> <xsl:variable
name="capacity" select="item[@name='_capacity']/value" /> <div class="imixs-requirement">
<h4>
<xsl:value-of select="item[@name='_subject']/value" />
<span class="small" style="float:right;"> Stand: <xsl:value-of
select="format-dateTime($eventDate, '[D01].[M01].[Y0001]')"></xsl:value-of>
</span>
</h4>
<p>
<xsl:value-of select="item[@name='_description']/value"
disable-output-escaping="yes" />
</p>
</div> <!-- efforts --> <table
class="imixs-table">
<thead>
<tr>
<th style="width:120px;">Datum</th>
<th>Leistungsbezeichnung</th>
<th style="width:120px;">Stunden</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="item[@name='_childitems']/value">
<tr>
<td style="text-align: center;">
<xsl:value-of
select="format-dateTime(item[@name='datdate']/value, '[D01].[M01].[Y0001]')" />
</td>
<td>
<xsl:value-of select="item[@name='name']/value" />
</td>
<td style="text-align: right;">
<xsl:value-of select="item[@name='amount']/value" />
</td>
</tr>
</xsl:for-each> <!--
Summe -->
</tbody>
<tfoot>
<tr>
<td></td>
<td style="text-align: right;">
<strong>Summe:</strong>
</td>
<td style="text-align: right;">
<xsl:value-of select="item[@name='_capacity']/value" />
</td>
</tr>
<tr>
<td></td>
<td style="text-align: right;">
<strong>Plan:</strong>
</td>
<td style="text-align: right;">
<xsl:value-of select="item[@name='_effort_planed']/value" />
</td>
</tr>
<tr>
<td></td>
<td style="text-align: right;">
<strong>Prozent:</strong>
</td>
<td style="text-align: right;">
<xsl:value-of select="item[@name='_effort_div']/value" /> % </td>
</tr>
</tfoot>
</table>
</xsl:template>
</xsl:stylesheet>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><document xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><item name="attributes"><value xsi:nil="true"/></item><item name="encoding"><value xsi:type="xs:string"></value></item><item name="txtname"><value xsi:type="xs:string">requirements-planning</value></item><item name="txtquery"><value xsi:type="xs:string">($uniqueid:"{id}")
OR
($workflowgroup:"Requirement"
AND ($workitemref:"{id}" OR txtworkitemref:"{id}")
AND $taskid:2010
)
</value></item><item name="xsl"><value xsi:type="xs:string">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;&lt;!DOCTYPE xsl:stylesheet [&lt;!ENTITY bdquo "" &gt;&lt;!ENTITY quot "" &gt;&lt;!ENTITY uuml "ü" &gt;&lt;!ENTITY auml "ä" &gt;&lt;!ENTITY ouml "ö" &gt;&lt;!ENTITY Uuml "Ü" &gt;&lt;!ENTITY Auml "Ä" &gt;&lt;!ENTITY Ouml "Ö" &gt;&lt;!ENTITY szlig "ß" &gt;&lt;!ENTITY nbsp " " &gt;&lt;!ENTITY lt "" &gt;&lt;!ENTITY gt "" &gt;]&gt;&lt;xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"&gt; &lt;xsl:output method="html" media-type="text/html" indent="no" encoding="UTF-8" /&gt; &lt;xsl:decimal-format name="euro" decimal-separator="," grouping-separator="." /&gt; &lt;xsl:variable name="currenttime" select="current-dateTime()" /&gt; &lt;xsl:template match="/"&gt; &lt;html&gt; &lt;head&gt; &lt;meta name="viewport" content="width=device-width" /&gt; &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt; &lt;title&gt;Imixs Software Solutions GmbH&lt;/title&gt; &lt;link href="../../layout/css/imixs-basic.css" charset="UTF-8" type="text/css" rel="stylesheet" /&gt; &lt;link href="../../layout/css/imixs-layout.css" charset="UTF-8" type="text/css" rel="stylesheet" /&gt; &lt;link href="../../layout/css/office-theme-print.css" charset="UTF-8" type="text/css" rel="stylesheet" /&gt; &lt;link href="../../layout/css/custom.css" charset="UTF-8" type="text/css" rel="stylesheet" /&gt; &lt;link href="../../custom-print.css" charset="UTF-8" type="text/css" rel="stylesheet" /&gt; &lt;style&gt; .toolbar.branding { font-size:1.75rem; } h2 { font-size:1.7em; } .small { font-size:65%; } #imixs-content { padding:10px; } #header { background-color: #FFF; color: #333; border-bottom: 1px solid #333; padding:0; } .imixs-requirement { margin-top:20px; margin-bottom:40px; } .imixs-requirement h4 { border-bottom: 1px solid #333; } .imixs-table { width: 100%; margin-bottom:4em; } @media print { body {font-size:0.66em;} } &lt;/style&gt; &lt;/head&gt; &lt;body&gt; &lt;!-- content --&gt; &lt;div id="container"&gt; &lt;div id="imixs-content"&gt; &lt;!-- generate Header --&gt; &lt;xsl:apply-templates select="/data/document[normalize-space(item[@name = '$workflowgroup']/value) = 'Auftrag']" /&gt; &lt;!-- body --&gt; &lt;xsl:apply-templates select="/data/document[normalize-space(item[@name = '$workflowgroup']/value) = 'Requirement']" /&gt; &lt;/div&gt; &lt;/div&gt; &lt;/body&gt; &lt;/html&gt; &lt;/xsl:template&gt; &lt;!-- Header Template --&gt; &lt;xsl:template match="/data/document[normalize-space(item[@name = '$workflowgroup']/value) = 'Auftrag']"&gt; &lt;div id="header"&gt; &lt;div id="imixs-servicenav"&gt; &lt;div class="toolbar branding" style="float:left;"&gt; &lt;span&gt; Auftrag - &lt;xsl:value-of select="item[@name='numsequencenumber']/value" /&gt; &lt;/span&gt; &lt;/div&gt; &lt;div style="font-size:12px;float:right"&gt; Imixs Software Solutions GmbH - &lt;br /&gt; Agnes-Pockels-Bogen 1 - 80992 München &lt;br /&gt; Tel.: +49 (0)89 / 45 21 36-0 &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;div&gt; &lt;h2&gt; &lt;xsl:value-of select="item[@name='_subject']/value" /&gt; &lt;/h2&gt; &lt;h3&gt;Requirements in Planung: &lt;xsl:value-of select="format-dateTime($currenttime, '[D01].[M01].[Y0001]')"&gt;&lt;/xsl:value-of&gt;&lt;/h3&gt; &lt;/div&gt; &lt;/xsl:template&gt; &lt;!-- Body Template --&gt; &lt;xsl:template match="/data/document[normalize-space(item[@name = '$workflowgroup']/value) = 'Requirement']"&gt; &lt;xsl:variable name="eventDate" select="item[@name='$lasteventdate']/value" /&gt; &lt;div class="imixs-requirement"&gt; &lt;h4&gt; &lt;xsl:value-of select="item[@name='_subject']/value" /&gt; &lt;span class="small" style="float:right;"&gt; Stand: &lt;xsl:value-of select="format-dateTime($eventDate, '[D01].[M01].[Y0001]')"&gt;&lt;/xsl:value-of&gt; &lt;/span&gt; &lt;/h4&gt; &lt;p&gt; &lt;xsl:value-of select="item[@name='_description']/value" disable-output-escaping="yes" /&gt; &lt;/p&gt; &lt;p&gt; &lt;strong&gt;Aufwand geplant: &lt;/strong&gt;&lt;xsl:value-of select="item[@name='_effort_planed']/value" /&gt; Stunden &lt;/p&gt; &lt;/div&gt; &lt;/xsl:template&gt;&lt;/xsl:stylesheet&gt;</value></item><item name="xslresource"><value xsi:type="xs:string">/imixs-super-office/src/reports/requirements-planning.xsl</value></item></document>

View file

@ -1,85 +0,0 @@
package ai.dynamixs;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.imixs.archive.core.SnapshotService;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.poi.POIFindReplaceAdapter;
import org.imixs.workflow.poi.XSSFUtil;
import jakarta.inject.Inject;
/**
* Dieser Adapter erweitert den POIFindReplaceAdapter und fügt in das
* Rechnungsformular zusätzliche Zeilen ein
*/
public class InvoicePOIAdapter extends POIFindReplaceAdapter {
private static Logger logger = Logger.getLogger(InvoicePOIAdapter.class.getName());
@Inject
WorkflowService workflowService;
@Inject
DocumentService documentService;
public static final String ERROR_CONFIG = "CONFIG_ERROR";
final String TYPE_TEXTBLOCK = "textblock";
@Inject
SnapshotService snapshotService;
@Override
public void updateXSSFWorkbook(XSSFWorkbook workbook, ItemCollection workitem, List<String> replaceDevList,
String eval) throws PluginException {
XSSFSheet sheet = workbook.getSheetAt(0);
// Steuer?
int steuer = workitem.getItemValueInteger("invoice.tax.rate");
if (steuer > 0) {
XSSFUtil.replaceXSSFSheetItemValue(workbook, sheet, "TAX_INFO", "Umsatzsteuer: ");
}
Double steuerD = (double) steuer / 100;
XSSFUtil.replaceXSSFSheetItemValue(workbook, sheet, "TAX_RATE", steuerD);
// insert invoice pos...
ItemCollection auftrag = documentService.load(workitem.getItemValueString("$workitemref"));
List<ItemCollection> requirements = new ArrayList<ItemCollection>();
List<String> refs = workitem.getItemValueList("_requirements", String.class);
for (String _id : refs) {
requirements.add(documentService.load(_id));
}
int pos = 1;
for (ItemCollection _requirement : requirements) {
int line = pos + 23;
XSSFUtil.replaceXSSFSheetItemValue(workbook, sheet, "A" + line, pos);
XSSFUtil.replaceXSSFSheetItemValue(workbook, sheet, "B" + line,
_requirement.getItemValueString("_subject"));
double rate = auftrag.getItemValueDouble("_rate");
double capacity = _requirement.getItemValueDouble("_capacity");
XSSFUtil.replaceXSSFSheetItemValue(workbook, sheet, "E" + line, rate);
XSSFUtil.replaceXSSFSheetItemValue(workbook, sheet, "F" + line, capacity);
XSSFUtil.evalXSSFSheet(workbook, sheet, "G" + line);
pos++;
}
super.updateXSSFWorkbook(workbook, workitem, replaceDevList, eval);
}
}

View file

@ -1,74 +0,0 @@
package com.imixs.intern;
import java.util.List;
import java.util.logging.Logger;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.exceptions.AccessDeniedException;
import org.imixs.workflow.faces.data.ViewController;
import org.imixs.workflow.faces.data.WorkflowController;
import org.imixs.workflow.faces.data.WorkflowEvent;
import org.imixs.workflow.faces.util.LoginController;
import org.imixs.workflow.office.forms.WorkitemLinkController;
import jakarta.annotation.Priority;
import jakarta.enterprise.context.RequestScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.inject.Named;
/**
* Dieser AuftragController hat nur den Zweck eine MIgration des neuen feldes
* contact.ref durchzuführen
*
*/
@Named
@RequestScoped
public class AuftragController extends ViewController {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(AuftragController.class.getName());
@Inject
LoginController loginController;
@Inject
WorkflowController workflowController;
@Inject
WorkitemLinkController workitemLinkController;
/**
* Diese Hilfsmethode sortiert die Requirements nach Datum.
*
* @param workflowEvent
* @throws AccessDeniedException
*/
public void onWorkflowEvent(@Observes @Priority(value = 1) WorkflowEvent workflowEvent)
throws AccessDeniedException {
ItemCollection workitem = workflowEvent.getWorkitem();
if (workitem == null) {
return;
}
if (workflowEvent.getEventType() == WorkflowEvent.WORKITEM_CHANGED) {
// skip if already defined
if (!workitem.getItemValueString("contact.ref").isEmpty()) {
return;
}
// check all refs...
List<ItemCollection> references = workitemLinkController.getReferences();
for (ItemCollection reference : references) {
if ("Kontakt".equals(reference.getWorkflowGroup())) {
workitem.setItemValue("contact.ref", reference.getUniqueID());
// Erledigt! :-)
return;
}
}
}
}
}

View file

@ -1,62 +0,0 @@
package com.imixs.intern;
import java.util.List;
import java.util.logging.Logger;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.SignalAdapter;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.exceptions.AccessDeniedException;
import org.imixs.workflow.exceptions.AdapterException;
import org.imixs.workflow.exceptions.ModelException;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.exceptions.ProcessingErrorException;
import org.imixs.workflow.odf.ODFDOMFindReplaceAdapter;
import jakarta.inject.Inject;
/**
* Der RechnungsAdapterComplete wird eingesetzt wenn eine Rechnung geprüft
* wurde. Dann werden alle Requirement Positionen auf 'Invoiced' gesetzt.
*
* Zusätzlich erzeugt der Adapter die Child Item Buchungszeile
*
*/
public class RechnungsAdapterFinish implements SignalAdapter {
private static Logger logger = Logger.getLogger(RechnungsAdapterFinish.class.getName());
@Inject
WorkflowService workflowService;
/**
* Executes all
* requriements with 2300.20**@throws PluginException
*/
@Override
public ItemCollection execute(ItemCollection workitem, ItemCollection event)
throws AdapterException, PluginException {
logger.info("Finish Imixs Rechnung....");
List<String> refs = workitem.getItemValueList("_requirements", String.class);
for (String _id : refs) {
try {
ItemCollection _requirement = workflowService.getDocumentService().load(_id);
if (_requirement.getTaskID() == 2300) {
workflowService.processWorkItem(_requirement, 20);
}
} catch (AccessDeniedException | ProcessingErrorException | ModelException e) {
throw new PluginException(ODFDOMFindReplaceAdapter.class.getSimpleName(), "UPDATE_ERROR",
"Failed to update Requirements : " + e.getMessage());
}
}
// copyRechnungssumme();
return workitem;
}
private void copyRechnungssumme() {
}
}

View file

@ -1,129 +0,0 @@
package com.imixs.intern;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.odf.ODFDOMFindReplaceAdapter;
import org.odftoolkit.odfdom.doc.OdfDocument;
import org.odftoolkit.odfdom.doc.table.OdfTable;
import org.odftoolkit.odfdom.doc.table.OdfTableRow;
import org.odftoolkit.odfdom.incubator.search.InvalidNavigationException;
import jakarta.inject.Inject;
/**
* Dieser Adapter erweitert den ODFDOMFindReplaceAdapter und fügt in das
* Rechnungsformular zusätzliche Zeilen ein
*/
public class RechnungsAdapterODF extends ODFDOMFindReplaceAdapter {
private static Logger logger = Logger.getLogger(ODFDOMFindReplaceAdapter.class.getName());
@Inject
WorkflowService workflowService;
@Inject
DocumentService documentService;
/**
* Updates a SpreadSheet Document
*
* Load all needed workitems....
*
* @param odfDoc
* @param workitem
* @param replaceDevList
* @throws PluginException
* @throws InvalidNavigationException
*/
@Override
public void updateODFDocument(OdfDocument odfDoc, ItemCollection workitem, List<String> replaceDevList)
throws PluginException, InvalidNavigationException {
String subject;
super.updateODFDocument(odfDoc, workitem, replaceDevList);
logger.info("Update Imixs Rechnung....");
// Load all needed workitems....
ItemCollection auftrag = documentService.load(workitem.getItemValueString("$workitemref"));
subject = auftrag.getItemValueString("_subject");
List<ItemCollection> requirements = new ArrayList<ItemCollection>();
List<String> refs = workitem.getItemValueList("_requirements", String.class);
for (String _id : refs) {
requirements.add(documentService.load(_id));
}
// find Kontakt
ItemCollection kontakt = null;
refs = auftrag.getItemValueList("$workitemref", String.class);
for (String _id : refs) {
ItemCollection _workitem = documentService.load(_id);
if (_workitem != null && "Kontakt".equals(_workitem.getItemValueString("$workflowgroup"))) {
kontakt = _workitem;
break;
}
}
// find row..
OdfTable tbl = odfDoc.getTableList().get(0);
// Update Address
if (kontakt != null) {
tbl.getCellByPosition("A7").setStringValue(kontakt.getItemValueString("_subject"));
tbl.getCellByPosition("A8").setStringValue(kontakt.getItemValueString("_address"));
tbl.getCellByPosition("A10")
.setStringValue(kontakt.getItemValueString("_zip") + " " + kontakt.getItemValueString("_city"));
tbl.getCellByPosition("A11").setStringValue(kontakt.getItemValueString("_country"));
}
// Update Auftrag
if (auftrag != null) {
tbl.getCellByPosition("G21").setStringValue(auftrag.getItemValueString("numsequencenumber"));
tbl.getCellByPosition("C21").setStringValue(auftrag.getItemValueString("_ordernumber"));
// update email if not defined
if (workitem.getItemValueString("invoice.email").isEmpty()) {
workitem.cloneItem("invoice.email", auftrag);
}
}
// Requirements
List<OdfTableRow> newRows = tbl.insertRowsBefore(24, requirements.size() - 1);
int pos = 1;
int line = 0;
for (ItemCollection _requirement : requirements) {
OdfTableRow newRow = tbl.getRowByIndex(22 + pos);
line = pos + 23;
newRow.getCellByIndex(0).setStringValue(pos + "");
newRow.getCellByIndex(1).setStringValue(_requirement.getItemValueString("_subject"));
newRow.getCellByIndex(4).setDoubleValue(auftrag.getItemValueDouble("_rate"));
newRow.getCellByIndex(5).setDoubleValue(_requirement.getItemValueDouble("_capacity"));
// set formular
newRow.getCellByIndex(6).setFormula("=E" + (line) + "*F" + (line));
pos++;
}
// Update Summary Formulars....
// line = 24;
// String formel = "=";
// for (ItemCollection _requirement : requirements) {
// formel = formel + "G" + line + "+";
// line++;
// }
// formel = formel.substring(0, formel.length() - 1);
// line = 25 + requirements.size();
// tbl.getCellByPosition("G" + (line)).setFormula(formel);
// line++;
// line++;
// tbl.getCellByPosition("G" + (line)).setFormula("=G" + (line - 2) + "+G" +
// (line - 1));
}
}

View file

@ -1,119 +0,0 @@
package com.imixs.intern;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Logger;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.ItemCollectionComparator;
import org.imixs.workflow.exceptions.AccessDeniedException;
import org.imixs.workflow.exceptions.QueryException;
import org.imixs.workflow.faces.data.ViewController;
import org.imixs.workflow.faces.data.WorkflowController;
import org.imixs.workflow.faces.data.WorkflowEvent;
import org.imixs.workflow.faces.util.LoginController;
import org.imixs.workflow.office.forms.ChildItemController;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Priority;
import jakarta.enterprise.event.Observes;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
@Named
@ViewScoped
public class RequirementsViewController extends ViewController {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(RequirementsViewController.class.getName());
@Inject
LoginController loginController;
@Inject
WorkflowController workflowController;
@Inject
ChildItemController childItemController;
@Override
@PostConstruct
public void init() {
super.init();
String id = "-1";
if (workflowController.getWorkitem() != null) {
id = workflowController.getWorkitem().getUniqueID();
}
this.setQuery(
"($workflowgroup:\"Requirement\") AND (type:\"workitem\" OR type:\"workitemarchive\") AND ($workitemref:\""
+ id + "\" OR txtworkitemref:\"" + id + "\")");
this.setSortBy("$taskid");
this.setSortReverse(false);
this.setPageSize(999);
this.setLoadStubs(false);
}
/**
* Compute summary....
*/
@Override
public List<ItemCollection> loadData() throws QueryException {
List<ItemCollection> result = super.loadData();
float capa = 0;
float plan = 0;
for (ItemCollection orderitem : result) {
// skip canceled entries
if (2900 == orderitem.getTaskID()) {
continue;
}
capa = capa + orderitem.getItemValueFloat("_capacity");
plan = plan + orderitem.getItemValueFloat("_effort_planed");
}
workflowController.getWorkitem().replaceItemValue("_capacity", capa);
workflowController.getWorkitem().replaceItemValue("_effort_planed", plan);
workflowController.getWorkitem().replaceItemValue("_effort_div", Float.valueOf((capa / plan) * 100));
// sort result by task and creation date
result.sort(Comparator
.comparingInt((ItemCollection item) -> item.getItemValueInteger("$taskid"))
.thenComparing(item -> item.getItemValueDate("$created"), Comparator.reverseOrder()));
return result;
}
/**
* Diese Hilfsmethode sortiert die Requirements nach Datum.
*
* @param workflowEvent
* @throws AccessDeniedException
*/
public void onWorkflowEvent(@Observes @Priority(value = 1) WorkflowEvent workflowEvent)
throws AccessDeniedException {
int eventType = workflowEvent.getEventType();
ItemCollection workitem = workflowEvent.getWorkitem();
if (workitem == null) {
return;
}
// nur reagieren wenn wir in einem Requirement oder bei Werksstudenten sind!
if ("Requirement".equals(workitem.getWorkflowGroup()) || "Werksstudent".equals(workitem.getWorkflowGroup())) {
// before the workitem is saved we sort the list by date
if (WorkflowEvent.WORKITEM_BEFORE_PROCESS == eventType
&& childItemController.getChildItems() != null) {
logger.info("...sorting requirement/effort list...");
Collections.sort(childItemController.getChildItems(), new ItemCollectionComparator("datdate", false));
}
}
}
}

View file

@ -1,175 +0,0 @@
package com.imixs.intern;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.plugins.AbstractPlugin;
import org.imixs.workflow.exceptions.PluginException;
/**
* Dieses Plugin berechnet die gebuchten Stunden pro tag und woche
*
* @author rsoika
*
*/
public class StatistikPlugin extends AbstractPlugin {
private String[] ignoreList = { "administration-np" };
private static Logger logger = Logger.getLogger(StatistikPlugin.class
.getName());
/**
*
*
* Skip if not a workitem and only run once a day!
*
* @throws PluginException
*
**/
@SuppressWarnings("unchecked")
@Override
public ItemCollection run(ItemCollection workitem, ItemCollection documentActivity) throws PluginException {
List<String> ignoreArrayList = Arrays.asList(ignoreList);
// skip if the workitem is from a different type (for example Teams
// may not be processed by this plugin)
String type = workitem.getItemValueString("type");
if (!type.equals("workitem"))
return workitem;
// lauf nur in workflow modell imixs-de
// und nur 9000.100
int processID = workitem.getItemValueInteger("$Processid");
int activityID = documentActivity.getItemValueInteger("numActivityID");
String model = workitem.getItemValueString("$ModelVersion");
if (!(processID == 9000 && activityID == 100 && model.startsWith("imixs-de")))
return workitem;
// sind wir heute schon gelaufen?
Calendar calToday = Calendar.getInstance();
calToday.setTime(new Date());
Calendar calLast = Calendar.getInstance();
Date datLast = workitem.getItemValueDate("datLetzteStatistik");
if (datLast != null)
calLast.setTime(datLast);
int dayOfYear = calLast.get(Calendar.DAY_OF_YEAR);
if (datLast != null
&& calLast.get(Calendar.DAY_OF_YEAR) == calToday
.get(Calendar.DAY_OF_YEAR)) {
logger.info("[Imixs StatistikPlugin] skipped");
// ganzen vorgang abbrechen, da sonst wieder eine Email gesendet wird
throw new PluginException("StatistikPlugin", "wrong date", "wrong date");
// return Plugin.PLUGIN_ERROR;
}
// ok wir starten die Auswertung!
logger.info("[Imixs StatistikPlugin] Starte Auswertung....");
workitem.replaceItemValue("datLetzteStatistik", calToday.getTime());
// jetzt brauchen wir die Werte von gestern!
calToday.add(Calendar.DATE, -1);
List<ItemCollection> aktuell = getStunden(calToday, calToday);
int stundenHeute = 0;
for (ItemCollection abr : aktuell) {
// prüfe ob categorie in ignore liste ist
String sKategorie = abr.getItemValueString("_category")
.toLowerCase();
if (Arrays.asList(ignoreList).contains(sKategorie))
continue;
stundenHeute += abr.getItemValueInteger("_duration");
}
logger.info("[Imixs StatistikPlugin] Stunden heute=" + stundenHeute);
workitem.replaceItemValue("numStundenHeute", stundenHeute);
// vorherige Woche berechnen
Date date = new Date();
int i = calToday.get(Calendar.DAY_OF_WEEK)
- calToday.getFirstDayOfWeek();
calToday.add(Calendar.DATE, -i - 7);
Date start = calToday.getTime();
calToday.add(Calendar.DATE, 6);
Date end = calToday.getTime();
logger.info("[Imixs StatistikPlugin] Vorwoche=" + start + " - " + end);
Calendar calStart = Calendar.getInstance();
calStart.setTime(start);
Calendar calEnd = Calendar.getInstance();
calEnd.setTime(end);
List<ItemCollection> vorwoche = getStunden(calStart, calEnd);
int stundenLetzeWoche = 0;
for (ItemCollection abr : vorwoche) {
// prüfe ob categorie in ignore liste ist
String sKategorie = abr.getItemValueString("_category")
.toLowerCase();
if (Arrays.asList(ignoreList).contains(sKategorie))
continue;
stundenLetzeWoche += abr.getItemValueInteger("_duration");
}
workitem.replaceItemValue("numStundenLetzeWoche", stundenLetzeWoche);
logger.info("[Imixs StatistikPlugin] Stunden Letze Woche="
+ stundenLetzeWoche);
return workitem;
}
public void close(int arg0) {
// no op
}
public String[] getIgnoreList() {
return ignoreList;
}
public void setIgnoreList(String[] ignoreList) {
this.ignoreList = ignoreList;
}
private List<ItemCollection> getStunden(Calendar dayFrom, Calendar dayTo) {
// dayformat 2014-12-31
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String sDateFrom = df.format(dayFrom.getTime());
String sDateTo = df.format(dayTo.getTime());
String sQuery = " SELECT workitem FROM Entity AS workitem"
+ " JOIN workitem.textItems AS type2"
+ " JOIN workitem.calendarItems AS type3"
+ " WHERE workitem.type IN ('childworkitem')"
+ " AND type3.itemName = 'datdate' "
+ " AND type3.itemValue BETWEEN '" + sDateFrom + " 00:00:00' AND '"
+ sDateTo + " 23:59:59'"
+ " AND type2.itemName = 'txtworkflowgroup' "
+ " AND type2.itemValue = 'Zeiterfassung'"
+ " ORDER BY type3.itemValue DESC ";
logger.fine("[Imixs StatistikPlugin] " + sQuery);
logger.warning("Imixs Statistik Collector is not implemented");
// return documentService.findAllEntities(sQuery, 0, -1);
return new ArrayList<ItemCollection>();
}
}

View file

@ -1,491 +0,0 @@
package com.imixs.intern;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import org.imixs.marty.team.TeamService;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.exceptions.QueryException;
import org.imixs.workflow.office.forms.AnalyticController;
import org.imixs.workflow.office.forms.AnalyticEvent;
import jakarta.enterprise.context.RequestScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.json.Json;
import jakarta.json.JsonArrayBuilder;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;
/**
* Der SuperOfficeAnalyticController berechnet verschiedene Analyse Daten
*
* @author rsoika
*
*/
@Named
@RequestScoped
public class SuperOfficeAnalyticController implements Serializable {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(AnalyticController.class.getName());
public static final String CHILD_ITEM_PROPERTY = "_ChildItems";
@Inject
protected DocumentService documentService;
@Inject
TeamService teamService;
List<ItemCollection> auftraege = null;
List<ItemCollection> rechnungen = null;
Map<String, List<ItemCollection>> requirementsCache = null;
Map<Integer, RequirementData> hoursByWeek = null;
int earliestWeek = Integer.MAX_VALUE;
int latestWeek = Integer.MIN_VALUE;
public void onEvent(@Observes AnalyticEvent event) {
if (!event.getKey().startsWith("superoffice.stats.")) {
return;
}
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(Locale.GERMANY);
ItemCollection processRequirements = teamService.getProcessByName("Sales");
if (processRequirements == null) {
logger.severe("Process 'Sales' not found!");
return;
}
ItemCollection processBuchhaltung = teamService.getProcessByName("Finance");
if (processBuchhaltung == null) {
logger.severe("Process 'Finance' not found!");
return;
}
String linkRequirements = "/pages/workitems/worklist.xhtml?processref=" + processRequirements.getUniqueID()
+ "&workflowgroup=Requirement";
String linkInvoices = "/pages/workitems/worklist.xhtml?processref=" + processBuchhaltung.getUniqueID()
+ "&workflowgroup=Rechnungsausgang";
if ("superoffice.stats.hours.total".equals(event.getKey())) {
event.setData(new ItemCollection());
event.getData().setItemValue("value", computeHoursTotal());
event.getData().setItemValue("label", "Stunden");
event.getData().setItemValue("description", "Noch nicht abgerechnete Stunden");
event.getData().setItemValue("link", linkRequirements);
}
if ("superoffice.stats.invoices.total".equals(event.getKey())) {
event.setData(new ItemCollection());
event.getData().setItemValue("Value", currencyFormat.format(computeOffeneRechnungen()));
event.getData().setItemValue("Label", "EUR");
event.getData().setItemValue("Description", "Offene Rechnungen");
event.getData().setItemValue("Link", linkInvoices);
}
// Charts
if ("superoffice.stats.hours.currentWeek".equals(event.getKey())) {
accumulateHoursByWeek();
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
int weekNumber = calendar.get(Calendar.WEEK_OF_YEAR);
int year = calendar.get(Calendar.YEAR);
int yearWeek = year * 100 + weekNumber; // Unique key for each year + week combination
RequirementData weekData = hoursByWeek.getOrDefault(yearWeek, new RequirementData());
event.setData(new ItemCollection());
event.getData().setItemValue("Value", weekData.total);
event.getData().setItemValue("Label", "Stunden");
event.getData().setItemValue("Description", "Stunden gesamt in dieser Woche - KW " + weekNumber);
event.getData().setItemValue("Link", linkRequirements);
}
if ("superoffice.stats.hours.trend".equals(event.getKey())) {
accumulateHoursByWeek();
event.setData(new ItemCollection());
event.getData().setItemValue("Value", buildHoursChart());
event.getData().setItemValue("Label", "Stunden");
event.getData().setItemValue("Description", "Stunden nach KW");
}
// computeKIPrompt(event.getWorkitem());
}
/**
* Berechnet die Summe aller offenen stunden
*
* @return
*/
private double computeHoursTotal() {
logger.fine("compute hours...");
List<ItemCollection> list = getAufträge();
double result = 0;
for (ItemCollection steuerItemCol : list) {
result = result + getStundenByAuftrag(steuerItemCol);
}
return round(result);
}
/**
* Berechnet die Summe aller offenen Rechnungen
*
* _amount
*
* @return
*/
private double computeOffeneRechnungen() {
logger.fine("compute offene Rechnungen...");
List<ItemCollection> list = getOffeneRechnungen();
double result = 0;
for (ItemCollection workitem : list) {
result = result + workitem.getItemValueDouble("_amount");
}
return round(result);
}
/**
* Berechnet die stunden pro auftrag (_capacity) Achtung: ist ein string der in
* double convertiert werden muss
*
* @param auftrag
* @return
*/
private double getStundenByAuftrag(ItemCollection auftrag) {
double result = 0;
List<ItemCollection> requirements = getRequirementsByAuftrag(auftrag);
for (ItemCollection requirement : requirements) {
result = result + requirement.getItemValueDouble("_capacity");
}
return result;
}
private void computeKIPrompt(ItemCollection workitem) {
String prompt = "Erstelle eine sehr kurze Geschäftsprognose über die Auftragslage auf Basis folgender Daten: \n";
prompt += "Wir haben aktuell offene Rechnungen in Höhe von " + workitem.getItemValueDouble("invoices.total")
+ " EUR .";
prompt += "Unser Stundensatz beträgt 150,- EUR .";
prompt += "In der aktuellen Woche haben wir bereits " + workitem.getItemValueInteger("stunden.total.week")
+ " Stunden gearbeitet. ";
prompt += "Insgesamt haben wir " + workitem.getItemValueInteger("stunden.total")
+ " Stunden gearbeitet die noch nicht in Rechnung gestellt sind. \n";
prompt += "Hier kommt eine übersicht der geleisteten Stunden die noch nicht abgerechnet wurden nach Kalenderwoche: \n";
Set<Integer> weekNumbers = hoursByWeek.keySet();
for (int kw : weekNumbers) {
String year = ("" + kw).substring(0, 4);
String weekNumber = ("" + kw).substring(4);
// Add the saldo for the week or 0.0 if no data
RequirementData requirementData = hoursByWeek.getOrDefault(kw, new RequirementData());
prompt += " - " + weekNumber + "/" + year + " = " + requirementData.total + "\n";
}
logger.info(prompt);
}
/**
* Lädt alle Aufträge
*
* @return
*/
private List<ItemCollection> getAufträge() {
if (auftraege != null) {
return auftraege;
}
logger.info("Load Aufträge for analytics....");
String query = "(type:workitem ) AND ($workflowgroup:\"Auftrag\")";
try {
auftraege = documentService.find(query, 999, 0, "$created", false);
return auftraege;
} catch (QueryException e) {
logger.severe("Failed to get invoices: " + e.getMessage());
}
return null;
}
/**
* Lädt alle offenen Rechnungen
*
* _amount
*
* @return
*/
private List<ItemCollection> getOffeneRechnungen() {
if (rechnungen != null) {
return rechnungen;
}
logger.info("Load Rechnung for analytics....");
String query = "(type:workitem ) AND ($workflowgroup:\"Rechnungsausgang\")";
try {
rechnungen = documentService.find(query, 999, 0, "$created", false);
return rechnungen;
} catch (QueryException e) {
logger.severe("Failed to get invoices: " + e.getMessage());
}
return null;
}
/**
* Lädt alle Requirements zu einem Auftrag
*
* @return
*/
private List<ItemCollection> getRequirementsByAuftrag(ItemCollection auftrag) {
if (requirementsCache == null) {
requirementsCache = new HashMap<>();
}
List<ItemCollection> result = requirementsCache.get(auftrag.getUniqueID());
if (result != null) {
return result;
}
// compute requirements....
logger.info("Load Requirements by Auftrag for analytics (" + auftrag.getUniqueID() + ")...");
String query = "($workflowgroup:\"Requirement\") AND (type:\"workitem\") AND ($taskid:[2100 TO 2300]) AND ($workitemref:\""
+ auftrag.getUniqueID() + "\")";
try {
result = documentService.find(query, 999, 0, "$created", false);
requirementsCache.put(auftrag.getUniqueID(), result);
return result;
} catch (QueryException e) {
logger.severe("Failed to get invoices: " + e.getMessage());
}
return null;
}
/**
* Akkumuliert alle Stunden nach KW. Die Methode nutzt einen Cache
*
* @return
*/
private void accumulateHoursByWeek() {
if (hoursByWeek != null) {
return;
}
logger.info("accumulate hours by week...");
hoursByWeek = new HashMap<>();
List<ItemCollection> list = getAufträge();
Calendar calendar = Calendar.getInstance();
// Step 1: Group saldo by week
for (ItemCollection auftrag : list) {
List<ItemCollection> requirements = getRequirementsByAuftrag(auftrag);
for (ItemCollection requirement : requirements) {
// dive into the stunden....
List<ItemCollection> stundenListe = explodeChildList(requirement);
for (ItemCollection stunden : stundenListe) {
double total = stunden.getItemValueDouble("amount");
Date date = stunden.getItemValueDate("datdate");
if (date == null) {
continue;
}
// Get the week number and year from the date
calendar.setTime(date);
int weekNumber = calendar.get(Calendar.WEEK_OF_YEAR);
int year = calendar.get(Calendar.YEAR);
int yearWeek = year * 100 + weekNumber; // Unique key for each year + week combination
if (year < 2024) {
logger.warning("Old Requirement in Auftrag " + auftrag.getUniqueID());
}
// Accumulate the hours per week
RequirementData steuerDataByWeek = hoursByWeek.getOrDefault(yearWeek, new RequirementData());
steuerDataByWeek.add(total, "");
hoursByWeek.put(yearWeek, steuerDataByWeek);
// Track the earliest and latest weeks
earliestWeek = Math.min(earliestWeek, yearWeek);
latestWeek = Math.max(latestWeek, yearWeek);
}
}
}
}
/**
* Berechnet das Chart zu den aktuell ermittelten Stunden
*
* <pre>
*
chartCfg = {
type: 'bar',
data: {
datasets: [{
data: [20, 10],
}],
labels: ['1', '2']
}
}
*
* </pre>
*
* @return
*/
private String buildHoursChart() {
accumulateHoursByWeek();
// Step 2: Prepare the JSON structure and ensure we have all weeks from earliest
// to latest
JsonArrayBuilder dataBuilderTotal = Json.createArrayBuilder();
JsonArrayBuilder labelsBuilder = Json.createArrayBuilder();
Calendar startCal = Calendar.getInstance();
startCal.set(Calendar.YEAR, earliestWeek / 100);
startCal.set(Calendar.WEEK_OF_YEAR, earliestWeek % 100);
Calendar endCal = Calendar.getInstance();
endCal.set(Calendar.YEAR, latestWeek / 100);
endCal.set(Calendar.WEEK_OF_YEAR, latestWeek % 100);
while (!startCal.after(endCal)) {
int weekNumber = startCal.get(Calendar.WEEK_OF_YEAR);
int year = startCal.get(Calendar.YEAR);
int yearWeek = year * 100 + weekNumber;
// Add the saldo for the week or 0.0 if no data
RequirementData requirementData = hoursByWeek.getOrDefault(yearWeek, new RequirementData());
dataBuilderTotal.add(requirementData.total);
labelsBuilder.add(weekNumber + "/" + year); // Label as 'week/year'
// Move to the next week
startCal.add(Calendar.WEEK_OF_YEAR, 1);
}
// Step 3: Prepare the JSON structure
JsonObjectBuilder jsonBuilder = Json.createObjectBuilder()
.add("type", "bar")
.add("data", Json.createObjectBuilder()
.add("datasets", Json.createArrayBuilder()
.add(Json.createObjectBuilder() // Third dataset for 'total'
.add("label", "Total")
.add("backgroundColor", "#4bc0c0")
.add("borderWidth", 1)
.add("data", dataBuilderTotal)))
.add("labels", labelsBuilder));
// Step 4: Return the JSON structure as a string
JsonObject chartCfg = jsonBuilder.build();
return chartCfg.toString();
}
/**
* Helper method to hold zoll and eust totals in an object. Needed to build
* totals per week.
*/
class RequirementData {
double total = 0.0;
String status = "";
public RequirementData() {
// default constructor
}
/**
* Adds new stunden
*
* @param totalNew
* @param statusNew
*/
public void add(double totalNew, String statusNew) {
total = total + totalNew;
status = statusNew;
}
}
public static double round(double value) {
BigDecimal bd = BigDecimal.valueOf(value);
bd = bd.setScale(2, RoundingMode.HALF_UP);
return bd.doubleValue();
}
/**
* converts the Map List of a workitem into a List of ItemCollectons
*/
public static List<ItemCollection> explodeChildList(ItemCollection workitem) {
return explodeChildList(workitem, CHILD_ITEM_PROPERTY);
}
/**
* converts the Map List of a workitem into a List of ItemCollectons
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static List<ItemCollection> explodeChildList(ItemCollection workitem, String childItemName) {
// convert current list of childItems into ItemCollection elements
ArrayList<ItemCollection> childItems = new ArrayList<ItemCollection>();
List<Object> mapOrderItems = workitem.getItemValue(childItemName);
for (Object mapOderItem : mapOrderItems) {
if (mapOderItem instanceof Map) {
ItemCollection itemCol = new ItemCollection((Map) mapOderItem);
childItems.add(itemCol);
}
}
return childItems;
}
/**
* Convert the List of ItemCollections back into a List of Map elements
*
* @param workitem
*/
public static void implodeChildList(ItemCollection workitem, List<ItemCollection> childItems) {
implodeChildList(workitem, childItems, CHILD_ITEM_PROPERTY);
}
/**
* Convert the List of ItemCollections back into a List of Map elements
*
* @param workitem
*/
@SuppressWarnings({ "rawtypes" })
public static void implodeChildList(ItemCollection workitem, List<ItemCollection> childItems,
String childItemName) {
List<Map> mapOrderItems = new ArrayList<Map>();
// convert the child ItemCollection elements into a List of Map
if (childItems != null) {
// iterate over all order items..
for (ItemCollection orderItem : childItems) {
mapOrderItems.add(orderItem.getAllItems());
}
workitem.replaceItemValue(childItemName, mapOrderItems);
}
}
}

View file

@ -1,112 +0,0 @@
/*******************************************************************************
* Imixs Workflow
* Copyright (C) 2001, 2011 Imixs Software Solutions GmbH,
* http://www.imixs.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You can receive a copy of the GNU General Public
* License at http://www.gnu.org/licenses/gpl.html
*
* Project:
* http://www.imixs.org
* http://java.net/projects/imixs-workflow
*
* Contributors:
* Imixs Software Solutions GmbH - initial API and implementation
* Ralph Soika - Software Developer
*******************************************************************************/
package com.imixs.intern;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import org.imixs.workflow.FileData;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.datev.export.DatevEvent;
import jakarta.annotation.Priority;
import jakarta.annotation.security.DeclareRoles;
import jakarta.annotation.security.RunAs;
import jakarta.ejb.LocalBean;
import jakarta.ejb.Stateless;
import jakarta.enterprise.event.Observes;
import jakarta.interceptor.Interceptor;
/**
* Der DatevService entscheidet welches File Exportiert werden soll.
*
* @author rsoika
*/
@DeclareRoles({ "org.imixs.ACCESSLEVEL.MANAGERACCESS" })
@RunAs("org.imixs.ACCESSLEVEL.MANAGERACCESS")
@Stateless
@LocalBean
public class SuperOfficeDatevService {
private static Logger logger = Logger.getLogger(SuperOfficeDatevService.class.getName());
/**
* This method reacts on CDI events of the type DatevEvent und gibt das richtige
* PDF zurück.
*
*
*/
public void onDatevEvent(@Observes @Priority(Interceptor.Priority.APPLICATION + 600) DatevEvent event) {
ItemCollection invoice = event.getWorkitem();
if (event.getEventType() == DatevEvent.ON_EXPORT_FILE) {
// nur für Ausgangsrechnungen interessant - ansonsten default verhalten nutzen
if (invoice.getModelVersion().startsWith("rechnungsausgang")) {
// wir nehmen das erste PDF das mir "R" beginnt.
FileData lastFileData = null;
List<FileData> fileDataList = invoice.getFileData();
for (FileData fileData : fileDataList) {
// we are only interested in files with sufix .pdf
// and start with "R"
if (!fileData.getName().toLowerCase().endsWith(".pdf")) {
// not a PDF file...
continue;
}
if (!fileData.getName().toLowerCase().startsWith("r")) {
// ist keine Rechnung
continue;
}
if (lastFileData == null) {
lastFileData = fileData;
} else {
// compare the $creation date....
ItemCollection attributes = new ItemCollection(fileData.getAttributes());
ItemCollection lastAttributes = new ItemCollection(lastFileData.getAttributes());
Date date = attributes.getItemValueDate("$created");
Date lastDate = lastAttributes.getItemValueDate("$created");
if (date != null && lastDate != null && (date.compareTo(lastDate) > 0)) {
// this is a newer fileData!
lastFileData = fileData;
}
}
}
if (lastFileData != null) {
event.setFileData(lastFileData);
}
}
}
}
}

View file

@ -1,98 +0,0 @@
package com.imixs.intern;
import java.util.List;
import java.util.logging.Logger;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.engine.plugins.AbstractPlugin;
import org.imixs.workflow.exceptions.PluginException;
import jakarta.inject.Inject;
/**
* Dieses Plugin berechnet die bezeihung Kunde->Auftrag->Requreimeent, usw....
*
* @author rsoika
*
*/
public class SuperOfficePlugin extends AbstractPlugin {
@Inject
DocumentService documentService;
private static Logger logger = Logger.getLogger(StatistikPlugin.class
.getName());
/**
*
*
* Skip if not a workitem and only run once a day!
*
* @throws PluginException
*
**/
@Override
public ItemCollection run(ItemCollection workitem, ItemCollection documentActivity) throws PluginException {
ItemCollection kontakt = null;
ItemCollection auftrag = null;
List<String> refs = workitem.getItemValueList("$workitemref", String.class);
if ("Auftrag".equals(workitem.getWorkflowGroup())) {
// find Kontakt
kontakt = findKontakt(workitem);
if (kontakt != null) {
// update kontakt info.....
workitem.setItemValue("contact.name", kontakt.getItemValueString("_subject"));
}
}
if ("Requirement".equals(workitem.getWorkflowGroup())) {
// find Auftrag
auftrag = findAuftrag(workitem);
if (auftrag != null) {
// kontakt = findKontakt(auftrag);
// update kontakt info.....
workitem.setItemValue("order.name", auftrag.getItemValueString("_subject"));
workitem.setItemValue("contact.name", auftrag.getItemValueString("contact.name"));
}
// convert efforts into a number
String ef = workitem.getItemValueString("_effort_planed");
ef = ef.replace(",", ".");
workitem.setItemValue("_effort_planed", Double.parseDouble(ef));
}
return workitem;
}
private ItemCollection findKontakt(ItemCollection workitem) {
ItemCollection result = null;
List<String> refs = workitem.getItemValueList("$workitemref", String.class);
for (String _id : refs) {
ItemCollection _workitem = documentService.load(_id);
if (_workitem != null && "Kontakt".equals(_workitem.getItemValueString("$workflowgroup"))) {
result = _workitem;
break;
}
}
return result;
}
private ItemCollection findAuftrag(ItemCollection workitem) {
ItemCollection result = null;
List<String> refs = workitem.getItemValueList("$workitemref", String.class);
for (String _id : refs) {
ItemCollection _workitem = documentService.load(_id);
if (_workitem != null && "Auftrag".equals(_workitem.getItemValueString("$workflowgroup"))) {
result = _workitem;
break;
}
}
return result;
}
}

View file

@ -1,791 +0,0 @@
/*******************************************************************************
* Imixs Workflow - jQUery API Copyright (C) 2012 Imixs Software Solutions GmbH,
* http://www.imixs.com
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You can receive a copy of the GNU General Public License at
* http://www.gnu.org/licenses/gpl.html
*
* Project: http://www.imixs.org
*
* Contributors: Imixs Software Solutions GmbH - initial API and implementation
* Ralph Soika - Software Developer
******************************************************************************/
var imixsServiceLocationURI = null;
var defaultModelVersion = null;
var defaultProcessID = null;
var requestLocale = null;
var defaultActionClass = null;
var cancelActionLabel = "Cancel";
var defaultImage = "images/default.gif";
/**
* Helper method to test for HTML 5 localStorage...
*
* @returns {Boolean}
*/
function hasLocalStorage() {
try {
return 'localStorage' in window && window['localStorage'] !== null;
} catch (e) {
return false;
}
}
/**
* This method is used to setup the workflow service
*
* @param aLocation -
* prafix for RESTService URI
* @param aDefaultModel -
* default model version
* @param aDefaultProcess -
* default ProcessID
*/
function setupWorkflowService(aLocation, aDefaultModel, aDefaultProcessID) {
imixsServiceLocationURI = aLocation;
defaultModelVersion = aDefaultModel;
defaultProcessID = aDefaultProcessID;
}
/**
* This method set the default action class for workflow action buttons. If no
* class is specified all action buttons will be styled as jQuery-UI button
* classes.
*
* @param aClass
*/
function setDefaultActionClass(aClass) {
defaultActionClass = aClass;
}
/**
* Overrides the default cancel button label.
*
* @param aLabel
*/
function setCancelActionLabel(aLabel) {
cancelActionLabel = aLabel;
}
/**
* this method clears the stored elements from the local cache
*
* @param identifier
*/
function clearWorkflowElement(identifier) {
// return if not html5 (IE7/8)
if (!hasLocalStorage())
return;
// alert('clearView....');
localStorage.removeItem("org.imixs.workflow." + identifier);
}
/**
* This method load a collection of workItems defined by a REST service URI.
* After the Ajax request is finished successful the method calls
* refreshWorklistView() to print the result into a page element.
*
* The result is stored into the clients localStorage.
*
*
* @param service -
* rest uri to be called ( workflow/worklistbyowner/null.json)
* @param selector -
* jquery selector for result list output
*/
function loadWorkitems(service, selector) {
// we first test if we still have the workflow groups in the local storage
var data = null;
if (hasLocalStorage())
data = localStorage.getItem("org.imixs.workflow." + service);
if (data == null) {
// create the list of workitems using the RESTful service interface
var serviceURL = imixsServiceLocationURI + service;
if (serviceURL.indexOf('?') > -1)
serviceURL = serviceURL + "&";
else
serviceURL = serviceURL + "?";
$
.getJSON(
serviceURL,
{
count : "30",
start : "0",
items : "$uniqueid,txtworkflowgroup,txtworkflowstatus,txtworkflowsummary,txtworkflowimageurl,namcurrenteditor,$modified"
}, function(data) {
// json request finished store the worklist.....
if (hasLocalStorage())
localStorage.setItem("org.imixs.workflow."
+ service, JSON.stringify(data));
refreshWorklistView(service, selector);
});
} else {
// use workflow groups from cache
refreshWorklistView(service, selector);
}
}
jQuery.events = function(expr) {
var rez = [], evo;
jQuery(expr).each(function() {
if (evo = jQuery._data(this, "events"))
rez.push({
element : this,
events : evo
});
});
return rez.length > 0 ? rez : null;
};
/**
* This method fills the page element ID=worklist_view with the selected
* workitems in a default layout.
*
* The method can be overwritten by binding a event listener
*
* <code>
* $(document).on( "refreshWorklist", function(e, data,service) {
....
});
* </code>
*
* If no refreshWorklist event is bound the method prints the worklist in a
* default layout. A refreshWorlist handler can be bound to the global document
* or to a specific selector
*
* <code>
* $(document).on( "refreshWorklist", "#worklist", function(e, data,service) {
....
});
* </code>
*/
function refreshWorklistView(service, selector) {
var dataString = null;
var data = null;
if (hasLocalStorage()) {
dataString = localStorage.getItem("org.imixs.workflow." + service);
data = JSON.parse(dataString);
}
if (data != null) {
// test if data.entity is an array....
if (!$.isArray(data.entity)) {
data.entity = jQuery.makeArray(data.entity);
}
}
// checking if an external general refreshWorklist method was bound
// there for we check the _data object for bound events....
var handlerFound = false;
var $ve = $._data(document, 'events');
if ($ve != null && typeof ($ve.refreshWorklist) != 'undefined') {
// the refreshWorklist method was bound! so now
// test if a binding for the current selector exists...
var handlerList = $ve.refreshWorklist;
$(handlerList).each(function(index) {
if (selector != null && selector == $(this).selector) {
// yes! we have a specific handler!
handlerFound = true;
// trigger handler
$(selector).trigger('refreshWorklist', [ data, service ]);
return;
}
});
if (handlerFound) {
// return from method
return;
}
// no specific handler was found so we trigger the general handler
// trigger external refreshWorklist method
$(document).trigger('refreshWorklist', [ data, service ]);
return;
}
// we did not found any handler - so do default output
// clear list
$("#worklist_view").empty();
if (data == null) {
$("#worklist_view").append(
"<li class=\"workitem\">Keine Daten vorhanden</li>");
return;
}
// iterate over all workitems
$
.each(
data.entity,
function(i, workitem) {
var imgurl = workitem.item[4].value.$;
// take defualt image if no image url is provided
if (imgurl == null)
imgurl = defaultImage;
var img = "<div class=\"workitem-thumb\"><img class=\"\" src=\""
+ imgurl + "\" /></div>";
var p_status = "<span class=\"workitem-summary\"><b>"
+ workitem.item[1].value.$ + "</b>: "
+ workitem.item[2].value.$ + "</span>";
$("#worklist_view")
.append(
"<li class=\"workitem\" onclick=\"loadWorkitem('"
+ workitem.item[0].value.$
+ "');\">"
+ img
+ "<div class=\"workitem-info\"><h3><a href=\"#\">"
+ ""
+ workitem.item[3].value.$
+ "</a></h3>"
+ p_status
+ "</div><div style=\"clear:left;\" /></li>");
});
}
// ############## Workitem ####################
/**
* this method loads a single workItem from the REST service and calls the
* method updateForm to print the content into a page. The optional selectorID
* specifies the area where the form data is placed. If no seletorId is given
* Imixs-Script searches for a section with the id #workitem_view.
*
*
* @param uid -
* $uniqueid of the workitem to be loaded
* @param selectorId -
* optinal param to define the section where the form data is filled
* in
*/
function loadWorkitem(uid, selectorId) {
if (selectorId == null || selectorId == "")
selectorId = '#workitem_view';
// allways reload the workitem!
var data = null;
// load the workitem by it's $uniqueid
$.getJSON(imixsServiceLocationURI + "workflow/workitem/" + uid + ".json?",
{
// items :
// "$uniqueid,$modelversion,$processid,txtworkflowgroup,txtworkflowstatus,txtworkflowsummary,txtworkflowimageurl,namcurrenteditor,$modified,txtworkflowabstract,_subject"
}, function(data) {
updateForm(data, selectorId);
});
}
/**
* This method updates a page section with the current workitem data. The method
* also rebuilds the activity section
*
* @param aWorkitem -
* the data object
* @param aSelector -
* optinal param to define the section where the form data is filled
* in
*/
function updateForm(aWorkitem, aSelector) {
disableActivities(aSelector);
loadProcessEntity(aWorkitem);
loadActivityList(aWorkitem, aSelector);
updateInputFields(aWorkitem, aSelector);
}
/**
* This method updates the input field values for all properties provided by the
* current workItem. The method only updates fields in specified selector. If no
* selectorId is provided the selectorId defaults to 'workitem_view'.
*
* Each value of an input element with a name corresponding to a item contained
* in the current Workitem will be updated.
*
* The method also clears all available Input fields (this is because of the
* case that a workItem did not provide a item for a specific input field. So in
* this case we need to clear the input in any case)
*
* @param aworkitem
* the workitem with the properties
* @param sectionid
* an optional selector
*/
function updateInputFields(aWorkitem, selectorId) {
if (selectorId == null || selectorId == "")
selectorId = '#workitem_view';
$(selectorId).trigger('beforeRefresh');
/* clear input fields... */
clear_form_elements(selectorId);
/*
* next we test if an element with the current item name exists. Then the
* .text() method will replace the content
*/
$.each(aWorkitem.item, function(i, item) {
var tagName = selectorId + " [name=" + item.name + "]";
var tagValue = "";
if (item.value != null && item.value.$ != null)
tagValue = item.value.$;
// $ is not allowed in a id because of jquery internals...
tagName = tagName.replace('$', '\\$');
if ($(tagName).length > 0) {
$(tagName).val(tagValue);
}
});
// see http://stackoverflow.com/questions/399867/custom-events-in-jquery
$(selectorId).trigger('afterRefresh', aWorkitem);
}
/**
* This method ad action buttons for the current workitem into the selectorID.
* Each activity for the current processID will result in a button. The method
* did not add activity buttons with the activityEntity property
* keypublicresult!=0.
*
* The method also adds all necessary hidden fields for processing a workitem.
*
* @param workitem -
* the current workitem
*
*/
function updateActivities(workitem, selectorId) {
if (selectorId == null || selectorId == "")
selectorId = '#workitem_view';
var modelversion = getEntityItemValue(workitem, "$modelversion");
var processid = getEntityItemValue(workitem, "$processid");
var unqiueid = getEntityItemValue(workitem, "$uniqueid");
var isauthor = getEntityItemValue(workitem, "$isauthor");
// iterate over all activity entities
var dataString = null;
var currentActivityList = null;
if (hasLocalStorage()) {
dataString = localStorage.getItem("org.imixs.workflow.activities."
+ modelversion + "." + processid);
currentActivityList = JSON.parse(dataString);
}
// clear list
$(selectorId + " #workitem_activities").empty();
// iterarte over all activities if available...
// activities will be only shown is workitem isNew or user isAuthor
if (currentActivityList != null && (unqiueid == "" || isauthor == "true")) {
// test if currentActivityList.entity is an array....
if (!$.isArray(currentActivityList.entity))
currentActivityList.entity = jQuery
.makeArray(currentActivityList.entity);
// iterate over all activities to build buttons...
$
.each(currentActivityList.entity,
function(i, activity) {
// only add button if keypublicresult!=0
var testPublicResult = getEntityItemValue(activity,
"keypublicresult");
if ("0" != testPublicResult) {
var actionName = getEntityItemValue(activity,
"txtname");
var actionID = getEntityItemValue(activity,
"numactivityid");
var tooltipText = getEntityItemValue(activity,
"rtfdescription");
addActionButton(selectorId, actionName,
actionID, false, tooltipText);
}
});
}
// append the cancel button
$(selectorId + " #workitem_activities").append(
"<input id=\"workflow_activity_cancel\" type=\"button\" value=\""
+ cancelActionLabel + "\"></input>");
// bind clearWorkitem method
// we need to bind the click method using jquery because otherwise external
// code can not unbind this call
$(selectorId + " #workitem_activities #workflow_activity_cancel").click(
function(event) {
clearWorkitem(selectorId);
});
// add $unqiueid, $modelversion, $activitid and $processid input fields if
// yet not part of the form
// $ is not allowed in a id because of jquery internals...
if ($(selectorId + " [name=\\$activityid]").length <= 0)
$(selectorId + " #workitem_activities").append(
"<input type=\"hidden\" name=\"$activityid\"></input>");
if ($(selectorId + " [name=\\$processid]").length <= 0)
$(selectorId + " #workitem_activities").append(
"<input type=\"hidden\" name=\"$processid\" value=\""
+ processid + "\"></input>");
if ($(selectorId + " [name=\\$uniqueid]").length <= 0)
$(selectorId + " #workitem_activities").append(
"<input type=\"hidden\" name=\"$uniqueid\" value=\"" + unqiueid
+ "\"></input>");
if ($(selectorId + " [name=\\$modelversion]").length <= 0)
$(selectorId + " #workitem_activities").append(
"<input type=\"hidden\" name=\"$modelversion\" value=\""
+ modelversion + "\"></input>");
if ($(selectorId + " [name=type]").length <= 0)
$(selectorId + " #workitem_activities")
.append(
"<input type=\"hidden\" name=\"type\" value=\"workitem\"></input>");
// finally style all buttons...
var sActionSelector = selectorId + " #workitem_activities input:button, "
+ selectorId + " #workitem_activities input:submit";
if (defaultActionClass == null)
$(sActionSelector).button();
else
$(sActionSelector).addClass(defaultActionClass);
/* Imixs Tooltip support */
// test if juery ui is availalbe....
if ($.fn.tooltip) {
$("span.imixs-tooltip").prev().tooltip({
position : {
my : "left top+5",
at : "left+10 bottom",
collision : "flipfit"
},
show : {
duration : 800
},
content : function() {
var tooltip = $(this).next();
tooltip.hide();
return tooltip.text();
}
});
// hide all imixs tooltips
$("span.imixs-tooltip").hide();
} // end of tooltip support
// trigger afterRefresh event
$(selectorId + ' #workitem_activities').trigger('afterRefresh', workitem);
}
/**
* clears all input fiels inside the given formpart
*/
function clear_form_elements(formpart) {
$(formpart).find(':input').each(function() {
switch (this.type) {
case 'text':
case 'hidden':
case 'password':
case 'select-multiple':
case 'select-one':
case 'textarea':
$(this).val('');
break;
case 'checkbox':
case 'radio':
this.checked = false;
}
});
}
/**
* This method create a new empty workitem and clears also the workitem_view
*/
function clearWorkitem(selectorId) {
if (selectorId == null || selectorId == "")
selectorId = '#workitem_view';
newWorkitem = {
"item" : [ {
"name" : "$processid",
"value" : {
"@type" : "xs:int",
"$" : defaultProcessID
}
}, {
"name" : "$modelversion",
"value" : {
"@type" : "xs:string",
"$" : defaultModelVersion
}
}, {
"name" : "_subject",
"value" : {
"@type" : "xs:string",
"$" : ""
}
} ]
};
updateForm(newWorkitem, selectorId);
}
/**
* This method loads the specifiy processEntity. The method uses the
* localStorage to cache processEntities already loaded
*
* @param workitem -
* the current workitem
*/
function loadProcessEntity(workitem, selectorId) {
var processid = null;
var modelversion = null;
// read processID and model version.....
$.each(workitem.item, function(i, item) {
if (item.name == "$modelversion")
modelversion = item.value.$;
if (item.name == "$processid")
processid = item.value.$;
if (modelversion != null && processid != null)
return;
});
// we first test if we still have the Entity in the local storage
var currentProcessEntity = null;
if (hasLocalStorage())
currentProcessEntity = localStorage
.getItem("org.imixs.workflow.process." + modelversion + "."
+ processid);
if (currentProcessEntity == null) {
// now we need to load the model information from the rest service...
$
.getJSON(imixsServiceLocationURI + "model/" + modelversion
+ "/process/" + processid + ".json",
function(data) {
// cache the result
if (hasLocalStorage())
localStorage.setItem(
"org.imixs.workflow.process."
+ modelversion + "."
+ processid, JSON
.stringify(data));
refreshWorkitemProcessView(currentProcessEntity,
selectorId);
});
} else
refreshWorkitemProcessView(currentProcessEntity, selectorId);
}
/**
* This method loads the specifiy activitylist. The method uses the localStorage
* to cache Entities already loaded
*
* @param workitem -
* the current workitem
*
* @param selectorId -
* optional param to force a refresh of a specific section
*/
function loadActivityList(workitem, selectorId) {
var modelversion = getEntityItemValue(workitem, "$modelversion");
var processid = getEntityItemValue(workitem, "$processid");
// we first test if we still have the Entity in the local storage
var currentProcessEntity = null;
if (hasLocalStorage())
currentProcessEntity = localStorage
.getItem("org.imixs.workflow.activities." + modelversion + "."
+ processid);
if (currentProcessEntity == null) {
// now we need to load the model information from the rest service...
$.getJSON(
imixsServiceLocationURI + "model/" + modelversion
+ "/activities/" + processid + ".json",
function(data) {
// cache the result
if (hasLocalStorage())
localStorage.setItem("org.imixs.workflow.activities."
+ modelversion + "." + processid, JSON
.stringify(data));
updateActivities(workitem, selectorId);
}).error(function() {
// if an error occur we also need to update the activityview....
updateActivities(workitem, selectorId);
});
} else
updateActivities(workitem, selectorId);
}
/**
* this method writes the html code for the current ProcessEntity into the
* element workitem_view
*
* @param aProcessEntity
* the aProcessEntity to be loaded
*/
function refreshWorkitemProcessView(aprocessEntity, selectorId) {
// ;
}
/**
* This method is called by the loadWorkitem() method to disable any action
* buttons from the current form until the workitem_view is refreshed
* completley. This is only a helper method to avoid inconsistent submits if the
* refresh process of the workitem_view will break for any reason.
*/
function disableActivities(selectorId) {
$(':input:button, :input:submit', selectorId + ' #workitem_activities')
.each(function() {
// disable the button...
$(this).attr('disabled', 'disabled');
});
}
/**
* Add a workflow action buttion int a defined section
*
* @param selectorId -
* the name of the section the buttion should be placed in
* @param actionName -
* the name of the button
* @param activityID -
* the activity entity ID to be processed
* @param tooltipText -
* optional tooltip for the button
* @param bInsert -
* optional, if true the button will be inserted at the first child
* element of the selectior
*/
function addActionButton(selectorId, actionName, activityID, bInsert,
tooltipText) {
if (selectorId == null || selectorId == "")
selectorId = '#workitem_view';
// test if selector was found
if ($(selectorId + " #workitem_activities").length) {
// build conclick event....
var activityScript = "onclick=\"processWorkitem('" + activityID + "');";
// build tooltip span tag
var tooltip = "";
if (tooltipText != "")
tooltip = "<span class=\"imixs-tooltip\">" + tooltipText
+ "</span>";
// insert at the bginning of the tag?
if (bInsert)
$(selectorId + " #workitem_activities").prepend(
"<input type=\"submit\" id=\"workflow_activity_"
+ activityID + "\" value=\"" + actionName + "\" "
+ activityScript + "\"title=\"\"></input>");
else
$(selectorId + " #workitem_activities").append(
"<input type=\"submit\" id=\"workflow_activity_"
+ activityID + "\" value=\"" + actionName + "\" "
+ activityScript + "\"title=\"\"></input>"
+ tooltip);
}
}
/**
* This method updates the $activityid input field .
*
* @param activityid
*/
function processWorkitem(activityid) {
$('#workitem_view').trigger('beforeProcess');
var tagName = "#workitem_activities [name=\\$activityid]";
if ($(tagName).length > 0) {
$(tagName).val(activityid);
}
}
/**
* This method returns the value of a specified item inside an entity. Maybe we
* can optimize the method???
*
* @param entity
*/
function getEntityItemValue(entity, itemname) {
var value = "";
$.each(entity.item, function(i, item) {
if (item.name == itemname) {
if (item.value != null) {
if ($.isArray(item.value))
value = item.value[0].$;
else
value = item.value.$;
return;
}
}
});
return value;
}
/**
* This method returns the value of a specified item inside an entity. Maybe we
* can optimize the method???
*
* @param entity
*/
function getEntityItemValueArray(entity, itemname) {
var value = "";
$.each(entity.item, function(i, item) {
if (item.name == itemname) {
if (item.value != null) {
if ($.isArray(item.value))
value = item.value;
else
value = jQuery.makeArray(item.value);
return;
}
}
});
return value;
}

View file

@ -1,320 +0,0 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:i="http://java.sun.com/jsf/composite/imixs"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:marty="http://java.sun.com/jsf/composite/marty"
template="/layout/template.xhtml">
<ui:define name="content">
<f:view>
<script type="text/javascript">
/*<![CDATA[*/
function updateStatustPanel(data) {
//initUserInput($('#userselector_id'));
if (data.status === 'success') {
// select with wildcard operator
$('[id$=status_panel]').imixsLayout();
}
}
/*]]>*/
</script>
<h:form id="import_form_id" enctype="multipart/form-data">
<div class="imixs-form">
<div class="imixs-header">
<h1>DATEV</h1>
</div>
<div class="imixs-body">
<div class="imixs-tabs">
<ul>
<li><a href="#tab-1">Einstellungen</a></li>
<li><a href="#tab-2">Import</a></li>
<li><a href="#tab-3">Export</a></li>
</ul>
<div id="tab-1">
<!-- **** Einstellungen ***** -->
<div class="imixs-form-section">
<div class="ui-state-highlight ui-corner-all"
style="margin-bottom: 10px; padding: .5em;">
<h3>DATEV Einstellungen</h3>
<p>Definieren Sie hier die DATEV Parameter die Ihnen von Ihrem Steuerberater mitgeteilt wurden.</p>
</div>
<div class="imixs-form-section-2">
<dl>
<dt>DATEV Mandant Name</dt>
<dd>
<h:inputText required="false"
value="#{datevController.configuration.item['datev.client.name']}">
</h:inputText>
</dd>
</dl>
<dl>
<dt>DATEV Mandantennummer </dt>
<dd>
<h:inputText required="false"
value="#{datevController.configuration.item['datev.client.id']}">
</h:inputText>
</dd>
</dl>
<dl>
<dt>
DATEV Beraternummer <span class="imixs-required">*</span>
</dt>
<dd>
<h:inputText required="true"
value="#{datevController.configuration.item['datev.consultant.id']}">
</h:inputText>
</dd>
</dl>
<dl>
<dt>BU Schlüssel:</dt>
<dd>
<h:inputTextarea required="false"
converter="org.imixs.VectorConverter"
style="height: 8em; width: 100%;"
value="#{datevController.configuration.itemList['datev.buschluessel']}">
</h:inputTextarea>
<span style="font-size:0.7rem;">Format: BEZEICHNUNG | DATEV_BU_SCHLUESSEL | PROZENTSATZ</span>
</dd>
</dl>
<dl>
<dt>
DATEV WJ-Beginn (MMTT) <span class="imixs-required">* <h:message
for="fiscalstart" /></span>
</dt>
<dd>
<h:inputText value="#{datevController.configuration.item['datev.fiscal_start']}"
id="fiscalstart" required="false"/>
</dd>
</dl>
<dl>
<dt>DATEV Sachkontennummernlänge</dt>
<dd>
<h:inputText
value="#{datevController.configuration.item['datev.sachkontennummernlaenge']}" />
</dd>
</dl>
<dl>
<dt>Kostenstelle I. (Nummer|Bezeichnung)</dt>
<dd>
<h:inputTextarea required="false"
converter="org.imixs.VectorConverter"
style="height: 8em; width: 100%;"
value="#{datevController.configuration.itemList['datev.kostenstelle1']}">
</h:inputTextarea>
</dd>
</dl>
<dl>
<dt>Kostenstellen II. (Nummer|Bezeichnung)</dt>
<dd>
<h:inputTextarea required="false"
converter="org.imixs.VectorConverter"
style="height: 8em; width: 100%;"
value="#{datevController.configuration.itemList['datev.kostenstelle2']}">
</h:inputTextarea>
</dd>
</dl>
</div>
</div>
</div>
<div id="tab-2">
<!-- **** DATEV import ***** -->
<div class="imixs-form-section">
<div class="ui-state-highlight ui-corner-all"
style="margin-bottom: 10px; padding: .5em;">
<h3>Import DATEV Stammdaten</h3>
<ul>
<li>Fügen Sie hier die zu importierende DATEV Datei an.</li>
<li>Die Datei muss im CSV Format vorliegen.</li>
<li>Die Datei muss zwei Header Zeilen enthalten:
<ol>
<li>Zeile: Datenart - z.B. "Kontobeschriftungen"</li>
<li>Zeile: Feldbezeichnungen - z.B. "Konto,
Kontobezeichnung"</li>
</ol>
</li>
<li>Fügen Sie immer nur eine Datei für den Import an!</li>
<li>Der Import kann einige Minuten in Anspruch nehmen.</li>
<li>Brechen Sie den Vorgang nicht ab und warten Sie bis
der Import vollständig abgeschlossen ist.</li>
</ul>
</div>
<dl>
<dt>Importdatei wählen:</dt>
<dd>
<i:imixsFileUpload id="file_upload_id"
workitem="#{datevController.importData}"
context_url="#{facesContext.externalContext.requestContextPath}/rest-service/workflow/workitem/#{workflowController.workitem.item['$uniqueid']}"
hideatachments="true" />
<h:panelGroup layout="block"
styleClass="ui-state-highlight ui-corner-all"
style="margin-bottom: 10px; padding: .5em;"
rendered="#{! empty datevController.importData.item['log']}">
<pre>#{datevController.importData.item['log']}</pre>
</h:panelGroup>
</dd>
</dl>
<dl>
<dt>Encoding </dt>
<dd>
<h:inputText required="false" style="width: 220px;"
value="#{datevController.configuration.item['datev.encoding']}">
</h:inputText>
</dd>
</dl>
<h:commandButton
actionListener="#{datevController.startImport}"
value="Start Import">
</h:commandButton>
</div>
</div>
<div id="tab-3">
<!-- **** Export Buchunsstapel ***** -->
<div class="imixs-form-section">
<div class="ui-state-highlight ui-corner-all"
style="margin-bottom: 10px; padding: .5em;">
<h3>Export DATEV Buchungsstapel</h3>
<p>Definieren Sie hier den Export Workflow sowie die Reportdefinition.</p>
</div>
<h:panelGroup layout="block" id="report_selection"
styleClass="imixs-form-section-2">
<dl>
<dt>
DATEV Schnittstellen-Typ <span class="imixs-required">*</span>
</dt>
<dd>
<h:selectOneRadio
value="#{datevController.configuration.item['export.type']}"
required="true">
<f:selectItem itemValue="xml"
itemLabel="DATEV Belegsatzschnittstelle im XML-Format"></f:selectItem>
<f:selectItem itemValue="csv"
itemLabel="DATEV-Format (csv)"></f:selectItem>
<f:ajax render="report_selection"/>
</h:selectOneRadio>
</dd>
</dl>
<dl>
<dt>
DATEV Report Definitionen <span class="imixs-required">*</span>
</dt>
<dd>
Belegexport:
<h:inputText required="true"
value="#{datevController.configuration.item['report.invoices']}">
</h:inputText>
<h:panelGroup
rendered="#{'xml' eq datevController.configuration.item['export.type']}">
<br />
Dokumente: <h:inputText required="false"
value="#{datevController.configuration.item['report.documents']}">
</h:inputText>
</h:panelGroup>
</dd>
</dl>
</h:panelGroup>
<div class="imixs-form-section-2">
<dl>
<dt>
DATEV Model Version <span class="imixs-required">*</span>
</dt>
<dd>
<h:inputText required="true"
value="#{datevController.configuration.item['model.version']}">
</h:inputText>
</dd>
</dl>
<dl>
<dt>
DATEV Initial Task <span class="imixs-required">*</span>
</dt>
<dd>
<h:inputText required="true"
value="#{datevController.configuration.item['initial.task']}">
</h:inputText>
</dd>
</dl>
</div>
<div class="imixs-form-section">
<p>
<span class="typcn typcn-lightbulb"></span> Der Initaltask
muss einen Report definieren, der die Abfrage und das Stylesheet enthält.
Die Rechnungen werden automatisch nach dem
Attribut "datev.client.id" sowie der Buchungsperiode gruppiert.
</p>
</div>
</div>
</div>
</div>
</div>
<div class="imixs-footer">
<h:outputLabel value="#{message.modified}: " />
<h:outputText
value="#{datevController.configuration.item['$modified']}">
<f:convertDateTime timeZone="#{message.timeZone}" type="both"
pattern="#{message.dateTimePattern}" />
</h:outputText>
<br />
<h:commandButton
actionListener="#{datevController.saveConfiguration()}"
value="#{message.save}">
</h:commandButton>
<h:commandButton value="#{message.close}" action="notes" />
</div>
</div>
</h:form>
</f:view>
</ui:define>
</ui:composition>

View file

@ -1,337 +0,0 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:i="http://java.sun.com/jsf/composite/imixs"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:pt="http://xmlns.jcp.org/jsf/passthrough"
xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions"
xmlns:marty="http://java.sun.com/jsf/composite/marty"
template="/layout/template.xhtml">
<ui:define name="content">
<f:view>
<script type="text/javascript">
/*<![CDATA[*/
$(document).ready(function() {
//$('.imixsdatatable').layoutImixsTable();
});
// This method refreshs the layout
function updateOptions(data) {
if (data.status === 'success') {
$('[id$=Optionlist]').imixsLayout();
/* var id='#'+data.source.id;
if (id.indexOf("input")>-1) {
$(id).focus();
} */
}
}
/*]]>*/
</script>
<h:form id="import_form_id">
<div class="imixs-form">
<div class="imixs-header">
<h1>Dokument Import</h1>
</div>
<div class="imixs-body">
<div class="imixs-tabs">
<ul>
<li><a href="#tab-1">Timer Setting</a></li>
<li><a href="#tab-2">Data Sources</a></li>
</ul>
<!-- ### Timer ### -->
<div id="tab-1">
<div class="ui-state-highlight ui-corner-all"
style="margin-bottom: 10px; padding: .5em;">
<p><span class="typcn typcn-lightbulb"></span> Define a crontab to schedule the import processor.</p>
</div>
<ui:include src="sub_scheduler_control.xhtml">
<ui:param name="schedulerController"
value="#{documentImportController}" />
</ui:include>
</div>
<!-- ### SMTP ### -->
<div id="tab-2">
<div class="ui-state-highlight ui-corner-all"
style="margin-bottom: 10px; padding: .5em;">
<p><span class="typcn typcn-lightbulb"></span> Define a destination IMAP server and assign mail addresses to specific workflow groups.</p>
</div>
<div class="imixs-form-panel">
<!-- ### Sources ### -->
<h:panelGroup layout="block"
id="imapOptionlist" binding="#{imapOptionlistContainer}">
<f:ajax onevent="updateOptions">
<table class="imixsdatatable"
style="width: 100%;">
<thead>
<tr>
<th style="width: 10px;text-align: center;">Pos</th>
<th style="width: 100px;text-align: center;">Type</th>
<th style="">Workflowgroup</th>
<th style="">Modelversion</th>
<th style="">Task</th>
<th style="">Event</th>
<th style="width: 110px;">
<!-- delete -->
</th>
</tr>
</thead>
<tbody>
<ui:repeat var="source" value="#{documentImportController.sources}">
<tr>
<!-- pos -->
<td style=" text-align: center;">
<h:commandLink
actionListener="#{documentImportController.selectSource(source.item['index'])}">#<h:outputText
value="#{source.item['index']}" />
<f:ajax render="#{imapOptionlistContainer.clientId}"
onevent="updateOptions" />
</h:commandLink>
</td>
<!-- type -->
<td style="text-align: center;">
<h:outputText value="#{source.item['type']}" />
</td>
<!-- Workflowgroup -->
<td><h:outputText
value="#{source.item['workflowgroup']}" />
</td>
<td><h:outputText
value="#{source.item['modelversion']}" />
</td>
<td><h:outputText
value="#{source.item['task']}" />
</td>
<td><h:outputText
value="#{source.item['event']}" />
</td>
<td>
<h:commandLink
actionListener="#{documentImportController.moveSourceDown(source.item['index'])}">
<span class="typcn typcn-arrow-down-thick imixs-state-info"></span>
<f:ajax render="#{imapOptionlistContainer.clientId}"
onevent="updateOptions" />
</h:commandLink>
<h:commandLink
actionListener="#{documentImportController.moveSourceUp(source.item['index'])}">
<span class="typcn typcn-arrow-up-thick imixs-state-info"></span>
<f:ajax render="#{imapOptionlistContainer.clientId}"
onevent="updateOptions" />
</h:commandLink>
<h:commandLink
actionListener="#{documentImportController.removeSource(source.item['index'])}">
<span class="typcn typcn-trash imixs-state-info"></span>
<f:ajax render="#{imapOptionlistContainer.clientId}"
onevent="updateOptions" />
</h:commandLink></td>
</tr>
</ui:repeat>
</tbody>
</table>
<!-- add button -->
<h:commandButton
value="#{message.add}"
actionListener="#{documentImportController.addSource()}">
<f:ajax render="#{imapOptionlistContainer.clientId}"
onevent="updateOptions" />
</h:commandButton>
<!-- ### Subform for selected source ### -->
<h:panelGroup layout="block" rendered="#{! empty documentImportController.source}" styleClass="imixs-form-panel">
<h3>Order ID #<h:outputText value="#{documentImportController.source.item['index']}"/></h3>
<div class="imixs-form-section-3">
<dl>
<dt>Type</dt>
<dd>
<h:selectOneRadio value="#{documentImportController.source.item['type']}">
<f:selectItem itemLabel="IMAP" itemValue="IMAP"/>
<f:selectItem itemLabel="FTP" itemValue="FTP"/>
</h:selectOneRadio>
</dd>
</dl>
<dl>
<dt>Workflowgroup</dt>
<dd>
<h:selectOneMenu
value="#{documentImportController.source.item['workflowgroup']}">
<c:forEach items="#{modelController.workflowGroups}" var="group">
<f:selectItem itemLabel="#{group}" itemValue="#{group}" />
</c:forEach>
</h:selectOneMenu>
</dd>
</dl>
</div>
<div class="imixs-form-section-3">
<dl>
<dt>Workflowmodel</dt>
<dd>
<h:inputText
value="#{documentImportController.source.item['workflowmodel']}"/>
</dd>
</dl>
<dl>
<dt>Task ID</dt>
<dd>
<h:inputText
value="#{documentImportController.source.item['task']}"/>
</dd>
</dl>
<dl>
<dt>Event ID</dt>
<dd>
<h:inputText
value="#{documentImportController.source.item['event']}"/>
</dd>
</dl>
</div>
<hr />
<!-- IMAP -->
<div class="imixs-form-section-3">
<dl>
<dt>Server : Port</dt>
<dd>
<h:inputText style="width:80%;"
value="#{documentImportController.source.item['server']}">
</h:inputText> : <h:inputText style="width:15%;"
value="#{documentImportController.source.item['port']}">
</h:inputText>
</dd>
</dl>
<dl>
<dt>User</dt>
<dd>
<h:inputText required="false"
value="#{documentImportController.source.item['user']}">
</h:inputText>
</dd>
</dl>
<dl>
<dt>Password</dt>
<dd>
<h:inputSecret required="false" redisplay="true"
value="#{documentImportController.source.item['password']}">
</h:inputSecret>
</dd>
</dl>
</div>
<div class="imixs-form-section">
<dl>
<dt>Selector</dt>
<dd>
<h:inputText required="false"
value="#{documentImportController.source.item['selector']}">
</h:inputText>
<p class="small">A selector can be an optional regular expression to be used to select a subset of data</p>
</dd>
</dl>
<dl>
<dt>Options</dt>
<dd>
<h:inputTextarea required="false"
style="height: 5em; width: 100%;"
value="#{documentImportController.source.item['options']}">
</h:inputTextarea>
<p class="small">You can apply custom properties here.
</p>
</dd>
</dl>
</div>
</h:panelGroup> <!-- end of source subform -->
</f:ajax>
</h:panelGroup>
</div>
</div>
</div>
</div>
<div class="imixs-footer">
<h:outputLabel value="#{message.modified}: " />
<h:outputText
value="#{documentImportController.configuration.item['$modified']}">
<f:convertDateTime timeZone="#{message.timeZone}" type="both"
pattern="#{message.dateTimePattern}" />
</h:outputText>
<br />
<h:commandButton
actionListener="#{documentImportController.saveConfiguration()}"
action="/pages/admin/document_import"
value="#{message.save}">
</h:commandButton>
<h:commandButton value="#{message.close}" action="notes" />
</div>
</div>
</h:form>
</f:view>
</ui:define>
</ui:composition>

Some files were not shown because too many files have changed in this diff Show more