# Contextra 오프라인 유지보수 도구

## 기본 원칙

- AI 서버의 평상시 사용은 CLI입니다. `ct`는 번호 메뉴, `CT_ENGLISH=1 ct`는 영문 메뉴입니다.
- GUI와 LLM, Grafana/Prometheus는 자동 실행하지 않습니다.
- Contextra와 LLM은 번갈아 사용합니다. LLM 종료 후 GPU 반환을 확인하고 Contextra를 시작합니다.
- `sudo`는 기존 si 권한으로 필요한 명령에만 사용합니다. 비밀번호 없는 전역 sudo는 추가하지 않습니다.
- 현재 군중 배포를 base로 하는 offline APP image 적용을 검증했습니다. 실제 새 주소/인증 수용은 현장 값으로 확인합니다.

## 짧은 명령

| 명령 | 역할 |
| --- | --- |
| `ct status` | Contextra container 상태, 디스크/GPU 사용량 |
| `ct stop` | Gateway 요청 유입 차단, 채널 Stop/reap, 기존 guarded service Stop |
| `ct start` | 기존 mount guard를 통해 서비스만 시작. 카메라 자동 Start 없음 |
| `ct-llm chat` | 한국어 CLI 질답 |
| `ct-llm serve` | localhost18080 API/브라우저 UI |
| `ct-agent` | 현재 작업 폴더에서 local OpenCode. LLM API가 먼저 실행되어 있어야 함 |
| `ct-llm stop` | 등록 PID의 소유권을 확인해 해당 LLM만 종료 |
| `ct-gui` | si 물리 콘솔에서 임시 Xfce. SSH에서는 거부 |
| `ct observe start/stop/status` | 별도 관측 project의 수동 실행/중지/상태 |
| `ct connection status` | 현재 guarded Compose 경로와 지문만 확인 |
| `ct connection check-ca FILE` | 공개 CA 형식/유효기간/fingerprint 확인. trust 변경 없음 |
| `ct apply SOURCE` | 서비스 정지와 base 지문 확인 후 Python APP image를 오프라인 적용. 자동 Start 없음 |
| `ct edit FILE` | 서비스가 정지한 상태에서 source 파일을 nano로 편집 |
| `ct access` | sudo로 /workspace si ACL 재적용. 인증 세션/TLS/private env 제외, 소유자 유지 |
| `ct auth status` | 현재 AI 로그인 ID·Sidecar·WSS와 진행 중 인증 작업 확인. 비밀번호/token 출력 없음 |
| `ct auth update` | AI 연결용 ID·비밀번호 숨김 입력, LOGIN 확인 후 로그인1회. 성공한 AI 세션만 적용 |
| `ct auth reconnect` | 저장된 AI 계정으로 확인 후 로그인1회. 기존 AI token이 갱신될 수 있음 |
| `ct auth resume` | 발급된 세션의 중단된 로컬 적용 재개. 로그인 HTTP 요청을 다시 하지 않음 |
| `ct auth cancel` | 적용 전·세션 미확보 작업만 취소. 기존 파일 유지, 가능한 경우 기존 Sidecar 재개 |
| `ct logs SERVICE` | 해당 Contextra 서비스 최근100줄. 외부 전달 전 비밀정보 검토 |

정상 Stop/reap, offline APP image, 네 모델 READY와 관측 target 응답을 확인했습니다. 카메라를 자동 Start하지 않았습니다.
실제 GUI 화면/한글 입력, Windows PC 연결은 현장 확인 대상입니다.

## 탐색기 권한과 재부팅

