F01 나의 구축 순서
Codex에서 구현하고 GitHub에 기록한 뒤 DB·공개 앱·메일·SNS를 연결한다.



강사 설명: 이 순서는 최초 구축의 이해를 돕는다. 실제 개발에서는 DB와 화면을 오가며 반복한다. 공개 URL을 만든 뒤 메일·OAuth 복귀 주소를 다시 맞추고 통합 검증한다. 도구 선택 자체가 보안과 로그인 완료를 보장하지 않는다.
참고: 

F02 Codex에서 GitHub까지
작은 요구를 구현하고 검토 가능한 기록으로 남긴다.
사용자·입력·처리·출력·완료 기준을 한 장으로 쓴다.
README·설계·기존 코드·실행 명령을 먼저 읽힌다.
수업용 branch 또는 Worktree에서 한 기능씩 구현한다.
관련 검사와 실제 동작을 확인하고 diff를 읽는다.
비밀값 없는 변경만 commit하고 원격 branch와 PR을 연결한다.


강사 설명: 
참고: https://developers.openai.com/codex/quickstart
https://git-scm.com/docs/gittutorial

F03 Supabase 프로젝트 기본 설정
PostgreSQL·Auth·Storage와 프로젝트의 키를 구분한다.
새 수업용 프로젝트와 지역을 선택하고 DB 비밀번호를 비밀 관리 위치에 보관한다.
프로젝트 URL과 publishable key를 앱의 공개 설정에 넣는다.
programs·applications 관계와 입력 제약·인덱스를 만든다.
노출할 테이블의 Data API 권한과 RLS를 함께 설정한다.
방문자·계정 A·계정 B로 조회·수정·삭제 범위를 확인한다.


강사 설명: DB 비밀번호는 PostgreSQL 접속 자격이다. 이용자의 로그인 비밀번호와 다르다. 현재 신규 테이블의 Data API 노출이 자동이라고 가정하지 않는다. GRANT는 테이블에 할 수 있는 작업, RLS는 접근 가능한 행을 제한한다. SQL Editor의 관리자 권한만으로 RLS를 검증하지 않는다.
참고: https://supabase.com/docs/guides/api/securing-your-api
https://supabase.com/docs/guides/database/postgres/row-level-security

F04 Supabase 보안과 로그인 설정표
화면에 보이는 옵션과 서버·DB가 강제할 조건을 함께 정한다.


영역 | 설정·설계 | 검증
이메일 가입 | 공개 가입/초대 전용 중 요구에 맞게 선택 | 정책 밖 가입 거부
확인·세션 | 이메일 확인·SSR 쿠키 갱신 | 미확인·새로고침·로그아웃
비밀번호 | 길이·유출 방지·재인증 제공 범위 확인 | 약한 비밀번호 거절
DB | 테이블 권한·RLS·소유권 | 다른 계정 직접 요청 거절
역할 | 서버 관리 역할·승인 상태 | 버튼·user_metadata로 승격 불가
메일·요청 | SMTP·빈도 제한·필요시 CAPTCHA | 중복·남용·오류 안내
강사 설명: 유출 비밀번호 방지는 현재 Pro 이상 제공 여부를 확인한다. 길이 정책은 수업 예시로12자 이상을 선택할 수 있으나 제품 기본값이라고 말하지 않는다. 관리자 계정 보호와 앱 이용자 MFA를 구분한다.
참고: https://supabase.com/docs/guides/auth/password-security
https://supabase.com/docs/guides/auth/auth-smtp
https://supabase.com/docs/guides/database/postgres/row-level-security

F05 설정 이름과 보관 위치
모든 키를 Vercel에 복사할 필요는 없다.


항목 | 보관 위치 | 브라우저 공개
Supabase URL·publishable key | 앱 환경변수 | 가능 · RLS 전제
DB 비밀번호·secret/service_role | 필요한 서버·비밀관리 | 불가
Resend SMTP API key | Supabase Auth SMTP Password | 불가
앱 알림용 RESEND_API_KEY | 메일 API를 호출할 서버 환경 | 불가
SNS Client Secret | Supabase provider 설정 | 불가
사이트 URL·기능 플래그 | 앱 환경별 설정 | 용도에 따라
강사 설명: Supabase Auth만 Resend SMTP로 메일을 보내면 앱 서버에 Resend API key가 필요하지 않다. 별도 알림 API를 직접 호출할 때만 서버 키를 둔다. 공개키는 사용자 권한을 대신하지 않는다.
참고: https://resend.com/docs/send-with-supabase-smtp
https://vercel.com/docs/environment-variables
https://supabase.com/docs/guides/api/securing-your-api

