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.
- package/LICENSE +21 -0
- package/README.md +3 -1
- package/apps/web/public/pages/documents.js +7 -2
- package/apps/web/public/pages/home.js +4 -7
- package/apps/web/public/pages/jobs.js +1 -5
- package/apps/web/public/pages/profile.js +3 -3
- package/apps/web/public/styles.css +7 -2
- package/dist/doctor.mjs +112 -90
- package/dist/install-page/analytics.js +97 -0
- package/dist/install-page/index.html +77 -56
- package/dist/install-page/og.png +0 -0
- package/dist/install-page/robots.txt +4 -0
- package/dist/install-page/sitemap.xml +21 -0
- package/dist/install-page/start.html +13 -10
- package/dist/install-page/style.css +75 -40
- package/dist/mcp.mjs +112 -90
- package/dist/migrate.mjs +95 -82
- package/dist/public/pages/documents.js +7 -2
- package/dist/public/pages/home.js +4 -7
- package/dist/public/pages/jobs.js +1 -5
- package/dist/public/pages/profile.js +3 -3
- package/dist/public/styles.css +7 -2
- package/dist/web.mjs +113 -86
- package/package.json +1 -2
- package/packages/db/src/repositories.ts +18 -1
- package/packages/mcp-tools/src/tools.ts +5 -5
- package/packages/parsers/src/documents.ts +13 -1
- package/packages/shared/src/schemas.ts +115 -81
- package/scripts/build-dist.mjs +7 -1
- package/scripts/gen-og.mjs +1 -1
- package/scripts/test.ts +25 -0
- package/scripts/ui-smoke.ts +32 -4
- package/dist/install-page/.omc/state/agent-replay-55a58c0d-bb6e-43ea-8a05-4b6c93b80b34.jsonl +0 -12
- package/dist/install-page/.omc/state/idle-notif-cooldown.json +0 -3
- package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/mission-state.json +0 -147
- package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/pre-tool-advisory-throttle.json +0 -22
- package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/subagent-tracking-state.json +0 -44
- package/docs/ARCHITECTURE.md +0 -208
- package/docs/CHANGES_V1.md +0 -103
- package/docs/DATA_MODEL.md +0 -460
- package/docs/DECISIONS.md +0 -277
- package/docs/DEMO.md +0 -242
- package/docs/MCP_TOOLS.md +0 -292
- package/docs/ROADMAP.md +0 -135
- package/docs/RUNTIME_DISTRIBUTION_RESEARCH.md +0 -135
- package/docs/START_WORKFLOW.md +0 -137
- package/docs/SUPPORTED_AI_APPS.md +0 -112
- package/docs/TODO.md +0 -57
- package/docs/UX_NOTES.md +0 -247
- package/docs/WORKFLOWS.md +0 -202
- package/docs/superpowers/specs/2026-06-16-demo-dashboard-deploy-design.md +0 -64
package/docs/START_WORKFLOW.md
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
# CareerMate 시작 런북 (연결 직후 AI용)
|
|
2
|
-
|
|
3
|
-
설치·연결(`INSTALL.md`)이 끝난 직후, AI(당신)가 사용자를 빠르게 생산적으로 만들기 위해 따라가는 런북입니다. 도구는 정해진 순서로 호출하고, 매 단계 무엇을 하고 있는지 쉬운 한국어로 설명하세요. MCP·job_id 같은 기술 용어는 노출하지 마세요. 확실하지 않은 정보는 지어내지 말고 사용자에게 확인하세요.
|
|
4
|
-
|
|
5
|
-
> 핵심 원칙: **분석과 글쓰기는 당신(AI)이 수행하고, CareerMate는 데이터를 제공·보관**합니다. 공고 분석이나 자기소개서 작성 전에는 항상 `get_application_context`를 먼저 호출해 근거 데이터를 가져오세요.
|
|
6
|
-
|
|
7
|
-
> **대시보드 안내 정책**: 브라우저를 직접 여는 건 **첫 온보딩에서 한 번만**(`open_dashboard`)입니다. 이후 무언가를 저장·완료할 때는 **자동으로 새로 열지 말고** 주소(`http://127.0.0.1:4319`)만 안내하고, 사용자가 "열어줘"라고 할 때만 `open_application`(단건)·`open_dashboard`(전체)로 엽니다.
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## A. 온보딩 (첫 연결 시 한 번)
|
|
12
|
-
|
|
13
|
-
### 1. 현재 상태 확인 — `get_onboarding_status`
|
|
14
|
-
|
|
15
|
-
- 연결 직후 가장 먼저 호출합니다.
|
|
16
|
-
- 결과의 `has_profile` / `has_resume` / `has_cover_letter` / `has_experience` / `has_skills` / `has_job`, `profile_completeness`(0~100), `next_steps`를 확인합니다.
|
|
17
|
-
- 사용자에게 "지금까지 등록된 정보"와 "앞으로 채우면 좋은 정보"를 짧게 안내합니다. **이미 채워진 항목은 다시 묻지 마세요.**
|
|
18
|
-
- (선택) 단계별 가이드가 필요하면 `get_workflow_guide('onboarding')`로 받을 수 있습니다.
|
|
19
|
-
|
|
20
|
-
### 2. 프로필 수집 및 저장 — `save_profile`
|
|
21
|
-
|
|
22
|
-
- 사용자가 올린 이력서/자기소개서 파일 또는 직접 알려준 내용을 바탕으로 프로필을 구조화합니다.
|
|
23
|
-
- 정리 항목: 이름, 연락처, 한 줄 소개(`headline`), 요약(`summary`), 희망 직무(`desired_roles`), 희망 근무 조건(`desired_conditions`).
|
|
24
|
-
- **글쓰기 선호도**를 함께 물어보세요: 선호 문체(`preferred_tone`, 예: "담백하고 구체적")와 강조 포인트(`emphasis_points`). 이 두 값은 이후 자기소개서 품질에 직접 영향을 줍니다.
|
|
25
|
-
- `save_profile`로 저장합니다. 전달한 필드만 갱신되고 나머지는 유지됩니다(부분 저장 안전). 한두 개만 바꿀 때도 그대로 `save_profile`을 다시 호출하면 됩니다.
|
|
26
|
-
- 파일에서 읽은 정보는 `source`를 `upload`, 사용자가 말로 준 정보는 `manual`로 표시합니다.
|
|
27
|
-
|
|
28
|
-
### 3. 이력서 등록 — `add_resume`
|
|
29
|
-
|
|
30
|
-
- **사용자가 이력서를 주는 방법은 앱마다 다릅니다.** 상황에 맞게 안내하세요:
|
|
31
|
-
- 가장 쉬운 공통 방법은 **내용을 대화창에 그대로 붙여넣기**(파일 위치 무관).
|
|
32
|
-
- Claude 채팅 앱(.mcpb)이면 **파일 직접 첨부**, 폴더 기반(Claude Code 탭/Codex/Antigravity)이면 작업 폴더에 두고 **파일명·경로로 지시**.
|
|
33
|
-
- 스캔본(이미지) PDF·보안 걸린 파일은 못 읽을 수 있으니, 그때는 **텍스트로 붙여넣어** 달라고 요청합니다.
|
|
34
|
-
- 업로드한 이력서/경력기술서/포트폴리오 본문을 `add_resume`로 저장합니다.
|
|
35
|
-
- `kind`(resume / career_description / portfolio / other)와 `title`을 적절히 지정하고, 대표 문서는 `is_primary=true`로 설정합니다. 대표 문서는 이후 `get_application_context`의 `primary_resume`로 노출됩니다.
|
|
36
|
-
- `source`는 `upload`를 사용합니다.
|
|
37
|
-
|
|
38
|
-
### 3-1. 경력·프로젝트·스킬 등록 (있는 경우) — `add_experience` · `add_project` · `add_skill`
|
|
39
|
-
|
|
40
|
-
- 이력서에서 파악되는 경력·프로젝트·보유 기술은 본문 저장과 별개로 `add_experience` / `add_project` / `add_skill`로 항목 단위 저장하면 적합도 분석·자소서·면접 준비에서 정밀하게 활용됩니다.
|
|
41
|
-
- 경력 `achievements`에는 가능하면 정량 지표를 넣고, 기술은 항목당 1건이라 여러 개면 `add_skill`을 반복 호출합니다.
|
|
42
|
-
- 이 항목들은 `get_onboarding_status`의 `has_experience` / `has_skills`와 프로필 완성도(0~100)에 반영됩니다.
|
|
43
|
-
|
|
44
|
-
### 4. 자기소개서 등록 (있는 경우) — `save_cover_letter_version`
|
|
45
|
-
|
|
46
|
-
- 기존 자기소개서가 있으면 `save_cover_letter_version`으로 저장합니다(`title` + `content`). 특정 공고용이면 `job_id`를 연결합니다.
|
|
47
|
-
- `cover_letter_id` 없이 `title`+`content`만 주면 새 자소서의 첫 버전(v1)으로 저장됩니다. 학습/참고용 보관에 적합합니다.
|
|
48
|
-
- 없으면 "나중에 공고를 분석한 뒤 맞춤 자기소개서를 써드릴 수 있어요"라고 안내만 합니다.
|
|
49
|
-
|
|
50
|
-
### 5. 대시보드 열기 & 다음 단계 — `open_dashboard`
|
|
51
|
-
|
|
52
|
-
- `open_dashboard`를 호출해 사용자가 자기 데이터를 눈으로 확인하게 합니다. (서버가 꺼져 있으면 `npm start` 안내를 돌려줍니다.)
|
|
53
|
-
- 다시 `get_onboarding_status`로 완성도를 확인하고, 비어 있는 부분이 있으면 채우자고 제안합니다.
|
|
54
|
-
- 마무리 제안: "지원하고 싶은 공고가 있으면 링크나 내용을 붙여주세요. 적합도를 분석해드릴게요."
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## B. 공고 분석하기 (핵심 흐름)
|
|
59
|
-
|
|
60
|
-
사용자가 공고 링크나 내용을 주면 아래 순서로 진행합니다.
|
|
61
|
-
|
|
62
|
-
### 1. 공고 저장 — `save_job_posting`
|
|
63
|
-
|
|
64
|
-
- `company`, `position`은 필수입니다. 공고 원문은 `description`에, 핵심 자격/우대는 `requirements` 배열에, 키워드는 `keywords`에 정리해 넣습니다.
|
|
65
|
-
- 붙여넣은 원문의 회사명/직무/마감일/기술 키워드 구조화는 AI가 직접 수행한 뒤 위 필드에 채워 저장하세요.
|
|
66
|
-
- 저장하면 지원(application) 항목이 자동 생성되고 `job_id`가 반환됩니다. 같은 `url`이면 중복 없이 갱신됩니다.
|
|
67
|
-
|
|
68
|
-
### 2. 지원 맥락 가져오기 — `get_application_context` ⭐ (반드시 먼저)
|
|
69
|
-
|
|
70
|
-
- **공고 분석/자소서 작성 전에 반드시 호출합니다.** `job_id`를 넘기면 한 번의 호출로 다음을 모두 돌려줍니다:
|
|
71
|
-
프로필, 대표 이력서, 전체 경력·프로젝트·스킬, 기존 자기소개서, 최근 지원 이력, 대상 공고와 이전 적합도 분석, 같은 회사/직무 관련 기록, 사용자의 선호 문체·강조 포인트.
|
|
72
|
-
- 이 데이터를 **근거로** 분석/작성하고, 결과는 아래 저장 도구로 다시 저장합니다.
|
|
73
|
-
|
|
74
|
-
### 3. 적합도 분석 결과 저장 — `save_fit_analysis`
|
|
75
|
-
|
|
76
|
-
- AI가 공고와 사용자 정보를 비교해 도출한 분석을 저장합니다. `job_id` 필수(2단계의 공고가 먼저 저장돼 있어야 함).
|
|
77
|
-
- 채울 필드: `score`(0~100), `summary`, `strengths`(강점), `gaps`(보완 필요), `matched_keywords` / `missing_keywords`, `recommendations`(자소서·지원 전략 제안).
|
|
78
|
-
- 같은 공고에 다시 저장하면 갱신됩니다.
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## C. 맞춤 자기소개서 쓰기
|
|
83
|
-
|
|
84
|
-
### 1. (아직 안 했다면) `get_application_context`로 근거 확보
|
|
85
|
-
|
|
86
|
-
- 선호 문체·강조 포인트·경력·대상 공고를 가져와 작성의 근거로 삼습니다.
|
|
87
|
-
|
|
88
|
-
### 2. 새 버전 저장 — `save_cover_letter_version`
|
|
89
|
-
|
|
90
|
-
- AI가 작성한 자기소개서를 새 버전으로 저장합니다(자소서 작성 워크플로우의 핵심 저장 단계).
|
|
91
|
-
- `cover_letter_id`를 주면 기존 자소서에 새 버전을 추가하고, 없으면 새 자소서를 만들어 v1로 저장합니다(이때 `title` 권장).
|
|
92
|
-
- `note`에 이 버전의 변경 요약(예: "지원동기 보강")을 남기면 사용자가 대시보드 버전 히스토리를 이해하기 쉽습니다.
|
|
93
|
-
- `job_id`로 공고에 연결하면 지원 항목과 자동 연결됩니다.
|
|
94
|
-
|
|
95
|
-
### 3. (요청 시) 파일로 내보내기 — `export_cover_letter`
|
|
96
|
-
|
|
97
|
-
- 사용자가 "파일로 받고 싶어"라고 하면 `cover_letter_id`와 `format`(`md` 기본 / 인쇄용 `html`)으로 내보냅니다. 파일은 `~/.careermate/exports`에 저장되고 경로를 알려줍니다.
|
|
98
|
-
|
|
99
|
-
---
|
|
100
|
-
|
|
101
|
-
## D. 지원 상태 관리
|
|
102
|
-
|
|
103
|
-
### `update_application_status`
|
|
104
|
-
|
|
105
|
-
- 지원 상태를 변경합니다. 가능한 상태는 8단계뿐입니다(AGENTS.md 기준): draft(작성 중), planned(지원 예정), applied(지원 완료), document_passed(서류 합격), interview(면접 진행), final_passed(최종 합격), rejected(불합격), on_hold(보류). 이 외의 값(saved·offer·closed 등)은 대시보드가 모르므로 쓰지 마세요.
|
|
106
|
-
- `note`에 변경 사유를 남길 수 있습니다.
|
|
107
|
-
- 상태가 **서류 합격(document_passed) 이상**으로 바뀌면 면접 준비를 제안하는 힌트를 함께 돌려줍니다 → 다음 단계(E)로 이어집니다.
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## E. 면접 준비
|
|
112
|
-
|
|
113
|
-
### `save_interview_prep`
|
|
114
|
-
|
|
115
|
-
- 보통 상태가 서류 합격으로 바뀐 뒤 진행합니다. 먼저 `get_application_context`(또는 `get_job_posting`)로 공고·직무·자소서를 가져와 근거로 삼으세요.
|
|
116
|
-
- AI가 생성한 자료를 저장합니다: 예상 면접 질문, 꼬리 질문, STAR 답변 가이드, 1분 자기소개 초안 등. `job_id` 필수. 같은 공고에 다시 저장하면 갱신됩니다.
|
|
117
|
-
- 저장 후 `open_application`(또는 `open_dashboard`)으로 사용자가 면접 페이지에서 바로 확인하게 안내합니다.
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
## 보조 도구
|
|
122
|
-
|
|
123
|
-
- `get_workflow_guide` — 표준 워크플로우(온보딩, 공고 분석, 자소서 작성, 상태 관리, 면접 준비)의 단계별 안내. 어떤 순서로 어떤 도구를 호출할지 확인할 때 사용. `workflow_id` 생략 시 전체 목록.
|
|
124
|
-
- `list_recent_activity` — 최근 활동(공고 저장, 적합도 분석, 자소서 버전, 상태 변경, 면접 준비 등). "최근에 뭐 했지?" 또는 작업을 이어갈 맥락이 필요할 때.
|
|
125
|
-
- `list_jobs` / `get_job_posting` — 저장된 공고 목록 / 단건 상세(적합도·상태·연결 자소서·면접 준비 포함).
|
|
126
|
-
- `get_profile` / `get_resumes` / `get_cover_letters` — 저장된 데이터 조회.
|
|
127
|
-
- `open_dashboard` / `open_application` — 사용자가 결과를 눈으로 확인하도록 브라우저에서 페이지 열기.
|
|
128
|
-
|
|
129
|
-
## 빠른 요약 — 공고 1건을 끝까지 처리하는 표준 경로
|
|
130
|
-
|
|
131
|
-
1. `save_job_posting` — 공고 저장 (`job_id` 획득)
|
|
132
|
-
2. `get_application_context` (`job_id`) — 근거 데이터 확보 ⭐
|
|
133
|
-
3. `save_fit_analysis` — 적합도 분석 저장
|
|
134
|
-
4. `save_cover_letter_version` — 맞춤 자소서 버전 저장
|
|
135
|
-
5. `update_application_status` — 지원 상태 갱신
|
|
136
|
-
6. `save_interview_prep` — (서류 합격 후) 면접 준비 저장
|
|
137
|
-
7. `open_application` / `open_dashboard` — 사용자에게 결과 보여주기
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
# 지원 AI 앱 & 설치 레퍼런스 (Supported AI Apps)
|
|
2
|
-
|
|
3
|
-
CareerMate는 LLM이 없는 **로컬 MCP 도구**입니다. *내 컴퓨터에서 로컬 프로그램을 직접 실행할 수 있는* AI 앱에서만 동작합니다.
|
|
4
|
-
|
|
5
|
-
> **가장 쉬운 사람용 설치 안내는 https://careermate.life (랜딩)** 입니다. 이 문서는 **지원 앱 매트릭스 + 클라이언트별 수동 MCP 설정 + 알려진 제약**을 모은 레퍼런스입니다. AI 에이전트가 따라가는 단계별 런북은 루트 [`/INSTALL.md`](../INSTALL.md), 설치 후 사용 흐름은 [docs/START_WORKFLOW.md](./START_WORKFLOW.md)를 보세요.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## 설치는 크게 3가지 — "누가 설치하느냐"
|
|
10
|
-
|
|
11
|
-
| | 무엇 | Node | 대상 |
|
|
12
|
-
|---|---|---|---|
|
|
13
|
-
| **1. 에이전트가 대신 설치** | 작업 폴더에서 **한 문장** → AI가 `careermate.life/llms-install.txt`를 읽고 npm 설치 + MCP 등록 | 필요(에이전트가 winget/brew 또는 nodejs.org로 도와줌) | Claude Code(데스크톱 **"Code" 탭** / CLI)·Codex CLI·Gemini CLI·Cursor 등 *명령 실행 가능한 에이전트* |
|
|
14
|
-
| **2. npm 명령 직접** | 터미널에 `npx -y careermate init` 한 줄(감지된 앱 자동 등록) | 필요 | Claude Desktop·Codex·Cursor 등(그 외는 `--print`로 수동) |
|
|
15
|
-
| **3. `.mcpb`** | 파일 하나를 설정에서 추가 | **불필요**(Claude Desktop 내장) | **Claude Desktop "채팅" 앱 전용** |
|
|
16
|
-
|
|
17
|
-
**1·2는 같은 메커니즘**(Node + npm/npx + MCP 등록) — 에이전트가 치느냐 / 내가 치느냐의 차이일 뿐입니다. 그래서 1·2의 "대상" 제품군이 서로 **겹칩니다**(같은 Claude Code·Codex·Cursor 등). 어느 앱이 어느 방식을 쓰는지는 아래 **앱 × 방식** 매트릭스로 보세요. **3(`.mcpb`)만 Claude Desktop "채팅" 앱 전용**이라 성격이 다릅니다(내장 Node 사용, 단 버전<22.5면 불안정).
|
|
18
|
-
|
|
19
|
-
### 앱 × 방식
|
|
20
|
-
|
|
21
|
-
| 앱 | 1 에이전트 | 2 npm직접 | 3 .mcpb | 영구 지침 | MCP 등록 위치 |
|
|
22
|
-
|---|---|---|---|---|---|
|
|
23
|
-
| **Claude Desktop "채팅"** | — | ✅(config 등록) | ✅ | — | `.mcpb` 또는 `claude_desktop_config.json` |
|
|
24
|
-
| **Claude Code (Code 탭 / CLI)** | ✅ | ✅ | — | 루트 `CLAUDE.md` | 프로젝트 `.mcp.json` |
|
|
25
|
-
| **Codex CLI** (⚠️ 데스크톱 앱 ✗) | ✅ | ✅ | — | 루트 `AGENTS.md` | `~/.codex/config.toml` |
|
|
26
|
-
| **Gemini CLI / Antigravity** | ✅ | ✅ | — | — | Gemini CLI `~/.gemini/settings.json` · Antigravity `~/.gemini/.../mcp_config.json` |
|
|
27
|
-
| **Cursor · Cline · Windsurf** | ✅ | ✅ | — | — | `~/.cursor/mcp.json` 등 |
|
|
28
|
-
|
|
29
|
-
> **Gemini CLI → Antigravity 전환(2026-06):** Google이 소비자(무료/Pro/Ultra)용 Gemini CLI를 **2026-06-18부터 Antigravity CLI로 전환**합니다(Gemini CLI repo는 오픈소스로 유지·엔터프라이즈 계속). MCP 스키마는 동일(`mcpServers` + `command`/`args`/`env`)합니다. `careermate init`은 **Gemini CLI(`~/.gemini/settings.json`)를 자동 등록**하고, **Antigravity는 설정 파일 경로가 유동적이라 후보 파일이 이미 있을 때만** 등록합니다(없으면 위 mcpServers 블록을 해당 파일에 수동 추가).
|
|
30
|
-
|
|
31
|
-
### 동작하지 않는 것
|
|
32
|
-
**ChatGPT · Gemini · Claude의 웹·모바일 앱은 안 됩니다.** 클라우드에서 실행되어 **원격 URL 기반 MCP만** 지원하므로, 내 컴퓨터의 로컬 stdio 서버에 직접 닿을 수 없습니다.
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## 구독·준비물 (2026)
|
|
37
|
-
|
|
38
|
-
- **Claude Code**(Code 탭/CLI): **Pro 이상**(무료 플랜 불가) 또는 `ANTHROPIC_API_KEY` 종량제.
|
|
39
|
-
- **Codex**: **ChatGPT Plus 이상** 로그인으로 충분(API 키 불필요).
|
|
40
|
-
- **`.mcpb`**(Claude Desktop 채팅 확장): **무료 플랜에서도 설치** 가능(안정성이 변수).
|
|
41
|
-
- **터미널/npx**: 무료(Node만). 연결할 앱의 구독 정책은 별개.
|
|
42
|
-
|
|
43
|
-
> **런타임.** CareerMate 서버는 Node 프로그램이라 **Node.js 22.5+ 가 필요**합니다 — 위 1·2 경로 공통(없으면 에이전트가 winget/brew, 안 되면 [nodejs.org](https://nodejs.org) LTS 설치 파일). **Node가 아예 필요 없는 길은 `.mcpb` 하나뿐**인데 그건 내장 Node 버전에 의존해 불안정할 수 있습니다 — **"완전 무설치 + 안정"을 동시에 주는 길은 아직 없습니다.**
|
|
44
|
-
>
|
|
45
|
-
> **Windows + Claude Code(Code 탭)**: [Git for Windows](https://git-scm.com/download/win) 사전 설치가 필요합니다(앱이 없으면 "Git is required" 안내). Claude Code가 **세션 격리(git worktree)와 내부 POSIX 셸 도구**에 Git을 쓰기 때문이며 CareerMate와는 무관합니다. macOS는 Git 기본 포함이라 불필요.
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## 작업 폴더 안에 설치 (권장 — GUI 앱·샌드박스 친화)
|
|
50
|
-
|
|
51
|
-
Claude "Code" 탭이나 Codex처럼 **작업 폴더(cwd)를 잡고** 쓰는 경우, 설치물과 데이터를 그 폴더 **안에** 두면 (1) 폴더만 백업·이동하면 데이터가 따라오고 (2) 샌드박스가 cwd 하위 쓰기를 허용해 마찰이 줄어듭니다. `<WS>`를 작업 폴더 절대경로라 할 때:
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
npm install --prefix "<WS>/.cm/app" careermate
|
|
55
|
-
```
|
|
56
|
-
데이터는 `CAREERMATE_DATA_DIR` 환경변수로 작업 폴더 안에 고정합니다(기본값 `~/.careermate` 대신). 아래 MCP 등록의 `env`에 넣으면 됩니다:
|
|
57
|
-
```
|
|
58
|
-
CAREERMATE_DATA_DIR = <WS>/.cm/data
|
|
59
|
-
```
|
|
60
|
-
- `<BIN>` = `<WS>/.cm/app/node_modules/careermate/bin/careermate.mjs` (이 셸이 `--experimental-sqlite`를 알아서 붙임).
|
|
61
|
-
- 데이터 폴더 이름을 `.git`·`.codex`·`.agents`로 두지 마세요(앱이 읽기 전용으로 보호).
|
|
62
|
-
- **포터블 Node(고급):** 시스템에 Node 22.5+가 없으면, 작업 폴더 안에 포터블 Node를 두고 `command`를 그 `node` 절대경로로 가리켜도 동작합니다. 단 다운로드 용량·OS 보안 경고·폴더 이동 시 경로 갱신 부담이 있어, 지금은 "시스템 Node 1회 설치"가 더 단순합니다.
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## 클라이언트별 수동 MCP 설정 (방식 2의 수동판)
|
|
67
|
-
|
|
68
|
-
대부분 `npx -y careermate init`(또는 소스에서 `npm run init`)이 자동 등록하므로 **수동 설정은 보통 불필요**합니다. 직접 붙여넣어야 할 때만 참고하세요. `npm run init -- --print`로 아래 스니펫을 출력할 수도 있습니다.
|
|
69
|
-
|
|
70
|
-
**경로 규칙** — 아래 `<BIN>`은 **실제 절대경로**로 바꾸세요(`~`·`$HOME`은 설정 파일 안에서 확장 안 됨).
|
|
71
|
-
- **Windows**: JSON에서 역슬래시는 `\\`로 두 번(`C:\\...\\careermate.mjs`). TOML은 **작은따옴표 리터럴**(`'C:\...\careermate.mjs'`)을 쓰면 한 번만.
|
|
72
|
-
- **macOS/Linux**: `/` 그대로.
|
|
73
|
-
|
|
74
|
-
### Claude Desktop (채팅앱 수동)
|
|
75
|
-
설정 파일: Windows `%APPDATA%\Claude\claude_desktop_config.json` · macOS `~/Library/Application Support/Claude/claude_desktop_config.json` (Settings → Developer → Edit Config로도 열림)
|
|
76
|
-
```json
|
|
77
|
-
{ "mcpServers": { "careermate": { "command": "node", "args": ["<BIN>", "mcp"] } } }
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### Claude Code (프로젝트 `.mcp.json`, 작업 폴더 최상단)
|
|
81
|
-
```json
|
|
82
|
-
{ "mcpServers": { "careermate": { "type": "stdio", "command": "node", "args": ["<BIN>", "mcp"], "env": { "CAREERMATE_DATA_DIR": "<WS>/.cm/data" } } } }
|
|
83
|
-
```
|
|
84
|
-
또는 CLI: `claude mcp add --scope project --transport stdio careermate -- node <BIN> mcp` · 첫 실행 시 **1회 승인**.
|
|
85
|
-
|
|
86
|
-
### Codex CLI (`~/.codex/config.toml`)
|
|
87
|
-
```toml
|
|
88
|
-
[mcp_servers.careermate]
|
|
89
|
-
command = "node"
|
|
90
|
-
args = ["<BIN>", "mcp"]
|
|
91
|
-
# 작업 폴더 안에 데이터: env = { CAREERMATE_DATA_DIR = "<WS>/.cm/data" }
|
|
92
|
-
```
|
|
93
|
-
또는 CLI: `codex mcp add careermate -- node <BIN> mcp` · 등록 후 `/mcp`로 확인.
|
|
94
|
-
|
|
95
|
-
### Cursor / Cline / Windsurf
|
|
96
|
-
`~/.cursor/mcp.json`(전역) 또는 `.cursor/mcp.json`(프로젝트) 등에 위 Claude Code와 같은 `mcpServers` 블록. 추가 후 클라이언트 재시작.
|
|
97
|
-
|
|
98
|
-
> **소스를 클론한 개발자**는 `<BIN>` 대신 TS 소스를 직접 가리킬 수 있습니다(빌드 불필요):
|
|
99
|
-
> `node --no-warnings --experimental-sqlite --import tsx <careermate>/apps/mcp/src/index.ts mcp`
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## 알려진 제약 · 트러블슈팅
|
|
104
|
-
|
|
105
|
-
- **Codex 데스크톱 앱(⚠️ CLI 권장):** [#24718](https://github.com/openai/codex/issues/24718)(OPEN) 시작 시 전역 `config.toml`을 재작성해 등록이 사라질 수 있음 + [#13025](https://github.com/openai/codex/issues/13025)(OPEN) 프로젝트 `.codex/config.toml` 무시. 그래서 **데스크톱 앱은 비권장, CLI를 쓰세요.** 설치 단계 `npm install`은 기본 샌드박스에서 네트워크가 꺼져 있어 **1회 허용**(또는 `[sandbox_workspace_write] network_access = true`)이 필요. (단 **MCP 서버 자체는 샌드박스 밖에서 돌아** 연결 후 데이터 읽기/쓰기는 막히지 않습니다.)
|
|
106
|
-
- **Claude Desktop에서 등록이 사라짐:** 팀/클라우드 동기화가 로컬 MCP를 덮어쓴 이슈([#59368](https://github.com/anthropics/claude-code/issues/59368), 수정됨). 동기화를 끄거나 **CLI + 프로젝트 `.mcp.json`** 사용.
|
|
107
|
-
- **연결 검증:** `get_onboarding_status` 호출(Codex는 `/mcp`). 빠른 점검: `npx -y careermate doctor`(Node·데이터 폴더·DB 상태).
|
|
108
|
-
- **자세한 복구**(포트 충돌·DB 마이그레이션·완전 초기화): 루트 [`/INSTALL.md`](../INSTALL.md) 9단계.
|
|
109
|
-
|
|
110
|
-
---
|
|
111
|
-
|
|
112
|
-
각 모드의 **영구 지침 파일**: Claude Code → [/CLAUDE.md](../CLAUDE.md), Codex → [/AGENTS.md](../AGENTS.md). 사람용 설치 → https://careermate.life · 사용 흐름 → [docs/START_WORKFLOW.md](./START_WORKFLOW.md).
|
package/docs/TODO.md
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# CareerMate TODO (향후 방향)
|
|
2
|
-
|
|
3
|
-
아래 항목은 **v1 범위에서 명시적으로 제외**한다. 다만 패키지 경계·데이터 모델·도구 인터페이스는 이후 추가를 수용하도록 **구조를 열어둔다**.
|
|
4
|
-
|
|
5
|
-
> 사이트별 크롤러, 클라우드 동기화, DOCX export, i18n 같은 **기능/패키지 단위 백로그**는 [ROADMAP.md](./ROADMAP.md)가 관리한다(구조 개방 근거 포함). 이 문서는 **제품 방향(v1.5 / v2)과 미해결 과제**만 다루며, 중복 기재하지 않는다.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## v1.5
|
|
10
|
-
|
|
11
|
-
설치형 데스크톱 앱으로의 전환.
|
|
12
|
-
|
|
13
|
-
- **Electron** 셸 — 대시보드를 데스크톱 앱으로 래핑(정적 자산이라 셸로 감싸기 적합).
|
|
14
|
-
- **Windows / macOS 설치형 앱** — 더블클릭 설치, Node 동봉.
|
|
15
|
-
- **자동 업데이트** — 백그라운드 갱신.
|
|
16
|
-
- **트레이 상주** — MCP·대시보드 프로세스를 트레이에서 관리(시작/중지/상태).
|
|
17
|
-
- **`CareerMate.exe`** — 단일 실행 진입점.
|
|
18
|
-
|
|
19
|
-
## v2
|
|
20
|
-
|
|
21
|
-
로컬 stdio의 한계를 넘어 원격·범용 AI 클라이언트까지 확장.
|
|
22
|
-
|
|
23
|
-
- **Gateway Mode** — 로컬 stdio를 원격에서 접근 가능한 형태로 중계.
|
|
24
|
-
- **ChatGPT 일반 채팅** — 웹/모바일 ChatGPT에서 사용(현재는 로컬 stdio라 불가).
|
|
25
|
-
- **Claude 일반 채팅** — Claude 웹 앱 연동.
|
|
26
|
-
- **Gemini** — Gemini 클라이언트 연동.
|
|
27
|
-
- **oneTimeToken** — Gateway 접근을 위한 일회용 토큰 핸드셰이크.
|
|
28
|
-
- **WebSocket Local Agent** — 로컬 에이전트와 원격 클라이언트 간 양방향 채널.
|
|
29
|
-
- **MCP Gateway** — 원격 URL 기반 MCP 엔드포인트 노출.
|
|
30
|
-
|
|
31
|
-
## 미래 방향
|
|
32
|
-
|
|
33
|
-
향후 `CareerMate.exe`가 중심에 설 수 있고(현재는 v1.5 과제, v1 비범위), 그 구도에서 **AI는 "연결 어댑터"** 역할을 한다. ChatGPT / Claude / Gemini / Codex / Claude Code 등은 두뇌를 제공하는 별개 인터페이스일 뿐, 커리어 데이터의 단일 출처(source of truth)는 항상 로컬의 CareerMate다. 사용자는 그날 손에 잡히는 AI를 골라 같은 서랍장에 연결한다. 즉 AI는 **갈아끼우는 부품**, CareerMate는 **고정된 본체**라는 구도다.
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## v1에서 제외 (구조는 열어둠)
|
|
38
|
-
|
|
39
|
-
다음은 v1에서 구현하지 않지만 설계상 길을 막지 않는다.
|
|
40
|
-
|
|
41
|
-
- Electron
|
|
42
|
-
- exe
|
|
43
|
-
- Gateway
|
|
44
|
-
- WebSocket
|
|
45
|
-
- oneTimeToken
|
|
46
|
-
- Cloud 저장 / 클라우드 동기화
|
|
47
|
-
- 인증 서버
|
|
48
|
-
|
|
49
|
-
## 열린 TODO / 미해결
|
|
50
|
-
|
|
51
|
-
확정·보완이 필요한 알려진 공백. 잊지 않도록 기록한다.
|
|
52
|
-
|
|
53
|
-
- **npm 게시 완료** — `careermate@0.1.0` 공개 게시됨. `npx -y careermate init`가 **동작한다**. (소스 기반 `npm install` → `npm run init`도 그대로 유효.)
|
|
54
|
-
- **.mcpb GitHub Release 생성됨(접근 제한)** — Release `v0.1.0`에 `careermate.mcpb` 첨부. 단 저장소가 **비공개**라 공개 다운로드 링크는 아직 없음. → 저장소를 public으로 전환하면 공개 다운로드 활성화.
|
|
55
|
-
- **공개 repo URL 확정** — git remote 기준 정본은 `osntak/CareerMate`(현재 **비공개**). 공개 전환 여부는 별도 결정 사항.
|
|
56
|
-
- **THIRD_PARTY_NOTICES — `im-not-ai`(MIT)** 항목의 저작권자/연도가 비어 있다. 실제 저작권자·연도로 채우기.
|
|
57
|
-
- **`install-page/` 폴더명 변경** — 이제 랜딩+시작마법사+데모(`/demo`)+설치안내를 모두 담는 "공개 웹사이트" 폴더라 `install-page`는 이름이 안 맞는다. 후보: `site` / `www` / `landing`. 주의: 이 폴더는 **Vercel 프로젝트의 Root Directory 설정**이므로, 폴더명을 바꾸면 Vercel 대시보드의 Root Directory 값도 같이 바꿔야 배포가 안 깨진다. 레포 내 코드 참조(고쳐야 할 곳): `scripts/build-dist.mjs`·`scripts/build-mcpb.mjs`·`scripts/shots.ts`·`scripts/gen-og.mjs`·`apps/web/src/server.ts`. 데모 완성 후 진행하기로 합의(2026-06-16).
|
package/docs/UX_NOTES.md
DELETED
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
# UI/UX 설계 노트
|
|
2
|
-
|
|
3
|
-
CareerMate 대시보드의 화면 설계 의도를 정리한 문서다. 무엇을 어떻게 만들었는지뿐 아니라 **왜 그렇게 했는지**를 남겨, 새 화면을 추가하거나 기존 화면을 손볼 때 일관성을 잃지 않도록 한다.
|
|
4
|
-
|
|
5
|
-
대시보드는 프레임워크·번들러·CDN 없이 동작하는 바닐라 JS + 자체 CSS 디자인 시스템으로 만들어졌다. 모든 컴포넌트와 토큰은 다음 두 파일에 모여 있다.
|
|
6
|
-
|
|
7
|
-
- `apps/web/public/lib.js` — DOM 헬퍼, API 클라이언트, 공용 컴포넌트
|
|
8
|
-
- `apps/web/public/styles.css` — 디자인 토큰과 컴포넌트 스타일
|
|
9
|
-
|
|
10
|
-
화면을 만드는 규칙은 [`apps/web/UI_CONTRACT.md`](../apps/web/UI_CONTRACT.md)에, 기준이 되는 참고 구현은 [`apps/web/public/pages/home.js`](../apps/web/public/pages/home.js)에 있다. 이 문서는 그 둘의 배경이 되는 설계 원칙을 담는다.
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## 1. 디자인 원칙
|
|
15
|
-
|
|
16
|
-
### 1.1 "진짜 생산성 도구"를 지향한다
|
|
17
|
-
|
|
18
|
-
`styles.css` 첫머리 주석이 톤을 규정한다.
|
|
19
|
-
|
|
20
|
-
> CareerMate design system — a calm, dense, real-productivity-tool aesthetic.
|
|
21
|
-
> Inspired by the restraint of Linear / Notion / Raycast — not AI-flashy.
|
|
22
|
-
|
|
23
|
-
차분하고(calm), 밀도 있고(dense), 실제 일이 되는(real-productivity) 도구가 목표다. 화려한 그라데이션이나 과장된 모션이 아니라, 매일 들여다봐도 피로하지 않은 절제된 화면을 만든다.
|
|
24
|
-
|
|
25
|
-
### 1.2 AI 슬롭(AI slop)을 회피한다
|
|
26
|
-
|
|
27
|
-
CareerMate는 사용자의 AI(ChatGPT·Claude·Gemini)가 MCP로 호출하는 도구이지, 내부에 LLM이 없다. 그래서 화면이 "AI 제품"처럼 보일 이유가 없다. [`UI_CONTRACT.md`](../apps/web/UI_CONTRACT.md)의 컨벤션이 이를 못박는다.
|
|
28
|
-
|
|
29
|
-
> Dense, calm, real-product feel. Avoid emoji-heavy or flashy "AI" styling.
|
|
30
|
-
|
|
31
|
-
- 반짝이·로봇·마법봉 같은 과시적 표현을 화면 곳곳에 뿌리지 않는다. (`sparkle` 아이콘이 `lib.js`에 존재하지만 강조 포인트로 아껴 쓴다.)
|
|
32
|
-
- 이모지를 정보 전달 수단으로 남용하지 않는다.
|
|
33
|
-
- 결과를 "AI가 만들었다"는 식으로 포장하지 않는다. 자기소개서 버전 출처는 `직접 입력 / 파일 업로드 / AI 생성 / 직접 수정`(`documents.js`의 `SOURCE_LABELS`)처럼 담백한 라벨로 사실만 표기한다.
|
|
34
|
-
|
|
35
|
-
### 1.3 밀도(density)
|
|
36
|
-
|
|
37
|
-
한 화면에서 많은 정보를 빠르게 훑을 수 있어야 한다.
|
|
38
|
-
|
|
39
|
-
- 기본 본문 폰트 14px, 줄간격 1.55 (`body`).
|
|
40
|
-
- 컴포넌트마다 의도된 작은 글자 크기 단계가 있다. 예: 네비 라벨 11px, 카드 부제 12.5px, 통계 값 26px.
|
|
41
|
-
- `.stat`, `.table`, `.board-card`, `.timeline` 등으로 목록·표·칸반·타임라인을 조밀하게 배치한다.
|
|
42
|
-
- 숫자는 `font-variant-numeric: tabular-nums`(`.tnum`)로 자릿수를 고정해 표/통계에서 흔들리지 않게 한다.
|
|
43
|
-
|
|
44
|
-
밀도는 "빽빽함"이 아니라 "여백을 낭비하지 않음"이다. 카드·셀의 패딩은 일정한 토큰 체계를 따른다.
|
|
45
|
-
|
|
46
|
-
### 1.4 친절한 empty state
|
|
47
|
-
|
|
48
|
-
비어 있는 화면이야말로 첫인상이다. 모든 목록은 비었을 때 다음을 제공한다(컨벤션상 필수, [`UI_CONTRACT.md`](../apps/web/UI_CONTRACT.md) "Always provide a friendly empty state").
|
|
49
|
-
|
|
50
|
-
1. 무엇을 하는 공간인지 한 문장 설명
|
|
51
|
-
2. **MCP로 자동 저장된다**는 안내 — 사용자가 AI와 대화하면 채워진다는 점을 알려준다
|
|
52
|
-
3. 직접 추가할 수 있는 1차 액션 버튼
|
|
53
|
-
|
|
54
|
-
예: 자기소개서 탭(`documents.js`)의 빈 상태.
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
title: '자기소개서가 없어요'
|
|
58
|
-
body: 'ChatGPT·Claude에게 작성을 요청하면 자동으로 여기에 저장되고,
|
|
59
|
-
수정할 때마다 버전이 기록됩니다. 직접 추가할 수도 있어요.'
|
|
60
|
-
action: '새 자기소개서'
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
공고 목록(`home.js`의 `RecentJobs`), 문서 탭, 면접 준비 영역도 같은 패턴을 따른다. 빈 상태는 `EmptyState({ iconName, title, body, action })` 컴포넌트(`lib.js`)로만 만든다.
|
|
64
|
-
|
|
65
|
-
### 1.5 비개발자 용어
|
|
66
|
-
|
|
67
|
-
사용자는 개발자가 아닐 수 있다. 화면 문구는 한국어 우선이고, 기술 용어를 노출하지 않는다.
|
|
68
|
-
|
|
69
|
-
- 상태 코드는 내부적으로 `document_passed`지만, 사용자에게는 항상 라벨(`서류 합격`)로 보인다. 8단계 라벨은 [`UI_CONTRACT.md`](../apps/web/UI_CONTRACT.md)에 정의돼 있다: `작성 중 / 지원 예정 / 지원 완료 / 서류 합격 / 면접 진행 / 최종 합격 / 불합격 / 보류`.
|
|
70
|
-
- 오류 메시지도 한국어다. `api()`(`lib.js`)는 실패 시 `요청 실패 (${status})`로, `toastError`는 제목 `오류`로 표시한다.
|
|
71
|
-
- 상대 시간도 사람 말투다: `방금 전 / N분 전 / N시간 전 / N일 전`(`fmtRelative`).
|
|
72
|
-
|
|
73
|
-
### 1.6 MCP·localhost는 설정에서만
|
|
74
|
-
|
|
75
|
-
CareerMate의 동작 기반(127.0.0.1 바인딩, MCP stdio 서버, 데이터 디렉터리, server.json 핸드셰이크)은 사용자가 매일 신경 쓸 대상이 아니다. 그래서 이런 기술적 디테일은 **Settings 페이지에만** 둔다. Home·Jobs·Applications 같은 일상 화면에는 포트 번호나 MCP 연결 상태 같은 내부 개념을 노출하지 않는다. 일상 화면은 "내 커리어"라는 도메인 언어로만 이야기한다.
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## 2. 정보 구조 (7페이지)
|
|
80
|
-
|
|
81
|
-
좌측 고정 사이드바(`--sidebar-w: 248px`)로 7개 페이지를 오간다. 라우팅은 해시 기반(`navigate(hash)` → `location.hash`)이고, `params`는 페이지 id 뒤 경로 세그먼트다(`#/jobs/abc` → `params=['abc']`).
|
|
82
|
-
|
|
83
|
-
| 페이지 | 역할 |
|
|
84
|
-
| --- | --- |
|
|
85
|
-
| **Home** | "지금 뭘 해야 하지?"를 한눈에. 통계 타일, 온보딩 카드, 최근 공고, 진행 중 지원, 면접 할 일, 최근 활동 |
|
|
86
|
-
| **Profile** | 프로필·경험·프로젝트·스킬 관리, 프로필 완성도 |
|
|
87
|
-
| **Jobs** | 저장된 공고 목록과 상세(적합도, 분석, 연결된 지원) |
|
|
88
|
-
| **Applications** | 지원 현황 칸반(8단계 상태 보드) |
|
|
89
|
-
| **Documents** | 자기소개서(버전 타임라인)와 이력서·경력기술서 문서 |
|
|
90
|
-
| **Interview** | 면접 준비 — 서류 합격 이상에서 해금 |
|
|
91
|
-
| **Settings** | 데이터 위치, MCP 연결, 테마 등 기술적 설정 |
|
|
92
|
-
|
|
93
|
-
### Home이 정보 구조의 중심인 이유
|
|
94
|
-
|
|
95
|
-
Home(`home.js`)은 다른 페이지로의 진입점이다. 구성:
|
|
96
|
-
|
|
97
|
-
- **PageHead** — 프로필 이름이 있으면 `{name}님, 안녕하세요`, 없으면 `환영합니다`. 부제는 `ChatGPT·Claude와 함께 쓰는 내 커리어 흐름 관리 도구`.
|
|
98
|
-
- **온보딩 카드** — 온보딩 미완료이거나 다음 할 일이 남았을 때만 노출(`!s.onboarding.completed || s.onboarding.next_steps.length`). 진행 바로 프로필 완성도를 보여주고, 다음 할 일을 최대 4개까지 나열한다.
|
|
99
|
-
- **통계 타일 4개**(`grid--4`) — 저장된 공고 / 진행 중 지원 / 자기소개서 / 면접 준비 필요. 면접 준비가 있으면 힌트 `서류 통과 후 준비하세요`.
|
|
100
|
-
- **2열 레이아웃**(`grid--2`) — 좌: 최근 공고 + 진행 중 지원, 우: 면접 할 일 + 최근 활동.
|
|
101
|
-
|
|
102
|
-
핵심은 **"무엇을 보여줄지보다, 무엇을 다음에 할지"**를 안내한다는 점이다.
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
## 3. 디자인 시스템
|
|
107
|
-
|
|
108
|
-
### 3.1 토큰 (CSS 변수)
|
|
109
|
-
|
|
110
|
-
`styles.css`의 `:root`에 모든 토큰이 모여 있다. 화면에서 색·반경·간격을 하드코딩하지 않고 토큰만 쓴다.
|
|
111
|
-
|
|
112
|
-
- **중립 팔레트**: `--bg`, `--bg-subtle`, `--bg-sunken`, `--surface`, `--surface-hover`, `--border`, `--border-strong`, `--text`, `--text-secondary`, `--text-tertiary`.
|
|
113
|
-
- **악센트**: 차분한 인디고. `--accent: #4f46e5`, `--accent-hover`, `--accent-soft`, `--accent-border`.
|
|
114
|
-
- **시맨틱 색**: `green / teal / blue / violet / amber / red / slate` 각각 본색·`-soft`·`-border` 3종. 상태 배지와 점수 색(`score-strong/mid/weak`)에 쓴다.
|
|
115
|
-
- **엘리베이션**: `--shadow-sm/md/lg`.
|
|
116
|
-
- **지오메트리**: `--radius-sm: 6px`, `--radius: 9px`, `--radius-lg: 14px`, `--sidebar-w`, `--topbar-h: 56px`, `--maxw: 1080px`.
|
|
117
|
-
- **타이포**: `--font`(Pretendard 우선, 한글 폴백 포함), `--mono`.
|
|
118
|
-
|
|
119
|
-
### 3.2 다크 모드
|
|
120
|
-
|
|
121
|
-
다크 모드는 **시스템 설정 자동 추종 + 명시적 강제** 두 경로를 모두 지원한다.
|
|
122
|
-
|
|
123
|
-
- `@media (prefers-color-scheme: dark)` 안에서 `:root:not([data-theme='light'])`에 다크 토큰을 적용 → 시스템이 다크이고 사용자가 라이트로 고정하지 않았으면 다크.
|
|
124
|
-
- `:root[data-theme='dark']` → 사용자가 명시적으로 다크를 고른 경우.
|
|
125
|
-
- 즉 `data-theme` 속성(`light`/`dark`/없음)으로 사용자 의도가 시스템 설정을 덮어쓴다.
|
|
126
|
-
|
|
127
|
-
다크 모드는 같은 토큰의 값만 교체하므로 컴포넌트 CSS는 변경 없이 그대로 동작한다. 이것이 토큰 우선 설계의 핵심 이득이다.
|
|
128
|
-
|
|
129
|
-
### 3.3 상태 배지 (Badge)
|
|
130
|
-
|
|
131
|
-
`Badge(status, label)`(`lib.js`)는 `badge badge--<status>` 클래스를 가진 캡슐을 만든다. 작은 점(`.dot`) + 라벨 구성이다. 8개 상태가 시맨틱 색과 1:1로 매핑된다(`styles.css`).
|
|
132
|
-
|
|
133
|
-
| 상태 | 색 |
|
|
134
|
-
| --- | --- |
|
|
135
|
-
| `draft` | slate |
|
|
136
|
-
| `planned` | blue |
|
|
137
|
-
| `applied` | violet |
|
|
138
|
-
| `document_passed` | teal |
|
|
139
|
-
| `interview` | amber |
|
|
140
|
-
| `final_passed` | green |
|
|
141
|
-
| `rejected` | red |
|
|
142
|
-
| `on_hold` | slate |
|
|
143
|
-
|
|
144
|
-
색은 단계가 진행될수록 따뜻해지고, 합격은 초록, 불합격은 빨강이라는 직관을 따른다. 배지는 "대표 자기소개서/문서" 표시에도 재활용된다(`final_passed` 색으로 `대표` 라벨, `documents.js`).
|
|
145
|
-
|
|
146
|
-
### 3.4 칸반 보드
|
|
147
|
-
|
|
148
|
-
Applications 페이지의 보드는 `.board`(가로 스크롤, `grid-auto-flow: column`, 열 너비 272px)와 `.board__col` / `.board__col-head`(상태명 + 개수 카운트) / `.board__cards` / `.board-card`로 구성한다. 카드 한 장은 회사명·직무·메타(상태 배지 등)를 담는다. 열 높이는 `calc(100vh - 200px)`로 묶고 내부 스크롤한다. 8단계 상태가 그대로 보드의 열이 된다.
|
|
149
|
-
|
|
150
|
-
### 3.5 버전 타임라인
|
|
151
|
-
|
|
152
|
-
Documents의 자기소개서 상세는 **버전 기록**을 세로 타임라인으로 보여준다(`documents.js`의 `CoverDetailBody` → `VersionItem`). 마크업은 `.timeline` 안에 `.tl-item`(레일 점 `.tl-item__dot` + 연결선 `.tl-item__line` + 본문 `.tl-item__body`)을 쌓는 구조다.
|
|
153
|
-
|
|
154
|
-
- 버전은 `version_no` 내림차순으로 정렬(최신이 위).
|
|
155
|
-
- 현재 버전은 `.is-current`로 점이 악센트 색으로 강조되고, 헤더에 `현재 버전` 배지가 붙는다.
|
|
156
|
-
- 각 항목에 출처 칩(`직접 입력 / 파일 업로드 / AI 생성 / 직접 수정`), 변경 메모, 상대 시간이 표시된다.
|
|
157
|
-
- 항목 액션: `이 버전 보기`(상단 미리보기 교체), `현재 버전으로 지정`, `복사`.
|
|
158
|
-
|
|
159
|
-
미리보기(`.doc-preview`)는 현재 버전 본문을 기본 표시하고, "이 버전 보기"로 특정 버전을 끼워 볼 수 있다.
|
|
160
|
-
|
|
161
|
-
### 3.6 그 밖의 공용 컴포넌트
|
|
162
|
-
|
|
163
|
-
`lib.js`가 제공하는 컴포넌트만 사용하고, 스타일을 손으로 짜지 않는다. `Card`, `Stat`, `Btn`(`primary/ghost/danger`), `IconBtn`, `EmptyState`, `Chips`, `Field`/`Input`/`Textarea`/`Select`, `PageHead`, `openModal`/`confirmDialog`, `toast`/`toastOk`/`toastError`, `Spinner`(스켈레톤). 아이콘은 `icon(name)`으로 1.7px 스트로크 SVG 세트를 쓴다.
|
|
164
|
-
|
|
165
|
-
피드백 패턴도 통일돼 있다. 변경 작업은 `try/catch`로 감싸 성공 시 `toastOk`, 실패 시 `toastError`, 위험한 삭제는 `confirmDialog`로 한 번 더 묻는다.
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
## 4. XSS-safe 렌더링 원칙
|
|
170
|
-
|
|
171
|
-
이 원칙은 타협하지 않는다. 데이터(이력서·자기소개서 본문 등)는 사용자/AI가 채우므로, 신뢰할 수 없는 문자열로 취급한다.
|
|
172
|
-
|
|
173
|
-
`lib.js` 상단 주석이 규칙을 명문화한다.
|
|
174
|
-
|
|
175
|
-
> XSS safety: el() puts strings into textContent (never innerHTML). User content (résumé/cover-letter text) is always rendered as text. Only our own trusted icon SVG strings use innerHTML.
|
|
176
|
-
|
|
177
|
-
구체적으로:
|
|
178
|
-
|
|
179
|
-
- `el(tag, props, ...children)`에서 문자열·숫자 자식은 `document.createTextNode`로 들어간다(`appendChildren`). 따라서 본문에 `<script>`가 있어도 코드로 실행되지 않고 글자로 보인다.
|
|
180
|
-
- `innerHTML`은 오직 **신뢰된 호출자**만 쓴다. `props.html` 키와 `icon()`의 SVG 주입이 전부이며, 이는 우리가 만든 고정 문자열이다. DB/사용자 문자열을 `html:`로 넘기지 않는다.
|
|
181
|
-
- 자기소개서·이력서 본문은 `.doc-preview` 요소에 텍스트로 넣는다. CSS가 `white-space: pre-wrap; word-break: break-word`를 처리하므로 줄바꿈·서식이 살아 있으면서도 안전하다(`documents.js`의 미리보기, 버전 보기).
|
|
182
|
-
|
|
183
|
-
새 페이지를 만들 때도 [`UI_CONTRACT.md`](../apps/web/UI_CONTRACT.md)가 같은 점을 강조한다: *"never use innerHTML with user/DB content."*
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
## 5. 직접 수정 → 새 버전 저장 UX
|
|
188
|
-
|
|
189
|
-
자기소개서는 **덮어쓰지 않고 버전을 쌓는다**는 것이 핵심 UX다. 사용자가 손으로 고친 결과도 사라지지 않고 기록으로 남는다.
|
|
190
|
-
|
|
191
|
-
흐름(`documents.js`의 `EditNewVersion`):
|
|
192
|
-
|
|
193
|
-
1. 상세 모달에서 `수정하여 새 버전 저장` 버튼을 누르면 편집 영역이 펼쳐지고, 현재 버전 본문이 편집창에 채워진다.
|
|
194
|
-
2. 내용을 고치고 선택적으로 변경 메모(예: `지원동기 보강, 문장 다듬기`)를 적는다.
|
|
195
|
-
3. `새 버전으로 저장`을 누르면 `POST /api/cover-letters/{id}/versions`로 새 버전이 생성된다. 이때 출처는 `source: 'edit'`(`직접 수정`)으로 기록된다.
|
|
196
|
-
4. 저장 후 타임라인이 갱신되고, 방금 저장한 버전이 최신으로 올라온다.
|
|
197
|
-
|
|
198
|
-
이 설계의 의도:
|
|
199
|
-
|
|
200
|
-
- **이력 보존** — AI가 생성한 버전과 사람이 고친 버전이 출처 라벨로 구분되어 한 타임라인에 공존한다.
|
|
201
|
-
- **되돌리기 가능** — 어떤 버전이든 `현재 버전으로 지정`(`PUT .../current-version`)으로 다시 활성화할 수 있다. 직접 수정이 곧 파괴가 아니다.
|
|
202
|
-
- **내보내기 분리** — 보관·열람과 별개로 MD/HTML 내보내기(`/api/export/cover-letter/{id}`)는 읽기 전용 GET이라 토큰 없이 동작한다.
|
|
203
|
-
|
|
204
|
-
문서(이력서·경력기술서)는 버전 타임라인 대신 단일 본문 수정(`PUT /api/documents/{id}`) 모델을 쓴다. 자기소개서만 버전 누적이 의미 있다고 보고 차등 적용했다.
|
|
205
|
-
|
|
206
|
-
---
|
|
207
|
-
|
|
208
|
-
## 6. 접근성
|
|
209
|
-
|
|
210
|
-
복잡한 ARIA를 쌓기보다, 시맨틱 마크업과 키보드·포커스 기본기를 지킨다.
|
|
211
|
-
|
|
212
|
-
- **포커스 가시성**: `:focus-visible`에 `2px` 악센트 아웃라인(`outline-offset: 2px`). 키보드 사용자가 현재 위치를 항상 알 수 있다.
|
|
213
|
-
- **아이콘 버튼 라벨**: `IconBtn`은 `aria-label`을 자동으로 붙인다(`title || name`). 글자가 없는 버튼도 스크린리더가 읽는다.
|
|
214
|
-
- **모달 키보드**: `openModal`은 `Escape`로 닫히고, 열릴 때 첫 입력 요소(`input,textarea,select,button`)에 포커스를 준다. 스크림 클릭으로도 닫힌다.
|
|
215
|
-
- **색에만 의존하지 않음**: 상태 배지는 색뿐 아니라 라벨 텍스트와 점을 함께 제공한다. 점수도 색(`score-strong/mid/weak`)과 숫자(`N점`)를 같이 보여준다.
|
|
216
|
-
- **시맨틱 요소**: 표는 `table/thead/th/tbody`, 제목은 `h1~h4`, 폼은 `label`과 컨트롤을 `Field`로 묶는다.
|
|
217
|
-
- **시스템 테마 존중**: `prefers-color-scheme`를 따라가므로 OS의 다크 선호를 자동 반영한다.
|
|
218
|
-
|
|
219
|
-
라이브 영역(toast 등)과 포커스 트랩 등은 추후 보강 여지가 있는 지점으로 남겨 둔다.
|
|
220
|
-
|
|
221
|
-
---
|
|
222
|
-
|
|
223
|
-
## 7. 참고 서비스의 영향과 차별점
|
|
224
|
-
|
|
225
|
-
`styles.css` 주석이 밝히듯 **Linear / Notion / Raycast의 절제**에서 톤을 빌렸다.
|
|
226
|
-
|
|
227
|
-
| 서비스 | 빌려온 것 |
|
|
228
|
-
| --- | --- |
|
|
229
|
-
| **Linear** | 조밀한 정보 밀도, 키보드 친화, 차분한 단색 악센트, 상태 칸반 |
|
|
230
|
-
| **Notion** | 중립 팔레트, 부드러운 카드·경계선, 콘텐츠 우선의 차분한 표면 |
|
|
231
|
-
| **Raycast** | 군더더기 없는 표면, 빠른 액션, "도구다움"의 미니멀함 |
|
|
232
|
-
|
|
233
|
-
차별점:
|
|
234
|
-
|
|
235
|
-
- **완전 오프라인·로컬 전용**: 프레임워크·CDN 없이 동작하고(`styles.css` 주석: *"works fully offline; nothing leaves the machine"*), 모든 데이터가 로컬에만 남는다. 위 서비스들이 클라우드 SaaS인 것과 정반대다.
|
|
236
|
-
- **MCP-우선, LLM 내장 없음**: 화면은 AI가 채우지만, 제품 자체는 "AI 앱"으로 보이지 않게 의도적으로 절제했다(§1.2). 분석·작성은 사용자의 AI가, 보관·구조화·열람은 CareerMate가 맡는다.
|
|
237
|
-
- **단일 도메인 특화**: 범용 노트(Notion)나 이슈 트래커(Linear)가 아니라, "취업 준비 한 사이클"(공고 → 적합도 → 자기소개서 → 지원 상태 → 면접)에 정확히 맞춘 정보 구조와 상태 모델을 갖는다.
|
|
238
|
-
- **빌드리스 바닐라**: 디자인 시스템이 CSS 변수 토큰 + 소수의 JS 컴포넌트로만 이뤄져, 번들러·런타임 의존성이 없다. 무거운 디자인 시스템 패키지 대신 `lib.js` 한 파일이 그 역할을 한다.
|
|
239
|
-
|
|
240
|
-
---
|
|
241
|
-
|
|
242
|
-
## 관련 문서
|
|
243
|
-
|
|
244
|
-
- 화면 작성 규칙: [`apps/web/UI_CONTRACT.md`](../apps/web/UI_CONTRACT.md)
|
|
245
|
-
- 참고 구현(Home): [`apps/web/public/pages/home.js`](../apps/web/public/pages/home.js)
|
|
246
|
-
- 디자인 토큰·스타일: [`apps/web/public/styles.css`](../apps/web/public/styles.css)
|
|
247
|
-
- 컴포넌트·API 클라이언트: [`apps/web/public/lib.js`](../apps/web/public/lib.js)
|