2026년 9월 6일 일요일

[행정/연구] 교원 당직·감독 자동 추첨 배포기 - 균등 배분과 원클릭 배치표



당직·시험 감독·청소 구역 배정이 눈금으로 정해진다 — 균등 배분 추첨 배포기 완전 정복

🏫 학기 초·학기말의 반복 업무 — 전 교직원 당직 근무, 지필평가 고사실 감독관 배치, 교내 환경정리 구역 배정. 기피 요일과 선호를 체크로 취합하면 균등 배분(fair allocation) 알고리즘이 배치표(roster)를 몇 초 만에 만들고, 파일 하나를 공유 폴더에 올려 전 교직원에게 배포합니다.

핵심은 투명성입니다 — 배분 규칙(누적 횟수 최소 우선, 기피 요일 제외)이 화면에 보이므로 수기 배정의 불공정 시비가 원천 차단됩니다. 서버·Apps Script 배포 없이 단일 HTML 더블클릭 완결이며, 배포본은 번호·닉네임만 다룹니다.

📖 한 줄 정의

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

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

1. 3대 핵심 분석 비교표

무엇이 바뀌었나요? / 영역 초보자를 위한 쉬운 설명 이렇게 한번 써보세요!
해결 문제 수기 배정의 불공정 시비 → 규칙이 코드로 보이는 균등 배분으로 전환. 당직·감독·청소 3가지 모드를 한 파일에서 전환합니다. 모드 3종 중 하나로 시작.
취합 기피 요일·선호 요일을 체크 입력으로 취합(2분) → 배분 계산은 몇 초. 사유까지 묻지 않습니다(정보의 최소 수집). 취합 표에서 요일만 체크.
균등 배분 알고리즘 누적 횟수 최소 우선 + 기피 요일 제외 + 직전 배정 제외 — 배분 규칙이 화면에 표시되어 투명합니다. allocate 함수로 배분 원리 이해.
배치표·배포 배치표(roster)를 화면에 크게 띄우고 CSV 내보내기로 로컬 저장 — 파일을 공유 폴더에 올려 전교직원 배포(자동 외부 전송 없음). downloadCSV → 공유 폴더 업로드.
개인정보 설계 배포본 화면은 번호·닉네임만 — 실명 배치표 CSV는 교무부가 로컬에서 관리합니다. 학내망 안에서 완결됩니다. EMBED 명단 상수 심기(외부 통신 0).

2. 핵심 아키텍처 해설

① 데이터: 명단과 요일 조건

const STAFF = [
  { no: 1, nick: "미리내", avoid: ["월"], pref: ["금"] },
  { no: 2, nick: "샛별",   avoid: [],     pref: ["화"] }
];

avoid는 기피 요일, pref는 선호 요일입니다. 사유는 저장하지 않습니다 — '월요일이 힘들다'는 사정까지 코드가 알 필요는 없습니다(정보의 최소 수집).

② 균등 배분: allocate

function allocate(pool, slots, history) {
  const sorted = shuffle(pool).sort(function (a, b) {
    return count(history, a.no) - count(history, b.no);
  });
  const roster = [];
  for (const s of slots) {
    const pick = sorted.find(function (p) {
      return !used(p) && s.avoid.indexOf(p.avoid) === -1;
    });
    if (pick) roster.push({ slot: s, who: pick });
  }
  return roster;
}

누적 횟수가 가장 적은 사람부터 슬롯을 채웁니다. 기피 요일이 겹치면 다음 후보로 넘어가고, 선호 요일이면 후보 순서에서 앞당겨집니다 — 배분 규칙이 화면에 그대로 표시됩니다.

③ 배치표(roster) 렌더

roster.forEach(function (r) {
  addRow(r.slot.day + " " + r.slot.task + " → " + r.who.no + " " + r.who.nick);
});

배치표는 회의 화면에 큰 글씨로 표기 — 모두가 같은 표를 보는 순간, 배정은 결론이 아니라 확인 절차가 됩니다.

