@qazuor/claude-code-config 0.5.0 → 0.6.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 (57) hide show
  1. package/README.md +106 -41
  2. package/dist/bin.cjs +963 -84
  3. package/dist/bin.cjs.map +1 -1
  4. package/dist/bin.js +963 -84
  5. package/dist/bin.js.map +1 -1
  6. package/dist/index.cjs +73 -56
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.cts +2 -0
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.js +73 -56
  11. package/dist/index.js.map +1 -1
  12. package/package.json +23 -24
  13. package/templates/CLAUDE.md.template +60 -5
  14. package/templates/agents/README.md +58 -39
  15. package/templates/agents/_registry.json +43 -202
  16. package/templates/agents/engineering/{hono-engineer.md → api-engineer.md} +61 -70
  17. package/templates/agents/engineering/database-engineer.md +253 -0
  18. package/templates/agents/engineering/frontend-engineer.md +302 -0
  19. package/templates/hooks/on-notification.sh +0 -0
  20. package/templates/scripts/add-changelogs.sh +0 -0
  21. package/templates/scripts/generate-code-registry.ts +0 -0
  22. package/templates/scripts/health-check.sh +0 -0
  23. package/templates/scripts/sync-registry.sh +0 -0
  24. package/templates/scripts/telemetry-report.ts +0 -0
  25. package/templates/scripts/validate-docs.sh +0 -0
  26. package/templates/scripts/validate-registry.sh +0 -0
  27. package/templates/scripts/validate-structure.sh +0 -0
  28. package/templates/scripts/worktree-cleanup.sh +0 -0
  29. package/templates/scripts/worktree-create.sh +0 -0
  30. package/templates/skills/README.md +99 -90
  31. package/templates/skills/_registry.json +323 -16
  32. package/templates/skills/api-frameworks/express-patterns.md +411 -0
  33. package/templates/skills/api-frameworks/fastify-patterns.md +419 -0
  34. package/templates/skills/api-frameworks/hono-patterns.md +388 -0
  35. package/templates/skills/api-frameworks/nestjs-patterns.md +497 -0
  36. package/templates/skills/database/drizzle-patterns.md +449 -0
  37. package/templates/skills/database/mongoose-patterns.md +503 -0
  38. package/templates/skills/database/prisma-patterns.md +487 -0
  39. package/templates/skills/frontend-frameworks/astro-patterns.md +415 -0
  40. package/templates/skills/frontend-frameworks/nextjs-patterns.md +470 -0
  41. package/templates/skills/frontend-frameworks/react-patterns.md +516 -0
  42. package/templates/skills/frontend-frameworks/tanstack-start-patterns.md +469 -0
  43. package/templates/skills/patterns/atdd-methodology.md +364 -0
  44. package/templates/skills/patterns/bdd-methodology.md +281 -0
  45. package/templates/skills/patterns/clean-architecture.md +444 -0
  46. package/templates/skills/patterns/hexagonal-architecture.md +567 -0
  47. package/templates/skills/patterns/vertical-slice-architecture.md +502 -0
  48. package/templates/agents/engineering/astro-engineer.md +0 -293
  49. package/templates/agents/engineering/db-drizzle-engineer.md +0 -360
  50. package/templates/agents/engineering/express-engineer.md +0 -316
  51. package/templates/agents/engineering/fastify-engineer.md +0 -399
  52. package/templates/agents/engineering/mongoose-engineer.md +0 -473
  53. package/templates/agents/engineering/nestjs-engineer.md +0 -429
  54. package/templates/agents/engineering/nextjs-engineer.md +0 -451
  55. package/templates/agents/engineering/prisma-engineer.md +0 -432
  56. package/templates/agents/engineering/react-senior-dev.md +0 -394
  57. package/templates/agents/engineering/tanstack-start-engineer.md +0 -447
