careermate 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/README.md +256 -0
  2. package/THIRD_PARTY_NOTICES.md +40 -0
  3. package/apps/mcp/src/index.ts +66 -0
  4. package/apps/web/DESIGN_GUIDE.md +105 -0
  5. package/apps/web/UI_CONTRACT.md +44 -0
  6. package/apps/web/public/app.js +118 -0
  7. package/apps/web/public/fonts/PretendardVariable.woff2 +0 -0
  8. package/apps/web/public/index.html +41 -0
  9. package/apps/web/public/lib.js +282 -0
  10. package/apps/web/public/pages/applications.js +98 -0
  11. package/apps/web/public/pages/documents.js +446 -0
  12. package/apps/web/public/pages/home.js +263 -0
  13. package/apps/web/public/pages/interview.js +230 -0
  14. package/apps/web/public/pages/jobs.js +494 -0
  15. package/apps/web/public/pages/profile.js +576 -0
  16. package/apps/web/public/pages/settings.js +233 -0
  17. package/apps/web/public/styles.css +426 -0
  18. package/apps/web/src/exports.ts +68 -0
  19. package/apps/web/src/http.ts +180 -0
  20. package/apps/web/src/index.ts +49 -0
  21. package/apps/web/src/info.ts +50 -0
  22. package/apps/web/src/routes.ts +350 -0
  23. package/apps/web/src/security.ts +102 -0
  24. package/apps/web/src/server.ts +141 -0
  25. package/apps/web/src/settings.ts +88 -0
  26. package/bin/careermate.mjs +74 -0
  27. package/dist/careermate.mcpb +0 -0
  28. package/dist/install-page/index.html +474 -0
  29. package/dist/install-page/style.css +391 -0
  30. package/dist/install-page/vercel.json +20 -0
  31. package/dist/mcp-smoke.err +3 -0
  32. package/dist/mcp.mjs +23704 -0
  33. package/dist/mcpb-stage/README.md +219 -0
  34. package/dist/mcpb-stage/dist/install-page/index.html +434 -0
  35. package/dist/mcpb-stage/dist/install-page/style.css +407 -0
  36. package/dist/mcpb-stage/dist/install-page/vercel.json +20 -0
  37. package/dist/mcpb-stage/dist/mcp.mjs +23704 -0
  38. package/dist/mcpb-stage/dist/public/app.js +118 -0
  39. package/dist/mcpb-stage/dist/public/fonts/PretendardVariable.woff2 +0 -0
  40. package/dist/mcpb-stage/dist/public/index.html +41 -0
  41. package/dist/mcpb-stage/dist/public/lib.js +282 -0
  42. package/dist/mcpb-stage/dist/public/pages/applications.js +98 -0
  43. package/dist/mcpb-stage/dist/public/pages/documents.js +446 -0
  44. package/dist/mcpb-stage/dist/public/pages/home.js +263 -0
  45. package/dist/mcpb-stage/dist/public/pages/interview.js +230 -0
  46. package/dist/mcpb-stage/dist/public/pages/jobs.js +494 -0
  47. package/dist/mcpb-stage/dist/public/pages/profile.js +576 -0
  48. package/dist/mcpb-stage/dist/public/pages/settings.js +233 -0
  49. package/dist/mcpb-stage/dist/public/styles.css +420 -0
  50. package/dist/mcpb-stage/dist/web.mjs +7240 -0
  51. package/dist/mcpb-stage/manifest.json +40 -0
  52. package/dist/public/app.js +118 -0
  53. package/dist/public/fonts/PretendardVariable.woff2 +0 -0
  54. package/dist/public/index.html +41 -0
  55. package/dist/public/lib.js +282 -0
  56. package/dist/public/pages/applications.js +98 -0
  57. package/dist/public/pages/documents.js +446 -0
  58. package/dist/public/pages/home.js +263 -0
  59. package/dist/public/pages/interview.js +230 -0
  60. package/dist/public/pages/jobs.js +494 -0
  61. package/dist/public/pages/profile.js +576 -0
  62. package/dist/public/pages/settings.js +233 -0
  63. package/dist/public/styles.css +426 -0
  64. package/dist/web.mjs +7240 -0
  65. package/docs/ARCHITECTURE.md +208 -0
  66. package/docs/CHANGES_V1.md +103 -0
  67. package/docs/DATA_MODEL.md +460 -0
  68. package/docs/DECISIONS.md +277 -0
  69. package/docs/DEMO.md +242 -0
  70. package/docs/INSTALL.md +148 -0
  71. package/docs/INSTALL_AND_USAGE.md +99 -0
  72. package/docs/MCP_TOOLS.md +233 -0
  73. package/docs/ROADMAP.md +134 -0
  74. package/docs/START_WORKFLOW.md +125 -0
  75. package/docs/SUPPORTED_AI_APPS.md +60 -0
  76. package/docs/TODO.md +57 -0
  77. package/docs/UX_NOTES.md +247 -0
  78. package/docs/WORKFLOWS.md +200 -0
  79. package/install-page/index.html +474 -0
  80. package/install-page/style.css +391 -0
  81. package/install-page/vercel.json +20 -0
  82. package/package.json +68 -0
  83. package/packages/core/src/context.ts +74 -0
  84. package/packages/core/src/index.ts +8 -0
  85. package/packages/core/src/onboarding.ts +81 -0
  86. package/packages/core/src/services.ts +146 -0
  87. package/packages/core/src/summary.ts +104 -0
  88. package/packages/db/src/connection.ts +46 -0
  89. package/packages/db/src/index.ts +22 -0
  90. package/packages/db/src/paths.ts +41 -0
  91. package/packages/db/src/repositories.ts +828 -0
  92. package/packages/db/src/runtime.ts +58 -0
  93. package/packages/db/src/schema.ts +189 -0
  94. package/packages/exporters/src/html.ts +113 -0
  95. package/packages/exporters/src/index.ts +364 -0
  96. package/packages/exporters/src/markdown.ts +178 -0
  97. package/packages/mcp-tools/src/bridge.ts +83 -0
  98. package/packages/mcp-tools/src/index.ts +8 -0
  99. package/packages/mcp-tools/src/result.ts +49 -0
  100. package/packages/mcp-tools/src/tools.ts +455 -0
  101. package/packages/parsers/src/html.ts +86 -0
  102. package/packages/parsers/src/index.ts +228 -0
  103. package/packages/parsers/src/keywords.ts +151 -0
  104. package/packages/prompts/src/humanize.ts +59 -0
  105. package/packages/prompts/src/index.ts +82 -0
  106. package/packages/prompts/src/install.ts +43 -0
  107. package/packages/prompts/src/onboarding.ts +35 -0
  108. package/packages/prompts/src/system.ts +53 -0
  109. package/packages/shared/src/enums.ts +103 -0
  110. package/packages/shared/src/index.ts +18 -0
  111. package/packages/shared/src/schemas.ts +398 -0
  112. package/packages/workflows/src/definitions.ts +107 -0
  113. package/packages/workflows/src/index.ts +39 -0
  114. package/scripts/build-dist.mjs +62 -0
  115. package/scripts/build-mcpb.mjs +70 -0
  116. package/scripts/doctor.ts +81 -0
  117. package/scripts/init.ts +342 -0
  118. package/scripts/mcp-probe.ts +55 -0
  119. package/scripts/migrate.ts +6 -0
  120. package/scripts/run.mjs +33 -0
  121. package/scripts/seed.ts +129 -0
  122. package/scripts/test.ts +117 -0
  123. package/scripts/ui-smoke.ts +73 -0
  124. package/tsconfig.json +29 -0
