2026년 9월 6일 일요일

[교과 연계] 우리 고장 생태·문화유산 실시간 탐색 도감 - 학생이 만드는 실시간 학급 지도



야외 체험학습이 살아있는 학급 지도가 된다 — 생태·문화유산 실시간 탐색 도감 완전 정복

🌿 3~4학년 야외 체험학습 중 학생들이 발견한 야생화·곤충·문화재 사진과 관찰 일기를 제출하면, 학급 도감 웹앱에 10분마다 새 카드가 자동으로 추가되는 실시간 학급 생태 지도. 학생들이 직접 데이터를 생산하고 실시간으로 공유하며 지식을 함께 쌓는 협업 수업입니다.

데이터 창고는 gviz/tq(구글 시트를 데이터베이스처럼 쓰는 공식 데이터 연결 주소) — 교사는 시트 하나만 만들면 됩니다. 단, 학생 실명이 담긴 시트는 공개 금지! 이 글에는 심기 모드(데이터 임베딩) 폴백(fallback)까지 담아 학내망 원칙까지 지키는 설계를 제시합니다.

📖 한 줄 정의

심기 모드(데이터 임베딩): API 데이터를 미리 받아 HTML 파일 안 상수로 박아두는 방식(앱 실행 중 외부 통신 0).

학내망 원칙: 학교 배포 웹앱은 개인정보 수집·저장·전송 없음(외부 CDN·API 호출 0, 단일 파일) — 학생은 학내망에서 교사 PC 서버에 접속.

1. 3대 핵심 분석 비교표

무엇이 바뀌었나요? / 영역 초보자를 위한 쉬운 설명 이렇게 한번 써보세요!
gviz/tq 데이터 파이프 구글 시트를 데이터베이스처럼 쓰는 공식 주소 — 시트를 '링크가 있는 모든 사용자에게 보기'로 열면, 키 발급 없이도 도감 앱에서 읽어옵니다. 학생이 제출할 때마다 도감이 갱신되는 실시간 흐름. docs.google.com/.../gviz/tq 주소 확인.
10분 자동 갱신 도감 앱이 10분마다 데이터를 다시 읽어 새 카드를 렌더링(rendering, 화면 그리기)합니다 — 체험학습 현장에서 돌아온 학생들이 곧바로 자기 발견을 볼 수 있습니다. setInterval 폴링(polling).
개인정보 안전장치 관찰 기록 시트에 학생 실명·사진을 올리면 안 됩니다! 표기는 '모둠 번호-닉네임' 기준으로 제출 양식 자체를 설계하고, 사진은 사람·주소가 안 나온 대상 사진만. 제출 양식 칸 검토.

2. 핵심 아키텍처 해설

① gviz/tq 응답의 래핑(감싸기) 실측

/*O_o*/
google.visualization.Query.setResponse({... "table": { "cols": [...], "rows": [...] }});

gviz/tq의 응답은 순수 JSON이 아니라 위와 같이 감싸진 JSONP(JSON with Padding) 형태로 돌아옵니다 — 이번 실증으로 직접 확인한 구조입니다. 파싱에는 아래 한 줄이 정답입니다.

② 응답 파싱 코드 (실측 기준)

const SHEET = "https://docs.google.com/spreadsheets/d/{시트ID}/gviz/tq?tqx=out:json";

async function loadEntries() {
  const res = await fetch(SHEET);
  const raw = await res.text();
  const json = JSON.parse(raw.substring(raw.indexOf("{"),
    raw.lastIndexOf("}") + 1));   // 래핑 벗기기 — 이 한 줄이 핵심
  return json.table.rows.map(function (r) {
    return {
      name: (r.c[0] || {}).v,     // 발견물 이름
      kind: (r.c[1] || {}).v,     // 생태/문화유산 구분
      note: (r.c[2] || {}).v,     // 관찰 일기
      who:  (r.c[3] || {}).v      // 모둠 번호-닉네임
    };
  });
}

문자열에서 첫 {부터 마지막 }까지 잘라내면 래핑이 벗겨집니다. 실측 응답 구조(table.cols·table.rows·r.c[].v)에 맞춘 안전한 추출 코드입니다.

③ 10분 폴링 자동 갱신

setInterval(function () { loadEntries().then(drawCards); }, 600000);

10분(600초)마다 데이터를 다시 읽어 새 카드를 그립니다. 체험학습 기간 동안 도감이 저절로 두꺼워지는 마법입니다.

④ 심기 모드 폴백(오프라인 안전망)

const EMBED_ENTRIES = [
  { name: "개나리", kind: "생태", note: "노란 꽃이 먼저 봄을 알렸다", who: "3모둠-코알라" }
];

async function loadEntries() {
  if (EMBED_ENTRIES.length > 0) return EMBED_ENTRIES;   // 심기 모드 우선
  ... (gviz/tq 읽기) ...
}

시트가 없거나 학내망이 인터넷과 닫혀 있을 때도 도감이 멈추지 않게, 미리 심은 카드 데이터로 폴백합니다 — 학내망 원칙 정합 설계.

⑤ 원칙·정합

시트는 '링크가 있는 모든 사용자에게 보기'로 열면 누구나 읽을 수 있으므로 학생 실명·개인 사진 금지를 제출 양식 단계부터 규칙으로. 앱은 단일 HTML 더블클릭 실행, 학급 홈페이지 임베드(내장)는 iframe(프레임 넣기) 한 줄로.

3. 초보자를 위한 바이브 코딩 실전 사용 예시

  1. 프롬프트 복사 — 아래 '제미나이 전용 에러 제로 프롬프트' 전체를 복사해 Gemini에 붙여넣습니다.
  2. 역질문 답변 — Gemini의 질문 3가지(데이터 칸 구조, 갱신 주기, 심기 모드 사용 여부)에 답하면 설계가 확정됩니다.
  3. HTML 파일 실행 — 완성 코드를 '탐색도감.html'로 저장 후 더블클릭 — 학급 홈페이지에는 iframe 한 줄로 임베드합니다.

제미나이 전용 에러 제로 프롬프트

[🚨 에러 방지 기본 안전장치]
1. 결과물은 외부 라이브러리·폰트·이미지 파일 없이 단일 HTML 파일로 완성한다 — 더블클릭 즉시 실행.
2. 사운드는 Web Audio API로 직접 합성한다: 새 카드 등장 '똑', 필터 전환 '틱'. 오디오 파일 사용 금지.
3. 파일 상단 EMBED_ENTRIES 상수에 예시 카드 데이터를 심어두어(심기 모드 — 데이터 임베딩), 시트 없이도 도감이 완전히 동작하게 한다.
4. gviz/tq 연동 주소는 상수 SHEET로 분리해두고, 응답 파싱은 '첫 {부터 마지막 }까지 잘라 JSON.parse' 방식으로 구현한다(JSONP 래핑 실측 대응).
5. 10분(setInterval 600000ms)마다 데이터를 다시 읽어 카드를 다시 그린다 — 로딩 실패 시 EMBED_ENTRIES로 폴백(fallback)하고 '오프라인 모드' 안내를 표시한다.
6. 카드에는 발견물 이름·분류(생태/문화유산)·관찰 일기·제보자(모둠 번호-닉네임)를 표시하고, 분류별 필터 버튼을 만든다.
7. 학생 실명·연락처 칸은 일절 만들지 않는다(학내망 개인정보 원칙).
8. // TODO, /* 생략 */ 같은 미완성 코드는 절대 넣지 말고 끝까지 완성한다.

[❓ 역질문 유도]
코드를 바로 만들지 말고, 아래 3가지를 먼저 나에게 질문한 뒤 내 답변으로 설계를 확정한다.
Q1. 시트 칸 구조는 무엇으로? (이름, 분류, 관찰 일기, 제보자 / 원하는 칸 추가)
Q2. 갱신 주기는? (기본 10분 / 30초 시연 모드)
Q3. 카드 디자인 톤은? (자연 파스텔 / 도감 노트 느낌)

🎯 에디터 한줄평

체험학습의 끝은 무엇일까요? 이 도감은 그 답을 '학생이 데이터를 생산하는 것'으로 바꿔줍니다. 내가 발견한 개나리가 도감에 실리고, 친구가 그걸 보고 다음 발견으로 나아가는 — 지식이 함께 두꺼워지는 흐름이 화면에 그대로 보입니다. gviz/tq의 JSONP 래핑 함정까지 실측으로 잡아낸 짜임새가 인상적입니다.

📚 기술·교육 참고 링크