---
template: policy-doc@1
doc_id: 04-feature-gates
title: 기능 게이트 — 무엇이 켜고 끄는가, 지금 켜져 있는지 알 수 있는가
config: ../_meta/template-config.yaml
last_verified: 4d798f55
policies:
  - id: gates:REACT_APP_SMARTRO_MODE
    status: conditional-enabled
    evidence: [S-component, S-constant]
    limitations:
      - 확보한 값은 스테이징 배포 자료의 것이다. 운영 환경이 같은 값을 넣고 있는지는 이 조사가 확인하지 않았고 두 환경이 갈릴 수 있다
      - 빈 값이 벤더에게 어떻게 해석되는지는 이 문서의 축이 아니다. 벤더 동작은 공급자 문서가 든다
    anchors:
      - insuniverse-site/front/src/pages/payment/PaymentPage.tsx:95
      - insuniverse-site/front/src/pages/payment/PaymentPage.tsx:199
  - id: gates:REACT_APP_TOSS_CLIENT_KEY
    status: conditional-enabled
    evidence: [S-component, S-constant]
    limitations:
      - 확보한 값은 스테이징 배포 자료의 것이다. 운영 환경이 같은 값을 넣고 있는지는 이 조사가 확인하지 않았고 두 환경이 갈릴 수 있다
      - 빈 키로 초기화가 어떻게 끝나는지는 이 문서의 축이 아니다. 벤더 동작은 공급자 문서가 든다
    anchors:
      - insuniverse-site/front/src/features/payment/hooks/usePayment.tsx:73
  - id: gates:ADMIN_VIEW_TOKEN_ENFORCE
    status: conditional-unknown
    evidence: [S-guard, S-test]
    unknown_reason: 이 관문을 차단으로 올리는 값이 운영 환경에서 무엇인지 확보하지 않았다. 코드가 정하는 것은 값이 없을 때의 동작뿐이고, 그 값은 환경별 배포 객체에 있으며 세 저장소 어디에도 없다
    anchors:
      - insuniverse-server/apps/api/src/modules/admin-view-token/admin-view-token.guard.ts:49
  - id: gates:ADMIN_VIEW_TOKEN_TTL_MS
    status: conditional-unknown
    evidence: [S-constant, S-test]
    unknown_reason: 열람 토큰의 유효 기간을 환경이 덮을 수 있는데 운영 환경이 그 자리에 무엇을 넣는지 확보하지 않았다. 코드가 정하는 것은 덮이지 않았을 때의 기간뿐이다
    anchors:
      - insuniverse-server/apps/api/src/modules/admin-view-token/admin-view-token.service.ts:25
  - id: gates:RATE_LIMIT_CERTIFY_PER_MIN
    status: conditional-unknown
    evidence: [S-guard, A-comment]
    unknown_reason: 분당 허용 횟수를 정하는 값이 운영 환경에서 무엇인지 확보하지 않았다. 값이 양수가 아니면 이 관문이 아무것도 세지 않으므로 지금 세고 있는지 판정하지 못한다
    limitations:
      - 이 관문을 무력화하는 조건이 이 게이트 말고 하나 더 있다. 같은 판정이 캐시 저장소 연결을 함께 묻고 그 연결 설정이 없으면 게이트 값과 무관하게 통과시킨다. 그 설정은 이 문서가 다루는 게이트 집합 밖이라 정책으로 서지 않고 이 항목이 사실로만 든다
    anchors:
      - insuniverse-server/apps/api/src/modules/treat/certify-rate-limit.guard.ts:31
  - id: gates:CAR_VIEW_ADMIN_IDS
    status: conditional-unknown
    evidence: [S-guard, S-test]
    unknown_reason: 어느 관리자가 허용목록에 있는지를 정하는 값이 운영 환경에서 무엇인지 확보하지 않았다. 목록이 비면 최고관리자 역할이 거절되므로 지금 누가 열람할 수 있는지 판정하지 못한다
    limitations:
      - 이 게이트를 읽는 코드가 아직 운영에 닿지 않았다. 동결 기준점의 그 자리를 마지막으로 고친 커밋이 운영 도달 목록 밖이다 — 미배포 상태이며 이 사실은 게이트 표기가 아니라 이 항목이 든다
    anchors:
      - insuniverse-server/apps/api/src/modules/auth/admin/car-view-admin.guard.ts:30
  - id: gates:DISEASE_PDF_HIDE_NAME_AGENCY_ID
    status: conditional-unknown
    evidence: [S-constant, S-test]
    unknown_reason: 어느 기업의 문서에서 환자명을 가릴지 정하는 값이 운영 환경에서 무엇인지 확보하지 않았다. 값이 정수가 아니거나 0 이하면 가림이 아예 걸리지 않으므로 지금 가려지고 있는지 판정하지 못한다
    limitations:
      - 이 게이트를 읽는 코드가 아직 운영에 닿지 않았다. 동결 기준점의 그 자리를 마지막으로 고친 커밋이 운영 도달 목록 밖이다 — 미배포 상태이며 이 사실은 게이트 표기가 아니라 이 항목이 든다
      - 생성 인덱스가 이 게이트의 독출 자리를 다른 행으로 적는다. 그 행을 그대로 따르면 도달 판정이 뒤집힌다 — 이 문서의 앵커는 동결 기준점에서 다시 찾은 것이다
    anchors:
      - insuniverse-server/apps/api/src/modules/analyze/analyze.service.ts:1268
  - id: gates:TREAT_PROVIDER
    status: conditional-unknown
    evidence: [S-constant, A-comment]
    unknown_reason: 어느 공급자로 진료내역을 모을지 정하는 값이 운영 환경에서 무엇인지 확보하지 않았다. 값이 없을 때의 공급자만 코드에서 읽었다
    anchors:
      - insuniverse-server/apps/api/src/config/configuration.ts:29
  - id: gates:TREAT_POOL
    status: conditional-unknown
    evidence: [S-constant, A-comment]
    unknown_reason: 분산 모드에서 어느 공급자를 어떤 예산으로 묶을지 정하는 값이 운영 환경에서 무엇인지 확보하지 않았다. 값이 없을 때의 편성만 코드에서 읽었다
    anchors:
      - insuniverse-server/apps/api/src/config/configuration.ts:33
  - id: gates:ENABLE_TREAT_CAR
    status: conditional-unknown
    evidence: [S-constant, S-schema]
    unknown_reason: 자동차보험 진료 수집을 켜는 값이 운영 환경에서 무엇인지 확보하지 않았다. 게다가 이 자리는 저장소 설정이 먼저 읽히므로 환경 값만으로는 지금 켜져 있는지 판정하지 못한다
    limitations:
      - 이 게이트를 읽는 코드가 아직 운영에 닿지 않았다. 동결 기준점의 그 자리를 마지막으로 고친 커밋이 운영 도달 목록 밖이다 — 미배포 상태이며 이 사실은 게이트 표기가 아니라 이 항목이 든다
    anchors:
      - insuniverse-server/apps/api/src/config/configuration.ts:47
  - id: gates:INHOUSE_CAR_CANARY
    status: conditional-unknown
    evidence: [S-constant, S-schema]
    unknown_reason: 자체엔진 자동차 카나리를 켜는 값이 운영 환경에서 무엇인지 확보하지 않았다. 이 자리도 저장소 설정이 먼저 읽히므로 환경 값만으로는 지금 켜져 있는지 판정하지 못한다
    limitations:
      - 이 게이트를 읽는 코드가 아직 운영에 닿지 않았다. 동결 기준점의 그 자리를 마지막으로 고친 커밋이 운영 도달 목록 밖이다 — 미배포 상태이며 이 사실은 게이트 표기가 아니라 이 항목이 든다
    anchors:
      - insuniverse-server/apps/api/src/config/configuration.ts:83
  - id: gates:B2C_BYPASS_SLOT
    status: conditional-unknown
    evidence: [S-constant, A-comment]
    unknown_reason: 외부 서비스 바이패스의 동시 슬롯 상한을 정하는 값이 운영 환경에서 무엇인지 확보하지 않았다. 값이 없을 때의 상한만 코드에서 읽었다
    anchors:
      - insuniverse-server/apps/api/src/config/configuration.ts:164
  - id: gates:SETTLE_TARGET_DATE
    status: conditional-unknown
    evidence: [A-scheduler, A-comment]
    unknown_reason: 대리점 정산을 어느 날짜 기준으로 돌릴지 정하는 값이 운영 환경에서 설정돼 있는지 확보하지 않았다. 값이 없을 때 어느 구간을 집계하는지만 코드에서 읽었다
    anchors:
      - insuniverse-server/apps/api/src/schedules/settlement-agency.schedule.ts:28
  - id: gates:RUN_MODE
    status: conditional-unknown
    evidence: [A-scheduler, A-comment]
    unknown_reason: 배포된 컨테이너가 실제로 어느 실행 모드로 뜨는지는 태스크 정의가 정하며 그 정의의 운영 내용을 이 조사가 확보하지 않았다. 이미지에 굳은 값과 그것을 덮는 자리까지만 읽었다
    anchors:
      - insuniverse-server/apps/api/dockerfile:35
      - insuniverse-server/apps/api/dockerfile:37
      - insuniverse-server/apps/api/dockerfile:40
      - insuniverse-server/.github/workflows/api.yml:24
      - insuniverse-server/.github/workflows/api.yml:121
      - insuniverse-server/.github/workflows/api.yml:126
      - insuniverse-server/.github/workflows/api.yml:181
      - insuniverse-server/.github/workflows/api.yml:225
      - insuniverse-server/.github/workflows/api.yml:226
  - id: gates:SCHEDULER_TYPE
    status: conditional-unknown
    evidence: [A-scheduler, A-comment]
    unknown_reason: 어느 스케줄러가 실제로 배포돼 도는지는 태스크 정의가 정하며 그 정의의 운영 내용을 이 조사가 확보하지 않았다. 이미지에 굳은 값과 그것을 덮는 자리까지만 읽었다
    anchors:
      - insuniverse-server/apps/api/dockerfile:36
      - insuniverse-server/apps/api/dockerfile:38
      - insuniverse-server/apps/api/dockerfile:41
      - insuniverse-server/.github/workflows/api.yml:24
      - insuniverse-server/.github/workflows/api.yml:181
      - insuniverse-server/.github/workflows/api.yml:199
      - insuniverse-server/.github/workflows/api.yml:225
      - insuniverse-server/.github/workflows/api.yml:226
