# ADR-0002: DDS 권한은 기존 권한 테이블을 런타임에 판정한다

> **상태**: Accepted · **날짜**: 2026-07-03 · **관련 이슈**: #617

## 맥락

현재 PoC는 `CB_*` 사용자·그룹·역할·퍼미션 모델을 사용자별 local DDS `DATA ROLE`과 `DATA GRANT`로 게시한다. 권한 변경 뒤 즉시 집행하려면 영향을 받는 모든 사용자의 DDS DDL을 재생성해야 한다. 이는 권한 원천이 두 곳이 되고, 동기화 실패·지연·drift를 만든다.

DDS `DATA GRANT`의 predicate는 SQL 서브쿼리와 `ORA_END_USER_CONTEXT`를 사용할 수 있다. 컬럼 권한은 Data Grant의 `SELECT (column...)`/`UPDATE (column...)`으로 정적 선언되지만, 그 Grant의 predicate는 매 SQL 실행 때 권한 테이블을 조회할 수 있다.

## 결정

1. `CB_*` 권한 테이블을 업무 권한의 유일한 원천으로 둔다.
2. `ADMIN.DDS_MCP_AUTHZ_PKG`의 definer-rights 함수를 통해 local DDS END USER를 업무 사용자로 해석하고, Object·CRUD·컬럼 그룹·행 속성에 대한 권한을 런타임에 판정한다.
3. DDS에는 보호 Object/CRUD/컬럼 그룹별 장기 `DATA GRANT`를 한 번 provisioning한다. 각 predicate는 `ORA_END_USER_CONTEXT.username`과 DDL에 고정한 whitelist Object·동작·컬럼 그룹을 함수에 전달한다.
4. 모든 MCP END USER에는 공통 `DDS_MCP_RUNTIME` DATA ROLE만 부여한다. 권한 테이블의 값 변경은 DDL 없이 다음 쿼리부터 반영한다.
5. 새 보호 Object·컬럼·CRUD, 또는 컬럼 그룹 재설계는 검토된 DDL provisioning 대상이다. 사용자/그룹/역할/퍼미션 값 변경은 provisioning 대상이 아니다.

## 결과

- 권한 변경의 즉시성은 권한 테이블 transaction commit으로 보장한다.
- Object/컬럼 목록은 여전히 정적이다. 함수는 컬럼 목록을 동적으로 만들거나 클라이언트 제공 Object 명으로 dynamic SQL을 실행하지 않는다.
- 셀 수준 제어는 고정 컬럼 그룹별 Grant와 동적 predicate를 결합한다. 여러 Grant는 additive이므로 광범위한 공통 `SELECT` Grant를 만들지 않는다.
- 함수는 권한 테이블을 보호 대상 Object와 분리해 조회해야 한다. 동일 Object 재조회는 순환 predicate 오류를 만든다.
- 권한 테이블은 같은 Oracle DB에 있어야 한다. DB link/원격 권한 원천은 DDS predicate에서 지원하지 않는다.
- 현재 사용자별 재게시 구현은 전환 기간의 PoC다. 기능 이행과 회귀 검증 후 `DdsMcpAuthorizationChangeListener`의 bulk publish 의존성을 제거한다.

## 대안

### 사용자별 DDS Grant 재게시

권한 계산 결과가 DB dictionary에 명시적으로 남고 쿼리 비용이 낮다는 장점이 있다. 그러나 권한 원천을 복제하고, 변경마다 bulk DDL·실패 복구·drift 관리가 필요해 채택하지 않는다.

### MCP Tool이 권한을 판정한 뒤 SQL을 선택

애플리케이션 버그·우회 경로·새 Tool이 데이터 보호를 무력화할 수 있어 채택하지 않는다. 판정은 보호 SQL과 같은 DB에서 DDS predicate로 집행한다.

### 컬럼별 동적 View 마스킹

View의 `CASE`와 함수로 구현할 수 있으나, 원본 Object 차단·View 권한·함수 성능을 별도로 보장해야 한다. DDS 컬럼 Grant가 필요한 기본 경로의 대체안으로 사용하지 않는다.
