# 07 · 사용자 제공 용어·정책 정리 ↔ 워크플로 산출물 대조 (2026-08-11)

> **성격**: 사실 대조. 규약도 결정도 아니다. `05-final-spec.md` 를 대체하지 않는다.
> **입력**: 사용자가 2026-08-11 제공한 "보험유니버스(보유) 정책 정리 (개인용)" 전문.
> **대조 대상**: `docs/_meta/index/**`(인덱스 축 산출물) · `.claude/meta/01~06` · `.claude/prds/**` · 3저장소 HEAD.
> **기준점**: server `4d798f55` · site `767d1e44` · admin `fb001e1d`(manifest `repos[].head`) + admin worktree HEAD `7df733a5`.
> **원인 분석은 여기 없다** — `08-operational-blindspot-causes.md`. 개선안은 `09-operational-knowledge-remediation.md`.

---

## 0. 결론 요약

| 판정 | 건수 | 의미 |
|---|---|---|
| 코드에서 도출 가능 + 사용자 서술과 일치 | 17 | 파이프라인이 **아직 안 만든 것**이지 못 만드는 것이 아니다 |
| 코드가 사용자보다 정밀 | 4 | 문서가 사용자에게 되돌려줄 수 있는 항목 |
| 코드와 사용자 서술이 어긋남 | 2 | 어느 쪽이 맞는지 별도 판정 필요 |
| 코드에서 원리적으로 도출 불가 | 6 | 사용자 구술이 **유일 소스**. 이 축은 파이프라인이 설계상 없다 |

**핵심**: 사용자 글의 용어층(23항목 중 21)은 저장소에서 기계 도출 가능하다. 도출 불가는 전부
**History 절**(창업 경위·수익 분배·법적 지연)과 **GA** 하나다. 그럼에도 워크플로가 이 문서를 못 낸
이유는 도출 능력의 부재가 아니라 **규약이 그 층을 배제하도록 설계돼 있기 때문**이다(→ `08`).

---

## 1. 항목별 대조표

`도출` = 3저장소 HEAD 만으로 기계 도출 가능한가. `포착` = 현재 파이프라인 산출물이 실제로 담고 있는가.

### 1-1. 서비스 정의 · 가치정보

| 사용자 서술 | 도출 | 포착 | 근거 / 판정 |
|---|---|---|---|
| "고객의 진료정보를 수집해서 제공하는 서비스" | O | **X** | `modules/treat`(수집) · `modules/analyze`(가공) · `modules/disease`(기준) 구조로 도출 가능. **docs 트리 50문서 중 서비스 정의를 담는 문서가 없다** (`05-final-spec.md` §4) |
| "모든 데이터를 정규화된 분석 가능한 형태로 가공" | O | 부분 | `analyze.service.ts` · `clinical-result` · `medication-standard` 모듈. `30-contracts-limits` 가 계약·스키마로만 다루고 **가공이 곧 상품가치라는 서술 자리는 없다** |
| "제공 단위: 채널, 기업, 고객사" | O | **X** | 3표면 전부 코드 실재 — `modules/sales-agency/channel` · `modules/agency`+corp · `modules/client`. **문서 구조는 actor 3분할(admin/sales/corp)뿐이고 제공단위 축이 없다** (상세 §3) |

### 1-2. 용어

| 용어 | 도출 | 포착 | 근거 / 판정 |
|---|---|---|---|
| 보험유니버스 / 보유 | O | — | 저장소명·`BRIDGE_NAME=insuniverse` |
| 심평원 | O | **X** | 주석 75블록. 그중 정책후보 16. **첫 레코드가 `class:"3_impl"` · `policy_candidate:false`** — `configuration.ts:21` "심평원 '내가 먹는약 한눈에' API URL". 규약이 버렸다 |
| 벤더(사) · 자체엔진 | O | 예정 | `configuration.ts:29,33,77-83` — `TREAT_PROVIDER`(기본 `codef`) · `TREAT_POOL`(`octover:30:3:1,coocon:30:3:1`) · `inhouse.baseUrl`/`apiKey`/`carCanary`. 주석 "자체 스크래퍼 엔진(scraper-engine)" 명시. `40-runtime-vendor-legal` 소관, 미착수 |
| FC | O | 예정 | 주석 113블록 + `modules/fc` |
| GA (법인대리점) | **X** | X | 코드 등장은 약관 수탁사 나열문 1곳뿐(`B2cPersonalInfoPage.tsx:12` "…GA코리아… 등 보험법인대리점"). **용어 정의로 쓰인 곳이 없다.** 사용자 구술이 유일 소스 |
| 영업대리점 / 영업대리점 채널 | O | 부분 | `modules/sales-agency/`(entity·repository·channel 하위) + `admin.constant.ts:52-54` 에러메시지가 관계를 정확히 진술 — `E1001` "해당 채널을 통해 가입된 회원이 있어 삭제할 수 없습니다", `E1002` "해당 영업대리점을 통해 가입된 기업이 있어 삭제할 수 없습니다". **관계는 도출되나 존재 이유(수익 분배)는 불가** |
| 기업 / 조직 | O | 예정 | `agcRole` `CORP_SUPER`/`CORP_ORG`(`auth.service.ts:132/192`) · `corpScope='ORG'`(`corp-readonly.guard.ts:21`). `06-access-model-findings.md` §6 4층 모델이 이미 실측 |
| 회원 / 일반회원 / 기업회원 | O | 예정 | `MEM001`(일반FC) · `MEM002`(기업FC). `10-index-code` `domain_status.yaml` 대상 |
| 회원고객 | O | 예정 | analyze 대상자. `analyze.dto.ts` |
| 일반구독상품 / 기업구독상품 | 부분 | X | `subscribe.entity.ts:43,49,61` 에 구독변경일시·변경취소일시·변경완료일시 필드 실재 → **일반 구독의 변경 가능성은 확정**. "기업구독 변경 불가 + 해지 후 재구독은 관리자만" 은 `subscribe-failed-admin.controller.ts:68` "재구독처리"(관리자 엔드포인트) 가 방증이나 **금지 강제 지점을 확인하지 못했다** |
| 주문 / 일반주문 / 기업주문 | O | 예정 | `modules/order` · `ODD` 코드군 |
| 분석 | O | 예정 | `modules/analyze` · `ANS` 코드군 59종 |
| 모니터링 | O | 예정 | `treat/monitor/treat-monitor.service.ts` · 스케줄 `analysis-stall` |
| Slot | O | **부분** | §2-1 참조. **코드가 사용자보다 정밀** |
| 머니 / 회원머니 / 기업머니 | O | 부분 | `modules/money` + 주석 211블록(정책후보 15). §2-2 참조 |
| 결제 | O | 예정 | `modules/payment` · toss/smartro |
| 정산 | O | 예정 | `modules/agency/settlement` · `client/settlement` · 스케줄 `settlement-*` |
| 청구서 | O | 예정 | `modules/invoice` + `pdf.util.ts` + fax 연동. 주석 101블록(정책후보 8) |
| 대상선정기준 (**사용자: "모름"**) | O | X | §2-3 참조. **역전 사례** |
| 진료 공급자 | O | 예정 | `treat/provider/treat-provider.service.ts` |
| 고객사 | O | **X** | `modules/client/{analyze,client,contract,order-detail,settlement}` + **독립 에러 네임스페이스** `client.constant.ts`(`S0000`/`E0101`/`E0103`). §2-4 에 불일치 기록. **docs 트리에 고객사 축 문서가 없다** |
| B2C | O | 예정 | `modules/b2c` · `B2C_BYPASS_SLOT`(기본 2) · `b2cAgreementContents.const.tsx` |

### 1-3. 특징 · History

| 사용자 서술 | 도출 | 판정 |
|---|---|---|
| "운영을 위한 정책의 영향을 많이 받은 서비스" | **X** | 메타 진술. 개별 정책은 도출되나 "정책 주도로 만들어졌다"는 성격 규정은 코드에 없다 |
| "주 3명의 대표가 아이디어 고안" | **X** | git author 는 커밋 주체이지 의사결정 주체가 아니다. **도출 불가** |
| "수익 분배·수익 구조 증설·서비스 독점으로 추가된 기능이 많음 (ex: 영업대리점)" | **X** | `sales-agency` 모듈의 **존재**는 도출되나 **왜 생겼는지**는 어디에도 없다. 커밋 본문 보유율 약 10%, 그나마 what 서술 |
| "포인트는 FAX 호출에서 추가" | 부분 | fax↔머니 결합은 코드로 확정(`fax-user.controller.ts:107,114` "머니 차감"). **선후관계(FAX 때문에 포인트가 생겼다)는 도출 불가** |
| "사용처 확대가 법적 문제로 지연, 타 프로젝트 쿠폰 서비스 이용 예정" | **X** | 저장소 밖 사건. 도출 불가 |

---

## 2. 사용자 서술과 어긋나거나 코드가 더 정밀한 항목

### 2-1. Slot — 코드가 더 정밀하고, 사용자의 "클러스터링" 은 다른 것을 가리킨다

사용자: "벤더사에서 트래픽이 몰리는걸 방지 및 API 수준을 제한. Slot수만큼 클러스터링 가능"

코드 실측 — `treat/dispatch/treat-queue.service.ts`:

```
capacity  = Σ over providers of  max(1, floor(limitPerMin / flowCost))     // :279-280
freeSlots = Σ over providers of  max(0, max − inflight(p.key))             // :281
```

- 슬롯은 **공급자별 분당한도 ÷ 흐름비용**으로 산출되는 파생값이지 독립 설정값이 아니다(`:279`).
- `inflight` 에 18초 임시 hold 가 포함된다(`:162` 주석) — 과다입장 방지 장치.
- 대기열은 Redis ZSET, `issueAdmit` 이 reserve 게이트(`:102-105`).
- `TREAT_POOL` 기본값 `octover:30:3:1,coocon:30:3:1` = `벤더:분당한도:흐름비용:가중치`.

→ 트래픽 방지·API 수준 제한이라는 **목적 서술은 코드가 지지**한다. 다만 "Slot수만큼 클러스터링"은
코드상 **공급자 풀 다중화**(`getPool()` 의 원소 수)에 대응하며, 슬롯 수는 그 결과이지 원인이 아니다.
`B2C_BYPASS_SLOT`(기본 2, `configuration.ts:164`)은 B2C 경로가 이 대기열을 우회하는 별도 정원이다 —
**사용자 정리에는 없는 정책 분기**다.

### 2-2. 머니 — FAX 차감 경로가 두 갈래이고 한쪽은 TODO 로 남아 있다

| 근거 | 내용 |
|---|---|
| `fax-user.controller.ts:107` | "FAX 재발송 (본인 FAX만 가능, 머니 차감)" |
| `fax-user.controller.ts:114` | "FAX 배치 발송 (여러 보험사 청구서를 한 번에 발송, **머니 1회 차감**)" |
| `fax.service.ts:797-799` | 주석 절차 — "1. 머니 차감 … 2-1. 실패 시: 머니 원복 + 히스토리 FAILED 생성" |
| `fax.service.ts:99,110,148,595` | **`// TODO: 포인트 차감`**, `// throw new BadRequestException('포인트가 부족합니다.')`(주석 처리), `// TODO: 포인트 환불` |

→ "포인트는 FAX를 사용하기 위해 소모됨"은 **일부 경로에서만 강제**되고, 다른 경로에는 미구현
TODO 가 남아 있다. 어느 쪽이 운영 현실인지는 코드만으로 판정되지 않는다. `50-domain` 또는
`findings` 회부 대상.

### 2-3. 대상선정기준 — 사용자가 "모름"이라 적은 항목이 코드에 완전히 정의돼 있다

`insuniverse-site/front/src/pages/criteria/CriteriaPage.tsx`