@@ -0,0 +1,277 @@
1
+ # 설계 결정 기록 (ADR)
2
+
3
+ 이 문서는 CareerMate의 주요 설계 결정을 맥락/결정/결과 형식으로 기록한다. 모든 결정은
4
+ **2026-06-14** 기준이며, 각 항목은 "왜 그렇게 정했는가"를 함께 남겨 이후 변경 시 근거를
5
+ 재추적할 수 있게 한다.
6
+
7
+ 관련 문서: [README](../README.md), [아키텍처](./ARCHITECTURE.md)(보안 경계 포함), [데이터 모델](./DATA_MODEL.md), [MCP 도구](./MCP_TOOLS.md)
8
+
9
+ > 표기: 결정은 코드/설정과 일치해야 한다. 본문의 사실은 `package.json`,
10
+ > `packages/db/src/connection.ts`, `scripts/run.mjs` 등 실제 소스를 근거로 한다.
11
+
12
+ ---
13
+
14
+ ## 결정 목록 요약
15
+
16
+ | # | 결정 | 날짜 | 상태 |
17
+ |---|------|------|------|
18
+ | 1 | `node:sqlite` 내장 드라이버 사용 | 2026-06-14 | 채택 |
19
+ | 2 | `tsx` 기반 무빌드 실행 | 2026-06-14 | 채택 |
20
+ | 3 | 대시보드는 프레임워크/CDN 없는 바닐라 JS + 자체 CSS | 2026-06-14 | 채택 |
21
+ | 4 | MCP-우선 · LLM 비내장 | 2026-06-14 | 채택 |
22
+ | 5 | 로컬-우선 보안 모델 | 2026-06-14 | 채택 |
23
+ | 6 | 대시보드와 MCP가 동일 SQLite 공유(WAL) + `server.json` 핸드셰이크 | 2026-06-14 | 채택 |
24
+ | 7 | 자소서 버전관리 모델 | 2026-06-14 | 채택 |
25
+ | 8 | 순수 Node 러너(`run.mjs`) + stdout verdict 우회 | 2026-06-14 | 채택 |
26
+
27
+ ---
28
+
29
+ ## 1. `node:sqlite` 내장 드라이버 사용 (네이티브 컴파일 회피)
30
+
31
+ - **날짜**: 2026-06-14
32
+
33
+ ### 맥락
34
+ CareerMate는 비개발자 사용자가 직접 설치하는 로컬 도구다. `better-sqlite3` 같은 인기
35
+ 드라이버는 네이티브 애드온을 빌드/리빌드해야 하며, 이는 `node-gyp`, Python, C/C++ 빌드
36
+ 툴체인(특히 Windows의 Visual Studio Build Tools)을 요구한다. 이런 전제는 "비개발자가
37
+ `npm install` 한 번으로 끝낸다"는 목표와 정면으로 충돌한다.
38
+
39
+ ### 결정
40
+ Node.js에 내장된 `node:sqlite`(`DatabaseSync`)를 사용한다. 별도 네이티브 패키지 의존을
41
+ 두지 않는다. 따라서 `package.json`의 런타임 의존성은 SQLite 드라이버를 포함하지 않으며
42
+ (`@modelcontextprotocol/sdk`, `tsx`, `zod`뿐), DB는 표준 라이브러리로만 동작한다.
43
+ `engines.node`는 `>=22.5.0`으로 고정해 `node:sqlite`가 보장되는 런타임을 강제한다.
44
+
45
+ 연결은 `packages/db/src/connection.ts`의 단일 진입점(`getDb()`)에서 생성하며, 연결 직후
46
+ 다음 PRAGMA를 적용한다.
47
+
48
+ ```ts
49
+ db.exec('PRAGMA journal_mode = WAL;');
50
+ db.exec('PRAGMA foreign_keys = ON;');
51
+ db.exec('PRAGMA busy_timeout = 5000;');
52
+ ```
53
+
54
+ ### 결과
55
+ - 설치 경로에서 네이티브 컴파일이 사라져 OS/아키텍처에 무관하게 `npm install`이 단순해졌다.
56
+ - 빌드 툴체인 부재로 인한 설치 실패 클래스가 통째로 제거됐다.
57
+ - 트레이드오프: Node 22.5.0 이상이 필수다. 구버전 Node 사용자는 업그레이드해야 한다.
58
+ - `DatabaseSync`는 동기 API이므로 DB 호출 패턴이 단순해지는 대신, 비동기 풀링 같은 고급
59
+ 패턴은 사용하지 않는다(로컬 단일 사용자 규모에서는 충분).
60
+
61
+ ---
62
+
63
+ ## 2. `tsx` 기반 무빌드 실행
64
+
65
+ - **날짜**: 2026-06-14
66
+
67
+ ### 맥락
68
+ TypeScript를 쓰되 사용자에게 "빌드 단계"를 강요하지 않으려 했다. 별도 컴파일 산출물
69
+ (`dist/`)을 만들고 배포하는 흐름은 설치/실행을 복잡하게 하고, 소스와 산출물 불일치
70
+ 같은 상태 오류를 유발한다.
71
+
72
+ ### 결정
73
+ 소스(`.ts`)를 빌드 없이 그대로 실행한다. Node에 `--import tsx`를 얹어 TypeScript를
74
+ 런타임에 트랜스파일한다. `package.json` 스크립트는 모두 이 형태다.
75
+
76
+ ```json
77
+ "start": "node --no-warnings --import tsx apps/web/src/index.ts",
78
+ "dev": "node --no-warnings --watch --import tsx apps/web/src/index.ts",
79
+ "mcp": "node --no-warnings --import tsx apps/mcp/src/index.ts",
80
+ "migrate": "node --no-warnings --import tsx scripts/migrate.ts",
81
+ "seed": "node --no-warnings --import tsx scripts/seed.ts",
82
+ "doctor": "node --no-warnings --import tsx scripts/doctor.ts"
83
+ ```
84
+
85
+ 타입 검증은 실행과 분리해 `typecheck`(`tsc --noEmit`)로만 수행한다. 즉 `tsc`는 산출물을
86
+ 내지 않고 타입만 본다.
87
+
88
+ ### 결과
89
+ - `npm install` 후 곧바로 `npm start`로 실행된다. 별도 빌드 단계가 없다.
90
+ - `dev`는 `--watch`로 파일 변경 시 자동 재시작한다.
91
+ - 빌드 산출물/소스 불일치 문제가 원천적으로 없다.
92
+ - 트레이드오프: 런타임 트랜스파일 비용(시작 시점 오버헤드)이 있으나 로컬 도구 규모에서는
93
+ 무시 가능하다. 또한 ESM 전용(`"type": "module"`)으로 일관한다.
94
+
95
+ ---
96
+
97
+ ## 3. 대시보드는 프레임워크/CDN 없는 바닐라 JS + 자체 CSS
98
+
99
+ - **날짜**: 2026-06-14
100
+
101
+ ### 맥락
102
+ 대시보드는 완전 로컬·오프라인 환경에서 동작해야 한다. React/Vue 같은 SPA 프레임워크나
103
+ CDN 의존은 (1) 네트워크 요청을 유발해 오프라인/프라이버시 원칙을 깨고, (2) 빌드 파이프라인을
104
+ 끌고 들어오며, (3) 보일러플레이트성 "슬롭(slop)" 코드를 양산한다.
105
+
106
+ ### 결정
107
+ 대시보드를 프레임워크 없이 바닐라 JavaScript로 작성하고, 외부 CDN을 일절 참조하지 않는다.
108
+ 스타일은 서드파티 CSS 라이브러리 대신 자체 CSS 디자인 시스템으로 구성한다. 모든 정적
109
+ 자산은 로컬에서 서빙되며 외부로 나가는 요청이 없다.
110
+
111
+ ### 결과
112
+ - 인터넷 연결 없이 대시보드가 완전히 동작한다(오프라인 보장).
113
+ - 외부 요청이 없어 사용자 데이터가 로컬을 벗어나지 않는다(프라이버시 보장).
114
+ - 프런트엔드 빌드 단계가 불필요해 결정 2(무빌드)와 일관된다.
115
+ - 트레이드오프: 프레임워크가 제공하는 라우팅/상태관리/컴포넌트 추상을 직접 구현해야 하며,
116
+ 7개 페이지(Home, Profile, Jobs, Applications, Documents, Interview, Settings)와
117
+ 다크모드를 손으로 관리한다. 규모가 제한적이라 감당 가능한 비용으로 판단했다.
118
+
119
+ ---
120
+
121
+ ## 4. MCP-우선 · LLM 비내장 (분석은 사용자 AI가 수행)
122
+
123
+ - **날짜**: 2026-06-14
124
+
125
+ ### 맥락
126
+ 커리어 분석/자소서 작성 같은 작업은 강력한 LLM이 필요하다. 그러나 CareerMate가 자체
127
+ LLM을 내장하면 (1) API 키/비용/모델 선택을 사용자에게 떠넘기고, (2) 데이터를 외부
128
+ 모델 제공자로 보내 프라이버시를 해치며, (3) 도구가 무거워진다.
129
+
130
+ ### 결정
131
+ CareerMate 내부에는 LLM을 두지 않는다. 대신 MCP(Model Context Protocol) 서버로서
132
+ 로컬 커리어 DB에 대한 **도구**만 노출한다. 사용자는 자신이 이미 쓰는 ChatGPT/Claude/Gemini와
133
+ 대화하고, 그 AI가 CareerMate의 MCP 도구를 호출해 로컬 DB를 읽고 쓴다. 분석·작성 같은
134
+ 지능 작업은 전적으로 사용자의 AI가 담당하고, CareerMate는 구조화된 데이터와 워크플로
135
+ 가이드를 제공한다. 의존성으로 `@modelcontextprotocol/sdk`를 채택하고, MCP 서버는
136
+ `npm run mcp`(`apps/mcp/src/index.ts`)로 stdio 기동한다.
137
+
138
+ ### 결과
139
+ - CareerMate는 LLM 비용/키 관리에서 자유롭다. 사용자는 이미 가진 AI 구독을 그대로 쓴다.
140
+ - 데이터 흐름의 통제권이 사용자에게 있다(어떤 AI를 쓸지 사용자가 선택).
141
+ - "인터페이스 = 대화, 저장소 = 로컬 DB"라는 역할 분리가 명확하다.
142
+ - 트레이드오프: CareerMate 단독으로는 분석을 못 한다. MCP를 지원하는 AI 클라이언트가
143
+ 전제된다. 도구 표면(24개 MCP 도구)과 워크플로 가이드 설계가 제품 품질의 핵심이 된다.
144
+
145
+ ---
146
+
147
+ ## 5. 로컬-우선 보안 모델
148
+
149
+ - **날짜**: 2026-06-14
150
+
151
+ ### 맥락
152
+ 대시보드는 로컬 HTTP 서버를 띄운다. 로컬 서버라도 브라우저를 통한 공격면(DNS 리바인딩,
153
+ CSRF, 악성 Origin, 경로 traversal)이 존재한다. 또한 이력서/자소서 본문 같은 민감
154
+ 데이터가 로그나 에러 응답으로 새지 않아야 한다.
155
+
156
+ ### 결정
157
+ 다음을 모두 적용한다.
158
+
159
+ - **127.0.0.1 전용 바인딩**: 외부 인터페이스에 노출하지 않는다.
160
+ - **Host 허용목록**: 허용된 Host 헤더만 처리해 DNS 리바인딩을 차단한다.
161
+ - **CSRF 세션 토큰**: 변경 요청은 세션 토큰을 요구하며, 토큰은 HTML `<meta>`로 주입한다.
162
+ - **외부 Origin 차단**: 허용되지 않은 Origin의 요청을 거부한다.
163
+ - **정적파일 경로 traversal 차단**: 정적 자산 서빙에서 경로 이탈을 막는다.
164
+ - **8MB 본문 제한**: 과도한 요청 본문을 거부한다.
165
+ - **민감 본문 미노출**: 이력서/자소서 본문은 로그와 에러 응답에 포함하지 않는다.
166
+
167
+ ### 결과
168
+ - 로컬 도구이면서도 브라우저 기반 공격면을 체계적으로 줄였다.
169
+ - 민감 데이터가 운영 로그/에러 메시지로 유출되지 않는다.
170
+ - 트레이드오프: 변경 요청에 CSRF 토큰 흐름이 필요해 클라이언트 호출이 조금 더 엄격해진다.
171
+ 자세한 위협 모델과 구현은 [ARCHITECTURE.md의 "보안 경계" 절](./ARCHITECTURE.md#5-보안-경계) 참조.
172
+
173
+ ---
174
+
175
+ ## 6. 대시보드와 MCP가 동일 SQLite 공유(WAL) + `server.json` 핸드셰이크
176
+
177
+ - **날짜**: 2026-06-14
178
+
179
+ ### 맥락
180
+ 대시보드(웹 서버 프로세스)와 MCP 서버(stdio 프로세스)는 별개 프로세스이지만 같은 커리어
181
+ 데이터를 봐야 한다. 사용자는 대시보드에서 편집하는 동시에 AI가 MCP로 데이터를 쓸 수 있다.
182
+ 즉 두 프로세스의 동시 접근을 일관되게 다뤄야 하고, MCP 서버가 실행 중인 대시보드 인스턴스를
183
+ 찾아 연동(딥링크 등)할 수 있어야 한다.
184
+
185
+ ### 결정
186
+ 두 프로세스가 **하나의 SQLite 파일**(`careermate.sqlite`)을 공유한다. 동시성은 SQLite의
187
+ **WAL(Write-Ahead Logging)** 모드로 처리한다. 연결은 `packages/db/src/connection.ts`의
188
+ 단일 `getDb()`에서 생성되며, 두 서버가 동일하게 이 모듈을 import 한다. 연결 시
189
+ `PRAGMA journal_mode = WAL`로 동시 읽기/쓰기를 허용하고, `PRAGMA busy_timeout = 5000`으로
190
+ 쓰기 락 경합 시 최대 5초 대기하며, `PRAGMA foreign_keys = ON`으로 무결성을 강제한다.
191
+ `connection.ts` 주석이 이 의도를 명시한다.
192
+
193
+ > "Both the web server and the MCP server import this. SQLite with WAL handles the
194
+ > two-process concurrency (dashboard editing + AI writing) cleanly."
195
+
196
+ 런타임 연동을 위해 데이터 디렉터리에 `server.json`을 두어 핸드셰이크한다. 대시보드가
197
+ 실제로 바인딩한 포트 등 런타임 정보를 기록하고, MCP 서버는 이를 읽어 실행 중인 대시보드를
198
+ 찾아 `open_dashboard`/`open_application` 같은 동작을 연결한다(포트가 사용 중이면 다음
199
+ 포트로 폴백하므로 고정 포트를 가정할 수 없어 핸드셰이크가 필요하다).
200
+
201
+ ### 결과
202
+ - 대시보드 편집과 AI 쓰기가 같은 데이터에 일관되게 반영된다(양방향 동일 DB).
203
+ - WAL + `busy_timeout`으로 두 프로세스 동시 접근이 락 오류 없이 처리된다.
204
+ - `server.json` 덕에 동적 포트 환경에서도 MCP→대시보드 딥링크가 동작한다.
205
+ - 트레이드오프: WAL 부가 파일(`-wal`, `-shm`)이 생기고, 두 프로세스가 같은 파일시스템
206
+ 위에 있어야 한다(로컬 전용 도구라 제약이 아님).
207
+
208
+ ---
209
+
210
+ ## 7. 자소서 버전관리 모델
211
+
212
+ - **날짜**: 2026-06-14
213
+
214
+ ### 맥락
215
+ 자기소개서는 한 번에 완성되지 않는다. 사용자(또는 그의 AI)는 같은 지원 건에 대해
216
+ 여러 차례 고쳐 쓴다. 단일 본문 필드를 덮어쓰면 이전 초안과 수정 이력이 사라져, 어떤
217
+ 버전을 어디에 제출했는지 추적할 수 없다.
218
+
219
+ ### 결정
220
+ 자소서를 단일 레코드가 아니라 **본문 + 버전 이력**으로 모델링한다. `cover_letters`와
221
+ `cover_letter_versions`를 분리해, 자소서의 각 수정본을 버전으로 누적 저장한다. MCP 도구
222
+ `save_cover_letter_version`으로 새 버전을 추가하고, 대시보드 Documents 페이지는 이를
223
+ **버전 타임라인**으로 보여준다. 내보내기는 `export_cover_letter`로 수행한다.
224
+
225
+ ### 결과
226
+ - 자소서의 모든 수정 이력이 보존돼 이전 버전으로 되돌아보거나 비교할 수 있다.
227
+ - 어떤 버전을 어떤 지원에 사용했는지 추적이 가능하다.
228
+ - 대시보드에서 타임라인으로 진행 과정을 시각화한다.
229
+ - 트레이드오프: 단순 덮어쓰기보다 데이터 모델과 도구가 약간 더 복잡하다. 추적성 이점이
230
+ 이를 상회한다고 판단했다.
231
+
232
+ ---
233
+
234
+ ## 8. 순수 Node 러너(`run.mjs`) + stdout verdict 우회
235
+
236
+ - **날짜**: 2026-06-14
237
+
238
+ ### 맥락
239
+ 테스트 스크립트(`scripts/test.ts`, `scripts/ui-smoke.ts`)는 `tsx`로 실행되며 top-level
240
+ `await`를 사용한다. 그런데 **Windows에서 tsx 모듈이 top-level `await`를 쓴 뒤
241
+ `process.exit()`를 호출하면 종료 코드가 오염**된다. esbuild 로더가 트랜스파일 중간
242
+ 상태일 때 프로세스가 종료되면서 실제 결과와 무관한 잘못된 exit code가 나온다. 이 때문에
243
+ `npm test`의 성공/실패를 종료 코드로 신뢰할 수 없다.
244
+
245
+ ### 결정
246
+ 종료 코드를 신뢰하지 않고, **테스트 스크립트가 stdout에 찍는 verdict 센티넬**로
247
+ 성패를 판정하는 별도 러너 `scripts/run.mjs`를 둔다. 이 러너는 `tsx`가 아니라 **순수
248
+ Node(.mjs)**로 실행되므로 자신의 종료 코드는 오염되지 않는다. 러너는 자식 프로세스로
249
+ 대상 tsx 스크립트를 띄우고, 자식의 mangled exit code는 무시한 채 stdout에 약속된
250
+ 센티넬 문자열이 있는지로 판정한다.
251
+
252
+ ```js
253
+ const res = spawnSync(process.execPath, ['--no-warnings', '--import', 'tsx', scriptPath], {
254
+ encoding: 'utf8', env: process.env, timeout: 180000,
255
+ });
256
+ // ...자식 출력을 정리해 surface...
257
+ const passed = (res.stdout || '').includes(sentinel);
258
+ process.exit(passed ? 0 : 1);
259
+ ```
260
+
261
+ `package.json`은 이 러너를 통해 테스트를 부른다.
262
+
263
+ ```json
264
+ "test": "node --no-warnings scripts/run.mjs scripts/test.ts \"TEST_VERDICT PASS\"",
265
+ "test:ui": "node --no-warnings scripts/run.mjs scripts/ui-smoke.ts \"UI_VERDICT PASS\""
266
+ ```
267
+
268
+ 추가로 러너는 Windows libuv 종료 단계에서 나오는 잡음 라인(`Assertion failed`,
269
+ `UV_HANDLE`, `Node.js vNN` 등)을 필터링해 출력을 깔끔하게 표면화한다.
270
+
271
+ ### 결과
272
+ - Windows에서도 테스트 성패가 안정적으로 판정된다(종료 코드 오염 우회).
273
+ - 자식 출력은 그대로 보이되 libuv 잡음만 제거돼 가독성이 좋다.
274
+ - `test`는 `"TEST_VERDICT PASS"`, `test:ui`는 `"UI_VERDICT PASS"` 센티넬을 약속한다.
275
+ 테스트 스크립트는 반드시 성공 시 해당 문자열을 stdout에 출력해야 한다.
276
+ - 트레이드오프: 테스트가 "센티넬을 반드시 출력한다"는 규약에 의존한다. 센티넬 출력 전
277
+ 크래시하면 실패로 판정되는데(올바른 동작), 규약을 어긴 신규 테스트는 오탐할 수 있다.
package/docs/DEMO.md ADDED
@@ -0,0 +1,242 @@
1
+ # CareerMate 데모 워크스루
2
+
3
+ 이 문서는 CareerMate를 직접 따라 해 볼 수 있는 두 가지 시나리오를 제공합니다.
4
+
5
+ - **(A) 빠른 데모** — 미리 채워진 데모 데이터로 대시보드를 1~2분 만에 둘러봅니다.
6
+ - **(B) 처음부터 시나리오 (18단계)** — 빈 상태에서 시작해 프로필 입력 → 공고 분석 → 자기소개서 작성 → 면접 준비까지 전체 흐름을 따라갑니다.
7
+
8
+ > 핵심 모델: **CareerMate 안에는 LLM이 없습니다.** 분석·작성은 당신의 AI(ChatGPT/Claude/Gemini)가 수행하고, CareerMate는 로컬 DB에 데이터를 읽고/쓰는 **MCP 도구**를 제공합니다. 모든 데이터는 로컬(`~/.careermate`)에만 저장됩니다.
9
+ >
10
+ > 관련 문서: [`INSTALL.md`](./INSTALL.md) · [`START_WORKFLOW.md`](./START_WORKFLOW.md)
11
+
12
+ ---
13
+
14
+ ## (A) 빠른 데모 — 채워진 대시보드 둘러보기
15
+
16
+ 데모 데이터를 한 번에 넣고 대시보드를 둘러보는 가장 빠른 길입니다. AI 연결 없이 화면만 확인합니다.
17
+
18
+ ### A-1. 설치 및 데모 데이터 주입
19
+
20
+ ```bash
21
+ npm install
22
+ npm run seed
23
+ npm start
24
+ ```
25
+
26
+ - `npm run seed`는 현실적인 데모 데이터를 한 번에 채웁니다.
27
+ - **주의:** 이미 실제 프로필 데이터가 있으면 덮어쓰지 않고 안내만 출력합니다. 그럴 때는 둘 중 하나를 사용하세요.
28
+ - 별도 폴더에 넣기(실제 데이터 보존): `CAREERMATE_DATA_DIR=./demo-data npm run seed`
29
+ - 그래도 강제 진행: `npm run seed -- --force`
30
+ - `npm start`는 대시보드를 `http://127.0.0.1:4319`에 띄우고(포트 사용 중이면 다음 포트로 폴백) 브라우저를 자동으로 엽니다. 자동 오픈을 끄려면 `CAREERMATE_NO_OPEN=1`.
31
+
32
+ ### A-2. 데모 데이터에 들어 있는 것
33
+
34
+ `npm run seed`가 생성하는 내용(실제 `scripts/seed.ts` 기준):
35
+
36
+ - **프로필 — 이서연**: 5년 차 백엔드 엔지니어(결제/정산 도메인), 희망 직무·근무 조건·선호 문체·강조 포인트까지 채워짐.
37
+ - **경력 2건**: 페이테크(현직, 결제 게이트웨이/정산), 커머스랩(주문/재고).
38
+ - **프로젝트 2건**: 실시간 정산 파이프라인, 결제 장애 자동 복구 시스템.
39
+ - **기술 6개**: Java(상), Spring Boot(상), Kafka(중), MySQL(상), Kubernetes(중), Python(중).
40
+ - **이력서 1건**: "이서연 이력서 (백엔드)" — 대표 문서.
41
+ - **공고 1건 — 토스 "백엔드 엔지니어 (결제)"**: 적합도 분석·자기소개서·상태·면접 준비가 모두 연결됨.
42
+ - **적합도 88점**: 강점(결제/정산 5년, p99 개선, Kafka), 보완점(Kotlin·MSA), 매칭/미매칭 키워드, 추천 전략 포함.
43
+ - **자기소개서 1건(2버전)**: v1(초안) → v2(지원동기·정량 성과 보강).
44
+ - **지원 상태**: `서류 합격(document_passed)` — 이 단계부터 면접 준비가 해금됩니다.
45
+ - **면접 준비 1건**: 예상 질문 2개(+꼬리 질문·답변 개요), STAR 가이드 1개, 1분 자기소개 초안.
46
+
47
+ ### A-3. 페이지별로 둘러보기 (7개)
48
+
49
+ | 페이지 | 무엇을 보나 | 데모에서 확인 포인트 |
50
+ | --- | --- | --- |
51
+ | **Home** | 전체 요약·최근 활동 | 온보딩 완성도, 최근 작업 타임라인 |
52
+ | **Profile** | 프로필·경력·프로젝트·기술 | 이서연 정보, 선호 문체("담백하고 구체적…"), 강조 포인트 |
53
+ | **Jobs** | 공고 목록 + 상세 | 토스 공고 클릭 → 적합도 88, 강점/보완점, 키워드 |
54
+ | **Applications** | 칸반 보드(8단계) | 토스 카드가 **서류 합격** 칼럼에 위치 |
55
+ | **Documents** | 자소서 버전 타임라인 + 이력서 | 토스 자소서의 v1 → v2 히스토리, `MD`/`HTML` 내보내기 버튼 |
56
+ | **Interview** | 면접 준비 | 예상 질문·꼬리 질문·STAR·1분 자기소개 |
57
+ | **Settings** | 데이터 위치·환경 | 데이터 디렉터리, 다크모드 토글 |
58
+
59
+ > 다크모드는 Settings에서 전환할 수 있습니다.
60
+
61
+ ### A-4. 데모 데이터 초기화(선택)
62
+
63
+ 별도 폴더로 데모를 돌렸다면 그 폴더를 지우면 됩니다. 기본 위치(`~/.careermate`)에 강제로 시드했다면, 데이터 디렉터리의 `careermate.sqlite`를 정리하거나 새 `CAREERMATE_DATA_DIR`로 다시 시작하세요.
64
+
65
+ ---
66
+
67
+ ## (B) 처음부터 시나리오 — 18단계
68
+
69
+ 빈 상태에서 시작해 한 건의 공고를 끝까지 처리하는 전체 흐름입니다. 각 단계마다 **사람이 직접 하는 일**과 **AI가 MCP 도구로 하는 일**을 구분했습니다. AI에게 그대로 줄 수 있는 **예시 프롬프트**도 포함했습니다.
70
+
71
+ > 전제: 이 시나리오는 데모 데이터를 넣지 않은 빈 상태를 가정합니다. (A)를 먼저 했다면 별도 폴더(`CAREERMATE_DATA_DIR=./scenario-data`)로 진행하세요.
72
+ >
73
+ > 표기: 🧑 = 사람이 하는 일 · 🤖 = AI가 MCP 도구로 하는 일
74
+
75
+ ---
76
+
77
+ ### 1단계 — 실행 🧑
78
+
79
+ ```bash
80
+ npm install
81
+ npm start
82
+ ```
83
+
84
+ - 대시보드가 `http://127.0.0.1:4319`에서 열립니다(사용 중이면 다음 포트로 폴백, 브라우저 자동 오픈).
85
+ - 이 서버는 대시보드 + 로컬 API를 제공합니다. MCP 서버와 **같은 로컬 DB**를 공유합니다.
86
+
87
+ ### 2단계 — 대시보드 첫 화면 확인 🧑
88
+
89
+ - 브라우저에서 Home 페이지를 봅니다. 아직 데이터가 없으므로 온보딩 안내가 보입니다.
90
+ - 데이터 저장 위치는 Settings에서 확인할 수 있습니다(기본 `~/.careermate`, `careermate.sqlite`).
91
+
92
+ ### 3단계 — 프로필 직접 입력 🧑
93
+
94
+ - Profile 페이지에서 기본 정보를 직접 입력합니다: 이름, 한 줄 소개, 요약, 희망 직무, 희망 근무 조건.
95
+ - **글쓰기 선호도**를 꼭 채우세요: 선호 문체(`preferred_tone`)와 강조 포인트(`emphasis_points`). 이 두 값이 이후 자기소개서 품질에 직접 영향을 줍니다.
96
+ - 경력·프로젝트·기술도 이 화면에서 추가할 수 있습니다.
97
+
98
+ > 참고: 같은 작업을 AI에게 맡길 수도 있습니다. 그 경우 AI가 `save_profile`(전체/부분 저장)·`update_profile`(일부 수정)을 호출합니다. 전달한 필드만 갱신되고 나머지는 유지됩니다(부분 저장 안전).
99
+
100
+ ### 4단계 — 자기소개서/이력서 추가 🧑
101
+
102
+ - 가진 이력서가 있으면 Documents 페이지에서 추가하고, 대표 문서로 지정합니다(대표 이력서는 이후 분석의 근거로 쓰입니다).
103
+ - 기존 자기소개서가 있으면 함께 등록해 두면 좋습니다(AI가 톤·표현을 참고).
104
+
105
+ > AI에게 맡기면 `add_resume`(이력서/경력기술서/포트폴리오), `add_cover_letter`(기존 자소서)를 호출합니다.
106
+
107
+ ### 5단계 — AI 클라이언트에서 MCP 연결 확인 🧑
108
+
109
+ - CareerMate는 **로컬 stdio MCP 서버**라, 내 컴퓨터에서 실행되며 로컬 프로그램을 띄울 수 있는 클라이언트에서만 동작합니다 — Claude Desktop · Cursor · Cline · Windsurf · Claude Code. (ChatGPT·Gemini의 웹/앱은 클라우드에서 돌아 로컬 MCP 서버에 직접 연결할 수 없습니다.) 설치는 두 갈래입니다: 비개발자는 `.mcpb` 원클릭, 개발자는 `npm run init` 자동 등록 — 자세한 절차는 [`INSTALL_AND_USAGE.md`](./INSTALL_AND_USAGE.md)를 참고하세요. MCP 서버 자체는 보통 다음 형태로 기동됩니다(클라이언트가 자동 실행).
110
+
111
+ ```bash
112
+ npm run mcp
113
+ ```
114
+
115
+ - 이 MCP 서버는 stdio로 동작하며, 1단계의 대시보드와 **같은 로컬 DB**를 읽고 씁니다(별도 프로세스라도 동일 데이터).
116
+
117
+ ### 6단계 — AI가 연결 상태/온보딩 확인 🤖
118
+
119
+ - 연결되면 AI가 가장 먼저 현재 상태를 점검합니다.
120
+ - 🤖 `get_onboarding_status` → 프로필/이력서/자소서/경력/기술/공고 존재 여부와 완성도(0~100), 다음 단계 제안을 받아옵니다.
121
+
122
+ **예시 프롬프트:**
123
+
124
+ > "CareerMate에 연결됐어. 지금 내 등록 상태를 확인하고, 비어 있는 부분이 뭔지 알려줘."
125
+
126
+ ### 7단계 — AI에게 "내 프로필 보여줘" 🧑→🤖
127
+
128
+ - 🧑 사람: 위 프롬프트를 입력합니다.
129
+ - 🤖 AI: `get_profile`(필요하면 `get_resumes` / `get_cover_letters`)를 호출해 저장된 정보를 사람이 읽기 쉬운 말로 요약합니다.
130
+
131
+ **예시 프롬프트:**
132
+
133
+ > "내 프로필 보여줘. 빠진 항목 있으면 같이 알려줘."
134
+
135
+ ### 8단계 — 공고 텍스트 붙여넣기 🧑
136
+
137
+ - 지원하고 싶은 채용 공고의 링크나 본문 텍스트를 AI에게 그대로 붙여넣습니다.
138
+
139
+ **예시 프롬프트:**
140
+
141
+ > "이 공고에 지원하려고 해. 분석해줘.
142
+ > [회사: 토스 / 직무: 백엔드 엔지니어(결제) / 주요 자격: Java·Kotlin 백엔드, 대규모 트래픽 처리, 결제·정산 도메인 이해 / 우대: Kafka, MSA …공고 원문 붙여넣기…]"
143
+
144
+ ### 9단계 — AI가 공고를 구조화해 저장 🤖
145
+
146
+ - 🤖 (선택) `parse_job_posting`으로 붙여넣은 원문에서 회사명/직무/마감일/키워드를 빠르게 추출합니다(판단은 AI가 직접).
147
+ - 🤖 `save_job_posting`으로 저장합니다. `company`·`position`은 필수, 원문은 `description`, 자격/우대는 `requirements`, 키워드는 `keywords`에 넣습니다. 저장하면 **지원(application) 항목이 자동 생성**됩니다. 같은 `url`이면 중복 없이 갱신됩니다.
148
+
149
+ ### 10단계 — AI가 지원 맥락을 가져옴 (★핵심) 🤖
150
+
151
+ - 🤖 `get_application_context`를 호출합니다. **분석·작성 전에 반드시 먼저 호출하는 핵심 도구**입니다.
152
+ - 한 번의 호출로 프로필, 대표 이력서, 전체 경력·프로젝트·스킬, 기존 자소서, 최근 지원 이력, 대상 공고와 이전 적합도, 같은 회사/직무 기록, **선호 문체·강조 포인트**를 모두 받아옵니다.
153
+ - AI는 이 데이터를 **근거로** 분석/작성합니다(추측 대신 실제 데이터 사용).
154
+
155
+ ### 11단계 — AI가 적합도를 분석해 저장 🤖
156
+
157
+ - 🤖 AI가 공고 요구사항과 내 정보를 비교해 적합도를 도출하고 `save_fit_analysis`로 저장합니다.
158
+ - 저장 필드: `score`(0~100), `summary`, `strengths`, `gaps`, `matched_keywords` / `missing_keywords`, `recommendations`(자소서·지원 전략 제안). 같은 공고에 다시 저장하면 갱신됩니다.
159
+
160
+ **예시 프롬프트:**
161
+
162
+ > "내 경력 기준으로 이 공고 적합도를 점수와 함께 분석하고, 강점·보완점·자소서 전략까지 정리해줘."
163
+
164
+ ### 12단계 — 대시보드에서 적합도 확인 🧑
165
+
166
+ - 🧑 Jobs 페이지에서 방금 저장한 공고를 클릭해 상세를 봅니다. 점수, 강점/보완점, 매칭/미매칭 키워드, 추천 전략이 보입니다.
167
+ - (AI가 `open_application` 또는 `open_dashboard`를 호출해 바로 열어 줄 수도 있습니다.)
168
+
169
+ ### 13단계 — AI가 맞춤 자기소개서 생성 🤖
170
+
171
+ - 🤖 AI가 10단계에서 받은 선호 문체·강조 포인트·경력·공고를 근거로 자기소개서 초안을 작성합니다.
172
+
173
+ **예시 프롬프트:**
174
+
175
+ > "이 공고에 맞춘 자기소개서를 써줘. 내 강조 포인트와 선호 문체를 반영하고, 결제 도메인 경험을 정량 수치로 보여줘."
176
+
177
+ ### 14단계 — AI가 자기소개서를 v1으로 저장 🤖
178
+
179
+ - 🤖 `save_cover_letter_version`으로 저장합니다. `cover_letter_id`가 없으면 새 자소서를 만들어 **v1**으로 저장합니다(이때 `title` 권장). `job_id`로 공고에 연결하면 지원 항목과 자동 연결됩니다.
180
+ - `note`에 변경 요약(예: "초안")을 남기면 대시보드 버전 히스토리가 명확해집니다.
181
+
182
+ ### 15단계 — 대시보드에서 자기소개서 확인 🧑
183
+
184
+ - 🧑 Documents 페이지에서 방금 저장된 자소서와 버전 타임라인을 봅니다. 본문 미리보기를 읽고 다듬을 부분을 찾습니다.
185
+
186
+ ### 16단계 — 문장을 수정해 새 버전(v2) 저장 🧑→🤖
187
+
188
+ - 🧑 사람: 고치고 싶은 부분을 AI에게 말합니다.
189
+ - 🤖 AI: 수정본을 만들어 **기존 자소서의 `cover_letter_id`에** `save_cover_letter_version`을 다시 호출합니다 → **v2**로 추가됩니다. `note`에 "지원동기·정량 성과 보강" 같은 변경 요약을 남깁니다.
190
+
191
+ **예시 프롬프트:**
192
+
193
+ > "지원동기 첫 문단을 더 구체적으로 고치고, p99 응답시간 개선 수치를 넣어서 새 버전으로 저장해줘."
194
+
195
+ - 🧑 Documents 페이지에서 v1 → v2 타임라인이 쌓이는 것을 확인합니다.
196
+
197
+ ### 17단계 — 파일로 내려받기 (MD / 인쇄용 HTML → PDF) 🧑 / 🤖
198
+
199
+ 자기소개서를 파일로 받는 방법은 두 가지입니다.
200
+
201
+ - 🧑 **대시보드에서:** Documents 페이지의 자소서에서 **`MD`** 또는 **`HTML`** 내보내기 버튼을 누릅니다.
202
+ - 🤖 **AI에게 시켜서:** `export_cover_letter`(`format`은 `md` 기본 / 인쇄용 `html`)를 호출합니다. 파일은 `~/.careermate/exports`에 저장되고 경로를 알려줍니다.
203
+
204
+ > **PDF가 필요하면:** CareerMate는 바이너리 PDF 라이브러리를 내장하지 않습니다. `HTML`로 내보낸 뒤 **브라우저에서 열어 "인쇄 → PDF로 저장"** 하세요. HTML 출력은 A4 인쇄에 맞춘 CSS로 만들어져 있습니다. (Markdown이 필요하면 `MD`를 그대로 사용)
205
+
206
+ **예시 프롬프트:**
207
+
208
+ > "이 자기소개서를 인쇄용 HTML로 내보내줘. 파일 경로도 알려줘."
209
+
210
+ ### 18단계 — 서류 합격으로 변경 → 면접 질문 생성/저장 🧑→🤖
211
+
212
+ - 🧑 사람: 서류 합격 소식을 AI에게 알리거나, Applications 칸반에서 카드를 **서류 합격** 칼럼으로 옮깁니다.
213
+ - 🤖 AI: `update_application_status`로 상태를 `document_passed`로 변경합니다. 상태가 **서류 합격 이상**으로 바뀌면 면접 준비를 제안하는 힌트가 함께 돌아오고, **면접 준비가 해금**됩니다.
214
+ - 🤖 이어서 `get_application_context`(또는 `get_job_posting`)로 공고·자소서를 근거 삼아 예상 질문을 만들고 `save_interview_prep`으로 저장합니다: 예상 질문, 꼬리 질문, STAR 답변 가이드, 1분 자기소개 초안 등. `job_id` 필수, 같은 공고에 다시 저장하면 갱신됩니다.
215
+ - 🤖 저장 후 `open_application`(또는 `open_dashboard`)으로 면접 페이지를 열어 줍니다. 🧑 사람은 Interview 페이지에서 질문·STAR·1분 자기소개를 확인합니다.
216
+
217
+ **예시 프롬프트:**
218
+
219
+ > "이 공고 서류 합격했어. 상태를 서류 합격으로 바꾸고, 결제 도메인 위주로 예상 면접 질문과 STAR 답변, 1분 자기소개까지 만들어서 저장해줘."
220
+
221
+ ---
222
+
223
+ ## 부록: 지원 상태 8단계
224
+
225
+ 지원 카드는 Applications 칸반에서 다음 8단계로 관리됩니다(실제 enum 기준):
226
+
227
+ `draft`(작성 중) · `planned`(지원 예정) · `applied`(지원 완료) · `document_passed`(서류 합격) · `interview`(면접 진행) · `final_passed`(최종 합격) · `rejected`(불합격) · `on_hold`(보류)
228
+
229
+ > **`document_passed`(서류 합격) 이상**에서 면접 준비가 해금됩니다.
230
+
231
+ ## 부록: 표준 경로 한눈에 (공고 1건 처리)
232
+
233
+ 1. `save_job_posting` — 공고 저장(`job_id` 획득, 지원 항목 자동 생성)
234
+ 2. `get_application_context` (`job_id`) — 근거 데이터 확보 ★
235
+ 3. `save_fit_analysis` — 적합도 분석 저장
236
+ 4. `save_cover_letter_version` — 맞춤 자소서 버전 저장(v1, 수정 시 v2…)
237
+ 5. `export_cover_letter` — (요청 시) `md`/`html` 파일로 내보내기
238
+ 6. `update_application_status` — 지원 상태 갱신(서류 합격 시 면접 해금)
239
+ 7. `save_interview_prep` — 면접 준비 저장
240
+ 8. `open_application` / `open_dashboard` — 사용자에게 결과 보여주기
241
+
242
+ > 더 자세한 단계별 런북은 [`START_WORKFLOW.md`](./START_WORKFLOW.md), 설치·연결은 [`INSTALL.md`](./INSTALL.md)를 참고하세요.
@@ -0,0 +1,148 @@
1
+ # CareerMate 설치 — 수동 MCP 설정 레퍼런스
2
+
3
+ > **단계별 설치 런북은 이 문서가 아니라 저장소 루트의 [`../INSTALL.md`](../INSTALL.md) 에 있습니다.**
4
+ > AI 어시스턴트가 사용자의 컴퓨터에 CareerMate를 설치·연결할 때는 루트 `INSTALL.md` 를 순서대로 따르세요. 동의 절차, Node 버전 확인, 설치, 검증까지의 전체 흐름이 거기에 정리되어 있습니다.
5
+ >
6
+ > 이 문서는 **클라이언트별 MCP 설정 스니펫만** 모은 레퍼런스입니다. 사람이 직접 손으로 설정을 붙여넣거나, AI가 특정 클라이언트의 정확한 설정 형식을 확인할 때 참고하세요.
7
+
8
+ ## 먼저: 자동 등록이 더 쉽습니다
9
+
10
+ 대부분의 경우 수동 설정은 필요 없습니다. CareerMate 폴더에서 한 줄이면 됩니다.
11
+
12
+ ```bash
13
+ npm install
14
+ npm run init
15
+ ```
16
+
17
+ `npm run init` 은 ~/.careermate 폴더를 만들고, **감지된 클라이언트**(설정 파일/폴더가 있는 클라이언트)에 CareerMate를 자동 등록하며, Claude Code 프로젝트용 `.mcp.json` 은 항상 CareerMate 폴더에 기록합니다. 기존 설정은 타임스탬프 백업 후 변경하고, 사용자의 다른 설정·env 는 보존합니다.
18
+
19
+ - 특정 클라이언트만: `npm run init -- --client claude|claude-code|codex|cursor`
20
+ - 감지 여부와 무관하게 전부: `npm run init -- --all-clients`
21
+ - 쓰지 않고 설정만 출력(붙여넣기용): `npm run init -- --print`
22
+
23
+ 설정 후에는 **AI 클라이언트를 완전히 종료했다가 다시 실행**해야 적용됩니다. Claude Code 는 첫 실행 시 1회 승인 프롬프트가 뜹니다.
24
+
25
+ > **npx로도 가능:** `careermate`는 npm에 게시되어 있어 클론 없이 `npx -y careermate init`으로도 등록할 수 있습니다(가장 간단). 위 소스 기반(`npm install` → `npm run init`, 동등하게 `node bin/careermate.mjs init`)은 개발이나 `.mcpb` 빌드 시 사용하세요.
26
+
27
+ ---
28
+
29
+ ## 경로에 대하여
30
+
31
+ 아래 모든 스니펫에서 `C:\path\to\careermate` 를 **실제 CareerMate 폴더의 절대 경로**로 바꾸세요. 실행 대상 파일은 `apps/mcp/src/index.ts` 입니다.
32
+
33
+ - **Windows**: JSON 안에서 역슬래시는 `\\` 로 두 번 씁니다 (예: `C:\\path\\to\\careermate\\apps\\mcp\\src\\index.ts`). TOML 에서는 작은따옴표 리터럴 문자열을 쓰면 역슬래시를 한 번만 써도 됩니다.
34
+ - **macOS / Linux**: 슬래시 `/` 를 그대로 사용합니다.
35
+
36
+ ---
37
+
38
+ ## Claude Desktop
39
+
40
+ 설정 파일 위치:
41
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
42
+ - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
43
+
44
+ (Claude Desktop → Settings → Developer → Edit Config 로도 같은 파일을 열 수 있습니다.)
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "careermate": {
50
+ "command": "node",
51
+ "args": ["--no-warnings", "--experimental-sqlite", "--import", "tsx", "C:\\path\\to\\careermate\\apps\\mcp\\src\\index.ts"]
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ 수정 후 Claude Desktop을 **완전히 종료했다가 다시 실행**해야 적용됩니다.
58
+
59
+ > 비개발자용 원클릭 설치(`.mcpb`)는 별도 경로입니다. 자세한 내용은 [INSTALL_AND_USAGE.md](./INSTALL_AND_USAGE.md) 와 [SUPPORTED_AI_APPS.md](./SUPPORTED_AI_APPS.md) 를 참고하세요.
60
+
61
+ ---
62
+
63
+ ## Claude Code
64
+
65
+ Claude Code 는 CareerMate 폴더의 **프로젝트 스코프 `.mcp.json`** 으로 MCP를 등록합니다. 파일은 CareerMate 폴더 최상단에 두며, 최상위 키는 `mcpServers` 입니다.
66
+
67
+ ```json
68
+ {
69
+ "mcpServers": {
70
+ "careermate": {
71
+ "type": "stdio",
72
+ "command": "node",
73
+ "args": ["--no-warnings", "--experimental-sqlite", "--import", "tsx", "C:\\path\\to\\careermate\\apps\\mcp\\src\\index.ts"]
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ CLI 로 추가하려면 (CareerMate 폴더에서 실행):
80
+
81
+ ```bash
82
+ claude mcp add --scope project --transport stdio careermate -- node --no-warnings --experimental-sqlite --import tsx C:\path\to\careermate\apps\mcp\src\index.ts
83
+ ```
84
+
85
+ > Claude Code 는 프로젝트 서버를 처음 실행할 때 **1회 승인 프롬프트**를 띄웁니다. 승인해야 CareerMate 도구를 쓸 수 있습니다.
86
+
87
+ ---
88
+
89
+ ## Codex (OpenAI Codex CLI)
90
+
91
+ Codex 는 `~/.codex/config.toml` 의 `[mcp_servers.careermate]` 테이블로 등록합니다.
92
+
93
+ ```toml
94
+ [mcp_servers.careermate]
95
+ command = "node"
96
+ args = ["--no-warnings", "--experimental-sqlite", "--import", "tsx", 'C:\path\to\careermate\apps\mcp\src\index.ts']
97
+ ```
98
+
99
+ > **Windows 경로:** TOML 에서 위처럼 큰따옴표 안에 백슬래시를 쓰면 이스케이프 문제가 생길 수 있으니, 작은따옴표 리터럴 문자열을 권장합니다: `'C:\path\to\careermate\apps\mcp\src\index.ts'`. macOS/Linux 는 슬래시 경로를 그대로 큰따옴표에 넣으면 됩니다.
100
+
101
+ CLI 로 추가하려면:
102
+
103
+ ```bash
104
+ codex mcp add careermate -- node --no-warnings --experimental-sqlite --import tsx C:\path\to\careermate\apps\mcp\src\index.ts
105
+ ```
106
+
107
+ 추가 후 Codex 안에서 `/mcp` 명령으로 careermate 가 연결되었는지 확인하세요.
108
+
109
+ ---
110
+
111
+ ## Cursor / 기타 stdio MCP 클라이언트
112
+
113
+ 설정 파일 위치:
114
+ - 프로젝트별: `.cursor/mcp.json`
115
+ - 전역: `~/.cursor/mcp.json`
116
+
117
+ Cline, Windsurf 등 대부분의 로컬 stdio MCP 클라이언트가 동일한 형식을 사용합니다.
118
+
119
+ ```json
120
+ {
121
+ "mcpServers": {
122
+ "careermate": {
123
+ "command": "node",
124
+ "args": ["--no-warnings", "--experimental-sqlite", "--import", "tsx", "C:\\path\\to\\careermate\\apps\\mcp\\src\\index.ts"]
125
+ }
126
+ }
127
+ }
128
+ ```
129
+
130
+ 추가 후 클라이언트를 다시 시작하세요.
131
+
132
+ > **ChatGPT / Gemini 웹은 연결 불가:** CareerMate 는 이 컴퓨터에서 도는 **로컬 stdio MCP 서버**입니다. ChatGPT·Gemini 웹/모바일 앱은 클라우드에서 실행되어 **원격 URL 기반 MCP만** 쓸 수 있으므로 로컬 stdio 서버에 직접 연결할 수 없습니다. 로컬에서 실행되는 Claude Desktop·Claude Code·Codex 는 연결 가능합니다.
133
+
134
+ ---
135
+
136
+ ## 문제 해결
137
+
138
+ 연결이 안 되거나 검증이 필요하면:
139
+
140
+ - 검증: MCP 도구 `get_onboarding_status` 를 호출해 결과가 돌아오면 연결 성공입니다.
141
+ - 자세한 진단·점검 절차는 루트 [`../INSTALL.md`](../INSTALL.md) 의 문제 해결 절과 [START_WORKFLOW.md](./START_WORKFLOW.md) 의 사용 런북을 따르세요.
142
+ - 빠른 점검: CareerMate 폴더에서 `npm run doctor` (Node 버전·데이터 폴더·DB 상태 점검).
143
+
144
+ 자주 막히는 지점:
145
+ 1. 설정의 경로가 `apps/mcp/src/index.ts` 까지 정확한지, Windows JSON 이라면 역슬래시를 `\\` 로 썼는지 확인.
146
+ 2. `node --version` 이 22.5.0 이상인지 확인.
147
+ 3. CareerMate 폴더에서 `npm install` 이 완료되었는지 확인.
148
+ 4. 설정 변경 후 AI 클라이언트를 **완전히 종료 후 재시작** (Claude Code 는 1회 승인 프롬프트 처리).