TrendShift 딥다이브 · 2026-06-30

exercises-dataset 딥다이브
— 1,324개 운동이 통째로 박힌 단일 HTML 운동 백과사전

exercises-dataset는 운동 1,324개를 이름·부위·기구·근육·6개 언어 설명·썸네일·움직임 GIF까지 묶어 바로 쓸 수 있게 정리한 데이터셋이다. 그런데 진짜 흥미로운 건 데이터 자체보다 포장 방식이다 — 서버도, 빌드도, 외부 라이브러리도 없이 HTML 파일 하나(index.html)를 더블클릭하면 검색·필터·무한스크롤이 되는 운동 탐색기가 열리고, 또 다른 파일(setup.html)은 이 데이터를 내 백엔드로 옮기는 SQL·API 코드·LLM 프롬프트를 브라우저 안에서 만들어 준다. "데이터셋을 제품처럼 포장하는 법"의 교과서다. (저장소: hasaneyldrm/exercises-dataset · HTML/JSON · ★249 · 포크 45 · 교육·비상업 전용)
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

이 저장소가 대체 무엇인가.

핵심 메시지

"운동 1,324개짜리 백과사전인데, 데이터베이스도 서버도 없다.
JSON 한 덩어리 + HTML 한 장이 곧 검색되는 앱이다."

이 저장소는 헬스·홈트 운동 1,324개를 정리한 데이터 모음이다. 각 운동은 이름, 대상 부위(가슴·등·하체 등), 필요한 기구(맨몸·덤벨·바벨 등), 주동근/협응근, 6개 언어 단계별 설명, 정지 썸네일(JPG), 동작 GIF까지 빠짐없이 들어 있다.

기술적으로 특이한 건 전달 방식이다. 보통 이런 데이터는 "JSON 파일 받아서 알아서 쓰세요"로 끝난다. 그런데 여기엔 데이터를 통째로 품은 단일 HTML 앱(index.html)과, 데이터를 내 서비스로 옮기는 작업을 자동화하는 개발자 온보딩 페이지(setup.html)가 함께 들어 있다.

즉 이 저장소는 세 덩어리다. ① 데이터(data/exercises.json) — 1,324개 운동의 모든 정보. ② 탐색기(index.html) — 그 데이터를 검색·필터·상세보기로 둘러보는 앱. ③ 온보딩 도구(setup.html) — 데이터를 DB에 넣고 API로 감싸는 코드를 자동 생성. 데이터셋 하나가 "받아쓰기 자료 + 데모 앱 + 통합 가이드"를 한 저장소에 다 갖춘 보기 드문 구성이다.

용어
데이터셋 (Dataset)
어떤 주제의 데이터를 일정한 형식으로 모아 둔 것. 여기선 "운동 한 개 = 레코드(record) 한 줄", 그 레코드 1,324개가 모인 JSON 배열이 데이터셋이다. 엑셀 한 시트가 표라면, JSON 배열은 "프로그램이 읽기 좋은 표"라고 보면 된다.
용어
JSON (제이슨, JavaScript Object Notation)
데이터를 { "이름": "값" } 형태로 적는 텍스트 형식. 사람도 읽고 거의 모든 언어(파이썬·자바스크립트·자바…)가 바로 불러올 수 있어, 프로그램끼리 데이터를 주고받는 공용어처럼 쓰인다.

2왜 주목받는가

트렌딩 이유 · 경쟁 자료 대비 장점.

① 즉시 완성형 데이터 · ② 무서버·무빌드 데모 · ③ "데이터셋을 제품처럼" 포장한 온보딩, 이 셋이 이 저장소를 TrendShift 상위로 끌어올렸다. 운동 앱·홈트 서비스·AI 코치를 만들려는 사람에게 "가장 귀찮은 첫 단계(데이터 모으기)"를 통째로 건너뛰게 해 주기 때문이다.

비교 대상한계exercises-dataset의 접근
운동 API (ExerciseDB 등)요청 수 제한·API 키·유료 플랜. 인터넷 끊기면 못 씀정적 JSON+미디어라 무제한·오프라인. 한 번 받으면 끝
직접 스크래핑사이트마다 구조 달라 수집·정제에 며칠1,324개가 동일 스키마로 이미 정제됨
흩어진 운동 자료설명만 있고 이미지/GIF 없음, 언어 1개썸네일+GIF+6개 언어 설명을 레코드마다 포함
일반 데이터셋(CSV만)"데모로 보여줄" 수단이 없어 감이 안 옴더블클릭으로 열리는 탐색기 + DB/API 생성기 동봉

