Metadata-Version: 2.4
Name: c2r-collect
Version: 0.1.3
Summary: Oracle data dictionary + PL/SQL source collector that writes okf-loom input folders
License-Expression: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: oracledb>=2.0
Requires-Dist: tomli>=2.0; python_version < "3.11"
Provides-Extra: s3
Requires-Dist: boto3>=1.34; extra == "s3"
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"

# c2r-collect

Oracle 스키마 하나에서 **PL/SQL 패키지 소스 · 관계 CSV · 데이터 사전 · 코드북 테이블**을 전부 뽑아
날짜 폴더(`raw/<날짜>/`)에 쓰고, 거기서 okf-loom이 읽는 입력 폴더(`input/<날짜>/`)를 만드는 명령줄 도구입니다.

- Python 3.10 이상, 관리자 권한 불필요
- 사람도 쓰고 LLM 에이전트도 셸로 부릅니다. 기계용 요약은 `python -m c2r_collect --help`

---

## 처음 하는 사람: DB 접속되는 PC에서 수집하기

DB에 접속되는 PC(예: 원격 데스크톱)에서 아래를 위에서부터 한 번씩 합니다.
명령은 **Git Bash** 기준이고, cmd에서 다른 곳만 따로 적었습니다.

```mermaid
flowchart LR
    A["1. Python 확인"] --> B["2. 설치"] --> C["3. Instant Client"] --> D["4. config.toml"]
    D --> E["5. 비밀번호"] --> F["6. 접속 확인"] --> G["7. 수집"] --> H["8. 결과 확인"]
```

### 1. Python이 있는지 확인

```
python --version
python -m pip --version
```
`Python 3.10` 이상과 pip 버전이 나와야 합니다. 없으면 이 PC에서는 진행할 수 없습니다(설치 요청 필요).

### 2. 이 도구 설치

```
python -m pip install --user -U c2r-collect
python -m c2r_collect --version
```
마지막 줄에 `c2r-collect <버전>`이 나오면 됩니다.

- `Scripts ... is not on PATH` 경고는 무시합니다. 이 매뉴얼은 항상 `python -m c2r_collect`로 실행합니다.
- 옛 버전이 그대로 보이면 pip 캐시입니다: `python -m pip install --user --no-cache-dir "c2r-collect==<버전>"`

### 3. Oracle Instant Client 받기 (한 번만)

DB가 접속 구간 암호화(Native Network Encryption)를 강제하면 Python만으로는 못 붙고 이 라이브러리가 필요합니다.
설치 프로그램이 아니라 zip을 푸는 것이라 관리자 권한이 필요 없습니다.

```
cd ~
curl -L -o ic.zip https://download.oracle.com/otn_software/nt/instantclient/instantclient-basiclite-windows.zip
unzip -q ic.zip && ls -d instantclient_*
ls instantclient_*/oci.dll
```
마지막 줄에 `instantclient_23_0/oci.dll` 같은 경로가 나오면 됩니다. 이 폴더의 **전체 경로**를 4번에서 씁니다.
(예: 홈이 `D:\Users\<id>`면 `D:/Users/<id>/instantclient_23_0`)

- `curl`이 막혀 있으면 브라우저로 같은 주소를 받아 홈 폴더에 풀어도 됩니다.
- 암호화를 강제하지 않는 DB라면 이 단계와 4번의 `client_lib_dir` 줄을 건너뛰어도 됩니다.

### 4. 작업 폴더와 설정 파일

```
mkdir -p ~/c2r && cd ~/c2r
notepad config.toml
```
메모장에 아래를 붙이고 `<...>`를 채웁니다. **저장할 때 인코딩은 UTF-8**(ANSI로 저장하면 `config must be saved as UTF-8` 오류).

