안녕하세요 연재 3회 를 시작 하겠습니다.
이번 회에서는 프로젝트 기초를 만들어볼겁니다. 우리가 OpenClaw 내구 구조를 파악하고 동일한 역활을 하는 구조로 프로젝트를 클론해보는 것이 목표이므로 거기에 맞는 프로젝트를 구성 하도록 하자는 목적입니다. 하나하나 따라 하다 실패하면 또 생성해보고 하면서 점점 익숙해 지니 너무 걱정마시고 절대 포기 하시 마세요 ^^ Chapter 1. 프로젝트 기초 공사 (Foundation Setup) 가장 먼저 튼튼한 기반을 다집니다. 이 프로젝트는 모든 구성 요소(서버, 앱, 플러그인)가 하나의 저장소에 있는 모노레포(Monorepo )구조를 따릅니다.
모노레포구조 란 ? 은유: 이것은 "온 가족의 짐을 하나의 거대한 트렁크에 담는 것"과 같습니다. 각자 작은 가방을 들고 다니면 잃어버리기 쉽지만, 하나로 묶어 관리하면 필요한 물건을 찾기도, 통째로 옮기기도 훨씬 쉬워지죠. (모노레포가 뭔지 까먹으셨다면? 👉 연재 1회의 '용어 미니 사전 2번' 을 다시 보고 오세요!)
1-1. 환경 설정 (Micro-Process) 1-1-0. 💡 [입문 수업] Node.js는 도대체 왜 쓰는 건가요?
자바스크립트는 들어봤는데, 노드(Node)는 또 뭐죠? Node 대해 잠깐 알아보고 진행 하도록 하죠.
- 은유: 수족관을 탈출한 자바스크립트 자바스크립트(JavaScript): 원래 브라우저(크롬, 사파리)라는 '수족관' 안에서만 살 수 있는 예쁜 물고기였습니다. 웹페이지 버튼 색을 바꾸거나 움직임을 주는 일만 할 수 있었죠.
Node.js: 이 물고기에게 **'강력한 기계 슈트'**를 입혀서 수족관 밖(컴퓨터 배경, 서버)으로 나오게 한 것입니다. 이제 자바스크립트는 수족관을 넘어 파일을 지우고, 데이터베이스를 관리하고, 서버를 운영하는 **'천하무적 일꾼'**이 되었습니다. 2. 엔진: 자전거에 페라리 엔진을 달다 (V8)
Node.js 안에는 구글 크롬에서 쓰이는 V8이라는 초고성능 엔진이 들어있습니다.
은유: 자전거(자바스크립트)에 페라리 엔진(V8)을 달아놓은 격입니다. 배우기 쉬운 가벼운 언어인데 속도는 엄청나게 빠른 마법 같은 이유가 여기에 있습니다.
- 한 줄 요약 Node.js는 "웹 브라우저 밖에서도 자바스크립트로 프로그램을 만들 수 있게 해주는 실행 환경"입니다.
우리가 만드는 OpenClaw의 든든한 '심장' 역할을 하게 될 친구입니다.
Node.js 설치: v22.12.0 이상 필수 (2장에서 이미 설치 하였음-참조용)
설명: Node.js는 자바스크립트 실행기로, 건설 현장의 작업자와 같은 역할을 합니다. 최신 LTS(Long Term Support, 장기 지원) 버전을 사용하는 이유는 비동기 I/O(입출력) 처리가 핵심인 게이트웨이 서버에 최적화되어 있기 때문입니다.
LTS란? : LTS는 "실수가 없는 노련한 베테랑 실무자"와 같습니다. 매일 새로운 기술이 쏟아지지만, 24시간 멈추지 않아야 하는 기반 시설에는 검증되지 않은 신입보다 경험 많은 베테랑이 필요하기 때문입니다.
설치 방법 (OS별 가이드)
🪟 Windows: 공식 홈페이지 (nodejs.org) 에서 LTS 버전(v22.x) 을 다운로드하여 설치합니다. (Next만 계속 누르면 됩니다)
🍎 Mac: 터미널에 brew install node@22 입력. (Homebrew가 없다면 여기 참조)
🐧 Linux: curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs
TIP 🎓 [개념 수업] 비동기 I/O (Asynchronous I/O)가 뭔가요? "맛집 웨이터의 서빙 방식" 으로 이해하면 쉽습니다.
동기(Synchronous = Blocking): 웨이터가 손님 1명에게 주문을 받습니다. 손님이 "음... 뭐 먹지?" 하고 고민하는 5분 동안 웨이터는 아무것도 안 하고 옆에 서 있습니다. 다른 손님들은 기다리다 지쳐 나갑니다.
비동기(Asynchronous = Non-Blocking): 웨이터가 주문을 받다가 손님이 고민하면 "결정되시면 벨 눌러주세요" 하고 다른 테이블로 가서 일을 합니다. 그러다 벨이 울리면(이벤트 발생) 다시 와서 주문을 받습니다.
Why? 왜?: OpenClaw 게이트웨이는 수천 명의 사용자가 동시에 메시지를 보냅니다. 한 명 메시지 처리하느라 다른 사람들을 기다리게 하면 안 되겠죠? 그래서 Node.js의 비동기 방식이 필수입니다.
Language: TypeScript (^5.9.3): 설명: TypeScript(타입스크립트)는 거대한 모노레포(Monorepo, 단일 저장소) 프로젝트의 타입 안정성을 보장하는 엄격한 문법 검사기입니다. 인터페이스(Interface, 약속된 규격) 기반 설계가 필수적인 대규모 프로젝트에서 타입 오류를 사전에 방지합니다.
비유 (인터페이스란?): 인터페이스는 "부품 규격 약속"과 같습니다. 전구가 소켓에 딱 맞아야 불이 들어오듯, "이 코드에는 반드시 이런 모양의 데이터가 들어와야 한다"는 약속을 미리 정해두는 것입니다.
설치 방법: 윈도우/맥 공통 터미널에서 아래 명령어를 입력하세요.( 2장에서 설치 완료 하였습니다. 자세한 이해를 위해 참조 하세요.)
npm install -g typescript
tsc -v
은유 (Metaphor): "철저한 설계도 감리사"
일반 자바스크립트가 "일단 건물을 짓고 나중에 무너지면 고치자"는 식이라면, 타입스크립트는 "벽돌 하나를 쌓을 때마다 설계도(Type)와 일치하는지 확인" 합니다. 조금 귀찮을 수 있지만, 나중에 건물이 무너지는(런타임 에러) 대형 사고를 99% 막아줍니다.
실사용 예제 (Concept Class) :
자바스크립트 (무책임): [사과] + 100 = "사과100" (이상하지만 에러 없이 진행됨)
타입스크립트 (책임감): "잠깐! 과일(String)에 숫자(Number)를 더하다니요? 말도 안 됩니다!" 하고 빨간 줄을 쫙 그어줍니다.
pnpm 설치 : (2장에서 설치 완료함 참조용)
npm install -g pnpm@10.23.0
1-1-1. 🚨 [배경 지식] 왜 npm 대신 pnpm을 쓰는가? (The Revolution of pnpm)
"npm도 잘 되는데 굳이 왜 이걸 또 깔아야 하나요?" 라는 질문은 매우 타당합니다. 하지만 OpenClaw(Moltbot) 같은 대규모 프로젝트(Monorepo)에서 npm을 쓰면 재앙이 닥칩니다.
- 은유(Metaphor): 도서관 책 빌리기
npm (비효율의 끝판왕): 학생 100명이 "해리포터" 책을 읽어야 한다고 합시다. npm 방식은 100권의 책을 새로 사서 각 학생의 가방에 넣어주는 것입니다. 가방(디스크)이 터지고, 책값(설치 시간)이 엄청 듭니다.
pnpm (효율적 공유): 학교 도서관에 "해리포터" 딱 한 권만 사놓습니다. 학생들에게는 책 위치가 적힌 쪽지(Symlink) 만 줍니다. 읽을 때는 도서관 책을 참조합니다. 100명이든 1000명이든 책은 한 권이면 됩니다.
- 실제 차이 (Real World Impact)
OpenClaw(Moltbot) 프로젝트는 수백 개의 라이브러리를 씁니다.
npm 사용 시 : 프로젝트를 복사할 때마다 1GB가 넘는 node_modules 폴더가 계속 복제됩니다. 하드디스크가 순식간에 꽉 찹니다.
pnpm 사용 시: 100개를 복사해도 용량은 거의 늘어나지 않습니다. (Content Addressable Store 방식)
- 결정적 이유 (Killer Feature): 엄격함(Strictness) npm의 유령(Phantom Dependencies): npm은 내가 설치하지 않은 라이브러리도 실수로 쓸 수 있게 허용하는 버그(혹은 관대함)가 있습니다. 나중에 배포할 때 "어? 내 컴퓨터에선 되는데 서버에선 안 돼요!" 하는 지옥을 맛보게 됩니다.
pnpm: 내가 package.json에 명시한 것만 정확히 쓸 수 있게 막아줍니다. "정의되지 않은 것은 없다" 는 철학입니다.
1-1-2. 🛑 [보충 수업] npm이 도대체 뭔가요? (What is npm?) "개발자들은 왜 자꾸 npm npm 거리는 걸까요?"
- 은유(Metaphor): 개발자들의 "앱스토어" 혹은 "다이소"
-
아이폰 앱스토어: 카카오톡이 필요하면 우리가 직접 코딩해서 만들지 않죠? 앱스토어에서 다운로드 받습니다.
-
npm (Node Package Manager): 개발할 때 "달력 기능"이나 "암호화 기능"이 필요하면 직접 짜지 않고 npm이라는 무료 부품 상점에서 다운로드 받습니다.
- 레고 블록 (Lego Blocks)
-
여러분이 "성(Castle)" 을 만든다고 상상해 보세요.
-
플라스틱을 녹여서 블록 하나하나를 직접 만드는 건 미친 짓입니다. (이게 npm 없이 개발하는 것)
-
npm은 "문", "창문", "성벽" 블록을 미리 만들어 파는 가게입니다. 우리는
npm install castle-wall명령어 한 줄로 성벽 블록을 가져와서 조립만 하면 됩니다.
- 사용하는 이유 (Why?)
시간 절약: 남들이 10년 동안 만든 검증된 코드를 1초 만에 가져와 씁니다.
검증된 품질: 전 세계 수백만 명이 같이 고쳐나가는 코드라서, 내가 짠 코드보다 튼튼할 확률이 높습니다.
- 사용 방법 (How?) 연재 2회에서 다루었던 터미널 기억하시죠? 별도로 새 창을 열 필요 없이 거기서 이어서 계속 입력하시면 됩니다. 주문을 외우듯 터미널에 아래 명령어를 입력해 보세요.
-
npm install [부품이름]: "이 부품 우리 집(프로젝트)에 배달해 줘." -
pnpm install: "이 부품 배달해 주는데, 아까 말했듯이 더 효율적으로(도서관 방식) 배달해 줘."
프로젝트 생성 (집터 닦기):
먼저 컴퓨터 하드디스크(C드라이브 혹은 홈 디렉토리)에 Workspace라는 이름의 폴더 아래 안에 들어가서, 다시 openclaw-lab이라는 폴더를 열어 둡니다.(2장에서 모두 생성함)
구조: 내 컴퓨터 -> Workspace -> openclaw-lab
터미널에서 만약 해당 폴더 안에 있지 않다면 아래 명령으로 이동한 뒤, 정보를 기입합니다.
cd ~/Workspace/openclaw-lab pnpm init
- 2장에서 이미 설치가 되었던 분들은 " ERR_PNPM_PACKAGE_JSON_EXISTS package.json already exists" 라는 메세지가 출력 되니 걱정 마세요.
NOTE [Coach's Tip] 왜 굳이 Workspace 폴더를 만드나요? 개발을 하다 보면 "어? 제 파일 어디 갔죠?" 하고 길을 잃는 경우가 정말 많습니다. 윈도우(C드라이브) 사용자, 맥(홈) 사용자 모두 Workspace라는 공통된 약속 장소를 정해두면, 나중에 "경로를 못 찾겠어요" 같은 문제를 99% 예방할 수 있습니다. 이것은 전 세계 개발자들의 '국룰(불문율)' 같은 습관이며, 경로 문제로 헷갈릴 일을 원천 봉쇄해 줍니다.
[ 내용 추가 예정 ]
1-2. 🚨 [심층 이해] 왜 코드를 짜기 전에 tsconfig.json 부터 건드리는가?
많은 분들이 "일단 server.ts 파일 만들고 코드부터 치면 안 되나요?" 라고 묻습니다. 결론부터 말하면, OpenClaw(Moltbot) 같은 거대한 프로젝트에서는 불가능합니다. 그 이유를 아주 쉽게 설명해 드립니다.
- 은유(Metaphor): 건물을 짓기 전의 "토지 용도 변경"
일반적인 코딩 (HTML/JS): 맨땅에 텐트를 치는 것과 같습니다. 그냥 폴대(index.html) 꽂고 천(script.js) 덮으면 집이 됩니다. 규칙이 없어도 됩니다.
OpenClaw (TS/ESM): 100층짜리 마천루를 짓는 것과 같습니다. 땅을 파기 전에 "여기는 상업지구이며, 내진 설계 기준은 7.0이고, 철근은 KS규격을 써야 한다" 는 법적/행정적 허가(tsconfig.json) 가 먼저 떨어져야 합니다. 허가증 없이 철근(import)을 하나라도 세우면 공사 중지 명령(Syntax Error)이 떨어집니다.
- 비교(Comparison): 동네 축구 vs 월드컵
동네 축구 (Legacy JS Project): 심판도 없고 규칙도 대충입니다. "손만 안 쓰면 돼." 바로 공 차면 됩니다.
월드컵 (Modern TypeScript Project): 경기 시작 전에 "오프사이드 반칙 기준", "VAR 판독 여부", "교체 선수 숫자"가 룰북(tsconfig.json)에 정의되어야 합니다. OpenClaw는 월드컵 결승전급의 엄격한 규칙 하에 돌아가는 시스템입니다.
- 실제 예시 (Real World Scenario)
만약 설정 없이 바로 코드를 짠다면?
개발자 : (자신있게) import { Server } from 'http';
컴퓨터(Node.js) : "잠깐, import가 뭐죠? 저는 옛날 방식(require)밖에 모르는데요?" -> 에러 발생 (Crash)
개발자 : (당황하며) 어? 요즘 다 이거 쓰던데?
컴퓨터 : "그건 tsconfig.json 이라는 번역기가 있을 때 얘기입니다. 저한테 미리 언질을 안 주셨잖아요."
결론: tsconfig.json을 먼저 만드는 것은 컴퓨터에게 "지금부터 우리는 최신 유행어(ESM)와 엄격한 문법(TypeScript)으로 대화할 거야. 준비해." 라고 선전포고를 하는 것입니다. 이 합의가 없으면 단 한 줄의 코드도 실행되지 않습니다.
1-3. 🛠️ [실전 가이드] tsconfig.json 설정: 새로운 나라의 헌법 제정 "Moltbot은 대형 프로젝트라서 이미 설정이 다 되어있지만, 맨땅에서 시작하는 나만의 작은 앱은 어떻게 시작하나요?"
- 은유(Metaphor): 새로운 국가를 세울 때의 "헌법 제정"
백지에 그림을 그리는 것과 같습니다. 나라를 처음 세울 때, 우리 국민은 어떤 언어를 쓰고(Target), 주변 나라와는 어떻게 소통하며(Module), 범죄(Error)에는 얼마나 엄격할 것인지(Strict)를 정하는 **'국가 헌법'**을 만드는 과정이 바로 tsconfig.json 초기화입니다. 헌법이 모호하면 나라가 혼란에 빠지듯, 이 설정이 부실하면 개발 과정 내내 충돌이 일어납니다.
- 개념(Concept): 초기화의 두 가지 경로 (자동 vs 실전)
TypeScript는 개발자가 처음부터 고생하지 않도록 **'표준 헌법 초안'**을 자동으로 생성해주는 도구(npx tsc --init)를 제공합니다. 초보자는 자동 생성된 초안에서 시작하고, 숙련자는 프로젝트의 목적(고성능 서버, 프론트엔드 등)에 맞춰 그 초안을 수정하여 사용합니다.
- 코드(Code): 헌법의 탄생과 핵심 3조항
방법 A: 표준 초안 자동 생성 (권장)
연재 2회에서 사용하던 터미널 창을 그대로 사용하세요. 다음 명령어를 입력하면 수중한 주석과 함께 설정 파일이 생성됩니다.
npx tsc --init 방법 B: 실전 프로젝트 핵심 설정 (수동 수정)
자동 생성된 파일에서 아래 **'핵심 3개 조항'**만은 반드시 확인하고 수정해 주세요.
{ "compilerOptions": { "target": "ES2022", // [제1조] 사용할 언어의 문법 수준 (최신 사투리 인정) "module": "NodeNext", // [제2조] 소통 규약 (최신 스마트폰 규격 사용) "strict": true // [제3조] 법 집행의 엄격함 (무관용 원칙) } 4. 배경 및 실전 가이드(Context & Guide): 왜 이 3가지인가?
왜 target: ES2022인가? : 과거에는 구식 브라우저를 위해 코드를 어렵게 번역해야 했습니다. 하지막 지금 우리가 만드는 서버(Node.js 22)는 똑똑합니다. 최신 문법을 그대로 써야 속도가 빠르고 코드가 깔끔해집니다.
왜 module: NodeNext인가? : 자바스크립트 세계는 지금 '구식(CommonJS)'과 '신식(ESM)'이 교체되는 과도기입니다. NodeNext는 "우리는 신식을 쓰되, 구식도 알아듣겠다"는 가장 현명한 중재안입니다.
왜 strict: true인가? : "대충 짜고 나중에 고치지 뭐"라는 생각은 개발자의 가장 큰 착각입니다. 처음부터 엄격하게 관리하는 것이, 나중에 버그를 찾느라 밤을 새우는 것보다 100배 경제적입니다.
TIP
요약: 작은 프로젝트라도 npx tsc --init으로 시작하고, Target(최신), Module(NodeNext), Strict(True) 이 세 가지만 기억하세요. 이것만으로도 여러분의 프로젝트는 구글이나 메타(Facebook) 부럽지 않은 튼튼한 기초를 갖추게 됩니다.
1-3-1. TypeScript 설정 (tsconfig.json) - 아키텍처 심층 분석
- 은유(Metaphor): 건물의 설계 규격과 "헌법(憲法)"
아파트 단지를 지을 때, 모든 건물의 자재 규격이 같아야 하고 배선은 통일된 규칙을 따라야 합니다. tsconfig.json은 이 프로젝트가 어떤 규칙으로 지어지고, 최종적으로 어떤 결과물(JavaScript)로 번역될지를 정하는 최상위 법전이자 설계 도면입니다. 이 도면이 틀리면 아무리 코드를 잘 짜도 집이 무너집니다.
- 개념(Concept): TypeScript 컴파일러 설정 안내서
이 파일은 tsc(컴파일러)에게 "이 프로젝트의 소스 코드는 여기에 있고, 번역된 결과물은 저기에 저장하고, 번역할 때는 이런 규칙을 지켜줘!"라고 상세히 지시하는 메뉴얼입니다. 단순한 설정 파일이 아니라, 프로젝트의 **정체성(ESM vs CJS)**을 결정짓는 핵심 문서입니다.
outDir (dist): 번역가 끝난 문서(결과물)를 차곡차곡 쌓아두는 '출고 창고'입니다. rootDir (src): 번역가가 작업해야 할 원본 원고가 들어있는 '원고 보관함'입니다. esModuleInterop : 서로 다른 통신 규격(ESM과 CJS)을 쓰는 부품들이 대화할 수 있게 해주는 '유니버설 어댑터'입니다. skipLibCheck: "이미 검증된 외부 서적까지 일일이 오타 검사를 하느라 시간을 낭비하지 않겠다"는 '검수 생략' 조항입니다.
- 코드(Code): 원본 tsconfig.json
{ "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "dist", "rootDir": "src", "strict": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true, "resolveJsonModule": true, "noEmitOnError": true, "allowSyntheticDefaultImports": true
}, "include": ["src//*"], "exclude": [ "node_modules", "dist", "src//.test.ts", "src/**/.test.tsx", "src/**/test-helpers.ts" ] }