0. 시작 전에 준비할 것
아래 계정 4개만 있으면 됩니다. 모두 처음에는 무료 플랜으로 시작할 수 있습니다.
| 서비스 | 용도 | 주소 |
|---|---|---|
| GitHub | 소스코드 Private 저장소 | github.com |
| Cloudflare | 웹 호스팅 + 서버 API | dash.cloudflare.com |
| Supabase | 로그인 + PostgreSQL DB | supabase.com |
| Google AI Studio | Gemini API Key | aistudio.google.com |
1. 앱의 전체 구조
브라우저에는 Supabase Publishable Key만 있습니다. Gemini API Key와 Supabase Secret Key는 Cloudflare 서버 영역에만 있습니다. AI 분석 원본은 브라우저가 직접 DB에 INSERT할 수 없고 서버 전용 저장 함수가 한 번의 DB transaction으로 저장합니다.
2. ZIP을 풀고 파일 확인
압축을 풀면 아래처럼 보여야 합니다.
3. Supabase 프로젝트 만들기
새 프로젝트를 만듭니다. 예: tubeenglish-study.
길고 안전한 비밀번호를 만들어 별도 비밀번호 관리자에 보관하세요.
주 사용자가 한국이라면 가능한 가까운 Asia region을 선택하세요.
왼쪽에 SQL Editor / Table Editor / Authentication이 보이면 됩니다.
4. Supabase DB를 한 번에 설치
설치되는 핵심 테이블은 다음과 같습니다.
| 테이블 | 역할 |
|---|---|
| profiles | 사용자 표시명과 user/admin 역할 |
| videos | YouTube 영상, 공개/비공개, 관리자 숨김/추천 |
| analyses | Gemini 분석 JSON 원본과 버전 |
| expressions | 개별 영어 표현, 타임스탬프, CEFR, AI 점수, 대표형 |
| user_expression_progress | 중요/헷갈림/외움, 듣기·반복·받아쓰기, 개인 메모, 복습일 |
| study_events | 장기 학습 이벤트 통계 |
| app_settings | 커뮤니티 운영 설정 |
| app_secrets | Gemini 키의 AES-GCM 암호문만 저장 |
| community_recommendations | 관리자 공식 추천 표현 |
5. 브라우저용 Supabase 정보 입력
Cloudflare 환경변수는 서버 Functions용입니다. 정적 브라우저 JavaScript에는 별도로 Supabase Project URL과 Publishable Key를 넣어야 합니다.
6. Supabase 로그인 설정
이메일 로그인
Supabase → Authentication → Providers에서 Email provider가 켜져 있는지 확인합니다.
테스트 중 이메일 인증
처음 혼자 테스트할 때 이메일 확인 절차가 번거롭다면 Auth 설정에서 이메일 확인 정책을 확인할 수 있습니다. 실제 공개 서비스에서는 이메일 인증을 사용하는 편이 안전합니다.
배포 후 URL 설정
Cloudflare 배포 후 Supabase → Authentication → URL Configuration에서:
7. GitHub Private 저장소에 업로드
초보자에게 쉬운 GitHub Desktop 방법
터미널 방법
8. GitHub Private 저장소를 Cloudflare Pages에 연결
| 설정 | 값 |
|---|---|
| Production branch | main |
| Framework preset | None |
| Build command | exit 0 |
| Build output directory | public |
| Root directory | 비움 |
Cloudflare의 현재 Static HTML 안내에서도 build가 필요 없는 프로젝트에 exit 0과 정적 output directory 사용을 안내합니다. functions 폴더는 public 안이 아니라 저장소 최상위에 있어야 Pages Functions 라우트가 생성됩니다.
9. Cloudflare Variables and Secrets 설정
Pages 프로젝트 → Settings → Variables and Secrets → Add에서 아래 항목을 등록합니다. Production 환경부터 설정하세요. Preview도 실제 테스트하려면 동일하게 추가합니다.
| 이름 | 값 예시 | 권장 종류 |
|---|---|---|
| SUPABASE_URL | https://xxxxx.supabase.co | Variable |
| SUPABASE_PUBLISHABLE_KEY | sb_publishable_xxxxx | Variable |
| SUPABASE_SECRET_KEY | sb_secret_xxxxx | Secret |
| APP_ENCRYPTION_KEY | 32바이트 Base64 | Secret |
| GEMINI_MODEL | gemini-3.7-flash | Variable |
| GEMINI_THINKING_LEVEL | medium | Variable |
| GEMINI_API_REVISION | 2026-05-20 | Variable |
| MAX_ANALYSES_PER_DAY | 10 | Variable |
| GEMINI_API_KEY | 선택 fallback | Secret, 선택 |
10. APP_ENCRYPTION_KEY 1회 생성
이 키는 관리자 화면에서 Gemini API Key를 암호화/복호화하기 위한 마스터 키입니다. 32바이트를 Base64로 만든 값이어야 합니다.
가장 쉬운 방법 — Node.js가 설치되어 있을 때
출력된 문자열 전체를 Cloudflare의 APP_ENCRYPTION_KEY Secret에 저장합니다.
macOS / Linux 대안
11. 첫 관리자 계정 만들기
12. 관리자 화면에서 Gemini API Key 연결
Google AI Studio에서 API Key를 생성한 뒤 이 단계에서 저장합니다.
13. 최초 전체 동작 테스트
아래를 순서대로 하나씩 확인하세요.
- https://내주소/api/health 접속 — backend_ready: true 확인
- 회원가입/로그인 성공
- 관리자 페이지 Gemini 연결 테스트 성공
- 공개 영어 대화 YouTube URL 입력
- 최대 10/20/40개 옵션 중 하나로 분석 성공
- 분석 결과가 새로고침 후에도 최근 영상/보관함에 유지
- 문장별 ▶ 듣기 → 해당 구간으로 이동
- 반복 3회/5회/계속이 실제 문장 구간에서 동작
- 0.75× / 1.0× / 1.25× 속도 변경
- 일시정지 → 계속 듣기, 정지, 다시 듣기
- 문장 여러 개 선택 → 선택 문장 연속 듣기
- 영문/한국어 가리기
- 받아쓰기 정답/재시도
- 중요 ★, 헷갈림 ?, 외웠어요, 개인 메모 저장
- 보관함에서 중요/헷갈림/외움/복습 예정 필터
- 통계에서 전체/1일/7일/30일/1년 전환
- 본인 영상 공개 → 다른 일반 계정의 공개 학습에 표시
- 관리자에서 공개 영상 숨김 → 일반 커뮤니티에서 사라짐
- 관리자 전체 표현 통계 → 추천 추가 → 공식 추천에 노출
14. 일반 사용자 앱 사용법
가장 기본 사용
- 로그인
- 홈에서 YouTube URL 붙여넣기
- 학습량 10/20/40 선택
- 영어 교재 만들기
- AI 분석 결과는 자동 저장
- 각 표현의 영상 원음을 듣고 표시/복습
영어 듣기 학습 기능
- 문장별 정확한 영상 구간 재생
- 1·3·5회·계속 반복
- 느린 0.75배 듣기
- 여러 표현 체크 후 순차 재생
- 영문 숨기기 → 귀로 먼저 듣기
- 한국어 숨기기 → 의미 떠올리기
- 받아쓰기 → 실제 문장 복원 연습
장기 복습 기능
중요/헷갈림/외움 상태, 메모, 반복/듣기 횟수, 복습 예정일이 계정에 축적됩니다. 같은 영상 URL을 다시 넣으면 저장된 교재를 열어 불필요한 AI 호출을 줄입니다.
15. 관리자 센터 사용법
| 탭 | 할 수 있는 일 |
|---|---|
| 운영 설정 | 공개 학습 전체 ON/OFF, 사용자 공개 허용, 전체 통계 공개, 공식 제목 |
| Gemini API | 키 상태, 후보 연결 테스트, 암호화 저장, 교체, 삭제 |
| 전체 URL | 모든 사용자 업로드 영상 검색/페이지 조회, 공개 자료 숨김, 추천 영상 지정 |
| 전체 표현 | 모든 저장 영어 표현/번역/레벨/점수/사용자/영상 검색 |
| 전체 통계·추천 | 출현 영상 수, 사용자 수, AI 중요도, 듣기/반복/중요/헷갈림 통계, 공식 추천 표현 관리 |
16. 내 PC에서 수정하며 개발하기
Wrangler가 표시한 localhost 주소로 접속합니다.
17. 수정한 뒤 Cloudflare에 반영하는 방법
GitHub 연동이 끝나면 배포는 매우 단순합니다.
Cloudflare Dashboard의 Deployments에서 성공/실패 여부를 확인하세요.
18. 자주 생기는 문제 해결
화면에 “초기 설정 필요”
public/assets/js/config.js의 Supabase URL/Publishable Key를 확인합니다.
/api/health가 503 또는 backend_ready=false
Cloudflare SUPABASE_URL / SUPABASE_PUBLISHABLE_KEY / SUPABASE_SECRET_KEY를 확인합니다. Gemini 키는 관리자 저장 전이라면 gemini_configured:false일 수 있습니다.
관리자에서 Gemini 키 저장 실패
APP_ENCRYPTION_KEY가 정확한 32바이트 Base64인지 확인합니다. 암호화 마스터 키 없이 관리자 저장은 허용되지 않습니다.
Supabase “Invalid JWT”
새 sb_secret_... 키를 Authorization Bearer로 직접 사용하는 외부 코드가 없는지 확인하세요. 이 프로젝트의 서버 helper는 새 Secret Key는 apikey로만 보내도록 구현되어 있습니다.
Functions 404
Cloudflare output은 public, functions 폴더는 저장소 root여야 합니다. Dashboard Direct Upload는 Pages Functions와 방식이 다르므로 이 프로젝트는 Git integration을 권장합니다.
YouTube 분석 실패
공개 영상인지 확인합니다. 비공개/일부공개는 직접 YouTube URL 입력이 지원되지 않습니다. API 무료 한도/일시 장애/영상 길이/Google 정책도 확인하세요.
같은 URL을 넣었는데 다시 분석되지 않음
의도한 동작입니다. 같은 계정의 동일 YouTube ID는 기존 교재를 엽니다. 향후 “재분석” 기능을 추가하면 모델/프롬프트 버전별 재생성이 가능합니다.
내 통계에 다른 사용자 데이터가 보임
v1.0.0에서는 개인 조회 함수에 user_id 필터를 명시했고 RLS도 함께 적용했습니다. 이전 버전을 설치했다면 최신 schema.sql과 소스 기준으로 재배포하세요.
19. 외부 공개 전 보안·운영 체크
- GitHub repository가 Private인지
- GitHub에 Gemini Key / sb_secret / 비밀번호가 없는지
- Supabase RLS가 켜져 있는지
- Cloudflare Secret에 SUPABASE_SECRET_KEY / APP_ENCRYPTION_KEY가 있는지
- 일반 계정으로 다른 사용자의 private video를 직접 읽을 수 없는지
- 일반 계정으로 analyses/expressions 원본을 직접 INSERT/UPDATE할 수 없는지
- 관리자 API가 일반 계정에 403을 반환하는지
- 공개 전환 기본값이 private인지
- 관리자 숨김 자료가 community에서 보이지 않는지
- 서비스 이용약관·개인정보 처리방침·Google/YouTube 약관을 실제 서비스 형태에 맞게 검토했는지
20. v1.0.0에서 알고 있어야 할 한계와 다음 개발 후보
- Google의 YouTube URL 직접 입력은 현재 Preview이므로 API 변경 가능성이 있습니다.
- AI가 추정한 문장 시작/끝 시간이 몇 초 어긋날 수 있습니다. 향후 자막/전사 타임코드 교차검증을 추가할 수 있습니다.
- 현재 받아쓰기는 텍스트 유사도 기반입니다. 발음 평가/마이크 녹음은 아직 포함하지 않았습니다.
- 현재 같은 URL은 저장된 교재를 우선합니다. 관리자 또는 사용자 재분석/버전 비교 UI는 후속 기능입니다.
- 대규모 공개 서비스가 되면 Cloudflare Turnstile, 더 정교한 abuse/rate limit, 감사 로그, 탈퇴/데이터 내보내기, 백업 정책을 추가하는 것이 좋습니다.
21. 백업·복구 — 꼭 설정해 두세요
이 앱은 시간이 지날수록 영상·영어표현·중요/헷갈림 표시·메모·복습기록이 쌓이므로 DB 백업이 매우 중요합니다.
A. 소스코드 백업
- GitHub Private 저장소 자체가 코드의 1차 백업입니다.
- 중요 변경 전에는 Git commit을 남기고 버전 태그를 만드세요. 예: v1.0.0.
- .dev.vars와 실제 Secret은 Git에 올리지 않습니다.
B. Supabase 데이터 백업
Supabase Dashboard의 Database 백업/내보내기 기능은 요금제와 시점에 따라 메뉴가 달라질 수 있습니다. 운영 전 현재 사용 중인 Supabase 플랜의 백업 정책을 확인하세요. 최소한 중요한 시점에는 아래 테이블 데이터를 별도로 내보내 보관하는 것을 권장합니다.
C. 복구 순서
- GitHub에서 정상 동작했던 코드 버전으로 되돌립니다.
- 새 Supabase 프로젝트를 만드는 경우 supabase/schema.sql을 먼저 실행합니다.
- 백업한 사용자/영상/표현/학습 데이터를 복구합니다.
- Cloudflare Variables/Secrets를 다시 등록합니다.
- 기존 암호화 Gemini 키를 복구한다면 동일한 APP_ENCRYPTION_KEY를 사용해야 합니다.
- /api/health → 로그인 → 저장영상 → 반복듣기 → 관리자 Gemini 테스트 순으로 확인합니다.
D. 실수로 잘못 배포했을 때
Cloudflare Pages Deployments에서 이전 성공 배포 상태를 확인하고, GitHub에서는 정상 commit으로 revert한 뒤 다시 push하는 방법이 가장 이해하기 쉽습니다. DB 스키마를 수정한 배포라면 코드만 되돌리지 말고 DB migration 영향도 함께 확인해야 합니다.
22. 장기 운영·업데이트 방법
업데이트 전 6단계
- GitHub에서 새 branch를 만들거나 현재 정상 버전에 tag를 남깁니다.
- Supabase DB를 백업합니다.
- 코드를 수정합니다.
- npm run check를 실행해 실패 0건인지 확인합니다.
- 가능하면 Preview 배포에서 일반 사용자/관리자 계정 각각으로 테스트합니다.
- 정상일 때 main에 반영합니다.
Gemini 모델이 바뀌었을 때
Cloudflare의 GEMINI_MODEL 값을 바꾸기 전에 Google AI Developer 공식 모델 문서에서 해당 모델이 Interactions API, YouTube URL 입력, Structured Output을 지원하는지 확인합니다. 무료 티어/요금/데이터 정책도 함께 확인하세요.
DB 구조를 바꿀 때
이미 사용 중인 서비스에서는 최신 schema.sql 전체를 무조건 다시 실행하기보다 변경분만 migration SQL로 적용하는 편이 안전합니다. 컬럼 삭제·타입 변경·RLS 정책 변경 전에는 반드시 백업합니다.
사용자가 많아질 때 추가 권장 기능
- Cloudflare Turnstile로 봇/무단 자동요청 방지
- 사용자·IP·시간대별 더 정교한 rate limit
- 관리자 감사 로그
- 회원 탈퇴와 내 데이터 삭제/내보내기
- DB 정기 백업·복구 리허설
- Gemini 비용/무료한도 사용량 모니터링
- AI 분석 재시도 큐와 실패 로그
- 프롬프트/모델 버전별 재분석 및 결과 비교