F06 Vercel 첫 연결과 환경 매핑
공개 URL과 서버 설정을 실제 배포에 연결한다.
GitHub 저장소를 Import하고 모노레포라면 앱의 Root Directory를 지정한다.
실제 framework·install·build·output 설정과 lockfile을 확인한다.
수업용 클라우드 Supabase에 검토한 migration·RLS·가상 seed를 적용하고 로컬과 대조한다.
Production branch를 확인하고 기능 branch는 Preview로 검증한다.
Development·Preview·Production의 Supabase 연결 대상을 기록한다.
환경변수 변경 뒤 새 배포에서 적용 여부를 확인한다.
배포 commit·Ready·실제 URL의 동작을 따로 기록한다.


강사 설명: Docker로 로컬 Supabase를 썼다는 이유로 그 컨테이너가 Vercel에서 자동 실행되는 것은 아니다. DB는 Supabase Cloud 등 별도 서비스로 연결한다. 생성도구에서 가져온 앱은 Vercel 런타임 호환성을 별도 확인한다.
참고: https://vercel.com/docs/git
https://vercel.com/docs/environment-variables

F07 Resend 도메인과 DNS 준비
발송 도메인 검증을 수업 전에 끝낸다.
Resend에서 사용할 발신 도메인 또는 전용 하위 도메인을 등록한다.
Resend가 표시한 DNS의 이름·형식·값을 DNS 관리자에 정확히 추가한다.
DKIM과 SPF 관련 안내를 따르고 Verify 상태를 확인한다.
기존 회사 메일의 MX·SPF를 임의 교체하지 않고 기존 레코드와 충돌을 검토한다.
검증 도메인의 발신 주소와 이름, 수업용 키·환경별 용도를 정한다.


강사 설명: 레코드의 실제 이름과 값은 계정의 Resend 화면에서 복사한다. 기존 도메인 메일 수신과 인증 메일 발신의 DNS 목적이 다를 수 있다. DNS 전파와 검증 대기 시간은 강의실 실습에서 제외한다.
참고: https://resend.com/docs/dashboard/domains/introduction
https://resend.com/docs/send-with-supabase-smtp

F08 Supabase Auth에 Resend SMTP 연결
메일을 발행하는 Auth와 전달하는 Resend를 연결한다.
Supabase Auth의 Email/SMTP 설정 화면에서 Custom SMTP를 켠다.
위 항목을 입력하고 저장한다. 키를 자료·Git·로그에 남기지 않는다.
가입·초대·복구 템플릿과 redirect 설정을 점검한다.
허용된 테스트 주소로 실제 메일과 링크 동작을 확인한다.

SMTP 항목 | 수업 설정 | 의미
Host | smtp.resend.com | Resend SMTP 서버
Port | 465 | TLS SMTP 예시
Username | resend | SMTP 사용자 이름
Password | 전용 Resend API key | Supabase DB 비밀번호와 다름
Sender email | 검증한 도메인의 발신 주소 | 실제 전달 주체
Sender name | 수업 서비스 이름 | 수신함 표시 이름
강사 설명: 
참고: https://resend.com/docs/send-with-supabase-smtp
https://supabase.com/docs/guides/auth/auth-smtp

F09 Site URL·Redirect URL·메일 링크
주소 세 종류의 목적을 구분한다.


항목 | 예시 | 역할
Site URL | https://course.example.org | 앱 기본 주소·기본 복귀
Supabase Redirect URLs | https://course.example.org/auth/callback | 앱이 요청할 복귀 허용 목록
복구 화면 | https://course.example.org/auth/update-password | 복구 세션 후 새 비밀번호 입력
이메일 확인 경로 | 앱이 구현한 /auth/confirm 등 | token_hash와 type 검증 방식
OAuth 공급자 callback | https://PROJECT_REF.supabase.co/auth/v1/callback | 외부 제공자가 Supabase로 돌아옴
강사 설명: 각 경로는 예시이므로 코드와 메일 템플릿의 실제 구현에 맞춘다. Site URL 하나를 바꾸어도 모든 템플릿과 명시적 redirectTo가 자동으로 바뀌는 것은 아니다. 스테이징은 별도 앱 주소·Supabase ref로 관리한다.
참고: https://supabase.com/docs/guides/auth/redirect-urls
https://supabase.com/docs/guides/auth/passwords
https://supabase.com/docs/guides/auth/auth-email-templates

F10 가입·초대·로그인·비밀번호의 차이
사용자가 출발하는 인증 상태가 다르다.


