콘텐츠 허브 프로젝트를 만들면서 일주일간 삽질하고 깨달은 것들을 쉽게 정리했습니다.

한 줄 요약

"조용히 실패하는 것이 가장 무섭다" — 이번 주 핵심 교훈


1. 서버 2개가 동시에 돌아가면 생기는 일

상황: 다이제스트 이메일이 안 왔다. 왜?

알고 보니 서버를 재시작할 때 기존 프로세스를 안 죽이고 새로 띄웠다. 두 개의 서버가 동시에 스케줄러를 돌리면서 서로 충돌.

해결책: PID 파일로 "지금 서버 돌아가고 있니?" 체크하는 스크립트 만듦

# 이런 식으로 단일 인스턴스 보장
if [ -f server.pid ] && kill -0 $(cat server.pid); then
    echo "이미 실행 중!"
    exit 1
fi

교훈: 백그라운드 서비스는 "하나만 돌아야 한다"를 코드로 보장해야 함


2. 에러가 났는데 아무도 모른다?

상황: 다이제스트 전송이 실패했는데, 로그 파일에만 남아서 한참 뒤에 발견

해결책: 실패하면 바로 Slack으로 알림 쏘기

async def send_system_alert(title, message):
    # 실패 즉시 Slack webhook으로 알림!
    await webhook.send(f"🚨 {title}\n{message}")

교훈: 로그는 디버깅용, 알림은 장애 감지용. 역할이 다르다!


3. AI한테 "꼭 해줘"라고 말해도 안 듣는다

상황: "Quick Scan 섹션을 꼭 포함해주세요"라고 했는데 Claude가 자주 빼먹음

해결책:

  • "작성하세요" → "절대 생략하지 마세요"
  • System prompt에 넣으면 더 잘 지킴

교훈: LLM한테는 권장이 아니라 금지로 말해야 듣는다


4. 이메일에서 CSS가 안 먹힌다

상황: 멋진 번호 매기기를 CSS counter로 만들었는데 Gmail에서 안 보임

진실: 이메일 클라이언트는 2005년에서 멈춰있음

  • flexbox? ❌
  • CSS grid? ❌
  • counter-increment? ❌
  • JavaScript? ❌

해결책: 그냥 <table>로 짜면 됨 (슬프지만 현실)


5. 소셜 미디어 시간 파싱의 함정

상황: LinkedIn에서 "3w · edited" 같은 텍스트를 시간으로 파싱해야 함

함정들:

  • , ·, -, , 전부 다른 문자임
  • "Jan 15"가 올해인지 작년인지 모름
  • 같은 피드인데 HTML 구조가 포스트마다 다름

해결책: 3단계 fallback 체인

  1. <time datetime> 태그 있으면 파싱
  2. 알려진 셀렉터로 시도
  3. 전체 텍스트 스캔

교훈: "한 패턴으로 다 커버"는 환상. 최소 3단계 fallback 필요


6. AI가 "언급했다"를 어떻게 판단할까?

상황: AI 요약에서 실제로 링크한 콘텐츠만 "기타 콘텐츠"에서 빼고 싶음

잘못된 방법: 제목에 "OpenAI"가 포함되면 언급한 걸로 간주
→ "OpenAI"가 들어간 글 10개가 다 제외됨

올바른 방법: 마크다운 링크의 URL만 추출해서 매칭

urls = re.findall(r"\(https?://[^\)]+\)", ai_output)

교훈: 제목은 겹치고, URL은 고유하다


7. XSS 공격은 생각보다 쉽게 터진다

상황: 기술 블로그 제목에 <script> 같은 게 들어있으면 이메일이 깨짐

해결책: html.escape()markdown 변환 전에 적용

# 순서가 중요!
text = html.escape(text)  # 먼저 이스케이프
text = text.replace("**", "<strong>")  # 그다음 마크다운 처리

교훈: 보안 수정은 테스트 필수. 안 그러면 리팩토링할 때 실수로 지움


이번 주 숫자

항목 수치
새로운 교훈 19개 (#14~#32)
추가된 테스트 11개 (103 → 118)
고친 버그 8개
새 파일 3개 (start_server.sh, admin API, system alert)

핵심 패턴 3가지

1. Fallback 체인

시도 A 실패 → 시도 B 실패 → 시도 C

한 가지 방법에 의존하지 말고 백업 경로를 만들어둔다.

2. 조용한 실패 방지

에러 → 로그 + 알림 + 재시도

에러가 나면 누군가는 알아야 한다.

3. 균일 정책

"HN만 5건 제한" → "모든 플랫폼 5건 제한"

특정 케이스만 고치면 다른 데서 터진다.


다음 주에는 이메일 실패 시 Slack fallbackhealth check API 추가 예정!