---

# 기능 게이트 — 무엇이 켜고 끄는가, 지금 켜져 있는지 알 수 있는가

이 문서는 **환경 설정 하나가 켜고 끄는 자리**만 다룬다. 한도의 수치는 앞 세 문서가 들고, 여기서
드는 것은 그 수치가 아니라 **그 자리가 지금 켜져 있는지를 이 저장소가 말할 수 있는가**다.

읽는 사람이 여기서 얻어야 하는 답은 둘이다.

**첫째, 운영에서 켜져 있는지는 대부분 이 문서로 알 수 없다.** 그것은 조사가 게을러서가 아니라
값이 있는 자리가 저장소 밖이기 때문이다. 배포는 환경마다 별도 설정 파일을 내려받아 컨테이너에
걸고, 그 파일은 세 저장소 어디에도 없다. **어디 있는지는 알고 값은 모른다** — 이 둘은 다르며,
이 문서는 앞엣것까지만 쓴다. 값을 받으면 그때 판정이 바뀐다.

**둘째, 알 수 없는 것과 알 수 있는 것이 섞여 있고 이 문서는 그 둘을 갈라 적는다.** 결제 벤더
자리는 스테이징 배포 자료를 이 저장소가 이미 수령해 정본 문서에 인용해 두었으므로 값이
확보돼 있다. 그래서 값이 확보된 항목만 본문에 있고 나머지는 부록에 있다. **전부를 부록으로 미는 문서는
확보된 것을 확보되지 않았다고 쓰는 것이고, 그것도 틀린 확신이다.**

세 갈래를 미리 밝힌다. **값이 확보된 자리**는 본문이고 게이트 활성으로 적되 운영 미확인 경고를
함께 단다. **운영값을 확보하지 못한 자리**는 부록이고 게이트 미상이다. **스캔 우주 밖에서
선언되는 자리**도 부록이고 게이트 미상이되 사유가 다르다 — 못 찾은 것이 아니라 찾는 자리의
바깥에 있는 것이며, 그 구별은 부록의 해당 항목이 직접 적는다.

각 게이트가 만드는 **의미**는 이 문서의 축이 아니다. 스케줄러가 실제로 무엇을 하는지는 일정
문서가, 공급자 편성의 결과는 공급자 문서가, 관리자 화면의 동작은 관리자 문서가 이미 들었다.
이 문서가 받는 것은 형제 문서들이 넘긴 것 — **게이트의 정의와 값 판정** — 뿐이다.

## 정책 (기획)

### gates:REACT_APP_SMARTRO_MODE

결제 화면이 벤더 위젯을 열 때 **어느 모드로 열지**를 이 자리가 정한다. 모드는 접속 비밀값이
아니라 벤더가 시험 처리와 실제 처리를 가르는 표시다.

**이 자리의 값은 확보돼 있다.** 스테이징 환경의 배포 자료를 이 저장소가 수령해 정본 문서에
인용해 두었고, 그 자료가 이 자리를 **결제 벤더 모드**로 분류하며 값이 시험 쪽을 가리킨다.
확보한 환경은 stg 하나다.

**그러나 운영에서 같은 값인지는 확인되지 않았다.** 두 환경은 서로 다른 배포 자료를 쓰고 이
조사는 그중 하나만 받았다. 그래서 표기는 정상이 아니라 **게이트 활성**이며, 운영 쪽이 다른
값일 가능성이 열려 있다. 값이 갈리면 같은 코드가 두 환경에서 다른 결제 경로로 간다.

이 자리가 비어 있으면 빈 모드가 그대로 벤더에게 넘어간다. 벤더가 빈 모드를 어떻게 읽는지는 이
문서가 판정하지 않는다 — 그 축은 공급자 문서 소관이다.

이용자에게 만드는 결과: 결제창이 어느 쪽 처리로 뜨는지가 이 한 자리에 걸린다.

### gates:REACT_APP_TOSS_CLIENT_KEY

같은 결제 화면이 다른 벤더의 위젯을 열 때 쓰는 **클라이언트 식별자**다. 이 값은 공개되는
식별자이며 서버 비밀값이 아니다.

**이 자리의 값도 확보돼 있다.** 같은 스테이징 배포 자료가 이 자리를 **테스트 키**로 분류하고
그 접두가 시험용임을 드러낸다. 확보한 환경은 stg 하나다.

