@codihaus/claude-skills 1.5.0 → 1.5.1

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,6 @@
1
1
  {
2
2
  "name": "@codihaus/claude-skills",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "Claude Code skills for software development workflow",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -8,7 +8,10 @@
8
8
  },
9
9
  "scripts": {
10
10
  "build": "node scripts/build.js",
11
- "prepublishOnly": "npm run build",
11
+ "release": "node scripts/publish.js",
12
+ "release:patch": "node scripts/publish.js patch",
13
+ "release:minor": "node scripts/publish.js minor",
14
+ "release:major": "node scripts/publish.js major",
12
15
  "test": "node bin/cli.js --help"
13
16
  },
14
17
  "type": "module",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: dev-coding-backend
3
3
  description: Backend implementation patterns and workflows
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  ---
6
6
 
7
7
  # /dev-coding-backend - Backend Implementation
@@ -11,6 +11,20 @@ version: 2.0.0
11
11
 
12
12
  Backend-specific workflow for API, schema, and data layer implementation.
13
13
 
14
+ ## Fundamentals (MUST READ FIRST)
15
+
16
+ **Before implementing, understand the principles:**
17
+
18
+ → Read `references/fundamentals.md`
19
+
20
+ This covers:
21
+ - **Core Mindset**: "Guardian of truth, trust nothing, enforce rules"
22
+ - **7 Principles**: Separation of Concerns, Single Source of Truth, Don't Repeat Work, Don't Make Users Wait, Don't Trust Anyone, Plan for Failure, Stateless Design
23
+ - **Pattern Recognition**: When to use Service Layer, Repository, Queue, Cache, Circuit Breaker, etc.
24
+ - **Architecture Layers**: Route → Service → Domain → Repository → Infrastructure
25
+
26
+ **Key Decision**: For each piece of code, ask "which principle applies?" Then choose the pattern that principle suggests.
27
+
14
28
  ## Knowledge Loading (CRITICAL)
15
29
 
16
30
  Before implementing, load relevant knowledge:
@@ -0,0 +1,428 @@
1
+ # Backend Fundamentals
2
+
3
+ The principles and patterns that enable scalable, maintainable backend systems.
4
+
5
+ ## Core Mindset
6
+
7
+ **"I am the guardian of truth. I trust nothing. I enforce rules. I must be reliable."**
8
+
9
+ The backend is the last line of defense. It:
10
+ - Protects data integrity
11
+ - Enforces business rules
12
+ - Handles failures gracefully
13
+ - Scales under load
14
+
15
+ ---
16
+
17
+ ## The Principles
18
+
19
+ Principles are the fundamental laws. Patterns are solutions derived from them.
20
+
21
+ ### 1. Separation of Concerns
22
+
23
+ **Law**: Each piece of code should have ONE responsibility.
24
+
25
+ **Why**: When things are mixed, changing one breaks another. Testing becomes impossible. New developers get lost.
26
+
27
+ **Patterns derived**:
28
+
29
+ | Pattern | What it Separates |
30
+ |---------|-------------------|
31
+ | Service Layer | Business logic FROM HTTP handling |
32
+ | Repository | Data access FROM business logic |
33
+ | Controller/Route | Request parsing FROM processing |
34
+ | Middleware | Cross-cutting concerns FROM main logic |
35
+ | Event-Driven | "What happened" FROM "What to do about it" |
36
+
37
+ **Recognition signals**:
38
+ - Function does more than one thing
39
+ - Can't test without real database/HTTP
40
+ - Changing one feature breaks another
41
+ - File is > 300 lines
42
+
43
+ **Structure example**:
44
+ ```
45
+ # BAD: Mixed concerns
46
+ route('/orders', async (req) => {
47
+ validate(req.body) # validation
48
+ const user = await db.users.find(req.userId) # data access
49
+ if (user.balance < req.body.total) throw Error # business rule
50
+ await db.orders.create(...) # data access
51
+ await sendEmail(user.email) # side effect
52
+ return order
53
+ })
54
+
55
+ # GOOD: Separated concerns
56
+ route('/orders', OrderController.create)
57
+
58
+ OrderController.create(req) {
59
+ const dto = OrderValidator.validate(req.body) # validation layer
60
+ const order = await OrderService.create(dto, req.userId) # service layer
61
+ return OrderPresenter.format(order) # presentation layer
62
+ }
63
+
64
+ OrderService.create(dto, userId) {
65
+ const user = await UserRepository.findById(userId) # repository
66
+ OrderRules.validateCanOrder(user, dto) # business rules
67
+ const order = await OrderRepository.create(dto)
68
+ await EventBus.emit('order.created', order) # events for side effects
69
+ return order
70
+ }
71
+ ```
72
+
73
+ ---
74
+
75
+ ### 2. Single Source of Truth
76
+
77
+ **Law**: Each piece of data or rule should exist in ONE place only.
78
+
79
+ **Why**: Duplicated data gets out of sync. Duplicated rules diverge over time.
80
+
81
+ **Patterns derived**:
82
+
83
+ | Pattern | What it Centralizes |
84
+ |---------|---------------------|
85
+ | Repository | All access to a data type |
86
+ | Domain Model | Business rules for an entity |
87
+ | Configuration | Environment-specific values |
88
+ | Constants/Enums | Magic values and statuses |
89
+ | Event Store | Historical record of changes |
90
+
91
+ **Recognition signals**:
92
+ - Same validation in multiple places
93
+ - Same query written twice
94
+ - Hardcoded values scattered around
95
+ - "Which one is correct?" questions
96
+
97
+ **Structure example**:
98
+ ```
99
+ # BAD: Rules in multiple places
100
+ # In controller:
101
+ if (order.status !== 'pending') throw Error
102
+
103
+ # In service:
104
+ if (order.status !== 'pending') throw Error
105
+
106
+ # In another service:
107
+ if (order.status != 'pending' && order.status != 'draft') throw Error # diverged!
108
+
109
+ # GOOD: Single source
110
+ class Order {
111
+ canBeModified() {
112
+ return ['pending', 'draft'].includes(this.status)
113
+ }
114
+ }
115
+
116
+ # Everywhere else:
117
+ if (!order.canBeModified()) throw Error
118
+ ```
119
+
120
+ ---
121
+
122
+ ### 3. Don't Repeat Work
123
+
124
+ **Law**: If the same work is done repeatedly with the same result, do it once and remember.
125
+
126
+ **Why**: Wasted resources, slower response, higher costs, database overload.
127
+
128
+ **Patterns derived**:
129
+
130
+ | Pattern | What it Remembers |
131
+ |---------|-------------------|
132
+ | Caching (Redis/Memory) | Expensive query results |
133
+ | Memoization | Function computation |
134
+ | Database Indexes | Query paths |
135
+ | CDN | Static assets |
136
+ | Materialized Views | Pre-computed aggregations |
137
+
138
+ **Recognition signals**:
139
+ - Same query runs multiple times per request
140
+ - Same computation on same input
141
+ - Dashboard aggregations are slow
142
+ - Database CPU is high
143
+
144
+ **Decision guide**:
145
+ ```
146
+ How often does data change?
147
+ ├── Never (static) → CDN, aggressive cache
148
+ ├── Rarely (config) → Long TTL cache (hours)
149
+ ├── Sometimes (user profile) → Medium TTL (minutes)
150
+ ├── Often (feed) → Short TTL (seconds) or real-time
151
+ └── Always (balance) → No cache, or cache with invalidation
152
+ ```
153
+
154
+ ---
155
+
156
+ ### 4. Don't Make Users Wait
157
+
158
+ **Law**: If something takes long and user doesn't need immediate result, do it later.
159
+
160
+ **Why**: Users leave, connections timeout, server resources blocked.
161
+
162
+ **Patterns derived**:
163
+
164
+ | Pattern | Use When |
165
+ |---------|----------|
166
+ | Message Queue | Task takes > 1-2 seconds |
167
+ | Background Jobs | Scheduled or deferred work |
168
+ | Webhooks | Notify instead of poll |
169
+ | Streaming | Large data transfer |
170
+ | Pagination | Large result sets |
171
+
172
+ **Recognition signals**:
173
+ - API timeout errors
174
+ - User waits > 3 seconds
175
+ - Sending emails in request
176
+ - Processing files in request
177
+ - Generating reports in request
178
+
179
+ **Structure example**:
180
+ ```
181
+ # BAD: User waits for everything
182
+ route('/orders', async (req) => {
183
+ const order = await createOrder(req.body)
184
+ await generateInvoicePDF(order) # 3 seconds
185
+ await sendEmail(order) # 2 seconds
186
+ await notifyWarehouse(order) # 1 second
187
+ await updateAnalytics(order) # 500ms
188
+ return order # User waited 6.5 seconds!
189
+ })
190
+
191
+ # GOOD: Return fast, process later
192
+ route('/orders', async (req) => {
193
+ const order = await createOrder(req.body)
194
+ await queue.add('order.process', { orderId: order.id })
195
+ return order # User waited 200ms
196
+ })
197
+
198
+ # Background worker handles the rest
199
+ worker.process('order.process', async (job) => {
200
+ const order = await OrderRepository.find(job.orderId)
201
+ await generateInvoicePDF(order)
202
+ await sendEmail(order)
203
+ await notifyWarehouse(order)
204
+ await updateAnalytics(order)
205
+ })
206
+ ```
207
+
208
+ ---
209
+
210
+ ### 5. Don't Trust Anyone
211
+
212
+ **Law**: Every input is potentially malicious or malformed. Validate at boundaries.
213
+
214
+ **Why**: Security breaches, data corruption, system crashes.
215
+
216
+ **Patterns derived**:
217
+
218
+ | Pattern | What it Protects |
219
+ |---------|------------------|
220
+ | Input Validation | Data integrity |
221
+ | Authentication | Identity verification |
222
+ | Authorization | Access control |
223
+ | Rate Limiting | Resource protection |
224
+ | Sanitization | Injection prevention |
225
+
226
+ **Recognition signals**:
227
+ - User input used directly in queries
228
+ - No authentication on endpoints
229
+ - Missing role checks
230
+ - No request size limits
231
+ - Error messages expose internals
232
+
233
+ **Validation layers**:
234
+ ```
235
+ Request arrives
236
+
237
+ [1. Rate Limit] → Too many? Reject 429
238
+
239
+ [2. Authentication] → Who is this? Reject 401 if unknown
240
+
241
+ [3. Authorization] → Can they do this? Reject 403 if not
242
+
243
+ [4. Input Validation] → Is data valid? Reject 400 if not
244
+
245
+ [5. Business Rules] → Is action allowed? Reject 422 if not
246
+
247
+ Process request
248
+ ```
249
+
250
+ ---
251
+
252
+ ### 6. Plan for Failure
253
+
254
+ **Law**: Everything will fail eventually. Design for it.
255
+
256
+ **Why**: Network fails, services go down, databases crash, disks fill up.
257
+
258
+ **Patterns derived**:
259
+
260
+ | Pattern | Failure it Handles |
261
+ |---------|-------------------|
262
+ | Circuit Breaker | External service down |
263
+ | Retry with Backoff | Temporary failures |
264
+ | Timeout | Hung connections |
265
+ | Fallback | Degraded operation |
266
+ | Dead Letter Queue | Unprocessable messages |
267
+ | Idempotency | Duplicate requests |
268
+
269
+ **Recognition signals**:
270
+ - No try/catch around external calls
271
+ - No timeout on HTTP requests
272
+ - Retrying without backoff (hammering)
273
+ - No fallback when service unavailable
274
+ - Duplicate orders when user clicks twice
275
+
276
+ **Structure example**:
277
+ ```
278
+ # BAD: Assumes success
279
+ const payment = await paymentService.charge(order)
280
+
281
+ # GOOD: Plans for failure
282
+ const payment = await circuitBreaker.call(
283
+ () => paymentService.charge(order),
284
+ {
285
+ timeout: 5000,
286
+ retry: { attempts: 3, backoff: 'exponential' },
287
+ fallback: () => {
288
+ queue.add('payment.retry', { orderId: order.id })
289
+ return { status: 'pending', message: 'Processing...' }
290
+ }
291
+ }
292
+ )
293
+ ```
294
+
295
+ **Idempotency example**:
296
+ ```
297
+ # Problem: User clicks "Pay" twice, charged twice
298
+
299
+ # Solution: Idempotency key
300
+ route('/payments', async (req) => {
301
+ const existingPayment = await PaymentRepository.findByIdempotencyKey(
302
+ req.headers['idempotency-key']
303
+ )
304
+
305
+ if (existingPayment) {
306
+ return existingPayment # Return same result, don't process again
307
+ }
308
+
309
+ const payment = await processPayment(req.body)
310
+ payment.idempotencyKey = req.headers['idempotency-key']
311
+ await PaymentRepository.save(payment)
312
+ return payment
313
+ })
314
+ ```
315
+
316
+ ---
317
+
318
+ ### 7. Stateless Design
319
+
320
+ **Law**: Server should not remember anything between requests (store state externally).
321
+
322
+ **Why**: Enables horizontal scaling, survives server restarts, simplifies deployment.
323
+
324
+ **Patterns derived**:
325
+
326
+ | Pattern | State it Externalizes |
327
+ |---------|----------------------|
328
+ | JWT Tokens | Session data in token |
329
+ | External Session Store | Session data in Redis |
330
+ | Database | All persistent data |
331
+ | Shared Cache | Computed/temporary data |
332
+ | Object Storage | Files and uploads |
333
+
334
+ **Recognition signals**:
335
+ - Using server memory for sessions
336
+ - Files stored on local disk
337
+ - In-memory caches that miss after deploy
338
+ - "Works on one server, fails with two"
339
+
340
+ **Structure example**:
341
+ ```
342
+ # BAD: Stateful (breaks with multiple servers)
343
+ const sessions = {} # In memory!
344
+ app.post('/login', (req) => {
345
+ sessions[userId] = { user, timestamp }
346
+ })
347
+ app.get('/me', (req) => {
348
+ return sessions[req.userId] # Other server doesn't have this!
349
+ })
350
+
351
+ # GOOD: Stateless (works with any number of servers)
352
+ app.post('/login', async (req) => {
353
+ const token = jwt.sign({ userId, role }) # State in token
354
+ await redis.set(`session:${userId}`, { lastLogin }) # State in Redis
355
+ return { token }
356
+ })
357
+ app.get('/me', async (req) => {
358
+ const payload = jwt.verify(req.token) # State from token
359
+ const session = await redis.get(`session:${payload.userId}`) # State from Redis
360
+ return { user: payload, session }
361
+ })
362
+ ```
363
+
364
+ ---
365
+
366
+ ## Pattern Decision Matrix
367
+
368
+ Quick reference for choosing patterns:
369
+
370
+ | Situation | Apply These Patterns |
371
+ |-----------|---------------------|
372
+ | Code is getting messy, hard to test | Service Layer + Repository + DI |
373
+ | Same logic in multiple places | Extract to Domain Model or Service |
374
+ | API is slow | Caching, Queue, Pagination |
375
+ | High database load | Caching, Indexing, Read Replicas |
376
+ | External service unreliable | Circuit Breaker, Retry, Fallback |
377
+ | Need audit trail | Event Sourcing or Audit Log |
378
+ | Complex workflows | Saga, State Machine |
379
+ | Many services communicating | Event Bus, API Gateway |
380
+ | Users hitting API too hard | Rate Limiting, Throttling |
381
+ | File uploads | Object Storage, Signed URLs |
382
+
383
+ ---
384
+
385
+ ## Architecture Layers
386
+
387
+ Standard backend structure:
388
+
389
+ ```
390
+ ┌─────────────────────────────────────────────┐
391
+ │ HTTP Layer (Routes/Controllers) │
392
+ │ - Parse request │
393
+ │ - Call service │
394
+ │ - Format response │
395
+ ├─────────────────────────────────────────────┤
396
+ │ Service Layer │
397
+ │ - Business logic │
398
+ │ - Orchestrate operations │
399
+ │ - Emit events │
400
+ ├─────────────────────────────────────────────┤
401
+ │ Domain Layer (Models/Entities) │
402
+ │ - Business rules │
403
+ │ - Validation │
404
+ │ - State transitions │
405
+ ├─────────────────────────────────────────────┤
406
+ │ Repository Layer │
407
+ │ - Data access │
408
+ │ - Query building │
409
+ │ - Caching │
410
+ ├─────────────────────────────────────────────┤
411
+ │ Infrastructure (Database, Queue, Cache) │
412
+ └─────────────────────────────────────────────┘
413
+ ```
414
+
415
+ **Rule**: Upper layers can call lower layers. Never the reverse.
416
+
417
+ ---
418
+
419
+ ## Checklist Before Implementation
420
+
421
+ - [ ] Which principle applies to this feature?
422
+ - [ ] What patterns does that principle suggest?
423
+ - [ ] Is there existing similar code to follow?
424
+ - [ ] Where does validation happen?
425
+ - [ ] What if this fails?
426
+ - [ ] What if 1000 users do this at once?
427
+ - [ ] Does this need to be synchronous?
428
+ - [ ] What state needs to be stored?
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: dev-coding-frontend
3
3
  description: Frontend implementation patterns and workflows
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  ---
6
6
 
