Skip to content

chore(release): dev → release 운영 서버 최초 배포 - #159

Open
uykm wants to merge 628 commits into
releasefrom
dev
Open

chore(release): dev → release 운영 서버 최초 배포#159
uykm wants to merge 628 commits into
releasefrom
dev

Conversation

@uykm

@uykm uykm commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

이 PR 의 목적

devrelease 로 승격해 운영 서버 최초 배포를 트리거한다. 머지되면 push: [release]deploy-prod.yml 이 돌아 운영 앱을 blue(:8083)에 무중단 배포한다. 이후 dev→release 머지가 곧 운영 배포다.

머지 전 전제 — 모두 충족됨

  • #158 dev 머지 (운영 배포 파이프라인 코드)
  • setup.sh 실행 — 운영 systemd 유닛·sudoers·디렉토리·my.prod.cnf 설치
  • 운영 DB/Redis 컨테이너 기동 (my.cnf 정상 마운트 확인)
  • PROD_ENV_FILE 시크릿 등록 + 서버 /opt/readum/prod.env 배치
  • .env.prod 외부 키(OpenAI·알라딘·Slack webhook) 채움

지금 머지해도 안전하다. 운영 앱이 :8083 에 뜨고 DB/Redis 는 이미 상주 중.

이 배포가 하는 것 / 안 하는 것

한다

  • 운영 jar 빌드·업로드, /opt/readum/prod.env 재작성(PROD_ENV_FILE 원본), readum-prod-blue(:8083) 기동 → readiness → readum-prod-upstream.conf 생성
  • prod-app.confsites-available 에 배치(비활성 상태)

안 한다 (DNS 준비 후 수동)

  • DNS·인증서·cutover — 그래서 아직 prod-api.readum.kr 로 공개되지 않는다. 운영 앱은 내부(127.0.0.1:8083)에서만 접근 가능하고 dev(api.readum.kr)와 충돌하지 않는다.

공개(HTTPS 노출)까지 남은 수동 단계 — DNS A 레코드 준비되면

  1. 가비아: prod-api.readum.kr A → 54.116.108.68 추가, dig +short prod-api.readum.kr 로 해석 확인
  2. 인증서(DNS 해석 뒤): sudo certbot certonly --webroot -w /var/www/certbot -d prod-api.readum.kr
  3. cutover: sudo ln -s /etc/nginx/sites-available/prod-app.conf /etc/nginx/sites-enabled/prod-app.conf && sudo nginx -t && sudo systemctl reload nginx

머지 후 검증 (서버)

/opt/readum/bin/deploy.sh prod status
curl -fsS http://127.0.0.1:8083/actuator/health/readiness   # UP 나와야 정상

참고 사항

  • base 가 main 이라 diff 가 크다(dev 전체를 운영으로 처음 승격하는 것이라 정상).
  • 노출된 시크릿(OpenAI 키·운영 Slack webhook)은 세팅 검증 뒤 재발급 권장 — 재발급 시 .env.prodPROD_ENV_FILE 둘 다 갱신.

🤖 Generated with Claude Code

