# 서버별 ct 설치와 재사용

## 준비 후보: 독립 오프라인 전체 배포 진입점 (2026-11-03)

[OFFLINE_OPERATOR](OFFLINE_OPERATOR.ko.md)의 `ct-offline`은 기존ct를 교체하지 않는 별도 준비 후보다.
test Compose backend용 image/설정 전환·복귀·로컬 기록·선택 반출을 격리 검증했다.
최종 패키지는 source commit과 image 반출 검증을 통과한 뒤 봉인한다. 실제 설치는 사용자 수동이다.
test의 후속 반출은 [10GiB 보호선/12GiB 선제 중단과 순차 저장](OFFLINE_OPERATOR.ko.md#준비-환경의-알려진-제약)을
명시적으로 사용한다. 설치/rollback과 다른 서버의 기존 공간 기준을 낮추는 정책이 아니다.
기존 transaction 현장판에는 자동 적용하지 않는다. 아래 설치 완료 기록과 이번 후보를 구분한다.
[실행 근거](../profiles/ltb1021/topics/runtime-lifecycle/run/20261103T102051+0900-run-offline-full-preparation.md).
[후속 반출 기록](../profiles/ltb1021/topics/runtime-lifecycle/run/20261103T121241+0900-run-offline-sequential-export.md).

## 최신: test 다중 ROI 설치 (2026-10-13)

다중 ROI 지원 APP·Sidecar와 `ct roi`를 test에 설치했다. 기본·설정·실제 적용값은 모두
`legacy / max_rois=8 / max_rules=48 / full_frame_roi_id=0`이다.
운영 multi_roi 전환, 최종 Web 스키마 연결과 영상시험은 하지 않았다.
[설치·검증·복구 근거](../profiles/ltb1021/topics/runtime-lifecycle/validation/20261013T135030+0900-validation-test-multi-roi-install.md),
[개발 계약](../MULTI_ROI_CONTRACT.ko.md)을 먼저 읽는다. 아래 과거 설치 기록은 당시 상태다.

- 호스트 원본: `/workspace/contextra-runtime-config/ct/setup/roi/roi-policy.json`.
- 보호 적용본: 같은 폴더의 `roi-policy.applied.json`; 직접 편집하지 않는다.
- 컨테이너 경로: `/run/contextra-roi/roi-policy.json`, `CONTEXTRA_ROI_POLICY_FILE`로 연결한다.
- 확인: `ct roi status`. 편집: `ct roi edit` 또는 원본 파일. 반영: `ct roi apply`에서 `APPLY`.
- Enter는 각 현재값을 유지한다. 파일 저장만으로 실행값이 바뀌지 않고, 적용 검증 후 재부팅에도 유지된다.
- 이 명령들은 Runtime 관리 API가 실행 중이어야 한다. `ct stop`을 먼저 할 필요가 없으며,
  명령 자체가 컨테이너나 채널을 자동 시작·재시작하지 않는다.
- mode는 이후 Start의 서버 공통 입력 계약이다. 기존 run을 자동 변환하지 않는다.
  후속 모드 전환 시험은 Web 채널 Stop → mode 편집·적용 → 맞는 형식의 Web Start 순서로 한다.
  Web 준비 전에는 legacy를 유지한다. 같은 mode를 적용하려고 재로그인·CSR 발급할 필요가 없다.
- 실제 기동 기준은 ct active transaction이다. 원래 Compose/env로 임의 `up`하거나
  저장소 Gateway template 변경만으로 배포 완료라고 판단하지 않는다.
- 이번 Gateway template은 transaction 내부 snapshot으로 고정했다. 다음 변경도 검토된 배포가 필요하다.

## 이전 설치 기록

2026-10-07: [자료 정리·초기화·보관 정책](CT_DATA_MAINTENANCE.ko.md)을 추가했다.
AI2/test 도구 설치 완료, 실제 삭제와 새 APP Runtime 활성화는 사용자 후속이다. 아래는 이전 설치 기준이다.

Last reviewed: `2026-10-01 18:26:23 KST`. 계약: CTG-01~13.
test 도구 설치·격리 검증 완료. 이 문서의 test 수용 대기는 당시 상태이며 이후 서버별 배포 결과와 구분한다.
추가 서버의 ct 설치·인증·서비스/모델 검증은
[AI 서버2 배포 기록](../profiles/ltb1021/topics/runtime-lifecycle/validation/20261006T195803+0900-validation-ai2-deployment.md)을 참고한다.

## 구조와 경계

```text
ct -> server_context (호스트/operator/project/path/capability)
   -> field_profiles (환경/Web/CA/계정 참조)
   -> field_cli -> field_runtime
                    + transaction: 기존 현장 guarded transaction
                    + compose_backend: 기존 Compose stack 채택
   -> network_prepare / 기존 Auth·TLS 도구
   -> deployment_kit.maintenance_bundle: 검토한 도구·APP 소스 패치
```

- `/etc/contextra-maintenance/server.json`은 root 소유 서버 정의이며 machine-id 지문을 확인한다.
  환경 프로필과 설치 구조를 구분한다. 현장판 전체 복사나 전역 문자열 치환을 하지 않는다.
- 기존 현장 설치는 자동 전환하지 않는다. 서버 정의 없는 기존 도구는 transaction 경로를 유지한다.
- Compose adapter는 실제 image ID, bind, named/anonymous volume, network를 보존한다.
  익명 Redis volume도 external 이름으로 고정해 빈 저장소로 바뀌지 않게 한다.
- test에는 도구와 관리 파일만 설치했다. 기존 Runtime 설정·인증·모델·기동 정책은 변경하지 않았다.
- 나중에 `ct config apply`를 실행하면 ct 관리 Compose/pointer가 지속 실행 기준이 된다.
  원래 Compose/env는 drift 비교 원본으로 보존한다. 이후에는 `ct start`를 쓰며 원래의 수동
  `docker compose up`과 혼용하지 않는다. 자동부팅 unit이나 restart 정책을 이번에 추가하지 않았다.

## test 경로

| 구분 | 실제 경로/명령 |
| --- | --- |
| 진입/operator/project | `/usr/local/bin/ct`, `root`, `contextra`; 확인 `ct server` |
| 설치 도구 | `/usr/local/lib/contextra-maintenance/portable-20261001T182138` |
| 일반 편집 원본 | `/workspace/contextra-runtime-config/ct/setup/profiles/office.json` |
| 비밀정보/CA | 같은 profiles 아래 `office.private/main.credentials.json`, `main.ca.crt` |
| 관리 Runtime | `/workspace/contextra-runtime-config/ct/runtime/state` |
| 준비 자료 | `/workspace/contextra-runtime-config/ct/data/site` |
| 상태/journal | `/var/lib/contextra-maintenance/contextra` |
| 입력/반출 | `/workspace/contextra-runtime-config/ct/setup/inbox`, `outbox` |

LLM/GUI/관측/전역 ACL 개방 capability는 test에서 활성화하지 않았다. USB/VSCode/자원 기능은
설정된 operator와 소유 프로세스만 대상으로 하며 설치 시 자동 실행하지 않는다.

## 편집·적용·복구

1. `ct config status`, `ct profile paths`에서 서버/환경/원본/실행 경로를 확인한다.
2. 메뉴와 VSCode는 같은 프로필을 편집한다. 공백/키 순서 변화는 의미 비교에 영향을 주지 않는다.
3. 실행 Compose/env의 지원 공개값 변경은 `ct emergency`로 차이를 확인하고 수용한다.
   image/mount/command·인증·DB까지 일반 설정처럼 승인하지 않는다. 수동 SHA 계산/편집은 요구하지 않는다.
4. `ct profile credentials`는 숨김 저장만 한다. `ct ca`는 공개 CA만 검증·복사한다.
5. `ct config prepare` → `connect` → `apply`는 별도 단계다. 원격 결과 불명확 시 자동 retry하지 않는다.
6. apply는 stopped·디스크·IP SAN·인증·image·원본/방화벽 drift를 확인하고 journal로 재개한다.
7. `ct config resume`은 실패 단계부터, `restore`는 소유 로컬 설정만 CAS 복구한다.
   Web 등록/token·DB·미디어는 로컬 rollback으로 복구되지 않는다. 자동 Start는 없다.
8. `ct config note/confirm/export`로 비민감 요약·차이·사용자 관측을 ZIP 반출한다.

`ct net nextboot`는 별도 root에서 후보 netplan을 검증하고 파일만 예약한다. 즉시 NIC 적용/재부팅은 없다.
`ct net scheduled`는 예약과 부팅 변경 여부를 표시한다. `ct net cancel`은 이후 편집을 보호하며 파일만 복구한다.
부팅 후 취소가 실제 NIC까지 되돌렸다는 뜻은 아니다. `ct net apply`는 물리 콘솔에서 유한 try로 적용한다.
SSH listener는 설치 정의의 포트를 유지하며 NIC 작업에서 바꾸지 않는다.

## 재사용 패치

SSH/USB는 동일 ZIP 운반 방식이다. 임의 압축 해제나 payload script 실행은 하지 않는다.

| 종류 | 처리 범위 |
| --- | --- |
| TOOLS | 설치 Python/vendor/kit exact 파일, 이전/현재/후보 비교·journal·resume/restore |
| APP_SOURCE | 승인 source의 app Python/template 편집. image build/배포는 별도 |
| 설정·인증 | profile/config·CA/credentials 전용 흐름. 패치 기본값으로 덮어쓰지 않음 |
| 모델/native·DB | 기존 deployment_kit release/migration 절차 및 별도 승인 |

manifest는 version/kind/changes/effect/호환성(image IDs·API·backend)/파일 지문/이전 지문을 갖는다.
SHA는 작성자 인증이 아니므로 검토된 출처의 별도 지문을 사용한다.

```text
ct patch create /절대경로/tools.zip --spec /절대경로/spec.json
ct patch verify /절대경로/tools.zip --sha256 승인된지문
ct patch apply /절대경로/tools.zip --sha256 승인된지문
ct patch restore /var/lib/contextra-maintenance/contextra/patches/해당journal.json
```

spec keys: `source,baseline,kind,version,paths,changes`. 예: TOOLS의 `paths=["field_cli.py"]`.
지문은 create가 출력한다. 같은 bundle apply로 중단 후 재개하며 CONFLICT 파일은 덮어쓰지 않는다.
APP_SOURCE를 Runtime 적용 성공으로 표시하지 않는다. 서비스 재시작은 자동 실행하지 않는다.
기존 transaction APP image 경로도 고정 배포 HEAD 대신 root 승인 `app-python-compatibility.json`을 요구한다.
`version=1,kind=PYTHON_APP_ONLY,base_image,app_path=/opt/contextra/app,runtime_uid=0,native_models_unchanged=true`
계약을 실제 baseline과 대조한다. 이 manifest를 임의 작성해 다른 native baseline을 우회하지 않는다.
이번에 기존 아이서티 설치본을 교체하지 않았다.

## 설치와 첫 수동시험

```text
python3 tools/icerti_offline/install_portable.py --project 대상project --operator 실제계정 --metadata 절대관리경로
```

기본은 읽기 전용 계획이다. 승인 뒤 `--apply`를 붙인다. 현재 자동 discovery는 표준5서비스와
검증된 기존 방화벽 adapter를 지원한다. 다른 설치 형태는 서버 정의/adapter 검토가 필요하다.
도구 복사/Compose 채택 뒤 끊겼고 프로필/launcher가 없으면 `--resume-tools 설치prefix --apply`로
기존 지문을 확인하고 마감 단계만 재개한다. 기존 프로필/ct는 자동 덮어쓰지 않는다.

test 첫 수동시험은 `ct config status`와 `ct profile credentials`부터다. 변경된 Web 비밀번호를 복사하지 않았다.
이번 읽기 전용 관측에서 원격 version2는 이전 장비를 가리켰다. 타 작업자의 추가 갱신이 없음을 확인한 뒤
`ct config version 3`을 명시하고 prepare로 이어간다. 매 실패마다 자동으로 번호를 높이지 않는다.
Web signer는 OS 환경변수뿐 아니라 Spring이 import하는 `.env`도 확인한다. 이번 TLS·계정 활성·CA/키
경로 확인은 실제 신규 발급·WSS·Redis·bbox 수용 성공을 대신하지 않는다.
