2026 하반기 GEG VISUALIZER · 솔루션 장터

Google Apps Script로
연수 등록 시스템 만들기

스프레드시트 한 장에 스크립트를 붙여 신청 접수 · 현장 등록과 전자 서명 · 확인증 발급 · 진위 확인 · 자료 공유 · 관리자 명단까지 도는 시스템을 만듭니다. 완성본 사본을 먼저 받아 동작을 확인한 뒤, 코드 세 군데를 직접 고쳐 내 연수에 맞춥니다.

소요 20분시트 5개화면 6개 준비물 개인 노트북 · 스마트폰외부 라이브러리 없음

무엇을 만드나

구글 폼으로 신청을 받으면 접수는 되지만, 출석 확인과 확인증 발급은 결국 손으로 하게 됩니다. 이 실습은 그 뒷단을 스프레드시트 안에서 끝냅니다. 시트가 데이터베이스, Apps Script가 서버, 웹앱이 참가자 화면입니다. 참가자는 성명과 연락처만 기억하면 되고, 행사장에서는 화면에 직접 서명을 남깁니다.

설정연수명 · 일시 · 정원 · 발급기관을 값으로 관리
신청자신청 내역과 서명 파일 링크, 등록(출석) 시각
출석로그언제 어떤 경로로 등록했는지 기록
확인증발급번호와 저장된 파일 링크
자료수업안 · 실습 파일 링크와 참가자 산출물
확인증은 아무나 못 받습니다 이름만 넣으면 문서가 나오는 구조면 그냥 문서 생성기입니다. 이 시스템은 서명까지 등록된 사람에게만 발급하고, 확인증마다 발급번호와 검증 QR을 넣어 진위 확인 화면에서 대조할 수 있게 했습니다.

1사본 만들고 시트 생성0–2분

  1. 진행자가 안내한 완성본 스프레드시트 링크를 열고 파일 → 사본 만들기를 누릅니다. 내 드라이브에 복사본이 생깁니다.
  2. 복사본에서 확장 프로그램 → Apps Script를 열어 코드가 함께 복사됐는지 확인합니다.
  3. 스프레드시트로 돌아와 새로고침하면 상단에 연수 등록 시스템 메뉴가 생깁니다.
  4. 연수 등록 시스템 → ① 시트 만들기를 실행합니다. 권한 승인 창이 뜨면 고급 → 안전하지 않은 페이지로 이동을 눌러 본인 계정으로 승인합니다.
권한 창이 무섭게 뜨는 이유 구글이 검수하지 않은 내 스크립트라서 그렇습니다. 내가 만든 코드가 내 시트와 드라이브에만 접근하는 것이므로 승인해도 됩니다. 다른 사람의 스크립트라면 코드를 먼저 열어보고 승인하세요.
결과 시트 5개가 만들어지고 예시 신청자 5명이 들어갑니다. 그중 2명은 이미 등록(서명)까지 된 상태라 바로 확인증 발급을 테스트할 수 있습니다.

2배포하고 관리자 코드 넣기2–5분

참가자가 쓸 화면을 인터넷에 올리는 단계입니다. 여기서 설정 하나를 놓치면 남들이 못 들어옵니다.

  1. Apps Script 편집기 오른쪽 위 배포 → 새 배포를 누릅니다.
  2. 톱니바퀴 유형 선택 → 웹 앱을 고릅니다.
  3. 다음 사용자로 실행: 나
  4. 액세스 권한이 있는 사용자: 모든 사용자 ← 이 항목이 핵심입니다.
  5. 배포를 누르고 나온 웹앱 URL을 복사합니다.
"모든 사용자"가 아니면 참가자가 로그인 벽을 만납니다 학교 계정으로 잠긴 조직이라면 조직 내 모든 사용자까지만 열릴 수 있습니다. 그때는 참가자가 같은 도메인 계정으로 접속해야 합니다.

관리자 코드 넣기 — 배포 직후 바로

