# 행사와 축제를 위한 근무 시간 선택이 있는 자원봉사자 신청 폼

> 사람들이 근무 시간을 고르고 당일 연락처를 남기는 자원봉사자 신청 폼과, 인원이 부족한 근무 시간을 보여 주고 근무표를 만드는 스크립트.

2026-10-25 게시 · https://ikiform.com/ko/guides/event-registration/volunteer-signup

자원봉사자가 폼 하나에서 가능한 근무 시간을 모두 체크하고 전화번호, 티셔츠 사이즈, 비상 연락처를 적어 Ikiform으로 POST하게 하세요. Ikiform은 각 신청을 저장하고 코디네이터에게 이메일을 보내지만 근무 시간을 채우거나 마감하지는 않으므로, 필요 인원 대비 근무 시간별 자원봉사자를 세고 근무표를 쓰는 짧은 스크립트를 실행하세요. 부족한 근무 시간은 여유 있는 자원봉사자에게 직접 요청해 채우세요.

## 자원봉사자는 무엇이 다른가

RSVP는 '오시나요?'라는 질문 하나만 합니다. 자원봉사자 신청은 '언제'를 묻고, 그 답은 각 근무 시간에 필요한 인원과 비교할 때만 의미가 있습니다. 오전 7시 설치에는 여섯 명이 필요한데 두 명이 오고, 화창한 오후에는 열 명이 필요한데 열아홉 명이 옵니다. 할 일은 인원 세기가 아니라 빈자리 채우기입니다.

- **하나의 선택이 아니라 가능한 시간.** 사람들은 여러 근무 시간을 맡을 수 있습니다. 무엇이 필요한지 짐작하게 하지 말고, 가능한 근무 시간을 모두 받아서 배정하세요.
- **당일 연락처.** 이메일은 계획용입니다. 당일에는 휴대폰 번호와 자원봉사자별 비상 연락처가 필요합니다.
- **주문할 것.** 티셔츠, 목걸이 명찰, 점심을 사이즈와 수량별로.
- **나이.** 많은 행사는 자원봉사자마다 성인이거나 보호자의 동의가 필요합니다. 어떤 규칙이 적용되는지 소속 단체에 확인하세요. 체크박스는 답을 기록할 뿐 법적 확인은 아닙니다.

SignUpGenius 같은 자원봉사 플랫폼은 슬롯이 차면 닫히는 슬롯 기반 신청을 운영합니다. 슬롯별 강제 제한이 필요하다면 그런 플랫폼을 쓰세요. Ikiform은 폼을 내 사이트에 두고, 깔끔한 명단에서 근무 시간을 손으로 배정해도 괜찮은 주최자에게 맞습니다.

다이어그램: 자원봉사자의 가능 시간을 빈자리가 보이는 근무표로 바꾸기

1. 자원봉사자가 신청 폼에서 가능한 근무 시간을 모두 체크하면, 폼이 Ikiform으로 POST합니다.
2. Ikiform은 각 신청을 저장하고 코디네이터에게 이메일을 보냅니다.
3. 스크립트가 API로 신청을 읽고, 근무 시간별로 필요 인원 대비 자원봉사자를 셉니다.
4. 근무 시간마다 이름과 전화번호가 담긴 rota.csv를 씁니다.
5. 설치 6명 중 2명처럼 부족한 근무 시간이 바로 드러나므로, 다른 곳에서 여유 있는 자원봉사자에게 요청할 수 있습니다.

Ikiform은 가능 시간을 보관합니다. 스크립트가 이를 충원 현황으로 바꾸고, 최종 결정은 코디네이터가 합니다.

## 폼

사람들이 훑어볼 수 있도록 근무 시간을 요일별로 묶으세요. 체크박스 이름이 `shifts[]`이므로 하나만 체크해도 목록으로 저장됩니다. 임베드를 지원하는 모든 사이트나 빌더에서 일반 HTML로 작동합니다.

`volunteer.html`:

```html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <label>Name <input name="name" autocomplete="name" required></label>
  <label>Email <input name="email" type="email" autocomplete="email" required></label>
  <label>Mobile number for the day <input name="phone" type="tel" autocomplete="tel" placeholder="+44 7700 900123" required></label>

  <fieldset>
    <legend>Shifts you can do</legend>
    <p>Saturday</p>
    <label><input type="checkbox" name="shifts[]" value="sat_setup"> 7:00 to 10:00, setup</label>
    <label><input type="checkbox" name="shifts[]" value="sat_day"> 10:00 to 14:00</label>
    <label><input type="checkbox" name="shifts[]" value="sat_late"> 14:00 to 18:00</label>
    <p>Sunday</p>
    <label><input type="checkbox" name="shifts[]" value="sun_day"> 10:00 to 14:00</label>
    <label><input type="checkbox" name="shifts[]" value="sun_pack"> 14:00 to 17:00, pack-down</label>
  </fieldset>

  <label>Where you'd like to help
    <select name="role">
      <option value="anywhere">Anywhere</option>
      <option value="welcome">Welcome desk</option>
      <option value="food">Food stall</option>
      <option value="stewarding">Stewarding</option>
    </select>
  </label>
  <label>T-shirt size
    <select name="tshirt" required>
      <option value="s">S</option><option value="m" selected>M</option><option value="l">L</option>
      <option value="xl">XL</option><option value="xxl">XXL</option>
    </select>
  </label>
  <label>Emergency contact name and number <input name="emergency_contact" required maxlength="160"></label>
  <label><input type="checkbox" name="adult" required> I'm 18 or over, or a parent or guardian is filling this in with me</label>

  <input type="hidden" name="_redirect" value="https://fair.example/volunteers/thanks">
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden>
  <button type="submit">Sign me up</button>
</form>
```

이 정의를 폼의 **Fields** 탭에 붙여 넣으세요. 그러면 어느 페이지에서 왔든 서버가 근무 시간이 없는 신청, 전화번호가 아닌 번호, 체크하지 않은 나이 확인란을 거부합니다.

폼: Volunteer signup

- **이름** (`name`, text, 필수)
- **이메일** (`email`, email, 필수)
- **당일 연락할 휴대폰 번호** (`phone`, phone, 필수)
- **가능한 근무 시간** (`shifts`, multi_select, 필수)
- **돕고 싶은 곳** (`role`, select)
- **티셔츠 사이즈** (`tshirt`, select, 필수)
- **비상 연락처 이름과 번호** (`emergency_contact`, text, 필수)
- **18세 이상이거나, 부모 또는 보호자가 함께 작성하고 있습니다** (`adult`, checkbox, 필수)

`shifts`는 `min_items: 1`인 `multi_select`입니다. `phone`은 번호의 형식을 확인하는 `phone` 필드입니다. `adult`는 반드시 체크해야 합니다.

| 필드 | 묻는 이유 |
| --- | --- |
| `phone` | 근무 변경 문자와 당일 연락 |
| `shifts` | 배정의 기준이 되는 가능 시간 |
| `role` | 선호 사항. 안내 데스크를 원한 사람이 안내 데스크에 배정되도록 |
| `tshirt` | 2주 전에 넣는 주문 |
| `emergency_contact` | 마케팅이 아니라 응급 처치 팀을 위한 정보 |
| `adult` | 자체 `created_at`을 가진 제출에 기록되는 단체의 나이 규칙 |

> 전화번호와 비상 연락처는 직접 신청하지 않는 사람에 관한 개인 정보입니다. 내보낸 파일은 비공개 장소에 보관하고, 근무표는 근무 책임자와만 공유하고, 행사 후에는 제출을 삭제하세요.

## 근무표를 만들고 빈자리 확인하기

현황이 필요할 때마다 Node와 시크릿 API 키로 실행하세요. 자원봉사자마다 최신 신청을 취해, 각 근무 시간을 충원, 부족, 여유로 출력하고, 근무 시간별 이름과 번호가 담긴 `rota.csv`를 씁니다.

`rota.ts`:

```ts
import { writeFileSync } from "node:fs";
import { createClient } from "@ikiform/sdk";

const NEEDED: Record<string, number> = { sat_setup: 6, sat_day: 10, sat_late: 10, sun_day: 8, sun_pack: 6 };
const ikiform = createClient({ apiKey: process.env.IKIFORM_SECRET_KEY! });
const people = new Map<string, Record<string, unknown>>();

for await (const submission of ikiform.submissions.iterate({ formId: "frm_xxxxxxxxxxxxxxxx", status: "received", limit: 100 })) {
  const email = String(submission.fields.email ?? "").trim().toLowerCase();
  if (email && !people.has(email)) people.set(email, submission.fields);
}

const cell = (value: unknown) => `"${String(value ?? "").replaceAll('"', '""')}"`;
const rows = [["shift", "name", "phone", "role", "tshirt"].join(",")];

for (const [shift, needed] of Object.entries(NEEDED)) {
  const team = [...people.values()].filter((fields) => (fields.shifts as string[] | undefined)?.includes(shift));
  const state = team.length < needed ? `SHORT ${needed - team.length}` : team.length > needed ? "spare" : "ok";
  console.log(`${shift.padEnd(10)} ${team.length}/${needed} ${state}`);
  for (const fields of team) {
    rows.push([shift, fields.name, fields.phone, fields.role, fields.tshirt].map(cell).join(","));
  }
}

