RSVP 블록
정원과 대기자 명단을 지원하는 무료 "참석하시겠어요?" 질문입니다 — 결제가 아니라 인원 파악만 필요한 행사를 위한, 상품 블록의 유료 티켓 재고 상한에 해당하는 무료 버전입니다.
작동 방식
게스트 없는 RSVP는 투표의 단일 선택 투표와 정확히 동일하게 동작합니다: "예"와 "아니요"는 투표 선택지에 대해 buildChipGroup이 만들어내는 것과 같은 링크 우선 칩 쌍으로 렌더링됩니다. 확인은 무언가가 기록되기 전에 호스팅된 라이브 뷰에서(또는 클라이언트가 지원하는 경우 이메일 내 폼 전송을 통해 직접) 이루어지므로, 링크를 미리 가져오는 기업 스캐너가 카운트를 부풀릴 수 없습니다.
게스트 동반 허용을 켜면 "예" 응답에만 변화가 생깁니다: 일반 GET 링크로는 실제 폼 필드가 제공하는 것 같은 선택지를 줄 수 없으므로, 게스트 수는 라이브 뷰 전용 키네틱 <form><select> 컨트롤이 됩니다. 이는 고정 링크로는 담을 수 없는 값에 대해 과제 블록의 단답형/링크 답변이 라이브 뷰를 필요로 하는 방식과 같습니다. "예(게스트 인원 선택)"는 티어 2/티어 3 폴백에서 /act로 곧장 향하는 대신 라이브 뷰 자체로 연결되는 일반 링크로 렌더링됩니다. 게스트 없는 "예"(게스트를 0명 선택했거나 게스트 기능 자체가 꺼져 있는 경우)는 어느 쪽이든 여전히 일반 원탭 링크로 /act에 도달합니다 — 게스트 수 선택 단계만 특별히 라이브 뷰를 필요로 합니다.
정원 집계는 수신자별 중복 제거 확인과 동일한 단일 Firestore 트랜잭션 안에서 이루어집니다. 단순히 .count() 쿼리를 다시 확인하고 드물게 발생하는 초과 판매 경쟁 상황에서 환불로 대응하는 상품 블록의 체크아웃과 달리, RSVP에는 정원 초과 응답에 대한 환불 같은 안전망이 없습니다. 그래서 결정과 기록이 별도의 두 단계로 나뉘어 경쟁 상황이 끼어들 수 있는 대신, 원자적으로 함께 이루어집니다. 정원을 0보다 크게 설정하고 확정된 RSVP와 그 게스트 수의 합이 이를 초과하게 되면, 해당 응답은 확정 대신 대기자로 기록되며 수신자는 일반적인 감사 인사 대신 여러분이 설정한 대기자 안내 메시지를 보게 됩니다.
"아니요" 응답은 항상 불참으로 기록되며 정원과는 절대 대조되지 않습니다. 정원 0은 무제한을 의미하며, 이는 상품 블록의 재고 필드가 쓰는 것과 동일한 "0 = 미설정" 규칙입니다. 익명 응답(수신자 토큰이 없는 경우 — 예를 들어 서드파티 ESP에 붙여넣은 내보내기 HTML 파일에서 온 응답)은 대조할 수신자가 없으므로 중복 제거 확인을 건너뜁니다. 다만 동일한 정원 트랜잭션은 그대로 거치므로, 익명 응답이 몰리더라도 대기자 명단 경계를 초과 판매할 수는 없습니다 — 다만 이 경로에서는 인원별 중복 감지만 사용할 수 없습니다.
프로젝트에 마감일이나 응답 상한이 설정되어 있다면(설문 라이프사이클 참고), 마감된 RSVP는 라이브 뷰에서 두 칩 모두 비활성화된 회색 버전과 "이 설문은 새 응답을 받지 않습니다"라는 안내로 교체됩니다.
설정 가능한 필드:
- 질문 — 기본값은 "참석하시겠어요?"입니다.
- 정원(0 = 무제한).
- 게스트 동반 허용 — "예"에 게스트 수 선택기를 추가합니다.
- RSVP당 최대 게스트 수(게스트가 허용된 경우) — 선택기의 범위를 제한합니다(1~20).
- 대기자 안내 메시지 — 정원이 다 찼을 때 일반적인 감사 인사 대신 표시됩니다.
- 카드의 배경색, 패딩, 테두리, 모서리 반경.
- 질문 색상/크기, 예/아니요 버튼 색상/배경 오버라이드.
모든 RSVP는 확정/불참/대기자 카운트와 게스트 합계로 집계되며, 다른 모든 블록이 사용하는 범용 응답 증가 경로가 아니라 프로젝트의 rsvpBlocks 집계 버킷에 직접 기록됩니다. 확정 대 대기자 결정이 카운트 자체와 같은 트랜잭션 안에서 이루어져야 하기 때문에 두는 의도적인 예외입니다.
예시
Subject
Will you join us?
"행사" 프로젝트 용도는 미팅 링크, 장소, 캘린더에 추가와 함께 RSVP 블록이 이미 배치된 새 프로젝트로 시작합니다. 좌석이 제한된 장소에 정원을 설정해 두면 별도의 설정 없이도 블록이 대기자 명단을 처리합니다 — 행사 & 웨비나를 참고하세요. 스포츠 클럽은 같은 블록을 트라이아웃이나 원정 좌석 인원 제한에 사용해, 누구도 수작업으로 추적할 필요 없이 정원이 인원수를 정확하게 유지하도록 합니다 — 스포츠 팀 & 클럽을 참고하세요. 좌석 제한이 전혀 없는 무료 커뮤니티 모임이라면 정원을 그냥 0으로 두어, 정원 강제 없이 순수하게 신뢰할 수 있는 인원 파악 용도로만 RSVP를 사용하면 됩니다.
정적 폴백의 모습
<div id="em-rsvp-1" style="margin:12px 0;background-color:transparent">
<p style="margin:0 0 10px;font-weight:600;font-size:16px;color:#111827">Will you attend?</p>
<div>
<span class="kn-fallback">
<a href="https://mailinapp.com/v/eyJhbGci.../act?blockId=rsvp-1&blockType=rsvp&action=rsvp&response=yes"
style="display:inline-block;margin:0 6px 6px 0;padding:8px 14px;border:1px solid #d1d5db;
border-radius:6px;background-color:#ffffff;color:#111827;font-size:14px;text-decoration:none">
Yes
</a>
<a href="https://mailinapp.com/v/eyJhbGci.../act?blockId=rsvp-1&blockType=rsvp&action=rsvp&response=no"
style="display:inline-block;margin:0 6px 6px 0;padding:8px 14px;border:1px solid #d1d5db;
border-radius:6px;background-color:#ffffff;color:#111827;font-size:14px;text-decoration:none">
No
</a>
</span>
</div>
</div>
이는 게스트 없는 티어 2 폴백입니다: /v/[token]/act로 연결되는 일반 링크이며, 투표 선택지 칩과 모양이 동일하고, 이메일 내 폼이 렌더링되지 않는 곳이라면 어디서나 표시됩니다.