Feature Flag 管理システム (recerdo-feature-flag)¶
作成者: Claude (AI) · 作成日: 2026-04-19 · ステータス: 承認済み (Approved)
Notion レビューコメント: 「この内容で設計を実施したいと思います。」(2026-04-18)
1. 概要¶
目的¶
Recerdo プラットフォーム全体の機能フラグ(Feature Flag)を一元管理するシステム。新機能のリリース制御、段階的ロールアウト、障害時の緊急停止(Kill Switch)、IP/Firewallベースのアクセス制御を提供する。OpenFeature SDK(CNCF標準)と Flipt(OSS、軽量)を組み合わせたゼロコスト構成を採用する。
ビジネスコンテキスト¶
解決する問題: - 新機能のリリース時に全ユーザーへの一括公開リスクを回避できない - エラー率が上昇した機能を即座に停止する手段がない - 特定ユーザーグループや地域向けの段階的公開ができない - Feature Flagの設定がコードやデプロイに依存しており、実行時変更ができない
Key User Stories: - 開発者として、新機能を全ユーザーに公開する前に、社内チームまたは5%のユーザーに試験公開したい - 運用担当として、特定機能のエラー率が閾値を超えたとき、コードデプロイなしで即座に機能を無効化したい - 管理者として、特定のIPアドレス範囲からのみアクセスを許可するフラグを設定したい - 機能オーナーとして、フラグの現在の状態(ON/OFF、適用ユーザー数)をダッシュボードで確認したい
2. エンティティ層(ドメイン)¶
ドメインモデル¶
| エンティティ | 説明 | 主要属性 |
|---|---|---|
| FeatureFlag | フラグ定義 | flag_key (string, unique), name, description, enabled (bool), flag_type (BOOLEAN/VARIANT), created_at, updated_at |
| FlagRule | フラグ適用ルール | rule_id (UUID), flag_key, rule_type (PERCENTAGE/SEGMENT/IP_RANGE/ALWAYS), rule_config (JSON), priority (int) |
| FlagEvaluation | フラグ評価ログ | eval_id (UUID), flag_key, entity_id (user_id), result (bool/variant), rule_matched, evaluated_at |
| FlagSegment | ユーザーセグメント | segment_key, description, conditions (user_id_list / org_id_list / custom JSON) |
| FlagAuditLog | 設定変更履歴 | log_id (UUID), flag_key, changed_by, old_value, new_value, changed_at |
値オブジェクト¶
| 値オブジェクト | 説明 | バリデーション |
|---|---|---|
| FlagKey | フラグ識別子 | snake_case、最大128文字、プレフィックス形式(feature.album.v2 等) |
| RolloutPercentage | ロールアウト割合 | 0〜100の整数 |
| IPRange | IP制限範囲 | CIDR表記(例: 192.168.1.0/24)、IPv4/IPv6 |
| ErrorRateThreshold | 自動停止エラー率閾値 | 0.0〜1.0(例: 0.05 = 5%) |
| EvaluationContext | フラグ評価コンテキスト | entity_id (user_id), org_id, ip_address, custom_attributes (map) |
ドメインルール / 不変条件¶
enabled = falseのフラグは、どのルールが定義されていても評価結果は常にfalse(Off)を返す- Percentage Rollout は同一
entity_idに対して決定論的でなければならない(同じユーザーには常に同じ結果) - Kill Switch が発動した場合(エラー率閾値超過)、フラグは自動的に
enabled = falseに遷移し、FlagAuditLog に記録する - FlagRule の
priorityは一意であり、低い値が優先評価される - IP制限フラグが定義されている場合、EvaluationContext に ip_address がなければ評価を拒否する
ドメインイベント¶
| イベント | トリガー | 主要ペイロード |
|---|---|---|
| FlagEnabled | フラグが ON に変更された | flag_key, changed_by, changed_at |
| FlagDisabled | フラグが OFF に変更された(Kill Switchを含む) | flag_key, reason (MANUAL/AUTO_KILLSWITCH), changed_by, changed_at |
| FlagRuleUpdated | ルール(Rollout、Segment等)が変更された | flag_key, rule_id, old_config, new_config |
| KillSwitchTriggered | エラー率閾値超過で自動停止 | flag_key, error_rate, threshold, triggered_at |
| EvaluationAnomaly | 予期しない評価エラーが多発 | flag_key, error_count, window_seconds |
3. ユースケース層(アプリケーション)¶
ユースケース一覧¶
| ユースケース | 入力 | 出力 | 説明 |
|---|---|---|---|
| EvaluateFlag | EvaluateFlagInput{flag_key, entity_id, context} | EvaluateFlagOutput{enabled, variant, reason} | フラグを評価(マイクロサービスが毎リクエスト呼び出し) |
| CreateFlag | CreateFlagInput{flag_key, name, description, enabled} | CreateFlagOutput{flag_key} | フラグ新規作成 |
| UpdateFlagStatus | UpdateFlagStatusInput{flag_key, enabled} | UpdateFlagStatusOutput{updated_at} | フラグON/OFF切り替え |
| SetRolloutRule | SetRolloutRuleInput{flag_key, percentage} | SetRolloutRuleOutput{rule_id} | Percentage Rollout設定 |
| SetIPRestriction | SetIPRestrictionInput{flag_key, cidr_ranges[]} | SetIPRestrictionOutput{rule_id} | IP制限設定 |
| TriggerKillSwitch | TriggerKillSwitchInput{flag_key, reason} | TriggerKillSwitchOutput{disabled_at} | Kill Switch発動(手動または自動) |
| GetFlagStatus | GetFlagStatusInput{flag_key} | GetFlagStatusOutput{enabled, rules[], eval_stats} | フラグ状態取得 |
| ListFlags | ListFlagsInput{filter} | ListFlagsOutput{flags[]} | フラグ一覧取得 |
ユースケース詳細(EvaluateFlag)¶
トリガー: 各マイクロサービスが機能実行前に呼び出し(OpenFeature SDK 経由)
フロー: 1. EvaluationContext(entity_id、org_id、ip_address 等)を受け取る 2. フラグ定義をキャッシュ(Redis / Flipt in-memory)から取得 3. enabled = false なら即座に {enabled: false, reason: FLAG_DISABLED} を返す 4. FlagRule を priority 順に評価: - IP_RANGE: EvaluationContext.ip_address が許可範囲か確認 - SEGMENT: entity_id が FlagSegment の条件を満たすか確認 - PERCENTAGE: hash(entity_id + flag_key) % 100 < percentage か確認 - ALWAYS: 無条件で適用 5. 最初にマッチしたルールの結果を返す 6. マッチなし → フラグデフォルト値(enabled の現在値)を返す 7. 評価ログを非同期で記録(FlagEvaluation)
エラーハンドリング: - Flipt 接続エラー時: フェイルオープン(enabled: true)またはフェイルクローズ(enabled: false)をフラグごとに設定可能 - デフォルトはフェイルクローズ(安全側)
ユースケース詳細(TriggerKillSwitch)¶
トリガー: - 手動: 管理者が API または Flipt UI から実行 - 自動: Prometheus Alertmanager(Beta/本番共通)が ErrorRate 閾値超過を検知し、QueuePort(Beta: Redis+BullMQ/asynq、本番: OCI Queue)経由で Flipt Admin API を呼び出す Worker がトリガーされる(AWS CloudWatch / SNS / Lambda は不使用、基本的方針 参照)
フロー: 1. flag_key と reason(MANUAL/AUTO_KILLSWITCH)を受け取る 2. FeatureFlag.enabled を false に更新 3. FlagAuditLog に変更履歴を記録 4. KillSwitchTriggered ドメインイベントを発行 5. Notification Service に通知(管理者への PUSH 通知) 6. Redis キャッシュを即座に無効化(次回評価からフラグOFF が反映される)
4. インフラ層¶
外部サービス連携¶
Flipt(CNCF OSS)¶
- 用途: Feature Flag サーバー(評価エンジン・管理UI)
- コスト: $0(OSS、自前運用)
- デプロイ: Docker コンテナ(Beta: XServer VPS 上の Docker Compose / k3s、本番: OCI Container Instances)
- Go SDK:
go.flipt.io/flipt/sdk/go - 特徴:
- gRPC + REST API
- Percentage Rollout、Segment、Boolean フラグをネイティブサポート
- 管理 UI(Web ダッシュボード)内包
- 評価結果のメトリクス出力(Prometheus)
OpenFeature SDK(CNCF標準)¶
- 用途: マイクロサービスがフラグを評価する際のクライアントインターフェース
- コスト: $0(OSS)
- Go SDK:
github.com/open-feature/go-sdk - 特徴:
- ベンダーニュートラルな標準インターフェース
- Flipt を Provider として設定(将来的に他ツールに切り替え可能)
- フック(Hook)機能でメトリクス収集・ログ出力を標準化
// OpenFeature SDK セットアップ例
import (
"github.com/open-feature/go-sdk/openfeature"
flipt "github.com/open-feature/go-sdk-contrib/providers/flipt/pkg/provider"
)
func InitFeatureFlags() {
provider := flipt.NewProvider(
flipt.WithAddress("http://flipt-svc:8080"),
)
openfeature.SetProvider(provider)
}
// 機能フラグ評価
func IsAlbumV2Enabled(ctx context.Context, userID string) bool {
client := openfeature.NewClient("album-svc")
enabled, err := client.BooleanValue(ctx, "feature.album.v2", false,
openfeature.NewEvaluationContext(userID, map[string]interface{}{
"org_id": orgID,
}),
)
if err != nil {
return false // フェイルクローズ
}
return enabled
}
MySQL 8.0 / MariaDB 10.11¶
- 用途: FeatureFlag、FlagRule、FlagSegment、FlagAuditLog の永続化
- Beta: XServer VPS 上の MySQL 8.0 / MariaDB 10.11(go-sql-driver/mysql、互換性を CI でテスト)
- 本番: OCI MySQL HeatWave
- テーブル:
feature_flags(flag_key, name, description, enabled, fail_mode, created_at, updated_at)flag_rules(rule_id, flag_key, rule_type, rule_config JSON, priority)flag_segments(segment_key, description, conditions JSON)flag_audit_logs(log_id, flag_key, changed_by, old_value, new_value, changed_at)
Redis¶
- 用途: フラグ評価結果キャッシュ(低レイテンシ応答)
- キー設計:
ff:flag:{flag_key}→ フラグ定義 JSON(TTL: 60秒)ff:eval:{flag_key}:{entity_id}→ 評価結果キャッシュ(TTL: 30秒)- Kill Switch 即時反映:
DEL ff:flag:{flag_key}でキャッシュを即時削除
インターフェース層 — REST API Endpoints¶
| エンドポイント | メソッド | 説明 | 認証 |
|---|---|---|---|
| POST /api/flags | POST | フラグ作成 | Admin JWT |
| GET /api/flags | GET | フラグ一覧取得 | Admin JWT |
| GET /api/flags/{flag_key} | GET | フラグ詳細取得 | Admin JWT |
| PUT /api/flags/{flag_key}/status | PUT | ON/OFF切り替え | Admin JWT |
| POST /api/flags/{flag_key}/kill-switch | POST | Kill Switch発動 | Admin JWT |
| PUT /api/flags/{flag_key}/rules/rollout | PUT | Percentage Rollout設定 | Admin JWT |
| PUT /api/flags/{flag_key}/rules/ip | PUT | IP制限設定 | Admin JWT |
| POST /api/flags/evaluate | POST | フラグ評価(内部API) | Service JWT |
| GET /api/flags/{flag_key}/audit | GET | 変更履歴取得 | Admin JWT |
5. 機能要件詳細¶
5.1 ON/OFF 切り替え¶
- Flipt UI または API から即時切り替え可能
- 変更は Redis キャッシュ無効化と同時に全インスタンスへ波及(60秒以内)
- 変更は FlagAuditLog に記録(誰が・いつ・何を変更したか)
5.2 エラーハンドリング(自動エラー率監視)¶
Prometheus Metrics (ErrorRate per flag_key) ← 各サービスが /metrics で公開
↓ 閾値超過(例: 5%超)
↓ Prometheus Alertmanager(Beta/本番共通)
↓ QueuePort publish -> recuerdo.flag.killswitch_requested(Beta: Redis+BullMQ/asynq、本番: OCI Queue Service)
↓ KillSwitch Worker: POST /api/flags/{flag_key}/kill-switch {reason: AUTO_KILLSWITCH}
↓ FeatureFlag.enabled = false
↓ KillSwitchTriggered イベント発行 → notifications-svc(FCM + Postfix メール)→ 管理者通知
5.3 Kill Switch(自動/手動)¶
- 手動: 管理者が API または Flipt ダッシュボードから即時実行
- 自動: Prometheus Alertmanager → QueuePort → KillSwitch Worker 連携で閾値超過を検知して自動発動(AWS CloudWatch / Lambda は不使用)
- 発動後、フラグは手動で明示的に再有効化するまで OFF を維持(自動復旧しない)
5.4 IP制限(Firewall)¶
- CIDR 表記で許可 IP 範囲を指定
- 複数 CIDR の AND または OR 条件をサポート
- マッチしない IP からの評価リクエストは
enabled: falseを返す(403 ではなくフラグOFF として扱う) - 利用ケース: 社内ネットワークからのみベータ機能を有効化
5.5 Percentage Rollout(段階的公開)¶
- 0〜100%の範囲でユーザーを均等にグループ分け
- 同一 user_id は常に同じグループに属する(決定論的ハッシュ)
- アルゴリズム:
hash(user_id + flag_key) % 100 < rollout_percentage - 段階的に 5% → 20% → 50% → 100% と拡大可能
6. コスト分析¶
| ソリューション | 年間コスト | Go SDK | CNCF準拠 | 自前運用 |
|---|---|---|---|---|
| OpenFeature + Flipt(採用) | $0 | ✅ | ✅ | 必要(Docker) |
| Unleash OSS | $0 | ✅ | ❌ | 必要 |
| Flagsmith OSS | $0 | ✅ | ❌ | 必要 |
| LaunchDarkly | $10,000+/年 | ✅ | ✅ | 不要 |
| Split.io | $7,000+/年 | ✅ | ❌ | 不要 |
Flipt は他 OSS と比較して軽量(単一バイナリ)でありながら、CNCF 標準の OpenFeature と組み合わせることで将来のツール移行コストを最小化できる。
7. デプロイ・インフラ¶
- Flipt サーバー: Docker コンテナ(Beta: XServer VPS の Docker Compose / k3s、本番: OCI Container Instances、最小 256MB / 0.25vCPU)
- 永続化: MySQL 8.0 / MariaDB 10.11(Beta XServer VPS)/ OCI MySQL HeatWave(本番)
- スケーリング: Flipt は水平スケール対応(評価エンジンはステートレス)
- モニタリング: Prometheus メトリクス(Flipt 内蔵)→ Prometheus + Loki + Grafana(AWS CloudWatch は不使用)
8. セキュリティ考慮事項¶
- Flipt 管理 UI へのアクセスは内部ネットワーク内に限定(Beta: XServer VPS のプライベート IP、本番: OCI VCN 内の Private Subnet、いずれもパブリック公開しない)
- API 経由の操作は Admin JWT(Permission Service発行)で認証
- マイクロサービスからの評価リクエストは Service JWT で認証
- フラグ変更は全て FlagAuditLog に記録(変更者・日時・内容)
最終更新: 2026-04-19 ポリシー適用