# 기능 플래그 빠른 시작

Mocco의 기능 플래그는 [OpenFeature](https://openfeature.dev)와 함께 동작합니다. 코드는 표준 OpenFeature API를 호출하고, 그 뒤에서 Mocco가 프로바이더 역할을 합니다. 서버는 자기 환경의 규칙을 내려받아 모든 플래그를 메모리에서 평가합니다. 평가는 네트워크를 기다리지 않으며, Mocco에 연결할 수 없으면 서버는 마지막으로 받은 규칙을 계속 사용합니다.

## 1. Feature flags 켜기

워크스페이스 멤버가 워크스페이스의 **Products** 페이지에서 **Feature flags**를 켭니다. 그러면 프로젝트에 **Feature flags** 페이지가 나타납니다.

## 2. 환경과 플래그 만들기

**Feature flags** 페이지에서 코드가 실행되는 곳마다 환경을 만듭니다. 예를 들면 `staging`과 `production`입니다. 환경은 규칙 묶음을 분리한 것일 뿐이며, 이름에 Mocco가 부여하는 특별한 의미는 없습니다.

그다음 `new-checkout` 같은 플래그를 만듭니다. 플래그는 기본적으로 `boolean`입니다. `string`, `number`, `json`을 고르면 `{ "short": "Pay", "long": "Pay securely" }`처럼 이름 붙은 변형을 가집니다. 새 플래그는 모든 환경에 **꺼진** 상태로 추가되므로, 플래그를 켜기 전까지 코드는 자체 기본값을 계속 사용합니다. 변경은 즉시 적용되고, 누가 무엇을 바꿨는지와 함께 환경의 이력에 기록됩니다.

![Feature flags 페이지: 각 환경의 플래그, Staging의 세그먼트와 이력](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/0d3a57eb-c353-4003-86a1-cb03fc58255f/flags-tab.png)

## 3. 사용자 타기팅

플래그를 열어 환경별로 누가 어떤 변형을 받을지 정합니다.

- **Rules**는 순서대로 시도되며, 조건이 모두 일치하는 첫 규칙이 자신의 변형을 제공합니다. 조건은 코드가 넘기는 평가 컨텍스트의 속성을 비교하거나(`plan is one of pro, enterprise`, `appVersion version ≥ 2.1.0`, `email ends with @acme.com`) 세그먼트 소속 여부를 확인합니다.
- **Segments**는 Feature flags 페이지에서 정의하는 환경별 이름 붙은 그룹입니다. 항상 포함되거나 절대 포함되지 않는 타기팅 키와, 속성 조건으로 구성됩니다.
- **When no rule matches**일 때 플래그는 변형 하나 또는 **percentage rollout**을 제공합니다. 롤아웃은 컨텍스트의 `targetingKey`를 기준으로 버킷을 나누므로 사용자는 항상 같은 버킷에 들어가고, 비율을 10%에서 20%로 올리면 사용자만 추가됩니다.

**Preview**는 저장하기 전에, SDK가 쓰는 것과 같은 평가기로 저장하지 않은 변경 사항을 임의의 컨텍스트에서 평가해 줍니다.

![Staging에서 플래그의 규칙: staff 세그먼트와 pro 요금제는 새 체크아웃을 받고, 나머지는 10%로 롤아웃되며, 미리보기가 ada의 결과를 보여 줍니다](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/890ad58d-2cd8-445b-a1c1-6f5d1013b27d/flags-rules.png)

## 4. 환경 보호하기

**Feature flags** 페이지에서 환경을 고르고 **Edit protection**을 선택합니다. 변경을 승인할 역할, 필요한 승인 수, 변경을 제안한 사람이 승인해도 되는지를 정합니다. 역할은 워크스페이스의 **Access** 페이지에서 정의합니다.

환경이 보호되면 변경을 저장해도 바로 적용되지 않고 승인을 위해 전달됩니다.

- 변경은 diff, 사유, 필요한 보호 수준과 함께 환경의 이력에서 대기합니다. 워크스페이스 알림 규칙에 플래그 변경이 포함되어 있으면(**Mocco** 프리셋에는 포함됩니다) 그 역할의 멤버가 알림을 받습니다.
- 승인자는 그 자리에서 승인하거나 거부합니다. 승인은 화면에 보이는 바로 그 변경에 묶이므로, 그사이 대체된 변경을 실수로 승인하는 일은 없습니다.
- 충분한 승인이 모이면 변경이 적용됩니다. 그전에 다른 사람이 환경을 바꾸었다면 **conflicted**로 표시되고 아무것도 적용되지 않습니다. 이때 제안자가 변경을 현재 버전 위로 **rebase**할 수 있고, 그러면 승인을 위해 다시 전달됩니다.
- 제안자는 대기 중인 변경을 철회할 수 있습니다. 7일 안에 아무도 결정하지 않은 변경은 만료됩니다.

환경의 보호 설정을 바꾸거나 제거하는 일도 현재 보호 설정 아래에서 승인을 받아야 합니다. 이미 대기 중인 변경은 제안될 당시의 보호 설정을 유지합니다.

![보호된 Staging 환경: 모바일 릴리스 승인 한 건을 기다리는 25%로 올리는 변경. 사유, diff, 해시가 함께 표시됩니다](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/82931bcb-2a9a-49dd-b952-6d5953036ef1/flags-approval.png)

## 5. 긴급할 때 플래그 킬하기

플래그가 문제를 일으키면 플래그를 열고 **Kill switch**에 사유를 입력한 뒤 **Kill**을 선택합니다. 플래그의 규칙과 상관없이 그 환경의 모든 사용자가 플래그의 **off variant**를 즉시 받습니다. Mocco를 모르는 SDK와 flagd 클라이언트도 포함됩니다. 제공되는 규칙 자체가 "off"라고 말하기 때문입니다.

킬은 보호된 환경에서도 승인을 기다리지 않으며, 누가 왜 했는지가 항상 기록됩니다. 보호된 환경에서는 그다음에 킬이 환경 승인자의 검토 대상이 되고, 승인자는 이를 검토 완료로 표시하거나 문제를 제기합니다. **off variant**는 플래그 페이지에서 설정합니다. 이를 바꾸는 일과, 킬된 플래그를 복원하는 일은 일반 변경이므로 보호된 환경에서는 승인이 필요합니다. **Feature flags** 페이지의 **Edit protection**에서는 그 환경에서 어떤 역할이 플래그를 킬할 수 있는지도 정합니다(기본값은 모든 워크스페이스 멤버).

![보호된 환경에서 킬된 플래그: 모두가 off를 받고, 복원을 제안할 수 있으며, 킬은 검토를 기다립니다](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/7c2f61a5-c2a8-48a5-a575-3a73923d2aad/flags-kill.png)

## 6. 환경 하나를 위한 서버 키 만들기

프로젝트의 **API keys** 페이지에서 **flags:read** 권한이 있는 **Secret** 키를 만들고 읽을 환경을 고릅니다. 키는 정확히 환경 하나만 읽으므로, 환경마다 키를 하나씩 만들어 각 서버에 자기 환경의 키를 주세요. 키는 한 번만 보이므로 바로 복사하세요.

![flags:read 권한의 secret 키 만들기: 양식이 키가 읽을 환경을 묻습니다](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/d032e2e7-6698-4e04-8c68-d57e57c9790e/flags-key.png)

이 키는 서버에만 두세요. 규칙에는 사용자 목록과 사용자에게 보여서는 안 되는 정보가 들어 있을 수 있으므로, Mocco는 브라우저에서 보낸 secret 키를 거부합니다.

## 7. Node에서 플래그 평가하기

OpenFeature의 서버 SDK와 Mocco 프로바이더를 설치합니다.

```bash
npm install @openfeature/server-sdk @mocco/openfeature-server
```

서버가 시작될 때 프로바이더를 한 번 등록하면, 어디서든 플래그를 요청할 수 있습니다.

```ts
import { MoccoProvider } from '@mocco/openfeature-server';
import { OpenFeature } from '@openfeature/server-sdk';

await OpenFeature.setProviderAndWait(new MoccoProvider({ secretKey: process.env.MOCCO_FLAGS_KEY! }));
const flags = OpenFeature.getClient();

if (await flags.getBooleanValue('new-checkout', false, { targetingKey: user.id, plan: user.plan })) {
  // the new checkout
}
```

프로바이더는 Mocco의 변경 스트림을 구독하므로, 콘솔에서 플래그를 바꾸면 서버가 1~2초 안에 반영하고 OpenFeature가 바뀐 플래그와 함께 `PROVIDER_CONFIGURATION_CHANGED`를 발생시킵니다. 스트림이 끊어질 때를 대비해 30초마다도 확인하며(`pollIntervalMs`로 바꿀 수 있습니다), 바뀐 것이 없으면 Mocco는 빈 `304 Not Modified`로 응답합니다.

Mocco에 연결할 수 없으면 프로바이더는 마지막으로 받은 규칙으로 계속 응답하고 다시 연결될 때까지 `PROVIDER_STALE`을 보고합니다. 부팅할 때 Mocco에 닿지 않아도 시작하려면 규칙의 저장된 사본을 `bootstrap`으로 넘기세요.

꺼진 플래그는 `DISABLED`라는 사유와 함께 코드의 기본값을 반환합니다. Mocco가 모르는 플래그 키는 `FLAG_NOT_FOUND` 오류와 함께 기본값을 반환하므로, 오타가 요청을 깨뜨리는 일은 없습니다.

## 배포와 플래그 변경을 나란히 보기

각 환경의 **History**에는 그 환경의 변경이 나열됩니다. 그 사이에 배포를 함께 보려면, History 제목 옆의 **Show the runs of**에서 환경이 제공하는 코드를 배포하는 파이프라인의 저장소를 고르세요. 그 파이프라인의 실행이 플래그 변경 사이에 나타나므로, 플래그를 읽는 코드가 배포되기 전에 켰는지 후에 켰는지 알 수 있습니다. 실행의 커밋을 선택하면 해당 실행이 열립니다. 파이프라인을 링크해도 History에 실행이 추가될 뿐, 규칙, 스위치, 승인은 바뀌지 않습니다.

![Production의 History: 플래그 변경 위의 acme/mobile 파이프라인 실행](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/b916eb32-038a-40bf-8ed0-825a13115826/flags-timeline.png)

파이프라인이 링크되어 있으면 Mocco는 플래그를 켜기 전에도 확인합니다. 파이프라인의 마지막 성공한 실행의 코드를 살펴보고, 플래그 키를 참조하는 파일이 없으면(`getBooleanValue('checkout', …)`처럼) 저장하기 전에 편집기가 경고합니다. 그 상태로 플래그를 켜면 아직 배포된 어떤 코드도 읽지 않는 값을 제공하게 됩니다. 경고가 저장을 막지는 않습니다.

![legacy-banner가 acme/mobile의 마지막 배포에 없다고 편집기가 경고합니다](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/6a744dd3-a323-43c6-8dce-f82dd03a42d1/flags-deploy-warning.png)

## 대신 flagd 사용하기

Mocco는 표준 flagd 플래그 정의를 제공하므로, [flagd](https://flagd.dev) 인스턴스가 Mocco에서 동기화해 어떤 언어의 OpenFeature flagd 프로바이더에든 플래그를 제공할 수 있습니다. flagd의 HTTP 동기화가 서버 키로 Mocco를 가리키게 하세요.

```bash
flagd start --sources='[{"uri":"https://api.mocco.club/v1/flags/ruleset","provider":"http","authHeader":"Bearer mk_sec_…","interval":30}]'
```

flagd는 폴링할 때마다 마지막 `ETag`를 보내므로, 규칙이 바뀌지 않았다면 작은 요청 한 번이면 됩니다.

## 브라우저와 앱

웹 페이지, React, React Native 앱은 [브라우저와 앱에서 기능 플래그 쓰기](https://www.mocco.club/docs/ko/articles/nb48sq-browsers-and-apps)를 참고하세요. 기기는 규칙이 아니라 답만 받습니다.

## 오래된 플래그 정리하기

Mocco는 코드에서 걷어 낼 때가 된 것처럼 보이는 플래그를 알려 줍니다. 한 번도 평가되지 않았거나, 최근에 평가되지 않았거나, 모두에게 하나의 값만 제공하는 플래그입니다. [오래된 플래그 정리하기](https://www.mocco.club/docs/ko/articles/e72bxg-stale-flags)를 참고하세요.

플래그를 저장소에 두고 풀 리퀘스트로 바꾸려면 [코드로 관리하는 플래그](https://www.mocco.club/docs/ko/articles/w6vma5-flags-as-code)를 참고하세요.
