Skip to content

[Feat] 출석 시 Weeth 에서 카메라 호출하도록 수정#111

Merged
dalzzy merged 13 commits into
developfrom
feat/WTH-381-출석-시-Weeth-안에서-카메라-호출할-수-있도록-추가하기
May 12, 2026

Hidden character warning

The head ref may contain hidden characters: "feat/WTH-381-\ucd9c\uc11d-\uc2dc-Weeth-\uc548\uc5d0\uc11c-\uce74\uba54\ub77c-\ud638\ucd9c\ud560-\uc218-\uc788\ub3c4\ub85d-\ucd94\uac00\ud558\uae30"
Merged

[Feat] 출석 시 Weeth 에서 카메라 호출하도록 수정#111
dalzzy merged 13 commits into
developfrom
feat/WTH-381-출석-시-Weeth-안에서-카메라-호출할-수-있도록-추가하기

Conversation

@dalzzy
Copy link
Copy Markdown
Member

@dalzzy dalzzy commented May 11, 2026

✅ PR 유형

어떤 변경 사항이 있었나요?

  • 새로운 기능 추가
  • 버그 수정
  • 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

📌 관련 이슈번호


✅ Key Changes

  • react-webcam, jsqr 패키지 추가하여 웹에서 카메라 호출 및 QR 디코딩 기능 구현
  • CameraIcon export 추가 (src/assets/icons/index.ts)
  • AttendanceCodeModal에 "QR코드 스캔하기" 버튼 통합
    • 버튼 클릭 시 같은 모달 내에서 카메라 뷰로 전환 (별도 모달 미생성)
    • videoConstraints: { facingMode: { ideal: 'environment' } } — 모바일은 후면 카메라, PC는 기본 카메라로 자동 fallback
    • 250ms 간격으로 비디오 프레임에서 QR 디코드 → 6자리 숫자 검출 시 자동으로 OTP에 입력 후 카메라 종료
    • 카메라 권한 거부 등 에러 발생 시 사용자 메시지 노출

📸 스크린샷 or 실행

2026-05-11.5.23.04.mov

🎸 기타 사항 or 추가 코멘트

@nabbang6 AttendanceCodeModal.tsx에서 충돌 나서 해결하긴 했는데 혹시 코드 빠진거 없는지 한번만 확인 부탁드려요 !! ㅠㅠ

Summary by CodeRabbit

출석 인증

  • New Features

    • 웹캠을 이용한 QR 코드 자동 스캔으로 출석 인증 기능 추가
    • 기존 수동 코드 입력 방식과 함께 카메라 기반 QR 코드 인식 옵션 제공
    • 실시간 카메라 미리보기에서 자동으로 6자리 출석 코드 인식 및 처리
  • Chores

    • 의존성 관리자 버전 고정
    • CI/CD 워크플로우 및 빌드 설정 최적화

Review Change Stack

@dalzzy dalzzy self-assigned this May 11, 2026
@github-actions
Copy link
Copy Markdown

PR 검증 결과

⏭️ TypeScript: 건너뜀
⏭️ ESLint: 건너뜀
⏭️ Prettier: 건너뜀
⏭️ Build: 건너뜀

⚠️ 일부 검증에 실패했습니다. 확인 후 수정해주세요.

@github-actions
Copy link
Copy Markdown

PR 테스트 결과

⏭️ Jest: 건너뜀

⚠️ 테스트에 실패했습니다. 확인 후 수정해주세요.

@github-actions
Copy link
Copy Markdown

구현한 기능 Preview: https://weeth-mqd28r8pn-weethsite-4975s-projects.vercel.app

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cfa62508-a6f5-43a6-8c8d-a56c24b01217

📥 Commits

Reviewing files that changed from the base of the PR and between 10cab9b and 6a55745.

📒 Files selected for processing (2)
  • src/components/attendance/AttendanceCodeModal.tsx
  • src/hooks/attendance/useQRScanner.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/hooks/attendance/useQRScanner.ts
  • src/components/attendance/AttendanceCodeModal.tsx

📝 Walkthrough

개요

AttendanceCodeModal에 웹캠 기반 QR 코드 스캔 기능을 추가하고, 새로운 useQRScanner 훅으로 실시간 QR 디코딩을 구현합니다. 관련 런타임 의존성, 카메라 아이콘, SSE 최적화 및 CI/pnpm 설정을 함께 업데이트합니다.

변경 사항

QR 스캔 기능 추가