**운영에서 같은 값인지는 역시 확인되지 않았다.** 표기는 **게이트 활성**이고 운영 미확인
경고가 함께 선다. 이 자리가 갈리면 결제가 실제 처리로 가는지 시험 처리로 가는지가 환경마다
달라진다 — 두 환경이 같다고 가정하고 읽으면 안 된다.

이 자리가 비어 있으면 빈 식별자로 위젯이 초기화된다. 그 결과는 벤더 쪽 동작이며 이 문서의 축이
아니다.

이용자에게 만드는 결과: 결제 수단 중 한 벤더의 창이 뜨는지 마는지가 이 한 자리에 걸린다.

## 강제 지점 (개발)

### gates:REACT_APP_SMARTRO_MODE

빌드 시점에 번들로 박히는 값이며 두 호출 자리가 같은 값을 읽는다. 읽는 자리마다 기본값이 병기돼
있어 미설정이 곧 빈 문자열이다.

- 기본값 `""` · 독출 형태 `기본값 병기` · 우선순위 `환경` · 미설정 동작 `분기 없음`
- 앵커 `insuniverse-site/front/src/pages/payment/PaymentPage.tsx:95`
- 앵커 `insuniverse-site/front/src/pages/payment/PaymentPage.tsx:199`

### gates:REACT_APP_TOSS_CLIENT_KEY

같은 빌드타임 주입이며 결제 훅 한 자리가 읽는다.

- 기본값 `""` · 독출 형태 `기본값 병기` · 우선순위 `환경` · 미설정 동작 `분기 없음`
- 앵커 `insuniverse-site/front/src/features/payment/hooks/usePayment.tsx:73`

### gates:ADMIN_VIEW_TOKEN_ENFORCE

관문이 값을 엄격 비교로 읽는다. 미설정이면 그 비교가 참이 되고 **참 쪽 가지가 통과시킨다** —
경고만 남기고 요청을 그대로 보낸다. 값이 정확히 참 표시일 때만 차단이 활성이다.

- 기본값 `—` · 독출 형태 `엄격 대조` · 우선순위 `환경` · 미설정 동작 `통과`
- 앵커 `insuniverse-server/apps/api/src/modules/admin-view-token/admin-view-token.guard.ts:49`

### gates:ADMIN_VIEW_TOKEN_TTL_MS

토큰 발급 서비스가 유효 기간을 읽는다. 기본값이 코드에 병기돼 있어 미설정이면 그 값이 쓰인다.

- 기본값 `600000` · 독출 형태 `기본값 병기` · 우선순위 `환경` · 미설정 동작 `기본값 대체`
- 앵커 `insuniverse-server/apps/api/src/modules/admin-view-token/admin-view-token.service.ts:25`

### gates:RATE_LIMIT_CERTIFY_PER_MIN

생성자가 분당 허용 횟수를 읽고 그 값을 필드에 묶는다. 미설정이면 병기된 기본값이 들어가고, 그
필드를 무는 관문 조건이 그 값에서 참이 되어 **아무것도 세지 않고 통과시킨다**. 기본값이 있는
자리인데도 결과는 통과다.

- 기본값 `0` · 독출 형태 `기본값 병기` · 우선순위 `환경` · 미설정 동작 `통과`
- 앵커 `insuniverse-server/apps/api/src/modules/treat/certify-rate-limit.guard.ts:31`

### gates:CAR_VIEW_ADMIN_IDS

허용목록 문자열을 읽어 집합으로 만든다. 미설정이면 병기된 빈 문자열이 들어가 **집합이 비고**,
그 집합을 무는 판정이 거짓이 되어 호출부가 예외를 던진다. **기본값이 있는데도 결과는 거부다** —
연산자만 보면 이 자리를 거꾸로 읽는다.

- 기본값 `''` · 독출 형태 `기본값 병기` · 우선순위 `환경` · 미설정 동작 `거부`
- 앵커 `insuniverse-server/apps/api/src/modules/auth/admin/car-view-admin.guard.ts:30`

### gates:DISEASE_PDF_HIDE_NAME_AGENCY_ID

기본값 병기 없이 그대로 읽어 수로 바꾼다. 미설정이면 수가 아니게 되고, 그 값을 무는 삼항 조건이
가림을 끄는 쪽을 고른다 — **가림이 걸리지 않은 채로 문서가 나간다**.

생성 인덱스가 이 게이트의 독출 자리를 다른 행으로 적는다. 동결 기준점의 그 행은 이 게이트와
무관한 인자 선언이며, 실제 독출은 아래 앵커다. 그 차이는 도달 판정까지 뒤집는다.

- 기본값 `—` · 독출 형태 `맨 독출` · 우선순위 `환경` · 미설정 동작 `통과`
- 앵커 `insuniverse-server/apps/api/src/modules/analyze/analyze.service.ts:1268`

### gates:TREAT_PROVIDER

설정 조립 자리에서 읽는다. 기본값이 병기돼 있고 그 값이 다음 층으로 그대로 넘어간다.

- 기본값 `'codef'` · 독출 형태 `기본값 병기` · 우선순위 `환경` · 미설정 동작 `기본값 대체`
- 앵커 `insuniverse-server/apps/api/src/config/configuration.ts:29`

### gates:TREAT_POOL

같은 자리에서 읽고 콤마와 콜론으로 나눠 공급자별 예산 목록을 만든다. 병기된 기본값 문자열이
콤마를 담고 있으므로 **첫 콤마에서 자르는 독법은 이 기본값의 절반만 읽는다**.

- 기본값 `'octover:30:3:1,coocon:30:3:1'` · 독출 형태 `기본값 병기` · 우선순위 `환경` · 미설정 동작 `기본값 대체`
- 앵커 `insuniverse-server/apps/api/src/config/configuration.ts:33`

### gates:ENABLE_TREAT_CAR

엄격 비교로 읽으며 기본값이 병기돼 있지 않다. 미설정이면 비교가 거짓이 되고 그 거짓이 다음 층으로
넘어간다. **같은 값을 저장소 설정에서 먼저 읽는 자리가 있고** 마이그레이션 선언이 그 설정이 이
환경 값을 대체한다고 적는다 — 그래서 우선순위가 두 칸이다.

- 기본값 `—` · 독출 형태 `엄격 대조` · 우선순위 `저장소 설정 → 환경` · 미설정 동작 `기본값 대체`
- 앵커 `insuniverse-server/apps/api/src/config/configuration.ts:47`

### gates:INHOUSE_CAR_CANARY

같은 형태다. 엄격 비교이고 기본값 병기가 없으며, 같은 저장소 설정 테이블의 다른 키가 이 자리보다
먼저 읽힌다.

- 기본값 `—` · 독출 형태 `엄격 대조` · 우선순위 `저장소 설정 → 환경` · 미설정 동작 `기본값 대체`
- 앵커 `insuniverse-server/apps/api/src/config/configuration.ts:83`

### gates:B2C_BYPASS_SLOT

설정 조립 자리에서 수로 바꿔 읽는다. 기본값이 병기돼 있어 미설정이면 그 수가 상한이 된다.

- 기본값 `2` · 독출 형태 `기본값 병기` · 우선순위 `환경` · 미설정 동작 `기본값 대체`
- 앵커 `insuniverse-server/apps/api/src/config/configuration.ts:164`

