AuditEvent.java
package com.rbctcsworld.ecommerce.audit;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.List;
/**
* Published by a service inside its transaction; AuditService writes it just before that transaction
* commits - so a change that is rolled back leaves no audit row, and a committed change always has one.
* The actor is taken when the event is created: the logged-in user, or "system" (scheduled jobs, startup).
*/
public record AuditEvent(String actor, List<AuditChange> changes) {
public static final String SYSTEM = "system";
public static AuditEvent of(List<AuditChange> changes) {
return new AuditEvent(currentActor(), List.copyOf(changes));
}
/** An order moved from one status to another. */
public static AuditEvent orderStatus(long orderId, String from, String to) {
return of(List.of(new AuditChange(AuditChange.ORDER, orderId, "ORDER_STATUS", "status", from, to)));
}
static String currentActor() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
return auth == null || auth.getName() == null || "anonymousUser".equals(auth.getName()) ? SYSTEM : auth.getName();
}
}