레이어 / 파일(s) 요약
런타임 의존성 추가
package.json
QR 디코딩(jsqr)과 웹캠 렌더링(react-webcam)을 위한 패키지를 dependencies에 추가합니다.
useQRScanner 훅 구현
src/hooks/attendance/useQRScanner.ts
클라이언트 측 QR 스캔 훅으로, 비디오 프레임을 250ms 간격으로 폴링하면서 jsQR을 사용하여 QR 코드를 디코딩하고 콜백으로 데이터를 전달합니다.
카메라 아이콘 내보내기
src/assets/icons/index.ts
카메라 SVG 자산을 CameraIcon으로 아이콘 인덱스에서 재내보냅니다.
AttendanceCodeModal: 웹캠 및 QR 스캔 통합
src/components/attendance/AttendanceCodeModal.tsx
웹캠 컴포넌트와 useQRScanner를 통합하여 실시간 QR 스캔을 활성화하고, 6자리 숫자 추출 시 자동 확정하며, 스캔/수동 입력 UI를 조건부로 렌더링합니다.
훅 모듈 재내보내기
src/hooks/attendance/index.ts
attendance 훅 인덱스에 useQRScanner를 추가하여 공개 API에 포함시킵니다.
useAttendanceSSE: 기본 스냅샷 최적화
src/hooks/attendance/useAttendanceSSE.ts
clubId가 없을 때 반환할 기본값을 EMPTY_SNAPSHOT 상수로 추출하여 코드 중복을 제거합니다.
CI/Amplify/워크스페이스 설정 변경
.github/workflows/ci.yml, .github/workflows/test.yml, amplify.yml, pnpm-workspace.yaml
pnpm 버전을 10.28.0으로 고정하고, pnpm-workspace 설정 키를 업데이트합니다.

예상 코드 리뷰 시간

🎯 3 (중간) | ⏱️ ~20분

관련 PR

제안하는 리뷰어

  • JIN921
  • woneeeee

🐰 웹캠으로 QR 코드를 스캔하고,
6자리 숫자가 뙇 튀어나오면,
출석 완료, 아주 간단해! ✨
짠! 스캔, 클릭, 끝! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 주요 변경사항(출석 시 Weeth에서 카메라 호출)을 명확하게 요약하며 변경 사항과 완전히 일치합니다.
Description check ✅ Passed PR 설명은 템플릿의 모든 주요 섹션(PR 유형, Key Changes, 스크린샷, 추가 코멘트)을 포함하며 충분히 작성되었습니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/WTH-381-출석-시-Weeth-안에서-카메라-호출할-수-있도록-추가하기

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/components/attendance/AttendanceCodeModal.tsx (1)

71-113: ⚡ Quick win

스캔 타임아웃 로직 추가를 고려하세요.

현재 QR 스캔은 성공하거나 사용자가 수동으로 취소할 때까지 무한정 실행됩니다. 카메라가 QR 코드를 인식하지 못하는 상황(조명 불량, 손떨림 등)에서 배터리와 리소스를 계속 소비하게 됩니다.

최대 스캔 시간(예: 30초~60초) 또는 최대 시도 횟수를 설정하여, 일정 시간 후 자동으로 중단하고 사용자에게 수동 입력을 안내하는 것을 권장합니다.