uykm and others added 30 commits June 17, 2026 16:24
Phase A~I: Plan2 삭제·동기 워커 단순화, execution_mode·BATCH 상태,
채팅 차단 확장, openai_batch, batch builder/collector, 스케줄러 배선, 테스트.
후속 안정성 보강(이슈 #86)은 범위 외로 명시.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- SummaryJob: 모든 조회가 execution_mode를 먼저 거르므로 idx_summary_job_claim 삭제, idx_summary_job_mode_claim 유지
- SummaryTokenEstimator: 제거된 TPM 양동이 언급을 'batch 청크 토큰 예산 산정' 으로 정정
- SummaryJobReaper: PROCESSING 전용이라는 주석을 PROCESSING·BATCH_BUILDING 포함으로 정정
- SummaryJobRepositoryTest: findOrphaned 테스트명에서 '만' 제거, BATCH_BUILDING lease 만료 케이스 추가

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- claimBatchChunk / recordSubmission / releaseBuilding 3개 메서드 단위 테스트 추가
- SummaryBatchSubmitServiceTest 미사용 anyInt import 제거 및 주석 문구 현행화
- SummaryJobLifecycleService.claimBatchChunk 에 루프 내 N 회 조회가 설계 의도임을 설명하는 주석 추가

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- SummaryPromptAssembler: 시스템 프롬프트 로딩·대화 이력 포맷·사용자 메시지 조립을
  AiSummaryClientImpl 과 SummaryBatchClientImpl 이 공유하는 컴포넌트로 추출
- AiSummaryClientImpl: SummaryPromptAssembler 를 주입받아 중복 로직 제거,
  @PostConstruct init() 제거 (파일 로딩 위임), 기존 동작 그대로 유지
- OpenAiBatchProperties: api-key·model·base-url·completion-window 를 외부화
  (secrets 는 환경변수, 기본값은 application.yml)
- SummaryBatchClientImpl: RestClient 로 OpenAI Files·Batch API 직접 호출;
  JSONL 조립 → 파일 업로드(purpose=batch) → batch 생성 → 상태 조회 → 결과 파싱
- SummaryPromptAssemblerTest: 대화 이력 포맷·사용자 메시지 조립 단위 테스트
- application.yml: openai-batch 설정 키 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- SummaryPromptAssembler.responseFormatSchema() 추가: JSON 스키마 구조를 단일 출처로 관리
- AiSummaryClientImpl: ResponseFormat 을 assembler.responseFormatSchema() 로 조립 (static 필드 → 인스턴스 필드, 명시적 생성자)
- SummaryBatchClientImpl: 로컬 스키마 맵 제거 → promptAssembler.responseFormatSchema() 사용
- SummaryBatchClientImpl: JdkClientHttpRequestFactory + connectTimeout/readTimeout 배선 (AladinHttpConfig 패턴)
- OpenAiBatchProperties: requestTimeout(Duration) 필드 추가, application.yml·test yml 에 PT60S 기본값
- SummaryBatchClientImpl: @EnableConfigurationProperties 제거 (ConfigurationPropertiesScan 중복)
- application.yml 주석 정정: api-key 는 환경변수, 나머지는 application.yml 기본값으로 명확히
- parseDraftResult 항목별 파싱 실패 로그를 ERROR → WARN 으로 변경
- splitLines: trim() 이 CRLF \r 도 제거함을 주석으로 명시
- SummaryPromptAssemblerTest: responseFormatSchema() 키 검증 케이스 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
findOrphaned 가 SUBMITTED 를 회수 대상에 포함하지 않음을 DAO 레벨에서 검증하고,
existsByActiveSessionId 가 BATCH 모드 SUBMITTED 작업도 중복 적재를 막는 활성 작업으로
인식함을 확인하는 케이스 2건을 SummaryJobRepositoryTest 에 추가한다.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
resume-summarized-session, reconcile-summary-model-with-dev 의 설계·계획 문서 삭제.
superpowers 문서는 로컬에서만 보기로 함(.gitignore 대상). 16·17일자 문서는 유지.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
배치 영속 엔티티 이름에 박혀 있던 제공자(OpenAI)명을 도메인 언어로 되돌린다.
의존성 역전은 이미 Port(SummaryBatchClient)로 돼 있었으므로, 모델·도메인
레이어에 남아 있던 "OpenAI" 표기만 걷어내 제공자 색깔을 adapter 한 겹으로 모은다.

- 엔티티 OpenAiBatch → SummaryBatch (테이블 openai_batch → summary_batch,
  인덱스 idx_openai_batch_status → idx_summary_batch_status)
- OpenAiBatchRepository → SummaryBatchRepository
- SummaryJob.openAiBatchId → summaryBatchId (컬럼 open_ai_batch_id → summary_batch_id),
  findByOpenAiBatchIdAndStatus → findBySummaryBatchIdAndStatus
- 엔티티·Port·DTO·서비스 주석/문구의 "OpenAI" 표기를 "외부 배치 제공자/배치"로 중립화
  (엔티티·Port javadoc 에만 "(현재 OpenAI)" 괄호로 구현체 명시)
- 어댑터 SummaryBatchClientImpl·OpenAiBatchProperties 는 제공자 특화라 OpenAI 이름 유지

동작 변경 없음. 전체 테스트 통과. (DB 는 초기화 후 배포 예정이라 테이블 rename 마이그레이션 불필요)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
마지막 채팅 시각 기준 월 조회, 감상문 없는 기록도 포함(summaryId nullable),
응답에 chatSessionId/chatSummary/lastChattedAt 추가. 구 MonthlySummary* DTO 삭제.
Hheojiwon and others added 7 commits July 9, 2026 03:03
fix(exception): NoResourceFoundException 을 404 로 처리해 불필요한 ERROR 알림 방지
수신기가 상호작용 payload 의 message.text 를 regex 로 긁어 fingerprint·deploy 를
추출했는데, 실제 Slack payload 에서 message.text 를 신뢰할 수 없어 두 값이 비면
'fingerprint·deploy 둘 다 비어 dispatch 건너뜀' 으로 분석 요청이 조용히 유실됐다.

앱(SlackWebhookAppender)이 '분석 이슈 만들기' 버튼 value 에 fingerprint·deploy·
traceId·message·stacktrace 를 구조화 JSON 으로 싣고, 수신기(parse.go)는 클릭된 버튼의
value 를 그대로 읽는다. value 는 클릭된 버튼에 Slack 이 항상 실어 보내므로 본문
스크래핑보다 견고하다. value 누락·옛 포맷 메시지는 본문 스크래핑으로 폴백한다.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
logback 이 참조하던 APP_ENV 환경변수가 어디에도 설정돼 있지 않아 알림에
APP_ENV_IS_UNDEFINED 로 표시됐다. 프로파일(local/dev/prod)이 곧 환경이므로
source 를 spring.profiles.active 로 바꿔 진실의 원본을 하나로 모은다.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…alue-parse

fix(logging): Slack 장애 분석 버튼이 분석 요청을 건너뛰던 문제 해결
개발 서버가 떠 있는 t3.small 인스턴스에 운영(prod) 스택을 나란히 올린다.
blue/green 전환 로직은 deploy.sh 하나를 공유하고 첫 인자(dev|prod)로 갈린다.
도메인·포트·systemd 유닛·nginx upstream·MySQL/Redis 컨테이너·환경 파일을 전부
분리해 되돌릴 수 없는 데이터 계층까지 격리한다.

- application-prod.yml: 운영 MySQL(3307)·Redis(6380) 접속, swagger off, com.readum INFO
- docker-compose.prod.yml + my.prod.cnf: 운영 전용 MySQL(버퍼 128M·perf_schema off)·Redis
- systemd readum-prod-{blue,green}: 포트 8083/8084, prod.env
- deploy.sh: 환경(dev|prod) 매개변수화 — 포트·유닛·경로·upstream 선택
- deploy-prod.yml: release 브랜치 트리거, PROD_ENV_FILE → /opt/readum/prod.env
- prod-app.conf: prod-api.readum.kr server 블록(readum_prod_backend)
- deploy.yml·deploy-prod.yml: compose·my.cnf 자동 업로드 + infra/ 전체를 /opt/readum/infra 로 배달(서버 git 체크아웃 없이 setup.sh 실행)
- sudoers·setup.sh: 운영 유닛·nginx 경로·디렉토리 부트스트랩 추가
- .gitignore: .env.prod 무시 추가
- docs/ops/infrastructure.md: 공존 구성도·개발/운영 비교표·활성화 수동 이유

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(infra): 운영 서버 무중단 배포 파이프라인을 개발 서버와 공존 구성
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 646e3f46-773a-4d4e-8ce4-880bf36ba4ed

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@uykm
uykm requested a review from Hheojiwon July 9, 2026 17:54
Hheojiwon and others added 21 commits July 11, 2026 17:59
…tion

chore(verify): 검증 체크리스트 탐지 항목 확장 및 Stop hook 개선
… 장애 분류 오도 방지)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
정산 예외가 성공 턴을 실패 경로(FAILED 중복 저장·이중 정산)로 뒤집거나
게이트 거절 429 를 500 으로 바꾸지 않도록 settle 호출을 조용한 실패로 감싼다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ient 로 재구성

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
빌더 기본 재시도(10회)는 read 타임아웃까지 재시도해 SseEmitter 상한(120초)을
지난 뒤까지 보이지 않는 과금 호출을 반복한다. 모더레이션 빈과 동일하게 무재시도로
고정해 실패를 즉시 error 이벤트로 표면화한다. 수동 구성 전환으로 더 이상 적용되지
않는 spring.ai.chat.observations 블록도 제거한다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
게이트 거절(429) 시 응답 없는 USER 메시지가 COMPLETED 로 대화 이력에
영구히 남던 간극 제거. 예약 전액 환불 동작은 그대로 유지.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…version

refactor(ai-chat): 채팅 응답 생성을 리액티브 스트림에서 가상 스레드 동기 호출로 전환
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants