---
template: policy-doc@1
doc_id: 03-audit
title: 감사 기록 — 흔적의 실제 소재와 열람의 무기록
config: ../_meta/template-config.yaml
last_verified: 4d798f55
policies:
  - id: audit:actor-column
    status: active-prod
    evidence: [S-schema, S-contract]
    anchors:
      - insuniverse-server/drizzle/schema.ts:331
      - insuniverse-server/drizzle/schema.ts:2773
  - id: audit:read-leaves-no-record
    status: active-prod
    evidence: [S-guard, A-comment]
    anchors:
      - insuniverse-server/apps/api/src/modules/admin-view-token/admin-view-token.guard.ts:51
  - id: audit:operational-log-not-audit
    status: active-prod
    evidence: [S-schema, S-contract]
    anchors:
      - insuniverse-server/drizzle/schema.ts:4
      - insuniverse-server/drizzle/schema.ts:19
  - id: audit:no-dedicated-store
    status: active-prod
    evidence: [S-guard, A-comment]
    anchors:
      - insuniverse-server/apps/api/src/interceptors/api-response.interceptor.ts:1
  - id: audit:retention-undecided
    status: conditional-unknown
    evidence: [S-schema, S-contract]
    unknown_reason: 기록이 얼마나 남는가는 삭제 배치가 실제로 도는가에 걸려 있고 그 활성 여부는 실행 모드와 스케줄러 종류를 정하는 환경값이 정한다. 두 값은 저장소 밖에 있으며 그 격리는 docs/05-schedules/04-runtime-topology.md 가 이미 소유한다 — 이 문서는 같은 격리를 다시 저작하지 않고 참조한다. 어휘도 신설하지 않는다
    anchors:
      - insuniverse-server/drizzle/schema.ts:19
---

# 감사 기록 — 흔적의 실제 소재와 열람의 무기록

이 문서는 **인덱스가 구조적으로 보지 못한 축**을 코드에서 직접 연다. 앞 두 문서와 달리 여기에는
대응하는 인덱스 키가 없다 — 법적 표면 인덱스 자신이 그 자리를 사각으로 선언했고 후보 인덱스의
법적 축 행에도 감사 행이 없다.

그래서 이 문서의 정책은 인덱스에서 오지 않고 계획서가 코드에서 유도해 선언한 것이다. 활성성만은
같은 오라클을 쓴다 — 앵커 행의 blame 과 릴리스 인덱스의 미도달 집합이다.

## 표면 대조

이 문서의 정책은 축 1(인덱스 7키) 밖에 있으므로 첫 열과 `state` 열이 전건 `—` 다. 대시는 빈 칸이
아니라 **그 축의 원소가 아니라는 관측**이다.

| 인덱스 키 | 정책 id | state | 앵커 도달성 | status | 배치 |
|---|---|---|---|---|---|
| — | `audit:actor-column` | — | `reached-prod` | `active-prod` | 본문 |
| — | `audit:read-leaves-no-record` | — | `reached-prod` | `active-prod` | 본문 |
| — | `audit:operational-log-not-audit` | — | `reached-prod` | `active-prod` | 본문 |
| — | `audit:no-dedicated-store` | — | `reached-prod` | `active-prod` | 본문 |
| — | `audit:retention-undecided` | — | `reached-prod` | `conditional-unknown` | 부록 |

마지막 행이 도달성과 status 가 갈리는 자리다. 앵커는 운영에 도달했지만 그 표에 쌓인 기록이 얼마나
남는가는 배치 활성 여부에 걸려 있고, 그 게이트 값은 저장소 밖이다.

## 인덱스 사각 — 감사

**법적 표면 인덱스가 이 자리를 스스로 사각으로 적었다.** 동의 기록 축의 사각 목록에 감사·이벤트
기록 표 항목이 있고, 그 사유는 탐색이 형태소 기반이라 형태소 없이 이름 지어진 표를 볼 수 없다는
것이다. 후보 인덱스의 법적 축 행에도 감사 행이 없다.

**형제 문서가 같은 자리를 이미 비워 두고 회부했다.** 관리자 콘솔 문서가 세 어휘로 서버 모듈
전체를 훑어 파일 0건을 적었고, *"세 어휘 밖의 구현은 이 검색이 보지 못하므로 부재 증명이 아니다"*
로 닫았다. 같은 문서가 그 스캔의 0건과 부재 증명 아님을 프론트매터 한 자리와 흐름 표 두 자리에
걸쳐 세 번 적는다.