### gates:SETTLE_TARGET_DATE

정산 스케줄러가 시작할 때 읽는다. **기본값이 리터럴이 아니라 식이다** — 미설정이면 그 식이
전월 기준 날짜를 만든다. 리터럴만 뽑는 독법은 이 자리에서 빈 값을 내고, 그러면 기본값이 실재하는
게이트를 없음으로 적게 된다.

- 기본값 `dayjs().subtract(1, 'month').format('YYYY-MM-DD')` · 독출 형태 `기본값 병기` · 우선순위 `환경` · 미설정 동작 `기본값 대체`
- 앵커 `insuniverse-server/apps/api/src/schedules/settlement-agency.schedule.ts:28`

### gates:RUN_MODE

컨테이너 선언이 빌드 인자를 받아 이미지 환경 변수로 굳히고, 실행 명령이 그 값으로 갈라진다.
빌드 워크플로가 이 이름에 값을 넘기므로 **이미지에는 그 값이 박혀 있다**. 배포 단계는 태스크
정의의 환경 목록으로 같은 이름을 덮으므로 그쪽이 앞선다.

- 기본값 `api` · 독출 형태 `이미지 ENV 로 굳음` · 우선순위 `태스크 정의 주입 → 이미지 ENV` · 미설정 동작 `기본값 대체`
- 앵커 `insuniverse-server/apps/api/dockerfile:35`
- 앵커 `insuniverse-server/apps/api/dockerfile:37`
- 앵커 `insuniverse-server/apps/api/dockerfile:40`
- 앵커 `insuniverse-server/.github/workflows/api.yml:24`
- 앵커 `insuniverse-server/.github/workflows/api.yml:121`
- 앵커 `insuniverse-server/.github/workflows/api.yml:126`
- 앵커 `insuniverse-server/.github/workflows/api.yml:181`
- 앵커 `insuniverse-server/.github/workflows/api.yml:225`
- 앵커 `insuniverse-server/.github/workflows/api.yml:226`

### gates:SCHEDULER_TYPE

같은 컨테이너 선언이 이 이름도 빌드 인자로 받아 이미지 환경 변수로 굳힌다. **그런데 빌드
워크플로가 이 이름에는 값을 넘기지 않는다** — 앞 게이트와 갈리는 자리다. 인자에 기본값이 없으므로
이미지의 이 변수는 빈 문자열이고, 실행 명령의 분기표는 빈 값과 맞는 항목을 갖지 않아 **아무
일정도 실행되지 않는다**. 실제 값은 배포 단계의 태스크 정의 환경 목록이 넣는다.

- 기본값 `(빈 문자열)` · 독출 형태 `이미지 ENV 로 굳음` · 우선순위 `태스크 정의 주입 → 이미지 ENV` · 미설정 동작 `거부`
- 앵커 `insuniverse-server/apps/api/dockerfile:36`
- 앵커 `insuniverse-server/apps/api/dockerfile:38`
- 앵커 `insuniverse-server/apps/api/dockerfile:41`
- 앵커 `insuniverse-server/.github/workflows/api.yml:24`
- 앵커 `insuniverse-server/.github/workflows/api.yml:181`
- 앵커 `insuniverse-server/.github/workflows/api.yml:199`
- 앵커 `insuniverse-server/.github/workflows/api.yml:225`
- 앵커 `insuniverse-server/.github/workflows/api.yml:226`

## 적용 범위 (actor × 서비스)

| 정책 id | 관리자 | 영업대리점 | 기업담당자 | 일반회원 | 기업회원 | server | site | admin |
|---|---|---|---|---|---|---|---|---|
| gates:REACT_APP_SMARTRO_MODE | — | — | 적용 | 적용 | 적용 | — | 강제 지점 | — |
| gates:REACT_APP_TOSS_CLIENT_KEY | — | — | 적용 | 적용 | 적용 | — | 강제 지점 | — |
| gates:ADMIN_VIEW_TOKEN_ENFORCE | 적용 | — | 적용 | — | — | 강제 지점 | — | — |
| gates:ADMIN_VIEW_TOKEN_TTL_MS | 적용 | — | 적용 | — | — | 강제 지점 | — | — |
| gates:RATE_LIMIT_CERTIFY_PER_MIN | — | — | 적용 | 적용 | 적용 | 강제 지점 | — | — |
| gates:CAR_VIEW_ADMIN_IDS | 적용 | — | 미적용 | — | — | 강제 지점 | — | — |
| gates:DISEASE_PDF_HIDE_NAME_AGENCY_ID | 적용 | — | 적용 | 적용 | 적용 | 강제 지점 | — | — |
| gates:TREAT_PROVIDER | 적용 | 적용 | 적용 | 적용 | 적용 | 강제 지점 | — | — |
| gates:TREAT_POOL | 적용 | 적용 | 적용 | 적용 | 적용 | 강제 지점 | — | — |
| gates:ENABLE_TREAT_CAR | 적용 | 적용 | 적용 | 적용 | 적용 | 강제 지점 | — | — |
| gates:INHOUSE_CAR_CANARY | 적용 | 적용 | 적용 | 적용 | 적용 | 강제 지점 | — | — |
| gates:B2C_BYPASS_SLOT | — | — | 적용 | — | — | 강제 지점 | — | — |
| gates:SETTLE_TARGET_DATE | 적용 | 적용 | — | — | — | 강제 지점 | — | — |
| gates:RUN_MODE | 적용 | 적용 | 적용 | 적용 | 적용 | 강제 지점 | — | — |
| gates:SCHEDULER_TYPE | 적용 | 적용 | 적용 | 적용 | 적용 | 강제 지점 | — | — |

`적용` = 그 actor 의 요청이 이 게이트의 판정을 지난다. `미적용` = 경로에는 등장하나 그 역할이
판정에 걸리지 않고 앞에서 갈라져 나간다. `—` = 그 actor 가 이 게이트의 경로에 등장하지 않는다.

서비스 열은 기계가 대조한다 — 각 정책의 앵커가 어느 저장소를 가리키는지에서 다시 만든 값과
같아야 한다. 이 표에서 읽어야 하는 것은 **결제 자리만 화면 쪽이고 나머지 전부가 서버 쪽**
이라는 사실이다. 화면 쪽 자리는 빌드 시점에 번들로 박히므로 서버가 그 값을 다시 확인하는 자리가
없다.

actor 열은 대조 밖이다. 권한 모델을 동결 트리에서 되짚을 경로가 이 조사에 없다. `미적용` 한 칸은
그 예외다 — 동결 소스가 그 역할을 허용목록 독출보다 앞에서 되돌려 보내는 것을 읽어 적었고,
같은 사실을 부록의 해당 항목이 서술로도 든다. 나머지 칸은 그 대조를 받지 않았다.

## 예외·폴백

