careermate 0.1.2 → 0.1.4

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 (77) hide show
  1. package/AGENTS.md +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +3 -1
  4. package/apps/web/public/pages/documents.js +7 -2
  5. package/apps/web/public/pages/home.js +4 -7
  6. package/apps/web/public/pages/jobs.js +1 -5
  7. package/apps/web/public/pages/profile.js +3 -3
  8. package/apps/web/public/styles.css +7 -2
  9. package/dist/doctor.mjs +112 -90
  10. package/dist/install-page/analytics.js +97 -0
  11. package/dist/install-page/index.html +77 -56
  12. package/dist/install-page/og.png +0 -0
  13. package/dist/install-page/robots.txt +4 -0
  14. package/dist/install-page/sitemap.xml +21 -0
  15. package/dist/install-page/start.html +13 -10
  16. package/dist/install-page/style.css +75 -40
  17. package/dist/mcp.mjs +112 -90
  18. package/dist/migrate.mjs +95 -82
  19. package/dist/public/pages/documents.js +7 -2
  20. package/dist/public/pages/home.js +4 -7
  21. package/dist/public/pages/jobs.js +1 -5
  22. package/dist/public/pages/profile.js +3 -3
  23. package/dist/public/styles.css +7 -2
  24. package/dist/web.mjs +113 -86
  25. package/docs/FAQ.md +101 -0
  26. package/docs/career-os/README.md +76 -0
  27. package/docs/career-os/eop/cover-letter.md +46 -0
  28. package/docs/career-os/eop/fit-analysis.md +48 -0
  29. package/docs/career-os/eop/interview-prep.md +39 -0
  30. package/docs/career-os/eop/job-analysis.md +42 -0
  31. package/docs/career-os/eop/profile-extraction.md +37 -0
  32. package/docs/career-os/knowledge/ats.md +131 -0
  33. package/docs/career-os/knowledge/company-research.md +137 -0
  34. package/docs/career-os/knowledge/cover-letter.md +135 -0
  35. package/docs/career-os/knowledge/fit-matching.md +121 -0
  36. package/docs/career-os/knowledge/human-writing.md +118 -0
  37. package/docs/career-os/knowledge/interview-behavioral.md +132 -0
  38. package/docs/career-os/knowledge/interview-technical.md +126 -0
  39. package/docs/career-os/knowledge/linkedin-profile.md +152 -0
  40. package/docs/career-os/knowledge/networking-referrals.md +166 -0
  41. package/docs/career-os/knowledge/offer-evaluation-decision.md +121 -0
  42. package/docs/career-os/knowledge/onboarding-first-90-days.md +126 -0
  43. package/docs/career-os/knowledge/portfolio.md +121 -0
  44. package/docs/career-os/knowledge/recruiter-screen.md +105 -0
  45. package/docs/career-os/knowledge/rejection-triage-iteration.md +115 -0
  46. package/docs/career-os/knowledge/resume.md +123 -0
  47. package/docs/career-os/knowledge/salary-negotiation.md +123 -0
  48. package/docs/career-os/knowledge/verifiers/ats-compat.md +64 -0
  49. package/docs/career-os/knowledge/verifiers/consistency.md +61 -0
  50. package/docs/career-os/knowledge/verifiers/human-voice.md +82 -0
  51. package/docs/career-os/knowledge/verifiers/recency-staleness.md +72 -0
  52. package/docs/career-os/knowledge/verifiers/responsiveness-on-target.md +82 -0
  53. package/docs/career-os/knowledge/verifiers/truthfulness.md +67 -0
  54. package/package.json +11 -3
  55. package/packages/db/src/repositories.ts +18 -1
  56. package/packages/mcp-tools/src/tools.ts +5 -5
  57. package/packages/parsers/src/documents.ts +13 -1
  58. package/packages/shared/src/schemas.ts +115 -81
  59. package/scripts/build-dist.mjs +7 -1
  60. package/scripts/gen-og.mjs +1 -1
  61. package/scripts/test.ts +25 -0
  62. package/scripts/ui-smoke.ts +32 -4
  63. package/dist/install-page/.omc/state/agent-replay-55a58c0d-bb6e-43ea-8a05-4b6c93b80b34.jsonl +0 -12
  64. package/dist/install-page/.omc/state/idle-notif-cooldown.json +0 -3
  65. package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/mission-state.json +0 -147
  66. package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/pre-tool-advisory-throttle.json +0 -22
  67. package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/subagent-tracking-state.json +0 -44
  68. package/docs/ARCHITECTURE.md +0 -208
  69. package/docs/CHANGES_V1.md +0 -103
  70. package/docs/DATA_MODEL.md +0 -460
  71. package/docs/DECISIONS.md +0 -277
  72. package/docs/DEMO.md +0 -242
  73. package/docs/ROADMAP.md +0 -135
  74. package/docs/RUNTIME_DISTRIBUTION_RESEARCH.md +0 -135
  75. package/docs/TODO.md +0 -57
  76. package/docs/UX_NOTES.md +0 -247
  77. package/docs/superpowers/specs/2026-06-16-demo-dashboard-deploy-design.md +0 -64
