Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .github/memberMap.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"seong-jin-jo": {
"name": "조성진",
"slackId": "U07V0TY7CF9"
},
"dongjooyun": {
"name": "윤동주",
"slackId": "U09KJ5DTD2B"
},
"Hyeonjun0527": {
"name": "최현준",
"slackId": "U08298MKCBE"
},
"HA-SEUNG-JEONG": {
"name": "정하승",
"slackId": "U0A6HD2AB0E"
},
"solvedacuser": {
"name": "노정환",
"slackId": "U0A6NRTGK2Q"
}
}
12 changes: 7 additions & 5 deletions .github/workflows/notify-pr-author-on-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ jobs:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Extract Slack IDs and DM Text
id: extract_info
env:
MEMBER_INFO: ${{ secrets.MEMBER_INFO_MAP }}
run: |
PR_AUTHOR="${{ github.event.pull_request.user.login }}"
REVIEWER="${{ github.event.review.user.login }}"
Expand All @@ -26,10 +27,11 @@ jobs:
exit 0
fi

echo "$MEMBER_INFO" | base64 --decode > memberMap.json
AUTHOR_SLACK_ID=$(jq -r --arg id "$PR_AUTHOR" '.[$id].slackId' memberMap.json)
REVIEWER_SLACK_ID=$(jq -r --arg id "$REVIEWER" '.[$id].slackId' memberMap.json)
# 코드베이스의 memberMap.json에서 Slack ID 조회
AUTHOR_SLACK_ID=$(jq -r --arg id "$PR_AUTHOR" '.[$id].slackId // empty' .github/memberMap.json)
REVIEWER_SLACK_ID=$(jq -r --arg id "$REVIEWER" '.[$id].slackId // empty' .github/memberMap.json)

