개발 일지 요약 (pposiraegi 프로젝트 인프라 구축 및 배포)

다음은 개발자와 AI 간의 오늘 하루 대화 로그야. 이 로그를 분석해서 내가 하루 동안 무엇에 집중하고 시간을 썼는지 한눈에 파악할 수 있도록 Obsidian 마크다운 형식으로 요약해줘.

1. 작업 분포

카테고리비중
인프라 구축/테라폼35%████░░░░░░
백엔드 배포/데이터30%███░░░░░░░
프론트엔드 연동/UI25%██░░░░░░░░
디버깅/문제 해결10%█░░░░░░░░░

2. 집중 영역 / 시간 소모 포인트

  • 생산적 작업

    • terraform plan을 통해 VPC, ALB, RDS, ElastiCache, CloudFront 등 52개의 AWS 리소스 배포 계획 수립 및 실행.
    • Docker Compose 구조를 운영용과 로컬용으로 분리하여 환경 변수 관리 체계 개선.
    • Redis와 DB 간의 재고 동기화 로직(StockSyncScheduler) 수정 및 1인 1구매 제한 로직(TimeDealDetail) 구현.
    • Mock PG 팝업 결제 연동(PaymentCallback 컴포넌트) 및 Same-Origin 전략으로의 CORS 이슈 근복적 해결.
  • 삽질/시간 소모 포인트

    • Terraform 배포 에러: Security Group 규칙 초과(CloudFront Prefix List 문제)와 Route53 레코드 중복 이슈로 인한 apply 재시도.
    • CloudFront 404 마스킹: 백엔드 API 에러(404)를 CloudFront가 index.html(200 OK)로 변환하여, 프론트엔드에서 에러를 JSON으로 파싱하지 못하고 undefined 크래시가 발생하는 원인을 파악하는 데 시간 소요.
    • Redis Codec 불일치: Lua 스크립트는 String로 쓰고 스케줄러는 Long으로 읻어 디코딩 실패, 재고 동기화가 안 되는 문제를 해결하기 위해 로직 분석.
    • 주문 번호 충돌: 컨테이너 재시작 시 메모리 기반 OrderNumberGenerator가 초기화되어 DB 기존 데이터와 중복 충돌 발생, DB 초기화로 임시 해결.

