Skip to content

Dev#60

Merged
DonjJin-github merged 14 commits intomainfrom
dev
Nov 11, 2025
Merged

Dev#60
DonjJin-github merged 14 commits intomainfrom
dev

Conversation

@parkji1on
Copy link
Contributor

요약

  • 이 PR의 목적과 배경을 한 줄로 설명해주세요.

주요 변경 사항

  • 변경 요약 1
  • 변경 요약 2

관련 이슈

  • Closes #번호 (예: Closes #123)

테스트/검증

  • 어떻게 검증했는지, 영향 범위는 어디인지 간략히 적어주세요.

확인 사항

  • 자기 리뷰 완료
  • 빌드/테스트 통과 확인
  • 문서/주석 업데이트(필요 시)
  • 브레이킹 체인지 없음 또는 마이그레이션 안내 포함

스크린샷/로그(선택)

  • 필요 시 첨부

@github-actions
Copy link

PR 검증 성공

브랜치: devmain
커밋: 2c692c0

모든 검증을 통과했습니다. 리뷰를 요청해주세요.

워크플로우 로그 확인

Copy link
Contributor

@DonjJin-github DonjJin-github left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다

@DonjJin-github DonjJin-github merged commit aeb1a05 into main Nov 11, 2025
11 checks passed
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces an alarm/notification system to the SCM service. The changes add event-driven notification functionality using Kafka to send alerts to users when specific purchase-related actions occur (requisition approval/rejection, purchase order approval/rejection/delivery).

  • Added alarm event data models including AlarmEvent, AlarmSentEvent, StatusEvent, and supporting enum types
  • Integrated alarm notification sending at key business events in purchase requisition and purchase order workflows
  • Updated Kafka infrastructure to support new alarm topics and event handling

Reviewed Changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
TargetType.java New enum defining alarm recipient types (employee, department, customer, supplier)
SourceType.java New enum defining alarm source systems with conversion and validation utilities
LinkType.java New enum defining types of linked documents for alarm references
AlarmType.java New enum defining alarm categories by department/module
StatusEvent.java New event class for tracking alarm processing status with failure details
AlarmSentEvent.java New event class for alarm delivery notifications from alarm server to clients
AlarmEvent.java New event class for alarm requests from services to alarm server
QuotationServiceImpl.java Added TODO comment for quotation confirmation alarm
MesServiceImpl.java Added empty line (whitespace change)
PurchaseRequisitionServiceImpl.java Integrated alarm sending for requisition approval and rejection
PurchaseOrderServiceImpl.java Integrated alarm sending for order approval, rejection, delivery start, and delivery completion
SalesOrderServiceImpl.java Added TODO comment for sales order shipment completion alarm
KafkaProducerServiceImpl.java Updated to use new alarm topic and improved code formatting
KafkaProducerService.java Updated import structure and formatting
AlarmStatusEventListener.java New Kafka listener for handling alarm status events
KafkaTopicConfig.java Added new alarm-related Kafka topics
.husky/pre-commit Removed husky pre-commit hook
.husky/commit-msg Removed husky commit message hook
Comments suppressed due to low confidence (1)

src/main/java/org/ever/_4ever_be_scm/scm/mm/service/impl/PurchaseOrderServiceImpl.java:1

  • Duplicate UUID generation on lines 512 and 516. Both eventId and alarmId are being assigned the same UUID value, but calling UuidCreator.getTimeOrderedEpoch().toString() twice may generate different values. If they should be the same, generate once and reuse; if different, this is likely unintended.
package org.ever._4ever_be_scm.scm.mm.service.impl;

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +322 to +327
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(UuidCreator.getTimeOrderedEpoch().toString())
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(UuidCreator.getTimeOrderedEpoch().toString())
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate UUID generation on lines 323 and 327. Both eventId and alarmId are being assigned the same UUID value, but calling UuidCreator.getTimeOrderedEpoch().toString() twice may generate different values. If they should be the same, generate once and reuse; if different, this is likely unintended. This pattern repeats throughout the file.

Suggested change
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(UuidCreator.getTimeOrderedEpoch().toString())
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(UuidCreator.getTimeOrderedEpoch().toString())
String uuid = UuidCreator.getTimeOrderedEpoch().toString();
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(uuid)
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(uuid)

Copilot uses AI. Check for mistakes.
Comment on lines +385 to +390
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(UuidCreator.getTimeOrderedEpoch().toString())
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(UuidCreator.getTimeOrderedEpoch().toString())
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate UUID generation on lines 386 and 390. Both eventId and alarmId are being assigned the same UUID value, but calling UuidCreator.getTimeOrderedEpoch().toString() twice may generate different values. If they should be the same, generate once and reuse; if different, this is likely unintended.

Suggested change
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(UuidCreator.getTimeOrderedEpoch().toString())
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(UuidCreator.getTimeOrderedEpoch().toString())
String alarmEventId = UuidCreator.getTimeOrderedEpoch().toString();
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(alarmEventId)
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(alarmEventId)

Copilot uses AI. Check for mistakes.
Comment on lines +394 to +399
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(UuidCreator.getTimeOrderedEpoch().toString())
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(UuidCreator.getTimeOrderedEpoch().toString())
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate UUID generation on lines 395 and 399. Both eventId and alarmId are being assigned the same UUID value, but calling UuidCreator.getTimeOrderedEpoch().toString() twice may generate different values. If they should be the same, generate once and reuse; if different, this is likely unintended. This pattern repeats in multiple places in this file.

