[BE-09] 데모 게이팅 기능 (featuredemo 슬라이스)
작업 내용 (설계 의도)
변경 사항
FR-9 완료 조건 — 신규 데모 엔드포인트 GET /feature-demo/hello를 RELEASE 플래그 demo.feature.hello로 게이팅한다. 근거 TDD: ../TDD.md “데모 게이팅 대상 결정”·API 계약. **별도 소비 도메인 featuredemo**로 두어 common.FeatureFlagEvaluator만 주입 — domain.featureflag를 import하지 않아 도메인 격리·FR-12 보일러플레이트 없음을 스스로 증명한다.
FeatureDemoDomainService(domain):greet(userId)→evaluator.isEnabled("demo.feature.hello", FeatureContext.of(userId), default=false)가 false면FeatureDisabledException(503) throw, true면Greeting반환.FeatureDisabledException(domain,BusinessException확장,ErrorStatus.SERVICE_UNAVAILABLE) — BE-01에서 추가한 503 매핑으로 GlobalExceptionHandler가 자동 503.GetDemoGreetingUseCase(application): DomainService 위임.FeatureDemoApiController(presentation,~ApiController.kt):GET /feature-demo/hello,X-User-Id헤더(optional)로 컨텍스트, 200{message, flagKey, userId, servedAt}.- 게이팅 대상 자체는 부작용 0(고정 인사 응답) — 킬스위치·퍼센티지 sticky 증명에 집중.
- 롤백: 플래그 archive/OFF 한 번으로 즉시 503(재배포 없음).
의존
- BE-06 (FeatureFlagEvaluator 구현 빈)
- BE-01 (common.FeatureFlagEvaluator·FeatureContext·ErrorStatus.SERVICE_UNAVAILABLE)
다이어그램
처리 흐름
sequenceDiagram participant C as FeatureDemoApiController participant U as GetDemoGreetingUseCase participant D as FeatureDemoDomainService participant E as FeatureFlagEvaluator C->>U: execute(userId) U->>D: greet(userId) D->>E: isEnabled("demo.feature.hello", ctx, false) alt ON E-->>D: true → Greeting D-->>C: 200 else OFF/미존재 E-->>D: false → throw D-->>C: 503 end
테스트 케이스
- 플래그 미존재 상태에서 GET /feature-demo/hello는 503을 반환한다(기본값 다크)
- GlobalToggle ON 플래그에서 200과 인사 메시지를 반환한다
- 플래그를 archive하면 즉시 503을 반환한다(킬스위치)
- PercentageRollout 50%에서 동일 X-User-Id를 반복 호출하면 200/503 판정이 일관된다(sticky)
- X-User-Id 없이 PercentageRollout 플래그 호출 시 default(false)로 503을 반환한다
- FeatureDemoDomainService는 domain.featureflag를 import하지 않는다(도메인 격리 — 정적 검증)