이 문서는 **그 스캔을 재현하고 우주를 넓힌다.** 게이트가 같은 세 어휘로 같은 범위를 다시 훑어
0건을 확인한 뒤, 저장 계층 전체에서 행위자와 이력을 담는 표를 부류별로 재열거한다. 아래 계수는
전건 게이트 유도값이며 저자가 세지 않는다.

| 기록 부류 | 표·파일 수 | 행위자 컬럼 | 이 부류가 답하는 질문 |
|---|---|---|---|
| 전용 감사 기록 | 0 | 0 | 없음 — 감사만을 위한 표도, 모든 요청을 가로채 남기는 층도 관측되지 않는다 |
| 행위자 컬럼 보유 표 | 9 | 9 | 누가 그 행을 만들었거나 승인했는가 |
| 운영 로그 표 | 5 | 0 | 무엇이 언제 실행되고 실패했는가 — 누가 했는지는 담지 않는다 |
| 업무 이력 표 | 7 | 2 | 그 업무 값이 어떻게 변해 왔는가 — 행위자는 일부만 담는다 |

**행위자 컬럼 보유 표에서 관리자 표 자신은 뺀다.** 그 표의 관리자 식별 칸은 자기 기본키이지 다른
행위의 행위자 기록이 아니다. 이 제외를 하지 않으면 계수가 하나 부풀고 부류의 정의가 흐려진다.

**아홉 표 중 여섯이 금전 축이다.** 즉 행위자가 남는 영역과 남지 않는 영역이 갈린다. 그 갈림이
설계된 것인지 아닌지는 이 문서가 판정하지 않는다 — 저장소 안에 그 의도를 적은 근거가 없다.
다만 아홉 표의 행위자 칸 정의 커밋이 전건 운영에 도달해 있으므로 **갈림 자체는 운영 사실**이다.

## 열람은 남지 않는다

**열람을 기록하는 표가 관측되지 않는다.** 위 세 부류의 칸을 전수 열거해도 조회 행위를 담는
칸이 없다. 관리자 열람 경로에서 이 창이 연 우주에 관측된 흔적은 열람 토큰 가드가 남기는 경고
로그 한 줄뿐이고, 그것도 **강제가 꺼져 있을 때만** 찍힌다 — 강제를 켜면 예외를 던지고 그 경로는
로그를 남기지 않는다.

즉 흔적이 남는 조건과 접근이 통제되는 조건이 서로 배타적이다. 통제가 켜지면 차단된 시도의 기록이
사라지고, 통제가 꺼지면 통과한 열람이 경고 한 줄로만 남는다. 어느 쪽에서도 **성공한 열람의 영속
기록은 만들어지지 않는다.**

열람 토큰 강제 게이트(`ADMIN_VIEW_TOKEN_ENFORCE`)의 정의와 그 값의 판정은 이 문서의 소유가
아니다. `docs/30-admin/05-treat-monitoring.md` 가 이미 그 게이트를 싣고 있으므로 이 문서는 그것을
다시 정의하지 않고, **열람이 영속 기록을 남기지 않는다** 는 사실만 적는다.

## 보존 기간

기록이 얼마나 남는가는 이 문서가 답하지 못한다. 삭제 배치가 실제로 도는가에 걸려 있고, 그 활성
여부는 실행 모드와 스케줄러 종류를 정하는 환경값이 정하며 두 값은 저장소 밖에 있다.

**그 격리는 이미 저작돼 있다.** `docs/05-schedules/04-runtime-topology.md` 가 배치의 선언 상태와
활성 미판정을 소유한다. 이 문서는 같은 격리를 다시 쓰지 않고 참조하며, 상태 어휘도 신설하지 않고
그 문서가 쓴 것과 같은 것을 쓴다.

## 정책 (기획)

**이 절에 본문 정책이 실린다.** 감사 축의 사실은 전부 저장 계층 선언과 코드 경로의 형태이고, 그
정의 커밋이 운영에 도달해 있다. 무엇이 남고 무엇이 남지 않는가는 지금 확정된다 — 판정을 미룰
자리는 보존 기간 하나뿐이고 그것만 부록에 있다.

### audit:actor-column

**관리자 행위의 흔적은 전용 감사 기록이 아니라 업무 표의 칸으로 흩어져 있다.** 아홉 개 표가
행위를 한 관리자를 가리키는 칸을 가지며, 그중 하나는 승인자를 따로 가리킨다.

이 형태에서는 "누가 무엇을 했는가" 를 한 자리에서 물을 수 없다. 답은 표마다 흩어져 있고, 칸이
없는 표의 행위는 애초에 답이 없다.

### audit:read-leaves-no-record

