@t3q-ui/design-system 0.0.0-stage โ†’ 1.56.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.
package/package.json CHANGED
@@ -1,6 +1,214 @@
1
1
  {
2
2
  "name": "@t3q-ui/design-system",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.56.0",
4
+ "description": "T3Q Design System - React Components",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "typesVersions": {
10
+ "*": {
11
+ "patterns": [
12
+ "./dist/patterns/index.d.ts"
13
+ ]
14
+ }
15
+ },
16
+ "exports": {
17
+ ".": {
18
+ "import": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./dist/index.js"
21
+ },
22
+ "require": {
23
+ "types": "./dist/index.d.cts",
24
+ "default": "./dist/index.cjs"
25
+ }
26
+ },
27
+ "./patterns": {
28
+ "import": {
29
+ "types": "./dist/patterns/index.d.ts",
30
+ "default": "./dist/patterns/index.js"
31
+ },
32
+ "require": {
33
+ "types": "./dist/patterns/index.d.cts",
34
+ "default": "./dist/patterns/index.cjs"
35
+ }
36
+ },
37
+ "./styles.css": "./dist/styles.css",
38
+ "./fonts.css": "./dist/fonts.css"
39
+ },
40
+ "sideEffects": [
41
+ "*.css"
42
+ ],
43
+ "bin": {
44
+ "t3q-design": "cli/t3q-design.mjs"
45
+ },
46
+ "files": [
47
+ "dist",
48
+ "cli",
49
+ "skills",
50
+ "CHANGELOG.md",
51
+ "!cli/*.test.mjs"
52
+ ],
53
+ "scripts": {
54
+ "build": "tsup && node scripts/fix-dts.mjs && npm run build:css",
55
+ "check": "pnpm lint && pnpm typecheck && pnpm build",
56
+ "build:css": "cp src/styles/fonts.css dist/fonts.css && echo '@source \"./**/*.js\";' > dist/styles.css && cat src/styles/tokens.css >> dist/styles.css && cat src/styles/utilities.css >> dist/styles.css && cat src/components/agGridTable/style.css >> dist/styles.css && cat src/components/parameterTable/parameterTable.css >> dist/styles.css",
57
+ "build:dev": "vite build --config vite.config.dev.ts",
58
+ "dev": "vite --config vite.config.dev.ts",
59
+ "dev:watch": "tsup --watch",
60
+ "lint": "eslint src/",
61
+ "test": "vitest run --project unit",
62
+ "test:audit": "vitest run --project audit",
63
+ "test:cli": "vitest run --project cli",
64
+ "test:eval": "vitest run --project eval",
65
+ "eval:judge": "node scripts/eval/judge.mjs",
66
+ "test:a11y": "node scripts/audit/tds-a11y.mjs --ci --md docs/audits/tds-a11y.md --json docs/audits/tds-a11y.json",
67
+ "test:keyboard": "node scripts/audit/tds-keyboard.mjs --ci --md docs/audits/tds-a11y-keyboard.md",
68
+ "typecheck": "tsc --noEmit && tsc -p tsconfig.examples.json",
69
+ "prepublishOnly": "npm run build && npm run build:css",
70
+ "prepare": "husky && npm run build",
71
+ "storybook": "storybook dev -p 6006",
72
+ "build-storybook": "storybook build && node scripts/mcp/build-skill-reference.mjs",
73
+ "cz": "cz",
74
+ "semantic-release": "semantic-release",
75
+ "audit:tokens": "node scripts/audit/audit-tokens.mjs",
76
+ "audit:mcp": "node scripts/audit/mcp-docs-check.mjs",
77
+ "mcp:serve": "node scripts/mcp/serve-static.mjs",
78
+ "audit:storybook": "node scripts/audit/storybook-export-audit.mjs --md docs/audits/storybook-export-audit.md --json docs/audits/storybook-export-audit.json && node scripts/audit/storybook-ai-readiness.mjs --md docs/audits/storybook-ai-readiness.md --json docs/audits/storybook-ai-readiness.json",
79
+ "eval": "node scripts/eval/run.mjs",
80
+ "eval:init": "node scripts/eval/init-sandbox.mjs",
81
+ "eval:html": "node scripts/eval/html-coverage.mjs",
82
+ "eval:errors": "node scripts/eval/run.mjs errors"
83
+ },
84
+ "peerDependencies": {
85
+ "@dnd-kit/core": "^6.3.1",
86
+ "@dnd-kit/sortable": "^10.0.0",
87
+ "@dnd-kit/utilities": "^3.2.2",
88
+ "@radix-ui/react-accordion": "^1.2.11",
89
+ "@radix-ui/react-alert-dialog": "^1.1.15",
90
+ "@radix-ui/react-checkbox": "^1.1.4",
91
+ "@radix-ui/react-dialog": "^1.1.6",
92
+ "@radix-ui/react-dropdown-menu": "^2.1.6",
93
+ "@radix-ui/react-label": "^2.1.2",
94
+ "@radix-ui/react-popover": "^1.1.6",
95
+ "@radix-ui/react-progress": "^1.1.2",
96
+ "@radix-ui/react-radio-group": "^1.2.3",
97
+ "@radix-ui/react-select": "^2.1.6",
98
+ "@radix-ui/react-separator": "^1.1.2",
99
+ "@radix-ui/react-slider": "^1.2.3",
100
+ "@radix-ui/react-slot": "^1.1.2",
101
+ "@radix-ui/react-switch": "^1.1.3",
102
+ "@radix-ui/react-tabs": "^1.1.3",
103
+ "@radix-ui/react-toggle-group": "^1.1.0",
104
+ "@radix-ui/react-tooltip": "^1.1.8",
105
+ "ag-grid-community": "^33.2.3 || ^36.0.0",
106
+ "ag-grid-react": "^33.2.3 || ^36.0.0",
107
+ "react": "^18.0.0",
108
+ "react-dom": "^18.0.0",
109
+ "react-hook-form": "^7.0.0",
110
+ "sonner": "^1.7.4 || ^2",
111
+ "tailwindcss": "^4.0.0"
112
+ },
113
+ "dependencies": {
114
+ "@tanstack/react-virtual": "^3.10.0",
115
+ "class-variance-authority": "^0.7.1",
116
+ "clsx": "^2.1.1",
117
+ "cmdk": "^1.0.0",
118
+ "date-fns": "^3.6.0",
119
+ "es-toolkit": "^1.0.0",
120
+ "lucide-react": "^0.468.0",
121
+ "pretendard": "^1.3.9",
122
+ "react-day-picker": "^8.10.1",
123
+ "react-lottie": "^1.2.10",
124
+ "react-textarea-autosize": "^8.5.3",
125
+ "tailwind-merge": "^2.6.0"
126
+ },
127
+ "devDependencies": {
128
+ "@chromatic-com/storybook": "^5.4.0",
129
+ "@commitlint/cli": "^20.4.1",
130
+ "@commitlint/config-conventional": "^20.4.1",
131
+ "@dnd-kit/core": "^6.3.1",
132
+ "@dnd-kit/sortable": "^10.0.0",
133
+ "@dnd-kit/utilities": "^3.2.2",
134
+ "@eslint/js": "^9.39.1",
135
+ "@radix-ui/react-accordion": "^1.2.11",
136
+ "@radix-ui/react-toggle-group": "^1.1.0",
137
+ "@semantic-release/gitlab": "^13.3.0",
138
+ "@storybook/addon-a11y": "^10.6.1",
139
+ "@storybook/addon-docs": "^10.6.1",
140
+ "@storybook/addon-mcp": "10.6.1",
141
+ "@storybook/addon-onboarding": "^10.6.1",
142
+ "@storybook/addon-vitest": "^10.6.1",
143
+ "@storybook/mcp": "10.6.1",
144
+ "@storybook/nextjs-vite": "^10.6.1",
145
+ "@tailwindcss/postcss": "^4.1.3",
146
+ "@tailwindcss/vite": "^4.1.18",
147
+ "@testing-library/jest-dom": "^6.9.1",
148
+ "@testing-library/react": "^16.3.2",
149
+ "@testing-library/user-event": "^14.6.1",
150
+ "@types/node": "^22.15.21",
151
+ "@types/react": "^18.3.18",
152
+ "@types/react-dom": "^18.3.5",
153
+ "@types/react-lottie": "^1.2.10",
154
+ "@typescript-eslint/eslint-plugin": "^8.48.0",
155
+ "@typescript-eslint/parser": "^8.48.0",
156
+ "@vitejs/plugin-react": "^5.1.4",
157
+ "@vitest/browser-playwright": "^4.0.16",
158
+ "@vitest/coverage-v8": "^4.0.16",
159
+ "ag-grid-community": "^36.2.0",
160
+ "ag-grid-react": "^36.2.0",
161
+ "commitizen": "^4.3.1",
162
+ "cz-conventional-changelog": "^3.3.0",
163
+ "eslint": "^8.57.1",
164
+ "eslint-config-prettier": "^10.1.8",
165
+ "eslint-plugin-jsx-a11y": "^6.10.2",
166
+ "eslint-plugin-prettier": "^5.5.4",
167
+ "eslint-plugin-react": "^7.37.5",
168
+ "eslint-plugin-react-hooks": "^7.0.1",
169
+ "eslint-plugin-simple-import-sort": "^12.1.1",
170
+ "eslint-plugin-storybook": "^10.6.1",
171
+ "globals": "^17.0.0",
172
+ "husky": "^9.1.7",
173
+ "jsdom": "^28.0.0",
174
+ "lint-staged": "^15.5.2",
175
+ "next": "^15.5.6",
176
+ "playwright": "^1.57.0",
177
+ "postcss": "^8.5.3",
178
+ "postcss-cli": "^11.0.0",
179
+ "prettier": "^3.7.3",
180
+ "react-hook-form": "^7.71.1",
181
+ "semantic-release": "^25.0.3",
182
+ "storybook": "^10.6.1",
183
+ "tailwindcss": "^4.1.3",
184
+ "tsup": "^8.3.5",
185
+ "typescript": "^5.7.3",
186
+ "typescript-eslint": "^8.51.0",
187
+ "vite": "^7.3.0",
188
+ "vitest": "^4.0.16"
189
+ },
190
+ "repository": {
191
+ "type": "git",
192
+ "url": "https://github.com/t3q-platform-service/t3q-ui-design-system"
193
+ },
194
+ "keywords": [
195
+ "design-system",
196
+ "react",
197
+ "components",
198
+ "tailwindcss",
199
+ "t3q"
200
+ ],
201
+ "license": "SEE LICENSE IN LICENSE.md",
202
+ "lint-staged": {
203
+ "src/**/*.{ts,tsx}": [
204
+ "eslint --fix",
205
+ "bash -c 'npm run typecheck'"
206
+ ]
207
+ },
208
+ "config": {
209
+ "commitizen": {
210
+ "path": "cz-conventional-changelog"
211
+ }
212
+ },
213
+ "packageManager": "pnpm@10.28.2+sha512.41872f037ad22f7348e3b1debbaf7e867cfd448f2726d9cf74c08f19507c31d2c8e7a11525b983febc2df640b5438dee6023ebb1f84ed43cc2d654d2bc326264"
214
+ }
@@ -0,0 +1,91 @@
1
+ ---
2
+ name: tds
3
+ description: '@t3q-ui/design-system(TDS) ๋กœ ํ™”๋ฉด์ด๋‚˜ UI ๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ ๊ณ ์น  ๋•Œ ์“ด๋‹ค. ํ™”๋ฉด ์œ ํ˜• ๋ถ„๋ฅ˜ โ†’ Pattern ์„ ํƒ โ†’ Storybook MCP ์กฐํšŒ โ†’ ์กฐ๋ฆฝ โ†’ ๊ฒ€์ฆ ์ˆœ์„œ.'
4
+ license: Proprietary. See LICENSE.md in the @t3q-ui/design-system package
5
+ ---
6
+
7
+ # TDS ๋กœ ํ™”๋ฉด ๋งŒ๋“ค๊ธฐ
8
+
9
+ ๊ทœ์น™ 9๊ฐœ๋Š” `AGENTS.md` ์˜ TDS ๋ธ”๋ก์— ์žˆ๋‹ค(ํ•ญ์ƒ ์ ์šฉ). ์ด Skill ์€ ๊ทธ ๊ทœ์น™์„ ์ง€ํ‚ค๋ฉฐ **์ƒˆ ํ™”๋ฉด์„ ๋งŒ๋“œ๋Š” ์ˆœ์„œ**๋‹ค.
10
+
11
+ ## ์ ˆ์ฐจ
12
+
13
+ 1. **ํ™”๋ฉด ์œ ํ˜•์„ ์ •ํ•œ๋‹ค.** ์š”์ฒญ์„ List / Detail / Form / Dashboard ์ค‘ ํ•˜๋‚˜๋กœ ๋ถ„๋ฅ˜ํ•˜๊ณ  ์•„๋ž˜ ํ‘œ๋กœ Pattern ์„ ๊ณ ๋ฅธ๋‹ค.
14
+ 2. **Pattern ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•œ๋‹ค.** `@t3q-ui/design-system/patterns` ์—์„œ import ํ•œ๋‹ค. ํ—ค๋”ยท๋ณธ๋ฌธยท์ƒํƒœ ํ‘œ์‹œ๋Š” Pattern ์ด ๊ฐ€์ง„๋‹ค. ๋งž๋Š” Pattern ์ด ์—†์„ ๋•Œ๋งŒ PageHeader + Component ๋กœ ์กฐ๋ฆฝํ•œ๋‹ค.
15
+ 3. **์กฐํšŒํ•œ๋‹ค.** MCP `docs-list` ๋กœ ID ๋ฅผ ์ฐพ๊ณ , `docs-show <id>` ๋กœ propsยทvariantยท"์–ธ์ œ ์“ฐ๋‚˜" ๋ฅผ ์ฝ๊ณ , ํ•„์š”ํ•˜๋ฉด `docs-show-story` ๋กœ ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ๋ณธ๋‹ค. MCP ๋ฅผ ๋ถ€๋ฅด์ง€ ์•Š๊ฑฐ๋‚˜ ์—†์œผ๋ฉด ์ด Skill ์˜ [reference/components.md](reference/components.md)(๊ฐ™์€ ๋‚ด์šฉ โ€” IDยท์–ธ์ œ ์“ฐ๋‚˜ยทpropsยท์˜ˆ์‹œ ์ฝ”๋“œ, ํŒจํ„ด์ด ๋จผ์ €)๋ฅผ ์ฝ๊ณ , ๊ทธ๊ฒƒ๋„ ์—†์œผ๋ฉด `node_modules/@t3q-ui/design-system/dist/index.d.ts`ยท`dist/patterns/index.d.ts` ๋ฅผ ์ฝ๋Š”๋‹ค. ํƒ€์ž… ์„ ์–ธ์—๋Š” ์˜ˆ์‹œ ์ฝ”๋“œ๊ฐ€ ์—†๋‹ค(2026-10-27 ํ™€๋“œ์•„์›ƒ 13: d.ts ๋งŒ ์ฝ์€ run ์ด MCP ๋ฅผ ๋ถ€๋ฅธ run ๋ณด๋‹ค Patternยทprops ๋ฅผ ๋œ ์ผ๋‹ค).
16
+ 4. **์กฐ๋ฆฝํ•œ๋‹ค.** ๋ฐ์ดํ„ฐ ์กฐํšŒยท์ƒํƒœ ๊ด€๋ฆฌ๋Š” ์•ฑ์ด, ๋ฐฐ์น˜ยท์ƒํƒœ ํ‘œ์‹œ๋Š” Pattern ์ด ๋งก๋Š”๋‹ค. ๋นˆ ์ƒํƒœ(`empty`)ยท๋กœ๋”ฉ(`loading`)ยท์˜ค๋ฅ˜(`error` + `onRetry`)๋ฅผ ๋ฐ˜๋“œ์‹œ ๋„˜๊ธด๋‹ค. ํŽ˜์ด์ง€๋Š” ์•ฑ ๋ ˆ์ด์•„์›ƒ์˜ `<main>` ํ•˜๋‚˜ ์•ˆ์— ๋‘๋˜ **`<main>` ์— paddingยทmax-widthยท๋ฐฐ๊ฒฝ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค**(Pattern ์ด ํ—ค๋” ๋ ์™€ ๋ณธ๋ฌธ ์—ฌ๋ฐฑ 24px ์„ ๊ฐ€์ง„๋‹ค โ€” `<main className='p-8'>` ๋กœ ๊ฐ์‹ธ๋ฉด ํ—ค๋”๊ฐ€ ๊ฐ€์žฅ์ž๋ฆฌ์—์„œ ๋–  ๋ณด์ธ๋‹ค, 2026-10-18 ํ•œ ์ค„ ํŒ). **์š”์ฒญ๋ฌธ์˜ ์š”์†Œยท๋™์ž‘์€ ๋น ์ง์—†์ด**(๊ทœ์น™ 9) โ€” Pattern ์— ์—†๋Š” ๊ฒƒ์€ ์ƒ๋žตํ•˜์ง€ ๋ง๊ณ  ์Šฌ๋กฏ(`filters`ยท`titleRight`ยท`detail`ยท`banner`ยท`footer`ยท`note`ยท`actionsNote`) ์•ˆ์— Component ๋กœ ๋งŒ๋“ ๋‹ค.
17
+ 5. **๊ฒ€์ฆํ•œ๋‹ค.** ํƒ€์ž…๊ฒ€์‚ฌยท๋นŒ๋“œ๋ฅผ ๋Œ๋ฆฐ๋‹ค. ์ง์ ‘ ์“ด `<button>`/`<input>`/`<table>`, raw hex, `red-500` ๊ฐ™์€ ๊ธฐ๋ณธ ํŒ”๋ ˆํŠธ, `bg-[#โ€ฆ]` ๊ฐ™์€ ์ž„์˜๊ฐ’์ด ์—†๋Š”์ง€ ํ›‘๋Š”๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ ์š”์ฒญ๋ฌธ์„ ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋กœ ์‚ผ์•„ ์—ดยทํ•„ํ„ฐยท์ •๋ ฌ ํ‘œ์‹œยท์ƒ์„ธ ํ•ญ๋ชฉยท๋ฒ„ํŠผ๊ณผ ๋น„ํ™œ์„ฑ ์‚ฌ์œ ยทํ™•์ธ ์ฐฝยท๋กœ๋”ฉ/๋นˆ/์˜ค๋ฅ˜ยท์ œ์ถœ ์ค‘ ์ƒํƒœ๋ฅผ ํ•˜๋‚˜์”ฉ ๋Œ€์กฐํ•œ๋‹ค.
18
+
19
+ ## ์˜ˆ์ œ โ€” ๋จผ์ € ์—ด์–ด ๋ณธ๋‹ค
20
+
21
+ - ๋ชฉ๋ก ํ™”๋ฉด: [examples/list-page.tsx](examples/list-page.tsx) โ€” ๊ฒ€์ƒ‰ยทํ•„ํ„ฐ(์ƒํƒœ์ƒ‰ ๊ฑด์ˆ˜ ๋ฑƒ์ง€ ์„ธ๊ทธ๋จผํŠธ) โ†’ ํ‘œ(์ •๋ ฌ ๊ฐ€๋Šฅ ์—ด์€ `sortable: true` ๋กœ ์•„์ด์ฝ˜์ด ๋ณด์ž„, ์ด๋ฆ„ ์•„๋ž˜ ๋ณด์กฐ ์ค„์€ `secondaryField`) โ†’ ํ–‰ ํด๋ฆญ ์ƒ์„ธ ํŒจ๋„(`detail` ์Šฌ๋กฏ, ๋ชฉ๋ก ์˜ค๋ฅธ์ชฝ์— ๋‚˜๋ž€ํžˆ, ๋น„ํ™œ์„ฑ ์‚ฌ์œ ๋Š” `note`) โ†’ ์‚ญ์ œ ํ™•์ธ. TDS ์ €์žฅ์†Œ์—์„œ ํƒ€์ž… ๊ฒ€์‚ฌยท๋ Œ๋” ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•œ ์ฝ”๋“œ๋‹ค. ์ƒˆ ๋ชฉ๋ก ํ™”๋ฉด์€ ์ด ๊ตฌ์กฐ๋ฅผ ๋ณต์‚ฌํ•ด ์‹œ์ž‘ํ•˜๊ณ , ํ•„๋“œยท์ปฌ๋Ÿผ๋งŒ ๊ณผ์ œ์— ๋งž๊ฒŒ ๋ฐ”๊พผ๋‹ค.
22
+ - ์ƒ์„ธ ํ™”๋ฉด: [examples/detail-page.tsx](examples/detail-page.tsx) โ€” ํ—ค๋”(์ƒํƒœยท**๋ฉ”ํƒ€ `meta` ํ•œ ๊ณณ**(`MetaGroup columns={3}` + `MetaItem` โ€” IDยท๋ฒ„์ „ยท์†Œ์œ ์žยท์ˆ˜์ •์ผ ๋“ฑ ํ•ต์‹ฌ ์ •๋ณด, ํƒญ ์œ„์— ํ•ญ์ƒ)ยทํ–‰๋™ ์Šฌ๋กฏ) โ†’ ํƒญ(๊ฑด์ˆ˜ ๋ฑƒ์ง€) โ†’ ๋ณธ๋ฌธ ์ „ํญ โ†’ ์‚ญ์ œ ํ™•์ธ. ๋ฉ”ํƒ€ ์ž๋ฆฌ๋ฅผ ๋‘ ๊ฐœ๋กœ ๋‚˜๋ˆ„์ง€ ์•Š๋Š”๋‹ค(2026-10-30 ์‚ฌ์šฉ์ž ๊ฒฐ์ • โ€” ๋ณ„๋„ ์š”์•ฝ ์ƒ์ž ์—†์Œ). ์˜ค๋ฅธ์ชฝ ํŒจ๋„(`aside`)์€ ์“ฐ์ง€ ์•Š๋Š”๋‹ค(์งง์€ ์˜ค๋ฅธ์ชฝ ํŒจ๋„์€ ์ฒซ ํ™”๋ฉด ์•„๋ž˜๊ฐ€ ๋น„์–ด ํ™€๋“œ์•„์›ƒ 9~12 ์—ฐ์† ๊ฐ์ ). ์ƒ์„ธ ํ™”๋ฉด์— ์•ˆ๋‚ด ํ•œ ์ค„(`actionsNote`)์€ ๋‘์ง€ ์•Š๋Š”๋‹ค(๋ณธ๋ฌธ ์œ„์— ๋–  ๋ณด์—ฌ 4๋ผ์šด๋“œ ์—ฐ์† ๊ฐ์ , 2026-10-18 11์ฐจ) โ€” ๋น„ํ™œ์„ฑ ๋ฒ„ํŠผ์€ ๋น„ํ™œ์„ฑ์œผ๋กœ๋งŒ, ์ƒํƒœ ์•ˆ๋‚ด๋Š” `banner`. ์˜ค๋ฅ˜ยท์—†์Œ์€ `error`/`notFound` prop. ๊ฐœ์š” ํƒญ์€ ์š”์•ฝ ํŒจ๋„ + ์ตœ๊ทผ Nํ–‰ ํ‘œ.
23
+ - ์ƒ์„ฑยท์ˆ˜์ • ํผ: [examples/form-page.tsx](examples/form-page.tsx) โ€” PageHeader โ†’ ์„น์…˜ 4๊ฐœ โ†’ ๋ˆ„๋ฅด๋ฉด ๊ฒ€์ฆ(`FormMessage`) โ†’ ์ œ์ถœ ์ค‘ ์ƒํƒœ(`submitting`, ๋ฒ„ํŠผ ์ž ๊ธˆยท์ค‘๋ณต ์ œ์ถœ ๋ฐฉ์ง€) โ†’ ์ทจ์†Œ ํ™•์ธ โ†’ ์„ฑ๊ณต toast. ์„ ํƒ์ง€ ๋กœ๋”ฉ ์‹คํŒจ๋Š” ํผ์„ ์œ ์ง€ํ•œ ์ฑ„ ๊ทธ ์„น์…˜ ์•ˆ์— `Alert variant='danger'` ํ•œ ์ค„ + `AlertActions` ๋‹ค์‹œ ์‹œ๋„.
24
+ - ๋Œ€์‹œ๋ณด๋“œ: [examples/dashboard-page.tsx](examples/dashboard-page.tsx) โ€” ์š”์•ฝ ํƒ€์ผ(`ratio`ยท`tone`) โ†’ ๊ธฐ๊ฐ„ ์„ ํƒ + SVG ์ถ”์ด ์ฐจํŠธ โ†’ ํ‘œ โ†’ `EventList`. ์˜ค๋ฅ˜ยท์—†์Œ์€ `error`/`empty` prop.
25
+ - ๋„ค ์˜ˆ์ œ ๋ชจ๋‘ ๊ฐ™์€ ๊ตฌ์กฐ๋‹ค: ๋ฐ์ดํ„ฐ๋Š” `fetch*` prop ์œผ๋กœ ๋ฐ›๊ณ , ์ƒํƒœ(๋กœ๋”ฉยท์˜ค๋ฅ˜ยท์—†์Œ)๋Š” ํŒจํ„ด prop ์œผ๋กœ ๋„˜๊ธฐ๊ณ , ํ™”๋ฉด ์กฐ๋ฆฝ๋งŒ ํ•œ๋‹ค.
26
+
27
+ ## ํ™”๋ฉด ์œ ํ˜• โ†’ Pattern
28
+
29
+ | ํ™”๋ฉด | Pattern | ์–ธ์ œ ์“ฐ๋‚˜ |
30
+ | ---------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
31
+ | ๋ชฉ๋ก | `ListPage` | ๊ฒ€์ƒ‰/ํ•„ํ„ฐ โ†’ ํ‘œ โ†’ ์ƒ์„ธ ์ง„์ž… ํ๋ฆ„์˜ ๋ฆฌ์†Œ์Šค ๋ชฉ๋ก |
32
+ | ์ƒ์„ธ | `DetailPage` | ๋ฆฌ์†Œ์Šค ํ•˜๋‚˜์˜ ์ƒ์„ธ. ํ•ต์‹ฌ ์ •๋ณด๋Š” ํ—ค๋” `meta` ํ•œ ๊ณณ(`MetaGroup columns={3}` + `MetaItem`) โ†’ ๋ณธ๋ฌธ ์ „ํญ. `aside` ๋Š” ์“ฐ์ง€ ์•Š๋Š”๋‹ค. ํ–‰๋™ ๋ฒ„ํŠผ์€ `deleteAction`ยท`secondaryActions`ยท`primaryAction` ์Šฌ๋กฏ โ€” ํŒจํ„ด์ด ์ œ๋ชฉ ์ค„ ์˜ค๋ฅธ์ชฝ์— [๋”๋ณด๊ธฐ โ‹ฏ][๋ณด์กฐ โ‰ค2][์ฃผ ํ–‰๋™]์œผ๋กœ ๋†“๊ณ  ์‚ญ์ œ๋Š” โ‹ฏ ๋ฉ”๋‰ด ์•ˆ |
33
+ | ์ž…๋ ฅ โ€” ์ „์šฉ URL | `FormPage` | ์Šคํฌ๋กค์ด ์ƒ๊ธฐ๋Š” ๊ธด ํผ โ€” ์„น์…˜ 3๊ฐœ ์ด์ƒ, ํ•œ ํ™”๋ฉด์„ ๋„˜๊น€, ๋˜๋Š” ์—ฌ๋Ÿฌ ๋‹จ๊ณ„. ์ƒ์„ฑยท์ˆ˜์ • ํ™”๋ฉด์˜ ๊ธฐ๋ณธ |
34
+ | ์ž…๋ ฅ โ€” ๋ชฉ๋ก ์œ„์— | `FormDrawer` | ๋ชฉ๋ก ๋งฅ๋ฝ์„ ์œ ์ง€ํ•ด์•ผ ํ•˜๊ณ  **Drawer ํ•œ ํ™”๋ฉด ์•ˆ์— ๋“ค์–ด๊ฐ€๋Š”** ํผ(์„น์…˜ 1~2๊ฐœ). ์Šคํฌ๋กค์ด ์ƒ๊ธฐ๋ฉด FormPage |
35
+ | ์ž…๋ ฅ โ€” ์งง๊ฒŒ | `FormDialog` | ์ด๋ฆ„ ๋ณ€๊ฒฝยทํƒœ๊ทธ ์ถ”๊ฐ€์ฒ˜๋Ÿผ ํ•„๋“œ 1~4๊ฐœ |
36
+ | ๋Œ€์‹œ๋ณด๋“œ | `DashboardLayout` + `DashboardSection`(`columns`) + `DashboardPanel` | ์ˆซ์ž ํƒ€์ผยท์ฐจํŠธ๋กœ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ํ•œ๋ˆˆ์— |
37
+
38
+ ๋˜๋Œ๋ฆด ์ˆ˜ ์—†๋Š” ์ž‘์—…์˜ ํ™•์ธ๋งŒ ๋ฐ›์„ ๋•Œ๋Š” Pattern ์ด ์•„๋‹ˆ๋ผ `AlertDialog` ๋ฅผ ์“ด๋‹ค.
39
+
40
+ **ํผ์„ ์–ด๋””์— ๋‘๋‚˜** โ€” ํ•„๋“œ ์ˆ˜์™€ ์Šคํฌ๋กค๋กœ ์ •ํ•œ๋‹ค(CarbonยทShopifyยทAtlassian ์˜ ๊ด€๋ก€์™€ ๊ฐ™๋‹ค, 2026-10-13): ํ•„๋“œ 1~4๊ฐœ โ†’ `FormDialog`, ๋ชฉ๋ก ๋งฅ๋ฝ์ด ํ•„์š”ํ•˜๊ณ  Drawer ํ•œ ํ™”๋ฉด ์•ˆ์— ๋“ค์–ด๊ฐ€๋ฉด โ†’ `FormDrawer`, ์Šคํฌ๋กค์ด ์ƒ๊ธฐ๊ฑฐ๋‚˜ ์„น์…˜์ด ์…‹ ์ด์ƒ์ด๊ฑฐ๋‚˜ ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋ฉด โ†’ `FormPage`. **๊ธด ํผ์„ Drawer ๋‚˜ Dialog ์— ๋„ฃ์ง€ ์•Š๋Š”๋‹ค.** ํผ ์•ˆ์€ ํ•œ ์—ด, ๋ผ๋ฒจ์€ ์œ„, ์„น์…˜ ์ œ๋ชฉ์œผ๋กœ ๋ฌถ๊ณ (FormSection), ์ €์žฅ ๋ฒ„ํŠผ์€ ์ž ๊ทธ์ง€ ์•Š๋Š”๋‹ค(`submitMode='always'`). **FormPage ์—๋Š” ๊ฒ€ํ†  ํŒจ๋„(`aside`)์„ ํ•ญ์ƒ ๋‘”๋‹ค** โ€” ์ง€๊ธˆ๊นŒ์ง€ ์ž…๋ ฅํ•œ ๊ฐ’์˜ ์š”์•ฝ๊ณผ ์˜ˆ์ƒ ๋น„์šฉยท์˜ํ–ฅ์ฒ˜๋Ÿผ ์ œ์ถœ ์ „์— ํ™•์ธํ•  ๊ฒƒ์„ ๋ณด์—ฌ ์ค€๋‹ค(์˜ˆ์ œ form-page.tsx ์˜ `aside`). ํผ ์—ด๋งŒ ๋‘๊ณ  ์˜ค๋ฅธ์ชฝ์„ ๋น„์šฐ์ง€ ์•Š๋Š”๋‹ค.
41
+
42
+ ## ์ž์ฃผ ํ‹€๋ฆฌ๋Š” ๊ฒƒ
43
+
44
+ - Pattern ๋ณธ๋ฌธ์€ ์ด๋ฏธ `<section>` landmark ๋‹ค. `<main>` ์œผ๋กœ ๋˜ ๊ฐ์‹ธ์ง€ ์•Š๋Š”๋‹ค. ์•ฑ์˜ `<main>` ์—๋Š” `p-8`ยท`max-w-*`ยท๋ฐฐ๊ฒฝ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค โ€” Pattern ์ด ํ—ค๋” ๋ (ํ™”๋ฉด ๋๊นŒ์ง€)์™€ ๋ณธ๋ฌธ ์—ฌ๋ฐฑ(24px)์„ ๊ฐ€์ง€๋ฏ€๋กœ, ๊ฐ์‹ธ๋ฉด ํ—ค๋”๊ฐ€ ๊ฐ€์žฅ์ž๋ฆฌ์—์„œ 32px ๋–  ๋ณด์ธ๋‹ค(2026-10-18 ํ•œ ์ค„ ํŒ run). **์‚ฌ์ด๋“œ๋ฐ”ยท์ƒ๋‹จ๋ฐ” ๊ฐ™์€ ์•ฑ ์…ธ์„ ์ƒˆ๋กœ ๊ทธ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค** โ€” ๊ณผ์ œ๋Š” ํŽ˜์ด์ง€ ํ•˜๋‚˜์ด๊ณ  Pattern ์ด ํ—ค๋”(์ œ๋ชฉยทํ–‰๋™)๋ฅผ ๊ทธ๋ฆฐ๋‹ค. ์…ธ์ด ๊ผญ ํ•„์š”ํ•˜๋ฉด `DashboardLayout` ์„ ์“ฐ๊ณ , `fixed` ์‚ฌ์ด๋“œ๋ฐ”๋กœ Pattern ์„ ๋ฎ์ง€ ์•Š๋Š”๋‹ค(2026-10-20 17์ฐจ: Codex ๊ฐ€ ๊ทธ๋ฆฐ ์‚ฌ์ด๋“œ๋ฐ”๊ฐ€ ListPage ์ œ๋ชฉ์„ ๋ฎ์–ด 27์ ).
45
+ - `ListPage` ์˜ `onResetFilters` ๋Š” **ํ•ญ์ƒ** ๋„˜๊ธฐ๊ณ , ํ•„ํ„ฐ๊ฐ€ ์—†์„ ๋•Œ๋Š” `filtersActive={false}` ๋กœ ๋ณด์ด์ง€ ์•Š๊ฒŒ ํ•œ๋‹ค(์ž๋ฆฌ๋Š” ์œ ์ง€). ์กฐ๊ฑด๋ถ€๋กœ ๋„˜๊ธฐ๋ฉด ๋นˆ ๊ฒฐ๊ณผ ํ™”๋ฉด์—์„œ ๋ฒ„ํŠผ์ด ํŠ€์–ด๋‚˜์™€ ๋ฐฐ์น˜๊ฐ€ ๋ฐ”๋€๋‹ค. ๋ฒ„ํŠผ์€ ํŒจํ„ด์ด ๋น ๋ฅธ ํ•„ํ„ฐ ์ค„ ์˜ค๋ฅธ์ชฝ์— ๊ทธ๋ฆฐ๋‹ค โ€” ๊ฒ€์ƒ‰์ฐฝ ์˜†์— ์ง์ ‘ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.
46
+ - `ListPage` ์— `tableTitle`("์‹คํ–‰ํ™˜๊ฒฝ ๋ชฉ๋ก" ๊ฐ™์€ ํ‘œ ์ œ๋ชฉ)์„ ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค โ€” ํ—ค๋” ์ œ๋ชฉ๊ณผ ์ค‘๋ณต์ด๊ณ  ๋น ๋ฅธ ํ•„ํ„ฐ ์˜†์—์„œ ๋นฝ๋นฝํ•ด ๋ณด์ธ๋‹ค(2026-10-18 10์ฐจ). ๋น ๋ฅธ ํ•„ํ„ฐ ์ค„์—๋Š” ์นฉ๊ณผ "ํ•„ํ„ฐ ์ดˆ๊ธฐํ™”"๋งŒ.
47
+ - **๋ผ์šด๋“œ๋Š” ํ•œ ๊ณ„์—ด** โ€” ๋ฑƒ์ง€ยทํƒœ๊ทธ 4px, ์นฉยท๋ฒ„ํŠผยท์ž…๋ ฅ 6px, ํ‘œยท์นด๋“œ 8px. ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ณธ๊ฐ’์ด ์ด๋ฏธ ๊ทธ๋ ‡๋‹ค. `rounded-full`ยท`shape='rounded'`ยท`rounded='full'` ์„ ๋ง์”Œ์›Œ pill ์„ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค(๊ฐ์ง„ ๊ฒƒ ์˜†์˜ pill ์€ ์„ธ ๋ผ์šด๋“œ ์—ฐ์† ๊ฐ์ , 2026-10-18 10์ฐจ).
48
+ - ํ–‰์„ ๋ˆŒ๋Ÿฌ ๋ณด๋Š” ์ƒ์„ธ๋Š” `ListPage detail={{ title, description, onClose, children, note, footer }}` ๋กœ **๋ชฉ๋ก ์˜ค๋ฅธ์ชฝ์— ๋‚˜๋ž€ํžˆ** ์—ฐ๋‹ค(ํ‘œ๊ฐ€ ์ข์•„์ง€๊ณ  ๋ชฉ๋ก์€ ๊ณ„์† ๋ณด์ธ๋‹ค, ๋‹ซ๊ธฐ ๋ฒ„ํŠผยทEsc). `activeRowId={selected?.id ?? null}` ๋กœ ์—ด๋ฆฐ ํ–‰์„ ํ‘œ์‹œํ•˜๊ณ , ์ƒ์„ธ ํ•„๋“œ๋Š” `MetaList` ์•ˆ์— `MetaRow` ๋กœ ์„ธ๋กœ๋กœ ์Œ“๋Š”๋‹ค. `Stack` ์€ ๊ธฐ๋ณธ ๋ฐฉํ–ฅ์ด ๊ฐ€๋กœ๋ผ MetaRow ๋ฅผ ๊ฐ์‹ธ๋ฉด ์˜†์œผ๋กœ ๋Š˜์–ด์„œ ์ž˜๋ฆฐ๋‹ค. ํ‘œ๋ฅผ ์ขํžˆ๋ฉด ์•ˆ ๋  ๋•Œ๋งŒ `<Drawer modal={false}>` ์˜† ํŒจ๋„(๋ฎ๋Š” ํ˜•ํƒœ)์„ ์“ด๋‹ค.
49
+ - **`DetailPage asideTitle` ์„ ์ฃผ๋ฉด ํŒจ๋„ ์•ˆ์— ๊ฐ™์€ ์ œ๋ชฉ์„ ๋˜ ์“ฐ์ง€ ์•Š๋Š”๋‹ค** โ€” ํŒจํ„ด์ด ํŒจ๋„ ์ œ๋ชฉ์„ ๊ทธ๋ฆฌ๋ฏ€๋กœ ์•ˆ์ชฝ `MetaList`ยท์นด๋“œ์— "์ž‘์—… ์ •๋ณด" ๊ฐ™์€ ๋จธ๋ฆฌ๊ธ€์„ ๋ฐ˜๋ณตํ•˜๋ฉด ์ œ๋ชฉ์ด ์—ฐ๋‹ฌ์•„ ๋‘ ๋ฒˆ ๋ณด์ธ๋‹ค(2026-10-27 ํ™€๋“œ์•„์›ƒ 12, ์‹ฌํŒ 2๊ฑด). ํŒจ๋„ ์•ˆ์€ ํ•ญ๋ชฉ(`MetaRow`)๋ถ€ํ„ฐ ์‹œ์ž‘ํ•œ๋‹ค.
50
+ - **"์˜ˆ์‹œ ๋ฐ์ดํ„ฐ๋กœ ๊ตฌ์„ฑ๋œ ํŽ˜์ด์ง€์ž…๋‹ˆ๋‹ค" ๊ฐ™์€ ๊ฐœ๋ฐœ์ž ๋ฉด์ฑ…๋ฌธยท'์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ' ๋ฑƒ์ง€๋ฅผ ํ™”๋ฉด์— ๋„ฃ์ง€ ์•Š๋Š”๋‹ค** โ€” ๋ชฉ ๋ฐ์ดํ„ฐ์ž„์€ ์ฝ”๋“œ ์ฃผ์„์—๋งŒ ์ ๋Š”๋‹ค. ์‹ฌํŒ์€ ์ด๋ฅผ ์ œํ’ˆ ๋ฌธ๊ตฌ์˜ ๊ฒฐํ•จ์œผ๋กœ ์ฝ๋Š”๋‹ค(2026-10-27 ํ™€๋“œ์•„์›ƒ 12, ๋ฌธ๊ตฌ ์ฐจ์› ๊ฐ์ ).
51
+ - **๋ชฉ๋ก์˜ ๊ฒ€์ƒ‰ ์ž…๋ ฅ์€ `ColumnFilter` + `ColumnFilterInput`**(์Šคํ† ๋ฆฌ์™€ ๊ฐ™์€ ์กฐํ•ฉ). ํ•„ํ„ฐ ์นฉ(`TableFilter*`, ์ฑ„์›€ํ˜•) ์˜†์— `TextField`(์™ธ๊ณฝ์„ )๋ฅผ ๋”ฐ๋กœ ๋‘๋ฉด ๋‘ ๋ชจ์–‘์ด ์–ด๊ธ‹๋‚˜ ๊ฐ์ (2026-10-26 ํ™€๋“œ์•„์›ƒ 11, ์‹ฌํŒ 4๊ฑด). ํ‘œ ์…€ ์ •๋ ฌ์€ `TableCell align='right'`(`className='text-right'` ๋„ ๊ฐ™์€ ํšจ๊ณผ), ์ˆซ์ž ์—ด์€ `type: 'number'`(cellClass ๋ฅผ ๋”ํ•ด๋„ ์ •๋ ฌ์ด ์œ ์ง€๋œ๋‹ค), ๊ธˆ์•ก ์•„๋ž˜ ์‚ฌ์šฉ๋Ÿ‰ ๊ฐ™์€ ๋‘ ์ค„ ์…€์€ `TwoLineCellRenderer`(์ง์ ‘ flex ๋กœ ๋‘ ์ค„์„ ๊ทธ๋ฆฌ๋ฉด ์œ„ยท์•„๋ž˜๋กœ ๋ฒŒ์–ด์ง„๋‹ค).
52
+ - ์ •๋ ฌํ•  ์ˆ˜ ์žˆ๋Š” ์—ด์€ `sortable: true` ๋ฅผ **๋ช…์‹œ**ํ•œ๋‹ค โ†’ ์ •๋ ฌ ์ „์—๋„ ์•„์ด์ฝ˜์ด ๋ณด์ด๊ณ , ๋ˆ„๋ฅด๋ฉด ๋ฐฉํ–ฅ์ด ๋ฐ”๋€๋‹ค. ์š”์ฒญ๋ฌธ์— "์ •๋ ฌ ๊ฐ€๋Šฅ" ์ด ์žˆ์œผ๋ฉด ๋ฐ˜๋“œ์‹œ.
53
+ - **๊ฒ€ํ†  ํŒจ๋„(`aside`)์ด ์žˆ๋Š” ํผ์˜ ์ทจ์†Œยท์ œ์ถœ ๋ฒ„ํŠผ์€ ํŒจ๋„ ๋ฐ”๋‹ฅ** โ€” FormPage ๊ฐ€ ๊ทธ๋ฆฐ๋‹ค(ํผ ๋์— ๋”ฐ๋กœ ๋‘์ง€ ์•Š๋Š”๋‹ค). ๊ธด ํผ ์˜†์—์„œ ํŒจ๋„์ด ์งง๊ฒŒ ๋๋‚˜๊ณ  ์ œ์ถœ์ด ๋ฉ€์–ด ๋‘ ์‹ฌํŒ ๋ชจ๋‘ ๊ฐ์ ํ–ˆ๋‹ค(2026-10-20 16์ฐจ). ์š”์•ฝ ํŒจ๋„์—๋Š” ์ž…๋ ฅ๊ฐ’ ์š”์•ฝ๊ณผ ์˜ˆ์ƒ ๋น„์šฉยท์‹œ๊ฐ„๋งŒ.
54
+ - **ํ‘œ์˜ ์ง„ํ–‰๋ฅ  ์—ด์€ ๊ณ ์ • ํญ ๋ง‰๋Œ€ + % ๊ธ€์ž ํ•œ ์ค„** โ€” `<Progress value={p} className='w-[120px]' aria-label={`GPU ์‚ฌ์šฉ๋ฅ  ${p}%`} />` ์˜ค๋ฅธ์ชฝ์— `tabular-nums` ๋กœ `{p}%`. **๋ง‰๋Œ€๋งˆ๋‹ค `aria-label` ๋กœ '๋ฌด์—‡ ๋ช‡ %' ์ด๋ฆ„์„ ์ค€๋‹ค** โ€” ์ด๋ฆ„ ์—†๋Š” progressbar ๋Š” ํ–‰๋งˆ๋‹ค axe serious(17์ฐจ ํŒŒ์ดํ”„๋ผ์ธ ๋ชฉ๋ก 21๊ฑด; DS ๊ฐ€ ๊ธฐ๋ณธ ์ด๋ฆ„ '46%' ๋ฅผ ๋ถ™์ด์ง€๋งŒ ๋œป์ด ์•ฝํ•˜๋‹ค). ๋ถ„์ˆ˜(816 / 1,200)๋Š” ์ƒ์„ธ๋‚˜ ํˆดํŒ์œผ๋กœ. ๊ธ€์ž ์•„๋ž˜ ๋ง‰๋Œ€๋ฅผ ์Œ“์œผ๋ฉด ํ–‰๋งˆ๋‹ค ๋ง‰๋Œ€ ํญ์ด ๋‹ฌ๋ผ์ ธ ๊ฐ์ (2026-10-20 ํ™€๋“œ์•„์›ƒ 8 Codex ๋ชฉ๋ก).
55
+ - ์ œ์ถœ ์ค‘ ์ƒํƒœ๋Š” ์•ฑ์ด `const [submitting, setSubmitting] = useState(false)` ๋กœ ๊ฐ–๊ณ  `FormPage submitting={submitting}` ์— ๋„˜๊ธด๋‹ค(`onSubmit` ์•ˆ์—์„œ try/finally). FormPage ๊ฐ€ ๋ฒ„ํŠผ์„ ์ž ๊ทธ๊ณ  ์Šคํ”ผ๋„ˆ๋ฅผ ๋ณด์ด์ง€๋งŒ, ์ƒํƒœ๊ฐ€ ์ฝ”๋“œ์— ๋“œ๋Ÿฌ๋‚˜์•ผ ์ค‘๋ณต ์ œ์ถœ ๋ฐฉ์ง€๊ฐ€ ํ™•์ธ๋œ๋‹ค.
56
+ - ๋นˆ ๊ฒฐ๊ณผ๋Š” ํŒจํ„ด์ด ์•„์ด์ฝ˜ยท์ œ๋ชฉยท์„ค๋ช…ยท"ํ•„ํ„ฐ ์ดˆ๊ธฐํ™”" ๋ฒ„ํŠผ ์ƒ์ž๋กœ ๊ทธ๋ฆฐ๋‹ค. `emptyState` ์—๋Š” `{ title: '์กฐ๊ฑด์— ๋งž๋Š” ๋ชจ๋ธ์ด ์—†์Šต๋‹ˆ๋‹ค', description: '๊ฒ€์ƒ‰์–ด๋‚˜ ํ•„ํ„ฐ๋ฅผ ๋ฐ”๊ฟ” ๋ณด์„ธ์š”.' }` ๋˜๋Š” ๋‘ ๋ฌธ์žฅ ๋ฌธ์ž์—ด("โ€ฆ์—†์Šต๋‹ˆ๋‹ค. โ€ฆํ•ด ๋ณด์„ธ์š”.")๋งŒ ๋„˜๊ธด๋‹ค. ๋ฒ„ํŠผยท์•„์ด์ฝ˜ยท`<div>` ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด ๋„ฃ์ง€ ์•Š๋Š”๋‹ค.
57
+ - ๋น„ํ™œ์„ฑ ๋ฒ„ํŠผ์€ `disabled` ๋กœ๋งŒ ๋‘”๋‹ค. DetailPage ์—๋Š” ์‚ฌ์œ  ์•ˆ๋‚ด ํ•œ ์ค„(`actionsNote`)์„ **์“ฐ์ง€ ์•Š๋Š”๋‹ค**(2026-10-18 11์ฐจ) โ€” ์ƒํƒœ ์ž์ฒด์˜ ์•ˆ๋‚ด๊ฐ€ ํ•„์š”ํ•˜๋ฉด `banner`(Alert). ListPage ์ƒ์„ธ ํŒจ๋„์˜ `detail.note` ๋Š” ๊ทธ๋Œ€๋กœ. `disabled` ๋ฅผ ๋นผ๋จน๊ณ  ๋ฐฐ๋„ˆ๋งŒ ๋‘์ง€ ์•Š๋Š”๋‹ค.
58
+ - **`banner` ๋Š” ์˜ค๋ฅ˜ยท๊ฒฝ๊ณ ์—๋งŒ**(์‹คํŒจยท์ค‘๋‹จยท๊ถŒํ•œยท์‚ญ์ œ ์˜ˆ์ •). "์‹คํ—˜์ด ์ง„ํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค" ๊ฐ™์€ ์ƒํƒœ ์•ˆ๋‚ด๋ฅผ ํฐ ๋ฐฐ๋„ˆ๋กœ ์˜ฌ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค โ€” ์ƒํƒœ๋Š” ์ƒํƒœ `Badge` ๊ฐ€ ๋ณด์—ฌ ์ค€๋‹ค(2026-10-19 14์ฐจ, 13์ฐจ ์ƒ์„ธ colorยทlayout ๊ฐ์ ).
59
+ - **ํƒญ ๊ฑด์ˆ˜(`badge`)ยท์ง„ํ–‰๋ฅ ยท"์ตœ๊ทผ Nํ–‰" ํ‘œ์˜ ํ–‰ ์ˆ˜๋Š” ๊ฐ™์€ ๋ฐฐ์—ด์—์„œ ๊ณ„์‚ฐํ•œ๋‹ค** โ€” ์ˆซ์ž๋ฅผ ๋”ฐ๋กœ ์ง€์–ด ์“ฐ๋ฉด ์‹ฌ์‚ฌ์ž๊ฐ€ ๋ชจ์ˆœ์œผ๋กœ ๋ณธ๋‹ค("์‹คํ–‰ 18" ํƒญ vs "15/24 ์™„๋ฃŒ"). ์‹œ๊ฐ„ยท๊ธฐ๊ฐ„์€ 0 ๋‹จ์œ„๋ฅผ ์ƒ๋žตํ•œ๋‹ค("0์‹œ๊ฐ„ 41๋ถ„" โ†’ "41๋ถ„").
60
+ - **์ฃผ์š” ํ–‰๋™ ๋ฒ„ํŠผ ์ž๋ฆฌ๋Š” ํŒจํ„ด์ด ์ •ํ•œ๋‹ค โ€” ์ œ๋ชฉ ์ค„ ์˜ค๋ฅธ์ชฝ.** ListPage `actions`ยทDashboardLayout `actions`ยทDetailPage ์Šฌ๋กฏ ๋ชจ๋‘ PageHeader ์ œ๋ชฉ ์ค„์— ๋†“์ธ๋‹ค(2026-10-19 14์ฐจ, PolarisยทGitHub IssuesยทPrimer ๊ด€๋ก€). ํ•„ํ„ฐ ์ค„์—๋Š” ๊ฒ€์ƒ‰ยทํ•„ํ„ฐยท"ํ•„ํ„ฐ ์ดˆ๊ธฐํ™”"๋งŒ ๋‘”๋‹ค. **ํ–‰๋™ ์ค„์—๋Š” ๋ฒ„ํŠผ๋งŒ** โ€” `Tag`ยท`Badge` ๋ฅผ ๋ฒ„ํŠผ ์˜†์— ๋‘๋ฉด ๋ฒ„ํŠผ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค("the 'GPU ๋…ธ๋“œ' tag looks like the buttons beside it", 2026-10-21 18์ฐจ); ํƒœ๊ทธยท์ข…๋ฅ˜๋Š” ์ œ๋ชฉ ์˜† ์ƒํƒœ ๋ฑƒ์ง€๋‚˜ ๋ฉ”ํƒ€ ์ค„์—.
61
+ - ๋ชฉ๋ก์˜ ์ฃผ ์‹๋ณ„์ž ์—ด์€ ListPage ๊ฐ€ `onRowClick` ์ด ์žˆ์œผ๋ฉด `name` ์—ด์„ ์ž๋™์œผ๋กœ ๊ฐ•์กฐํ•œ๋‹ค(๊ตต๊ฒŒ, hover ๋ฐ‘์ค„). ์ด๋ฆ„ ์—ด field ๊ฐ€ `name` ์ด ์•„๋‹ˆ๋ฉด `primaryField` ๋กœ ์ง€์ •ํ•˜๊ณ , ์…€ ๋ Œ๋”๋Ÿฌ๋กœ ํŒŒ๋ž€ ๋งํฌ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. ํ‘œ ์œ„ ์ œ๋ชฉยท๊ฑด์ˆ˜๋Š” `tableTitle` ๊ณผ `pagination.total` ๋กœ ๋ณด์ธ๋‹ค.
62
+ - **์ƒํƒœ์ฒ˜๋Ÿผ ์„ ํƒ์ง€๊ฐ€ 3~6๊ฐœ์ธ ๋‹ค์ค‘ ์„ ํƒ ํ•„ํ„ฐ๋Š” `ListPage quickFilter`** ๋กœ ํ‘œ ์™ผ์ชฝ ์œ„์— ์„ธ๊ทธ๋จผํŠธ(ToggleGroup)๋กœ ๋‘”๋‹ค โ€” ๋“œ๋กญ๋‹ค์šด์„ ์—ด์ง€ ์•Š์•„๋„ ์„ ํƒ์ง€๊ฐ€ ๋ณด์ด๊ณ , `count` ๋กœ ํ•ญ๋ชฉ๋งˆ๋‹ค ๊ฑด์ˆ˜๋ฅผ ๋ถ™์ด๊ณ  **`countVariant` ์— ํ‘œ์˜ ์ƒํƒœ ๋ฑƒ์ง€์™€ ๊ฐ™์€ tone**(`STATUS[s].tone`: `success`ยท`secondary`ยท`danger`โ€ฆ)์„ ์ค€๋‹ค โ€” ๊ฑด์ˆ˜๋Š” ์ƒํƒœ์ƒ‰ pill ๋ฑƒ์ง€๋กœ ๊ทธ๋ ค์ ธ ์นฉ๊ณผ ํ‘œ๊ฐ€ ๊ฐ™์€ ์ƒ‰ ์–ธ์–ด๊ฐ€ ๋œ๋‹ค(์˜ˆ์ œ์˜ `statusCounts`; "์ „์ฒด" ๋Š” ํŒจํ„ด์ด primary, 2026-10-18 13์ฐจ). ๋“œ๋กญ๋‹ค์šด์— ์ˆจ๊ธฐ์ง€ ์•Š๋Š”๋‹ค. ์„ ํƒ์ง€๊ฐ€ ๋งŽ๊ฑฐ๋‚˜(7๊ฐœ ์ด์ƒ) ๊ฒ€์ƒ‰์ด ํ•„์š”ํ•œ ์ถ•๋งŒ `TableFilterSingleSelect`/`TableFilterMultiSelect` ๋กœ `filters` ์— ๋‘๊ณ , ๊ทธ๋•Œ๋Š” `title`(์˜ˆ: 'ํ”„๋ ˆ์ž„์›Œํฌ')์„ ์ฃผ๋ฉด "ํ”„๋ ˆ์ž„์›Œํฌ ยท ์ „์ฒด" ์ฒ˜๋Ÿผ ๋Œ€์ƒ์ด ํ•ญ์ƒ ๋ณด์ธ๋‹ค. placeholder ์— "์ „์ฒด" ๋งŒ ๋„ฃ์ง€ ์•Š๋Š”๋‹ค. ์ผ๋ฐ˜ `Select` ๋ฅผ ํ•„ํ„ฐ๋กœ ์“ฐ๋ฉด placeholder ์— "์ „์ฒด ์ƒํƒœ" ์ฒ˜๋Ÿผ ๋Œ€์ƒ ์ด๋ฆ„์„ ๋„ฃ๋Š”๋‹ค. ๋ผ๋ฒจ ์—†์ด "์ „์ฒด" ๋งŒ ๋ณด์ด๋Š” ํ•„ํ„ฐ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.
63
+ - ํ‘œ๋Š” `AgGridTable` ๋กœ ๋งŒ๋“ ๋‹ค. `ag-grid-react` ๋ฅผ ์ง์ ‘ ์“ฐ์ง€ ์•Š๋Š”๋‹ค. ํ–‰ ํด๋ฆญ๊ณผ ํ‚ค๋ณด๋“œ Enter ๋Š” ๊ฐ™์€ ํ–‰ ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ๋กœ ๋“ค์–ด์˜จ๋‹ค.
64
+ - ์ฃผ์š” ํ–‰๋™ ๋ฒ„ํŠผ(์ƒ์„ฑยท๋“ฑ๋ก)์€ `ListPage actions` ์— ๋‘”๋‹ค โ€” ํŒจํ„ด์ด ์ œ๋ชฉ ์ค„ ์˜ค๋ฅธ์ชฝ์— ๋†“๋Š”๋‹ค(์ง์ ‘ ํ•„ํ„ฐ ์Šฌ๋กฏ์ด๋‚˜ `titleRight` ์— ๋„ฃ์ง€ ์•Š๋Š”๋‹ค). `PageHeader actions` ๋„ ์ œ๋ชฉ ์ค„ ์˜ค๋ฅธ์ชฝ(ํƒญ์ด ์žˆ์–ด๋„ ๊ฐ™๋‹ค, 2026-10-19 14์ฐจ).
65
+ - **์œ ํ˜•ยท๋ฐฉ์‹ ์„ ํƒ(์†Œ์Šค ์œ ํ˜•ยท๊ณต๊ฐœ ๋ฒ”์œ„ยท์ž…๋ ฅ ๋ฐฉ์‹์ฒ˜๋Ÿผ ์„ ํƒ์ง€ 2๊ฐœ ์ด์ƒ์— ์ œ๋ชฉยท์„ค๋ช…์ด ๋ถ™๋Š” ๊ฒƒ)์€ `RadioSectionGroup` + `RadioSection`(์นด๋“œํ˜•)** ์œผ๋กœ โ€” dl-ui-v3 ์˜ ๊ด€๋ก€(21๊ณณ). ๋ฐฐ์น˜๋Š” ๊ทธ๋ฃน์ด ๊ฐœ์ˆ˜๋กœ ์ •ํ•œ๋‹ค: 1~3๊ฐœ ํ•œ ์ค„, **4๊ฐœ๋Š” 2ร—2, 5๊ฐœ ์ด์ƒ์€ ์„ธ๋กœ ์Œ“๊ธฐ**(์นด๋“œ ์•ˆ์€ ์ œ๋ชฉ ยท ์„ค๋ช… ๊ฐ€๋กœ) โ€” `className` ์œผ๋กœ grid ๋ฅผ ์ง์ ‘ ์งœ์ง€ ์•Š๋Š”๋‹ค. ์„ค๋ช… ์—†๋Š” ์งง์€ ์„ ํƒ(์˜ˆยท์•„๋‹ˆ์˜ค)๋งŒ `RadioGroup`, ์„ ํƒ์ง€ 7๊ฐœ ์ด์ƒยท๊ฒ€์ƒ‰์ด ํ•„์š”ํ•˜๋ฉด `Select`. **๋ณต์ˆ˜ ์„ ํƒ์— ์ œ๋ชฉยท์„ค๋ช…์ด ๋ถ™์œผ๋ฉด `CheckboxSectionGroup` + `CheckboxSection`**(์•Œ๋ฆผ ์ฑ„๋„), ์„ค๋ช… ์—†๋Š” ์งง์€ ์˜ต์…˜๋งŒ `Checkbox`. **์ผœ๊ธฐ/๋„๊ธฐ ํ•˜๋‚˜์˜ ์„ค์ •(๊ทœ์น™ ์‚ฌ์šฉ, ์‹คํŒจ ์‹œ ์•Œ๋ฆผ, ๋…ธํŠธ๋ถ ์ง€์›)์€ `SwitchSection`**(๋ฐ•์Šค + ์ œ๋ชฉยท์„ค๋ช… + Switch, dl-ui-v3 ToggleField ๊ด€๋ก€) โ€” ํผ ์ œ์ถœ๊ฐ’์ด์–ด๋„ Checkbox ๋กœ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. ์˜ˆ์ œ form-page.tsx ์˜ ์Šค์ผ€์ค„ ์„ ํƒ(RadioSectionGroup)๊ณผ ์‹คํŒจ ์•Œ๋ฆผ(SwitchSection)์ด ๋ณธ๋ณด๊ธฐ(`FormLabel id` + ๊ทธ๋ฃน `aria-labelledby`).
66
+ - ๋ฒ„ํŠผ ๋ฌถ์Œ ์‚ฌ์ด ๊ฐ„๊ฒฉ์€ 8px. PageHeaderยทDialogยทDrawerยทForm ์˜ ๋ฒ„ํŠผ ์Šฌ๋กฏ์ด ์ด๋ฏธ ๊ทธ๋ ‡๊ฒŒ ๊ทธ๋ฆฐ๋‹ค.
67
+ - **์ƒํƒœ ํ‘œ์‹œ๋Š” `Badge` ์— ์•„์ด์ฝ˜ + ๊ธ€์ž** โ€” `<Badge variant='success'><LucideIcon iconComponentName='circle-check' />์™„๋ฃŒ</Badge>`. ์•„์ด์ฝ˜์€ Badge ์˜ ์ž์‹์œผ๋กœ ๋ฐ”๋กœ ๋„ฃ๊ณ (Badge ๊ฐ€ 16pxยท๊ธ€์ž์ƒ‰์œผ๋กœ ๋งž์ถ˜๋‹ค), ํฌ๊ธฐ๋Š” ๊ธฐ๋ณธ(`size` ๋ฅผ ์ฃผ์ง€ ์•Š๋Š”๋‹ค โ€” ๊ฑด์ˆ˜ ๋ฑƒ์ง€์™€ ๊ฐ™์€ 20px). **๋ณ„๋„ ์ƒํƒœ ์ปดํฌ๋„ŒํŠธยท๋ž˜ํผ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค**(2026-10-30 ์‚ฌ์šฉ์ž ๊ฒฐ์ • โ€” ์˜ˆ์ „์˜ ์ƒํƒœ ์ „์šฉ ๋ž˜ํผ๋Š” ํฌ๊ธฐยท์—ฌ๋ฐฑ์ด ๋‹ฌ๋ผ ํƒœ๊ทธ์ธ์ง€ ๋ฑƒ์ง€์ธ์ง€ ๋ชจ๋ฅผ ๋ถ€ํ’ˆ์ด ๋๋‹ค). ์ƒํƒœ๊ฐ’ โ†’ `variant`ยท์•„์ด์ฝ˜ ๋งคํ•‘์€ ์ƒ์ˆ˜ ํ•œ ๊ณณ์—. **์–ดํœ˜**: ์ž‘์—…ยท๋…ธํŠธ๋ถยทํŒŒ์ดํ”„๋ผ์ธยท์„œ๋ฒ„์ฒ˜๋Ÿผ ๋Œ์•„๊ฐ€๋Š” ํ”„๋กœ์„ธ์Šค์˜ '์‹คํ–‰ ์ค‘' `primary` + `play`(โ–ถ), ํ™œ์„ฑยท์‚ฌ์šฉ ์ค‘ยท๊ฐ์‹œ ์ค‘ยทํ—ˆ์šฉยท์—ฐ๊ฒฐ๋จ ๊ฐ™์€ ์ผœ์ง„ ์ƒํƒœ `primary` + `circle-dot`(โ—) โ€” โ–ถ ๋ฅผ ์ผœ์ง„ ์ƒํƒœ์— ๋ถ™์ด๋ฉด ์žฌ์ƒ ๋ฒ„ํŠผ์ฒ˜๋Ÿผ ์ฝํžŒ๋‹ค(2026-10-21 18์ฐจ), ์™„๋ฃŒยท์ค€๋น„๋จ `success` + `circle-check`(โœ“) โ€” ์‹คํ–‰ ์ค‘์— โœ“ ๋ฅผ ๋ถ™์ด๋ฉด ๋๋‚œ ๊ฒƒ์œผ๋กœ ์ฝํžŒ๋‹ค(2026-10-20 17์ฐจ), ํ•™์Šต ์ค‘ยท๋ฐฐํฌ ์ค‘์ฒ˜๋Ÿผ ๋์ด ์žˆ๋Š” ์ง„ํ–‰ `info` + `loader-circle`(์ •์  ์•„์ด์ฝ˜ โ€” ์Šคํ”ผ๋„ˆ๋Š” ์ •์ง€ ํ™”๋ฉด์—์„œ ์  ๋ญ‰์น˜๋กœ ๋ณด์ธ๋‹ค), ๋Œ€๊ธฐ `secondary` + `clock`, ์ค‘์ง€ยท๋น„ํ™œ์„ฑ `secondary` + `circle-pause`, ์‹คํŒจ `danger` + `circle-x`, ๊ฒฝ๊ณ ยท์•Œ๋ฆผ ๋ฐœ์ƒ `warning` + `triangle-alert`. **ํ•œ ํ™”๋ฉด์— ๊ฐ™์€ variant ์˜ ์ƒํƒœ ๋‘˜์„ ๋‘์ง€ ์•Š๋Š”๋‹ค** โ€” '์ค€๋น„๋จ'(`success` โœ“)๊ณผ '์‚ฌ์šฉ ์ค‘'(`primary` โ—)์ฒ˜๋Ÿผ ์ƒํƒœ๋งˆ๋‹ค ์ƒ‰์ด ๋‹ฌ๋ผ์•ผ ํ•œ๋‹ค(2026-10-21 19์ฐจ "two different states look the same"). ๊ธฐ๋ณธ์€ ์—ฐํ•œ ์ƒ‰ ์ฑ„์›€(`appearance` ๋ฅผ ์ฃผ์ง€ ์•Š๋Š”๋‹ค โ€” 2026-10-18 10์ฐจ). **lucide ์ด๋ฆ„์€ ์ •์‹ ์ด๋ฆ„๋งŒ**(`circle-pause`ยท`loader-circle`ยท`triangle-alert`; ์˜› alias `pause-circle` ๊ฐ™์€ ๊ฒƒ์€ ์“ฐ์ง€ ์•Š๋Š”๋‹ค). ๊ฐ™์€ ํ™”๋ฉด์˜ ์ƒํƒœ ๋ฑƒ์ง€๋Š” **์ „๋ถ€ ์•„์ด์ฝ˜์ด ์žˆ๊ฒŒ** โ€” ์„ž์ด๋ฉด ์‹ฌ์‚ฌ์ž๊ฐ€ ๋ถˆ์ผ์น˜๋กœ ๋ณธ๋‹ค. ์ƒ‰์€ `variant` ๋กœ ์ •ํ•˜๊ณ  `className` ์œผ๋กœ ๋ง์”Œ์šฐ์ง€ ์•Š๋Š”๋‹ค.
68
+ - **์ฃผ์š” ํ–‰๋™ ๋ฒ„ํŠผ์—๋Š” lucide ์•„์ด์ฝ˜**์„ ๊ธ€์ž ์•ž์— ๋ถ™์ธ๋‹ค โ€” ์ƒ์„ฑ `plus`, ์‚ญ์ œ `trash-2`, ์ค‘์ง€ `square`, ๋ฐฐํฌ `rocket`, ๋‹ค์‹œ ์‹œ๋„ `refresh-cw`, ๋‚ด๋ณด๋‚ด๊ธฐ `download`(`<Button variant='primaryBold'><LucideIcon iconComponentName='plus' /> ์ƒ์„ฑ</Button>`). `LucideIcon` ์˜ ๊ธฐ๋ณธ ํฌ๊ธฐ๋Š” 16px ์ด๊ณ  ๋ฒ„ํŠผ ์•ˆ ์•„์ด์ฝ˜์€ ๊ทธ ํฌ๊ธฐ๋กœ ๋‘”๋‹ค(`size={20}`ยท`24` ๋ฅผ ์ฃผ๋ฉด ๋ฒ„ํŠผ๋ณด๋‹ค ์ปค ๋ณด์ธ๋‹ค). ์•„์ด์ฝ˜ ์—†๋Š” ๊ธ€์ž ๋ฒ„ํŠผ๋งŒ ๋Š˜์–ด๋†“์ง€ ์•Š๋Š”๋‹ค.
69
+ - **์ˆซ์ž ์—ด(๊ฐœ์ˆ˜ยทํฌ๊ธฐยท๋น„์œจยท์‹œ๊ฐ„)์€ `type: 'number'`** โ€” AgGridTable ์ด ์…€๊ณผ ์ œ๋ชฉ์„ ์˜ค๋ฅธ์ชฝ ์ •๋ ฌํ•˜๊ณ  ์ˆซ์ž ํญ์„ ๊ณ ์ •ํ•œ๋‹ค(์…€ ๋ Œ๋”๋Ÿฌ๊ฐ€ ์žˆ์–ด๋„ ์ ์šฉ). ํญ์„ ์•ˆ ์ฃผ๋ฉด 140 ์œผ๋กœ ์žก๋Š”๋‹ค(ag-grid ๊ธฐ๋ณธ 200 ์€ ์ˆซ์ž ์—ด์ด ๋น„์–ด ๋ณด์ธ๋‹ค โ€” 2026-10-27 ํ™€๋“œ์•„์›ƒ 13 layout ์ง€์  "wide empty area"). ์ˆซ์ž๋ฅผ ์™ผ์ชฝ ์ •๋ ฌ๋กœ ๋‘์ง€ ์•Š๋Š”๋‹ค.
70
+ - **์ƒ์„ธ ํŒจ๋„ยท์˜ค๋ฅธ์ชฝ ์ •๋ณด ์—ด์˜ ํ•„๋“œ๋Š” `MetaRow align='start'`** โ€” ๊ฐ’์ด ๋ผ๋ฒจ ๋ฐ”๋กœ ์˜†์— ๋ถ™๋Š”๋‹ค. ๊ธฐ๋ณธ(`end`)์€ ๊ฐ’์„ ํ–‰ ์˜ค๋ฅธ์ชฝ ๋์— ๋‘์–ด ๋„“์€ ํŒจ๋„์—์„œ ๋ผ๋ฒจ๊ณผ ๊ฐ’ ์‚ฌ์ด๊ฐ€ ๋นˆ๋‹ค.
71
+ - **์ง„ํ–‰ ๋ง‰๋Œ€์˜ ์ƒ‰์€ ์ƒํƒœ์™€ ๋งž์ถ˜๋‹ค** โ€” ์‹คํŒจํ•œ ์ž‘์—…์€ `Progress variant='danger'`, ๊ฒฝ๊ณ ๋Š” `warning`, ์™„๋ฃŒ๋Š” `success`. ์‹คํŒจํ•œ ์ž‘์—…์— ํŒŒ๋ž€ ๋ง‰๋Œ€๋ฅผ ๋‘์ง€ ์•Š๋Š”๋‹ค.
72
+ - **ํ—ค๋” `meta` ์— ์“ด ๊ฐ’(IDยท๋ฒ„์ „ยท์†Œ์œ ์žยท์ˆ˜์ •์ผ)์€ ๋ณธ๋ฌธ Panel ์— ๋‹ค์‹œ ์“ฐ์ง€ ์•Š๋Š”๋‹ค** โ€” ๊ฐ™์€ ๊ฐ’์ด ๋‘ ๋ฒˆ ๋ณด์—ฌ๋„ ์‹ฌ์‚ฌ์ž๊ฐ€ ์ค‘๋ณต์œผ๋กœ ๋ณธ๋‹ค. ํ‚ค์›Œ๋“œยท๋ถ„๋ฅ˜ ํƒœ๊ทธ๋Š” `Tag variant='secondary'`(๊ธฐ๋ณธ ๊ฐ์ง„ 4px) โ€” ์ƒํƒœ ๋ฑƒ์ง€ยท์นฉยท์ž…๋ ฅ๊ณผ ๊ฐ™์€ ๋ผ์šด๋“œ ๊ณ„์—ด. pill(`shape='rounded'`)๋กœ ๊ทธ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค(2026-10-18 10์ฐจ).
73
+ - **์„ค๋ช… ๋ฌธ์žฅ์€ PageHeader `description` ํ•œ ๊ณณ์—๋งŒ.** ๊ฐ™์€ ๋ฌธ์žฅ์„ ๋ณธ๋ฌธ ์œ„ยท์นด๋“œ ์•ˆ์— ๋‹ค์‹œ ์“ฐ์ง€ ์•Š๊ณ , ๋ณธ๋ฌธ์— "์„ค๋ช…" Panel ์„ ๋”ฐ๋กœ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค(์˜ˆ์ œ detail-page ์™€ ๊ฐ™์ด โ€” ๊ฐ™์€ ๋ฌธ์žฅ์ด ๋‘ ๋ฒˆ ๋ณด์ด๋ฉด ์‹ฌ์‚ฌ์ž๊ฐ€ ์ค‘๋ณต์œผ๋กœ ๋ณธ๋‹ค). ๋ณธ๋ฌธ์˜ `<p>` ์•ˆ๋‚ด๋ฌธ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ง€๊ธˆ ํ•ด์•ผ ํ•  ์ผ์ด ์žˆ์„ ๋•Œ๋งŒ. ๋ณธ๋ฌธ ๋ฌธ๋‹จ์—๋Š” `break-keep wrap-break-word` ๋ฅผ ๋ถ™์ธ๋‹ค(ํ•œ๊ตญ์–ด๊ฐ€ ๋‹จ์–ด ์ค‘๊ฐ„์—์„œ ๊บพ์ด์ง€ ์•Š๊ฒŒ).
74
+ - **์ƒ์„ธ ๊ฐœ์š” ํƒญ์˜ ๋ธ”๋ก(์ •๋ณดยทํ‘œยท๋ชฉ๋ก)์€ ์ „๋ถ€ `Panel` ์•ˆ์—** โ€” ํ‘œ ๋ธ”๋ก๋„ `Panel title='์ตœ๊ทผ ์‹คํ–‰' titleRight={<Button variant='primaryLink'>์ „์ฒด ๋ณด๊ธฐ</Button>}` ์•ˆ์— ๋„ฃ๊ณ , ์ œ๋ชฉ(`h2`) + ํ‘œ๋ฅผ ๋งจ๋ชธ์œผ๋กœ ๋‘์ง€ ์•Š๋Š”๋‹ค(์ด์›ƒ์ด ์นด๋“œ์ธ๋ฐ ํ•˜๋‚˜๋งŒ ์นด๋“œ ๋ฐ–์ด๋ฉด "sits outside a card unlike its neighbors", 2026-10-21 18์ฐจ ์ƒ์„ธ 4/6 run). **์นด๋“œ ์•ˆ์˜ ํ‘œ๋Š” ์˜ˆ์ œ์ฒ˜๋Ÿผ `Table`(๊ฐ€๋ฒผ์šด ํ‘œ)๋กœ** โ€” `AgGridTable`(ํšŒ์ƒ‰ ๋จธ๋ฆฌ์ค„ยท๋‘ฅ๊ทผ ํ…Œ๋‘๋ฆฌ ์ƒ์ž)์€ ๋ชฉ๋ก ํ™”๋ฉด๊ณผ ์ „์šฉ ํƒญ์—๋งŒ ์“ฐ๊ณ  ์นด๋“œ ์•ˆ์— ๋„ฃ์ง€ ์•Š๋Š”๋‹ค("bordered table header inside the jobs card while the other cards use plain rows", 2026-10-21 19์ฐจ). **๊ฐœ์š” ํƒญ์€ ์š”์•ฝ ํŒจ๋„ + ์ž‘์€ ํ‘œ** โ€” `Panel '์ฃผ์š” ์ •๋ณด'`(MetaList) ์•„๋ž˜ `Panel '์ตœ๊ทผ ๋ฐฐํฌ'`(๋˜๋Š” ์ตœ๊ทผ ์‹คํ–‰ยท์ตœ๊ทผ ๋ฒ„์ „) Table **4์—ดยท5ํ–‰๊นŒ์ง€**(์ด๋ฆ„ยท์ƒํƒœยทํ•ต์‹ฌ ์ง€ํ‘œ 1ยท์‹œ๊ฐ) + `titleRight` ์— '์ „์ฒด ๋ณด๊ธฐ' ๋งํฌ(`Button variant='primaryLink'`)๋กœ ์ „์šฉ ํƒญ. ์—ด์ด ๋” ํ•„์š”ํ•œ ํ‘œ๋Š” ์ „์šฉ ํƒญ์—์„œ โ€” ํŒจํ„ด์ด `aside` ์—†๋Š” ํƒญ์„ **์ „์ฒด ํญ**์œผ๋กœ ๊ทธ๋ฆฐ๋‹ค(GitHub PR ์‹: Conversation ์€ 2๋‹จ, Files changed ๋Š” ์ „์ฒด ํญ). ์—ด 5~7๊ฐœ ํ‘œ๋ฅผ 2/3 ์—ด์— ๋„ฃ์œผ๋ฉด ์ด๋ฆ„ยท๋‚ ์งœ๊ฐ€ ์ค„๋ฐ”๊ฟˆํ•ด ๋‘ ์‹ฌํŒ ๋ชจ๋‘ ๊ฐ์ (2026-10-19 15์ฐจ). ํŒจ๋„ ํ•˜๋‚˜๋งŒ ๋‘๋ฉด ์˜ค๋ฅธ์ชฝ ์—ด ์•„๋ž˜๊ฐ€ ๋น„์–ด "large empty area" ๊ฐ์ (11์ฐจ).
75
+ - **์ƒ์„ธ ์ฃผ ํ–‰๋™์€ ์ƒ์‚ฐ์  ํ–‰๋™ ํ•˜๋‚˜** โ€” `primaryAction` ์€ ๋ฐฐํฌยท์‹คํ–‰ยท์ €์žฅ์ฒ˜๋Ÿผ ๋˜๋Œ๋ฆด ์ˆ˜ ์žˆ๋Š” ๊ฒƒ. ์ค‘์ง€ยท์‚ญ์ œยท์ดˆ๊ธฐํ™”๋Š” `secondaryActions`(ํšŒ์ƒ‰) ๋˜๋Š” โ‹ฏ ๋ฉ”๋‰ด(`deleteAction`) โ€” primary ํŒŒ๋ž‘๋„ ๋นจ๊ฐ„ ์ฑ„์›€๋„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค(5์ฐจ ๋นจ๊ฐ„ ๋ฒ„ํŠผยท15์ฐจ ํŒŒ๋ž€ "์‹คํ—˜ ์ค‘์ง€" ๊ฐ์ ).
76
+ - **์ƒํƒœ ๋‹จ์–ด๋Š” ํ•œ ํ‘œ์—์„œ** โ€” ์ƒํƒœ๊ฐ’ โ†’ ๋ผ๋ฒจยทtone ๋งคํ•‘ ๊ฐ์ฒด ํ•˜๋‚˜๋ฅผ ํ—ค๋” ๋ฑƒ์ง€ยทํ‘œยทํƒญ์ด ๊ฐ™์ด ์“ด๋‹ค("์ง„ํ–‰ ์ค‘" vs "์‹คํ–‰ ์ค‘" ์ฒ˜๋Ÿผ ๊ฐˆ๋ฆฌ๋ฉด ๊ฐ์ , 15์ฐจ). ์ง„ํ–‰๋ฅ ์€ "์™„๋ฃŒ 10 / ์ „์ฒด 12 ยท ์‹คํŒจ 2" ์ฒ˜๋Ÿผ ํ’€์–ด ์“ด๋‹ค.
77
+ - **์•„์ด์ฝ˜ยท๊ธ€์ž** โ€” ์ค‘์ง€๋Š” `circle-stop`(`square` ๋Š” ์ฒดํฌ๋ฐ•์Šค๋กœ ์ฝํž˜). ํƒœ๊ทธยท๋ฑƒ์ง€ ๊ธ€์ž๋Š” ํ•œ๊ตญ์–ด, ์˜๋ฌธ์€ ๊ณ ์œ ๋ช…์‚ฌ๋งŒ("Best run" ๊ฐ™์€ ์žฅ์‹ ์˜๋ฌธ ๊ฐ์ , 15์ฐจ).
78
+ - **์ƒ์„ธ ๋ณธ๋ฌธ ๊ตฌ์—ญ์€ `Panel title='โ€ฆ'` ์•ˆ์— `MetaList`** โ€” ๊ตฌ์—ญ๋งˆ๋‹ค ์ƒ์ž ํ•˜๋‚˜, ์ƒ์ž ์‚ฌ์ด 16px. `Separator`ยท`Card`ยท๋งจ `<h2>` ๋กœ ๋‚˜๋ˆ„์ง€ ์•Š๋Š”๋‹ค. ์˜† ํŒจ๋„(`aside`)ยท๋ชฉ๋ก์˜ ์ƒ์„ธ ํŒจ๋„(`detail`)ยทํผ์˜ ๊ฒ€ํ†  ํŒจ๋„(`aside`)์€ ํŒจํ„ด์ด ๊ฐ™์€ Panel ๋กœ ๊ทธ๋ฆฌ๋ฏ€๋กœ ์•ˆ์— ์ƒ์ž๋ฅผ ๋˜ ๋‘๋ฅด์ง€ ์•Š๋Š”๋‹ค. ํ‘œ(`Table`ยท`AgGridTable`)๋Š” ์ž๊ธฐ ์ƒ์ž๊ฐ€ ์žˆ์œผ๋‹ˆ Panel ๋กœ ๊ฐ์‹ธ์ง€ ์•Š๋Š”๋‹ค.
79
+ - **ํผ ์˜† ๊ฒ€ํ† ยท์š”์•ฝ ํŒจ๋„์€ `FormPage aside={โ€ฆ} asideTitle='๊ฒ€ํ† '`** ๋กœ โ€” ํŒจํ„ด์ด ํผ ์—ด ์˜†์— ์„ธ๋กœ์„ ์œผ๋กœ ๊ตฌ๋ถ„ํ•ด sticky ๋กœ ๋”ฐ๋ผ์˜ค๊ฒŒ ๊ทธ๋ฆฐ๋‹ค(์ข์œผ๋ฉด ํผ ์•„๋ž˜). FormPage ๋ฅผ `<div className='flex'>` ๋กœ ๊ฐ์‹ธ ์˜†์— `<aside>` ๋ฅผ ๋‘์ง€ ์•Š๋Š”๋‹ค: ํ—ค๋”๊ฐ€ ํ™”๋ฉด ํญ์„ ๋‹ค ๋ชป ์จ ๊ตฌ๋ถ„์„ ์ด ํŒจ๋„์—์„œ ๋Š๊ธฐ๊ณ , ํŒจ๋„์ด ์ค‘๊ฐ„์—์„œ ์ž˜๋ฆฐ๋‹ค. Card(๊ทธ๋ฆผ์ž)๋กœ ๋งŒ๋“ค์ง€๋„ ์•Š๋Š”๋‹ค. FormPage ๋Š” ํ—ค๋” ๋‚ด์šฉ๊ณผ ๋ณธ๋ฌธ์„ ๊ฐ™์€ ๊ฐ€์šด๋ฐ ํญ(ํŒจ๋„ ์žˆ์œผ๋ฉด 1152, ์—†์œผ๋ฉด 720)์— ๊ฐ€๋‘”๋‹ค(2026-10-26 22์ฐจ) โ€” ๋ฐ”๊นฅ์—์„œ `max-w`ยท`mx-auto` ๋กœ ๋˜ ๊ฐ์‹ธ์ง€ ์•Š๋Š”๋‹ค.
80
+ - **๋‚ ์งœยท์‹œ๊ฐ ์ž…๋ ฅ์€ `DatePicker`ยท`TimePicker` ๋กœ, ํผ ์นธ์„ ์ฑ„์šฐ๊ฒŒ** โ€” ๊ธฐ๋ณธ ํญ์ด 250ยท160px ๋ผ ๋‘ ์นธ ์ค„์—์„œ ์ ˆ๋ฐ˜์ด ๋นˆ๋‹ค(2026-10-28 ํ™€๋“œ์•„์›ƒ 14, OpusยทGemini "date/time fields leave a lot of unused space"). `DatePicker classNames={{ button: 'w-full' }}`ยท`TimePicker classNames={{ trigger: 'w-full' }}`(๋‘ ๋ถ€ํ’ˆ์˜ ํ†ต๋กœ ์ด๋ฆ„์ด ๋‹ค๋ฅด๋‹ค). `<input type='date'>` ๋ฅผ ์ง์ ‘ ์“ฐ์ง€ ์•Š๋Š”๋‹ค.
81
+ - **๋ชฉ ๋ฐ์ดํ„ฐ๋Š” ์˜๋ฏธ๊ฐ€ ๋งž๊ฒŒ, ์–‘๋„ ํ™”๋ฉด์„ ์ฑ„์šธ ๋งŒํผ** โ€” ํƒœ์Šคํฌยทํ”„๋ ˆ์ž„์›Œํฌยท์ด๋ฆ„ยท์ƒํƒœ๊ฐ€ ์„œ๋กœ ์–ด์šธ๋ฆฌ๋Š” ์กฐํ•ฉ(์˜ˆ: `yolo-v8-detector` ๋Š” `object-detection` + `PyTorch`), ๋‚ ์งœ๋Š” ์ƒ์„ฑ์ผ โ‰ค ์ˆ˜์ •์ผ, ๊ฑด์ˆ˜๋Š” ๋ชฉ๋ก ๊ธธ์ด์™€ ์ผ์น˜. **๋ชฉ๋ก์€ 20ํ–‰ ์ด์ƒ**(ํŽ˜์ด์ง€ ํฌ๊ธฐ 20 ์ด๋ฉด ๋‘ ํŽ˜์ด์ง€ ๋ถ„๋Ÿ‰) โ€” 10~12ํ–‰์ด๋ฉด ํ‘œ ์•„๋ž˜๊ฐ€ ๋น„์–ด ์‹ฌ์‚ฌ์ž๊ฐ€ "๋นˆ ๊ณต๊ฐ„" ์œผ๋กœ ๊นŽ๋Š”๋‹ค(ํ•œ ์ค„ ํŒ 12์ฐจ 6์Œ, 2026-10-18). ์‹ฌ์‚ฌ์ž๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋ง์ด ๋˜๋Š”์ง€๋„ ๋ณธ๋‹ค.
82
+ - **ํ‘œ ์—ด ํญ** โ€” ์ด๋ฆ„ ์—ด `flex: 2, minWidth: 200, maxWidth: 480`, **๊ธ€์ž๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ์—ด์€ ๋ชจ๋‘** `flex: 1, minWidth: 120`(์†Œ์œ ์žยทํŒ€ยทํ”„๋ ˆ์ž„์›Œํฌยท์„ค๋ช… โ€” ํ•˜๋‚˜๋งŒ ๊ณ ๋ฅด์ง€ ์•Š๋Š”๋‹ค. ๋‚จ๋Š” ํญ์ด ์—ฌ๋Ÿฌ ์—ด๋กœ ํฉ์–ด์ ธ์•ผ ์ด๋ฆ„ ์—ด๋งŒ ๋„“์–ด์ง€์ง€ ์•Š๋Š”๋‹ค; ๊ธ€์ž ์—ด์ด ํ•˜๋‚˜๋ฟ์ด๋ฉด 2:1 ๋กœ ๋‚˜๋ˆ ๋„ ์ด๋ฆ„ ์—ด์ด 500px ๋ผ "name column leaves substantial whitespace", 2026-10-20 17์ฐจยท18์ฐจ), ์ˆซ์žยท๋‚ ์งœยท์ƒํƒœยท์ง„ํ–‰๋ฅ  ์—ด์€ `width` ๋กœ โ€” **์ˆซ์ž ์—ด์€ `type: 'number'` ๋งŒ ์ฃผ๊ณ  `flex` ๋ฅผ ์ฃผ์ง€ ์•Š๋Š”๋‹ค**(ํญ ์—†์œผ๋ฉด 140). DS `Table` ์˜ ์ˆซ์ž ์—ด์€ `TableHead align='right'` ๋กœ โ€” ํญ 140 ์œผ๋กœ ๊ณ ์ •๋ผ ๊ธ€์ž ์—ด์ด ๋‚จ๋Š” ํญ์„ ๊ฐ€์ง„๋‹ค(ํ‘œ๊ฐ€ `table-fixed` ๋ผ ๋จธ๋ฆฌ๊ธ€์˜ `align` ์ด ์—ด ํญ์„ ์ •ํ•œ๋‹ค). **DS `Table` ์˜ ์ƒํƒœ ์—ด์€ `TableHead className='w-32'`, ๋‚ ์งœยท์‹œ๊ฐ ์—ด์€ `className='w-44'` ๋กœ ํญ์„ ์ค€๋‹ค** โ€” ํญ ์—†๋Š” ์—ด์€ ๋‚จ๋Š” ํญ์„ ๋˜‘๊ฐ™์ด ๋‚˜๋ˆ  ๊ฐ€์ ธ ๋ฑƒ์ง€ ํ•˜๋‚˜๋ฟ์ธ ์ƒํƒœ ์—ด์ด 400px ๊ฐ€ ๋œ๋‹ค(2026-10-30 ํ™€๋“œ์•„์›ƒ 17 "large empty gap between the status and GPU columns"). ๋‚จ๋Š” ํญ์€ ์ด๋ฆ„ยท๊ธ€์ž ์—ด์ด ๋‚˜๋ˆˆ๋‹ค. ๊ธ€์ž ์—ด์ด ํ•˜๋‚˜๋„ ์—†์œผ๋ฉด `maxWidth` ๋ฅผ ๋บ€๋‹ค(ํ‘œ ์˜ค๋ฅธ์ชฝ์ด ๋นˆ๋‹ค โ€” ์ƒํ•œ ์—†๋Š” flex ์—ด์ด ์—†์œผ๋ฉด AgGridTable ์ด flex ์—ด์˜ `maxWidth` ๋ฅผ ๋–ผ์–ด ํ‘œ๋ฅผ ์ฑ„์šด๋‹ค, 2026-10-28 ํ™€๋“œ์•„์›ƒ 14 "row dividers stop around 1330px")(์ œ๋ชฉ ๊ธ€์ž๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ์ตœ์†Œ ํญ์€ AgGridTable ์ด ๋ณด์ •ํ•˜๊ณ  ๋„˜์น˜๋Š” ์…€ ๊ธ€์ž๋Š” ๋ง์ค„์ž„ํ‘œ๋กœ ๋๋‚œ๋‹ค). ์—ด์€ 6~7๊ฐœ ์ด๋‚ด๋กœ โ€” **๋ณด์กฐ ์ •๋ณด(idยท์ด๋ฏธ์ง€ยท๊ฒฝ๋กœยท์„ค๋ช…)๋Š” ์—ด์„ ๋Š˜๋ฆฌ์ง€ ๋ง๊ณ  `ListPage secondaryField='image'` ๋กœ ์ด๋ฆ„ ์•„๋ž˜ 12px ์ค„์—**(dl-ui-v3 ๋ชฉ๋ก์˜ ์ด๋ฆ„ / ์„ค๋ช… ์…€; ํŒจํ„ด์ด ํ–‰์„ 56 ์œผ๋กœ ๊ทธ๋ฆฐ๋‹ค). ์…€๋งˆ๋‹ค `cellStyle`ยท`width: 110` ๊ฐ™์€ ์ข์€ ํญ์„ ์†์œผ๋กœ ๋งž์ถ”์ง€ ์•Š๋Š”๋‹ค(2026-10-18 13์ฐจ). **์ฃผ ์‹๋ณ„์ž๊ฐ€ ์งง์€ IDยท์ฝ”๋“œ(์š”์ฒญ IDยท์ปค๋ฐ‹ ํ•ด์‹œยทํ‚ค)๋ฉด ์ด๋ฆ„ ์—ด ๊ณต์‹(`flex: 2`) ๋Œ€์‹  `width: 200` ์œผ๋กœ ๊ณ ์ •**ํ•˜๊ณ , ๋‚จ๋Š” ํญ์€ ์—”๋“œํฌ์ธํŠธยท๋ชจ๋ธยท์„ค๋ช… ๊ฐ™์€ ๊ธ€์ž ์—ด(`flex: 1`)์ด ๋‚˜๋ˆˆ๋‹ค โ€” ID ์—ด์ด ๋‚จ๋Š” ํญ์„ ๋‹ค ๋ฐ›์œผ๋ฉด "request ID column is too wide"(2026-10-28 ํ™€๋“œ์•„์›ƒ 14, ๋ชฉ๋ก 3/3).
83
+ - **๋„์›€๋ง ๋ฌธ๊ตฌ(`FormDescription`)๋Š” ๊ทœ์น™ยท์ „์ œยท์ถ”์ฒœ๊ฐ’** โ€” "์‹คํ–‰ ๊ฒฝ๋กœ์— ์“ฐ์—ฌ ๋งŒ๋“  ๋’ค ๋ฐ”๊ฟ€ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์˜๋ฌธ ์†Œ๋ฌธ์žยท์ˆซ์žยทํ•˜์ดํ”ˆ 3~40์ž", "1~32 ์ฝ”์–ด. ์ „์ฒ˜๋ฆฌ๋Š” 2~4, ํ•™์Šต์€ 8 ์ด์ƒ์„ ๊ถŒํ•ฉ๋‹ˆ๋‹ค". placeholder ์™€ ๊ฐ™์€ ๋ง("1~64" / "1~64")์„ ๋˜ํ’€์ดํ•˜์ง€ ์•Š๊ณ , placeholder ๋Š” "์˜ˆ: 4" ๊ฐ™์€ ๋ณด๊ธฐ ํ•˜๋‚˜. **๋„์›€๋งยท์„ ํƒ์ง€ ์„ค๋ช…์€ ๋ฌธ์žฅ ๋ ๋งˆ์นจํ‘œ ์—†์ด ํ†ต์ผ**ํ•œ๋‹ค(๋‘ ๋ฌธ์žฅ์„ ์ด์„ ๋•Œ๋งŒ ๊ฐ€์šด๋ฐ ๋งˆ์นจํ‘œ โ€” "1~32 ์ฝ”์–ด. ์ „์ฒ˜๋ฆฌ๋Š” 2~4") โ€” ์ผ๋ถ€๋งŒ ๋งˆ์นจํ‘œ๊ฐ€ ๋ถ™์œผ๋ฉด ์‹ฌ์‚ฌ์ž๊ฐ€ copy ๋ถˆ์ผ์น˜๋กœ ๋ณธ๋‹ค(2026-10-18 13์ฐจ ํผ). ๊ฒ€ํ† ยท์š”์•ฝ ํŒจ๋„์˜ **๋นˆ ๊ฐ’์€ "โ€”" ํ•˜๋‚˜**(๋‹จ์œ„๋Š” ๊ฐ’์ด ์žˆ์„ ๋•Œ๋งŒ โ€” "CPU โ€”์ฝ”์–ด ยท ๋ฉ”๋ชจ๋ฆฌ โ€”GB" ์ฒ˜๋Ÿผ ์ด์–ด ๋ถ™์ด์ง€ ์•Š๊ณ  ํ•ญ๋ชฉ๋งˆ๋‹ค ํ•œ ํ–‰). ์˜ˆ์ œ form-page.tsx ์˜ ๋ฆฌ์†Œ์Šค ์„น์…˜ยท๊ฒ€ํ†  ํŒจ๋„์ด ๋ณธ๋ณด๊ธฐ(2026-10-18 13์ฐจ, ๊ธฐ์ค€์„  copy 12์Œ ๋ฒค์น˜๋งˆํ‚น).
84
+ - **๊ธ€์ž ์ˆ˜("0 / 500์ž") ๊ฐ™์€ ๋ณด์กฐ ํ‘œ์‹œ๋Š” `FormDescription icon={false}`** โ€” `FormDescription` ์€ ์•ž์— ์ •๋ณด ์•„์ด์ฝ˜์„ ๊ทธ๋ฆฌ๋ฏ€๋กœ ์•ˆ๋‚ด ๋ฌธ์žฅ์—๋งŒ ์“ด๋‹ค(2026-10-28 ํ™€๋“œ์•„์›ƒ 15, OpusยทGemini "info icon next to a simple character counter").
85
+ - **ํ‘œ ์•ˆ ์ง„ํ–‰๋ฅ  ์—ด์€ `type: 'number'` ๋ฅผ ์ฃผ์ง€ ์•Š๋Š”๋‹ค** โ€” ์˜ค๋ฅธ์ชฝ ์ •๋ ฌ์ด ๋˜๋ฉด % ๊ธ€์ž ํญ์— ๋”ฐ๋ผ ๋ง‰๋Œ€ ์‹œ์ž‘์ ์ด ํ”๋“ค๋ฆฐ๋‹ค. ์…€ ์•ˆ์—์„œ `Progress` ๋Š” ๊ณ ์ • ํญ(`w-24`), % ๊ธ€์ž๋„ ๊ณ ์ • ํญ(`w-10 text-right tabular-nums`)์œผ๋กœ ๋‚˜๋ž€ํžˆ ๋‘๊ณ , ์ •์ง€ยท๋Œ€๊ธฐ ํ–‰๋„ ๋นˆ ๋ง‰๋Œ€(`value={0}`)๋ฅผ ๊ทธ๋ฆฐ๋‹ค(2026-10-28 ํ™€๋“œ์•„์›ƒ 15, "progress bars have uneven lengths and starting points").
86
+ - **์˜ค๋ฅ˜ยท์—†์Œ ํ™”๋ฉด์€ ํŒจํ„ด prop ์œผ๋กœ** โ€” DetailPage `error`/`notFound`, DashboardLayout `error`/`empty`, ListPage `error`/`emptyState`. ํŒจํ„ด์ด ๊ทธ๋ฆผ(๋นˆ ์ƒํƒœ๋Š” `EmptyBoxIllustration` ์ƒ์ž ์ผ๋Ÿฌ์ŠคํŠธ, ์˜ค๋ฅ˜๋Š” ๊ฒฝ๊ณ  ์•„์ด์ฝ˜)ยท์ œ๋ชฉยท์„ค๋ช…ยท"๋‹ค์‹œ ์‹œ๋„" ์ƒ์ž๋กœ ๊ทธ๋ฆฐ๋‹ค. ๋นจ๊ฐ„ `Alert` ์ค„์ด๋‚˜ `<div>` ๋กœ ๋ณธ๋ฌธ์„ ๋Œ€์ฒดํ•˜์ง€ ์•Š๋Š”๋‹ค. ํŒจํ„ด ๋ฐ–(ํผ์˜ ์„ ํƒ์ง€ ๋ชฉ๋ก ๋“ฑ)์—์„œ๋Š” `@t3q-ui/design-system/patterns` ์˜ `ErrorState`ยท`EmptyState` ๋ฅผ ์“ด๋‹ค.
87
+ - ํผ์˜ ์„ ํƒ์ง€ ๋ชฉ๋ก(์‹คํ–‰ํ™˜๊ฒฝ ๋“ฑ)์„ ๋ชป ๋ถˆ๋Ÿฌ์™”์œผ๋ฉด **ํผ์„ ์ง€์šฐ์ง€ ๋ง๊ณ ** ๊ทธ ์„น์…˜ ์•ˆ์— `Alert variant='danger'`(์•„์ด์ฝ˜ + ํ•œ ์ค„ ์ œ๋ชฉ + ์„ค๋ช… + `AlertActions` ์˜ ๋งํฌํ˜• "๋‹ค์‹œ ์‹œ๋„")๋ฅผ ๋‘”๋‹ค. `ErrorState` ์ƒ์ž๋Š” ํ™”๋ฉดยทํŒจ๋„ ๋ณธ๋ฌธ์„ ํ†ต์งธ๋กœ ๋ชป ๋ถˆ๋Ÿฌ์™”์„ ๋•Œ๋งŒ. ์ œ์ถœ ๋ฒ„ํŠผ์€ ๊ธฐ๋ณธ์œผ๋กœ ํ•ญ์ƒ ๋ˆŒ๋ฆฌ๊ณ  ๋ˆ„๋ฅด๋ฉด ๊ฒ€์ฆํ•ด ํ‹€๋ฆฐ ํ•ญ๋ชฉ๋งˆ๋‹ค `FormMessage` ๋ฅผ ๋ณด์ธ๋‹ค(`submitMode` ๊ธฐ๋ณธ `always`).
88
+ - ์ˆซ์ž ์ž…๋ ฅ์˜ ๋‹จ์œ„(๊ฐœยทGBยท์ฝ”์–ด)๋Š” `TextField elemAfterInput='๊ฐœ'` ๋กœ ์ž…๋ ฅ ์นธ ์•ˆ์— ๋ถ™์ธ๋‹ค. ๋ผ๋ฒจ์— "(GB)" ๋ฅผ ๋„ฃ๊ฑฐ๋‚˜ ์˜†์— `<span>` ์„ ๋‘์ง€ ์•Š๋Š”๋‹ค.
89
+ - **๊ฐ„๊ฒฉ์€ ์„ธ ๋‹จ๊ณ„** โ€” ๋ถ™์–ด ์žˆ๋Š” ์š”์†Œ 8, ํ•œ ๋ฌถ์Œ ์•ˆ 16, ๋ฌถ์Œ(์„น์…˜) ์‚ฌ์ด 32(ํผ ์„น์…˜ ์‚ฌ์ด 48, ์ƒ์„ธ ํŒจ๋„ ์‚ฌ์ด๋Š” ํŒจํ„ด ๊ธฐ๋ณธ 24). ํŒจํ„ด์ด ๊ธฐ๋ณธ์œผ๋กœ ๊ทธ๋ฆฌ๋‹ˆ `gap`ยท`space-y` ๋ฅผ ๋ง๋ถ™์—ฌ ํ‰ํ‰ํ•˜๊ฒŒ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. ๊ฐ™์€ 16 ์ด๋‚˜ 24 ๊ฐ€ ํ™”๋ฉด ์ „์ฒด์— ๋ฐ˜๋ณต๋˜๋ฉด ํ‹€๋ฆฐ ๊ฒƒ์ด๋‹ค(2026-10-17).
90
+ - ์ƒ์„ธ ํŒจ๋„ยท์ •๋ณด ์—ด์˜ ๊ฐ’์€ 14px ๊ธฐ๋ณธ, ๋ผ๋ฒจ 12px โ€” **ํ–‰๋งˆ๋‹ค ๊ฐ’ ํฌ๊ธฐ๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค**(8์ฐจ์— ๊ฑด์ˆ˜ยท์šฉ๋Ÿ‰ ํ–‰๋งŒ 20px ๋กœ ํ‚ค์› ๋”๋‹ˆ ์‹ฌํŒ์ด "ํŒจ๋„ ์•ˆ ํฌ๊ธฐ๊ฐ€ ๋“ค์ญ‰๋‚ ์ญ‰"์œผ๋กœ ์ฝ์–ด ๊ฐ์ , 2026-10-18 ๋˜๋Œ๋ฆผ).
91
+ - ๋Œ€์‹œ๋ณด๋“œ ์š”์•ฝ ํƒ€์ผ์˜ ์‚ฌ์šฉ๋ฅ ์€ `stats` ํ•ญ๋ชฉ์— `ratio`(0~1 โ†’ ์ง„ํ–‰ ๋ง‰๋Œ€)์™€ `tone`(๊ธฐ์ค€ ์ดˆ๊ณผ๋ฉด `'warning'`)์„ ์ค€๋‹ค. ์ตœ๊ทผ ์ด๋ฒคํŠธ๋Š” `EventList`(๋ ˆ๋ฒจ ์ƒ‰ ๋  + Badge + ์‹œ๊ฐ).