221205 어드민에서 관리자의 활동 기록을 남겨보자

샨티(shanti)·2022년 12월 5일
0

하루를 마무리 하기 전, 오늘 있었던 일들을 잔잔히 되짚어봅니다.
성공과 실패의 모든 요소에서 '배울 점'을 찾아내어 기록하고,
더 성장하는 내일의 나를 위해 'action plan'을 세웁니다.

오늘은 기능 구현을 1차로 마무리 하는 날이었다.
한 주 동안 어드민 기능을 여러모로 구현해보았는데 처음 계획보다 굉-장히 조촐한 기능이 되어 좀 아쉽지만.. 그래도 어드민 기능을 구현해보면서 사용자 단의 서비스를 구현할 때 생각하지 못했던 부분들을 생각해보기도 했고, 왠지 모를 욕심에 수료 후에 이런 저런 기능들을 추가해야지! 하며 의지를 불태우기도..ㅎㅎ

스프린트 점검 직전까지 뭘 조금 더 해볼 수 있을까? 하고 고민해봤는데 '관리자 활동 로그'를 만드는 게 좋겠다는 생각이 들었다.
지난번에 사용자 리뷰 삭제 버튼 클릭 시 삭제 사유를 입력하는 모달창을 띄우는 이벤트를 만들어두었는데 그게 마무리되지 않은 탓도 있었고, 예전에 회사생활을 하면서 어드민을 사용했을 때 정말 사소한 것 하나까지 사유란에 적어야 했던 웃픈 에피소드가 있었기에...
뭔가 그 떄의 추억을 되살리면서 관리자 활동 기록을 남겨보기로 결정.

사실 지금 만들려는 관리자 활동 기록, 즉 로그라고 할 수 있는 이 기록은 노아님이 라이브러리를 활용하여 구현할 수 있다고 하셨다.
하지만 어떤 라이브러리를 활용해야 할지 감이 잘 오지 않았고, 스프린트 점검 직전까지 빠짝 완성을 해놓아야 했기에 AdminLog라는 entity를 생성해서 admin의 action이 발생할 때 로그를 생성하여 repository에 저장하는 방식으로 구현을 해보려 했다.


어드민이 사용자의 리뷰를 삭제하기 위해 삭제 버튼을 눌렀을 때 위와 같은 모달창으로 사유, 그리고 해당 admin의 로그인 비밀번호를 입력하도록 구현했다.
예전 직장에서는 민원인과 조금이라도 트러블이 생겼을 때 당시의 상황과 오고 간 이야기들이 사유란에 남아있어야 대응이 되었었기에..ㅎㅎ 그런 경험에서 우러난 기능(;;)이라고 볼 수 있겠다.
그리고 지금 사용자 리뷰를 삭제하는 방식이 soft delete 방식이 아니기에 삭제 방식을 변환하는 리팩토링 전까지는 더더욱 이 로그를 남겨야 한다는 왠지 모를 불안함이..ㅎㅎ
근데 지금 TIL을 쓰면서 보니 로그에 남겨지는 기록이 너무 조촐한 것 같기도 하다.
담당자 ID, 사번, 삭제일(오늘 날짜), 사유, 비밀번호이고 서버측에서 로그가 생성될 때 어떤 액션이 발생한건지(ex. 사용자 리뷰 삭제) 기록해주는데...

적어도 삭제된 게시물id나 작성자id 정도는 추가로 들어가야 하는게 아닌가 싶기도 하다.

아래는 controller와 service의 코드.

// AdminUserReviewController.java

@RestController
@RequestMapping("admin-user-reviews")
public class AdminUserReviewController {
    private final GetUserReviewService getUserReviewService;
    private final DeleteUserReviewService deleteUserReviewService;

    public AdminUserReviewController(GetUserReviewService getUserReviewService,
                                     DeleteUserReviewService deleteUserReviewService) {
        this.getUserReviewService = getUserReviewService;
        this.deleteUserReviewService = deleteUserReviewService;
    }
    
