비전공자용 · 처음부터 배포까지

TubeEnglish Study v1.0.0
설치·DB·GitHub·Cloudflare 완전 가이드

YouTube URL만 입력하면 Gemini가 실제 영어 대화에서 학습할 표현을 골라 저장하고, 영상 원음을 반복해서 공부하는 웹앱입니다. 아래 순서를 위에서 아래로 그대로 따라 하면 됩니다.

0. 시작 전에 준비할 것

아래 계정 4개만 있으면 됩니다. 모두 처음에는 무료 플랜으로 시작할 수 있습니다.

서비스용도주소
GitHub소스코드 Private 저장소github.com
Cloudflare웹 호스팅 + 서버 APIdash.cloudflare.com
Supabase로그인 + PostgreSQL DBsupabase.com
Google AI StudioGemini API Keyaistudio.google.com
추천: 우선 본인 혼자 테스트하고, 모든 기능이 정상임을 확인한 뒤 가족/지인 계정을 추가하세요.

1. 앱의 전체 구조

① 사용자 스마트폰 / 태블릿 / PC
② Cloudflare Pages — HTML / CSS / JavaScript
③ Cloudflare Pages Functions — 로그인 확인, Gemini 호출, 안전한 DB 저장
④ Gemini 3.7 Flash — 공개 YouTube URL 분석
⑤ Supabase — 사용자·영상·표현·복습·통계 장기 저장
중요한 보안 설계
브라우저에는 Supabase Publishable Key만 있습니다. Gemini API Key와 Supabase Secret Key는 Cloudflare 서버 영역에만 있습니다. AI 분석 원본은 브라우저가 직접 DB에 INSERT할 수 없고 서버 전용 저장 함수가 한 번의 DB transaction으로 저장합니다.

2. ZIP을 풀고 파일 확인

압축을 풀면 아래처럼 보여야 합니다.

TubeEnglish-Study-v1.0.0/ ├─ public/ │ ├─ index.html 일반 사용자 앱 │ ├─ admin.html 관리자 센터 │ ├─ _headers 보안 헤더 │ ├─ assets/css/ 반응형 UI │ ├─ assets/js/ 프론트엔드 기능 │ └─ docs/SETUP_GUIDE.html 지금 보고 있는 설명서 ├─ functions/ │ ├─ api/analyze.js Gemini 분석 + 서버 DB 저장 │ ├─ api/health.js 서버 설정 확인 │ ├─ api/admin/ 관리자 API │ ├─ api/community/ 공개 학습 API │ ├─ api/settings/ Gemini 키 관리 API │ └─ _lib/, _shared/ 공통 서버 코드/프롬프트/JSON Schema ├─ supabase/schema.sql DB·RLS·통계·RPC 전체 SQL ├─ scripts/check.mjs 자동 정적검사 ├─ .dev.vars.example 로컬 서버 설정 예시 ├─ wrangler.toml ├─ package.json ├─ README.md └─ TEST_REPORT.md
실제 Secret을 파일에 쓰지 마세요. SUPABASE_SECRET_KEY, APP_ENCRYPTION_KEY, Gemini API Key는 GitHub에 올리면 안 됩니다.

3. Supabase 프로젝트 만들기

1
Supabase 로그인 → New project

새 프로젝트를 만듭니다. 예: tubeenglish-study.

2
Database Password 보관

길고 안전한 비밀번호를 만들어 별도 비밀번호 관리자에 보관하세요.

3
Region 선택

주 사용자가 한국이라면 가능한 가까운 Asia region을 선택하세요.

4
프로젝트 준비 완료 확인

왼쪽에 SQL Editor / Table Editor / Authentication이 보이면 됩니다.

4. Supabase DB를 한 번에 설치

1
supabase/schema.sql을 VS Code나 메모장으로 엽니다.
2
Ctrl+ACtrl+C로 전체 복사합니다.
3
Supabase → SQL EditorNew query → 붙여넣기 → Run.