관리자 화면에는 참가자 연락처가 그대로 보입니다. 웹앱 주소는 QR로 모두에게 공개되고 뒤에 ?mode=admin만 붙이면 되므로, 코드를 넣기 전까지 관리자 기능은 잠겨 있습니다.

  1. Apps Script 편집기 왼쪽 프로젝트 설정(톱니바퀴)으로 이동합니다.
  2. 아래쪽 스크립트 속성에서 속성 ADMIN_CODE, 값에 원하는 암호를 넣고 저장합니다.
  3. 웹앱 관리자 탭을 열면 이제 코드를 물어봅니다.
넣기 전에 관리자 탭을 누르면 "관리자 화면이 잠겨 있습니다"라는 안내만 나옵니다. 오류가 아니라 기본값이 잠김이라는 뜻입니다. 코드를 잊었다면 같은 자리(프로젝트 설정 → 스크립트 속성)에서 값을 다시 볼 수 있습니다.

주소는 ?mode= 뒤에 붙이는 값으로 화면이 갈립니다. 접수대 안내판에는 등록 주소를 QR로 띄워두면 됩니다(관리자 화면에 QR이 있습니다).

주소 뒤에 붙이는 값열리는 화면누가 쓰나
(붙이지 않음)현장 등록 · 서명기본 화면
?mode=apply사전 신청신청자
?mode=register현장 등록 · 서명당일 참가자 · 접수대
?mode=cert확인증 발급등록 완료자
?mode=verify&no=…진위 확인확인증을 받은 기관
?mode=resource연수 자료 · 산출물참가자 (링크 아는 누구나)
?mode=admin관리자운영진

※ 과거에 나눠 준 ?mode=checkin 주소도 등록 화면으로 연결됩니다.

3신청 → 등록 → 확인증까지 한 바퀴5–9분

고치기 전에 완성품이 어떻게 도는지 먼저 봅니다. 본인 이름으로 직접 한 바퀴 돌려보세요. 기억할 것은 성명과 연락처뿐입니다.

  1. 사전 신청 — 웹앱 주소 뒤에 ?mode=apply를 붙여 열고 본인 정보로 신청합니다. 이메일은 필수입니다. 제출하면 "완료되었습니다" 팝업이 뜨고, 잠시 뒤 신청 내역과 행사 안내 메일이 도착합니다.
  2. 스프레드시트 신청자 시트를 보면 방금 신청한 행이 실시간으로 쌓여 있습니다.
  3. 등록 — 등록 탭(또는 ?mode=register)에서 성명과 연락처를 넣고 사전 신청 조회를 누릅니다. 기록이 있으면 소속·직위 칸이 사라지고 서명 칸만 열립니다. 서명한 뒤 "서명하고 등록 완료"를 누르면 끝입니다.
  4. 처음 온 사람으로도 해 보세요 — 아무 이름과 번호로 조회하면 "기록이 없습니다"가 뜨면서 소속·직위·이메일 칸이 펼쳐집니다. 채워 넣고 서명하면 그 자리에서 새 참가자로 등록됩니다.
  5. 확인증 — 확인증 탭에서 성명과 연락처를 넣으면 확인증이 화면에 그려집니다. PNG로 내려받거나 PDF로 드라이브에 저장할 수 있습니다.
  6. 진위 확인 — 확인증 우측 하단 QR을 휴대폰 카메라로 찍으면 검증 화면이 열립니다. 이름은 박○종처럼 가려서 보여줍니다.
왜 조회부터 하나 사전 신청한 분에게 소속을 다시 묻지 않기 위해서입니다. 조회는 성명과 연락처가 둘 다 맞아야 통과하고, 결과로는 "있다/없다"만 알려 줍니다. 번호만 아는 사람이 남의 소속을 알아내지 못하도록 개인정보는 화면으로 내보내지 않습니다.
미등록자로 한 번 실패해 보세요 신청자 시트에서 출석시각이 빈 사람의 성명과 연락처로 확인증을 요청하면 "출석 기록이 없어 발급할 수 없습니다"가 뜹니다. 이 거절이 시스템의 신뢰를 만드는 부분입니다.
같은 사람이 두 번 등록하면? 연락처가 같으면 기존 행을 이어씁니다. 같은 사람이 또 서명하면 "이미 출석"으로 걸러집니다. 대기 상태로 받은 사람도 현장에 오면 등록하며 승인으로 승격됩니다.

*자료·산출물 링크참고

수업안과 산출물 링크 걸어두기

자료 시트에 링크를 적으면 자료 탭에 카드로 뜹니다. 위쪽은 운영진이 올리는 자료, 아래쪽은 참가자가 올린 산출물입니다.

운영진 자료 — 시트에 적기

자료 시트에 한 줄씩 추가합니다. 코드는 건드리지 않습니다.

열넣을 값
자료ID겹치지 않는 아무 값 (R0004 …)
구분운영자
제목수업안 / 실습 파일 / 발표자료
링크https:// 로 시작하는 주소만 들어갑니다
설명한 줄 설명 (비워도 됩니다)
공개공개 또는 숨김

참가자 산출물 — 웹앱에서 올리기

  • 자료 탭 아래 내 산출물 올리기에서 성명과 연락처를 넣고 링크를 제출합니다.
  • 한 사람당 한 건입니다. 다시 올리면 기존 링크가 바뀝니다.
  • 부적절한 링크는 관리자 탭 자료와 산출물 표에서 숨기기를 누르면 자료 화면에서 사라집니다.
보기는 열려 있고, 올리기는 잠겨 있습니다 자료 화면은 링크를 아는 사람이면 누구나 볼 수 있게 열어 두었습니다. 대신 올리는 것은 등록된 본인만 가능합니다. 아무나 링크를 꽂아넣을 수 있으면 스팸 통로가 되기 때문입니다. 올린 제목·링크와 성명·소속은 자료 화면에 그대로 보이므로, 참가자에게 공개해도 되는 링크만 올리라고 미리 안내하세요. 연락처와 이메일은 이 화면으로 나가지 않습니다.

전체를 비공개로 운영하려면 설정 시트의 산출물제출을 false로 두면 제출 칸이 사라지고, 개별 자료는 공개 열을 숨김으로 바꾸면 됩니다.

4코드 세 군데 고치기9–15분

전부 이해할 필요는 없습니다. 아래 세 곳만 만져보면 "데이터 → 규칙 → 결과물"이라는 구조가 손에 잡힙니다. 고칠 위치는 코드에 ✏️ 실습 주석으로 표시해 두었습니다.

  1. ✏️ ① 코드를 건드리지 않는 수정 — 설정 시트에서 연수명 · 발급기관 등 값을 바꿉니다.
  2. ✏️ ② 규칙 바꾸기 — Code.gs의 submitApplication 함수 안 한 줄 (정원이 찼을 때).
  3. ✏️ ③ 결과물 바꾸기 — Index.html의 drawCertificate 함수 (확인증 디자인).

① 설정 시트 — 코드 없이 바꾸는 것들

설정 시트로 가서 값 열만 고치고 웹앱을 새로고침하면 바로 반영됩니다.

키바꿀 값 예시어디에 나타나나
연수명전남 GEG 에듀테크 연수모든 화면 제목, 확인증
정원25초과 시 대기자 처리, 자동 승격 기준
사전신청사용true / false사전 신청 탭과 등록 화면의 조회 단계
발급기관명본인 학교 · 기관 이름확인증 하단 발급자
발급자직위교장 / 원장확인증 하단 발급자
확인증제목참관 확인증 / 연수 이수증확인증 큰 제목
확인증사용true / false발급 기간 열고 닫기
산출물제출true / false산출물 올리기 칸 열고 닫기
안내문지참물 · 안내 문구사전 신청 화면, 신청 메일
발급기관명은 반드시 실제 소속으로 기본값 ○○초등학교는 자리표시자입니다. 확인증은 발급기관 이름으로 나가는 문서이므로, 본인이 발급 권한을 가진 기관 이름으로만 바꿔 쓰세요.
사전신청사용을 false로 두면 사전 신청 탭이 사라지고, 등록 화면도 조회 단계 없이 처음부터 모든 칸이 보입니다. 전원이 현장에서 등록하는 연수라면 이쪽이 빠릅니다.

② 정원이 찼을 때의 규칙 — Code.gs

편집기에서 Ctrl+F로 ✏️ 실습 ②를 찾으면 이 줄이 나옵니다.

현재 코드 (Code.gs · submitApplication 안)
// ✏️ 실습 ②: 정원이 찼을 때의 처리 — '대기'로 받을지, 아예 막을지 이 줄에서 정합니다.
status = (capacity > 0 && approved >= capacity) ? APP.STATUS.WAITING : APP.STATUS.APPROVED;

대기자를 아예 받지 않고 정원이 찼으면 바로 거절하려면, 위 줄을 지우고 아래를 붙여넣습니다.

바꾸는 코드
if (capacity > 0 && approved >= capacity) {
  throw new Error('정원이 모두 찼습니다. 다음 기수를 이용해 주세요.');
}
status = APP.STATUS.APPROVED;

저장(💾) 후 웹앱을 새로고침하고, 정원을 현재 승인 인원과 같게 낮춘 뒤 신청해 보면 바뀐 동작이 보입니다. 이렇게 고치면 대기자가 생기지 않으므로 5단계의 자동 승격도 일어나지 않습니다. 대기 명단을 관리할 연수라면 원래 코드를 그대로 두세요.

③ 확인증 디자인 — Index.html

✏️ 실습 ③ 아래 drawCertificate 함수가 확인증을 캔버스에 그립니다. 좌표는 가로 1754 × 세로 1240 기준입니다.

현재 코드 (Index.html · drawCertificate 안)
g.strokeStyle = '#1e3a7b'; g.lineWidth = 8;  g.strokeRect(46, 46, W - 92, H - 92);

g.textAlign = 'center'; g.fillStyle = '#16233a';
g.font = '700 96px ' + serif;
g.fillText(cert.제목, W / 2, 268);

색을 학교 상징색으로 바꾸고 제목을 키워 보세요. 아래를 참고해 숫자와 색 코드를 바꿔도 됩니다.

참고 — 색과 크기 바꾸기
// 테두리 색을 학교 상징색으로 ( lineWidth = 굵기 )
g.strokeStyle = '#8a2b2b'; g.lineWidth = 10; g.strokeRect(46, 46, W - 92, H - 92);

// 제목 크기와 위치 ( W/2 = 가운데 , 268 = 위에서부터의 높이 )
g.font = '700 110px ' + serif;
g.fillText(cert.제목, W / 2, 288);
왜 그림으로 그리나 확인증을 이미지 하나로 만들면 PNG와 PDF가 완전히 같은 모양이 됩니다. 화면에서 그린 이미지를 서버가 받아 A4 가로 문서에 넣고 PDF로 변환합니다.

5관리자 화면과 명단 문서15–20분

  1. 웹앱 주소 뒤에 ?mode=admin을 붙이거나 상단 관리자 탭을 누르고, 2단계에서 넣은 관리자 코드를 입력합니다.
  2. 신청 · 승인 · 대기 · 등록 · 확인증 발급 수가 한눈에 보입니다. 표에서 상태를 바꾸면 시트에 바로 반영됩니다.
  3. 현장 안내용 QR이 화면에 떠 있습니다. 접수대 모니터에 띄워 두면 참가자가 폰으로 찍어 바로 등록 화면으로 들어옵니다.
  4. 등록부(서명 포함) Docs · PDF를 누르면 A4 세로 5열(순번/소속/직위/성명/서명)의 공식 문서가 드라이브에 만들어집니다. 결재 · 공문 첨부에 그대로 씁니다.
취소하면 대기자가 자동으로 올라갑니다 승인 상태인 참가자를 취소로 바꾸면 자리가 하나 나므로, 대기 1순위(신청이 이른 순서)가 자동으로 승인되고 참가 확정 안내 메일이 나갑니다. 명단의 대기자 옆에는 대기 1순위처럼 순번이 표시됩니다.
정원이 0이거나 사전 신청을 받지 않는 연수에서는 대기 개념이 없으므로 동작하지 않습니다.
대기자가 현장에 오면 정원과 상관없이 받습니다 정원은 사전 신청을 조절하는 기준이지, 이미 도착한 사람을 돌려보내는 기준이 아니기 때문입니다. 대기자가 등록 화면에서 서명하면 그 자리에서 승인으로 올라갑니다. 좌석이 엄격한 행사라면 대기 안내 메일에 참석 여부를 미리 회신받도록 운영하세요.

+막힐 때