**열람은 어느 표에도 남지 않는다.** 위 아홉 표의 칸은 행을 만들거나 승인한 주체를 담지 조회한
주체를 담지 않는다. 조회 경로에서 남는 것은 열람 토큰 가드의 경고 로그 한 줄뿐이고, 그것도 강제가
꺼져 있는 동안에만 찍힌다.

그래서 "누가 이 정보를 봤는가" 는 저장소 안 근거로 답해지지 않는다. 이것은 확인 못 함이 아니라
**기록 지점의 부재**다.

### audit:operational-log-not-audit

운영 로그 표가 다섯 있다. 메일 발송 실패 · 진료 수집 · 소비자 수집 · 손해 분석 · 정산 메일 발송이
각각 자기 표를 갖는다.

**이 표들은 감사 기록이 아니다.** 어느 표에도 행위자 칸이 없다. 무엇이 언제 실행되고 실패했는가는
답하지만 누가 그것을 일으켰는가는 답하지 않는다. 두 축을 같은 이름으로 부르면 "로그가 있다" 가
"흔적이 남는다" 로 읽힌다.

### audit:no-dedicated-store

**감사만을 위한 표가 없고, 모든 요청을 가로채 남기는 층도 없다.** 요청 가로채기 층에 있는 것은
응답 형태를 통일하는 두 종류뿐이며 어느 쪽도 기록을 쓰지 않는다.

형제 문서의 어휘 세 종 스캔이 파일 0건을 냈고 이 문서의 게이트가 그것을 재현한다. **그러나 0건
스캔은 부재 증명이 아니다** — 세 어휘 밖의 이름으로 구현된 것은 그 검색이 보지 못한다. 그래서 이
문서는 스캔 결과를 그대로 두지 않고 우주를 넓혀 실제 소재를 위 표로 냈다.

## 강제 지점 (개발)

정책 내용을 다시 쓰지 않는다. 각 정책이 저장소 안 **어디에서** 강제되는가와 그 기제만 적는다.
배치가 부록인 정책도 이 절에 있다. 기준점은 전건 동결 stg `4d798f55` 다.

### audit:actor-column

- 강제 방식: 스키마 선언. 각 표가 관리자 식별 칸을 직접 갖고, 일부는 참조 무결성 제약까지 건다.
- 앵커: `insuniverse-server/drizzle/schema.ts:331` (참조 제약이 걸린 형태) · `:2773` (제약 없이 칸만 둔 형태)
- 게이트: 없음 — 저장 계층 선언이며 조건에 걸리지 않는다.

### audit:read-leaves-no-record

- 강제 방식: 가드의 경고 로그. 강제가 꺼진 동안 미검증 요청을 통과시키며 경고를 한 줄 찍고, 켜지면 예외를 던지고 로그를 남기지 않는다.
- 앵커: `insuniverse-server/apps/api/src/modules/admin-view-token/admin-view-token.guard.ts:51`
- 게이트: 열람 토큰 강제 게이트 — 정의와 값 판정은 `docs/30-admin/05-treat-monitoring.md` 소유다.

### audit:operational-log-not-audit

- 강제 방식: 스키마 선언. 다섯 표가 각각 실행 결과를 담고 행위자 칸을 두지 않는다.
- 앵커: `insuniverse-server/drizzle/schema.ts:4` · `:19`
- 게이트: 없음.

### audit:no-dedicated-store

- 강제 방식: 없음. 요청 가로채기 층에 기록 지점이 존재하지 않는 것이 관측 지점이며, 앵커는 그 층의 첫 파일이다.
- 앵커: `insuniverse-server/apps/api/src/interceptors/api-response.interceptor.ts:1`
- 게이트: 없음.

### audit:retention-undecided

- 강제 방식: 없음. 표는 무한히 쌓이는 형태이고 삭제는 별도 배치가 한다.
- 앵커: `insuniverse-server/drizzle/schema.ts:19`
- 게이트: 삭제 배치의 실행 모드와 스케줄러 종류 — 격리는 `docs/05-schedules/04-runtime-topology.md` 소유다.

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

`적용` 은 그 표면이 해당 축에서 실제로 관측되는 경우에만 쓴다. 그 밖은 `—` 이며 빈 칸이 아니라
관측된 부재다.

행위자 칸과 열람 경로는 관리자 콘솔에서 발생하므로 `관리자` 가 `적용` 이다. 나머지 로그인 주체는
이 축의 기록 대상이 아니다 — 아홉 표의 칸이 가리키는 것은 전부 관리자 식별자이고, 일반 사용자의
행위를 담는 칸은 이 부류에 없다. 서비스 축은 모든 앵커가 server 저장소에 있으므로 `server` 만
`적용` 이다.