Suggested change
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(UuidCreator.getTimeOrderedEpoch().toString())
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(UuidCreator.getTimeOrderedEpoch().toString())
String eventAlarmUuid = UuidCreator.getTimeOrderedEpoch().toString();
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(eventAlarmUuid)
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(eventAlarmUuid)

Copilot uses AI. Check for mistakes.
.targetType(TargetType.EMPLOYEE)
.title("발주서 승인")
.message("해당 발주서가 승인되었습니다. 발주서 번호 = " + productOrder.getProductOrderCode())
.linkId(productOrder.getProductOrderCode())
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent linkId field usage. Line 405 uses productOrder.getProductOrderCode() while other alarm events in this file (lines 523, 590, 710) also use the same. However, in PurchaseRequisitionServiceImpl, the linkId is set to productRequest.getId() (lines 333, 396). The linkId should consistently use either the ID or the code, not mix both approaches.

Suggested change
.linkId(productOrder.getProductOrderCode())
.linkId(productOrder.getId())

Copilot uses AI. Check for mistakes.
Comment on lines +579 to +584
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(UuidCreator.getTimeOrderedEpoch().toString())
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(UuidCreator.getTimeOrderedEpoch().toString())
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate UUID generation on lines 580 and 584. Both eventId and alarmId are being assigned the same UUID value, but calling UuidCreator.getTimeOrderedEpoch().toString() twice may generate different values. If they should be the same, generate once and reuse; if different, this is likely unintended.

Suggested change
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(UuidCreator.getTimeOrderedEpoch().toString())
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(UuidCreator.getTimeOrderedEpoch().toString())
String alarmEventId = UuidCreator.getTimeOrderedEpoch().toString();
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(alarmEventId)
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(alarmEventId)

Copilot uses AI. Check for mistakes.
Comment on lines +699 to +704
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(UuidCreator.getTimeOrderedEpoch().toString())
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(UuidCreator.getTimeOrderedEpoch().toString())
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate UUID generation on lines 700 and 704. Both eventId and alarmId are being assigned the same UUID value, but calling UuidCreator.getTimeOrderedEpoch().toString() twice may generate different values. If they should be the same, generate once and reuse; if different, this is likely unintended.

Suggested change
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(UuidCreator.getTimeOrderedEpoch().toString())
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(UuidCreator.getTimeOrderedEpoch().toString())
String alarmEventId = UuidCreator.getTimeOrderedEpoch().toString();
AlarmEvent alarmEventForCreate = AlarmEvent.builder()
.eventId(alarmEventId)
.eventType(AlarmEvent.class.getName())
.timestamp(LocalDateTime.now())
.source(SourceType.SCM.name())
.alarmId(alarmEventId)

Copilot uses AI. Check for mistakes.
Comment on lines +341 to +355
kafkaProducerService.sendAlarmEvent(alarmEventForCreate)
.whenComplete((result, ex) -> {
if (ex != null) {
log.error("[ALARM] 알림 요청 전송 실패 - alarmId: {}, targetId: {}, error: {}",
alarmEventForCreate.getAlarmId(), targetId, ex.getMessage(), ex);
} else if (result != null) {
log.info("[ALARM] 알림 요청 전송 성공 - topic: {}, partition: {}, offset: {}",
result.getRecordMetadata().topic(),
result.getRecordMetadata().partition(),
result.getRecordMetadata().offset());
} else {
log.warn("[ALARM] 알림 요청 전송 결과가 null 입니다 - alarmId: {}, targetId: {}",
alarmEventForCreate.getAlarmId(), targetId);
}
});
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated alarm event logging code. This exact logging pattern for handling alarm event results is repeated multiple times across PurchaseRequisitionServiceImpl and PurchaseOrderServiceImpl. Consider extracting this into a reusable method or utility to reduce code duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
// public static final String ALARM_SENT_TOPIC = "alarm-sent"; // 알림 발송
// public static final String ALARM_SENT_STATUS_TOPIC = "alarm-sent-status"; // 알림 발송 상태

@Bean
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Kafka topic bean definitions. While ALARM_REQUEST_TOPIC and ALARM_REQUEST_STATUS_TOPIC constants are defined, there are no corresponding @Bean methods to actually create these topics (unlike other topics in this file which have bean definitions). This will cause the topics not to be auto-created by Spring Kafka.

Suggested change
@Bean
@Bean
public NewTopic alarmRequestTopic() {
return TopicBuilder.name(ALARM_REQUEST_TOPIC)
.partitions(3)
.replicas(1)
.build();
}
@Bean
public NewTopic alarmRequestStatusTopic() {
return TopicBuilder.name(ALARM_REQUEST_STATUS_TOPIC)
.partitions(3)
.replicas(1)
.build();
}
@Bean

Copilot uses AI. Check for mistakes.
Comment on lines +4 to +8
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary Lombok annotations on enum. The @RequiredArgsConstructor annotation is unnecessary for enums as they cannot have constructors in the traditional sense. Additionally, @Getter is redundant since enum values are already accessible. These annotations have no effect and should be removed.

Suggested change
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor

Copilot uses AI. Check for mistakes.
import org.ever._4ever_be_scm.infrastructure.kafka.event.BaseEvent;

@Getter
@SuperBuilder
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default toString(): FailureInfo inherits toString() from Object, and so is not suitable for printing.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants