@makitt.io/mds-mcp-server 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +142 -41
  2. package/dist/catalog.d.ts +16 -0
  3. package/dist/catalog.d.ts.map +1 -0
  4. package/dist/catalog.js +383 -0
  5. package/dist/catalog.js.map +1 -0
  6. package/dist/data/catalog.json +42535 -5019
  7. package/dist/data/playbook/ai-fill.md +62 -49
  8. package/dist/data/playbook/anti-patterns.md +112 -110
  9. package/dist/data/playbook/array-input.md +95 -50
  10. package/dist/data/playbook/async-states.md +71 -61
  11. package/dist/data/playbook/data-grid.md +177 -80
  12. package/dist/data/playbook/feedback.md +107 -88
  13. package/dist/data/playbook/form.md +164 -134
  14. package/dist/data/playbook/overlay.md +98 -89
  15. package/dist/data/playbook/page-layout.md +96 -77
  16. package/dist/data/playbook/responsive-tokens.md +78 -59
  17. package/dist/data/recipes/admin-list-page.md +86 -0
  18. package/dist/data/recipes/async-state-section.md +60 -0
  19. package/dist/data/recipes/dashboard-overview.md +65 -0
  20. package/dist/data/recipes/detail-drawer.md +69 -0
  21. package/dist/data/recipes/modal-form.md +67 -0
  22. package/dist/data/recipes/settings-form-page.md +79 -0
  23. package/dist/index.d.ts +4 -23
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +25 -339
  26. package/dist/index.js.map +1 -1
  27. package/dist/loaders.d.ts +8 -0
  28. package/dist/loaders.d.ts.map +1 -0
  29. package/dist/loaders.js +120 -0
  30. package/dist/loaders.js.map +1 -0
  31. package/dist/recipes.d.ts +13 -0
  32. package/dist/recipes.d.ts.map +1 -0
  33. package/dist/recipes.js +82 -0
  34. package/dist/recipes.js.map +1 -0
  35. package/dist/responses.d.ts +8 -0
  36. package/dist/responses.d.ts.map +1 -0
  37. package/dist/responses.js +25 -0
  38. package/dist/responses.js.map +1 -0
  39. package/dist/text.d.ts +4 -0
  40. package/dist/text.d.ts.map +1 -0
  41. package/dist/text.js +20 -0
  42. package/dist/text.js.map +1 -0
  43. package/dist/tool-definitions.d.ts +3 -0
  44. package/dist/tool-definitions.d.ts.map +1 -0
  45. package/dist/tool-definitions.js +199 -0
  46. package/dist/tool-definitions.js.map +1 -0
  47. package/dist/tools.d.ts +4 -0
  48. package/dist/tools.d.ts.map +1 -0
  49. package/dist/tools.js +233 -0
  50. package/dist/tools.js.map +1 -0
  51. package/dist/types.d.ts +107 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/dist/types.js +10 -0
  54. package/dist/types.js.map +1 -0
  55. package/package.json +20 -16
@@ -1,23 +1,23 @@
1
1
  # MDS Playbook — DataGrid + Table
2
2
 
3
- list / table 데이터 표시 약속.
3
+ list / table 데이터 표시에 대한 약속.
4
4
 
5
- > mds 의 list 컴포넌트 = **DataGrid** (full-feature) + **Table** (custom column).
6
- > 99% list 페이지 = DataGrid. Table 은 특수 case.
5
+ > mds 의 list 컴포넌트 = **DataGrid** (full-feature) + **Table** (custom
6
+ > column). 99% list 페이지 = DataGrid. Table 은 특수 case.
7
7
 
8
8
  ---
9
9
 
10
10
  ## 1. DataGrid vs Table 선택
11
11
 
12
- | 케이스 | 답 | 이유 |
13
- |---|---|---|
14
- | 셀러 admin 의 list 페이지 (customers / orders / products) | **DataGrid** | filter / search / sort / pagination / selection / bulk action / loading / empty / error 자동 |
15
- | URL state 동기화 필요 (deep link) | **DataGrid** | controlled props (page / sort / filter / search) 모두 노출 |
16
- | Server-side filter/sort | **DataGrid** `mode="server"` | totalItems / onPageChange / onSortChange caller 처리 |
17
- | 단순 정보 표시 (정적 list, 보통 5-10 row) | **Table** | DataGrid 의 toolbar 과잉 |
18
- | 페이지의 한 섹션 안 작은 list (예: 고객의 최근 주문 3개) | **Table** | 페이지의 다른 컨텍스트와 통합 |
19
- | 매우 custom layout (column 별 다른 component) | **Table** + caller column render |
20
- | Tree / nested rows | **Tree** (compounds) — Table 아님 |
12
+ | 케이스 | 답 | 이유 |
13
+ | --------------------------------------------------------- | --------------------------------- | -------------------------------------------------------------------------------------------- |
14
+ | 셀러 admin 의 list 페이지 (customers / orders / products) | **DataGrid** | filter / search / sort / pagination / selection / bulk action / loading / empty / error 자동 |
15
+ | URL state 동기화 필요 (deep link) | **DataGrid** | controlled props (page / sort / filter / search) 모두 노출 |
16
+ | Server-side filter/sort | **DataGrid** `mode="server"` | totalItems / onPageChange / onSortChange caller 처리 |
17
+ | 단순 정보 표시 (정적 list, 보통 5-10 row) | **Table** | DataGrid 의 toolbar 과잉 |
18
+ | 페이지의 한 섹션 안 작은 list (예: 고객의 최근 주문 3개) | **Table** | 페이지의 다른 컨텍스트와 통합 |
19
+ | 매우 custom layout (column 별 다른 component) | **Table** + caller column render |
20
+ | Tree / nested rows | **Tree** (compounds) — Table 아님 |
21
21
 
22
22
  > **Default = DataGrid**. Table 은 의식적 결정.
23
23
 
@@ -34,7 +34,12 @@ list / table 데이터 표시 의 약속.
34
34
  title="주문"
35
35
  filters={[
36
36
  { value: 'all', label: '전체', count: 248, predicate: () => true },
37
- { value: 'pending', label: '결제 대기', count: 12, predicate: (o) => o.status === 'pending' },
37
+ {
38
+ value: 'pending',
39
+ label: '결제 대기',
40
+ count: 12,
41
+ predicate: (o) => o.status === 'pending',
42
+ },
38
43
  ]}
39
44
  defaultFilter="all"
40
45
  searchableKeys={['id', 'customer']}
@@ -52,7 +57,7 @@ list / table 데이터 표시 의 약속.
52
57
  onRowClick={(o) => navigate(`/orders/${o.id}`)}
53
58
  density="default"
54
59
  stickyHeader
55
- storageKey="orders-grid" // localStorage column widths / hidden
60
+ storageKey="orders-grid" // localStorage column widths / hidden
56
61
  />
57
62
  ```
58
63
 
@@ -69,104 +74,195 @@ const columns: ColumnDef<Order>[] = [
69
74
 
70
75
  ### Column 패턴 (셀러 admin 표준)
71
76
 
72
- | Column 종류 | 컴포넌트 | 예 |
73
- |---|---|---|
74
- | ID / 번호 | `Code size="xs"` | `#HE-2719` |
75
- | 사람 (고객 / 사용자) | `PersonCell` | avatar + name + sub |
76
- | 상태 | `Pill tone={...}` | success / warning / danger / info |
77
- | 금액 | tabular-nums + right-align | `₩123,456` |
78
- | 날짜 | `relativeDate` 또는 `formatDate` | `3일 전` / `2026-05-01` |
79
- | 액션 | `IconButton` / `Menu` | 행 끝 |
80
- | 진행률 | `ProgressRow` | bar + pct |
81
- | 추세 | `Sparkline` | mini chart |
77
+ | Column 종류 | 컴포넌트 | 예 |
78
+ | -------------------- | -------------------------------- | --------------------------------- |
79
+ | ID / 번호 | `Code size="xs"` | `#HE-2719` |
80
+ | 사람 (고객 / 사용자) | `PersonCell` | avatar + name + sub |
81
+ | 상태 | `Pill tone={...}` | success / warning / danger / info |
82
+ | 금액 | tabular-nums + right-align | `₩123,456` |
83
+ | 날짜 | `relativeDate` 또는 `formatDate` | `3일 전` / `2026-05-01` |
84
+ | 액션 | `IconButton` / `Menu` | 행 끝 |
85
+ | 진행률 | `ProgressRow` | bar + pct |
86
+ | 추세 | `Sparkline` | mini chart |
87
+
88
+ ### Column key 명명 표준 (필수)
89
+
90
+ | 표준 key | 의도 | 비고 |
91
+ | ------------------------- | ------------------------------- | ----------------------------------------------------------------------- |
92
+ | `id` | entity primary id | snake_case 금지 (`created_at` ❌ → `createdAt`) |
93
+ | `name` / `title` | entity 의 식별용 이름 / 제목 | 도메인 별 alias (`orderNumber` / `productName`) 는 의도가 명확하면 허용 |
94
+ | `customer` | actor (PersonCell) | — |
95
+ | `status` | Pill tone enum | — |
96
+ | `amount` | 금액 (right-align mono) | `total` 같은 alias 허용 단 의도 일관성 우선 |
97
+ | `createdAt` / `updatedAt` | 날짜 (camelCase 필수) | `created_at` 같은 snake_case 금지 |
98
+ | `actions` | row actions (IconButton / Menu) | 모든 list 의 마지막 column 으로 고정 |
99
+
100
+ → **camelCase 필수**. snake_case (`created_at`) / mixed naming 금지.
101
+
102
+ ### Column 순서 표준
103
+
104
+ `[entity-id → entity-info → actor → status → amount → metadata → actions]`
105
+
106
+ ```ts
107
+ // 표준 순서 예 (order list)
108
+ const columns = [
109
+ { key: 'id', header: '주문 번호' }, // 1. entity-id
110
+ { key: 'product', header: '상품' }, // 2. entity-info
111
+ { key: 'customer', header: '고객' }, // 3. actor
112
+ { key: 'status', header: '상태' }, // 4. status
113
+ { key: 'amount', header: '금액', align: 'right' }, // 5. amount
114
+ { key: 'createdAt', header: '주문일' }, // 6. metadata
115
+ { key: 'actions', header: '', align: 'right' }, // 7. actions (마지막)
116
+ ];
117
+ ```
118
+
119
+ > 일부 도메인 (예: blog) 은 amount 가 없을 수 있음 → metadata 직전 으로 의도된
120
+ > 생략 OK. 단 — `id → ... → actions` 의 **앞 / 뒤 anchor** 는 모든 list 에서
121
+ > 동일.
122
+
123
+ ### Actions column 활용
124
+
125
+ ```tsx
126
+ {
127
+ key: 'actions',
128
+ header: '',
129
+ align: 'right',
130
+ width: '60px',
131
+ render: (row) => (
132
+ <Menu.Root>
133
+ <Menu.Trigger><IconButton aria-label="더보기" variant="ghost"><MoreHorizontal size={14} /></IconButton></Menu.Trigger>
134
+ <Menu.Content>
135
+ <Menu.Item onClick={() => edit(row.id)}>편집</Menu.Item>
136
+ <Menu.Item onClick={() => duplicate(row.id)}>복제</Menu.Item>
137
+ <Menu.Separator />
138
+ <Menu.Item onClick={() => remove(row.id)} variant="danger">삭제</Menu.Item>
139
+ </Menu.Content>
140
+ </Menu.Root>
141
+ ),
142
+ }
143
+ ```
144
+
145
+ - **모든 list 의 마지막 column 은 actions** (강제)
146
+ - Menu 활용 — 2 개 이상 action 이면 Menu 안에 단일 IconButton trigger
147
+ - Single action — 직접 IconButton (예: preview / open)
148
+ - destructive action — `Menu.Item variant="danger"` + Menu.Separator 로 분리
82
149
 
83
150
  ---
84
151
 
85
- ## 3. Mobile 변형
152
+ ## 3. Mobile 변형 (Responsive 표준)
153
+
154
+ | Desktop (≥ md) | Mobile (< md) |
155
+ | ----------------------------------------- | ---------------------------------------------------------- |
156
+ | DataGrid table 형 | **Card list** (각 row → card, primary column 1-2개만 표시) |
157
+ | Sticky header | `position: sticky` 그대로 |
158
+ | Toolbar (filter pills + search + actions) | toolbar collapse — filter drawer / search expand |
159
+ | Pagination (page numbers) | infinite scroll 또는 numeric only |
160
+ | selection (checkbox column) | hidden — long-press 또는 명시 toggle |
161
+ | actions column (Menu) | swipe-actions 또는 row-bottom IconButton |
162
+
163
+ ### Mobile 변환 mechanism
164
+
165
+ ```tsx
166
+ <DataGrid
167
+ data={rows}
168
+ columns={columns}
169
+ // Mobile = card 형식 으로 자동 변환
170
+ mobileView={{
171
+ title: (row) => row.name, // card primary
172
+ subtitle: (row) => row.email, // card secondary
173
+ statusKey: 'status', // status badge 표시 column
174
+ actionsKey: 'actions', // 우측 swipe actions
175
+ }}
176
+ />
177
+ ```
86
178
 
87
- | Desktop | Mobile (< md) |
88
- |---|---|
89
- | DataGrid table | **Card list** (각 row card, primary column 1-2개만 표시) |
90
- | Sticky header | `position: sticky` 그대로 (모바일도 동작) |
91
- | Toolbar (filter pills + search + actions) | toolbar collapse filter drawer / search expand |
92
- | Pagination (page numbers) | infinite scroll 또는 numeric only |
93
- | selection (checkbox column) | 일반적으로 숨김 — long-press 로 multi-select 도 가능 (TBD) |
179
+ - **Default**: Tailwind preset 의 token responsive (text-3xl / space-\* 등
180
+ mobile fallback 자동 — responsive-tokens.md)
181
+ - **DataGrid mobile = card list 자동 변환** `mobileView` prop 지정하면
182
+ caller 별도 layout 작성 없이 mobile card 표시 가능
183
+ - **Breakpoint = md (768px)**`useIsBreakpointUp('md')` 내부 활용
94
184
 
95
- > Mobile 변환 mechanism — DataGrid 의 `mobileView` prop 또는 자동 (`useIsBreakpointUp('md')`).
96
- > 현재 mds 의 DataGrid = desktop only. Mobile 자동 변환 = **TBD** (Step 11 builder / web 마이그레이션 시).
185
+ > 현재 상태 — DataGrid 의 `mobileView` prop **TBD: mds 의 DataGrid 에 추가
186
+ > 필요** (지금은 desktop only). 임시로는 caller `useBreakpoint()` + 별도
187
+ > CardList 직접 구현.
97
188
 
98
189
  ---
99
190
 
100
191
  ## 4. Loading / Error / Empty state — async-states.md §1 참조
101
192
 
102
- | state | 컴포넌트 |
103
- |---|---|
104
- | loading (초기 fetch) | `<SkeletonRows>` (DataGrid 자동) |
105
- | loading 더 보기 (page 2) | 부분 skeleton + 기존 row 유지 |
106
- | error | `<ErrorState error={err} onRetry={refetch}>` (DataGrid `errorState` prop) |
107
- | empty (필터 결과 0) | `<EmptyState variant="search" action={resetFilters}>` |
108
- | empty (한 번도 없음) | `<EmptyState variant="onboarding" action={createX}>` |
193
+ | state | 컴포넌트 |
194
+ | ------------------------ | ------------------------------------------------------------------------- |
195
+ | loading (초기 fetch) | `<SkeletonRows>` (DataGrid 자동) |
196
+ | loading 더 보기 (page 2) | 부분 skeleton + 기존 row 유지 |
197
+ | error | `<ErrorState error={err} onRetry={refetch}>` (DataGrid `errorState` prop) |
198
+ | empty (필터 결과 0) | `<EmptyState variant="search" action={resetFilters}>` |
199
+ | empty (한 번도 없음) | `<EmptyState variant="onboarding" action={createX}>` |
109
200
 
110
201
  ---
111
202
 
112
203
  ## 5. 결정 표 (lookup)
113
204
 
114
- | 케이스 | 답 |
115
- |---|---|
116
- | "page list 표시" | DataGrid |
117
- | "5개 정도 단순 table" | Table |
118
- | "tree / nested" | Tree (compounds) |
119
- | "row click → 상세" | DataGrid `onRowClick={navigate(...)}` |
120
- | "row click → 옆 편집 (목록 유지)" | DataGrid `onRowClick={() => openDrawer(...)}` |
121
- | "URL filter / page 동기화" | DataGrid controlled props (`page`, `onPageChange` etc.) |
122
- | "Server-side" | DataGrid `mode="server" totalItems={N}` |
123
- | "bulk action" | DataGrid `selectable bulkActions={(selected) => ...}` |
124
- | "column resize / hide / reorder" | DataGrid `storageKey` + 자동 |
125
- | "column custom component" | `column.render` prop |
126
- | "특정 column 만 sortable" | `column.sortable: true` |
127
- | "1 필드 inline 편집" | DataGrid column.render = controlled input + form.md §5 (Inline 편집 — Enter 명시 저장) |
205
+ | 케이스 | 답 |
206
+ | --------------------------------- | -------------------------------------------------------------------------------------- |
207
+ | "page list 표시" | DataGrid |
208
+ | "5개 정도 단순 table" | Table |
209
+ | "tree / nested" | Tree (compounds) |
210
+ | "row click → 상세" | DataGrid `onRowClick={navigate(...)}` |
211
+ | "row click → 옆 편집 (목록 유지)" | DataGrid `onRowClick={() => openDrawer(...)}` |
212
+ | "URL filter / page 동기화" | DataGrid controlled props (`page`, `onPageChange` etc.) |
213
+ | "Server-side" | DataGrid `mode="server" totalItems={N}` |
214
+ | "bulk action" | DataGrid `selectable bulkActions={(selected) => ...}` |
215
+ | "column resize / hide / reorder" | DataGrid `storageKey` + 자동 |
216
+ | "column custom component" | `column.render` prop |
217
+ | "특정 column 만 sortable" | `column.sortable: true` |
218
+ | "1 필드 inline 편집" | DataGrid column.render = controlled input + form.md §5 (Inline 편집 — Enter 명시 저장) |
128
219
 
129
220
  ---
130
221
 
131
222
  ## 6. 안티 패턴
132
223
 
133
- - ❌ **DataGrid 안에 form (모든 row 의 input)** — 큰 form 은 별도 페이지 (page-form). DataGrid 는 list / inline 편집 1 필드만
134
- - ❌ **Table 으로 DataGrid 흉내** toolbar / filter / pagination 다 caller 구현 = 중복. DataGrid 사용
224
+ - ❌ **DataGrid 안에 form (모든 row 의 input)** — 큰 form 은 별도 페이지
225
+ (page-form). DataGrid list / inline 편집 1 필드만
226
+ - ❌ **Table 으로 DataGrid 흉내** — toolbar / filter / pagination 다 caller 구현
227
+ = 중복. DataGrid 사용
135
228
  - ❌ **DataGrid 의 column 50+** — 사용자 스캔 불가. 일부 hidden + caller 가 선택
136
- - ❌ **Loading 시 empty state 표시** — async-states.md §2 — 로딩 중 ErrorState/EmptyState 금지
137
- - ❌ **row 클릭 + checkbox 동시 작동** — 한쪽만. selection 모드 시 row click 막힘 또는 다른 의미
229
+ - ❌ **Loading 시 empty state 표시** — async-states.md §2 — 로딩 중
230
+ ErrorState/EmptyState 금지
231
+ - ❌ **row 클릭 + checkbox 동시 작동** — 한쪽만. selection 모드 시 row click
232
+ 막힘 또는 다른 의미
138
233
  - ❌ **pagination size 가 50+** — render 부담 + a11y. 최대 20-30 권장
139
234
  - ❌ **column header 가 너무 길거나 wrap** — fixed height, ellipsis
140
- - ❌ **selection state 가 page 이동 후 사라짐** — DataGrid 의 selectedIds Set 유지 (cross-page)
235
+ - ❌ **selection state 가 page 이동 후 사라짐** — DataGrid 의 selectedIds Set
236
+ 유지 (cross-page)
141
237
 
142
238
  ---
143
239
 
144
240
  ## 7. Cross-cutting
145
241
 
146
- | Axis | 적용 |
147
- |---|---|
148
- | **Responsive** | DataGrid → card list mobile (TBD 자동 변환) |
149
- | **A11y** | `<table role="table">` 자동 / column header `<th scope="col">` / sortable button aria-sort / selection checkbox aria-label |
150
- | **i18n** | column label / filter label / empty message 모두 `t()` |
151
- | **AI fill** | DataGrid 의 filter 가 AI 자동 제안 가능 (Step 4.8) |
152
- | **Catalog** | DataGrid props (columns / filters / mode / state props) 자동 catalog (Step 5) |
153
- | **Telemetry** | row click / sort / filter / search / bulk action 자동 log (Step 7) |
242
+ | Axis | 적용 |
243
+ | -------------- | -------------------------------------------------------------------------------------------------------------------------- |
244
+ | **Responsive** | DataGrid → card list mobile (TBD 자동 변환) |
245
+ | **A11y** | `<table role="table">` 자동 / column header `<th scope="col">` / sortable button aria-sort / selection checkbox aria-label |
246
+ | **i18n** | column label / filter label / empty message 모두 `t()` |
247
+ | **AI fill** | DataGrid 의 filter 가 AI 자동 제안 가능 (Step 4.8) |
248
+ | **Catalog** | DataGrid props (columns / filters / mode / state props) 자동 catalog (Step 5) |
249
+ | **Telemetry** | row click / sort / filter / search / bulk action 자동 log (Step 7) |
154
250
 
155
251
  ---
156
252
 
157
253
  ## 8. apps/web 의 실 사용 (Step 7 Web Playbook 의 baseline)
158
254
 
159
- | Page | DataGrid 사용 |
160
- |---|---|
161
- | `/merchant/customers` | DataGrid (filter / search / row click → drawer / bulk action) |
162
- | `/merchant/orders` | DataGrid (filter / search / row click → detail page / status update bulk) |
163
- | `/merchant/payment/transactions` | DataGrid (server mode + URL state) |
164
- | `/merchant/payment/refunds` | 동일 |
165
- | `/merchant/content/blogs` (list) | DataGrid |
166
- | `/merchant/content/announcements` | DataGrid |
167
- | `/merchant/content/banners` | DataGrid |
168
- | `/admin/dead-letters` | DataGrid (admin) |
169
- | `/admin/exchange-rates` | DataGrid (admin) |
255
+ | Page | DataGrid 사용 |
256
+ | --------------------------------- | ------------------------------------------------------------------------- |
257
+ | `/merchant/customers` | DataGrid (filter / search / row click → drawer / bulk action) |
258
+ | `/merchant/orders` | DataGrid (filter / search / row click → detail page / status update bulk) |
259
+ | `/merchant/payment/transactions` | DataGrid (server mode + URL state) |
260
+ | `/merchant/payment/refunds` | 동일 |
261
+ | `/merchant/content/blogs` (list) | DataGrid |
262
+ | `/merchant/content/announcements` | DataGrid |
263
+ | `/merchant/content/banners` | DataGrid |
264
+ | `/admin/dead-letters` | DataGrid (admin) |
265
+ | `/admin/exchange-rates` | DataGrid (admin) |
170
266
 
171
267
  → 20+ 페이지가 DataGrid 사용. 균일성 보장 = Web Playbook (Step 7) 의 표준.
172
268
 
@@ -176,7 +272,8 @@ const columns: ColumnDef<Order>[] = [
176
272
 
177
273
  1. **Mobile 자동 변환** — DataGrid → card list 의 자동 변환 컴포넌트 (CardList?)
178
274
  2. **Long-press multi-select** — 모바일 의 selection 패턴
179
- 3. **Inline 편집 컴포넌트** — DataGrid cell 의 EditCell wrapper 추가 (Enter / 체크 명시 저장)
275
+ 3. **Inline 편집 컴포넌트** — DataGrid cell 의 EditCell wrapper 추가 (Enter /
276
+ 체크 명시 저장)
180
277
  4. **Sticky column** — first / last column 의 sticky (가로 scroll 시)
181
278
  5. **Virtual scroll** — row 1000+ 시 virtualization (현재 mds 미지원)
182
279
  6. **Group by** — row grouping (예: status 별 group)