@@ -0,0 +1,487 @@
1
+ # Prisma ORM Patterns
2
+
3
+ ## Overview
4
+
5
+ Prisma is a next-generation ORM with auto-generated types and intuitive API. This skill provides patterns for database operations with Prisma.
6
+
7
+ ---
8
+
9
+ ## Schema Definition
10
+
11
+ ### Model with Relations
12
+
13
+ ```prisma
14
+ // schema.prisma
15
+ generator client {
16
+ provider = "prisma-client-js"
17
+ }
18
+
19
+ datasource db {
20
+ provider = "postgresql"
21
+ url = env("DATABASE_URL")
22
+ }
23
+
24
+ model User {
25
+ id String @id @default(cuid())
26
+ email String @unique
27
+ name String?
28
+ password String
29
+ role Role @default(USER)
30
+ items Item[]
31
+ createdAt DateTime @default(now())
32
+ updatedAt DateTime @updatedAt
33
+ deletedAt DateTime?
34
+
35
+ @@index([email])
36
+ @@map("users")
37
+ }
38
+
39
+ model Item {
40
+ id String @id @default(cuid())
41
+ title String
42
+ description String?
43
+ status Status @default(ACTIVE)
44
+ price Int
45
+ author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
46
+ authorId String
47
+ tags ItemTag[]
48
+ createdAt DateTime @default(now())
49
+ updatedAt DateTime @updatedAt
50
+ deletedAt DateTime?
51
+
52
+ @@index([authorId])
53
+ @@index([status])
54
+ @@map("items")
55
+ }
56
+
57
+ model Tag {
58
+ id String @id @default(cuid())
59
+ name String @unique
60
+ items ItemTag[]
61
+
62
+ @@map("tags")
63
+ }
64
+
65
+ model ItemTag {
66
+ item Item @relation(fields: [itemId], references: [id], onDelete: Cascade)
67
+ itemId String
68
+ tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
69
+ tagId String
70
+
71
+ @@id([itemId, tagId])
72
+ @@map("item_tags")
73
+ }
74
+
75
+ enum Role {
76
+ USER
77
+ ADMIN
78
+ }
79
+
80
+ enum Status {
81
+ ACTIVE
82
+ ARCHIVED
83
+ }
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Query Patterns
89
+
90
+ ### Basic CRUD
91
+
92
+ ```typescript
93
+ import { prisma } from './client';
94
+
95
+ // Create
96
+ const item = await prisma.item.create({
97
+ data: {
98
+ title: 'New Item',
99
+ price: 100,
100
+ authorId: userId,
101
+ },
102
+ });
103
+
104
+ // Read one with relations
105
+ const item = await prisma.item.findUnique({
106
+ where: { id: itemId },
107
+ include: {
108
+ author: {
109
+ select: {
110
+ id: true,
111
+ name: true,
112
+ email: true,
113
+ },
114
+ },
115
+ tags: {
116
+ include: {
117
+ tag: true,
118
+ },
119
+ },
120
+ },
121
+ });
122
+
123
+ // Read many with filters
124
+ const items = await prisma.item.findMany({
125
+ where: {
126
+ status: 'ACTIVE',
127
+ deletedAt: null,
128
+ },
129
+ include: {
130
+ author: {
131
+ select: { name: true },
132
+ },
133
+ },
134
+ orderBy: { createdAt: 'desc' },
135
+ take: 10,
136
+ });
137
+
138
+ // Update
139
+ const updated = await prisma.item.update({
140
+ where: { id: itemId },
141
+ data: {
142
+ title: 'Updated Title',
143
+ },
144
+ });
145
+
146
+ // Delete
147
+ await prisma.item.delete({
148
+ where: { id: itemId },
149
+ });
150
+ ```
151
+
152
+ ### Pagination
153
+
154
+ ```typescript
155
+ async function findPaginated(input: {
156
+ page: number;
157
+ pageSize: number;
158
+ status?: Status;
159
+ }) {
160
+ const { page, pageSize, status } = input;
161
+ const skip = (page - 1) * pageSize;
162
+
163
+ const where = {
164
+ deletedAt: null,
165
+ ...(status && { status }),
166
+ };
167
+
168
+ const [items, total] = await Promise.all([
169
+ prisma.item.findMany({
170
+ where,
171
+ include: {
172
+ author: {
173
+ select: { name: true },
174
+ },
175
+ },
176
+ orderBy: { createdAt: 'desc' },
177
+ take: pageSize,
178
+ skip,
179
+ }),
180
+ prisma.item.count({ where }),
181
+ ]);
182
+
183
+ return {
184
+ data: items,
185
+ pagination: {
186
+ total,
187
+ page,
188
+ pageSize,
189
+ totalPages: Math.ceil(total / pageSize),
190
+ },
191
+ };
192
+ }
193
+ ```
194
+
195
+ ### Cursor Pagination
196
+
197
+ ```typescript
198
+ async function findWithCursor(cursor?: string, take = 10) {
199
+ const items = await prisma.item.findMany({
200
+ take: take + 1,
201
+ ...(cursor && {
202
+ skip: 1,
203
+ cursor: { id: cursor },
204
+ }),
205
+ where: { deletedAt: null },
206
+ orderBy: { createdAt: 'desc' },
207
+ });
208
+
209
+ const hasMore = items.length > take;
210
+ const results = hasMore ? items.slice(0, -1) : items;
211
+ const nextCursor = hasMore ? results[results.length - 1].id : null;
212
+
213
+ return {
214
+ items: results,
215
+ nextCursor,
216
+ hasMore,
217
+ };
218
+ }
219
+ ```
220
+
221
+ ### Soft Delete
222
+
223
+ ```typescript
224
+ // Soft delete
225
+ await prisma.item.update({
226
+ where: { id: itemId },
227
+ data: { deletedAt: new Date() },
228
+ });
229
+
230
+ // Restore
231
+ await prisma.item.update({
232
+ where: { id: itemId },
233
+ data: { deletedAt: null },
234
+ });
235
+
236
+ // Middleware for automatic filtering
237
+ prisma.$use(async (params, next) => {
238
+ if (params.model === 'Item') {
239
+ if (params.action === 'findUnique' || params.action === 'findMany') {
240
+ params.args.where = {
241
+ ...params.args.where,
242
+ deletedAt: null,
243
+ };
244
+ }
245
+ }
246
+ return next(params);
247
+ });
248
+ ```
249
+
250
+ ### Transactions
251
+
252
+ ```typescript
253
+ // Sequential transaction
254
+ const [item, user] = await prisma.$transaction([
255
+ prisma.item.create({
256
+ data: { title: 'New', price: 100, authorId: userId },
257
+ }),
258
+ prisma.user.update({
259
+ where: { id: userId },
260
+ data: { itemsCount: { increment: 1 } },
261
+ }),
262
+ ]);
263
+
264
+ // Interactive transaction
265
+ const result = await prisma.$transaction(async (tx) => {
266
+ const user = await tx.user.findUnique({
267
+ where: { id: userId },
268
+ });
269
+
270
+ if (!user || user.itemsCount >= 100) {
271
+ throw new Error('Item limit reached');
272
+ }
273
+
274
+ const item = await tx.item.create({
275
+ data: { title, price, authorId: userId },
276
+ });
277
+
278
+ await tx.user.update({
279
+ where: { id: userId },
280
+ data: { itemsCount: { increment: 1 } },
281
+ });
282
+
283
+ return item;
284
+ });
285
+ ```
286
+
287
+ ---
288
+
289
+ ## Service Pattern
290
+
291
+ ```typescript
292
+ import { prisma } from './client';
293
+ import type { Prisma } from '@prisma/client';
294
+
295
+ export class ItemService {
296
+ async findById(id: string) {
297
+ return prisma.item.findUnique({
298
+ where: { id, deletedAt: null },
299
+ include: { author: true },
300
+ });
301
+ }
302
+
303
+ async findByAuthor(authorId: string) {
304
+ return prisma.item.findMany({
305
+ where: { authorId, deletedAt: null },
306
+ orderBy: { createdAt: 'desc' },
307
+ });
308
+ }
309
+
310
+ async create(data: Prisma.ItemCreateInput) {
311
+ return prisma.item.create({ data });
312
+ }
313
+
314
+ async update(id: string, data: Prisma.ItemUpdateInput) {
315
+ return prisma.item.update({
316
+ where: { id },
317
+ data,
318
+ });
319
+ }
320
+
321
+ async softDelete(id: string) {
322
+ return prisma.item.update({
323
+ where: { id },
324
+ data: { deletedAt: new Date() },
325
+ });
326
+ }
327
+ }
328
+ ```
329
+
330
+ ---
331
+
332
+ ## Migrations
333
+
334
+ ### Commands
335
+
336
+ ```bash
337
+ # Create migration
338
+ pnpm prisma migrate dev --name add_items_table
339
+
340
+ # Apply migrations in production
341
+ pnpm prisma migrate deploy
342
+
343
+ # Reset database (dev only)
344
+ pnpm prisma migrate reset
345
+
346
+ # Generate client after schema changes
347
+ pnpm prisma generate
348
+
349
+ # Open Prisma Studio
350
+ pnpm prisma studio
351
+ ```
352
+
353
+ ### Seeding
354
+
355
+ ```typescript
356
+ // prisma/seed.ts
357
+ import { prisma } from '../src/lib/prisma';
358
+
359
+ async function main() {
360
+ // Create users
361
+ const user = await prisma.user.upsert({
362
+ where: { email: 'admin@example.com' },
363
+ update: {},
364
+ create: {
365
+ email: 'admin@example.com',
366
+ name: 'Admin',
367
+ password: 'hashed_password',
368
+ role: 'ADMIN',
369
+ },
370
+ });
371
+
372
+ // Create items
373
+ await prisma.item.createMany({
374
+ data: [
375
+ { title: 'Item 1', price: 100, authorId: user.id },
376
+ { title: 'Item 2', price: 200, authorId: user.id },
377
+ ],
378
+ });
379
+
380
+ console.log('Seed completed');
381
+ }
382
+
383
+ main()
384
+ .catch(console.error)
385
+ .finally(() => prisma.$disconnect());
386
+ ```
387
+
388
+ ---
389
+
390
+ ## Client Setup
391
+
392
+ ```typescript
393
+ // lib/prisma.ts
394
+ import { PrismaClient } from '@prisma/client';
395
+
396
+ const globalForPrisma = globalThis as unknown as {
397
+ prisma: PrismaClient | undefined;
398
+ };
399
+
400
+ export const prisma =
401
+ globalForPrisma.prisma ??
402
+ new PrismaClient({
403
+ log: process.env.NODE_ENV === 'development'
404
+ ? ['query', 'error', 'warn']
405
+ : ['error'],
406
+ });
407
+
408
+ if (process.env.NODE_ENV !== 'production') {
409
+ globalForPrisma.prisma = prisma;
410
+ }
411
+ ```
412
+
413
+ ---
414
+
415
+ ## Testing
416
+
417
+ ```typescript
418
+ import { describe, it, expect, beforeEach, afterAll } from 'vitest';
419
+ import { PrismaClient } from '@prisma/client';
420
+ import { ItemService } from '../services/item.service';
421
+
422
+ const prisma = new PrismaClient({
423
+ datasourceUrl: process.env.TEST_DATABASE_URL,
424
+ });
425
+
426
+ describe('ItemService', () => {
427
+ const service = new ItemService();
428
+
429
+ beforeEach(async () => {
430
+ await prisma.item.deleteMany();
431
+ await prisma.user.deleteMany();
432
+ });
433
+
434
+ afterAll(async () => {
435
+ await prisma.$disconnect();
436
+ });
437
+
438
+ describe('create', () => {
439
+ it('should create item', async () => {
440
+ const user = await prisma.user.create({
441
+ data: {
442
+ email: 'test@example.com',
443
+ name: 'Test',
444
+ password: 'hash',
445
+ },
446
+ });
447
+
448
+ const item = await service.create({
449
+ title: 'Test Item',
450
+ price: 100,
451
+ author: { connect: { id: user.id } },
452
+ });
453
+
454
+ expect(item.id).toBeDefined();
455
+ expect(item.title).toBe('Test Item');
456
+ });
457
+ });
458
+
459
+ describe('findById', () => {
460
+ it('should return null for non-existent', async () => {
461
+ const item = await service.findById('non-existent-id');
462
+ expect(item).toBeNull();
463
+ });
464
+ });
465
+ });
466
+ ```
467
+
468
+ ---
469
+
470
+ ## Best Practices
471
+
472
+ ### Good
473
+
474
+ - Use `@@map` for custom table names
475
+ - Use `@@index` for frequently queried fields
476
+ - Use `select` over `include` when you don't need all fields
477
+ - Use transactions for multi-step operations
478
+ - Use soft deletes for recoverability
479
+ - Review generated migrations before applying
480
+
481
+ ### Bad
482
+
483
+ - No indexes (poor query performance)
484
+ - Include everything (fetches unnecessary data)
485
+ - Ignoring migrations (production deployment issues)
486
+ - Duplicate types (let Prisma generate types)
487
+ - No soft deletes (data loss risk)