# 프로젝트 분석 보고서: grpccanary ## 1. 개요 `grpccanary`는 **Go 언어로 JSON 처리 → HTTP 서버 → gRPC 서버/클라이언트로 이어지는 학습 여정을 다루는 한국어 튜토리얼 저장소**입니다. 저장소 이름(`grpccanary`)과 달리 실제 내용은 gRPC 단일 주제가 아니라, "데이터 직렬화(JSON) → 웹 서버(HTTP/gin) → 원격 프로시저 호출(gRPC)"로 난이도를 높여가는 3단계 실습 커리큘럼이며, 현재는 **gRPC 파트가 가장 완성도 높게 구현**되어 있습니다. 저장소 루트에는 이 학습 프로젝트와는 성격이 다른 **`multi-agent-mux`라는 다중 에이전트(Claude Code) 오케스트레이션 인프라**가 함께 자리 잡고 있습니다(`.agents/`, `.mam/` 디렉토리). 이 인프라는 tmux 세션 + MQTT 메시지 브로커를 이용해 여러 AI 에이전트(팀장/리뷰어 역할)가 하나의 작업 저장소를 공유하며 협업하도록 설계된 별도의 도구 체계이며, 실제로 이 보고서를 작성하는 작업(`job 702ea1d8`) 자체도 이 인프라를 통해 위임되었습니다. 즉 이 저장소는 **"gRPC를 배우기 위한 Go 예제 코드"**와 **"그 예제 코드를 여러 AI 에이전트가 함께 작업하도록 돕는 협업 프레임워크"**가 한 저장소 안에 공존하는 구조입니다. --- ## 2. 저장소 구조 ``` grpccanary/ ├── README.md # 메인 튜토리얼 (JSON/HTTP/gRPC 개념 설명 + 실행 가이드, 한국어) ├── AGENTS.md # LLM 코딩 행동 지침 (일반 원칙) ├── go.mod / go.sum # Go 모듈 정의 (module grpccanary, go 1.25.4) ├── protoapi.proto # gRPC 서비스 IDL(Protocol Buffers) 정의 원본 ├── protoapi/ # protoc로 생성된 Go stub 코드 │ ├── protoapi.pb.go # 메시지 타입 (protoc-gen-go) │ └── protoapi_grpc.pb.go # 서비스/클라이언트 stub (protoc-gen-go-grpc) ├── obj.json # JSON 예제용 샘플 데이터 파일 ├── examples/ │ ├── main.go # 실행 진입점 (현재는 JSON 예제만 호출하도록 설정됨) │ ├── jsonexample/ │ │ └── json_parser.go # encoding/json 마샬링·언마샬링 예제 │ ├── httpentity/ │ │ ├── server.go # gin 기반 HTTP 서버 (전체가 주석 처리된 미완성 스텁) │ │ └── client.go # 패키지 선언만 있는 빈 파일 │ └── grpcentity/ │ ├── server.go # gRPC 서버 구현 (Random 서비스) │ ├── client.go # gRPC 클라이언트 구현 │ └── README.md # gRPC 서버/클라이언트 구현 상세 해설 (한국어) ├── docs/ │ └── Working with JSON/ │ ├── README.md # JSON 관련 학습 자료 (영문) │ └── README-kr.md # JSON 관련 학습 자료 (한글) ├── scripts/ │ └── generate-env.sh # .env.example → .env 복사 스크립트 (멀티에이전트 인프라용) ├── .env.example # 멀티에이전트 인프라(MQTT 브로커 등) 설정 템플릿 ├── .agents/ # 멀티에이전트 오케스트레이션 규칙·스킬 (아래 4절 참고) └── .mam/ # 멀티에이전트 잡(Job) 레지스트리 및 세션 상태 (런타임 산출물) ``` 빌드 확인 결과 `go build ./...` 및 `go vet ./...` 모두 오류 없이 통과했으며, 테스트 파일(`*_test.go`)은 저장소에 존재하지 않습니다. --- ## 3. 핵심 구성 요소 (학습용 Go 코드) ### 3.1 진입점 — `examples/main.go` - 프로젝트의 유일한 `main()` 함수. `var port = ":8080"`을 정의하고 있으며, 기본 상태에서는 `jsonexample.JsonParsingExample()`만 호출합니다. - gRPC 예제를 실행하려면 README.md 안내에 따라 `main()` 내부를 수동으로 편집해 `grpcSample()`을 호출하도록 바꿔야 합니다(미사용 import 오류 방지를 위해 `jsonexample` import를 주석 처리해야 함). 즉 **하나의 코드베이스 안에서 학습 단계별로 진입점을 수동 전환하는 방식**으로 설계되어 있습니다. - `grpcSample()` 함수는 `entity.ServerRun(port)`를 고루틴으로 백그라운드 실행한 뒤 1초 대기 후 `entity.ClientRun(...)`을 호출해, 같은 프로세스 안에서 서버·클라이언트가 통신하는 데모를 구성합니다. ### 3.2 JSON 파싱 예제 — `examples/jsonexample/json_parser.go` - `encoding/json` 표준 라이브러리를 이용해 (1) `map[string]interface{}` ↔ JSON 문자열 변환, (2) 구조체(`Person`) ↔ JSON 변환의 마샬링/언마샬링을 시연합니다. - 외부 의존성 없이 표준 라이브러리만 사용하는 가장 단순한 예제로, 커리큘럼의 1단계 역할을 합니다. ### 3.3 HTTP 서버 예제 — `examples/httpentity/` - `server.go`는 `gin-gonic/gin`을 이용한 REST API 서버(정적 파일 서빙 + `/api/randomNumber`, `/api/randomPassword`, `/api/randomDate` 라우트) 초안이 **전체 주석 처리**된 상태로만 존재합니다. 즉 코드는 작성되어 있으나 활성화되지 않은 미완성/보류 상태입니다. - `client.go`는 `package httpentity` 선언 한 줄만 있는 빈 파일입니다. - `go.mod`에는 `gin-gonic/gin` 의존성이 여전히 선언되어 있어, 이 파트가 완전히 폐기된 것이 아니라 추후 재개를 염두에 둔 진행 중(work-in-progress) 상태로 보입니다. ### 3.4 gRPC 서비스 정의 — `protoapi.proto` - `proto3` 문법으로 `Random`이라는 gRPC 서비스를 정의하며 3개의 RPC 메서드를 제공합니다. - `GetDate(RequestDateTime) returns (DateTime)` — 서버의 현재 날짜/시간 반환 - `GetRandom(RandomParams) returns (RandomInt)` — 시드(Seed)와 위치(Place)를 기반으로 한 의사난수 생성 - `GetRandomPass(RequestPass) returns (RandomPass)` — 시드와 길이(Length)를 받아 무작위 ASCII 비밀번호 생성 - `option go_package = "./protoapi/;protoapi"`로 지정되어 있어, `protoc` 컴파일 시 `protoapi/` 디렉토리에 Go 패키지 `protoapi`가 생성됩니다. - 이미 컴파일된 stub(`protoapi/protoapi.pb.go`, `protoapi/protoapi_grpc.pb.go`)이 저장소에 커밋되어 있어 `protoc` 재설치 없이 바로 빌드/실행이 가능합니다. ### 3.5 gRPC 서버 구현 — `examples/grpcentity/server.go` - `RandomServer` 구조체가 `protoapi.UnimplementedRandomServer`를 임베딩하여 3개 RPC 메서드(`GetDate`, `GetRandom`, `GetRandomPass`)를 구현합니다. - `getString(len int64)`은 ASCII 코드 `!`(33)부터 94개 범위 내에서 문자를 뽑아 임의 문자열(비밀번호)을 생성하는 헬퍼입니다. - `ServerRun(addr string)`이 `grpc.NewServer()`로 서버를 만들고 `reflection.Register(server)`로 gRPC reflection(예: `grpcurl` 같은 외부 CLI 디버깅 도구 지원)을 활성화한 뒤 TCP 포트를 리슨합니다. - **주의(코드상 특이점)**: `ServerRun`은 인자로 받은 `addr`을 실제로 사용하지 않고 패키지 전역 변수 `port = ":8080"`으로 리슨합니다(`net.Listen("tcp", port)`). 따라서 현재 코드는 항상 `:8080`에서만 동작하며, 호출부에서 다른 포트를 넘겨도 무시됩니다. - `rand.Seed(r.GetSeed())`(패키지 전역 시드 설정, Go 1.20+에서는 deprecated)와 `rand.NewSource`를 혼용하고 있어 스레드 안전성이나 API 일관성 측면에서 다소 오래된 패턴을 보입니다(학습용 예제이므로 의도된 단순화로 판단됨). ### 3.6 gRPC 클라이언트 구현 — `examples/grpcentity/client.go` - `grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))`로 평문(TLS 미적용) 채널을 생성합니다(로컬 테스트 목적). - `AskingDateTime`, `AskPass`, `AskRandom` 세 개의 래퍼 함수가 각각 대응하는 RPC를 호출합니다. - `ClientRun(addr)`이 실행 엔트리포인트로, 날짜/시간 조회 1회, 비밀번호 생성 1회, 서로 다른 파라미터로 난수 생성 2회를 순차 호출하며 결과를 표준 출력으로 출력합니다. ### 3.7 문서 자료 - **`README.md`(루트)**: 이야기체(스타트업 개발자 '민우'의 사례)로 gRPC 도입 배경(REST/JSON의 한계, Protobuf 계약, HTTP/2)을 설명한 뒤, Go 버전 요구사항(1.25.4+), 의존성 설치, `main.go` 수동 편집 방법, 실행 명령(`go run ./examples`), 기대 출력 예시, 트러블슈팅(포트 충돌, 모듈 로드 오류)까지 안내하는 실행 가이드로 구성되어 있습니다. - **`examples/grpcentity/README.md`**: `.proto` 파일 문법 요소별 상세 해설, `protoc`/`protoc-gen-go`/`protoc-gen-go-grpc` 설치 및 컴파일 절차, 서버·클라이언트 코드의 구현 단계별 설명을 담은 심화 가이드입니다. - **`docs/Working with JSON/`**: JSON 관련 별도 학습 자료(영/한 병기)가 준비되어 있으나, 루트 README와 직접 링크되어 있지는 않습니다. --- ## 4. 두 번째 레이어 — 멀티에이전트 오케스트레이션 인프라 저장소에는 학습 콘텐츠와 무관한 **AI 에이전트 협업 인프라**가 함께 포함되어 있습니다. - **`AGENTS.md`**: 일반적인 LLM 코딩 행동 지침(가정하지 말 것, 최소 변경, 외과적 수정 등)을 규정합니다. - **`.agents/MULTI_AGENT_RULES.md`(+ 한국어판)**: MQTT 메시징 백플레인과 tmux 기반 다중 에이전트 협업 프로토콜을 정의합니다. 총괄 매니저(Orchestrator) → 팀장(개발/리뷰) → 작업 위임 및 리뷰 루프 → 완료 보고로 이어지는 워크플로우, Job 레지스트리(`​.mam/jobs/.json`, `fcntl` 파일 락), 세션 레지스트리(`.mam/agent-sessions.db`, SQLite WAL), HMAC-SHA256 기반 메시지 인증(PoC 모드에서는 비활성) 등을 상세히 규정합니다. - **`.agents/skills/`**: `multi-agent-mux-{create,delegate-job,loop,monitor,resume,status,stop}` 등 실제 세션 생성·작업 위임·모니터링·중지를 수행하는 스킬(스크립트) 모음입니다. - **`.mam/`**: 위 인프라의 런타임 상태 저장소로, `jobs/`(작업 레지스트리 및 브리프 파일), `agent-sessions.yaml`/`.db`(세션 상태), `agent_homes/`(에이전트별 메모리), `delegate_job_logs/`(위임 감사 로그)를 포함합니다. 이번 작업 브리프(`​.mam/jobs/702ea1d8/brief.md`) 역시 이 구조를 통해 전달되었습니다. - **`scripts/generate-env.sh`, `.env.example`**: 이 인프라가 사용하는 MQTT 브로커 접속 정보, 경로 설정 등을 `.env`로 초기화하는 헬퍼입니다. 실제 비밀 값은 `.env`(git-ignored)에만 두고 `.env.example`에는 플레이스홀더만 커밋하도록 설계되어 있습니다. **참고**: 새로 추가된 `.gitignore`는 `.agents/`, `.mam/`, `.env`, `AGENTS.md` 등을 앞으로 git 추적 대상에서 제외하도록 지정하고 있습니다. 다만 `git log`를 보면 `AGENTS.md`, `examples/grpcentity/README.md` 등은 과거 커밋(`init 251117`, `update 260609`, 이후 docs 커밋들)에서 이미 저장소에 커밋되어 있으므로, 이번 `.gitignore` 추가는 향후 신규/변경 파일이 실수로 다시 커밋되는 것을 막기 위한 조치로 보입니다(기존에 추적 중인 파일을 소급 제외하지는 않음). --- ## 5. 실행 방법 ### 5.1 사전 준비 ```bash go version # Go 1.25.4 이상 필요 go mod download # 의존성 다운로드 ``` ### 5.2 JSON 예제 실행 (기본값, 별도 수정 불필요) ```bash go run ./examples ``` `examples/main.go`가 기본적으로 `jsonexample.JsonParsingExample()`만 호출하므로, 별도 수정 없이 바로 JSON 마샬링/언마샬링 결과가 콘솔에 출력됩니다. ### 5.3 gRPC 예제 실행 (수동 편집 필요) 1. `examples/main.go`를 열어 `jsonexample` import를 주석 처리하고 `main()` 안에서 `grpcSample()`을 호출하도록 변경. 2. 저장 후 실행: ```bash go run ./examples ``` 3. 내부적으로 `:8080` 포트에서 gRPC 서버(고루틴)가 기동되고, 1초 후 클라이언트가 `GetDate`, `GetRandomPass`, `GetRandom`(2회) 순으로 RPC를 호출하며 결과를 출력합니다. 4. 포트 충돌 시(`bind: address already in use`) `examples/grpcentity/server.go`의 `port` 전역 변수를 변경해야 합니다(3.5절에서 언급했듯 `ServerRun`의 `addr` 인자는 무시되므로, 포트 변경은 이 전역 변수 수정으로만 가능). ### 5.4 HTTP 예제 `httpentity` 패키지는 서버 로직 전체가 주석 처리되어 있고 클라이언트 파일은 비어 있어, 현재 상태로는 실행 가능한 산출물이 없습니다. 향후 주석을 해제하고 `main.go`에 호출부를 추가해야 실습이 가능합니다. ### 5.5 `.proto` 재컴파일 (선택) `.proto` 정의를 수정하고 stub을 재생성하려면: ```bash protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. \ --go-grpc_opt=paths=source_relative protoapi.proto ``` 사전에 `protoc`, `protoc-gen-go`, `protoc-gen-go-grpc`가 설치되어 있어야 합니다(설치 방법은 `examples/grpcentity/README.md` 참고). --- ## 6. 주요 관찰 사항 및 특이점 1. **단일 진입점, 수동 전환 방식**: `examples/main.go`가 유일한 실행 지점이며, 학습 단계(JSON/HTTP/gRPC)를 전환하려면 코드를 직접 편집해야 합니다. 각 예제를 독립적으로 실행할 수 있는 별도 커맨드나 플래그는 없습니다. 2. **`ServerRun(addr)`의 `addr` 인자 미사용**: gRPC 서버는 전달받은 인자 대신 패키지 전역 `port` 변수로 리슨하므로, 함수 시그니처와 실제 동작이 일치하지 않는 잠재적 혼동 요소입니다. 3. **HTTP 파트 미완성**: `gin` 의존성은 `go.mod`에 존재하지만 실제 코드는 비활성 상태로, 커리큘럼상 "다음 실습 예정" 단계로 보입니다. 4. **테스트 부재**: 저장소 전체에 자동화된 테스트(`*_test.go`)가 없어, 코드 정상 동작 여부는 수동 실행(`go run`)과 콘솔 출력 확인에 의존합니다. `go build ./...`, `go vet ./...`는 통과합니다. 5. **레거시 API 사용**: `rand.Seed(...)`(전역 시드 설정) 등 Go 최신 버전에서 권장되지 않는(deprecated) 패턴이 사용되고 있으나, 학습용 예제의 단순성을 위한 의도적 선택으로 보입니다. 6. **이중 성격의 저장소**: 순수 학습 콘텐츠(gRPC/JSON/HTTP 튜토리얼)와 AI 에이전트 협업 인프라(multi-agent-mux)가 한 저장소에 공존하며, 두 영역은 서로 기능적으로 독립적입니다. 협업 인프라(`​.agents/`, `.mam/`)는 이 학습 프로젝트를 대상으로 여러 AI 에이전트가 작업을 위임받고 결과를 보고하는 용도로 사용되고 있습니다(본 보고서 작성 작업 자체가 그 예시).