데이터 품질도 단단하다. 1,324개 레코드 전부가 13개 필드를 100% 채우고 있다 — 빈칸(null)이 없다. 설명은 영어·이탈리아어·터키어·스페인어·러시아어·중국어 6개 언어가 모두 들어 있고, 썸네일과 GIF도 1,324개씩 빠짐없이 매칭된다. "받아서 바로 화면에 꽂을 수 있는" 상태라는 뜻이다.

기존 방식의 함정
"운동 데이터 좀 구하자"가 프로젝트를 멈춘다

운동 앱을 만들려면 운동 목록·부위 분류·시범 이미지가 필요한데, 막상 모으려면 외부 API는 요청 제한과 과금이 걸리고, 직접 스크래핑은 법적·기술적으로 번거롭다. 많은 토이 프로젝트가 바로 이 "데이터 확보" 단계에서 멈춘다.

exercises-dataset의 해결
데이터·데모·통합코드를 한 번에

클론 한 번이면 1,324개 운동 데이터와 미디어가 손에 들어오고, index.html로 바로 둘러보고, setup.html로 DB·API 코드를 뽑아 내 서비스에 붙인다. "데이터 → 데모 → 통합"의 거리가 거의 0이다.

반드시 짚을 것 — 라이선스
교육·비상업 전용, 상업적 사용 금지

저장소는 "교육 및 비상업적 연구 목적"으로만 제공된다고 명시한다. 이미지·GIF는 각 원저작권자의 것이고 상업적 사용은 금지다(README의 Disclaimer·License). created_at이 전부 한 날짜(2026-03-18)인 점으로 보아 외부 출처에서 일괄 수집·정제된 집합물이다. 학습·프로토타입엔 훌륭하지만, 제품에 그대로 실으려면 미디어 저작권을 따로 해결해야 한다.

3기술 스택 전체 지도

반전 — "프레임워크가 0개"라는 게 핵심이다.

화려한 스택 목록을 기대했다면 또 한 번 김이 샌다. 이 저장소의 코드는 의존성 0개다 — React도, 빌드 도구도, 차트 라이브러리도 없다. 1,324개를 검색·필터하는 앱이 순수 HTML·CSS·바닐라 자바스크립트만으로 돌아간다. GitHub가 매긴 언어 비율이 HTML 100.0%인 이유다.

