careermate 0.1.0 โ 0.1.2
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/README.md +22 -17
- package/THIRD_PARTY_NOTICES.md +15 -0
- package/apps/mcp/src/index.ts +4 -3
- package/apps/web/DESIGN_GUIDE.md +2 -2
- package/apps/web/demo/demo-shim.js +536 -0
- package/apps/web/demo/demo.css +75 -0
- package/apps/web/demo/seed.js +269 -0
- package/apps/web/public/app.js +34 -2
- package/apps/web/public/icon-180.png +0 -0
- package/apps/web/public/index.html +14 -3
- package/apps/web/public/lib.js +135 -23
- package/apps/web/public/pages/applications.js +18 -9
- package/apps/web/public/pages/documents.js +66 -50
- package/apps/web/public/pages/home.js +12 -11
- package/apps/web/public/pages/interview.js +9 -12
- package/apps/web/public/pages/jobs.js +39 -36
- package/apps/web/public/pages/profile.js +66 -86
- package/apps/web/public/pages/settings.js +21 -14
- package/apps/web/public/styles.css +105 -38
- package/apps/web/src/http.ts +31 -4
- package/apps/web/src/info.ts +9 -22
- package/apps/web/src/routes.ts +19 -14
- package/apps/web/src/server.ts +34 -29
- package/apps/web/src/settings.ts +35 -17
- package/bin/careermate.mjs +8 -5
- package/dist/doctor.mjs +78908 -0
- package/dist/install-page/.omc/state/agent-replay-55a58c0d-bb6e-43ea-8a05-4b6c93b80b34.jsonl +12 -0
- package/dist/install-page/.omc/state/idle-notif-cooldown.json +3 -0
- package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/mission-state.json +147 -0
- package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/pre-tool-advisory-throttle.json +22 -0
- package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/subagent-tracking-state.json +44 -0
- package/dist/install-page/favicon.svg +1 -0
- package/dist/install-page/icon-180.png +0 -0
- package/dist/install-page/icon-512.png +0 -0
- package/dist/install-page/index.html +328 -225
- package/dist/install-page/landing.js +54 -0
- package/dist/install-page/llms-install.txt +202 -0
- package/dist/install-page/og.png +0 -0
- package/dist/install-page/shots/applications-dark.png +0 -0
- package/dist/install-page/shots/applications-light.png +0 -0
- package/dist/install-page/shots/documents-dark.png +0 -0
- package/dist/install-page/shots/documents-light.png +0 -0
- package/dist/install-page/shots/home-dark.png +0 -0
- package/dist/install-page/shots/home-light.png +0 -0
- package/dist/install-page/shots/interview-dark.png +0 -0
- package/dist/install-page/shots/interview-light.png +0 -0
- package/dist/install-page/shots/jobs-dark.png +0 -0
- package/dist/install-page/shots/jobs-light.png +0 -0
- package/dist/install-page/shots/settings-dark.png +0 -0
- package/dist/install-page/shots/settings-light.png +0 -0
- package/dist/install-page/start.html +323 -0
- package/dist/install-page/style.css +128 -4
- package/dist/mcp.mjs +74225 -2007
- package/dist/{mcpb-stage/dist/web.mjs โ migrate.mjs} +142 -2660
- package/dist/pdf.worker.min.mjs +28 -0
- package/dist/public/app.js +34 -2
- package/dist/public/icon-180.png +0 -0
- package/dist/public/index.html +14 -3
- package/dist/public/lib.js +135 -23
- package/dist/public/pages/applications.js +18 -9
- package/dist/public/pages/documents.js +66 -50
- package/dist/public/pages/home.js +12 -11
- package/dist/public/pages/interview.js +9 -12
- package/dist/public/pages/jobs.js +39 -36
- package/dist/public/pages/profile.js +66 -86
- package/dist/public/pages/settings.js +21 -14
- package/dist/public/styles.css +105 -38
- package/dist/web.mjs +39950 -369
- package/docs/ARCHITECTURE.md +5 -5
- package/docs/DECISIONS.md +1 -1
- package/docs/DEMO.md +6 -6
- package/docs/MCP_TOOLS.md +68 -9
- package/docs/ROADMAP.md +11 -10
- package/docs/RUNTIME_DISTRIBUTION_RESEARCH.md +135 -0
- package/docs/START_WORKFLOW.md +19 -7
- package/docs/SUPPORTED_AI_APPS.md +85 -33
- package/docs/TODO.md +1 -1
- package/docs/WORKFLOWS.md +8 -6
- package/docs/superpowers/specs/2026-06-16-demo-dashboard-deploy-design.md +64 -0
- package/package.json +8 -3
- package/packages/core/src/services.ts +42 -1
- package/packages/db/src/connection.ts +30 -0
- package/packages/db/src/index.ts +1 -0
- package/packages/db/src/paths.ts +11 -0
- package/packages/db/src/repositories.ts +109 -63
- package/packages/db/src/schema.ts +118 -0
- package/packages/exporters/src/html.ts +9 -12
- package/packages/mcp-tools/src/bridge.ts +55 -32
- package/packages/mcp-tools/src/index.ts +9 -0
- package/packages/mcp-tools/src/tools.ts +269 -65
- package/packages/mcp-tools/src/update.ts +330 -0
- package/packages/parsers/src/documents.ts +521 -0
- package/packages/parsers/src/index.ts +8 -5
- package/packages/prompts/src/onboarding.ts +2 -2
- package/packages/shared/src/build-info.ts +22 -0
- package/packages/shared/src/enums.ts +39 -0
- package/packages/shared/src/index.ts +1 -0
- package/packages/shared/src/schemas.ts +24 -3
- package/packages/workflows/src/definitions.ts +4 -2
- package/scripts/build-demo.mjs +130 -0
- package/scripts/build-dist.mjs +46 -8
- package/scripts/build-mcpb.mjs +60 -4
- package/scripts/doctor.ts +16 -3
- package/scripts/gen-og.mjs +86 -0
- package/scripts/init.ts +32 -3
- package/scripts/seed.ts +5 -5
- package/scripts/shots-seed.ts +192 -0
- package/scripts/shots.ts +89 -0
- package/tsconfig.json +3 -1
- package/dist/careermate.mcpb +0 -0
- package/dist/mcp-smoke.err +0 -3
- package/dist/mcpb-stage/README.md +0 -219
- package/dist/mcpb-stage/dist/install-page/index.html +0 -434
- package/dist/mcpb-stage/dist/install-page/style.css +0 -407
- package/dist/mcpb-stage/dist/install-page/vercel.json +0 -20
- package/dist/mcpb-stage/dist/mcp.mjs +0 -23704
- package/dist/mcpb-stage/dist/public/app.js +0 -118
- package/dist/mcpb-stage/dist/public/index.html +0 -41
- package/dist/mcpb-stage/dist/public/lib.js +0 -282
- package/dist/mcpb-stage/dist/public/pages/applications.js +0 -98
- package/dist/mcpb-stage/dist/public/pages/documents.js +0 -446
- package/dist/mcpb-stage/dist/public/pages/home.js +0 -263
- package/dist/mcpb-stage/dist/public/pages/interview.js +0 -230
- package/dist/mcpb-stage/dist/public/pages/jobs.js +0 -494
- package/dist/mcpb-stage/dist/public/pages/profile.js +0 -576
- package/dist/mcpb-stage/dist/public/pages/settings.js +0 -233
- package/dist/mcpb-stage/dist/public/styles.css +0 -420
- package/dist/mcpb-stage/manifest.json +0 -40
- package/docs/INSTALL.md +0 -148
- package/docs/INSTALL_AND_USAGE.md +0 -99
- package/install-page/index.html +0 -474
- package/install-page/style.css +0 -391
- package/install-page/vercel.json +0 -20
- /package/dist/{mcpb-stage/dist/public โ install-page}/fonts/PretendardVariable.woff2 +0 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Demo seed data โ realistic sample career workspace for careermate.life/demo.
|
|
3
|
+
// Loaded fresh into the in-memory demo DB on every page load (and on reset).
|
|
4
|
+
// Shapes mirror @careermate/shared *Record types (see packages/shared/src/schemas.ts).
|
|
5
|
+
// All timestamps are fixed strings so the demo is deterministic (no Date.now()).
|
|
6
|
+
// =============================================================================
|
|
7
|
+
|
|
8
|
+
// Anchor "now" for relative-time rendering. Recent activity is dated near this.
|
|
9
|
+
const T = (iso) => iso; // readability helper
|
|
10
|
+
|
|
11
|
+
export function buildSeed() {
|
|
12
|
+
return {
|
|
13
|
+
profile: {
|
|
14
|
+
id: 'p1',
|
|
15
|
+
created_at: '2026-05-02T09:00:00.000Z',
|
|
16
|
+
updated_at: '2026-06-14T11:20:00.000Z',
|
|
17
|
+
name: '๊นํ๋',
|
|
18
|
+
email: 'haneul.kim@example.com',
|
|
19
|
+
phone: '010-1234-5678',
|
|
20
|
+
location: '์์ธ ์ฑ๋๊ตฌ',
|
|
21
|
+
headline: '5๋
์ฐจ ๋ฐฑ์๋ ์์ง๋์ด ยท ๊ฒฐ์ /์ ์ฐ ๋๋ฉ์ธ',
|
|
22
|
+
summary:
|
|
23
|
+
'๋๊ท๋ชจ ํธ๋ํฝ์ ๊ฒฐ์ ยท์ ์ฐ ์์คํ
์ ์ค๊ณยท์ด์ํด ์จ ๋ฐฑ์๋ ์์ง๋์ด์
๋๋ค. ' +
|
|
24
|
+
'์ฅ์ ๋์๊ณผ ์ ์ง์ ๋ง์ด๊ทธ๋ ์ด์
๊ฒฝํ์ด ๋ง๊ณ , ํ์ ๋ฐฐํฌ ํ์ดํ๋ผ์ธ์ ์ ๋นํด ' +
|
|
25
|
+
'๋ฐฐํฌ ๋น๋๋ฅผ ์ฃผ 1ํ์์ ์ผ 5ํ๋ก ๋์ด์ฌ๋ ธ์ต๋๋ค.',
|
|
26
|
+
desired_roles: ['๋ฐฑ์๋ ์์ง๋์ด', 'ํ๋ซํผ ์์ง๋์ด'],
|
|
27
|
+
desired_conditions: '์ฐ๋ด 7,000๋ง์+ ยท ์์ธ/ํ๊ต ยท ์ฃผ 2ํ ์ด์ ์ฌํ',
|
|
28
|
+
preferred_tone: '๋ด๋ฐฑํ๊ณ ๊ตฌ์ฒด์ ์ธ ยท ์ฑ๊ณผ๋ ์ซ์๋ก',
|
|
29
|
+
emphasis_points: ['๊ฒฐ์ /์ ์ฐ ๋๋ฉ์ธ ์ ๋ฌธ์ฑ', '๋์ฉ๋ ํธ๋ํฝ ์์ ํ', 'ํ ์์ฐ์ฑ ๊ฐ์ '],
|
|
30
|
+
links: [
|
|
31
|
+
{ label: 'GitHub', url: 'https://github.com/example' },
|
|
32
|
+
{ label: '๊ธฐ์ ๋ธ๋ก๊ทธ', url: 'https://blog.example.com' },
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
experiences: [
|
|
37
|
+
{
|
|
38
|
+
id: 'e1', created_at: '2026-05-02T09:05:00.000Z', updated_at: '2026-05-02T09:05:00.000Z',
|
|
39
|
+
company: 'ํ์ด์ฝ์ด', role: '๋ฐฑ์๋ ์์ง๋์ด (์๋์ด)', employment_type: '์ ๊ท์ง',
|
|
40
|
+
start_date: '2022-03', end_date: null, is_current: true,
|
|
41
|
+
description: '๊ฒฐ์ ๊ฒ์ดํธ์จ์ด์ ์ ์ฐ ์์คํ
๋ฐฑ์๋ ๊ฐ๋ฐยท์ด์.',
|
|
42
|
+
achievements: [
|
|
43
|
+
'์ ์ฐ ๋ฐฐ์น ์ฒ๋ฆฌ ์๊ฐ์ 4์๊ฐ โ 38๋ถ์ผ๋ก ๋จ์ถ (์ฟผ๋ฆฌยท์ธ๋ฑ์คยท๋ณ๋ ฌํ)',
|
|
44
|
+
'๊ฒฐ์ ์น์ธ API p99 ์ง์ฐ 320ms โ 110ms ๊ฐ์ ',
|
|
45
|
+
'๋ฌด์ค๋จ DB ๋ง์ด๊ทธ๋ ์ด์
์ผ๋ก ์ 1ํ ์ ๊ธฐ ์ ๊ฒ ๋ค์ดํ์ ์ ๊ฑฐ',
|
|
46
|
+
],
|
|
47
|
+
tech: ['Java', 'Spring', 'Kafka', 'MySQL', 'Redis', 'Kubernetes'],
|
|
48
|
+
order_index: 0,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'e2', created_at: '2026-05-02T09:06:00.000Z', updated_at: '2026-05-02T09:06:00.000Z',
|
|
52
|
+
company: '์ปค๋จธ์ค๋ฉ', role: '๋ฐฑ์๋ ์์ง๋์ด', employment_type: '์ ๊ท์ง',
|
|
53
|
+
start_date: '2019-01', end_date: '2022-02', is_current: false,
|
|
54
|
+
description: '์ด์ปค๋จธ์ค ์ฃผ๋ฌธ/์ฌ๊ณ ๋๋ฉ์ธ API ๊ฐ๋ฐ.',
|
|
55
|
+
achievements: [
|
|
56
|
+
'์ฃผ๋ฌธ ํญ์ฃผ ์ ์ฌ๊ณ ๋์์ฑ ๋ฒ๊ทธ ํด๊ฒฐ (๋ถ์ฐ ๋ฝ ๋์
, ์ค๋ฒ์
0๊ฑด)',
|
|
57
|
+
'์ ๊ท ์ ๊ธฐ๋ฐฐ์ก ๊ธฐ๋ฅ ๋ฐฑ์๋ ๋จ๋
์ค๊ณยท์ถ์',
|
|
58
|
+
],
|
|
59
|
+
tech: ['Node.js', 'TypeScript', 'PostgreSQL', 'AWS'],
|
|
60
|
+
order_index: 1,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
|
|
64
|
+
projects: [
|
|
65
|
+
{
|
|
66
|
+
id: 'pr1', created_at: '2026-05-02T09:10:00.000Z', updated_at: '2026-05-02T09:10:00.000Z',
|
|
67
|
+
name: '์ ์ฐ ์์คํ
์ฐจ์ธ๋ ๋ฆฌ์ํคํ
์ฒ', role: '๋ฆฌ๋',
|
|
68
|
+
description: '๋ ๊ฑฐ์ ๋ฐฐ์น ์ ์ฐ์ ์ด๋ฒคํธ ๊ธฐ๋ฐ ์คํธ๋ฆฌ๋ฐ ์ ์ฐ์ผ๋ก ์ ํ.',
|
|
69
|
+
highlights: ['Kafka ๊ธฐ๋ฐ ์ด๋ฒคํธ ์์ฑ ๋์
', '์ ์ฐ ์ ํ๋ ๊ฒ์ฆ ํ์ดํ๋ผ์ธ ์๋ํ'],
|
|
70
|
+
tech: ['Kafka', 'Java', 'Spring Batch'],
|
|
71
|
+
url: 'https://github.com/example/settlement', start_date: '2023-06', end_date: '2024-01',
|
|
72
|
+
order_index: 0,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 'pr2', created_at: '2026-05-02T09:11:00.000Z', updated_at: '2026-05-02T09:11:00.000Z',
|
|
76
|
+
name: '์ฌ๋ด ๋ฐฐํฌ ํ์ดํ๋ผ์ธ ์ ๋น', role: '๊ฐ์ธ ์ฃผ๋',
|
|
77
|
+
description: 'GitHub Actions + ArgoCD๋ก ์นด๋๋ฆฌ ๋ฐฐํฌ ์๋ํ.',
|
|
78
|
+
highlights: ['๋ฐฐํฌ ๋น๋ ์ฃผ1ํ โ ์ผ5ํ', '๋กค๋ฐฑ ํ๊ท 12๋ถ โ 90์ด'],
|
|
79
|
+
tech: ['GitHub Actions', 'ArgoCD', 'Kubernetes'],
|
|
80
|
+
url: null, start_date: '2024-02', end_date: '2024-05',
|
|
81
|
+
order_index: 1,
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
|
|
85
|
+
skills: [
|
|
86
|
+
{ id: 's1', created_at: '2026-05-02T09:12:00.000Z', updated_at: '2026-05-02T09:12:00.000Z', name: 'Java / Spring', category: '์ธ์ด/ํ๋ ์์ํฌ', level: '์', years: 5, order_index: 0 },
|
|
87
|
+
{ id: 's2', created_at: '2026-05-02T09:12:10.000Z', updated_at: '2026-05-02T09:12:10.000Z', name: 'Kafka', category: '์ธํ๋ผ', level: '์', years: 3, order_index: 1 },
|
|
88
|
+
{ id: 's3', created_at: '2026-05-02T09:12:20.000Z', updated_at: '2026-05-02T09:12:20.000Z', name: 'MySQL / PostgreSQL', category: '๋ฐ์ดํฐ๋ฒ ์ด์ค', level: '์', years: 5, order_index: 2 },
|
|
89
|
+
{ id: 's4', created_at: '2026-05-02T09:12:30.000Z', updated_at: '2026-05-02T09:12:30.000Z', name: 'Kubernetes', category: '์ธํ๋ผ', level: '์ค', years: 3, order_index: 3 },
|
|
90
|
+
{ id: 's5', created_at: '2026-05-02T09:12:40.000Z', updated_at: '2026-05-02T09:12:40.000Z', name: 'TypeScript / Node.js', category: '์ธ์ด/ํ๋ ์์ํฌ', level: '์ค', years: 3, order_index: 4 },
|
|
91
|
+
],
|
|
92
|
+
|
|
93
|
+
documents: [
|
|
94
|
+
{
|
|
95
|
+
id: 'd1', created_at: '2026-05-03T10:00:00.000Z', updated_at: '2026-06-10T08:30:00.000Z',
|
|
96
|
+
kind: 'resume', title: '๊นํ๋ ์ด๋ ฅ์ (2026)', source: 'upload', is_primary: true,
|
|
97
|
+
tags: ['๋ฐฑ์๋', '๊ฒฐ์ '],
|
|
98
|
+
content:
|
|
99
|
+
'# ๊นํ๋ โ ๋ฐฑ์๋ ์์ง๋์ด\n\n## ๊ฒฝ๋ ฅ ์์ฝ\n๊ฒฐ์ ยท์ ์ฐ ๋๋ฉ์ธ 5๋
. ๋์ฉ๋ ํธ๋ํฝ ์์ ํ์ ํ ์์ฐ์ฑ ๊ฐ์ ์ ๊ฐ์ .\n\n' +
|
|
100
|
+
'## ํต์ฌ ์ฑ๊ณผ\n- ์ ์ฐ ๋ฐฐ์น 4h โ 38m\n- ๊ฒฐ์ API p99 320ms โ 110ms\n- ๋ฌด์ค๋จ ๋ง์ด๊ทธ๋ ์ด์
์ผ๋ก ์ ๊ธฐ ๋ค์ดํ์ ์ ๊ฑฐ\n',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: 'd2', created_at: '2026-05-20T13:00:00.000Z', updated_at: '2026-05-20T13:00:00.000Z',
|
|
104
|
+
kind: 'career_description', title: '๊ฒฝ๋ ฅ๊ธฐ์ ์ โ ํ์ด์ฝ์ด', source: 'manual', is_primary: false,
|
|
105
|
+
tags: ['๊ฒฐ์ '],
|
|
106
|
+
content: '## ํ์ด์ฝ์ด (2022.03~)\n๊ฒฐ์ ๊ฒ์ดํธ์จ์ด/์ ์ฐ ๋ฐฑ์๋. ์์ธ ํ๋ก์ ํธ์ ์ฑ๊ณผ๋ ๋ณธ๋ฌธ ์ฐธ์กฐ.\n',
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
|
|
110
|
+
jobs: [
|
|
111
|
+
{
|
|
112
|
+
id: 'j1', created_at: '2026-06-01T09:00:00.000Z', updated_at: '2026-06-12T09:00:00.000Z',
|
|
113
|
+
company: 'ํ ์คํ์ด๋จผ์ธ ', position: '๋ฐฑ์๋ ์์ง๋์ด (๊ฒฐ์ )', url: 'https://example.com/jobs/j1',
|
|
114
|
+
location: '์์ธ ๊ฐ๋จ๊ตฌ', employment_type: '์ ๊ท์ง',
|
|
115
|
+
description: '๊ฒฐ์ ์ฝ์ด ์์คํ
์ ํจ๊ป ๋ง๋ค ๋ฐฑ์๋ ์์ง๋์ด๋ฅผ ์ฐพ์ต๋๋ค. ๋์ฉ๋ ํธ๋์ญ์
์ฒ๋ฆฌ ๊ฒฝํ ์ฐ๋.',
|
|
116
|
+
requirements: ['JVM ๊ธฐ๋ฐ ๋ฐฑ์๋ 5๋
+', '๋์ฉ๋ ํธ๋ํฝ ๊ฒฝํ', '๊ฒฐ์ /๊ธ์ต ๋๋ฉ์ธ ์ฐ๋'],
|
|
117
|
+
keywords: ['Java', 'Spring', 'Kafka', 'MSA', '๊ฒฐ์ '],
|
|
118
|
+
deadline: '2026-06-30', source: '์ํฐ๋',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: 'j2', created_at: '2026-06-03T09:00:00.000Z', updated_at: '2026-06-11T09:00:00.000Z',
|
|
122
|
+
company: '์ฟ ํก', position: 'Software Engineer, Backend', url: 'https://example.com/jobs/j2',
|
|
123
|
+
location: '์์ธ ์กํ๊ตฌ', employment_type: '์ ๊ท์ง',
|
|
124
|
+
description: '์ปค๋จธ์ค ์ฃผ๋ฌธ/์ ์ฐ ํ๋ซํผ ๋ฐฑ์๋. ๊ธ๋ก๋ฒ ์ค์ผ์ผ์ ๋ถ์ฐ ์์คํ
.',
|
|
125
|
+
requirements: ['๋ถ์ฐ ์์คํ
์ค๊ณ ๊ฒฝํ', 'Java ๋๋ Kotlin', '์์ด ํ์
๊ฐ๋ฅ'],
|
|
126
|
+
keywords: ['Java', 'Kotlin', 'AWS', '๋ถ์ฐ์์คํ
'],
|
|
127
|
+
deadline: '2026-07-15', source: '์ฌ๋์ธ',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: 'j3', created_at: '2026-06-05T09:00:00.000Z', updated_at: '2026-06-05T09:00:00.000Z',
|
|
131
|
+
company: '๋น๊ทผ', position: 'ํ๋ซํผ ์์ง๋์ด', url: 'https://example.com/jobs/j3',
|
|
132
|
+
location: '์์ธ ์์ด๊ตฌ', employment_type: '์ ๊ท์ง',
|
|
133
|
+
description: '์ฌ๋ด ๊ฐ๋ฐ ์์ฐ์ฑ์ ๋์ด์ฌ๋ฆด ํ๋ซํผ ์์ง๋์ด.',
|
|
134
|
+
requirements: ['Kubernetes ์ด์ ๊ฒฝํ', 'CI/CD ํ์ดํ๋ผ์ธ ์ค๊ณ', 'Go ๋๋ Java'],
|
|
135
|
+
keywords: ['Kubernetes', 'CI/CD', 'Platform', 'Go'],
|
|
136
|
+
deadline: null, source: '์ง์ ์
๋ ฅ',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
id: 'j4', created_at: '2026-05-25T09:00:00.000Z', updated_at: '2026-06-08T09:00:00.000Z',
|
|
140
|
+
company: '๋ค์ด๋ฒํ์ด', position: '๋ฐฑ์๋ ๊ฐ๋ฐ์ (์ ์ฐ)', url: 'https://example.com/jobs/j4',
|
|
141
|
+
location: '๊ฒฝ๊ธฐ ์ฑ๋จ์', employment_type: '์ ๊ท์ง',
|
|
142
|
+
description: '์ ์ฐ ์์คํ
๋ฐฑ์๋ ๊ฐ๋ฐ. ๋ฐฐ์น/์คํธ๋ฆฌ๋ฐ ์ ์ฐ ๊ฒฝํ ์ฐ๋.',
|
|
143
|
+
requirements: ['Spring Batch ๊ฒฝํ', '์ ์ฐ ๋๋ฉ์ธ ์ดํด', 'SQL ์ต์ ํ'],
|
|
144
|
+
keywords: ['Java', 'Spring Batch', '์ ์ฐ', 'MySQL'],
|
|
145
|
+
deadline: '2026-06-22', source: '์ํฐ๋',
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
id: 'j5', created_at: '2026-05-15T09:00:00.000Z', updated_at: '2026-06-02T09:00:00.000Z',
|
|
149
|
+
company: '๋ฐฐ๋ฌ์๋ฏผ์กฑ', position: '์๋ฒ ๊ฐ๋ฐ์', url: 'https://example.com/jobs/j5',
|
|
150
|
+
location: '์์ธ ์กํ๊ตฌ', employment_type: '์ ๊ท์ง',
|
|
151
|
+
description: '์ฃผ๋ฌธ ์ค๊ณ ํ๋ซํผ ์๋ฒ ๊ฐ๋ฐ.',
|
|
152
|
+
requirements: ['Java/Kotlin', '๋์ฉ๋ ํธ๋ํฝ', 'MSA ๊ฒฝํ'],
|
|
153
|
+
keywords: ['Kotlin', 'Spring', 'MSA'],
|
|
154
|
+
deadline: '2026-06-18', source: '์ฌ๋์ธ',
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: 'j6', created_at: '2026-06-10T09:00:00.000Z', updated_at: '2026-06-10T09:00:00.000Z',
|
|
158
|
+
company: '์นด์นด์ค๋ฑ
ํฌ', position: '๋ฐฑ์๋ ์์ง๋์ด', url: 'https://example.com/jobs/j6',
|
|
159
|
+
location: '๊ฒฝ๊ธฐ ์ฑ๋จ์', employment_type: '์ ๊ท์ง',
|
|
160
|
+
description: '๋ฑ
ํน ์ฝ์ด ๋ฐฑ์๋. ์์ ์ฑ๊ณผ ์ ํฉ์ฑ์ด ์ต์ฐ์ .',
|
|
161
|
+
requirements: ['๊ธ์ต ๋๋ฉ์ธ ๊ฒฝํ', 'Java', '๋์ ํ
์คํธ ์ปค๋ฒ๋ฆฌ์ง ๋ฌธํ'],
|
|
162
|
+
keywords: ['Java', '๊ธ์ต', 'Spring'],
|
|
163
|
+
deadline: '2026-07-05', source: '์ง์ ์
๋ ฅ',
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
|
|
167
|
+
// job_id โ application. status drives the pipeline + board.
|
|
168
|
+
applications: [
|
|
169
|
+
{ id: 'a1', created_at: '2026-06-01T10:00:00.000Z', updated_at: '2026-06-13T10:00:00.000Z', job_id: 'j1', status: 'interview', resume_id: 'd1', cover_letter_id: 'c1', applied_at: '2026-06-06', notes: '1์ฐจ ๊ธฐ์ ๋ฉด์ ํต๊ณผ, 2์ฐจ ์์๋ฉด์ ์์ ' },
|
|
170
|
+
{ id: 'a2', created_at: '2026-06-03T10:00:00.000Z', updated_at: '2026-06-09T10:00:00.000Z', job_id: 'j2', status: 'applied', resume_id: 'd1', cover_letter_id: null, applied_at: '2026-06-09', notes: null },
|
|
171
|
+
{ id: 'a3', created_at: '2026-06-05T10:00:00.000Z', updated_at: '2026-06-05T10:00:00.000Z', job_id: 'j3', status: 'planned', resume_id: null, cover_letter_id: null, applied_at: null, notes: '์ง์์ ์์ฑ ์ค' },
|
|
172
|
+
{ id: 'a4', created_at: '2026-05-25T10:00:00.000Z', updated_at: '2026-06-12T10:00:00.000Z', job_id: 'j4', status: 'document_passed', resume_id: 'd1', cover_letter_id: 'c2', applied_at: '2026-05-28', notes: '์๋ฅ ํฉ๊ฒฉ โ ๋ฉด์ ์ผ์ ์กฐ์จ ์ค' },
|
|
173
|
+
{ id: 'a5', created_at: '2026-05-15T10:00:00.000Z', updated_at: '2026-06-02T10:00:00.000Z', job_id: 'j5', status: 'rejected', resume_id: 'd1', cover_letter_id: null, applied_at: '2026-05-18', notes: '์๋ฅ ํ๋ฝ' },
|
|
174
|
+
{ id: 'a6', created_at: '2026-06-10T10:00:00.000Z', updated_at: '2026-06-10T10:00:00.000Z', job_id: 'j6', status: 'draft', resume_id: null, cover_letter_id: null, applied_at: null, notes: null },
|
|
175
|
+
],
|
|
176
|
+
|
|
177
|
+
fits: [
|
|
178
|
+
{
|
|
179
|
+
id: 'f1', created_at: '2026-06-02T09:30:00.000Z', updated_at: '2026-06-02T09:30:00.000Z', job_id: 'j1',
|
|
180
|
+
score: 88, summary: '๊ฒฐ์ ๋๋ฉ์ธ ์ ๋ฌธ์ฑ๊ณผ ๋์ฉ๋ ํธ๋ํฝ ๊ฒฝํ์ด ๊ณต๊ณ ์๊ตฌ์ ๊ฐํ๊ฒ ๋ง์ต๋๋ค.',
|
|
181
|
+
strengths: ['๊ฒฐ์ /์ ์ฐ 5๋
์ค๋ฌด', 'KafkaยทSpring ์๋ จ', 'p99 ์ง์ฐ ๊ฐ์ ์ ๋ ์ฑ๊ณผ'],
|
|
182
|
+
gaps: ['MSA ์ ํ ๋ฆฌ๋ฉ ๊ฒฝํ์ ๋ณด๊ฐํ๋ฉด ์ข์'],
|
|
183
|
+
matched_keywords: ['Java', 'Spring', 'Kafka', '๊ฒฐ์ '], missing_keywords: ['MSA'],
|
|
184
|
+
recommendations: ['์ง์๋๊ธฐ์ ๊ฒฐ์ ์ฝ์ด ์์ ํ ๊ฒฝํ์ ์์ธ์ฐ๊ธฐ', 'MSA ๊ด๋ จ ํ์ต/์ฌ์ด๋ ์ธ๊ธ'],
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
id: 'f2', created_at: '2026-05-26T09:30:00.000Z', updated_at: '2026-05-26T09:30:00.000Z', job_id: 'j4',
|
|
188
|
+
score: 91, summary: '์ ์ฐ ๋ฐฐ์น ์ต์ ํ ๊ฒฝํ์ด ๊ณต๊ณ ํต์ฌ ์๊ตฌ์ ๊ฑฐ์ ์ผ์นํฉ๋๋ค.',
|
|
189
|
+
strengths: ['Spring Batch ์ ์ฐ ์ค๋ฌด', '๋ฐฐ์น 4hโ38m ์ฑ๊ณผ', 'SQL ์ต์ ํ'],
|
|
190
|
+
gaps: ['์คํธ๋ฆฌ๋ฐ ์ ์ฐ์ ํ๋ก์ ํธ ๊ฒฝํ 1๊ฑด'],
|
|
191
|
+
matched_keywords: ['Java', 'Spring Batch', '์ ์ฐ', 'MySQL'], missing_keywords: [],
|
|
192
|
+
recommendations: ['์ ์ฐ ์ ํ๋ ๊ฒ์ฆ ์๋ํ ์ฌ๋ก๋ฅผ ๊ตฌ์ฒด ์์น๋ก ์ ์'],
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
id: 'f3', created_at: '2026-06-04T09:30:00.000Z', updated_at: '2026-06-04T09:30:00.000Z', job_id: 'j2',
|
|
196
|
+
score: 72, summary: '๋ฐฑ์๋ ์ญ๋์ ์ถฉ๋ถํ๋ ๊ธ๋ก๋ฒ ์ค์ผ์ผ ๋ถ์ฐ ์์คํ
๊ฒฝํ์ ๋ถ๋ถ์ ์
๋๋ค.',
|
|
197
|
+
strengths: ['๋์ฉ๋ ํธ๋ํฝ ์์ ํ', '๋์์ฑ ๋ฌธ์ ํด๊ฒฐ'],
|
|
198
|
+
gaps: ['๊ธ๋ก๋ฒ ๋ฉํฐ๋ฆฌ์ ์ด์ ๊ฒฝํ', '์์ด ํ์
๋น๋'],
|
|
199
|
+
matched_keywords: ['Java', 'AWS'], missing_keywords: ['Kotlin', '๋ถ์ฐ์์คํ
'],
|
|
200
|
+
recommendations: ['๋ถ์ฐ ํธ๋์ญ์
์ฌ๋ก ๊ฐ์กฐ', 'Kotlin ํ์ต ๊ณํ ์ธ๊ธ'],
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
|
|
204
|
+
coverLetters: [
|
|
205
|
+
{
|
|
206
|
+
id: 'c1', created_at: '2026-06-04T11:00:00.000Z', updated_at: '2026-06-08T11:00:00.000Z',
|
|
207
|
+
title: 'ํ ์คํ์ด๋จผ์ธ ๋ฐฑ์๋ ์ง์๋๊ธฐ', job_id: 'j1', is_primary: true,
|
|
208
|
+
current_version_id: 'c1v2', version_count: 2,
|
|
209
|
+
current_content:
|
|
210
|
+
'๊ฒฐ์ ๋ ํ ๋ฒ์ ์ค๋ฅ๊ฐ ๊ณง ์ ๋ขฐ์ ์์ค์ธ ๋๋ฉ์ธ์
๋๋ค. ํ์ด์ฝ์ด์์ ๊ฒฐ์ ์น์ธ API์ p99 ์ง์ฐ์ ' +
|
|
211
|
+
'320ms์์ 110ms๋ก ์ค์ด๋ฉฐ, ๋น ๋ฅด๋ฉด์๋ ํ๋ฆฌ์ง ์๋ ์์คํ
์ด ๋ฌด์์ธ์ง ์ฒด๋ํ์ต๋๋ค. ' +
|
|
212
|
+
'ํ ์คํ์ด๋จผ์ธ ์ ๊ฒฐ์ ์ฝ์ด์์ ์ด ๊ฒฝํ์ ์ด์ด๊ฐ๊ณ ์ถ์ต๋๋ค.',
|
|
213
|
+
versions: [
|
|
214
|
+
{ id: 'c1v1', cover_letter_id: 'c1', version_no: 1, content: '(์ด์) ๊ฒฐ์ ๋๋ฉ์ธ ๊ฒฝํ ์ค์ฌ ์ง์๋๊ธฐ ์ด์.', note: '์ด์', source: 'ai', created_at: '2026-06-04T11:00:00.000Z' },
|
|
215
|
+
{ id: 'c1v2', cover_letter_id: 'c1', version_no: 2, content: '๊ฒฐ์ ๋ ํ ๋ฒ์ ์ค๋ฅ๊ฐ ๊ณง ์ ๋ขฐ์ ์์ค์ธ ๋๋ฉ์ธ์
๋๋ค. ํ์ด์ฝ์ด์์ ๊ฒฐ์ ์น์ธ API์ p99 ์ง์ฐ์ 320ms์์ 110ms๋ก ์ค์ด๋ฉฐ, ๋น ๋ฅด๋ฉด์๋ ํ๋ฆฌ์ง ์๋ ์์คํ
์ด ๋ฌด์์ธ์ง ์ฒด๋ํ์ต๋๋ค. ํ ์คํ์ด๋จผ์ธ ์ ๊ฒฐ์ ์ฝ์ด์์ ์ด ๊ฒฝํ์ ์ด์ด๊ฐ๊ณ ์ถ์ต๋๋ค.', note: '์์น ๋ณด๊ฐ + ๋ง๋ฌด๋ฆฌ ๋ค๋ฌ๊ธฐ', source: 'edit', created_at: '2026-06-08T11:00:00.000Z' },
|
|
216
|
+
],
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
id: 'c2', created_at: '2026-05-27T11:00:00.000Z', updated_at: '2026-05-27T11:00:00.000Z',
|
|
220
|
+
title: '๋ค์ด๋ฒํ์ด ์ ์ฐ ์ง์๋๊ธฐ', job_id: 'j4', is_primary: false,
|
|
221
|
+
current_version_id: 'c2v1', version_count: 1,
|
|
222
|
+
current_content:
|
|
223
|
+
'์ ์ฐ์ ์ ํํจ์ด ์ ๋ถ์
๋๋ค. Spring Batch ๊ธฐ๋ฐ ์ ์ฐ ๋ฐฐ์น๋ฅผ 4์๊ฐ์์ 38๋ถ์ผ๋ก ์ค์ด๋ฉด์๋ ' +
|
|
224
|
+
'๊ฒ์ฆ ํ์ดํ๋ผ์ธ์ ์๋ํํด ์ ํฉ์ฑ์ ์ง์ผฐ์ต๋๋ค. ๋ค์ด๋ฒํ์ด ์ ์ฐ ์์คํ
์ ๊ธฐ์ฌํ๊ณ ์ถ์ต๋๋ค.',
|
|
225
|
+
versions: [
|
|
226
|
+
{ id: 'c2v1', cover_letter_id: 'c2', version_no: 1, content: '์ ์ฐ์ ์ ํํจ์ด ์ ๋ถ์
๋๋ค. Spring Batch ๊ธฐ๋ฐ ์ ์ฐ ๋ฐฐ์น๋ฅผ 4์๊ฐ์์ 38๋ถ์ผ๋ก ์ค์ด๋ฉด์๋ ๊ฒ์ฆ ํ์ดํ๋ผ์ธ์ ์๋ํํด ์ ํฉ์ฑ์ ์ง์ผฐ์ต๋๋ค. ๋ค์ด๋ฒํ์ด ์ ์ฐ ์์คํ
์ ๊ธฐ์ฌํ๊ณ ์ถ์ต๋๋ค.', note: 'AI ์์ฑ', source: 'ai', created_at: '2026-05-27T11:00:00.000Z' },
|
|
227
|
+
],
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
|
|
231
|
+
interviews: [
|
|
232
|
+
{
|
|
233
|
+
id: 'iv1', created_at: '2026-06-12T14:00:00.000Z', updated_at: '2026-06-13T09:30:00.000Z', job_id: 'j1',
|
|
234
|
+
self_introduction:
|
|
235
|
+
'์๋
ํ์ธ์, ๊ฒฐ์ ยท์ ์ฐ ๋๋ฉ์ธ 5๋
์ฐจ ๋ฐฑ์๋ ์์ง๋์ด ๊นํ๋์
๋๋ค. ' +
|
|
236
|
+
'ํ์ด์ฝ์ด์์ ํ๋ฃจ ์๋ฐฑ๋ง ๊ฑด์ ๊ฒฐ์ ํธ๋์ญ์
์ ๋ค๋ฃจ๋ฉฐ, "๋น ๋ฅด๋ฉด์๋ ์ ๋ ํ๋ฆฌ์ง ์๋" ์์คํ
์ ' +
|
|
237
|
+
'๋ง๋๋ ๋ฐ ์ง์คํด ์์ต๋๋ค. ๊ฒฐ์ ์น์ธ API์ p99 ์ง์ฐ์ 320ms์์ 110ms๋ก ์ค์๊ณ , ' +
|
|
238
|
+
'์ ์ฐ ๋ฐฐ์น๋ฅผ 4์๊ฐ์์ 38๋ถ์ผ๋ก ๋จ์ถํ๋ฉด์๋ ๊ฒ์ฆ ์๋ํ๋ก ์ ํฉ์ฑ์ ์ง์ผฐ์ต๋๋ค. ' +
|
|
239
|
+
'ํ ์คํ์ด๋จผ์ธ ์ ๊ฒฐ์ ์ฝ์ด์์ ์ด ๊ฒฝํ์ ํ ๋จ๊ณ ๋ ํค์ฐ๊ณ ์ถ์ต๋๋ค.',
|
|
240
|
+
notes:
|
|
241
|
+
'2์ฐจ ์์๋ฉด์ โ ์ปฌ์ฒํ + ์์คํ
์ค๊ณ ์์ฃผ ์์.\n' +
|
|
242
|
+
'ยท ๊ฒฐ์ ๋๋ฉ์ธ์์์ "์ ํ์ฑ vs ์๋" ํธ๋ ์ด๋์คํ ๊ด์ ๊ฐ์กฐํ๊ธฐ\n' +
|
|
243
|
+
'ยท ํ์ด์ฝ์ด โ ํ ์คํ์ด๋จผ์ธ ์ง์ ๋๊ธฐ(๊ท๋ชจ/์ํฉํธ) ์์งํ๊ฒ\n' +
|
|
244
|
+
'ยท ์ญ์ง๋ฌธ: ๊ฒฐ์ ์ฝ์ด ํ์ ์จ์ฝ/์ฅ์ ๋์ ๋ฌธํ, ์ฐจ์ธ๋ ์ ์ฐ ๋ก๋๋งต',
|
|
245
|
+
questions: [
|
|
246
|
+
{ question: '๊ฒฐ์ ์น์ธ API์ p99 ์ง์ฐ์ ์ด๋ป๊ฒ 320ms์์ 110ms๋ก ์ค์๋์?', intent: '์ฑ๋ฅ ์ต์ ํ์ ์ฌ๊ณ ๊ณผ์ ๊ณผ ์ธก์ ๊ธฐ๋ฐ ์ ๊ทผ ํ์ธ', followups: ['๋ณ๋ชฉ์ ์ด๋ป๊ฒ ์ธก์ ํ๋์?', '๊ฐ์ ์ ํธ๋ ์ด๋์คํ๋ ๋ฌด์์ด์๋์?', '์บ์ ์ ํฉ์ฑ์ ์ด๋ป๊ฒ ๋ณด์ฅํ๋์?'], answer_outline: 'APM์ผ๋ก ๊ตฌ๊ฐ๋ณ ์ธก์ โ ๊ฐ์ค(N+1 ์ฟผ๋ฆฌยท์ง๋ ฌํยท์ปค๋ฅ์
๋๊ธฐ) โ ์ธ๋ฑ์ค ์ฌ์ค๊ณยท์ปค๋ฅ์
ํ ํ๋ยท์ฝ๊ธฐ ์บ์ ์์ฐจ ์ ์ฉ โ ๊ฐ ๋จ๊ณ A/B๋ก ํจ๊ณผ ๊ฒ์ฆ. ์บ์๋ TTL+์ด๋ฒคํธ ๋ฌดํจํ๋ก ์ ํฉ์ฑ ์ ์ง.' },
|
|
247
|
+
{ question: '๋ฌด์ค๋จ์ผ๋ก ๊ฒฐ์ DB๋ฅผ ๋ง์ด๊ทธ๋ ์ด์
ํ ๊ฒฝํ์ ์ค๋ช
ํด ์ฃผ์ธ์.', intent: '์ด์ ์์ ์ฑ๊ณผ ๋จ๊ณ์ ์ ํ ์ค๊ณ ์ญ๋', followups: ['๋กค๋ฐฑ ์ ๋ต์?', '๋ฐ์ดํฐ ์ ํฉ์ฑ ๊ฒ์ฆ์?'], answer_outline: '๋์ผ ๋ผ์ดํธ โ ๊ณผ๊ฑฐ ๋ฐ์ดํฐ ๋ฐฑํ โ ์ ๊ตฌ ๋น๊ต ๊ฒ์ฆ โ ์ ์ง ํธ๋ํฝ ์ปท์ค๋ฒ. ๊ฐ ๋จ๊ณ๊ฐ ๊ฐ์ญ์ ์ด๋ผ ์ธ์ ๋ ๋กค๋ฐฑ ๊ฐ๋ฅํ๊ฒ ์ค๊ณ.' },
|
|
248
|
+
{ question: '๋์ฉ๋ ํธ๋ํฝ์์ ๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ฌ๋ก๊ฐ ์๋์?', intent: '๋ถ์ฐ ํ๊ฒฝ ๋์์ฑ ์ดํด๋', followups: ['๋ถ์ฐ ๋ฝ์ ํ๊ณ๋?', '๋ฉฑ๋ฑ์ฑ์ ์ด๋ป๊ฒ ๋ณด์ฅํ๋์?'], answer_outline: '์ฃผ๋ฌธ ํญ์ฃผ ์ ์ฌ๊ณ ์ค๋ฒ์
โ ๋ถ์ฐ ๋ฝ(Redis) + ๋ฉฑ๋ฑ ํค๋ก ์ค๋ณต ์ฒ๋ฆฌ ์ฐจ๋จ. ๋ฝ ๊ฒฝํฉ์ด ํฐ ๊ตฌ๊ฐ์ ํ ๊ธฐ๋ฐ ์ง๋ ฌํ๋ก ์ ํํด ์ค๋ฒ์
0๊ฑด ๋ฌ์ฑ.' },
|
|
249
|
+
{ question: '๊ฒฐ์ ์ฒ๋ผ ์ ํ์ฑ์ด ์ค์ํ ๋๋ฉ์ธ์์ ์ฅ์ ๊ฐ ๋ฌ์ ๋ ์ด๋ป๊ฒ ๋์ํ๋์?', intent: '์ฅ์ ๋์ ์์น๊ณผ ์ฐ์ ์์ ํ๋จ', followups: ['์ฌํ ๋ถ์์ ์ด๋ป๊ฒ ํ๋์?'], answer_outline: '1) ์ํฅ ๋ฒ์ ๊ฒฉ๋ฆฌยท์ฐจ๋จ(์ํท๋ธ๋ ์ด์ปค) 2) ์ ํฉ์ฑ ์ฐ์ โ ์์ฌ ๊ฑฐ๋๋ ๋ณด๋ฅ ์ฒ๋ฆฌ 3) ๋ณต๊ตฌ ํ ์ ์ฐ ์ฌ๋์ฌ 4) ๋ธ๋ ์๋ฆฌ์ค ํฌ์คํธ๋ชจํ
์ผ๋ก ์ฌ๋ฐ ๋ฐฉ์ง ์ก์
ํ.' },
|
|
250
|
+
{ question: 'ํจ๊ป ์ผํ๊ธฐ ์ข์ ๋๋ฃ/ํ ๋ฌธํ๋ ๋ฌด์์ด๋ผ๊ณ ์๊ฐํ๋์?', intent: '์ปฌ์ฒํ', followups: ['์ฝ๋ ๋ฆฌ๋ทฐ ๋ฌธํ์ ๋ํ ์๊ฐ์?'], answer_outline: '๋ฌธ์ ๋ฅผ ์จ๊ธฐ์ง ์๊ณ ์ผ์ฐ ๊ณต์ ํ๋ ๋ฌธํ, ๊ทธ๋ฆฌ๊ณ ๊ฒฐ์ ์ "์"๋ฅผ ๋ฌธ์๋ก ๋จ๊ธฐ๋ ํ. ๋ฆฌ๋ทฐ๋ ์ฌ๋์ด ์๋๋ผ ์ฝ๋/์ค๊ณ๋ฅผ ํฅํ๊ฒ.' },
|
|
251
|
+
],
|
|
252
|
+
star_guides: [
|
|
253
|
+
{ question: '๊ฐ์ฅ ์ด๋ ค์ ๋ ์ฅ์ ๋์ ๊ฒฝํ์?', situation: '์๋ง ์ ์ฐ ๋ฐฐ์น๊ฐ ์ง์ฐ๋๋ฉฐ ๋ง๊ฐ ์ํ์ ๋๊ธธ ์ํ์ ์ฒํจ', task: '4์๊ฐ ๋ด ์ ์ฐ์ ์ ํํ ์๋ฃํ๊ณ ์ฌ๋ฐ์ ๋ง์์ผ ํ์', action: '๋ณ๋ชฉ ๋ฐฐ์น๋ฅผ ๋ณ๋ ฌํํ๊ณ ์ธ๋ฑ์ค๋ฅผ ์ฌ์ค๊ณ, ํซํฝ์ค๋ฅผ ๋ฌด์ค๋จ ๋ฐฐํฌ ํ ๊ฒ์ฆ ํ์ดํ๋ผ์ธ์ผ๋ก ์ ํฉ์ฑ ํ์ธ', result: '์ฒ๋ฆฌ ์๊ฐ์ 38๋ถ์ผ๋ก ๋จ์ถํ๊ณ ์ดํ ๋์ผ ์ฅ์ ์ฌ๋ฐ 0๊ฑด, ์ ์ฐ SLA๋ฅผ ์์ ํ' },
|
|
254
|
+
{ question: '์ฃผ๋์ ์ผ๋ก ํ์ ๋ฌธ์ ๋ฅผ ๊ฐ์ ํ ๊ฒฝํ์?', situation: '๋ฐฐํฌ๊ฐ ์ฃผ 1ํ๋ก ๋ฌถ์ฌ ๊ธฐ๋ฅ ์ถ์๊ฐ ๋๋ฆฌ๊ณ ๋กค๋ฐฑ์ด ์ด๋ ค์ ์', task: '๋ฐฐํฌ ๋น๋๋ฅผ ๋์ด๋ฉด์๋ ์์ ์ฑ์ ์์ง ์์์ผ ํ์', action: 'GitHub Actions + ArgoCD๋ก ์นด๋๋ฆฌ ๋ฐฐํฌ ์๋ํ, ํฌ์ค์ฒดํฌ ๊ธฐ๋ฐ ์๋ ๋กค๋ฐฑ ๊ตฌ์ฑ', result: '๋ฐฐํฌ ๋น๋ ์ฃผ1ํ โ ์ผ5ํ, ๋กค๋ฐฑ ํ๊ท 12๋ถ โ 90์ด๋ก ๋จ์ถ' },
|
|
255
|
+
],
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
|
|
259
|
+
activities: [
|
|
260
|
+
{ id: 'ac1', type: 'application_status_changed', entity_type: 'application', entity_id: 'a1', summary: 'ํ ์คํ์ด๋จผ์ธ โ ๋ฉด์ ์งํ์ผ๋ก ์ํ๋ฅผ ๋ณ๊ฒฝํ์ต๋๋ค.', created_at: '2026-06-13T10:00:00.000Z' },
|
|
261
|
+
{ id: 'ac2', type: 'interview_prep_saved', entity_type: 'interview_prep', entity_id: 'iv1', summary: 'ํ ์คํ์ด๋จผ์ธ ๋ฉด์ ์ค๋น ์๋ฃ๋ฅผ ์ ์ฅํ์ต๋๋ค.', created_at: '2026-06-12T14:00:00.000Z' },
|
|
262
|
+
{ id: 'ac3', type: 'application_status_changed', entity_type: 'application', entity_id: 'a4', summary: '๋ค์ด๋ฒํ์ด โ ์๋ฅ ํฉ๊ฒฉ์ผ๋ก ์ํ๋ฅผ ๋ณ๊ฒฝํ์ต๋๋ค.', created_at: '2026-06-12T10:00:00.000Z' },
|
|
263
|
+
{ id: 'ac4', type: 'cover_letter_version_saved', entity_type: 'cover_letter', entity_id: 'c1', summary: 'ํ ์คํ์ด๋จผ์ธ ์ง์๋๊ธฐ v2๋ฅผ ์ ์ฅํ์ต๋๋ค.', created_at: '2026-06-08T11:00:00.000Z' },
|
|
264
|
+
{ id: 'ac5', type: 'fit_analysis_saved', entity_type: 'fit_analysis', entity_id: 'f1', summary: 'ํ ์คํ์ด๋จผ์ธ ์ ํฉ๋ ๋ถ์(88์ )์ ์ ์ฅํ์ต๋๋ค.', created_at: '2026-06-02T09:30:00.000Z' },
|
|
265
|
+
{ id: 'ac6', type: 'job_saved', entity_type: 'job', entity_id: 'j6', summary: '์นด์นด์ค๋ฑ
ํฌ ๊ณต๊ณ ๋ฅผ ์ ์ฅํ์ต๋๋ค.', created_at: '2026-06-10T09:00:00.000Z' },
|
|
266
|
+
{ id: 'ac7', type: 'resume_added', entity_type: 'document', entity_id: 'd1', summary: '๊นํ๋ ์ด๋ ฅ์(2026)๋ฅผ ์ถ๊ฐํ์ต๋๋ค.', created_at: '2026-05-03T10:00:00.000Z' },
|
|
267
|
+
],
|
|
268
|
+
};
|
|
269
|
+
}
|
package/apps/web/public/app.js
CHANGED
|
@@ -19,6 +19,7 @@ const view = document.getElementById('view');
|
|
|
19
19
|
const navEl = document.getElementById('nav');
|
|
20
20
|
const titleEl = document.getElementById('topbar-title');
|
|
21
21
|
const actionsEl = document.getElementById('topbar-actions');
|
|
22
|
+
const routeStatusEl = document.getElementById('route-status');
|
|
22
23
|
const moduleCache = new Map();
|
|
23
24
|
|
|
24
25
|
function parseHash() {
|
|
@@ -87,23 +88,54 @@ async function route() {
|
|
|
87
88
|
if (token !== renderToken) return; // a newer navigation superseded this one
|
|
88
89
|
clear(view);
|
|
89
90
|
await mod.render(ctx);
|
|
91
|
+
// Announce just the new page name to screen readers (titleEl reflects any
|
|
92
|
+
// detail-page ctx.setTitle override).
|
|
93
|
+
if (routeStatusEl) routeStatusEl.textContent = titleEl.textContent || def.label;
|
|
90
94
|
} catch (err) {
|
|
91
95
|
if (token !== renderToken) return;
|
|
92
96
|
clear(view);
|
|
93
97
|
view.append(el('div', { class: 'card' }, el('div', { class: 'card__body' },
|
|
94
98
|
el('h3', { style: { marginBottom: '8px' } }, 'ํ์ด์ง๋ฅผ ๋ถ๋ฌ์ค์ง ๋ชปํ์ต๋๋ค'),
|
|
95
|
-
el('p', { class: 'text-secondary' }, err instanceof Error ? err.message : String(err))
|
|
99
|
+
el('p', { class: 'text-secondary', style: { marginBottom: '14px' } }, err instanceof Error ? err.message : String(err)),
|
|
100
|
+
el('button', { class: 'btn btn--primary', type: 'button', onClick: () => route() }, '๋ค์ ์๋'))));
|
|
96
101
|
toastError(err);
|
|
97
102
|
}
|
|
98
103
|
}
|
|
99
104
|
|
|
105
|
+
// Mobile/narrow-window nav: the sidebar is the only navigation, so below 900px it
|
|
106
|
+
// becomes an off-canvas drawer toggled from the topbar. Without this a phone/narrow
|
|
107
|
+
// window is stranded on whatever page loaded first.
|
|
108
|
+
function setupMobileNav() {
|
|
109
|
+
const toggle = document.getElementById('nav-toggle');
|
|
110
|
+
const scrim = document.getElementById('nav-scrim');
|
|
111
|
+
const app = document.querySelector('.app');
|
|
112
|
+
if (!toggle || !app) return;
|
|
113
|
+
const setOpen = (open) => {
|
|
114
|
+
app.classList.toggle('nav-open', open);
|
|
115
|
+
toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
116
|
+
toggle.setAttribute('aria-label', open ? '๋ฉ๋ด ๋ซ๊ธฐ' : '๋ฉ๋ด ์ด๊ธฐ');
|
|
117
|
+
};
|
|
118
|
+
toggle.addEventListener('click', () => setOpen(!app.classList.contains('nav-open')));
|
|
119
|
+
scrim?.addEventListener('click', () => setOpen(false));
|
|
120
|
+
navEl.addEventListener('click', (e) => { if (e.target.closest('.nav__item')) setOpen(false); });
|
|
121
|
+
document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && app.classList.contains('nav-open')) setOpen(false); });
|
|
122
|
+
}
|
|
123
|
+
|
|
100
124
|
function initTheme() {
|
|
101
|
-
|
|
125
|
+
// Read new key, falling back to the legacy 'cf-theme' so existing users keep their choice.
|
|
126
|
+
const saved = localStorage.getItem('careermate-theme') || localStorage.getItem('cf-theme');
|
|
102
127
|
if (saved === 'light' || saved === 'dark') document.documentElement.dataset.theme = saved;
|
|
103
128
|
}
|
|
104
129
|
|
|
105
130
|
async function boot() {
|
|
106
131
|
initTheme();
|
|
132
|
+
setupMobileNav();
|
|
133
|
+
// Skip link: jump keyboard focus past the sidebar to the page content. A hash
|
|
134
|
+
// anchor would collide with the router, so move focus directly instead.
|
|
135
|
+
document.getElementById('skip-link')?.addEventListener('click', () => {
|
|
136
|
+
view.setAttribute('tabindex', '-1');
|
|
137
|
+
view.focus();
|
|
138
|
+
});
|
|
107
139
|
// Show data location in the footer (privacy: user can always see where data lives).
|
|
108
140
|
try {
|
|
109
141
|
const h = await get('/api/health');
|
|
Binary file
|
|
@@ -5,13 +5,18 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
6
|
<title>CareerMate โ ๋ด ์ปค๋ฆฌ์ด ํ๋ฆ ๊ด๋ฆฌ</title>
|
|
7
7
|
<meta name="description" content="ChatGPT/Claude์ ํจ๊ป ์ฐ๋ ๋ก์ปฌ ์ปค๋ฆฌ์ด ๊ด๋ฆฌ ๋๊ตฌ" />
|
|
8
|
-
<
|
|
8
|
+
<meta name="theme-color" content="#faf8f4" media="(prefers-color-scheme: light)" />
|
|
9
|
+
<meta name="theme-color" content="#14130f" media="(prefers-color-scheme: dark)" />
|
|
10
|
+
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><rect width='24' height='24' rx='6' fill='%230f7256'/><text x='12' y='17' font-size='14' text-anchor='middle' fill='white' font-family='sans-serif' font-weight='bold'>C</text></svg>" />
|
|
11
|
+
<link rel="apple-touch-icon" href="/icon-180.png" />
|
|
9
12
|
<link rel="preload" href="/fonts/PretendardVariable.woff2" as="font" type="font/woff2" crossorigin />
|
|
10
13
|
<link rel="stylesheet" href="/styles.css" />
|
|
11
14
|
</head>
|
|
12
15
|
<body>
|
|
16
|
+
<button class="skip-link" id="skip-link" type="button">๋ณธ๋ฌธ์ผ๋ก ๊ฑด๋๋ฐ๊ธฐ</button>
|
|
13
17
|
<div class="app">
|
|
14
|
-
<
|
|
18
|
+
<div class="nav-scrim" id="nav-scrim"></div>
|
|
19
|
+
<aside class="sidebar" id="sidebar">
|
|
15
20
|
<div class="sidebar__brand">
|
|
16
21
|
<div class="sidebar__logo">C</div>
|
|
17
22
|
<div>
|
|
@@ -28,12 +33,18 @@
|
|
|
28
33
|
|
|
29
34
|
<div class="main">
|
|
30
35
|
<header class="topbar">
|
|
36
|
+
<button class="nav-toggle" id="nav-toggle" type="button" aria-label="๋ฉ๋ด ์ด๊ธฐ" aria-expanded="false" aria-controls="sidebar">
|
|
37
|
+
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M3 6h18M3 12h18M3 18h18"/></svg>
|
|
38
|
+
</button>
|
|
31
39
|
<div class="topbar__title" id="topbar-title">CareerMate</div>
|
|
32
40
|
<div class="topbar__spacer"></div>
|
|
33
41
|
<div id="topbar-actions" class="flex gap-2"></div>
|
|
34
42
|
</header>
|
|
35
|
-
<main id="view" class="view"
|
|
43
|
+
<main id="view" class="view"></main>
|
|
36
44
|
</div>
|
|
45
|
+
<!-- Concise route announcer: speaks only the new page name, not the whole view
|
|
46
|
+
(the old aria-live on #view re-read the entire page on every navigation). -->
|
|
47
|
+
<div id="route-status" class="sr-only" role="status" aria-live="polite"></div>
|
|
37
48
|
</div>
|
|
38
49
|
|
|
39
50
|
<script type="module" src="/app.js"></script>
|