# 설계: 신청 접수 알림과 완료 안내 메일 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_leads` insert 직후 - **받는 사람**: 신청자가 남긴 연락처 - **내용**: 접수 사실, 어떤 URL로 접수됐는지, 언제쯤 연락이 가는지, 문의처(`o2oteam@o2o.kr`) - **보내지 않는 것**: 결과 링크, 진행률 ### 3-2. 신규 신청 알림 (운영자에게, 자동) - **시점**: 3-1과 동시 - **받는 사람**: 운영 담당 주소 1개 - **내용**: 병원명·URL·연락처, 빌드 큐 등록 여부, 확인 화면 링크(`/images/`, `/supporters/`) - **목적**: 신청을 놓치지 않는 최소 장치. 이것만 있어도 지금 상태보다 낫습니다 ### 3-3. 완료 안내 (신청자에게, 사람이 보냄) - **시점**: 운영자가 이미지 검토와 결과 확인을 마치고 **보내기를 눌렀을 때** - **받는 사람**: 신청자 - **내용**: 무엇을 만들었는지, 미리보기 링크(noindex), 병원이 확인해야 할 것 두 가지(`/images/` 사진 확인, `/supporters/` 확인 항목), 색인 전환은 법무 확인 뒤라는 안내 - **전제**: 발송 전에 사진 검토가 끝나 있어야 합니다 --- ## 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 결정이 필요한 것 1. **발송 서비스**: Resend를 추천합니다. 계정과 발신 도메인(`o2o.kr` 하위 무엇으로 할지)이 필요합니다 2. **운영자 알림 수신 주소**: 개인 주소인지 공용 주소인지 3. **완료 안내를 사람이 보내는 방식으로 할지**: 자동 발송으로 하면 사진 검토를 건너뛴 링크가 나갈 수 있습니다. 이 설계는 사람이 보내는 쪽을 전제합니다 4. **"리포트"의 정의**: 완료 안내로 보내는 것이 서포터즈 사이트인지, AEO/GEO 진단 리포트인지, 둘 다인지. 지금 파이프라인은 앞의 것만 만듭니다