설치되는 핵심 테이블은 다음과 같습니다.

테이블역할
profiles사용자 표시명과 user/admin 역할
videosYouTube 영상, 공개/비공개, 관리자 숨김/추천
analysesGemini 분석 JSON 원본과 버전
expressions개별 영어 표현, 타임스탬프, CEFR, AI 점수, 대표형
user_expression_progress중요/헷갈림/외움, 듣기·반복·받아쓰기, 개인 메모, 복습일
study_events장기 학습 이벤트 통계
app_settings커뮤니티 운영 설정
app_secretsGemini 키의 AES-GCM 암호문만 저장
community_recommendations관리자 공식 추천 표현
schema.sql은 RLS도 설치합니다. 일반 사용자는 자신의 비공개 데이터만 보고, 공개 전환된 학습자료만 다른 사용자에게 보입니다.
새 프로젝트에서 먼저 실행하는 것을 권장합니다. 기존에 같은 이름의 자체 테이블/함수가 있는 Supabase에 합치려면 별도 마이그레이션 검토가 필요합니다.

5. 브라우저용 Supabase 정보 입력

Cloudflare 환경변수는 서버 Functions용입니다. 정적 브라우저 JavaScript에는 별도로 Supabase Project URL과 Publishable Key를 넣어야 합니다.

1
Supabase Dashboard의 Connect 또는 Settings → API Keys에서 Project URLPublishable key를 복사합니다.
2
public/assets/js/config.js를 열어 아래 두 값만 바꿉니다.
export const APP_CONFIG = { SUPABASE_URL: 'https://xxxxx.supabase.co', SUPABASE_PUBLISHABLE_KEY: 'sb_publishable_xxxxx' };
Publishable Key는 웹/모바일 같은 공개 클라이언트용 키입니다. Secret Key와 완전히 다릅니다. RLS를 반드시 함께 사용해야 합니다.
절대 금지: 여기에 sb_secret_..., legacy service_role, Gemini API Key를 넣지 마세요.

6. Supabase 로그인 설정

이메일 로그인

Supabase → Authentication → Providers에서 Email provider가 켜져 있는지 확인합니다.

테스트 중 이메일 인증

처음 혼자 테스트할 때 이메일 확인 절차가 번거롭다면 Auth 설정에서 이메일 확인 정책을 확인할 수 있습니다. 실제 공개 서비스에서는 이메일 인증을 사용하는 편이 안전합니다.

배포 후 URL 설정

Cloudflare 배포 후 Supabase → Authentication → URL Configuration에서:

Site URL https://내프로젝트.pages.dev Redirect URLs (로컬 개발을 할 경우 추가) http://localhost:8788/**

7. GitHub Private 저장소에 업로드

초보자에게 쉬운 GitHub Desktop 방법

1
GitHub Desktop 설치 후 로그인.
2
File → Add Local Repository. 저장소가 아니라는 안내가 나오면 Create a repository를 선택해 이 프로젝트 폴더를 지정합니다.
3
첫 Commit을 만든 뒤 Publish repository.
4
Keep this code private가 체크되어 있는지 확인한 뒤 업로드합니다.
업로드 전 프로젝트 전체에서 실제 AIza...sb_secret_... 키를 직접 적은 적이 없는지 확인하세요. 이 배포본에는 실제 키가 포함되어 있지 않습니다.

터미널 방법

git init git add . git commit -m "TubeEnglish Study v1.0.0" git branch -M main git remote add origin https://github.com/내계정/내저장소.git git push -u origin main

8. GitHub Private 저장소를 Cloudflare Pages에 연결

1
Cloudflare Dashboard → Workers & Pages → Pages 프로젝트 생성/기존 Git repository 연결.
2
GitHub 권한을 연결하고 방금 만든 Private repository를 선택합니다.
3
빌드 설정을 아래처럼 입력합니다.
설정
Production branchmain
Framework presetNone
Build commandexit 0
Build output directorypublic
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_URLhttps://xxxxx.supabase.coVariable
SUPABASE_PUBLISHABLE_KEYsb_publishable_xxxxxVariable
SUPABASE_SECRET_KEYsb_secret_xxxxxSecret
APP_ENCRYPTION_KEY32바이트 Base64Secret
GEMINI_MODELgemini-3.7-flashVariable
GEMINI_THINKING_LEVELmediumVariable
GEMINI_API_REVISION2026-05-20Variable
MAX_ANALYSES_PER_DAY10Variable
GEMINI_API_KEY선택 fallbackSecret, 선택
추천 방식: GEMINI_API_KEY는 Cloudflare에 넣지 않아도 됩니다. 먼저 APP_ENCRYPTION_KEY까지 설정하고 관리자 계정을 만든 뒤, 앱 관리자 화면에서 Gemini 키를 테스트→저장하면 됩니다.
Supabase 새 Secret Key 호환: 이 코드에서는 새 sb_secret_... 키를 apikey header로 사용하고 Bearer JWT로 잘못 보내지 않게 처리했습니다. legacy service_role JWT도 방어적으로 호환합니다.

10. APP_ENCRYPTION_KEY 1회 생성

이 키는 관리자 화면에서 Gemini API Key를 암호화/복호화하기 위한 마스터 키입니다. 32바이트를 Base64로 만든 값이어야 합니다.

가장 쉬운 방법 — Node.js가 설치되어 있을 때

node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"

출력된 문자열 전체를 Cloudflare의 APP_ENCRYPTION_KEY Secret에 저장합니다.

macOS / Linux 대안

openssl rand -base64 32
이 값을 나중에 임의로 바꾸지 마세요. 기존에 암호화해 저장한 Gemini Key를 복호화할 수 없게 됩니다. 비밀번호 관리자에 별도 백업하세요.

11. 첫 관리자 계정 만들기

1
Cloudflare 배포 주소에서 본인이 사용할 이메일로 회원가입합니다.
2
Supabase → SQL Editor에서 아래 SQL의 이메일만 본인 것으로 바꿔 실행합니다.
update public.profiles p set role = 'admin' from auth.users u where p.id = u.id and u.email = '내이메일@example.com';
3
앱에서 로그아웃 → 다시 로그인. 상단에 관리 버튼이 표시됩니다. 또는 https://내주소/admin.html.

12. 관리자 화면에서 Gemini API Key 연결

Google AI Studio에서 API Key를 생성한 뒤 이 단계에서 저장합니다.

1
Google AI Studio → API Key 메뉴에서 Gemini API Key 생성.
2
TubeEnglish 관리자 → Gemini API 탭 → 키 입력.
3
연결 테스트를 먼저 누릅니다. 후보 키는 이때 DB에 저장되지 않습니다.
4
성공하면 테스트 후 안전하게 저장을 누릅니다.
5
저장 후 키 전체 대신 마지막 4자리, 사용 모델, 마지막 테스트 상태만 표시됩니다.
저장 과정: 브라우저 → Cloudflare 관리자 API → AES-GCM 암호화 → Supabase app_secrets에는 ciphertext/IV/last4만 저장. 실제 Gemini Key 평문은 브라우저로 다시 반환하지 않습니다.
기본 모델은 현재 코드 기준 gemini-3.7-flash, 기본 thinking level은 medium입니다. 모델이 바뀌면 Cloudflare GEMINI_MODEL만 바꿀 수 있습니다.

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년 전환
  • 본인 영상 공개 → 다른 일반 계정의 공개 학습에 표시
  • 관리자에서 공개 영상 숨김 → 일반 커뮤니티에서 사라짐
  • 관리자 전체 표현 통계 → 추천 추가 → 공식 추천에 노출
YouTube URL 직접 입력 기능은 Google 문서상 Preview 기능입니다. 공개 영상만 지원되며 Google 측 기능/한도 변경 가능성이 있습니다.

14. 일반 사용자 앱 사용법

가장 기본 사용

  1. 로그인
  2. 홈에서 YouTube URL 붙여넣기
  3. 학습량 10/20/40 선택
  4. 영어 교재 만들기
  5. AI 분석 결과는 자동 저장
  6. 각 표현의 영상 원음을 듣고 표시/복습

영어 듣기 학습 기능

  • 문장별 정확한 영상 구간 재생
  • 1·3·5회·계속 반복
  • 느린 0.75배 듣기
  • 여러 표현 체크 후 순차 재생
  • 영문 숨기기 → 귀로 먼저 듣기
  • 한국어 숨기기 → 의미 떠올리기
  • 받아쓰기 → 실제 문장 복원 연습

장기 복습 기능

중요/헷갈림/외움 상태, 메모, 반복/듣기 횟수, 복습 예정일이 계정에 축적됩니다. 같은 영상 URL을 다시 넣으면 저장된 교재를 열어 불필요한 AI 호출을 줄입니다.

15. 관리자 센터 사용법

할 수 있는 일
운영 설정공개 학습 전체 ON/OFF, 사용자 공개 허용, 전체 통계 공개, 공식 제목
Gemini API키 상태, 후보 연결 테스트, 암호화 저장, 교체, 삭제
전체 URL모든 사용자 업로드 영상 검색/페이지 조회, 공개 자료 숨김, 추천 영상 지정
전체 표현모든 저장 영어 표현/번역/레벨/점수/사용자/영상 검색
전체 통계·추천출현 영상 수, 사용자 수, AI 중요도, 듣기/반복/중요/헷갈림 통계, 공식 추천 표현 관리
전체 통계는 “표현 출현 집계”와 “사용자 학습 행동 집계”를 먼저 따로 계산한 뒤 결합해, 한 표현에 여러 사용자의 progress가 붙어 출현 횟수가 뻥튀기되는 문제를 방지했습니다.

16. 내 PC에서 수정하며 개발하기

1
Node.js LTS와 VS Code를 설치합니다.
2
프로젝트 폴더에서 터미널을 열고:
npm install npm run check
3
.dev.vars.example을 복사하여 .dev.vars를 만들고 본인 서버 설정값을 입력합니다.
SUPABASE_URL="https://xxxxx.supabase.co" SUPABASE_PUBLISHABLE_KEY="sb_publishable_xxxxx" SUPABASE_SECRET_KEY="sb_secret_xxxxx" APP_ENCRYPTION_KEY="생성한_Base64_키" GEMINI_MODEL="gemini-3.7-flash" GEMINI_THINKING_LEVEL="medium" GEMINI_API_REVISION="2026-05-20" MAX_ANALYSES_PER_DAY="10" # GEMINI_API_KEY="선택 fallback"
4
public/assets/js/config.js에도 브라우저용 URL/Publishable Key를 입력합니다.
5
실행:
npm run dev

Wrangler가 표시한 localhost 주소로 접속합니다.

17. 수정한 뒤 Cloudflare에 반영하는 방법

GitHub 연동이 끝나면 배포는 매우 단순합니다.

VS Code에서 파일 수정
npm run check
Git Commit + Push to main
Cloudflare Pages가 자동 build/deploy
git add . git commit -m "Improve study feature" git push

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 약관을 실제 서비스 형태에 맞게 검토했는지
무료 Gemini 데이터 정책: 무료 티어의 가격·한도·데이터 사용 정책은 변할 수 있으므로 실제 외부 서비스 공개 직전에 Google AI Developer 공식 가격/약관 페이지를 다시 확인하세요.