```toml
[db]
host = "<DB 호스트>"
port = 1521
service = "<서비스 이름>"
user = "<읽기 계정>"
client_lib_dir = "<3번의 instantclient 폴더 전체 경로>"

[scope]
source_owner = "<패키지 소유 스키마>"
dict_owner_like = "<딕셔너리 대상 스키마 LIKE 패턴>"
dict_exclude_referenced = ["SYS","SYSTEM","XDB","MDSYS","ORDSYS","CTXSYS","WMSYS","EXFSYS","DBSNMP","OUTLN"]
codebook_tables = ["<코드북 테이블1>", "<코드북 테이블2>"]

[paths]
root = "<작업 폴더 전체 경로, 예: D:/Users/<id>/c2r>"
```
- 비밀번호는 이 파일에 넣지 않습니다(5번).
- 경로는 `/`로 씁니다. `\`를 쓰면 TOML에서 깨질 수 있습니다.

### 5. 비밀번호 넣기 (창을 열 때마다)

```
export C2R_DB_PASSWORD='<비밀번호>'
```
cmd에서는 `set C2R_DB_PASSWORD=<비밀번호>`. 창을 닫으면 사라집니다. 넣지 않으면 실행 때 물어봅니다.

### 6. 접속 확인

```
python -m c2r_collect discover-codebook
```
DB에서 코드북 후보 목록만 읽습니다(아무것도 쓰지 않음). 마지막 줄이 `ok: N candidates`면 접속·권한 정상입니다.
안 되면 아래 "막히면" 표.

### 7. 수집

처음엔 표본으로 동작부터 봅니다(패키지 20개, 코드북 테이블당 1,000행. 딕셔너리는 전체).
```
python -m c2r_collect collect --sample 20
```
표본이 `ok:`로 끝나면 그 결과 폴더를 지우고 전체를 돌립니다.
```
rm -rf ~/c2r/raw/$(date +%F)
python -m c2r_collect collect
```
- 진행 줄 `[c2r 13:25:04] dict_columns: fetching rows...`가 단계마다 찍힙니다. `dict_columns`(데이터 사전 컬럼 전체, 백만 행 단위)는 **10분 넘게** 다음 줄 없이 지나가는 게 정상입니다.
- 범위 필터는 없습니다. 지정한 스키마의 패키지 전부와 딕셔너리 전부를 뽑습니다.

### 8. 결과 확인

마지막 줄이 셋 중 하나입니다.

| 마지막 줄 | 뜻 | 할 일 |
|---|---|---|
| `ok: <폴더>` | 전부 성공 | `<폴더>/collect-report.md` 확인 |
| `partial: <폴더> - N problem(s)` | 폴더는 생겼고 일부 파일 실패 | 보고서 "오류" 절을 보고 판단 |
| `error: ...` | 필수 파일 실패, 결과 폴더 없음 | `<날짜>.partial/collect-report.md`에 원인 |

```
cat ~/c2r/raw/$(date +%F)/collect-report.md
```
보고서에서 볼 것:
- **소스** 표의 패키지 수
- **파일** 표의 행 수가 `dict/dict_manifest.csv`의 개수와 맞는지(`dict_constraints`만 제약×컬럼이라 더 많은 게 정상)
- **비ASCII / `?`만** 열: 한글이 살아 있으면 비ASCII 행이 0보다 크고 `?`만 행이 거의 0

결과 폴더(`raw/<날짜>/`)를 빌드 PC로 옮기는 방법은 환경마다 다릅니다(S3가 열려 있으면 `upload`/`download`).

### 막히면

| 메시지 | 원인 | 조치 |
|---|---|---|
| `DPY-3001: Native Network Encryption ... only supported in thick mode` | DB가 암호화를 강제 | 3번 Instant Client + 4번 `client_lib_dir` |
| `ORA-20002: YOUR IP ... IS NOT ALLOWED` | DB 로그온 트리거가 이 PC의 IP를 막음 | 코드로 못 푼다. DBA에게 IP·프로그램(python.exe) 허용 요청 |
| `DPI-1047: Cannot locate a 64-bit Oracle Client library` | `client_lib_dir` 경로가 틀림 | 그 폴더에 `oci.dll`이 있는지 `ls`로 확인 |
| `config must be saved as UTF-8` | 메모장이 ANSI로 저장 | 다른 이름으로 저장 → 인코딩 UTF-8 |
| `config not found` | `config.toml`이 없는 폴더에서 실행 | `cd ~/c2r` 후 실행, 또는 `--config <경로>` |
| `output already exists` | 같은 날짜 결과가 이미 있음 | 지우거나 `--force` |
| `ORA-01017` | 계정·비밀번호 틀림 | 5번 다시 |
| `ORA-12541` / `ORA-12170` | 호스트·포트가 틀렸거나 네트워크 차단 | SQL Developer의 접속 정보와 대조 |

---

## 빌드 PC: okf-loom 입력 만들기

```
python -m c2r_collect make-input --date <날짜> [--prev <이전 날짜>] [--add add.txt]
```
`input/<날짜>/sources/`에는 **이전에 설명(enrichment)이 있던 패키지 + add.txt의 이름**만 들어갑니다(LLM 비용을 묶는 자리).
첫 세대에는 `--add`가 필요합니다. 자세한 규칙은 `--help`.

## 명령 요약

```
python -m c2r_collect collect [--sample N] [--date YYYY-MM-DD] [--force]
python -m c2r_collect discover-codebook
python -m c2r_collect upload   --date YYYY-MM-DD      # pip install "c2r-collect[s3]"
python -m c2r_collect download --date YYYY-MM-DD
python -m c2r_collect make-input --date YYYY-MM-DD [--prev YYYY-MM-DD] [--add PATH|URL]
```
종료코드 0 성공 · 2 입력/설정 오류 또는 부분 성공 · 3 접속/필수 산출 실패 · 4 S3 전송 실패.
진행 줄은 stderr, 마지막 결과 줄(`ok:`/`partial:`/`error:`)은 stdout.
