@qazuor/claude-code-config 0.1.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 (171) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1248 -0
  3. package/dist/bin.cjs +11886 -0
  4. package/dist/bin.cjs.map +1 -0
  5. package/dist/bin.d.cts +1 -0
  6. package/dist/bin.d.ts +1 -0
  7. package/dist/bin.js +11869 -0
  8. package/dist/bin.js.map +1 -0
  9. package/dist/index.cjs +3887 -0
  10. package/dist/index.cjs.map +1 -0
  11. package/dist/index.d.cts +1325 -0
  12. package/dist/index.d.ts +1325 -0
  13. package/dist/index.js +3835 -0
  14. package/dist/index.js.map +1 -0
  15. package/package.json +86 -0
  16. package/templates/.log/notifications.log +1775 -0
  17. package/templates/agents/README.md +164 -0
  18. package/templates/agents/_registry.json +443 -0
  19. package/templates/agents/design/content-writer.md +353 -0
  20. package/templates/agents/design/ux-ui-designer.md +382 -0
  21. package/templates/agents/engineering/astro-engineer.md +293 -0
  22. package/templates/agents/engineering/db-drizzle-engineer.md +360 -0
  23. package/templates/agents/engineering/express-engineer.md +316 -0
  24. package/templates/agents/engineering/fastify-engineer.md +399 -0
  25. package/templates/agents/engineering/hono-engineer.md +263 -0
  26. package/templates/agents/engineering/mongoose-engineer.md +473 -0
  27. package/templates/agents/engineering/nestjs-engineer.md +429 -0
  28. package/templates/agents/engineering/nextjs-engineer.md +451 -0
  29. package/templates/agents/engineering/node-typescript-engineer.md +347 -0
  30. package/templates/agents/engineering/prisma-engineer.md +432 -0
  31. package/templates/agents/engineering/react-senior-dev.md +394 -0
  32. package/templates/agents/engineering/tanstack-start-engineer.md +447 -0
  33. package/templates/agents/engineering/tech-lead.md +269 -0
  34. package/templates/agents/product/product-functional.md +329 -0
  35. package/templates/agents/product/product-technical.md +578 -0
  36. package/templates/agents/quality/debugger.md +514 -0
  37. package/templates/agents/quality/qa-engineer.md +390 -0
  38. package/templates/agents/specialized/enrichment-agent.md +277 -0
  39. package/templates/agents/specialized/i18n-specialist.md +322 -0
  40. package/templates/agents/specialized/seo-ai-specialist.md +387 -0
  41. package/templates/agents/specialized/tech-writer.md +300 -0
  42. package/templates/code-style/.editorconfig +27 -0
  43. package/templates/code-style/.prettierignore +25 -0
  44. package/templates/code-style/.prettierrc +12 -0
  45. package/templates/code-style/biome.json +78 -0
  46. package/templates/code-style/commitlint.config.js +44 -0
  47. package/templates/commands/README.md +175 -0
  48. package/templates/commands/_registry.json +420 -0
  49. package/templates/commands/add-new-entity.md +211 -0
  50. package/templates/commands/audit/accessibility-audit.md +360 -0
  51. package/templates/commands/audit/performance-audit.md +290 -0
  52. package/templates/commands/audit/security-audit.md +231 -0
  53. package/templates/commands/code-check.md +127 -0
  54. package/templates/commands/five-why.md +225 -0
  55. package/templates/commands/formatting/format-markdown.md +197 -0
  56. package/templates/commands/git/commit.md +247 -0
  57. package/templates/commands/meta/create-agent.md +257 -0
  58. package/templates/commands/meta/create-command.md +312 -0
  59. package/templates/commands/meta/create-skill.md +321 -0
  60. package/templates/commands/meta/help.md +318 -0
  61. package/templates/commands/planning/check-completed-tasks.md +224 -0
  62. package/templates/commands/planning/cleanup-issues.md +248 -0
  63. package/templates/commands/planning/planning-cleanup.md +251 -0
  64. package/templates/commands/planning/sync-planning-github.md +133 -0
  65. package/templates/commands/planning/sync-todos-github.md +203 -0
  66. package/templates/commands/quality-check.md +211 -0
  67. package/templates/commands/run-tests.md +159 -0
  68. package/templates/commands/start-feature-plan.md +232 -0
  69. package/templates/commands/start-refactor-plan.md +244 -0
  70. package/templates/commands/sync-planning.md +176 -0
  71. package/templates/commands/update-docs.md +242 -0
  72. package/templates/docs/CHECKPOINT-SYSTEM.md +504 -0
  73. package/templates/docs/INDEX.md +677 -0
  74. package/templates/docs/RECOMMENDED-HOOKS.md +415 -0
  75. package/templates/docs/_registry.json +329 -0
  76. package/templates/docs/diagrams/README.md +220 -0
  77. package/templates/docs/diagrams/agent-hierarchy.mmd +55 -0
  78. package/templates/docs/diagrams/documentation-map.mmd +61 -0
  79. package/templates/docs/diagrams/tools-relationship.mmd +55 -0
  80. package/templates/docs/diagrams/workflow-decision-tree.mmd +38 -0
  81. package/templates/docs/doc-sync.md +533 -0
  82. package/templates/docs/examples/end-to-end-workflow.md +1505 -0
  83. package/templates/docs/glossary.md +495 -0
  84. package/templates/docs/guides/mockup-prompt-engineering.md +644 -0
  85. package/templates/docs/guides/mockup-setup.md +737 -0
  86. package/templates/docs/learnings/README.md +250 -0
  87. package/templates/docs/learnings/common-architectural-patterns.md +123 -0
  88. package/templates/docs/learnings/common-mistakes-to-avoid.md +149 -0
  89. package/templates/docs/learnings/markdown-formatting-standards.md +104 -0
  90. package/templates/docs/learnings/monorepo-command-execution.md +64 -0
  91. package/templates/docs/learnings/optimization-tips.md +146 -0
  92. package/templates/docs/learnings/planning-linear-sync-workflow.md +70 -0
  93. package/templates/docs/learnings/shell-compatibility-fish.md +46 -0
  94. package/templates/docs/learnings/test-organization-structure.md +68 -0
  95. package/templates/docs/mcp-installation.md +613 -0
  96. package/templates/docs/mcp-servers.md +989 -0
  97. package/templates/docs/notification-installation.md +570 -0
  98. package/templates/docs/quick-start.md +354 -0
  99. package/templates/docs/standards/architecture-patterns.md +1064 -0
  100. package/templates/docs/standards/atomic-commits.md +513 -0
  101. package/templates/docs/standards/code-standards.md +993 -0
  102. package/templates/docs/standards/design-standards.md +656 -0
  103. package/templates/docs/standards/documentation-standards.md +1160 -0
  104. package/templates/docs/standards/testing-standards.md +969 -0
  105. package/templates/docs/system-maintenance.md +604 -0
  106. package/templates/docs/templates/PDR-template.md +561 -0
  107. package/templates/docs/templates/TODOs-template.md +534 -0
  108. package/templates/docs/templates/tech-analysis-template.md +800 -0
  109. package/templates/docs/workflows/README.md +519 -0
  110. package/templates/docs/workflows/atomic-task-protocol.md +955 -0
  111. package/templates/docs/workflows/decision-tree.md +482 -0
  112. package/templates/docs/workflows/edge-cases.md +856 -0
  113. package/templates/docs/workflows/phase-1-planning.md +957 -0
  114. package/templates/docs/workflows/phase-2-implementation.md +896 -0
  115. package/templates/docs/workflows/phase-3-validation.md +792 -0
  116. package/templates/docs/workflows/phase-4-finalization.md +927 -0
  117. package/templates/docs/workflows/quick-fix-protocol.md +505 -0
  118. package/templates/docs/workflows/task-atomization.md +537 -0
  119. package/templates/docs/workflows/task-completion-protocol.md +448 -0
  120. package/templates/hooks/on-notification.sh +28 -0
  121. package/templates/schemas/checkpoint.schema.json +97 -0
  122. package/templates/schemas/code-registry.schema.json +84 -0
  123. package/templates/schemas/pdr.schema.json +314 -0
  124. package/templates/schemas/problems.schema.json +55 -0
  125. package/templates/schemas/tech-analysis.schema.json +404 -0
  126. package/templates/schemas/telemetry.schema.json +298 -0
  127. package/templates/schemas/todos.schema.json +234 -0
  128. package/templates/schemas/workflows.schema.json +69 -0
  129. package/templates/scripts/add-changelogs.sh +105 -0
  130. package/templates/scripts/generate-code-registry.ts +270 -0
  131. package/templates/scripts/health-check.sh +343 -0
  132. package/templates/scripts/sync-registry.sh +40 -0
  133. package/templates/scripts/telemetry-report.ts +36 -0
  134. package/templates/scripts/validate-docs.sh +224 -0
  135. package/templates/scripts/validate-registry.sh +225 -0
  136. package/templates/scripts/validate-schemas.ts +283 -0
  137. package/templates/scripts/validate-structure.sh +165 -0
  138. package/templates/scripts/worktree-cleanup.sh +81 -0
  139. package/templates/scripts/worktree-create.sh +63 -0
  140. package/templates/sessions/planning/.gitkeep +0 -0
  141. package/templates/sessions/planning/archived/.gitkeep +0 -0
  142. package/templates/settings.json +202 -0
  143. package/templates/settings.local.json +138 -0
  144. package/templates/skills/README.md +197 -0
  145. package/templates/skills/_registry.json +473 -0
  146. package/templates/skills/audit/accessibility-audit.md +309 -0
  147. package/templates/skills/audit/performance-audit.md +257 -0
  148. package/templates/skills/audit/security-audit.md +217 -0
  149. package/templates/skills/auth/nextauth-patterns.md +308 -0
  150. package/templates/skills/brand-guidelines.md +240 -0
  151. package/templates/skills/documentation/markdown-formatter.md +302 -0
  152. package/templates/skills/git/git-commit-helper.md +321 -0
  153. package/templates/skills/i18n/i18n-patterns.md +251 -0
  154. package/templates/skills/patterns/error-handling-patterns.md +242 -0
  155. package/templates/skills/patterns/tdd-methodology.md +342 -0
  156. package/templates/skills/qa/qa-criteria-validator.md +383 -0
  157. package/templates/skills/qa/web-app-testing.md +398 -0
  158. package/templates/skills/react/react-hook-form-patterns.md +359 -0
  159. package/templates/skills/state/redux-toolkit-patterns.md +272 -0
  160. package/templates/skills/state/tanstack-query-patterns.md +299 -0
  161. package/templates/skills/state/zustand-patterns.md +301 -0
  162. package/templates/skills/tech/mermaid-diagram-specialist.md +195 -0
  163. package/templates/skills/tech/shadcn-specialist.md +252 -0
  164. package/templates/skills/tech/vercel-specialist.md +297 -0
  165. package/templates/skills/testing/api-app-testing.md +254 -0
  166. package/templates/skills/testing/performance-testing.md +275 -0
  167. package/templates/skills/testing/security-testing.md +348 -0
  168. package/templates/skills/utils/add-memory.md +295 -0
  169. package/templates/skills/utils/json-data-auditor.md +283 -0
  170. package/templates/skills/utils/pdf-creator-editor.md +342 -0
  171. package/templates/tools/format-markdown.sh +185 -0