상황 | 시작 | 완료
일반 가입 | 이메일·비밀번호 입력 | 이메일 확인과 앱 가입 조건 완료
초대 후 최초 설정 | 관리자가 발행한 유효 초대 | 초대 검증·본인 비밀번호 설정
일반 로그인 | 확인된 계정·비밀번호 | Auth 세션·업무 권한 확인
로그인 후 비밀번호 변경 | 유효 세션·필요시 재인증 | 새 비밀번호 저장
비밀번호 분실 | 복구 요청·실제 메일 | 복구 검증·변경·새 로그인
강사 설명: 이용자 비밀번호는 Supabase Auth가 관리한다. 앱 테이블에 평문이나 자체 비밀번호 열을 만들지 않는다. 학교 포털 비밀번호·DB 비밀번호·SMTP Password와 같은 비밀번호라고 가르치지 않는다.
참고: https://supabase.com/docs/guides/auth/passwords
https://supabase.com/docs/guides/auth/password-security

F11 비밀번호 재설정의 전체 흐름
요청 성공에서 멈추지 않고 새 비밀번호 로그인까지 확인한다.
등록 여부를 드러내지 않는 동일한 요청 안내를 쓴다.
메일 템플릿과 앱 callback이 사용하는 token_hash 검증 또는 PKCE 방식을 맞춘다.
허용된 복귀 주소와 복구 세션을 확인한다.
새 비밀번호·확인 입력과 Auth 비밀번호 정책을 적용한다.
만료·재사용 링크와 새 로그인, 기존 세션 처리 정책을 시험한다.


강사 설명: 
참고: https://supabase.com/docs/guides/auth/passwords
https://supabase.com/docs/guides/auth/password-security
https://supabase.com/docs/guides/auth/redirect-urls

F12 메일 실패를 찾는 다섯 지점
요청·처리·배달·링크·세션을 나누면 원인을 찾기 쉽다.


지점 | 확인할 것
Auth 요청 | 요청 종류·오류·빈도 제한·confirm 설정
SMTP 처리 | host·port·자격·도메인·발신 주소
전달·수신 | Resend 이벤트·반송·스팸함·메일 정책
메일 링크 | 앱 주소·만료·재사용·보안 스캐너
앱 세션 | 쿠키·교환·returnTo·환경별 키
강사 설명: Resend의 처리 성공과 받은 편지함 도착, 링크 확인과 로그인은 서로 다르다. 미발송을 성공으로 표시하거나 자동 이메일 확인으로 우회하지 않는다. 발송 자격을 확인한 것만으로 실제 회원 메일 도착을 주장하지 않는다.
참고: https://supabase.com/docs/guides/auth/auth-smtp
https://supabase.com/docs/guides/auth/passwords
https://resend.com/docs/send-with-supabase-smtp

F13 uc-anchor의 Resend 구축에서 읽을 점
SMTP 자격 확인과 최종 사용자 검증을 구분한 기록이다.
2026-09-28 Preview Resend 보고서는 SMTP TLS 인증과 hosted Auth 설정 확인을 기록했다.
실제 회원 메일은 발송하지 않았으며 테스트 초대·복구 수신 확인을 다음 검증으로 남겼다.
후속 설계는 환경과 키를 분리하고 Production을 읽기 전용으로 취급했다.
수업에서도 설정·발송 처리·수신·링크·로그인을 별도 칸으로 기록한다.


강사 설명: 출처: uc-anchor/docs/04-report/preview-resend-smtp.report.md 및 docs/02-design/features/preview-resend-smtp.design.md. 구 지역 Preview와 후속 서울 staging의 기록을 섞지 않는다. 프로젝트 ref·키·개인 메일을 수업용 설정으로 복사하지 않는다.
참고: 

F14 현재 메일 정책에서 확인할 점
기본 메일과 Custom SMTP의 제공 범위를 구분한다.
Supabase 기본 SMTP는 탐색용이며 일반 서비스 수신자에게 보낼 운영 발송 경로로 가정하지 않는다.
2026-06-03 이후 새 Free 프로젝트의 기본 SMTP 템플릿 편집 제한을 확인한다.
Custom SMTP를 설정한 경우의 템플릿 기능과 발송 한도를 실제 계정에서 확인한다.
고정된 무료 발송량이나 모든 계정의 같은 한도를 강의자료에 약속하지 않는다.


강사 설명: 
참고: https://supabase.com/docs/guides/auth/auth-smtp
https://supabase.com/changelog/46599-changes-to-email-template-customisation-on-free-tier

F15 SNS 로그인 공통 왕복 구조
외부 계정 인증 뒤 Supabase 세션과 앱 가입 상태를 확인한다.



