Skip to content

Commit 5310e9a

Browse files
authored
Merge pull request #2 from sopt-makers/feat/#1
feat: 센트리 웹훅 수신 기능 구현 완료
2 parents 23d2dbd + 474bf2d commit 5310e9a

34 files changed

+999
-7
lines changed

.github/release-drafter-config.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name-template: 'v$RESOLVED_VERSION'
2+
tag-template: 'v$RESOLVED_VERSION'
3+
4+
categories:
5+
- title: '✨ 새로운 기능'
6+
labels: ['feat']
7+
- title: '🐞 버그 수정'
8+
labels: ['fix']
9+
- title: '🧹 코드 개선 및 리팩토링'
10+
labels: ['refactor', 'style', 'chore']
11+
- title: '🧪 테스트'
12+
labels: ['test']
13+
- title: '🛠 문서 및 기타 변경'
14+
labels: ['docs']
15+
16+
change-template: '- $TITLE (#$NUMBER by @$AUTHOR)'
17+
no-changes-template: '이번 릴리스에는 변경 사항이 없습니다.'
18+
19+
template: |
20+
## 🚀 릴리스 노트: v$RESOLVED_VERSION
21+
아래는 이번 릴리스에 포함된 변경 사항입니다.
22+
---
23+
24+
$CHANGES
25+
26+
version-resolver:
27+
major:
28+
labels:
29+
- '1️⃣ major'
30+
minor:
31+
labels:
32+
- '2️⃣ minor'
33+
patch:
34+
labels:
35+
- '3️⃣ patch'
36+
default: patch
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: Release Drafter
2+
on:
3+
push:
4+
branches:
5+
- main
6+
jobs:
7+
update_release_draft:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: release-drafter/release-drafter@v5
11+
with:
12+
config-name: release-drafter-config.yml
13+
env:
14+
GITHUB_TOKEN: ${{ secrets.ACTION_TOKEN }}

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@
77
이를 **팀명과 서버 유형(FE/BE 등)에 따라 분기 처리**하여
88
슬랙 등의 외부 알림 채널로 전송해주는 Lambda 기반 서비스입니다.
99

10+
본 프로젝트는 Sentry 이벤트를 Slack으로 전송하는 AWS Lambda 함수를 구현하기 위해 Spring 없이 Java만으로 구현했습니다.
11+
이러한 기술적 결정에는 다음과 같은 이유가 있습니다:
12+
13+
- AWS Lambda 콜드 스타트 최소화: SpringBoot와 같은 무거운 프레임워크는 초기화 시간이 길어 Lambda의 콜드 스타트 지연 문제를 악화시킬 수 있습니다. 그래서 순수 Java로만 구현하여 시작 시간을 단축했습니다.
14+
- 리소스 효율성: 경량화된 애플리케이션으로 Lambda의 메모리 사용량을 최소화하고, 이는 비용 효율성으로 이어집니다.
15+
- 조직 친화적 기술 스택: Kotlin + Ktor와 같은 대안도 고려했지만, BE 챕터원들이 메이커스 프로젝트 개발에 Java를 주로 사용하고 있다는 점을 고려했습니다. 새로운 언어 도입 시 팀 내 지식 공유와 유지보수에 추가적인 부담이 발생할 수 있어 기존 기술 스택인 Java를 선택했습니다.
16+
- 최소 의존성: 필요한 최소한의 라이브러리만 사용하여 배포 패키지 크기를 줄이고 시작 시간을 개선했습니다.
17+
1018
## 🏗️ Tech Stack
1119

1220
- **Java 21**

