1 프로젝트 개요
고객(학생, 선생님, 학부모)이 교재를 검색할 수 있는 웹 기반 검색 시스템입니다.
대상 사용자
학생 / 교사 / 학부모
전 연령대 사용 가능
핵심 기능
ISBN / 도서명 / 출판사 /
저자명 다중 검색
핵심 가치
심플하지만 강력한
사용성 중심 설계
2 현재 문제점
문제 1 — 고객의 교재 검색 접근성
현재는 노션 페이지를 활용해서 교재 유무를 검색하고 있습니다. 노션 내 검색 기능은 접근성이 매우 떨어지며, 검색을 어디서 해야 하는지 몰라 혼란을 겪고 있습니다.
교재가 이미 있음에도 불구하고 교재 신청을 하는 경우가 빈번히 발생하고 있습니다. 검색 접근성이 떨어져 기존 교재를 찾지 못하고 중복 신청을 하게 되어, 불필요한 업무 부하와 비용이 발생합니다.
문제 2 — 노션 페이지 교재 업로드의 구조적 문제
노션 페이지에 교재 업로드는 현재 반자동으로 작업 중입니다. 아래의 수동 단계를 거쳐야만 고객이 검색할 수 있습니다:
이 프로세스에서 실무자가 깜빡하고 시트에 업데이트를 하지 않으면, BCMS에는 교재가 업로드되었지만 노션에는 반영되지 않아 고객이 해당 교재를 확인할 수 없게 됩니다.
BCMS ✓ 등록 완료 | 노션 ✗ 미반영 | 고객 ✗ 검색 불가
현재 문제의 본질
BCMS에 교재가 있어도, 수동 프로세스를 거쳐야만
고객이 볼 수 있는 구조적 병목이 존재합니다.
3 솔루션 제안
핵심 아이디어
프론트엔드적으로는 고객이 직접 BCMS에서 검색하는 것처럼 보이게 하지만,
실제로는 아래의 안전한 흐름으로 동작합니다:
실무자가 엑셀 다운로드 → 시트 복붙 → Zapier 대기 과정을 전부 생략합니다. BCMS에 업로드만 하면 고객이 바로 검색 가능합니다.
실무자 누락 리스크 0% — 구조적 병목 해소
노션 대신 전용 검색 페이지를 제공하여, ISBN / 도서명 / 출판사 / 저자명 4가지 필터로 누구나 쉽게 검색할 수 있습니다. 노션의 검색 접근성 문제를 근본적으로 해결합니다.
교재 표지, 출판사, 가격 등 시각적 정보를 제공하며, 미등록 교재 검색 시 자동으로 교재 신청 폼으로 안내하여 불필요한 중복 신청을 방지합니다.
고객에게 BCMS 접근 권한을 직접 부여하지 않고, GAS가 안전하게 인증 토큰을 받아 BCMS를 대리 검색합니다. 기존 GAS, Google Sheets, BCMS 인프라를 모두 그대로 활용합니다.
AS-IS (현재)
BCMS 업로드
실무자 엑셀 다운로드
시트 복붙 (누락 위험)
Zapier → 노션 업데이트
고객이 노션에서 검색 (어려움)
TO-BE (제안)
BCMS 업로드
끝! 고객이 바로 검색 가능
4 시스템 아키텍처
[ 고객 (Browser) ] | | "BCMS에서 직접 검색하는 것처럼 보임" v [ Cloudflare Workers ] ← Frontend + API Proxy | |—— /api/search?isbn=xxx | | | v | [ Google Apps Script ] | | | |—— 인증토큰 발급 | v | [ BCMS API ] ← 안전한 서버간 통신 | 교재 등록 여부 실시간 확인 | v | { isRegistered, message } | |—— /api/bookinfo?isbn=xxx | | | v | [ 네이버 도서 API ] → 표지/출판사/가격 | 미발견 시 ↓ | [ 알라딘 ] → [ Google Books ] | |—— /api/books?q=xxx&filter=title v [ 네이버 도서 상세검색 API ]
보안 포인트: 고객에게 BCMS 접근 권한을 직접 부여하지 않습니다. GAS가 서버 사이드에서 안전하게 인증 토큰을 받아 BCMS를 대리 검색하므로, 고객은 검색 결과만 확인할 수 있습니다.
Cloudflare Workers
엣지 서버에서 실행. 프론트엔드 제공 + API 프록시. 무료 플랜으로 충분히 운영 가능
Google Apps Script
핵심 미들웨어. 인증토큰 발급 → BCMS API 호출 → 결과 반환. 기존 인프라 활용, 추가 서버 불필요
BCMS
교재 원본 데이터 소스. 업로드 즉시 검색 가능. 기존 업로드 프로세스 변경 없음
네이버 / 알라딘 / Google
교재 표지, 출판사, 가격 등 부가 정보 제공. 3단계 폴백으로 커버리지 극대화
5 GAS 구현 상세
현재 교재 등록 여부 확인은 Google Apps Script(GAS)를 통해 구현되어 있습니다. GAS는 Google Sheets에 저장된 교재 데이터를 기반으로 ISBN 매칭을 수행합니다.
GAS의 역할
웹앱 엔드포인트로 배포되어 외부에서 HTTP GET 요청을 받을 수 있음
요청된 ISBN을 Google Sheets 내 교재 목록에서 검색
매칭 결과에 따라 등록 여부(isRegistered)와 교재명(title)을 JSON으로 반환
GAS 내부 동작 흐름
[ Cloudflare Workers ] | | GET /api/search?isbn=9788905059156 v [ Google Apps Script (웹앱) ] | |—— doGet(e) 함수 실행 | | | v | e.parameter.isbn 에서 ISBN 추출 | | | v | [ Google Sheets ] | 스프레드시트 내 교재 목록 시트 접근 | ISBN 컬럼에서 일치하는 행 검색 | | | ┌───────┴───────┐ | 매칭 O 매칭 X | │ │ | v v | isRegistered: isRegistered: | true false | title: "교재명" message: "등록되지 | 않은 신규 교재" v [ JSON 응답 반환 ]
GAS 응답 예시
{
"success": true,
"isRegistered": true,
"title": "풍산자 필수유형 중학수학 2-2(2026)"
}
{
"success": true,
"isRegistered": false,
"message": "등록되지 않은 신규 교재입니다."
}
GAS 코드 구조 (추정)
// Google Apps Script - 웹앱으로 배포됨 function doGet(e) { const isbn = e.parameter.isbn; // Google Sheets에서 교재 목록 시트 접근 const sheet = SpreadsheetApp .openById('스프레드시트_ID') .getSheetByName('교재목록'); const data = sheet.getDataRange().getValues(); // ISBN 컬럼에서 매칭되는 행 검색 for (let i = 1; i < data.length; i++) { if (data[i][ISBN_COLUMN] == isbn) { return ContentService .createTextOutput(JSON.stringify({ success: true, isRegistered: true, title: data[i][TITLE_COLUMN] })) .setMimeType(ContentService.MimeType.JSON); } } // 매칭 실패 시 return ContentService .createTextOutput(JSON.stringify({ success: true, isRegistered: false, message: "등록되지 않은 신규 교재입니다." })) .setMimeType(ContentService.MimeType.JSON); }
현재 GAS의 한계점
현재 GAS는 ISBN으로만 교재 조회가 가능합니다. 도서명, 출판사, 저자명으로는 사내 DB 등록 여부를 확인할 수 없습니다.
BCMS에 교재를 업로드해도 Google Sheets에 수동으로 반영하지 않으면 GAS 검색에서 해당 교재를 찾을 수 없습니다. 이것이 바로 앞서 언급한 “구조적 병목”입니다.
GAS는 등록 여부와 교재명만 반환합니다. 표지 이미지, 출판사, 가격 등 상세 정보는 별도로 네이버/알라딘/Google Books API를 통해 보완하고 있습니다.
TO-BE: GAS 확장 방향
BCMS 직접 연동: GAS가 BCMS API에 직접 인증 토큰을 발급받아 검색하면, Sheets 수동 업데이트 없이 실시간 조회가 가능합니다.
다중 검색 지원: ISBN뿐 아니라 도서명, 출판사, 저자명으로도 사내 DB를 검색할 수 있도록 GAS를 확장합니다.
보안 유지: 고객은 BCMS에 직접 접근하지 않고, GAS가 서버 사이드에서 인증 → 검색 → 결과 반환을 안전하게 처리합니다.
6 검색 플로우 (작동 로직)
ISBN 검색 플로우
사용자가 ISBN 번호를 입력하고 검색 클릭
프론트엔드가 /api/search + /api/bookinfo 두 API를 병렬 호출 (Promise.all)
Google Apps Script → 사내 DB에서 등록 여부 확인
{ success: true, isRegistered: true/false }
네이버 도서 API → 교재 상세 정보 + 표지 이미지 + 가격 반환
{ title, authors, publisher, thumbnail, price, ... }
미발견 시 알라딘 → Google Books 순서로 폴백
두 응답을 병합하여 교재 카드 렌더링 → 클릭 시 상세 팝업(모달)
도서명/출판사/저자 검색 플로우
네이버 도서 API 연동 완료: 도서명, 출판사, 저자명 검색은 네이버 도서 상세검색 API(book_adv)를 통해 정확한 필터 검색을 지원합니다.
참고: 사내 DB 등록 여부는 ISBN 검색 시에만 확인 가능하며, 제품화 시 GAS 확장으로 다중 검색 연동이 필요합니다.
7 API 명세
/api/search
사내 DB 조회
Parameters
isbn (string, required) — ISBN 번호 (하이픈 자동 제거)
Response
{
"success": true,
"isRegistered": true | false,
"message": "등록된 교재입니다." | "등록되지 않은 신규 교재입니다."
}
내부 동작
→ Cloudflare Workers에서 Google Apps Script 웹앱으로 프록시 전달. CORS 문제를 해결하고 응답 속도를 개선.
/api/bookinfo
교재 상세 정보
Parameters
isbn (string, required) — ISBN 번호
Response
{
"success": true,
"source": "aladin",
"book": {
"title": "풍산자 필수유형 중학 수학 2-2 (2026년)",
"authors": "풍산자수학연구소",
"publisher": "지학사(참고서)",
"publishedDate": "2025-12-10",
"description": "풍쌤비법으로 중학수학 2-2...",
"thumbnail": "https://image.aladin.co.kr/...",
"isbn": "9788905059156",
"categories": "풍산자, 중학수학, ...",
"language": "ko",
"price": 17100,
"aladinUrl": "https://www.aladin.co.kr/...",
"kyoboUrl": "https://product.kyobobook.co.kr/..."
}
}
내부 동작
→ 1차: 네이버 도서 API (API 키 인증, 한국도서 최고 커버리지) → 2차: 알라딘 OG 태그 파싱 (ISBN → 검색 페이지 폴백) → 3차: Google Books (해외 도서 대응)
/api/books
일반 도서 검색
Parameters
q (string, required) — 검색어
filter (string, optional) — title | author | publisher (기본: title)
Response
{
"success": true,
"source": "naver",
"total": 10,
"books": [
{ "title": "...", "authors": "...", "publisher": "...",
"thumbnail": "...", "isbn": "...", "price": 17100, ... }
]
}
내부 동작
→ 네이버 도서 상세검색 API: d_titl(도서명) / d_auth(저자) / d_publ(출판사) 파라미터 활용. 네이버 미발견 시 Google Books API 폴백.