| 정책 id | 예외 조건 | 폴백 동작 | 확인 근거 |
|---|---|---|---|
| gates:REACT_APP_SMARTRO_MODE | 빌드에 값이 없음 | 빈 모드가 벤더 위젯으로 그대로 넘어간다 | `PaymentPage.tsx:95` |
| gates:REACT_APP_SMARTRO_MODE | 두 환경의 값이 다름 | 같은 코드가 환경마다 다른 결제 경로로 간다. 이 문서는 한 환경만 확보했다 | `PaymentPage.tsx:199` |
| gates:REACT_APP_TOSS_CLIENT_KEY | 빌드에 값이 없음 | 빈 식별자로 위젯이 초기화된다 | `usePayment.tsx:73` |
| gates:REACT_APP_TOSS_CLIENT_KEY | 시험용 접두가 운영 번들에 박힘 | 운영 결제가 시험 처리로 간다. 확보한 값은 스테이징 것뿐이다 | `usePayment.tsx:73` |
| gates:ADMIN_VIEW_TOKEN_ENFORCE | 미설정 | 관문이 경고만 남기고 통과시킨다 | `admin-view-token.guard.ts:49` |
| gates:ADMIN_VIEW_TOKEN_ENFORCE | 참 표시가 아닌 다른 값 | 미설정과 같다. 정확히 참 표시일 때만 차단이 선다 | `admin-view-token.guard.ts:49` |
| gates:ADMIN_VIEW_TOKEN_TTL_MS | 미설정 | 코드에 병기된 기간이 쓰인다 | `admin-view-token.service.ts:25` |
| gates:ADMIN_VIEW_TOKEN_TTL_MS | 수가 아닌 값 | 기간 계산이 수가 아니게 되고 그 결과는 이 문서가 판정하지 않는다 | `admin-view-token.service.ts:25` |
| gates:RATE_LIMIT_CERTIFY_PER_MIN | 미설정 | 세지 않고 통과시킨다. 동작이 켜기 전과 같다 | `certify-rate-limit.guard.ts:31` |
| gates:RATE_LIMIT_CERTIFY_PER_MIN | 0 이하 | 미설정과 같다. 관문 조건이 그 값에서 참이 되어 그 자리에서 통과시킨다 | `certify-rate-limit.guard.ts:31` |
| gates:RATE_LIMIT_CERTIFY_PER_MIN | 수가 아닌 값 | 관문 조건이 참이 되지 않는다 — 수가 아닌 값은 0 이하 비교가 거짓이기 때문이다. 캐시 저장소 연결이 있으면 카운터 증가와 만료 설정까지 실행되고 임계 비교만 성립하지 않아 결과적으로 막지 않는다. 최종 결과는 미설정과 같으나 실행 경로가 다르다 | `certify-rate-limit.guard.ts:31` |
| gates:RATE_LIMIT_CERTIFY_PER_MIN | 0 과 1 사이의 값 · 세는 자리가 정상일 때 | 값을 정수로 만들거나 범위를 좁히는 자리가 없다. 카운터는 첫 요청에서 1 이 되고 그 수가 이미 한도를 넘으므로 **그 조건에서는 모든 요청이 막힌다** — 켜는 값처럼 보이지만 전면 차단이다. 세는 자리가 정상이 아니면 아래 행이 이긴다 | `certify-rate-limit.guard.ts:51` |
| gates:RATE_LIMIT_CERTIFY_PER_MIN | 유한하지 않은 크기의 값 | 같은 자리에서 어떤 유한 카운터도 한도를 넘지 못한다. 세기는 하되 **한 번도 막지 않는다** | `certify-rate-limit.guard.ts:51` |
| gates:RATE_LIMIT_CERTIFY_PER_MIN | 세는 자리의 연산이 실패 | 넘침 차단만 위로 다시 던지고 나머지 예외는 삼켜 그 요청을 통과시킨다 — 값이 무엇이든 그 요청은 막히지 않는다. **이 행이 위의 값 조건들을 덮는다**: 앞 행들은 세는 자리가 정상일 때의 서술이다 | `certify-rate-limit.guard.ts:60` |
| gates:RATE_LIMIT_CERTIFY_PER_MIN | 카운터 증가는 성공하고 기간 설정이 실패 | 그 요청은 위 행대로 통과하지만 **카운터가 기간 없이 남는다.** 기간은 카운터가 처음일 때만 걸리므로 다시 걸리지 않고, 자리가 정상으로 돌아와도 줄지 않는다 — 유한한 양수 한도에서는 그 식별자의 요청이 결국 계속 막힌다. 통과와 굳음이 같은 실패에서 나온다 | `certify-rate-limit.guard.ts:50` |
| gates:RATE_LIMIT_CERTIFY_PER_MIN | 캐시 저장소 연결 설정 없음 | 이 자리에 양수가 있어도 세지 않고 통과시킨다. 같은 판정의 두 번째 항이며 이 게이트 밖 설정이 정한다 | `certify-rate-limit.guard.ts:35` |
| gates:RATE_LIMIT_CERTIFY_PER_MIN | 요청에서 식별자를 만들지 못함 | 그 요청은 세지 않고 지나간다. 관문이 켜져 있어도 그렇다 | `certify-rate-limit.guard.ts:46` |
| gates:CAR_VIEW_ADMIN_IDS | 미설정 | 허용목록이 비어 최고관리자 역할이 거절된다 | `car-view-admin.guard.ts:30` |
| gates:CAR_VIEW_ADMIN_IDS | 목록에 없는 식별자만 들어 있음 | 미설정과 같다. 해당 역할이 거절된다 | `car-view-admin.guard.ts:30` |
| gates:DISEASE_PDF_HIDE_NAME_AGENCY_ID | 미설정 | 가림이 걸리지 않고 문서가 그대로 나간다 | `analyze.service.ts:1268` |
| gates:DISEASE_PDF_HIDE_NAME_AGENCY_ID | 정수가 아니거나 0 이하 | 미설정과 같다. 조건이 가림을 끄는 쪽을 고른다 | `analyze.service.ts:1268` |
| gates:TREAT_PROVIDER | 미설정 | 병기된 공급자가 쓰인다 | `configuration.ts:29` |
| gates:TREAT_PROVIDER | 허용 목록에 없는 이름 | 이 자리는 값을 그대로 넘긴다. 그 뒤 판정은 공급자 문서가 든다 | `configuration.ts:29` |
| gates:TREAT_POOL | 미설정 | 병기된 두 공급자 편성이 쓰인다 | `configuration.ts:33` |
| gates:TREAT_POOL | 항목 형식이 아님 | 자리마다 폴백 수가 쓰인다. 값은 이 문서가 적지 않는다 | `configuration.ts:33` |
| gates:ENABLE_TREAT_CAR | 미설정 | 비교가 거짓이 되어 그 값이 다음 층으로 넘어간다 | `configuration.ts:47` |
| gates:ENABLE_TREAT_CAR | 저장소 설정에 행이 있음 | 그쪽이 먼저 읽히고 환경 값은 폴백으로 내려간다 | `configuration.ts:47` |
| gates:ENABLE_TREAT_CAR | 이 게이트가 켜져 있고 카나리 게이트가 꺼져 있음 | **두 자리가 같은 물음에 답하지 않는다.** 관리 화면이 부르는 자리는 이 게이트만 읽어 켜짐을 내고, 진료 편성이 부르는 자리는 이 게이트와 카나리 게이트가 **둘 다 켜졌을 때만** 켜짐을 낸다. 장애가 없어도 갈린다 | `treat-provider.service.ts:130` · `treat-provider.service.ts:148` |
| gates:ENABLE_TREAT_CAR | 저장소 조회가 실패 | 관리 화면 쪽은 환경 값으로 되돌아가고, 진료 편성 쪽은 **두 설정 중 어느 것을 읽다 실패했든** 꺼짐을 낸다. 그래서 환경 값이 명시적으로 켜는 값이거나 앞 행의 조합이면 화면이 켜짐으로 보고하는 동안 실제 경로가 닫혀 있다 | `treat-provider.service.ts:119` · `treat-provider.service.ts:153` |
| gates:INHOUSE_CAR_CANARY | 미설정 | 비교가 거짓이 되어 그 값이 다음 층으로 넘어간다 | `configuration.ts:83` |
| gates:INHOUSE_CAR_CANARY | 저장소 설정에 행이 있음 | 그쪽이 먼저 읽히고 환경 값은 폴백으로 내려간다 | `configuration.ts:83` |
| gates:B2C_BYPASS_SLOT | 미설정 | 병기된 수가 동시 슬롯 상한이 된다 | `configuration.ts:164` |
| gates:B2C_BYPASS_SLOT | 수가 아닌 값 | 상한 계산이 수가 아니게 되고 그 결과는 이 문서가 판정하지 않는다 | `configuration.ts:164` |
| gates:SETTLE_TARGET_DATE | 미설정 | 병기된 식이 전월 기준 날짜를 만든다 | `settlement-agency.schedule.ts:28` |
| gates:SETTLE_TARGET_DATE | 날짜 형식이 아닌 값 | 그 값이 그대로 집계 기준으로 넘어간다. 형식 검사 자리를 찾지 못했다 | `settlement-agency.schedule.ts:28` |
| gates:RUN_MODE | 태스크 정의가 덮지 않음 | 이미지에 굳은 값으로 뜬다 | `apps/api/dockerfile:37` |
| gates:RUN_MODE | 분기표에 없는 값 | 실행 명령의 else 쪽으로 가서 API 프로세스가 뜬다 | `apps/api/dockerfile:40` |
| gates:SCHEDULER_TYPE | 태스크 정의가 덮지 않음 | 이미지의 이 변수는 빈 문자열이다. 빌드 인자가 이 이름을 넘기지 않는다 | `.github/workflows/api.yml:126` |
| gates:SCHEDULER_TYPE | 분기표에 없는 값 | 어느 항목과도 맞지 않아 아무 일정도 실행되지 않는다 | `apps/api/dockerfile:41` |