증상원인과 해결
시트에 메뉴가 안 보임스프레드시트를 새로고침하세요. 그래도 없으면 Apps Script에서 onOpen 함수를 한 번 직접 실행합니다.
"시트가 없습니다" 오류① 시트 만들기를 아직 실행하지 않았습니다.
관리자 화면이 "잠겨 있습니다"만 나옴정상입니다. 프로젝트 설정 → 스크립트 속성에 ADMIN_CODE를 넣으면 코드 입력창이 나타납니다(2단계 참고).
관리자 코드를 잊음프로젝트 설정 → 스크립트 속성에서 저장된 값을 그대로 볼 수 있습니다. 바꾸려면 값만 고치면 됩니다.
등록 화면에 소속 칸이 없음정상입니다. 사전 신청 기록이 확인되면 이미 있는 정보는 다시 묻지 않습니다. 처음 온 분은 조회 결과에 따라 칸이 펼쳐집니다.
조회했는데 "성명이 다릅니다"같은 연락처로 신청된 이름과 다릅니다. 사전 신청 때 쓴 이름 그대로 넣어야 합니다.
다른 사람이 웹앱에 못 들어옴배포 설정의 액세스 권한이 모든 사용자인지 확인하세요.
코드를 고쳤는데 그대로임웹앱은 배포된 버전을 보여줍니다. 배포 → 배포 관리 → 연필 → 버전: 새 버전으로 다시 배포하세요.
PNG 내려받기가 안 됨웹앱이 iframe 안에서 실행돼 다운로드가 막히는 환경입니다. PDF로 저장하기를 눌러 드라이브 링크로 여세요.
신청 메일이 안 옴스팸함을 먼저 확인하세요. 그래도 없으면 Apps Script의 무료 메일 하루 할당량(약 100통)을 넘지 않았는지, 메일로그 시트의 오류 메시지를 확인하세요.
서명이 등록부에 안 보임서명 후 발급된 문서부터 들어갑니다. 문서를 다시 만들어 주세요.
QR이 안 찍힘화면 밝기를 올리고 QR을 크게 띄우세요. 휴대폰 기본 카메라 앱이면 별도 앱이 필요 없습니다.
확인증 발급이 거절됨정상 동작입니다. 등록(서명)을 먼저 해야 발급됩니다.
자료 링크가 안 올라감http://나 단축 주소는 막혀 있습니다. https:// 로 시작하는 원본 주소를 넣으세요.

✅실제 연수에 쓰기 전 점검

실습용 시트를 그대로 실전에 쓰려면 아래를 먼저 확인하세요. 개인정보를 다루는 시스템입니다.

  1. ② 예시 신청자 다시 만들기로 만든 더미 데이터를 지우고 시작합니다.
  2. ADMIN_CODE를 실제 암호로 바꿉니다. 실습 때 쓴 임시 값이 그대로 남아 있지 않은지 확인하세요.
  3. 스프레드시트 공유 범위를 확인합니다. 링크가 있는 모든 사용자로 열려 있으면 웹앱을 잠가도 명단이 통째로 노출됩니다.
  4. 신청 화면의 동의 문구를 기관 방침에 맞게 고치고, 연수 종료 후 수집한 정보를 실제로 파기합니다.
  5. 확인증 발급기관명이 본인이 발급 권한을 가진 기관인지 확인합니다.
  6. 서명 원본은 드라이브의 "연수 서명 보관함" 폴더에 쌓입니다. 이 폴더의 공유 범위도 함께 확인하세요.
  7. 자료 화면은 링크를 아는 누구나 볼 수 있습니다. 참가자 산출물에 학생 개인정보가 담긴 링크가 올라오지 않도록 미리 안내하세요.

⚠️이 실습에서 못 하는 것

웹앱은 보안 정책상 카메라를 열 수 없어, 접수대에서 스캐너로 참가자 개인 QR을 읽는 방식은 동작하지 않습니다. 그래서 참가자가 자기 휴대폰으로 접수대 QR(또는 관리자 화면 QR)을 찍고, 성명과 연락처로 직접 등록하며 서명하는 방향으로 설계했습니다. 스캐너가 꼭 필요하면 크롬북 · 태블릿에 별도 스캐너 앱을 두고 접수를 대리 입력하는 방식으로 운영하세요.

완성본 웹앱 열어 보기 →

진행자 데모: script.google.com/macros/s/AKfycbz…/exec