# 출처 장부 — 메모 → 학부모 리포트

이 튜토리얼의 도구 사용법·한도·약관은 아래 1차 출처에서 확인했다. 확인일은 모두 2026-09-21.
구글 로그인이 필요해 직접 실행하지 못한 단계는 `실행 확인: 사용자`, 문서에서 답을 찾지 못한 것은 `확인 필요`로 남겼다.

## 확인한 사실

| # | 확인한 사실 | 쓰인 곳 | 출처 | 문서 갱신일 |
|:-:|---|---|---|---|
| 1 | 사용자 메뉴는 문서에 묶인(bound) 스크립트만 만들 수 있다. `onOpen` → `getUi().createMenu().addItem().addToUi()` | 가이드 1·2, 카드 6 | https://developers.google.com/apps-script/guides/menus | 2026-09-03 |
| 2 | 단순 트리거는 권한이 필요한 서비스를 쓸 수 없고, 30초를 넘길 수 없고, 보기·댓글 전용으로 연 파일에서는 실행되지 않는다 | 가이드 2, 막히는 곳 | https://developers.google.com/apps-script/guides/triggers | 2026-09-03 |
| 3 | 스크립트 속성: `PropertiesService.getScriptProperties().getProperty(key)` / `setProperty(key, value)`. "스크립트의 모든 사용자"가 접근 | 가이드 3, 카드 7 | https://developers.google.com/apps-script/guides/properties | 2026-09-03 |
| 4 | `UrlFetchApp.fetch(url, params)`의 매개변수 `method` · `contentType` · `headers` · `payload` · `muteHttpExceptions`. 필요한 범위 `https://www.googleapis.com/auth/script.external_request` | Code.gs `callGemini_` | https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app | 2026-05-15 |
| 5 | `HTTPResponse.getResponseCode()`, `getContentText()` | Code.gs `callGemini_` | https://developers.google.com/apps-script/reference/url-fetch/http-response | 2026-04-13 |
| 6 | `DocumentApp.create(name)`은 새 문서를 만들어 반환. `getBody()`, `Body.appendParagraph(text)`. 필요한 범위 `https://www.googleapis.com/auth/documents` | Code.gs `buildReportForSelectedRow` | https://developers.google.com/apps-script/reference/document/document-app | 2026-04-13 |
| 7 | 개인 계정 한도: URL Fetch 20,000회/일, 실행당 6분, 문서 생성 250개/일, 트리거 총 실행 90분/일. Workspace: 100,000회 / 6분 / 1,500개 / 6시간 | 가이드 한도 | https://developers.google.com/apps-script/guides/services/quotas | 2026-09-03 |
| 8 | `POST https://generativelanguage.googleapis.com/v1beta/{model=models/*}:generateContent`. 본문 `contents[].parts[].text`, `systemInstruction.parts[].text`. 응답 본문 경로 `candidates[0].content.parts[0].text` | Code.gs `buildRequestBody`, `extractText` | https://ai.google.dev/api/generate-content | 표기 없음 |
| 9 | API 키는 `x-goog-api-key` 헤더로 전달. 공식 예제의 모델 이름 `gemini-3.8-flash` | Code.gs `MODEL`, `callGemini_` | https://ai.google.dev/gemini-api/docs/text-generation | 2026-09-17 |
| 10 | 키 발급 위치 aistudio.google.com/apikey. 신규 사용자는 약관 동의 뒤 기본 프로젝트 자동 생성. 키를 소스 관리에 올리지 말 것, 클라이언트 코드에 넣지 말 것, 키 제한을 걸 것 | 가이드 3, 카드 7 | https://ai.google.dev/gemini-api/docs/api-key | 2026-09-16 |
| 11 | 무료(Unpaid) 서비스: 사람 검토자가 입력·출력을 읽고 처리할 수 있음, 민감·기밀·개인 정보를 제출하지 말 것. 유료(Paid) 서비스: 프롬프트·응답을 제품 개선에 쓰지 않음. 이용 연령 만 18세 이상 | 가이드 "시작하기 전에", 카드 4·5 | https://ai.google.dev/gemini-api/terms | 2026-04-28 (발효 2026-03-23) |

## 열려 있는 항목

| 항목 | 상태 | 닫는 방법 |
|---|---|---|
| 시트 **편집자**에게 스크립트 속성 값(API 키)이 보이는가 | 확인 필요 — 공식 문서에 명시 없음 | 부계정에 편집 권한을 주고 확장 프로그램 → Apps Script → 프로젝트 설정을 열어 본다 |
| 권한 승인 창의 "확인되지 않은 앱" 경고 문구와 버튼 이름 | 확인 필요 | 새 시트에서 ①을 처음 누를 때 화면을 기록한다 |
| 한국어 UI의 메뉴 이름 "확장 프로그램 → Apps Script", "프로젝트 설정 → 스크립트 속성" | 실행 확인: 사용자 | 실제 화면과 대조 |
| ① → ② → ③ → ④ 전체 흐름이 실제 계정에서 도는가 | 실행 확인: 사용자 | 가이드의 "혼자 다시 해 보기" 목록을 그대로 수행 |
| Interactions API(`/v1beta/interactions`)로 옮길 시점 | 보류 | 공식 가이드는 새 API를 앞세우지만 `generateContent`에 폐기 표시는 없다. 폐기 공지가 나오면 `callGemini_`와 `extractText`만 바꾸면 된다 |

## 문서 확인 없이 검증한 것

서비스에 의존하지 않는 함수(`headerMap`, `missingHeaders`, `maskNames`, `buildRequestBody`, `extractText`, `canPublish`)는 `source/check.mjs`로 Node에서 실행해 확인했다.

```bash
node source/check.mjs
```

확인 내용: 열 순서가 바뀌어도 머리글로 찾는다 / 긴 이름부터 가려 "김민서"가 "학생서"로 남지 않는다 / 요청 본문에 이름과 학생ID가 들어가지 않는다 / 차단·빈 응답에서 읽을 수 있는 오류를 던진다 / 확정일시와 확정피드백이 둘 다 있어야 발행된다.

## 이 튜토리얼이 기대고 있지 않은 것

주제 선정 단계에서 국내 교육 사이트의 업무 자동화 유형 목록을 **주제 지도로만** 참고했다. 제목, 등장인물, 수치, 글의 전개는 가져오지 않았다. 내용은 작성자가 실제로 운영하는 학부모 리포트 시스템을 가르치기 위해 줄인 것이고, 본문의 수치는 작성자의 컨설팅 기록에서 나온 것만 쓴다.
