--- name: shipping-and-launch description: 프로덕션 출시를 준비합니다. 프로덕션 배포를 준비할 때, 또는 출시 전에 무엇을 갖춰야 하는지 물을 때 사용하세요. 출시 전 체크리스트가 필요할 때, 모니터링을 설정할 때, 단계적 롤아웃을 계획할 때, 롤백 전략이 필요할 때 사용하세요. --- # Shipping and Launch ## 개요 확신을 갖고 출시하세요. 목표는 배포 자체가 아닙니다. 모니터링을 갖추고, 롤백 계획을 준비하며, 성공이 어떤 모습인지 명확히 알고 안전하게 배포하는 일입니다. 모든 출시는 되돌릴 수 있고, 관찰할 수 있고, 점진적이어야 합니다. ## 언제 사용하나 - 기능을 프로덕션에 처음 배포할 때 - 사용자에게 큰 변경을 릴리스할 때 - 데이터나 인프라를 마이그레이션할 때 - 베타 또는 얼리 액세스 프로그램을 열 때 - 위험이 있는 모든 배포 (배포는 모두 그렇습니다) ## 출시 전 체크리스트 ### 코드 품질 - [ ] 모든 테스트가 통과합니다 (단위, 통합, e2e) - [ ] 경고 없이 빌드가 성공합니다 - [ ] 린트와 타입 체크가 통과합니다 - [ ] 코드 리뷰가 완료되고 승인되었습니다 - [ ] 출시 전에 해결해야 할 TODO 주석이 없습니다 - [ ] 프로덕션 코드에 디버깅용 `console.log`가 없습니다 - [ ] 오류 처리가 예상되는 실패 양상을 다룹니다 ### 보안 - [ ] 코드나 버전 관리에 시크릿이 없습니다 - [ ] 생태계의 의존성 감사 (`npm audit`, `pip-audit`, `cargo audit` 등)에서 치명적 또는 높음 취약점이 없습니다 - [ ] 모든 사용자 대면 엔드포인트에 입력 검증이 있습니다 - [ ] 인증과 인가 검사가 있습니다 - [ ] 보안 헤더가 구성되었습니다 (CSP, HSTS 등) - [ ] 인증 엔드포인트에 속도 제한이 있습니다 - [ ] CORS가 특정 오리진으로 구성되었습니다 (와일드카드가 아님) ### 성능 - [ ] Core Web Vitals가 "Good" 기준 안에 있습니다 - [ ] 핵심 경로에 N+1 쿼리가 없습니다 - [ ] 이미지가 최적화되었습니다 (압축, 반응형 크기, 지연 로딩) - [ ] 번들 크기가 예산 안에 있습니다 - [ ] 데이터베이스 쿼리에 적절한 인덱스가 있습니다 - [ ] 정적 자산과 반복 쿼리에 캐시가 구성되었습니다 ### 접근성 - [ ] 모든 상호작용 요소에서 키보드 탐색이 동작합니다 - [ ] 스크린 리더가 페이지 콘텐츠와 구조를 전달할 수 있습니다 - [ ] 색 대비가 WCAG 2.1 AA를 충족합니다 (텍스트 4.5:1) - [ ] 모달과 동적 콘텐츠의 포커스 관리가 올바릅니다 - [ ] 오류 메시지가 구체적이고 폼 필드와 연결됩니다 - [ ] axe-core나 Lighthouse에 접근성 경고가 없습니다 ### 인프라 - [ ] 프로덕션에 환경 변수가 설정되었습니다 - [ ] 데이터베이스 마이그레이션이 적용되었습니다 (또는 적용 준비가 되었습니다) - [ ] DNS와 SSL이 구성되었습니다 - [ ] 정적 자산용 CDN이 구성되었습니다 - [ ] 로깅과 오류 보고가 구성되었습니다 - [ ] 헬스 체크 엔드포인트가 있고 응답합니다 ### 문서 - [ ] 새로운 설정 요구사항이 있으면 README를 업데이트했습니다 - [ ] API 문서가 최신입니다 - [ ] 아키텍처 결정이 있으면 ADR을 작성했습니다 - [ ] 변경 이력을 업데이트했습니다 - [ ] 해당되면 사용자 대면 문서를 업데이트했습니다 ## 피처 플래그 전략 피처 플래그 뒤에 출시해서 배포와 릴리스를 분리하세요. ```typescript // Feature flag check const flags = await getFeatureFlags(userId); if (flags.taskSharing) { // New feature: task sharing return ; } // Default: existing behavior return null; ``` **피처 플래그 수명 주기:** ``` 1. 플래그 OFF로 배포 → 코드는 프로덕션에 있지만 비활성 2. 팀/베타에 활성화 → 프로덕션 환경에서 내부 테스트 3. 점진적 롤아웃 → 사용자의 5% → 25% → 50% → 100% 4. 각 단계에서 모니터링 → 오류율, 성능, 사용자 피드백을 지켜봅니다 5. 정리 → 전체 롤아웃 후 플래그와 죽은 코드 경로를 제거 ``` **규칙:** - 모든 피처 플래그에는 소유자와 만료일이 있습니다 - 전체 롤아웃 후 2주 안에 플래그를 정리하세요 - 피처 플래그를 중첩하지 마세요 (조합이 지수적으로 늘어납니다) - CI에서 플래그 두 상태(켜짐과 꺼짐)를 모두 테스트하세요 ## 단계적 롤아웃 ### 롤아웃 순서 ``` 1. 스테이징에 배포 └── 스테이징 환경에서 전체 테스트 스위트 └── 핵심 흐름의 수동 스모크 테스트 2. 프로덕션에 배포 (피처 플래그 OFF) └── 배포 성공 확인 (헬스 체크) └── 오류 모니터링 확인 (새 오류 없음) 3. 팀에 활성화 (내부 사용자에게 플래그 ON) └── 팀이 프로덕션에서 기능을 사용 └── 24시간 모니터링 구간 4. 카나리 롤아웃 (사용자 5%에게 플래그 ON) └── 오류율, 지연 시간, 사용자 행동을 모니터링 └── 지표 비교: 카나리 대 기준선 └── 24~48시간 모니터링 구간 └── 모든 기준을 통과할 때만 진행 (아래 표 참조) 5. 점진적 확대 (25% -> 50% -> 100%) └── 각 단계에서 같은 모니터링 └── 어느 시점에서든 이전 비율로 롤백할 수 있음 6. 전체 롤아웃 (모든 사용자에게 플래그 ON) └── 1주 모니터링 └── 피처 플래그 정리 ``` ### 롤아웃 판단 기준 각 단계에서 진행할지, 보류할지, 롤백할지 이 기준으로 결정하세요. | 지표 | 진행 (녹색) | 보류하고 조사 (황색) | 롤백 (적색) | |--------|-----------------|-------------------------------|-----------------| | 오류율 | 기준선의 10% 이내 | 기준선보다 10~100% 높음 | 기준선의 2배 초과 | | P95 지연 시간 | 기준선의 20% 이내 | 기준선보다 20~50% 높음 | 기준선보다 50% 초과 | | 클라이언트 JS 오류 | 새로운 오류 유형 없음 | 세션의 0.1% 미만에서 새 오류 | 세션의 0.1% 초과에서 새 오류 | | 비즈니스 지표 | 중립 또는 긍정 | 5% 미만 하락 (잡음일 수 있음) | 5% 초과 하락 | ### 언제 롤백하나 다음이면 즉시 롤백하세요. - 오류율이 기준선의 2배를 넘습니다 - P95 지연 시간이 50%를 넘게 증가합니다 - 사용자 제보 이슈가 급증합니다 - 데이터 무결성 문제가 발견됩니다 - 보안 취약점이 발견됩니다 ## 모니터링과 옵저버빌리티 ### 무엇을 모니터링하나 ``` 애플리케이션 지표: ├── 오류율 (전체, 엔드포인트별) ├── 응답 시간 (p50, p95, p99) ├── 요청량 ├── 활성 사용자 └── 핵심 비즈니스 지표 (전환, 참여) 인프라 지표: ├── CPU와 메모리 사용률 ├── 데이터베이스 커넥션 풀 사용량 ├── 디스크 공간 ├── 네트워크 지연 시간 └── 큐 깊이 (해당될 때) 클라이언트 지표: ├── Core Web Vitals (LCP, INP, CLS) ├── JavaScript 오류 ├── 클라이언트 관점의 API 오류율 └── 페이지 로드 시간 ``` ### 오류 보고 ```typescript // Set up error boundary with reporting class ErrorBoundary extends React.Component { state = { hasError: false }; static getDerivedStateFromError() { return { hasError: true }; } componentDidCatch(error: Error, info: React.ErrorInfo) { // Report to error tracking service reportError(error, { componentStack: info.componentStack, userId: getCurrentUser()?.id, page: window.location.pathname, }); } render() { if (this.state.hasError) { return this.setState({ hasError: false })} />; } return this.props.children; } } // Server-side error reporting app.use((err: Error, req: Request, res: Response, next: NextFunction) => { reportError(err, { method: req.method, url: req.url, userId: req.user?.id, }); // Don't expose internals to users res.status(500).json({ error: { code: 'INTERNAL_ERROR', message: 'Something went wrong' }, }); }); ``` ### 출시 후 검증 출시 후 첫 한 시간: ``` 1. 헬스 엔드포인트가 200을 반환하는지 확인 2. 오류 모니터링 대시보드 확인 (새 오류 유형 없음) 3. 지연 시간 대시보드 확인 (회귀 없음) 4. 핵심 사용자 흐름을 수동으로 테스트 5. 로그가 흐르고 읽을 수 있는지 확인 6. 롤백 수단이 동작하는지 확인 (가능하면 드라이런) ``` ## 오류 예산 릴리스 게이트 서비스의 오류 예산, 즉 SLO가 실패를 허용하는 요청 또는 시간의 비율은 출시해도 안전한지를 결정합니다. 협상 대상이 아니라 객관적인 게이트로 쓰세요. ``` 남은 오류 예산 > 20% → 평소대로 출시하고, 면밀히 모니터링하세요 남은 오류 예산 0~20% → 느린 롤아웃만 하세요. 고위험 변경은 하지 마세요 오류 예산 소진 → 기능 작업을 멈추고, 안정성에만 집중하세요 오류 예산 초기화 → 평소 속도로 재개하세요. 예산을 회복시킨 수정이 자리 잡았는지 확인하세요 ``` 카나리 중 소진 속도가 높으면 (기준 속도보다 빨리 예산을 소모하면) 위 롤아웃 기준 표의 **보류** 신호입니다. 높아진 오류율과 같이 다루세요. ## 롤백 전략 모든 배포에는 실행 전에 롤백 계획이 필요합니다. ```markdown ## [기능/릴리스] 롤백 계획 ### 발동 조건 - 오류율 > 기준선의 2배 - P95 지연 시간 > [X]ms - [특정 이슈]에 대한 사용자 제보 ### 롤백 단계 1. 피처 플래그 비활성화 (해당될 때) 또는 1. 이전 버전 배포: `git revert && git push` 2. 롤백 검증: 헬스 체크, 오류 모니터링 3. 소통: 팀에 롤백을 알림 ### 데이터베이스 고려사항 - 마이그레이션 [X]에 롤백이 있음: <검증된 명령 또는 런북 링크> - 새 기능이 넣은 데이터: [보존 / 정리] ### 롤백에 걸리는 시간 - 피처 플래그: 1분 미만 - 이전 버전 재배포: 5분 미만 - 데이터베이스 롤백: 15분 미만 ``` ## 함께 보기 - 이 체크리스트 전에 모든 변경이 통과해야 하는 프로젝트 전체 완료 정의는 `../../references/definition-of-done.md`를 보세요 - 보안 출시 전 검사는 `../../references/security-checklist.md`를 보세요 - 성능 출시 전 체크리스트는 `../../references/performance-checklist.md`를 보세요 - 출시 전 접근성 검증은 `../../references/accessibility-checklist.md`를 보세요 - 알림 규칙과 SLO에 묶인 기준은 `observability-and-instrumentation`을 보세요 ## 흔한 합리화 | 합리화 | 현실 | |---|---| | "스테이징에서 되니까 프로덕션에서도 될 것입니다" | 프로덕션은 데이터, 트래픽 패턴, 엣지 케이스가 다릅니다. 배포 후 모니터링하세요. | | "이것에는 피처 플래그가 필요 없습니다" | 모든 기능은 킬 스위치가 있으면 이득입니다. "단순한" 변경도 무언가를 깨뜨릴 수 있습니다. | | "모니터링은 오버헤드입니다" | 모니터링이 없으면 대시보드가 아니라 사용자 불만으로 문제를 알게 됩니다. | | "모니터링은 나중에 넣겠습니다" | 출시 전에 넣으세요. 보이지 않는 것은 디버깅할 수 없습니다. | | "롤백은 실패를 인정하는 일입니다" | 롤백은 책임 있는 엔지니어링입니다. 실패한 것은 깨진 기능을 출시하는 일입니다. | | "오류율이 괜찮아 보이니 계속 출시합시다" | 현재 오류율만이 아니라 소진 속도를 보세요. 개별 기준이 녹색이어도, 기준선보다 빨리 예산을 소모하면 보류 신호입니다. | ## 레드 플래그 - 롤백 계획 없이 배포 - 프로덕션에 모니터링이나 오류 보고가 없음 - 빅뱅 릴리스 (한 번에 전부, 스테이징 없음) - 만료나 소유자가 없는 피처 플래그 - 첫 한 시간 동안 배포를 지켜보는 사람이 없음 - 프로덕션 환경 설정을 코드가 아니라 기억으로 함 - "금요일 오후니까 그냥 출시하자" - 오류 예산은 소진됐는데 기능 작업은 그대로 계속됨 ## 검증 배포 전: - [ ] 출시 전 체크리스트를 완료했습니다 (모든 절이 녹색) - [ ] 피처 플래그를 구성했습니다 (해당될 때) - [ ] 롤백 계획을 문서로 남겼습니다 - [ ] 모니터링 대시보드를 준비했습니다 - [ ] 팀에 배포를 알렸습니다 배포 후: - [ ] 헬스 체크가 200을 반환합니다 - [ ] 오류율이 정상입니다 - [ ] 지연 시간이 정상입니다 - [ ] 핵심 사용자 흐름이 동작합니다 - [ ] 로그가 흐르고 있습니다 - [ ] 롤백을 테스트했거나, 준비되었음을 확인했습니다 출시한 모든 서비스: - [ ] 오류 예산 정책이 있습니다. 예산이 20% 아래로 떨어질 때와 소진됐을 때 어떤 조치를 할지 압니다