@corbat-tech/coding-standards-mcp 1.0.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/LICENSE +21 -0
- package/README.md +371 -0
- package/assets/demo.gif +0 -0
- package/dist/agent.d.ts +53 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +629 -0
- package/dist/agent.js.map +1 -0
- package/dist/cli/init.d.ts +3 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +651 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/config.d.ts +73 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +105 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/profiles.d.ts +39 -0
- package/dist/profiles.d.ts.map +1 -0
- package/dist/profiles.js +526 -0
- package/dist/profiles.js.map +1 -0
- package/dist/prompts-legacy.d.ts +25 -0
- package/dist/prompts-legacy.d.ts.map +1 -0
- package/dist/prompts-legacy.js +600 -0
- package/dist/prompts-legacy.js.map +1 -0
- package/dist/prompts-v2.d.ts +30 -0
- package/dist/prompts-v2.d.ts.map +1 -0
- package/dist/prompts-v2.js +310 -0
- package/dist/prompts-v2.js.map +1 -0
- package/dist/prompts.d.ts +30 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +310 -0
- package/dist/prompts.js.map +1 -0
- package/dist/resources.d.ts +18 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +95 -0
- package/dist/resources.js.map +1 -0
- package/dist/tools-legacy.d.ts +196 -0
- package/dist/tools-legacy.d.ts.map +1 -0
- package/dist/tools-legacy.js +1230 -0
- package/dist/tools-legacy.js.map +1 -0
- package/dist/tools-v2.d.ts +92 -0
- package/dist/tools-v2.d.ts.map +1 -0
- package/dist/tools-v2.js +410 -0
- package/dist/tools-v2.js.map +1 -0
- package/dist/tools.d.ts +92 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +410 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +3054 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +515 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/retry.d.ts +44 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +74 -0
- package/dist/utils/retry.js.map +1 -0
- package/package.json +79 -0
- package/profiles/README.md +199 -0
- package/profiles/custom/.gitkeep +2 -0
- package/profiles/templates/_template.yaml +159 -0
- package/profiles/templates/angular.yaml +494 -0
- package/profiles/templates/java-spring-backend.yaml +512 -0
- package/profiles/templates/minimal.yaml +102 -0
- package/profiles/templates/nodejs.yaml +338 -0
- package/profiles/templates/python.yaml +340 -0
- package/profiles/templates/react.yaml +331 -0
- package/profiles/templates/vue.yaml +598 -0
- package/standards/architecture/ddd.md +173 -0
- package/standards/architecture/hexagonal.md +97 -0
- package/standards/cicd/github-actions.md +567 -0
- package/standards/clean-code/naming.md +175 -0
- package/standards/clean-code/principles.md +179 -0
- package/standards/containerization/dockerfile.md +419 -0
- package/standards/database/selection-guide.md +443 -0
- package/standards/documentation/guidelines.md +189 -0
- package/standards/event-driven/domain-events.md +527 -0
- package/standards/kubernetes/deployment.md +518 -0
- package/standards/observability/guidelines.md +665 -0
- package/standards/project-setup/initialization-checklist.md +650 -0
- package/standards/spring-boot/best-practices.md +598 -0
- package/standards/testing/guidelines.md +559 -0
- package/standards/workflow/llm-development-workflow.md +542 -0
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# CORBAT MCP - Vue Profile
|
|
3
|
+
# ============================================================================
|
|
4
|
+
# Production-ready standards for Vue 3.4+ applications.
|
|
5
|
+
# Covers Composition API, script setup, Pinia, and modern Vue patterns.
|
|
6
|
+
# Updated for Vue 3.5/3.6 best practices (2025-2026).
|
|
7
|
+
# ============================================================================
|
|
8
|
+
|
|
9
|
+
name: "Vue Standards"
|
|
10
|
+
description: "Production-ready standards for Vue 3.4+ applications with TypeScript, focusing on Composition API, script setup, Pinia, Vapor Mode readiness, and modern Vue ecosystem"
|
|
11
|
+
|
|
12
|
+
# ----------------------------------------------------------------------------
|
|
13
|
+
# ARCHITECTURE
|
|
14
|
+
# ----------------------------------------------------------------------------
|
|
15
|
+
architecture:
|
|
16
|
+
type: "feature-based"
|
|
17
|
+
enforceLayerDependencies: true
|
|
18
|
+
layers:
|
|
19
|
+
- name: features
|
|
20
|
+
description: "Feature modules containing views, components, and composables for specific features"
|
|
21
|
+
allowedDependencies:
|
|
22
|
+
- shared
|
|
23
|
+
- core
|
|
24
|
+
packages:
|
|
25
|
+
- "src/features/*"
|
|
26
|
+
- "src/views/*"
|
|
27
|
+
|
|
28
|
+
- name: shared
|
|
29
|
+
description: "Reusable components, composables, and utilities used across features"
|
|
30
|
+
allowedDependencies:
|
|
31
|
+
- core
|
|
32
|
+
packages:
|
|
33
|
+
- "src/shared"
|
|
34
|
+
- "src/components"
|
|
35
|
+
- "src/composables"
|
|
36
|
+
- "src/utils"
|
|
37
|
+
|
|
38
|
+
- name: core
|
|
39
|
+
description: "Application core: router, stores, API client, types"
|
|
40
|
+
allowedDependencies: []
|
|
41
|
+
packages:
|
|
42
|
+
- "src/core"
|
|
43
|
+
- "src/stores"
|
|
44
|
+
- "src/api"
|
|
45
|
+
- "src/types"
|
|
46
|
+
|
|
47
|
+
# ----------------------------------------------------------------------------
|
|
48
|
+
# CODE QUALITY
|
|
49
|
+
# ----------------------------------------------------------------------------
|
|
50
|
+
codeQuality:
|
|
51
|
+
maxMethodLines: 30
|
|
52
|
+
maxClassLines: 200
|
|
53
|
+
maxFileLines: 300
|
|
54
|
+
maxMethodParameters: 4
|
|
55
|
+
maxCyclomaticComplexity: 10
|
|
56
|
+
requireDocumentation: true
|
|
57
|
+
requireTests: true
|
|
58
|
+
minimumTestCoverage: 70
|
|
59
|
+
|
|
60
|
+
principles:
|
|
61
|
+
- "Composition API with script setup"
|
|
62
|
+
- "Single File Components (SFC)"
|
|
63
|
+
- "Composables for reusable logic"
|
|
64
|
+
- "Props down, events up"
|
|
65
|
+
- "Pinia for global state"
|
|
66
|
+
- "TypeScript for type safety"
|
|
67
|
+
- "Prefer computed over methods for derived state"
|
|
68
|
+
|
|
69
|
+
# ----------------------------------------------------------------------------
|
|
70
|
+
# NAMING CONVENTIONS
|
|
71
|
+
# ----------------------------------------------------------------------------
|
|
72
|
+
naming:
|
|
73
|
+
general:
|
|
74
|
+
component: "PascalCase (UserCard.vue)"
|
|
75
|
+
composable: "useCamelCase (useUser.ts)"
|
|
76
|
+
store: "useCamelCaseStore (useUserStore.ts)"
|
|
77
|
+
util: "camelCase"
|
|
78
|
+
constant: "SCREAMING_SNAKE_CASE"
|
|
79
|
+
type: "PascalCase"
|
|
80
|
+
interface: "PascalCase (no I prefix)"
|
|
81
|
+
enum: "PascalCase"
|
|
82
|
+
|
|
83
|
+
files:
|
|
84
|
+
component: "PascalCase.vue"
|
|
85
|
+
composable: "useName.ts"
|
|
86
|
+
store: "nameStore.ts or useName.ts"
|
|
87
|
+
util: "camelCase.ts"
|
|
88
|
+
type: "name.types.ts or types.ts"
|
|
89
|
+
test: "Name.spec.ts or Name.test.ts"
|
|
90
|
+
|
|
91
|
+
folders:
|
|
92
|
+
feature: "kebab-case"
|
|
93
|
+
component: "PascalCase (component folder)"
|
|
94
|
+
|
|
95
|
+
props:
|
|
96
|
+
boolean: "is/has/should prefix (isActive, hasError)"
|
|
97
|
+
handler: "onAction (onClick, onSubmit)"
|
|
98
|
+
data: "descriptive noun (user, items)"
|
|
99
|
+
|
|
100
|
+
emits:
|
|
101
|
+
event: "kebab-case (update:modelValue, item-selected)"
|
|
102
|
+
handler: "onEventName in parent"
|
|
103
|
+
|
|
104
|
+
# ----------------------------------------------------------------------------
|
|
105
|
+
# VUE 3 MODERN PATTERNS
|
|
106
|
+
# ----------------------------------------------------------------------------
|
|
107
|
+
modernPatterns:
|
|
108
|
+
scriptSetup:
|
|
109
|
+
required: true
|
|
110
|
+
description: "Always use <script setup> for components"
|
|
111
|
+
example: |
|
|
112
|
+
<script setup lang="ts">
|
|
113
|
+
import { ref, computed } from 'vue'
|
|
114
|
+
import type { User } from '@/types'
|
|
115
|
+
|
|
116
|
+
const props = defineProps<{
|
|
117
|
+
user: User
|
|
118
|
+
}>()
|
|
119
|
+
|
|
120
|
+
const emit = defineEmits<{
|
|
121
|
+
(e: 'select', id: string): void
|
|
122
|
+
}>()
|
|
123
|
+
|
|
124
|
+
const isActive = ref(false)
|
|
125
|
+
</script>
|
|
126
|
+
|
|
127
|
+
compositionAPI:
|
|
128
|
+
required: true
|
|
129
|
+
description: "Use Composition API, avoid Options API"
|
|
130
|
+
patterns:
|
|
131
|
+
- "ref() for primitive reactive values"
|
|
132
|
+
- "reactive() for objects (use sparingly)"
|
|
133
|
+
- "computed() for derived state"
|
|
134
|
+
- "watch() / watchEffect() for side effects"
|
|
135
|
+
- "Composables for reusable logic"
|
|
136
|
+
|
|
137
|
+
defineModel:
|
|
138
|
+
description: "Use defineModel for v-model binding (Vue 3.4+)"
|
|
139
|
+
example: |
|
|
140
|
+
<script setup lang="ts">
|
|
141
|
+
const modelValue = defineModel<string>({ required: true })
|
|
142
|
+
// Automatically handles :modelValue + @update:modelValue
|
|
143
|
+
</script>
|
|
144
|
+
|
|
145
|
+
propsDefaults:
|
|
146
|
+
description: "Use withDefaults for props with defaults"
|
|
147
|
+
example: |
|
|
148
|
+
const props = withDefaults(defineProps<{
|
|
149
|
+
size?: 'sm' | 'md' | 'lg'
|
|
150
|
+
disabled?: boolean
|
|
151
|
+
}>(), {
|
|
152
|
+
size: 'md',
|
|
153
|
+
disabled: false
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
genericComponents:
|
|
157
|
+
description: "Use generic components for type-safe reusable components"
|
|
158
|
+
example: |
|
|
159
|
+
<script setup lang="ts" generic="T extends { id: string }">
|
|
160
|
+
defineProps<{
|
|
161
|
+
items: T[]
|
|
162
|
+
selected?: T
|
|
163
|
+
}>()
|
|
164
|
+
|
|
165
|
+
defineEmits<{
|
|
166
|
+
(e: 'select', item: T): void
|
|
167
|
+
}>()
|
|
168
|
+
</script>
|
|
169
|
+
|
|
170
|
+
# ----------------------------------------------------------------------------
|
|
171
|
+
# VAPOR MODE (Vue 3.6+)
|
|
172
|
+
# ----------------------------------------------------------------------------
|
|
173
|
+
vaporMode:
|
|
174
|
+
status: "Experimental in Vue 3.6"
|
|
175
|
+
description: "Vapor Mode eliminates Virtual DOM for faster rendering"
|
|
176
|
+
benefits:
|
|
177
|
+
- "No Virtual DOM overhead"
|
|
178
|
+
- "100,000 components mounted in ~100ms"
|
|
179
|
+
- "Smaller bundle size (<10KB base)"
|
|
180
|
+
- "Improved memory usage with Alien Signals"
|
|
181
|
+
- "Drop-in performance upgrade"
|
|
182
|
+
|
|
183
|
+
requirements:
|
|
184
|
+
- "Must use Composition API (not Options API)"
|
|
185
|
+
- "Must use <script setup> syntax"
|
|
186
|
+
- "Component-level opt-in"
|
|
187
|
+
|
|
188
|
+
preparation:
|
|
189
|
+
- "Ensure all components use Composition API"
|
|
190
|
+
- "Migrate from Options API if needed"
|
|
191
|
+
- "Avoid mixins and extends"
|
|
192
|
+
- "Use modern reactivity patterns"
|
|
193
|
+
|
|
194
|
+
rules:
|
|
195
|
+
- "Write Vapor-ready code now for future compatibility"
|
|
196
|
+
- "Composition API is mandatory for Vapor Mode"
|
|
197
|
+
- "Test in isolated branches when experimenting"
|
|
198
|
+
- "Benchmark performance improvements"
|
|
199
|
+
|
|
200
|
+
# ----------------------------------------------------------------------------
|
|
201
|
+
# COMPOSABLES
|
|
202
|
+
# ----------------------------------------------------------------------------
|
|
203
|
+
composables:
|
|
204
|
+
description: "Extract reusable logic into composables"
|
|
205
|
+
patterns:
|
|
206
|
+
- "Name: useSomething"
|
|
207
|
+
- "Return reactive state and methods"
|
|
208
|
+
- "Handle cleanup in onUnmounted"
|
|
209
|
+
- "Support SSR when needed"
|
|
210
|
+
|
|
211
|
+
structure: |
|
|
212
|
+
// composables/useUser.ts
|
|
213
|
+
export function useUser(userId: Ref<string>) {
|
|
214
|
+
const user = ref<User | null>(null)
|
|
215
|
+
const isLoading = ref(false)
|
|
216
|
+
const error = ref<Error | null>(null)
|
|
217
|
+
|
|
218
|
+
async function fetchUser() {
|
|
219
|
+
isLoading.value = true
|
|
220
|
+
try {
|
|
221
|
+
user.value = await api.getUser(userId.value)
|
|
222
|
+
} catch (e) {
|
|
223
|
+
error.value = e as Error
|
|
224
|
+
} finally {
|
|
225
|
+
isLoading.value = false
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
watch(userId, fetchUser, { immediate: true })
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
user: readonly(user),
|
|
233
|
+
isLoading: readonly(isLoading),
|
|
234
|
+
error: readonly(error),
|
|
235
|
+
refetch: fetchUser
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
rules:
|
|
240
|
+
- "Prefix with 'use'"
|
|
241
|
+
- "Return readonly refs when state shouldn't be modified externally"
|
|
242
|
+
- "Accept refs as parameters for reactivity"
|
|
243
|
+
- "Handle cleanup (removeEventListener, clearInterval)"
|
|
244
|
+
- "Document parameters and return values"
|
|
245
|
+
|
|
246
|
+
# ----------------------------------------------------------------------------
|
|
247
|
+
# STATE MANAGEMENT
|
|
248
|
+
# ----------------------------------------------------------------------------
|
|
249
|
+
stateManagement:
|
|
250
|
+
local:
|
|
251
|
+
tool: "ref / reactive"
|
|
252
|
+
useWhen:
|
|
253
|
+
- "Component-specific state"
|
|
254
|
+
- "Form state"
|
|
255
|
+
- "UI state (modals, dropdowns)"
|
|
256
|
+
|
|
257
|
+
shared:
|
|
258
|
+
tool: "Pinia"
|
|
259
|
+
useWhen:
|
|
260
|
+
- "State shared across multiple components"
|
|
261
|
+
- "Complex state logic"
|
|
262
|
+
- "State that persists across routes"
|
|
263
|
+
- "State that needs devtools support"
|
|
264
|
+
|
|
265
|
+
server:
|
|
266
|
+
tool: "TanStack Query (Vue Query) or VueUse useFetch"
|
|
267
|
+
useWhen:
|
|
268
|
+
- "API data fetching"
|
|
269
|
+
- "Caching server state"
|
|
270
|
+
- "Optimistic updates"
|
|
271
|
+
- "Background refetching"
|
|
272
|
+
|
|
273
|
+
piniaPatterns:
|
|
274
|
+
setup: |
|
|
275
|
+
// stores/userStore.ts
|
|
276
|
+
export const useUserStore = defineStore('user', () => {
|
|
277
|
+
// State
|
|
278
|
+
const user = ref<User | null>(null)
|
|
279
|
+
const isLoading = ref(false)
|
|
280
|
+
|
|
281
|
+
// Getters (computed)
|
|
282
|
+
const isLoggedIn = computed(() => !!user.value)
|
|
283
|
+
const fullName = computed(() =>
|
|
284
|
+
user.value ? `${user.value.firstName} ${user.value.lastName}` : ''
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
// Actions
|
|
288
|
+
async function login(credentials: Credentials) {
|
|
289
|
+
isLoading.value = true
|
|
290
|
+
try {
|
|
291
|
+
user.value = await authApi.login(credentials)
|
|
292
|
+
} finally {
|
|
293
|
+
isLoading.value = false
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function logout() {
|
|
298
|
+
user.value = null
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return {
|
|
302
|
+
user: readonly(user),
|
|
303
|
+
isLoading: readonly(isLoading),
|
|
304
|
+
isLoggedIn,
|
|
305
|
+
fullName,
|
|
306
|
+
login,
|
|
307
|
+
logout
|
|
308
|
+
}
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
rules:
|
|
312
|
+
- "Prefer Setup Stores over Options Stores"
|
|
313
|
+
- "Use readonly() for state that shouldn't be modified directly"
|
|
314
|
+
- "Colocate related state, getters, and actions"
|
|
315
|
+
- "Use storeToRefs() when destructuring reactive state"
|
|
316
|
+
|
|
317
|
+
# ----------------------------------------------------------------------------
|
|
318
|
+
# TYPESCRIPT
|
|
319
|
+
# ----------------------------------------------------------------------------
|
|
320
|
+
technologies:
|
|
321
|
+
- name: typescript
|
|
322
|
+
version: "5.x"
|
|
323
|
+
specificRules:
|
|
324
|
+
strict: true
|
|
325
|
+
noImplicitAny: true
|
|
326
|
+
strictNullChecks: true
|
|
327
|
+
noUnusedLocals: true
|
|
328
|
+
noUnusedParameters: true
|
|
329
|
+
|
|
330
|
+
- name: vue
|
|
331
|
+
version: "3.5+"
|
|
332
|
+
specificRules:
|
|
333
|
+
scriptSetup: true
|
|
334
|
+
compositionAPI: true
|
|
335
|
+
defineModel: true
|
|
336
|
+
typescript: true
|
|
337
|
+
vaporModeReady: "use Composition API for future compatibility"
|
|
338
|
+
|
|
339
|
+
- name: linting
|
|
340
|
+
tools:
|
|
341
|
+
- "ESLint"
|
|
342
|
+
- "eslint-plugin-vue"
|
|
343
|
+
- "Prettier"
|
|
344
|
+
- "@vue/eslint-config-typescript"
|
|
345
|
+
|
|
346
|
+
# ----------------------------------------------------------------------------
|
|
347
|
+
# TESTING
|
|
348
|
+
# ----------------------------------------------------------------------------
|
|
349
|
+
testing:
|
|
350
|
+
framework: "Vitest"
|
|
351
|
+
assertionLibrary: "Vitest"
|
|
352
|
+
componentTesting: "Vue Testing Library"
|
|
353
|
+
|
|
354
|
+
types:
|
|
355
|
+
unit:
|
|
356
|
+
suffix: ".spec.ts"
|
|
357
|
+
location: "co-located or __tests__/"
|
|
358
|
+
coverage: 70
|
|
359
|
+
|
|
360
|
+
component:
|
|
361
|
+
suffix: ".spec.ts"
|
|
362
|
+
location: "co-located"
|
|
363
|
+
tool: "Vue Testing Library"
|
|
364
|
+
patterns:
|
|
365
|
+
- "Test user interactions"
|
|
366
|
+
- "Use screen queries"
|
|
367
|
+
- "Avoid testing implementation details"
|
|
368
|
+
|
|
369
|
+
integration:
|
|
370
|
+
suffix: ".integration.spec.ts"
|
|
371
|
+
location: "tests/integration"
|
|
372
|
+
|
|
373
|
+
e2e:
|
|
374
|
+
tool: "Playwright or Cypress"
|
|
375
|
+
location: "e2e/"
|
|
376
|
+
|
|
377
|
+
patterns:
|
|
378
|
+
arrange_act_assert: true
|
|
379
|
+
behavior_testing: true
|
|
380
|
+
mock_api_calls: true
|
|
381
|
+
testing_library_vue: true
|
|
382
|
+
|
|
383
|
+
example: |
|
|
384
|
+
import { render, screen } from '@testing-library/vue'
|
|
385
|
+
import userEvent from '@testing-library/user-event'
|
|
386
|
+
import UserCard from './UserCard.vue'
|
|
387
|
+
|
|
388
|
+
test('displays user name and handles click', async () => {
|
|
389
|
+
const user = userEvent.setup()
|
|
390
|
+
const onClick = vi.fn()
|
|
391
|
+
|
|
392
|
+
render(UserCard, {
|
|
393
|
+
props: { name: 'John Doe' },
|
|
394
|
+
attrs: { onClick }
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
expect(screen.getByText('John Doe')).toBeInTheDocument()
|
|
398
|
+
|
|
399
|
+
await user.click(screen.getByRole('button'))
|
|
400
|
+
expect(onClick).toHaveBeenCalled()
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
rules:
|
|
404
|
+
- "Prefer Vue Testing Library over @vue/test-utils directly"
|
|
405
|
+
- "Test user-visible behavior"
|
|
406
|
+
- "Mock Pinia stores when testing components"
|
|
407
|
+
- "Use createTestingPinia() for store tests"
|
|
408
|
+
|
|
409
|
+
# ----------------------------------------------------------------------------
|
|
410
|
+
# STYLING
|
|
411
|
+
# ----------------------------------------------------------------------------
|
|
412
|
+
styling:
|
|
413
|
+
approach: "Scoped CSS, CSS Modules, or Tailwind CSS"
|
|
414
|
+
tools:
|
|
415
|
+
- "Scoped CSS (default)"
|
|
416
|
+
- "Tailwind CSS"
|
|
417
|
+
- "CSS Modules"
|
|
418
|
+
- "UnoCSS"
|
|
419
|
+
|
|
420
|
+
rules:
|
|
421
|
+
- "Use <style scoped> by default"
|
|
422
|
+
- "Use :deep() for styling child components"
|
|
423
|
+
- "CSS variables for theming"
|
|
424
|
+
- "Mobile-first responsive design"
|
|
425
|
+
- "Avoid !important"
|
|
426
|
+
|
|
427
|
+
example: |
|
|
428
|
+
<style scoped>
|
|
429
|
+
.card {
|
|
430
|
+
@apply p-4 rounded-lg shadow;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/* Deep selector for child components */
|
|
434
|
+
:deep(.child-class) {
|
|
435
|
+
color: var(--text-primary);
|
|
436
|
+
}
|
|
437
|
+
</style>
|
|
438
|
+
|
|
439
|
+
# ----------------------------------------------------------------------------
|
|
440
|
+
# PERFORMANCE
|
|
441
|
+
# ----------------------------------------------------------------------------
|
|
442
|
+
performance:
|
|
443
|
+
rendering:
|
|
444
|
+
- "Use v-once for static content"
|
|
445
|
+
- "Use v-memo for expensive list items"
|
|
446
|
+
- "Avoid v-if + v-for on same element"
|
|
447
|
+
- "Use computed properties over methods in templates"
|
|
448
|
+
- "Use shallowRef for large objects that don't need deep reactivity"
|
|
449
|
+
|
|
450
|
+
lazyLoading:
|
|
451
|
+
- "Lazy load routes with defineAsyncComponent"
|
|
452
|
+
- "Use Suspense for async components"
|
|
453
|
+
- "Dynamic imports for heavy libraries"
|
|
454
|
+
|
|
455
|
+
lists:
|
|
456
|
+
- "Always use :key with unique identifier"
|
|
457
|
+
- "Use v-memo for expensive item rendering"
|
|
458
|
+
- "Virtual scrolling for large lists (vue-virtual-scroller)"
|
|
459
|
+
|
|
460
|
+
rules:
|
|
461
|
+
- "Avoid reactive() for large objects (use ref)"
|
|
462
|
+
- "Use shallowRef/shallowReactive when appropriate"
|
|
463
|
+
- "Debounce expensive watchers"
|
|
464
|
+
- "Use computed with memo"
|
|
465
|
+
|
|
466
|
+
# ----------------------------------------------------------------------------
|
|
467
|
+
# ROUTING
|
|
468
|
+
# ----------------------------------------------------------------------------
|
|
469
|
+
routing:
|
|
470
|
+
tool: "Vue Router 4"
|
|
471
|
+
patterns:
|
|
472
|
+
- "Lazy load all routes"
|
|
473
|
+
- "Use typed routes (vue-router auto)"
|
|
474
|
+
- "Navigation guards for auth"
|
|
475
|
+
- "Route-level code splitting"
|
|
476
|
+
|
|
477
|
+
example: |
|
|
478
|
+
const routes: RouteRecordRaw[] = [
|
|
479
|
+
{
|
|
480
|
+
path: '/users',
|
|
481
|
+
component: () => import('@/views/UsersView.vue'),
|
|
482
|
+
meta: { requiresAuth: true }
|
|
483
|
+
}
|
|
484
|
+
]
|
|
485
|
+
|
|
486
|
+
# ----------------------------------------------------------------------------
|
|
487
|
+
# API INTEGRATION
|
|
488
|
+
# ----------------------------------------------------------------------------
|
|
489
|
+
api:
|
|
490
|
+
client: "Axios or ofetch with TanStack Query"
|
|
491
|
+
patterns:
|
|
492
|
+
- "Centralize API configuration"
|
|
493
|
+
- "Type all responses"
|
|
494
|
+
- "Use interceptors for auth/errors"
|
|
495
|
+
- "TanStack Query for caching"
|
|
496
|
+
|
|
497
|
+
structure: |
|
|
498
|
+
// api/client.ts
|
|
499
|
+
export const api = ofetch.create({
|
|
500
|
+
baseURL: import.meta.env.VITE_API_URL,
|
|
501
|
+
onRequest({ options }) {
|
|
502
|
+
const token = useAuthStore().token
|
|
503
|
+
if (token) {
|
|
504
|
+
options.headers.set('Authorization', `Bearer ${token}`)
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
})
|
|
508
|
+
|
|
509
|
+
// api/users.ts
|
|
510
|
+
export const usersApi = {
|
|
511
|
+
getAll: () => api<User[]>('/users'),
|
|
512
|
+
getById: (id: string) => api<User>(`/users/${id}`),
|
|
513
|
+
create: (data: CreateUserDto) => api<User>('/users', { method: 'POST', body: data })
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
tanstackQuery: |
|
|
517
|
+
// composables/useUsers.ts
|
|
518
|
+
export function useUsers() {
|
|
519
|
+
return useQuery({
|
|
520
|
+
queryKey: ['users'],
|
|
521
|
+
queryFn: () => usersApi.getAll()
|
|
522
|
+
})
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
# ----------------------------------------------------------------------------
|
|
526
|
+
# VUEUSE
|
|
527
|
+
# ----------------------------------------------------------------------------
|
|
528
|
+
vueuse:
|
|
529
|
+
description: "Use VueUse for common composables"
|
|
530
|
+
recommended:
|
|
531
|
+
- "useLocalStorage / useSessionStorage"
|
|
532
|
+
- "useDebounceFn / useThrottleFn"
|
|
533
|
+
- "useEventListener"
|
|
534
|
+
- "useIntersectionObserver"
|
|
535
|
+
- "useDark / useColorMode"
|
|
536
|
+
- "useBreakpoints"
|
|
537
|
+
- "useFetch (simple cases)"
|
|
538
|
+
|
|
539
|
+
rules:
|
|
540
|
+
- "Prefer VueUse over custom implementations"
|
|
541
|
+
- "Check VueUse first before writing a composable"
|
|
542
|
+
|
|
543
|
+
# ----------------------------------------------------------------------------
|
|
544
|
+
# PROJECT STRUCTURE
|
|
545
|
+
# ----------------------------------------------------------------------------
|
|
546
|
+
# Recommended folder structure:
|
|
547
|
+
#
|
|
548
|
+
# src/
|
|
549
|
+
# ├── api/ # API client and endpoints
|
|
550
|
+
# │ ├── client.ts
|
|
551
|
+
# │ └── users.ts
|
|
552
|
+
# │
|
|
553
|
+
# ├── assets/ # Static assets
|
|
554
|
+
# │ └── images/
|
|
555
|
+
# │
|
|
556
|
+
# ├── components/ # Global/shared components
|
|
557
|
+
# │ ├── ui/ # Base UI components
|
|
558
|
+
# │ │ ├── Button.vue
|
|
559
|
+
# │ │ ├── Input.vue
|
|
560
|
+
# │ │ └── Modal.vue
|
|
561
|
+
# │ └── layout/ # Layout components
|
|
562
|
+
# │ ├── Header.vue
|
|
563
|
+
# │ └── Sidebar.vue
|
|
564
|
+
# │
|
|
565
|
+
# ├── composables/ # Global composables
|
|
566
|
+
# │ ├── useAuth.ts
|
|
567
|
+
# │ └── useApi.ts
|
|
568
|
+
# │
|
|
569
|
+
# ├── features/ # Feature modules
|
|
570
|
+
# │ ├── auth/
|
|
571
|
+
# │ │ ├── components/
|
|
572
|
+
# │ │ ├── composables/
|
|
573
|
+
# │ │ ├── views/
|
|
574
|
+
# │ │ │ ├── LoginView.vue
|
|
575
|
+
# │ │ │ └── RegisterView.vue
|
|
576
|
+
# │ │ └── index.ts
|
|
577
|
+
# │ └── dashboard/
|
|
578
|
+
# │
|
|
579
|
+
# ├── stores/ # Pinia stores
|
|
580
|
+
# │ ├── auth.ts
|
|
581
|
+
# │ └── user.ts
|
|
582
|
+
# │
|
|
583
|
+
# ├── types/ # TypeScript types
|
|
584
|
+
# │ ├── user.ts
|
|
585
|
+
# │ └── api.ts
|
|
586
|
+
# │
|
|
587
|
+
# ├── utils/ # Utility functions
|
|
588
|
+
# │ └── format.ts
|
|
589
|
+
# │
|
|
590
|
+
# ├── views/ # Route views (alternative to features)
|
|
591
|
+
# │ └── HomeView.vue
|
|
592
|
+
# │
|
|
593
|
+
# ├── App.vue
|
|
594
|
+
# ├── main.ts
|
|
595
|
+
# └── router.ts
|
|
596
|
+
#
|
|
597
|
+
# e2e/ # E2E tests
|
|
598
|
+
# └── specs/
|