```
:63   실손보험조사대상 선정기준
:65   보험사기 예방 모범규준 제12조의1, 제12조의2 및 제12조의4에 따라 …
:81   금융감독원의 보험사기 예방 모범기준 제12조 2에 따라 실손의료보험의 보험금 지급사유 조사대상 선정기준을 …
:338  ■ 조사대상 선정기준   (:350 표 헤더 `선정기준`)
```

법령 근거까지 명시된 고지 페이지가 실재한다. `serviceCard.const.ts:87` 에 "조사 선정기준/질환별 대상"
카드가 **주석 처리**되어 있어 현재 노출 여부는 별도 확인이 필요하다.

→ **문서화의 방향이 일방향이 아니다.** 이 항목은 문서가 사용자에게 되돌려주는 산출이다.

### 2-4. 고객사 — 사용자 서술과 코드가 어긋난다

사용자: "진료정보수집 API가 아닌 단순히 고객 정보만 제공받는 DB 서비스 이용자"

코드 실측:

| 근거 | 내용 |
|---|---|
| `client/analyze/client-analyze-admin.controller.ts:44-101` | `분석데이터(기본)` · `분석데이터(상세)` · `분석데이터(5년치계산분)` · `처방조제정보` — 전부 `@Get` |
| `client/contract/client-contract.dto.ts:16` | `분석옵션 타입` |
| `client.constant.ts:E0102` | "요청한 분석 옵션은 **해당 고객사의 계약 옵션**에 포함되지 않습니다" |
| `client.constant.ts:E0103` | "이번 달 **분석 가능 횟수**를 초과하였습니다" (`contract.repository.ts:144` CI 기반 월간 분석완료 건수) |
| `client/analyze/client-analyze.controller.ts` | `@ApiTags('고객사 분석상세')` 이나 **라우트 0개** — 껍데기 |

→ 고객사는 **분석 결과를 계약 옵션·월 쿼터 단위로 제공받는다.** "단순 고객 정보"가 아니다.
사용자 서술이 "수집 **트리거**를 갖지 않는다"는 뜻이라면 코드가 지지한다 — client 쪽은 전부 조회이고
`treat` 수집 호출이 없다. 그 해석이라면 어긋남이 아니라 **표현의 축약**이다. 어느 쪽인지는 사용자 확인 사항.

### 2-5. 기업구독 변경 불가 — 클라이언트 게이트만 확인되고 서버 강제는 미확인 (2026-08-11 추가)

사용자: "기업구독상품 — 구독 변경 불가능, 해지 후 재구독은 관리자만 가능"

| 층 | 실측 |
|---|---|
| 프론트 | `SubscriptionCard.tsx:94,99,104` — `user.memType === "일반"` 일 때만 `구독 변경` · `해지 취소` · `변경 취소` 버튼 렌더 |
| 서버 guard | `subscribe.controller.ts:24` — 클래스 레벨 `@UseGuards(JwtAuthGuard)` **하나뿐**. `memType`·`corp` 조건 guard 없음 |
| 서버 라우트 | `:72` `@Post('prompt')`(구독즉시변경)가 `@Body() body: PromptSubscribeDto` 만 받는다 — 이 지점에서 JWT 주체와의 결합이 보이지 않는다 |
| 서버 service | `subscribe.service.ts` 에서 `memType` 은 엑셀 컬럼 분기(`:907,910,947`)에만 등장. **변경 차단 분기 0건** |

→ 사용자 진술의 **결과는 맞다**(기업회원은 화면에서 변경할 수 없다). 그러나 강제 층이
**표시 필터**이며, `06-access-model-findings.md` §2 의 "메뉴 권한은 서버 API 를 막지 않는다"와
**같은 형태**다.

**미확인**: `subscribeService.prompt()` 본문 전수를 읽지 않았다. 소유자 결속·상품 유형 검증이 그
안에 있을 수 있다. **부재 증명이 아니라 미탐색**이다 — `30-contracts-limits` 또는 `50-domain` 착수
시 확인 대상. 런타임 반증(기업 계정으로 직접 호출)은 하지 않았다.

