@spectrabrain/eds 0.1.0 → 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 (62) hide show
  1. package/AI.md +13 -63
  2. package/AI_CONTEXT.json +26 -95
  3. package/CHANGELOG.md +70 -4
  4. package/CONSUMER_AGENT.md +86 -164
  5. package/FRONTEND_CONVENTIONS.md +252 -0
  6. package/QUICKSTART.md +24 -29
  7. package/README.md +29 -73
  8. package/TAILWIND_V4.md +52 -184
  9. package/TOKEN_CONTEXT.md +79 -36
  10. package/consumer/align/templates/components.json +21 -0
  11. package/consumer/align/templates/env.mock +1 -0
  12. package/consumer/align/templates/eslint.config.js +35 -0
  13. package/consumer/align/templates/package.scripts.json +10 -0
  14. package/consumer/align/templates/prettierignore +2 -0
  15. package/consumer/align/templates/prettierrc.json +7 -0
  16. package/consumer/align/templates/src/app/App.tsx +16 -0
  17. package/consumer/align/templates/src/app/main.tsx +27 -0
  18. package/consumer/align/templates/src/app/providers/ErrorBoundary.tsx +58 -0
  19. package/consumer/align/templates/src/app/providers/ErrorHandler.tsx +29 -0
  20. package/consumer/align/templates/src/app/router/index.tsx +23 -0
  21. package/consumer/align/templates/src/app/styles/index.css +2 -0
  22. package/consumer/align/templates/src/mocks/browser.ts +5 -0
  23. package/consumer/align/templates/src/mocks/handlers.ts +4 -0
  24. package/consumer/align/templates/src/shared/api/index.ts +23 -0
  25. package/consumer/align/templates/src/shared/api/queryClient.ts +24 -0
  26. package/consumer/align/templates/src/shared/lib/eventBus.ts +44 -0
  27. package/consumer/align/templates/src/shared/lib/utils/index.ts +6 -0
  28. package/consumer/align/templates/src/vite-env.d.ts +2 -0
  29. package/consumer/align/templates/tsconfig.json +22 -0
  30. package/consumer/align/templates/vite.config.babel.ts +36 -0
  31. package/consumer/align/templates/vite.config.rolldown.ts +35 -0
  32. package/consumer/align-analysis.mjs +1159 -0
  33. package/consumer/align-plan.mjs +377 -0
  34. package/consumer/align-rules.mjs +473 -0
  35. package/consumer/align.mjs +401 -0
  36. package/consumer/cli.mjs +90 -40
  37. package/consumer/css-root.mjs +24 -4
  38. package/consumer/doctor.mjs +47 -21
  39. package/consumer/generate-tailwind.mjs +41 -1
  40. package/consumer/init.mjs +39 -25
  41. package/consumer/managed-block.mjs +11 -5
  42. package/consumer/paths.mjs +69 -14
  43. package/consumer/register-scripts.mjs +17 -12
  44. package/consumer/scan-classes.mjs +24 -5
  45. package/consumer/sync.mjs +35 -13
  46. package/consumer/update-agent-context.mjs +63 -7
  47. package/consumer-postinstall.mjs +8 -7
  48. package/dist/components/Button/README.md +66 -95
  49. package/dist/components/Button/spec.json +19 -138
  50. package/dist/components.css +102 -366
  51. package/dist/index.d.mts +20 -18
  52. package/dist/index.d.ts +20 -18
  53. package/dist/index.js +301 -1
  54. package/dist/index.mjs +301 -1
  55. package/dist/tokens.css +30 -0
  56. package/dist/tokens.d.mts +7 -3
  57. package/dist/tokens.d.ts +7 -3
  58. package/dist/tokens.js +301 -1
  59. package/dist/tokens.json +360 -0
  60. package/dist/tokens.mjs +301 -1
  61. package/llms.txt +20 -14
  62. package/package.json +3 -1
@@ -0,0 +1,473 @@
1
+ // The EVA frontend conventions as data. FRONTEND_CONVENTIONS.md states the same rules in prose, and
2
+ // scripts/check-consumer-guidance.mjs checks that every replacement category and layer listed here appears there.
3
+
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ export const alignDirectory = ".eds/align";
9
+ export const planFileName = "PLAN.md";
10
+ export const stateFileName = "state.json";
11
+ export const templatesDirectoryName = "templates";
12
+ export const stateSchemaVersion = 1;
13
+ export const conventionsFileName = "FRONTEND_CONVENTIONS.md";
14
+
15
+ // FSD layers from top to bottom. A module imports only layers below its own, plus its own slice.
16
+ export const layerOrder = ["app", "pages", "widgets", "features", "entities", "shared"];
17
+ // Layers whose second path segment is a slice (pages/<domain>, widgets/<name>, features/<domain>, entities/<domain>).
18
+ export const slicedLayers = new Set(["pages", "widgets", "features", "entities"]);
19
+ // src/ entries allowed besides the layers: MSW handlers, global declaration files and the file eds sync generates.
20
+ export const auxiliarySourceDirectories = ["mocks", "types", "styles"];
21
+ export const allowedSourceRootFiles = ["vite-env.d.ts"];
22
+ export const generatedStylesFileName = "eds-tokens.css";
23
+
24
+ export const appEntries = ["main.tsx", "App.tsx", "providers", "router", "styles"];
25
+ export const entitySegments = ["components", "hooks", "services", "stores", "types", "lib"];
26
+ export const featureSegments = ["ui", "lib", "types"];
27
+ export const sharedSegments = ["api", "assets", "hooks", "lib", "ui"];
28
+
29
+ // Relative to the source directory (src/) and to the Vite root (the directory of index.html).
30
+ export const requiredSourceFiles = [
31
+ "app/main.tsx",
32
+ "app/App.tsx",
33
+ "app/router/index.tsx",
34
+ "app/styles/index.css",
35
+ "shared/api/index.ts",
36
+ "shared/api/queryClient.ts",
37
+ "shared/lib/utils/index.ts",
38
+ ];
39
+ export const entryModule = "app/main.tsx";
40
+
41
+ // Scripts every aligned frontend declares; the value is what the template uses when the script is missing.
42
+ export const requiredScripts = {
43
+ lint: "eslint .",
44
+ format: "prettier --write .",
45
+ "format:check": "prettier --check .",
46
+ typecheck: "tsc --noEmit",
47
+ build: "vite build",
48
+ };
49
+
50
+ // Packages an aligned frontend declares. axios is required unless the app talks to its backend only through a data SDK.
51
+ export const requiredDependencies = [
52
+ "react",
53
+ "react-dom",
54
+ "react-router-dom",
55
+ "@tanstack/react-query",
56
+ "sonner",
57
+ "clsx",
58
+ "tailwind-merge",
59
+ "tailwindcss",
60
+ "@spectrabrain/eds",
61
+ ];
62
+ export const requiredDevDependencies = [
63
+ "vite",
64
+ "@vitejs/plugin-react",
65
+ "@tailwindcss/vite",
66
+ "@types/react",
67
+ "@types/react-dom",
68
+ "babel-plugin-react-compiler",
69
+ "typescript",
70
+ "eslint",
71
+ "@eslint/js",
72
+ "typescript-eslint",
73
+ "eslint-plugin-react-hooks",
74
+ "eslint-plugin-react-refresh",
75
+ "globals",
76
+ "prettier",
77
+ ];
78
+ // Vite 8 moved Babel out of @vitejs/plugin-react; the React Compiler then runs through this plugin.
79
+ export const rolldownBabelPackage = "@rolldown/plugin-babel";
80
+ export const minimumMajors = { react: 19, "@tanstack/react-query": 5, tailwindcss: 4 };
81
+
82
+ // Install ranges the templates are written against. Packages without a range install at their latest version.
83
+ export const installRanges = {
84
+ eslint: "^9.22",
85
+ "@eslint/js": "^9.22",
86
+ "typescript-eslint": "^8",
87
+ "eslint-plugin-react-hooks": "^7",
88
+ "eslint-plugin-react-refresh": "^0.4.20",
89
+ prettier: "^3",
90
+ "babel-plugin-react-compiler": "^1",
91
+ tailwindcss: "^4",
92
+ "@tailwindcss/vite": "^4",
93
+ "@types/react": "^19",
94
+ "@types/react-dom": "^19",
95
+ "@tanstack/react-query": "^5",
96
+ react: "^19",
97
+ "react-dom": "^19",
98
+ };
99
+ // The oldest versions the eslint.config template loads with (eslint/config defineConfig, react-hooks flat configs,
100
+ // react-refresh configs.vite). An older declared or installed version fails the check and is reinstalled in step 3.
101
+ export const templateToolMinimums = {
102
+ eslint: "9.22.0",
103
+ "@eslint/js": "9.22.0",
104
+ "typescript-eslint": "8.0.0",
105
+ "eslint-plugin-react-hooks": "7.0.0",
106
+ "eslint-plugin-react-refresh": "0.4.20",
107
+ };
108
+ // Installed with the tooling step although no check requires them: the templates reference them.
109
+ export const templateDevDependencies = ["vite-plugin-svgr", "terser", "tw-animate-css", "msw"];
110
+ // The lucide-react version EDS depends on: a consumer that imports lucide-react directly declares the same one, so the
111
+ // icon code is bundled once.
112
+ export const edsLucideVersion = JSON.parse(fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf8")).dependencies?.["lucide-react"] ?? null;
113
+ // Installed in step 6 only when the app calls a REST API that gets MSW handlers.
114
+ export const mockDevDependencies = ["@faker-js/faker"];
115
+
116
+ // Tests are outside the conventions: a prototype's test policy may change at any time. eds align neither requires,
117
+ // replaces nor lists test tooling, and leaves test files, test directories and test setup files where they are.
118
+ export const testDirectoryNames = ["test", "tests", "__tests__", "__mocks__"];
119
+ export const testFilePattern = /\.(?:test|spec)\.[cm]?[jt]sx?$/;
120
+ export const testSetupFilePattern = /^(?:setupTests|setup-tests|testSetup|test-setup|vitest\.setup|jest\.setup)\.[cm]?[jt]sx?$/;
121
+ export const testToolingPattern =
122
+ /^(?:jest|jest-.+|@jest\/.+|ts-jest|babel-jest|vitest|@vitest\/.+|@testing-library\/.+|cypress|@cypress\/.+|playwright|@playwright\/.+|happy-dom|jsdom|enzyme|enzyme-.+|identity-obj-proxy|mocha|chai|sinon|nock|supertest)$/;
123
+
124
+ // Libraries a prototype often brings and the EVA standard that replaces each category.
125
+ export const replacementRules = [
126
+ { category: "routing", target: "react-router-dom", packages: ["wouter", "@tanstack/react-router", "@reach/router"] },
127
+ { category: "server-state", target: "@tanstack/react-query", packages: ["swr", "react-query"] },
128
+ {
129
+ category: "http",
130
+ target: "axios",
131
+ packages: ["ky", "ofetch", "redaxios", "wretch", "superagent", "cross-fetch", "isomorphic-fetch", "node-fetch"],
132
+ },
133
+ {
134
+ category: "client-state",
135
+ target: "zustand",
136
+ packages: [
137
+ "redux",
138
+ "@reduxjs/toolkit",
139
+ "react-redux",
140
+ "redux-thunk",
141
+ "redux-saga",
142
+ "redux-persist",
143
+ "jotai",
144
+ "recoil",
145
+ "mobx",
146
+ "mobx-react",
147
+ "mobx-react-lite",
148
+ "valtio",
149
+ "effector",
150
+ "effector-react",
151
+ "@preact/signals-react",
152
+ "@legendapp/state",
153
+ ],
154
+ },
155
+ {
156
+ category: "form",
157
+ target: "useState or Context + useReducer",
158
+ label: "useState 또는 Context + useReducer",
159
+ packages: ["react-hook-form", "@hookform/resolvers", "formik", "react-final-form", "final-form", "@tanstack/react-form"],
160
+ },
161
+ {
162
+ category: "validation",
163
+ target: "TypeScript types and validation functions",
164
+ label: "TypeScript 타입과 검증 함수",
165
+ packages: ["zod", "yup", "valibot", "joi", "superstruct"],
166
+ },
167
+ {
168
+ category: "styling",
169
+ target: "Tailwind CSS v4 + EDS tokens",
170
+ packages: [
171
+ "styled-components",
172
+ "@emotion/react",
173
+ "@emotion/styled",
174
+ "@emotion/css",
175
+ "sass",
176
+ "sass-embedded",
177
+ "less",
178
+ "stylus",
179
+ "@stitches/react",
180
+ "@vanilla-extract/css",
181
+ "goober",
182
+ "jss",
183
+ "react-jss",
184
+ "@pandacss/dev",
185
+ "twin.macro",
186
+ "unocss",
187
+ "windicss",
188
+ ],
189
+ },
190
+ {
191
+ category: "ui-kit",
192
+ target: "EDS Button + shadcn/ui (Radix)",
193
+ packages: [
194
+ "@mui/material",
195
+ "@mui/joy",
196
+ "@mui/lab",
197
+ "@mui/system",
198
+ "@material-ui/core",
199
+ "@chakra-ui/react",
200
+ "antd",
201
+ "@mantine/core",
202
+ "@mantine/hooks",
203
+ "react-bootstrap",
204
+ "bootstrap",
205
+ "reactstrap",
206
+ "@headlessui/react",
207
+ "@nextui-org/react",
208
+ "@heroui/react",
209
+ "daisyui",
210
+ "flowbite",
211
+ "flowbite-react",
212
+ "primereact",
213
+ "semantic-ui-react",
214
+ "@blueprintjs/core",
215
+ "rsuite",
216
+ "@fluentui/react",
217
+ "@radix-ui/themes",
218
+ ],
219
+ },
220
+ {
221
+ category: "icon",
222
+ target: "lucide-react",
223
+ packages: [
224
+ "react-icons",
225
+ "@heroicons/react",
226
+ "@fortawesome/react-fontawesome",
227
+ "@fortawesome/fontawesome-svg-core",
228
+ "@fortawesome/free-solid-svg-icons",
229
+ "@fortawesome/free-regular-svg-icons",
230
+ "@fortawesome/free-brands-svg-icons",
231
+ "@tabler/icons-react",
232
+ "@phosphor-icons/react",
233
+ "phosphor-react",
234
+ "@iconify/react",
235
+ "react-feather",
236
+ "@radix-ui/react-icons",
237
+ "@mui/icons-material",
238
+ "@ant-design/icons",
239
+ ],
240
+ },
241
+ { category: "toast", target: "sonner", packages: ["react-toastify", "react-hot-toast", "notistack"] },
242
+ { category: "date", target: "date-fns", packages: ["moment", "moment-timezone", "dayjs", "luxon"] },
243
+ { category: "virtual-list", target: "react-virtuoso", packages: ["react-window", "react-virtualized", "@tanstack/react-virtual"] },
244
+ { category: "api-mock", target: "msw", packages: ["miragejs"] },
245
+ {
246
+ category: "lint-format",
247
+ target: "ESLint flat config + Prettier",
248
+ packages: [
249
+ "@biomejs/biome",
250
+ "rome",
251
+ "oxlint",
252
+ "standard",
253
+ "xo",
254
+ "ts-standard",
255
+ "eslint-config-airbnb",
256
+ "eslint-config-airbnb-typescript",
257
+ "eslint-config-standard",
258
+ "eslint-config-react-app",
259
+ ],
260
+ },
261
+ { category: "build-plugin", target: "@vitejs/plugin-react", packages: ["@vitejs/plugin-react-swc", "@vitejs/plugin-react-oxc"] },
262
+ ];
263
+
264
+ // Client SDKs that carry the backend data contract. They stay, and shared/api creates their client once. With one of
265
+ // them and no fetch() call, axios is not required.
266
+ export const backendDataClientPackages = [
267
+ "@supabase/supabase-js",
268
+ "@supabase/ssr",
269
+ "firebase",
270
+ "appwrite",
271
+ "pocketbase",
272
+ "convex",
273
+ "@trpc/client",
274
+ "@trpc/react-query",
275
+ "@trpc/tanstack-react-query",
276
+ "@apollo/client",
277
+ "urql",
278
+ "graphql-request",
279
+ "aws-amplify",
280
+ ];
281
+ // Auth and payment SDKs: they stay, but REST calls next to them still go through axios.
282
+ export const serviceClientPackages = [
283
+ "@clerk/clerk-react",
284
+ "@auth0/auth0-react",
285
+ "@stripe/stripe-js",
286
+ "@stripe/react-stripe-js",
287
+ ];
288
+ export const backendClientPackages = [...backendDataClientPackages, ...serviceClientPackages];
289
+
290
+ // Server-side packages: when the frontend package declares one, it also contains backend code.
291
+ export const backendServerPackages = [
292
+ "express",
293
+ "fastify",
294
+ "koa",
295
+ "@koa/router",
296
+ "hono",
297
+ "@hono/node-server",
298
+ "@nestjs/core",
299
+ "drizzle-orm",
300
+ "drizzle-kit",
301
+ "prisma",
302
+ "@prisma/client",
303
+ "mongoose",
304
+ "pg",
305
+ "postgres",
306
+ "mysql2",
307
+ "better-sqlite3",
308
+ "sqlite3",
309
+ "knex",
310
+ "sequelize",
311
+ "typeorm",
312
+ "socket.io",
313
+ "ws",
314
+ "passport",
315
+ "express-session",
316
+ "connect-pg-simple",
317
+ "memorystore",
318
+ "@neondatabase/serverless",
319
+ "json-server",
320
+ ];
321
+
322
+ // Stack changes that are framework migrations, not alignment: eds align stops with exit 2.
323
+ export const unsupportedFrameworks = [
324
+ ["next", "Next.js"],
325
+ ["@remix-run/react", "Remix"],
326
+ ["@react-router/dev", "React Router framework mode"],
327
+ ["@tanstack/react-start", "TanStack Start"],
328
+ ["gatsby", "Gatsby"],
329
+ ["astro", "Astro"],
330
+ ["expo", "Expo"],
331
+ ["react-native", "React Native"],
332
+ ["react-scripts", "Create React App"],
333
+ ["@docusaurus/core", "Docusaurus"],
334
+ ["vike", "Vike"],
335
+ ["waku", "Waku"],
336
+ ];
337
+
338
+ // Top-level directories (of the frontend package or the repository) that hold backend or deployment code.
339
+ export const backendDirectoryNames = [
340
+ "server",
341
+ "backend",
342
+ "api",
343
+ "functions",
344
+ "supabase",
345
+ "prisma",
346
+ "drizzle",
347
+ "migrations",
348
+ "db",
349
+ "database",
350
+ "convex",
351
+ "amplify",
352
+ "netlify",
353
+ "lambda",
354
+ "workers",
355
+ ];
356
+ // A top-level shared/ is protected when backend code sits next to it (the server imports it).
357
+ export const sharedWithBackendDirectoryName = "shared";
358
+
359
+ // Backend, deployment and run configuration files at the top of the frontend package or the repository.
360
+ export const backendMarkerFiles = [
361
+ "requirements.txt",
362
+ "pyproject.toml",
363
+ "Pipfile",
364
+ "poetry.lock",
365
+ "go.mod",
366
+ "Cargo.toml",
367
+ "pom.xml",
368
+ "build.gradle",
369
+ "build.gradle.kts",
370
+ "Gemfile",
371
+ "composer.json",
372
+ "manage.py",
373
+ "drizzle.config.ts",
374
+ "drizzle.config.js",
375
+ "wrangler.toml",
376
+ "wrangler.json",
377
+ "wrangler.jsonc",
378
+ "vercel.json",
379
+ "netlify.toml",
380
+ "firebase.json",
381
+ ".firebaserc",
382
+ "Dockerfile",
383
+ "docker-compose.yml",
384
+ "docker-compose.yaml",
385
+ "compose.yml",
386
+ "compose.yaml",
387
+ "Procfile",
388
+ "nixpacks.toml",
389
+ ".replit",
390
+ "replit.nix",
391
+ "fly.toml",
392
+ "render.yaml",
393
+ "app.yaml",
394
+ "serverless.yml",
395
+ "amplify.yml",
396
+ ];
397
+
398
+ // A script runs backend code when it names a backend runtime or tool, or a bundled server entry.
399
+ export const backendScriptPattern =
400
+ /\b(?:nodemon|ts-node|uvicorn|gunicorn|flask|django-admin|python3?|drizzle-kit|prisma|supabase|wrangler|firebase|netlify|json-server|nest)\b|\bnode\s+(?:dist|build)\//;
401
+
402
+ // Lockfiles at the repository root change when a workspace package installs dependencies.
403
+ export const rootLockfiles = ["package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "yarn.lock", "bun.lock", "bun.lockb"];
404
+
405
+ export const testSupportHint = "테스트 코드는 정렬 대상이 아니므로 그대로 둡니다";
406
+
407
+ // Where the usual prototype directories go. Keys are src/ top-level names (lower case).
408
+ export const structureHints = {
409
+ app: "app/ (main.tsx · App.tsx · router/ · providers/ · styles/)",
410
+ pages: "pages/<domain>/<action>/page.tsx · pages/<name>/page.tsx (resource 밖 화면)",
411
+ routes: "pages/<domain>/<action>/page.tsx · pages/<name>/page.tsx (resource 밖 화면)",
412
+ views: "pages/<domain>/<action>/page.tsx · pages/<name>/page.tsx (resource 밖 화면)",
413
+ screens: "pages/<domain>/<action>/page.tsx · pages/<name>/page.tsx (resource 밖 화면)",
414
+ widgets: "widgets/<name>/",
415
+ layouts: "widgets/layout/",
416
+ layout: "widgets/layout/",
417
+ features: "features/<domain>/<feature>/{ui,lib,types}",
418
+ entities: "entities/<domain>/{components,hooks,services,stores,types,lib}",
419
+ shared: "shared/{api,assets,hooks,lib,ui}",
420
+ components: "widgets/<name> (화면 구획) · features/<domain>/<feature>/ui (사용자 행동) · entities/<domain>/components (도메인 표시) · shared/ui (범용)",
421
+ ui: "shared/ui/",
422
+ hooks: "shared/hooks (범용) · entities/<domain>/hooks (서버 데이터)",
423
+ lib: "shared/lib/ (cn은 shared/lib/utils, queryClient는 shared/api/queryClient.ts)",
424
+ utils: "shared/lib/utils/",
425
+ helpers: "shared/lib/",
426
+ api: "shared/api (axios instance·queryClient) · entities/<domain>/services (endpoint 함수)",
427
+ services: "entities/<domain>/services/<domain>Service.ts · shared/api",
428
+ requests: "entities/<domain>/services/",
429
+ store: "entities/<domain>/stores/ (zustand)",
430
+ stores: "entities/<domain>/stores/ (zustand)",
431
+ state: "entities/<domain>/stores/ (zustand)",
432
+ redux: "entities/<domain>/stores/ (zustand로 교체)",
433
+ slices: "entities/<domain>/stores/ (zustand로 교체)",
434
+ atoms: "entities/<domain>/stores/ (zustand로 교체)",
435
+ context: "app/providers (앱 전역) · features/<domain>/<feature>/lib (폼 context)",
436
+ contexts: "app/providers (앱 전역) · features/<domain>/<feature>/lib (폼 context)",
437
+ providers: "app/providers/",
438
+ router: "app/router/index.tsx",
439
+ routing: "app/router/index.tsx",
440
+ types: "entities/<domain>/types/api.ts (API 타입) · types/ (전역 선언만)",
441
+ interfaces: "entities/<domain>/types/",
442
+ models: "entities/<domain>/types/",
443
+ assets: "shared/assets/",
444
+ images: "shared/assets/",
445
+ icons: "shared/assets/ 또는 lucide-react",
446
+ fonts: "삭제 (EDS가 Pretendard를 제공)",
447
+ styles: "app/styles/index.css (전역) · Tailwind className (컴포넌트). eds sync가 만든 eds-tokens.css는 그대로 둡니다",
448
+ css: "app/styles/index.css (전역) · Tailwind className (컴포넌트)",
449
+ config: "shared/lib/ · entities/<domain>/types/enums.ts",
450
+ constants: "shared/lib/ · entities/<domain>/types/enums.ts",
451
+ consts: "shared/lib/ · entities/<domain>/types/enums.ts",
452
+ i18n: "shared/lib/ (기존 i18n 설정은 지우지 않고 옮깁니다. 새 문구는 「UI 문구」를 따릅니다)",
453
+ locales: "shared/lib/ (기존 번역 파일은 지우지 않고 옮깁니다)",
454
+ lang: "shared/lib/ (기존 번역 파일은 지우지 않고 옮깁니다)",
455
+ translations: "shared/lib/ (기존 번역 파일은 지우지 않고 옮깁니다)",
456
+ mocks: "mocks/<domain>/index.ts",
457
+ integrations: "shared/api/ (backend client SDK)",
458
+ "app.tsx": "app/App.tsx",
459
+ "app.jsx": "app/App.tsx",
460
+ "main.tsx": "app/main.tsx",
461
+ "main.jsx": "app/main.tsx",
462
+ "i18n.ts": "shared/lib/i18n.ts (기존 i18n 설정은 지우지 않고 옮깁니다)",
463
+ "i18n.tsx": "shared/lib/i18n.ts (기존 i18n 설정은 지우지 않고 옮깁니다)",
464
+ "i18n.js": "shared/lib/i18n.ts (기존 i18n 설정은 지우지 않고 옮깁니다)",
465
+ "i18n.jsx": "shared/lib/i18n.ts (기존 i18n 설정은 지우지 않고 옮깁니다)",
466
+ "index.tsx": "app/main.tsx",
467
+ "index.jsx": "app/main.tsx",
468
+ "index.css": "app/styles/index.css",
469
+ "app.css": "app/styles/index.css (컴포넌트 규칙은 className으로)",
470
+ "globals.css": "app/styles/index.css",
471
+ "global.css": "app/styles/index.css",
472
+ "vite-env.d.ts": "그대로 둡니다",
473
+ };