# 온톨로지 서버 핸드오프 — 맥미니 세션용

> 2026-07-19 작성. 본진(맥북) Claude Code 세션 → 맥미니 Claude Code 세션 인수인계.
> 이 문서가 실행 계획이다. 함께 배포된 원자료: [/kit.md](/kit.md) (진단 온톨로지 키트) · [/jobslab-ontology.md](/jobslab-ontology.md) (첫 사본 = 시드 데이터) · [/spec.md](/spec.md) (승인된 설계문서)
> 설계 결정의 "왜"는 spec.md에 있다. 여기선 "무엇을 어떤 순서로"만.

---

## 0. 미션 한 줄

지금 이 문서가 떠 있는 **ontology.jobslab.dev를 통째로 대체**한다 — 정적 핸드오프 페이지에서 → **그래프 시각화 + API 문서 + REST API + MCP 접속점**을 가진 살아있는 온톨로지 서버로. DB와 서버는 이 맥미니에서 돌고, Cloudflare Tunnel로 같은 도메인에 노출한다. **서브도메인 추가 없이 경로로만 분리한다.**

## 1. 최종 형태 (경로 설계)

| 경로 | 무엇 | 프로세스 |
|---|---|---|
| `/` | 온톨로지 그래프 시각화 (테넌트 선택 → 노드/관계 탐색) | Next.js (3000) |
| `/docs` | API 문서 페이지 (REST + MCP 접속 방법, 데이터 모델, 어휘 12개) | Next.js (3000) |
| `/api/*` | REST API — 그래프 조회/쓰기. **테넌트 파라미터 필수 강제** | Next.js API routes (3000) |
| `/mcp/*` | MCP 접속점 (Claude Code·jedit·jurin용) | mcp-neo4j-cypher 공식 서버 (8080) |
| `/handoff` | 이 문서 보존 (대체 후에도 접근 가능하게) | Next.js (3000) |

라우팅은 **cloudflared 터널의 ingress 규칙**이 담당: `/mcp/*` → `localhost:8080`, 나머지 전부 → `localhost:3000`. Neo4j(7687)는 외부 비노출 — 로컬 전용.

**웹 프레임워크는 Next.js(App Router) 확정** — 시각화 화면·문서 페이지·REST를 한 앱·한 프로세스로 묶는 게 가장 깔끔하고, REST 층이 나중에 고객사 격리 강제 게이트웨이로 자랄 자리다. MCP만 공식 파이썬 서버로 분리 유지 (직접 만들지 말 것 — spec.md 의사결정 로그 참조).

## 2. 데이터 모델 (kit.md 1층 = 스키마, 변경 금지)

- **노드 라벨 6**: `Actor` `Object` `Event` `Record` `Rule` `Bottleneck`
- **공통 속성**: `tenant`(필수, 첫 값 `jobslab`) · `id`(A-01 형식) · `name` · `desc` · `status`(`확인됨`|`미확인`) · `evidence`
- **Bottleneck 추가 속성**: `pattern`(P01~P12) · `pain`(1~3)
- **관계 12개만 허용**: `CREATES`(만든다) `APPROVES`(승인한다) `CHECKS`(확인한다) `HANDS_OFF`(전달한다) `WRITES_TO`(적는다) `REFERENCES`(참조한다) `WAITS_ON`(기다린다) `JUDGES_BY`(판단한다) `OWNS`(소유한다) `REQUESTS`(요청한다) `NOTIFIES`(알린다) `RECONCILES`(대사한다)
- **제약**: `(tenant, id)` 복합 유니크
- **모든 질의에 tenant 필터 필수** — 커뮤니티 에디션은 DB 분리가 안 되므로(유료판 기능) 이 규약이 격리의 전부다. REST 층에서는 코드로 강제하고, MCP 쪽은 에이전트 지침으로 강제한다.

## 3. 작업 순서 (Phase 1 → 2 → 3)

### Phase 1 — DB + 시드 (로컬 완결)

1. 사전 확인: Homebrew, Node 20+, uv(uvx), cloudflared 설치 여부. 없으면 설치.
2. `brew install neo4j` → 초기 비밀번호 설정 → `brew services start neo4j`. 힙 메모리는 512m~1g면 충분 (소규모 그래프).
3. 제약 생성: 라벨 6개 각각에 `(tenant, id)` 유니크 제약.
4. **시드 적재**: [/jobslab-ontology.md](/jobslab-ontology.md)의 개체 카드 전부(A-01~06, O-01~06, R-01~05, RU-01~06, B-01~06)와 문서에 서술된 관계를 Cypher 시드 파일로 변환해 적재. 파서 만들지 말 것 — 30개 미만이라 수기 변환이 최소 구현. 시드 파일은 프로젝트에 보관(재현용).
5. 검증: 라벨별 노드 수가 문서의 카드 수와 일치하는지 대조.

### Phase 2 — 접속층 (MCP + Next + 터널)

6. MCP 서버: `uvx mcp-neo4j-cypher`를 HTTP 모드로 — `--transport http --server-host 127.0.0.1 --server-port 8080 --server-path /mcp/ --allowed-hosts "ontology.jobslab.dev,localhost,127.0.0.1"`. LaunchAgent로 자동 기동 등록.
7. Next.js 앱 (포트 3000):
   - `/` 시각화: 그래프 라이브러리는 가벼운 것 1개만 (force-graph 계열 권장). 라벨별 색 구분, 노드 클릭 → 속성 패널, 테넌트 셀렉터. **Bottleneck은 시각적으로 강조** (이 그래프의 존재 이유가 병목 지도다).
   - `/docs`: 데이터 모델 표, 관계 어휘 12개, REST 사용법, MCP 연결법(Claude Code 등록 명령 포함), 에이전트 규약("tenant 필터 필수, 12개 어휘만").
   - `/api/*`: 최소 셋 — 그래프 전체 조회(테넌트별), 노드 검색, 병목 목록, 노드/관계 생성. **tenant 파라미터 없는 요청은 400**. 12개 외 관계 생성 요청은 422.
   - `/handoff`: 이 문서 렌더.
   - 디자인: 라이트 우선, 브랜드 색 `#332D7B` 하나만. 잡스랩 규칙상 **colored left-border 콜아웃 금지**.
8. cloudflared: 터널 생성(`cloudflared tunnel login` → `create ontology`) → ingress 설정: hostname `ontology.jobslab.dev`에서 `path: /mcp` → 8080, 기본 → 3000. LaunchAgent 등록.
9. **DNS 전환** (이 순간 핸드오프 페이지가 대체됨): 기존 `ontology` CNAME은 Pages(ontology-jobslab.pages.dev)를 보고 있다. `cloudflared tunnel route dns --overwrite-dns ontology ontology.jobslab.dev`로 교체. overwrite가 안 먹으면 Cloudflare 대시보드에서 CNAME을 터널 주소(`<터널ID>.cfargotunnel.com`)로 수동 교체. ⚠️ 이 맥미니엔 DNS API 토큰이 없다 — cloudflared 로그인 인증서나 대시보드로만. Pages 프로젝트는 지우지 말 것(롤백용).
10. 절전 방지: 시스템 설정에서 잠자기 끄기 (상시 가동 전제).

### Phase 3 — 보호 + 소비자 연결 + 운영

11. Cloudflare Access: `ontology.jobslab.dev` 전체에 앱 생성 — 사람은 이메일 OTP, EC2 에이전트용 **서비스 토큰** 발급. 토큰 없는 요청 거부 확인.
12. EC2 연결: jurin·카톡봇에 MCP 주소(`https://ontology.jobslab.dev/mcp/`) 또는 REST + 서비스 토큰 헤더 설정. 에이전트 지침에 2절의 규약 문구 추가.
13. 백업: launchd 일일 스케줄 — `neo4j-admin database dump` → 로컬 백업 폴더, 14일 보존. (이 덤프가 나중에 EC2/관리형으로 옮기는 탈출 경로다.)

## 4. 완료 기준 (Sprint Contract — spec.md와 동일 + 확장)

1. 맥미니 로컬에서 Claude Code가 MCP 경유로 jobslab 병목 목록(B-01~06) 조회 성공
2. 외부에서 `https://ontology.jobslab.dev/` 접속 시 시각화 페이지가 뜨고, 그래프에 시드 데이터가 보임
3. `/api/...` 병목 조회가 tenant 파라미터 없으면 400, 있으면 B-01~06 반환
4. EC2에서 서비스 토큰으로 조회 성공 + **토큰 없는 요청 거부** 확인
5. 시드 개수 대조: jobslab-ontology.md 카드 수 = 그래프 노드 수
6. 맥미니 재부팅 후 Neo4j · MCP · Next · 터널 4종 자동 복구
7. `/handoff`에서 이 문서 접근 가능

## 5. 하지 말 것

- MCP 서버 직접 개발 (공식 mcp-neo4j-cypher 사용 확정)
- 관계 어휘 13번째 추가, 라벨 7번째 추가 — 스키마 변경은 본진과 합의 후
- 서브도메인 추가 (경로 분리 원칙)
- Neo4j 포트(7687, 7474) 외부 노출
- Pages 프로젝트(ontology-jobslab) 삭제 — 롤백 경로
- 마크다운 원본(kit.md 등) 임의 수정 — 원본은 잡스랩 저장소 `docs/ontology/`가 진실 원천

## 6. 맥락 (5분 요약)

잡스랩의 A 상품은 "2주 안에 진단 + 자동화 1개"다. 진단 산출물이 회사별 온톨로지(업무 지도)이고, 이 서버가 그 지도들을 에이전트가 소비하는 형태로 저장하는 인프라다. 첫 테넌트는 잡스랩 자신 — 자기 진단 결과(병목 6개, 처방: 관계 파이프라인)가 시드 데이터다. 나중에 고객사 진단이 늘 때마다 테넌트가 추가되고, 이 인프라가 구독(C) 사업의 기반이 된다. 상세 맥락과 리스크 경계(맥미니=집 인프라, 고객 실시간 의존 전 이전 원칙)는 [/spec.md](/spec.md).
