MMU 체크리스트의 false-pass 문제를 해결하기 위해 17개 feature flag와 condition marker 시스템을 설계하고, 48개 테스트로 점수 정확도를 개선한 과정 기록
false-pass 문제
MMU의 체크리스트를 초기 사용자에게 테스트해달라고 했을 때, 반복적으로 나온 피드백이 있었습니다:
“Stripe 안 쓰는데 billing fail이 나와요.”
구체적으로:
| 시나리오 | 체크리스트 항목 | 사용자 상태 | 결과 | 문제 |
|---|---|---|---|---|
| Stripe webhook 검증 | ”Webhook 서명을 검증하고 있는가?” | Stripe 미사용 | ❌ Fail | false-fail |
| 환불 정책 | ”환불 정책이 명시되어 있는가?” | 무료 프로젝트 | ❌ Fail | false-fail |
| GDPR 동의 배너 | ”GDPR 쿠키 동의 배너가 있는가?” | 한국 전용 서비스 | ❌ Fail | false-fail |
| iOS 가이드라인 | ”App Store 리뷰 가이드라인을 준수하는가?” | 웹 전용 | ❌ Fail | false-fail |
534개 항목 중 일부는 특정 조건에서만 해당되는 항목이었습니다. 결제를 안 쓰는 프로젝트에 결제 관련 항목이 fail로 나오면, 체크리스트 전체의 신뢰도가 떨어집니다.
graph TB
A["534개 체크리스트 항목"] --> B{"모든 항목이\n모든 프로젝트에\n해당되나?"}
B -->|"아니오"| C["조건부 항목 존재\n~120개"]
B -->|"예"| D["보편 항목\n~414개"]
C --> E["false-fail 발생\n(해당 안 되는데 fail)"]
E --> F["점수 왜곡\n체크리스트 신뢰도 ↓"]
style E fill:#ffebee,stroke:#f44336
style F fill:#ffebee,stroke:#f44336
해결 방향: Condition Marker
모든 항목을 모든 프로젝트에 적용하는 대신, 이 항목은 이 조건에서만 유효라는 마커를 추가하기로 했습니다.
설계 원칙
- 명시적 선언: 각 조건부 항목에
when필드 추가 - 사용자가 조건을 선택: CLI 실행 시 프로젝트의 특성을 입력
- 해당 없는 항목은 skip: fail이 아니라 not-applicable로 처리
- 점수 계산에서 제외: skip된 항목은 분모에서도 빠짐
Condition Marker 데이터 구조
{
"id": "billing-webhook-verification",
"title": "Webhook 서명을 검증하고 있는가?",
"category": "billing",
"priority": "P0",
"when": {
"has_billing": true,
"payment_provider": ["stripe", "lemonsqueezy", "paddle"]
}
}
{
"id": "gdpr-cookie-consent",
"title": "GDPR 쿠키 동의 배너가 있는가?",
"category": "legal",
"priority": "P1",
"when": {
"target_region": ["eu", "global"]
}
}
17개 Feature Flag
프로젝트의 특성을 나타내는 flag를 17개로 정리했습니다.
| # | Flag | 값 | 영향 범위 |
|---|---|---|---|
| 1 | has_billing | true/false | 결제 관련 48개 항목 |
| 2 | payment_provider | stripe/lemonsqueezy/paddle/none | 결제사별 세부 항목 |
| 3 | has_auth | true/false | 인증 관련 32개 항목 |
| 4 | auth_provider | supabase/firebase/auth0/custom | 제공자별 세부 항목 |
| 5 | target_region | kr/us/eu/global | 법적 규제 관련 항목 |
| 6 | platform | web/mobile/desktop/cli | 플랫폼별 항목 |
| 7 | has_api | true/false | API 보안, 문서화 항목 |
| 8 | has_database | true/false | DB 백업, 마이그레이션 항목 |
| 9 | has_file_upload | true/false | 파일 처리, 스토리지 항목 |
| 10 | has_email | true/false | 이메일 발송, 반송 처리 항목 |
| 11 | has_analytics | true/false | 분석 도구 연동 항목 |
| 12 | has_ci_cd | true/false | CI/CD 파이프라인 항목 |
| 13 | is_oss | true/false | 오픈소스 관련 항목 (라이선스, README) |
| 14 | team_size | solo/small/medium | 팀 규모별 항목 |
| 15 | has_i18n | true/false | 다국어 관련 항목 |
| 16 | has_realtime | true/false | WebSocket, SSE 관련 항목 |
| 17 | has_ai_features | true/false | AI/LLM 관련 항목 (프롬프트 인젝션 등) |
Flag 수 결정 과정
| 검토 수 | 결과 |
|---|---|
| 5개 | 조건 커버리지 부족 (false-fail 50%만 해결) |
| 10개 | 주요 시나리오 커버 (80% 해결) |
| 17개 | 거의 모든 시나리오 커버 (95%+ 해결) |
| 25개+ | 사용자 입력 부담 과다 → 이탈 위험 |
17개는 “커버리지와 사용성의 균형점”입니다. CLI에서 Y/N 17개를 묻는 데 약 2분. 그 2분으로 false-fail을 95%+ 제거합니다.
CLI 플로우 변경
Before (flag 없이)
$ npx make-me-unicorn
🦄 Make Me Unicorn - SaaS Launch Checklist
Running all 534 items...
[FAIL] Webhook signature verification missing
[FAIL] Refund policy not found
[FAIL] GDPR cookie consent banner missing
...
Score: 312/534 (58%)
→ 사용자: “나는 결제도 없고 EU 서비스도 아닌데 왜 58%지?”
After (flag 적용)
$ npx make-me-unicorn
🦄 Make Me Unicorn - SaaS Launch Checklist
Quick setup (2 min):
Has billing? [Y/n] n
Has authentication? [Y/n] y
Target region? [kr/us/eu/global] kr
Platform? [web/mobile/desktop/cli] web
Has AI features? [Y/n] n
...
Applying 17 flags → 89 items skipped (not applicable)
Running 445 applicable items...
[PASS] Auth session expiry configured
[FAIL] Password reset flow missing
[SKIP] Webhook verification (no billing)
...
Score: 380/445 (85%)
(89 items skipped as not applicable)
→ 사용자: “85%라니, 거의 다 됐네. 남은 65개만 고치면 되겠다.”
graph LR
A["534 전체 항목"] -->|"17 flags 적용"| B["445 해당 항목"]
A -->|"17 flags 적용"| C["89 skip 항목"]
B --> D["380 PASS"]
B --> E["65 FAIL"]
F["Before: 312/534 = 58%"] -->|"false-fail 제거"| G["After: 380/445 = 85%"]
style F fill:#ffebee,stroke:#f44336
style G fill:#e8f5e9,stroke:#4caf50
테스트 설계: 48개 회귀 테스트
Feature flag 시스템이 정확하게 작동하는지 검증하기 위해 48개 테스트 케이스를 작성했습니다.
테스트 카테고리
| 카테고리 | 테스트 수 | 검증 내용 |
|---|---|---|
| Flag 조합 | 12 | 17개 flag의 대표적 조합에서 올바른 항목이 포함/제외되는지 |
| 경계 케이스 | 8 | 모든 flag가 false, 모든 flag가 true, 단일 flag만 true |
| 점수 계산 | 10 | skip 항목이 분모에서 정확히 제외되는지 |
| 역호환성 | 6 | flag 없이 실행해도 기존 동작(534 전체) 유지 |
| 조건 충돌 | 8 | 여러 when 조건이 겹칠 때 올바르게 해석되는지 |
| 출력 포맷 | 4 | skip 항목이 리포트에 올바르게 표시되는지 |
핵심 테스트 예시
// flag 조합 테스트: 결제 없는 한국 웹 프로젝트
test('billing=false, region=kr should skip billing + GDPR items', () => {
const flags = {
has_billing: false,
target_region: 'kr',
platform: 'web',
};
const result = filterItems(ALL_ITEMS, flags);
// 결제 관련 48개 항목 skip
expect(result.skipped).toContain('billing-webhook-verification');
expect(result.skipped).toContain('refund-policy');
// GDPR 관련 항목 skip (kr 전용이므로)
expect(result.skipped).toContain('gdpr-cookie-consent');
// 한국 개인정보보호법 항목은 포함
expect(result.applicable).toContain('kr-privacy-policy');
});
// 점수 계산 테스트: skip 항목이 분모에서 제외
test('score calculation excludes skipped items from denominator', () => {
const flags = { has_billing: false };
const result = runChecklist(ALL_ITEMS, flags, mockAnswers);
// 534 - 48(billing) = 486 applicable
expect(result.total).toBe(486);
expect(result.score).toBe(result.passed / 486);
// NOT result.passed / 534
});
점수 정확도 = 신뢰의 핵심
왜 정확도가 중요한가
| false-fail이 많으면 | false-pass가 많으면 |
|---|---|
| ”이 도구 쓸모없네” → 이탈 | ”다 통과했네!” → 실제 문제 방치 |
| 체크리스트 자체에 대한 불신 | 론칭 후 장애, 법적 문제 |
| 사용자가 결과를 무시하기 시작 | 체크리스트의 존재 이유가 사라짐 |
체크리스트 도구의 가장 중요한 지표는 정확도입니다. 기능이 아닙니다. 기능이 100개여도 결과가 부정확하면 아무도 안 씁니다. Feature flag는 기능 추가가 아니라 정확도 개선입니다.
개선 결과
| 지표 | Before | After | 변화 |
|---|---|---|---|
| false-fail 비율 | ~22% | ~3% | -19%p |
| 사용자 체감 점수 | 58% (과소) | 85% (정확) | +27%p |
| ”쓸모없다” 피드백 | 빈번 | 거의 없음 | 해소 |
| 완주율 (끝까지 확인) | ~40% | ~75% | +35%p |
교훈
1. 체크리스트는 “보편성”이 아니라 “적합성”이 가치
534개 항목이 모두에게 해당된다는 전제는 틀렸습니다. 가치는 “많은 항목”이 아니라 “나에게 맞는 항목”에서 나옵니다. Feature flag는 534개를 줄이는 것이 아니라, 534개 중 나에게 맞는 것을 정확히 골라주는 것입니다.
2. 정확도와 사용성은 트레이드오프
Flag를 늘리면 정확도가 올라가지만 사용성이 떨어집니다. 17개는 이 트레이드오프의 현재 균형점이며, 사용자 피드백에 따라 조정될 수 있습니다.
3. 테스트는 flag 시스템에 필수
조건부 로직은 버그의 온상입니다. 48개 테스트 없이 17개 flag를 운영하면, flag 추가할 때마다 기존 조합이 깨질 수 있습니다.
정리
| 핵심 | 내용 |
|---|---|
| 문제 | false-fail — 해당 안 되는 항목이 fail로 나와서 점수 왜곡 |
| 해결 | Condition Marker + 17개 Feature Flag |
| 결과 | false-fail 22% → 3%, 완주율 40% → 75% |
| 교훈 | 체크리스트의 가치 = 항목 수가 아니라 정확도 |
관련 글

PLG에서 공유 기능이 왜 첫 번째인가 — mmu share 설계 기록
Make Me Unicorn의 PLG 성장을 위해 설계한 3가지 공유 요소(점수 카드, 배지, 체크리스트 커스텀 링크)의 심리적 기제와 바이럴 루프 구현 전략 기록

코드는 됐는데 나머지가 안 됐다
기능 구현(12%) 이후 론칭까지 추가로 소요된 3주간의 작업(결제 안정성, 보안, 법적 문서, SEO 등)을 통해 '코드 완료'와 '제품 완료'의 차이를 분석

534개 항목은 어디서 왔나
SaaS 론칭 체크리스트 534개 항목이 80개 서비스 분석, 12개 가이드라인, 5개 실전 실패 사례에서 도출된 과정과 항목별 우선순위(P0–P3) 결정 로직 기록