20. v1.0.0에서 알고 있어야 할 한계와 다음 개발 후보

  • Google의 YouTube URL 직접 입력은 현재 Preview이므로 API 변경 가능성이 있습니다.
  • AI가 추정한 문장 시작/끝 시간이 몇 초 어긋날 수 있습니다. 향후 자막/전사 타임코드 교차검증을 추가할 수 있습니다.
  • 현재 받아쓰기는 텍스트 유사도 기반입니다. 발음 평가/마이크 녹음은 아직 포함하지 않았습니다.
  • 현재 같은 URL은 저장된 교재를 우선합니다. 관리자 또는 사용자 재분석/버전 비교 UI는 후속 기능입니다.
  • 대규모 공개 서비스가 되면 Cloudflare Turnstile, 더 정교한 abuse/rate limit, 감사 로그, 탈퇴/데이터 내보내기, 백업 정책을 추가하는 것이 좋습니다.
현재 버전의 목표: 개인/가족/소규모 사용자로 실제 학습 효과와 사용성을 충분히 검증할 수 있는 안전한 MVP를 완성하는 것입니다.

21. 백업·복구 — 꼭 설정해 두세요

이 앱은 시간이 지날수록 영상·영어표현·중요/헷갈림 표시·메모·복습기록이 쌓이므로 DB 백업이 매우 중요합니다.

A. 소스코드 백업

  • GitHub Private 저장소 자체가 코드의 1차 백업입니다.
  • 중요 변경 전에는 Git commit을 남기고 버전 태그를 만드세요. 예: v1.0.0.
  • .dev.vars와 실제 Secret은 Git에 올리지 않습니다.

B. Supabase 데이터 백업

Supabase Dashboard의 Database 백업/내보내기 기능은 요금제와 시점에 따라 메뉴가 달라질 수 있습니다. 운영 전 현재 사용 중인 Supabase 플랜의 백업 정책을 확인하세요. 최소한 중요한 시점에는 아래 테이블 데이터를 별도로 내보내 보관하는 것을 권장합니다.

profiles videos analyses expressions user_expression_progress study_events app_settings community_recommendations
app_secrets 주의: Gemini 키 암호문을 백업하더라도 Cloudflare의 APP_ENCRYPTION_KEY가 없으면 복호화할 수 없습니다. 이 마스터 키는 비밀번호 관리자 등 안전한 장소에 별도로 백업하세요.

C. 복구 순서

  1. GitHub에서 정상 동작했던 코드 버전으로 되돌립니다.
  2. 새 Supabase 프로젝트를 만드는 경우 supabase/schema.sql을 먼저 실행합니다.
  3. 백업한 사용자/영상/표현/학습 데이터를 복구합니다.
  4. Cloudflare Variables/Secrets를 다시 등록합니다.
  5. 기존 암호화 Gemini 키를 복구한다면 동일한 APP_ENCRYPTION_KEY를 사용해야 합니다.
  6. /api/health → 로그인 → 저장영상 → 반복듣기 → 관리자 Gemini 테스트 순으로 확인합니다.

D. 실수로 잘못 배포했을 때

Cloudflare Pages Deployments에서 이전 성공 배포 상태를 확인하고, GitHub에서는 정상 commit으로 revert한 뒤 다시 push하는 방법이 가장 이해하기 쉽습니다. DB 스키마를 수정한 배포라면 코드만 되돌리지 말고 DB migration 영향도 함께 확인해야 합니다.

22. 장기 운영·업데이트 방법

업데이트 전 6단계

  1. GitHub에서 새 branch를 만들거나 현재 정상 버전에 tag를 남깁니다.
  2. Supabase DB를 백업합니다.
  3. 코드를 수정합니다.
  4. npm run check를 실행해 실패 0건인지 확인합니다.
  5. 가능하면 Preview 배포에서 일반 사용자/관리자 계정 각각으로 테스트합니다.
  6. 정상일 때 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 분석 재시도 큐와 실패 로그
  • 프롬프트/모델 버전별 재분석 및 결과 비교
운영 원칙: 이 서비스의 가장 중요한 자산은 시간이 지나며 쌓이는 학습 데이터입니다. 새 기능보다 먼저 “기존 사용자 데이터가 사라지지 않는가”를 확인하세요.