@@ -0,0 +1,1064 @@
1
+ # Architecture Patterns
2
+
3
+ This document defines the architectural patterns and design principles.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ <!-- markdownlint-disable MD051 -->
10
+
11
+ 1. [Layer Architecture](#layer-architecture)
12
+ 2. [Entity Creation Flow](#entity-creation-flow)
13
+ 3. [Base Classes & Patterns](#base-classes--patterns)
14
+ 4. [Database Patterns](#database-patterns)
15
+ 5. [Service Patterns](#service-patterns)
16
+ 6. [API Patterns](#api-patterns)
17
+ 7. [Frontend Patterns](#frontend-patterns)
18
+ 8. [Authentication & Authorization](#authentication--authorization)
19
+ 9. [Error Handling](#error-handling)
20
+ 10. [Validation Flow](#validation-flow)
21
+
22
+ <!-- markdownlint-enable MD051 -->
23
+
24
+ ---
25
+
26
+ ## Layer Architecture
27
+
28
+ ### Bottom-Up Layers
29
+
30
+ ```text
31
+ ┌─────────────────────────────────────────┐
32
+ │ Frontend Layer │
33
+ │ (Astro, React, TanStack) │
34
+ │ - UI Components │
35
+ │ - State Management │
36
+ │ - Forms & Validation │
37
+ └─────────────────┬───────────────────────┘
38
+ │ HTTP/REST
39
+ ┌─────────────────▼───────────────────────┐
40
+ │ API Layer │
41
+ │ (Hono Routes) │
42
+ │ - Request/Response Handling │
43
+ │ - Middleware (auth, validation) │
44
+ │ - Route Factories │
45
+ └─────────────────┬───────────────────────┘
46
+ │ Function Calls
47
+ ┌─────────────────▼───────────────────────┐
48
+ │ Service Layer │
49
+ │ (Business Logic) │
50
+ │ - Services extending BaseCrudService │
51
+ │ - Business Rules & Validation │
52
+ │ - Transactions │
53
+ └─────────────────┬───────────────────────┘
54
+ │ ORM Calls
55
+ ┌─────────────────▼───────────────────────┐
56
+ │ Database Layer │
57
+ │ (Drizzle ORM + PostgreSQL) │
58
+ │ - Models extending BaseModel │
59
+ │ - Database Schemas │
60
+ │ - Migrations │
61
+ └─────────────────────────────────────────┘
62
+ ```text
63
+
64
+ ### Layer Responsibilities
65
+
66
+ **Database Layer** (`@repo/db`)
67
+
68
+ - Define Drizzle schemas
69
+ - Implement models (extend `BaseModel`)
70
+ - Handle database queries
71
+ - Manage migrations
72
+
73
+ **Service Layer** (`@repo/service-core`)
74
+
75
+ - Implement business logic
76
+ - Enforce business rules
77
+ - Handle transactions
78
+ - Coordinate between models
79
+
80
+ **API Layer** (`apps/api`)
81
+
82
+ - Handle HTTP requests/responses
83
+ - Validate input (Zod)
84
+ - Authenticate/authorize requests
85
+ - Call service methods
86
+
87
+ **Frontend Layer** (`apps/web`, `apps/admin`)
88
+
89
+ - Render UI
90
+ - Handle user interactions
91
+ - Manage client state
92
+ - Call API endpoints
93
+
94
+ ---
95
+
96
+ ## Entity Creation Flow
97
+
98
+ ### Complete Order (Never Skip Steps)
99
+
100
+ When creating a new entity, follow this exact order:
101
+
102
+ ```text
103
+
104
+ 1. Zod Schemas (@repo/schemas)
105
+
106
+
107
+
108
+ 2. Types via z.infer<typeof schema>
109
+
110
+
111
+
112
+ 3. Drizzle Schema (@repo/db/schemas)
113
+
114
+
115
+
116
+ 4. Model extending BaseModel (@repo/db/models)
117
+
118
+
119
+
120
+ 5. Service extending BaseCrudService (@repo/service-core)
121
+
122
+
123
+
124
+ 6. API Routes using factory pattern (apps/api/routes)
125
+
126
+
127
+
128
+ 7. Frontend Components (apps/web or apps/admin)
129
+
130
+ ```text
131
+
132
+ ### Step-by-Step Example: Entity Entity
133
+
134
+ #### Step 1: Zod Schemas
135
+
136
+ ```typescript
137
+ // packages/schemas/src/entity/entity.schema.ts
138
+
139
+ import { z } from 'zod';
140
+
141
+ export const entitySchema = z.object({
142
+ id: z.string().uuid(),
143
+ name: z.string().min(1).max(200),
144
+ type: z.enum(['house', 'apartment', 'room']),
145
+ capacity: z.number().int().positive().max(50),
146
+ pricePerNight: z.number().positive(),
147
+ hostId: z.string().uuid(),
148
+ createdAt: z.date(),
149
+ updatedAt: z.date(),
150
+ deletedAt: z.date().nullable(),
151
+ });
152
+
153
+ export const createEntitySchema = entitySchema.omit({
154
+ id: true,
155
+ createdAt: true,
156
+ updatedAt: true,
157
+ deletedAt: true,
158
+ });
159
+
160
+ export const updateEntitySchema = createEntitySchema.partial();
161
+
162
+ export const searchEntitySchema = z.object({
163
+ q: z.string().optional(),
164
+ type: z.enum(['house', 'apartment', 'room']).optional(),
165
+ minCapacity: z.number().optional(),
166
+ maxPrice: z.number().optional(),
167
+ page: z.number().default(1),
168
+ pageSize: z.number().default(20),
169
+ });
170
+ ```text
171
+
172
+ #### Step 2: Infer Types
173
+
174
+ ```typescript
175
+ // In the same file or separate types file
176
+ export type Entity = z.infer<typeof entitySchema>;
177
+ export type CreateEntityInput = z.infer<typeof createEntitySchema>;
178
+ export type UpdateEntityInput = z.infer<typeof updateEntitySchema>;
179
+ export type SearchEntityInput = z.infer<typeof searchEntitySchema>;
180
+ ```text
181
+
182
+ #### Step 3: Drizzle Schema
183
+
184
+ ```typescript
185
+ // packages/db/src/schemas/entity/entity.schema.ts
186
+
187
+ import { pgTable, uuid, varchar, integer, numeric, timestamp } from 'drizzle-orm/pg-core';
188
+ import { users } from '../user/user.schema';
189
+
190
+ export const entitys = pgTable('entitys', {
191
+ id: uuid('id').primaryKey().defaultRandom(),
192
+ name: varchar('name', { length: 200 }).notNull(),
193
+ type: varchar('type', { length: 50 }).notNull(),
194
+ capacity: integer('capacity').notNull(),
195
+ pricePerNight: numeric('price_per_night', { precision: 10, scale: 2 }).notNull(),
196
+ hostId: uuid('host_id').references(() => users.id).notNull(),
197
+ createdAt: timestamp('created_at').defaultNow().notNull(),
198
+ updatedAt: timestamp('updated_at').defaultNow().notNull(),
199
+ deletedAt: timestamp('deleted_at'),
200
+ });
201
+ ```text
202
+
203
+ #### Step 4: Model
204
+
205
+ ```typescript
206
+ // packages/db/src/models/entity.model.ts
207
+
208
+ import { BaseModel } from './base.model';
209
+ import { entitys } from '../schemas/entity/entity.schema';
210
+ import type { Entity } from '@repo/schemas';
211
+ import { eq, and, isNull, ilike, sql } from 'drizzle-orm';
212
+
213
+ export class EntityModel extends BaseModel<Entity> {
214
+ protected table = entitys;
215
+ protected entityName = 'Entity';
216
+
217
+ /**
218
+
219
+ * Find entitys with text search
220
+
221
+ *
222
+
223
+ * @param options - Search options
224
+ * @returns List of entitys matching search
225
+
226
+ */
227
+ async findAll(options?: {
228
+ search?: { q?: string };
229
+ page?: number;
230
+ pageSize?: number;
231
+ }) {
232
+ const { search, page = 1, pageSize = 20 } = options ?? {};
233
+
234
+ const conditions = [isNull(this.table.deletedAt)];
235
+
236
+ if (search?.q) {
237
+ conditions.push(
238
+ ilike(this.table.name, `%${search.q}%`)
239
+ );
240
+ }
241
+
242
+ const offset = (page - 1) * pageSize;
243
+
244
+ const items = await this.db
245
+ .select()
246
+ .from(this.table)
247
+ .where(and(...conditions))
248
+ .limit(pageSize)
249
+ .offset(offset);
250
+
251
+ const [{ count }] = await this.db
252
+ .select({ count: sql<number>`count(*)` })
253
+ .from(this.table)
254
+ .where(and(...conditions));
255
+
256
+ return {
257
+ items,
258
+ pagination: {
259
+ page,
260
+ pageSize,
261
+ total: Number(count),
262
+ totalPages: Math.ceil(Number(count) / pageSize),
263
+ },
264
+ };
265
+ }
266
+ }
267
+ ```text
268
+
269
+ #### Step 5: Service
270
+
271
+ ```typescript
272
+ // packages/service-core/src/services/entity/entity.service.ts
273
+
274
+ import { BaseCrudService } from '../base-crud.service';
275
+ import { EntityModel } from '@repo/db';
276
+ import type { ServiceContext } from '../../types';
277
+ import type {
278
+ Entity,
279
+ CreateEntityInput,
280
+ UpdateEntityInput,
281
+ SearchEntityInput,
282
+ } from '@repo/schemas';
283
+
284
+ export class EntityService extends BaseCrudService<
285
+ Entity,
286
+ EntityModel,
287
+ CreateEntityInput,
288
+ UpdateEntityInput,
289
+ SearchEntityInput
290
+ > {
291
+ constructor(ctx: ServiceContext, model?: EntityModel) {
292
+ super(ctx, model ?? new EntityModel(ctx.db));
293
+ }
294
+
295
+ /**
296
+
297
+ * Create entity with additional business logic
298
+
299
+ */
300
+ async create({ input, user }: { input: CreateEntityInput; user: User }) {
301
+ return this.runWithLoggingAndValidation(
302
+ 'create',
303
+ { input, user },
304
+ async () => {
305
+ // Business rule: Only hosts can create entitys
306
+ if (user.role !== 'host') {
307
+ throw new ServiceError(
308
+ 'Only hosts can create entitys',
309
+ ServiceErrorCode.FORBIDDEN
310
+ );
311
+ }
312
+
313
+ // Business rule: Set hostId to current user
314
+ const entityData = {
315
+ ...input,
316
+ hostId: user.id,
317
+ };
318
+
319
+ return super.create({ input: entityData, user });
320
+ }
321
+ );
322
+ }
323
+ }
324
+ ```text
325
+
326
+ #### Step 6: API Routes
327
+
328
+ ```typescript
329
+ // apps/api/src/routes/entity/index.ts
330
+
331
+ import { Hono } from 'hono';
332
+ import { createCRUDRoute, createListRoute } from '../../factories/route-factory';
333
+ import { EntityService } from '@repo/service-core';
334
+ import {
335
+ createEntitySchema,
336
+ updateEntitySchema,
337
+ searchEntitySchema,
338
+ } from '@repo/schemas';
339
+
340
+ const app = new Hono();
341
+
342
+ // Public list route (no auth required)
343
+ const listRoute = createListRoute({
344
+ service: EntityService,
345
+ schema: searchEntitySchema,
346
+ options: {
347
+ skipAuth: true,
348
+ },
349
+ });
350
+
351
+ // Protected CRUD routes
352
+ const crudRoute = createCRUDRoute({
353
+ service: EntityService,
354
+ schemas: {
355
+ create: createEntitySchema,
356
+ update: updateEntitySchema,
357
+ search: searchEntitySchema,
358
+ },
359
+ options: {
360
+ skipAuth: false,
361
+ permissions: ['entity:write'],
362
+ },
363
+ });
364
+
365
+ app.route('/', listRoute); // GET /entitys (public)
366
+ app.route('/', crudRoute); // POST, PUT, DELETE (protected)
367
+
368
+ export default app;
369
+ ```text
370
+
371
+ #### Step 7: Frontend Components
372
+
373
+ ```typescript
374
+ // apps/web/src/components/entity/EntityList.tsx
375
+
376
+ import { useQuery } from '@tanstack/react-query';
377
+ import { EntityCard } from './EntityCard';
378
+ import type { SearchEntityInput } from '@repo/schemas';
379
+
380
+ const fetchEntitys = async (params: SearchEntityInput) => {
381
+ const res = await fetch(`/api/entitys?${new URLSearchParams(params)}`);
382
+ return res.json();
383
+ };
384
+
385
+ export const EntityList = () => {
386
+ const { data, isLoading } = useQuery({
387
+ queryKey: ['entitys'],
388
+ queryFn: () => fetchEntitys({ page: 1, pageSize: 20 }),
389
+ });
390
+
391
+ if (isLoading) return <div>Loading...</div>;
392
+
393
+ return (
394
+ <div className="grid grid-cols-3 gap-4">
395
+ {data.items.map((entity) => (
396
+ <EntityCard key={entity.id} entity={entity} />
397
+ ))}
398
+ </div>
399
+ );
400
+ };
401
+ ```text
402
+
403
+ ---
404
+
405
+ ## Base Classes & Patterns
406
+
407
+ ### BaseModel Pattern
408
+
409
+ **All models MUST extend BaseModel:**
410
+
411
+ ```typescript
412
+ import { BaseModel } from './base.model';
413
+ import type { YourEntity } from '@repo/schemas';
414
+
415
+ export class YourEntityModel extends BaseModel<YourEntity> {
416
+ protected table = yourEntitiesTable;
417
+ protected entityName = 'YourEntity';
418
+
419
+ // Override methods as needed
420
+ async findAll(options?: SearchOptions) {
421
+ // Custom implementation
422
+ }
423
+ }
424
+ ```text
425
+
426
+ **BaseModel provides:**
427
+
428
+ - `findById(id)` - Find by primary key
429
+ - `findAll(options)` - List with pagination
430
+ - `create(data)` - Insert record
431
+ - `update(id, data)` - Update record
432
+ - `softDelete(id)` - Soft delete (set deletedAt)
433
+ - `restore(id)` - Restore soft deleted
434
+ - `hardDelete(id)` - Permanent delete
435
+
436
+ ### BaseCrudService Pattern
437
+
438
+ **All services MUST extend BaseCrudService:**
439
+
440
+ ```typescript
441
+ import { BaseCrudService } from '../base-crud.service';
442
+
443
+ export class YourService extends BaseCrudService<
444
+ Entity,
445
+ EntityModel,
446
+ CreateSchema,
447
+ UpdateSchema,
448
+ SearchSchema
449
+ > {
450
+ constructor(ctx: ServiceContext, model?: EntityModel) {
451
+ super(ctx, model ?? new EntityModel(ctx.db));
452
+ }
453
+
454
+ // Override or add methods
455
+ async customMethod({ input }: { input: CustomInput }) {
456
+ return this.runWithLoggingAndValidation(
457
+ 'customMethod',
458
+ { input },
459
+ async () => {
460
+ // Implementation
461
+ }
462
+ );
463
+ }
464
+ }
465
+ ```text
466
+
467
+ **BaseCrudService provides:**
468
+
469
+ - `findById({ id })` - Get single record
470
+ - `findAll({ search, page, pageSize })` - List with pagination
471
+ - `create({ input, user })` - Create record
472
+ - `update({ id, input, user })` - Update record
473
+ - `delete({ id, user })` - Soft delete record
474
+ - `runWithLoggingAndValidation()` - Wrapper for logging/validation
475
+
476
+ ---
477
+
478
+ ## Database Patterns
479
+
480
+ ### Soft Delete Pattern
481
+
482
+ **Default behavior: Soft delete**
483
+
484
+ ```typescript
485
+ // Soft delete (sets deletedAt)
486
+ await model.softDelete(id);
487
+
488
+ // Restore
489
+ await model.restore(id);
490
+
491
+ // Hard delete (permanent)
492
+ await model.hardDelete(id);
493
+ ```text
494
+
495
+ ### Pagination Pattern
496
+
497
+ ```typescript
498
+ // Request pagination
499
+ const result = await model.findAll({
500
+ page: 1,
501
+ pageSize: 20,
502
+ orderBy: { field: 'createdAt', direction: 'desc' },
503
+ });
504
+
505
+ // Response format
506
+ type PaginatedResult<T> = {
507
+ items: T[];
508
+ pagination: {
509
+ page: number;
510
+ pageSize: number;
511
+ total: number;
512
+ totalPages: number;
513
+ };
514
+ };
515
+ ```text
516
+
517
+ ### Transaction Pattern
518
+
519
+ ```typescript
520
+ // Use transactions for multi-step operations
521
+ await db.transaction(async (trx) => {
522
+ const entity = await trx
523
+ .insert(entitys)
524
+ .values(data)
525
+ .returning();
526
+
527
+ await trx
528
+ .insert(entityImages)
529
+ .values(images.map(img => ({ ...img, entityId: entity.id })));
530
+
531
+ return entity;
532
+ });
533
+ ```text
534
+
535
+ ### Query Optimization
536
+
537
+ ```typescript
538
+ // Use indexes for frequent queries
539
+ CREATE INDEX idx_entitys_host_id ON entitys(host_id);
540
+ CREATE INDEX idx_entitys_type ON entitys(type);
541
+ CREATE INDEX idx_entitys_created_at ON entitys(created_at DESC);
542
+
543
+ // Composite index for common filter combinations
544
+ CREATE INDEX idx_entitys_type_capacity ON entitys(type, capacity);
545
+ ```text
546
+
547
+ ---
548
+
549
+ ## Service Patterns
550
+
551
+ ### Business Logic Encapsulation
552
+
553
+ ```typescript
554
+ export class BookingService extends BaseCrudService<...> {
555
+ /**
556
+
557
+ * Create booking with business rules
558
+
559
+ */
560
+ async create({ input, user }: CreateParams) {
561
+ return this.runWithLoggingAndValidation(
562
+ 'create',
563
+ { input, user },
564
+ async () => {
565
+ // Business rule 1: Check availability
566
+ const isAvailable = await this.checkAvailability(
567
+ input.entityId,
568
+ input.checkIn,
569
+ input.checkOut
570
+ );
571
+
572
+ if (!isAvailable) {
573
+ throw new ServiceError(
574
+ 'Entity not available for selected dates',
575
+ ServiceErrorCode.CONFLICT
576
+ );
577
+ }
578
+
579
+ // Business rule 2: Calculate total price
580
+ const entity = await this.entityModel.findById(
581
+ input.entityId
582
+ );
583
+ const nights = this.calculateNights(input.checkIn, input.checkOut);
584
+ const totalPrice = entity.pricePerNight * nights;
585
+
586
+ // Create booking
587
+ const booking = await this.model.create({
588
+ ...input,
589
+ totalPrice,
590
+ status: 'pending',
591
+ userId: user.id,
592
+ });
593
+
594
+ // Business rule 3: Send confirmation email
595
+ await this.emailService.sendBookingConfirmation(booking);
596
+
597
+ return { booking };
598
+ }
599
+ );
600
+ }
601
+ }
602
+ ```text
603
+
604
+ ### Service Composition
605
+
606
+ ```typescript
607
+ export class EntityService extends BaseCrudService<...> {
608
+ private imageService: ImageService;
609
+ private amenityService: AmenityService;
610
+
611
+ constructor(
612
+ ctx: ServiceContext,
613
+ model?: EntityModel,
614
+ imageService?: ImageService,
615
+ amenityService?: AmenityService
616
+ ) {
617
+ super(ctx, model ?? new EntityModel(ctx.db));
618
+ this.imageService = imageService ?? new ImageService(ctx);
619
+ this.amenityService = amenityService ?? new AmenityService(ctx);
620
+ }
621
+
622
+ async create({ input, user }: CreateParams) {
623
+ return this.db.transaction(async (trx) => {
624
+ // Create entity
625
+ const entity = await this.model.create(input);
626
+
627
+ // Add images
628
+ if (input.images) {
629
+ await this.imageService.createMultiple({
630
+ entityId: entity.id,
631
+ images: input.images,
632
+ });
633
+ }
634
+
635
+ // Add amenities
636
+ if (input.amenityIds) {
637
+ await this.amenityService.linkToEntity({
638
+ entityId: entity.id,
639
+ amenityIds: input.amenityIds,
640
+ });
641
+ }
642
+
643
+ return { entity };
644
+ });
645
+ }
646
+ }
647
+ ```text
648
+
649
+ ---
650
+
651
+ ## API Patterns
652
+
653
+ ### Route Factory Pattern
654
+
655
+ **Always use factory functions:**
656
+
657
+ ```typescript
658
+ // Simple list route (GET only)
659
+ const listRoute = createListRoute({
660
+ service: YourService,
661
+ schema: searchSchema,
662
+ options: {
663
+ skipAuth: true, // Public endpoint
664
+ },
665
+ });
666
+
667
+ // Full CRUD routes
668
+ const crudRoute = createCRUDRoute({
669
+ service: YourService,
670
+ schemas: {
671
+ create: createSchema,
672
+ update: updateSchema,
673
+ search: searchSchema,
674
+ },
675
+ options: {
676
+ skipAuth: false, // Protected endpoints
677
+ permissions: ['entity:write'],
678
+ },
679
+ });
680
+
681
+ // Custom route
682
+ const customRoute = createSimpleRoute({
683
+ method: 'post',
684
+ path: '/custom-action',
685
+ schema: customSchema,
686
+ handler: async (c) => {
687
+ const input = c.req.valid('json');
688
+ // Custom logic
689
+ return c.json({ success: true, data: result });
690
+ },
691
+ options: {
692
+ skipAuth: false,
693
+ permissions: ['custom:action'],
694
+ },
695
+ });
696
+ ```text
697
+
698
+ ### Middleware Chain
699
+
700
+ ```typescript
701
+ // Order matters
702
+ app.post(
703
+ '/entitys',
704
+ // 1. CORS (if needed)
705
+ cors(),
706
+ // 2. Authentication
707
+ authenticate(),
708
+ // 3. Authorization
709
+ requirePermissions(['entity:write']),
710
+ // 4. Validation
711
+ zValidator('json', createEntitySchema),
712
+ // 5. Rate limiting
713
+ rateLimit({ max: 10, window: '1m' }),
714
+ // 6. Handler
715
+ async (c) => {
716
+ const input = c.req.valid('json');
717
+ const user = c.get('user');
718
+ // ...
719
+ }
720
+ );
721
+ ```text
722
+
723
+ ### Error Response Format
724
+
725
+ ```typescript
726
+ // Success
727
+ type SuccessResponse<T> = {
728
+ success: true;
729
+ data: T;
730
+ };
731
+
732
+ // Error
733
+ type ErrorResponse = {
734
+ success: false;
735
+ error: {
736
+ code: string;
737
+ message: string;
738
+ details?: unknown;
739
+ };
740
+ };
741
+
742
+ // In handler
743
+ try {
744
+ const result = await service.method({ input });
745
+ return c.json({ success: true, data: result });
746
+ } catch (error) {
747
+ if (error instanceof ServiceError) {
748
+ return c.json(
749
+ {
750
+ success: false,
751
+ error: {
752
+ code: error.code,
753
+ message: error.message,
754
+ },
755
+ },
756
+ error.statusCode
757
+ );
758
+ }
759
+ throw error;
760
+ }
761
+ ```text
762
+
763
+ ---
764
+
765
+ ## Frontend Patterns
766
+
767
+ ### Query Key Factory
768
+
769
+ ```typescript
770
+ // Define query keys centrally
771
+ export const entityKeys = {
772
+ all: ['entitys'] as const,
773
+ lists: () => [...entityKeys.all, 'list'] as const,
774
+ list: (filters: Filters) => [...entityKeys.lists(), filters] as const,
775
+ details: () => [...entityKeys.all, 'detail'] as const,
776
+ detail: (id: string) => [...entityKeys.details(), id] as const,
777
+ };
778
+ ```text
779
+
780
+ ### Query Hooks
781
+
782
+ ```typescript
783
+ // Fetch single item
784
+ export const useEntity = (id: string) => {
785
+ return useQuery({
786
+ queryKey: entityKeys.detail(id),
787
+ queryFn: () => fetchEntity(id),
788
+ enabled: !!id,
789
+ });
790
+ };
791
+
792
+ // Fetch list
793
+ export const useEntitys = (filters: Filters) => {
794
+ return useQuery({
795
+ queryKey: entityKeys.list(filters),
796
+ queryFn: () => fetchEntitys(filters),
797
+ });
798
+ };
799
+ ```text
800
+
801
+ ### Mutation Hooks
802
+
803
+ ```typescript
804
+ export const useCreateEntity = () => {
805
+ const queryClient = useQueryClient();
806
+
807
+ return useMutation({
808
+ mutationFn: createEntity,
809
+ onSuccess: () => {
810
+ // Invalidate lists
811
+ queryClient.invalidateQueries({
812
+ queryKey: entityKeys.lists()
813
+ });
814
+ },
815
+ });
816
+ };
817
+ ```text
818
+
819
+ ### Component Patterns
820
+
821
+ ```typescript
822
+ // Container/Presenter pattern
823
+ export const EntityListContainer = () => {
824
+ const { data, isLoading, error } = useEntitys({ page: 1 });
825
+
826
+ if (isLoading) return <LoadingSpinner />;
827
+ if (error) return <ErrorMessage error={error} />;
828
+
829
+ return <EntityListPresenter entitys={data.items} />;
830
+ };
831
+
832
+ // Pure presenter component
833
+ type EntityListPresenterProps = {
834
+ entitys: Entity[];
835
+ };
836
+
837
+ export const EntityListPresenter = ({
838
+ entitys
839
+ }: EntityListPresenterProps) => {
840
+ return (
841
+ <div className="grid grid-cols-3 gap-4">
842
+ {entitys.map((entity) => (
843
+ <EntityCard key={entity.id} entity={entity} />
844
+ ))}
845
+ </div>
846
+ );
847
+ };
848
+ ```text
849
+
850
+ ---
851
+
852
+ ## Authentication & Authorization
853
+
854
+ ### Get Actor from Context
855
+
856
+ ```typescript
857
+ import { getActorFromContext } from '../utils/auth';
858
+
859
+ const handler = async (c: Context) => {
860
+ const actor = await getActorFromContext(c);
861
+
862
+ // Actor has: role, permissions, userId, etc.
863
+ console.log(actor.role); // 'admin' | 'host' | 'guest'
864
+ console.log(actor.permissions); // ['entity:write', ...]
865
+ };
866
+ ```text
867
+
868
+ ### Role-Based Access
869
+
870
+ ```typescript
871
+ // Check role
872
+ if (actor.role !== 'admin') {
873
+ return c.json(
874
+ { success: false, error: { code: 'FORBIDDEN', message: 'Admin only' } },
875
+ 403
876
+ );
877
+ }
878
+ ```text
879
+
880
+ ### Permission-Based Access
881
+
882
+ ```typescript
883
+ // Check permission
884
+ if (!actor.permissions.includes('entity:delete')) {
885
+ return c.json(
886
+ { success: false, error: { code: 'FORBIDDEN', message: 'Permission denied' } },
887
+ 403
888
+ );
889
+ }
890
+ ```text
891
+
892
+ ### Public Endpoints
893
+
894
+ ```typescript
895
+ // Use skipAuth option in route factory
896
+ const publicRoute = createListRoute({
897
+ service: EntityService,
898
+ schema: searchSchema,
899
+ options: {
900
+ skipAuth: true, // No authentication required
901
+ },
902
+ });
903
+ ```text
904
+
905
+ ---
906
+
907
+ ## Error Handling
908
+
909
+ ### ServiceError Usage
910
+
911
+ ```typescript
912
+ import { ServiceError, ServiceErrorCode } from '@repo/service-core';
913
+
914
+ // Not found
915
+ throw new ServiceError(
916
+ 'Entity not found',
917
+ ServiceErrorCode.NOT_FOUND,
918
+ { entityId: id }
919
+ );
920
+
921
+ // Validation error
922
+ throw new ServiceError(
923
+ 'Invalid input data',
924
+ ServiceErrorCode.VALIDATION_ERROR,
925
+ { errors: validationErrors }
926
+ );
927
+
928
+ // Forbidden
929
+ throw new ServiceError(
930
+ 'You do not have permission to perform this action',
931
+ ServiceErrorCode.FORBIDDEN
932
+ );
933
+
934
+ // Conflict
935
+ throw new ServiceError(
936
+ 'Email already in use',
937
+ ServiceErrorCode.CONFLICT,
938
+ { email }
939
+ );
940
+ ```text
941
+
942
+ ### Global Error Handler
943
+
944
+ ```typescript
945
+ // In app setup
946
+ app.onError((err, c) => {
947
+ if (err instanceof ServiceError) {
948
+ return c.json(
949
+ {
950
+ success: false,
951
+ error: {
952
+ code: err.code,
953
+ message: err.message,
954
+ },
955
+ },
956
+ err.statusCode
957
+ );
958
+ }
959
+
960
+ // Log unexpected errors
961
+ logger.error('Unexpected error', { error: err });
962
+
963
+ return c.json(
964
+ {
965
+ success: false,
966
+ error: {
967
+ code: 'INTERNAL_ERROR',
968
+ message: 'An unexpected error occurred',
969
+ },
970
+ },
971
+ 500
972
+ );
973
+ });
974
+ ```text
975
+
976
+ ---
977
+
978
+ ## Validation Flow
979
+
980
+ ### Client → Server Validation
981
+
982
+ ```text
983
+
984
+ 1. User Input
985
+
986
+
987
+
988
+ 2. Client-Side Validation (Zod schema)
989
+ - Immediate feedback
990
+ - User-friendly errors
991
+
992
+
993
+
994
+ 3. API Request
995
+
996
+
997
+
998
+ 4. Server-Side Validation (Zod middleware)
999
+ - zValidator('json', schema)
1000
+ - Security layer
1001
+
1002
+
1003
+
1004
+ 5. Business Logic Validation (Service)
1005
+ - Business rules
1006
+ - Database constraints
1007
+
1008
+
1009
+
1010
+ 6. Database Constraints
1011
+ - Final safety net
1012
+
1013
+ ```text
1014
+
1015
+ ### Example
1016
+
1017
+ ```typescript
1018
+ // 1. Client-side (React component)
1019
+ const { register, handleSubmit, formState: { errors } } = useForm({
1020
+ resolver: zodResolver(createEntitySchema),
1021
+ });
1022
+
1023
+ // 2. API route (Server-side)
1024
+ app.post(
1025
+ '/entitys',
1026
+ zValidator('json', createEntitySchema), // Validates again
1027
+ async (c) => {
1028
+ const input = c.req.valid('json'); // Validated and typed
1029
+ // ...
1030
+ }
1031
+ );
1032
+
1033
+ // 3. Service (Business logic)
1034
+ async create({ input, user }) {
1035
+ // Additional business validation
1036
+ if (input.capacity > 100) {
1037
+ throw new ServiceError('Capacity too high', ServiceErrorCode.VALIDATION_ERROR);
1038
+ }
1039
+ // ...
1040
+ }
1041
+ ```text
1042
+
1043
+ ---
1044
+
1045
+ ## Summary Checklist
1046
+
1047
+ When implementing a new feature, ensure:
1048
+
1049
+ - [ ] Follows layer architecture (Database → Service → API → Frontend)
1050
+ - [ ] Entity created in correct order (Zod → Types → Drizzle → Model → Service → API)
1051
+ - [ ] Models extend BaseModel
1052
+ - [ ] Services extend BaseCrudService
1053
+ - [ ] API routes use factory pattern
1054
+ - [ ] Proper authentication/authorization
1055
+ - [ ] Soft delete pattern used
1056
+ - [ ] Transactions for multi-step operations
1057
+ - [ ] Validation at all layers
1058
+ - [ ] Consistent error handling
1059
+ - [ ] TanStack Query for frontend state
1060
+
1061
+ ---
1062
+
1063
+ **These patterns are mandatory. Deviations must be discussed and approved.**
1064
+