수량·금액 경계 — 0 · 음수 · 소수 · 상한 · 합계 오버플로
API 에서 classes.price 조회해 금액 대조 + 0/음수 거부 + DB CHECK 제약 추가
79개 항목을 읽었습니다. 막는 것부터 근거(파일·줄)와 푸는 순서를 적었어요.
API 에서 classes.price 조회해 금액 대조 + 0/음수 거부 + DB CHECK 제약 추가
NEXT_PUBLIC_TOSS_SECRET_KEY → TOSS_SECRET_KEY 로 변경 (서버 전용)
orders 테이블 RLS 활성화 · 웹훅 서명 검증 추가 · API 인증 미들웨어 추가
잘 되어 있는 곳 토스페이먼츠 결제창 연동과 승인 호출 자체는 붙어 있고, .env.example 이 코드가 읽는 키를 빠짐없이 적고 있어요. 의존성도 군더더기 없이 쓰는 것만 있어요.
비어 있는 곳 결제 금액을 브라우저가 보낸 값 그대로 믿고, 토스 시크릿 키가 NEXT_PUBLIC_ 이름이라 화면 코드에 실려 나가요. /admin 은 로그인 없이 열리고 수강생 전화번호가 그대로 보이며, orders 테이블에 RLS 가 없어요. 약관·처리방침 링크는 # 이고, 탈퇴 기능이 없어요.
가장 먼저 금액을 서버에서 다시 계산하기 (4.2), 시크릿 키를 서버 전용으로 옮기기 (1.2), 관리자 화면과 주문 테이블 막기 (2.1). 셋 다 코드 몇 줄이라 반나절이면 끝나요.
출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [1.1] 저장소와 전 히스토리에 시크릿이 없다 지금 상태: 커밋 파일 ○ — .env.example 만 있음 (git ls-files) · 히스토리 ? — 이번 진단은 현재 파일만 봤어요 · 방지 장치 ✕ — gitleaks/secret-scan 설정 없음 (glob → 0건) · CI 단계 ✕ — .github/workflows 없음 관련 위치: .github/workflows, gitleaks/secret-scan 할 일: gitleaks 설정 추가 · CI 스캔 단계 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [1.2] 브라우저가 받는 응답에 서버 시크릿이 없다 지금 상태: 공개 접두 변수 ✕ — NEXT_PUBLIC_TOSS_SECRET_KEY (app/api/checkout/confirm/route.ts:10 — 서버 전용 비밀이 NEXT_PUBLIC_ 접두로 노출) · 클라이언트 참조 ✕ — app/classes/page.tsx:16 NEXT_PUBLIC_TOSS_CLIENT_KEY (클라이언트 키는 정상, 하지만 SECRET_KEY 가 NEXT_PUBLIC_ 로 노출됨) · 오류 본문 ○ — 오류 처리 없음 (catch 문 0건) · 도메인 제한 기록 ✕ — 없음 · 빌드 산출물 ③ 관련 위치: app/api/checkout/confirm/route.ts:10, app/classes/page.tsx:16 할 일: NEXT_PUBLIC_TOSS_SECRET_KEY → TOSS_SECRET_KEY 로 변경 (서버 전용) 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[1.3] 로그 채널별로 개인정보·토큰이 찍히지 않는다
지금 상태: 앱 로그 ✕ — console.log('confirm', { paymentKey, orderId, amount }) (app/api/checkout/confirm/route.ts:5 — paymentKey 토큰 노출) · DB 오류 로그 ○ — ORM 로깅 설정 없음 (Supabase 클라이언트는 기본 로깅 안 함) · 접근 로그 ○ — 프록시 없음 (middleware.ts 없음 · 00-map.md:26) · 재설정 토큰 — — 기능 없음
관련 위치: app/api/checkout/confirm/route.ts:5
할 일: console.log 에서 paymentKey 제거 또는 마스킹
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.! 연산자만 — 런타임 오류는 내지만 부팅 전 검증 없음) · 검사 spec ✕ — 테스트 없음 (*.test.* → 0건) · 집합 차 ✕ — 코드 읽음 {NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, NEXT_PUBLIC_TOSS_CLIENT_KEY, NEXT_PUBLIC_TOSS_SECRET_KEY, ADMIN_EMAIL} − 배포 주입 {} = 전부 누락 (배포 설정 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[1.4] 프로덕션 시크릿 주입 경로가 실제로 있고, 개발 기본값·누락이면 부팅이 거부된다
지금 상태: 배포 설정 ✕ — 없음 (Dockerfile · docker-compose · vercel.json · fly.toml → 0건) · 부팅 검사 ✕ — 없음 (lib/supabase.ts:4-5 ! 연산자만 — 런타임 오류는 내지만 부팅 전 검증 없음) · 검사 spec ✕ — 테스트 없음 (.test. → 0건) · 집합 차 ✕ — 코드 읽음 {NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, NEXT_PUBLIC_TOSS_CLIENT_KEY, NEXT_PUBLIC_TOSS_SECRET_KEY, ADMIN_EMAIL} − 배포 주입 {} = 전부 누락 (배포 설정 없음)
관련 위치: lib/supabase.ts:4-5
할 일: 부팅 시 필수 env 검증 추가 · 배포 설정에 env 주입 명시
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [2.1] 모든 API 라우트가 권한을 명시하고 미명시는 기본 거부다 지금 상태: 라우트 ✕ — app/api/checkout/confirm/route.ts (POST) · app/api/webhooks/toss/route.ts (POST) 총 2개 · 전역 가드 ✕ — middleware.ts 없음 · RLS 전수 ✕ — orders 테이블 RLS 없음 (001_init.sql:9-19 — classes 만 RLS, orders 는 누구나 조회·수정 가능) · 신원 위조 ✕ — app/api/webhooks/toss/route.ts:4-6 body.data.orderId 를 그대로 신뢰 (서명 검증 없음) · 미명시 처리 ✕ — 인증 검사 없음 (auth/guard/Depends → 0건) · 테스트 ✕ — 없음 관련 위치: app/api/checkout/confirm/route.ts, app/api/webhooks/toss/route.ts, app/api/webhooks/toss/route.ts:4-6, auth/guard/Depends 할 일: orders 테이블 RLS 활성화 · 웹훅 서명 검증 추가 · API 인증 미들웨어 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
.select('*') (조건 없음 — 전체 조회) · app/api/checkout/confirm/route.ts:17 .eq('id', orderId) (user_id 검증 없음 — 남의 주문도 PAID 처리 가능) · app/api/webhooks/toss/route.ts:6 .eq('id', body.data.orderId) (소유자 검증 없음) · 신원 서버 결정 ✕ — 클라이언트가 보낸 orderId (app/pay/success/page.tsx:11 쿼리 파라미터) 를 그대로 사용 · 404/403 구분 ✕ — 없음 · IDOR 테스트 ✕ — 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[2.2] 소유자·테넌트 격리 — 남의 id 로 조회·수정·취소하면 404/403 (IDOR)
지금 상태: WHERE user_id ✕ — app/admin/page.tsx:8 .select('') (조건 없음 — 전체 조회) · app/api/checkout/confirm/route.ts:17 .eq('id', orderId) (user_id 검증 없음 — 남의 주문도 PAID 처리 가능) · app/api/webhooks/toss/route.ts:6 .eq('id', body.data.orderId) (소유자 검증 없음) · 신원 서버 결정 ✕ — 클라이언트가 보낸 orderId (app/pay/success/page.tsx:11 쿼리 파라미터) 를 그대로 사용 · 404/403 구분 ✕ — 없음 · IDOR 테스트 ✕ — 없음
관련 위치: 404/403, app/admin/page.tsx:8, app/api/checkout/confirm/route.ts:17, app/api/webhooks/toss/route.ts:6, app/pay/success/page.tsx:11
할 일: orders 테이블에 WHERE user_id 조건 추가 · 세션에서 user_id 추출
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [2.3] 서버 액션·라우트 핸들러·엣지 함수가 API 가드를 우회해 DB 를 직접 만지지 않는다 지금 상태: 웹 앱 DB 드라이버 ✕ — lib/supabase.ts:3-6 (클라이언트 앱에서 Supabase 직접 생성 · app/classes/page.tsx:8 · app/admin/page.tsx:8 브라우저에서 직접 DB 조회) · API 호출 단일화 ✕ — 클라이언트 컴포넌트가 supabase.from() 직접 호출 (app/classes/page.tsx:8·13 · app/admin/page.tsx:8) · 우회 경로 ✕ — 있음 (서버 액션은 없지만 클라이언트가 DB 직접 조회) · 서버 액션 인증 — — 서버 액션 없음 관련 위치: app/admin/page.tsx:8, app/classes/page.tsx:8, lib/supabase.ts:3-6 할 일: 클라이언트의 직접 DB 접근 제거 · API 라우트로 전환 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
getSession|getUser|auth().user 호출 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [3.4] 운영에서 실제로 동작하는 가입·로그인 경로가 하나 이상 있다 지금 상태: ✕ 경로는 있으나(app/login/page.tsx:8 카카오 OAuth) 공급자 연결 확인 불가 — Supabase 콘솔 설정에서만 확인됨 (코드에 공급자 연결 상태 없음 · .env.example의 SUPABASE_URL/ANON_KEY 예시값) · ✕ 로그인 후 세션 확인 코드 없음 (앱 전체에 getSession¦getUser¦auth().user 호출 0건) 관련 위치: SUPABASE_URL/ANON_KEY, app/login/page.tsx:8 할 일: Supabase 콘솔에서 카카오 OAuth 공급자 연결 확인 + 세션 확인 코드 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
lock|locked|attempts|failed.*login → 0건) · ✕ 잠금 해제 경로 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [3.5] 모든 역할(고객 · 판매자 · 직원 · 관리자)에 비밀번호 복구와 계정 잠금 경로가 닫혀 있다 지금 상태: — 비밀번호 복구 (OAuth 전용, 해당 없음) · ✕ 계정 잠금 전무 (검색: lock¦locked¦attempts¦failed.login → 0건) · ✕ 잠금 해제 경로 없음 할 일: 로그인 시도 횟수 제한 + 잠금 구현 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
zod|yup|joi|class-validator|pydantic → 0건) · ✕ API 입력 무검증 (app/api/checkout/confirm/route.ts:4 req.json() 결과를 바로 구조분해, 스키마 없음) · ✕ 웹훅 입력 무검증 (app/api/webhooks/toss/route.ts:4 req.json() 바로 사용) · ✕ 클라이언트 입력 무검증 (app/classes/page.tsx:11-12 prompt() 결과를 ! 로만 처리)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [4.1] 모든 쓰기 입력(body · param · query · header)이 스키마/파서를 거치고, 모르는 필드는 거부 지금 상태: ✕ 입력 검증 라이브러리 없음 (검색: zod¦yup¦joi¦class-validator¦pydantic → 0건) · ✕ API 입력 무검증 (app/api/checkout/confirm/route.ts:4 req.json() 결과를 바로 구조분해, 스키마 없음) · ✕ 웹훅 입력 무검증 (app/api/webhooks/toss/route.ts:4 req.json() 바로 사용) · ✕ 클라이언트 입력 무검증 (app/classes/page.tsx:11-12 prompt() 결과를 ! 로만 처리) 관련 위치: app/api/checkout/confirm/route.ts:4, app/api/webhooks/toss/route.ts:4, app/classes/page.tsx:11-12 할 일: zod 등 스키마 라이브러리 추가 + 모든 API 경로에 검증 적용 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
amount 를 req.json()에서 받아 토스로 그대로 전달 · 0/음수/상한 검사 없음) · ✕ 서버 금액 재계산 없음 (app/pay/success/page.tsx:11 클라이언트가 보낸 amount 를 그대로 confirm API 로 전달 · classes 테이블 price 와 대조 안 함) · ✕ DB 제약 없음 (supabase/migrations/001_init.sql:4·15 price·amount 필드가 int not null 만, CHECK 제약 없음 — 음수 허용) · ○ 소수 가드 (001_init.sql:4·15 int 타입)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [4.2] 수량·금액 경계 — 0 · 음수 · 소수 · 상한 · 합계 오버플로 지금 상태: ✕ 금액 검증 없음 (app/api/checkout/confirm/route.ts:4 amount 를 req.json()에서 받아 토스로 그대로 전달 · 0/음수/상한 검사 없음) · ✕ 서버 금액 재계산 없음 (app/pay/success/page.tsx:11 클라이언트가 보낸 amount 를 그대로 confirm API 로 전달 · classes 테이블 price 와 대조 안 함) · ✕ DB 제약 없음 (supabase/migrations/001_init.sql:4·15 price·amount 필드가 int not null 만, CHECK 제약 없음 — 음수 허용) · ○ 소수 가드 (001_init.sql:4·15 int 타입) 관련 위치: app/api/checkout/confirm/route.ts:4, app/pay/success/page.tsx:11, supabase/migrations/001_init.sql:4 할 일: API 에서 classes.price 조회해 금액 대조 + 0/음수 거부 + DB CHECK 제약 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
https://api.tosspayments.com/v1/payments/confirm — 토스페이먼츠로 선정됨<br>• .env.example:3-4 test_ck_ · test_sk_ — 테스트 키만 예시로 제공<br>• 계약·심사 상태 기록 문서 없음 (검색: `docsprocess.env.NEXT_PUBLIC_TOSS_SECRET_KEY — 키 검증 없음, test_ 접두사 확인 없음<br>• app/classes/page.tsx:16 process.env.NEXT_PUBLIC_TOSS_CLIENT_KEY — 클라이언트 키도 검증 없음<br>• 부팅 시 키 검증 코드 없음 (검색: startsWith.*test_|NODE_ENV.*production → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [5.2] 테스트/목 결제는 운영에서 막혀 있다 지금 상태: ✕ 운영 키 검증 · ✕ 테스트 모드 거부 • app/api/checkout/confirm/route.ts:10 process.env.NEXT_PUBLIC_TOSS_SECRET_KEY — 키 검증 없음, test_ 접두사 확인 없음 • app/classes/page.tsx:16 process.env.NEXT_PUBLIC_TOSS_CLIENT_KEY — 클라이언트 키도 검증 없음 • 부팅 시 키 검증 코드 없음 (검색: startsWith.test_¦NODE_ENV.production → 0건) 관련 위치: app/api/checkout/confirm/route.ts:10, app/classes/page.tsx:16 할 일: 부팅 시 운영 환경이면 test_ 키 거부·테스트 모드 표시 제거 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
amount 파라미터를 PG 에 그대로 전달 — 서버 재계산 없음<br>• app/api/checkout/confirm/route.ts:17 .update({ status: 'PAID' }).eq('id', orderId) — WHERE status 조건 없음, 중복 호출 시 덮어씀<br>• supabase/migrations/001_init.sql — CHECK 제약 없음 (검색: CHECK|CONSTRAINT → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[5.3] 승인 멱등성 · 금액 검증 · 상태 머신
지금 상태: ✕ 멱등 · ✕ 금액 검증 · ✕ 상태 머신 • app/api/checkout/confirm/route.ts:4 amount 파라미터를 PG 에 그대로 전달 — 서버 재계산 없음 • app/api/checkout/confirm/route.ts:17 .update({ status: 'PAID' }).eq('id', orderId) — WHERE status 조건 없음, 중복 호출 시 덮어씀 • supabase/migrations/001_init.sql — CHECK 제약 없음 (검색: CHECK¦CONSTRAINT → 0건)
관련 위치: app/api/checkout/confirm/route.ts:17, app/api/checkout/confirm/route.ts:4, supabase/migrations/001_init.sql
할 일: 주문 조회·금액 재계산·비교 · UPDATE WHERE status='PENDING' · CHECK (status IN …)
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.await req.json() — 서명 검증 없음, PG 재조회 없음 (검색: signature|verify|fetch.*payments → 0건)<br>• app/api/webhooks/toss/route.ts:6 .update({ status: body.data.status }) — 이벤트 id 저장 없음, 중복 수신 시 덮어씀<br>• 순서 역전 분기 없음 (검색: eventType|event.*id|webhook.*log → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[5.4] 웹훅 서명 검증 · 중복 방지 · 순서 역전
지금 상태: ✕ 서명 검증 · ✕ 중복 방지 · ✕ 순서 역전 • app/api/webhooks/toss/route.ts:4 await req.json() — 서명 검증 없음, PG 재조회 없음 (검색: signature¦verify¦fetch.payments → 0건) • app/api/webhooks/toss/route.ts:6 .update({ status: body.data.status }) — 이벤트 id 저장 없음, 중복 수신 시 덮어씀 • 순서 역전 분기 없음 (검색: eventType¦event.id¦webhook.log → 0건)
관련 위치: app/api/webhooks/toss/route.ts:4, app/api/webhooks/toss/route.ts:6
할 일: 토스 서명 검증 또는 paymentKey 로 PG 재조회 · 이벤트 id 유니크 저장 · 상태 전이 조건
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.GET.*payments|fetch.*payments.*key → confirm 만 있음, GET 없음)<br>• 잡·큐 없음 (검색: cron|schedule|queue|job|worker → 0건)<br>• 운영자 알림 없음 (검색: alert|notify|mail|send → ADMIN_EMAIL 변수만, 발송 코드 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [5.5] 고객이 돌아오지 않을 때 끝낼 주체 지금 상태: ✕ PG 조회 · ✕ 대사 작업 · ✕ 알림 • PG 조회 API 없음 (검색: GET.payments¦fetch.payments.key → confirm 만 있음, GET 없음) • 잡·큐 없음 (검색: cron¦schedule¦queue¦job¦worker → 0건) • 운영자 알림 없음 (검색: alert¦notify¦mail¦send → ADMIN_EMAIL 변수만, 발송 코드 없음) 할 일: PENDING 30분 이상 주문 조회·PG 재조회·상태 동기화 cron · 슬랙·메일 알림 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
if (!res.ok) return Response.json({ ok: false }) — 실패 응답은 있음<br>• app/pay/success/page.tsx:12 j.ok ? '결제 완료!' : '결제 실패' — 실패 메시지 있음<br>• 중복 클릭 방지 없음 (검색: disabled|pending|loading → 0건) · 주문 유니크 제약 없음 (001_init.sql — payment_key 유니크 없음)<br>• e2e 없음 (검색: e2e|test|spec|cypress|playwright → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[5.6] 결제 실패 경로와 실 PG e2e
지금 상태: ✕ 실패 분기 ○ · ✕ 중복 방지 · ✕ e2e • app/api/checkout/confirm/route.ts:15 if (!res.ok) return Response.json({ ok: false }) — 실패 응답은 있음 • app/pay/success/page.tsx:12 j.ok ? '결제 완료!' : '결제 실패' — 실패 메시지 있음 • 중복 클릭 방지 없음 (검색: disabled¦pending¦loading → 0건) · 주문 유니크 제약 없음 (001_init.sql — payment_key 유니크 없음) • e2e 없음 (검색: e2e¦test¦spec¦cypress¦playwright → 0건)
관련 위치: app/api/checkout/confirm/route.ts:15, app/pay/success/page.tsx:12
할 일: 버튼 비활성·payment_key 유니크 · 토스 테스트 모드 e2e (성공·실패·취소)
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.refund|cancel|환불|취소 → 0건)<br>• 약관 없음 (app/login/page.tsx:9 <a href="#">이용약관</a> — href="#", 실제 파일 없음)<br>• 결제 전 고지 없음 (app/classes/page.tsx — 결제 전 동의·고지 화면 없음, prompt() 후 바로 결제)<br>• 규정·약관·고지 셋 모두 부재출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [5.7] 취소·환불 규정 확정 및 코드·약관·고지 일치 지금 상태: ✕ 환불 규정 · ✕ 약관 · ✕ 결제 전 고지 • 환불 코드 없음 (검색: refund¦cancel¦환불¦취소 → 0건) • 약관 없음 (app/login/page.tsx:9 <a href="#">이용약관</a> — href="#", 실제 파일 없음) • 결제 전 고지 없음 (app/classes/page.tsx — 결제 전 동의·고지 화면 없음, prompt() 후 바로 결제) • 규정·약관·고지 셋 모두 부재 관련 위치: app/classes/page.tsx, app/login/page.tsx:9 할 일: 환불 규정 확정 → 함수·약관·결제 전 고지 문안 작성 및 동의 체크 · 주문 행에 버전 기록 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
refund|cancel|환불 → 0건)<br>• PG 취소 호출 없음 (검색: cancel|refund → 0건)<br>• 환불 상태·큐 없음 (001_init.sql — status 열에 REFUND 언급 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [5.8] 환불 실행 — 부분·재시도·알림 지금 상태: ✕ 환불 코드 · ✕ 부분 환불 · ✕ 재시도 • 환불 코드 없음 (검색: refund¦cancel¦환불 → 0건) • PG 취소 호출 없음 (검색: cancel¦refund → 0건) • 환불 상태·큐 없음 (001_init.sql — status 열에 REFUND 언급 없음) 할 일: 토스 취소 API 호출 (트랜잭션 밖) · 부분 환불 지원 · 실패 시 재시도 큐·알림 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
.select('*') — 취소·환불 쓰기 라우트 없음)<br>• 취소·환불 API 없음 (app/api — checkout/confirm · webhooks/toss 만, cancel 엔드포인트 없음)<br>• 배상 조항 없음 (약관 파일 자체가 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[5.9] 판매자 측 취소·배상 규정·행위자 권한
지금 상태: ✕ 판매자·운영자 취소 · ✕ 배상 규정 • 관리자 화면 읽기만 (app/admin/page.tsx:8 .select('') — 취소·환불 쓰기 라우트 없음) • 취소·환불 API 없음 (app/api — checkout/confirm · webhooks/toss 만, cancel 엔드포인트 없음) • 배상 조항 없음 (약관 파일 자체가 없음)
관련 위치: app/admin/page.tsx:8, app/api, checkout/confirm, webhooks/toss
할 일: 관리자 취소·환불 API · 일괄 환불 기능 · 약관에 배상 조항 추가
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘..insert())<br>[5.11-c] 검색 worker|cron|cleanup|expire|ttl → 0건 — 만료 정리 없음, 이 서비스엔 선점 개념 없음(장바구니·hold 없음) — 해당없음 —<br>[5.11-d] 검색 k6|locust|artillery|describe|it\( → 0건 — 동시성 spec 없음seats > 0 WHERE 조건부 UPDATE 로 변경 · 동시성 테스트 작성출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [5.11] 동시성 — DB 가 최종 방어선(부분 유니크 · EXCLUDE · CHECK), 판정은 잠금 아래 한 문장, 만료 선점이 자정(自淨)된다 지금 상태: 제약 ✕ · 잠금 ✕ · 만료 정리 — · 동시성 spec ✕ · 부하 ③ [5.11-a] supabase/migrations/001_init.sql:1-19 — UNIQUE/EXCLUDE/CHECK 제약 없음 (검색 → 0건) [5.11-b] app/classes/page.tsx:13-15 — INSERT 에 조건부 WHERE · FOR UPDATE · ON CONFLICT 없음, 트랜잭션 없음 (단순 .insert()) [5.11-c] 검색 worker¦cron¦cleanup¦expire¦ttl → 0건 — 만료 정리 없음, 이 서비스엔 선점 개념 없음(장바구니·hold 없음) — 해당없음 — [5.11-d] 검색 k6¦locust¦artillery¦describe¦it\( → 0건 — 동시성 spec 관련 위치: UNIQUE/EXCLUDE/CHECK, app/classes/page.tsx:13-15, supabase/migrations/001_init.sql:1-19 할 일: 재고(seats) 감소 시 DB 제약(CHECK seats >= 0) 추가 · 주문 INSERT 를 seats > 0 WHERE 조건부 UPDATE 로 변경 · 동시성 테스트 작성 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
Dockerfile|vercel.json|fly.toml|render.yaml|Procfile → 0건) · ✕ TLS/HSTS/리다이렉트 설정 없음 (middleware.ts 없음) · ✕ 스테이징 결정 기록 없음 (docs 디렉터리 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [6.1] 프로덕션 환경이 실제로 있다 지금 상태: ✕ 배포 대상 선언 없음 (검색: Dockerfile¦vercel.json¦fly.toml¦render.yaml¦Procfile → 0건) · ✕ TLS/HSTS/리다이렉트 설정 없음 (middleware.ts 없음) · ✕ 스테이징 결정 기록 없음 (docs 디렉터리 없음) 관련 위치: TLS/HSTS 할 일: 배포 플랫폼 선택 및 설정 파일 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
Dockerfile → 0건) · ✕ .dockerignore 없음 (ls → 없음) · ○ package.json:4 scripts.build: "next build" 존재출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [6.2] 배포 재현성 지금 상태: ✕ Dockerfile/빌드 스크립트 없음 (검색: Dockerfile → 0건) · ✕ .dockerignore 없음 (ls → 없음) · ○ package.json:4 scripts.build: "next build" 존재 할 일: Dockerfile 또는 플랫폼 빌드 설정 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
.github/workflows 디렉터리 없음) · ✕ 시드 동기화 없음 (검색: seed → 0건) · ✕ 헬스체크 없음 (검색: health|liveness|readiness → 0건) · ✕ 롤백 절차 없음 (README.md:11-17 개발 실행만)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [6.3] 배포 절차 — 마이그레이션 · 시드 · 헬스 · 롤백 지금 상태: ✕ 워크플로/스크립트 없음 (.github/workflows 디렉터리 없음) · ✕ 시드 동기화 없음 (검색: seed → 0건) · ✕ 헬스체크 없음 (검색: health¦liveness¦readiness → 0건) · ✕ 롤백 절차 없음 (README.md:11-17 개발 실행만) 관련 위치: .github/workflows 할 일: 배포 워크플로 및 절차 문서 작성 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
.env.example 에 있음 (lib/supabase.ts:4-5 · app/api/checkout/confirm/route.ts:10 · app/classes/page.tsx:16 · .env.example:1-5) · ✕ 배포 설정 없음 (compose/플랫폼 변수 파일 없음) · ✕ 대조 spec 없음 (검색: *.test.*|*.spec.* → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [6.4] 환경변수 — 코드 ↔ 예시 ↔ 배포 설정 지금 상태: ○ 코드가 읽는 5개 키 전부 .env.example 에 있음 (lib/supabase.ts:4-5 · app/api/checkout/confirm/route.ts:10 · app/classes/page.tsx:16 · .env.example:1-5) · ✕ 배포 설정 없음 (compose/플랫폼 변수 파일 없음) · ✕ 대조 spec 없음 (검색: .test.¦.spec. → 0건) 관련 위치: app/api/checkout/confirm/route.ts:10, app/classes/page.tsx:16, lib/supabase.ts:4-5 할 일: 배포 설정 추가 및 환경변수 대조 테스트 작성 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
test_ck_xxxxxxxx · test_sk_xxxxxxxx (테스트 접두사) · ✕ .env.example:5 owner@example.com (예시값) · ✕ 결정 기록 없음 (검색: ADR|설계|결정 → 0건) · ✕ 세션 TTL · 보유 기간 · 수수료 설정 없음 (검색 → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [6.5] 정책값이 결정값이다 지금 상태: ✕ .env.example:3-4 토스 키가 test_ck_xxxxxxxx · test_sk_xxxxxxxx (테스트 접두사) · ✕ .env.example:5 owner@example.com (예시값) · ✕ 결정 기록 없음 (검색: ADR¦설계¦결정 → 0건) · ✕ 세션 TTL · 보유 기간 · 수수료 설정 없음 (검색 → 0건) 할 일: 프로덕션 값 결정 및 .env.example 갱신 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
seed → 0건 — 환경 가드도 없음) · ✕ 목 게이트웨이 부팅 거부 없음 (.env.example:3-4 test_ 키가 기본값 — 환경 검사 없음) · — API 문서 UI 없음 (검색: swagger|graphql → 0건) · ✕ 관리자 경로 무인증 (app/admin/page.tsx:5 주석 "메뉴에는 안 보이게 해 둠" — URL 직접 접근 가능)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [6.7] 개발 시드 · 목 결제 · 디버그 도구 프로덕션 거부 지금 상태: ✕ 시드 스크립트 없음 (검색: seed → 0건 — 환경 가드도 없음) · ✕ 목 게이트웨이 부팅 거부 없음 (.env.example:3-4 test_ 키가 기본값 — 환경 검사 없음) · — API 문서 UI 없음 (검색: swagger¦graphql → 0건) · ✕ 관리자 경로 무인증 (app/admin/page.tsx:5 주석 "메뉴에는 안 보이게 해 둠" — URL 직접 접근 가능) 관련 위치: app/admin/page.tsx:5 할 일: 환경 가드 추가 (test_ 키 거부, 관리자 인증) 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
error.tsx 없음 — 검색: error.tsx → 0건) · ✕ 요청 id 미들웨어 없음 (검색: requestId|request_id|correlation → 0건) · ✕ 에러 응답 구성 없음 (app/api/checkout/confirm/route.ts:15 !res.ok 시 {ok: false} 만 — 메시지 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[7.1] 5xx 응답에 스택 없음 + 전역 필터 + 요청 id
지금 상태: ✕ 전역 예외 필터 없음 (Next.js App Router error.tsx 없음 — 검색: error.tsx → 0건) · ✕ 요청 id 미들웨어 없음 (검색: requestId¦request_id¦correlation → 0건) · ✕ 에러 응답 구성 없음 (app/api/checkout/confirm/route.ts:15 !res.ok 시 {ok: false} 만 — 메시지 없음)
관련 위치: app/api/checkout/confirm/route.ts:15
할 일: 전역 error.tsx · 요청 id 미들웨어 · 5xx 필터 추가
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.fetch — timeout/AbortSignal 없음) · ✕ 재시도 정책 없음 (검색: retry|attempts → 0건) · ✕ 멱등 키 없음 (route.ts:7-14 paymentKey · orderId 는 토스가 생성 — 재시도 시 중복 가능)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [7.3] 외부 호출 타임아웃 · 재시도 지금 상태: ✕ 토스 confirm API 타임아웃 없음 (app/api/checkout/confirm/route.ts:7 fetch — timeout/AbortSignal 없음) · ✕ 재시도 정책 없음 (검색: retry¦attempts → 0건) · ✕ 멱등 키 없음 (route.ts:7-14 paymentKey · orderId 는 토스가 생성 — 재시도 시 중복 가능) 관련 위치: app/api/checkout/confirm/route.ts:7, timeout/AbortSignal 할 일: fetch 타임아웃 추가 (PG 필수) 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
.github/workflows 디렉터리 없음) · ✕ 자동 검증 없음 (검색: *.test.*|*.spec.* → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [8.1] 머지된 코드 자동 검증 · CI 분 예산 지금 상태: ✕ 워크플로 없음 (.github/workflows 디렉터리 없음) · ✕ 자동 검증 없음 (검색: .test.¦.spec. → 0건) 관련 위치: .github/workflows 할 일: GitHub Actions 워크플로 추가 (빌드 · 테스트) 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
*.test.*|*.spec.* → 0건) · ✕ 결제 테스트 없음 (app/api/checkout/confirm/route.ts:7 토스 confirm — 테스트 없음) · — 환불 없음 (검색: refund|환불 → 0건) · ✕ 동시성 테스트 없음 (supabase/migrations/001_init.sql:6 seats — 감소 로직 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [8.2] 결제 · 환불 · 동시성 통합 테스트 + e2e 지금 상태: ✕ spec 파일 없음 (검색: .test.¦.spec. → 0건) · ✕ 결제 테스트 없음 (app/api/checkout/confirm/route.ts:7 토스 confirm — 테스트 없음) · — 환불 없음 (검색: refund¦환불 → 0건) · ✕ 동시성 테스트 없음 (supabase/migrations/001_init.sql:6 seats — 감소 로직 없음) 관련 위치: app/api/checkout/confirm/route.ts:7, supabase/migrations/001_init.sql:6 할 일: 결제 · 재고 통합 테스트 작성 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
sentry|@sentry|bugsnag|rollbar → 0건)<br>헬스체크: 없음 (검색: /health|/ping|/ready|healthcheck → 0건)<br>알림: 없음 (검색: slack|discord|webhook|notification|alert → 0건 — .env.example:5 ADMIN_EMAIL 변수명만 존재, 메일 발송 구현 없음)<br>실 발화 기록: 없음 (저장소 내 문서 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [11.1] 에러 추적(국외 이전 고지 포함) + 헬스체크가 DB·큐를 보고 공개 경로로 도달 + 알림 사슬이 1회 울렸다 지금 상태: 에러 추적 ✕ · 헬스체크 ✕ · 알림 ✕ · 실 발화 기록 ✕ 에러 추적: 없음 (검색: sentry¦@sentry¦bugsnag¦rollbar → 0건) 헬스체크: 없음 (검색: /health¦/ping¦/ready¦healthcheck → 0건) 알림: 없음 (검색: slack¦discord¦webhook¦notification¦alert → 0건 — .env.example:5 ADMIN_EMAIL 변수명만 존재, 메일 발송 구현 없음) 실 발화 기록: 없음 (저장소 내 문서 없음) 할 일: Sentry 류 SDK 추가 · /health 경로 생성 (Supabase 연결 확인) · 알림 연결 설정 · 테스트 발화 후 기록 문서화 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
backup|snapshot|restore|dump → 0건 · Supabase 플랫폼 자동 백업은 콘솔 설정이나 저장소에 보존일 언급 없음)<br>리허설 기록: 없음 (검색: runbook|procedure|operation|rehearsal → 0건)<br>롤백 명령: 없음 (supabase/migrations 에 up 만, down 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [11.2] 백업 보존일 + 복구 리허설 + 롤백 리허설(소요 시간 기록) 지금 상태: 백업 설정 ✕ · 복구 리허설 ✕ · 롤백 리허설 ✕ 백업 설정: 없음 (검색: backup¦snapshot¦restore¦dump → 0건 · Supabase 플랫폼 자동 백업은 콘솔 설정이나 저장소에 보존일 언급 없음) 리허설 기록: 없음 (검색: runbook¦procedure¦operation¦rehearsal → 0건) 롤백 명령: 없음 (supabase/migrations 에 up 만, down 없음) 관련 위치: supabase/migrations 할 일: Supabase 콘솔 백업 설정 확인 후 보존일 문서화 · DB 복구 리허설 수행 및 기록 · 마이그레이션 롤백 스크립트 작성 · 애플리케이션 이전 버전 배포 절차 문서화 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
budget|cost|billing|alarm → 0건)<br>스토리지 상한: 없음 (Supabase DB · 스토리지 사용 없음 — 00-map.md:16 확인, 설정 문서 없음)<br>CDN: 해당 없음 (객체 스토리지 미사용)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [11.3] 비용 상한 — 예산 알람(50/80/100%) · 스토리지 자동 확장 상한 · 공개 버킷 트래픽 앞단 지금 상태: 예산 알람 ✕ · 스토리지 상한 ✕ · CDN — 예산 알람: 없음 (검색: budget¦cost¦billing¦alarm → 0건) 스토리지 상한: 없음 (Supabase DB · 스토리지 사용 없음 — 00-map.md:16 확인, 설정 문서 없음) CDN: 해당 없음 (객체 스토리지 미사용) 할 일: Supabase 프로젝트 예산 알람 설정 (콘솔) · DB 용량 상한 정책 수립 · 설정값 문서화 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
scripts.dev/build/start 만)<br>관리 명령: 없음 (첫 관리자 생성 스크립트 · 잠금 해제 · 카탈로그 동기화 코드 전무)<br>절차 문서: 없음 (검색: procedure|admin|operation → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [11.5] 운영 환경에서 관리 명령(첫 관리자 생성 · 잠금 해제 · 카탈로그 동기화)을 실행할 경로가 있다 지금 상태: CLI 실행 경로 ✕ · 비밀번호 노출 위험 ③ CLI 실행 경로: 없음 (Dockerfile · docker-compose 없음 · 플랫폼 명시 없음 · package.json:4 scripts.dev/build/start 만) 관리 명령: 없음 (첫 관리자 생성 스크립트 · 잠금 해제 · 카탈로그 동기화 코드 전무) 절차 문서: 없음 (검색: procedure¦admin¦operation → 0건) 관련 위치: scripts.dev/build/start 할 일: 배포 플랫폼 결정 후 CLI 실행 경로 문서화 (Vercel 등 매니지드면 로컬 스크립트 + Supabase SQL) · 관리자 초기화 스크립트 작성 · classes 카탈로그 시드 스크립트 작성 · 절차 문서 작성 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
cp .env.example .env.local · npm install · npm run dev)<br>배포 문서: 없음 (검색: deploy|runbook|operation → 0건 · README 개발 환경만)<br>계정 대장: 없음 (검색: account|credential|owner|2FA → 0건)<br>시크릿 대장: 없음 (검색: secret|rotation|rotate → 0건 · .env.example:1-5 키 목록만)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [11.6] 인수인계 — 실행·배포 문서, 외부 계정 대장(소유자 · 2FA · 복구 메일 · 결제수단 · 접근자), 시크릿 대장(위치 · 회전일) 지금 상태: 실행 문서 ○ · 배포 문서 ✕ · 계정 대장 ✕ · 시크릿 대장 ✕ 실행 문서: README.md:11-17 (cp .env.example .env.local · npm install · npm run dev) 배포 문서: 없음 (검색: deploy¦runbook¦operation → 0건 · README 개발 환경만) 계정 대장: 없음 (검색: account¦credential¦owner¦2FA → 0건) 시크릿 대장: 없음 (검색: secret¦rotation¦rotate → 0건 · .env.example:1-5 키 목록만) 할 일: 배포 플랫폼·절차 문서 작성 · Supabase·토스페이먼츠·배포 플랫폼 계정 대장 작성 (소유자 · 2FA · 복구 메일 · 결제수단 · 접근자) · 시크릿 대장 작성 (위치: Supabase 프로젝트 설정 · 토스 개발자센터 · 플랫폼 환경변수 / 회전일 정책) 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
cancel|refund|환불|취소 → 0건)<br>입장 확인: 없음 (수강생 출석 체크 로직 없음 · orders.status 가 PAID 로만 종결)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [12.2] 판매자(운영 당사자)가 실제 운영에 필요한 쓰기 — 취소 · 환불 · 입장/수령 확인 지금 상태: 판매자 콘솔 쓰기 ✕ · 환불 ✕ · 입장 확인 ✕ 판매자 콘솔: app/admin/page.tsx:8-18 (orders 조회만 · 쓰기 없음) 환불: 없음 (검색: cancel¦refund¦환불¦취소 → 0건) 입장 확인: 없음 (수강생 출석 체크 로직 없음 · orders.status 가 PAID 로만 종결) 관련 위치: app/admin/page.tsx:8-18 할 일: app/admin 에 환불 버튼 추가 (토스 결제 취소 API 호출) · 입장 확인 화면 추가 (QR 스캔 또는 주문 ID 검색 → orders.status 를 ATTENDED 등으로 업데이트) 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
nodemailer|resend|smtp|sendgrid|ses|mailgun|postmark → 0건)<br>DNS 인증: 없음 (검색: SPF|DKIM|DMARC → 0건)<br>템플릿: 없음 (메일 템플릿 파일 없음 · .env.example:5 ADMIN_EMAIL 변수만)<br>주문 확인: app/pay/success/page.tsx:12 "마이페이지에서 예약 코드를 확인하세요" 문구만 (실제 발송 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [12.3] 메일·문자 실발송 + 도달(SPF/DKIM/DMARC, 스팸함) + 거래 알림(주문 확인) 템플릿 지금 상태: 발송 어댑터 ✕ · DNS 인증 ✕ · 템플릿 ✕ · 실발송 ③ 발송 어댑터: 없음 (검색: nodemailer¦resend¦smtp¦sendgrid¦ses¦mailgun¦postmark → 0건) DNS 인증: 없음 (검색: SPF¦DKIM¦DMARC → 0건) 템플릿: 없음 (메일 템플릿 파일 없음 · .env.example:5 ADMIN_EMAIL 변수만) 주문 확인: app/pay/success/page.tsx:12 "마이페이지에서 예약 코드를 확인하세요" 문구만 (실제 발송 없음) 관련 위치: app/pay/success/page.tsx:12 할 일: Resend 류 발송 어댑터 추가 · 주문 확인 메일 템플릿 작성 · 도메인 DNS SPF/DKIM/DMARC 설정 · app/api/checkout/confirm/route.ts:17 뒤에 메일 발송 로직 추가 · 실발송 테스트 후 기록 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
test.*checklist|test.*pass|manual.*test → 0건)<br>실기기 기록: 없음 (저장소 내 문서 없음)<footer>© 공방 원데이</footer> — 저작권 표시만, 사업자 정보·통판 번호·보호책임자 없음<br>검색: 고객센터|상담|문의|contact|support → 0건출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [13.1] 사업자 정보·통신판매업 번호 footer + 개인정보 보호책임자 + 문의 동선 지금 상태: 사업자 정보 ✕ · 통판 번호 ✕ · 보호책임자 ✕ · 문의 동선 ✕ app/layout.tsx:3 <footer>© 공방 원데이</footer> — 저작권 표시만, 사업자 정보·통판 번호·보호책임자 없음 검색: 고객센터¦상담¦문의¦contact¦support → 0건 관련 위치: app/layout.tsx:3 할 일: footer 에 사업자 정보·통판 번호·보호책임자·연락 수단(메일/전화) 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
<a href="#">이용약관</a> — href="#", 실제 문안 없음<br>검색: 약관|terms → 링크만, 문안 파일(md·json·CMS) 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [13.2] 약관 — 구매·지급·청약철회·환급 조항, 거래 구조(중개자 고지), 자리 표시자 0, 효력일 순서 지금 상태: 약관 문안 ✕ · 자리 표시자 — · 효력일 ✕ app/login/page.tsx:9 <a href="#">이용약관</a> — href="#", 실제 문안 없음 검색: 약관¦terms → 링크만, 문안 파일(md·json·CMS) 없음 관련 위치: app/login/page.tsx:9 할 일: 약관 문안 작성(구매·청약철회·환급·중개자 여부 명시), 효력일 기재, 문안 파일 추가 및 링크 수정 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
<a href="#">개인정보처리방침</a> — href="#", 실제 문안 없음<br>코드 사실: supabase/migrations/001_init.sql:13-14 buyer_name text, buyer_phone text (이름·전화 수집) · app/api/checkout/confirm/route.ts:7-14 토스페이먼츠 API 전송 → 문안 없어 대조 불가출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [13.3] 처리방침 — 수집 항목·처리위탁·보존 기간·국외 이전·판매자 제공 항목이 코드 사실과 일치 지금 상태: 처리방침 문안 ✕ · 코드 대조 ✕ app/login/page.tsx:9 <a href="#">개인정보처리방침</a> — href="#", 실제 문안 없음 코드 사실: supabase/migrations/001_init.sql:13-14 buyer_name text, buyer_phone text (이름·전화 수집) · app/api/checkout/confirm/route.ts:7-14 토스페이먼츠 API 전송 → 문안 없어 대조 불가 관련 위치: app/api/checkout/confirm/route.ts:7-14, app/login/page.tsx:9, supabase/migrations/001_init.sql:13-14 할 일: 처리방침 문안 작성(수집: 이름·전화·결제정보 / 위탁: 토스·Supabase / 국외 이전: Supabase 위치 확인 / 보존: 거래 5년), 문안 파일 추가 및 링크 수정 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
<p>가입하면 <a href="#">이용약관</a>과 <a href="#">개인정보처리방침</a>에 동의한 것으로 봅니다.</p> — 체크박스 없음, 묵시 동의<br>supabase/migrations/001_init.sql:9-19 orders 테이블 — 동의 버전 열 없음<br>app/classes/page.tsx:10-26 결제 흐름 — 취소 규정 동의 체크 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [13.4] 동의 — 필수/선택 분리 · 만 14세 · 마케팅 분리·철회 · 결제 전 취소 규정 동의와 버전 기록 지금 상태: 필수/선택 분리 ✕ · 만 14세 ✕ · 마케팅 분리 — · 결제 전 동의 ✕ · 버전 기록 ✕ app/login/page.tsx:9 <p>가입하면 <a href="#">이용약관</a>과 <a href="#">개인정보처리방침</a>에 동의한 것으로 봅니다.</p> — 체크박스 없음, 묵시 동의 supabase/migrations/001_init.sql:9-19 orders 테이블 — 동의 버전 열 없음 app/classes/page.tsx:10-26 결제 흐름 — 취소 규정 동의 체크 없음 관련 위치: app/classes/page.tsx:10-26, app/login/page.tsx:9, supabase/migrations/001_init.sql:9-19 할 일: 가입 화면에 체크박스(필수: 약관·방침·만 14세, 선택: 마케팅) 추가, 결제 전 취소 규정 동의 체크박스 추가, orders.consent_version 열 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
탈퇴|withdraw|delete.*account → 0건, 탈퇴 기능 없음<br>supabase/migrations/001_init.sql:9-19 orders 테이블 — 보존·익명화 정책 명시 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [13.5] 거래기록 5년 보존 vs 탈퇴·삭제 정책, 탈퇴 동선 지금 상태: 탈퇴 동선 ✕ · 보존 정책 ✕ 검색: 탈퇴¦withdraw¦delete.account → 0건, 탈퇴 기능 없음 supabase/migrations/001_init.sql:9-19 orders 테이블 — 보존·익명화 정책 명시 없음 관련 위치: supabase/migrations/001_init.sql:9-19 할 일: 탈퇴 동선 추가(마이페이지·설정), 탈퇴 시 주문 행 보존 정책 결정(거래 5년 vs 개인정보 삭제), 익명화 로직 구현 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
보상|배상|손해|불이행 → 0건, 약관 없음(13.2)<br>검색: age|연령|미성년 → 0건, 연령 제한 상품 해당 없음(원데이 클래스)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [13.6] 판매자 불이행 보상(소비자분쟁해결기준)과 배상 주체, 연령 제한 상품의 확인 강제 지금 상태: 보상 조항 ✕ · 배상 집행 ✕ · 연령 확인 — 검색: 보상¦배상¦손해¦불이행 → 0건, 약관 없음(13.2) 검색: age¦연령¦미성년 → 0건, 연령 제한 상품 해당 없음(원데이 클래스) 할 일: 약관에 불이행 보상 조항 추가(배상 주체: 판매자 직접 or 플랫폼 중개), 코드의 환불·보상 집행 경로 구현 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
검토|review|lawyer|변호사|법무 → 0건<br>docs 디렉터리 없음, .github/issues 없음(이슈 기록은 저장소 밖이라 확인 못 함)test_ck_xxxxxxxx · test_sk_xxxxxxxx — 테스트 키, 프로덕션 심사 전<br>서류(사업자등록증·통판·신분증·통장)는 외부 — 확인 불가(?)nodemailer|resend|sendgrid|ses|smtp|mailer → 0건, 메일 어댑터 없음<br>.env.example:5 ADMIN_EMAIL=owner@example.com — 수신 주소만, 발신 구현 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [14.2] 메일 공급자 프로덕션 액세스 · 도메인 인증(DKIM) · 바운스 처리 지금 상태: 메일 어댑터 구현 ✕ · DKIM ✕ · 바운스 처리 ✕ 검색: nodemailer¦resend¦sendgrid¦ses¦smtp¦mailer → 0건, 메일 어댑터 없음 .env.example:5 ADMIN_EMAIL=owner@example.com — 수신 주소만, 발신 구현 없음 할 일: 메일 공급자(Resend·SendGrid·SES 등) 선택 및 어댑터 구현, 발신 도메인 DKIM 설정, 바운스 웹훅 처리 코드 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [1.1] 저장소와 전 히스토리에 시크릿이 없다 지금 상태: 커밋 파일 ○ — .env.example 만 있음 (git ls-files) · 히스토리 ? — 이번 진단은 현재 파일만 봤어요 · 방지 장치 ✕ — gitleaks/secret-scan 설정 없음 (glob → 0건) · CI 단계 ✕ — .github/workflows 없음 관련 위치: .github/workflows, gitleaks/secret-scan 할 일: gitleaks 설정 추가 · CI 스캔 단계 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [1.2] 브라우저가 받는 응답에 서버 시크릿이 없다 지금 상태: 공개 접두 변수 ✕ — NEXT_PUBLIC_TOSS_SECRET_KEY (app/api/checkout/confirm/route.ts:10 — 서버 전용 비밀이 NEXT_PUBLIC_ 접두로 노출) · 클라이언트 참조 ✕ — app/classes/page.tsx:16 NEXT_PUBLIC_TOSS_CLIENT_KEY (클라이언트 키는 정상, 하지만 SECRET_KEY 가 NEXT_PUBLIC_ 로 노출됨) · 오류 본문 ○ — 오류 처리 없음 (catch 문 0건) · 도메인 제한 기록 ✕ — 없음 · 빌드 산출물 ③ 관련 위치: app/api/checkout/confirm/route.ts:10, app/classes/page.tsx:16 할 일: NEXT_PUBLIC_TOSS_SECRET_KEY → TOSS_SECRET_KEY 로 변경 (서버 전용) 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[1.3] 로그 채널별로 개인정보·토큰이 찍히지 않는다
지금 상태: 앱 로그 ✕ — console.log('confirm', { paymentKey, orderId, amount }) (app/api/checkout/confirm/route.ts:5 — paymentKey 토큰 노출) · DB 오류 로그 ○ — ORM 로깅 설정 없음 (Supabase 클라이언트는 기본 로깅 안 함) · 접근 로그 ○ — 프록시 없음 (middleware.ts 없음 · 00-map.md:26) · 재설정 토큰 — — 기능 없음
관련 위치: app/api/checkout/confirm/route.ts:5
할 일: console.log 에서 paymentKey 제거 또는 마스킹
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.! 연산자만 — 런타임 오류는 내지만 부팅 전 검증 없음) · 검사 spec ✕ — 테스트 없음 (*.test.* → 0건) · 집합 차 ✕ — 코드 읽음 {NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, NEXT_PUBLIC_TOSS_CLIENT_KEY, NEXT_PUBLIC_TOSS_SECRET_KEY, ADMIN_EMAIL} − 배포 주입 {} = 전부 누락 (배포 설정 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[1.4] 프로덕션 시크릿 주입 경로가 실제로 있고, 개발 기본값·누락이면 부팅이 거부된다
지금 상태: 배포 설정 ✕ — 없음 (Dockerfile · docker-compose · vercel.json · fly.toml → 0건) · 부팅 검사 ✕ — 없음 (lib/supabase.ts:4-5 ! 연산자만 — 런타임 오류는 내지만 부팅 전 검증 없음) · 검사 spec ✕ — 테스트 없음 (.test. → 0건) · 집합 차 ✕ — 코드 읽음 {NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, NEXT_PUBLIC_TOSS_CLIENT_KEY, NEXT_PUBLIC_TOSS_SECRET_KEY, ADMIN_EMAIL} − 배포 주입 {} = 전부 누락 (배포 설정 없음)
관련 위치: lib/supabase.ts:4-5
할 일: 부팅 시 필수 env 검증 추가 · 배포 설정에 env 주입 명시
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘._PREVIOUS|_OLD|rotation → 0건) · 절차 문서 ✕ — 없음 (docs 디렉터리 없음 · README 실행 섹션만) · 리허설 기록 ✕ — 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [2.1] 모든 API 라우트가 권한을 명시하고 미명시는 기본 거부다 지금 상태: 라우트 ✕ — app/api/checkout/confirm/route.ts (POST) · app/api/webhooks/toss/route.ts (POST) 총 2개 · 전역 가드 ✕ — middleware.ts 없음 · RLS 전수 ✕ — orders 테이블 RLS 없음 (001_init.sql:9-19 — classes 만 RLS, orders 는 누구나 조회·수정 가능) · 신원 위조 ✕ — app/api/webhooks/toss/route.ts:4-6 body.data.orderId 를 그대로 신뢰 (서명 검증 없음) · 미명시 처리 ✕ — 인증 검사 없음 (auth/guard/Depends → 0건) · 테스트 ✕ — 없음 관련 위치: app/api/checkout/confirm/route.ts, app/api/webhooks/toss/route.ts, app/api/webhooks/toss/route.ts:4-6, auth/guard/Depends 할 일: orders 테이블 RLS 활성화 · 웹훅 서명 검증 추가 · API 인증 미들웨어 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
.select('*') (조건 없음 — 전체 조회) · app/api/checkout/confirm/route.ts:17 .eq('id', orderId) (user_id 검증 없음 — 남의 주문도 PAID 처리 가능) · app/api/webhooks/toss/route.ts:6 .eq('id', body.data.orderId) (소유자 검증 없음) · 신원 서버 결정 ✕ — 클라이언트가 보낸 orderId (app/pay/success/page.tsx:11 쿼리 파라미터) 를 그대로 사용 · 404/403 구분 ✕ — 없음 · IDOR 테스트 ✕ — 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[2.2] 소유자·테넌트 격리 — 남의 id 로 조회·수정·취소하면 404/403 (IDOR)
지금 상태: WHERE user_id ✕ — app/admin/page.tsx:8 .select('') (조건 없음 — 전체 조회) · app/api/checkout/confirm/route.ts:17 .eq('id', orderId) (user_id 검증 없음 — 남의 주문도 PAID 처리 가능) · app/api/webhooks/toss/route.ts:6 .eq('id', body.data.orderId) (소유자 검증 없음) · 신원 서버 결정 ✕ — 클라이언트가 보낸 orderId (app/pay/success/page.tsx:11 쿼리 파라미터) 를 그대로 사용 · 404/403 구분 ✕ — 없음 · IDOR 테스트 ✕ — 없음
관련 위치: 404/403, app/admin/page.tsx:8, app/api/checkout/confirm/route.ts:17, app/api/webhooks/toss/route.ts:6, app/pay/success/page.tsx:11
할 일: orders 테이블에 WHERE user_id 조건 추가 · 세션에서 user_id 추출
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [2.3] 서버 액션·라우트 핸들러·엣지 함수가 API 가드를 우회해 DB 를 직접 만지지 않는다 지금 상태: 웹 앱 DB 드라이버 ✕ — lib/supabase.ts:3-6 (클라이언트 앱에서 Supabase 직접 생성 · app/classes/page.tsx:8 · app/admin/page.tsx:8 브라우저에서 직접 DB 조회) · API 호출 단일화 ✕ — 클라이언트 컴포넌트가 supabase.from() 직접 호출 (app/classes/page.tsx:8·13 · app/admin/page.tsx:8) · 우회 경로 ✕ — 있음 (서버 액션은 없지만 클라이언트가 DB 직접 조회) · 서버 액션 인증 — — 서버 액션 없음 관련 위치: app/admin/page.tsx:8, app/classes/page.tsx:8, lib/supabase.ts:3-6 할 일: 클라이언트의 직접 DB 접근 제거 · API 라우트로 전환 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
audit|log.*admin → 0건) · 관리자 콘솔 ○ — 있음 (app/admin/page.tsx — 인증은 없지만 화면은 존재)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [2.4] 관리자 응답이 개인정보를 가리고, 열람·검색이 기록된다 지금 상태: 관리자 API ✕ — app/admin/page.tsx:15 buyer_name · buyer_phone 원문 표시 · 열람 감사 로그 ✕ — 없음 (검색: audit¦log.admin → 0건) · 관리자 콘솔 ○ — 있음 (app/admin/page.tsx — 인증은 없지만 화면은 존재) 관련 위치: app/admin/page.tsx, app/admin/page.tsx:15 할 일: 개인정보 마스킹 (전화 뒷자리) · 열람 로그 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
upload|storage|bucket|S3|blob → 0건 · 00-map.md:15)signInWithOAuth({ provider: 'kakao' }) · 비밀번호 필드·해시·저장 코드 전무)Secure · HttpOnly · SameSite · Domain 없음, 파기·정지가 요청마다 즉시 반영미확인차단signOut|logout|로그아웃 → 0건) · ? 세션 파기·재설정 로직 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [3.2] 세션 쿠키 Secure · HttpOnly · SameSite · Domain 없음, 파기·정지가 요청마다 즉시 반영 지금 상태: ? Supabase SDK 기본값에 의존 — 쿠키 설정 코드 없음 (lib/supabase.ts:3-5 createClient 호출만, 세션 관리·로그아웃 구현 전무) · ? 로그아웃 경로 없음 (검색: signOut¦logout¦로그아웃 → 0건) · ? 세션 파기·재설정 로직 없음 관련 위치: lib/supabase.ts:3-5 할 일: Supabase Auth 쿠키 설정 확인 + 로그아웃 경로 구현 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
reset|forgot|recovery|토큰|OTP|code → 0건)getSession|getUser|auth().user 호출 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [3.4] 운영에서 실제로 동작하는 가입·로그인 경로가 하나 이상 있다 지금 상태: ✕ 경로는 있으나(app/login/page.tsx:8 카카오 OAuth) 공급자 연결 확인 불가 — Supabase 콘솔 설정에서만 확인됨 (코드에 공급자 연결 상태 없음 · .env.example의 SUPABASE_URL/ANON_KEY 예시값) · ✕ 로그인 후 세션 확인 코드 없음 (앱 전체에 getSession¦getUser¦auth().user 호출 0건) 관련 위치: SUPABASE_URL/ANON_KEY, app/login/page.tsx:8 할 일: Supabase 콘솔에서 카카오 OAuth 공급자 연결 확인 + 세션 확인 코드 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
lock|locked|attempts|failed.*login → 0건) · ✕ 잠금 해제 경로 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [3.5] 모든 역할(고객 · 판매자 · 직원 · 관리자)에 비밀번호 복구와 계정 잠금 경로가 닫혀 있다 지금 상태: — 비밀번호 복구 (OAuth 전용, 해당 없음) · ✕ 계정 잠금 전무 (검색: lock¦locked¦attempts¦failed.login → 0건) · ✕ 잠금 해제 경로 없음 할 일: 로그인 시도 횟수 제한 + 잠금 구현 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
TOTP|totp|authenticator|2fa|twoFactor → 0건) · ✕ 잠금 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [3.6] 관리자 로그인은 2단계(TOTP) + 잠금, 등록·복구·해제가 운영 환경에서 실행 가능 지금 상태: ✕ 관리자 콘솔 있음 (app/admin/page.tsx:5 "사장님 화면 — 메뉴에는 안 보이게 해 둠") · ✕ 인증 전무 (app/admin/page.tsx:6-8 세션 확인·권한 검사 없이 바로 orders 조회) · ✕ 2단계 인증 없음 (검색: TOTP¦totp¦authenticator¦2fa¦twoFactor → 0건) · ✕ 잠금 없음 관련 위치: app/admin/page.tsx:5, app/admin/page.tsx:6-8 할 일: 관리자 세션 확인 + 역할 검사 + TOTP 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
zod|yup|joi|class-validator|pydantic → 0건) · ✕ API 입력 무검증 (app/api/checkout/confirm/route.ts:4 req.json() 결과를 바로 구조분해, 스키마 없음) · ✕ 웹훅 입력 무검증 (app/api/webhooks/toss/route.ts:4 req.json() 바로 사용) · ✕ 클라이언트 입력 무검증 (app/classes/page.tsx:11-12 prompt() 결과를 ! 로만 처리)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [4.1] 모든 쓰기 입력(body · param · query · header)이 스키마/파서를 거치고, 모르는 필드는 거부 지금 상태: ✕ 입력 검증 라이브러리 없음 (검색: zod¦yup¦joi¦class-validator¦pydantic → 0건) · ✕ API 입력 무검증 (app/api/checkout/confirm/route.ts:4 req.json() 결과를 바로 구조분해, 스키마 없음) · ✕ 웹훅 입력 무검증 (app/api/webhooks/toss/route.ts:4 req.json() 바로 사용) · ✕ 클라이언트 입력 무검증 (app/classes/page.tsx:11-12 prompt() 결과를 ! 로만 처리) 관련 위치: app/api/checkout/confirm/route.ts:4, app/api/webhooks/toss/route.ts:4, app/classes/page.tsx:11-12 할 일: zod 등 스키마 라이브러리 추가 + 모든 API 경로에 검증 적용 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
amount 를 req.json()에서 받아 토스로 그대로 전달 · 0/음수/상한 검사 없음) · ✕ 서버 금액 재계산 없음 (app/pay/success/page.tsx:11 클라이언트가 보낸 amount 를 그대로 confirm API 로 전달 · classes 테이블 price 와 대조 안 함) · ✕ DB 제약 없음 (supabase/migrations/001_init.sql:4·15 price·amount 필드가 int not null 만, CHECK 제약 없음 — 음수 허용) · ○ 소수 가드 (001_init.sql:4·15 int 타입)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [4.2] 수량·금액 경계 — 0 · 음수 · 소수 · 상한 · 합계 오버플로 지금 상태: ✕ 금액 검증 없음 (app/api/checkout/confirm/route.ts:4 amount 를 req.json()에서 받아 토스로 그대로 전달 · 0/음수/상한 검사 없음) · ✕ 서버 금액 재계산 없음 (app/pay/success/page.tsx:11 클라이언트가 보낸 amount 를 그대로 confirm API 로 전달 · classes 테이블 price 와 대조 안 함) · ✕ DB 제약 없음 (supabase/migrations/001_init.sql:4·15 price·amount 필드가 int not null 만, CHECK 제약 없음 — 음수 허용) · ○ 소수 가드 (001_init.sql:4·15 int 타입) 관련 위치: app/api/checkout/confirm/route.ts:4, app/pay/success/page.tsx:11, supabase/migrations/001_init.sql:4 할 일: API 에서 classes.price 조회해 금액 대조 + 0/음수 거부 + DB CHECK 제약 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
dangerouslySetInnerHTML|innerHTML|eval|new Function → 0건) · ○ SQL 주입 없음 (Supabase 클라이언트 쿼리 빌더만 사용 · app/api/checkout/confirm/route.ts:17 .update({ status: 'PAID', payment_key: paymentKey }).eq('id', orderId) — 파라미터 바인딩) · ○ 템플릿 보간 상수만 (app/classes/page.tsx:23-24 ${location.origin} 브라우저 내장 객체)upload|multer|formidable|multipart|storage → 0건)orderId 를 req.json()에서 받아 .eq('id', orderId) 로 바로 사용 · UUID 형식 검증 없음) · ✕ NUL/제어문자 가드 없음 (전체 코드에 입력 정제 로직 없음) · — 프록시 없음 (middleware.ts·nginx·Caddy 설정 전무 · 00-map.md:26 "프록시/엣지: 없음")출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[4.5] 비정상 입력(잘못된 id · 토큰 · NUL · 거대 본문)이 500 이 아니라 400 이고, 프록시 본문 상한이 API 상한과 맞는다
지금 상태: ✕ id 파싱 검증 없음 (app/api/checkout/confirm/route.ts:4 orderId 를 req.json()에서 받아 .eq('id', orderId) 로 바로 사용 · UUID 형식 검증 없음) · ✕ NUL/제어문자 가드 없음 (전체 코드에 입력 정제 로직 없음) · — 프록시 없음 (middleware.ts·nginx·Caddy 설정 전무 · 00-map.md:26 "프록시/엣지: 없음")
관련 위치: app/api/checkout/confirm/route.ts:4
할 일: 입력 스키마에 UUID 검증 추가 + 문자열 정제
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.https://api.tosspayments.com/v1/payments/confirm — 토스페이먼츠로 선정됨<br>• .env.example:3-4 test_ck_ · test_sk_ — 테스트 키만 예시로 제공<br>• 계약·심사 상태 기록 문서 없음 (검색: `docsprocess.env.NEXT_PUBLIC_TOSS_SECRET_KEY — 키 검증 없음, test_ 접두사 확인 없음<br>• app/classes/page.tsx:16 process.env.NEXT_PUBLIC_TOSS_CLIENT_KEY — 클라이언트 키도 검증 없음<br>• 부팅 시 키 검증 코드 없음 (검색: startsWith.*test_|NODE_ENV.*production → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [5.2] 테스트/목 결제는 운영에서 막혀 있다 지금 상태: ✕ 운영 키 검증 · ✕ 테스트 모드 거부 • app/api/checkout/confirm/route.ts:10 process.env.NEXT_PUBLIC_TOSS_SECRET_KEY — 키 검증 없음, test_ 접두사 확인 없음 • app/classes/page.tsx:16 process.env.NEXT_PUBLIC_TOSS_CLIENT_KEY — 클라이언트 키도 검증 없음 • 부팅 시 키 검증 코드 없음 (검색: startsWith.test_¦NODE_ENV.production → 0건) 관련 위치: app/api/checkout/confirm/route.ts:10, app/classes/page.tsx:16 할 일: 부팅 시 운영 환경이면 test_ 키 거부·테스트 모드 표시 제거 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
amount 파라미터를 PG 에 그대로 전달 — 서버 재계산 없음<br>• app/api/checkout/confirm/route.ts:17 .update({ status: 'PAID' }).eq('id', orderId) — WHERE status 조건 없음, 중복 호출 시 덮어씀<br>• supabase/migrations/001_init.sql — CHECK 제약 없음 (검색: CHECK|CONSTRAINT → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[5.3] 승인 멱등성 · 금액 검증 · 상태 머신
지금 상태: ✕ 멱등 · ✕ 금액 검증 · ✕ 상태 머신 • app/api/checkout/confirm/route.ts:4 amount 파라미터를 PG 에 그대로 전달 — 서버 재계산 없음 • app/api/checkout/confirm/route.ts:17 .update({ status: 'PAID' }).eq('id', orderId) — WHERE status 조건 없음, 중복 호출 시 덮어씀 • supabase/migrations/001_init.sql — CHECK 제약 없음 (검색: CHECK¦CONSTRAINT → 0건)
관련 위치: app/api/checkout/confirm/route.ts:17, app/api/checkout/confirm/route.ts:4, supabase/migrations/001_init.sql
할 일: 주문 조회·금액 재계산·비교 · UPDATE WHERE status='PENDING' · CHECK (status IN …)
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.await req.json() — 서명 검증 없음, PG 재조회 없음 (검색: signature|verify|fetch.*payments → 0건)<br>• app/api/webhooks/toss/route.ts:6 .update({ status: body.data.status }) — 이벤트 id 저장 없음, 중복 수신 시 덮어씀<br>• 순서 역전 분기 없음 (검색: eventType|event.*id|webhook.*log → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[5.4] 웹훅 서명 검증 · 중복 방지 · 순서 역전
지금 상태: ✕ 서명 검증 · ✕ 중복 방지 · ✕ 순서 역전 • app/api/webhooks/toss/route.ts:4 await req.json() — 서명 검증 없음, PG 재조회 없음 (검색: signature¦verify¦fetch.payments → 0건) • app/api/webhooks/toss/route.ts:6 .update({ status: body.data.status }) — 이벤트 id 저장 없음, 중복 수신 시 덮어씀 • 순서 역전 분기 없음 (검색: eventType¦event.id¦webhook.log → 0건)
관련 위치: app/api/webhooks/toss/route.ts:4, app/api/webhooks/toss/route.ts:6
할 일: 토스 서명 검증 또는 paymentKey 로 PG 재조회 · 이벤트 id 유니크 저장 · 상태 전이 조건
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.GET.*payments|fetch.*payments.*key → confirm 만 있음, GET 없음)<br>• 잡·큐 없음 (검색: cron|schedule|queue|job|worker → 0건)<br>• 운영자 알림 없음 (검색: alert|notify|mail|send → ADMIN_EMAIL 변수만, 발송 코드 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [5.5] 고객이 돌아오지 않을 때 끝낼 주체 지금 상태: ✕ PG 조회 · ✕ 대사 작업 · ✕ 알림 • PG 조회 API 없음 (검색: GET.payments¦fetch.payments.key → confirm 만 있음, GET 없음) • 잡·큐 없음 (검색: cron¦schedule¦queue¦job¦worker → 0건) • 운영자 알림 없음 (검색: alert¦notify¦mail¦send → ADMIN_EMAIL 변수만, 발송 코드 없음) 할 일: PENDING 30분 이상 주문 조회·PG 재조회·상태 동기화 cron · 슬랙·메일 알림 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
if (!res.ok) return Response.json({ ok: false }) — 실패 응답은 있음<br>• app/pay/success/page.tsx:12 j.ok ? '결제 완료!' : '결제 실패' — 실패 메시지 있음<br>• 중복 클릭 방지 없음 (검색: disabled|pending|loading → 0건) · 주문 유니크 제약 없음 (001_init.sql — payment_key 유니크 없음)<br>• e2e 없음 (검색: e2e|test|spec|cypress|playwright → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[5.6] 결제 실패 경로와 실 PG e2e
지금 상태: ✕ 실패 분기 ○ · ✕ 중복 방지 · ✕ e2e • app/api/checkout/confirm/route.ts:15 if (!res.ok) return Response.json({ ok: false }) — 실패 응답은 있음 • app/pay/success/page.tsx:12 j.ok ? '결제 완료!' : '결제 실패' — 실패 메시지 있음 • 중복 클릭 방지 없음 (검색: disabled¦pending¦loading → 0건) · 주문 유니크 제약 없음 (001_init.sql — payment_key 유니크 없음) • e2e 없음 (검색: e2e¦test¦spec¦cypress¦playwright → 0건)
관련 위치: app/api/checkout/confirm/route.ts:15, app/pay/success/page.tsx:12
할 일: 버튼 비활성·payment_key 유니크 · 토스 테스트 모드 e2e (성공·실패·취소)
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.refund|cancel|환불|취소 → 0건)<br>• 약관 없음 (app/login/page.tsx:9 <a href="#">이용약관</a> — href="#", 실제 파일 없음)<br>• 결제 전 고지 없음 (app/classes/page.tsx — 결제 전 동의·고지 화면 없음, prompt() 후 바로 결제)<br>• 규정·약관·고지 셋 모두 부재출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [5.7] 취소·환불 규정 확정 및 코드·약관·고지 일치 지금 상태: ✕ 환불 규정 · ✕ 약관 · ✕ 결제 전 고지 • 환불 코드 없음 (검색: refund¦cancel¦환불¦취소 → 0건) • 약관 없음 (app/login/page.tsx:9 <a href="#">이용약관</a> — href="#", 실제 파일 없음) • 결제 전 고지 없음 (app/classes/page.tsx — 결제 전 동의·고지 화면 없음, prompt() 후 바로 결제) • 규정·약관·고지 셋 모두 부재 관련 위치: app/classes/page.tsx, app/login/page.tsx:9 할 일: 환불 규정 확정 → 함수·약관·결제 전 고지 문안 작성 및 동의 체크 · 주문 행에 버전 기록 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
refund|cancel|환불 → 0건)<br>• PG 취소 호출 없음 (검색: cancel|refund → 0건)<br>• 환불 상태·큐 없음 (001_init.sql — status 열에 REFUND 언급 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [5.8] 환불 실행 — 부분·재시도·알림 지금 상태: ✕ 환불 코드 · ✕ 부분 환불 · ✕ 재시도 • 환불 코드 없음 (검색: refund¦cancel¦환불 → 0건) • PG 취소 호출 없음 (검색: cancel¦refund → 0건) • 환불 상태·큐 없음 (001_init.sql — status 열에 REFUND 언급 없음) 할 일: 토스 취소 API 호출 (트랜잭션 밖) · 부분 환불 지원 · 실패 시 재시도 큐·알림 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
.select('*') — 취소·환불 쓰기 라우트 없음)<br>• 취소·환불 API 없음 (app/api — checkout/confirm · webhooks/toss 만, cancel 엔드포인트 없음)<br>• 배상 조항 없음 (약관 파일 자체가 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[5.9] 판매자 측 취소·배상 규정·행위자 권한
지금 상태: ✕ 판매자·운영자 취소 · ✕ 배상 규정 • 관리자 화면 읽기만 (app/admin/page.tsx:8 .select('') — 취소·환불 쓰기 라우트 없음) • 취소·환불 API 없음 (app/api — checkout/confirm · webhooks/toss 만, cancel 엔드포인트 없음) • 배상 조항 없음 (약관 파일 자체가 없음)
관련 위치: app/admin/page.tsx:8, app/api, checkout/confirm, webhooks/toss
할 일: 관리자 취소·환불 API · 일괄 환불 기능 · 약관에 배상 조항 추가
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.영수증|receipt|매출전표 → 0건)<br>• 환불 소요 문구 없음 (검색: 소요|영업일|refund.*time → 0건)<br>• 주문 내역 화면 없음 (app/pay/success/page.tsx:12 "마이페이지" 언급 — 실제 페이지 없음, 검색: mypage|마이페이지 → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [5.10] 영수증 링크 · 환불 소요 고지 · 내역 조회 지금 상태: ✕ 영수증 · ✕ 소요 고지 · ✕ 내역 조회 • 영수증 링크 없음 (검색: 영수증¦receipt¦매출전표 → 0건) • 환불 소요 문구 없음 (검색: 소요¦영업일¦refund.time → 0건) • 주문 내역 화면 없음 (app/pay/success/page.tsx:12 "마이페이지" 언급 — 실제 페이지 없음, 검색: mypage¦마이페이지 → 0건) 관련 위치: app/pay/success/page.tsx:12 할 일: 마이페이지 생성 · 주문 내역·영수증 링크 (토스 receiptUrl) · 환불 시 소요 시간 고지 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
.insert())<br>[5.11-c] 검색 worker|cron|cleanup|expire|ttl → 0건 — 만료 정리 없음, 이 서비스엔 선점 개념 없음(장바구니·hold 없음) — 해당없음 —<br>[5.11-d] 검색 k6|locust|artillery|describe|it\( → 0건 — 동시성 spec 없음seats > 0 WHERE 조건부 UPDATE 로 변경 · 동시성 테스트 작성출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [5.11] 동시성 — DB 가 최종 방어선(부분 유니크 · EXCLUDE · CHECK), 판정은 잠금 아래 한 문장, 만료 선점이 자정(自淨)된다 지금 상태: 제약 ✕ · 잠금 ✕ · 만료 정리 — · 동시성 spec ✕ · 부하 ③ [5.11-a] supabase/migrations/001_init.sql:1-19 — UNIQUE/EXCLUDE/CHECK 제약 없음 (검색 → 0건) [5.11-b] app/classes/page.tsx:13-15 — INSERT 에 조건부 WHERE · FOR UPDATE · ON CONFLICT 없음, 트랜잭션 없음 (단순 .insert()) [5.11-c] 검색 worker¦cron¦cleanup¦expire¦ttl → 0건 — 만료 정리 없음, 이 서비스엔 선점 개념 없음(장바구니·hold 없음) — 해당없음 — [5.11-d] 검색 k6¦locust¦artillery¦describe¦it\( → 0건 — 동시성 spec 관련 위치: UNIQUE/EXCLUDE/CHECK, app/classes/page.tsx:13-15, supabase/migrations/001_init.sql:1-19 할 일: 재고(seats) 감소 시 DB 제약(CHECK seats >= 0) 추가 · 주문 INSERT 를 seats > 0 WHERE 조건부 UPDATE 로 변경 · 동시성 테스트 작성 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
rate.?limit|middleware → 0건 — 프록시/미들웨어 설정 없음<br>[5.12-b] supabase/migrations/001_init.sql:9-19 — orders 테이블에 사용자당 활성 선점 제약 없음<br>[5.12-c] 이 서비스엔 좌석 등급·티켓 종류가 없음 (classes.seats 는 총 정원 1개뿐) — 해당없음 —출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [5.12] 쓰기 경로(선점·주문) 레이트 리밋 + 사용자당 동시 보유 상한 + 정원형은 등급별 정원 지금 상태: 레이트 리밋 ✕ · 사용자당 상한 ✕ · 등급별 정원 — [5.12-a] 검색 rate.?limit¦middleware → 0건 — 프록시/미들웨어 설정 없음 [5.12-b] supabase/migrations/001_init.sql:9-19 — orders 테이블에 사용자당 활성 선점 제약 없음 [5.12-c] 이 서비스엔 좌석 등급·티켓 종류가 없음 (classes.seats 는 총 정원 1개뿐) — 해당없음 — 관련 위치: supabase/migrations/001_init.sql:9-19 할 일: API Routes 에 rate limit 미들웨어 추가 · 사용자당 활성 주문 수 제약 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
Dockerfile|vercel.json|fly.toml|render.yaml|Procfile → 0건) · ✕ TLS/HSTS/리다이렉트 설정 없음 (middleware.ts 없음) · ✕ 스테이징 결정 기록 없음 (docs 디렉터리 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [6.1] 프로덕션 환경이 실제로 있다 지금 상태: ✕ 배포 대상 선언 없음 (검색: Dockerfile¦vercel.json¦fly.toml¦render.yaml¦Procfile → 0건) · ✕ TLS/HSTS/리다이렉트 설정 없음 (middleware.ts 없음) · ✕ 스테이징 결정 기록 없음 (docs 디렉터리 없음) 관련 위치: TLS/HSTS 할 일: 배포 플랫폼 선택 및 설정 파일 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
Dockerfile → 0건) · ✕ .dockerignore 없음 (ls → 없음) · ○ package.json:4 scripts.build: "next build" 존재출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [6.2] 배포 재현성 지금 상태: ✕ Dockerfile/빌드 스크립트 없음 (검색: Dockerfile → 0건) · ✕ .dockerignore 없음 (ls → 없음) · ○ package.json:4 scripts.build: "next build" 존재 할 일: Dockerfile 또는 플랫폼 빌드 설정 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
.github/workflows 디렉터리 없음) · ✕ 시드 동기화 없음 (검색: seed → 0건) · ✕ 헬스체크 없음 (검색: health|liveness|readiness → 0건) · ✕ 롤백 절차 없음 (README.md:11-17 개발 실행만)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [6.3] 배포 절차 — 마이그레이션 · 시드 · 헬스 · 롤백 지금 상태: ✕ 워크플로/스크립트 없음 (.github/workflows 디렉터리 없음) · ✕ 시드 동기화 없음 (검색: seed → 0건) · ✕ 헬스체크 없음 (검색: health¦liveness¦readiness → 0건) · ✕ 롤백 절차 없음 (README.md:11-17 개발 실행만) 관련 위치: .github/workflows 할 일: 배포 워크플로 및 절차 문서 작성 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
.env.example 에 있음 (lib/supabase.ts:4-5 · app/api/checkout/confirm/route.ts:10 · app/classes/page.tsx:16 · .env.example:1-5) · ✕ 배포 설정 없음 (compose/플랫폼 변수 파일 없음) · ✕ 대조 spec 없음 (검색: *.test.*|*.spec.* → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [6.4] 환경변수 — 코드 ↔ 예시 ↔ 배포 설정 지금 상태: ○ 코드가 읽는 5개 키 전부 .env.example 에 있음 (lib/supabase.ts:4-5 · app/api/checkout/confirm/route.ts:10 · app/classes/page.tsx:16 · .env.example:1-5) · ✕ 배포 설정 없음 (compose/플랫폼 변수 파일 없음) · ✕ 대조 spec 없음 (검색: .test.¦.spec. → 0건) 관련 위치: app/api/checkout/confirm/route.ts:10, app/classes/page.tsx:16, lib/supabase.ts:4-5 할 일: 배포 설정 추가 및 환경변수 대조 테스트 작성 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
test_ck_xxxxxxxx · test_sk_xxxxxxxx (테스트 접두사) · ✕ .env.example:5 owner@example.com (예시값) · ✕ 결정 기록 없음 (검색: ADR|설계|결정 → 0건) · ✕ 세션 TTL · 보유 기간 · 수수료 설정 없음 (검색 → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [6.5] 정책값이 결정값이다 지금 상태: ✕ .env.example:3-4 토스 키가 test_ck_xxxxxxxx · test_sk_xxxxxxxx (테스트 접두사) · ✕ .env.example:5 owner@example.com (예시값) · ✕ 결정 기록 없음 (검색: ADR¦설계¦결정 → 0건) · ✕ 세션 TTL · 보유 기간 · 수수료 설정 없음 (검색 → 0건) 할 일: 프로덕션 값 결정 및 .env.example 갱신 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
NEXT_PUBLIC_SUPABASE_URL 만) · ✕ DB ssl 옵션 명시 없음 (Supabase SDK 기본값 확인 불가) · — 큐/캐시 없음 (검색: redis|queue → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [6.6] 국내 리전 · DB 암호화 · 큐/캐시 인증 지금 상태: ✕ 리전 설정 없음 (Supabase 클라이언트는 URL 기반 — lib/supabase.ts:4 NEXT_PUBLIC_SUPABASE_URL 만) · ✕ DB ssl 옵션 명시 없음 (Supabase SDK 기본값 확인 불가) · — 큐/캐시 없음 (검색: redis¦queue → 0건) 관련 위치: lib/supabase.ts:4 할 일: Supabase 프로젝트 리전 확인 및 SSL 명시 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
seed → 0건 — 환경 가드도 없음) · ✕ 목 게이트웨이 부팅 거부 없음 (.env.example:3-4 test_ 키가 기본값 — 환경 검사 없음) · — API 문서 UI 없음 (검색: swagger|graphql → 0건) · ✕ 관리자 경로 무인증 (app/admin/page.tsx:5 주석 "메뉴에는 안 보이게 해 둠" — URL 직접 접근 가능)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [6.7] 개발 시드 · 목 결제 · 디버그 도구 프로덕션 거부 지금 상태: ✕ 시드 스크립트 없음 (검색: seed → 0건 — 환경 가드도 없음) · ✕ 목 게이트웨이 부팅 거부 없음 (.env.example:3-4 test_ 키가 기본값 — 환경 검사 없음) · — API 문서 UI 없음 (검색: swagger¦graphql → 0건) · ✕ 관리자 경로 무인증 (app/admin/page.tsx:5 주석 "메뉴에는 안 보이게 해 둠" — URL 직접 접근 가능) 관련 위치: app/admin/page.tsx:5 할 일: 환경 가드 추가 (test_ 키 거부, 관리자 인증) 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
error.tsx 없음 — 검색: error.tsx → 0건) · ✕ 요청 id 미들웨어 없음 (검색: requestId|request_id|correlation → 0건) · ✕ 에러 응답 구성 없음 (app/api/checkout/confirm/route.ts:15 !res.ok 시 {ok: false} 만 — 메시지 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[7.1] 5xx 응답에 스택 없음 + 전역 필터 + 요청 id
지금 상태: ✕ 전역 예외 필터 없음 (Next.js App Router error.tsx 없음 — 검색: error.tsx → 0건) · ✕ 요청 id 미들웨어 없음 (검색: requestId¦request_id¦correlation → 0건) · ✕ 에러 응답 구성 없음 (app/api/checkout/confirm/route.ts:15 !res.ok 시 {ok: false} 만 — 메시지 없음)
관련 위치: app/api/checkout/confirm/route.ts:15
할 일: 전역 error.tsx · 요청 id 미들웨어 · 5xx 필터 추가
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.error.tsx · not-found.tsx · loading.tsx 없음 (검색 → 0건) · ○ 빈 상태 있음 (app/classes/page.tsx:31 classes.map — 빈 배열이면 안 보임) · ✕ 실패 안내 부족 (app/pay/success/page.tsx:12 "결제 실패" 만 — 다음 행동 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [7.2] 화면 — 루트 error/not-found/loading, 빈 상태, 실패 안내 지금 상태: ✕ 루트 error.tsx · not-found.tsx · loading.tsx 없음 (검색 → 0건) · ○ 빈 상태 있음 (app/classes/page.tsx:31 classes.map — 빈 배열이면 안 보임) · ✕ 실패 안내 부족 (app/pay/success/page.tsx:12 "결제 실패" 만 — 다음 행동 없음) 관련 위치: app/classes/page.tsx:31, app/pay/success/page.tsx:12 할 일: 루트 error.tsx · 결제 실패 안내 개선 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
fetch — timeout/AbortSignal 없음) · ✕ 재시도 정책 없음 (검색: retry|attempts → 0건) · ✕ 멱등 키 없음 (route.ts:7-14 paymentKey · orderId 는 토스가 생성 — 재시도 시 중복 가능)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [7.3] 외부 호출 타임아웃 · 재시도 지금 상태: ✕ 토스 confirm API 타임아웃 없음 (app/api/checkout/confirm/route.ts:7 fetch — timeout/AbortSignal 없음) · ✕ 재시도 정책 없음 (검색: retry¦attempts → 0건) · ✕ 멱등 키 없음 (route.ts:7-14 paymentKey · orderId 는 토스가 생성 — 재시도 시 중복 가능) 관련 위치: app/api/checkout/confirm/route.ts:7, timeout/AbortSignal 할 일: fetch 타임아웃 추가 (PG 필수) 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
queue|job|worker|cron|schedule → 0건).github/workflows 디렉터리 없음) · ✕ 자동 검증 없음 (검색: *.test.*|*.spec.* → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [8.1] 머지된 코드 자동 검증 · CI 분 예산 지금 상태: ✕ 워크플로 없음 (.github/workflows 디렉터리 없음) · ✕ 자동 검증 없음 (검색: .test.¦.spec. → 0건) 관련 위치: .github/workflows 할 일: GitHub Actions 워크플로 추가 (빌드 · 테스트) 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
*.test.*|*.spec.* → 0건) · ✕ 결제 테스트 없음 (app/api/checkout/confirm/route.ts:7 토스 confirm — 테스트 없음) · — 환불 없음 (검색: refund|환불 → 0건) · ✕ 동시성 테스트 없음 (supabase/migrations/001_init.sql:6 seats — 감소 로직 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [8.2] 결제 · 환불 · 동시성 통합 테스트 + e2e 지금 상태: ✕ spec 파일 없음 (검색: .test.¦.spec. → 0건) · ✕ 결제 테스트 없음 (app/api/checkout/confirm/route.ts:7 토스 confirm — 테스트 없음) · — 환불 없음 (검색: refund¦환불 → 0건) · ✕ 동시성 테스트 없음 (supabase/migrations/001_init.sql:6 seats — 감소 로직 없음) 관련 위치: app/api/checkout/confirm/route.ts:7, supabase/migrations/001_init.sql:6 할 일: 결제 · 재고 통합 테스트 작성 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
.github/dependabot.yml|renovate.json → 0건) · ✕ lockfile 없음 (ls → package-lock.json · yarn.lock · pnpm-lock.yaml 전부 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [8.3] 의존성 취약점 — 주기 감사 + 보안 알림 지금 상태: ✕ audit 단계 없음 (워크플로 없음) · ✕ Dependabot/Renovate 설정 없음 (검색: .github/dependabot.yml¦renovate.json → 0건) · ✕ lockfile 없음 (ls → package-lock.json · yarn.lock · pnpm-lock.yaml 전부 없음) 관련 위치: .github/dependabot.yml, Dependabot/Renovate 할 일: Dependabot 설정 · npm ci 위한 lockfile 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
jest.config|vitest.config → 0건) · ✕ spec 없음 (검색: *.test.*|*.spec.* → 0건) · ✕ 커버리지 설정 없음 (package.json:4 scripts 에 test 명령 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [8.4] 새 spec 자동 실행 + 커버리지 지금 상태: ✕ 테스트 러너 설정 없음 (검색: jest.config¦vitest.config → 0건) · ✕ spec 없음 (검색: .test.¦.spec. → 0건) · ✕ 커버리지 설정 없음 (package.json:4 scripts 에 test 명령 없음) 할 일: 테스트 러너 설정 · 커버리지 설정 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
k6|locust|artillery|siege|loadtest → 0건 — 부하 측정 스크립트/기록 없음<br>[9.1-b] 검색 log_min_duration|slow.?query|maxQueryExecutionTime → 0건 — 느린 쿼리 로그 설정 없음<br>[9.1-c] 검색 pool.*size|timeout|semaphore → 0건 — 세마포어/타임아웃/풀 크기 설정 없음 (Supabase 클라이언트 기본값)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [9.1] 피크 부하 1회 측정(p95 · 에러율 · BUSY 비율) + 느린 쿼리 로그 지금 상태: 측정 ✕ · 느린 쿼리 로그 ✕ · 임계값 근거 ✕ · 관리형 DB 파라미터 ③ [9.1-a] 검색 k6¦locust¦artillery¦siege¦loadtest → 0건 — 부하 측정 스크립트/기록 없음 [9.1-b] 검색 log_min_duration¦slow.?query¦maxQueryExecutionTime → 0건 — 느린 쿼리 로그 설정 없음 [9.1-c] 검색 pool.size¦timeout¦semaphore → 0건 — 세마포어/타임아웃/풀 크기 설정 없음 (Supabase 클라이언트 기본값) 할 일: 부하 테스트 도구로 피크 측정 실행 · Supabase 대시보드에서 느린 쿼리 로그 활성화 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
.select('*').order('created_at') 루프 안 쿼리 없음, lazy relation 없음 — N+1 없음 ○<br>[9.2-b] supabase/migrations/001_init.sql:11 — class_id int references classes(id) FK 있음, 검색 CREATE INDEX → 0건 — FK 열 인덱스 없음<br>[9.2-c] app/admin/page.tsx:8 ORDER BY created_at — created_at 인덱스 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[9.2] 목록 질의 수가 행 수에 비례하지 않고(N+1 없음), FK·조회 조건에 인덱스
지금 상태: N+1 ○ · FK 인덱스 ✕ [9.2-a] app/admin/page.tsx:8 — .select('').order('created_at') 루프 안 쿼리 없음, lazy relation 없음 — N+1 없음 ○ [9.2-b] supabase/migrations/001_init.sql:11 — class_id int references classes(id) FK 있음, 검색 CREATE INDEX → 0건 — FK 열 인덱스 없음 [9.2-c] app/admin/page.tsx:8 ORDER BY created_at — created_at 인덱스 없음
관련 위치: app/admin/page.tsx:8, supabase/migrations/001_init.sql:11
할 일: orders(class_id) · orders(created_at) 인덱스 추가
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.Cache-Control|revalidate|ISR → 0건 — 캐시 헤더 설정 없음<br>[9.3-b] 검색 rate.?limit|middleware → 0건 — catch-all rate limit 없음 (5.12 와 중복)<br>[9.3-c] 검색 next/image|cdn|cloudfront|signed.*url → 0건 — 이미지 업로드/표시 기능 없음 — 해당없음 —<br>[9.3-d] 검색 redis|queue|bull → 0건 — 큐 없음 — 해당없음 —출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [9.3] 공개 조회 캐싱 · 일반 API 레이트 리밋 · 이미지 파생본/CDN · 큐 메모리 상한 지금 상태: 캐싱 ✕ · 레이트 리밋 ✕ · 이미지 — · 큐 — [9.3-a] 검색 Cache-Control¦revalidate¦ISR → 0건 — 캐시 헤더 설정 없음 [9.3-b] 검색 rate.?limit¦middleware → 0건 — catch-all rate limit 없음 (5.12 와 중복) [9.3-c] 검색 next/image¦cdn¦cloudfront¦signed.url → 0건 — 이미지 업로드/표시 기능 없음 — 해당없음 — [9.3-d] 검색 redis¦queue¦bull → 0건 — 큐 없음 — 해당없음 — 관련 위치: next/image 할 일: 공개 GET (app/classes/page.tsx) 에 revalidate 설정 추가 · API rate limit 미들웨어 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
ADR|설계 → 0건) · ○ 테이블명 classes · orders (supabase/migrations/001_init.sql:1,9 — 원데이 클래스 업종에 고착, 확장 예정 없음 → README.md:1 "샘플용 가상 앱" 명시)any 0(결제·주문) · 중복 컴포넌트문제후순위any 3건 (app/classes/page.tsx:7 any[] · :10 c: any · app/admin/page.tsx:7 any[]) · ○ @ts-ignore 없음 (검색 → 0건) · — 중복 컴포넌트 없음 (앱 1개)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [10.2] 미사용 의존성 0 · any 0(결제·주문) · 중복 컴포넌트 지금 상태: ○ 의존성 4개 전부 사용 (package.json:5-10 next · react · supabase · tosspayments 전부 import 있음) · ✕ 결제·주문 모듈 any 3건 (app/classes/page.tsx:7 any[] · :10 c: any · app/admin/page.tsx:7 any[]) · ○ @ts-ignore 없음 (검색 → 0건) · — 중복 컴포넌트 없음 (앱 1개) 관련 위치: app/admin/page.tsx:7, app/classes/page.tsx:7 할 일: 결제·주문 타입 정의 (Order · Class 인터페이스) 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
cp .env.example .env.local → npm install → npm run dev ↔ package.json:4 scripts.dev: "next dev" 일치 · ○ 상태 표 없음 (README 에 "상태 표" 없음) · ✕ "목업/준비 중" 서술 문제 (app/pay/success/page.tsx:12 "마이페이지에서 예약 코드를 확인하세요" — 실제 마이페이지 없음, 검색: app/my|app/profile → 0건) · ✕ AI 규칙 파일 없음 (검색: CLAUDE.md|AGENTS.md|.cursorrules → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [10.3] README · AI 규칙 파일이 코드와 맞는다 지금 상태: ○ README.md:14-16 기동 순서 cp .env.example .env.local → npm install → npm run dev ↔ package.json:4 scripts.dev: "next dev" 일치 · ○ 상태 표 없음 (README 에 "상태 표" 없음) · ✕ "목업/준비 중" 서술 문제 (app/pay/success/page.tsx:12 "마이페이지에서 예약 코드를 확인하세요" — 실제 마이페이지 없음, 검색: app/my¦app/profile → 0건) · ✕ AI 규칙 파일 없음 (검색: CLAUDE.md¦AGENTS.md¦.cursorrules → 0건) 관련 위치: app/my, app/pay/success/page.tsx:12, app/profile 할 일: 마이페이지 구현 또는 안내 수정 · AI 규칙 파일 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
sentry|@sentry|bugsnag|rollbar → 0건)<br>헬스체크: 없음 (검색: /health|/ping|/ready|healthcheck → 0건)<br>알림: 없음 (검색: slack|discord|webhook|notification|alert → 0건 — .env.example:5 ADMIN_EMAIL 변수명만 존재, 메일 발송 구현 없음)<br>실 발화 기록: 없음 (저장소 내 문서 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [11.1] 에러 추적(국외 이전 고지 포함) + 헬스체크가 DB·큐를 보고 공개 경로로 도달 + 알림 사슬이 1회 울렸다 지금 상태: 에러 추적 ✕ · 헬스체크 ✕ · 알림 ✕ · 실 발화 기록 ✕ 에러 추적: 없음 (검색: sentry¦@sentry¦bugsnag¦rollbar → 0건) 헬스체크: 없음 (검색: /health¦/ping¦/ready¦healthcheck → 0건) 알림: 없음 (검색: slack¦discord¦webhook¦notification¦alert → 0건 — .env.example:5 ADMIN_EMAIL 변수명만 존재, 메일 발송 구현 없음) 실 발화 기록: 없음 (저장소 내 문서 없음) 할 일: Sentry 류 SDK 추가 · /health 경로 생성 (Supabase 연결 확인) · 알림 연결 설정 · 테스트 발화 후 기록 문서화 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
backup|snapshot|restore|dump → 0건 · Supabase 플랫폼 자동 백업은 콘솔 설정이나 저장소에 보존일 언급 없음)<br>리허설 기록: 없음 (검색: runbook|procedure|operation|rehearsal → 0건)<br>롤백 명령: 없음 (supabase/migrations 에 up 만, down 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [11.2] 백업 보존일 + 복구 리허설 + 롤백 리허설(소요 시간 기록) 지금 상태: 백업 설정 ✕ · 복구 리허설 ✕ · 롤백 리허설 ✕ 백업 설정: 없음 (검색: backup¦snapshot¦restore¦dump → 0건 · Supabase 플랫폼 자동 백업은 콘솔 설정이나 저장소에 보존일 언급 없음) 리허설 기록: 없음 (검색: runbook¦procedure¦operation¦rehearsal → 0건) 롤백 명령: 없음 (supabase/migrations 에 up 만, down 없음) 관련 위치: supabase/migrations 할 일: Supabase 콘솔 백업 설정 확인 후 보존일 문서화 · DB 복구 리허설 수행 및 기록 · 마이그레이션 롤백 스크립트 작성 · 애플리케이션 이전 버전 배포 절차 문서화 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
budget|cost|billing|alarm → 0건)<br>스토리지 상한: 없음 (Supabase DB · 스토리지 사용 없음 — 00-map.md:16 확인, 설정 문서 없음)<br>CDN: 해당 없음 (객체 스토리지 미사용)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [11.3] 비용 상한 — 예산 알람(50/80/100%) · 스토리지 자동 확장 상한 · 공개 버킷 트래픽 앞단 지금 상태: 예산 알람 ✕ · 스토리지 상한 ✕ · CDN — 예산 알람: 없음 (검색: budget¦cost¦billing¦alarm → 0건) 스토리지 상한: 없음 (Supabase DB · 스토리지 사용 없음 — 00-map.md:16 확인, 설정 문서 없음) CDN: 해당 없음 (객체 스토리지 미사용) 할 일: Supabase 프로젝트 예산 알람 설정 (콘솔) · DB 용량 상한 정책 수립 · 설정값 문서화 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
log.*retention|winston|pino|bunyan|logging → 0건 · app/api/checkout/confirm/route.ts:5 console.log 1건만)<br>외부 감시: 없음 (검색: uptimerobot|pingdom|monitor → 0건)<br>런북: 없음 (검색: runbook|procedure → 0건 · README.md 개발 실행만)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [11.4] 로그 보존·검색 · 외부 가동 감시 · 장애 런북(결제 · 중복 판매 · DB 복구 · 시크릿 회전 · 관리자 잠금 해제) 지금 상태: 로그 보존 ✕ · 외부 감시 ✕ · 런북 ✕ 로그: 없음 (검색: log.retention¦winston¦pino¦bunyan¦logging → 0건 · app/api/checkout/confirm/route.ts:5 console.log 1건만) 외부 감시: 없음 (검색: uptimerobot¦pingdom¦monitor → 0건) 런북: 없음 (검색: runbook¦procedure → 0건 · README.md 개발 실행만) 관련 위치: app/api/checkout/confirm/route.ts:5 할 일: 로그 수집 설정 (Next.js 로깅 + 플랫폼 연동) · UptimeRobot 류 외부 감시 설정 · 결제/DB/시크릿/관리자 장애 런북 작성 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
scripts.dev/build/start 만)<br>관리 명령: 없음 (첫 관리자 생성 스크립트 · 잠금 해제 · 카탈로그 동기화 코드 전무)<br>절차 문서: 없음 (검색: procedure|admin|operation → 0건)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [11.5] 운영 환경에서 관리 명령(첫 관리자 생성 · 잠금 해제 · 카탈로그 동기화)을 실행할 경로가 있다 지금 상태: CLI 실행 경로 ✕ · 비밀번호 노출 위험 ③ CLI 실행 경로: 없음 (Dockerfile · docker-compose 없음 · 플랫폼 명시 없음 · package.json:4 scripts.dev/build/start 만) 관리 명령: 없음 (첫 관리자 생성 스크립트 · 잠금 해제 · 카탈로그 동기화 코드 전무) 절차 문서: 없음 (검색: procedure¦admin¦operation → 0건) 관련 위치: scripts.dev/build/start 할 일: 배포 플랫폼 결정 후 CLI 실행 경로 문서화 (Vercel 등 매니지드면 로컬 스크립트 + Supabase SQL) · 관리자 초기화 스크립트 작성 · classes 카탈로그 시드 스크립트 작성 · 절차 문서 작성 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
cp .env.example .env.local · npm install · npm run dev)<br>배포 문서: 없음 (검색: deploy|runbook|operation → 0건 · README 개발 환경만)<br>계정 대장: 없음 (검색: account|credential|owner|2FA → 0건)<br>시크릿 대장: 없음 (검색: secret|rotation|rotate → 0건 · .env.example:1-5 키 목록만)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [11.6] 인수인계 — 실행·배포 문서, 외부 계정 대장(소유자 · 2FA · 복구 메일 · 결제수단 · 접근자), 시크릿 대장(위치 · 회전일) 지금 상태: 실행 문서 ○ · 배포 문서 ✕ · 계정 대장 ✕ · 시크릿 대장 ✕ 실행 문서: README.md:11-17 (cp .env.example .env.local · npm install · npm run dev) 배포 문서: 없음 (검색: deploy¦runbook¦operation → 0건 · README 개발 환경만) 계정 대장: 없음 (검색: account¦credential¦owner¦2FA → 0건) 시크릿 대장: 없음 (검색: secret¦rotation¦rotate → 0건 · .env.example:1-5 키 목록만) 할 일: 배포 플랫폼·절차 문서 작성 · Supabase·토스페이먼츠·배포 플랫폼 계정 대장 작성 (소유자 · 2FA · 복구 메일 · 결제수단 · 접근자) · 시크릿 대장 작성 (위치: Supabase 프로젝트 설정 · 토스 개발자센터 · 플랫폼 환경변수 / 회전일 정책) 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
procedure|operation → 0건 · "비개발자용 화면 절차" 문서 없음)<br>환불 처리: 없음 (검색: cancel|refund|환불|취소 → 0건 · app/admin/page.tsx 조회만 가능, 쓰기 없음)<br>삭제: 없음 (orders 테이블에 deleted_at 같은 soft delete 컬럼 없음 · supabase/migrations/001_init.sql:9-19)<br>복구 재료: 없음 (감사 테이블 없음 · 스냅샷 절차 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [11.7] 비개발자용 운영 절차(입점 · 정지 · 환불 처리) + 데이터 복구 가능성(hard delete 에 복구 재료) 지금 상태: 운영 절차 ✕ · 복구 재료 ✕ 운영 절차: 없음 (검색: procedure¦operation → 0건 · "비개발자용 화면 절차" 문서 없음) 환불 처리: 없음 (검색: cancel¦refund¦환불¦취소 → 0건 · app/admin/page.tsx 조회만 가능, 쓰기 없음) 삭제: 없음 (orders 테이블에 deleted_at 같은 soft delete 컬럼 없음 · supabase/migrations/001_init.sql:9-19) 복구 재료: 없음 (감사 테이블 없음 · 스냅샷 절차 없음) 관련 위치: app/admin/page.tsx, supabase/migrations/001_init.sql:9-19 할 일: 환불 처리 화면 (/admin 에 환불 버튼) 추가 · 클래스 등록/수정/삭제 화면 및 절차 문서 작성 · orders 테이블 soft delete (deleted_at) 추가 또는 감사 로그 테이블 생성 · 운영 절차 문서 작성 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
from .*mock|fixture|dummy|PreviewFab|검수용|미리보기|시안 → 0건)<br>메뉴: app/page.tsx:3 (고정 링크 2개 /classes · /login — 실제 페이지 존재)<br>외부 이미지: 없음 (검색: picsum|placeholder|lorempixel|unsplash\.it → 0건)<br>테스트 문구: 없음 (검색: 준비.*중|테스트|coming.*soon|work.*in.*progress → 0건)cancel|refund|환불|취소 → 0건)<br>입장 확인: 없음 (수강생 출석 체크 로직 없음 · orders.status 가 PAID 로만 종결)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [12.2] 판매자(운영 당사자)가 실제 운영에 필요한 쓰기 — 취소 · 환불 · 입장/수령 확인 지금 상태: 판매자 콘솔 쓰기 ✕ · 환불 ✕ · 입장 확인 ✕ 판매자 콘솔: app/admin/page.tsx:8-18 (orders 조회만 · 쓰기 없음) 환불: 없음 (검색: cancel¦refund¦환불¦취소 → 0건) 입장 확인: 없음 (수강생 출석 체크 로직 없음 · orders.status 가 PAID 로만 종결) 관련 위치: app/admin/page.tsx:8-18 할 일: app/admin 에 환불 버튼 추가 (토스 결제 취소 API 호출) · 입장 확인 화면 추가 (QR 스캔 또는 주문 ID 검색 → orders.status 를 ATTENDED 등으로 업데이트) 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
nodemailer|resend|smtp|sendgrid|ses|mailgun|postmark → 0건)<br>DNS 인증: 없음 (검색: SPF|DKIM|DMARC → 0건)<br>템플릿: 없음 (메일 템플릿 파일 없음 · .env.example:5 ADMIN_EMAIL 변수만)<br>주문 확인: app/pay/success/page.tsx:12 "마이페이지에서 예약 코드를 확인하세요" 문구만 (실제 발송 없음)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [12.3] 메일·문자 실발송 + 도달(SPF/DKIM/DMARC, 스팸함) + 거래 알림(주문 확인) 템플릿 지금 상태: 발송 어댑터 ✕ · DNS 인증 ✕ · 템플릿 ✕ · 실발송 ③ 발송 어댑터: 없음 (검색: nodemailer¦resend¦smtp¦sendgrid¦ses¦mailgun¦postmark → 0건) DNS 인증: 없음 (검색: SPF¦DKIM¦DMARC → 0건) 템플릿: 없음 (메일 템플릿 파일 없음 · .env.example:5 ADMIN_EMAIL 변수만) 주문 확인: app/pay/success/page.tsx:12 "마이페이지에서 예약 코드를 확인하세요" 문구만 (실제 발송 없음) 관련 위치: app/pay/success/page.tsx:12 할 일: Resend 류 발송 어댑터 추가 · 주문 확인 메일 템플릿 작성 · 도메인 DNS SPF/DKIM/DMARC 설정 · app/api/checkout/confirm/route.ts:17 뒤에 메일 발송 로직 추가 · 실발송 테스트 후 기록 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
test.*checklist|test.*pass|manual.*test → 0건)<br>실기기 기록: 없음 (저장소 내 문서 없음)helmet|X-Frame-Options|Content-Security-Policy|X-Content-Type-Options|HSTS|Strict-Transport → 0건)<br>sitemap: 없음 (app/sitemap.ts 없음)<br>robots: 없음 (app/robots.ts 없음)<br>관리자 noindex: 없음 (app/admin/page.tsx 에 metadata 없음)<br>OG: app/layout.tsx:1 metadata (title 만 · og 태그 없음)export const metadata = { robots: { index: false } } 추가 · 상세 페이지 OG 메타 추가 (예: app/classes/[id]/page.tsx 의 generateMetadata)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[12.5] 보안 헤더(HSTS · nosniff · Referrer-Policy · CSP) · SEO(sitemap · robots) · 비공개 호스트 noindex ·
지금 상태: 보안 헤더 ✕ · sitemap ✕ · robots ✕ · 관리자 noindex ✕ · OG ○ 보안 헤더: 없음 (검색: helmet¦X-Frame-Options¦Content-Security-Policy¦X-Content-Type-Options¦HSTS¦Strict-Transport → 0건) sitemap: 없음 (app/sitemap.ts 없음) robots: 없음 (app/robots.ts 없음) 관리자 noindex: 없음 (app/admin/page.tsx 에 metadata 없음) OG: app/layout.tsx:1 metadata (title 만 · og 태그 없음)
관련 위치: app/admin/page.tsx, app/layout.tsx:1, app/robots.ts, app/sitemap.ts
할 일: next.config 또는 middleware.ts 에 보안 헤더 추가 · app/sitemap.ts · app/robots.ts 생성 · app/admin/page.tsx 에 export const metadata = { robots: { index: false } } 추가 · 상세 페이지 OG 메타 추가 (예: app/classes/[id]/page.tsx 의 generateMetadata)
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.contrast|color.*ratio|wcag|a11y|accessibility → 0건 · 스크립트·CI 없음)<br>키보드: 없음 (검색: aria-|role=|tab.*index|keyboard|onKey → 0건 · app/classes/page.tsx:35 button 은 기본 접근성 있으나 명시 핸들러 없음)<br>금액 aria: 없음 (app/classes/page.tsx:34 {c.price.toLocaleString()}원 — aria-label 없음)<span aria-label="가격 {c.price}원">{c.price.toLocaleString()}원</span> 추가출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[12.6] 접근성 기본 — 대비 검사 통과 이력, 키보드 조작, 스크린리더 금액 낭독
지금 상태: 대비 검사 ✕ · 키보드 ✕ · aria ✕ 대비 검사: 없음 (검색: contrast¦color.ratio¦wcag¦a11y¦accessibility → 0건 · 스크립트·CI 없음) 키보드: 없음 (검색: aria-¦role=¦tab.index¦keyboard¦onKey → 0건 · app/classes/page.tsx:35 button 은 기본 접근성 있으나 명시 핸들러 없음) 금액 aria: 없음 (app/classes/page.tsx:34 {c.price.toLocaleString()}원 — aria-label 없음)
관련 위치: app/classes/page.tsx:34, app/classes/page.tsx:35
할 일: axe-core 류 대비 검사 도구 추가 · 테스트 실행 후 이력 문서화 · 핵심 버튼에 키보드 핸들러 추가 (이미 작동하나 명시) · 금액 표시에 <span aria-label="가격 {c.price}원">{c.price.toLocaleString()}원</span> 추가
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.<footer>© 공방 원데이</footer> — 저작권 표시만, 사업자 정보·통판 번호·보호책임자 없음<br>검색: 고객센터|상담|문의|contact|support → 0건출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [13.1] 사업자 정보·통신판매업 번호 footer + 개인정보 보호책임자 + 문의 동선 지금 상태: 사업자 정보 ✕ · 통판 번호 ✕ · 보호책임자 ✕ · 문의 동선 ✕ app/layout.tsx:3 <footer>© 공방 원데이</footer> — 저작권 표시만, 사업자 정보·통판 번호·보호책임자 없음 검색: 고객센터¦상담¦문의¦contact¦support → 0건 관련 위치: app/layout.tsx:3 할 일: footer 에 사업자 정보·통판 번호·보호책임자·연락 수단(메일/전화) 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
<a href="#">이용약관</a> — href="#", 실제 문안 없음<br>검색: 약관|terms → 링크만, 문안 파일(md·json·CMS) 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [13.2] 약관 — 구매·지급·청약철회·환급 조항, 거래 구조(중개자 고지), 자리 표시자 0, 효력일 순서 지금 상태: 약관 문안 ✕ · 자리 표시자 — · 효력일 ✕ app/login/page.tsx:9 <a href="#">이용약관</a> — href="#", 실제 문안 없음 검색: 약관¦terms → 링크만, 문안 파일(md·json·CMS) 없음 관련 위치: app/login/page.tsx:9 할 일: 약관 문안 작성(구매·청약철회·환급·중개자 여부 명시), 효력일 기재, 문안 파일 추가 및 링크 수정 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
<a href="#">개인정보처리방침</a> — href="#", 실제 문안 없음<br>코드 사실: supabase/migrations/001_init.sql:13-14 buyer_name text, buyer_phone text (이름·전화 수집) · app/api/checkout/confirm/route.ts:7-14 토스페이먼츠 API 전송 → 문안 없어 대조 불가출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [13.3] 처리방침 — 수집 항목·처리위탁·보존 기간·국외 이전·판매자 제공 항목이 코드 사실과 일치 지금 상태: 처리방침 문안 ✕ · 코드 대조 ✕ app/login/page.tsx:9 <a href="#">개인정보처리방침</a> — href="#", 실제 문안 없음 코드 사실: supabase/migrations/001_init.sql:13-14 buyer_name text, buyer_phone text (이름·전화 수집) · app/api/checkout/confirm/route.ts:7-14 토스페이먼츠 API 전송 → 문안 없어 대조 불가 관련 위치: app/api/checkout/confirm/route.ts:7-14, app/login/page.tsx:9, supabase/migrations/001_init.sql:13-14 할 일: 처리방침 문안 작성(수집: 이름·전화·결제정보 / 위탁: 토스·Supabase / 국외 이전: Supabase 위치 확인 / 보존: 거래 5년), 문안 파일 추가 및 링크 수정 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
<p>가입하면 <a href="#">이용약관</a>과 <a href="#">개인정보처리방침</a>에 동의한 것으로 봅니다.</p> — 체크박스 없음, 묵시 동의<br>supabase/migrations/001_init.sql:9-19 orders 테이블 — 동의 버전 열 없음<br>app/classes/page.tsx:10-26 결제 흐름 — 취소 규정 동의 체크 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [13.4] 동의 — 필수/선택 분리 · 만 14세 · 마케팅 분리·철회 · 결제 전 취소 규정 동의와 버전 기록 지금 상태: 필수/선택 분리 ✕ · 만 14세 ✕ · 마케팅 분리 — · 결제 전 동의 ✕ · 버전 기록 ✕ app/login/page.tsx:9 <p>가입하면 <a href="#">이용약관</a>과 <a href="#">개인정보처리방침</a>에 동의한 것으로 봅니다.</p> — 체크박스 없음, 묵시 동의 supabase/migrations/001_init.sql:9-19 orders 테이블 — 동의 버전 열 없음 app/classes/page.tsx:10-26 결제 흐름 — 취소 규정 동의 체크 없음 관련 위치: app/classes/page.tsx:10-26, app/login/page.tsx:9, supabase/migrations/001_init.sql:9-19 할 일: 가입 화면에 체크박스(필수: 약관·방침·만 14세, 선택: 마케팅) 추가, 결제 전 취소 규정 동의 체크박스 추가, orders.consent_version 열 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
탈퇴|withdraw|delete.*account → 0건, 탈퇴 기능 없음<br>supabase/migrations/001_init.sql:9-19 orders 테이블 — 보존·익명화 정책 명시 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [13.5] 거래기록 5년 보존 vs 탈퇴·삭제 정책, 탈퇴 동선 지금 상태: 탈퇴 동선 ✕ · 보존 정책 ✕ 검색: 탈퇴¦withdraw¦delete.account → 0건, 탈퇴 기능 없음 supabase/migrations/001_init.sql:9-19 orders 테이블 — 보존·익명화 정책 명시 없음 관련 위치: supabase/migrations/001_init.sql:9-19 할 일: 탈퇴 동선 추가(마이페이지·설정), 탈퇴 시 주문 행 보존 정책 결정(거래 5년 vs 개인정보 삭제), 익명화 로직 구현 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
보상|배상|손해|불이행 → 0건, 약관 없음(13.2)<br>검색: age|연령|미성년 → 0건, 연령 제한 상품 해당 없음(원데이 클래스)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [13.6] 판매자 불이행 보상(소비자분쟁해결기준)과 배상 주체, 연령 제한 상품의 확인 강제 지금 상태: 보상 조항 ✕ · 배상 집행 ✕ · 연령 확인 — 검색: 보상¦배상¦손해¦불이행 → 0건, 약관 없음(13.2) 검색: age¦연령¦미성년 → 0건, 연령 제한 상품 해당 없음(원데이 클래스) 할 일: 약관에 불이행 보상 조항 추가(배상 주체: 판매자 직접 or 플랫폼 중개), 코드의 환불·보상 집행 경로 구현 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
검토|review|lawyer|변호사|법무 → 0건<br>docs 디렉터리 없음, .github/issues 없음(이슈 기록은 저장소 밖이라 확인 못 함)test_ck_xxxxxxxx · test_sk_xxxxxxxx — 테스트 키, 프로덕션 심사 전<br>서류(사업자등록증·통판·신분증·통장)는 외부 — 확인 불가(?)nodemailer|resend|sendgrid|ses|smtp|mailer → 0건, 메일 어댑터 없음<br>.env.example:5 ADMIN_EMAIL=owner@example.com — 수신 주소만, 발신 구현 없음출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘. [14.2] 메일 공급자 프로덕션 액세스 · 도메인 인증(DKIM) · 바운스 처리 지금 상태: 메일 어댑터 구현 ✕ · DKIM ✕ · 바운스 처리 ✕ 검색: nodemailer¦resend¦sendgrid¦ses¦smtp¦mailer → 0건, 메일 어댑터 없음 .env.example:5 ADMIN_EMAIL=owner@example.com — 수신 주소만, 발신 구현 없음 할 일: 메일 공급자(Resend·SendGrid·SES 등) 선택 및 어댑터 구현, 발신 도메인 DKIM 설정, 바운스 웹훅 처리 코드 추가 지켜 줄 것: - 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘. - 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로. - 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.
sms|문자|alimtalk|알림톡|ncp|solapi → 0건<br>app/login/page.tsx:8 카카오 OAuth 로그인 — 문자 인증 미사용<br>app/pay/success/page.tsx:12 "마이페이지에서 예약 코드를 확인하세요" — 문자 알림 미사용(화면 안내만)supabase.auth.signInWithOAuth({ provider: 'kakao' }) — Supabase 가 redirect_uri 자동 구성, 코드에 명시 없음<br>app/login/page.tsx:9 <a href="#">개인정보처리방침</a> — href="#", 공개 URL 없음(13.3)<br>카카오 콘솔 등록 상태는 외부 — 확인 불가(?)출시 전 점검에서 이 항목이 걸렸어. 고쳐 줘.
[14.4] 소셜 로그인 콘솔 등록 — redirect_uri 글자 일치, 처리방침 URL 공개가 심사 선행(카카오)
지금 상태: redirect_uri 설정 ? · 처리방침 공개 URL ✕ app/login/page.tsx:8 supabase.auth.signInWithOAuth({ provider: 'kakao' }) — Supabase 가 redirect_uri 자동 구성, 코드에 명시 없음 app/login/page.tsx:9 <a href="#">개인정보처리방침</a> — href="#", 공개 URL 없음(13.3) 카카오 콘솔 등록 상태는 외부 — 확인 불가(?)
관련 위치: app/login/page.tsx:8, app/login/page.tsx:9
할 일: 처리방침 공개 URL 확보(문안 작성 → 배포), Supabase/카카오 콘솔에서 redirect_uri 등록 확인
지켜 줄 것:
- 먼저 관련 파일을 읽고 무엇을 바꿀지 짧게 계획부터 보여 줘.
- 이 항목과 관계없는 파일은 바꾸지 마. 비밀 값(키·토큰)은 코드에 넣지 말고 환경변수로.
- 끝나면 바꾼 파일 목록과 이유, 그리고 고쳐졌는지 내가 확인하는 방법을 한 줄로 알려 줘.naver.*map|kakao.*map|google.*map|지도 → 0건<br>검색: API.*KEY|GOOGLE|NAVER|KAKAO (.env.example 제외) → 0건, 지도·주소 API 미사용log_min_duration_statement 설정 확인curl -I https://<도메인> 으로 TLS · HSTS 확인SELECT * FROM orders (익명 세션) 실행 → 조회되면 RLS 부재 확인git log --all -S'AKIA' --name-only --format='%h' · git log --all -G'PASSWORD=' --name-only --format='%h' (패턴: AKIA · sk_live · sk_test · -----BEGIN · PASSWORD= · SECRET= · DATABASE_URL=postgres://)npm run build && grep -r "test_sk_" .next/ (NEXT_PUBLIC_TOSS_SECRET_KEY 가 번들에 포함되는지)/admin 경로를 비로그인 상태에서 접근해 주문 목록이 뜨는지 확인 (뜨면 인증 없음 확인됨)/api/checkout/confirm POST 에 {"paymentKey":"x","orderId":"y","amount":-1000,"extraField":"evil"} 전송 → extraField 거부 여부 · 음수 amount 거부 여부 확인/api/checkout/confirm POST 에 {"paymentKey":"x","orderId":"valid-uuid","amount":0} 전송 → 0원 결제 거부 여부 확인 · classes 테이블 price 와 대조 여부 확인/api/checkout/confirm POST 에 {"paymentKey":"x","orderId":"not-a-uuid","amount":1000} 전송 → 400 응답인지 500 응답인지 확인script.sh 2>&1 | grep password)queue|job|worker|cron|schedule → 0건) 10.1 — 설계 노트가 없고, README.md:3 에 "샘플용 가상 앱" 으로 명시된 저장소 (확장 예정 없음)"통과" 는 코드와 설정을 읽어서 확인한 것입니다. 운영 환경에서의 동작은 "실행해야 확정되는 것" 의 방법으로 닫습니다. 참고 자료이며 법률·세무 자문이 아닙니다.