`찾지 못했다` 와 `검사하지 않는다` 는 다르다. 앞엣것은 볼 수단을 확보하지 못했다는 뜻이고
뒤엣것은 보았고 그 자리가 없음을 확인했다는 뜻이다.

## 부록

이 절의 정책은 전부 **게이트 미상**이며 사유가 갈린다. 한쪽은 **운영에서 어떤 값이 들어가는지
확보하지 못했고**, 다른 쪽은 **이 축의 스캔 우주 밖에서 선언된다**. 앞엣것과 뒤엣것은 사유가
다르고 그 차이를 각 항목이 직접 적는다. 어느 항목이 어느 쪽에 드는지도 그 항목이 든다 — 각
쪽의 크기는 이 문면이 아니라 정본 파일이 정한다.

**미확보의 공통 사유는 같다.** 배포는 환경마다 별도 설정 파일을 내려받아 컨테이너에 걸고, 그
파일은 이 조사가 든 저장소 어디에도 없다. 그래서 아래 항목마다 반복해 적는 것은 그 공통 사유가 아니라 **그
게이트가 무엇을 갈라놓는가**다.

미확보 쪽 일부에는 한 가지가 더 있다 — **읽는 코드가 아직 운영에 닿지 않았다.** 그 사실은 표기가
아니라 한계 기록이 든다. 이 저장소의 규칙에서 게이트가 걸린 정책의 표기는 값의 확보 여부가 정하고
도달 여부는 별개 축이기 때문이며, 살아 있는 형제 문서도 같은 형태로 쓰고 있다.

### gates:ADMIN_VIEW_TOKEN_ENFORCE

관리자가 다른 화면을 대신 열어 볼 때 쓰는 토큰을 **강제로 검증할지**를 이 자리가 가른다.
꺼져 있으면 토큰이 없거나 틀려도 요청이 통과하고 경고만 남는다. 켜면 그 요청이 막힌다.

무중단 전환을 위해 일부러 이렇게 만든 자리다 — 코드를 먼저 배포해 놓고, 화면들이 토큰을 실제로
싣는지 운영에서 확인한 뒤에 켜는 순서다. 그래서 **꺼져 있는 상태 자체는 결함이 아니다.**

**지금 켜져 있는지는 이 문서가 답하지 못한다.** 세 가지 중 코드상 기본 동작과 값이 없을 때의
동작은 확보했고, 운영에서의 활성 여부는 확보하지 못했다. 값은 환경별 배포 자료에 있다.

이용자에게 만드는 결과: 꺼져 있는 동안은 남의 분석 화면을 여는 요청이 토큰 없이도 지나갈 수
있다. 켜지면 그 경로가 닫힌다.

### gates:ADMIN_VIEW_TOKEN_TTL_MS

같은 토큰이 **얼마 동안 유효한지**를 이 자리가 정한다. 짧으면 링크가 금방 죽고 길면 유출된
링크가 오래 산다.

코드에는 값이 없을 때 쓰는 기간이 병기돼 있고 그것은 확보했다. 운영이 그 자리를 다른 수로 덮고
있는지는 확보하지 못했다 — **덮여 있으면 실제 유효 기간은 코드가 적은 것과 다르다.**

이용자에게 만드는 결과: 대신 열어 보기 링크가 언제 죽는지가 이 한 자리에 걸린다.

### gates:RATE_LIMIT_CERTIFY_PER_MIN

인증 요청을 **분당 몇 번까지 받을지**를 이 자리가 정한다. 값이 양수가 아니면 관문은 결과적으로
아무것도 막지 않는다 — **다만 그 경로가 한 갈래가 아니다.** 0 이하이면 관문 조건이 그 자리에서
참이 되어 곧바로 지나보내고, 수가 아닌 값이면 그 조건이 참이 되지 않아 세는 코드까지 들어간 뒤
임계 비교만 성립하지 않는다. 결과가 같다고 실행 경로가 같지는 않으며, 이 문서는 그 차이를 판정
없이 사실로 적는다.

**양수 쪽도 한 갈래가 아니다.** 이 자리는 값을 정수로 만들거나 범위를 좁히지 않고 그대로 비교에
쓴다. 그래서 0 과 1 사이의 값은 첫 요청부터 한도를 넘겨 **전면 차단**이 되고, 유한하지 않은 크기의
값은 어떤 카운터로도 한도에 닿지 못해 **한 번도 막지 않는다**. 둘 다 운영자가 보기에는 그저 양수를
넣은 것이고, 설정 문서로 이 문서를 읽는 사람에게는 그 차이가 보이지 않는다. 고쳐야 하는지는 이
문서가 판정하지 않는다 — 코드 수정은 이 조사의 범위 밖이고, 여기서는 사실만 든다.

**앞의 값 서술은 전부 세는 자리가 정상일 때의 것이다.** 세는 동안 그 자리의 연산이 실패하면 넘침
차단만 위로 다시 던지고 나머지 예외는 삼켜 그 요청을 통과시킨다. 값이 무엇이든 **그 요청은** 막히지
않는다는 뜻이다. 값 축과 장애 축은 따로이며 뒤엣것이 앞엣것을 덮는다.