7
7
  # /dev-coding-frontend - Frontend Implementation
@@ -12,6 +12,22 @@ version: 2.0.0
12
12
 
13
13
  Frontend-specific workflow for UI components, pages, and client-side logic.
14
14
 
15
+ ## Fundamentals (MUST READ FIRST)
16
+
17
+ **Before implementing, understand the principles:**
18
+
19
+ → Read `references/fundamentals.md`
20
+
21
+ This covers:
22
+ - **Core Mindset**: "Communicator with humans - clear, responsive, consistent"
23
+ - **6 Principles**: Always Communicate, Feel Instant, Stay Consistent, Work for Everyone, Single Source of Truth, Minimize Complexity
24
+ - **Pattern Recognition**: When to use Loading States, Optimistic UI, State Management, Lazy Loading, etc.
25
+ - **UI States**: Every component must handle loading, error, empty, success
26
+
27
+ **Key Decision**: For each piece of code, ask "which principle applies?" Then choose the pattern that principle suggests.
28
+
29
+ **CRITICAL - Consistency**: Before writing ANY code, check existing codebase for naming conventions, file structure, component patterns, and styling approach. Match them exactly.
30
+
15
31
  ## Knowledge Loading (CRITICAL)
16
32
 
17
33
  Before implementing, load relevant knowledge:
@@ -0,0 +1,577 @@
1
+ # Frontend Fundamentals
2
+
3
+ The principles and patterns that create excellent user experiences.
4
+
5
+ ## Core Mindset
6
+
7
+ **"I am the communicator with humans. I must be clear, responsive, and consistent."**
8
+
9
+ The frontend is the interface between humans and the system. It:
10
+ - Communicates what's happening
11
+ - Responds instantly (or appears to)
12
+ - Behaves consistently
13
+ - Works for everyone
14
+
15
+ ---
16
+
17
+ ## The Principles
18
+
19
+ Principles are the fundamental laws. Patterns are solutions derived from them.
20
+
21
+ ### 1. Always Communicate
22
+
23
+ **Law**: The user should NEVER wonder what's happening.
24
+
25
+ **Why**: Uncertainty creates anxiety. Users abandon apps that feel "broken" or "stuck."
26
+
27
+ **Patterns derived**:
28
+
29
+ | Pattern | What it Communicates |
30
+ |---------|---------------------|
31
+ | Loading State | "I'm working on it" |
32
+ | Error State | "Something went wrong, here's what" |
33
+ | Empty State | "Nothing here yet, here's why" |
34
+ | Success Feedback | "Done! Here's the result" |
35
+ | Progress Indicator | "X% complete" |
36
+ | Skeleton UI | "Content is coming, here's the shape" |
37
+
38
+ **Recognition signals**:
39
+ - Blank screen while loading
40
+ - Click button, nothing visible happens
41
+ - Error occurs, user sees nothing
42
+ - Form submits, no confirmation
43
+ - List might be empty, just shows nothing
44
+
45
+ **State matrix for EVERY data-fetching component**:
46
+ ```
47
+ STATE WHAT USER SEES
48
+ ─────────────────────────────────────
49
+ idle Initial state, maybe CTA
50
+ loading Spinner, skeleton, or shimmer
51
+ success The actual content
52
+ empty Helpful message + action
53
+ error What went wrong + retry option
54
+ ```
55
+
56
+ **Structure example**:
57
+ ```vue
58
+ <!-- BAD: No communication -->
59
+ <template>
60
+ <div v-for="item in items">{{ item.name }}</div>
61
+ </template>
62
+
63
+ <!-- GOOD: Always communicating -->
64
+ <template>
65
+ <!-- Loading: Show skeleton -->
66
+ <div v-if="pending">
67
+ <Skeleton v-for="i in 3" :key="i" />
68
+ </div>
69
+
70
+ <!-- Error: Explain and offer action -->
71
+ <div v-else-if="error">
72
+ <ErrorMessage :error="error" />
73
+ <Button @click="refresh">Try Again</Button>
74
+ </div>
75
+
76
+ <!-- Empty: Guide the user -->
77
+ <div v-else-if="items.length === 0">
78
+ <EmptyState
79
+ title="No items yet"
80
+ description="Create your first item to get started"
81
+ action="Create Item"
82
+ @action="openCreateModal"
83
+ />
84
+ </div>
85
+
86
+ <!-- Success: Show content -->
87
+ <div v-else>
88
+ <Item v-for="item in items" :key="item.id" :item="item" />
89
+ </div>
90
+ </template>
91
+ ```
92
+
93
+ ---
94
+
95
+ ### 2. Feel Instant
96
+
97
+ **Law**: Perception matters more than reality. Make it FEEL fast.
98
+
99
+ **Why**: Users perceive 100ms as instant. After 1s they notice delay. After 3s they leave.
100
+
101
+ **Patterns derived**:
102
+
103
+ | Pattern | How it Feels Faster |
104
+ |---------|---------------------|
105
+ | Optimistic UI | Show result before server confirms |
106
+ | Skeleton Loading | Show shape, brain fills in details |
107
+ | Lazy Loading | Load what's visible first |
108
+ | Prefetching | Load before user needs it |
109
+ | Debouncing | Don't overwork on rapid input |
110
+ | Code Splitting | Smaller initial bundle |
111
+ | Instant Navigation | Client-side routing |
112
+
113
+ **Recognition signals**:
114
+ - User clicks, waits, then sees change
115
+ - Full page reload on navigation
116
+ - Large bundle size, slow initial load
117
+ - Images load all at once, page jumps
118
+ - Search triggers on every keystroke
119
+
120
+ **Optimistic UI example**:
121
+ ```javascript
122
+ // BAD: Wait for server
123
+ async function toggleLike(post) {
124
+ const result = await api.likePost(post.id) // User waits 500ms
125
+ post.liked = result.liked
126
+ post.likeCount = result.likeCount
127
+ }
128
+
129
+ // GOOD: Optimistic update
130
+ async function toggleLike(post) {
131
+ // Immediately update UI (feels instant)
132
+ const previousState = { liked: post.liked, count: post.likeCount }
133
+ post.liked = !post.liked
134
+ post.likeCount += post.liked ? 1 : -1
135
+
136
+ try {
137
+ await api.likePost(post.id)
138
+ } catch (error) {
139
+ // Rollback if server fails
140
+ post.liked = previousState.liked
141
+ post.likeCount = previousState.count
142
+ toast.error('Could not update like')
143
+ }
144
+ }
145
+ ```
146
+
147
+ **Loading priority**:
148
+ ```
149
+ 1. Critical content (above fold) → Load immediately
150
+ 2. Interactive elements → Load immediately
151
+ 3. Below-fold content → Lazy load on scroll
152
+ 4. Images → Lazy load + placeholder
153
+ 5. Analytics, tracking → Load after page ready
154
+ 6. Non-essential features → Load on interaction
155
+ ```
156
+
157
+ ---
158
+
159
+ ### 3. Stay Consistent
160
+
161
+ **Law**: Same action should always produce same result. Match existing patterns.
162
+
163
+ **Why**: Consistency builds trust. Inconsistency confuses and frustrates.
164
+
165
+ **Patterns derived**:
166
+
167
+ | Pattern | What it Standardizes |
168
+ |---------|---------------------|
169
+ | Design System | Visual appearance |
170
+ | Component Library | UI behavior |
171
+ | Naming Conventions | Code readability |
172
+ | Layout Templates | Page structure |
173
+ | Form Patterns | Input behavior |
174
+ | Navigation Patterns | Movement through app |
175
+
176
+ **Recognition signals**:
177
+ - Buttons look different on different pages
178
+ - Same action has different animations
179
+ - Forms behave differently
180
+ - Different naming styles in codebase
181
+ - New code doesn't match existing patterns
182
+
183
+ **Consistency checklist**:
184
+ ```
185
+ Before writing new code, check existing codebase for:
186
+
187
+ NAMING:
188
+ □ How are components named? (PascalCase, kebab-case?)
189
+ □ How are files named? (index.vue, ComponentName.vue?)
190
+ □ How are props named? (isOpen, open, opened?)
191
+ □ How are events named? (onClose, handleClose, close?)
192
+ □ How are functions named? (getData, fetchData, loadData?)
193
+
194
+ STRUCTURE:
195
+ □ Where do components live? (components/, shared/?)
196
+ □ How is state managed? (Pinia, composables, local?)
197
+ □ How are forms handled? (controlled, libraries?)
198
+ □ How is API data fetched? (useFetch, custom hooks?)
199
+
200
+ STYLE:
201
+ □ What CSS approach? (Tailwind, modules, styled?)
202
+ □ What design tokens exist? (colors, spacing, shadows?)
203
+ □ How are responsive breakpoints handled?
204
+
205
+ BEHAVIOR:
206
+ □ How do modals open/close?
207
+ □ How is form validation shown?
208
+ □ How are notifications displayed?
209
+ □ How do lists handle empty/loading states?
210
+ ```
211
+
212
+ **Match existing pattern example**:
213
+ ```javascript
214
+ // EXISTING CODE uses this pattern:
215
+ const { data: users, pending, error } = await useFetch('/api/users')
216
+
217
+ // NEW CODE should match:
218
+ // GOOD - matches existing
219
+ const { data: products, pending, error } = await useFetch('/api/products')
220
+
221
+ // BAD - different pattern
222
+ const products = ref([])
223
+ const loading = ref(true)
224
+ onMounted(async () => {
225
+ loading.value = true
226
+ products.value = await fetch('/api/products').then(r => r.json())
227
+ loading.value = false
228
+ })
229
+ ```
230
+
231
+ ---
232
+
233
+ ### 4. Work for Everyone
234
+
235
+ **Law**: The interface must work for all users, not just ideal conditions.
236
+
237
+ **Why**: Users have disabilities, slow connections, old devices, different languages.
238
+
239
+ **Patterns derived**:
240
+
241
+ | Pattern | Who it Helps |
242
+ |---------|-------------|
243
+ | Semantic HTML | Screen readers, SEO |
244
+ | Keyboard Navigation | Motor disabilities, power users |
245
+ | Color Contrast | Visual impairments |
246
+ | Responsive Design | Mobile users |
247
+ | Offline Support | Poor connections |
248
+ | Error Recovery | All users |
249
+ | Internationalization | Non-English speakers |
250
+
251
+ **Recognition signals**:
252
+ - Can't use with keyboard only
253
+ - No alt text on images
254
+ - Low color contrast
255
+ - Breaks on mobile
256
+ - Crashes on slow connection
257
+ - No error recovery
258
+
259
+ **Accessibility minimum**:
260
+ ```html
261
+ <!-- Semantic HTML first -->
262
+ <nav> not <div class="nav">
263
+ <button> not <div onclick>
264
+ <main> not <div class="main">
265
+ <h1>, <h2>, <h3> in order
266
+
267
+ <!-- Images -->
268
+ <img src="..." alt="Description of what image shows" />
269
+ <img src="decorative.png" alt="" /> <!-- Empty alt for decorative -->
270
+
271
+ <!-- Interactive elements -->
272
+ <button aria-label="Close dialog">×</button>
273
+ <input aria-describedby="help-text" />
274
+ <div id="help-text">Password must be 8+ characters</div>
275
+
276
+ <!-- Focus management -->
277
+ <!-- When modal opens: focus first element -->
278
+ <!-- When modal closes: focus trigger element -->
279
+
280
+ <!-- Keyboard -->
281
+ <!-- All interactive elements reachable via Tab -->
282
+ <!-- Enter/Space activates buttons -->
283
+ <!-- Escape closes modals/dropdowns -->
284
+ ```
285
+
286
+ **Responsive approach**:
287
+ ```
288
+ MOBILE FIRST:
289
+ 1. Design for smallest screen first
290
+ 2. Add complexity for larger screens
291
+ 3. Test at: 320px, 768px, 1024px, 1440px
292
+
293
+ CSS ORDER:
294
+ .component {
295
+ /* Mobile styles (default) */
296
+ padding: 1rem;
297
+ }
298
+
299
+ @media (min-width: 768px) {
300
+ /* Tablet and up */
301
+ padding: 2rem;
302
+ }
303
+
304
+ @media (min-width: 1024px) {
305
+ /* Desktop and up */
306
+ padding: 3rem;
307
+ }
308
+ ```
309
+
310
+ ---
311
+
312
+ ### 5. Single Source of Truth
313
+
314
+ **Law**: Each piece of state should live in ONE place.
315
+
316
+ **Why**: Duplicate state gets out of sync. Bugs appear. Debugging is nightmare.
317
+
318
+ **Patterns derived**:
319
+
320
+ | Pattern | What it Centralizes |
321
+ |---------|---------------------|
322
+ | State Management (Pinia) | Global app state |
323
+ | Composables | Shared logic |
324
+ | Controlled Components | Form input values |
325
+ | URL as State | Navigation/filter state |
326
+ | Props Down, Events Up | Component communication |
327
+
328
+ **Recognition signals**:
329
+ - Same data stored in multiple places
330
+ - Prop drilling through many levels
331
+ - Components directly modifying parent state
332
+ - State out of sync after actions
333
+ - "Why isn't this updating?"
334
+
335
+ **State location guide**:
336
+ ```
337
+ WHO NEEDS THIS STATE?
338
+
339
+ ├─ Just this component → Local state (ref/reactive)
340
+
341
+ ├─ Parent and children → Props down, events up
342
+
343
+ ├─ Siblings → Lift state to common parent, or use composable
344
+
345
+ ├─ Many unrelated components → Global store (Pinia)
346
+
347
+ └─ Should survive refresh → URL params or localStorage
348
+ ```
349
+
350
+ **Example**:
351
+ ```javascript
352
+ // BAD: Duplicate state
353
+ // In Parent:
354
+ const selectedUser = ref(null)
355
+
356
+ // In Child (duplicating):
357
+ const selectedUser = ref(null) // Out of sync risk!
358
+
359
+ // GOOD: Single source
360
+ // In Parent:
361
+ const selectedUser = ref(null)
362
+
363
+ // In Child (receiving):
364
+ const props = defineProps(['selectedUser'])
365
+ const emit = defineEmits(['update:selectedUser'])
366
+
367
+ // Or use store for global state:
368
+ // store/user.js
369
+ export const useUserStore = defineStore('user', () => {
370
+ const selectedUser = ref(null)
371
+ const selectUser = (user) => selectedUser.value = user
372
+ return { selectedUser, selectUser }
373
+ })
374
+
375
+ // Any component:
376
+ const userStore = useUserStore()
377
+ userStore.selectUser(user)
378
+ ```
379
+
380
+ ---
381
+
382
+ ### 6. Minimize Complexity
383
+
384
+ **Law**: Simple is better than clever. Obvious is better than magical.
385
+
386
+ **Why**: Others (and future you) must understand and modify this code.
387
+
388
+ **Patterns derived**:
389
+
390
+ | Pattern | How it Simplifies |
391
+ |---------|-------------------|
392
+ | Small Components | Each does one thing |
393
+ | Composition | Combine simple pieces |
394
+ | Explicit Props | Clear interface |
395
+ | Flat State | Avoid deep nesting |
396
+ | Co-location | Related code together |
397
+
398
+ **Recognition signals**:
399
+ - Component file > 300 lines
400
+ - Props > 10 items
401
+ - Deeply nested state (a.b.c.d.e)
402
+ - "Magic" that's hard to trace
403
+ - Heavy abstraction for simple tasks
404
+
405
+ **Component size guide**:
406
+ ```
407
+ IDEAL COMPONENT:
408
+ - One clear responsibility
409
+ - < 200 lines (template + script)
410
+ - < 10 props
411
+ - Can describe in one sentence
412
+
413
+ TOO BIG IF:
414
+ - Multiple responsibilities
415
+ - Lots of conditional rendering
416
+ - Can't understand in 30 seconds
417
+ - Needs comments to explain
418
+
419
+ SPLIT INTO:
420
+ - Container (data/logic) + Presenter (UI)
421
+ - Multiple smaller components
422
+ - Composable for shared logic
423
+ ```
424
+
425
+ **Composition over complexity**:
426
+ ```vue
427
+ <!-- BAD: One complex component -->
428
+ <template>
429
+ <div>
430
+ <div v-if="mode === 'edit'">
431
+ <!-- 100 lines of edit form -->
432
+ </div>
433
+ <div v-else-if="mode === 'view'">
434
+ <!-- 100 lines of view display -->
435
+ </div>
436
+ <div v-else-if="mode === 'loading'">
437
+ <!-- 50 lines of skeleton -->
438
+ </div>
439
+ </div>
440
+ </template>
441
+
442
+ <!-- GOOD: Composed simple components -->
443
+ <template>
444
+ <ProductSkeleton v-if="pending" />
445
+ <ProductEditForm v-else-if="mode === 'edit'" :product="data" @save="save" />
446
+ <ProductView v-else :product="data" @edit="startEdit" />
447
+ </template>
448
+ ```
449
+
450
+ ---
451
+
452
+ ## Pattern Decision Matrix
453
+
454
+ Quick reference for choosing patterns:
455
+
456
+ | Situation | Apply These Patterns |
457
+ |-----------|---------------------|
458
+ | Data from API | Loading + Error + Empty states |
459
+ | User action → Server | Optimistic UI or Loading feedback |
460
+ | Form with many fields | Form library + Validation schema |
461
+ | Large list (100+ items) | Virtualization |
462
+ | Heavy component rarely used | Lazy loading |
463
+ | Multiple components need same data | State management (Pinia) |
464
+ | Complex UI with many states | State machine |
465
+ | Need to match existing code | Study patterns first, match exactly |
466
+ | Reusable UI element | Extract to component |
467
+ | Reusable logic | Extract to composable |
468
+
469
+ ---
470
+
471
+ ## Component Structure
472
+
473
+ Standard component organization:
474
+
475
+ ```vue
476
+ <script setup lang="ts">
477
+ // 1. Imports
478
+ import { ref, computed, watch } from 'vue'
479
+ import { useUserStore } from '@/stores/user'
480
+ import ChildComponent from './ChildComponent.vue'
481
+
482
+ // 2. Props & Emits
483
+ const props = defineProps<{
484
+ title: string
485
+ items: Item[]
486
+ }>()
487
+
488
+ const emit = defineEmits<{
489
+ select: [item: Item]
490
+ close: []
491
+ }>()
492
+
493
+ // 3. Composables & Stores
494
+ const userStore = useUserStore()
495
+ const { data, pending, error } = await useFetch('/api/data')
496
+
497
+ // 4. Local State
498
+ const isOpen = ref(false)
499
+ const searchQuery = ref('')
500
+
501
+ // 5. Computed
502
+ const filteredItems = computed(() =>
503
+ props.items.filter(item =>
504
+ item.name.includes(searchQuery.value)
505
+ )
506
+ )
507
+
508
+ // 6. Methods
509
+ function handleSelect(item: Item) {
510
+ emit('select', item)
511
+ }
512
+
513
+ // 7. Lifecycle & Watchers
514
+ watch(searchQuery, (newValue) => {
515
+ // React to changes
516
+ })
517
+ </script>
518
+
519
+ <template>
520
+ <!-- Single root with clear structure -->
521
+ </template>
522
+
523
+ <style scoped>
524
+ /* Component-specific styles */
525
+ </style>
526
+ ```
527
+
528
+ ---
529
+
530
+ ## UI States Template
531
+
532
+ Every data component should handle:
533
+
534
+ ```vue
535
+ <script setup>
536
+ const { data, pending, error, refresh } = await useFetch('/api/resource')
537
+ </script>
538
+
539
+ <template>
540
+ <div class="resource-container">
541
+ <!-- Loading -->
542
+ <ResourceSkeleton v-if="pending" />
543
+
544
+ <!-- Error -->
545
+ <ErrorState
546
+ v-else-if="error"
547
+ :message="error.message"
548
+ @retry="refresh"
549
+ />
550
+
551
+ <!-- Empty -->
552
+ <EmptyState
553
+ v-else-if="!data || data.length === 0"
554
+ title="No resources found"
555
+ description="Create your first resource to get started"
556
+ >
557
+ <Button @click="openCreate">Create Resource</Button>
558
+ </EmptyState>
559
+
560
+ <!-- Success -->
561
+ <ResourceList v-else :items="data" />
562
+ </div>
563
+ </template>
564
+ ```
565
+
566
+ ---
567
+
568
+ ## Checklist Before Implementation
569
+
570
+ - [ ] Which principle applies to this feature?
571
+ - [ ] Does this match existing code patterns?
572
+ - [ ] What are all the UI states? (loading, error, empty, success)
573
+ - [ ] How can this feel instant?
574
+ - [ ] Can it be used with keyboard only?
575
+ - [ ] Does it work on mobile?
576
+ - [ ] Where should state live?
577
+ - [ ] Is this component doing too much?