You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2021/09/08 22:04:48 UTC

[isis] 01/02: ISIS-2735: wip, bringing in Command as abstract class

This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch ISIS-2735-command-log
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 890ae8dfd6527f645ae98049de51607c2371514d
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Tue Sep 7 07:24:13 2021 +0100

    ISIS-2735: wip, bringing in Command as abstract class
---
 .../applib/mixins/system/DomainChangeRecord.java   | 136 +++++-
 .../domain/_commands/ExposePersistedCommands.java  |   2 +-
 .../ExposePersistedCommands_commands.java          |   2 +-
 .../IsisModuleExtCommandLogApplib.java             |  18 +-
 .../extensions/commandlog/applib/dom/Command.java  | 527 +++++++++++++++++++++
 .../command => applib/dom}/CommandModel.java       |  11 +-
 .../dom}/CommandModelRepository.java               |   2 +-
 .../{model/command => applib/dom}/ReplayState.java |   2 +-
 .../{model => applib}/util/BigDecimalUtils.java    |   2 +-
 .../{model => applib}/util/StringUtils.java        |   2 +-
 .../util/StringUtils_trimmed_Test.java             |   4 +-
 .../commandlog/jdo/IsisModuleExtCommandLogJdo.java |   4 +-
 .../commandlog/jdo/entities/CommandJdo.java        |   8 +-
 .../jdo/entities/CommandJdoRepository.java         |   6 +-
 .../jdo/entities/CommandJdo_childCommands.java     |   2 +-
 .../commandlog/jdo/entities/CommandJdo_retry.java  |   2 +-
 .../commandlog/jpa/entities/CommandJpa.java        |   8 +-
 .../jpa/entities/CommandJpaRepository.java         |   6 +-
 .../primary/IsisModuleExtCommandReplayPrimary.java |   2 +-
 .../primary/restapi/CommandRetrievalService.java   |   4 +-
 .../primary/spiimpl/CaptureResultOfCommand.java    |   2 +-
 .../primary/ui/CommandReplayOnPrimaryService.java  |   4 +-
 .../IsisModuleExtCommandReplaySecondary.java       |   2 +-
 .../secondary/analyser/CommandReplayAnalyser.java  |   2 +-
 .../analyser/CommandReplayAnalyserException.java   |   2 +-
 .../analyser/CommandReplayAnalyserResult.java      |   2 +-
 .../analysis/CommandReplayAnalysisService.java     |   2 +-
 .../secondary/fetch/CommandFetcher.java            |   2 +-
 .../jobcallables/ReplicateAndRunCommands.java      |   6 +-
 .../secondary/mixins/CommandJdo_replayQueue.java   |   4 +-
 .../secondary/mixins/CommandModel_exclude.java     |   6 +-
 .../ui/CommandReplayOnSecondaryService.java        |   4 +-
 32 files changed, 707 insertions(+), 81 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/mixins/system/DomainChangeRecord.java b/api/applib/src/main/java/org/apache/isis/applib/mixins/system/DomainChangeRecord.java
index 944b004..c1dfe15 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/mixins/system/DomainChangeRecord.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/mixins/system/DomainChangeRecord.java
@@ -18,13 +18,20 @@
  */
 package org.apache.isis.applib.mixins.system;
 
-import java.sql.Timestamp;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import java.util.UUID;
 
+import org.apache.isis.applib.annotation.Editing;
 import org.apache.isis.applib.annotation.Optionality;
+import org.apache.isis.applib.annotation.Parameter;
+import org.apache.isis.applib.annotation.ParameterLayout;
 import org.apache.isis.applib.annotation.Property;
 import org.apache.isis.applib.annotation.PropertyLayout;
 import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.events.domain.PropertyDomainEvent;
 import org.apache.isis.applib.mixins.security.HasUsername;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 
