You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2022/04/15 08:27:11 UTC

[isis] branch master updated: ISIS-2735: Command Replay: start unification of JDO and JPA

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

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new a91bb7e424 ISIS-2735: Command Replay: start unification of JDO and JPA
a91bb7e424 is described below

commit a91bb7e42460b21b3738b505e29009b18335a966
Author: andi-huber <ah...@apache.org>
AuthorDate: Fri Apr 15 10:27:02 2022 +0200

    ISIS-2735: Command Replay: start unification of JDO and JPA
---
 .../domain/_commands/ExposePersistedCommands.java  |   6 +-
 .../ExposePersistedCommands_commands.java          |   8 +-
 .../applib/IsisModuleExtCommandLogApplib.java      |   2 +
 .../commandlog/applib/command/CommandLog.java}     | 187 ++++---
 .../applib/command/CommandLog.layout.fallback.xml} |   0
 .../commandlog/applib/command/CommandLog.png}      | Bin
 ...elRepository.java => CommandLogRepository.java} |  18 +-
 .../{CommandModel.java => ICommandLog.java}        |  36 +-
 .../command/mixins/CommandLog_childCommands.java}  |  22 +-
 .../mixins/CommandLog_openResultObject.java}       |  19 +-
 .../mixins/CommandLog_openTargetObject.java}       |  19 +-
 .../applib/command/mixins/CommandLog_retry.java}   |  27 +-
 .../mixins/CommandLog_siblingCommands.java}        |  27 +-
 .../commandlog/jdo/IsisModuleExtCommandLogJdo.java |   4 +-
 .../commandlog/jdo/entities/CommandJdo.java        | 444 +---------------
 .../jdo/entities/CommandJdoRepository.java         |  18 +-
 .../commandlog/jpa/entities/CommandJpa.java        | 569 +--------------------
 .../jpa/entities/CommandJpaRepository.java         |  10 +-
 .../restapi/CommandRetrievalOnPrimaryService.java  |  12 +-
 .../primary/spiimpl/CaptureResultOfCommand.java    |  16 +-
 .../primary/ui/CommandReplayOnPrimaryService.java  |  17 +-
 .../secondary/analyser/CommandReplayAnalyser.java  |   4 +-
 .../analyser/CommandReplayAnalyserException.java   |   8 +-
 .../analyser/CommandReplayAnalyserResult.java      |   8 +-
 .../analysis/CommandReplayAnalysisService.java     |  10 +-
 .../secondary/fetch/CommandFetcher.java            |   6 +-
 .../jobcallables/ReplicateAndRunCommands.java      |  36 +-
 ...dModel_exclude.java => CommandLog_exclude.java} |  25 +-
 ...eplayQueue.java => CommandLog_replayQueue.java} |  18 +-
 .../ui/CommandReplayOnSecondaryService.java        |  12 +-
 .../secondary/fetch/CommandFetcher_Test.java       |   9 +-
 31 files changed, 340 insertions(+), 1257 deletions(-)

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 8e96a652e8..e0a2c4084b 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.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.PriorityPrecedence;
 import org.apache.isis.applib.services.tablecol.TableColumnOrderForCollectionTypeAbstract;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.command.ICommandLog;
 
 /**
  * Marker interface for mixins to contribute to.
@@ -35,9 +35,9 @@ public interface ExposePersistedCommands {
 
     @Service
     @javax.annotation.Priority(PriorityPrecedence.EARLY)
-    public static class TableColumnOrderDefault extends TableColumnOrderForCollectionTypeAbstract<CommandModel> {
+    public static class TableColumnOrderDefault extends TableColumnOrderForCollectionTypeAbstract<ICommandLog> {
 
-        public TableColumnOrderDefault() { super(CommandModel.class); }
+        public TableColumnOrderDefault() { super(ICommandLog.class); }
 
         @Override
         protected List<String> orderParented(Object parent, String collectionId, List<String> propertyIds) {
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 761e51c041..ccef2132fb 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
@@ -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.applib.command.CommandModel;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModelRepository;
+import org.apache.isis.extensions.commandlog.applib.command.ICommandLog;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLogRepository;
 
 import lombok.RequiredArgsConstructor;
 
@@ -39,10 +39,10 @@ public class ExposePersistedCommands_commands {
     private final ExposePersistedCommands exposePersistedCommands;
 
     //tag::class[]
-    public List<? extends CommandModel> coll() {
+    public List<? extends ICommandLog> coll() {
         return commandModelRepository.findCompleted();
     }
 
-    @Inject CommandModelRepository<? extends CommandModel> commandModelRepository;
+    @Inject CommandLogRepository<? extends ICommandLog> commandModelRepository;
 }
 //end::class[]
diff --git a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/IsisModuleExtCommandLogApplib.java b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/IsisModuleExtCommandLogApplib.java
index 94838612a6..c8190ff094 100644
--- a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/IsisModuleExtCommandLogApplib.java
+++ b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/IsisModuleExtCommandLogApplib.java
@@ -24,6 +24,8 @@ import org.apache.isis.testing.fixtures.applib.modules.ModuleWithFixtures;
 public interface IsisModuleExtCommandLogApplib
 extends ModuleWithFixtures {
 
+    public static final String NAMESPACE = "isis.ext.commandLog";
+
     public abstract static class TitleUiEvent<S>
         extends org.apache.isis.applib.events.ui.TitleUiEvent<S> { }
 
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/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandLog.java
similarity index 83%
copy from extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo.java
copy to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandLog.java
index 312481f71a..fd0f87f825 100644
--- a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo.java
+++ b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandLog.java
@@ -16,11 +16,11 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.extensions.commandlog.jdo.entities;
+package org.apache.isis.extensions.commandlog.applib.command;
 
 import java.math.BigDecimal;
 import java.sql.Timestamp;
-import java.text.SimpleDateFormat;
+import java.time.format.DateTimeFormatter;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
@@ -28,7 +28,13 @@ import java.util.Optional;
 import java.util.UUID;
 import java.util.function.Consumer;
 
-import javax.jdo.annotations.IdentityType;
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.Lob;
+import javax.persistence.Transient;
 
 import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Service;
@@ -54,11 +60,9 @@ import org.apache.isis.applib.util.TitleBuffer;
 import org.apache.isis.commons.functional.Try;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModel;
-import org.apache.isis.extensions.commandlog.applib.command.ReplayState;
+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.extensions.commandlog.jdo.IsisModuleExtCommandLogJdo;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.cmd.v2.MapDto;
 
@@ -78,6 +82,7 @@ import lombok.val;
  * Note that this class doesn't subclass from {@link Command} ({@link Command}
  * is not an interface).
  */
+/*FIXME convert to JPA
 @javax.jdo.annotations.PersistenceCapable(
         identityType=IdentityType.APPLICATION,
         schema = "isisExtensionsCommandLog",
@@ -86,36 +91,36 @@ import lombok.val;
     @javax.jdo.annotations.Query(
             name="findByInteractionIdStr",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE interactionIdStr == :interactionIdStr "),
     @javax.jdo.annotations.Query(
             name="findByParent",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE parent == :parent "),
     @javax.jdo.annotations.Query(
             name="findCurrent",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE completedAt == null "
                     + "ORDER BY this.timestamp DESC"),
     @javax.jdo.annotations.Query(
             name="findCompleted",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE completedAt != null "
                     + "ORDER BY this.timestamp DESC"),
     @javax.jdo.annotations.Query(
             name="findRecentByTarget",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE target == :target "
                     + "ORDER BY this.timestamp DESC "
                     + "RANGE 0,30"),
     @javax.jdo.annotations.Query(
             name="findByTargetAndTimestampBetween",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE target == :target "
                     + "&& timestamp >= :from "
                     + "&& timestamp <= :to "
@@ -123,58 +128,58 @@ import lombok.val;
     @javax.jdo.annotations.Query(
             name="findByTargetAndTimestampAfter",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE target == :target "
                     + "&& timestamp >= :from "
                     + "ORDER BY this.timestamp DESC"),
     @javax.jdo.annotations.Query(
             name="findByTargetAndTimestampBefore",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE target == :target "
                     + "&& timestamp <= :to "
                     + "ORDER BY this.timestamp DESC"),
     @javax.jdo.annotations.Query(
             name="findByTarget",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE target == :target "
                     + "ORDER BY this.timestamp DESC"),
     @javax.jdo.annotations.Query(
             name="findByTimestampBetween",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE timestamp >= :from "
                     + "&&    timestamp <= :to "
                     + "ORDER BY this.timestamp DESC"),
     @javax.jdo.annotations.Query(
             name="findByTimestampAfter",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE timestamp >= :from "
                     + "ORDER BY this.timestamp DESC"),
     @javax.jdo.annotations.Query(
             name="findByTimestampBefore",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE timestamp <= :to "
                     + "ORDER BY this.timestamp DESC"),
     @javax.jdo.annotations.Query(
             name="find",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " ORDER BY this.timestamp DESC"),
     @javax.jdo.annotations.Query(
             name="findRecentByUsername",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE username == :username "
                     + "ORDER BY this.timestamp DESC "
                     + "RANGE 0,30"),
     @javax.jdo.annotations.Query(
             name="findFirst",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE startedAt   != null "
                     + "   && completedAt != null "
                     + "ORDER BY this.timestamp ASC "
@@ -184,7 +189,7 @@ import lombok.val;
     @javax.jdo.annotations.Query(
             name="findSince",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE timestamp > :timestamp "
                     + "   && startedAt != null "
                     + "   && completedAt != null "
@@ -195,7 +200,7 @@ import lombok.val;
     @javax.jdo.annotations.Query(
             name="findMostRecentReplayed",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE (replayState == 'OK' || replayState == 'FAILED') "
                     + "ORDER BY this.timestamp DESC "
                     + "RANGE 0,2"), // this should be RANGE 0,1 but results in DataNucleus submitting "FETCH NEXT ROW ONLY"
@@ -206,7 +211,7 @@ import lombok.val;
     @javax.jdo.annotations.Query(
             name="findMostRecentCompleted",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE startedAt   != null "
                     + "   && completedAt != null "
                     + "ORDER BY this.timestamp DESC "
@@ -216,7 +221,7 @@ import lombok.val;
     @javax.jdo.annotations.Query(
             name="findNotYetReplayed",
             value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
+                    + "FROM " + CommandEntity.FQCN
                     + " WHERE replayState == 'PENDING' "
                     + "ORDER BY this.timestamp ASC "
                     + "RANGE 0,10"),    // same as batch size
@@ -241,34 +246,36 @@ import lombok.val;
 //        @javax.jdo.annotations.Index(name = "CommandJdo__replayState__timestamp__startedAt_IDX", members = { "replayState", "timestamp", "startedAt"}),
 //        @javax.jdo.annotations.Index(name = "CommandJdo__replayState__startedAt__completedAt_IDX", members = {"startedAt", "replayState", "completedAt"}),
 })
+*/
+@Entity
 @DomainObject(
-        logicalTypeName = CommandJdo.LOGICAL_TYPE_NAME,
+        logicalTypeName = CommandLog.LOGICAL_TYPE_NAME,
         editing = Editing.DISABLED
 )
 @DomainObjectLayout(
         named = "Command",
-        titleUiEvent = CommandModel.TitleUiEvent.class,
-        iconUiEvent = CommandModel.IconUiEvent.class,
-        cssClassUiEvent = CommandModel.CssClassUiEvent.class,
-        layoutUiEvent = CommandModel.LayoutUiEvent.class
+        titleUiEvent = ICommandLog.TitleUiEvent.class,
+        iconUiEvent = ICommandLog.IconUiEvent.class,
+        cssClassUiEvent = ICommandLog.CssClassUiEvent.class,
+        layoutUiEvent = ICommandLog.LayoutUiEvent.class
 )
 //@Log4j2
 @NoArgsConstructor
-public class CommandJdo
+public class CommandLog
 implements