| 정책 id | 관리자 | 영업대리점 | 기업담당자 | 일반회원 | 기업회원 | server | site | admin |
|---|---|---|---|---|---|---|---|---|
| audit:actor-column | 적용 | — | — | — | — | 적용 | — | — |
| audit:read-leaves-no-record | 적용 | — | — | — | — | 적용 | — | — |
| audit:operational-log-not-audit | — | — | — | — | — | 적용 | — | — |
| audit:no-dedicated-store | — | — | — | — | — | 적용 | — | — |
| audit:retention-undecided | — | — | — | — | — | 적용 | — | — |

## 예외·폴백

예외가 없는 정책도 행을 둔다 — 없다는 것도 확인의 결과이며 그 확인 근거를 함께 적는다.

| 정책 id | 예외 | 폴백 | 확인 근거 |
|---|---|---|---|
| audit:actor-column | 칸을 갖지 않는 표의 행위는 행위자가 남지 않는다 | 없음 | 저장 계층 전수 재열거에서 이 칸을 가진 표가 아홉이고 나머지는 갖지 않는다 |
| audit:read-leaves-no-record | 강제가 꺼져 있을 때 미검증 열람이 경고 한 줄을 남긴다 | 없음 — 강제를 켜면 그 줄도 남지 않는다 | `insuniverse-server/apps/api/src/modules/admin-view-token/admin-view-token.guard.ts:51` |
| audit:operational-log-not-audit | 없음 | 없음 — 행위자를 담는 다른 칸이 다섯 표 어디에도 없다 | 다섯 표의 칸 열거 전수 |
| audit:no-dedicated-store | 없음 | 없음 — 대체 기록 지점이 관측되지 않는다 | 형제 어휘 세 종 재스캔 0파일 · 요청 가로채기 층 전수 열거 |
| audit:retention-undecided | 삭제 배치가 돌지 않으면 기록은 지워지지 않는다 | 없음 — 이 문서는 그 배치의 활성을 판정하지 않는다 | `docs/05-schedules/04-runtime-topology.md` 의 격리 |

## 부록

이 절의 정책은 **현행 발효 여부가 판정되지 않아** 본문에서 격리한다. 이 문서의 격리 사유는
하나다 — 삭제 배치의 활성이 미판정이다. 코드도 표도 운영에 있지만 그것이 지금 도는지가 저장소
밖 값에 걸려 있다.

### audit:retention-undecided

운영 로그와 업무 이력이 얼마나 오래 남는가의 표면이다. 표 자체에는 보존 기간을 담는 칸이 없고,
지우는 일은 별도 삭제 배치가 한다.

**그 배치가 도는지는 저장소 안에서 답해지지 않는다.** 실행 모드와 스케줄러 종류를 정하는 두
환경값이 그것을 정하고 값은 배포 시점에 주입된다. 그 격리는 배치 축 문서가 이미 소유하므로 이
문서는 같은 판정을 다시 내리지 않는다.

## 연혁

릴리스 태그가 존재하지 않는다. 릴리스 열은 `—` 로 두고 커밋 SHA 로 추적한다. 행은 커밋 인덱스가
이 문서의 앵커 경로 접촉으로 기록한 커밋 집합 안에서 **흔적이 남는 자리가 바뀐 시점**만 골랐다.
앵커 경로 중 스키마 파일 하나가 접촉 300건을 넘으므로 전건을 싣지 않으며, 그 선별은 사람 판단이고
게이트는 앵커 경로 접촉까지만 본다.

| 릴리스 | 날짜 | SHA | 변경 요약 |
|---|---|---|---|
| — | 2025-03-26 | `1809f9f5` | 관리자 알림 표가 서면서 행위자 칸이 처음 생긴다 — 참조 제약이 걸린 형태 |
| — | 2025-06-04 | `560601e1` | 진료 수집 결과를 남기는 운영 로그 표가 선다 — 행위자 칸 없이 |
| — | 2026-01-12 | `46efac63` | 금전 축 전반이 재편되며 행위자 칸을 가진 표가 넷 늘어난다 — 행위자가 남는 영역이 금전 축에 몰리는 지점 |
| — | 2026-07-01 | `55c4eaac` | 열람 토큰 가드가 선다 — 미검증 열람에 경고 한 줄이 생기고, 강제를 켜면 그 줄이 사라지는 형태도 이때 정해진다 |
| — | 2026-07-06 | `397f7453` | 충전 요청 표에 승인자 칸이 붙는다 — 만든 주체와 승인한 주체를 가르는 첫 자리 |
| — | 2026-07-20 | `f0038eb9` | 열람 토큰이 서명된 관리자 클레임을 복원하는 형태로 바뀐다 — 열람 경로의 흔적 형태는 그대로다 |