@@ -38,6 +45,33 @@ import org.apache.isis.applib.services.bookmark.Bookmark;
  */
 public interface DomainChangeRecord extends HasInteractionId, HasUsername {
 
+    @Property(
+            domainEvent = ChangeTypeMeta.DomainEvent.class,
+            editing = Editing.DISABLED,
+            maxLength = ChangeTypeMeta.MAX_LENGTH
+    )
+    @PropertyLayout(
+            hidden = Where.ALL_EXCEPT_STANDALONE_TABLES,
+            fieldSetId = "Identifiers",
+            sequence = "1",
+            typicalLength = ChangeTypeMeta.TYPICAL_LENGTH
+    )
+    @Parameter(
+            maxLength = ChangeTypeMeta.MAX_LENGTH
+    )
+    @ParameterLayout(
+            named = "Change Type",
+            typicalLength = ChangeTypeMeta.TYPICAL_LENGTH
+    )
+    @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface ChangeTypeMeta {
+        int MAX_LENGTH = 24;
+        int TYPICAL_LENGTH = 24;
+
+        class DomainEvent extends PropertyDomainEvent<DomainChangeRecord, DomainChangeRecord.ChangeType> {}
+    }
+
     /**
      * Enumerates the different types of changes recognised.
      *
@@ -56,40 +90,114 @@ public interface DomainChangeRecord extends HasInteractionId, HasUsername {
     /**
      * Distinguishes commands from audit entries from published events/interactions (when these are shown mixed together in a (standalone) table).
      */
-    @Property
-    @PropertyLayout(
-            hidden = Where.ALL_EXCEPT_STANDALONE_TABLES,
-            fieldSetId="Identifiers",
-            sequence = "1")
+    @ChangeTypeMeta
     ChangeType getType();
 
 
+
+    @Property(
+            domainEvent = InteractionId.DomainEvent.class,
+            editing = Editing.DISABLED,
+            maxLength = InteractionId.MAX_LENGTH
+    )
+    @PropertyLayout(
+            fieldSetId = "Identifiers",
+            sequence = "50",
+            typicalLength = InteractionId.TYPICAL_LENGTH
+    )
+    @Parameter(
+            maxLength = InteractionId.MAX_LENGTH
+    )
+    @ParameterLayout(
+            typicalLength = InteractionId.TYPICAL_LENGTH
+    )
+    @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface InteractionId {
+        int MAX_LENGTH = 36;
+        int TYPICAL_LENGTH = 36;
+
+        class DomainEvent extends PropertyDomainEvent<DomainChangeRecord, UUID> { }
+    }
+
+
     /**
      * The unique identifier (a GUID) of the
      * {@link org.apache.isis.applib.services.iactn.Interaction} within which
      * this change occurred.
      */
+    @InteractionId
     @Override
-    @Property
-    @PropertyLayout(fieldSetId="Identifiers",sequence = "50")
     UUID getInteractionId();
 
 
+
+    @Property(
+            domainEvent = Username.DomainEvent.class,
+            editing = Editing.DISABLED,
+            maxLength = Username.MAX_LENGTH
+    )
+    @PropertyLayout(
+            fieldSetId="Identifiers",
+            sequence = "10",
+            typicalLength = Username.TYPICAL_LENGTH,
+            hidden = Where.PARENTED_TABLES
+    )
+    @Parameter(
+            maxLength = Username.MAX_LENGTH
+    )
+    @ParameterLayout(
+            named = "Username",
+            typicalLength = Username.TYPICAL_LENGTH
+    )
+    @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface Username {
+        int MAX_LENGTH = 120;
+        int TYPICAL_LENGTH = 40;
+
+        class DomainEvent extends PropertyDomainEvent<DomainChangeRecord, String> {}
+    }
+
     /**
      * The user that caused the change.
      */
-    @Override
-    @Property
-    @PropertyLayout(fieldSetId="Identifiers", sequence = "10")
+    @Username
     String getUsername();
 
 
+
+    @Property(
+            domainEvent = DomainChangeRecord.Timestamp.DomainEvent.class,
+            editing = Editing.DISABLED,
+            maxLength = Timestamp.MAX_LENGTH
+    )
+    @PropertyLayout(
+            fieldSetId="Identifiers",
+            sequence = "20",
+            typicalLength = Timestamp.TYPICAL_LENGTH
+    )
+    @Parameter(
+            maxLength = Timestamp.MAX_LENGTH
+    )
+    @ParameterLayout(
+            named = "Timestamp",
+            typicalLength = Timestamp.TYPICAL_LENGTH
+    )
+    @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface Timestamp {
+        int MAX_LENGTH = 32;
+        int TYPICAL_LENGTH = 32;
+
+        class DomainEvent extends PropertyDomainEvent<DomainChangeRecord, java.sql.Timestamp> {}
+    }
+
     /**
      * The time that the change occurred.
      */
-    @Property
-    @PropertyLayout(fieldSetId="Identifiers", sequence = "20")
-    Timestamp getTimestamp();
+    @DomainChangeRecord.Timestamp
+    java.sql.Timestamp getTimestamp();
 
 
     /**
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/_commands/ExposePersistedCommands.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/_commands/ExposePersistedCommands.java
index 106899d..51254d5 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/domain/_commands/ExposePersistedCommands.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/_commands/ExposePersistedCommands.java
@@ -25,7 +25,7 @@ import org.apache.isis.applib.annotation.PriorityPrecedence;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.services.tablecol.TableColumnOrderForCollectionTypeAbstract;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
 
 /**
  * Marker interface for mixins to contribute to.
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/_commands/ExposePersistedCommands_commands.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/_commands/ExposePersistedCommands_commands.java
index d857ee6..767f8f9 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/domain/_commands/ExposePersistedCommands_commands.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/_commands/ExposePersistedCommands_commands.java
@@ -25,7 +25,7 @@ import javax.inject.Inject;
 import org.apache.isis.applib.annotation.Collection;
 import org.apache.isis.applib.annotation.CollectionLayout;
 import org.apache.isis.extensions.commandlog.jdo.entities.CommandJdoRepository;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
 
 import lombok.RequiredArgsConstructor;
 
diff --git a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/IsisModuleExtCommandLogApplib.java b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/IsisModuleExtCommandLogApplib.java
similarity index 78%
rename from extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/IsisModuleExtCommandLogApplib.java
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/IsisModuleExtCommandLogApplib.java
index f6a9576..2206d1f 100644
--- a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/IsisModuleExtCommandLogApplib.java
+++ b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/IsisModuleExtCommandLogApplib.java
@@ -16,32 +16,34 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.extensions.commandlog.model;
+package org.apache.isis.extensions.commandlog.applib;
 
 import org.apache.isis.testing.fixtures.applib.modules.ModuleWithFixtures;
 
 public interface IsisModuleExtCommandLogApplib
 extends ModuleWithFixtures {
 
-    public abstract static class TitleUiEvent<S>
+    String NAMESPACE = "isis.ext.commandLog";
+
+    abstract class TitleUiEvent<S>
         extends org.apache.isis.applib.events.ui.TitleUiEvent<S> { }
 
-    public abstract static class IconUiEvent<S>
+    abstract class IconUiEvent<S>
         extends org.apache.isis.applib.events.ui.IconUiEvent<S> { }
 
-    public abstract static class CssClassUiEvent<S>
+    abstract class CssClassUiEvent<S>
         extends org.apache.isis.applib.events.ui.CssClassUiEvent<S> { }
 
-    public abstract static class LayoutUiEvent<S>
+    abstract class LayoutUiEvent<S>
         extends org.apache.isis.applib.events.ui.LayoutUiEvent<S> { }
 
-    public abstract static class ActionDomainEvent<S>
+    abstract class ActionDomainEvent<S>
         extends org.apache.isis.applib.events.domain.ActionDomainEvent<S> { }
 
-    public abstract static class CollectionDomainEvent<S,T>
+    abstract class CollectionDomainEvent<S,T>
         extends org.apache.isis.applib.events.domain.CollectionDomainEvent<S,T> { }
 
-    public abstract static class PropertyDomainEvent<S,T>
+    abstract class PropertyDomainEvent<S,T>
         extends org.apache.isis.applib.events.domain.PropertyDomainEvent<S,T> { }
 
 }
diff --git a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/Command.java b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/Command.java
new file mode 100644
index 0000000..5dc6c8c
--- /dev/null
+++ b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/Command.java
@@ -0,0 +1,527 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.extensions.commandlog.applib.dom;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.function.Consumer;
+
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Service;
+
+import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.DomainObjectLayout;
+import org.apache.isis.applib.annotation.Editing;
+import org.apache.isis.applib.annotation.MemberSupport;
+import org.apache.isis.applib.annotation.Parameter;
+import org.apache.isis.applib.annotation.ParameterLayout;
+import org.apache.isis.applib.annotation.PriorityPrecedence;
+import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.annotation.PropertyLayout;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.jaxb.JavaSqlXMLGregorianCalendarMarshalling;
+import org.apache.isis.applib.mixins.system.DomainChangeRecord;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.command.CommandOutcomeHandler;
+import org.apache.isis.applib.services.commanddto.conmap.UserDataKeys;
+import org.apache.isis.applib.services.tablecol.TableColumnOrderForCollectionTypeAbstract;
+import org.apache.isis.applib.util.ObjectContracts;
+import org.apache.isis.applib.util.TitleBuffer;
+import org.apache.isis.commons.functional.Result;
+import org.apache.isis.commons.internal.base._Strings;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
+import org.apache.isis.extensions.commandlog.applib.util.BigDecimalUtils;
+import org.apache.isis.extensions.commandlog.applib.util.StringUtils;
+import org.apache.isis.schema.cmd.v2.CommandDto;
+import org.apache.isis.schema.cmd.v2.MapDto;
+
+import lombok.val;
+
+@DomainObject(
+        logicalTypeName = Command.LOGICAL_TYPE_NAME,
+        editing = Editing.DISABLED
+)
+@DomainObjectLayout(
+        titleUiEvent = Command.TitleUiEvent.class,
+        iconUiEvent = Command.IconUiEvent.class,
+        cssClassUiEvent = Command.CssClassUiEvent.class,
+        layoutUiEvent = Command.LayoutUiEvent.class
+)
+public abstract class Command implements DomainChangeRecord {
+
+    public final static String LOGICAL_TYPE_NAME = IsisModuleExtCommandLogApplib.NAMESPACE + ".Command";
+
+    public static class TitleUiEvent extends IsisModuleExtCommandLogApplib.TitleUiEvent<CommandModel> { }
+    public static class IconUiEvent extends IsisModuleExtCommandLogApplib.IconUiEvent<CommandModel> { }
+    public static class CssClassUiEvent extends IsisModuleExtCommandLogApplib.CssClassUiEvent<CommandModel> { }
+    public static class LayoutUiEvent extends IsisModuleExtCommandLogApplib.LayoutUiEvent<CommandModel> { }
+
+    public static abstract class PropertyDomainEvent<T> extends IsisModuleExtCommandLogApplib.PropertyDomainEvent<CommandModel, T> { }
+    public static abstract class CollectionDomainEvent<T> extends IsisModuleExtCommandLogApplib.CollectionDomainEvent<CommandModel, T> { }
+
+
+    public Command(final org.apache.isis.applib.services.command.Command command) {
+
+        setInteractionIdStr(command.getInteractionId().toString());
+        setUsername(command.getUsername());
+        setTimestamp(command.getTimestamp());
+
+        setCommandDto(command.getCommandDto());
+        setTarget(command.getTarget());
+        setLogicalMemberIdentifier(command.getLogicalMemberIdentifier());
+
+        setStartedAt(command.getStartedAt());
+        setCompletedAt(command.getCompletedAt());
+
+        setResult(command.getResult());
+        setException(command.getException());
+
+        setReplayState(ReplayState.UNDEFINED);
+    }
+
+
+    /**
+     * Intended for use on secondary (replay) system.
+     *
+     * @param commandDto - obtained from the primary system as a representation of a command invocation
+     * @param replayState - controls whether this is to be replayed
+     * @param targetIndex - if the command represents a bulk action, then it is flattened out when replayed; this indicates which target to execute against.
+     */
+    public Command(
+            final CommandDto commandDto,
+            final ReplayState replayState,
+            final int targetIndex) {
+
+        setInteractionIdStr(commandDto.getInteractionId());
+        setUsername(commandDto.getUser());
+        setTimestamp(JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(commandDto.getTimestamp()));
+
+        setCommandDto(commandDto);
+        setTarget(Bookmark.forOidDto(commandDto.getTargets().getOid().get(targetIndex)));
+        setLogicalMemberIdentifier(commandDto.getMember().getLogicalMemberIdentifier());
+
+        // the hierarchy of commands calling other commands is only available on the primary system, and is
+        setParent(null);
+
+        setStartedAt(JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(commandDto.getTimings().getStartedAt()));
+        setCompletedAt(JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(commandDto.getTimings().getCompletedAt()));
+
+        copyOver(commandDto, UserDataKeys.RESULT, value -> this.setResult(Bookmark.parse(value).orElse(null)));
+        copyOver(commandDto, UserDataKeys.EXCEPTION, this::setException);
+
+        setReplayState(replayState);
+    }
+
+    static void copyOver(
+            final CommandDto commandDto,
+            final String key, final Consumer<String> consume) {
+        commandDto.getUserData().getEntry()
+                .stream()
+                .filter(x -> Objects.equals(x.getKey(), key))
+                .map(MapDto.Entry::getValue)
+                .filter(Objects::nonNull)
+                .filter(x -> x.length() > 0)
+                .findFirst()
+                .ifPresent(consume);
+    }
+
+    @Service
+    public static class TitleProvider {
+
+        @EventListener(TitleUiEvent.class)
+        public void on(final TitleUiEvent ev) {
+            if(!Objects.equals(ev.getTitle(), "Command Jdo") || ev.getTranslatableTitle() != null) {
+                return;
+            }
+            ev.setTitle(title((Command)ev.getSource()));
+        }
+
+        private static String title(final Command source) {
+            // nb: not thread-safe
+            // formats defined in https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
+            val format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+
+            val buf = new TitleBuffer();
+            buf.append(format.format(source.getTimestamp()));
+            buf.append(" ").append(source.getLogicalMemberIdentifier());
+            return buf.toString();
+        }
+    }
+
+
+    @DomainChangeRecord.ChangeTypeMeta
+    @Override
+    public DomainChangeRecord.ChangeType getType() {
+        return ChangeType.COMMAND;
+    }
+
+
+    @DomainChangeRecord.InteractionId
+    @Override
+    public abstract UUID getInteractionId();
+    public abstract void setInteractionId(UUID interactionId);
+
+
+    @DomainChangeRecord.Username
+    @Override
+    public abstract String getUsername();
+    public abstract void setUsername(String username);
+
+
+    @DomainChangeRecord.Timestamp
+    @Override
+    public abstract java.sql.Timestamp getTimestamp();
+    public abstract void setTimestamp(java.sql.Timestamp timestamp);
+
+
+
+    @Property(
+            domainEvent = ReplayState.DomainEvent.class,
+            editing = Editing.DISABLED,
+            maxLength = ReplayState.MAX_LENGTH
+    )
+    @PropertyLayout(
+            // fieldSetId = "XXX",  // TODO: fix
+            // sequence = "XXX",
+            typicalLength = ReplayState.TYPICAL_LENGTH
+    )
+    @Parameter(
+            maxLength = ReplayState.MAX_LENGTH
+    )
+    @ParameterLayout(
+            named = "Replay State",
+            typicalLength = ReplayState.TYPICAL_LENGTH
+    )
+    @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface ReplayState {
+        int MAX_LENGTH = 12;
+        int TYPICAL_LENGTH = 12;
+
+        class DomainEvent extends PropertyDomainEvent<org.apache.isis.extensions.commandlog.applib.dom.ReplayState> {}
+    }
+
+
+    /**
+     * For a replayed command, what the outcome was.
+     */
+    @Command.ReplayState
+    public abstract org.apache.isis.extensions.commandlog.applib.dom.ReplayState getReplayState();
+    public abstract void setReplayState(org.apache.isis.extensions.commandlog.applib.dom.ReplayState replayState);
+
+
+
+    // UP TO HERE...
+
+    public static class ReplayStateFailureReasonDomainEvent extends PropertyDomainEvent<ReplayState> { }
+    /**
+     * For a {@link org.apache.isis.extensions.commandlog.applib.dom.ReplayState#FAILED failed} replayed command,
+     * what the reason was for the failure.
+     */
+    @Property(
+            domainEvent = ReplayStateFailureReasonDomainEvent.class
+    )
+    @PropertyLayout(
+            hidden = Where.ALL_TABLES,
+            multiLine = 5
+    )
+    public abstract String getReplayStateFailureReason();
+    public abstract void setReplayStateFailureReason(String replayStateFailureReason);
+
+    @MemberSupport public boolean hideReplayStateFailureReason() {
+        return getReplayState() == null || !getReplayState().isFailed();
+    }
+
+
+    public static class ParentDomainEvent extends PropertyDomainEvent<org.apache.isis.applib.services.command.Command> { }
+    @Property(
+            domainEvent = ParentDomainEvent.class
+    )
+    @PropertyLayout(
+            hidden = Where.ALL_TABLES
+    )
+    public abstract Command getParent();
+    public abstract void setParent(Command parent);
+
+
+
+    public static class TargetDomainEvent extends PropertyDomainEvent<Bookmark> { }
+    @Property(
+            domainEvent = TargetDomainEvent.class
+    )
+    @PropertyLayout(
+            named = "Object"
+    )
+    public abstract Bookmark getTarget();
+    public abstract void setTarget(Bookmark target);
+
+    public String getTargetStr() {
+        return Optional.ofNullable(getTarget()).map(Bookmark::toString).orElse(null);
+    }
+
+    @Override
+    public String getTargetMember() {
+        return getCommandDto().getMember().getLogicalMemberIdentifier();
+    }
+
+
+    public static class LocalMemberEvent extends PropertyDomainEvent<String> { }
+    @Property(
+            domainEvent = LocalMemberEvent.class
+    )
+    @PropertyLayout(
+            named = "Member"
+    )
+    public String getLocalMember() {
+        val targetMember = getTargetMember();
+        return targetMember.substring(targetMember.indexOf("#") + 1);
+    }
+
+
+    public static class LogicalMemberIdentifierDomainEvent extends PropertyDomainEvent<String> { }
+    @Property(
+            domainEvent = LogicalMemberIdentifierDomainEvent.class
+    )
+    @PropertyLayout(
+            hidden = Where.ALL_TABLES
+    )
+    public abstract String getLogicalMemberIdentifier();
+    public abstract void setLogicalMemberIdentifier(String logicalMemberIdentifier);
+
+
+    public static class CommandDtoDomainEvent extends PropertyDomainEvent<CommandDto> { }
+    @Property(
+            domainEvent = CommandDtoDomainEvent.class
+    )
+    @PropertyLayout(
+            multiLine = 9
+    )
+    public abstract CommandDto getCommandDto();
+    public abstract void setCommandDto(CommandDto commandDto);
+
+
+
+    public static class StartedAtDomainEvent extends PropertyDomainEvent<Timestamp> { }
+    @Property(
+            domainEvent = StartedAtDomainEvent.class
+    )
+    public abstract Timestamp getStartedAt();
+    public abstract void setStartedAt(Timestamp startedAt);
+
+
+    public static class CompletedAtDomainEvent extends PropertyDomainEvent<Timestamp> { }
+    @Property(
+            domainEvent = CompletedAtDomainEvent.class
+    )
+    public abstract Timestamp getCompletedAt();
+    public abstract void setCompletedAt(Timestamp completedAt);
+
+
+    public static class DurationDomainEvent extends PropertyDomainEvent<BigDecimal> { }
+    /**
+     * The number of seconds (to 3 decimal places) that this interaction lasted.
+     *
+     * <p>
+     * Populated only if it has {@link #getCompletedAt() completed}.
+     */
+    @javax.validation.constraints.Digits(integer=5, fraction=3)
+    @Property(
+            domainEvent = DurationDomainEvent.class
+    )
+    public BigDecimal getDuration() {
+        return BigDecimalUtils.durationBetween(getStartedAt(), getCompletedAt());
+    }
+
+
+    public static class IsCompleteDomainEvent extends PropertyDomainEvent<Boolean> { }
+    @Property(
+            domainEvent = IsCompleteDomainEvent.class
+    )
+    @PropertyLayout(
+            hidden = Where.OBJECT_FORMS
+    )
+    public boolean isComplete() {
+        return getCompletedAt() != null;
+    }
+
+
+
+    public static class ResultSummaryDomainEvent extends PropertyDomainEvent<String> { }
+    @Property(domainEvent = ResultSummaryDomainEvent.class)
+    @PropertyLayout(hidden = Where.OBJECT_FORMS, named = "Result")
+    public String getResultSummary() {
+        if(getCompletedAt() == null) {
+            return "";
+        }
+        if(!_Strings.isNullOrEmpty(getException())) {
+            return "EXCEPTION";
+        }
+        if(getResult() != null) {
+            return "OK";
+        } else {
+            return "OK (VOID)";
+        }
+    }
+
+
+    public static class ResultDomainEvent extends PropertyDomainEvent<String> { }
+    @Property(
+            domainEvent = ResultDomainEvent.class
+    )
+    @PropertyLayout(
+            hidden = Where.ALL_TABLES,
+            named = "Result Bookmark"
+    )
+    public abstract Bookmark getResult();
+    public abstract void setResult(Bookmark result);
+
+
+    public static class ExceptionDomainEvent extends PropertyDomainEvent<String> { }
+    /**
+     * Stack trace of any exception that might have occurred if this interaction/transaction aborted.
+     *
+     * <p>
+     * Not part of the applib API, because the default implementation is not persistent
+     * and so there's no object that can be accessed to be annotated.
+     */
+    @Property(
+            domainEvent = ExceptionDomainEvent.class
+    )
+    @PropertyLayout(
+            hidden = Where.ALL_TABLES,
+            multiLine = 5, named = "Exception (if any)"
+    )
+    public abstract String getException();
+    public abstract void setException(final String exception);
+
+    public void setException(final Throwable exception) {
+        setException(_Exceptions.asStacktrace(exception));
+    }
+
+
+    public static class IsCausedExceptionDomainEvent extends PropertyDomainEvent<Boolean> { }
+    @Property(
+            domainEvent = IsCausedExceptionDomainEvent.class
+    )
+    @PropertyLayout(
+            hidden = Where.OBJECT_FORMS
+    )
+    public boolean isCausedException() {
+        return getException() != null;
+    }
+
+
+    @Override
+    public String getPreValue() {
+        return null;
+    }
+
+    @Override
+    public String getPostValue() {
+        return null;
+    }
+
+
+    public void saveAnalysis(final String analysis) {
+        if (analysis == null) {
+            setReplayState(ReplayState.OK);
+        } else {
+            setReplayState(ReplayState.FAILED);
+            setReplayStateFailureReason(StringUtils.trimmed(analysis, 255));
+        }
+    }
+
+    @Override
+    public String toString() {
+        return toFriendlyString();
+    }
+
+    String toFriendlyString() {
+        return ObjectContracts
+                .toString("interactionId", Command::getInteractionId)
+                .thenToString("username", Command::getUsername)
+                .thenToString("timestamp", Command::getTimestamp)
+                .thenToString("target", Command::getTarget)
+                .thenToString("logicalMemberIdentifier", Command::getLogicalMemberIdentifier)
+                .thenToStringOmitIfAbsent("startedAt", Command::getStartedAt)
+                .thenToStringOmitIfAbsent("completedAt", Command::getCompletedAt)
+                .toString(this);
+    }
+
+    public CommandOutcomeHandler outcomeHandler() {
+        return new CommandOutcomeHandler() {
+            @Override
+            public Timestamp getStartedAt() {
+                return Command.this.getStartedAt();
+            }
+
+            @Override
+            public void setStartedAt(final Timestamp startedAt) {
+                Command.this.setStartedAt(startedAt);
+            }
+
+            @Override
+            public void setCompletedAt(final Timestamp completedAt) {
+                Command.this.setCompletedAt(completedAt);
+            }
+
+            @Override
+            public void setResult(final Result<Bookmark> resultBookmark) {
+                Command.this.setResult(resultBookmark.getValue().orElse(null));
+                Command.this.setException(resultBookmark.getFailure().orElse(null));
+            }
+
+        };
+    }
+
+    @Service
+    @javax.annotation.Priority(PriorityPrecedence.LATE - 10)
+    public static class TableColumnOrderDefault extends TableColumnOrderForCollectionTypeAbstract<Command> {
+
+        public TableColumnOrderDefault() { super(Command.class); }
+
+        @Override
+        protected List<String> orderParented(final Object parent, final String collectionId, final List<String> propertyIds) {
+            return ordered(propertyIds);
+        }
+
+        @Override
+        protected List<String> orderStandalone(final List<String> propertyIds) {
+            return ordered(propertyIds);
+        }
+
+        private List<String> ordered(final List<String> propertyIds) {
+            return Arrays.asList(
+                "timestamp", "target", "targetMember", "username", "complete", "resultSummary", "interactionIdStr"
+            );
+        }
+    }
+}
+
diff --git a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/command/CommandModel.java b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/CommandModel.java
similarity index 71%
rename from extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/command/CommandModel.java
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/CommandModel.java
index daad926..de23ac8 100644
--- a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/command/CommandModel.java
+++ b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/CommandModel.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.extensions.commandlog.model.command;
+package org.apache.isis.extensions.commandlog.applib.dom;
 
 import java.sql.Timestamp;
 import java.util.UUID;