 // 중략
 
 @DeleteMapping("{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteUserReview(
        @PathVariable Long id,
        @RequestAttribute String socialLoginId,
        @RequestBody DeleteReviewRequestDto deleteReviewRequestDto
    ) {
        deleteUserReviewService.delete(id, socialLoginId, deleteReviewRequestDto);
    }
 }

// DeleteUserReviewService.java

@Service
@Transactional
public class DeleteUserReviewService {
    private final UserReviewRepository userReviewRepository;
    private final AdminRepository adminRepository;
    private final AdminLogRepository adminLogRepository;
    private final PasswordEncoder passwordEncoder;

    public DeleteUserReviewService(UserReviewRepository userReviewRepository,
                                   AdminRepository adminRepository,
                                   AdminLogRepository adminLogRepository,
                                   PasswordEncoder passwordEncoder) {
        this.userReviewRepository = userReviewRepository;
        this.adminRepository = adminRepository;
        this.adminLogRepository = adminLogRepository;
        this.passwordEncoder = passwordEncoder;
    }
    
// 중략

public void delete(Long reviewId, String adminSocialLoginId,
                       DeleteReviewRequestDto deleteReviewRequestDto) {

        String password = deleteReviewRequestDto.getPassword();
        String reason = deleteReviewRequestDto.getReason();

        // 어드민의 socialLoginId, password 일치 여부를 한번 더 확인하여 삭제 진행

        Admin foundAdmin = adminRepository.findBySocialLoginId(adminSocialLoginId)
            .orElseThrow(AuthenticationError::new);

        boolean isCorrectAdmin = foundAdmin.authenticate(password, passwordEncoder);

        if (!isCorrectAdmin) {
            throw new AdminPasswordError();
        }

        userReviewRepository.deleteById(reviewId);

        AdminLog createdAdminLog = new AdminLog(adminSocialLoginId,
            foundAdmin.employeeIdentificationNumber(),
            "deleteUserReview", reason);

        adminLogRepository.save(createdAdminLog);
    }
}

가장 고민이 되는 지점이 있었는데, 바로 삭제 행위 후 어드민 로그를 생성해주는 포인트를 DeleteUserReviewService에서 잡아줘도 되는지였다.

예전같았으면 별 생각없이 삭제 행위 후에 바로 이어서 써줬을 것 같은데, 클래스 이름 앞에 'Delete'가 붙으니 왠지 delete에 해당하는 행위만 포함되어야 할 것 같은 이유에서였다.

도저히 나만의 노력으론 풀릴 것 같지 않아 동료들에게 조언을 구했는데, 마카오뱅크 강의에서 송금(transfer)이 발생한 후 이에 해당하는 거래내역(transaction)이 TransferService에서 생성되었다는 점을 상기시켜주었다.

그렇게 생각해보니 리뷰가 삭제된 후에 바로 로그가 그 서비스 안에서 생성되고 repository에 저장될 수 있겠다 싶어 위와 같이 구현해낼 수 있었다.

비록 스프린트 점검시간엔 위 기능이 모두 구현되지는 않았지만 오늘 내로 완성하면 내일부턴 에이미님이 만들어주신 디자인을 덧입힐 수 있을 것 같다.

넘... ㅇㅖ쁜 디자인이 와서.. 아깐 코드를 더 치지 못하고 (ㅋㅋ) 피그마만 여러번 열었다 닫았다를 반복했다.

무언가를 만들어낸다는 게 이런거구나... 오랜만에 신선한 즐거움을 느끼고 있다.

어서 부족한 점을 보완하고 한차례 마무리를 지은 다음에 또 원하는 기능들을 추가하면서 고도화하고 싶다.

이제 정-말 마지막 한 주... 잘 마무리 하자. 끝까지 포기하지 말고~ 나는야 중꺾맘!!!(중요한 것은 꺾이지 않는 엄마... 읭?)

profile
가벼운 사진, 그렇지 못한 글

0개의 댓글