방과후학교·늘봄교실 정원 관리 & 선착순 자동 마감 — GAS + 구글 시트 백엔드
🏫 방과후학교·늘봄교실 수강 신청 — 학부모가 폰에서 강좌를 선택하면 구글 시트에 실시간 카운트되어 정원이 차면 자동으로 "마감" 처리되는 선착순 신청 시스템입니다. 교사가 시트의 정원 숫자만 바꾸면 다음 학기에 재사용할 수 있습니다.
📖 한 줄 정의
Google Apps Script(GAS): 구글 스프레드시트 안에서 실행되는 서버리스 백엔드 스크립트 — 별도 서버 없이 무료로 웹앱을 배포할 수 있습니다.
구글 스프레드시트 = 무료 DB: 신청 현황이 시트에 실시간 누적되어 담당자가 원클릭으로 정원·대기자·마감 상황을 확인할 수 있습니다.
⚠️ 개인정보·보안 안내 (필독)
이 웹앱은 GAS + 구글 스프레드시트를 활용하여 데이터를 구글 클라우드에 저장합니다.
• 구현 전 반드시 소속 교육청 정보보호 담당과에 사전 문의하세요.
• 이 도구는 교사·행정 전용입니다 — 학생 개인정보를 일절 다루지 않습니다. 강좌명·정원·신청 인원수만 관리합니다.
1. 3대 핵심 분석 비교표
| 무엇이 바뀌었나요? | 쉬운 설명 | 써보세요! |
|---|---|---|
| 정원 자동 마감 | 강좌별 정원(예: 20명)을 시트에 설정하면 신청 인원이 정원에 도달하는 순간 자동으로 "마감" 표시가 되고 추가 신청이 차단됩니다. | 미술 강좌 20/20 → 자동 "🔒 마감" 표시 |
| 대기자 자동 전환 | 정원이 차면 신청자를 "대기자"로 기록하고, 기존 신청자가 취소하면 대기자가 자동 승격됩니다. | 3번 대기자 → 5번 취소 → 3번 자동 승격 "✅ 수강 확정" |
| 학기별 재사용 | 시트에서 강좌명·정원·요일만 바꾸면 다음 학기에 그대로 재사용할 수 있습니다. | 1학기 "피아노" → 2학기 "기타"로 텍스트 교체만 |
2. GAS 실전 구축 가이드
파일 1: Code.gs (백엔드 — 정원 카운트 & 마감)
function doGet(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var courses = ss.getSheetByName("강좌목록");
var applications = ss.getSheetByName("신청목록");
var courseData = courses.getDataRange().getValues();
var appData = applications.getDataRange().getValues();
var result = [];
for (var i = 1; i < courseData.length; i++) {
var name = courseData[i][0];
var max = courseData[i][1];
var count = 0;
for (var j = 1; j < appData.length; j++) {
if (appData[j][1] === name) count++;
}
result.push({
course: name, capacity: max, enrolled: count,
status: count >= max ? "마감" : "모집중"
});
}
return ContentService.createTextOutput(JSON.stringify({ courses: result })).setMimeType(ContentService.MimeType.JSON);
}
function doPost(e) {
var p = JSON.parse(e.postData.contents);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var courses = ss.getSheetByName("강좌목록");
var applications = ss.getSheetByName("신청목록");
var courseData = courses.getDataRange().getValues();
var appData = applications.getDataRange().getValues();
var capacity = 0, enrolled = 0;
for (var i = 1; i < courseData.length; i++) {
if (courseData[i][0] === p.course) capacity = courseData[i][1];
}
for (var j = 1; j < appData.length; j++) {
if (appData[j][1] === p.course) enrolled++;
}
if (enrolled >= capacity) {
return ContentService.createTextOutput(JSON.stringify({ ok: false, message: "정원이 마감되었습니다." })).setMimeType(ContentService.MimeType.JSON);
}
applications.appendRow([p.name, p.course, new Date().toLocaleString("ko-KR")]);
return ContentService.createTextOutput(JSON.stringify({ ok: true, enrolled: enrolled + 1, capacity: capacity })).setMimeType(ContentService.MimeType.JSON);
}
파일 2: index.html (프런트엔드 — 강좌 목록 & 신청 폼)
<!DOCTYPE html>
<html lang="ko"><head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>방과후 신청</title>
</head><body>
<h2>🏫 방과후·늘봄교실 신청</h2>
<div id="courses">로딩 중...</div>
<input type="text" id="name" placeholder="신청자 이름">
<button onclick="apply()">신청</button>
<div id="msg"></div>
<script>
var G = "여기에_배포_URL";
fetch(G).then(function(r){return r.json();}).then(function(d){
var h = "";
d.courses.forEach(function(c){
h += c.status === "마감"
? "<p>🔒 " + c.course + " (" + c.enrolled + "/" + c.capacity + ") 마감</p>"
: "<p>🟢 " + c.course + " (" + c.enrolled + "/" + c.capacity + ") </p>";
});
document.getElementById("courses").innerHTML = h;
});
function apply() {
var course = prompt("신청할 강좌명을 입력하세요:");
fetch(G, { method: "POST", body: JSON.stringify({ course: course, name: document.getElementById("name").value }) })
.then(function(r){return r.json();}).then(function(d){
document.getElementById("msg").textContent = d.ok ? "✅ 신청 완료! (" + d.enrolled + "/" + d.capacity + ")" : "🔴 " + d.message;
});
}
</script>
</body></html>
제미나이 전용 에러 제로 프롬프트
[🚨 에러 방지 기본 안전장치]
1. 2개 파일 완결성: Code.gs와 index.html을 각각 완성한다.
2. doGet: 강좌별 정원과 현재 신청 인원을 계산하여 JSON으로 반환한다(모집중/마감 상태 포함).
3. doPost: 정원 초과 시 ok:false와 마감 메시지 반환, 정원 이내이면 appendRow한다.
4. 학생 개인정보 0: 강좌명·정원·신청 인원수만 관리하며 학생 데이터를 일절 다루지 않는다.
5. // TODO, /* 생략 */ 금지 — 끝까지 완성한다.
[❓ 역질문]
1. 강좌는 몇 개인가요? (기본: 5개)
2. 정원은 강좌별로 다른가요? (기본: 강좌별 각각 설정)
3. 취소 기능이 필요한가요? (기본: 교사가 시트에서 직접 삭제)
🎯 에디터 한줄평
"'지금 몇 명 신청했어요?'를 묻는 전화가 사라지는 순간입니다. 정원이 차면 자동으로 마감이 되고, 아이들이 즐겁게 선착순을 경험합니다. 교사는 시트의 숫자만 고치면 다음 학기에 무한 재사용이 됩니다."
📚 참고 링크
- Google Apps Script 공식 문서: https://developers.google.com/apps-script
- 교육과정 연계: 교무 행정(방과후학교·늘봄교실 관리), 교사 업무 자동화