⏱️ 타임아웃 추가 예시
  useEffect(() => {
    if (!scanning) return;
+   const startTime = Date.now();
+   const SCAN_TIMEOUT_MS = 30000; // 30초

    const intervalId = window.setInterval(() => {
+     if (Date.now() - startTime > SCAN_TIMEOUT_MS) {
+       setCameraError('QR 코드를 찾을 수 없습니다. 수동으로 코드를 입력해 주세요.');
+       handleStopScan();
+       return;
+     }
+
      if (scannedRef.current) return;
      // ... 나머지 로직
    }, 250);

    return () => {
      window.clearInterval(intervalId);
    };
  }, [scanning]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/attendance/AttendanceCodeModal.tsx` around lines 71 - 113, The
scanning loop in the useEffect (triggered by scanning) can run indefinitely; add
a timeout or max-attempts mechanism that stops the interval and calls
handleStopScan after a configurable period (e.g., 30–60s) or after N attempts to
prevent battery/resource drain; implement by tracking elapsed time or an
attempts counter inside the interval (or by creating a separate setTimeout) and
when the limit is reached clearInterval(intervalId), set scannedRef.current
appropriately, and call handleStopScan (also ensure cleanup in the return
callback clears both interval and timeout and that you update any related state
via setCode only when within the allowed time/attempts).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/components/attendance/AttendanceCodeModal.tsx`:
- Around line 71-113: The scanning loop in the useEffect (triggered by scanning)
can run indefinitely; add a timeout or max-attempts mechanism that stops the
interval and calls handleStopScan after a configurable period (e.g., 30–60s) or
after N attempts to prevent battery/resource drain; implement by tracking
elapsed time or an attempts counter inside the interval (or by creating a
separate setTimeout) and when the limit is reached clearInterval(intervalId),
set scannedRef.current appropriately, and call handleStopScan (also ensure
cleanup in the return callback clears both interval and timeout and that you
update any related state via setCode only when within the allowed
time/attempts).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bcc628ca-52de-4255-8e37-b706e4da72f0

📥 Commits

Reviewing files that changed from the base of the PR and between ea38f85 and dba29dd.

⛔ Files ignored due to path filters (2)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • src/assets/icons/camera.svg is excluded by !**/*.svg
📒 Files selected for processing (3)
  • package.json
  • src/assets/icons/index.ts
  • src/components/attendance/AttendanceCodeModal.tsx

@dalzzy dalzzy requested review from JIN921, nabbang6 and woneeeee and removed request for nabbang6 and woneeeee May 11, 2026 08:27
@dalzzy dalzzy added the ✨ Feature 기능 개발 label May 11, 2026
Copy link
Copy Markdown
Collaborator

@JIN921 JIN921 left a comment

Choose a reason for hiding this comment

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

확인했습니다 충돌만 해결해 주시면 될 거 같아요~! 수고하셧어요!!

@github-actions
Copy link
Copy Markdown

PR 검증 결과

⏭️ TypeScript: 건너뜀
⏭️ ESLint: 건너뜀
⏭️ Prettier: 건너뜀
⏭️ Build: 건너뜀

⚠️ 일부 검증에 실패했습니다. 확인 후 수정해주세요.

@github-actions
Copy link
Copy Markdown

PR 테스트 결과

⏭️ Jest: 건너뜀

⚠️ 테스트에 실패했습니다. 확인 후 수정해주세요.

Copy link
Copy Markdown
Collaborator

@nabbang6 nabbang6 left a comment

Choose a reason for hiding this comment

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

확인햇습니다~!! 충돌 파일도 확인해봣는데 문제 없이 깔끔쓰한 게 고쳐주싱 것 같습니다,,, ㅠ ㅠ 짱!!!👍

…into feat/WTH-381-출석-시-Weeth-안에서-카메라-호출할-수-있도록-추가하기
@github-actions
Copy link
Copy Markdown

PR 검증 결과

⏭️ TypeScript: 건너뜀
⏭️ ESLint: 건너뜀
⏭️ Prettier: 건너뜀
⏭️ Build: 건너뜀

⚠️ 일부 검증에 실패했습니다. 확인 후 수정해주세요.

@github-actions
Copy link
Copy Markdown

PR 테스트 결과

⏭️ Jest: 건너뜀

⚠️ 테스트에 실패했습니다. 확인 후 수정해주세요.

@github-actions
Copy link
Copy Markdown

PR 검증 결과

⏭️ TypeScript: 건너뜀
⏭️ ESLint: 건너뜀
⏭️ Prettier: 건너뜀
⏭️ Build: 건너뜀

⚠️ 일부 검증에 실패했습니다. 확인 후 수정해주세요.

@github-actions
Copy link
Copy Markdown

PR 검증 결과

⏭️ TypeScript: 건너뜀
⏭️ ESLint: 건너뜀
⏭️ Prettier: 건너뜀
⏭️ Build: 건너뜀

⚠️ 일부 검증에 실패했습니다. 확인 후 수정해주세요.

@github-actions
Copy link
Copy Markdown

PR 테스트 결과

⏭️ Jest: 건너뜀

⚠️ 테스트에 실패했습니다. 확인 후 수정해주세요.

@github-actions
Copy link
Copy Markdown

PR 테스트 결과

Jest: 통과

🎉 모든 테스트를 통과했습니다!

@github-actions
Copy link
Copy Markdown

PR 검증 결과

TypeScript: 통과
ESLint: 통과
Prettier: 통과
Build: 통과

🎉 모든 검증을 통과했습니다!

@github-actions
Copy link
Copy Markdown

PR 테스트 결과

Jest: 통과

🎉 모든 테스트를 통과했습니다!

@github-actions
Copy link
Copy Markdown

PR 검증 결과

TypeScript: 통과
ESLint: 통과
Prettier: 통과
Build: 통과

🎉 모든 검증을 통과했습니다!

@github-actions
Copy link
Copy Markdown

PR 테스트 결과

Jest: 통과

🎉 모든 테스트를 통과했습니다!

@github-actions
Copy link
Copy Markdown

PR 검증 결과

TypeScript: 통과
ESLint: 통과
Prettier: 실패
Build: 실패

⚠️ 일부 검증에 실패했습니다. 확인 후 수정해주세요.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/components/attendance/AttendanceCodeModal.tsx (1)

141-141: ⚡ Quick win

spacing 클래스는 토큰 규칙에 맞춰 교체해 주세요.

Line 141의 gap-2.5는 현재 가이드의 spacing 토큰 범위와 맞지 않습니다. 토큰 클래스(gap-100~gap-400)로 변경하는 편이 일관성에 맞습니다.

예시
-              <div className="bg-container-neutral-alternative flex items-start gap-2.5 self-stretch rounded-md p-300">
+              <div className="bg-container-neutral-alternative flex items-start gap-100 self-stretch rounded-md p-300">

As per coding guidelines "Use spacing token classes: p-100~500, gap-100~400."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/attendance/AttendanceCodeModal.tsx` at line 141, In
AttendanceCodeModal replace the non-token spacing class "gap-2.5" on the div
with the spacing token variant (e.g., "gap-200" or another token within
gap-100..gap-400) so the className that currently contains
"bg-container-neutral-alternative flex items-start gap-2.5 self-stretch
rounded-md p-300" uses a permitted spacing token; update the class string to the
chosen token and ensure consistency with other spacing tokens like p-300 already
used.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/api/proxy/`[...path]/route.ts:
- Around line 6-8: maxDuration is defined with a runtime conditional
(process.env.VERCEL ? 300 : 700), which is not allowed for Route Segment Config;
replace it with a static numeric value or resolve the value at build time.
Update the export const maxDuration in route.ts to a fixed number (e.g., 300 or
700) or change your build process to inject a static constant so maxDuration is
a literal in the output manifest; ensure you only modify the definition named
maxDuration and do not rely on process.env in that declaration.

In `@src/components/attendance/AttendanceCodeModal.tsx`:
- Around line 73-76: The current on successful scan calls onOpenChange(false)
directly which bypasses the component's handleOpenChange and its setCode('')
reset; update the success path in the block containing stopCamera(),
onConfirm?.(digits), onOpenChange(false) to either call handleOpenChange(false)
instead of onOpenChange(false) or explicitly call setCode('') before closing so
the modal's code state is cleared for the next open; ensure you reference and
use the existing handleOpenChange, setCode, stopCamera, onConfirm, and digits
symbols when making the change.

---

Nitpick comments:
In `@src/components/attendance/AttendanceCodeModal.tsx`:
- Line 141: In AttendanceCodeModal replace the non-token spacing class "gap-2.5"
on the div with the spacing token variant (e.g., "gap-200" or another token
within gap-100..gap-400) so the className that currently contains
"bg-container-neutral-alternative flex items-start gap-2.5 self-stretch
rounded-md p-300" uses a permitted spacing token; update the class string to the
chosen token and ensure consistency with other spacing tokens like p-300 already
used.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8bc71bca-0cb1-4446-bccd-e8594617e9ab

📥 Commits

Reviewing files that changed from the base of the PR and between de8d1c1 and 10cab9b.

📒 Files selected for processing (8)
  • .github/workflows/ci.yml
  • .github/workflows/test.yml
  • amplify.yml
  • pnpm-workspace.yaml
  • src/app/api/proxy/[...path]/route.ts
  • src/components/attendance/AttendanceCodeModal.tsx
  • src/hooks/attendance/index.ts
  • src/hooks/attendance/useQRScanner.ts
✅ Files skipped from review due to trivial changes (2)
  • .github/workflows/ci.yml
  • amplify.yml

Comment thread src/app/api/proxy/[...path]/route.ts Outdated
Comment thread src/components/attendance/AttendanceCodeModal.tsx Outdated
@github-actions
Copy link
Copy Markdown

PR 테스트 결과

Jest: 통과

🎉 모든 테스트를 통과했습니다!

@github-actions
Copy link
Copy Markdown

PR 검증 결과

TypeScript: 통과
ESLint: 통과
Prettier: 통과
Build: 통과

🎉 모든 검증을 통과했습니다!

@github-actions
Copy link
Copy Markdown

PR 테스트 결과

Jest: 통과

🎉 모든 테스트를 통과했습니다!

@github-actions
Copy link
Copy Markdown

PR 검증 결과

TypeScript: 통과
ESLint: 통과
Prettier: 통과
Build: 통과

🎉 모든 검증을 통과했습니다!

@dalzzy dalzzy merged commit 895211c into develop May 12, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants