Add and update DOCS research records

This commit is contained in:
happybell80 2026-03-13 15:50:27 +09:00
parent b9d9b1fd27
commit 274812aef3
6 changed files with 362 additions and 207 deletions

View File

@ -1,80 +1,6 @@
# 이중 NAS 에이전트 파일 스토리지 구조 아이디어
# 260307_이중_NAS_에이전트_파일_스토리지_구조_아이디어
tags: [nas, agent, storage, sync, architecture]
이 문서는 인프라 기준 문서로 이관되었습니다.
## 목적
- 외부 NAS의 파일을 내부 NAS로 이중 저장 또는 동기화한다.
- 에이전트는 외부 NAS를 직접 읽지 않고, 내부 NAS만 읽는다.
- NAS는 연산 서버가 아니라 파일 스토리지로만 사용한다.
## 기본 구조
외부 NAS(public)
-> 동기화
-> 내부 NAS(LAN)
-> 네트워크 마운트
-> 에이전트 서버
핵심 원칙:
- 외부 NAS: 외부 수집/저장
- 내부 NAS: 에이전트용 파일 저장소
- 에이전트 서버: 연산/파싱/AI 처리
## 왜 이 구조인가
- 외부 NAS를 에이전트가 직접 읽게 하면 보안과 연결 안정성이 약해진다.
- 내부 NAS만 읽게 하면 에이전트는 내부망 기준 단순 파일 처리로 끝난다.
- NAS가 느려도 파일 스토리지 역할에는 적합하다.
## 권장 동기화 방식
### 1. Synology Drive ShareSync
- 외부 NAS -> 내부 NAS 단방향 동기화
- 장점: 설정이 쉽고 Synology 간 궁합이 좋다.
- 용도: 거의 실시간 파일 복제
### 2. rsync
- 외부 NAS -> 내부 NAS 주기 동기화
- 장점: 단순하고 서버 관점에서 제어가 쉽다.
- 용도: 5분/10분 주기 파일 동기화
### 3. Hyper Backup
- 외부 NAS -> 내부 NAS 백업
- 장점: 복구용으로 강하다.
- 단점: 실시간 동기화 용도에는 덜 적합하다.
## 내부 NAS를 에이전트가 읽는 방식
- 내부 NAS를 NFS 또는 CIFS로 에이전트 서버에 마운트한다.
- 에이전트는 `/mnt/agent` 같은 단일 경로만 읽는다.
권장 예시:
- `/mnt/agent/raw`
- `/mnt/agent/crawl`
- `/mnt/agent/output`
- `/mnt/agent/logs`
## NAS에 둘 것
- PDF, CSV, JSON, HTML, 이미지 같은 원본 파일
- 크롤링 결과물
- 장기 로그
- 에이전트 산출물
## NAS에 두지 말 것
- 벡터 DB
- SQLite 실시간 쓰기 경로
- 캐시
- 모델 로딩 경로
- 고빈도 랜덤 I/O가 필요한 런타임 데이터
## 현재 기준 가능 여부
### 가능한 부분
- 내부 NAS(192.168.0.101)는 현재 51123에서 실마운트 가능하다.
- Gitea LFS도 NAS 저장소로 실제 동작 검증이 끝났다.
- 따라서 내부 NAS를 에이전트 파일 스토리지로 쓰는 것은 가능하다.
### 아직 필요한 부분
- 외부 NAS(`sigongipc.synology.me:5000`)에 대한 실제 동기화 경로는 아직 미구현이다.
- 외부 NAS -> 내부 NAS 동기화 방식(Drive ShareSync / rsync / Hyper Backup) 중 하나를 고정해야 한다.
- 내부 NAS 공유 폴더를 에이전트 전용 경로로 분리해야 한다.
## 현재 판단
- 이 구조는 가능하다.
- 다만 지금 당장 완성된 것은 아니고, 핵심 선행조건은 `외부 NAS -> 내부 NAS 단방향 동기화 확정``내부 NAS의 에이전트 전용 공유폴더 설계`다.
- 연산은 미니서버, 저장은 NAS로 분리하는 방향이 맞다.
- 새 위치: <https://git.ro-being.com/ivada-infra/DOCS/src/branch/main/journey/ideas/260307_external_nas_companyx_sync_%EC%95%84%EC%9D%B4%EB%94%94%EC%96%B4.md>
- 이유: 외부 NAS -> 내부 NAS 동기화, 내부 NAS 마운트, 저장 경로 분리 문제는 `robeing` 기능 문서보다 `infra` 운영 문서로 관리하는 것이 SSOT에 맞습니다.

View File

@ -0,0 +1,101 @@
# 260310 콜드메일 `skill-rag-file` 500 및 실패은닉 원인확정 리서치
tags: [coldmail, skill-rag-file, rb8001, scheduler, postgres, research]
**날짜**: 2026-03-10
**작성자**: Codex
**관련 파일**: `rb8001/app/services/coldmail_processor.py`, `rb8001/app/services/workflows/coldmail_workflow.py`, `rb8001/app/scheduler/jobs/coldmail_briefing.py`, `skill-rag-file/app/api/upload.py`, `skill-rag-file/.env`
**상위 원칙**: [전역 원칙](../../../../0_VALUE/00_Principles/global-principles.md), [문서 작성 원칙](../../book/300_architecture/312_writing-principles.md), [Backend Coding Principles](../../book/300_architecture/311_backend_coding_principles.md)
## 관련 문서
- [콜드메일 `skill-rag-file` 500과 실패가시성 복구](../troubleshooting/260310_coldmail_skill_rag_file_500_stale_db_host_및_실패가시성_복구.md)
- [9시 네이버 이메일 분석 미전송과 실패 은닉 해결](../troubleshooting/260309_9시_네이버이메일분석_미전송_실패은닉_해결.md)
- [51123 임시복구 서비스 연속성 조치내역](../../../../infra/DOCS/journey/troubleshooting/260304_51123_임시복구_서비스연속성_조치내역.md)
---
## 1. 목적
- `2026-03-10 09:05` KST 콜드메일 프로세스가 "안 돈 것처럼 보인 이유"를 로그, 코드, 런타임 설정 기준으로 단일 원인까지 확정한다.
- `skill-rag-file` 업로드 `500 Internal Server Error`의 직접 원인을 확정한다.
- 실패은닉이 어떤 코드 경로에서 발생했는지 분리한다.
## 2. 범위 / 비범위
- 범위: `rb8001`, `skill-rag-file`, PostgreSQL 연결 경로, `2026-03-10 09:05` 실행 구간
- 비범위: 콜드메일 후보 선정 로직 자체의 품질, 다른 스케줄러 잡, 다른 프로젝트
## 3. 사실(Facts)
### 3-1. 09:05 작업은 실제 실행됐다
- `rb8001` 로그에 `2026-03-10 09:05:00` `Running job: Coldmail Daily Briefing`이 기록됐다.
- 같은 실행에서 콜드메일 후보 3건이 선택됐고, 각 후보 처리 중 첨부 PDF 업로드 단계가 실패했다.
- 최종 로그는 `Coldmail briefing completed: 0 emails processed`로 닫혔다.
- 같은 프로세스에서 뒤이은 다른 잡은 계속 실행됐고, APScheduler는 작업을 `executed successfully`로 기록했다.
### 3-2. 직접 실패 지점은 `skill-rag-file` 업로드였다
- `skill-rag-file` 컨테이너 로그의 같은 시각대에 `POST /api/upload HTTP/1.1" 500 Internal Server Error`가 반복 기록됐다.
- 스택트레이스는 `/app/app/api/upload.py` 내부 `await db.execute(...)` 경로에서 끝났고, 최종 예외는 `TimeoutError`였다.
- 이 시점 업로드 실패는 콜드메일 후보 수집 이후, 첨부파일 문서화 단계에서 발생했다.
### 3-3. `skill-rag-file`의 데이터베이스 주소는 stale 값이었다
- 컨테이너 환경변수에서 `DATABASE_URL=postgresql://robeings:robeings@192.168.219.45:5432/main_db`가 확인됐다.
- 현재 호스트 IP는 `192.168.0.100`, `172.17.0.1` 등으로 확인됐고 `192.168.219.45`는 현재 서버 유효 주소가 아니었다.
- 호스트에서 `192.168.219.45:5432` 연결은 timeout이 발생했다.
- 반대로 컨테이너 내부에서 `127.0.0.1:5432``172.17.0.1:5432` 연결은 성공했다.
### 3-4. stale 값의 근거는 로컬 오버라이드 `.env`였다
- `skill-rag-file/.env``DATABASE_URL=postgresql://robeings:robeings@192.168.219.45:5432/main_db`가 남아 있었다.
- `2026-03-04` 임시복구 문서에는 `192.168.219.45` 임시 IP 경로를 사용한 조치가 남아 있다.
- 따라서 현재 서비스는 SSOT 런타임 환경이 아니라 과거 임시 오버라이드 값을 우선 사용하고 있었다.
### 3-5. 실패은닉은 `rb8001` 상위 흐름에서 발생했다
- `rb8001/app/services/coldmail_processor.py`는 첨부 처리 실패를 `None` 반환으로 닫는 경로가 있었다.
- `rb8001/app/services/workflows/coldmail_workflow.py``None` 결과를 "처리 안 된 후보"로만 누락시켰다.
- `rb8001/app/scheduler/jobs/coldmail_briefing.py`는 워크플로우 예외가 없으면 성공 종료로 기록했다.
- 그래서 하위 업로드 실패가 있어도 스케줄러는 성공처럼 보였다.
### 3-6. 수정 후 검증 결과
- `skill-rag-file/.env`의 DB 호스트를 `172.17.0.1`로 교정한 뒤 실제 팀 ID `38bdc27d-cb01-4960-867e-41733d2f3529` 업로드는 `200` 응답으로 성공했다.
- 잘못된 팀 ID는 추가 검증에서 `404 Team not found`로 반환되도록 정리했다.
- `rb8001`은 처리 실패를 `processing_failures`로 수집하고, 하나라도 있으면 스케줄러 레벨에서 예외를 올리도록 바꿨다.
## 4. 배제된 가설
- "09:05 스케줄러가 아예 돌지 않았다": 거짓. 시작 로그와 내부 처리 로그가 존재한다.
- "Neo4j unavailable 경고가 직접 원인이다": 거짓. 경고는 있었지만 콜드메일 흐름은 첨부 업로드 단계까지 진행됐다.
- "첨부 PDF 자체가 손상돼서 실패했다": 직접 원인 아님. 동일 시점 `skill-rag-file` 로그의 실제 예외는 DB timeout이었다.
- "운영 DB 자체가 완전히 죽어 있었다": 거짓. 올바른 호스트 경로로는 연결 가능했고, 수정 후 업로드가 성공했다.
## 5. 해석(Interpretation)
### 5-1. 09:05 운영 실패의 직접 원인
- 직접 원인은 `skill-rag-file`이 오래된 DB 호스트 `192.168.219.45`를 사용한 것이다.
- 이 값 때문에 첨부 저장용 DB insert가 timeout으로 실패했고, 콜드메일 후보 3건 모두 문서화에 실패했다.
### 5-2. 사용자가 "안 돌았다"고 체감한 이유
- 실제 작업은 실행됐지만 핵심 산출물 생성에 모두 실패했다.
- 동시에 상위 잡이 실패를 예외로 승격하지 않아 스케줄러 성공 로그만 남았기 때문에, 운영 관측상 "안 돌았다"로 보이게 됐다.
### 5-3. 왜 `500`이 문제였는가
- 원래 원인은 DB 연결 timeout이므로 일반 `500`보다 구체적인 비가용성 오류로 분리되어야 한다.
- 또 팀 미존재 같은 입력/무결성 오류까지 `503`이나 `500`으로 뭉개면 원인성이 깨진다.
- 따라서 "연결 불가 계열만 `503`", "존재하지 않는 팀은 `404`", "콜드메일 처리 실패는 스케줄러 실패"가 맞다.
## 6. 결론
### 결론 A. 09:05 콜드메일은 실행됐지만 업무적으로 실패했다
- 스케줄러 실행 성공과 업무 성공은 달랐다.
- 운영 기준 최종 판정은 "실행은 됐고, 첨부 업로드 실패로 결과 생성에 실패"다.
### 결론 B. `skill-rag-file` 500의 단일 직접 원인은 stale DB 호스트다
- `192.168.219.45`는 과거 임시복구 경로의 잔존값이었다.
- 현재 정상 경로는 컨테이너에서 접근 가능한 `172.17.0.1:5432`다.
### 결론 C. 실패은닉의 단일 직접 원인은 `None` 기반 누락 처리다
- 하위 실패가 예외 대신 빈 결과처럼 흡수되면서 APScheduler 성공 로그가 남았다.
- 이 경로를 끊어야 운영 로그와 실제 결과가 일치한다.
## 7. 이 이슈를 닫는 기준
- `skill-rag-file` 업로드가 실제 운영 팀 ID에서 `200`이어야 한다.
- DB 연결 불가 계열만 `503`으로 남아야 한다.
- 잘못된 팀 ID는 `404`여야 한다.
- 첨부 업로드 실패가 다시 발생하면 `rb8001` 스케줄러 로그는 실패로 남아야 한다.
## 8. 남은 확인 포인트
- 현재 로컬 셸의 `pytest`는 프로젝트 런타임 의존성 경로가 맞지 않아 바로 실행되지 않았다.
- 따라서 이번 문서의 검증 근거는 컨테이너 재배포, 실제 업로드 응답 코드, 컨테이너 로그, `py_compile` 기준이다.

View File

@ -0,0 +1,202 @@
---
tags: [AI, Agent, Context-Engineering, DeepAgents, Claude-Code, MCP, Exa, Stitch, Robeing]
date: 2026-03-13
last_updated: 2026-03-13
author: Codex
---
# Context Engineering, DeepAgents, Claude Code 영상 리서치
상위 원칙:
- [writing-principles](../../../book/300_architecture/312_writing-principles.md)
관련 문서:
- [MCP & A2A 리서치 인덱스](../mcp_a2a/README.md)
- [OpenClaw 공식 문서 요약](./260205_openclaw_official_docs_summary.md)
- [LangGraph vs n8n 비교](./250925_langgraph_vs_n8n_comparison.md)
## 1. 개요
유튜브 영상 `[전현준 x 테디노트] Context Engineering 을 위한 DeepAgents 와 Agentic Coding(Claude Code)`를 기준으로, 로빙에 참고할 만한 도구와 개념을 정리합니다. 본 문서는 영상의 전체 자막을 직접 전사한 문서가 아니라, 영상 메타데이터와 사용자 제공 요약을 바탕으로 공식 1차 문서와 교차 검증한 리서치입니다.
핵심 질문은 세 가지입니다.
1. 영상에서 말하는 `Context Engineering`은 어떤 운영 원칙으로 해석하는 것이 안전한가
2. `DeepAgents`, `Claude Code`, `MCP`, `Exa`, `Stitch`는 각각 무엇을 담당하는가
3. 로빙 문서 체계와 아키텍처에서 이 내용을 어디까지 참고해야 하는가
## 2. Facts
### 2.1 영상 메타데이터
- 영상 제목: `[전현준 x 테디노트] #Context Engineering 을 위한 #DeepAgents 와 #Agentic Coding(Claude Code)`
- 채널: `테디노트 TeddyNote`
- 영상 URL: `https://www.youtube.com/watch?v=SKqCA-43nPM`
- 페이지 메타 기준 게시 시각: `2026-01-21T18:49:46-08:00`
- 한국 시간 기준으로는 `2026-01-22`
- 확인 방법:
- YouTube `oEmbed`
- YouTube 페이지 `publishDate`, `uploadDate` 메타
### 2.2 Claude Code 관련 공식 사실
- Claude Code는 CLI 기반 코딩 에이전트 워크플로우를 제공한다.
- 공식 문서에는 `hooks`, `sub-agents`, `MCP` 연동이 독립 기능으로 존재한다.
- `hooks`는 특정 이벤트 전후에 명령이나 검증을 자동 실행하는 구조다.
- `sub-agents`는 역할을 분리한 별도 에이전트를 선언해 작업을 위임하는 구조다.
- `MCP`는 외부 도구와 컨텍스트 소스를 표준 방식으로 연결하는 인터페이스로 안내된다.
공식 출처:
- https://docs.anthropic.com/en/docs/claude-code/hooks
- https://docs.anthropic.com/en/docs/claude-code/sub-agents
- https://docs.anthropic.com/en/docs/claude-code/mcp
### 2.3 DeepAgents 관련 공식 사실
- DeepAgents는 LangChain 측에서 소개하는 에이전트 하네스 성격의 프레임워크다.
- 핵심 개념으로 `planning`, `subagents`, `files`, `stateful execution`이 제시된다.
- 긴 작업을 한 번의 대화에 모두 밀어넣기보다, 계획과 파일 기반 상태를 분리해 유지하는 흐름을 강조한다.
공식 출처:
- https://www.langchain.com/deep-agents
- https://docs.langchain.com/oss/python/deepagents/overview
- https://docs.langchain.com/oss/python/deepagents/subagents
### 2.4 MCP 관련 공식 사실
- MCP(Model Context Protocol)는 모델과 도구, 리소스, 프롬프트 서버를 연결하기 위한 개방형 프로토콜이다.
- 로컬 파일, API, 데이터베이스, 사내 도구를 통일된 방식으로 노출하는 데 초점이 있다.
- 이미 로빙 문서에도 MCP 관련 리서치가 축적되어 있다.
공식 출처:
- https://modelcontextprotocol.io/introduction
- https://modelcontextprotocol.io/specification/2025-06-18
### 2.5 Exa 관련 공식 사실
- Exa는 AI 에이전트용 웹 검색 및 콘텐츠 수집 API를 제공한다.
- 일반 검색 결과 목록만이 아니라, 실제 본문 수집과 구조화된 검색 결과를 제공하는 방향으로 문서화되어 있다.
- 최신 기술 문서나 웹 근거 수집에 사용할 수 있다.
공식 출처:
- https://exa.ai/exa-api
- https://docs.exa.ai/reference/search
### 2.6 Stitch 관련 공식 사실
- Stitch는 Google이 공개한 UI 설계/프론트엔드 생성 도구 계열로 소개된다.
- 프롬프트나 시각 입력을 바탕으로 UI 목업과 프론트엔드 코드 생성을 지원하는 방향으로 발표되었다.
- 영상에서 디자인 보조 도구로 언급되었다면 맥락상 자연스럽다.
공식 출처:
- https://developers.googleblog.com/stitch-a-new-way-to-design-uis/
### 2.7 이번 확인 범위에서 공식 출처를 확정하지 못한 항목
- `MGrab`
- `Clarify`
- `Oh My Claude Code`
위 세 항목은 사용자 제공 요약에는 등장하지만, 이번 작업에서는 공식 1차 출처를 확인하지 못했다. 따라서 로빙 SSOT나 원칙 문서에는 확정 도구처럼 올리지 않는 편이 안전하다.
## 3. Interpretation
### 3.1 영상의 핵심은 모델 성능보다 하네스 설계다
영상 제목과 도구 구성을 교차하면, 핵심 메시지는 "더 좋은 모델" 단독보다 "계획, 파일, 도구 연결, 역할 분리"를 포함한 하네스가 실제 생산성을 좌우한다는 주장으로 해석하는 것이 타당하다.
이 해석은 DeepAgents의 파일 기반 상태 유지, Claude Code의 hooks/sub-agents/MCP 구조와 정합적이다. 즉, 프롬프트 한 장으로 모든 문제를 해결하려 하기보다:
- 계획을 별도로 유지하고
- 외부 지식을 도구로 연결하고
- 작업 단위를 분리하고
- 검증을 자동화하는 방향
`Context Engineering`의 실무 해석에 가깝다.
### 3.2 Context Engineering은 프롬프트 문구 작성보다 운영 구조 설계에 가깝다
이번 영상 맥락에서 `Context Engineering`은 단순히 프롬프트를 예쁘게 쓰는 기술이 아니다. 더 안전한 정의는 아래와 같다.
- 어떤 정보를 항상 메모리에 둘지 결정한다.
- 어떤 정보는 파일이나 도구 호출로 늦게 가져올지 결정한다.
- 어떤 작업은 별도 에이전트에 위임할지 결정한다.
- 어떤 시점에 lint, test, search, review를 자동 실행할지 결정한다.
즉 로빙에서 말하면, `컨텍스트 설계 = 프롬프트 + 문서 + 파일 + 도구 + 검증 루프` 전체를 아우르는 운영 설계다.
### 3.3 도구별 역할 분리는 아래 정도로 정리하는 것이 안전하다
| 도구/개념 | 안전한 해석 | 로빙 적용 포인트 |
|---|---|---|
| Claude Code | 코딩 작업용 에이전트 CLI. 훅, 서브에이전트, MCP 연결 지원 | 코드 수정, 테스트, 리뷰 자동화 패턴 참고 |
| DeepAgents | 긴 작업을 계획/파일/서브에이전트로 분리하는 하네스 | 장기 작업, 문서 기반 상태 유지, 분업 구조 참고 |
| MCP | 도구/리소스 연결 표준 | 로빙 내부 skill, DB, 파일 접근 표준화 참고 |
| Exa | 최신 웹 근거 수집용 검색 API | 외부 문서 리서치, 최신 기술 검증 |
| Stitch | UI 초안/프론트엔드 생성 도구 | 디자인 프로토타입 실험 |
### 3.4 자동 compact 비활성화 조언은 "파일로 상태를 빼라"는 실무 팁으로 해석하는 편이 맞다
사용자 제공 요약에는 자동 compact를 조심하라는 조언이 있다. 이번 작업에서는 해당 발언 자체를 공식 문서로 확정하지는 못했지만, 방향성은 충분히 합리적이다.
긴 작업에서 상태 요약을 모델 내부 메모리에만 의존하면:
- 중요한 세부가 누락될 수 있고
- 요약 품질이 불안정할 수 있으며
- 회귀 추적이 어려워진다
따라서 작업 상태를 Markdown 문서, 계획 파일, 리서치 파일처럼 외부 파일에 저장하는 방식은 로빙 SSOT와도 잘 맞는다.
## 4. Unresolved
- 영상 전체 자막을 직접 확보하지 못해, 발언 단위의 정확한 워딩은 이번 문서에서 확정하지 않았다.
- `MGrab`, `Clarify`, `Oh My Claude Code`가 실제로 어떤 제품을 가리키는지, 또는 영상 내 비공식 별칭인지 추가 확인이 필요하다.
- 영상에서 `Stitch`를 어떤 깊이로 다뤘는지, 단순 예시인지 실제 추천 도구인지는 자막 확인 전까지 보류가 안전하다.
## 5. 로빙 적용 권장선
### 5.1 바로 문서화해도 되는 수준
- Context Engineering을 "프롬프트 문구"가 아니라 "문서/파일/도구/검증 루프 설계"로 해석하는 것
- MCP를 내부 도구 연결 표준 후보로 계속 추적하는 것
- Claude Code/DeepAgents 사례를 통해 하네스 중심 설계를 연구 대상으로 축적하는 것
### 5.2 아직 원칙 문서로 승격하면 이른 수준
- `MGrab`, `Clarify`, `Oh My Claude Code`를 로빙 표준 도구 목록으로 고정하는 것
- 영상의 개별 발언을 자막 검증 없이 확정적 문장으로 옮기는 것
- 특정 상용 도구 선택을 구조 원칙처럼 일반화하는 것
## 6. 문서 배치 판단
이 주제는 문제 해결 기록이 아니므로 `troubleshooting` 대상이 아니다. 또한 실행 순서를 고정한 문서도 아니므로 `plans`도 아니다. 현재로서는 `orchestration_tools` 아래 리서치 문서가 가장 자연스럽다.
배치 이유:
- 도구 비교와 하네스 설계 관점이 중심이다.
- 로빙에 즉시 적용할 실행안보다, 구조 해석과 참조 정리가 중심이다.
- MCP 자체를 깊게 파는 문서가 아니라, 여러 에이전트 코딩 도구를 묶어 해석하는 문서다.
## 7. 결론
이번 영상은 "좋은 모델을 고르는 문제"보다 "좋은 하네스를 설계하는 문제"를 강조하는 자료로 보는 것이 맞다. 공식 문서로 확정 가능한 부분은 `Claude Code`, `DeepAgents`, `MCP`, `Exa`, `Stitch` 정도이며, 나머지 도구명은 보류가 안전하다.
로빙 관점에서는 이 영상을 다음 한 줄로 요약할 수 있다.
`에이전트 품질은 프롬프트 단독이 아니라 계획, 파일, 도구 연결, 역할 분리, 검증 자동화로 결정된다.`
## 8. 출처
- YouTube oEmbed: https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=SKqCA-43nPM&format=json
- YouTube 영상 페이지: https://www.youtube.com/watch?v=SKqCA-43nPM
- Anthropic Claude Code Hooks: https://docs.anthropic.com/en/docs/claude-code/hooks
- Anthropic Claude Code Sub-agents: https://docs.anthropic.com/en/docs/claude-code/sub-agents
- Anthropic Claude Code MCP: https://docs.anthropic.com/en/docs/claude-code/mcp
- LangChain DeepAgents 소개: https://www.langchain.com/deep-agents
- LangChain DeepAgents Overview: https://docs.langchain.com/oss/python/deepagents/overview
- LangChain DeepAgents Subagents: https://docs.langchain.com/oss/python/deepagents/subagents
- MCP Introduction: https://modelcontextprotocol.io/introduction
- MCP Specification: https://modelcontextprotocol.io/specification/2025-06-18
- Exa API: https://exa.ai/exa-api
- Exa Search API Reference: https://docs.exa.ai/reference/search
- Google Stitch 소개: https://developers.googleblog.com/stitch-a-new-way-to-design-uis/

View File

@ -7,3 +7,4 @@
- [OpenClaw 공식 문서 요약](260205_openclaw_official_docs_summary.md) — docs.openclaw.ai 요약 및 로빙 적용 우선순위
- [로빙 에이전트 루프·스킬 훅·LLM 실행 구조 리서치](260312_로빙_에이전트루프_스킬훅_LLM실행구조_리서치.md) — LLM API, 에이전트 런타임, 스킬 계약, 훅 구조를 로빙 기준으로 정리
- [로빙 LLM API·Agent API·모델 선정·비용 비교 리서치](260312_로빙_LLM_API_Agent_API_모델선정_비용비교_리서치.md) — Gemini/OpenAI 계열 비교, 비용 문서화 원칙, 로빙 기준 모델 선택 방향 정리
- [Context Engineering, DeepAgents, Claude Code 영상 리서치](260313_컨텍스트엔지니어링_딥에이전트_클로드코드_영상리서치.md) — 유튜브 영상의 도구 설명을 공식 문서와 교차 검증한 리서치

View File

@ -1,131 +1,6 @@
# 250801 크론잡 로그 동기화 설정
# 250801_claude_크론잡로그동기화설정
## 배경
이 문서는 인프라 기준 문서로 이관되었습니다.
### 이전 문서 참조
- [250731_로그저장소_SSHFS설정과_템플릿해결책.md](./250731_로그저장소_SSHFS설정과_템플릿해결책.md)
- [250731_claude_SSHFS권한문제해결.md](./250731_claude_SSHFS권한문제해결.md)
### 문제 상황
- Docker SSHFS 충돌로 중앙 로그 시스템 구축 실패
- 로그가 51124 서버 SSD에 저장되고 있음 (CLAUDE.md 규칙 위반)
- SSHFS 마운트는 되어있지만 Docker 볼륨 마운트 시 충돌 발생
## 해결 방안: 크론잡 동기화
### 오전 9시 30분 - 새로운 접근 방식 결정
로컬 개발자 제안: "24서버에 로그 저장하고 하루에 한번씩 크론잡으로 HDD로 넘기는 건 어때?"
장점:
1. Docker 설정 변경 불필요
2. SSHFS 충돌 없음
3. SSD 쓰기 성능 활용
4. 배포 시 추가 작업 불필요
5. 로그 손실 위험 감소
### 오전 9시 35분 - 스크립트 작성
```bash
# 스크립트 디렉토리 생성
mkdir -p /home/admin/scripts
# 동기화 스크립트 작성
/home/admin/scripts/sync_logs_to_hdd.sh
```
초기 실행 시 권한 문제 발생:
- `/var/log/sync_logs` 생성 실패 (Permission denied)
- `/home/admin/logs/sync_logs`로 변경하여 해결
### 오전 9시 38분 - SSHFS 권한 문제 발견
```
rsync: [receiver] mkstemp failed: Permission denied (13)
```
원인: SSHFS가 UID 999(docker)로 마운트되어 admin(UID 1001)이 쓸 수 없음
해결:
1. SSHFS를 UID/GID 매핑으로 재마운트
```bash
fusermount -u /mnt/51123logs
sshfs -o IdentityFile=/home/admin/.ssh/id_rsa_deploy,reconnect,uid=$(id -u),gid=$(id -g) \
admin@192.168.219.45:/mnt/hdd/logs/51124-server /mnt/51123logs -p 51123
```
2. 51123 서버에서 디렉토리 권한을 admin으로 변경 (로컬 개발자가 수행)
### 오전 9시 41분 - 동기화 성공
모든 서비스 로그 동기화 완료:
- rb10508_test: 474,540 bytes 동기화
- rb10408_test: 0 bytes 동기화
- rb8001: 18,751 bytes 동기화
- skill_news: 125 bytes 동기화
- skill_email: 로그 디렉토리 없음
### 오전 9시 42분 - 크론탭 설정
```bash
# 크론탭 설정 (매일 새벽 3시)
0 3 * * * /home/admin/scripts/sync_logs_to_hdd.sh >> /home/admin/logs/sync_logs/cron.log 2>&1
```
## 최종 구조
### 51124 서버 (원본)
```
/home/admin/ivada_project/
├── rb10508_test/logs/
├── rb10408_test/logs/
├── rb8001/logs/
├── skill_news/logs/
└── skill_email/logs/
```
### 51123 서버 (백업)
```
/mnt/hdd/logs/51124-server/
├── rb10508_test/
├── rb10408_test/
├── rb8001/
├── skill_news/
└── skill_email/
```
## 발견된 문제
### rb10508_test 중복 디렉토리 구조
51124 서버에 이미 중복 구조 존재:
```
/home/admin/ivada_project/rb10508_test/logs/
├── rb10508_test_app.log
└── rb10508_test/
└── rb10508_test_app.log (0 bytes)
```
이는 Docker 볼륨 마운트나 애플리케이션 설정 문제로 추정됨.
## 결과
1. **로그 백업 자동화 완성**: 매일 새벽 3시에 자동 실행
2. **SSD 공간 관리**: 7일 이상된 로컬 로그 자동 삭제
3. **CLAUDE.md 준수**: 로그가 최종적으로 HDD에 저장됨
4. **Docker 충돌 회피**: SSHFS 마운트 포인트와 Docker 볼륨 충돌 없음
## 교훈
1. **복잡한 해결책보다 간단한 방법이 낫다**: Docker SSHFS 통합보다 크론잡이 더 안정적
2. **권한 문제는 여러 레벨에서 발생**: SSHFS UID 매핑과 원격 디렉토리 권한 모두 확인 필요
3. **점진적 마이그레이션**: 실시간 동기화보다 배치 처리가 더 안전할 수 있음
4. **로그 파일 경로 정리 필요**: 중복 디렉토리 구조는 추후 정리 필요
---
작성일: 2025-08-01 09:30 - 09:45
작성자: Claude (51124 서버)
주제: Docker SSHFS 충돌 회피를 위한 크론잡 로그 동기화 설정
---
**2025-09-08 업데이트**:
- rb8001 파일 로깅 구현 완료 (app/core/logger.py)
- rb8001/logs/rb8001.log 생성 확인 (7.6KB)
- 내일 새벽 3시 크론잡에 자동 포함됨
- HDD 동기화 문제 해결 완료
- 새 위치: <https://git.ro-being.com/ivada-infra/DOCS/src/branch/main/journey/troubleshooting/250801_%ED%81%AC%EB%A1%A0%EC%9E%A1%EB%A1%9C%EA%B7%B8%EB%8F%99%EA%B8%B0%ED%99%94%EC%84%A4%EC%A0%95.md>
- 이유: 51123/51124 간 로그 저장소 마운트, SSHFS 권한, 크론 동기화 구조는 프로젝트 기능 이슈가 아니라 인프라 운영 이슈이기 때문입니다.

View File

@ -0,0 +1,50 @@
# 콜드메일 `skill-rag-file` 500과 실패가시성 복구
tags: [coldmail, skill-rag-file, rb8001, postgres, scheduler, troubleshooting]
**날짜**: 2026-03-10
**작성자**: Codex
**관련 파일**: `rb8001/app/services/coldmail_processor.py`, `rb8001/app/services/workflows/coldmail_workflow.py`, `rb8001/app/scheduler/jobs/coldmail_briefing.py`, `rb8001/tests/test_coldmail_failure_visibility.py`, `skill-rag-file/app/api/upload.py`, `skill-rag-file/.env`
**상위 원칙**: [전역 원칙](../../../../0_VALUE/00_Principles/global-principles.md), [문서 작성 원칙](../../book/300_architecture/312_writing-principles.md), [Backend Coding Principles](../../book/300_architecture/311_backend_coding_principles.md)
## 관련 문서
- [콜드메일 `skill-rag-file` 500 및 실패은닉 원인확정 리서치](../research/260310_콜드메일_skill_rag_file_500_및_실패은닉_원인확정_리서치.md)
- [9시 네이버 이메일 분석 미전송과 실패 은닉 해결](./260309_9시_네이버이메일분석_미전송_실패은닉_해결.md)
- [51123 임시복구 서비스 연속성 조치내역](../../../../infra/DOCS/journey/troubleshooting/260304_51123_임시복구_서비스연속성_조치내역.md)
---
## 문제 상황
- `2026-03-10 09:05` KST 콜드메일 작업은 실제 실행됐지만, 첨부 PDF 업로드가 전부 실패해 결과가 0건으로 끝났다.
- `skill-rag-file``POST /api/upload`에서 `500 Internal Server Error`를 반환했고, 실제 스택트레이스는 DB timeout이었다.
- `rb8001` 상위 흐름은 이 실패를 예외로 올리지 않아 APScheduler에는 성공처럼 보였다.
## 근본 원인
- `skill-rag-file/.env`가 과거 임시복구용 DB 주소 `192.168.219.45:5432`를 계속 우선 사용하고 있었다.
- 현재 서버에서 해당 주소는 더 이상 유효하지 않아 DB insert 시 timeout이 발생했다.
- `rb8001`은 첨부 처리 실패를 `None`으로 흡수해 "0건 처리"로만 닫는 구조였다.
## 조치
- `skill-rag-file/.env``DATABASE_URL` 호스트를 `172.17.0.1`로 교정했다.
- `skill-rag-file/app/api/upload.py`에서 DB 비가용성 예외만 `503`으로 분리하고, 없는 `team_id``404`로 반환하도록 정리했다.
- `rb8001/app/services/coldmail_processor.py`에서 첨부 처리 실패를 `ColdmailProcessingError`로 승격했다.
- `rb8001/app/services/workflows/coldmail_workflow.py`에서 실패 목록을 `processing_failures`로 수집하게 바꿨다.
- `rb8001/app/scheduler/jobs/coldmail_briefing.py`에서 실패 목록이 있으면 예외를 다시 올리도록 바꿨다.
- `rb8001/tests/test_coldmail_failure_visibility.py`를 추가해 실패 수집과 스케줄러 예외 승격을 검증했다.
## 검증
- `python3 -m py_compile``rb8001` 변경 파일, `skill-rag-file/app/api/upload.py`, 테스트 파일 컴파일을 확인했다.
- `docker compose ... up -d --build``rb8001`, `skill-rag-file` 재배포를 완료했다.
- 실제 팀 ID `38bdc27d-cb01-4960-867e-41733d2f3529` 업로드 응답은 `200`이었다.
- 없는 팀 ID `00000000-0000-0000-0000-000000000001` 업로드 응답은 `404`였다.
- 재검증 시 `skill-rag-file` 로그에는 더 이상 DB timeout 기반 `500`이 남지 않았다.
## 구현 결과
- 콜드메일 첨부 업로드 실패는 더 이상 스케줄러 성공으로 숨겨지지 않는다.
- `skill-rag-file`의 상태코드가 원인성에 맞게 정리됐다.
- 오늘 09:05 장애의 직접 원인인 stale DB host 경로는 제거됐다.
## 교훈
- 서비스별 `.env` 오버라이드는 SSOT 런타임 값을 덮기 때문에, 임시복구 값이 남아 있으면 후속 장애의 직접 원인이 된다.
- 외부/하위 서비스 실패를 `None`이나 `0건`으로 흡수하면 운영 판단이 틀어진다.
- 비가용성, 입력 오류, 무결성 오류는 서로 다른 상태코드로 유지해야 원인 추적이 가능하다.