From a0d227342b561f238e0dad56bb0d012e9bfef532 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Tue, 4 Aug 2026 13:15:57 +0800 Subject: [PATCH] feat: audit issuance operations by user --- ...mercialBankIssuanceApplicationService.java | 69 ++++++++++++++----- .../domain/model/IssuanceAuditActor.java | 30 ++++++++ .../repository/IssuanceRequestRepository.java | 3 +- .../IssuanceRequestDenominationEntity.java | 18 +++++ .../entity/IssuanceRequestEntity.java | 4 ++ .../MybatisIssuanceRequestRepository.java | 36 ++++++---- .../CommercialBankIssuanceController.java | 10 ++- src/main/resources/schema.sql | 8 +++ .../MybatisIssuanceRequestRepositoryTest.java | 42 ++++++----- 9 files changed, 169 insertions(+), 51 deletions(-) create mode 100644 src/main/java/com/yau/digitalrmb/issuance/domain/model/IssuanceAuditActor.java diff --git a/src/main/java/com/yau/digitalrmb/issuance/application/service/CommercialBankIssuanceApplicationService.java b/src/main/java/com/yau/digitalrmb/issuance/application/service/CommercialBankIssuanceApplicationService.java index cc4056d..c9891ea 100644 --- a/src/main/java/com/yau/digitalrmb/issuance/application/service/CommercialBankIssuanceApplicationService.java +++ b/src/main/java/com/yau/digitalrmb/issuance/application/service/CommercialBankIssuanceApplicationService.java @@ -8,6 +8,7 @@ import com.yau.digitalrmb.issuance.application.query.CommercialBankInventoryView import com.yau.digitalrmb.issuance.application.query.IssuanceRequestView; import com.yau.digitalrmb.issuance.domain.model.DenominationItem; import com.yau.digitalrmb.issuance.domain.model.IssuanceApplicationId; +import com.yau.digitalrmb.issuance.domain.model.IssuanceAuditActor; import com.yau.digitalrmb.issuance.domain.model.IssuanceBankInventory; import com.yau.digitalrmb.issuance.domain.model.IssuanceRequest; import com.yau.digitalrmb.issuance.domain.repository.IssuanceRequestRepository; @@ -58,96 +59,124 @@ public class CommercialBankIssuanceApplicationService { } @Transactional - public IssuanceRequestView create(CreateIssuanceRequestCommand command, String authenticatedAccountName) { + public IssuanceRequestView create(CreateIssuanceRequestCommand command, IssuanceAuditActor auditActor) { try { UUID id = UUID.randomUUID(); IssuanceRequest request = IssuanceRequest.create(new IssuanceApplicationId(id), requestNo(id), command.getBankCode(), command.getOrganizationId(), command.getTotalAmount(), command.getCurrency(), command.getDenominations()); - repository.save(request, auditActor(authenticatedAccountName)); + repository.save(request, auditActor(auditActor)); return IssuanceRequestView.from(request); } catch (IllegalArgumentException | IllegalStateException | NullPointerException exception) { throw validationError(exception); } } + public IssuanceRequestView create(CreateIssuanceRequestCommand command, String username) { + return create(command, legacyAuditActor(username)); + } + @Transactional - public IssuanceRequestView update(UUID id, UpdateIssuanceRequestCommand command, String authenticatedAccountName) { + public IssuanceRequestView update(UUID id, UpdateIssuanceRequestCommand command, IssuanceAuditActor auditActor) { try { IssuanceRequest request = requireRequest(id); request.updateDraft(command.getTotalAmount(), command.getCurrency(), command.getDenominations()); - repository.save(request, auditActor(authenticatedAccountName)); + repository.save(request, auditActor(auditActor)); return IssuanceRequestView.from(request); } catch (IllegalArgumentException | IllegalStateException | NullPointerException exception) { throw validationError(exception); } } + public IssuanceRequestView update(UUID id, UpdateIssuanceRequestCommand command, String username) { + return update(id, command, legacyAuditActor(username)); + } + @Transactional - public IssuanceRequestView prepareMessage(UUID id, String authenticatedAccountName) { + public IssuanceRequestView prepareMessage(UUID id, IssuanceAuditActor auditActor) { try { IssuanceRequest request = requireRequest(id); String timestamp = LocalDateTime.now().format(TIMESTAMP_FORMAT); String message = messageComposer.compose(request.getBankCode(), request.getOrganizationId(), request.getTotalAmount(), request.getDenominations(), request.getCurrency(), timestamp); request.prepareMessage(timestamp, message); - repository.save(request, auditActor(authenticatedAccountName)); + repository.save(request, auditActor(auditActor)); return IssuanceRequestView.from(request); } catch (IllegalArgumentException | IllegalStateException | NullPointerException exception) { throw validationError(exception); } } + public IssuanceRequestView prepareMessage(UUID id, String username) { + return prepareMessage(id, legacyAuditActor(username)); + } + @Transactional - public IssuanceRequestView digest(UUID id, String authenticatedAccountName) { + public IssuanceRequestView digest(UUID id, IssuanceAuditActor auditActor) { try { IssuanceRequest request = requireRequest(id); SignedIssuancePayload signedPayload = signatureService.sign(SIGNING_KEY_REF, request.getMessageText()); request.recordDigest(signedPayload.getDigest()); - repository.save(request, auditActor(authenticatedAccountName)); + repository.save(request, auditActor(auditActor)); return IssuanceRequestView.from(request); } catch (IllegalArgumentException | IllegalStateException | NullPointerException exception) { throw validationError(exception); } } + public IssuanceRequestView digest(UUID id, String username) { + return digest(id, legacyAuditActor(username)); + } + @Transactional - public IssuanceRequestView sign(UUID id, String authenticatedAccountName) { + public IssuanceRequestView sign(UUID id, IssuanceAuditActor auditActor) { try { IssuanceRequest request = requireRequest(id); SignedIssuancePayload signedPayload = signatureService.sign(SIGNING_KEY_REF, request.getMessageText()); request.recordSignature(signedPayload.getSigningKeyRef(), signedPayload.getSignature()); - repository.save(request, auditActor(authenticatedAccountName)); + repository.save(request, auditActor(auditActor)); return IssuanceRequestView.from(request); } catch (IllegalArgumentException | IllegalStateException | NullPointerException exception) { throw validationError(exception); } } + public IssuanceRequestView sign(UUID id, String username) { + return sign(id, legacyAuditActor(username)); + } + @Transactional - public IssuanceRequestView packagePayload(UUID id, String authenticatedAccountName) { + public IssuanceRequestView packagePayload(UUID id, IssuanceAuditActor auditActor) { try { IssuanceRequest request = requireRequest(id); request.packagePayload(payloadFor(request)); - repository.save(request, auditActor(authenticatedAccountName)); + repository.save(request, auditActor(auditActor)); return IssuanceRequestView.from(request); } catch (IllegalArgumentException | IllegalStateException | NullPointerException exception) { throw validationError(exception); } } + public IssuanceRequestView packagePayload(UUID id, String username) { + return packagePayload(id, legacyAuditActor(username)); + } + @Transactional - public IssuanceRequestView send(UUID id, String authenticatedAccountName) { + public IssuanceRequestView send(UUID id, IssuanceAuditActor auditActor) { try { IssuanceRequest request = requireRequest(id); request.sendToCentralBank(Instant.now()); - repository.save(request, auditActor(authenticatedAccountName)); + repository.save(request, auditActor(auditActor)); return IssuanceRequestView.from(request); } catch (IllegalArgumentException | IllegalStateException | NullPointerException exception) { throw validationError(exception); } } + public IssuanceRequestView send(UUID id, String username) { + return send(id, legacyAuditActor(username)); + } + @Transactional(readOnly = true) public IssuanceRequestView getCommercialBankView(UUID id) { return IssuanceRequestView.from(requireRequest(id)); @@ -204,11 +233,15 @@ public class CommercialBankIssuanceApplicationService { return "ISSUE_REQ_" + id.toString().replace("-", "").toUpperCase(Locale.ROOT); } - private static String auditActor(String authenticatedAccountName) { - if (authenticatedAccountName == null || authenticatedAccountName.trim().isEmpty()) { - throw new IllegalArgumentException("authenticated account name must not be blank"); + private static IssuanceAuditActor auditActor(IssuanceAuditActor auditActor) { + if (auditActor == null) { + throw new IllegalArgumentException("audit actor must not be null"); } - return authenticatedAccountName; + return auditActor; + } + + private static IssuanceAuditActor legacyAuditActor(String username) { + return new IssuanceAuditActor(0L, username); } private static BusinessException validationError(RuntimeException exception) { diff --git a/src/main/java/com/yau/digitalrmb/issuance/domain/model/IssuanceAuditActor.java b/src/main/java/com/yau/digitalrmb/issuance/domain/model/IssuanceAuditActor.java new file mode 100644 index 0000000..c06cbd5 --- /dev/null +++ b/src/main/java/com/yau/digitalrmb/issuance/domain/model/IssuanceAuditActor.java @@ -0,0 +1,30 @@ +package com.yau.digitalrmb.issuance.domain.model; + +import java.util.Objects; + +/** The authenticated user responsible for an issuance operation. */ +public final class IssuanceAuditActor { + public static final IssuanceAuditActor SYSTEM = new IssuanceAuditActor(0L, "SYSTEM"); + + private final long userId; + private final String username; + + public IssuanceAuditActor(long userId, String username) { + if (userId < 0L) { + throw new IllegalArgumentException("audit user id must not be negative"); + } + if (username == null || username.trim().isEmpty()) { + throw new IllegalArgumentException("audit username must not be blank"); + } + this.userId = userId; + this.username = username.trim(); + } + + public long getUserId() { + return userId; + } + + public String getUsername() { + return username; + } +} diff --git a/src/main/java/com/yau/digitalrmb/issuance/domain/repository/IssuanceRequestRepository.java b/src/main/java/com/yau/digitalrmb/issuance/domain/repository/IssuanceRequestRepository.java index 38637e4..090e3e1 100644 --- a/src/main/java/com/yau/digitalrmb/issuance/domain/repository/IssuanceRequestRepository.java +++ b/src/main/java/com/yau/digitalrmb/issuance/domain/repository/IssuanceRequestRepository.java @@ -1,6 +1,7 @@ package com.yau.digitalrmb.issuance.domain.repository; import com.yau.digitalrmb.issuance.domain.model.IssuanceApplicationId; +import com.yau.digitalrmb.issuance.domain.model.IssuanceAuditActor; import com.yau.digitalrmb.issuance.domain.model.IssuanceBankInventory; import com.yau.digitalrmb.issuance.domain.model.IssuanceRequest; @@ -9,7 +10,7 @@ import java.util.Optional; public interface IssuanceRequestRepository { void save(IssuanceRequest request); - default void save(IssuanceRequest request, String auditActor) { + default void save(IssuanceRequest request, IssuanceAuditActor auditActor) { save(request); } diff --git a/src/main/java/com/yau/digitalrmb/issuance/infrastructure/persistence/entity/IssuanceRequestDenominationEntity.java b/src/main/java/com/yau/digitalrmb/issuance/infrastructure/persistence/entity/IssuanceRequestDenominationEntity.java index 3e3c4c2..5d2f5d8 100644 --- a/src/main/java/com/yau/digitalrmb/issuance/infrastructure/persistence/entity/IssuanceRequestDenominationEntity.java +++ b/src/main/java/com/yau/digitalrmb/issuance/infrastructure/persistence/entity/IssuanceRequestDenominationEntity.java @@ -1,5 +1,6 @@ package com.yau.digitalrmb.issuance.infrastructure.persistence.entity; +import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; @@ -8,6 +9,7 @@ import lombok.Getter; import lombok.Setter; import java.math.BigDecimal; +import java.time.LocalDateTime; @Getter @Setter @@ -19,4 +21,20 @@ public class IssuanceRequestDenominationEntity { private BigDecimal denomination; private Integer quantity; + + @TableField(value = "created_at", fill = FieldFill.INSERT) + private LocalDateTime createdAt; + + @TableField(value = "updated_at", fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updatedAt; + + @TableField(value = "created_by", fill = FieldFill.INSERT) + private String createdBy; + + @TableField(value = "updated_by", fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + private Long createdByUserId; + + private Long updatedByUserId; } diff --git a/src/main/java/com/yau/digitalrmb/issuance/infrastructure/persistence/entity/IssuanceRequestEntity.java b/src/main/java/com/yau/digitalrmb/issuance/infrastructure/persistence/entity/IssuanceRequestEntity.java index f4a47b2..6b9b5a9 100644 --- a/src/main/java/com/yau/digitalrmb/issuance/infrastructure/persistence/entity/IssuanceRequestEntity.java +++ b/src/main/java/com/yau/digitalrmb/issuance/infrastructure/persistence/entity/IssuanceRequestEntity.java @@ -46,6 +46,10 @@ public class IssuanceRequestEntity { @TableField(value = "updated_by", fill = FieldFill.INSERT_UPDATE) private String updatedBy; + private Long createdByUserId; + + private Long updatedByUserId; + @TableLogic private Boolean deleted; } diff --git a/src/main/java/com/yau/digitalrmb/issuance/infrastructure/persistence/repository/MybatisIssuanceRequestRepository.java b/src/main/java/com/yau/digitalrmb/issuance/infrastructure/persistence/repository/MybatisIssuanceRequestRepository.java index 1394146..1561f17 100644 --- a/src/main/java/com/yau/digitalrmb/issuance/infrastructure/persistence/repository/MybatisIssuanceRequestRepository.java +++ b/src/main/java/com/yau/digitalrmb/issuance/infrastructure/persistence/repository/MybatisIssuanceRequestRepository.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.yau.digitalrmb.issuance.domain.model.CentralBankReceiveStatus; import com.yau.digitalrmb.issuance.domain.model.DenominationItem; import com.yau.digitalrmb.issuance.domain.model.IssuanceApplicationId; +import com.yau.digitalrmb.issuance.domain.model.IssuanceAuditActor; import com.yau.digitalrmb.issuance.domain.model.IssuanceBankInventory; import com.yau.digitalrmb.issuance.domain.model.IssuanceRequest; import com.yau.digitalrmb.issuance.domain.model.IssuanceRequestStatus; @@ -48,40 +49,40 @@ public class MybatisIssuanceRequestRepository implements IssuanceRequestReposito @Override @Transactional - public void save(IssuanceRequest request, String auditActor) { + public void save(IssuanceRequest request, IssuanceAuditActor auditActor) { saveInternal(request, Objects.requireNonNull(auditActor, "auditActor must not be null")); } - private void saveInternal(IssuanceRequest request, String auditActor) { + private void saveInternal(IssuanceRequest request, IssuanceAuditActor auditActor) { + IssuanceAuditActor effectiveActor = auditActor == null ? IssuanceAuditActor.SYSTEM : auditActor; String requestId = request.getId().value().toString(); IssuanceRequestEntity entity = toEntity(request); IssuanceRequestEntity existing = requestMapper.selectById(requestId); if (existing == null) { - assignAuditActorForInsert(entity, auditActor); + assignAuditActorForInsert(entity, effectiveActor); requestMapper.insert(entity); } else { - assignAuditActorForUpdate(entity, auditActor); + assignAuditActorForUpdate(entity, effectiveActor); requestMapper.updateById(entity); } denominationMapper.delete(new LambdaQueryWrapper() .eq(IssuanceRequestDenominationEntity::getRequestId, requestId)); for (DenominationItem denomination : request.getDenominations()) { - denominationMapper.insert(toDenominationEntity(requestId, denomination)); + denominationMapper.insert(toDenominationEntity(requestId, denomination, effectiveActor)); } } - private void assignAuditActorForInsert(IssuanceRequestEntity entity, String auditActor) { - if (auditActor != null) { - entity.setCreatedBy(auditActor); - entity.setUpdatedBy(auditActor); - } + private void assignAuditActorForInsert(IssuanceRequestEntity entity, IssuanceAuditActor auditActor) { + entity.setCreatedBy(auditActor.getUsername()); + entity.setUpdatedBy(auditActor.getUsername()); + entity.setCreatedByUserId(auditActor.getUserId()); + entity.setUpdatedByUserId(auditActor.getUserId()); } - private void assignAuditActorForUpdate(IssuanceRequestEntity entity, String auditActor) { - if (auditActor != null) { - entity.setUpdatedBy(auditActor); - } + private void assignAuditActorForUpdate(IssuanceRequestEntity entity, IssuanceAuditActor auditActor) { + entity.setUpdatedBy(auditActor.getUsername()); + entity.setUpdatedByUserId(auditActor.getUserId()); } @Override @@ -131,11 +132,16 @@ public class MybatisIssuanceRequestRepository implements IssuanceRequestReposito return entity; } - private IssuanceRequestDenominationEntity toDenominationEntity(String requestId, DenominationItem denomination) { + private IssuanceRequestDenominationEntity toDenominationEntity(String requestId, DenominationItem denomination, + IssuanceAuditActor auditActor) { IssuanceRequestDenominationEntity entity = new IssuanceRequestDenominationEntity(); entity.setRequestId(requestId); entity.setDenomination(denomination.getDenomination()); entity.setQuantity(denomination.getQuantity()); + entity.setCreatedBy(auditActor.getUsername()); + entity.setUpdatedBy(auditActor.getUsername()); + entity.setCreatedByUserId(auditActor.getUserId()); + entity.setUpdatedByUserId(auditActor.getUserId()); return entity; } diff --git a/src/main/java/com/yau/digitalrmb/issuance/interfaces/rest/CommercialBankIssuanceController.java b/src/main/java/com/yau/digitalrmb/issuance/interfaces/rest/CommercialBankIssuanceController.java index 637a0c0..c9d1af5 100644 --- a/src/main/java/com/yau/digitalrmb/issuance/interfaces/rest/CommercialBankIssuanceController.java +++ b/src/main/java/com/yau/digitalrmb/issuance/interfaces/rest/CommercialBankIssuanceController.java @@ -8,6 +8,7 @@ import com.yau.digitalrmb.issuance.application.query.IssuanceRequestView; import com.yau.digitalrmb.issuance.application.service.CommercialBankIssuanceApplicationService; import com.yau.digitalrmb.issuance.application.service.DenominationPlanService; import com.yau.digitalrmb.issuance.domain.model.DenominationItem; +import com.yau.digitalrmb.issuance.domain.model.IssuanceAuditActor; import com.yau.digitalrmb.issuance.interfaces.dto.CreateIssuanceRequest; import com.yau.digitalrmb.issuance.interfaces.dto.DenominationItemRequest; import com.yau.digitalrmb.issuance.interfaces.dto.DenominationPlanRequest; @@ -62,6 +63,13 @@ public class CommercialBankIssuanceController { } return result; } - private String actor(Jwt jwt){String account=jwt.getClaimAsString("preferred_username"); return account==null||account.trim().isEmpty()?jwt.getSubject():account;} + private IssuanceAuditActor actor(Jwt jwt){ + String username=jwt.getClaimAsString("preferred_username"); + if(username==null||username.trim().isEmpty()) username=jwt.getSubject(); + Object claim=jwt.getClaim("userId"); + String userId=claim==null?jwt.getSubject():String.valueOf(claim); + try{return new IssuanceAuditActor(Long.parseLong(userId),username);} + catch(NumberFormatException exception){throw new IllegalArgumentException("current user id must be a number");} + } private ApiResponse ok(T data){return ApiResponse.success(data,MDC.get(TraceIdFilter.MDC_KEY));} } diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index ae2c631..f69480e 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -105,6 +105,8 @@ CREATE TABLE IF NOT EXISTS issuance_request ( updated_at TIMESTAMP NOT NULL, created_by VARCHAR(64) NOT NULL, updated_by VARCHAR(64) NOT NULL, + created_by_user_id BIGINT NOT NULL, + updated_by_user_id BIGINT NOT NULL, deleted BOOLEAN NOT NULL DEFAULT FALSE ); @@ -112,6 +114,12 @@ CREATE TABLE IF NOT EXISTS issuance_request_denomination ( request_id CHAR(36) NOT NULL, denomination DECIMAL(10, 2) NOT NULL, quantity INT NOT NULL, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL, + created_by VARCHAR(64) NOT NULL, + updated_by VARCHAR(64) NOT NULL, + created_by_user_id BIGINT NOT NULL, + updated_by_user_id BIGINT NOT NULL, PRIMARY KEY (request_id, denomination) ); diff --git a/src/test/java/com/yau/digitalrmb/issuance/infrastructure/persistence/MybatisIssuanceRequestRepositoryTest.java b/src/test/java/com/yau/digitalrmb/issuance/infrastructure/persistence/MybatisIssuanceRequestRepositoryTest.java index 6490d42..d0a2591 100644 --- a/src/test/java/com/yau/digitalrmb/issuance/infrastructure/persistence/MybatisIssuanceRequestRepositoryTest.java +++ b/src/test/java/com/yau/digitalrmb/issuance/infrastructure/persistence/MybatisIssuanceRequestRepositoryTest.java @@ -6,6 +6,7 @@ import com.yau.digitalrmb.issuance.application.service.CommercialBankIssuanceApp import com.yau.digitalrmb.issuance.domain.model.CentralBankReceiveStatus; import com.yau.digitalrmb.issuance.domain.model.DenominationItem; import com.yau.digitalrmb.issuance.domain.model.IssuanceBankInventory; +import com.yau.digitalrmb.issuance.domain.model.IssuanceAuditActor; import com.yau.digitalrmb.issuance.domain.model.IssuanceApplicationId; import com.yau.digitalrmb.issuance.domain.model.IssuanceRequest; import com.yau.digitalrmb.issuance.domain.model.IssuanceRequestStatus; @@ -97,21 +98,21 @@ class MybatisIssuanceRequestRepositoryTest { @Test void commercialBankWritesPersistTheSuppliedActorForCreateUpdateAndTransitions() { - UUID requestId = commercialBankService.create(createCommand(), "creator").getId(); - assertAuditActor(requestId, "creator", "creator"); - - commercialBankService.update(requestId, updateCommand(), "updater"); - assertAuditActor(requestId, "creator", "updater"); - commercialBankService.prepareMessage(requestId, "preparer"); - assertAuditActor(requestId, "creator", "preparer"); - commercialBankService.digest(requestId, "digester"); - assertAuditActor(requestId, "creator", "digester"); - commercialBankService.sign(requestId, "signer"); - assertAuditActor(requestId, "creator", "signer"); - commercialBankService.packagePayload(requestId, "packager"); - assertAuditActor(requestId, "creator", "packager"); - commercialBankService.send(requestId, "sender"); - assertAuditActor(requestId, "creator", "sender"); + UUID requestId = commercialBankService.create(createCommand(), actor(101L, "creator")).getId(); + assertAuditActor(requestId, 101L, "creator", 101L, "creator"); + + commercialBankService.update(requestId, updateCommand(), actor(102L, "updater")); + assertAuditActor(requestId, 101L, "creator", 102L, "updater"); + commercialBankService.prepareMessage(requestId, actor(103L, "preparer")); + assertAuditActor(requestId, 101L, "creator", 103L, "preparer"); + commercialBankService.digest(requestId, actor(104L, "digester")); + assertAuditActor(requestId, 101L, "creator", 104L, "digester"); + commercialBankService.sign(requestId, actor(105L, "signer")); + assertAuditActor(requestId, 101L, "creator", 105L, "signer"); + commercialBankService.packagePayload(requestId, actor(106L, "packager")); + assertAuditActor(requestId, 101L, "creator", 106L, "packager"); + commercialBankService.send(requestId, actor(107L, "sender")); + assertAuditActor(requestId, 101L, "creator", 107L, "sender"); } private CreateIssuanceRequestCommand createCommand() { @@ -124,10 +125,19 @@ class MybatisIssuanceRequestRepositoryTest { Arrays.asList(new DenominationItem(100, 500))); } - private void assertAuditActor(UUID requestId, String expectedCreatedBy, String expectedUpdatedBy) { + private IssuanceAuditActor actor(long userId, String username) { + return new IssuanceAuditActor(userId, username); + } + + private void assertAuditActor(UUID requestId, long expectedCreatedByUserId, String expectedCreatedBy, + long expectedUpdatedByUserId, String expectedUpdatedBy) { com.yau.digitalrmb.issuance.infrastructure.persistence.entity.IssuanceRequestEntity entity = requestMapper.selectById(requestId.toString()); + assertThat(entity.getCreatedAt()).isNotNull(); + assertThat(entity.getUpdatedAt()).isNotNull(); + assertThat(entity.getCreatedByUserId()).isEqualTo(expectedCreatedByUserId); assertThat(entity.getCreatedBy()).isEqualTo(expectedCreatedBy); + assertThat(entity.getUpdatedByUserId()).isEqualTo(expectedUpdatedByUserId); assertThat(entity.getUpdatedBy()).isEqualTo(expectedUpdatedBy); }