**다만 그 통과가 장애 전체를 열어 두는 것은 아니다.** 세는 일은 증가와 기간 설정 둘로 나뉘어 있고
기간 설정은 카운터가 처음 만들어질 때만 걸린다. 증가는 성공하고 기간 설정이 실패하면 그 요청은
위 규칙대로 통과하지만 **카운터는 기간 없이 남는다.** 그 뒤로는 카운터가 처음이 아니므로 기간이
다시 걸리지 않고, 자리가 정상으로 돌아온 뒤에도 그 카운터는 줄지 않는다 — 유한한 양수 한도라면
그 식별자의 요청은 결국 계속 막힌다. 그러니 이 자리의 장애는 한 방향이 아니다: 실패한 그 요청은
통과하지만, 실패가 남긴 상태는 반대로 굳는다.

코드상 기본은 세지 않는 쪽이며 그것은 확보했다. 운영이 양수를 넣어 두었는지는 확보하지 못했다 —
**넣지 않았다면 이 한도는 존재하지 않는 것과 같다.**

**이 자리 말고 관문을 끄는 조건이 하나 더 있다.** 같은 판정이 캐시 저장소 연결을 함께 묻고, 그
연결 설정이 없으면 이 자리에 양수가 들어 있어도 관문은 아무것도 세지 않는다. 그 연결 설정은 이
문서가 다루는 게이트 집합 밖이라 정책으로 서지 않는다 — 그러나 *지금 세고 있는가* 의 답이 이 자리
하나로 정해지지 않는다는 사실은 여기서 든다. 뒤이어 요청에서 식별자를 만들지 못하는 경우에도 그
요청은 세지 않고 지나간다.

이용자에게 만드는 결과: 켜져 있고 넘기면 요청이 많다는 안내를 받는다. 꺼져 있으면 아무 안내도
없고 그 사실은 화면에 드러나지 않는다.

### gates:CAR_VIEW_ADMIN_IDS

자동차 분석 원문을 **어느 관리자가 열람할 수 있는지**를 이 자리가 정한다. 목록에 실린 식별자만
통과한다.

코드상 기본은 빈 목록이고, 빈 목록이면 최고관리자 역할이 **거절**된다 — 기본값이 병기돼 있는데도
결과는 막는 쪽이다. 기업 쪽 역할은 그 앞에서 이미 갈라져 나가므로 이 자리의 적용을 받지 않는다.
운영이 어떤 목록을 넣었는지는 확보하지 못했다.

이용자에게 만드는 결과: 목록이 비어 있으면 최고관리자가 자동차 분석 원문을 열지 못한다.

### gates:DISEASE_PDF_HIDE_NAME_AGENCY_ID

병명예측 문서에서 **어느 기업의 건에 환자명을 가릴지**를 이 자리가 정한다. 기업 코드가 아니라
환경마다 바뀌지 않는 식별자로 지정한다.

코드상 기본은 없고, 값이 수가 아니거나 0 이하면 가림이 아예 걸리지 않는다 — **가려지지 않은
문서가 나간다는 뜻이다.** 운영이 어떤 식별자를 넣었는지는 확보하지 못했다.

이 게이트에는 관측이 하나 더 있다. 생성된 색인이 이 게이트를 읽는 자리를 **다른 행으로 적는다.**
동결 기준점의 그 행은 이 게이트와 무관한 인자 선언이다. 색인을 그대로 베끼면 문서가 존재하지 않는
자리를 가리키고, 그 행에 걸린 도달 판정까지 뒤집힌다. 이 관측은 판단 없이 사실로만 남긴다 —
색인을 고치는 것은 다른 축의 몫이다.

이용자에게 만드는 결과: 대상 기업의 환자명이 문서에서 가려지는지 마는지가 이 한 자리에 걸린다.

### gates:TREAT_PROVIDER

진료내역을 **어느 공급자로 모을지**를 이 자리가 정한다. 하나를 고르거나 분산 모드를 켤 수 있다.

코드상 기본 공급자는 병기돼 있고 그것은 확보했다. 운영이 어느 공급자를 쓰는지는 확보하지 못했다.
공급자마다 무엇이 달라지는지는 이 문서의 축이 아니다 — 공급자 문서가 이미 그 축을 들었다.

이용자에게 만드는 결과: 같은 요청이 어느 바깥 서비스로 나가는지가 이 한 자리에 걸린다.

### gates:TREAT_POOL

분산 모드일 때 **어느 공급자를 어떤 예산으로 묶을지**를 이 자리가 정한다. 항목마다 네 자리가
있고 각 자리는 이름과 한도와 비용을 뜻한다.

코드상 기본 편성은 병기돼 있고 그것은 확보했다. 그 문자열은 콤마를 담고 있어 첫 콤마에서 자르면
편성의 절반만 읽게 된다. 운영이 어떤 편성을 넣었는지는 확보하지 못했다. 각 자리의 수와 그
해석은 한도 문서가 이미 들었다.

이용자에게 만드는 결과: 분산 모드에서 어느 공급자에 얼마나 몰리는지가 이 한 자리에 걸린다.

### gates:ENABLE_TREAT_CAR

자동차보험 진료 수집을 **통째로 켜고 끄는** 자리다.

이 자리에는 층이 둘이다. **저장소 설정이 먼저 읽히고 환경 값은 그 뒤다.** 마이그레이션 선언이
그 설정이 이 환경 값을 대체한다고 적고, 재배포 없이 즉시 막고 풀기 위한 것이라고 밝힌다.
그래서 환경 값을 안다고 해서 지금 켜져 있는지가 정해지지 않는다 — 저장소 쪽 값을 함께 봐야
하고 이 조사는 그것도 확보하지 않았다.

코드상 기본은 명시적으로 켜는 값일 때만 켜지는 쪽이다. 운영값은 두 층 모두 확보하지 못했다.

**그런데 이 자리를 읽는 코드가 하나가 아니고, 둘은 애초에 같은 물음에 답하지 않는다.** 관리
화면에 지금 상태를 보여 주는 자리는 **이 게이트만** 읽는다. 진료 편성이 실제로 묻는 자리는 이
게이트가 켜졌는지를 먼저 보고, 켜졌으면 이어서 카나리 게이트까지 읽어 **둘 다 켜졌을 때만**
켜짐을 낸다. 그래서 이 게이트가 켜져 있고 카나리가 꺼져 있으면 장애가 하나도 없어도 화면은
켜짐, 실제 경로는 꺼짐이다.

**장애가 얹히면 그 위에 한 겹이 더 붙는다.** 앞엣것은 저장소 조회가 실패하면 환경 값으로
되돌아간다. 뒤엣것은 두 설정 중 어느 것을 읽다 실패했든 하나의 처리로 꺼짐을 낸다 — 앞 게이트를
읽다 실패했을 때뿐 아니라 **앞 게이트는 켜짐으로 읽힌 뒤 카나리를 읽다 실패했을 때도** 그렇다.

**이것을 결함으로 판정하지 않는다.** 두 물음 중 어느 쪽이 *지금 켜져 있는가* 의 옳은 답인지는 이
조사가 정할 자리가 아니고, 두 게이트를 곱해 얻는 편성의 의미는 이 문서의 축도 아니다. 여기서 드는
것은 **화면이 답하는 물음과 실제 경로가 답하는 물음이 다르고, 장애가 그 차이를 한 방향으로 더
벌린다**는 사실뿐이다. 이 문서를 상태 조회의 근거로 쓰는 사람에게 필요한 것이 그것이다.

이용자에게 만드는 결과: 자동차보험 진료가 수집되는지 마는지가 이 두 층에 걸린다.