# slackId가 없으면 DM 전송 불가 (skip)
if [ -z "$AUTHOR_SLACK_ID" ] || [ -z "$REVIEWER_SLACK_ID" ] || \
[ "$AUTHOR_SLACK_ID" = "null" ] || [ "$REVIEWER_SLACK_ID" = "null" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
Expand Down
22 changes: 16 additions & 6 deletions .github/workflows/notify-slack-on-pr-opened.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,29 @@ jobs:
runs-on: ubuntu-latest

steps:
- name: Decode memberMap.json from secret
run: |
echo "${{ secrets.MEMBER_INFO_MAP }}" | base64 --decode > memberMap.json
- name: Checkout
uses: actions/checkout@v4

- name: Get PR author and reviewers
id: get_member_info
run: |
# PR 작성자 이름 추출
PR_AUTHOR_GITHUB_ID="${{ github.event.pull_request.user.login }}"
PR_AUTHOR_NAME=$(jq -r --arg id "$PR_AUTHOR_GITHUB_ID" '.[$id].name' memberMap.json)
PR_AUTHOR_NAME=$(jq -r --arg id "$PR_AUTHOR_GITHUB_ID" '.[$id].name // "알 수 없음"' .github/memberMap.json)
echo "pr_author_name=$PR_AUTHOR_NAME" >> $GITHUB_OUTPUT

# PR 작성자 제외한 멤버들의 slackId를 멘션으로 모으기
MENTIONS=$(jq -r --arg author "$PR_AUTHOR_GITHUB_ID" 'to_entries | map(select(.key != $author)) | map("<@" + .value.slackId + ">") | join(" ")' memberMap.json)
# PR 작성자 제외한 멤버들의 slackId를 멘션으로 모으기 (slackId가 있는 경우만)
MENTIONS=$(jq -r --arg author "$PR_AUTHOR_GITHUB_ID" '
to_entries
| map(select(.key != $author and .value.slackId != null and .value.slackId != ""))
| map("<@" + .value.slackId + ">")
| join(" ")
' .github/memberMap.json)

# 멘션이 없으면 빈 문자열로 설정
if [ -z "$MENTIONS" ] || [ "$MENTIONS" = "null" ]; then
MENTIONS=""
fi
echo "reviewers_mention=$MENTIONS" >> $GITHUB_OUTPUT

- name: Send Slack message
Expand Down
15 changes: 14 additions & 1 deletion src/components/payment/paymentActionClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,21 @@ export default function PaymentCheckoutPage({ study }: Props) {

// 회원 결제
// @docs https://docs.tosspayments.com/sdk/v2/js#tosspaymentspayment
// customerKey 형식: 영문 대소문자, 숫자, 특수문자 -, _, =, ., @로 2자 이상 50자 이하
// memberId를 안전한 형식으로 변환 (예: 기존 123 -> 변경 후 member-123)
const customerKey = `member-${study.memberId}`.replace(
/[^a-zA-Z0-9\-_=.@]/g,
'',
);

// Toss 에서 2자이상 50자이하 문자열을 요구함
if (customerKey.length < 2 || customerKey.length > 50) {
throw new Error(
`customerKey가 유효하지 않습니다: ${customerKey} (길이: ${customerKey.length})`,
);
}
Comment on lines +127 to +131
Copy link

@coderabbitai coderabbitai bot Feb 23, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

customerKey 유효성 검사 실패 시 사용자에게 오해를 줄 수 있는 에러 처리

유효성 검사에서 throw new Error를 하더라도 해당 에러는 137번 줄의 catch 블록에서 console.error만 호출하고 payment 상태는 null로 유지됩니다. 이후 사용자가 결제하기 버튼을 클릭하면 onPay 내부(40번 줄)에서 "결제 모듈을 불러오는 중입니다. 잠시 후 다시 시도해주세요."라는 오해의 소지가 있는 메시지가 표시됩니다. 실제 원인(customerKey 형식 오류)과 전혀 다른 메시지를 보게 됩니다.

또한, 에러 메시지에 customerKey 값(= memberId 기반)이 그대로 포함되어 console.error로 출력될 수 있습니다.

🛡️ 수정 제안: 유효성 검사 실패 시 사용자에게 명확한 피드백 제공
         // Toss 에서 2자이상 50자이하 문자열을 요구함
         if (customerKey.length < 2 || customerKey.length > 50) {
+          console.error(`customerKey가 유효하지 않습니다 (길이: ${customerKey.length})`);
+          alert('결제 정보를 불러오는 데 문제가 발생했습니다. 고객센터에 문의해주세요.');
+          return;
-          throw new Error(
-            `customerKey가 유효하지 않습니다: ${customerKey} (길이: ${customerKey.length})`,
-          );
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (customerKey.length < 2 || customerKey.length > 50) {
throw new Error(
`customerKey가 유효하지 않습니다: ${customerKey} (길이: ${customerKey.length})`,
);
}
if (customerKey.length < 2 || customerKey.length > 50) {
console.error(`customerKey가 유효하지 않습니다 (길이: ${customerKey.length})`);
alert('결제 정보를 불러오는 데 문제가 발생했습니다. 고객센터에 문의해주세요.');
return;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/payment/paymentActionClient.tsx` around lines 127 - 131, The
customerKey validation currently throws an Error inside the block guarded by
customerKey length check (the customerKey validation in paymentActionClient.tsx)
which only gets console.error'd in the surrounding catch (the catch near the
existing payment assignment) leaving payment as null and causing onPay (the
onPay handler) to show a misleading "loading module" message; change the flow so
that validation failures do not throw a generic Error but instead set a clear,
user-facing error state (e.g., setPaymentError or setPayment with an object
describing validation error) and log a redacted message (no raw customerKey) in
the console; update the catch to rethrow or propagate unexpected errors but
handle validation-specific results so onPay can display a specific "invalid
customer ID" UI instead of the generic loading message.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@claude 너도 대안을 제시해봐

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

const payment = tossPayments.payment({
customerKey: String(study.memberId),
customerKey,
});

setPayment(payment);
Expand Down
Loading