④ CSV 기록과 배포

function rosterCSV(roster) {
  return roster.map(function (r) {
    return r.slot.day + "," + r.slot.task + "," + r.who.no + "," + r.who.nick;
  }).join("\n");
}
// CSV 내보내기로 로컬 파일 저장 — 자동 외부 전송 없음

배치표 CSV를 로컬 파일로 내보내면, 교무부는 그 파일을 학내망 공유 폴더에 올려 전 교직원에게 배포합니다(외부 클라우드·Apps Script 배포 없음). 실명이 필요한 공문용 배치표는 교무부가 로컬에서 관리합니다.

⑤ 운영 체크리스트

  • 배분 규칙(누적 최소 우선·기피 제외·직전 배정 제외)을 화면 하단에 상시 표시 — 투명성이 최고의 안전장치입니다.
  • '다시 배분'은 회의 안건으로 — 배분의 재현은 규칙 논의의 시작점입니다.
  • 신규 교원·신설 업무가 생기면 파일 상단 상수를 갱신(심기 루틴)합니다.

3. 따라하기 3단계

  1. 제미나이 전용 에러 제로 프롬프트를 복사해 Gemini에 붙여넣습니다.
  2. AI가 던지는 역질문 3가지(배분 대상, 요일 구조, CSV 서식)에 답하면 단일 HTML 코드가 완성됩니다.
  3. 코드를 배분배포기.html로 저장 후 더블클릭 — 취합 2분 → 배분 몇 초 → CSV 저장 → 공유 폴더 배포로 마무리됩니다.

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

[🚨 에러 방지 기본 안전장치]
1. 결과물은 외부 라이브러리·폰트·이미지 없이 단일 HTML 파일로 완성한다 — 더블클릭 즉시 실행(서버·설치·회원가입·구글 시트 API·Apps Script 금지).
2. 배포본 화면은 번호·닉네임만 다룬다(실명 저장 금지) — 기피 정보는 '기피 요일'만 취합(사유·건강 정보 저장 금지 — 정보의 최소 수집).
3. 균등 배분: 누적 횟수 최소 우선, 기피 요일 제외, 직전 배정 제외 — 배분 규칙을 화면에 표시해 투명하게.
4. 당직·시험 감독·청소 구역 3가지 모드를 한 파일에서 전환한다.
5. 배치표(roster)는 CSV 내보내기로 로컬 파일 저장 — 자동 외부 전송 없음(시트·공유는 교무부 수동).
6. 회의 화면 대응: 배치표 큰 글씨, 버튼 88px 이상. 배정 확정 사운드는 Web Audio 합성('똑').
7. 명단·요일 조건은 파일 상단 상수로 심기(학내망 배포용 외부 통신 0).
8. // TODO, /* 생략 */ 금지 — 끝까지 완성한다.

[❓ 역질문 유도]
코드를 바로 만들지 말고, 아래 3가지를 먼저 질문한 뒤 내 답변으로 설계를 확정한다.
Q1. 배분 대상은? (당직 / 시험 감독 / 청소 구역 / 3종 모드)
Q2. 요일 구조는? (월~금 / 주말 포함)
Q3. 배치표 CSV 서식은? (요일,업무,번호,닉네임 기본)

🎯 에디터 한줄평

수기 배정의 '누가 자꾸 나가?'라는 시비가 누적 횟수라는 한 칸의 눈금으로 끝납니다 — 공정은 감(感)이 아니라 눈금입니다. 그리고 이 도구의 진짜 우아함은 기피 사유까지 묻지 않는 설계에 있습니다. 요일만 묻는 배려는 동료를 존중하는 정보의 최소 수집이자, 배분 알고리즘보다 먼저 지켜야 할 원칙입니다.

📚 기술·교육 참고 링크

  • MDN — Array.sort() : 균등 배분의 정렬 원리
  • 교육·행정 연계: 교무 기획 업무(당직·시험 감독·환경정리), 연수·회의 운영으로 확장