writeFileSync("rota.csv", `${rows.join("\n")}\n`);
```

- 목록은 최신순으로 오므로, 가능 시간을 바꿔 다시 신청한 자원봉사자는 최신 응답으로 집계됩니다.
- 한 사람이 체크한 모든 근무 시간 아래에 나타납니다. 이것은 가능 시간입니다. CSV에서 배정으로 줄이고, 각자에게 최종 근무 시간을 알려 주세요.
- 이름에 들어간 쉼표와 따옴표는 이스케이프되므로, CSV가 어떤 스프레드시트에서든 깔끔하게 열립니다.

코드 없이 빠르게 보려면 **Submissions**에서 CSV를 내보내고 `sat_setup` 같은 근무 시간 값으로 `shifts` 열을 필터링하세요. 내보낸 파일에서 다중 선택 값은 한 셀에 합쳐져 있습니다.

## 가능 시간에서 배정으로

1. 2주 전에 근무표를 실행하고 `tshirt` 개수로 티셔츠를 주문하세요.
2. 부족한 근무 시간마다, 여유가 있으면서 그 근무 시간도 체크한 자원봉사자에게 메시지를 보내세요. 이미 가능하다고 한 사람들입니다.
3. 이메일이나 메신저 도구로 자원봉사자마다 최종 근무 시간을 보내세요. 알림 이메일의 **Reply**는 바로 그 사람에게 갑니다.
4. 전날, 근무 책임자용으로 전화번호가 들어간 근무표를 인쇄하세요.

Ikiform은 폼을 작성한 사람에게 이메일을 보내지 않습니다. 알림 이메일은 여러분과 팀에게만 가므로 자동 응답, 확인 이메일, 더블 옵트인이 없습니다. 이런 이메일은 [웹훅](https://ikiform.com/ko/docs/webhooks.md)으로 트리거해 이메일 도구에서 보내세요. 자원봉사자는 무엇을 신청했는지 잊어버리므로, 최종 근무표는 일주일 전과 전날 저녁에 한 번씩 직접 보내세요.

팀이 이미 대화하는 곳에서 신청 소식을 받으려면 웹훅을 [Slack](https://ikiform.com/blog/form-submissions-to-slack.md)이나 [Discord](https://ikiform.com/blog/form-submissions-to-discord.md)로 보내세요. 그러면 코디네이터가 부족한 근무 시간이 채워지는 것을 실시간으로 볼 수 있습니다.

## 모집하기 전에 확인하기

1. 폼의 **Allowed domains**에 사이트 도메인을 추가하고, 개발하는 동안에는 `localhost`도 추가하세요. 비워 두면 어디서든 POST를 받습니다.
2. 근무 시간 하나를 체크해 신청해 보세요. 대시보드에서 `shifts`는 값이 하나인 목록입니다.
3. 근무 시간 없이, 또는 나이 확인란을 체크하지 않고 신청해 보세요. 브라우저가 막고, 직접 만든 POST는 `422`를 받습니다.
4. 알림 수신자 각각의 받은편지함을 확인하세요. 각자 필드가 담긴 이메일을 받고, 폼에 `email` 필드가 있으면 **Reply**는 제출자에게 갑니다.
5. 근무표 스크립트를 실행하세요. 테스트 신청은 해당 근무 시간 아래에 나오고, 나머지 근무 시간은 모두 부족으로 표시됩니다.
6. 스프레드시트에서 `rota.csv`를 열고 전화번호 열을 확인하세요.

## 주의할 점

| 문제 | 해결 방법 |
| --- | --- |
| 근무 시간 하나가 목록이 아니라 텍스트로 저장됩니다 | 체크박스 이름이 `[]` 없이 `shifts`이고 정의된 필드가 없습니다. 이름을 `shifts[]`로 바꾸거나 `shifts`를 `multi_select`로 정의하세요. |
| `phone`에서 `422` | 번호가 전화번호처럼 보이지 않습니다. 정의에서처럼 도움말 텍스트에서 국가 번호를 요청하세요. |
| 근무표에 자원봉사자가 두 번 나옵니다 | 서로 다른 이메일 두 개로 신청했습니다. 손으로 합치세요. 스크립트는 이메일을 기준으로 합니다. |
| `422 validation_failed` | POST가 폼의 필드 정의와 맞지 않습니다. `error.fields`에 각 필드와 이유가 나옵니다. 입력의 `name`을 필드 ID와 맞추세요. |
| `429 rate_limited` | 한 방문자가 폼의 레이트 리밋보다 많이 보냈습니다. Standard는 방문자당 분당 5회를 허용합니다. `Retry-After`만큼 기다리거나, 공유 IP 하나에서 POST하는 폼이라면 Relaxed나 Custom을 고르세요. |

## 질문

### 근무 시간이 차면 Ikiform이 마감할 수 있나요?

아니요. Ikiform에는 옵션별 제한이 없습니다. 가능 시간을 받고, 스크립트나 시트로 근무 시간별 자원봉사자를 세고, 직접 배정하세요. 강제 제한이 더 중요하다면 슬롯 기반 신청 도구를 쓰세요.

### 한 자원봉사자에게서 여러 근무 시간을 받으려면 어떻게 하나요?

shifts[]라는 이름의 체크박스를 쓰고 shifts를 multi_select 필드로 정의하세요. 체크한 근무 시간은 모두 목록 하나에 저장되고, min_items: 1로 최소 하나를 필수로 만듭니다.

### 자원봉사자가 근무 시간을 바꿀 수 있나요?

같은 이메일로 다시 신청하게 하세요. 근무표 스크립트는 자원봉사자별 최신 신청을 쓰므로, 새 가능 시간이 이전 것을 대신합니다.

### Ikiform이 폼을 제출한 사람에게 이메일을 보낼 수 있나요?

아니요. Ikiform은 제출자가 아니라 여러분과 팀에게 이메일을 보내므로, 자동 응답이나 확인 이메일이 없습니다. 이메일 도구로 웹훅을 보내고 거기서 확인 이메일을 발송하세요.

### Ikiform은 무료인가요?

아니요, 무료 플랜은 없습니다. 테스트는 무료입니다. 결제 전에 localhost에서 테스트 제출을 매월 50건 보낼 수 있습니다. 실제로 운영하려면 Pro가 제출 500건에 월 $6부터이며, 한 번만 결제해 제출 10,000건을 $49에, 50,000건을 $149에 살 수도 있습니다. 크레딧은 만료되지 않습니다.

## 가이드 더 보기

- [행사 등록](https://ikiform.com/ko/guides/event-registration.md): 티켓 앱 없이 내 행사 페이지에서 RSVP를 받는 방법: 폼, 동반 인원 제한, 정확한 인원 집계, 마감, 체크인 명단.
- [Eventbrite 없이](https://ikiform.com/ko/guides/event-registration/without-eventbrite.md): 무료 커뮤니티 행사의 등록을 내 사이트에서 운영하세요: 세션 선택, 내 도구로 보내는 확인 이메일, 강의실별 인원, 체크인 명단.
- [결혼식 RSVP](https://ikiform.com/ko/guides/event-registration/wedding-rsvp.md): 직접 만든 웨딩 웹사이트용 RSVP 폼: 초대장당 응답 하나, 이름이 있는 손님별 식사, 마감일, 아직 응답하지 않은 사람 목록.
