# 출처 장부 — 수강료·재등록, 오늘 챙길 것

이 튜토리얼의 도구 사용법·한도는 아래 1차 출처에서 확인했다. 확인일은 모두 2026-10-11.
구글 로그인이 필요해 직접 실행하지 못한 단계는 `실행 확인: 사용자`, 문서에서 답을 찾지 못한 것은 `확인 필요`로 남겼다.
이전 편(`../hakwon-parent-report/SOURCES.md`)의 #1·#2·#3·#7과 같은 페이지는 이번에 다시 열어 확인했다.

## 확인한 사실

| # | 확인한 사실 | 쓰인 곳 | 출처 | 문서 갱신일 |
|:-:|---|---|---|---|
| 1 | 사용자 메뉴는 문서에 묶인(bound) 스크립트만 만들 수 있다. `onOpen` → `getUi().createMenu().addItem().addSeparator().addToUi()` | 가이드 1·2, 카드 6 | https://developers.google.com/apps-script/guides/menus | 2026-09-03 |
| 2 | 단순 트리거(`onOpen`)는 권한이 필요한 서비스를 쓸 수 없고 30초 안에 끝나야 하며, 보기 전용으로 연 파일에서는 실행되지 않는다 | 가이드 2, 막히는 곳 | https://developers.google.com/apps-script/guides/triggers | 2026-09-03 |
| 3 | 설치형 트리거는 **만든 사람의 계정으로** 실행된다. 시간 트리거는 최소 1분, 최대 1개월 간격. 지정 시각은 정확하지 않고 "9시로 설정하면 9시에서 10시 사이"에 실행되며 한 번 정해진 시각은 날마다 유지된다. 바꾸려면 지우고 새로 만든다. `ScriptApp.getProjectTriggers()`로 나열, `ScriptApp.deleteTrigger(t)`로 삭제 | 가이드 "시작하기 전에"·5, 카드 9, Code.gs `enableDaily`·`deleteOurTriggers_` | https://developers.google.com/apps-script/guides/triggers/installable | 2026-09-03 |
| 4 | `ScriptApp.newTrigger(fn).timeBased().everyDays(n).atHour(h).create()`. `atHour`는 "스크립트 시간대에서 5시~6시 사이에 실행" 식의 1시간 창. `inTimezone(string)`으로 시간대 지정 가능(기본은 스크립트 시간대). `atHour`를 쓰려면 빈도(`everyDays` 등)가 필요 | Code.gs `enableDaily`, 가이드 5 | https://developers.google.com/apps-script/reference/script/clock-trigger-builder | 2026-04-13 |
| 5 | 한도: 트리거 20개/사용자/스크립트, 트리거 총 실행 90분/일(개인) · 6시간/일(Workspace), 실행당 6분, 동시 실행 30/사용자 | 가이드 한도 | https://developers.google.com/apps-script/guides/services/quotas | 2026-09-03 |
| 6 | `Range` 메서드: `setBackground(color)`, `setBackgrounds(color[][])`, `setValues(values)`, `setValue(value)`, `getValues()`, `clearFormat()`, `setNote(note)` — 레퍼런스 페이지의 메서드 앵커로 확인 | Code.gs `scanAndMark`, `ensureSheet_` | https://developers.google.com/apps-script/reference/spreadsheet/range | 2026-08-19 |
| 7 | `Sheet` 메서드: `getLastRow()`, `getRange(row, col, numRows, numCols)`, `setFrozenRows(n)`, `clearContents()`, `appendRow()`, `clear()` — 메서드 앵커로 확인 | Code.gs | https://developers.google.com/apps-script/reference/spreadsheet/sheet | 2026-04-13 |
| 8 | `Range.clearContent()`, `Spreadsheet.insertSheet(name)` · `getSheetByName(name)`, `Trigger.getHandlerFunction()`, `Session.getScriptTimeZone()`, `Utilities.formatDate(date, tz, format)` — 각 레퍼런스 페이지의 메서드 앵커로 확인 | Code.gs | https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet · …/script/trigger · …/base/session · …/utilities/utilities | 2026-04-13 (Range는 2026-08-19) |

## 열려 있는 항목

| 항목 | 상태 | 닫는 방법 |
|---|---|---|
| `getValues()`가 날짜 서식 셀을 JavaScript `Date`로 돌려주는지 | 확인 필요 — 레퍼런스 페이지가 길어 해당 문장을 읽지 못함. 코드는 `Date`와 `연-월-일` 글자 둘 다 받도록 짜서 어느 쪽이든 동작 | 실제 시트에서 ②를 누른 뒤 색이 칠해지면 닫힘 |
| 트리거 권한 승인 창의 문구와 버튼 이름 | 확인 필요 | 새 시트에서 ③을 처음 누를 때 화면을 기록 |
| 편집기 프로젝트 설정의 시간대 항목 이름 | 확인 필요 | 실제 화면과 대조 |
| 한국어 UI의 메뉴 이름 "확장 프로그램 → Apps Script", 왼쪽 "트리거" 메뉴 | 실행 확인: 사용자 | 실제 화면과 대조 |
| ① → ② → ③ → 다음 날 아침 전체 흐름 | 실행 확인: 사용자 | 가이드의 "혼자 다시 해 보기" 목록을 그대로 수행 |

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

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

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

확인 내용: 열 순서가 바뀌어도 머리글로 찾는다 / 날짜 객체·`2026-10-18`·`2026.10.18`·`2026/10/18`을 같은 날로 읽고 시각은 무시한다 / 연도 없는 `10-18`과 글자는 건너뛴다 / 지난 납부는 빨강, 오늘~7일은 노랑, 8일부터는 색 없음, 종료 14일 안은 주황, 15일부터와 이미 끝난 수강은 색 없음 / 납부와 종료가 겹치면 납부가 이긴다 / 목록은 지난 것 → 남은 일수 → 학생ID 순이고 입력을 바꾸지 않는다.

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

주제 선정 단계에서 국내 교육 사이트의 업무 자동화 유형 목록을 **주제 지도로만** 참고했다. 제목, 등장인물, 수치, 글의 전개는 가져오지 않았다. 학부모 자동 발송을 넣지 않은 것, 트리거를 하나로 유지하는 것, 연도 없는 날짜를 건너뛰는 것은 작성자의 학원 운영 경험에서 나온 설계다.