package/docs/DECISIONS.md DELETED
@@ -1,277 +0,0 @@
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
- 전제된다. 도구 표면(31개 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 DELETED
@@ -1,242 +0,0 @@
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`을 호출합니다. 전달한 필드만 갱신되고 나머지는 유지됩니다(부분 저장 안전).
99
-
100
- ### 4단계 — 자기소개서/이력서 추가 🧑
101
-
102
- - 가진 이력서가 있으면 Documents 페이지에서 추가하고, 대표 문서로 지정합니다(대표 이력서는 이후 분석의 근거로 쓰입니다).
103
- - 기존 자기소개서가 있으면 함께 등록해 두면 좋습니다(AI가 톤·표현을 참고).
104
-
105
- > AI에게 맡기면 `add_resume`(이력서/경력기술서/포트폴리오), `save_cover_letter_version`(기존 자소서는 title+content로 v1 저장)을 호출하고, 구조화된 경력·프로젝트·스킬은 `add_experience`·`add_project`·`add_skill`로 저장합니다.
106
-
107
- ### 5단계 — AI 클라이언트에서 MCP 연결 확인 🧑
108
-
109
- - CareerMate는 **로컬 stdio MCP 서버**라, 내 컴퓨터에서 실행되며 로컬 프로그램을 띄울 수 있는 클라이언트에서만 동작합니다 — Claude Desktop · Cursor · Cline · Windsurf · Claude Code. (ChatGPT·Gemini의 웹/앱은 클라우드에서 돌아 로컬 MCP 서버에 직접 연결할 수 없습니다.) 설치는 크게 세 갈래입니다: 에이전트가 한 문장으로 대신 설치 / 터미널 `npx -y careermate init` / Claude Desktop `.mcpb` — 자세한 절차는 [`SUPPORTED_AI_APPS.md`](./SUPPORTED_AI_APPS.md)(또는 사람용 안내 https://careermate.life)를 참고하세요. 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
- - 🤖 붙여넣은 원문에서 회사명/직무/마감일/키워드를 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)를 참고하세요.
package/docs/ROADMAP.md DELETED
@@ -1,135 +0,0 @@
1
- # CareerMate 로드맵
2
-
3
- CareerMate는 MCP-우선 로컬 커리어 관리 도구다. 사용자는 자신의 ChatGPT/Claude/Gemini와 대화하고, 그 AI가 CareerMate의 로컬 MCP 도구를 호출해 로컬 커리어 DB를 읽고 쓴다. CareerMate 내부에는 LLM이 없으며(분석·작성은 사용자의 AI가 수행), 모든 데이터는 로컬에만 저장된다.
4
-
5
- 이 문서는 현재 버전(`0.1.1`)의 MVP 완료 범위와, 지금은 제외하되 구조는 열어둔 향후 과제를 정리한다.
6
-
7
- 관련 문서: [README](../README.md), [설치 런북](../INSTALL.md), [지원 앱·설치 레퍼런스](./SUPPORTED_AI_APPS.md), [워크플로우](./WORKFLOWS.md), [시작하기 워크플로우](./START_WORKFLOW.md)
8
-
9
- ---
10
-
11
- ## 현재 버전
12
-
13
- - 버전: `0.1.1` (`package.json`)
14
- - 런타임 요구: Node `>=22.5.0` (`node:sqlite` 내장 사용, 네이티브 컴파일 없음)
15
- - 실행 방식: 무빌드(tsx) — `node --no-warnings --import tsx ...`
16
-
17
- ---
18
-
19
- ## MVP 완료 항목 (Done)
20
-
21
- 현재 코드/설정과 일치하는, 동작 검증된 범위다.
22
-
23
- ### 코어 런타임 / 인프라
24
- - [x] **모노레포 구조**: `packages/{shared,db,core,mcp-tools,exporters,parsers,prompts,workflows}`, `apps/{web,mcp}`, `install-page`, `docs`, `scripts`
25
- - [x] **무빌드 실행**: TypeScript(ESM)를 `tsx`로 직접 실행 (`npm start`, `npm run dev --watch`, `npm run mcp`)
26
- - [x] **내장 SQLite**: `node:sqlite` 사용 — 별도 네이티브 모듈/컴파일 불필요
27
- - [x] **데이터 디렉터리**: 기본 `~/.careermate`, 환경변수 `CAREERMATE_DATA_DIR`로 변경 가능
28
- - [x] **DB 파일 및 부속 디렉터리**: `careermate.sqlite`, `exports/`, `backups/`, `uploads/`, 런타임 핸드셰이크 `server.json`
29
- - [x] **환경변수 지원**: `CAREERMATE_DATA_DIR`, `CAREERMATE_PORT`, `CAREERMATE_NO_OPEN`
30
- - [x] **npm 스크립트**: `start`, `dev`, `mcp`, `migrate`, `seed`, `doctor`, `test`, `test:ui`, `typecheck`
31
-
32
- ### 로컬 대시보드 + API (`apps/web`)
33
- - [x] **로컬 대시보드 서버**: 기본 `http://127.0.0.1:4319`, 포트 사용 중이면 다음 포트로 폴백, 브라우저 자동 오픈(`CAREERMATE_NO_OPEN`으로 비활성화)
34
- - [x] **프레임워크/CDN 없는 프런트엔드**: 바닐라 JS + 자체 CSS 디자인시스템
35
- - [x] **7개 페이지**: Home, Profile, Jobs(목록+상세), Applications(칸반), Documents(자소서 버전 타임라인 + 이력서), Interview, Settings
36
- - [x] **다크모드** 지원
37
-
38
- ### 데이터베이스 (`packages/db`)
39
- - [x] **12개 테이블**: `profile`, `experiences`, `projects`, `skills`, `documents`, `cover_letters`, `cover_letter_versions`, `jobs`, `fit_analyses`, `applications`, `interview_preps`, `activities` (+ 스키마 버전용 `_meta`)
40
- - [x] **마이그레이션/시드**: `npm run migrate`, `npm run seed`
41
- - [x] **지원 상태 8단계**: `draft`(작성 중), `planned`(지원 예정), `applied`(지원 완료), `document_passed`(서류 합격), `interview`(면접 진행), `final_passed`(최종 합격), `rejected`(불합격), `on_hold`(보류) — `document_passed` 이상에서 면접 준비 해금
42
-
43
- ### MCP 서버 (`apps/mcp`) + 도구 (`packages/mcp-tools`)
44
- - [x] **MCP stdio 서버**: `@modelcontextprotocol/sdk` 기반, AI 클라이언트가 `npm run mcp`로 기동, 대시보드와 동일 DB 공유
45
- - [x] **커리어 워크플로 MCP 도구 (26개)**:
46
- - 온보딩/프로필: `get_onboarding_status`, `save_profile`, `get_profile`
47
- - 문서: `add_resume`, `get_resumes`, `get_cover_letters`
48
- - 경력·프로젝트·스킬: `add_experience`, `get_experiences`, `add_project`, `get_projects`, `add_skill`, `get_skills`
49
- - 공고: `save_job_posting`, `get_job_posting`, `list_jobs`
50
- - 컨텍스트(핵심): `get_application_context`
51
- - 분석/작성: `save_fit_analysis`, `save_cover_letter_version`
52
- - 지원/면접: `update_application_status`, `save_interview_prep`
53
- - 글쓰기: `get_writing_style_guide`
54
- - 출력/연동: `export_cover_letter`, `open_dashboard`, `open_application`, `list_recent_activity`, `get_workflow_guide`
55
-
56
- ### 워크플로우 (`packages/workflows`)
57
- - [x] **5종 워크플로우**: `onboarding`, `analyze_job`, `write_cover_letter`, `manage_application_status`, `prepare_interview`
58
-
59
- ### 기능 흐름 (저장/관리)
60
- - [x] **온보딩**: 프로필·경력·프로젝트·스킬 입력 흐름
61
- - [x] **공고 저장**: 공고 본문 저장(회사명/직무/키워드 구조화는 AI가 수행)
62
- - [x] **적합도(fit) 분석 저장**: `save_fit_analysis`
63
- - [x] **자소서 버전 관리**: `cover_letter_versions` 테이블 + 타임라인 (Documents 페이지)
64
- - [x] **지원 상태 관리**: 8단계 칸반 (Applications 페이지) + `update_application_status`
65
- - [x] **면접 준비 저장**: `save_interview_prep` (서류 합격 이상 해금)
66
-
67
- ### Export
68
- - [x] **자소서 export**: `export_cover_letter` → `exports/` 디렉터리에 저장 (`format`: `md`(Markdown) 또는 `html`(인쇄용 HTML, 브라우저에서 PDF로 저장), 기본값 `md`)
69
-
70
- ### 보안
71
- - [x] `127.0.0.1` 전용 바인딩
72
- - [x] **Host 허용목록**(DNS 리바인딩 차단)
73
- - [x] **CSRF 세션 토큰**: 변경 요청 보호, HTML `<meta>` 주입 방식
74
- - [x] **외부 Origin 차단**
75
- - [x] **정적 파일 경로 traversal 차단**
76
- - [x] **8MB 본문 제한**
77
- - [x] **민감 본문 보호**: 이력서/자소서 본문은 로그·에러 응답에 미노출
78
-
79
- ### 설치 안내 / 문서 / 테스트
80
- - [x] **설치**: `npm install` → `npm start` (대시보드 자동 오픈), MCP 서버는 AI 클라이언트가 `npm run mcp`로 기동
81
- - [x] **설치 페이지**: `install-page`
82
- - [x] **문서**: `docs`
83
- - [x] **진단**: `npm run doctor`
84
- - [x] **타입 검사**: `npm run typecheck` (`tsc --noEmit`)
85
- - [x] **E2E 테스트** (`scripts/test.ts`, `npm test`): 17개 — 보안 / 업무 흐름 / MCP stdio / 대시보드↔MCP 동일 DB 양방향
86
- - [x] **UI 스모크 테스트** (`scripts/ui-smoke.ts`, `npm run test:ui`): Playwright로 8개 페이지 렌더 검증
87
- - [x] 두 테스트 스위트 모두 통과
88
-
89
- ---
90
-
91
- ## 후순위 / 향후 과제 (Backlog)
92
-
93
- 아래 항목은 **지금은 제외하되, 구조는 열어둔다**. 즉 현재 MVP 범위에서 구현하지 않지만, 패키지 경계·데이터 모델·도구 인터페이스가 이후 추가를 수용할 수 있도록 설계되어 있다.
94
-
95
- ### 공고 크롤링 (사람인 / 잡코리아 / 원티드)
96
- - 현재는 사용자가 공고 본문을 붙여넣으면 AI가 직접 구조화해 `save_job_posting`으로 저장한다. URL 입력 시 자동 크롤링은 미구현.
97
- - 구조 개방: 텍스트 정제 로직이 `packages/parsers`로 분리되어 있어(대시보드 `/api/parse/job`에서 사용), 사이트별 크롤러/어댑터를 추가하는 형태로 확장 가능.
98
- - **지금은 제외, 구조는 열어둠.**
99
-
100
- ### 클라우드 동기화
101
- - 현재 모든 데이터는 로컬(`~/.careermate`)에만 저장되며 외부 전송이 없다.
102
- - 구조 개방: 데이터 접근이 `packages/db`로 일원화되어 있어, 동기화 계층을 별도 어댑터로 얹을 여지가 있다.
103
- - **지금은 제외, 구조는 열어둠.** (로컬 전용·프라이버시가 현재 설계 원칙)
104
-
105
- ### ChatGPT App / Claude Extension 마켓 등록
106
- - 현재는 사용자가 로컬에서 `npm run mcp`로 직접 MCP 서버를 연결한다.
107
- - 구조 개방: MCP stdio 서버(`apps/mcp`)가 표준 `@modelcontextprotocol/sdk`를 사용하므로, 패키징/배포 형태로 마켓 등록을 추진할 수 있다.
108
- - **지금은 제외, 구조는 열어둠.**
109
-
110
- ### 브라우저 확장
111
- - 채용 사이트에서 공고를 바로 CareerMate로 보내는 확장.
112
- - 구조 개방: 로컬 API(`apps/web`)와 파서가 이미 분리되어 있어 확장에서 호출할 엔드포인트를 노출하는 형태로 연결 가능.
113
- - **지금은 제외, 구조는 열어둠.**
114
-
115
- ### Tauri / Electron 데스크톱 래퍼
116
- - 현재는 Node + 브라우저 기반 로컬 앱으로 동작한다.
117
- - 구조 개방: 대시보드가 프레임워크/CDN 의존이 없는 정적 자산이라 데스크톱 셸로 감싸기에 적합하다.
118
- - **지금은 제외, 구조는 열어둠.**
119
-
120
- ### DOCX export
121
- - 현재 export는 Markdown과 인쇄용 HTML(브라우저에서 PDF로 저장) 두 포맷만 지원한다(`packages/exporters`). 바이너리 DOCX 출력은 미구현.
122
- - 구조 개방: 출력 로직이 `packages/exporters`로 분리되어 있어, DOCX 등 포맷별 익스포터를 추가하는 형태로 확장 가능.
123
- - **지금은 제외, 구조는 열어둠.**
124
-
125
- ### 다국어 (i18n)
126
- - 현재 UI/프롬프트는 단일 언어 중심이다.
127
- - 구조 개방: 프롬프트가 `packages/prompts`로, UI 문자열이 대시보드 자산으로 분리되어 있어 다국어 리소스 도입 여지가 있다.
128
- - **지금은 제외, 구조는 열어둠.**
129
-
130
- ---
131
-
132
- ## 비목표 (Non-Goals)
133
-
134
- - **CareerMate 내부에 LLM을 두지 않는다.** 분석·작성은 사용자의 AI(ChatGPT/Claude/Gemini)가 MCP를 통해 수행한다.
135
- - **로컬 우선 원칙을 깨지 않는다.** 위 향후 과제(특히 클라우드 동기화)는 사용자 선택형·옵트인 전제하에서만 검토한다.