`/workspace`와 하위 Runtime·데이터·작업 폴더는 si가 목록 조회·읽기·쓰기를 할 수 있습니다.
기동에 필요한 인증 세션·TLS 폴더·private env/key는 예외입니다. 기본 ACL은 filesystem에
저장되므로 재부팅 후에도 유지됩니다. 프로그램이 새 파일을600/700으로 만들면 명시적 mode가
우선하므로, 필요한 때 `ct access` 후 VSCode 탐색기를 새로고침합니다. 이 명령은 파일 내용과
소유자를 바꾸지 않으며 모델·서비스·카메라를 재시작하지 않습니다. 상시 ACL 감시기는 없습니다.
이전 ACL은 root 전용 `/var/lib/contextra-maintenance/workspace-acl-*`에 보관합니다.
데이터 디스크 또는 bind view가 일치하지 않으면 적용하지 않습니다.

## Web 연결 계정 변경

카메라를 먼저 모두 Stop하고, Web PC가 켜져 있고 현재 주소·CA가 맞는지 확인합니다.
`ct auth update`에서 **AI 연결용** ID와 비밀번호를 입력하고 `LOGIN`으로 확인합니다.
Web 브라우저용 계정과 같다고 가정하지 않습니다. 응답의 `actorType=AI`와 기존 `serverId`를 검사합니다.
카메라·모델·CA·주소를 이 명령으로 변경하지 않습니다. 비밀번호를 명령줄 인자로 입력하지 않습니다.

- `AI_LOGIN_PASS; WSS_CONNECTED`: 로그인과 WSS까지 확인.
- `AI_LOGIN_PASS; WSS_NOT_CONFIRMED`: 로그인은 성공. 반복 로그인하지 말고 Web 연결 상태 확인.
- `AI_LOGIN_REJECTED`: 기존 파일 유지. 계정/비밀번호를 확인한 뒤에만 다시 실행.
- `pending=true`: `ct auth status`의 phase와 비민감 응답 요약을 확인. 발급 세션이 있으면 `resume`.
- 결과가 불명확하면 자동 재시도하지 않습니다. 외부 상태 확인 후 `ct auth retry`는 명시적 추가 로그인입니다.
- Web이 꺼져 있고 적용을 보류하려면 `ct auth cancel`. 현재 인증 파일이 변했거나 새 세션이 있으면 취소를 거부합니다.

SSH의 TTY 제한이 있는 자동화는 소유자 전용600 입력파일과 명시적 확인 옵션을 지원합니다.
파일에는 loginId/password만 두고, `ct auth update --credentials-file /보호된/파일 --confirm-login`을 사용합니다.
실행 후 입력파일은 삭제합니다. 비밀번호·token·전체 응답을 로그나 Git에 남기지 않습니다.
원격 로그인 결과가 미확정인 채 일부 파일만 적용된 상태에서는 기동 guard가 자동 Start를 차단합니다.

부팅은 `multi-user.target`의 CLI가 기본이고, 데이터 mount 이후 Contextra service가 시작됩니다.
LLM·GUI·관측은 기본 Off입니다. 실제 OS IP는 자동 변경하지 않으므로 새 현장 IP는 주소/CA 안내를 따릅니다.

## 작업 기록

현재 작업본은 `/workspace/contextra/source/crowd-0f172d94`입니다. 검증된 군중 image에서 추출했고 부모 배포 source와 대조했습니다.
Runtime은 이 수정 폴더를 직접 bind하지 않습니다. `ct apply`가 작은 root 소유 snapshot을 만들고 현재 image 위에 Python만 적용합니다.
편집 중인 파일이 실행 중인 Runtime에 바로 반영되지 않습니다. SDK/native/의존성 변경은 이 경로의 범위가 아닙니다.

```bash
ct work begin /workspace/contextra/source/승인된작업본
ct work note '수정 이유와 실행한 테스트 결과'
ct work end
# 수정 내용과 검증 결과를 확인한 뒤 적용
ct apply /workspace/contextra/source/crowd-0f172d94
# 서비스/모델을 확인할 때만 실행. LLM은 먼저 종료
ct start
# SUMMARY.ko.md와 changes.diff에 비밀정보가 없는지 검토
ct work export 기록이름 --reviewed
```

기록은 si의 `~/.local/state/contextra-work/`에 저장합니다. 원본 source의 baseline hash, 변경/추가/삭제 diff,
수정 파일, 수동 메모를 남깁니다. shell history나 전체 환경변수는 수집하지 않습니다.
명령의 성공/실패는 `note`에 남깁니다. OpenCode session export는 검토 후 별도 첨부합니다.
이 도구가 모든 secret을 자동 제거하거나 모든 수동 명령을 녹화한다고 가정하지 않습니다.

## 주소 변경 계획

```bash
ct connection plan --ai-ip 실제AI주소 --web-ip 실제WEB주소 \
  --manager https://실제WEB주소:HTTPS포트 --event-url https://실제WEB주소:이벤트포트/api/v1/events \
  --control-port 38443 --redis-port 16379 --lan-cidr 실제허용망CIDR
```

plan은 계획만 작성하며 OS IP, 활성 Compose, CA, token, firewall을 바꾸지 않습니다.
후속 prepare/enroll/apply는 [NETWORK_TRANSITION](NETWORK_TRANSITION.ko.md)의 순서를 따릅니다.
기존 TLS/Config/Auth 검증 코드를 재사용하며 로그인/CSR POST의 불명확한 결과를 자동 반복하지 않습니다.
카메라 설정·DB·Event 원장·원본 자료는 IP 변경과 관계없이 보존합니다.

## 관측 설정

- Prometheus v3.15.0, Grafana13.2.2, Node Exporter1.12.1. 고정 image와 archive SHA256 보관.
- localhost만 사용: Node19100, Prometheus39090, Grafana33000.
- 수집15초, 보관7일 또는 retained blocks10GiB 중 먼저 도달하는 조건.
- WAL/compaction 때문에 filesystem 전체 사용량이 정확히10GiB로 고정되는 것은 아닙니다.
- 저장 `/backup/contextra/observability`, 설정 `/etc/contextra-maintenance/observability`.
- CPU는 전체 논리 CPU 평균0~100%, GPU는 NVIDIA-SMI의 표본 사용률입니다.
- Triton/Contextra target은 관측 시작 때 실제 analytics container 주소로 확인합니다.
  analytics를 recreate했다면 관측을 Stop/Start해 target을 갱신합니다.
- GPU collector는15초마다 NVIDIA-SMI를 호출합니다. GPU context/driver/profiler를 추가하지 않습니다.
- Grafana admin password는 root 전용 파일에서 관리하며 USB/공유 문서에는 넣지 않습니다.

## 실행 중단 상태 복구

source/network 적용 도중 실패하면 `ct start`와 부팅 guard가 미완료 transaction을 차단합니다.
`state/inflight.json`과 해당 transaction의 `previous-active.json`, `previous-site.json`, `previous-unit`을
현재 실제 파일과 대조해 실패한 단계만 재개합니다. DB/인증/원본을 일괄 rollback하지 않습니다.
새 APP image와 이전 image는 모두 남깁니다. `ct apply`는 기존 source를 지우거나 이전 image를 prune하지 않습니다.

## VSCode 검색 범위

전체 `/` 또는 데이터가 많은 `/workspace/contextra/data`를 프로젝트 root로 열지 않는 것을 권장합니다.
source 폴더만 workspace로 열면 모델·영상·backup의 전체 파일 검색을 피할 수 있습니다.
이번 준비 중 VSCode의 `rg --files --hidden --no-ignore --follow`가 약11.6코어를 사용한 것을 확인했고,
해당 검색 PID만 종료했습니다. VSCode/SSH 프로세스나 사용자 파일은 종료·삭제하지 않았습니다.

## USB 반입

반입 파일은 최종 USB 목록과 SHA256 manifest 기준으로 복사합니다. LLM 모델·현재 Contextra image·변환된 모델은
이미 현장 서버에 보존되어 있으며 도구 묶음만으로 서버 전체를 새로 설치할 수 있다고 표현하지 않습니다.
원본 영상·DB·비밀키·운영 password/token은 일반 USB 묶음에서 제외합니다.