레이어기술 / 구성역할
데이터(원본)data/exercises.json9.3MB·1,324 레코드. 13개 필드 100% 채움. 단일 진실원(Single Source of Truth).
탐색기 앱index.html (바닐라 JS)8.7MB. 데이터를 파일 안에 통째로 inlinefetch() 없이 동작. 검색·필터·무한스크롤·상세 모달.
온보딩 도구setup.html (바닐라 JS)60KB. 브라우저 안에서 SQL·다국어 API 코드·LLM 프롬프트를 생성. 외부 라이브러리 0.
미디어images/ · videos/썸네일 JPG 1,324개 + 동작 GIF 1,324개. 레코드의 image/gif_url이 상대경로로 가리킴.
스타일인라인 <style> + CSS 변수디자인 토큰(--accent:#ff4f00 등)·CSS Grid 레이아웃. 외부 CSS 프레임워크 없음.
빌드 / 번들없음webpack·vite·npm 스크립트 부재. 파일을 그대로 열면 끝.
서버 / DB없음백엔드·데이터베이스 0. 필요하면 setup.html로 "내가" 만들어 붙이는 구조.
용어
바닐라 JS (Vanilla JavaScript)
React·Vue 같은 프레임워크 없이 브라우저에 기본 내장된 순수 자바스크립트만 쓰는 것. "아무것도 안 얹은 기본 맛(바닐라)"이라는 농담에서 온 말. 의존성이 없어 가볍고, 몇 년 뒤에도 그대로 열린다.
용어
데이터 인라이닝 (Data Inlining)
데이터를 별도 파일로 불러오지(fetch) 않고 HTML/JS 코드 안에 직접 박아 넣는 것. index.html은 9MB 데이터를 통째로 품어서, 인터넷·서버 없이 파일 하나만 열어도 완전히 동작한다. 대가는 파일이 무거워진다는 것(8.7MB).

4아키텍처 심화 분석

"JSON 한 덩어리"가 두 갈래로 쓰이는 길을 따라가기.

이 저장소의 심장은 exercises.json 하나다. 그 데이터가 두 방향으로 흐른다 — 왼쪽은 "보여주기"(탐색기), 오른쪽은 "넘겨주기"(내 백엔드로). 먼저 전체 그림을 한 장으로 보자.

┌─────────────────────────────────────────────────────────────────────┐ │ exercises-dataset 시스템 전체 │ │ │ │ ┌──────────────────────────────┐ │ │ │ data/exercises.json │ ← 단일 진실원 │ │ │ 1,324 레코드 · 13 필드 │ │ │ │ 6개 언어 · 9.3MB │ │ │ └───────┬──────────────┬───────┘ │ │ 빌드 때 통째로 inline │ │ 읽어서 코드로 변환 │ │ ▼ ▼ │ │ ┌──────────────────────┐ ┌──────────────────────────┐ │ │ │ index.html (탐색기) │ │ setup.html (온보딩 도구) │ │ │ │ │ │ │ │ │ │ EXERCISES = [...] │ │ ① CREATE TABLE 생성 │ │ │ │ (데이터 inline) │ │ ② INSERT .sql 다운로드 │ │ │ │ │ │ │ ③ 7개 언어 API 코드 │ │ │ │ ▼ 검색·필터 │ │ ④ "LLM에게 물어보기" │ │ │ │ ▼ 그리드(60개씩) │ │ 백엔드 생성 프롬프트 │ │ │ │ ▼ 무한 스크롤 │ └────────────┬─────────────┘ │ │ │ ▼ 상세 모달(6개 언어)│ │ 복사/다운로드 │ │ └──────────┬───────────┘ ▼ │ │ │ 미디어 상대경로 ┌──────────────────────────┐ │ │ ▼ │ 내 백엔드 (직접 구현) │ │ │ ┌──────────────────────┐ │ DB + REST API + 서버 │ │ │ │ images/*.jpg │ └──────────────────────────┘ │ │ │ videos/*.gif (hover시)│ │ │ └──────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘

핵심 설계는 "데이터는 한 곳, 쓰임은 여러 곳"이다. JSON 원본이 진실원이고, index.html은 그걸 화면으로, setup.html은 그걸 코드로 바꾼다. 이제 가장 대표적인 흐름 "탐색기에서 운동을 검색하고 상세를 여는" 한 줄기를 입력부터 화면까지 손으로 따라가 보자.

흐름 추적 — 검색창에 "press"를 치면 무슨 일이 벌어지나

// index.html 의 동작 순서 (개념 발췌)
// ① 앱이 켜질 때: 데이터를 받고, 검색용 색인을 미리 만든다
state.exercises = EXERCISES;
state.exercises.forEach(ex => {
  ex._idx = `${ex.name} ${ex.category} ${ex.target} ${ex.equipment} ${ex.muscle_group}`.toLowerCase();
});                          // 검색할 때마다 만들지 않고, 한 번만 합쳐 둔다

// ② 사용자가 타이핑 → 250ms 멈추면 한 번만 실행(debounce)
searchEl.addEventListener('input', debounce(() => {
  state.search = searchEl.value;   applyFilters();
}, 250));

// ③ 필터 적용: 검색어 + 카테고리/기구/타깃(다중선택)을 모두 통과한 것만
state.filtered = state.exercises.filter(ex => {
  if (q && !ex._idx.includes(q)) return false;          // 미리 만든 색인에서 부분일치
  if (category.size && !category.has(ex.category)) return false;
  return true;
});

// ④ 화면엔 처음 60개만 그린다(페이지네이션)
const slice = state.filtered.slice(0, state.pageSize);   // pageSize = 60

여기서 멈추지 않는다. 사용자가 스크롤을 내리면 화면 맨 아래의 보이지 않는 "감지선"이 뷰포트에 들어오고, 그걸 IntersectionObserver가 알아채 다음 60개를 이어 붙인다(appendNextPage). 카드에 마우스를 올리면 그제서야 무거운 GIF를 불러오고(mouseovergif.src = data-src), 카드를 클릭하면 상세 모달이 열려 6개 언어 탭으로 단계별 설명을 보여 준다.

비유 — 뷔페와 미리 만든 이름표

검색 색인(_idx)을 미리 만드는 건, 뷔페에서 모든 접시에 "치킨·매움·닭고기" 같은 이름표를 미리 붙여 두는 것과 같다. 손님이 "매운 거"를 찾을 때 접시를 하나씩 들춰 재료를 확인하는(매번 문자열을 합치는) 대신, 붙은 이름표만 슥 보면 된다. 무한 스크롤은 "접시를 한 번에 다 깔지 않고, 손님이 끝에 다다르면 다음 판을 내오는" 것 — 1,324개를 한꺼번에 그리면 브라우저가 버벅이니까.

이 아키텍처의 핵심 설계 패턴 5가지

패턴설명 · 어디서 배우나
데이터 인라이닝9MB JSON을 index.html에 통째로 박아 fetch·서버 없이 자기완결. 대가는 무거운 파일.
사전계산 검색 색인앱 시작 때 운동마다 _idx(합친 소문자 문자열)를 1회 생성 → 타이핑마다 부분일치만. 매번 재가공 안 함.
디바운스(debounce)타이핑이 250ms 멈춰야 필터 실행. 글자마다 1,324개를 훑는 낭비를 막음.
페이지네이션 + IntersectionObserver한 번에 60개만 렌더, 끝에 닿으면 다음 판 추가. DOM 폭증 방지.
지연 로딩(lazy) + 이벤트 위임썸네일은 loading="lazy", GIF는 hover 때만 로드. 클릭/hover는 그리드에 한 번만 건다.
트레이드오프 (공짜는 아니다)
8.7MB 단일 HTML의 대가

데이터를 inline한 덕에 "서버 없이 더블클릭으로 열림"을 얻었지만, 대신 ① 첫 로딩에 8.7MB를 통째로 받아 파싱하고, ② 데이터가 바뀌면 HTML을 다시 구워야 하며(데이터·표현이 한 파일에 묶임), ③ 검색은 includes() 단순 부분일치라 오타·동의어엔 약하다. 데이터 규모가 이 단순함이 감당할 선(수천 개)이라 성립하는 선택이다.

5디렉토리 구조 해부

루트 파일 몇 개 + 미디어 폴더 둘 — 전부 본다.

exercises-dataset/ ├── data/ │ └── exercises.json ★ 데이터 본체. 1,324 레코드 · 9.3MB · 6개 언어 ├── images/ 썸네일 JPG 1,324개 (예: 0001-2gPfomN.jpg) ├── videos/ 동작 GIF 1,324개 (예: 0001-2gPfomN.gif) — 이름은 썸네일과 짝 ├── index.html 탐색기 앱 (데이터 inline · 8.7MB · 바닐라 JS) ├── setup.html 개발자 온보딩 (SQL/API/LLM 프롬프트 생성 · 60KB) ├── README.md 소개·통계·스키마·사용 예제 (21KB) └── .gitignore __pycache__, *.pyc, .DS_Store, .venv/, *.zip
경로역할 요약
data/exercises.json저장소의 심장. 운동 1,324개가 동일 스키마(13필드)로. 모든 화면·코드가 결국 이 파일을 가리킨다.
images/각 운동의 정지 썸네일. 파일명은 {id}-{해시}.jpg. 레코드의 image 필드가 상대경로로 참조.
videos/동작 시범 GIF. 썸네일과 같은 베이스 이름({id}-{해시}.gif)이라 짝을 맞추기 쉽다. 레코드의 gif_url이 참조.
index.html데이터를 품은 탐색기 SPA. 의존성 0. 더블클릭이면 끝.
setup.html"이 데이터를 내 서비스에 넣는 법"을 자동화한 페이지. 3개 탭(DB·API·LLM).
README.md개요·통계·스키마·언어별 사용 예제. 단, 일부 수치가 실제 데이터와 다르다(아래 관찰).
관찰 — 문서보다 데이터를 믿어라
README 수치가 실제와 어긋난다
GitHub "About"엔 433개라고 적혀 있지만 실제 exercises.json1,324개다(저장소가 자란 뒤 설명만 안 고친 흔적). 또 README 스키마는 설명이 "영어·터키어 2개"라 하지만 실제 데이터엔 6개 언어(en·it·tr·es·ru·zh)가 들어 있다. 데이터셋을 쓸 땐 문서가 아니라 실제 파일을 직접 까 보는 습관이 중요하다는 좋은 사례.

6학습 포인트 (기술별)

이 저장소에서 진짜로 배울 것 + 어디를 보면 되는지.

포인트 1 · 프론트엔드

바닐라 JS로 수천 개 데이터 SPA 만들기 (의존성 0)

React 없이도 검색·다중필터·무한스크롤·모달이 다 된다. 상태 객체 하나(state)에 데이터/필터/페이지를 담고, "필터 → 슬라이스 → 렌더" 파이프라인으로 화면을 다시 그리는 전형적 패턴을 작은 코드로 읽을 수 있다. 프레임워크가 뒤에서 해 주던 일을 "직접" 보게 되는 게 핵심.

볼 파일: index.htmlapplyFilters()renderGrid() 흐름

포인트 2 · 성능

사전계산 색인 + 디바운스로 "빠른 검색" 만들기

검색이 느려지는 흔한 이유는 "글자 하나 칠 때마다 전체를 무겁게 재가공"하기 때문. 이 앱은 시작 때 운동마다 검색 문자열(_idx)을 한 번 만들어 두고(사전계산), 타이핑이 멈출 때만(디바운스) 부분일치를 돌린다. 두 기법의 교과서적 조합.

볼 파일: init()_idx 생성, debounce() 유틸

포인트 3 · 브라우저 API

IntersectionObserver 무한스크롤 + hover 지연 로딩

스크롤 위치를 직접 계산하지 않고, 화면 끝 "감지선"이 보이면 콜백이 도는 IntersectionObserver로 다음 페이지를 붙인다. 또 무거운 GIF는 카드에 마우스를 올릴 때만 로드해 데이터 낭비를 막는다. 이미지가 많은 갤러리/피드에 그대로 응용된다.

볼 파일: appendNextPage(), 그리드의 mouseover 핸들러

포인트 4 · 클라이언트 코드 생성

브라우저 안에서 SQL을 만들어 .sql 파일로 내려받기

setup.html은 서버 없이 데이터로부터 CREATE TABLE + 1,324개 INSERT를 만들어 Blob으로 다운로드시킨다. DB 방언(MS SQL·PostgreSQL·MySQL·SQLite)마다 컬럼 타입과 따옴표 이스케이프가 다른 걸 코드로 처리하는 법을 배운다.

// setup.html — DB마다 다른 CREATE TABLE 템플릿(PostgreSQL 발췌)
CREATE TABLE exercises (
  id                VARCHAR(10) PRIMARY KEY,
  name              VARCHAR(255) NOT NULL,
  instructions_en   TEXT,  instructions_es  TEXT,  instructions_zh  TEXT,  // 6개 언어를 컬럼으로 평탄화
  secondary_muscles TEXT,   // 배열은 JSON 문자열로 저장
  image  VARCHAR(500),  gif_url  VARCHAR(500),  created_at  TIMESTAMP
);

볼 파일: buildInserts(), escStr(), generateInsertSql()

포인트 5 · 데이터 모델링(i18n)

다국어를 어떻게 저장할까 — 컬럼 평탄화 vs 정규화

원본 JSON은 instructions.en처럼 언어를 중첩 객체로 담는다. 그런데 setup.html의 SQL 스키마는 이를 instructions_en, instructions_es… 처럼 컬럼으로 펼친다. "별도 번역 테이블로 정규화"하는 정석 대신 "컬럼 평탄화"를 택한 트레이드오프(조회 단순 ↔ 언어 추가 시 스키마 변경)를 비교해 보는 좋은 재료다.

볼 파일: JSON의 instructions 구조 vs setup.htmlCREATE TABLE

포인트 6 · 2026년 패턴

"Ask Your LLM" — 데이터셋이 백엔드 부트스트랩 프롬프트를 동봉

가장 시대를 타는 부분. setup.html은 프레임워크(Express·FastAPI·ASP.NET·Spring Boot·Laravel·Gin)와 DB를 고르면, "이 데이터로 완성형 REST API를 만들어 줘"라는 구조화된 프롬프트를 생성한다. 그대로 ChatGPT·Claude에 붙여 백엔드 초안을 받는 흐름이다. "문서 대신 프롬프트를 배포한다"는 새로운 온보딩 감각.

볼 파일: buildLlmPrompt(framework, db)

7시스템 요구사항

"보기"는 거의 0, "제품화"는 미디어 용량이 관건.

목적필요한 것
탐색기 그냥 보기최신 웹 브라우저뿐. index.html 더블클릭. 서버·인터넷 불필요(데이터가 inline).
데이터만 활용아무 언어나(파이썬·JS·자바…). json 파서로 exercises.json을 읽으면 끝. 1만 행 미만이라 메모리 부담 적음.
DB에 적재setup.html.sql 생성 → SQLite/PostgreSQL 등에 import. SQLite면 설치도 거의 불필요.
앱/백엔드 구축프레임워크 자유. setup.html의 API 코드·LLM 프롬프트를 출발점으로.
미디어까지 호스팅여기가 진짜 비용. JPG·GIF 합쳐 약 2,648개 파일(수백 MB급). 그대로 git에 두기보다 CDN이나 git LFS 고려.
비유 — 텍스트는 깃털, 미디어는 짐가방

운동 데이터(텍스트)는 9MB라 깃털처럼 가볍게 어디든 들고 다닌다. 진짜 무게는 GIF·이미지(짐가방)다 — 수백 MB가 될 수 있어, 웹에 올릴 땐 이 짐을 어디(저장소? CDN? LFS?)에 둘지가 설계의 핵심이 된다. 텍스트와 미디어의 "이사 방법"을 분리해서 생각하는 게 요령.

8직접 해볼 수 있는 실습 과제

데이터 만지기 → 화면 붙이기 → 백엔드 세우기 순으로.

실습 1

클론해서 탐색기 열고, 파이썬으로 통계 뽑기 난이도 ★☆☆ 입문

저장소를 클론한 뒤 index.html을 더블클릭해 검색·필터를 체험한다. 그다음 exercises.json을 파이썬으로 읽어 "부위별 운동 수", "기구별 분포"를 출력해 본다. README의 "433개"가 아니라 실제로 몇 개인지 직접 세어 보는 게 포인트(스포일러: 1,324개).

# 부위(category)별 운동 개수 세기
import json, collections
data = json.load(open("data/exercises.json", encoding="utf-8"))
print("총 운동:", len(data))
print(collections.Counter(ex["category"] for ex in data))
실습 2

"오늘의 맨몸 루틴 6개" 랜덤 생성기 난이도 ★☆☆ 입문

기구가 body weight인 운동(325개)만 골라 무작위 6개를 뽑아 "오늘의 홈트 루틴"으로 출력하는 스크립트를 짠다. 부위가 겹치지 않게 고르는 조건을 붙이면 난이도가 살짝 올라간다. 데이터 필터링·랜덤 샘플링의 기본기 연습.

실습 3

setup.html로 SQLite DB 만들어 조회하기 난이도 ★★☆ 중급

setup.html을 열어 SQLite 방언으로 .sql을 생성·다운로드하고, sqlite3 gym.db < exercises.sql로 적재한다. 그다음 "가슴 운동 중 덤벨만", "부위별 개수" 같은 쿼리를 직접 날려 본다. 생성된 스키마가 다국어를 어떻게 컬럼으로 폈는지 확인하는 게 핵심.

실습 4

"부위 클릭 → 운동 목록" 미니 웹앱 난이도 ★★☆ 중급

바닐라 JS 또는 React로 작은 앱을 만든다 — 인체 부위 버튼을 누르면 해당 category 운동을 카드로 보여주고, 카드를 누르면 GIF와 설명을 띄운다. 원본 index.htmlcreateCard()·openModal()을 참고하되 내 식으로 다시 써 보는 게 목표.

실습 5

FastAPI로 운동 REST API 세우기 (+ LLM 부트스트랩) 난이도 ★★★ 고급

setup.html의 "Ask Your LLM"에서 FastAPI+SQLite 프롬프트를 뽑아 백엔드 초안을 받고, 거기에 ?category=chest&equipment=dumbbell&page=2 같은 필터·페이지네이션을 직접 구현한다. 이미지/GIF는 정적 파일로 서빙. "LLM 초안 → 내가 검증·보강"이라는 2026년형 개발 흐름을 체험한다.

팁: 페이지네이션은 원본 탐색기처럼 offset = (page-1) * limit로 잘라 반환. 응답에 total·has_more를 같이 주면 프론트가 무한스크롤을 붙이기 쉽다.
실습 6

데이터 품질 검증 스크립트 난이도 ★★★ 고급

"신뢰하되 검증하라". image/gif_url이 가리키는 파일이 실제로 images/·videos/에 있는지, ID 중복은 없는지, 6개 언어가 빠짐없이 채워졌는지 검사하는 스크립트를 만든다. 데이터셋을 제품에 넣기 전 반드시 거치는 "수입 검사" 과정을 직접 설계하는 실습.

9관련 기술 심화 학습 로드맵

한 주씩 따라가는 "데이터 → 프론트 → 백엔드 → 운영" 코스.

주차주제학습 자료 / 할 일
1주차JSON·데이터 모델 읽기exercises.json 스키마 분석, 파이썬/JS로 로드·집계(실습 1·2)
2주차바닐라 DOM — 검색·필터applyFilters() 따라 만들기, 다중선택 필터(Set) 이해
3주차성능 — 디바운스·사전계산색인 생성·debounce 직접 구현, 있고/없고 속도 비교
4주차브라우저 API — 무한스크롤·lazyIntersectionObserver·loading="lazy"로 이미지 갤러리 만들기
5주차SQL 적재·인덱싱setup.html로 .sql 생성, 인덱스 추가 후 쿼리 속도 측정(실습 3)
6주차i18n 데이터 설계컬럼 평탄화 vs 번역 테이블 정규화 비교, 언어 추가 시나리오 토론
7주차REST API 구축FastAPI/Express로 필터·페이지네이션 API(실습 5)
8주차미디어 파이프라인 + 저작권GIF 최적화·CDN/git LFS, 데이터셋 라이선스·저작권 점검

10핵심 키워드 사전

본문에 나온 용어 빠른 참조.

용어의미
데이터셋 (Dataset)일정 형식으로 모은 데이터 묶음. 여기선 운동 1,324개의 JSON 배열.
JSON{ "키": "값" } 형태의 텍스트 데이터 형식. 거의 모든 언어가 바로 읽음.
스키마 (Schema)데이터의 "정해진 형식". 어떤 필드가 어떤 타입으로 있는지의 약속(여기선 13개 필드).
레코드 (Record)데이터 한 건. 운동 한 개 = 레코드 한 줄.
바닐라 JS프레임워크 없이 쓰는 순수 자바스크립트.
SPASingle Page Application. 페이지 새로고침 없이 JS로 화면을 바꾸는 앱.
데이터 인라이닝데이터를 외부에서 불러오지 않고 코드 안에 직접 박는 것. index.html의 9MB.
디바운스 (Debounce)연속 이벤트(타이핑)가 잠잠해진 뒤 한 번만 실행하게 묶는 기법.
검색 색인 (Index)빨리 찾으려고 미리 만들어 둔 보조 데이터. 여기선 합친 소문자 문자열 _idx.
IntersectionObserver어떤 요소가 화면에 보이는지 감지하는 브라우저 API. 무한스크롤·lazy 로딩에 씀.
무한 스크롤끝까지 내리면 다음 묶음을 이어 붙여 계속 보여 주는 UI 패턴.
지연 로딩 (Lazy Loading)필요할 때(보일 때·hover 때)만 자원을 불러와 낭비를 줄이는 기법.
이벤트 위임 (Delegation)자식마다 핸들러를 달지 않고 부모에 하나만 달아 이벤트를 처리.
i18n (국제화)internationalization. 여러 언어를 지원하도록 만드는 것(여기선 6개 언어 설명).
정규화 / 평탄화다국어를 별도 테이블로 쪼개면 정규화, instructions_en처럼 컬럼으로 펴면 평탄화.
Blob / Object URL브라우저가 메모리의 데이터를 "파일처럼" 만들어 다운로드시키는 수단(setup.html의 .sql).
REST APIHTTP로 데이터를 주고받는 표준 방식. GET /exercises?category=chest 같은 형태.
페이지네이션큰 목록을 page·limit으로 나눠 조금씩 주는 것.
CDN전 세계에 파일을 빠르게 배포하는 네트워크. 무거운 미디어 서빙에 적합.
git LFSLarge File Storage. 큰 바이너리(이미지·GIF)를 git에서 따로 관리하는 확장.

11참고 링크