3535
3636에디터 모달의 비교 연산자 드롭다운은 ** Legacy 단일 모드에서만** 표시하며, ` < ` (LESS_THAN)과 ` > ` (GREATER_THAN) 두 가지만 제공한다. 스키마에는 ` LESS_THAN_OR_EQUAL ` , ` GREATER_THAN_OR_EQUAL ` 도 존재하지만, UI에서는 사용하지 않는다.
3737
38- #### 2. 조건 모드 선택 (단일/범위 )
38+ #### 2. 조건 모드 선택 (Scale In / Scale Out / Scale In & Out )
3939
40- Auto Scaling Rule 에디터 모달에 Ant Design ` Segmented ` 컴포넌트를 추가하여 "단일" / "범위" 모드를 전환한다 .
40+ Auto Scaling Rule 에디터 모달에 Ant Design ` Radio.Group ` (버튼형) 컴포넌트를 추가하여 세 가지 조건 방향을 선택한다. 비교 연산자는 항상 ` < ` (strict less than)만 사용하며, ` ≤ ` 선택 UI는 제공하지 않는다 .
4141
42- - ** 단일 모드** (기본): "상한" 또는 "하한" 방향을 선택하고 threshold 값을 입력
43- - 상한 (` metric < threshold ` ): ` maxThreshold ` 만 설정, ` minThreshold ` 는 null
44- - 하한 (` threshold < metric ` ): ` minThreshold ` 만 설정, ` maxThreshold ` 는 null
45- - ** 범위 모드** : ` [하한값] ` ~ ` [상한값] ` 범위를 지정 (` minThreshold ` + ` maxThreshold ` 동시 사용)
42+ - ** Scale In** (` metric < threshold ` ): ` minThreshold ` 만 설정, ` maxThreshold ` 는 null
43+ - UI: ` Metric < [입력값] `
44+ - ** Scale Out** (` threshold < metric ` ): ` maxThreshold ` 만 설정, ` minThreshold ` 는 null
45+ - UI: ` [입력값] < Metric `
46+ - 기본 선택값
47+ - ** Scale In & Out** (범위): ` minThreshold ` + ` maxThreshold ` 동시 설정
48+ - UI: ` Metric < [하한값] ` + ` [상한값] < Metric ` 두 행으로 표시
4649 - 하한값 >= 상한값이면 validation 에러를 표시
4750
48- > ** 참고** : Strawberry API (>=26.4.0) 전용. Legacy (<26.4.0)에서는 ` comparator ` + 단일 ` threshold ` 를 그대로 사용하며, 범위 모드는 지원하지 않는다.
51+ 스텝 사이즈 필드의 prefix 기호는 조건 모드에 따라 자동으로 변경된다:
52+ - Scale In: ` − ` (minus)
53+ - Scale Out: ` + ` (plus)
54+ - Scale In & Out: ` ± `
55+
56+ > ** 참고** : Strawberry API (>=26.4.0) 전용. Legacy (<26.4.0)에서는 ` comparator ` + 단일 ` threshold ` 를 그대로 사용하며, Scale In & Out(범위) 모드는 지원하지 않는다.
4957
5058#### 3. Prometheus Preset 기반 메트릭 선택
5159
@@ -57,21 +65,22 @@ Auto Scaling Rule 에디터 모달에 Ant Design `Segmented` 컴포넌트를 추
5765
5866` <26.4.0 ` 에서는 ` KERNEL ` /` INFERENCE_FRAMEWORK ` 만 표시되며, ` PROMETHEUS ` 는 노출하지 않는다.
5967
68+ ` >=26.4.0 ` 에서는 ` INFERENCE_FRAMEWORK ` 가 드롭다운에서 제거되고 ` KERNEL ` 과 ` PROMETHEUS ` 만 표시된다. (` isSupportPrometheusAutoScalingRule ` 가 true이면 ` INFERENCE_FRAMEWORK ` 옵션을 숨긴다.)
69+
6070| metricSource | Preset 선택 UI | prometheusQueryPresetId | metric name |
6171| ---| ---| ---| ---|
6272| ` KERNEL ` | 숨김 | ` null ` | AutoComplete (자동완성 목록: ` cpu_util ` , ` mem ` , ` net_rx ` , ` net_tx ` + 자유 입력 가능) |
63- | ` INFERENCE_FRAMEWORK ` | 숨김 | ` null ` | AutoComplete (자동완성 목록 없음, 자유 입력) |
64- | ` PROMETHEUS ` | 표시 (필수) | 필수 | preset의 ` metricName ` 에서 자동 채움 (입력 불필요) |
73+ | ` INFERENCE_FRAMEWORK ` | 숨김 | ` null ` | AutoComplete (자동완성 목록 없음, 자유 입력) — ` <26.4.0 ` 에서만 표시 |
74+ | ` PROMETHEUS ` | 표시 (필수) | 필수 | preset 선택 시 자동 채움 (입력 불필요, 숨김 필드로 폼에 포함 ) |
6575
6676##### Preset 선택 UI 동작
6777
68781 . metric source 드롭다운에서 ` PROMETHEUS ` 선택 시 Prometheus Query Preset Select가 추가로 노출
69792 . Preset 목록은 ` prometheusQueryPresets ` query로 로드하여 카테고리별로 그룹핑(` category.name ` )하고 ` name ` 을 드롭다운에 표시
70803 . Preset 선택 시:
7181 - ` prometheusQueryPresetId ` 에 선택된 preset의 UUID 저장 (Relay global ID를 디코딩한 raw UUID)
72- - ` metricName ` 은 preset의 ` metricName ` 에서 자동으로 채움 (사용자 입력 불필요)
73- - ` queryTemplate ` 을 읽기 전용으로 표시하여 사용자가 쿼리 내용 확인 가능
74- - ` timeWindow ` 가 자동 적용 (preset의 ` timeWindow ` 가 null이면 사용자 입력)
82+ - ` metricName ` 은 preset의 ` metricName ` 에서 자동으로 채움 (사용자 입력 불필요, 숨김 필드)
83+ - ` timeWindow ` 가 자동 적용 (preset의 ` timeWindow ` 가 유효한 숫자값이면 적용, null이면 기존값 유지)
7584
7685##### Rule 목록에서 Prometheus preset 표시
7786
@@ -107,24 +116,29 @@ Prometheus Preset 모드(>=26.4.0)에서 메트릭 설정 form item의 `extra`
107116- [ ] 기존 KERNEL/INFERENCE_FRAMEWORK metric source 수동 입력이 동작한다
108117
109118** Strawberry (>=26.4.0)**
110- - [ ] 에디터 모달에서 Segmented로 "단일"/"범위" 모드를 전환할 수 있다
111- - [ ] 단일 모드에서 "상한"(` maxThreshold ` 만) 또는 "하한"(` minThreshold ` 만) 방향을 선택할 수 있다
112- - [ ] 범위 모드에서 ` minThreshold ` + ` maxThreshold ` 를 동시에 입력하고, ` [min] < [metric] < [max] ` 로 표시된다
113- - [ ] 범위 모드에서 하한값 >= 상한값이면 validation 에러가 표시된다
114- - [ ] metric source에 ` PROMETHEUS ` 옵션이 추가되고, 선택 시 Prometheus Preset Select가 표시된다
115- - [ ] Prometheus preset 선택 시 ` metricName ` 이 자동으로 채워지고, ` queryTemplate ` 이 읽기 전용으로 표시된다
119+ - [ ] 에디터 모달에서 Radio.Group 버튼으로 "Scale In" / "Scale Out" / "Scale In & Out" 세 가지 조건 방향을 선택할 수 있다
120+ - [ ] Scale In 선택 시 ` minThreshold ` 만 설정되고, ` Metric < [값] ` UI가 표시된다
121+ - [ ] Scale Out 선택 시 ` maxThreshold ` 만 설정되고, ` [값] < Metric ` UI가 표시된다 (기본값)
122+ - [ ] Scale In & Out 선택 시 ` minThreshold ` + ` maxThreshold ` 를 동시에 입력하고, 두 행으로 표시된다
123+ - [ ] Scale In & Out 모드에서 하한값 >= 상한값이면 validation 에러가 표시된다
124+ - [ ] Step Size 필드의 prefix가 조건 모드에 따라 ` − ` /` + ` /` ± ` 로 자동 변경된다
125+ - [ ] metric source 드롭다운에 ` KERNEL ` 과 ` PROMETHEUS ` 만 표시된다 (` INFERENCE_FRAMEWORK ` 숨김)
126+ - [ ] metric source에 ` PROMETHEUS ` 선택 시 Prometheus Preset Select가 표시된다
127+ - [ ] Prometheus preset 선택 시 ` metricName ` 이 자동으로 채워진다 (숨김 필드)
116128- [ ] Prometheus preset 선택 시 ` prometheusQueryPresetId ` (raw UUID)가 Rule에 저장된다
117- - [ ] ` KERNEL ` / ` INFERENCE_FRAMEWORK ` 선택 시 preset 선택 UI가 숨겨진다
129+ - [ ] ` KERNEL ` 선택 시 preset 선택 UI가 숨겨진다
118130- [ ] Rule 목록에서 ` PROMETHEUS ` source인 rule은 preset 이름이 표시된다
119131- [ ] Rule 목록은 ` ModelDeployment.autoScalingRules ` nested connection으로 조회된다
120132
121133## 버전 게이팅 전략
122134
123135| 기능 | <26.4.0 (Legacy) | >=26.4.0 (Strawberry) | >=26.4.3 |
124136| ---| ---| ---| ---|
125- | 비교 연산자 표시 정규화 | 적용 (LESS_THAN/GREATER_THAN 반전) | 적용 (min/maxThreshold 기반) | 동일 |
126- | 조건 모드 (단일/범위) | 단일만 지원 (Legacy에 범위 필드 없음) | 단일 + 범위 모두 지원 | 동일 |
127- | Metric Source: PROMETHEUS | 미표시 (KERNEL/INFERENCE_FRAMEWORK만) | PROMETHEUS 추가, Preset 기반 Select | 동일 |
137+ | 비교 연산자 표시 정규화 | 적용 (LESS_THAN/GREATER_THAN 반전) | 적용 (min/maxThreshold 기반, 항상 ` < ` ) | 동일 |
138+ | 조건 모드 UI | 단일만 지원 (Legacy에 범위 필드 없음) | Radio.Group 3-way: Scale In / Scale Out / Scale In & Out | 동일 |
139+ | Metric Source: INFERENCE_FRAMEWORK | 표시 | 숨김 (` isSupportPrometheusAutoScalingRule ` ) | 동일 |
140+ | Metric Source: PROMETHEUS | 미표시 | 추가, Preset 기반 Select (카테고리별 그룹핑) | 동일 |
141+ | Step Size prefix | 없음 | ` − ` /` + ` /` ± ` (조건 모드 연동) | 동일 |
128142| Rule 목록 preset 이름 표시 | 미표시 | ` prometheusQueryPresetId ` 기반 (별도 query) | ` queryPreset ` 필드 직접 사용 |
129143| 쿼리 결과값 미리보기 | 미표시 | 표시 (Nice to Have) | 동일 |
130144
@@ -153,81 +167,3 @@ Strawberry API 마이그레이션과 UX 개선을 동시에 진행하므로, 기
153167- Query: ` endpoint_auto_scaling_rule_nodes(endpoint) ` → ` ModelDeployment.autoScalingRules ` (nested connection)
154168- Mutation: ` create_endpoint_auto_scaling_rule_node ` → ` createAutoScalingRule ` , ` modify_endpoint_auto_scaling_rule_node ` → ` updateAutoScalingRule ` , ` delete_endpoint_auto_scaling_rule_node ` → ` deleteAutoScalingRule `
155169- 필드: snake_case → camelCase, ` threshold ` +` comparator ` → ` minThreshold ` /` maxThreshold ` , ` cooldown_seconds ` → ` timeWindow ` , ` endpoint ` → ` modelDeploymentId `
156-
157- ## 참조
158-
159- ### 현재 코드
160-
161- | 파일 | 설명 |
162- | ---| ---|
163- | ` react/src/components/AutoScalingRuleEditorModal.tsx ` | 기존 Rule 추가/편집 모달 (Legacy). rename → ` AutoScalingRuleEditorModalLegacy.tsx ` |
164- | ` react/src/pages/EndpointDetailPage.tsx ` | Rules 목록 테이블 (line 697-926), ` baiClient.supports('auto-scaling-rule') ` (line 170) |
165-
166- ### GraphQL API
167-
168- #### Auto Scaling Rule (Strawberry, >=26.4.0)
169-
170- | 쿼리/뮤테이션 | 설명 |
171- | ---| ---|
172- | ` ModelDeployment.autoScalingRules(filter, orderBy, ...) ` | Rule 목록 조회 — ` ModelDeployment ` type의 nested connection |
173- | ` createAutoScalingRule(input: CreateAutoScalingRuleInput!) ` | Rule 생성 (` modelDeploymentId ` 필수) |
174- | ` updateAutoScalingRule(input: UpdateAutoScalingRuleInput!) ` | Rule 수정 (partial update) |
175- | ` deleteAutoScalingRule(input: DeleteAutoScalingRuleInput!) ` | Rule 삭제 |
176-
177- #### Prometheus Query Preset (Read only, 모든 인증된 사용자)
178-
179- | 쿼리 | 설명 |
180- | ---| ---|
181- | ` prometheusQueryPresets(filter, orderBy, limit, offset) ` | Preset 목록 조회 (` QueryDefinition.category ` 필드로 카테고리 정보 함께 조회 가능) |
182- | ` prometheusQueryPreset(id: ID!) ` | Preset 단건 조회 |
183- | ` prometheusQueryPresetResult(id, timeRange, options, timeWindow) ` | Preset 기반 쿼리 실행 결과 (Nice to Have) |
184- | ` prometheusQueryPresetCategories(filter, orderBy, ...) ` | Preset 카테고리 목록 조회 |
185- | ` prometheusQueryPresetCategory(id: ID!) ` | Preset 카테고리 단건 조회 |
186-
187- ### ID 변환 주의사항
188-
189- - Preset 목록 조회 (` prometheusQueryPresets ` ) 응답의 ` id ` 는 Relay global ID (base64 인코딩)
190- - Rule 생성/수정 시 ` prometheusQueryPresetId ` 에는 ` toLocalId(globalId) ` 로 디코딩한 raw UUID를 전달
191- - Rule 조회 응답의 ` prometheusQueryPresetId ` 는 raw UUID로 반환됨
192- - ` AutoScalingRule.queryPreset ` 필드(>=26.4.3)를 사용하면 ID 변환 없이 preset 이름/카테고리 등 정보를 직접 조회 가능
193- - Rule 수정 시 preset select 초기값 복원은 ` prometheusQueryPresetId ` 와 preset 목록 Relay global ID를 ` toLocalId() ` 로 변환하여 매칭
194-
195- ### 주요 타입 (스키마 기준)
196-
197- #### AutoScalingMetricComparator (enum)
198- ` LESS_THAN ` , ` LESS_THAN_OR_EQUAL ` , ` GREATER_THAN ` , ` GREATER_THAN_OR_EQUAL `
199-
200- #### AutoScalingMetricSource (enum)
201- ` KERNEL ` , ` INFERENCE_FRAMEWORK ` , ` PROMETHEUS ` (PROMETHEUS는 >=26.4.0)
202-
203- #### AutoScalingRule (type, added 25.19.0)
204- ` id ` , ` metricSource ` , ` metricName ` , ` minThreshold: Decimal ` , ` maxThreshold: Decimal ` , ` stepSize ` , ` timeWindow ` , ` minReplicas ` , ` maxReplicas ` , ` prometheusQueryPresetId: ID ` (added 26.4.2), ` createdAt ` , ` lastTriggeredAt ` , ` queryPreset: QueryDefinition ` (added 26.4.3 — preset 객체 직접 resolve)
205-
206- #### CreateAutoScalingRuleInput
207- ` modelDeploymentId: ID! ` , ` metricSource: AutoScalingMetricSource! ` , ` metricName: String! ` , ` minThreshold: Decimal ` , ` maxThreshold: Decimal ` , ` stepSize: Int! ` , ` timeWindow: Int! ` , ` minReplicas: Int ` , ` maxReplicas: Int ` , ` prometheusQueryPresetId: ID `
208-
209- #### UpdateAutoScalingRuleInput
210- ` id: ID! ` , ` metricSource ` , ` metricName ` , ` minThreshold ` , ` maxThreshold ` , ` stepSize ` , ` timeWindow ` , ` minReplicas ` , ` maxReplicas ` , ` prometheusQueryPresetId: ID `
211-
212- #### QueryDefinition (type, added 26.3.0)
213- ` id ` , ` name ` , ` description: String ` , ` rank: Int! ` , ` categoryId: UUID ` , ` metricName ` , ` queryTemplate ` , ` timeWindow: String ` , ` options: QueryDefinitionOptions! ` (` filterLabels: [String!]! ` , ` groupLabels: [String!]! ` ), ` createdAt ` , ` updatedAt ` , ` category: QueryPresetCategory ` (added 26.4.3 — 카테고리 엔티티 직접 resolve)
214-
215- #### QueryPresetCategory (type, added 26.3.0)
216- ` id: UUID! ` , ` name: String! ` , ` description: String ` , ` createdAt: DateTime! ` , ` updatedAt: DateTime! `
217-
218- #### QueryDefinitionExecuteResult (type, added 26.3.0)
219- ` status: String! ` , ` resultType: String! ` , ` result: [QueryDefinitionMetricResult!]! `
220- - ** QueryDefinitionMetricResult** : ` metric: [MetricLabelEntry!]! ` , ` values: [QueryDefinitionMetricResultValue!]! `
221- - ** QueryDefinitionMetricResultValue** : ` timestamp: Float! ` , ` value: String! `
222-
223- #### ExecuteQueryDefinitionOptionsInput
224- ` filterLabels: [MetricLabelEntryInput!] ` , ` groupLabels: [String!] `
225-
226- #### QueryTimeRangeInput (added 26.3.0)
227- ` start: DateTime! ` , ` end: DateTime! ` , ` step: String! `
228-
229- ## 범위 외 (Out of Scope)
230-
231- - Admin Prometheus Query Preset CUD (` adminCreatePrometheusQueryPreset ` , ` adminModifyPrometheusQueryPreset ` , ` adminDeletePrometheusQueryPreset ` ) — 별도 Spec
232- - Auto Scaling Rule CRUD 자체 (이미 구현됨, 이 spec에서는 Strawberry API로 마이그레이션)
233- - Legacy 코드 완전 제거 (백엔드 최소 버전 올린 후 별도 진행)
0 commit comments