careermate 0.1.2 → 0.1.3

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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -1
  3. package/apps/web/public/pages/documents.js +7 -2
  4. package/apps/web/public/pages/home.js +4 -7
  5. package/apps/web/public/pages/jobs.js +1 -5
  6. package/apps/web/public/pages/profile.js +3 -3
  7. package/apps/web/public/styles.css +7 -2
  8. package/dist/doctor.mjs +112 -90
  9. package/dist/install-page/analytics.js +97 -0
  10. package/dist/install-page/index.html +77 -56
  11. package/dist/install-page/og.png +0 -0
  12. package/dist/install-page/robots.txt +4 -0
  13. package/dist/install-page/sitemap.xml +21 -0
  14. package/dist/install-page/start.html +13 -10
  15. package/dist/install-page/style.css +75 -40
  16. package/dist/mcp.mjs +112 -90
  17. package/dist/migrate.mjs +95 -82
  18. package/dist/public/pages/documents.js +7 -2
  19. package/dist/public/pages/home.js +4 -7
  20. package/dist/public/pages/jobs.js +1 -5
  21. package/dist/public/pages/profile.js +3 -3
  22. package/dist/public/styles.css +7 -2
  23. package/dist/web.mjs +113 -86
  24. package/package.json +1 -2
  25. package/packages/db/src/repositories.ts +18 -1
  26. package/packages/mcp-tools/src/tools.ts +5 -5
  27. package/packages/parsers/src/documents.ts +13 -1
  28. package/packages/shared/src/schemas.ts +115 -81
  29. package/scripts/build-dist.mjs +7 -1
  30. package/scripts/gen-og.mjs +1 -1
  31. package/scripts/test.ts +25 -0
  32. package/scripts/ui-smoke.ts +32 -4
  33. package/dist/install-page/.omc/state/agent-replay-55a58c0d-bb6e-43ea-8a05-4b6c93b80b34.jsonl +0 -12
  34. package/dist/install-page/.omc/state/idle-notif-cooldown.json +0 -3
  35. package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/mission-state.json +0 -147
  36. package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/pre-tool-advisory-throttle.json +0 -22
  37. package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/subagent-tracking-state.json +0 -44
  38. package/docs/ARCHITECTURE.md +0 -208
  39. package/docs/CHANGES_V1.md +0 -103
  40. package/docs/DATA_MODEL.md +0 -460
  41. package/docs/DECISIONS.md +0 -277
  42. package/docs/DEMO.md +0 -242
  43. package/docs/MCP_TOOLS.md +0 -292
  44. package/docs/ROADMAP.md +0 -135
  45. package/docs/RUNTIME_DISTRIBUTION_RESEARCH.md +0 -135
  46. package/docs/START_WORKFLOW.md +0 -137
  47. package/docs/SUPPORTED_AI_APPS.md +0 -112
  48. package/docs/TODO.md +0 -57
  49. package/docs/UX_NOTES.md +0 -247
  50. package/docs/WORKFLOWS.md +0 -202
  51. package/docs/superpowers/specs/2026-06-16-demo-dashboard-deploy-design.md +0 -64
package/docs/MCP_TOOLS.md DELETED
@@ -1,292 +0,0 @@
1
- # MCP 도구 레퍼런스
2
-
3
- CareerMate는 **MCP-우선** 로컬 커리어 관리 도구입니다. 사용자는 자신의 ChatGPT/Claude/Gemini와 대화하고, 그 AI가 여기 정의된 MCP 도구를 호출해 로컬 커리어 DB(`~/.careermate/careermate.sqlite`)를 읽고 씁니다. **CareerMate 내부에는 LLM이 없습니다.** 적합도 분석·자기소개서 작성 같은 추론은 모두 사용자의 AI가 수행하고, CareerMate는 데이터를 저장하고 다시 돌려주는 역할만 합니다.
4
-
5
- 이 문서는 `packages/mcp-tools/src/tools.ts`에 정의된 커리어 워크플로 **31개 도구**의 레퍼런스입니다. 도구의 입력 파라미터는 `packages/shared/src/schemas.ts`의 zod 스키마와 일치합니다.
6
-
7
- > 설계 원칙: 이 도구들은 단순 CRUD 래퍼가 아닙니다. 각 도구는 AI가 사용자를 대신해 수행하는 실제 작업에 대응하며, 설명에 *언제* 그리고 *어떻게* 호출해야 하는지가 담겨 있습니다. 가장 중요한 도구는 [`get_application_context`](#get_application_context-) 입니다.
8
-
9
- 관련 문서: 전체 워크플로우는 `get_workflow_guide` 도구 또는 `packages/workflows`를, 데이터 구조는 `packages/shared/src/schemas.ts`를 참고하세요.
10
-
11
- ---
12
-
13
- ## 읽기 전용(read-only) 표기 안내
14
-
15
- 각 도구 항목의 **읽기전용** 열은 `tools.ts`의 `readOnly: true` 플래그를 그대로 반영합니다. 읽기전용 도구는 DB를 변경하지 않고 조회만 하며, 그 외 도구는 데이터를 생성·갱신하거나(쓰기) 브라우저를 여는 등의 부수효과를 가집니다.
16
-
17
- | 읽기전용(✅) 도구 | 쓰기/부수효과(✏️) 도구 |
18
- | --- | --- |
19
- | `read_document`, `read_inbox`, `get_onboarding_status`, `get_profile`, `get_resumes`, `get_experiences`, `get_projects`, `get_skills`, `get_cover_letters`, `get_job_posting`, `list_jobs`, `get_application_context`, `list_recent_activity`, `get_workflow_guide`, `get_writing_style_guide`, `check_for_update` | `open_inbox`, `save_profile`, `add_resume`, `add_experience`, `add_project`, `add_skill`, `save_cover_letter_version`, `save_job_posting`, `save_fit_analysis`, `update_application_status`, `save_interview_prep`, `export_cover_letter`, `open_dashboard`, `open_application`, `update_careermate` |
20
-
21
- ---
22
-
23
- ## 0. 문서 읽기 (Read Document)
24
-
25
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
26
- | --- | --- | --- | --- | --- | --- |
27
- | `read_document` | 컴퓨터의 문서 파일에서 본문 텍스트 추출(PDF·Word·한컴·텍스트) | `path`(절대 경로 권장), `max_chars?` | `{ path, format, characters, truncated, warnings[], text }` | 사용자가 파일 경로를 주며 "이 파일 읽어줘/참고해줘"라고 할 때 | ✅ |
28
-
29
- - 지원 형식: `.pdf`, `.docx`, `.hwp`(HWP 5.x), `.hwpx`, `.txt`/`.md` 등 텍스트. 전부 **순수 JS로 추출**하며 외부 변환기(poppler 등) 설치가 필요 없습니다.
30
- - 추출한 텍스트는 그대로 새 파일로 다시 쓰지 말고, 분석/작성에 활용한 뒤 결과를 `add_resume`·`save_job_posting`·`save_cover_letter_version` 등으로 CareerMate에 저장하세요.
31
- - **이미지·스캔 PDF**는 텍스트 레이어가 없어 추출되지 않습니다(`unsupported`로 반환되며 `warnings`에 안내). 이때는 이미지를 직접 볼 수 있는 클라이언트(예: Claude)로 읽거나, 사용자에게 내용을 텍스트로 붙여넣어 달라고 안내하세요. 구형 `.doc`/`.ppt`/`.xls`·`.odt`·iWork는 미지원이니 PDF/`.docx`로 다시 저장하도록 안내합니다.
32
- - 파일은 **로컬에서만** 처리되며 외부로 전송되지 않습니다. 25MB를 넘는 파일은 거부합니다.
33
-
34
- ---
35
-
36
- ## 0-1. 인입 폴더 (Inbox)
37
-
38
- CLI 클라이언트(Claude Code·Codex 등)는 파일 첨부가 안 되므로, 사용자가 기존 이력서·경력기술서 파일을 끌어다 넣을 수 있는 로컬 인입 폴더(`~/.careermate/inbox`)를 두고 그 안의 파일을 읽습니다. 사용자가 파일 **경로**를 직접 알려주는 경우에는 인입 폴더 대신 `read_document`를 쓰세요.
39
-
40
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
41
- | --- | --- | --- | --- | --- | --- |
42
- | `open_inbox` | 인입 폴더(`~/.careermate/inbox`)를 보장하고 파일 탐색기로 열기 + 현재 들어 있는 파일 목록 반환 | 없음 | `{ dir, files[] }` | 온보딩에서 사용자가 "기존에 작성해 둔 이력서 파일이 있다"고 답했을 때만(묻지 않고 자동으로 열지 마세요) | ✏️ |
43
- | `read_inbox` | 인입 폴더에 넣어 둔 문서들의 본문을 한 번에 추출해 반환 | `filename?`(대소문자 무시, 생략 시 전체), `max_chars?`(파일별 기본 20000자) | `{ dir, files[] }`(각 `{ filename, path, format, unsupported, truncated, warnings[], text }`) | `open_inbox`로 안내한 뒤 사용자가 "다 넣었어"라고 할 때 | ✅ |
44
-
45
- - `open_inbox`는 폴더를 열기만 합니다. 사용자가 파일을 다 넣었다고 하면 `read_inbox`로 본문을 읽으세요.
46
- - `docx`/`hwp`/`hwpx`/텍스트는 텍스트를 추출하고, **`pdf`·이미지는 추출하지 않고 파일 경로만** 돌려주니(`unsupported`) AI 클라이언트의 파일 읽기 기능으로 그 경로를 직접 열어 읽으세요.
47
- - 읽은 내용은 그대로 새 파일로 다시 쓰지 말고, 구조화해 `save_profile`·`add_resume` 등 알맞은 도구로 CareerMate에 저장하세요.
48
- - 응답 폭발을 막기 위해 파일별 본문은 `max_chars`(기본 20000자)로 잘라서 돌려주며, 잘린 경우 `truncated: true`로 표시합니다.
49
-
50
- ---
51
-
52
- ## 1. 온보딩 (Onboarding)
53
-
54
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
55
- | --- | --- | --- | --- | --- | --- |
56
- | `get_onboarding_status` | CareerMate에 어떤 정보(프로필·이력서·경력·스킬·자소서·공고)가 준비되어 있는지 확인하고 다음 단계를 제시 | 없음 | `completed`, `has_profile`/`has_resume`/`has_cover_letter`/`has_experience`/`has_skills`/`has_job`, `profile_completeness`(0~100), `next_steps[]` | AI 클라이언트 연결 직후 가장 먼저 | ✅ |
57
-
58
- AI 클라이언트가 연결되면 이 도구를 가장 먼저 호출해 상태를 파악한 뒤, 단계별 가이드가 필요하면 `get_workflow_guide('onboarding')`로 받으세요. 안내 흐름: 프로필 입력 → 이력서/경력·스킬 추가 → 대시보드 열기.
59
-
60
- ---
61
-
62
- ## 2. 프로필 (Profile)
63
-
64
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
65
- | --- | --- | --- | --- | --- | --- |
66
- | `get_profile` | 기본 프로필 조회(이름, 한 줄 소개, 요약, 희망 직무/조건, 선호 문체, 강조 포인트, 링크) | 없음 | `ProfileRecord` 또는 `null` | 프로필 확인이 필요할 때 | ✅ |
67
- | `save_profile` | 프로필 저장(부분 저장 안전 — 전달한 필드만 갱신, 나머지는 유지) | 아래 프로필 필드 | 저장된 `ProfileRecord` | 이력서 구조화 후 이름/소개/희망 직무/선호 문체/강조 포인트를 채워 저장할 때 | ✏️ |
68
-
69
- 프로필 입력 필드(`ProfileInputSchema`):
70
-
71
- - `name`(이름), `email`, `phone`, `location`
72
- - `headline`(한 줄 소개 / 직무 타이틀), `summary`(자기소개 요약)
73
- - `desired_roles[]`(희망 직무), `desired_conditions`(희망 근무 조건: 연봉·지역·근무형태)
74
- - `preferred_tone`(자기소개서 선호 문체, 예: "담백하고 구체적")
75
- - `emphasis_points[]`(강조하고 싶은 핵심 포인트)
76
- - `links[]`(`{ label, url }` — 포트폴리오/깃허브/링크드인)
77
-
78
- > `preferred_tone`과 `emphasis_points`는 이후 자기소개서 작성 품질에 직접 영향을 줍니다.
79
-
80
- ---
81
-
82
- ## 3. 이력서 (Resumes / Documents)
83
-
84
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
85
- | --- | --- | --- | --- | --- | --- |
86
- | `add_resume` | 이력서·경력기술서·포트폴리오 등 문서 저장 | `title`, `content`(필수), `kind?`, `source?`, `is_primary?`, `tags?` | 저장된 `DocumentRecord` | 사용자가 업로드/붙여넣은 텍스트(또는 정리한 Markdown)를 보관할 때 | ✏️ |
87
- | `get_resumes` | 저장된 문서 조회(종류 필터 가능) | `kind?` | `DocumentRecord[]` | 저장된 이력서/문서를 확인할 때 | ✅ |
88
-
89
- - `kind` 값: `resume`(이력서, 기본값) / `career_description`(경력기술서) / `portfolio` / `other`
90
- - `is_primary: true`로 대표 문서를 지정하면 `get_application_context`의 `primary_resume`로 노출됩니다.
91
-
92
- ---
93
-
94
- ## 3-1. 경력·프로젝트·기술스택 (Experiences / Projects / Skills)
95
-
96
- 이력서 본문(`add_resume`)과 별개로, **구조화된** 경력·프로젝트·기술을 각각의 테이블에 항목 단위로 저장합니다. `get_application_context`의 `experiences`/`projects`/`skills`로 노출되며, `get_onboarding_status`의 `has_experience`/`has_skills`와 프로필 완성도(0~100) 계산에 직접 반영됩니다. (대시보드의 Profile 페이지에서도 같은 데이터를 편집합니다.)
97
-
98
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
99
- | --- | --- | --- | --- | --- | --- |
100
- | `add_experience` | 경력(직장 단위) 항목 저장 | `company`(필수), `role?`, `employment_type?`, `start_date?`, `end_date?`, `is_current?`, `description?`, `achievements?`, `tech?`, `order_index?` | 저장된 `ExperienceRecord` | 이력서에서 경력을 구조화해 보관할 때 | ✏️ |
101
- | `get_experiences` | 저장된 경력을 시간 역순으로 조회 | 없음 | `ExperienceRecord[]` | 경력 목록만 빠르게 확인할 때 | ✅ |
102
- | `add_project` | 대표 프로젝트 항목 저장 | `name`(필수), `role?`, `description?`, `highlights?`, `tech?`, `url?`, `start_date?`, `end_date?`, `order_index?` | 저장된 `ProjectRecord` | 프로젝트 이력을 구조화해 보관할 때 | ✏️ |
103
- | `get_projects` | 저장된 프로젝트 조회 | 없음 | `ProjectRecord[]` | 프로젝트 목록만 확인할 때 | ✅ |
104
- | `add_skill` | 기술스택 항목 저장(개당 1건) | `name`(필수), `category?`, `level?`, `years?`, `order_index?` | 저장된 `SkillRecord` | 보유 기술을 정리해 둘 때 | ✏️ |
105
- | `get_skills` | 저장된 기술스택 조회 | 없음 | `SkillRecord[]` | 기술 목록만 확인할 때 | ✅ |
106
-
107
- - `achievements`/`highlights`에는 정량 지표가 담긴 성과를, `tech`에는 사용 기술을 배열로 넣으면 적합도 분석·자소서·면접 준비에서 근거로 활용됩니다.
108
- - 기술은 항목당 1건이므로 여러 개면 `add_skill`을 반복 호출하세요.
109
- - 입력 스키마: `ExperienceInputSchema` / `ProjectInputSchema` / `SkillInputSchema`(`packages/shared/src/schemas.ts`).
110
-
111
- ---
112
-
113
- ## 4. 자기소개서 (Cover Letters)
114
-
115
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
116
- | --- | --- | --- | --- | --- | --- |
117
- | `get_cover_letters` | 저장된 자기소개서 조회(공고별 필터 가능). 각 항목은 현재 버전 내용·버전 수 포함 | `job_id?` | `CoverLetterRecord[]` | 자소서 목록/내용을 확인할 때 | ✅ |
118
- | `save_cover_letter_version` | 자기소개서의 새 버전 저장 — 자소서 작성 워크플로우의 핵심 저장 단계 | `content`(필수), `cover_letter_id?`, `title?`, `job_id?`, `note?`, `source?`, `set_current?` | `{ coverLetter, version }` | 새 공고용 자소서를 생성·갱신해 버전으로 남길 때 | ✏️ |
119
-
120
- `save_cover_letter_version` 동작(`CoverLetterVersionInputSchema`):
121
-
122
- - `cover_letter_id`를 주면 기존 자소서에 **새 버전을 추가**하고, 없으면 새 자소서를 만들어 **v1**로 저장합니다(이때 `title` 권장).
123
- - `note`에 변경 요약(예: "지원동기 보강")을 남기면 대시보드 버전 히스토리에서 이해하기 쉽습니다.
124
- - `job_id`로 공고에 연결하면 지원(application) 항목과 자동 연결됩니다.
125
- - `set_current`(기본 `true`): 이 버전을 현재 버전으로 지정.
126
-
127
- > 기존 자소서를 학습용으로 보관하든 새 공고용 자소서를 새로 쓰든, 저장은 모두 `save_cover_letter_version`으로 합니다. `title`+`content`만 주면 새 자소서의 v1로 저장됩니다.
128
-
129
- ---
130
-
131
- ## 5. 채용공고 (Jobs)
132
-
133
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
134
- | --- | --- | --- | --- | --- | --- |
135
- | `save_job_posting` | 채용공고 저장(있으면 갱신). 저장 시 지원(application) 항목 자동 생성 | `company`, `position`(필수), `url?`, `location?`, `employment_type?`, `description?`, `requirements?`, `keywords?`, `deadline?`, `source?` | 저장된 `JobRecord`(`job_id` 포함) | 공고를 DB에 등록/갱신할 때 | ✏️ |
136
- | `get_job_posting` | 공고 1건 상세 조회 | `job_id` | `{ job, fit, application, cover_letters, interview }` | 한 공고의 분석·상태·자소서·면접 자료를 한 번에 볼 때 | ✅ |
137
- | `list_jobs` | 저장된 모든 공고를 지원 상태·적합도 점수와 함께 목록화 | 없음 | 공고 메타 포함 배열 | 전체 공고를 훑어볼 때 | ✅ |
138
-
139
- - `url`이 같으면 중복 생성 없이 갱신됩니다.
140
- - `requirements`에는 자격요건/우대사항 핵심, `keywords`에는 핵심 키워드를 정리해 넣으면 이후 적합도 분석·자소서 작성에 활용됩니다.
141
- - 붙여넣은 공고 원문의 구조화(회사명/직무/마감일/키워드 추출)는 AI가 직접 수행한 뒤 `save_job_posting`으로 저장합니다.
142
-
143
- ---
144
-
145
- ## 6. 적합도 (Fit Analysis)
146
-
147
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
148
- | --- | --- | --- | --- | --- | --- |
149
- | `save_fit_analysis` | AI가 도출한 적합도 분석 결과 저장(같은 공고에 다시 저장하면 갱신) | `job_id`(필수), `score?`(0~100), `summary?`, `strengths?`, `gaps?`, `matched_keywords?`, `missing_keywords?`, `recommendations?` | 저장된 `FitAnalysisRecord` | 공고와 사용자 정보를 비교 분석한 결과를 저장할 때 | ✏️ |
150
-
151
- - `job_id`는 필수이며, 먼저 `save_job_posting`으로 공고가 저장되어 있어야 합니다.
152
- - 분석 자체는 AI가 수행하고, 이 도구는 결과만 저장합니다. 분석 전에는 반드시 [`get_application_context`](#get_application_context-)로 맥락을 가져오세요.
153
-
154
- ---
155
-
156
- ## 7. 지원 상태 (Application Status)
157
-
158
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
159
- | --- | --- | --- | --- | --- | --- |
160
- | `update_application_status` | 지원 상태 변경. `document_passed` 이상이면 면접 준비를 제안하는 힌트 동봉 | `job_id`, `status`, `note?` | 변경 결과(`hint` 포함 가능) | 지원 진행 단계가 바뀔 때 | ✏️ |
161
-
162
- 지원 상태 8단계(`APPLICATION_STATUSES`):
163
-
164
- | 상태 | 라벨 |
165
- | --- | --- |
166
- | `draft` | 작성 중 |
167
- | `planned` | 지원 예정 |
168
- | `applied` | 지원 완료 |
169
- | `document_passed` | 서류 합격 |
170
- | `interview` | 면접 진행 |
171
- | `final_passed` | 최종 합격 |
172
- | `rejected` | 불합격 |
173
- | `on_hold` | 보류 |
174
-
175
- > `document_passed`(서류 합격) 이상에서 면접 준비가 해금되며, 상태 변경 응답에 면접 준비 제안 힌트가 함께 돌아옵니다.
176
-
177
- ---
178
-
179
- ## 8. 면접 준비 (Interview Prep)
180
-
181
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
182
- | --- | --- | --- | --- | --- | --- |
183
- | `save_interview_prep` | 예상 질문·꼬리 질문·STAR 답변 가이드·1분 자기소개 초안 등 면접 준비 자료 저장(같은 공고면 갱신) | `job_id`(필수), `questions?`, `star_guides?`, `self_introduction?`, `notes?` | 저장된 `InterviewPrepRecord`(질문 수 포함) | 보통 서류 합격 후, AI가 생성한 면접 자료를 저장할 때 | ✏️ |
184
-
185
- 입력 구조(`InterviewPrepInputSchema`):
186
-
187
- - `questions[]`: `{ question, intent?(질문 의도), followups?(예상 꼬리 질문), answer_outline?(답변 가이드/핵심 포인트) }`
188
- - `star_guides[]`: `{ question, situation?, task?, action?, result? }`
189
- - `self_introduction`: 1분 자기소개 초안
190
- - `notes`: 면접 후기/메모
191
-
192
- ---
193
-
194
- ## 9. 내보내기 (Exports)
195
-
196
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
197
- | --- | --- | --- | --- | --- | --- |
198
- | `export_cover_letter` | 자기소개서를 Markdown 또는 인쇄용 HTML 파일로 데이터 폴더 `exports/`에 저장 | `cover_letter_id`, `format?`(`md`(기본)/`html`) | `{ path, filename, content }` | 사용자가 "자소서 파일로 받고 싶어"라고 할 때 | ✏️ |
199
-
200
- - HTML은 인쇄용으로, 브라우저에서 PDF로 저장할 수 있습니다.
201
- - 대시보드의 Documents 페이지에서 직접 다운로드할 수도 있습니다.
202
-
203
- ---
204
-
205
- ## 10. 대시보드 (Dashboard UI)
206
-
207
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
208
- | --- | --- | --- | --- | --- | --- |
209
- | `open_dashboard` | 로컬 대시보드를 사용자 브라우저에서 열기(서버 미실행 시 자동 시작) | 없음 | `{ url, running }` | 저장 결과를 사용자가 눈으로 확인하게 할 때(예: 분석/자소서 저장 후) | ✏️ |
210
- | `open_application` | 특정 공고의 지원 상세 페이지(`/#/jobs/{job_id}`)를 브라우저에서 열기 | `job_id` | `{ url, running }` | 적합도·자소서·면접 준비를 바로 확인하도록 안내할 때 | ✏️ |
211
-
212
- - 대시보드 기본 주소: `http://127.0.0.1:4319` (포트 사용 중이면 다음 포트로 폴백).
213
- - 서버가 실행 중이 아니면 안내 메시지에 `npm start` 실행을 권고합니다.
214
-
215
- ---
216
-
217
- ## 11. 활동 (Activity)
218
-
219
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
220
- | --- | --- | --- | --- | --- | --- |
221
- | `list_recent_activity` | 최근 활동 내역(공고 저장, 적합도 분석, 자소서 버전, 상태 변경, 면접 준비 등) 조회 | `limit?`(기본 20) | `ActivityRecord[]` | "최근에 뭐 했지?" 또는 이어서 작업할 맥락이 필요할 때 | ✅ |
222
-
223
- ---
224
-
225
- ## 12. 워크플로우 가이드 (Workflow Guide)
226
-
227
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
228
- | --- | --- | --- | --- | --- | --- |
229
- | `get_workflow_guide` | 표준 워크플로우의 단계별 안내 반환 | `workflow_id?` | 단일 워크플로우 Markdown 또는 전체 목록(`{ id, title, trigger }[]`) | 어떤 순서로 어떤 도구를 호출할지 확인할 때 | ✅ |
230
-
231
- `workflow_id` 값: `onboarding`, `analyze_job`, `write_cover_letter`, `manage_application_status`, `prepare_interview`. 생략하면 전체 목록을 돌려줍니다.
232
-
233
- ---
234
-
235
- ## 13. 글쓰기 스타일 가이드 (Writing Style Guide)
236
-
237
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
238
- | --- | --- | --- | --- | --- | --- |
239
- | `get_writing_style_guide` | "AI 티 안 나는" 한국어 글쓰기 규칙 반환 | 없음 | `{ guide }` (작성 규칙 + 저장 전 자가 점검) | 자기소개서·자기 PR·지원 메일 등 사람이 쓴 듯한 글을 작성하기 직전 | ✅ |
240
-
241
- 번역투·클리셰·기계적 병렬·상투적 연결어·균일한 문장 리듬 같은 AI-tell을 제거하면서, 사실·수치·고유명사는 그대로 보존하도록 안내합니다. `write_cover_letter` / `analyze_job` 워크플로우의 작성 단계에서 함께 적용합니다. (규칙 출처: `epoko77-ai/im-not-ai`, MIT.)
242
-
243
- ---
244
-
245
- ## 14. 업데이트 (Update)
246
-
247
- CareerMate를 최신 버전으로 유지하기 위한 유지보수 도구입니다. 확인은 `check_for_update`로, 실제 적용은 `update_careermate`로 합니다.
248
-
249
- | 도구 | 목적 | 주요 입력 | 반환 | 언제 호출 | 읽기전용 |
250
- | --- | --- | --- | --- | --- | --- |
251
- | `check_for_update` | npm 레지스트리에서 새 버전이 있는지 지금 확인(공개 버전 정보만 GET, 사용자 데이터 미전송) | 없음 | `{ current, latest, update_available }` | 사용자가 "최신이야?/업데이트 있어?"라고 묻거나 `get_onboarding_status`가 새 버전을 알릴 때 | ✅ |
252
- | `update_careermate` | 설치 폴더에 `careermate@latest`를 npm으로 설치해 최신 버전으로 업데이트 | 없음 | 업데이트 결과(`{ ok, message, manual? }`) | 사용자가 명시적으로 "업데이트해줘"라고 할 때만 | ✏️ |
253
-
254
- - `check_for_update`는 확인만 하며 데이터를 변경하지 않습니다. 새 버전이 있으면 `update_careermate`로 적용하세요.
255
- - `update_careermate` 성공 후에는 적용을 위해 AI 앱(또는 MCP 연결) **재시작**이 필요합니다. 재시작 시 데이터베이스는 자동 마이그레이션되어 기존 데이터가 보존됩니다.
256
- - 자동 설치가 막히면(개발 모드·비표준 설치) 직접 칠 명령(`manual`)을 안내합니다.
257
-
258
- ---
259
-
260
- ## ⭐ get_application_context — 분석/작성 전 필수 호출
261
-
262
- > `get_application_context`는 **가장 중요한 도구**입니다. 공고를 분석하거나 자기소개서를 작성하기 **전에 반드시 먼저** 호출하세요. 한 번의 호출로 사용자에 대한 모든 맥락을 돌려줍니다. 읽기전용(✅)입니다.
263
-
264
- **입력**
265
-
266
- - `job_id?`(선택) — 특정 공고 기준으로 맥락을 모을 때.
267
-
268
- **한 번에 반환하는 데이터 전체**(`ApplicationContextSchema`):
269
-
270
- | 필드 | 내용 |
271
- | --- | --- |
272
- | `profile` | 사용자 프로필(`ProfileRecord` 또는 `null`) |
273
- | `primary_resume` | 대표 이력서(`is_primary` 문서, 없으면 `null`) |
274
- | `resumes` | 전체 이력서/문서 배열 |
275
- | `experiences` | 전체 경력 배열 |
276
- | `projects` | 프로젝트 배열 |
277
- | `skills` | 기술스택 배열 |
278
- | `cover_letters` | 기존 자기소개서 배열(버전 정보 포함) |
279
- | `recent_applications` | 최근 지원 이력 배열 |
280
- | `job` | (`job_id` 제공 시) 대상 공고(`JobRecord` 또는 `null`) |
281
- | `fit_analysis` | (`job_id` 제공 시) 대상 공고의 이전 적합도 분석(`FitAnalysisRecord` 또는 `null`) |
282
- | `related_history` | 같은 회사/직무 관련 이전 기록 배열 — 각 항목 `{ job, application, fit_analysis }` |
283
- | `writing_preferences` | 자소서 작성 선호 — `{ preferred_tone, emphasis_points[] }` |
284
-
285
- **사용 흐름**
286
-
287
- 1. (자소서/분석 대상이 있으면) `save_job_posting`으로 공고를 먼저 저장해 `job_id`를 확보.
288
- 2. `get_application_context({ job_id })`로 위 데이터를 한 번에 가져옴.
289
- 3. 이 데이터를 근거로 **AI가** 적합도 분석 또는 자기소개서를 작성.
290
- 4. 결과를 `save_fit_analysis` / `save_cover_letter_version`으로 다시 저장.
291
-
292
- > CareerMate는 데이터를 제공할 뿐이고, 분석·작성은 사용자의 AI가 수행합니다. 맥락 없이 작성하지 말고 항상 이 도구로 먼저 사용자 데이터를 확보하세요.
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
- - **로컬 우선 원칙을 깨지 않는다.** 위 향후 과제(특히 클라우드 동기화)는 사용자 선택형·옵트인 전제하에서만 검토한다.
@@ -1,135 +0,0 @@
1
- # 런타임·배포 조사: 완전 원클릭(Codex .exe / Claude `.mcpb`) 실현 가능성
2
-
3
- - **작성일**: 2026-06-15
4
- - **상태**: 조사 완료 / 큰 작업은 **보류(문서만)**
5
- - **관련**: [ADR #1 `node:sqlite` 채택](./DECISIONS.md), [ADR #6 대시보드·MCP의 SQLite(WAL) 공유 + `server.json` 핸드셰이크](./DECISIONS.md), [ROADMAP](./ROADMAP.md)
6
-
7
- > 이 문서는 "사용자가 Node/npx/git을 미리 깔지 않고도 한 번에 설치되는 경험"을 두 경로
8
- > (① OpenAI **Codex Windows 앱** + 단일 `.exe`, ② Claude Desktop **`.mcpb`**)에서 만들 수
9
- > 있는지 조사한 기록이다. 결론과 근거, 그리고 다음에 누가 이어받든 헛수고하지 않도록
10
- > "무엇이 작은 수정이고 무엇이 큰 작업인지"를 남긴다.
11
-
12
- ---
13
-
14
- ## TL;DR
15
-
16
- - **공통 근본 제약**: CareerMate는 **`node:sqlite`(Node ≥22.5의 최신 내장 기능)**에 의존한다.
17
- "무설치 번들 런타임" 전략의 성패는 전부 **"충분히 새로운 Node를 어떻게 확보하느냐"**로 수렴한다.
18
- - **Codex Windows 앱 + 단일 `.exe`**: 패키징(Node SEA)은 **기술적으로 성립**하나, **자가등록 지속성**과
19
- **샌드박스** 두 개의 (2026-05~06 기준) 외부 버그/제약 때문에 **진정한 무인 원클릭은 현재 불가**. → **보류.**
20
- - **Claude `.mcpb`**: 산출물(`dist/mcp.mjs`)은 **Node ≥22.5에서 정상 동작**함을 실증함. 사용자가 겪은
21
- "설치는 됐는데 도구가 안 뜸/빨간 에러"는 **Claude Desktop 내장 Node가 22.5 미만**일 때의 증상으로 추정되며,
22
- 그 경우의 해결은 **저장 계층 rewrite(= 큰 작업)**다. → **로그로 근본 원인 확정 후 결정.**
23
-
24
- ---
25
-
26
- ## 1. 배경 / 질문
27
-
28
- - CareerMate는 로컬 MCP stdio 서버 + 로컬 웹 대시보드. 저장은 `node:sqlite`.
29
- - 목표: 비개발자가 **아무것도 미리 설치하지 않고** 한 번에 쓰기 시작하는 경험.
30
- - 두 경로를 검토:
31
- 1. **Codex Windows 데스크톱 앱**(2026-03 출시, MS Store, 로컬 샌드박스+PowerShell)에 **Node 런타임을
32
- 동봉한 단일 `.exe`**(Node SEA)를 더블클릭 → 자가등록 → 동작.
33
- 2. **Claude Desktop `.mcpb`**(런타임 동봉형 원클릭) — 이미 빌드 파이프라인 존재(`scripts/build-mcpb.mjs`).
34
-
35
- ---
36
-
37
- ## 2. Codex Windows 앱 + 단일 `.exe` (Node SEA)
38
-
39
- ### 2.1 패키징 자체 — 성립 (조건부 가능)
40
-
41
- | 항목 | 판정 | 근거 |
42
- |---|---|---|
43
- | Windows에서 SEA `.exe` 생성 | 가능 | Node SEA의 **첫 번째 CI 테스트 플랫폼이 Windows**. `.exe` 출력 지원. 안정성 지수는 1.1(Active development). |
44
- | 빌드 워크플로 | 간소화됨 | Node **25.5.0**의 `--build-sea` 단일 플래그로 통합(종전 postject 3단계 불필요). |
45
- | 정적 자산(대시보드 HTML/CSS/JS) 임베드 | 가능 | `sea.getAsset()`/`getRawAsset()` 계열로 번들·런타임 서빙(v20.12.0~). 단 현재 `apps/web`는 디스크에서 자산을 읽으므로 **임베드용 코드 수정 필요**. |
46
- | `node:sqlite` 플래그 | 사실상 비이슈 | **Node ≥22.13 / ≥23.4부터 `--experimental-sqlite` 없이 동작**. 최신 Node를 임베드하면 해결. 필요시 SEA `execArgv`로 플래그 주입도 가능. |
47
-
48
- 근거 출처(주요): nodejs.org `single-executable-applications`, `sqlite` 문서; Node v25.5.0 릴리스 블로그;
49
- Joyee Cheung 블로그(Windows PE 주입 실테스트); commit `55239a48b6`("unflag sqlite module").
50
-
51
- ### 2.2 자가등록·동작을 막는 두 개의 블로커 — 현재 불가
52
-
53
- 1. **🚨 Codex 데스크톱이 시작 시 `~/.codex/config.toml`을 재작성하며 사용자 커스텀 `[mcp_servers]` 블록을 삭제**
54
- - openai/codex **issue #24718** (2026-05-27 OPEN, v26.519.11010.0, Win11 26200): "Codex Desktop overwrites
55
- `%USERPROFILE%\.codex\config.toml` during startup ... removes a manually configured custom MCP server",
56
- "blocking data-loss issue." (보강: #26530, #24387, JetBrains LLM-24906)
57
- - 의미: `.exe`가 `init`으로 스스로 등록해도 **앱이 지워버릴 수 있음** → 자가등록 전략의 핵심 전제가 깨짐.
58
- 2. **샌드박스가 MCP stdio 서브프로세스에도 상속됨**
59
- - 공식 문서: "The sandbox applies to spawned commands ... inherit the same sandbox boundaries", "Every file
60
- write, terminal command, network request, and process spawn goes through the sandbox."
61
- - 기본 `workspace-write`의 쓰기 가능 루트는 `cwd + $TMPDIR + /tmp`뿐 → **워크스페이스 바깥인
62
- `~/.careermate` 쓰기와 127.0.0.1 포트 바인딩이 기본 거부**. `danger-full-access` 또는
63
- `sandbox_workspace_write.writable_roots` 명시 필요. (실증: issue #18243, #24727 "windows sandbox failed: spawn setup")
64
-
65
- > 두 블로커 모두 **CareerMate 코드 문제가 아니라 Codex 앱 측 미해결 버그/설계 제약**이라 우리가 코드로 못 고친다.
66
- > #24718이 패치되고 샌드박스 정책이 정리되면 결론이 뒤집힐 수 있으므로 **추적 대상**.
67
-
68
- ### 2.3 결론(Codex)
69
-
70
- - 패키징은 가능, **무인 원클릭은 현재 불가** → **보류.** 당분간 Codex는 CLI/IDE 확장 경로 또는
71
- "Node 1회 설치 → `npx -y careermate init`" 안내가 현실적.
72
-
73
- ---
74
-
75
- ## 3. Claude Desktop `.mcpb`
76
-
77
- ### 3.1 실증 결과 (이 저장소, 2026-06-15, Node v25)
78
-
79
- - `manifest.json`은 정상: `server.type:"node"`, `args:["--experimental-sqlite","${__dirname}/dist/mcp.mjs"]`.
80
- - **`dist/mcp.mjs` 단독 부팅 성공** — `initialize` 응답 정상, **도구 24개** 로드, 데이터 `~/.careermate` 연결.
81
- - 이 PC의 **Node v25**에서: `--experimental-sqlite`는 **거부되지 않고 경고만**, 플래그 없이도 `node:sqlite` 동작.
82
- → "최신 Node가 플래그를 거부해 죽는다" 시나리오는 (최소 v25까지) **없음**.
83
-
84
- ### 3.2 그렇다면 사용자가 본 "도구 안 뜸/빨간 에러"의 원인
85
-
86
- - 산출물·플래그가 Node ≥22.5에서 멀쩡하므로, **sqlite 경로의 유일한 실패 원인 = Claude Desktop 내장 Node < 22.5**.
87
- 그 경우 `node:sqlite` 모듈이 **아예 없고** `--experimental-sqlite`도 **모르는 옵션**이라 서버가 즉시 죽는다.
88
- - (대안 가설) sqlite 무관 환경 문제 — 단 Claude Desktop 미설치 환경에서는 재현 불가.
89
- - **확정 방법(저비용, 먼저 할 것)**: `.mcpb`를 깐 PC에서 로그 확인
90
- - Windows: `%APPDATA%\Claude\logs\mcp-server-careermate.log` (또는 `mcp.log`)
91
- - `bad option: --experimental-sqlite` / `No such built-in module: node:sqlite` → **내장 Node < 22.5 확정**
92
- - 그 외(경로/ESM/`__dirname`) → 패키징 문제(별개 갈래)
93
-
94
- ### 3.3 내장 Node < 22.5가 확정될 경우 — 저장 계층 대안
95
-
96
- 코드 결합도는 낮다. `node:sqlite`를 만지는 곳은 **3개 파일**뿐:
97
- `packages/db/src/{connection.ts, schema.ts, repositories.ts}`. 사용 API도 작은 부분집합
98
- (`DatabaseSync`, `exec`, `prepare().get()/.all()/.run()`, `?`/`@name` 인자, `.changes`, `close`), **JOIN 없음**.
99
- → `getDb()` 뒤 어댑터 교체 자체는 소규모.
100
-
101
- **그러나 두 개의 지뢰:**
102
-
103
- 1. **2-프로세스 동시성(ADR #6)** — 웹 대시보드와 MCP 서버가 **별도 프로세스로 같은 DB를 WAL 동시 접근**.
104
- - `sql.js`(WASM): 낡은 Node까지 호환되지만 **인메모리+수동 저장**이라 두 프로세스 공유 시 last-writer-wins로 **깨짐**.
105
- - JSON 스토어(lowdb 등): 동일하게 동시성 재설계 필요.
106
- 2. **네이티브 ABI** — `better-sqlite3`는 API가 거의 동일하지만 **네이티브 모듈**이라 내장 Node ABI와
107
- prebuilt 불일치(NODE_MODULE_VERSION) 위험. 버전 문제를 다른 형태로 되살림.
108
-
109
- | 대안 | 낡은 내장 Node 호환 | 2-프로세스 동시성 | 비용 |
110
- |---|---|---|---|
111
- | sql.js (WASM) | ✅ | ❌ 재설계 필요 | 中~大 |
112
- | better-sqlite3 | ❌ ABI 위험 | ✅ | 中(근본 미해결) |
113
- | JSON 스토어 | ✅ | ❌ 재설계 필요 | 中~大 |
114
-
115
- 가장 깔끔한 방향: **MCP 서버가 DB를 직접 열지 않고 웹 서버의 127.0.0.1 HTTP로 데이터를 요청 → 웹 서버가
116
- 단일 DB 소유자**. 이러면 sql.js가 성립하지만 "대시보드가 안 떠 있어도 MCP 동작" UX를 잃는다(진짜 아키텍처 변경).
117
-
118
- → 어느 쪽이든 **"작은 수정"이 아니라 아키텍처 변경**이므로, 근본 원인(로그) 확정 전에는 착수하지 않는다.
119
-
120
- ---
121
-
122
- ## 4. 권고 / 다음 단계
123
-
124
- 1. **(먼저, 저비용)** `.mcpb` 깐 PC에서 로그 한 줄 확인 → 내장 Node < 22.5 여부 확정.
125
- - 플래그류 에러면: (가설과 달리) 단순 수정 가능성 → 재검토.
126
- - `node:sqlite` 부재면: 아래 3.3 rewrite를 정식 과제로.
127
- 2. **단기 우회**(무설치 포기 허용 시): "Node ≥22.5 1회 설치 → `npx -y careermate init`" — Claude/Codex 공통으로 가장 견고.
128
- 3. **추적**: Codex issue #24718(config 재작성) 상태. 닫히면 Codex SEA 원클릭을 재평가.
129
-
130
- ## 5. 검증 메모 / 한계
131
-
132
- - Codex 데스크톱 관련 결론은 **2026-05~06 기준 OPEN 버그**에 의존(시간 민감).
133
- - #24718의 구체 재현은 HTTP MCP였다는 점에서 stdio 삭제는 광범위 재작성 정황으로의 소폭 일반화.
134
- - 미서명 `.exe`의 SmartScreen/Defender 경고가 원클릭 UX를 얼마나 저해하는지는 **이번 라운드에서 확정 근거 미확보**(미검증).
135
- - `.mcpb` 실패의 "내장 Node < 22.5" 결론은 **로그로 직접 확정 전까지 강한 추정**이다.