Skip to content

[FE-67 -> develop] feat: 릴리즈 disabled/mandatory 전용 엔드포인트 분리 및 웹 mandatory 토글 - #29

Merged
devlasbe merged 11 commits into
developfrom
FE-67
Jul 14, 2026
Merged

devlasbe merged 11 commits into
developfrom
FE-67

Conversation

@devlasbe

@devlasbe devlasbe commented Jul 14, 2026 •

Copy link
Copy Markdown

요약

릴리즈 메타데이터 수정을 disabled/mandatory 전용 엔드포인트 2개로 분리하고, 웹에서 Mandatory 토글을 지원한다. Slack 알림도 두 액션 모두 발사하며 이모지를 단순화한다.

  • PRD: 없음
  • Figma: 없음

배경

  • 오리지널 CodePush는 patch -m으로 mandatory 변경이 가능했으나, 이 재구현 서버는 PackageInfoUpdateSchema에 isMandatory가 없고 updatePackage도 UPDATE하지 않아 200 응답을 주면서 조용히 무시하는 상태.
  • 웹은 Disable/Enable만 가능하고 Mandatory는 배지 표시만 있어, 배포 후 강제 업데이트 전환이 불가능했다.

변경 사항

  • management.ts — disabled/mandatory 전용 PATCH 엔드포인트 2개 신설

    • Before: PATCH /release 하나로 appVersion/description/isDisabled만 수정 가능, isMandatory는 침묵 무시
    • After: /release/disabled {label?, isDisabled} / /release/mandatory {label?, isMandatory}로 각 상태를 따로 관리
    • 세부:
      • label 생략 시 최신 릴리즈 대상 (기존 update와 동일 규칙)
      • 권한: Collaborator (기존과 동일 게이트: 401 → 404 → 403)
      • 기존 PATCH /release는 CLI(code-push-standalone patch) 호환을 위해 그대로 유지
      • 각 핸들러가 Slack 알림 발사 (disabled → Disabled/Enabled, mandatory → MandatoryOn/Off)
  • d1.ts / storage.ts — updatePackageMetadata 부분 UPDATE 신설

    • Before: updatePackage가 캐시에서 읽은 release의 여러 필드를 통째 SET
    • After: 신규 핸들러는 대상 컬럼만 UPDATE (deploymentId+label+deletedAt 스코프)
    • 세부:
      • 히스토리 캐시가 isolate별 메모리(TTL 5분)라, stale 캐시 기반 전체 SET은 다른 isolate가 방금 바꾼 필드를 되돌릴 수 있음(lost update — 예: 긴급 disable 직후 다른 isolate에서 mandatory 토글 시 disable 풀림) → 부분 UPDATE로 원천 차단
      • 쓰기 후 캐시 무효화는 기존과 동일
  • slack.ts — 액션 종류 재구성 + 업로드 실패 알림 추가

    • Before: Uploaded/Enabled/Disabled 3종, 헤더에 큰 원형 이모지 🟢/🔴, 업로드 실패 시 알림 없음
    • After: 종류별 4종 — Uploaded(🚀) / UploadFailed(🚨) / Disabled(🧊) / Mandatory(🔥)
    • 세부:
      • on/off는 헤더 텍스트가 Disabled true/false, Mandatory true/false로 표현 (이모지는 종류 구분만)
      • release.create의 업로드 파이프라인(롤아웃 미완 409/중복 번들 409/R2·D1 오류)을 try-catch로 감싸 실패 시 UploadFailed 알림 발사, 에러 메시지를 본문 코드 블록으로 첨부 (인증·권한 실패는 대상 아님)
  • HistoryPage.tsx(web) — Mandatory 토글 + 버튼 단순화

    • Before: 카드마다 빨간 filled(destructive) Disable 버튼, Mandatory는 배지 표시만
    • After: Mandatory/Optional + Enable/Disable 버튼 2개를 무채색 outline으로 통일
    • 세부:
      • disableMutation을 신규 /release/disabled로 교체, mandatoryMutation 신설
      • Mandatory ON confirm에 강제 업데이트 승격 경고 명시 (updateCheck의 mandatory 승격 로직 파급 고지)
  • api-client — pnpm generate 재생성 (신규 메서드 2개)

테스트

  • 로컬 실서버(677개 릴리즈) E2E: mandatory ON/OFF·disabled ON/OFF → DB 반영 + 캐시 무효화 확인
  • 부분 UPDATE 검증 — disabled 토글이 mandatory 값을 건드리지 않음
  • label 생략 시 최신 릴리즈 대상 / 미인증 401 / 기존 PATCH /release 200 불변
  • tsc·biome ci·vitest 117/117 (server), tsc·build (web)

테스트 후 로컬 DB 상태 원상복구 완료.

참고

  • 캐싱·위험성 분석 전체는 Jira 참조: https://yplabs.atlassian.net/browse/FE-67
  • 기존 PATCH /release(CLI 경로)에는 전체 필드 SET 패턴이 남아 있음 — pre-existing이며 범위 밖 (별도 트랙 후보)
  • DB 마이그레이션 불필요 (is_mandatory 컬럼 기존재)

🤖 Generated with Claude Code

devlasbe and others added 11 commits July 14, 2026 13:22
- PATCH /release/disabled, /release/mandatory 신규 (label 생략 시 최신)
- updatePackageMetadata 부분 UPDATE로 stale 캐시 lost update 차단
- Slack MandatoryOn/Off 액션 추가, 헤더 이모지 🟢/🔴 → ✓/✕ 단순화
- 웹 Mandatory/Optional 토글 + 승격 경고 confirm, 카드 버튼 outline 통일
- api-client 재생성

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
on/off는 헤더 텍스트가 isDisabled/isMandatory 값으로 표현

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 인증·권한 통과 후 업로드 파이프라인(롤아웃 미완/중복 번들/R2·D1 오류) 실패 시 UploadFailed(🚨) 알림 발사
- 에러 메시지를 본문 코드 블록으로 첨부

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Mandatory 버튼: Zap 아이콘 (Mandatory로 전환 시 amber, Optional 전환 시 muted)
- Disable 버튼: Power 아이콘 (Disable 시 red, Enable 시 emerald)
- 버튼 골격은 무채색 outline 유지

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 버튼 h-9 → h-7, 패딩 px-2, 글자 text-xs
- 아이콘 [&_svg]:size-3 강제 (버튼 베이스 [&_svg]:size-4 오버라이드), gap-1
- 버튼 사이 간격 gap-0.5

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- label 지정/생략(최신) 대상 선택, 부분 UPDATE(다른 필드 불변), 404, 401

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- hooks/: useHistoryTarget(앱·배포 선택), useReleaseHistory(이력·지표·페이지), useReleaseToggles(disabled/mandatory 토글)
- components/: ReleaseCard, HistoryPagination 분리 (formatBytes/formatTime은 ReleaseCard로 이동)
- types.ts로 응답 타입 분리
- useEffect 3개 기명화: selectFirstAppOnLoad / selectDefaultDeployment / resetPageOnTargetChange
- 동작 동일, 내부 구조만 변경

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vitest-pool-workers가 wrangler.toml 경유로 .dev.vars의 CODE_PUSH_NOTI_SLACK을
로드해 토글 테스트가 실채널로 webhook을 쏘고 있었음. 테스트 바인딩에서 빈 값으로 고정.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@devlasbe
devlasbe merged commit 14bdac5 into develop Jul 14, 2026
2 checks passed
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.

1 participant