강사 설명: 제공자 Redirect URI는 Supabase 대시보드의 callback을 복사한다. 앱 callback은 Supabase 이후 돌아갈 주소다. 로그인 버튼 선택은 강사·관리자 역할 부여가 아니다. 앱 동의와 제공자 정보 동의도 별도로 관리한다.
참고: https://supabase.com/docs/guides/auth/social-login/auth-google
https://supabase.com/docs/guides/auth/social-login/auth-kakao
https://supabase.com/docs/guides/auth/custom-oauth-providers
https://supabase.com/docs/guides/auth/server-side/creating-a-client?queryGroups=framework&framework=nextjs

F16 Google Cloud 로그인 연결
Google OAuth Client를 Supabase Google 제공자에 등록한다.
Google Cloud에서 수업용 프로젝트와 Google Auth Platform을 연다.
Branding·지원 연락처·도메인·개인정보 URL, Audience와 Data Access 범위를 검토한다.
웹 애플리케이션 OAuth Client를 만들고 Authorized redirect URI에 Supabase callback을 등록한다.
Supabase Google 제공자에 Client ID와 Secret을 보관한다.
앱에서 Google OAuth와 허용된 앱 callback을 연결한다.
계정의 대상 사용자·게시/검증 상태를 확인하고 최초 가입·취소·재로그인을 시험한다.


강사 설명: 승인된 JavaScript origin은 사용한 Google 클라이언트 방식이 요구할 때 등록한다. 불필요한 Drive·Calendar 접근은 요청하지 않는다. u-livet의 openid email 축소는 앱이 queryParams로 인가 URL을 조정한 프로젝트 구현이므로 기본 SDK 동작으로 단정하지 않는다.
참고: https://developers.google.com/identity/protocols/oauth2/web-server
https://supabase.com/docs/guides/auth/social-login/auth-google

F17 Kakao Developers 로그인 연결
REST API 키와 카카오 로그인 설정을 Supabase에 맞춘다.
수업용 앱을 등록하고 웹 서비스 플랫폼·도메인 정보를 확인한다.
카카오 로그인을 활성화하고 Redirect URI에 해당 Supabase callback을 등록한다.
필요한 동의 항목과 제공 가능 여부를 확인한다.
REST API 키와 현재 Secret 설정을 Supabase Kakao provider의 해당 항목에 넣는다.
앱 버튼을 연결하고 미완료 가입·이메일 누락·동의 취소를 처리한다.
로그아웃·재로그인·기존 회원 연결과 역할 검증을 확인한다.


강사 설명: REST API 키, JavaScript 키, Admin 키는 역할이 다르다. 수업에서 이메일이 항상 제공된다고 가정하지 않는다. provider 설정만 켠 상태와 앱의 실제 사용 가능 상태를 구분한다.
참고: https://developers.kakao.com/docs/ko/kakaologin/prerequisite
https://supabase.com/docs/guides/auth/social-login/auth-kakao

F18 Naver Developers와 Custom OAuth
u-livet은 custom:naver와 서버 userinfo 어댑터를 사용한다.
Naver Developers에서 서비스 URL·callback·개인정보 URL과 테스트 계정을 준비한다.
Client ID·Secret과 Supabase Custom OAuth 제공자 항목을 맞춘다.
서버 어댑터에서 Bearer 토큰으로 고정 네이버 userinfo를 확인한다.
검증한 response.id를 sub로 바꾸고 필요한 필드만 반환한다.
잘못된 토큰·이메일 누락·취소·재로그인과 가입 조건을 확인한다.

항목 | 설정 예시
제공자 유형 | OAuth2 · identifier naver
앱 provider 값 | custom:naver
Authorization | https://nid.naver.com/oauth2.0/authorize
Token | https://nid.naver.com/oauth2.0/token
원본 userinfo | https://openapi.naver.com/v1/nid/me
Supabase userinfo | 내 서버의 검증·평탄화 어댑터 URL
강사 설명: Naver는 여기서 OIDC discovery/JWKS가 아닌 OAuth2 경로다. Supabase Custom OAuth 제공 범위·quota·email_optional 지원을 계정에서 확인한다. 브라우저가 보내는 임의 사용자 JSON을 신뢰하지 않는다.
참고: https://supabase.com/docs/guides/auth/custom-oauth-providers
https://developers.naver.com/docs/login/api/api.md

F19 네이버 최초 가입과 이메일 확인
외부 identity를 유지하며 앱에서 요구할 이메일을 실제 확인한다.
네이버 응답에 확인 상태가 없으면 email_verified를 true로 만들지 않는다.
u-livet 후속 구현은 이 provider만 email_optional=true로 가입 대기 OAuth 세션을 만들었다.
사용자가 앱에서 선택한 이메일을 별도 검증하고 동의·프로필 완료 후 회원 기능을 연다.
재로그인은 같은 네이버 identity에 연결하며 이메일 일치만으로 기존 역할을 복사하지 않는다.
// 합성 사용자 정보 변환 예시
{
  "sub": "synthetic-naver-user-001",
  "email": "learner@example.invalid",
  "email_verified": false
}

강사 설명: 실제 후속 기록은 별도 무저장 클라이언트의 이메일 OTP 검증 후 원 OAuth 세션을 갱신한다. 초보자가 OTP 로그인으로 기존 세션을 덮어쓰는 것을 피하도록 강사 기준 구현을 사용한다. 기존 대화·문서에도 개인 계정 전체 가입 완료는 별도 확인으로 남은 범위가 있으므로 모의 검사와 구분한다.
참고: https://supabase.com/docs/guides/auth/custom-oauth-providers
https://developers.naver.com/docs/login/api/api.md

F20 MFA 등록과 보호된 작업
추가 인증 강도와 데이터 소유권을 동시에 검사한다.
서비스 이용자 계정의 TOTP factor를 등록한다.
QR 또는 수동 키를 본인 인증앱에 넣고 코드를 검증한다.
다시 로그인해 challenge 또는 challengeAndVerify로 AAL2를 확인한다.
본인 내보내기에서 서버와 DB가 AAL2·소유권을 함께 확인한다.
틀린 코드·중복 요청·분실 안내와 안전한 내부 복귀 주소를 확인한다.


강사 설명: AAL2는 인증 강도이며 관리자 역할이 아니다. QR·비밀키·인증코드를 URL·로그·영구 브라우저 저장에 남기지 않는다. factor 등록만으로 검증이 끝난 것은 아니다. 실제 복구 운영은 승인된 계정 복구 절차로 연결한다.
참고: https://supabase.com/docs/guides/auth/auth-mfa/totp
https://supabase.com/docs/guides/database/postgres/row-level-security

F21 계정 A/B와 인증 통합 점검
정상 결과와 실패 결과를 같은 표에 남긴다.


조건 | 행동 | 기대 결과
방문자 | 보호 API 직접 호출 | 거부
계정 A | 저장·새로고침·본인 수정 | 동일 본인 기록
계정 B | A 기록 조회·수정·삭제 | 거부 또는 0행
SNS 신규·기존 | 최초 가입·취소·재로그인 | 정해진 가입 상태·동일 identity
복구 메일 | 만료·사용한 링크·변경 후 로그인 | 올바른 거절과 새 비밀번호
MFA 전후 | 보호 내보내기 직접 요청 | 전:거부 / 후:본인만 허용
강사 설명: SQL Editor 관리자 결과만으로 사용자 RLS 통과를 선언하지 않는다. 수신함을 보지 않은 메일 항목이나 실제 SNS 계정에서 실행하지 않은 항목은 미확인으로 남긴다.
참고: https://supabase.com/docs/guides/database/postgres/row-level-security
https://supabase.com/docs/guides/auth/passwords
https://supabase.com/docs/guides/auth/auth-mfa/totp

F22 staging에서 main으로 전달할 기록
설정은 Git에 모두 들어 있지 않다.
PR base/head, 검증 commit, 배포 commit·URL·환경을 연결한다.
migration·RLS와 기존 코드 호환성을 확인한다.
Vercel 환경변수, Supabase Auth·SMTP·Redirect, 공급자 callback을 별도 점검한다.
Production Ready 뒤 실제 목록·저장·로그인·복구·SNS 핵심 흐름을 확인한다.


강사 설명: 한 단계의 성공이 다음 단계를 자동으로 증명하지 않는다. Git의 소스 변경과 hosted Auth 설정은 서로 다른 이력이다. 환경별 체크표에 값 대신 이름·대상·확인 시각만 기록한다.
참고: https://chatgpt.com/c/6af151e4-aa58-83ee-b884-46e97f10a2af
https://vercel.com/docs/git
https://supabase.com/docs/guides/auth/auth-smtp

F23 처음 구축한 뒤 남길 운영 안내
다음 사람이 실행·검증·복구할 수 있게 기록한다.
로컬 실행·의존성·빌드와 Git 작업 규칙.
환경별 URL·Supabase 대상·설정 이름과 담당자.
가입·초대·SNS·비밀번호·MFA의 실제 지원 범위.
메일 실패 확인 순서, 미완료 기능과 다음 개선.
정상 배포와 데이터 복구의 서로 다른 기준.


강사 설명: 
참고: 