src/main/java/org/sopt/makers/Main.java

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.sopt.makers.dto;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
5+
import lombok.AccessLevel;
6+
import lombok.Builder;
7+
8+
@Builder(access = AccessLevel.PRIVATE)
9+
public record SentryEventDetail(
10+
String issueId,
11+
String webUrl,
12+
String message,
13+
String datetime,
14+
String level
15+
) {
16+
public static SentryEventDetail from(JsonNode eventNode) {
17+
return SentryEventDetail.builder()
18+
.issueId(eventNode.path("issue_id").asText())
19+
.webUrl(eventNode.path("web_url").asText())
20+
.message(eventNode.path("message").asText())
21+
.datetime(eventNode.path("datetime").asText())
22+
.level(eventNode.path("level").asText())
23+
.build();
24+
}
25+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.sopt.makers.dto;
2+
3+
import java.util.Map;
4+
5+
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
6+
7+
import lombok.AccessLevel;
8+
import lombok.Builder;
9+
10+
@Builder(access = AccessLevel.PRIVATE)
11+
public record WebhookRequest(
12+
String stage,
13+
String team,
14+
String type,
15+
String serviceType
16+
) {
17+
public static WebhookRequest from(APIGatewayProxyRequestEvent input) {
18+
String stage = input.getRequestContext().getStage();
19+
Map<String, String> pathParameters = input.getPathParameters();
20+
if (pathParameters == null) {
21+
pathParameters = Map.of();
22+
}
23+
24+
String team = pathParameters.get("team");
25+
String type = pathParameters.get("type");
26+
String serviceType = pathParameters.getOrDefault("service", "slack");
27+
28+
return WebhookRequest.builder()
29+
.stage(stage)
30+
.team(team)
31+
.type(type)
32+
.serviceType(serviceType)
33+
.build();
34+
}
35+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.sopt.makers.global.config;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import com.fasterxml.jackson.databind.DeserializationFeature;
5+
import com.fasterxml.jackson.databind.ObjectMapper;
6+
import com.fasterxml.jackson.databind.SerializationFeature;
7+
8+
import lombok.AccessLevel;
9+
import lombok.NoArgsConstructor;
10+
11+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
12+
public class ObjectMapperConfig {
13+
14+
public static ObjectMapper getInstance() {
15+
return ObjectMapperHolder.INSTANCE;
16+
}
17+
18+
private static class ObjectMapperHolder {
19+
private static final ObjectMapper INSTANCE = createObjectMapper();
20+
21+
private static ObjectMapper createObjectMapper() {
22+
ObjectMapper objectMapper = new ObjectMapper();
23+
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
24+
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
25+
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
26+
return objectMapper;
27+
}
28+
}
29+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.sopt.makers.global.constant;
2+
3+
import java.util.Arrays;
4+
import java.util.Set;
5+
6+
import lombok.Getter;
7+
import lombok.RequiredArgsConstructor;
8+
9+
@Getter
10+
@RequiredArgsConstructor
11+
public enum Color {
12+
RED("#FF0000", Set.of("fatal", "critical")),
13+
ORANGE("#E36209", Set.of("error")),
14+
YELLOW("#FFCC00", Set.of("warning")),
15+
GREEN("#36A64F", Set.of("info")),
16+
BLUE("#87CEFA", Set.of("debug")),
17+
GRAY("#AAAAAA", Set.of());
18+
19+
private final String value;
20+
private final Set<String> levels;
21+
22+
public static String getColorByLevel(String level) {
23+
if (level == null || level.trim().isEmpty()) {
24+
return GRAY.value;
25+
}
26+
27+
String normalized = level.trim().toLowerCase();
28+
return Arrays.stream(Color.values())
29+
.filter(color -> color.levels.contains(normalized))
30+
.map(Color::getValue)
31+
.findFirst()
32+
.orElse(GRAY.value);
33+
}
34+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package org.sopt.makers.global.constant;
2+
3+
import lombok.AccessLevel;
4+
import lombok.NoArgsConstructor;
5+
6+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
7+
public final class SlackConstant {
8+
// 날짜 포맷 형식
9+
public static final String DATE_FORMAT_PATTERN = "yyyy-MM-dd HH:mm:ss";
10+
11+
// 버튼 텍스트
12+
public static final String SENTRY_BUTTON_TEXT = "상세 보기";
13+
14+
// HTTP 관련 상수
15+
public static final String HEADER_CONTENT_TYPE = "Content-Type";
16+
public static final String CONTENT_TYPE_JSON = "application/json";
17+
18+
// Slack 블록 타입 상수
19+
public static final String BLOCK_TYPE_HEADER = "header";
20+
public static final String BLOCK_TYPE_SECTION = "section";
21+
public static final String BLOCK_TYPE_ACTIONS = "actions";
22+
23+
// 텍스트 타입 상수
24+
public static final String TEXT_TYPE_PLAIN = "plain_text";
25+
public static final String TEXT_TYPE_MARKDOWN = "mrkdwn";
26+
27+
// 요소 타입 상수 (버튼)
28+
public static final String ELEMENT_TYPE_BUTTON = "button";
29+
30+
// 스타일 상수
31+
public static final String STYLE_PRIMARY = "primary";
32+
33+
// 시간대 관련 상수
34+
public static final String TIMEZONE_SEOUL = "Asia/Seoul";
35+
36+
// 줄바꿈 상수
37+
public static final String NEW_LINE = "\n";
38+
39+
// JSON 키 상수
40+
public static final String MESSAGE = "message";
41+
public static final String ERROR = "error";
42+
public static final String CODE = "code";
43+
44+
// 성공 메시지
45+
public static final String SUCCESS_MESSAGE = "알림이 성공적으로 전송되었습니다";
46+
47+
// 폴백 메시지 (기본 오류 메시지)
48+
public static final String FALLBACK_MESSAGE = "알림이 전송되었습니다";
49+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.sopt.makers.global.exception.base;
2+
3+
public interface BaseErrorCode {
4+
int getStatus();
5+
String getCode();
6+
String getMessage();
7+
}

0 commit comments

Comments
 (0)