Join the Agent Deck Discord Server!
Discord에서 Agent Deck 커뮤니티 확인, 357명과 자유 음성·텍스트 채팅 이용
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
사랑의교회 청년부 한반도이웃사랑선교국 2026 짝기도 매칭 QR로 신청을 받아 짝을 지어주고, 빔프로젝터 화면에서 추첨하듯 조를 공개하는 현장용 웹앱. • 프레임워크 Next.js 15 (App Router · Server Actions) • DB Supabase (PostgreSQL + Realtime) • 스타일 Tailwind CSS v4 • 호스팅 Vercel /admin에서 매칭을 확정하면 /display가 Realtime으로 즉시 갱신됩니다. 새로고침이나 폴링이 필요 없습니다. 기도제목은 두 곳에서만 보입니다: 관리자 화면(전체 관리용)과 본인의 개인 링크 /me/[id](자기 조 안에서만). 모두가 보는 /display에는 절대 나가지 않습니다.README 전문 보기 ↗
QR로 신청을 받아 짝을 지어주고, 빔프로젝터 화면에서 추첨하듯 조를 공개하는 현장용 웹앱.
배포 링크: https://hansarangpray-2026.vercel.app
| 경로 | 링크 | 용도 |
|---|---|---|
/ | 바로가기 | 참가자 입력 폼. QR로 진입하는 모바일 화면 |
/admin | 바로가기 | 관리자 대시보드. 접수 현황 · 매칭 실행 · CSV · 데이터 삭제 |
/display | 바로가기 | 빔프로젝터 송출 화면. 모두에게 보이는 화면 — 이름만 나옵니다 |
/me/[참가자id] | — | 참가자 개인 링크. 본인과 기도짝에게만 보이는 화면 — 조원들의 기도제목이 나옵니다 |
/admin에서 매칭을 확정하면 /display가 Realtime으로 즉시 갱신됩니다. 새로고침이나 폴링이 필요 없습니다.
기도제목은 두 곳에서만 보입니다: 관리자 화면(전체 관리용)과 본인의 개인 링크 /me/[id](자기 조 안에서만). 모두가 보는 /display에는 절대 나가지 않습니다.
신청 직후 뜨는 "내 기도짝 확인하기" 링크가 그 사람의 /me/[id]입니다. 이 링크는 브라우저에 12시간 동안 기억되므로, 새로고침하거나 나중에 다시 접속해도 빈 폼 대신 "이미 신청하셨어요 → 내 기도짝 확인하기" 화면이 뜹니다(같은 사람이 모르고 두 번 신청하는 것도 이걸로 막습니다). 폰을 빌려준 경우를 위해 "다른 분이 신청하시나요? 새로 신청하기" 버튼을 함께 뒀습니다. 매칭 전에는 "아직 매칭 전입니다"만 보이다가, 관리자가 매칭을 확정하면 Realtime으로 자동으로 자기 조 멤버들의 이름·팀·기도제목으로 바뀝니다. 다른 조 내용은 서버에서부터 아예 그 사람에게 전달되지 않습니다.
주의 — 진짜 인증은 아닙니다.
/me/[id]의id는 추측하기 어려운 UUID일 뿐, 비밀번호나 로그인이 걸린 건 아닙니다. 링크를 다른 사람에게 전달하면 그 사람도 볼 수 있습니다. 로그인 없이 낮은 리스크로 개인화하는 절충안이며, 더 강한 보호(문자 인증 등)가 필요하면 별도로 알려주세요.
참가자 입력 화면에는 신청 전·완료 후·재방문 모두 "휴대폰 기도제목 입력 완료 후 창을 닫지 말아주세요!" 안내가 표시됩니다. /display에서도 대기·추첨·결과 단계 내내 같은 안내와 "내 기도짝 확인하기" 사용 방법을 보여 줍니다.
/display는 상태가 셋입니다.
Space)을 누르면 3초간 통이 흔들리며 이름표가 마구 섞이고, 그다음 조별 카드가 하나씩 튀어나옵니다.진행자가 버튼을 누르는 시점을 잡을 수 있어서, 관리자가 미리 매칭을 확정해 두고 순서에 맞춰 공개할 수 있습니다. 추첨 버튼 또는 Space를 누를 때마다 서버에서 최신 신청 명단을 확인합니다. 추가 신청자가 있으면 기존 조원과 조 번호를 유지하면서 추가 참가자만 배정·저장한 뒤 연출을 시작합니다. 추가 신청자가 없으면 기존 결과의 연출만 재생합니다. 새로고침해도 결과는 그대로 남습니다(연출만 건너뜁니다).
추가 신청 인원은 송출 화면에 표시됩니다. 추가 배정은 송출 화면과 같은 브라우저에서 관리자 로그인 후 실행할 수 있으며, 로그인하지 않았다면 안내와 관리자 로그인 링크를 보여 줍니다. 먼저 기존 조의 정원 안쪽 빈자리를 채우고, 적은 수의 잔여 인원은 깍두기로 합류시킵니다. 인원이 많으면 추가 참가자끼리 새 조를 만듭니다. 한 명만 남으면 가장 작은 기존 조에 합류합니다. 배정 도중 도착한 신청자는 추가 신청 인원으로 표시되며 다음 추첨 때 배정됩니다.
추가 배정은 데이터베이스 트랜잭션 하나로 저장합니다. 동시 추첨이나 명단 변경 시 최신 명단으로 재시도하고, 저장 실패 시 연출을 시작하지 않습니다. npm test로 기존 조 유지·중복 방지·관리자 권한·동시 변경 처리 회귀 검증을 실행할 수 있습니다.
신청 QR은 모든 단계에서 계속 떠 있습니다(결과 발표 중에는 왼쪽 아래에 작게). 늦게 온 사람도 언제든 스캔할 수 있게 하기 위함입니다. QR은 이미지 파일이 아니라 요청 주소에서 서버가 직접 생성하므로, 도메인을 바꿔도 따라오고 외부 QR 서비스가 죽어도 영향이 없습니다. 주소를 고정하고 싶으면 NEXT_PUBLIC_SITE_URL 환경변수를 지정하세요.
카드에는 이름만 나옵니다. 화면에 보이는 것뿐 아니라 페이지 소스(RSC 페이로드)에도 이름 외에는 실리지 않도록 서버 쪽에서 값을 잘라서 넘기고, React key도 실제 DB id 대신 화면 전용 가짜 값을 씁니다 — 실제 id가 그대로 노출되면 페이지 소스에서 모든 참가자의 /me/[id] 링크를 추출할 수 있게 되기 때문입니다.
| 항목 | 형태 |
|---|---|
| 이름 | 텍스트 (20자 이내) |
| 팀 | 드롭다운 — 영등포쪽방촌팀 · 단비팀 · 통일선교팀 · 전도팀 · 운영팀 · 국장 · 교역자 |
| 기도제목 | 텍스트 영역 (500자 이내) |
| 직접 나누기 | 체크박스 — 선택하면 기도제목 입력 없이 신청 가능 |
"기도제목을 입력하지 않고 매칭된 조 안에서 직접 나눌래요"를 선택하면 기도제목 입력란이 비활성화됩니다. 입력한 기도제목 대신 "기도제목은 매칭된 조 안에서 직접 나눌게요."가 저장되어 개인 링크·관리자 화면·CSV에서도 선택한 의사를 확인할 수 있습니다.
팀 목록은 NEXT_PUBLIC_TEAMS 환경변수로 바꿀 수 있습니다.
src/lib/matching.ts. 조 인원(2~10인) × 방식(2가지) = 버튼 18개.
team, 기본) — 같은 팀을 최대한 피해 배치random) — 아무 조건 없이 섞음한 명씩 "지금 가장 덜 겹치는 조"에 넣는 그리디 배치입니다.
한 팀이 전체 인원의 절반을 넘으면 같은 팀끼리 겹치는 조가 수학적으로 반드시 생깁니다(비둘기집 원리). 그런 경우에도 겹치는 횟수를 이론적 최소치에 맞춥니다 — 예: 9명 중 3명이 한 팀이고 2개 조로 나누면 최소 1쌍은 반드시 겹치는데, 알고리즘이 정확히 그 최소치를 냅니다.
computeGroupSizes()가 조별 인원을 먼저 계산합니다. 정원을 채운 조를 만들고, 남는 사람은 깍두기로 기존 조에 한 명씩 끼워 넣습니다. 남는 인원이 조 수보다 많으면 남은 사람들로 별도 조를 만들고, 전체 인원이 정원보다 적으면 한 조로 묶습니다.
| 인원 | 2인 기준 | 3인 기준 | 4인 기준 | 5인 기준 | 6인 기준 |
|---|---|---|---|---|---|
| 7명 | 3, 2, 2 | 4, 3 | 4, 3 | 5, 2 | 7 |
| 9명 | 3, 2, 2, 2 | 3, 3, 3 | 5, 4 | 5, 4 | 6, 3 |
| 11명 | 3, 2, 2, 2, 2 | 4, 4, 3 | 4, 4, 3 | 6, 5 | 6, 5 |
| 13명 | 3, 2, 2, 2, 2, 2 | 4, 3, 3, 3 | 5, 4, 4 | 5, 5, 3 | 7, 6 |
예를 들어 6인 기준 10명은 6, 4, 10인 기준 21명은 11, 10으로 나눕니다. 0200명 × 210인 × 두 매칭 방식 전 구간에서 인원 합계와 참가자 누락·중복 여부를 검사합니다.
셔플은 Fisher-Yates입니다. sort(() => Math.random() - 0.5)는 분포가 치우쳐서 쓰지 않았습니다.
새 프로젝트를 만들고 SQL Editor에 supabase/schema.sql을 붙여넣어 실행합니다. 테이블 4개(participants, match_rounds, match_groups, match_members), RLS 정책, Realtime 발행이 한 번에 설정됩니다.
기존 프로젝트에는 추가 참가자 배정 마이그레이션을 적용합니다. 추가 배정 함수는 서버의 service_role만 실행할 수 있습니다.
RLS는 익명 사용자에게 조회(select)만 허용합니다. 신청·본인 수정·매칭 실행·삭제는 검증된 서버 액션이 service_role 키로 수행하며, 그 전에 관리자 비밀번호를 검증합니다.
.env.example을 .env.local로 복사해 채웁니다.
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY= # 서버 전용. NEXT_PUBLIC_ 붙이지 말 것
ADMIN_PASSWORD=
NEXT_PUBLIC_TEAMS=영등포쪽방촌팀,단비팀,통일선교팀,전도팀,운영팀,국장,교역자
npm install
npm run dev
앞으로 요청하는 수정 작업은 검증 후 운영 사이트 배포와 반영 확인까지 완료합니다.
GitHub에 푸시하고 Vercel에서 Import → 위 환경변수 5개를 등록하면 끝입니다. 도메인과 SSL은 자동입니다.
배포된 URL(https://<프로젝트>.vercel.app)을 QR 생성기에 넣어 주보나 화면에 노출하세요.
/display를 빔프로젝터에 띄우고 F11로 전체화면. 접수 중에는 안내 문구가 표시됩니다./에 들어와 이름·팀·기도제목을 제출합니다. 이름이 송출 화면 통 안에 바로 나타납니다. 제출 후 "내 기도짝 확인하기" 개인 링크가 뜨고, 폼은 감춰져 중복 제출이 걸러집니다./admin에서 접수 현황(팀별 인원)을 보며 마감 시점을 판단하고, 매칭 버튼을 누릅니다. 기존 결과가 있으면 추가 참여자 반영으로 미배정자만 기존 조에 넣습니다. 전체 변경은 인원·방식을 고르고 확인란을 선택한 뒤 초기화 후 조 편성을 누릅니다. 참가자 명단과 기도제목은 유지됩니다./display에 추첨 시작 버튼이 뜹니다. 휴대폰 /admin에서 모든 화면에서 추첨·결과 공개를 누르거나, 로그인한 /display에서 누르면(또는 Space) 이름표가 섞이는 연출 후 조별 카드(이름만)가 공개됩니다.src/
app/
page.tsx 참가자 입력 화면
actions.ts 신청 접수 서버 액션
me/[id]/page.tsx 개인 링크 — 본인 조의 기도제목만
admin/
page.tsx 대시보드 (서버 컴포넌트)
LoginForm.tsx 비밀번호 로그인
actions.ts 매칭 실행 · 삭제 · 초기화
display/
page.tsx 송출 화면 (이름만 잘라서 클라이언트에 전달)
DisplayStage.tsx 이름표 통 · 추첨 연출 · 조별 그리드
api/admin/export/ CSV 내려받기 (UTF-8 BOM)
components/
ParticipantForm.tsx
RealtimeRefresher.tsx Realtime 변경 감지 → router.refresh()
lib/
matching.ts 매칭 알고리즘
queries.ts 조회 (getMyGroup 등)
auth.ts 관리자 세션 (HMAC 쿠키)
types.ts
supabase/ 브라우저 / 서버 / 관리자 클라이언트
supabase/schema.sql
supabase/migrations의 새 마이그레이션을 순서대로 적용한 후 앱을 배포합니다. npm test, npm run build로 검증합니다. tests/event-transaction.sql은 마지막에 롤백하는 DB 회귀 검사입니다.node tests/fixture-server.cjs는 운영 DB와 분리된 로컬 검증 서버(3030/3031)를 엽니다. 로그인 암호는 검증 전용 fixture-only-password이며 실제 서비스에는 쓰이지 않습니다. 로컬 신청 → 추가 참여자 반영 → 기존 조 유지 → 초기화 후 조 편성 → 정보 수정 흐름을 확인할 수 있습니다.
신규 신청에는 브라우저 요청 ID를 사용해 응답 유실·중복 탭 제출 시 같은 참가자가 두 번 저장되지 않도록 합니다. 요청 ID는 공개 참가자 데이터와 분리된 접근 제한 테이블에 저장합니다.