3. 타임라인

  • 10:03 ⌨️ terraform 디렉토리 이동 및 plan 명령어 실행.
  • 10:08 🦦 terraform apply 시도 중 사용자 승인(yes) 요구로 EOF 오류 발생.
  • 10:11 ⌨️ 사용자가 로컬 터미널에서 apply 수동 실행.
  • 10:33 ⌨️ Terraform apply 실패 (Security Group 규칙 초과, Route53 CNAME 중복).
  • 11:03 ⌨️ Route53 Hosted Zone 소스를 data로 변경하여 destroy 방지.
  • 11:55 🦦 Docker Compose 구조 개편(dev-override.yml 분리) 및 user_data.sh.env 파일 방식으로 수정.
  • 13:14 🦦 DB 스키마 생성 및 Seed 데이터 삽입 완료.
  • 13:50 🦦 체크아웃 시 undefined 에러 발생. CloudFront의 404 변환 설정 문제로 추정.
  • 14:05 🦦 CloudFront가 API 404 응답을 index.html로 변환하여 파싱 실패하는 현상 확인.
  • 14:20 🦦 CORS 문제 발견. CloudFront가 Preflight 헤더를 포워딩하지 않음.
  • 14:27 🦦 Same-Origin 전략 수립: 프론트엔드 API URL을 pposiraegi.cloud로 변경.
  • 14:37 🦦 WebSocket Mixed Content 에러(ws:// vs wss://) 발생.
  • 14:42 🐹 GCP Cloud Run Mock PG 서비스에 CORS 미들웨어 추가 후 재배포.
  • 15:02 🦦 수정 사항이 로컬 브랜치에 있어 EC2(main)에는 적용되지 않은 문제 발견.
  • 15:07 ⌨️ 시간 부족으로 EC2 내부에서 sed 명령어로 MockPgClient 로직 직접 패치 후 재빌드.
  • 15:53 ⌨️ 로그인 시 특수문자(!) 이스케이프 문제로 실패, 테스트 유저 생성.
  • 15:55 ⌨️ CloudFront가 /api 요청에 대해 HTML을 반환, 캐시 무효화 실행.
  • 15:57 ⌨️ 주문 생성 시 orders_order_number_key 중복 에러 발생, DB 테이블 초기화.
  • 16:02 🦦 주문 DB 저장 실패 로그 확인. Redis 재고 복구 스케줄러 동작 의심.
  • 16:05 🦦 StockSyncSchedulerLongCodec으로 읽어 StringCodec과 충돌하는 원인 발견.
  • 16:06 ⌨️ StockSyncScheduler.java 코덱 수정(StringCodec로 변경) 후 재배포.
  • 16:21 🦦 프론트엔드 timedeal.js에서 딜 레벨 수량 대신 SKU 재고 합계 사용하도록 수정.
  • 16:31 🦦 뒤로가기 재결제 방지 로직(sessionStorage + replace: true) 추가.
  • 16:44 🦦 auth.js에 401 인터셉터 추가하여 자동 로그아웃 처리.
  • 16:58 🦦 SKU 재고 0일 경우 ACTIVE 상태를 SOLDOUT으로 오버라이드하는 로직 추가.
  • 17:33 🦦 PaymentCallback.jsx 생성 및 팝업 호출 로직 구현.
  • 17:39 🦦 팝업 강제 종료(X 버튼) 감지 폴링 로직 추가.
  • 17:53 🦦 로컬과 클라우드런 Mock PG 소스 혼동 문제 지적, 단일 소스(epicodix/mock-pg-server)로 통일 작업.
  • 18:00 ⌨️ 구버전 mock-pg 폴더 삭제.
  • 18:15 🦦 TimeDealDetail.jsx에 1인 1구매 제한 로직 구현.
  • 18:18 🦦 사용자가 여전히 결제 페이지로 넘어간다고 보고, 원인 분석 중 AI 사용량 제한(Rate limit) 도달.

4. 해결한 문제와 인사이트

  • 문제 1: Terraform Apply EOF 오류

    • 해결: AI 도구 내 비대화형 환경 제약으로 인해 terraform apply 시 승인 입력(yes)이 불가능하여 발생. 사용자가 로컬 터미널에서 직접 명령어를 입력하여 해결.
    • 인사이트: 사용자 승인이 필요한 명령어는 자동화 도구보다 로컬 터미널 실행이 유리하거나 -auto-approve 옵션 활용이 필요함.
  • 문제 2: CloudFront 404 → HTML 변환

    • 해결: SPA 호스팅을 위해 CloudFront에 설정된 404 Custom Error Response( index.html)가 API 경로에도 적용되어, 프론트가 JSON 대신 HTML을 받아 파싱 실패하는 문제였음. API 경로에 대한 에러 변환 설정을 제거하거나 Behavior를 분리하여 해결.
    • 인사이트: 백엔드 에러 응답이 프론트까지 정확히 전달되지 않으면 디버깅 난이도가 급상승하므로, CDN/LB 설정 시 API와 프론트의 에러 처리를 명확히 분리해야 함.
  • 문제 3: Redis-DB 재고 동기화 실패

    • 해결: Lua 스크립트는 SKU ID를 String으로 dirty set에 저장하지만, StockSyncSchedulerLong으로 읽으려 시도하여 디코딩에 실패함. StockSyncScheduler.java의 코덱 설정을 StringCodec으로 변경하여 해결.
    • 인사이트: 분산 환경(Redis 등)에서 데이터를 주고받을 때는 직렬화/역직렬화 방식(String/Long 등)을 양측에서 정확히 일치시켜야 함.
  • 문제 4: 주문 번호 충돌 (Order Number Collision)

    • 해결: 메모리 기반 OrderNumberGenerator가 컨테이너 재시작 시 초기화되어 DB 기존 데이터와 중복됨. DB 테이블을 초기화하여 임시 해결.
    • 인사이트: 메모리 상태에 의존하는 ID 생성 로직은 서버 재시작 시 유지되지 않으므로, DB Sequence나 Snowflake와 같은 안전한 생성 전략이 필요함.
  • 문제 5: 팝업 결제 창 닫힘 미감지

    • 해결: 단순 postMessage 의존 시 사용자가 팝업을 강제 종료(X 버튼)하면 이벤트가 누락됨. setInterval로 500ms마다 popup.closed 상태를 폴링하여 강제 종료를 감지하도록 수정.
    • 인사이트: 사용자 인터랙션(팝업 닫기 등)은 엣지 케이스(강제 종료)까지 고려하여 이중으로 감지하는 로직이 필요함.
  • 문제 6: CORS 및 Same-Origin

    • 해결: 복잡한 CORS 헤더 설정을 디버깅하는 대신, 프론트엔드 API 도메인을 pposiraegi.cloud로 통일하여 Same-Origin 정책을 만듦으로써 근본적인 해결.
    • 인사이트: 가능하다면 도메인을 통일하여 SOP(Same-Origin Policy) 내에서 운영하는 것이 CORS 설정 복잡도를 줄이는 가장 좋은 방법임.

Supported by ai-log-sync & GLM-4.7