@codihaus/claude-skills 1.0.0 → 1.3.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.
@@ -0,0 +1,469 @@
1
+ # Nuxt.js
2
+
3
+ > Vue.js meta-framework with SSR, file-based routing, and auto-imports
4
+
5
+ ## Overview
6
+
7
+ **What it is:**
8
+ - Full-stack Vue.js framework
9
+ - Server-side rendering (SSR) by default
10
+ - File-based routing (pages/)
11
+ - Auto-imported composables and components
12
+ - Nitro server engine for API routes
13
+
14
+ **When to use:**
15
+ - Vue.js applications needing SEO (SSR)
16
+ - Full-stack apps (frontend + API)
17
+ - Projects wanting convention over configuration
18
+ - Teams familiar with Vue ecosystem
19
+
20
+ **Key concepts:**
21
+ - **Pages** = File-based routes in `pages/`
22
+ - **Composables** = Reusable logic in `composables/`
23
+ - **Components** = Auto-imported from `components/`
24
+ - **Server Routes** = API endpoints in `server/api/`
25
+ - **Middleware** = Route guards in `middleware/`
26
+ - **Plugins** = App initialization in `plugins/`
27
+
28
+ ## Best Practices
29
+
30
+ ### Project Structure
31
+
32
+ ```
33
+ nuxt-app/
34
+ ├── assets/ # Uncompiled assets (SCSS, images)
35
+ ├── components/ # Auto-imported Vue components
36
+ │ ├── common/ # Shared components
37
+ │ ├── forms/ # Form components
38
+ │ └── ui/ # UI primitives
39
+ ├── composables/ # Auto-imported composables
40
+ │ ├── useAuth.ts # Auth logic
41
+ │ ├── useApi.ts # API client
42
+ │ └── use{Feature}.ts # Feature-specific
43
+ ├── layouts/ # Page layouts
44
+ ├── middleware/ # Route middleware
45
+ ├── pages/ # File-based routes
46
+ ├── plugins/ # Nuxt plugins
47
+ ├── server/ # Nitro server
48
+ │ ├── api/ # API routes
49
+ │ ├── middleware/ # Server middleware
50
+ │ └── utils/ # Server utilities
51
+ ├── stores/ # Pinia stores (if using)
52
+ ├── types/ # TypeScript types
53
+ └── utils/ # Shared utilities
54
+ ```
55
+
56
+ ### Data Fetching
57
+
58
+ ```
59
+ DO:
60
+ ✓ Use useFetch/useAsyncData for SSR-compatible fetching
61
+ ✓ Use $fetch for client-only or event handlers
62
+ ✓ Set key for caching: useFetch('/api/users', { key: 'users' })
63
+ ✓ Use lazy: true for non-critical data
64
+
65
+ DON'T:
66
+ ✗ Use raw fetch() in components (breaks SSR hydration)
67
+ ✗ Fetch in onMounted for initial data
68
+ ✗ Forget error handling
69
+ ```
70
+
71
+ ### Composables
72
+
73
+ ```
74
+ DO:
75
+ ✓ Name with use* prefix (useAuth, useProducts)
76
+ ✓ Return reactive refs and functions
77
+ ✓ Handle SSR context (check process.client if needed)
78
+ ✓ Keep composables focused (single responsibility)
79
+
80
+ DON'T:
81
+ ✗ Use component-specific logic
82
+ ✗ Directly mutate external state
83
+ ✗ Forget to handle loading/error states
84
+ ```
85
+
86
+ ### Server Routes (Nitro)
87
+
88
+ ```
89
+ DO:
90
+ ✓ Use server/api/ for API endpoints
91
+ ✓ Define event handlers with defineEventHandler
92
+ ✓ Use readBody for POST data
93
+ ✓ Return objects (auto-serialized)
94
+ ✓ Use server-only secrets (process.env)
95
+
96
+ DON'T:
97
+ ✗ Expose secrets to client (use runtimeConfig.secret)
98
+ ✗ Skip input validation
99
+ ✗ Forget error handling
100
+ ```
101
+
102
+ ### State Management
103
+
104
+ ```
105
+ DO:
106
+ ✓ Use useState for simple shared state
107
+ ✓ Use Pinia for complex state
108
+ ✓ Keep state minimal (derive where possible)
109
+ ✓ Use localStorage only via plugins (SSR-safe)
110
+
111
+ DON'T:
112
+ ✗ Use Vue reactive() at module level (SSR leak)
113
+ ✗ Store derived data (compute it)
114
+ ✗ Forget SSR hydration
115
+ ```
116
+
117
+ ## Anti-Patterns
118
+
119
+ | Anti-Pattern | Problem | Better Approach |
120
+ |--------------|---------|-----------------|
121
+ | `fetch()` in setup | SSR hydration mismatch | Use `useFetch()` |
122
+ | Direct localStorage | Fails on server | Use `useState` + plugin |
123
+ | Reactive at module level | State leak between requests | Use `useState()` |
124
+ | Heavy sync operations | Blocks rendering | Use `lazy: true` or defer |
125
+ | Ignoring loading state | Poor UX | Handle pending/error |
126
+ | API secrets in client | Security risk | Use `runtimeConfig.secret` |
127
+
128
+ ## For /dev-specs
129
+
130
+ ### Page Specification
131
+
132
+ ```markdown
133
+ ## Page: /products/[id]
134
+
135
+ ### Route
136
+ - Path: `/products/:id`
137
+ - File: `pages/products/[id].vue`
138
+
139
+ ### Data Requirements
140
+ - Product details (useFetch from API/Directus)
141
+ - Related products (lazy load)
142
+
143
+ ### Components
144
+ | Component | Purpose |
145
+ |-----------|---------|
146
+ | ProductGallery | Image carousel |
147
+ | ProductInfo | Name, price, description |
148
+ | AddToCart | Cart interaction |
149
+
150
+ ### SEO
151
+ - Title: `{product.name} | Store`
152
+ - Meta description: `{product.description}`
153
+ - OG image: `{product.image}`
154
+ ```
155
+
156
+ ### Composable Specification
157
+
158
+ ```markdown
159
+ ## Composable: useProducts
160
+
161
+ ### Purpose
162
+ Manage product data fetching and caching
163
+
164
+ ### Interface
165
+ ```typescript
166
+ function useProducts() {
167
+ return {
168
+ products: Ref<Product[]>,
169
+ pending: Ref<boolean>,
170
+ error: Ref<Error | null>,
171
+ refresh: () => Promise<void>,
172
+ getProduct: (id: string) => Product | undefined,
173
+ }
174
+ }
175
+ ```
176
+
177
+ ### Usage
178
+ ```vue
179
+ const { products, pending } = useProducts()
180
+ ```
181
+ ```
182
+
183
+ ### Server Route Specification
184
+
185
+ ```markdown
186
+ ## API: POST /api/orders
187
+
188
+ ### Purpose
189
+ Create new order
190
+
191
+ ### Request
192
+ ```typescript
193
+ {
194
+ items: { productId: string, quantity: number }[],
195
+ shippingAddress: Address,
196
+ }
197
+ ```
198
+
199
+ ### Response
200
+ ```typescript
201
+ { orderId: string, total: number, status: 'pending' }
202
+ ```
203
+
204
+ ### Errors
205
+ | Code | Reason |
206
+ |------|--------|
207
+ | 400 | Invalid items or address |
208
+ | 401 | Not authenticated |
209
+ | 422 | Insufficient stock |
210
+ ```
211
+
212
+ ## For /dev-coding
213
+
214
+ ### Composable Pattern
215
+
216
+ ```typescript
217
+ // composables/useProducts.ts
218
+ export const useProducts = () => {
219
+ const products = useState<Product[]>('products', () => []);
220
+ const pending = ref(false);
221
+ const error = ref<Error | null>(null);
222
+
223
+ const fetch = async () => {
224
+ pending.value = true;
225
+ error.value = null;
226
+ try {
227
+ const data = await $fetch<Product[]>('/api/products');
228
+ products.value = data;
229
+ } catch (e) {
230
+ error.value = e as Error;
231
+ } finally {
232
+ pending.value = false;
233
+ }
234
+ };
235
+
236
+ const getProduct = (id: string) =>
237
+ products.value.find(p => p.id === id);
238
+
239
+ return {
240
+ products: readonly(products),
241
+ pending: readonly(pending),
242
+ error: readonly(error),
243
+ fetch,
244
+ getProduct,
245
+ };
246
+ };
247
+ ```
248
+
249
+ ### Page with Data Fetching
250
+
251
+ ```vue
252
+ <!-- pages/products/[id].vue -->
253
+ <script setup lang="ts">
254
+ const route = useRoute();
255
+ const { data: product, pending, error } = await useFetch(
256
+ `/api/products/${route.params.id}`,
257
+ { key: `product-${route.params.id}` }
258
+ );
259
+
260
+ // SEO
261
+ useSeoMeta({
262
+ title: () => product.value?.name ?? 'Product',
263
+ description: () => product.value?.description,
264
+ });
265
+ </script>
266
+
267
+ <template>
268
+ <div v-if="pending">Loading...</div>
269
+ <div v-else-if="error">Error: {{ error.message }}</div>
270
+ <div v-else-if="product">
271
+ <h1>{{ product.name }}</h1>
272
+ <p>{{ product.price }}</p>
273
+ </div>
274
+ </template>
275
+ ```
276
+
277
+ ### Server Route
278
+
279
+ ```typescript
280
+ // server/api/products/[id].get.ts
281
+ export default defineEventHandler(async (event) => {
282
+ const id = getRouterParam(event, 'id');
283
+
284
+ if (!id) {
285
+ throw createError({
286
+ statusCode: 400,
287
+ message: 'Product ID required',
288
+ });
289
+ }
290
+
291
+ // Fetch from Directus or database
292
+ const product = await getProduct(id);
293
+
294
+ if (!product) {
295
+ throw createError({
296
+ statusCode: 404,
297
+ message: 'Product not found',
298
+ });
299
+ }
300
+
301
+ return product;
302
+ });
303
+ ```
304
+
305
+ ### Server Route with Body
306
+
307
+ ```typescript
308
+ // server/api/orders.post.ts
309
+ export default defineEventHandler(async (event) => {
310
+ const body = await readBody(event);
311
+
312
+ // Validate
313
+ const parsed = orderSchema.safeParse(body);
314
+ if (!parsed.success) {
315
+ throw createError({
316
+ statusCode: 400,
317
+ message: 'Invalid order data',
318
+ data: parsed.error.flatten(),
319
+ });
320
+ }
321
+
322
+ // Create order
323
+ const order = await createOrder(parsed.data);
324
+
325
+ return { orderId: order.id, status: order.status };
326
+ });
327
+ ```
328
+
329
+ ### Middleware (Auth)
330
+
331
+ ```typescript
332
+ // middleware/auth.ts
333
+ export default defineNuxtRouteMiddleware((to, from) => {
334
+ const { user } = useAuth();
335
+
336
+ if (!user.value && to.meta.requiresAuth) {
337
+ return navigateTo('/login');
338
+ }
339
+ });
340
+
341
+ // Usage in page
342
+ definePageMeta({
343
+ middleware: 'auth',
344
+ requiresAuth: true,
345
+ });
346
+ ```
347
+
348
+ ### Plugin (Client-only)
349
+
350
+ ```typescript
351
+ // plugins/localStorage.client.ts
352
+ export default defineNuxtPlugin(() => {
353
+ return {
354
+ provide: {
355
+ localStorage: {
356
+ get: (key: string) => localStorage.getItem(key),
357
+ set: (key: string, value: string) => localStorage.setItem(key, value),
358
+ },
359
+ },
360
+ };
361
+ });
362
+
363
+ // Usage: const { $localStorage } = useNuxtApp()
364
+ ```
365
+
366
+ ## For /dev-review
367
+
368
+ ### SSR Compatibility Checklist
369
+
370
+ - [ ] Using `useFetch`/`useAsyncData` for data
371
+ - [ ] No `window`/`document` access without `process.client` check
372
+ - [ ] Using `useState` instead of module-level reactive
373
+ - [ ] Plugins marked `.client.ts` if browser-only
374
+ - [ ] No localStorage without client check
375
+
376
+ ### Performance Checklist
377
+
378
+ - [ ] Using `lazy: true` for below-fold data
379
+ - [ ] Images optimized with `<NuxtImg>`
380
+ - [ ] Components lazy-loaded where appropriate
381
+ - [ ] Using `key` parameter for cache control
382
+ - [ ] No blocking operations in setup
383
+
384
+ ### Security Checklist
385
+
386
+ - [ ] Secrets in `runtimeConfig` (not `public`)
387
+ - [ ] Server routes validate input
388
+ - [ ] Auth middleware on protected routes
389
+ - [ ] CSRF protection on mutations
390
+ - [ ] No sensitive data in client bundle
391
+
392
+ ### Common Mistakes
393
+
394
+ | Mistake | Impact | Fix |
395
+ |---------|--------|-----|
396
+ | `fetch()` instead of `useFetch` | Hydration mismatch | Use `useFetch` |
397
+ | Missing `key` in useFetch | Cache conflicts | Add unique key |
398
+ | Ignoring `pending` state | Flash of empty | Show loading |
399
+ | Direct localStorage | SSR crash | Use plugin or client check |
400
+ | Secrets in `public` config | Leaked to client | Use `runtimeConfig.secret` |
401
+
402
+ ## Integration
403
+
404
+ ### With Directus
405
+
406
+ ```typescript
407
+ // composables/useDirectus.ts
408
+ import { createDirectus, rest, authentication } from '@directus/sdk';
409
+
410
+ export const useDirectus = () => {
411
+ const config = useRuntimeConfig();
412
+
413
+ const client = createDirectus<Schema>(config.public.directusUrl)
414
+ .with(rest())
415
+ .with(authentication('cookie', { credentials: 'include' }));
416
+
417
+ return client;
418
+ };
419
+
420
+ // composables/useProducts.ts
421
+ export const useProducts = () => {
422
+ const directus = useDirectus();
423
+
424
+ return useAsyncData('products', () =>
425
+ directus.request(readItems('products', {
426
+ filter: { status: { _eq: 'published' } },
427
+ }))
428
+ );
429
+ };
430
+ ```
431
+
432
+ ### With Pinia
433
+
434
+ ```typescript
435
+ // stores/cart.ts
436
+ export const useCartStore = defineStore('cart', () => {
437
+ const items = ref<CartItem[]>([]);
438
+
439
+ const total = computed(() =>
440
+ items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
441
+ );
442
+
443
+ const addItem = (product: Product, quantity = 1) => {
444
+ const existing = items.value.find(i => i.productId === product.id);
445
+ if (existing) {
446
+ existing.quantity += quantity;
447
+ } else {
448
+ items.value.push({ productId: product.id, ...product, quantity });
449
+ }
450
+ };
451
+
452
+ return { items, total, addItem };
453
+ });
454
+ ```
455
+
456
+ ## Resources
457
+
458
+ ### Official Docs
459
+ - Docs: https://nuxt.com/docs
460
+ - Modules: https://nuxt.com/modules
461
+
462
+ ### Context7 Queries
463
+
464
+ ```
465
+ Query: "Nuxt 3 useFetch best practices"
466
+ Query: "Nuxt 3 server routes authentication"
467
+ Query: "Nuxt 3 middleware patterns"
468
+ Query: "Nuxt 3 Pinia setup"
469
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codihaus/claude-skills",
3
- "version": "1.0.0",
3
+ "version": "1.3.0",
4
4
  "description": "Claude Code skills for software development workflow",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -40,6 +40,8 @@
40
40
  "bin",
41
41
  "src",
42
42
  "skills",
43
+ "knowledge",
44
+ "project-scripts",
43
45
  "templates",
44
46
  "README.md"
45
47
  ]