**이 항목이 대조 작업의 가치를 보여준다.** 코드만 읽으면 "기업은 변경 못 한다"는 규칙이 존재한다는
사실 자체를 떠올릴 수 없고, 따라서 그 강제 층이 어디인지 물을 일도 없다. **구술이 검증 가능한
주장을 만들었고 코드가 그것을 반쯤 반박했다.**

---

## 3. 축 불일치 — 이것이 가장 큰 구조적 차이다

| | 사용자 모델 | 현행 문서 구조 |
|---|---|---|
| 1차 분할 축 | **제공 단위** — 채널 / 기업 / 고객사 | **actor** — admin / sales / corp |
| 축의 정체 | 계약·수익이 귀속되는 주체 | 관리자 콘솔에 로그인하는 주체 |
| 근거 | 사용자 글 `[가치정보] 1. 진료정보` | `05-final-spec.md` §4 `30-admin/` · `06-access-model-findings.md` §3 라우터 3분할 |

두 축은 교차하지, 포함관계가 아니다.

- **고객사(client)** 는 관리자 콘솔의 actor 가 **아니다**. API 소비자다. 따라서 actor 축 문서 어디에도
  자리가 없고, 실제로 `05-final-spec.md` §4 의 50문서 중 `client` 축 문서는 **0개**다
  (`10-server/` 8문서: analysis · treat · subscription-order · settlement-money · agency-corp ·
  communication · content · b2c-insurance — client 없음).
- **채널** 은 sales actor 아래 하위 개념이지만, 수익 귀속 단위로서의 채널은 별도 서술이 필요하다.

→ actor 축만으로 문서를 짜면 **고객사 축이 통째로 누락**된다. 이미 그렇게 되어 있다.

---

## 4. 대조 과정에서 드러난 부수 결함 2건

기존 `findings/11-index-code.md` 발견 1·5(E코드 비유일)의 연장이나, **네임스페이스 층이 다르다**는
점에서 별건이다.

### 4-1. `E0001` 이 3중으로 충돌하고 그중 하나는 외부 계약이다

| 파일:행 | 심볼 | 메시지 | 층 |
|---|---|---|---|
| `constants/api.constant.ts:16` | `UNAUTHORIZED` | `Unauthorized` | 내부 사용자 API |
| `constants/admin.constant.ts:62` | `INVALID_PARAMETER` | 필수값이 누락되었거나 형식이 올바르지 않습니다 | 내부 관리자 API |
| `constants/client.constant.ts:29` | `INVALID_AUTHORIZATION` | Authorization 미입력 | **외부 고객사 계약** |

`client.constant.ts` 는 필드명부터 다르다 — `resultCode`/`resultMsg`(vs 내부 `code`/`message`),
성공값 `S0000`, 기능별 앞 2자리 규약(기본요청 00 / 계약정보 01 / 주문 02 / 분석 03).
**이것은 대외 API 계약이므로 내부 E코드와 같은 namespace 에 두면 안 된다.**
manifest `error_codes: '^E[0-9]{4}$'` 는 셋을 한 통에 담는다.

### 4-2. `docs/` 산출물이 0건이다 — "못 잡았다"의 일부는 "아직 안 잡았다"

`docs/admin` · `docs/common` · `docs/server` · `docs/site` 전부 **파일 0개**. 존재하는 것은
`docs/_meta/` 뿐이다(manifest · index 6 jsonl · verify 스크립트 · findings 3). 인덱스 축
(`10`/`11`/`12`)만 진행됐고 문서 축 5개 PRD(`20`~`60`)는 전부 미착수다.

→ §1 의 "포착 = 예정" 항목들은 **규약의 실패가 아니라 미착수**다. 이 둘을 섞으면 원인 진단이 틀린다.
규약의 실패로 판정되는 것은 **X 로 표시된 8건**뿐이며, 그 원인은 `08` 에 있다.
