Recent Posts
Tags
- 코딩테스트 python
- 이것이 취업을 위한 코딩테스트다 with 파이썬
- SQL
- 부스트코스
- 프로그래머스
- AI 플랫폼을 활용한 데이터 분석
- r
- 코딩테스트
- 데이터 분석 기반 에너지 운영 관리자 양성 및 취업과정
- PY4E
- 오라클
- 이기적
- python
- 네이버부스트캠프
- 기초다지기
- Ai
- unsub
- 빅데이터분석기사
- DB
- 데이터베이스
- 인공지능기초다지기
- Oracle
- 빅데이터 분석 기반 에너지 운영 관리자 양성 및 취업과정
- 빅분기
- 파이썬
- boostcoures
- 정보처리기사
- Django
- [멀티잇]데이터 시각화&분석 취업캠프(Python)
- boostcourse
- Today
- Total
매일공부
캠페인 상태 머신: 테스트 없이 실제 메일이 나가지 않도록 만들기 본문
이메일 캠페인 도구 개발기 시리즈 (5/9). 전체 개요
문제
초기 버전은 캠페인을 만들면 바로 pending 상태가 되고, 스케줄러 (scripts/send_scheduled_campaigns.py)가 scheduled_at이 되면 별도 확인 없이 전체 대상자에게 즉시 발송했다. 실수로 오타가 있는 본문, 잘못된 대상 그룹을 그대로 전체 발송해버릴 위험이 있는 구조였다.
해결: 상태 머신에 "테스트 승인" 단계 추가
pending_review (작성/테스트 대기)
│ 테스트 발송(TEST 그룹) 성공
▼
pending (승인, 예약 발송 대기)
│ scheduled_at 도달 + 스케줄러 실행
▼
sending → sent / failed
- campaigns.status ENUM에 pending_review 추가, 기본값도 pending_review로 변경
- 테스트 발송 시각 기록용 test_sent_at DATETIME NULL 컬럼 추가
- 새 캠페인은 INSERT 시점에 pending_review로 생성 → 스케줄러는 status='pending'만 조회하므로, 승인 전까지는 절대 자동 발송 대상이 되지 않는다
테스트 발송
- 캠페인 상태가 pending_review일 때만 동작
- subscribers WHERE company_type_id=999(운영 중인 TEST 그룹, 구독 여부 무관 전체)를 수신자로 삼아 실제 발송 함수(models.send_messages)로 즉시 발송
- 성공 시 campaigns.test_sent_at=NOW() 기록. 실패하면 test_sent_at을 건드리지 않고 오류 메시지를 캠페인 상세 페이지에 표시
승인 — 서버 쪽에서 이중으로 막기
# POST /campaign/<id>/approve
# 상태가 pending_review이고 test_sent_at이 채워져 있을 때만 status='pending'으로 전환
두 조건 중 하나라도 안 맞으면 아무것도 하지 않는다. 승인 버튼 자체도 test_sent_at이 없으면 disabled 처리하지만, URL을 직접 조작해서 테스트를 건너뛰고 승인을 호출해도 서버 쪽 조건 검사에서 막힌다 — 클라이언트 쪽 UI 제약은 서버 검증의 보조 수단일 뿐, 실제 방어는 항상 서버에서 해야 한다는 원칙을 그대로 따른 부분.
수정하면 다시 검토 상태로
승인된(pending) 캠페인이라도 내용을 수정하면 저장 시 무조건 status='pending_review', test_sent_at=NULL로 되돌아가게 강제했다. 그렇지 않으면 "승인 후 내용을 몰래 고쳐도 테스트 없이 그대로 자동 발송되는" 구멍이 생긴다. 반면 실패 후 재시도(campaign_retry)는 내용 변경이 없으므로 재테스트 없이 바로 pending으로 복귀시켰다 — 같은 "다시 pending으로" 동작이라도 내용이 바뀌었는지 여부에 따라 재검토가 필요한지가 갈린다는 게 포인트.
배운 점
- 자동화된 배치가 있는 시스템에서는 "사람이 확인했다"는 사실 자체를 DB 컬럼 (test_sent_at)으로 남기고, 그 컬럼을 게이트 조건으로 쓰는 게 가장 단순하고 확실하다.
- UI에서 버튼을 숨기거나 비활성화하는 것은 사용성일 뿐 보안/안전장치가 아니다. 실제 게이트는 항상 서버 라우트 안의 조건문이어야 한다.
- "수정 = 재검토 필요"라는 규칙을 상태 전이 로직에 명시적으로 넣어두면, 나중에 이 프로젝트를 안 보다가 다시 봐도 왜 이렇게 짰는지 코드만 봐도 알 수 있다.
'IT > 작업기록' 카테고리의 다른 글
| 서로 다른 두 고객 데이터소스를 하나의 구독자 목록으로 통합하기 (0) | 2026.08.31 |
|---|---|
| HTML 이메일 렌더링 트러블슈팅: Quill 에디터, 표 스타일, 그리고 naver.com만 반송되던 버그 (0) | 2026.08.31 |
| Flask 첫 프로젝트에서 마주친 삽질들 (0) | 2026.08.31 |
| 이메일 캠페인 발송 시스템 DB 설계 노트 (0) | 2026.08.31 |
| 사내용 이메일 캠페인 관리 툴을 Flask로 직접 만든 이유와 구조 (0) | 2026.08.31 |
Comments