-    CommandModel,
+    ICommandLog,
     DomainChangeRecord {
 
-    public final static String LOGICAL_TYPE_NAME = IsisModuleExtCommandLogJdo.NAMESPACE + ".Command";
+    public final static String LOGICAL_TYPE_NAME = IsisModuleExtCommandLogApplib.NAMESPACE + ".CommandLogEntity";
 
-    protected final static String FQCN = "org.apache.isis.extensions.commandlog.jdo.entities.CommandJdo";
+    protected final static String FQCN = "org.apache.isis.extensions.commandlog.applib.command.CommandLogEntity";
 
     /**
      * Intended for use on primary system.
      *
      * @param command
      */
-    public CommandJdo(final Command command) {
+    public CommandLog(final Command command) {
 
         setInteractionIdStr(command.getInteractionId().toString());
         setUsername(command.getUsername());
@@ -295,7 +302,7 @@ implements
      * @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 CommandJdo(
+    public CommandLog(
             final CommandDto commandDto,
             final ReplayState replayState,
             final int targetIndex) {
@@ -336,23 +343,26 @@ implements
     @Service
     public static class TitleProvider {
 
+        private final DateTimeFormatter formatter =
+                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
+
         @EventListener(TitleUiEvent.class)
         public void on(final TitleUiEvent ev) {
-            if(!Objects.equals(ev.getTitle(), "Command Jdo") || ev.getTranslatableTitle() != null) {
-                return;
+            if(ev.getTranslatableTitle() != null
+                    && ev.getSource() != null
+                    && ev.getSource().getTimestamp() != null
+                    && (Objects.equals(ev.getTitle(), "Command Jdo")
+                            || Objects.equals(ev.getTitle(), "Command Jpa")
+                    )) {
+                ev.setTitle(title((CommandLog)ev.getSource()));
             }
-            ev.setTitle(title((CommandJdo)ev.getSource()));
         }
 
-        private static String title(final CommandJdo 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();
+        private String title(final CommandLog source) {
+            return new TitleBuffer()
+            .append(formatter.format(source.getTimestamp().toLocalDateTime()))
+            .append(" ").append(source.getLogicalMemberIdentifier())
+            .toString();
         }
     }
 
@@ -363,28 +373,35 @@ implements
      * to persist if using h2 (perhaps would need to be mapped differently).
      * @see <a href="https://www.datanucleus.org/products/accessplatform/jdo/mapping.html#_other_types">www.datanucleus.org</a>
      */
-    @javax.jdo.annotations.PrimaryKey
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="false", name = "interactionId", length = 36)
+
     @Property(domainEvent = InteractionIdDomainEvent.class)
     @PropertyLayout(named = "Interaction Id")
-    @Getter @Setter
+    //@Getter
+    @Setter
     private String interactionIdStr;
-    @Override
+
+    @Id
+    @Column(nullable=false, name = "interactionId", length = 36)
+    public String getInteractionIdStr() {
+        return interactionIdStr;
+    }
+
+
     @Programmatic
+    @Override
     public UUID getInteractionId() {return UUID.fromString(getInteractionIdStr());}
 
 
     public static class UsernameDomainEvent extends PropertyDomainEvent<String> { }
-    @javax.jdo.annotations.Column(allowsNull="false", length = 50)
+    @Column(nullable=false, length = 50)
     @Property(domainEvent = UsernameDomainEvent.class)
     @Getter @Setter
     private String username;
 
 
     public static class TimestampDomainEvent extends PropertyDomainEvent<Timestamp> { }
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="false")
+
+    @Column(nullable=false)
     @Property(domainEvent = TimestampDomainEvent.class)
     @Getter @Setter
     private Timestamp timestamp;
@@ -401,7 +418,7 @@ implements
     /**
      * For a replayed command, what the outcome was.
      */
-    @javax.jdo.annotations.Column(allowsNull="true", length=10)
+    @Column(nullable=true, length=10)
     @Property(domainEvent = ReplayStateDomainEvent.class)
     @Getter @Setter
     private ReplayState replayState;
@@ -411,7 +428,7 @@ implements
     /**
      * For a {@link ReplayState#FAILED failed} replayed command, what the reason was for the failure.
      */
-    @javax.jdo.annotations.Column(allowsNull="true", length=255)
+    @Column(nullable=true, length=255)
     @Property(domainEvent = ReplayStateFailureReasonDomainEvent.class)
     @PropertyLayout(hidden = Where.ALL_TABLES, multiLine = 5)
     @Getter @Setter
@@ -422,17 +439,17 @@ implements
 
 
     public static class ParentDomainEvent extends PropertyDomainEvent<Command> { }
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(name="parentId", allowsNull="true")
+
+    @Column(name="parentId", nullable=true)
     @Property(domainEvent = ParentDomainEvent.class)
     @PropertyLayout(hidden = Where.ALL_TABLES)
     @Getter @Setter
-    private CommandJdo parent;
+    private CommandLog parent;
 
 
     public static class TargetDomainEvent extends PropertyDomainEvent<String> { }
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="true", length = 2000, name="target")
+
+    @Column(nullable=true, length = 2000, name="target")
     @Property(domainEvent = TargetDomainEvent.class)
     @PropertyLayout(named = "Object")
     @Getter @Setter
@@ -457,14 +474,15 @@ implements
     public static class LogicalMemberIdentifierDomainEvent extends PropertyDomainEvent<String> { }
     @Property(domainEvent = LogicalMemberIdentifierDomainEvent.class)
     @PropertyLayout(hidden = Where.ALL_TABLES)
-    @javax.jdo.annotations.Column(allowsNull="false", length = MemberIdentifierType.Meta.MAX_LEN)
+    @Column(nullable=false, length = MemberIdentifierType.Meta.MAX_LEN)
     @Getter @Setter
     private String logicalMemberIdentifier;
 
 
     public static class CommandDtoDomainEvent extends PropertyDomainEvent<CommandDto> { }
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="true", jdbcType="CLOB")
+
+    @Lob @Basic(fetch=FetchType.LAZY)
+    @Column(nullable=true, columnDefinition="CLOB")
     @Property(domainEvent = CommandDtoDomainEvent.class)
     @PropertyLayout(multiLine = 9)
     @Getter @Setter
@@ -472,16 +490,16 @@ implements
 
 
     public static class StartedAtDomainEvent extends PropertyDomainEvent<Timestamp> { }
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="true")
+
+    @Column(nullable=true)
     @Property(domainEvent = StartedAtDomainEvent.class)
     @Getter @Setter
     private Timestamp startedAt;
 
 
     public static class CompletedAtDomainEvent extends PropertyDomainEvent<Timestamp> { }
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="true")
+
+    @Column(nullable=true)
     @Property(domainEvent = CompletedAtDomainEvent.class)
     @Getter @Setter
     private Timestamp completedAt;
@@ -494,7 +512,7 @@ implements
      * <p>
      * Populated only if it has {@link #getCompletedAt() completed}.
      */
-    @javax.jdo.annotations.NotPersistent
+    @Transient
     @javax.validation.constraints.Digits(integer=5, fraction=3)
     @Property(domainEvent = DurationDomainEvent.class)
     public BigDecimal getDuration() {
@@ -503,7 +521,7 @@ implements
 
 
     public static class IsCompleteDomainEvent extends PropertyDomainEvent<Boolean> { }
-    @javax.jdo.annotations.NotPersistent
+    @Transient
     @Property(domainEvent = IsCompleteDomainEvent.class)
     @PropertyLayout(hidden = Where.OBJECT_FORMS)
     public boolean isComplete() {
@@ -512,7 +530,7 @@ implements
 
 
     public static class ResultSummaryDomainEvent extends PropertyDomainEvent<String> { }
-    @javax.jdo.annotations.NotPersistent
+    @Transient
     @Property(domainEvent = ResultSummaryDomainEvent.class)
     @PropertyLayout(hidden = Where.OBJECT_FORMS, named = "Result")
     public String getResultSummary() {
@@ -531,8 +549,8 @@ implements
 
 
     public static class ResultDomainEvent extends PropertyDomainEvent<String> { }
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="true", length = 2000, name="result")
+
+    @Column(nullable=true, length = 2000, name="result")
     @Property(domainEvent = ResultDomainEvent.class)
     @PropertyLayout(hidden = Where.ALL_TABLES, named = "Result Bookmark")
     @Getter @Setter
@@ -546,7 +564,8 @@ implements
      * 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.
      */
-    @javax.jdo.annotations.Column(allowsNull="true", jdbcType="CLOB")
+    @Lob @Basic(fetch=FetchType.LAZY)
+    @Column(nullable=true, columnDefinition="CLOB")
     @Property(domainEvent = ExceptionDomainEvent.class)
     @PropertyLayout(hidden = Where.ALL_TABLES, multiLine = 5, named = "Exception (if any)")
     @Getter
@@ -559,7 +578,7 @@ implements
     }
 
     public static class IsCausedExceptionDomainEvent extends PropertyDomainEvent<Boolean> { }
-    @javax.jdo.annotations.NotPersistent
+    @Transient
     @Property(domainEvent = IsCausedExceptionDomainEvent.class)
     @PropertyLayout(hidden = Where.OBJECT_FORMS)
     public boolean isCausedException() {
@@ -599,23 +618,23 @@ implements
         return new CommandOutcomeHandler() {
             @Override
             public Timestamp getStartedAt() {
-                return CommandJdo.this.getStartedAt();
+                return CommandLog.this.getStartedAt();
             }
 
             @Override
             public void setStartedAt(final Timestamp startedAt) {
-                CommandJdo.this.setStartedAt(startedAt);
+                CommandLog.this.setStartedAt(startedAt);
             }
 
             @Override
             public void setCompletedAt(final Timestamp completedAt) {
-                CommandJdo.this.setCompletedAt(completedAt);
+                CommandLog.this.setCompletedAt(completedAt);
             }
 
             @Override
             public void setResult(final Try<Bookmark> resultBookmark) {
-                CommandJdo.this.setResult(resultBookmark.getValue().orElse(null));
-                CommandJdo.this.setException(resultBookmark.getFailure().orElse(null));
+                CommandLog.this.setResult(resultBookmark.getValue().orElse(null));
+                CommandLog.this.setException(resultBookmark.getFailure().orElse(null));
             }
 
         };
@@ -623,9 +642,9 @@ implements
 
     @Service
     @javax.annotation.Priority(PriorityPrecedence.LATE - 10) // before the framework's own default.
-    public static class TableColumnOrderDefault extends TableColumnOrderForCollectionTypeAbstract<CommandJdo> {
+    public static class TableColumnOrderDefault extends TableColumnOrderForCollectionTypeAbstract<CommandLog> {
 
-        public TableColumnOrderDefault() { super(CommandJdo.class); }
+        public TableColumnOrderDefault() { super(CommandLog.class); }
 
         @Override
         protected List<String> orderParented(final Object parent, final String collectionId, final List<String> propertyIds) {
diff --git a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo.layout.fallback.xml b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandLog.layout.fallback.xml
similarity index 100%
rename from extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo.layout.fallback.xml
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandLog.layout.fallback.xml
diff --git a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo.png b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandLog.png
similarity index 100%
rename from extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo.png
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandLog.png
diff --git a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandModelRepository.java b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandLogRepository.java
similarity index 86%
rename from extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandModelRepository.java
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandLogRepository.java
index 175ca86703..21cc1aa9f5 100644
--- a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandModelRepository.java
+++ b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandLogRepository.java
@@ -32,11 +32,11 @@ import org.apache.isis.schema.cmd.v2.CommandsDto;
 
 import lombok.Getter;
 
-public interface CommandModelRepository<C extends CommandModel> {
+public interface CommandLogRepository<C extends ICommandLog> {
 
     Optional<C> findByInteractionId(UUID interactionId);
 
-    List<C> findByParent(CommandModel parent);
+    List<C> findByParent(ICommandLog parent);
 
     List<C> findByFromAndTo(LocalDate from, LocalDate to);
 
@@ -54,27 +54,27 @@ public interface CommandModelRepository<C extends CommandModel> {
      * Intended to support the replay of commands on a secondary instance of
      * the application.
      *
-     * This finder returns all (completed) {@link CommandModel}s started after
+     * This finder returns all (completed) {@link ICommandLog}s started after
      * the command with the specified interactionId.  The number of commands
      * returned can be limited so that they can be applied in batches.
      *
      * If the provided interactionId is null, then only a single
-     * {@link CommandModel command} is returned.  This is intended to support
+     * {@link ICommandLog command} is returned.  This is intended to support
      * the case when the secondary does not yet have any
-     * {@link CommandModel command}s replicated.  In practice this is unlikely;
+     * {@link ICommandLog command}s replicated.  In practice this is unlikely;
      * typically we expect that the secondary will be set up to run against a
      * copy of the primary instance's DB (restored from a backup), in which
-     * case there will already be a {@link CommandModel command} representing the
+     * case there will already be a {@link ICommandLog command} representing the
      * current high water mark on the secondary system.
      *
      * If the interactionId is not null but the corresponding
-     * {@link CommandModel command} is not found, then <tt>null</tt> is returned.
+     * {@link ICommandLog command} is not found, then <tt>null</tt> is returned.
      * In the replay scenario the caller will probably interpret this as an
      * error because it means that the high water mark on the secondary is
-     * inaccurate, referring to a non-existent {@link CommandModel command} on
+     * inaccurate, referring to a non-existent {@link ICommandLog command} on
      * the primary.
      *
-     * @param interactionId - the identifier of the {@link CommandModel command} being
+     * @param interactionId - the identifier of the {@link ICommandLog command} being
      *                   the replay HWM (using {@link #findMostRecentReplayed()} on the
      *                   secondary), or null if no HWM was found there.
      * @param batchSize - to restrict the number returned (so that replay
diff --git a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandModel.java b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/ICommandLog.java
similarity index 69%
rename from extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandModel.java
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/ICommandLog.java
index 9be9a3f24f..8a59751229 100644
--- a/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/CommandModel.java
+++ b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/ICommandLog.java
@@ -28,19 +28,19 @@ import org.apache.isis.applib.util.ObjectContracts;
 import org.apache.isis.applib.util.ToString;
 import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
 
-public interface CommandModel
+public interface ICommandLog
 extends
     HasCommandDto,
-    Comparable<CommandModel> {
+    Comparable<ICommandLog> {
 
-    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 class TitleUiEvent extends IsisModuleExtCommandLogApplib.TitleUiEvent<ICommandLog> { }
+    public static class IconUiEvent extends IsisModuleExtCommandLogApplib.IconUiEvent<ICommandLog> { }
+    public static class CssClassUiEvent extends IsisModuleExtCommandLogApplib.CssClassUiEvent<ICommandLog> { }
+    public static class LayoutUiEvent extends IsisModuleExtCommandLogApplib.LayoutUiEvent<ICommandLog> { }
 
-    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> { }
+    public static abstract class PropertyDomainEvent<T> extends IsisModuleExtCommandLogApplib.PropertyDomainEvent<ICommandLog, T> { }
+    public static abstract class CollectionDomainEvent<T> extends IsisModuleExtCommandLogApplib.CollectionDomainEvent<ICommandLog, T> { }
+    public static abstract class ActionDomainEvent extends IsisModuleExtCommandLogApplib.ActionDomainEvent<ICommandLog> { }
 
 
     Bookmark getResult();
@@ -67,21 +67,21 @@ extends
 
     void setReplayState(ReplayState excluded);
 
-    static final ToString<CommandModel> stringifier = ObjectContracts
-        .toString("interactionId", CommandModel::getInteractionId)
-        .thenToString("username", CommandModel::getUsername)
-        .thenToString("timestamp", CommandModel::getTimestamp)
-        .thenToString("target", CommandModel::getTarget)
-        .thenToString("logicalMemberIdentifier", CommandModel::getLogicalMemberIdentifier)
-        .thenToStringOmitIfAbsent("startedAt", CommandModel::getStartedAt)
-        .thenToStringOmitIfAbsent("completedAt", CommandModel::getCompletedAt);
+    static final ToString<ICommandLog> stringifier = ObjectContracts
+        .toString("interactionId", ICommandLog::getInteractionId)
+        .thenToString("username", ICommandLog::getUsername)
+        .thenToString("timestamp", ICommandLog::getTimestamp)
+        .thenToString("target", ICommandLog::getTarget)
+        .thenToString("logicalMemberIdentifier", ICommandLog::getLogicalMemberIdentifier)
+        .thenToStringOmitIfAbsent("startedAt", ICommandLog::getStartedAt)
+        .thenToStringOmitIfAbsent("completedAt", ICommandLog::getCompletedAt);
 
     default String toFriendlyString() {
         return stringifier.toString(this);
     }
 
     @Override
-    default int compareTo(final CommandModel other) {
+    default int compareTo(final ICommandLog other) {
         return this.getTimestamp().compareTo(other.getTimestamp());
     }
 
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/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_childCommands.java
similarity index 67%
rename from extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_childCommands.java
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_childCommands.java
index 4e5766854b..90d8e0d372 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/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_childCommands.java
@@ -16,38 +16,42 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.extensions.commandlog.jdo.entities;
+package org.apache.isis.extensions.commandlog.applib.command.mixins;
 
 import java.util.List;
 
 import org.apache.isis.applib.annotation.Collection;
 import org.apache.isis.applib.annotation.CollectionLayout;
+import org.apache.isis.applib.annotation.MemberSupport;
 import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.command.ICommandLog;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLog;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLogRepository;
 
 import lombok.RequiredArgsConstructor;
 
 
 @Collection(
-    domainEvent = CommandJdo_childCommands.CollectionDomainEvent.class
+    domainEvent = CommandLog_childCommands.CollectionDomainEvent.class
 )
 @CollectionLayout(
     defaultView = "table",
     sequence = "100.100"
 )
 @RequiredArgsConstructor
-public class CommandJdo_childCommands {
+public class CommandLog_childCommands {
 
     public static class CollectionDomainEvent
-            extends IsisModuleExtCommandLogApplib.CollectionDomainEvent<CommandJdo_childCommands, CommandModel> { }
+            extends IsisModuleExtCommandLogApplib.CollectionDomainEvent<CommandLog_childCommands, ICommandLog> { }
 
-    private final CommandJdo commandJdo;
+    private final CommandLog commandLog;
 
-    public List<CommandJdo> coll() {
-        return commandJdoRepository.findByParent(commandJdo);
+    @MemberSupport
+    public List<CommandLog> coll() {
+        return commandLogRepository.findByParent(commandLog);
     }
 
     @javax.inject.Inject
-    private CommandJdoRepository commandJdoRepository;
+    private CommandLogRepository<CommandLog> commandLogRepository;
 
 }
diff --git a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_openResultObject.java b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_openResultObject.java
similarity index 77%
rename from extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_openResultObject.java
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_openResultObject.java
index aee88d9de3..663ae1e3f7 100644
--- a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_openResultObject.java
+++ b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_openResultObject.java
@@ -16,43 +16,46 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.extensions.commandlog.jdo.entities;
+package org.apache.isis.extensions.commandlog.applib.command.mixins;
 
 import javax.inject.Inject;
 
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.MemberSupport;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.services.message.MessageService;
 import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLog;
 
 import lombok.RequiredArgsConstructor;
 import lombok.val;
 
 @Action(
     semantics = SemanticsOf.SAFE,
-    domainEvent = CommandJdo_openResultObject.ActionDomainEvent.class
+    domainEvent = CommandLog_openResultObject.ActionDomainEvent.class
 )
 @ActionLayout(named = "Open", associateWith = "result", sequence="1")
 @RequiredArgsConstructor
-public class CommandJdo_openResultObject {
+public class CommandLog_openResultObject {
 
     public static class ActionDomainEvent
-            extends IsisModuleExtCommandLogApplib.ActionDomainEvent<CommandJdo_openResultObject> { }
+            extends IsisModuleExtCommandLogApplib.ActionDomainEvent<CommandLog_openResultObject> { }
 
-    private final CommandJdo commandJdo;
+    private final CommandLog commandLog;
 
+    @MemberSupport
     public Object act() {
-        val targetBookmark = bookmarkService.lookup(commandJdo.getResult()).orElse(null);
+        val targetBookmark = bookmarkService.lookup(commandLog.getResult()).orElse(null);
         if(targetBookmark == null) {
             messageService.warnUser("Object not found - has it since been deleted?");
             return null;
         }
         return targetBookmark;
     }
-    public boolean hideAct() {
-        return commandJdo.getResult() == null;
+    @MemberSupport public boolean hideAct() {
+        return commandLog.getResult() == null;
     }
 
     @Inject BookmarkService bookmarkService;
diff --git a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_openTargetObject.java b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_openTargetObject.java
similarity index 77%
rename from extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_openTargetObject.java
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_openTargetObject.java
index 53ffcf9f77..a9d680382c 100644
--- a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_openTargetObject.java
+++ b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_openTargetObject.java
@@ -16,43 +16,46 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.extensions.commandlog.jdo.entities;
+package org.apache.isis.extensions.commandlog.applib.command.mixins;
 
 import javax.inject.Inject;
 
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.MemberSupport;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.services.message.MessageService;
 import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLog;
 
 import lombok.RequiredArgsConstructor;
 import lombok.val;
 
 @Action(
     semantics = SemanticsOf.SAFE,
-    domainEvent = CommandJdo_openTargetObject.ActionDomainEvent.class
+    domainEvent = CommandLog_openTargetObject.ActionDomainEvent.class
 )
 @ActionLayout(named = "Open", associateWith = "target", sequence="1")
 @RequiredArgsConstructor
-public class CommandJdo_openTargetObject {
+public class CommandLog_openTargetObject {
 
     public static class ActionDomainEvent
-            extends IsisModuleExtCommandLogApplib.ActionDomainEvent<CommandJdo_openTargetObject> { }
+            extends IsisModuleExtCommandLogApplib.ActionDomainEvent<CommandLog_openTargetObject> { }
 
-    private final CommandJdo commandJdo;
+    private final CommandLog commandLog;
 
+    @MemberSupport
     public Object act() {
-        val targetBookmark = bookmarkService.lookup(commandJdo.getTarget()).orElse(null);
+        val targetBookmark = bookmarkService.lookup(commandLog.getTarget()).orElse(null);
         if(targetBookmark == null) {
             messageService.warnUser("Object not found - has it since been deleted?");
             return null;
         }
         return targetBookmark;
     }
-    public boolean hideAct() {
-        return commandJdo.getTarget() == null;
+    @MemberSupport public boolean hideAct() {
+        return commandLog.getTarget() == null;
     }
 
     @Inject BookmarkService bookmarkService;
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/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_retry.java
similarity index 77%
rename from extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_retry.java
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_retry.java
index 6c1c524d5b..1ff4fa1cd3 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/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_retry.java
@@ -16,12 +16,13 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.extensions.commandlog.jdo.entities;
+package org.apache.isis.extensions.commandlog.applib.command.mixins;
 
 import javax.inject.Inject;
 
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.MemberSupport;
 import org.apache.isis.applib.annotation.Publishing;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
@@ -31,33 +32,35 @@ import org.apache.isis.applib.services.metamodel.MetaModelService;
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.applib.services.xactn.TransactionService;
 import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLog;
 import org.apache.isis.extensions.commandlog.applib.command.ReplayState;
 
 import lombok.RequiredArgsConstructor;
 
 @Action(
     semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE,
-    domainEvent = CommandJdo_retry.ActionDomainEvent.class,
+    domainEvent = CommandLog_retry.ActionDomainEvent.class,
     commandPublishing = Publishing.DISABLED
 )
 @ActionLayout(associateWith = "executeIn", sequence = "1")
 @RequiredArgsConstructor
-public class CommandJdo_retry {
+public class CommandLog_retry {
 
-    private final CommandJdo commandJdo;
+    private final CommandLog commandLog;
 
     public static class ActionDomainEvent
-        extends IsisModuleExtCommandLogApplib.ActionDomainEvent<CommandJdo_retry> { }
+        extends IsisModuleExtCommandLogApplib.ActionDomainEvent<CommandLog_retry> { }
 
-    public CommandJdo act() {
+    @MemberSupport
+    public CommandLog act() {
 
-        commandJdo.setReplayState(ReplayState.PENDING);
-        commandJdo.setResult(null);
-        commandJdo.setException((Exception)null);
-        commandJdo.setStartedAt(null);
-        commandJdo.setCompletedAt(null);
+        commandLog.setReplayState(ReplayState.PENDING);
+        commandLog.setResult(null);
+        commandLog.setException((Exception)null);
+        commandLog.setStartedAt(null);
+        commandLog.setCompletedAt(null);
 
-        return commandJdo;
+        return commandLog;
     }
 
     @Inject InteractionService interactionService;
diff --git a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_siblingCommands.java b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_siblingCommands.java
similarity index 65%
rename from extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_siblingCommands.java
rename to extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_siblingCommands.java
index 73060d1082..099e9dc81f 100644
--- a/extensions/core/command-log/jdo/src/main/java/org/apache/isis/extensions/commandlog/jdo/entities/CommandJdo_siblingCommands.java
+++ b/extensions/core/command-log/applib/src/main/java/org/apache/isis/extensions/commandlog/applib/command/mixins/CommandLog_siblingCommands.java
@@ -16,45 +16,48 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.extensions.commandlog.jdo.entities;
+package org.apache.isis.extensions.commandlog.applib.command.mixins;
 
 import java.util.Collections;
 import java.util.List;
 
-import javax.inject.Inject;
-
 import org.apache.isis.applib.annotation.Collection;
 import org.apache.isis.applib.annotation.CollectionLayout;
+import org.apache.isis.applib.annotation.MemberSupport;
 import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLog;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLogRepository;
 
 import lombok.RequiredArgsConstructor;
 
 @Collection(
-    domainEvent = CommandJdo_siblingCommands.CollectionDomainEvent.class
+    domainEvent = CommandLog_siblingCommands.CollectionDomainEvent.class
 )
 @CollectionLayout(
     defaultView = "table",
     sequence = "100.110"
 )
 @RequiredArgsConstructor
-public class CommandJdo_siblingCommands {
+public class CommandLog_siblingCommands {
 
     public static class CollectionDomainEvent
-            extends IsisModuleExtCommandLogApplib.CollectionDomainEvent<CommandJdo_siblingCommands, CommandJdo> { }
+            extends IsisModuleExtCommandLogApplib.CollectionDomainEvent<CommandLog_siblingCommands, CommandLog> { }
 
-    private final CommandJdo commandJdo;
+    private final CommandLog commandLog;
 
-    public List<CommandJdo> coll() {
-        final CommandJdo parentJdo = commandJdo.getParent();
+    @MemberSupport
+    public List<CommandLog> coll() {
+        final CommandLog parentJdo = commandLog.getParent();
         if(parentJdo == null) {
             return Collections.emptyList();
         }
-        final List<CommandJdo> siblingCommands = commandJdoRepository.findByParent(parentJdo);
-        siblingCommands.remove(commandJdo);
+        final List<CommandLog> siblingCommands = commandLogRepository.findByParent(parentJdo);
+        siblingCommands.remove(commandLog);
         return siblingCommands;
     }
 
 
-    @Inject CommandJdoRepository commandJdoRepository;
+    @javax.inject.Inject
+    private CommandLogRepository<CommandLog> commandLogRepository;
 
 }
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 a0cb49c4c6..a45dfd4f18 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
@@ -22,7 +22,7 @@ import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 
-import org.apache.isis.extensions.commandlog.applib.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.command.ICommandLog;
 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;
@@ -60,7 +60,7 @@ public class IsisModuleExtCommandLogJdo {
         return new TeardownFixtureJdoAbstract() {
             @Override
             protected void execute(final ExecutionContext executionContext) {
-                deleteFrom(CommandModel.class);
+                deleteFrom(ICommandLog.class);
             }
         };
     }
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 312481f71a..98e78087cf 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
@@ -18,70 +18,33 @@
  */
 package org.apache.isis.extensions.commandlog.jdo.entities;
 
-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 javax.jdo.annotations.IdentityType;
-
-import org.springframework.context.event.EventListener;
-import org.springframework.stereotype.Service;
+import javax.persistence.Entity;
+import javax.persistence.Table;
 
 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.PriorityPrecedence;
-import org.apache.isis.applib.annotation.Programmatic;
-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.Command;
-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.types.MemberIdentifierType;
-import org.apache.isis.applib.util.TitleBuffer;
-import org.apache.isis.commons.functional.Try;
-import org.apache.isis.commons.internal.base._Strings;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLog;
 import org.apache.isis.extensions.commandlog.applib.command.ReplayState;
-import org.apache.isis.extensions.commandlog.applib.util.BigDecimalUtils;
-import org.apache.isis.extensions.commandlog.applib.util.StringUtils;
 import org.apache.isis.extensions.commandlog.jdo.IsisModuleExtCommandLogJdo;
 import org.apache.isis.schema.cmd.v2.CommandDto;
-import org.apache.isis.schema.cmd.v2.MapDto;
 
-import lombok.Getter;
 import lombok.NoArgsConstructor;
-import lombok.Setter;
-import lombok.val;
 
 /**
- * A persistent representation of a {@link Command}.
- *
- * <p>
- *     Use cases requiring persistence including auditing, and for replay of
- *     commands for regression testing purposes.
- * </p>
- *
- * Note that this class doesn't subclass from {@link Command} ({@link Command}
- * is not an interface).
+ * @deprecated use {@link CommandLog} instead
  */
-@javax.jdo.annotations.PersistenceCapable(
-        identityType=IdentityType.APPLICATION,
+//@javax.jdo.annotations.PersistenceCapable(
+//        identityType = IdentityType.APPLICATION,
+//        schema = "isisExtensionsCommandLog",
+//        table = "Command")
+
+@Entity
+@Table(
         schema = "isisExtensionsCommandLog",
-        table = "Command")
+        name = "Command"
+)
+
 @javax.jdo.annotations.Queries( {
     @javax.jdo.annotations.Query(
             name="findByInteractionIdStr",
@@ -245,21 +208,13 @@ import lombok.val;
         logicalTypeName = CommandJdo.LOGICAL_TYPE_NAME,
         editing = Editing.DISABLED
 )
-@DomainObjectLayout(
-        named = "Command",
-        titleUiEvent = CommandModel.TitleUiEvent.class,
-        iconUiEvent = CommandModel.IconUiEvent.class,
-        cssClassUiEvent = CommandModel.CssClassUiEvent.class,
-        layoutUiEvent = CommandModel.LayoutUiEvent.class
-)
 //@Log4j2
+@Deprecated
 @NoArgsConstructor
 public class CommandJdo
-implements
-    CommandModel,
-    DomainChangeRecord {
+extends CommandLog {
 
-    public final static String LOGICAL_TYPE_NAME = IsisModuleExtCommandLogJdo.NAMESPACE + ".Command";
+    public final static String LOGICAL_TYPE_NAME = IsisModuleExtCommandLogJdo.NAMESPACE + ".CommandJdo";
 
     protected final static String FQCN = "org.apache.isis.extensions.commandlog.jdo.entities.CommandJdo";
 
@@ -269,22 +224,7 @@ implements
      * @param command
      */
     public CommandJdo(final 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);
+        super(command);
     }
 
 
@@ -299,349 +239,15 @@ implements
             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((CommandJdo)ev.getSource()));
-        }
-
-        private static String title(final CommandJdo 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();
-        }
-    }
-
-
-    public static class InteractionIdDomainEvent extends PropertyDomainEvent<String> { }
-    /**
-     * Implementation note: persisted as a string rather than a UUID as fails
-     * to persist if using h2 (perhaps would need to be mapped differently).
-     * @see <a href="https://www.datanucleus.org/products/accessplatform/jdo/mapping.html#_other_types">www.datanucleus.org</a>
-     */
-    @javax.jdo.annotations.PrimaryKey
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="false", name = "interactionId", length = 36)
-    @Property(domainEvent = InteractionIdDomainEvent.class)
-    @PropertyLayout(named = "Interaction Id")
-    @Getter @Setter
-    private String interactionIdStr;
-    @Override
-    @Programmatic
-    public UUID getInteractionId() {return UUID.fromString(getInteractionIdStr());}
-
-
-    public static class UsernameDomainEvent extends PropertyDomainEvent<String> { }
-    @javax.jdo.annotations.Column(allowsNull="false", length = 50)
-    @Property(domainEvent = UsernameDomainEvent.class)
-    @Getter @Setter
-    private String username;
-
-
-    public static class TimestampDomainEvent extends PropertyDomainEvent<Timestamp> { }
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="false")
-    @Property(domainEvent = TimestampDomainEvent.class)
-    @Getter @Setter
-    private Timestamp timestamp;
-
-
-
-    @Override
-    public ChangeType getType() {
-        return ChangeType.COMMAND;
-    }
-
-
-    public static class ReplayStateDomainEvent extends PropertyDomainEvent<ReplayState> { }
-    /**
-     * For a replayed command, what the outcome was.
-     */
-    @javax.jdo.annotations.Column(allowsNull="true", length=10)
-    @Property(domainEvent = ReplayStateDomainEvent.class)
-    @Getter @Setter
-    private ReplayState replayState;
-
-
-    public static class ReplayStateFailureReasonDomainEvent extends PropertyDomainEvent<ReplayState> { }
-    /**
-     * For a {@link ReplayState#FAILED failed} replayed command, what the reason was for the failure.
-     */
-    @javax.jdo.annotations.Column(allowsNull="true", length=255)
-    @Property(domainEvent = ReplayStateFailureReasonDomainEvent.class)
-    @PropertyLayout(hidden = Where.ALL_TABLES, multiLine = 5)
-    @Getter @Setter
-    private String replayStateFailureReason;
-    @MemberSupport public boolean hideReplayStateFailureReason() {
-        return getReplayState() == null || !getReplayState().isFailed();
-    }
-
-
-    public static class ParentDomainEvent extends PropertyDomainEvent<Command> { }
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(name="parentId", allowsNull="true")
-    @Property(domainEvent = ParentDomainEvent.class)
-    @PropertyLayout(hidden = Where.ALL_TABLES)
-    @Getter @Setter
-    private CommandJdo parent;
-
-
-    public static class TargetDomainEvent extends PropertyDomainEvent<String> { }
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="true", length = 2000, name="target")
-    @Property(domainEvent = TargetDomainEvent.class)
-    @PropertyLayout(named = "Object")
-    @Getter @Setter
-    private Bookmark target;
-
-    public String getTargetStr() {
-        return Optional.ofNullable(getTarget()).map(Bookmark::toString).orElse(null);
+        super(commandDto, replayState, targetIndex);
     }
 
-    @Override
-    public String getTargetMember() {
-        return getCommandDto().getMember().getLogicalMemberIdentifier();
-    }
-
-    @Property(domainEvent = TargetDomainEvent.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)
-    @javax.jdo.annotations.Column(allowsNull="false", length = MemberIdentifierType.Meta.MAX_LEN)
-    @Getter @Setter
-    private String logicalMemberIdentifier;
-
-
-    public static class CommandDtoDomainEvent extends PropertyDomainEvent<CommandDto> { }
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="true", jdbcType="CLOB")
-    @Property(domainEvent = CommandDtoDomainEvent.class)
-    @PropertyLayout(multiLine = 9)
-    @Getter @Setter
-    private CommandDto commandDto;
-
-
-    public static class StartedAtDomainEvent extends PropertyDomainEvent<Timestamp> { }
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="true")
-    @Property(domainEvent = StartedAtDomainEvent.class)
-    @Getter @Setter
-    private Timestamp startedAt;
-
-
-    public static class CompletedAtDomainEvent extends PropertyDomainEvent<Timestamp> { }
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="true")
-    @Property(domainEvent = CompletedAtDomainEvent.class)
-    @Getter @Setter
-    private 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.jdo.annotations.NotPersistent
-    @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> { }
-    @javax.jdo.annotations.NotPersistent
-    @Property(domainEvent = IsCompleteDomainEvent.class)
-    @PropertyLayout(hidden = Where.OBJECT_FORMS)
-    public boolean isComplete() {
-        return getCompletedAt() != null;
-    }
-
-
-    public static class ResultSummaryDomainEvent extends PropertyDomainEvent<String> { }
-    @javax.jdo.annotations.NotPersistent
-    @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> { }
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="true", length = 2000, name="result")
-    @Property(domainEvent = ResultDomainEvent.class)
-    @PropertyLayout(hidden = Where.ALL_TABLES, named = "Result Bookmark")
-    @Getter @Setter
-    private 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.
-     */
-    @javax.jdo.annotations.Column(allowsNull="true", jdbcType="CLOB")
-    @Property(domainEvent = ExceptionDomainEvent.class)
-    @PropertyLayout(hidden = Where.ALL_TABLES, multiLine = 5, named = "Exception (if any)")
-    @Getter
-    private String exception;
-    public void setException(final String exception) {
-        this.exception = exception;
-    }
-    public void setException(final Throwable exception) {
-        setException(_Exceptions.asStacktrace(exception));
-    }
-
-    public static class IsCausedExceptionDomainEvent extends PropertyDomainEvent<Boolean> { }
-    @javax.jdo.annotations.NotPersistent
-    @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;
-    }
-
-
-    @Override
-    public void saveAnalysis(final String analysis) {
-        if (analysis == null) {
-            setReplayState(ReplayState.OK);
-        } else {
-            setReplayState(ReplayState.FAILED);
-            setReplayStateFailureReason(StringUtils.trimmed(analysis, 255));
-        }
-
-    }
+//    @Override
+//    @Id
+//    @Column(nullable=false, name = "interactionId", length = 36)
+//    public String getInteractionIdStr() {
+//        return super.getInteractionIdStr();
+//    }
 
-    @Override
-    public String toString() {
-        return toFriendlyString();
-    }
-
-    @Override
-    public CommandOutcomeHandler outcomeHandler() {
-        return new CommandOutcomeHandler() {
-            @Override
-            public Timestamp getStartedAt() {
-                return CommandJdo.this.getStartedAt();
-            }
-
-            @Override
-            public void setStartedAt(final Timestamp startedAt) {
-                CommandJdo.this.setStartedAt(startedAt);
-            }
-
-            @Override
-            public void setCompletedAt(final Timestamp completedAt) {
-                CommandJdo.this.setCompletedAt(completedAt);
-            }
-
-            @Override
-            public void setResult(final Try<Bookmark> resultBookmark) {
-                CommandJdo.this.setResult(resultBookmark.getValue().orElse(null));
-                CommandJdo.this.setException(resultBookmark.getFailure().orElse(null));
-            }
-
-        };
-    }
-
-    @Service
-    @javax.annotation.Priority(PriorityPrecedence.LATE - 10) // before the framework's own default.
-    public static class TableColumnOrderDefault extends TableColumnOrderForCollectionTypeAbstract<CommandJdo> {
-
-        public TableColumnOrderDefault() { super(CommandJdo.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/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 cdd768b435..1eec66efbb 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,8 +45,8 @@ 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.applib.command.CommandModel;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModelRepository;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLogRepository;
+import org.apache.isis.extensions.commandlog.applib.command.ICommandLog;
 import org.apache.isis.extensions.commandlog.applib.command.ReplayState;
 import org.apache.isis.extensions.commandlog.jdo.IsisModuleExtCommandLogJdo;
 import org.apache.isis.persistence.jdo.applib.services.JdoSupportService;
@@ -70,7 +70,7 @@ import lombok.val;
 @RequiredArgsConstructor
 //@Log4j2
 public class CommandJdoRepository
-implements CommandModelRepository<CommandJdo> {
+implements CommandLogRepository<CommandJdo> {
 
     @Inject final Provider<InteractionProvider> interactionProviderProvider;
     @Inject final Provider<RepositoryService> repositoryServiceProvider;
@@ -112,7 +112,7 @@ implements CommandModelRepository<CommandJdo> {
     }
 
     @Override
-    public List<CommandJdo> findByParent(final CommandModel parent) {
+    public List<CommandJdo> findByParent(final ICommandLog parent) {
         return repositoryService().allMatches(
                 Query.named(CommandJdo.class, "findByParent")
                     .withParameter("parent", parent));
@@ -211,13 +211,9 @@ implements CommandModelRepository<CommandJdo> {
 
 
     private CommandJdo findByInteractionIdElseNull(final UUID interactionId) {
-        val tsq = jdoSupport.newTypesafeQuery(CommandJdo.class);
-        val cand = QCommandJdo.candidate();
-        val q = tsq.filter(
-                cand.interactionIdStr.eq(tsq.parameter("interactionIdStr", String.class))
-        );
-        q.setParameter("interactionIdStr", interactionId.toString());
-        return q.executeUnique();
+        val q = Query.named(CommandJdo.class, "findByInteractionIdStr")
+        .withParameter("interactionIdStr", interactionId.toString());
+        return repositoryService().uniqueMatch(q).orElse(null);
     }
 
     private List<CommandJdo> findSince(
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 dc14511959..2ac4cd903c 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
@@ -18,232 +18,31 @@
  */
 package org.apache.isis.extensions.commandlog.jpa.entities;
 
-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 javax.persistence.Entity;
 
-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.PriorityPrecedence;
-import org.apache.isis.applib.annotation.Programmatic;
-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.Command;
-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.TitleBuffer;
-import org.apache.isis.commons.functional.Try;
-import org.apache.isis.commons.internal.base._Strings;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLog;
 import org.apache.isis.extensions.commandlog.applib.command.ReplayState;
-import org.apache.isis.extensions.commandlog.applib.util.BigDecimalUtils;
-import org.apache.isis.extensions.commandlog.applib.util.StringUtils;
 import org.apache.isis.extensions.commandlog.jpa.IsisModuleExtCommandLogJpa;
 import org.apache.isis.schema.cmd.v2.CommandDto;
-import org.apache.isis.schema.cmd.v2.MapDto;
 
-import lombok.Getter;
 import lombok.NoArgsConstructor;
-import lombok.Setter;
-import lombok.val;
 
 /**
- * A persistent representation of a {@link Command}.
- *
- * <p>
- *     Use cases requiring persistence including auditing, and for replay of
- *     commands for regression testing purposes.
- * </p>
- *
- * Note that this class doesn't subclass from {@link Command} ({@link Command}
- * is not an interface).
+ * @deprecated use {@link CommandLog} instead
  */
-/* TODO migrate to JPA
-@javax.jdo.annotations.PersistenceCapable(
-        identityType=IdentityType.APPLICATION,
-        schema = "isisExtensionsCommandLog",
-        table = "Command")
-@javax.jdo.annotations.Queries( {
-    @javax.jdo.annotations.Query(
-            name="findByInteractionIdStr",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE interactionIdStr == :interactionIdStr "),
-    @javax.jdo.annotations.Query(
-            name="findByParent",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE parent == :parent "),
-    @javax.jdo.annotations.Query(
-            name="findCurrent",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE completedAt == null "
-                    + "ORDER BY this.timestamp DESC"),
-    @javax.jdo.annotations.Query(
-            name="findCompleted",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE completedAt != null "
-                    + "ORDER BY this.timestamp DESC"),
-    @javax.jdo.annotations.Query(
-            name="findRecentByTarget",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE target == :target "
-                    + "ORDER BY this.timestamp DESC "
-                    + "RANGE 0,30"),
-    @javax.jdo.annotations.Query(
-            name="findByTargetAndTimestampBetween",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE target == :target "
-                    + "&& timestamp >= :from "
-                    + "&& timestamp <= :to "
-                    + "ORDER BY this.timestamp DESC"),
-    @javax.jdo.annotations.Query(
-            name="findByTargetAndTimestampAfter",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE target == :target "
-                    + "&& timestamp >= :from "
-                    + "ORDER BY this.timestamp DESC"),
-    @javax.jdo.annotations.Query(
-            name="findByTargetAndTimestampBefore",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE target == :target "
-                    + "&& timestamp <= :to "
-                    + "ORDER BY this.timestamp DESC"),
-    @javax.jdo.annotations.Query(
-            name="findByTarget",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE target == :target "
-                    + "ORDER BY this.timestamp DESC"),
-    @javax.jdo.annotations.Query(
-            name="findByTimestampBetween",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE timestamp >= :from "
-                    + "&&    timestamp <= :to "
-                    + "ORDER BY this.timestamp DESC"),
-    @javax.jdo.annotations.Query(
-            name="findByTimestampAfter",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE timestamp >= :from "
-                    + "ORDER BY this.timestamp DESC"),
-    @javax.jdo.annotations.Query(
-            name="findByTimestampBefore",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE timestamp <= :to "
-                    + "ORDER BY this.timestamp DESC"),
-    @javax.jdo.annotations.Query(
-            name="find",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " ORDER BY this.timestamp DESC"),
-    @javax.jdo.annotations.Query(
-            name="findRecentByUsername",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE username == :username "
-                    + "ORDER BY this.timestamp DESC "
-                    + "RANGE 0,30"),
-    @javax.jdo.annotations.Query(
-            name="findFirst",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE startedAt   != null "
-                    + "   && completedAt != null "
-                    + "ORDER BY this.timestamp ASC "
-                    + "RANGE 0,2"),
-        // this should be RANGE 0,1 but results in DataNucleus submitting "FETCH NEXT ROW ONLY"
-        // which SQL Server doesn't understand.  However, as workaround, SQL Server *does* understand FETCH NEXT 2 ROWS ONLY
-    @javax.jdo.annotations.Query(
-            name="findSince",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE timestamp > :timestamp "
-                    + "   && startedAt != null "
-                    + "   && completedAt != null "
-                    + "ORDER BY this.timestamp ASC"),
-    // most recent (replayed) command previously replicated from primary to
-    // secondary.  This should always exist except for the very first times
-    // (after restored the prod DB to secondary).
-    @javax.jdo.annotations.Query(
-            name="findMostRecentReplayed",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE (replayState == 'OK' || replayState == 'FAILED') "
-                    + "ORDER BY this.timestamp DESC "
-                    + "RANGE 0,2"), // this should be RANGE 0,1 but results in DataNucleus submitting "FETCH NEXT ROW ONLY"
-                                    // which SQL Server doesn't understand.  However, as workaround, SQL Server *does* understand FETCH NEXT 2 ROWS ONLY
-    // the most recent completed command, as queried on the
-    // secondary, corresponding to the last command run on primary before the
-    // production database was restored to the secondary
-    @javax.jdo.annotations.Query(
-            name="findMostRecentCompleted",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE startedAt   != null "
-                    + "   && completedAt != null "
-                    + "ORDER BY this.timestamp DESC "
-                    + "RANGE 0,2"),
-        // this should be RANGE 0,1 but results in DataNucleus submitting "FETCH NEXT ROW ONLY"
-        // which SQL Server doesn't understand.  However, as workaround, SQL Server *does* understand FETCH NEXT 2 ROWS ONLY
-    @javax.jdo.annotations.Query(
-            name="findNotYetReplayed",
-            value="SELECT "
-                    + "FROM " + CommandJdo.FQCN
-                    + " WHERE replayState == 'PENDING' "
-                    + "ORDER BY this.timestamp ASC "
-                    + "RANGE 0,10"),    // same as batch size
-})
-@javax.jdo.annotations.Indices({
-        @javax.jdo.annotations.Index(name = "CommandJdo__startedAt__timestamp__IDX", members = { "startedAt", "timestamp" }),
-        @javax.jdo.annotations.Index(name = "CommandJdo__timestamp__IDX", members = { "timestamp" }),
-})
-*/
 @Entity
 @DomainObject(
         logicalTypeName = CommandJpa.LOGICAL_TYPE_NAME,
         editing = Editing.DISABLED
 )
-@DomainObjectLayout(
-        named = "Command",
-        titleUiEvent = CommandModel.TitleUiEvent.class,
-        iconUiEvent = CommandModel.IconUiEvent.class,
-        cssClassUiEvent = CommandModel.CssClassUiEvent.class,
-        layoutUiEvent = CommandModel.LayoutUiEvent.class
-)
 //@Log4j2
+@Deprecated
 @NoArgsConstructor
 public class CommandJpa
-implements
-    CommandModel,
-    DomainChangeRecord {
+extends CommandLog {
 
     public final static String LOGICAL_TYPE_NAME = IsisModuleExtCommandLogJpa.NAMESPACE + ".Command";
     protected final static String FQCN = "org.apache.isis.extensions.commandlog.jpa.entities.CommandJpa";
@@ -254,22 +53,7 @@ implements
      * @param command
      */
     public CommandJpa(final 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);
+        super(command);
     }
 
 
@@ -284,349 +68,8 @@ implements
             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((CommandJpa)ev.getSource()));
-        }
-
-        private static String title(final CommandJpa 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();
-        }
-    }
-
-
-    public static class InteractionIdDomainEvent extends PropertyDomainEvent<String> { }
-    /**
-     * Implementation note: persisted as a string rather than a UUID as fails
-     * to persist if using h2 (perhaps would need to be mapped differently).
-     * @see <a href="https://www.datanucleus.org/products/accessplatform/jdo/mapping.html#_other_types">www.datanucleus.org</a>
-     */
-//    @javax.jdo.annotations.PrimaryKey
-//    @javax.jdo.annotations.Persistent
-//    @javax.jdo.annotations.Column(allowsNull="false", name = "interactionId", length = 36)
-    @Property(domainEvent = InteractionIdDomainEvent.class)
-    @PropertyLayout(named = "Interaction Id")
-    @Getter @Setter
-    private String interactionIdStr;
-    @Override
-    @Programmatic
-    public UUID getInteractionId() {return UUID.fromString(getInteractionIdStr());}
-
-
-    public static class UsernameDomainEvent extends PropertyDomainEvent<String> { }
-//    @javax.jdo.annotations.Column(allowsNull="false", length = 50)
-    @Property(domainEvent = UsernameDomainEvent.class)
-    @Getter @Setter
-    private String username;
-
-
-    public static class TimestampDomainEvent extends PropertyDomainEvent<Timestamp> { }
-//    @javax.jdo.annotations.Persistent
-//    @javax.jdo.annotations.Column(allowsNull="false")
-    @Property(domainEvent = TimestampDomainEvent.class)
-    @Getter @Setter
-    private Timestamp timestamp;
-
-
-
-    @Override
-    public ChangeType getType() {
-        return ChangeType.COMMAND;
-    }
-
-
-    public static class ReplayStateDomainEvent extends PropertyDomainEvent<ReplayState> { }
-    /**
-     * For a replayed command, what the outcome was.
-     */
-//    @javax.jdo.annotations.Column(allowsNull="true", length=10)
-    @Property(domainEvent = ReplayStateDomainEvent.class)
-    @Getter @Setter
-    private ReplayState replayState;
-
-
-    public static class ReplayStateFailureReasonDomainEvent extends PropertyDomainEvent<ReplayState> { }
-    /**
-     * For a {@link ReplayState#FAILED failed} replayed command, what the reason was for the failure.
-     */
-//    @javax.jdo.annotations.Column(allowsNull="true", length=255)
-    @Property(domainEvent = ReplayStateFailureReasonDomainEvent.class)
-    @PropertyLayout(hidden = Where.ALL_TABLES, multiLine = 5)
-    @Getter @Setter
-    private String replayStateFailureReason;
-    @MemberSupport public boolean hideReplayStateFailureReason() {
-        return getReplayState() == null || !getReplayState().isFailed();
-    }
-
-
-    public static class ParentDomainEvent extends PropertyDomainEvent<Command> { }
-//    @javax.jdo.annotations.Persistent
-//    @javax.jdo.annotations.Column(name="parentId", allowsNull="true")
-    @Property(domainEvent = ParentDomainEvent.class)
-    @PropertyLayout(hidden = Where.ALL_TABLES)
-    @Getter @Setter
-    private CommandJpa parent;
-
-
-    public static class TargetDomainEvent extends PropertyDomainEvent<String> { }
-//    @javax.jdo.annotations.Persistent
-//    @javax.jdo.annotations.Column(allowsNull="true", length = 2000, name="target")
-    @Property(domainEvent = TargetDomainEvent.class)
-    @PropertyLayout(named = "Object")
-    @Getter @Setter
-    private Bookmark target;
-
-    public String getTargetStr() {
-        return Optional.ofNullable(getTarget()).map(Bookmark::toString).orElse(null);
-    }
-
-    @Override
-    public String getTargetMember() {
-        return getCommandDto().getMember().getLogicalMemberIdentifier();
+        super(commandDto, replayState, targetIndex);
     }
 
-    @Property(domainEvent = TargetDomainEvent.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)
-//    @javax.jdo.annotations.Column(allowsNull="false", length = MemberIdentifierType.Meta.MAX_LEN)
-    @Getter @Setter
-    private String logicalMemberIdentifier;
-
-
-    public static class CommandDtoDomainEvent extends PropertyDomainEvent<CommandDto> { }
-//    @javax.jdo.annotations.Persistent
-//    @javax.jdo.annotations.Column(allowsNull="true", jdbcType="CLOB")
-    @Property(domainEvent = CommandDtoDomainEvent.class)
-    @PropertyLayout(multiLine = 9)
-    @Getter @Setter
-    private CommandDto commandDto;
-
-
-    public static class StartedAtDomainEvent extends PropertyDomainEvent<Timestamp> { }
-//    @javax.jdo.annotations.Persistent
-//    @javax.jdo.annotations.Column(allowsNull="true")
-    @Property(domainEvent = StartedAtDomainEvent.class)
-    @Getter @Setter
-    private Timestamp startedAt;
-
-
-    public static class CompletedAtDomainEvent extends PropertyDomainEvent<Timestamp> { }
-//    @javax.jdo.annotations.Persistent
-//    @javax.jdo.annotations.Column(allowsNull="true")
-    @Property(domainEvent = CompletedAtDomainEvent.class)
-    @Getter @Setter
-    private 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.jdo.annotations.NotPersistent
-    @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> { }
-//    @javax.jdo.annotations.NotPersistent
-    @Property(domainEvent = IsCompleteDomainEvent.class)
-    @PropertyLayout(hidden = Where.OBJECT_FORMS)
-    public boolean isComplete() {
-        return getCompletedAt() != null;
-    }
-
-
-    public static class ResultSummaryDomainEvent extends PropertyDomainEvent<String> { }
-//    @javax.jdo.annotations.NotPersistent
-    @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> { }
-//    @javax.jdo.annotations.Persistent
-//    @javax.jdo.annotations.Column(allowsNull="true", length = 2000, name="result")
-    @Property(domainEvent = ResultDomainEvent.class)
-    @PropertyLayout(hidden = Where.ALL_TABLES, named = "Result Bookmark")
-    @Getter @Setter
-    private 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.
-     */
-//    @javax.jdo.annotations.Column(allowsNull="true", jdbcType="CLOB")
-    @Property(domainEvent = ExceptionDomainEvent.class)
-    @PropertyLayout(hidden = Where.ALL_TABLES, multiLine = 5, named = "Exception (if any)")
-    @Getter
-    private String exception;
-    public void setException(final String exception) {
-        this.exception = exception;
-    }
-    public void setException(final Throwable exception) {
-        setException(_Exceptions.asStacktrace(exception));
-    }
-
-    public static class IsCausedExceptionDomainEvent extends PropertyDomainEvent<Boolean> { }
-//    @javax.jdo.annotations.NotPersistent
-    @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;
-    }
-
-
-    @Override
-    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();
-    }
-
-    @Override
-    public CommandOutcomeHandler outcomeHandler() {
-        return new CommandOutcomeHandler() {
-            @Override
-            public Timestamp getStartedAt() {
-                return CommandJpa.this.getStartedAt();
-            }
-
-            @Override
-            public void setStartedAt(final Timestamp startedAt) {
-                CommandJpa.this.setStartedAt(startedAt);
-            }
-
-            @Override
-            public void setCompletedAt(final Timestamp completedAt) {
-                CommandJpa.this.setCompletedAt(completedAt);
-            }
-
-            @Override
-            public void setResult(final Try<Bookmark> resultBookmark) {
-                CommandJpa.this.setResult(resultBookmark.getValue().orElse(null));
-                CommandJpa.this.setException(resultBookmark.getFailure().orElse(null));
-            }
-
-        };
-    }
-
-    @Service
-    @javax.annotation.Priority(PriorityPrecedence.LATE - 10) // before the framework's own default.
-    public static class TableColumnOrderDefault extends TableColumnOrderForCollectionTypeAbstract<CommandJpa> {
-
-        public TableColumnOrderDefault() { super(CommandJpa.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/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 7a2f586128..7ac0c61792 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,8 +45,8 @@ 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.applib.command.CommandModel;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModelRepository;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLogRepository;
+import org.apache.isis.extensions.commandlog.applib.command.ICommandLog;
 import org.apache.isis.extensions.commandlog.applib.command.ReplayState;
 import org.apache.isis.extensions.commandlog.jpa.IsisModuleExtCommandLogJpa;
 import org.apache.isis.schema.cmd.v2.CommandDto;
@@ -63,13 +63,13 @@ import lombok.val;
  * {@link CommandJpa command} entities.
  */
 @Service
-@Named(IsisModuleExtCommandLogJpa.NAMESPACE + ".CommandJdoRepository")
+@Named(IsisModuleExtCommandLogJpa.NAMESPACE + ".CommandJpaRepository")
 @javax.annotation.Priority(PriorityPrecedence.MIDPOINT)
 @Qualifier("Jpa")
 @RequiredArgsConstructor
 //@Log4j2
 public class CommandJpaRepository
-implements CommandModelRepository<CommandJpa> {
+implements CommandLogRepository<CommandJpa> {
 
     @Inject final Provider<InteractionProvider> interactionProviderProvider;
     @Inject final Provider<RepositoryService> repositoryServiceProvider;
@@ -111,7 +111,7 @@ implements CommandModelRepository<CommandJpa> {
     }
 
     @Override
-    public List<CommandJpa> findByParent(final CommandModel parent) {
+    public List<CommandJpa> findByParent(final ICommandLog parent) {
         return repositoryService().allMatches(
                 Query.named(CommandJpa.class, "findByParent")
                     .withParameter("parent", parent));
diff --git a/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/restapi/CommandRetrievalOnPrimaryService.java b/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/restapi/CommandRetrievalOnPrimaryService.java
index 740e9a0dbd..dc96f4402d 100644
--- a/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/restapi/CommandRetrievalOnPrimaryService.java
+++ b/extensions/core/command-replay/primary/src/main/java/org/apache/isis/extensions/commandreplay/primary/restapi/CommandRetrievalOnPrimaryService.java
@@ -37,9 +37,9 @@ import org.apache.isis.applib.annotation.ParameterLayout;
 import org.apache.isis.applib.annotation.PriorityPrecedence;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModel;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModelRepository;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModelRepository.NotFoundException;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLog;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLogRepository;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLogRepository.NotFoundException;
 import org.apache.isis.extensions.commandreplay.primary.IsisModuleExtCommandReplayPrimary;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
@@ -59,7 +59,7 @@ public class CommandRetrievalOnPrimaryService {
 
     public static class FindCommandsOnPrimaryFromDomainEvent extends ActionDomainEvent { }
 
-    @Inject CommandModelRepository<? extends CommandModel> commandModelRepository;
+    @Inject CommandLogRepository<? extends CommandLog> commandLogRepository;
 
     /**
      * TODO: outdated info ...
@@ -84,9 +84,9 @@ public class CommandRetrievalOnPrimaryService {
             @ParameterLayout(named="Batch size")
             final Integer batchSize) throws NotFoundException {
 
-        return commandModelRepository.findCommandsOnPrimaryElseFail(interactionId, batchSize)
+        return commandLogRepository.findCommandsOnPrimaryElseFail(interactionId, batchSize)
                 .stream()
-                .map(CommandModel::getCommandDto)
+                .map(CommandLog::getCommandDto)
                 .collect(Collectors.toList());
     }
     @MemberSupport public Integer default1FindCommandsOnPrimaryAsDto() {
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 92d447e2c6..de0cba00c0 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.applib.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLog;
 import org.apache.isis.extensions.commandreplay.primary.IsisModuleExtCommandReplayPrimary;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
@@ -52,16 +52,16 @@ public class CaptureResultOfCommand implements CommandDtoProcessorService {
     @Override
     public CommandDto process(final Object domainObject, CommandDto commandDto) {
 
-        if (!(domainObject instanceof CommandModel)) {
+        if (!(domainObject instanceof CommandLog)) {
             return commandDto;
         }
 
-        val commandModel = (CommandModel) domainObject;
+        val commandLog = (CommandLog) domainObject;
         if(commandDto == null) {
-            commandDto = commandModel.getCommandDto();
+            commandDto = commandLog.getCommandDto();
         }
 
-        final Bookmark result = commandModel.getResult();
+        final Bookmark result = commandLog.getResult();
         CommandDtoUtils.setUserData(commandDto, UserDataKeys.RESULT, result);
 
         // knowing whether there was an exception is on the primary is
@@ -69,11 +69,11 @@ public class CaptureResultOfCommand implements CommandDtoProcessorService {
         // secondary if an exception occurs there also
         CommandDtoUtils.setUserData(commandDto,
                 UserDataKeys.EXCEPTION,
-                commandModel.getException());
+                commandLog.getException());
 
         val timings = CommandDtoUtils.timingsFor(commandDto);
-        timings.setStartedAt(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(commandModel.getStartedAt()));
-        timings.setCompletedAt(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(commandModel.getCompletedAt()));
+        timings.setStartedAt(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(commandLog.getStartedAt()));
+        timings.setCompletedAt(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(commandLog.getCompletedAt()));
 
         return commandDto;
     }
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 6d8aef303b..8edb25290e 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
@@ -41,9 +41,10 @@ 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.applib.IsisModuleExtCommandLogApplib;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModel;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModelRepository;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModelRepository.NotFoundException;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLog;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLogRepository;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLogRepository.NotFoundException;
+import org.apache.isis.extensions.commandlog.applib.command.ICommandLog;
 import org.apache.isis.extensions.commandreplay.primary.IsisModuleExtCommandReplayPrimary;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.cmd.v2.CommandsDto;
@@ -67,7 +68,7 @@ import lombok.RequiredArgsConstructor;
 //@Log4j2
 public class CommandReplayOnPrimaryService {
 
-    @Inject final CommandModelRepository<? extends CommandModel> commandModelRepository;
+    @Inject final CommandLogRepository<? extends CommandLog> commandLogRepository;
     @Inject final JaxbService jaxbService;
     @Inject final MessageService messageService;
     @Inject final ContentMappingServiceForCommandsDto contentMappingServiceForCommandsDto;
@@ -90,7 +91,7 @@ public class CommandReplayOnPrimaryService {
          * @param batchSize - the maximum number of commands to return.  If not specified, all found will be returned.
          * @throws NotFoundException - if the command with specified transaction cannot be found.
          */
-        @MemberSupport public List<? extends CommandModel> act(
+        @MemberSupport public List<? extends CommandLog> act(
                 @Nullable
                 @ParameterLayout(named="Interaction Id")
                 final UUID interactionId,
@@ -98,7 +99,7 @@ public class CommandReplayOnPrimaryService {
                 @ParameterLayout(named="Batch size")
                 final Integer batchSize)
                 throws NotFoundException {
-            return commandModelRepository.findCommandsOnPrimaryElseFail(interactionId, batchSize);
+            return commandLogRepository.findCommandsOnPrimaryElseFail(interactionId, batchSize);
         }
         @MemberSupport public Integer default1Act() {
             return 25;
@@ -126,7 +127,7 @@ public class CommandReplayOnPrimaryService {
                 @Nullable
                 final Integer batchSize,
                 final String filenamePrefix) {
-            final List<? extends CommandModel> commands = commandModelRepository.findSince(interactionId, batchSize);
+            final List<? extends ICommandLog> commands = commandLogRepository.findSince(interactionId, batchSize);
             if(commands == null) {
                 messageService.informUser("No commands found");
             }
@@ -168,7 +169,7 @@ public class CommandReplayOnPrimaryService {
                 final UUID interactionId,
                 final String filenamePrefix) {
 
-            return commandModelRepository.findByInteractionId(interactionId)
+            return commandLogRepository.findByInteractionId(interactionId)
                     .map(commandJdo -> {
 
                         final CommandDto commandDto = commandJdo.getCommandDto();
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 1f845090ce..3125d76972 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.applib.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.command.ICommandLog;
 
 /**
  * @since 2.0 {@index}
@@ -30,6 +30,6 @@ public interface CommandReplayAnalyser {
      * @param commandJdo
      * @return - if not <code>null</code>, indicates the reason that there was an issue replaying the command.
      */
-    String analyzeReplay(final CommandModel commandJdo);
+    String analyzeReplay(final ICommandLog commandJdo);
 
 }
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 1d073848d9..10a467445e 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.applib.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.command.ICommandLog;
 import org.apache.isis.extensions.commandreplay.secondary.IsisModuleExtCommandReplaySecondary;
 import org.apache.isis.schema.common.v2.InteractionType;
 
@@ -55,12 +55,12 @@ public class CommandReplayAnalyserException implements CommandReplayAnalyser {
     }
 
     @Override
-    public String analyzeReplay(final CommandModel commandModel) {
+    public String analyzeReplay(final ICommandLog commandLog) {
         if(!enabled) {
             return null;
         }
 
-        val dto = commandModel.getCommandDto();
+        val dto = commandLog.getCommandDto();
         if(dto.getMember().getInteractionType() == InteractionType.PROPERTY_EDIT) {
             return null;
         }
@@ -70,7 +70,7 @@ public class CommandReplayAnalyserException implements CommandReplayAnalyser {
             return null;
         }
 
-        val replayedException = commandModel.getException();
+        val replayedException = commandLog.getException();
 
         val primaryExceptionTrimmed = trimmed(primaryException);
         val replayedExceptionTrimmed = trimmed(replayedException);
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 32a143bbfd..992feb44cd 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.apache.isis.applib.annotation.PriorityPrecedence;
 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.applib.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.command.ICommandLog;
 import org.apache.isis.extensions.commandreplay.secondary.IsisModuleExtCommandReplaySecondary;
 import org.apache.isis.schema.common.v2.InteractionType;
 
@@ -54,12 +54,12 @@ public class CommandReplayAnalyserResult implements CommandReplayAnalyser {
     }
 
     @Override
-    public String analyzeReplay(final CommandModel commandModel) {
+    public String analyzeReplay(final ICommandLog commandLog) {
         if(!enabled) {
             return null;
         }
 
-        val dto = commandModel.getCommandDto();
+        val dto = commandLog.getCommandDto();
         if(dto.getMember().getInteractionType() == InteractionType.PROPERTY_EDIT) {
             return null;
         }
@@ -68,7 +68,7 @@ public class CommandReplayAnalyserResult implements CommandReplayAnalyser {
         // ... either the same result when replayed
         val primaryResultStr = CommandDtoUtils.getUserData(dto, UserDataKeys.RESULT);
 
-        val secondaryResult = commandModel.getResult();
+        val secondaryResult = commandLog.getResult();
         val secondaryResultStr =
                 secondaryResult != null ? secondaryResult.toString() : null;
         return Objects.equals(primaryResultStr, secondaryResultStr)
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 67779ff33e..6fee1e151f 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.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.PriorityPrecedence;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.command.ICommandLog;
 import org.apache.isis.extensions.commandreplay.secondary.IsisModuleExtCommandReplaySecondary;
 import org.apache.isis.extensions.commandreplay.secondary.analyser.CommandReplayAnalyser;
 
@@ -46,13 +46,13 @@ public class CommandReplayAnalysisService {
      * as in error.
      * This will effectively block the running of any further commands until the administrator fixes the issue.
      */
-    public void analyse(final CommandModel commandModel) {
-        final String analysis = analyseReplay(commandModel);
+    public void analyse(final ICommandLog commandLog) {
+        final String analysis = analyseReplay(commandLog);
 
-        commandModel.saveAnalysis(analysis);
+        commandLog.saveAnalysis(analysis);
     }
 
-    private String analyseReplay(final CommandModel commandJdo) {
+    private String analyseReplay(final ICommandLog commandJdo) {
 
         for (final CommandReplayAnalyser analyser : analysers) {
             try {
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 fd851a1c27..1281e3383e 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
@@ -33,7 +33,7 @@ import org.apache.isis.applib.annotation.PriorityPrecedence;
 import org.apache.isis.applib.client.SuppressionType;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.command.ICommandLog;
 import org.apache.isis.extensions.commandreplay.secondary.config.SecondaryConfig;
 import org.apache.isis.extensions.commandreplay.secondary.status.SecondaryStatus;
 import org.apache.isis.extensions.commandreplay.secondary.status.StatusException;
@@ -77,7 +77,7 @@ public class CommandFetcher {
      * @throws StatusException
      */
     public Can<CommandDto> fetchCommand(
-            final @Nullable CommandModel previousHwmIfAny)
+            final @Nullable ICommandLog previousHwmIfAny)
             throws StatusException {
 
         log.debug("finding command on primary ...");
@@ -90,7 +90,7 @@ public class CommandFetcher {
      * @param previousHwmIfAny
      * @throws StatusException
      */
-    private Can<CommandDto> fetchCommands(final CommandModel previousHwmIfAny)
+    private Can<CommandDto> fetchCommands(final ICommandLog previousHwmIfAny)
             throws StatusException {
 
         final UUID transactionId = previousHwmIfAny != null
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 2e5f0f4e6b..b92df7d84f 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,8 +28,8 @@ 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.applib.command.CommandModel;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModelRepository;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLog;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLogRepository;
 import org.apache.isis.extensions.commandlog.applib.command.ReplayState;
 import org.apache.isis.extensions.commandreplay.secondary.analysis.CommandReplayAnalysisService;
 import org.apache.isis.extensions.commandreplay.secondary.fetch.CommandFetcher;
@@ -58,7 +58,7 @@ public class ReplicateAndRunCommands implements Callable<SecondaryStatus> {
     @Inject CommandExecutorService commandExecutorService;
     @Inject TransactionService transactionService;
     @Inject CommandFetcher commandFetcher;
-    @Inject CommandModelRepository<? extends CommandModel> commandModelRepository;
+    @Inject CommandLogRepository<CommandLog> commandLogRepository;
     @Inject CommandReplayAnalysisService analysisService;
     @Inject Optional<ReplayCommandExecutionController> controller;
 
@@ -79,18 +79,18 @@ public class ReplicateAndRunCommands implements Callable<SecondaryStatus> {
             return;
         }
 
-        List<? extends CommandModel> commandsToReplay;
+        List<CommandLog> commandsToReplay;
 
         while(isRunning()) {
 
             // is there a pending command already?
             // (we fetch several at a time, so we may not have processed them all yet)
-            commandsToReplay = commandModelRepository.findNotYetReplayed();
+            commandsToReplay = commandLogRepository.findNotYetReplayed();
 
             if(commandsToReplay.isEmpty()) {
 
                 // look for previously replayed on secondary
-                CommandModel hwm = commandModelRepository.findMostRecentReplayed().orElse(null);
+                CommandLog hwm = commandLogRepository.findMostRecentReplayed().orElse(null);
 
                 if (hwm != null) {
                     // give up if there was a failure; admin will need to fix issue and retry
@@ -103,7 +103,7 @@ public class ReplicateAndRunCommands implements Callable<SecondaryStatus> {
                     // after a DB restore from primary to secondary, there won't be
                     // any that have been replayed.  So instead we simply use
                     // latest completed (on primary) as the HWM.
-                    hwm = commandModelRepository.findMostRecentCompleted().orElse(null);
+                    hwm = commandLogRepository.findMostRecentCompleted().orElse(null);
                 }
 
                 // fetch next command(s) from primary (if any)
@@ -111,7 +111,7 @@ public class ReplicateAndRunCommands implements Callable<SecondaryStatus> {
                 commandsToReplay = commandDtos.stream()
                         .map(dto ->
                                 transactionService.callWithinCurrentTransactionElseCreateNew(
-                                    () -> commandModelRepository.saveForReplay(dto))
+                                    () -> commandLogRepository.saveForReplay(dto))
                                 .ifFailureFail()
                                 .getValue().orElse(null)
                         )
@@ -131,16 +131,16 @@ public class ReplicateAndRunCommands implements Callable<SecondaryStatus> {
      * @param commandsToReplay
      * @apiNote could return, whether there was a command to process (and so continue)
      */
-    private void replay(final List<? extends CommandModel> commandsToReplay) {
+    private void replay(final List<CommandLog> commandsToReplay) {
 
-        commandsToReplay.forEach(commandModel -> {
+        commandsToReplay.forEach(commandLog -> {
 
-            log.info("replaying {}", commandModel.getInteractionId());
+            log.info("replaying {}", commandLog.getInteractionId());
 
             //
             // run command
             //
-            val replayState = executeCommandInTranAndAnalyse(commandModel);
+            val replayState = executeCommandInTranAndAnalyse(commandLog);
             if(replayState.isFailed()) {
                 // will effectively block the running of any further commands
                 // until the issue is fixed.
@@ -150,11 +150,11 @@ public class ReplicateAndRunCommands implements Callable<SecondaryStatus> {
             //
             // find child commands, and run them
             //
-            val parent = commandModel;
+            val parent = commandLog;
 
             val childCommands =
                     transactionService.callWithinCurrentTransactionElseCreateNew(
-                            () -> commandModelRepository.findByParent(parent))
+                            () -> commandLogRepository.findByParent(parent))
                     .ifFailureFail()
                     .getValue().orElse(Collections.emptyList());
             for (val childCommand : childCommands) {
@@ -170,18 +170,18 @@ public class ReplicateAndRunCommands implements Callable<SecondaryStatus> {
 
     }
 
-    private ReplayState executeCommandInTranAndAnalyse(final CommandModel commandJdo) {
+    private ReplayState executeCommandInTranAndAnalyse(final CommandLog commandLog) {
         transactionService.runWithinCurrentTransactionElseCreateNew(
                 () -> {
                     commandExecutorService.executeCommand(
-                        CommandExecutorService.InteractionContextPolicy.SWITCH_USER_AND_TIME, commandJdo.getCommandDto(), commandJdo.outcomeHandler());
+                        CommandExecutorService.InteractionContextPolicy.SWITCH_USER_AND_TIME, commandLog.getCommandDto(), commandLog.outcomeHandler());
                 });
 
         transactionService.runWithinCurrentTransactionElseCreateNew(() -> {
-            analysisService.analyse(commandJdo);
+            analysisService.analyse(commandLog);
         });
 
-        return commandJdo.getReplayState();
+        return commandLog.getReplayState();
 
     }
 
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/CommandLog_exclude.java
similarity index 79%
rename from extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/mixins/CommandModel_exclude.java
rename to extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/mixins/CommandLog_exclude.java
index 8d5af04190..2c64253b85 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/CommandLog_exclude.java
@@ -24,9 +24,10 @@ import javax.inject.Inject;
 
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.MemberSupport;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.extensions.commandlog.applib.IsisModuleExtCommandLogApplib;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModel;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLog;
 import org.apache.isis.extensions.commandlog.applib.command.ReplayState;
 import org.apache.isis.extensions.commandreplay.secondary.config.SecondaryConfig;
 
@@ -38,29 +39,29 @@ import lombok.RequiredArgsConstructor;
  */
 @Action(
     semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE,
-    domainEvent = CommandModel_exclude.ActionDomainEvent.class
+    domainEvent = CommandLog_exclude.ActionDomainEvent.class
 )
 @ActionLayout(associateWith = "executeIn", sequence = "2")
 @RequiredArgsConstructor
 //@Log4j2
-public class CommandModel_exclude {
+public class CommandLog_exclude {
 
     public static class ActionDomainEvent
-            extends IsisModuleExtCommandLogApplib.ActionDomainEvent<CommandModel_exclude> { }
+            extends IsisModuleExtCommandLogApplib.ActionDomainEvent<CommandLog_exclude> { }
 
-    final CommandModel commandModel;
+    final CommandLog commandLog;
 
-    public CommandModel act() {
-        commandModel.setReplayState(ReplayState.EXCLUDED);
-        return commandModel;
+    @MemberSupport
+    public CommandLog act() {
+        commandLog.setReplayState(ReplayState.EXCLUDED);
+        return commandLog;
     }
-
-    public boolean hideAct() {
+    @MemberSupport public boolean hideAct() {
         return !secondaryConfig.isPresent() || !secondaryConfig.get().isConfigured() ;
     }
-    public String disableAct() {
+    @MemberSupport public String disableAct() {
         final boolean notInError =
-                commandModel.getReplayState() == null || !commandModel.getReplayState().isFailed();
+                commandLog.getReplayState() == null || !commandLog.getReplayState().isFailed();
         return notInError
                 ? "This command is not in error, so cannot be excluded."
                 : null;
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/CommandLog_replayQueue.java
similarity index 81%
rename from extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/mixins/CommandJdo_replayQueue.java
rename to extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/mixins/CommandLog_replayQueue.java
index 1a8ad63100..681829db10 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/CommandLog_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.applib.command.CommandModel;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModelRepository;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLog;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLogRepository;
 import org.apache.isis.extensions.commandreplay.secondary.IsisModuleExtCommandReplaySecondary;
 import org.apache.isis.extensions.commandreplay.secondary.config.SecondaryConfig;
 
@@ -35,28 +35,28 @@ import lombok.RequiredArgsConstructor;
  * @since 2.0 {@index}
  */
 @Collection(
-    domainEvent = CommandJdo_replayQueue.CollectionDomainEvent.class
+    domainEvent = CommandLog_replayQueue.CollectionDomainEvent.class
 )
 @CollectionLayout(
     defaultView = "table",
     sequence = "100.100"
 )
 @RequiredArgsConstructor
-public class CommandJdo_replayQueue {
+public class CommandLog_replayQueue {
 
     public static class CollectionDomainEvent
-            extends IsisModuleExtCommandReplaySecondary.CollectionDomainEvent<CommandJdo_replayQueue, CommandModel> { }
+            extends IsisModuleExtCommandReplaySecondary.CollectionDomainEvent<CommandLog_replayQueue, CommandLog> { }
 
-    final CommandModel commandModel;
+    final CommandLog commandLog;
 
-    public List<? extends CommandModel> coll() {
-        return commandModelRepository.findReplayedOnSecondary();
+    public List<CommandLog> coll() {
+        return commandLogRepository.findReplayedOnSecondary();
     }
     public boolean hideColl() {
         return !secondaryConfig.isConfigured();
     }
 
     @Inject SecondaryConfig secondaryConfig;
-    @Inject CommandModelRepository<? extends CommandModel> commandModelRepository;
+    @Inject CommandLogRepository<CommandLog> commandLogRepository;
 
 }
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 f158e5c4f5..8240a539ee 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
@@ -34,8 +34,8 @@ import org.apache.isis.applib.annotation.PriorityPrecedence;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.jaxb.JaxbService;
 import org.apache.isis.applib.value.Clob;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModel;
-import org.apache.isis.extensions.commandlog.applib.command.CommandModelRepository;
+import org.apache.isis.extensions.commandlog.applib.command.ICommandLog;
+import org.apache.isis.extensions.commandlog.applib.command.CommandLogRepository;
 import org.apache.isis.extensions.commandreplay.secondary.IsisModuleExtCommandReplaySecondary;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.cmd.v2.CommandsDto;
@@ -59,7 +59,7 @@ import lombok.val;
 //@Log4j2
 public class CommandReplayOnSecondaryService {
 
-    @Inject CommandModelRepository<? extends CommandModel> commandModelRepository;
+    @Inject CommandLogRepository<? extends ICommandLog> commandLogRepository;
     @Inject JaxbService jaxbService;
 
     public static abstract class ActionDomainEvent<T> extends IsisModuleExtCommandReplaySecondary.ActionDomainEvent<T> { }
@@ -70,8 +70,8 @@ public class CommandReplayOnSecondaryService {
 
         public class ActionEvent extends ActionDomainEvent<findMostRecentReplayed> { }
 
-        @MemberSupport public CommandModel act() {
-            return commandModelRepository.findMostRecentReplayed().orElse(null);
+        @MemberSupport public ICommandLog act() {
+            return commandLogRepository.findMostRecentReplayed().orElse(null);
         }
     }
 
@@ -99,7 +99,7 @@ public class CommandReplayOnSecondaryService {
             }
 
             for (final CommandDto commandDto : commandDtoList) {
-                commandModelRepository.saveForReplay(commandDto);
+                commandLogRepository.saveForReplay(commandDto);
             }
         }
 
diff --git a/extensions/core/command-replay/secondary/src/test/java/org/apache/isis/extensions/commandreplay/secondary/fetch/CommandFetcher_Test.java b/extensions/core/command-replay/secondary/src/test/java/org/apache/isis/extensions/commandreplay/secondary/fetch/CommandFetcher_Test.java
index f5a5c82e87..ab18d149f1 100644
--- a/extensions/core/command-replay/secondary/src/test/java/org/apache/isis/extensions/commandreplay/secondary/fetch/CommandFetcher_Test.java
+++ b/extensions/core/command-replay/secondary/src/test/java/org/apache/isis/extensions/commandreplay/secondary/fetch/CommandFetcher_Test.java
@@ -26,15 +26,14 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.test.context.TestPropertySource;
 
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.core.metamodel._testing.MetaModelContext_forTesting;
 import org.apache.isis.extensions.commandreplay.secondary.config.SecondaryConfig;
 import org.apache.isis.extensions.commandreplay.secondary.status.StatusException;
 
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
 import lombok.val;
-import lombok.extern.log4j.Log4j2;
 
 @SpringBootTest(
         classes = {
@@ -50,7 +49,7 @@ import lombok.extern.log4j.Log4j2;
 })
 //intended only for manual verification.
 @DisabledIfSystemProperty(named = "isRunningWithSurefire", matches = "true")
-@Log4j2
+//@Log4j2
 class CommandFetcher_Test {
 
     @Configuration
@@ -76,7 +75,7 @@ class CommandFetcher_Test {
         val fetcher = new CommandFetcher(secondaryConfig, useRequestDebugLogging);
 
         // when
-        log.info("about to call REST endpoint ...");
+        //log.info("about to call REST endpoint ...");
         val commands = fetcher.callPrimary(null);
         assertNotNull(commands);
         System.out.println(commands);