### gates:INHOUSE_CAR_CANARY

자체 엔진으로 자동차 건을 **일부만 흘려보는 카나리**를 켜는 자리다.

앞 항목과 같은 두 층 구조다. 같은 저장소 설정 테이블의 다른 키가 먼저 읽히고 환경 값은 그 뒤다.
코드상 기본은 꺼짐이며, 운영값은 두 층 모두 확보하지 못했다.

이용자에게 만드는 결과: 자동차 건 일부가 자체 엔진으로 가는지가 이 두 층에 걸린다.

### gates:B2C_BYPASS_SLOT

외부 서비스가 이 시스템을 거쳐 진료를 모을 때 **동시에 몇 자리까지 쓸 수 있는지**를 정한다.
자리 수는 외부 서비스마다 따로 센다.

코드상 기본 상한은 병기돼 있고 그것은 확보했다. 운영이 그 수를 덮고 있는지는 확보하지 못했다.

이용자에게 만드는 결과: 외부 서비스 쪽 요청이 몰릴 때 얼마나 동시에 처리되는지가 이 한 자리에
걸린다.

### gates:SETTLE_TARGET_DATE

대리점 정산을 **어느 날짜 기준으로 돌릴지**를 정한다. 선언 자리의 주석이 이 자리를 로컬과 수동
시험용으로 한정하고, 운영 기본은 전월 기준이라고 적는다.

**코드상 기본은 리터럴이 아니라 식이다** — 값이 없을 때 그 식이 전월 기준 날짜를 만든다. 값만
뽑는 독법은 이 자리에서 빈 값을 내고, 그러면 기본이 실재하는 자리를 없다고 적게 된다. 이 문서는
그 식을 그대로 든다.

운영이 이 자리를 설정해 두었는지는 확보하지 못했다. 설정돼 있으면 정산이 전월이 아닌 다른 구간을
집계한다.

이용자에게 만드는 결과: 대리점 정산이 어느 달을 대상으로 도는지가 이 한 자리에 걸린다.

### gates:RUN_MODE

컨테이너가 **어느 실행 모드로 뜰지**를 정한다. 하나는 요청을 받는 프로세스이고 다른 하나는
일정 프로세스다.

**이 자리는 스캔 우주 밖에 있다.** 이 축의 스캔 우주는 추출 명세의 src_roots 가 정하는 소스
뿌리 아래의 타입스크립트 파일이고, 이 게이트는 그 안에서 선언되지도 읽히지도 않는다. 선언은
컨테이너 이미지 선언과 배포 워크플로에 있으며 **동결 기준점에서 실재를 확인했다.** 못 찾은 것이
아니라 찾는 자리의 바깥에 있는 것이며, 그 둘은 다르다.

층이 둘이다. 빌드가 이 이름에 값을 넘겨 이미지에 굳히고, 배포가 태스크 정의의 환경 목록으로
같은 이름을 덮는다. **이미지에 굳은 값은 기본값이지 운영값이 아니다.** 운영에서 어느 값이 실제로
걸리는지는 태스크 정의의 내용이 정하고 이 조사는 그것을 확보하지 않았다.

이용자에게 만드는 결과: 같은 이미지가 요청을 받는 프로세스로 뜨는지 일정 프로세스로 뜨는지가
이 자리에 걸린다.

### gates:SCHEDULER_TYPE

일정 프로세스로 뜬 컨테이너가 **어느 일정을 돌릴지**를 고른다. 실행 명령에 분기표가 있고
항목마다 다른 일정이 걸려 있다.

**이 자리도 스캔 우주 밖에 있다.** 앞 항목과 같은 이유다 — 스캔 우주는 추출 명세의 src_roots
아래 타입스크립트 파일이고 이 게이트의 선언은 컨테이너 이미지 선언과 배포 워크플로에 있다.
동결 기준점에서 그 실재를 확인했다. 결손이 아니라 우주 밖이다.

**앞 게이트와 갈리는 자리가 하나 있다.** 빌드는 앞 게이트에는 값을 넘기지만 이 이름에는 넘기지
않는다. 인자에 기본이 없으므로 이미지의 이 변수는 빈 문자열이고, 빈 값은 분기표의 어느 항목과도
맞지 않아 **아무 일정도 실행되지 않는다.** 즉 실제 값은 오로지 배포 단계가 넣으며, 그 내용을 이
조사는 확보하지 않았다. 두 게이트를 같은 경로로 묶어 읽으면 이 자리에 없는 기본값을 지어내게
된다.

이용자에게 만드는 결과: 어떤 정기 작업이 실제로 도는지가 이 자리에 걸리고, 그 답은 이 저장소가
아니라 배포 정의에 있다.

## 연혁

릴리스 태그가 존재하지 않는다. 릴리스 열은 `—` 로 두고 커밋으로 추적한다. 아래 SHA 는 동결
기준점에서 그 게이트의 독출 자리를 마지막으로 고친 커밋이며, **그 커밋이 그 게이트를 처음 들여온
것인지는 이 문서가 판정하지 않는다.**

| 릴리스 | 날짜 | SHA | 변경 요약 |
|---|---|---|---|
| — | 2024-11-19 | `9270738f` | 결제 클라이언트 키를 읽는 화면 훅 파일이 들어왔다 |
| — | 2024-12-16 | `c67fdf2f` | 스케줄러용 태스크 정의 배포가 생기며 실행 모드 인자가 들어왔다 |
| — | 2024-12-16 | `ae2be62c` | 스케줄 태스크 리팩터링으로 일정 종류 변수와 실행 명령 분기표가 자리 잡았다 |
| — | 2024-12-16 | `6ebfd552` | 실행 모드 변수를 이미지에 굳히는 행이 지금 형태가 됐다 |
| — | 2026-02-03 | `5e5bfdcb` | 결제 벤더 모드가 환경 변수로 빠졌다 |
| — | 2026-06-04 | `21b4a602` | 진료내역 공급자 스위치가 들어왔다 |
| — | 2026-06-05 | `af16d981` | 분산 공급자 풀 편성 문자열이 들어왔다 |
| — | 2026-06-07 | `03850ef0` | 빌드 캐시 정리로 실행 모드 값을 빌드 인자로 넘기는 자리가 지금 형태가 됐다 |
| — | 2026-06-07 | `71d3a4e5` | 배포 워크플로 통합으로 두 실행 변수를 태스크 정의에 주입하는 자리가 생겼다 |
| — | 2026-06-30 | `eed6bf4f` | 외부 서비스 바이패스의 동시 슬롯 상한이 들어왔다 |
| — | 2026-07-01 | `55c4eaac` | 관리자 열람 토큰의 강제 게이트와 유효 기간이 함께 들어왔다 |
| — | 2026-07-01 | `31f4f8f3` | 인증 요청 분당 관문이 기본 꺼짐으로 들어왔다 |
| — | 2026-07-11 | `d4513a79` | 대리점 정산 기준일 자리가 들어왔다 |
| — | 2026-07-20 | `f0038eb9` | 자동차 분석 열람 허용목록이 들어왔다 |
| — | 2026-07-20 | `8cc3230c` | 자동차 수집 활성과 자체엔진 카나리 두 자리가 함께 들어왔다 |
| — | 2026-07-24 | `9d3ccff7` | 병명예측 문서의 환자명 가림 대상 지정이 들어왔다 |
