랜딩 신청 모달은 남긴 연락처로 안내한다고 말하는데 보내는 코드가 없다. 운영자도 신청이 들어온 사실을 알 방법이 없다. discovery_leads 는 anon insert 만 열려 있고 폴러는 supporter_builds 만 본다. 메일을 셋으로 나눈다. 접수 확인(신청자)과 신규 신청 알림(운영자)은 insert 트리거로 자동 보내고, 완료 안내는 사람이 보낸다. 자동으로 보내면 사진 검토를 건너뛴 링크가 나간다. 발송은 Edge Function 에 두고 프런트에서 부르지 않는다(anon 키 스팸 경로). email_log 로 중복 발송을 막고 안 갔다는 문의에 답할 근거를 남긴다. 연락처가 전화번호일 수 있어 contact_kind 를 함께 저장한다. 발송 서비스 계정·발신 도메인·"리포트"의 정의는 결정 대기로 8절에 적었다. 개인 업무 문서(주간보고)는 저장소에 올리지 않는다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
7.8 KiB
설계: 신청 접수 알림과 완료 안내 메일 v0.1
작성 2026-09-18 · 대상 AI Discovery 랜딩(/discovery) 신청 흐름
1. 지금 무엇이 비어 있나
랜딩 신청 모달은 이렇게 말합니다.
입력하신 URL을 실측 진단한 뒤, 남겨주신 연락처로 리포트를 안내드립니다.
보내는 코드가 없습니다. workers/, scripts/, supabase/functions/ 전체에 메일 발송이 없습니다. 유일한 mailto:는 저장 실패 시 사람이 직접 메일을 쓰라고 띄우는 폴백입니다(DiscoveryLeadModal.tsx:82).
그래서 지금은 이렇게 됩니다.
신청 → discovery_leads (status: new)
→ supporter_builds 큐 → 워커가 빌드 → preview
→ 여기서 끝. 신청자에게도, 운영자에게도 아무 연락이 없음
2026-09-18 JK성형외과 신청이 정상 접수되고 10분 만에 빌드까지 끝났지만, 신청자가 직접 확인하기 전까지 아무도 몰랐습니다.
문제는 두 갈래입니다.
| 문제 | |
|---|---|
| 운영자 | 신청이 들어온 사실을 알 방법이 없습니다. discovery_leads는 anon insert만 열려 있고 조회는 service_role 전용이며, 폴러는 supporter_builds만 봅니다 |
| 신청자 | 화면이 약속한 안내를 받지 못합니다 |
2. 설계 원칙
원칙 1. 자동 발송은 접수 알림까지만 한다.
완료 안내를 자동으로 보내면 사람 검토를 건너뛴 결과물 링크가 나갑니다. 이번 JK 건에서 첫 화면 대표 사진이 사람 확인이 필요한 사진이었던 것을 생각하면, 자동 발송이 아니었던 것이 결과적으로 안전했습니다. 완료 안내는 사람이 보내기를 누를 때 나갑니다.
원칙 2. 화면의 약속과 코드를 맞춘다.
지금 모달 문구는 자동으로 갈 것처럼 읽힙니다. 실제 동작에 맞게 문구를 고치거나, 동작을 문구에 맞추거나 둘 중 하나를 해야 합니다. 이 설계는 후자에 가깝되 검토 단계를 명시하는 쪽입니다.
원칙 3. "리포트"라는 말을 정확히 쓴다.
현재 파이프라인이 만드는 것은 서포터즈 사이트입니다. 랜딩이 말하는 AEO/GEO 36항목 진단 리포트(/discovery/viewclinic 형태)는 이 빌드에서 생성되지 않습니다. 신청 한 건이 서로 다른 두 산출물로 갈라져 있어, 메일 문안에서 무엇을 보내는지 분명히 해야 합니다.
3. 보내는 메일 3종
3-1. 접수 확인 (신청자에게, 자동)
- 시점:
discovery_leadsinsert 직후 - 받는 사람: 신청자가 남긴 연락처
- 내용: 접수 사실, 어떤 URL로 접수됐는지, 언제쯤 연락이 가는지, 문의처(
o2oteam@o2o.kr) - 보내지 않는 것: 결과 링크, 진행률
3-2. 신규 신청 알림 (운영자에게, 자동)
- 시점: 3-1과 동시
- 받는 사람: 운영 담당 주소 1개
- 내용: 병원명·URL·연락처, 빌드 큐 등록 여부, 확인 화면 링크(
/images/<clinic_id>,/supporters/<clinic_id>) - 목적: 신청을 놓치지 않는 최소 장치. 이것만 있어도 지금 상태보다 낫습니다
3-3. 완료 안내 (신청자에게, 사람이 보냄)
- 시점: 운영자가 이미지 검토와 결과 확인을 마치고 보내기를 눌렀을 때
- 받는 사람: 신청자
- 내용: 무엇을 만들었는지, 미리보기 링크(noindex), 병원이 확인해야 할 것 두 가지(
/images/<id>사진 확인,/supporters/<id>확인 항목), 색인 전환은 법무 확인 뒤라는 안내 - 전제: 발송 전에 사진 검토가 끝나 있어야 합니다
4. 무엇으로 보내나
4-1. 발송 수단
현재 메일 발송 키가 하나도 없습니다. .env에 Resend·SendGrid·SES·SMTP 어느 것도 없어 계정부터 필요합니다.
| 후보 | 장점 | 단점 |
|---|---|---|
| Resend (추천) | Edge Function에서 fetch 한 번. 도메인 인증이 단순. 무료 한도로 이 규모는 충분 | 계정·도메인 인증 필요 |
| SendGrid | 전달률 기록이 길다 | 설정 항목이 많다 |
| AWS SES | 단가가 가장 낮다 | 샌드박스 해제 심사가 필요 |
발신 도메인은 o2o.kr 계열을 쓰고, 신규 도메인은 초기 전달률이 낮으므로 SPF·DKIM·DMARC를 먼저 맞춥니다.
4-2. 발송 위치
Supabase Edge Function notify-lead 를 새로 만듭니다.
프런트에서 직접 부르지 않습니다. 프런트가 부르면 anon 키로 메일을 쏠 수 있게 되어 스팸 경로가 됩니다. DB 변경을 신호로 삼습니다.
discovery_leads INSERT
→ Postgres 트리거 (pg_net)
→ Edge Function notify-lead (service_role 검증)
→ Resend 호출 2건 (신청자 접수 확인 + 운영자 알림)
→ email_log 기록
완료 안내(3-3)는 같은 함수의 다른 진입점으로 두고, 운영자 화면의 버튼에서 호출합니다.
5. 필요한 DB 변경
5-1. email_log 신설
무엇을 언제 누구에게 보냈는지 남깁니다. 중복 발송을 막고, 안 갔다는 문의에 답할 근거가 됩니다.
| 열 | 용도 |
|---|---|
id |
|
kind |
lead_ack · lead_notify · build_done |
lead_id / clinic_id |
대상 |
to_addr |
받는 주소 |
status |
sent · failed |
provider_id |
발송 서비스가 준 id. 전달 추적용 |
error |
실패 사유 |
created_at |
중복 발송 방지는 (kind, lead_id) 유니크로 겁니다.
5-2. discovery_leads.status 를 실제로 쓴다
지금은 모든 행이 new로 고정입니다. 흐름을 담도록 값을 정합니다.
new → notified(접수 메일 발송) → building → review(사람 검토 중)
→ delivered(완료 안내 발송) → closed
5-3. 연락처가 이메일이 아닐 수 있다
모달은 "이메일 또는 전화번호"를 받습니다. 전화번호면 메일을 보낼 수 없습니다.
- 저장 시 형식을 판별해
contact_kind(email·phone)를 같이 남깁니다 phone이면 접수 메일을 건너뛰고 운영자 알림에 전화로 연락 필요를 표시합니다
6. 화면에서 고칠 것
| 위치 | 지금 | 바꿀 안 |
|---|---|---|
| 신청 모달 완료 문구 | "실측 진단한 뒤, 남겨주신 연락처로 리포트를 안내드립니다" | "접수됐습니다. 확인 메일을 보내 드렸습니다. 결과가 준비되면 남겨주신 연락처로 안내드립니다" |
| 운영자 화면 | 없음 | 완료 안내 발송 버튼. 사진 검토가 끝나지 않았으면 버튼을 잠그고 이유를 표시 |
7. 만들 순서
| 순서 | 할 일 | 비고 |
|---|---|---|
| 1 | 발송 서비스 계정과 도메인 인증 | haewon 결정 필요. 이것 없이는 아무것도 못 보냅니다 |
| 2 | email_log 테이블, contact_kind 열 추가 |
|
| 3 | Edge Function notify-lead + 트리거 |
3-1·3-2 자동 발송 |
| 4 | 모달 문구 수정 | 1~3과 무관하게 지금 할 수 있습니다 |
| 5 | 완료 안내 발송 버튼 | 사진 검토 완료 조건과 묶습니다 |
1번이 없으면 2~3번이 무의미하므로, 4번을 먼저 넣어 화면과 코드의 어긋남부터 없애는 방법도 있습니다.
8. haewon 결정이 필요한 것
- 발송 서비스: Resend를 추천합니다. 계정과 발신 도메인(
o2o.kr하위 무엇으로 할지)이 필요합니다 - 운영자 알림 수신 주소: 개인 주소인지 공용 주소인지
- 완료 안내를 사람이 보내는 방식으로 할지: 자동 발송으로 하면 사진 검토를 건너뛴 링크가 나갈 수 있습니다. 이 설계는 사람이 보내는 쪽을 전제합니다
- "리포트"의 정의: 완료 안내로 보내는 것이 서포터즈 사이트인지, AEO/GEO 진단 리포트인지, 둘 다인지. 지금 파이프라인은 앞의 것만 만듭니다