@@ -25,21 +25,12 @@ import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.command.CommandOutcomeHandler;
 import org.apache.isis.applib.services.commanddto.HasCommandDto;
 import org.apache.isis.applib.util.ObjectContracts;
-import org.apache.isis.extensions.commandlog.model.IsisModuleExtCommandLogApplib;
 
 public interface CommandModel
 extends
     HasCommandDto,
     Comparable<CommandModel> {
 
-    public static class TitleUiEvent extends IsisModuleExtCommandLogApplib.TitleUiEvent<CommandModel> { }
-    public static class IconUiEvent extends IsisModuleExtCommandLogApplib.IconUiEvent<CommandModel> { }
-    public static class CssClassUiEvent extends IsisModuleExtCommandLogApplib.CssClassUiEvent<CommandModel> { }
-    public static class LayoutUiEvent extends IsisModuleExtCommandLogApplib.LayoutUiEvent<CommandModel> { }
-
-    public static abstract class PropertyDomainEvent<T> extends IsisModuleExtCommandLogApplib.PropertyDomainEvent<CommandModel, T> { }
-    public static abstract class CollectionDomainEvent<T> extends IsisModuleExtCommandLogApplib.CollectionDomainEvent<CommandModel, T> { }
-    public static abstract class ActionDomainEvent extends IsisModuleExtCommandLogApplib.ActionDomainEvent<CommandModel> { }
 
 
     Bookmark getResult();
diff --git a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/command/CommandModelRepository.java b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/CommandModelRepository.java
similarity index 98%
rename from extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/command/CommandModelRepository.java
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/CommandModelRepository.java
index 668e8a2..cc65c64 100644
--- a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/command/CommandModelRepository.java
+++ b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/CommandModelRepository.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.extensions.commandlog.model.command;
+package org.apache.isis.extensions.commandlog.applib.dom;
 
 import java.time.LocalDate;
 import java.util.List;
diff --git a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/command/ReplayState.java b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/ReplayState.java
similarity index 95%
rename from extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/command/ReplayState.java
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/ReplayState.java
index 75d99e6..07d0e7e 100644
--- a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/command/ReplayState.java
+++ b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/dom/ReplayState.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.extensions.commandlog.model.command;
+package org.apache.isis.extensions.commandlog.applib.dom;
 
 public enum ReplayState {
     /**
diff --git a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/util/BigDecimalUtils.java b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/util/BigDecimalUtils.java
similarity index 96%
rename from extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/util/BigDecimalUtils.java
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/util/BigDecimalUtils.java
index 7d27553..813227f 100644
--- a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/util/BigDecimalUtils.java
+++ b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/util/BigDecimalUtils.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.extensions.commandlog.model.util;
+package org.apache.isis.extensions.commandlog.applib.util;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
diff --git a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/util/StringUtils.java b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/util/StringUtils.java
similarity index 95%
rename from extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/util/StringUtils.java
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/util/StringUtils.java
index 9e613c6..21cb229 100644
--- a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/model/util/StringUtils.java
+++ b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/util/StringUtils.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.extensions.commandlog.model.util;
+package org.apache.isis.extensions.commandlog.applib.util;
 
 import lombok.experimental.UtilityClass;
 
diff --git a/extensions/core/command-log/applib/src/test/java/org/apache/isis/extensions/commandlog/model/util/StringUtils_trimmed_Test.java b/extensions/core/command-log/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/util/StringUtils_trimmed_Test.java
similarity index 91%
rename from extensions/core/command-log/applib/src/test/java/org/apache/isis/extensions/commandlog/model/util/StringUtils_trimmed_Test.java
rename to extensions/core/command-log/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/util/StringUtils_trimmed_Test.java
index 2c2d6b3..6931a82 100644
--- a/extensions/core/command-log/applib/src/test/java/org/apache/isis/extensions/commandlog/model/util/StringUtils_trimmed_Test.java
+++ b/extensions/core/command-log/applib/src/test/java/org/apache/isis/extensions/commandlog/applib/util/StringUtils_trimmed_Test.java
@@ -16,13 +16,11 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.extensions.commandlog.model.util;
+package org.apache.isis.extensions.commandlog.applib.util;
 
 import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 
-import org.apache.isis.extensions.commandlog.model.util.StringUtils;
-
 public class StringUtils_trimmed_Test {
 
     @Test
diff --git a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/IsisModuleExtCommandLogJdo.java b/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/IsisModuleExtCommandLogJdo.java
index d4044cb..cad004a 100644
--- a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/IsisModuleExtCommandLogJdo.java
+++ b/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/IsisModuleExtCommandLogJdo.java
@@ -25,8 +25,8 @@ import org.springframework.context.annotation.Import;
 import org.apache.isis.extensions.commandlog.jdo.entities.CommandJdo;
 import org.apache.isis.extensions.commandlog.jdo.entities.CommandJdoRepository;
 import org.apache.isis.extensions.commandlog.jdo.ui.CommandServiceMenu;
-import org.apache.isis.extensions.commandlog.model.IsisModuleExtCommandLogApplib;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
 import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScript;
 import org.apache.isis.testing.fixtures.applib.teardown.jdo.TeardownFixtureJdoAbstract;
 
diff --git a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo.java b/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo.java
index 08bbc73..3042c5d 100644
--- a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo.java
+++ b/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo.java
@@ -55,10 +55,10 @@ import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.extensions.commandlog.jdo.IsisModuleExtCommandLogJdo;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
-import org.apache.isis.extensions.commandlog.model.command.ReplayState;
-import org.apache.isis.extensions.commandlog.model.util.BigDecimalUtils;
-import org.apache.isis.extensions.commandlog.model.util.StringUtils;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.ReplayState;
+import org.apache.isis.extensions.commandlog.applib.util.BigDecimalUtils;
+import org.apache.isis.extensions.commandlog.applib.util.StringUtils;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.cmd.v2.MapDto;
 
diff --git a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdoRepository.java b/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdoRepository.java
index 4f476d2..ae47780 100644
--- a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdoRepository.java
+++ b/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdoRepository.java
@@ -45,9 +45,9 @@ import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.iactn.InteractionProvider;
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
-import org.apache.isis.extensions.commandlog.model.command.CommandModelRepository;
-import org.apache.isis.extensions.commandlog.model.command.ReplayState;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModelRepository;
+import org.apache.isis.extensions.commandlog.applib.dom.ReplayState;
 import org.apache.isis.persistence.jdo.applib.services.JdoSupportService;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.cmd.v2.CommandsDto;
diff --git a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_childCommands.java b/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_childCommands.java
index 8636b34..d55341c 100644
--- a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_childCommands.java
+++ b/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_childCommands.java
@@ -23,7 +23,7 @@ import java.util.List;
 import org.apache.isis.applib.annotation.Collection;
 import org.apache.isis.applib.annotation.CollectionLayout;
 import org.apache.isis.extensions.commandlog.jdo.IsisModuleExtCommandLogJdo;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
 
 import lombok.RequiredArgsConstructor;
 
diff --git a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_retry.java b/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_retry.java
index 4d1b9d1..b58cfa2 100644
--- a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_retry.java
+++ b/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_retry.java
@@ -31,7 +31,7 @@ import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.applib.services.xactn.TransactionService;
 import org.apache.isis.applib.services.iactnlayer.InteractionService;
 import org.apache.isis.extensions.commandlog.jdo.IsisModuleExtCommandLogJdo;
-import org.apache.isis.extensions.commandlog.model.command.ReplayState;
+import org.apache.isis.extensions.commandlog.applib.dom.ReplayState;
 
 import lombok.RequiredArgsConstructor;
 
diff --git a/extensions/core/command-log/jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/entities/CommandJpa.java b/extensions/core/command-log/jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/entities/CommandJpa.java
index 973060a..f1d7538 100644
--- a/extensions/core/command-log/jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/entities/CommandJpa.java
+++ b/extensions/core/command-log/jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/entities/CommandJpa.java
@@ -54,10 +54,10 @@ import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.extensions.commandlog.jpa.IsisModuleExtCommandLogJpa;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
-import org.apache.isis.extensions.commandlog.model.command.ReplayState;
-import org.apache.isis.extensions.commandlog.model.util.BigDecimalUtils;
-import org.apache.isis.extensions.commandlog.model.util.StringUtils;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.ReplayState;
+import org.apache.isis.extensions.commandlog.applib.util.BigDecimalUtils;
+import org.apache.isis.extensions.commandlog.applib.util.StringUtils;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.cmd.v2.MapDto;
 
diff --git a/extensions/core/command-log/jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/entities/CommandJpaRepository.java b/extensions/core/command-log/jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/entities/CommandJpaRepository.java
index 877aa49..8309ed3 100644
--- a/extensions/core/command-log/jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/entities/CommandJpaRepository.java
+++ b/extensions/core/command-log/jpa/src/main/java/org/apache/isis/extensions/commandlog/jpa/entities/CommandJpaRepository.java
@@ -45,9 +45,9 @@ import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.iactn.InteractionProvider;
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
-import org.apache.isis.extensions.commandlog.model.command.CommandModelRepository;
-import org.apache.isis.extensions.commandlog.model.command.ReplayState;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModelRepository;
+import org.apache.isis.extensions.commandlog.applib.dom.ReplayState;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.cmd.v2.CommandsDto;
 import org.apache.isis.schema.cmd.v2.MapDto;
diff --git a/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/IsisModuleExtCommandReplayPrimary.java b/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/IsisModuleExtCommandReplayPrimary.java
index 3b78177..9fc6e4b 100644
--- a/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/IsisModuleExtCommandReplayPrimary.java
+++ b/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/IsisModuleExtCommandReplayPrimary.java
@@ -22,7 +22,7 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 import org.springframework.context.annotation.Profile;
 
-import org.apache.isis.extensions.commandlog.model.IsisModuleExtCommandLogApplib;
+import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
 import org.apache.isis.extensions.commandreplay.primary.config.PrimaryConfig;
 import org.apache.isis.extensions.commandreplay.primary.mixins.Object_openOnSecondary;
 import org.apache.isis.extensions.commandreplay.primary.restapi.CommandRetrievalService;
diff --git a/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/restapi/CommandRetrievalService.java b/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/restapi/CommandRetrievalService.java
index dd0bcef..1f2de45 100644
--- a/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/restapi/CommandRetrievalService.java
+++ b/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/restapi/CommandRetrievalService.java
@@ -28,8 +28,8 @@ import javax.inject.Named;
 import org.apache.isis.applib.annotation.*;
 import org.apache.isis.applib.annotation.PriorityPrecedence;
 import org.apache.isis.applib.exceptions.RecoverableException;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
-import org.apache.isis.extensions.commandlog.model.command.CommandModelRepository;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModelRepository;
 import org.apache.isis.extensions.commandreplay.primary.IsisModuleExtCommandReplayPrimary;
 
 import lombok.Getter;
diff --git a/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/spiimpl/CaptureResultOfCommand.java b/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/spiimpl/CaptureResultOfCommand.java
index 7365f2f..4e433d2 100644
--- a/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/spiimpl/CaptureResultOfCommand.java
+++ b/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/spiimpl/CaptureResultOfCommand.java
@@ -29,7 +29,7 @@ import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.commanddto.conmap.UserDataKeys;
 import org.apache.isis.applib.services.commanddto.processor.spi.CommandDtoProcessorService;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
 import lombok.val;
diff --git a/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/ui/CommandReplayOnPrimaryService.java b/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/ui/CommandReplayOnPrimaryService.java
index fb56ee0..b9b37ca 100644
--- a/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/ui/CommandReplayOnPrimaryService.java
+++ b/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/ui/CommandReplayOnPrimaryService.java
@@ -40,8 +40,8 @@ import org.apache.isis.applib.services.commanddto.conmap.ContentMappingServiceFo
 import org.apache.isis.applib.services.jaxb.JaxbService;
 import org.apache.isis.applib.services.message.MessageService;
 import org.apache.isis.applib.value.Clob;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
-import org.apache.isis.extensions.commandlog.model.command.CommandModelRepository;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModelRepository;
 import org.apache.isis.extensions.commandreplay.primary.IsisModuleExtCommandReplayPrimary;
 import org.apache.isis.extensions.commandreplay.primary.restapi.CommandRetrievalService;
 import org.apache.isis.schema.cmd.v2.CommandDto;
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/IsisModuleExtCommandReplaySecondary.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/IsisModuleExtCommandReplaySecondary.java
index f8e5245..6033409 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/IsisModuleExtCommandReplaySecondary.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/IsisModuleExtCommandReplaySecondary.java
@@ -38,7 +38,7 @@ import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
 import org.springframework.scheduling.quartz.SpringBeanJobFactory;
 
 import org.apache.isis.core.config.IsisConfiguration;
-import org.apache.isis.extensions.commandlog.model.IsisModuleExtCommandLogApplib;
+import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
 import org.apache.isis.extensions.commandreplay.secondary.analyser.CommandReplayAnalyserException;
 import org.apache.isis.extensions.commandreplay.secondary.analyser.CommandReplayAnalyserResult;
 import org.apache.isis.extensions.commandreplay.secondary.analysis.CommandReplayAnalysisService;
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analyser/CommandReplayAnalyser.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analyser/CommandReplayAnalyser.java
index 4264739..b86172d 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analyser/CommandReplayAnalyser.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analyser/CommandReplayAnalyser.java
@@ -18,7 +18,7 @@
  */
 package org.apache.isis.extensions.commandreplay.secondary.analyser;
 
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
 
 /**
  * @since 2.0 {@index}
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analyser/CommandReplayAnalyserException.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analyser/CommandReplayAnalyserException.java
index 1bbd919..abb0252 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analyser/CommandReplayAnalyserException.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analyser/CommandReplayAnalyserException.java
@@ -30,7 +30,7 @@ import org.apache.isis.applib.services.commanddto.conmap.UserDataKeys;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.core.config.IsisConfiguration;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
 import org.apache.isis.schema.common.v2.InteractionType;
 
 import lombok.RequiredArgsConstructor;
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analyser/CommandReplayAnalyserResult.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analyser/CommandReplayAnalyserResult.java
index c5380e3..5f7695f 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analyser/CommandReplayAnalyserResult.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analyser/CommandReplayAnalyserResult.java
@@ -29,7 +29,7 @@ import org.springframework.stereotype.Service;
 import org.apache.isis.applib.services.commanddto.conmap.UserDataKeys;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
 import org.apache.isis.core.config.IsisConfiguration;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
 import org.apache.isis.schema.common.v2.InteractionType;
 
 import lombok.RequiredArgsConstructor;
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analysis/CommandReplayAnalysisService.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analysis/CommandReplayAnalysisService.java
index 5a08e07..c2fe4e3 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analysis/CommandReplayAnalysisService.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/analysis/CommandReplayAnalysisService.java
@@ -26,7 +26,7 @@ import javax.inject.Named;
 import org.apache.isis.applib.annotation.PriorityPrecedence;
 import org.springframework.stereotype.Service;
 
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
 import org.apache.isis.extensions.commandreplay.secondary.analyser.CommandReplayAnalyser;
 
 import lombok.extern.log4j.Log4j2;
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/fetch/CommandFetcher.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/fetch/CommandFetcher.java
index 7b1ec09..472d291 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/fetch/CommandFetcher.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/fetch/CommandFetcher.java
@@ -34,7 +34,7 @@ import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.services.jaxb.JaxbService;
 import org.apache.isis.applib.services.jaxb.JaxbService.Simple;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
 import org.apache.isis.extensions.commandreplay.secondary.SecondaryStatus;
 import org.apache.isis.extensions.commandreplay.secondary.StatusException;
 import org.apache.isis.extensions.commandreplay.secondary.config.SecondaryConfig;
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/ReplicateAndRunCommands.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/ReplicateAndRunCommands.java
index 2d36807..c4b7c1f 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/ReplicateAndRunCommands.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/ReplicateAndRunCommands.java
@@ -28,9 +28,9 @@ import javax.inject.Inject;
 
 import org.apache.isis.applib.services.command.CommandExecutorService;
 import org.apache.isis.applib.services.xactn.TransactionService;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
-import org.apache.isis.extensions.commandlog.model.command.CommandModelRepository;
-import org.apache.isis.extensions.commandlog.model.command.ReplayState;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModelRepository;
+import org.apache.isis.extensions.commandlog.applib.dom.ReplayState;
 import org.apache.isis.extensions.commandreplay.secondary.SecondaryStatus;
 import org.apache.isis.extensions.commandreplay.secondary.StatusException;
 import org.apache.isis.extensions.commandreplay.secondary.analysis.CommandReplayAnalysisService;
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/mixins/CommandJdo_replayQueue.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/mixins/CommandJdo_replayQueue.java
index 81e34a1..b148baf 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/mixins/CommandJdo_replayQueue.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/mixins/CommandJdo_replayQueue.java
@@ -24,8 +24,8 @@ import javax.inject.Inject;
 
 import org.apache.isis.applib.annotation.Collection;
 import org.apache.isis.applib.annotation.CollectionLayout;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
-import org.apache.isis.extensions.commandlog.model.command.CommandModelRepository;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModelRepository;
 import org.apache.isis.extensions.commandreplay.secondary.IsisModuleExtCommandReplaySecondary;
 import org.apache.isis.extensions.commandreplay.secondary.config.SecondaryConfig;
 
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/mixins/CommandModel_exclude.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/mixins/CommandModel_exclude.java
index deadccc..ec04041 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/mixins/CommandModel_exclude.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/mixins/CommandModel_exclude.java
@@ -25,9 +25,9 @@ import javax.inject.Inject;
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.ActionLayout;
 import org.apache.isis.applib.annotation.SemanticsOf;
-import org.apache.isis.extensions.commandlog.model.IsisModuleExtCommandLogApplib;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
-import org.apache.isis.extensions.commandlog.model.command.ReplayState;
+import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.ReplayState;
 import org.apache.isis.extensions.commandreplay.secondary.config.SecondaryConfig;
 
 import lombok.RequiredArgsConstructor;
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/ui/CommandReplayOnSecondaryService.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/ui/CommandReplayOnSecondaryService.java
index 6c3bf0a..f80aa46 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/ui/CommandReplayOnSecondaryService.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/ui/CommandReplayOnSecondaryService.java
@@ -28,8 +28,8 @@ import org.apache.isis.applib.annotation.*;
 import org.apache.isis.applib.annotation.PriorityPrecedence;
 import org.apache.isis.applib.services.jaxb.JaxbService;
 import org.apache.isis.applib.value.Clob;
-import org.apache.isis.extensions.commandlog.model.command.CommandModel;
-import org.apache.isis.extensions.commandlog.model.command.CommandModelRepository;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.dom.CommandModelRepository;
 import org.apache.isis.extensions.commandreplay.secondary.IsisModuleExtCommandReplaySecondary;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.cmd.v2.CommandsDto;