create-tigra 1.1.0 → 2.0.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.
Files changed (243) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +80 -87
  3. package/bin/create-tigra.js +259 -308
  4. package/package.json +49 -41
  5. package/template/_claude/QUICK_REFERENCE.md +193 -0
  6. package/template/_claude/README.md +53 -0
  7. package/template/_claude/commands/create-client.md +881 -0
  8. package/template/_claude/commands/create-server.md +383 -0
  9. package/template/_claude/rules/client/01-project-structure.md +133 -0
  10. package/template/_claude/rules/client/02-components-and-types.md +146 -0
  11. package/template/_claude/rules/client/03-data-and-state.md +156 -0
  12. package/template/_claude/rules/client/04-design-system.md +185 -0
  13. package/template/_claude/rules/client/05-security.md +55 -0
  14. package/template/_claude/rules/client/06-ux-checklist.md +81 -0
  15. package/template/_claude/rules/client/core.md +42 -0
  16. package/template/_claude/rules/global/core.md +77 -0
  17. package/template/_claude/rules/server/core.md +50 -0
  18. package/template/_claude/rules/server/database.md +124 -0
  19. package/template/_claude/rules/server/project-conventions.md +150 -0
  20. package/template/_claude/rules/server/response-handling.md +144 -0
  21. package/template/client/.env.example +5 -0
  22. package/template/client/README.md +36 -0
  23. package/template/client/components.json +23 -0
  24. package/template/client/eslint.config.mjs +18 -0
  25. package/template/client/next.config.ts +34 -0
  26. package/template/client/package.json +44 -0
  27. package/template/client/postcss.config.mjs +7 -0
  28. package/template/client/src/app/(auth)/layout.tsx +18 -0
  29. package/template/client/src/app/(auth)/login/page.tsx +13 -0
  30. package/template/client/src/app/(auth)/register/page.tsx +13 -0
  31. package/template/client/src/app/(main)/dashboard/page.tsx +22 -0
  32. package/template/client/src/app/(main)/layout.tsx +11 -0
  33. package/template/client/src/app/error.tsx +27 -0
  34. package/template/client/src/app/favicon.ico +0 -0
  35. package/template/client/src/app/globals.css +145 -0
  36. package/template/client/src/app/layout.tsx +36 -0
  37. package/template/client/src/app/loading.tsx +11 -0
  38. package/template/client/src/app/not-found.tsx +23 -0
  39. package/template/client/src/app/page.tsx +45 -0
  40. package/template/client/src/app/providers.tsx +43 -0
  41. package/template/client/src/components/common/ConfirmDialog.tsx +56 -0
  42. package/template/client/src/components/common/EmptyState.tsx +31 -0
  43. package/template/client/src/components/common/LoadingSpinner.tsx +30 -0
  44. package/template/client/src/components/common/Pagination.tsx +55 -0
  45. package/template/client/src/components/layout/Footer.tsx +17 -0
  46. package/template/client/src/components/layout/Header.tsx +173 -0
  47. package/template/client/src/components/layout/MainLayout.tsx +18 -0
  48. package/template/client/src/components/ui/alert-dialog.tsx +196 -0
  49. package/template/client/src/components/ui/badge.tsx +48 -0
  50. package/template/client/src/components/ui/button.tsx +64 -0
  51. package/template/client/src/components/ui/card.tsx +92 -0
  52. package/template/client/src/components/ui/input.tsx +21 -0
  53. package/template/client/src/components/ui/label.tsx +24 -0
  54. package/template/client/src/components/ui/select.tsx +190 -0
  55. package/template/client/src/components/ui/skeleton.tsx +13 -0
  56. package/template/client/src/components/ui/table.tsx +116 -0
  57. package/template/client/src/features/auth/components/AuthInitializer.tsx +55 -0
  58. package/template/client/src/features/auth/components/LoginForm.tsx +107 -0
  59. package/template/client/src/features/auth/components/RegisterForm.tsx +178 -0
  60. package/template/client/src/features/auth/hooks/useAuth.ts +84 -0
  61. package/template/client/src/features/auth/services/auth.service.ts +52 -0
  62. package/template/client/src/features/auth/store/authSlice.ts +38 -0
  63. package/template/client/src/features/auth/types/auth.types.ts +32 -0
  64. package/template/client/src/hooks/useDebounce.ts +14 -0
  65. package/template/client/src/hooks/useLocalStorage.ts +55 -0
  66. package/template/client/src/hooks/useMediaQuery.ts +27 -0
  67. package/template/client/src/lib/api/api.types.ts +34 -0
  68. package/template/client/src/lib/api/axios.config.ts +98 -0
  69. package/template/client/src/lib/constants/api-endpoints.ts +18 -0
  70. package/template/client/src/lib/constants/app.constants.ts +12 -0
  71. package/template/client/src/lib/constants/routes.ts +9 -0
  72. package/template/client/src/lib/utils/error.ts +32 -0
  73. package/template/client/src/lib/utils/format.ts +37 -0
  74. package/template/client/src/lib/utils/security.ts +34 -0
  75. package/template/client/src/lib/utils.ts +6 -0
  76. package/template/client/src/middleware.ts +57 -0
  77. package/template/client/src/store/hooks.ts +7 -0
  78. package/template/client/src/store/index.ts +12 -0
  79. package/template/client/src/types/index.ts +3 -0
  80. package/template/client/tsconfig.json +34 -0
  81. package/template/gitignore +34 -0
  82. package/template/server/.dockerignore +66 -0
  83. package/template/server/.env.example +96 -69
  84. package/template/server/.env.production.example +90 -0
  85. package/template/server/Dockerfile +94 -0
  86. package/template/server/docker-compose.yml +82 -111
  87. package/template/server/docs/logging.md +62 -0
  88. package/template/server/eslint.config.mjs +17 -0
  89. package/template/server/package.json +68 -81
  90. package/template/server/phpmyadmin-config.php +26 -0
  91. package/template/server/postman_collection.json +666 -0
  92. package/template/server/prisma/schema.prisma +77 -93
  93. package/template/server/prisma/seed.ts +46 -142
  94. package/template/server/scripts/flush-redis.ts +41 -0
  95. package/template/server/src/app.ts +243 -71
  96. package/template/server/src/config/env.ts +67 -94
  97. package/template/server/src/libs/auth.ts +88 -0
  98. package/template/server/src/libs/cleanup.ts +35 -0
  99. package/template/server/src/libs/cookies.ts +46 -0
  100. package/template/server/src/libs/logger.ts +33 -60
  101. package/template/server/src/libs/monitoring.ts +205 -0
  102. package/template/server/src/libs/password.ts +38 -0
  103. package/template/server/src/libs/prisma.ts +68 -0
  104. package/template/server/src/libs/redis.ts +60 -79
  105. package/template/server/src/libs/requestLogger.ts +66 -0
  106. package/template/server/src/libs/storage/file-storage.service.ts +211 -0
  107. package/template/server/src/libs/storage/file-validator.ts +97 -0
  108. package/template/server/src/libs/storage/filename-sanitizer.ts +71 -0
  109. package/template/server/src/libs/storage/image-optimizer.service.ts +144 -0
  110. package/template/server/src/modules/auth/__tests__/auth.service.test.ts +365 -0
  111. package/template/server/src/modules/auth/auth.controller.ts +90 -141
  112. package/template/server/src/modules/auth/auth.repo.ts +120 -218
  113. package/template/server/src/modules/auth/auth.routes.ts +96 -83
  114. package/template/server/src/modules/auth/auth.schemas.ts +35 -137
  115. package/template/server/src/modules/auth/auth.service.ts +286 -329
  116. package/template/server/src/modules/auth/session.repo.ts +110 -0
  117. package/template/server/src/modules/users/users.controller.ts +120 -0
  118. package/template/server/src/modules/users/users.repo.ts +77 -0
  119. package/template/server/src/modules/users/users.routes.ts +89 -0
  120. package/template/server/src/modules/users/users.schemas.ts +21 -0
  121. package/template/server/src/modules/users/users.service.ts +169 -0
  122. package/template/server/src/server.ts +58 -139
  123. package/template/server/src/shared/errors/AppError.ts +21 -0
  124. package/template/server/src/shared/errors/errors.ts +43 -0
  125. package/template/server/src/shared/responses/paginatedResponse.ts +38 -0
  126. package/template/server/src/shared/responses/successResponse.ts +17 -0
  127. package/template/server/src/shared/schemas/pagination.schema.ts +12 -0
  128. package/template/server/src/shared/types/index.ts +26 -0
  129. package/template/server/src/test/setup.ts +74 -38
  130. package/template/server/tsconfig.json +27 -89
  131. package/template/server/uploads/avatars/.gitkeep +1 -0
  132. package/template/server/vitest.config.ts +43 -98
  133. package/template/.agent/rules/client/01-project-structure.md +0 -326
  134. package/template/.agent/rules/client/02-component-patterns.md +0 -249
  135. package/template/.agent/rules/client/03-typescript-rules.md +0 -226
  136. package/template/.agent/rules/client/04-state-management.md +0 -474
  137. package/template/.agent/rules/client/05-api-integration.md +0 -129
  138. package/template/.agent/rules/client/06-forms-validation.md +0 -129
  139. package/template/.agent/rules/client/07-common-patterns.md +0 -150
  140. package/template/.agent/rules/client/08-color-system.md +0 -93
  141. package/template/.agent/rules/client/09-security-rules.md +0 -97
  142. package/template/.agent/rules/client/10-testing-strategy.md +0 -370
  143. package/template/.agent/rules/global/ai-edit-safety.md +0 -38
  144. package/template/.agent/rules/server/01-db-and-migrations.md +0 -242
  145. package/template/.agent/rules/server/02-general-rules.md +0 -111
  146. package/template/.agent/rules/server/03-migrations.md +0 -20
  147. package/template/.agent/rules/server/04-pagination.md +0 -130
  148. package/template/.agent/rules/server/05-project-conventions.md +0 -71
  149. package/template/.agent/rules/server/06-response-handling.md +0 -173
  150. package/template/.agent/rules/server/07-testing-strategy.md +0 -506
  151. package/template/.agent/rules/server/08-observability.md +0 -180
  152. package/template/.agent/rules/server/10-background-jobs-v2.md +0 -185
  153. package/template/.agent/rules/server/11-rate-limiting-v2.md +0 -210
  154. package/template/.agent/rules/server/12-performance-optimization.md +0 -567
  155. package/template/.claude/rules/client-01-project-structure.md +0 -327
  156. package/template/.claude/rules/client-02-component-patterns.md +0 -250
  157. package/template/.claude/rules/client-03-typescript-rules.md +0 -227
  158. package/template/.claude/rules/client-04-state-management.md +0 -475
  159. package/template/.claude/rules/client-05-api-integration.md +0 -130
  160. package/template/.claude/rules/client-06-forms-validation.md +0 -130
  161. package/template/.claude/rules/client-07-common-patterns.md +0 -151
  162. package/template/.claude/rules/client-08-color-system.md +0 -94
  163. package/template/.claude/rules/client-09-security-rules.md +0 -98
  164. package/template/.claude/rules/client-10-testing-strategy.md +0 -371
  165. package/template/.claude/rules/global-ai-edit-safety.md +0 -39
  166. package/template/.claude/rules/server-01-db-and-migrations.md +0 -243
  167. package/template/.claude/rules/server-02-general-rules.md +0 -112
  168. package/template/.claude/rules/server-03-migrations.md +0 -21
  169. package/template/.claude/rules/server-04-pagination.md +0 -131
  170. package/template/.claude/rules/server-05-project-conventions.md +0 -72
  171. package/template/.claude/rules/server-06-response-handling.md +0 -174
  172. package/template/.claude/rules/server-07-testing-strategy.md +0 -507
  173. package/template/.claude/rules/server-08-observability.md +0 -181
  174. package/template/.claude/rules/server-10-background-jobs-v2.md +0 -186
  175. package/template/.claude/rules/server-11-rate-limiting-v2.md +0 -211
  176. package/template/.claude/rules/server-12-performance-optimization.md +0 -568
  177. package/template/.cursor/rules/client-01-project-structure.mdc +0 -327
  178. package/template/.cursor/rules/client-02-component-patterns.mdc +0 -250
  179. package/template/.cursor/rules/client-03-typescript-rules.mdc +0 -227
  180. package/template/.cursor/rules/client-04-state-management.mdc +0 -475
  181. package/template/.cursor/rules/client-05-api-integration.mdc +0 -130
  182. package/template/.cursor/rules/client-06-forms-validation.mdc +0 -130
  183. package/template/.cursor/rules/client-07-common-patterns.mdc +0 -151
  184. package/template/.cursor/rules/client-08-color-system.mdc +0 -94
  185. package/template/.cursor/rules/client-09-security-rules.mdc +0 -98
  186. package/template/.cursor/rules/client-10-testing-strategy.mdc +0 -371
  187. package/template/.cursor/rules/global-ai-edit-safety.mdc +0 -39
  188. package/template/.cursor/rules/server-01-db-and-migrations.mdc +0 -243
  189. package/template/.cursor/rules/server-02-general-rules.mdc +0 -112
  190. package/template/.cursor/rules/server-03-migrations.mdc +0 -21
  191. package/template/.cursor/rules/server-04-pagination.mdc +0 -131
  192. package/template/.cursor/rules/server-05-project-conventions.mdc +0 -72
  193. package/template/.cursor/rules/server-06-response-handling.mdc +0 -174
  194. package/template/.cursor/rules/server-07-testing-strategy.mdc +0 -507
  195. package/template/.cursor/rules/server-08-observability.mdc +0 -181
  196. package/template/.cursor/rules/server-09-api-documentation-v2.mdc +0 -169
  197. package/template/.cursor/rules/server-10-background-jobs-v2.mdc +0 -186
  198. package/template/.cursor/rules/server-11-rate-limiting-v2.mdc +0 -211
  199. package/template/.cursor/rules/server-12-performance-optimization.mdc +0 -568
  200. package/template/CLAUDE.md +0 -207
  201. package/template/server/.tsc-aliasrc.json +0 -13
  202. package/template/server/IMPORT_FIX_CHECKLIST.md +0 -98
  203. package/template/server/IMPORT_FIX_COMPLETE.md +0 -89
  204. package/template/server/README.md +0 -183
  205. package/template/server/REMAINING_IMPORT_FIXES.md +0 -150
  206. package/template/server/SECURITY.md +0 -190
  207. package/template/server/Tigra-API.postman_collection.json +0 -733
  208. package/template/server/biome.json +0 -42
  209. package/template/server/scripts/fix-all-imports.ps1 +0 -52
  210. package/template/server/scripts/fix-imports-reference.ps1 +0 -16
  211. package/template/server/scripts/fix-imports.mjs +0 -55
  212. package/template/server/scripts/setup-env.js +0 -50
  213. package/template/server/scripts/wait-for-db.js +0 -60
  214. package/template/server/src/hooks/request-timing.hook.ts +0 -26
  215. package/template/server/src/libs/auth/authenticate.middleware.ts +0 -22
  216. package/template/server/src/libs/auth/rbac.middleware.test.ts +0 -134
  217. package/template/server/src/libs/auth/rbac.middleware.ts +0 -147
  218. package/template/server/src/libs/db.ts +0 -76
  219. package/template/server/src/libs/error-handler.ts +0 -89
  220. package/template/server/src/libs/queue.ts +0 -79
  221. package/template/server/src/modules/admin/admin.controller.ts +0 -122
  222. package/template/server/src/modules/admin/admin.routes.ts +0 -62
  223. package/template/server/src/modules/admin/admin.schemas.ts +0 -35
  224. package/template/server/src/modules/admin/admin.service.ts +0 -167
  225. package/template/server/src/modules/auth/auth.integration.test.ts +0 -150
  226. package/template/server/src/modules/auth/auth.service.test.ts +0 -119
  227. package/template/server/src/modules/auth/auth.types.ts +0 -97
  228. package/template/server/src/modules/resources/resources.controller.ts +0 -218
  229. package/template/server/src/modules/resources/resources.repo.ts +0 -253
  230. package/template/server/src/modules/resources/resources.routes.ts +0 -116
  231. package/template/server/src/modules/resources/resources.schemas.ts +0 -146
  232. package/template/server/src/modules/resources/resources.service.ts +0 -218
  233. package/template/server/src/modules/resources/resources.types.ts +0 -73
  234. package/template/server/src/plugins/rate-limit.plugin.ts +0 -21
  235. package/template/server/src/plugins/security.plugin.ts +0 -21
  236. package/template/server/src/routes/health.routes.ts +0 -31
  237. package/template/server/src/types/fastify.d.ts +0 -36
  238. package/template/server/src/utils/errors.ts +0 -108
  239. package/template/server/src/utils/pagination.ts +0 -120
  240. package/template/server/src/utils/response.ts +0 -110
  241. package/template/server/src/workers/file.worker.ts +0 -106
  242. package/template/server/tsconfig.build.json +0 -30
  243. package/template/server/tsconfig.test.json +0 -22
@@ -1,567 +0,0 @@
1
- ---
2
- trigger: always_on
3
- ---
4
-
5
- > **SCOPE**: These rules apply specifically to the **server** directory.
6
-
7
- # Performance Optimization
8
-
9
- ## Core Principles
10
-
11
- - **Measure first, optimize second** - Use profiling to find actual bottlenecks
12
- - **Database queries** are the #1 performance killer
13
- - **Caching** can eliminate 80% of database queries
14
- - **Async everything** - Never block the event loop
15
-
16
- ---
17
-
18
- ## Database Query Optimization
19
-
20
- ### 1. Prevent N+1 Queries
21
-
22
- ```typescript
23
- // ❌ BAD - N+1 query problem
24
- async function getResourcesWithOwners() {
25
- const resources = await prisma.resource.findMany();
26
-
27
- // This executes 1 query per resource!
28
- for (const resource of resources) {
29
- resource.owner = await prisma.user.findUnique({
30
- where: { id: resource.ownerId },
31
- });
32
- }
33
-
34
- return resources;
35
- }
36
-
37
- // ✅ GOOD - Single query with join
38
- async function getResourcesWithOwners() {
39
- return await prisma.resource.findMany({
40
- include: {
41
- owner: true, // Prisma joins in one query
42
- },
43
- });
44
- }
45
- ```
46
-
47
- ### 2. Select Only Needed Fields
48
-
49
- ```typescript
50
- // ❌ BAD - Fetches all columns
51
- const users = await prisma.user.findMany();
52
-
53
- // ✅ GOOD - Select specific fields
54
- const users = await prisma.user.findMany({
55
- select: {
56
- id: true,
57
- email: true,
58
- name: true,
59
- // Don't fetch password, createdAt, etc.
60
- },
61
- });
62
- ```
63
-
64
- ### 3. Use Pagination
65
-
66
- ```typescript
67
- // ❌ BAD - Loads all records into memory
68
- const resources = await prisma.resource.findMany();
69
-
70
- // ✅ GOOD - Paginate
71
- const resources = await prisma.resource.findMany({
72
- take: limit,
73
- skip: (page - 1) * limit,
74
- });
75
- ```
76
-
77
- ### 4. Index Frequently Queried Fields
78
-
79
- ```prisma
80
- // schema.prisma
81
- model Resource {
82
- id String @id @default(uuid())
83
- ownerId String
84
- status String
85
- price Float
86
- category String
87
- createdAt DateTime @default(now())
88
-
89
- // Add indexes for fields used in WHERE clauses
90
- @@index([ownerId])
91
- @@index([status])
92
- @@index([category])
93
- @@index([createdAt])
94
-
95
- // Composite index for common queries
96
- @@index([category, status, createdAt])
97
- }
98
- ```
99
-
100
- ### 5. Use Transactions Sparingly
101
-
102
- ```typescript
103
- // ❌ BAD - Unnecessary transaction
104
- await prisma.$transaction([
105
- prisma.user.findUnique({ where: { id: '1' } }), // Just a read!
106
- ]);
107
-
108
- // ✅ GOOD - Transaction only for writes
109
- await prisma.$transaction([
110
- prisma.user.update({ where: { id: '1' }, data: { credits: { decrement: 10 } } }),
111
- prisma.payment.create({ data: { userId: '1', amount: 10 } }),
112
- ]);
113
- ```
114
-
115
- ---
116
-
117
- ## Redis Caching Strategies
118
-
119
- ### 1. Cache Expensive Queries
120
-
121
- ```typescript
122
- // libs/cache.ts
123
- import { redis } from './redis';
124
-
125
- export async function getCachedOrFetch<T>(
126
- key: string,
127
- fetchFn: () => Promise<T>,
128
- ttl = 300 // 5 minutes
129
- ): Promise<T> {
130
- // Try cache first
131
- const cached = await redis.get(key);
132
- if (cached) {
133
- return JSON.parse(cached);
134
- }
135
-
136
- // Fetch from DB
137
- const data = await fetchFn();
138
-
139
- // Store in cache
140
- await redis.setex(key, ttl, JSON.stringify(data));
141
-
142
- return data;
143
- }
144
- ```
145
-
146
- ```typescript
147
- // Usage in service
148
- async function getPopularResources() {
149
- return getCachedOrFetch(
150
- 'popular-resources',
151
- async () => {
152
- return await prisma.resource.findMany({
153
- where: { isPopular: true },
154
- take: 10,
155
- });
156
- },
157
- 600 // Cache for 10 minutes
158
- );
159
- }
160
- ```
161
-
162
- ### 2. Cache Invalidation
163
-
164
- ```typescript
165
- // When resource is updated, invalidate cache
166
- async function updateResource(id: string, data: any) {
167
- const updated = await prisma.resource.update({
168
- where: { id },
169
- data,
170
- });
171
-
172
- // Invalidate relevant caches
173
- await redis.del(`resource:${id}`);
174
- await redis.del('popular-resources');
175
- await redis.del('recent-resources');
176
-
177
- return updated;
178
- }
179
- ```
180
-
181
- ### 3. Cache Patterns
182
-
183
- ```typescript
184
- // Pattern: Cache-Aside (Lazy Loading)
185
- async function getResource(id: string) {
186
- const cacheKey = `resource:${id}`;
187
- const cached = await redis.get(cacheKey);
188
-
189
- if (cached) return JSON.parse(cached);
190
-
191
- const resource = await prisma.resource.findUnique({ where: { id } });
192
- if (resource) {
193
- await redis.setex(cacheKey, 300, JSON.stringify(resource));
194
- }
195
-
196
- return resource;
197
- }
198
-
199
- // Pattern: Write-Through
200
- async function createResource(data: CreateResourceInput) {
201
- const resource = await prisma.resource.create({ data });
202
-
203
- // Immediately cache new resource
204
- await redis.setex(
205
- `resource:${resource.id}`,
206
- 300,
207
- JSON.stringify(resource)
208
- );
209
-
210
- return resource;
211
- }
212
- ```
213
-
214
- ---
215
-
216
- ## Query Performance Monitoring
217
-
218
- ### 1. Log Slow Queries
219
-
220
- ```typescript
221
- // libs/db.ts (already in observability.md)
222
- prisma.$on('query', (e) => {
223
- if (e.duration > 1000) {
224
- logger.warn(
225
- {
226
- query: e.query,
227
- duration: e.duration,
228
- params: e.params,
229
- },
230
- 'Slow query detected'
231
- );
232
- }
233
- });
234
- ```
235
-
236
- ### 2. Database Connection Pooling
237
-
238
- ```typescript
239
- // Prisma auto-manages connection pool
240
- // Configure in DATABASE_URL
241
- // mysql://user:pass@localhost:3306/db?connection_limit=10
242
- ```
243
-
244
- ---
245
-
246
- ## Response Compression
247
-
248
- ```typescript
249
- // app.ts
250
- import compress from '@fastify/compress';
251
-
252
- await app.register(compress, {
253
- global: true,
254
- threshold: 1024, // Only compress responses > 1KB
255
- encodings: ['gzip', 'deflate'],
256
- });
257
- ```
258
-
259
- ---
260
-
261
- ## Async Processing Best Practices
262
-
263
- ### 1. Use Background Jobs for Slow Operations
264
-
265
- ```typescript
266
- // ❌ BAD - Blocks HTTP response
267
- app.post('/resources', async (request, reply) => {
268
- const resource = await createResource(request.body);
269
-
270
- // This takes 5 seconds!
271
- await sendEmailToOwner(resource.ownerId);
272
- await generateThumbnails(resource.images);
273
- await notifyFollowers(resource.ownerId);
274
-
275
- return reply.send(resource);
276
- });
277
-
278
- // ✅ GOOD - Offload to background jobs
279
- app.post('/resources', async (request, reply) => {
280
- const resource = await createResource(request.body);
281
-
282
- // Queue background jobs (non-blocking)
283
- await emailQueue.add('notify-owner', { resourceId: resource.id });
284
- await fileQueue.add('generate-thumbnails', { resourceId: resource.id });
285
- await notificationQueue.add('notify-followers', { ownerId: resource.ownerId });
286
-
287
- // Return immediately
288
- return reply.send(resource);
289
- });
290
- ```
291
-
292
- ### 2. Parallel Execution
293
-
294
- ```typescript
295
- // ❌ BAD - Sequential (slow)
296
- const user = await prisma.user.findUnique({ where: { id } });
297
- const resources = await prisma.resource.findMany({ where: { ownerId: id } });
298
- const stats = await calculateUserStats(id);
299
-
300
- // ✅ GOOD - Parallel (fast)
301
- const [user, resources, stats] = await Promise.all([
302
- prisma.user.findUnique({ where: { id } }),
303
- prisma.resource.findMany({ where: { ownerId: id } }),
304
- calculateUserStats(id),
305
- ]);
306
- ```
307
-
308
- ---
309
-
310
- ## Response Optimization
311
-
312
- ### 1. Minimize Response Size
313
-
314
- ```typescript
315
- // ❌ BAD - Returns entire objects
316
- app.get('/resources', async (request, reply) => {
317
- const resources = await prisma.resource.findMany();
318
- return resources; // Includes unnecessary fields
319
- });
320
-
321
- // ✅ GOOD - Select only needed fields
322
- app.get('/resources', async (request, reply) => {
323
- const resources = await prisma.resource.findMany({
324
- select: {
325
- id: true,
326
- title: true,
327
- price: true,
328
- thumbnailUrl: true,
329
- // Don't include description, metadata, etc. in list view
330
- },
331
- });
332
- return resources;
333
- });
334
- ```
335
-
336
- ### 2. Use Streaming for Large Responses
337
-
338
- ```typescript
339
- // For large datasets, stream instead of buffering
340
- app.get('/export/resources', async (request, reply) => {
341
- reply.type('application/json');
342
-
343
- const stream = prisma.resource.findMany({ stream: true });
344
-
345
- return reply.send(stream);
346
- });
347
- ```
348
-
349
- ---
350
-
351
- ## Memory Management
352
-
353
- ### 1. Avoid Memory Leaks
354
-
355
- ```typescript
356
- // ❌ BAD - Memory leak
357
- const cache = new Map();
358
-
359
- app.get('/data', (request, reply) => {
360
- const data = getExpensiveData();
361
- cache.set(request.id, data); // Never cleaned up!
362
- return data;
363
- });
364
-
365
- // ✅ GOOD - Use Redis or LRU cache
366
- import LRU from 'lru-cache';
367
-
368
- const cache = new LRU({
369
- max: 500, // Max 500 items
370
- ttl: 1000 * 60 * 5, // 5 minutes
371
- });
372
- ```
373
-
374
- ### 2. Batch Processing
375
-
376
- ```typescript
377
- // ❌ BAD - Process one by one
378
- for (const user of users) {
379
- await sendEmail(user.email);
380
- }
381
-
382
- // ✅ GOOD - Batch process
383
- const chunks = chunkArray(users, 100);
384
- for (const chunk of chunks) {
385
- await Promise.all(chunk.map(user => sendEmail(user.email)));
386
- }
387
- ```
388
-
389
- ---
390
-
391
- ## API Design for Performance
392
-
393
- ### 1. Cursor-Based Pagination (Large Datasets)
394
-
395
- ```typescript
396
- // Better than offset pagination for large datasets
397
- app.get('/resources', async (request, reply) => {
398
- const { cursor, limit = 10 } = request.query;
399
-
400
- const resources = await prisma.resource.findMany({
401
- take: limit + 1, // Fetch one extra to check if more exist
402
- cursor: cursor ? { id: cursor } : undefined,
403
- orderBy: { createdAt: 'desc' },
404
- });
405
-
406
- const hasMore = resources.length > limit;
407
- const items = hasMore ? resources.slice(0, -1) : resources;
408
-
409
- return {
410
- items,
411
- nextCursor: hasMore ? items[items.length - 1].id : null,
412
- };
413
- });
414
- ```
415
-
416
- ### 2. Field Selection (GraphQL-style)
417
-
418
- ```typescript
419
- // Allow clients to request only needed fields
420
- app.get('/users/:id', async (request, reply) => {
421
- const { fields } = request.query; // ?fields=id,email,name
422
-
423
- const select = fields
424
- ? fields.split(',').reduce((acc, field) => {
425
- acc[field] = true;
426
- return acc;
427
- }, {})
428
- : undefined;
429
-
430
- const user = await prisma.user.findUnique({
431
- where: { id: request.params.id },
432
- select,
433
- });
434
-
435
- return user;
436
- });
437
- ```
438
-
439
- ---
440
-
441
- ## Load Testing
442
-
443
- ```bash
444
- # Install k6 for load testing
445
- brew install k6 # macOS
446
- # or
447
- choco install k6 # Windows
448
-
449
- # Create load test script
450
- cat > load-test.js << 'EOF'
451
- import http from 'k6/http';
452
- import { check } from 'k6';
453
-
454
- export const options = {
455
- stages: [
456
- { duration: '30s', target: 50 }, // Ramp up to 50 users
457
- { duration: '1m', target: 100 }, // Stay at 100 users
458
- { duration: '30s', target: 0 }, // Ramp down
459
- ],
460
- thresholds: {
461
- http_req_duration: ['p(95)<500'], // 95% of requests < 500ms
462
- },
463
- };
464
-
465
- export default function () {
466
- const res = http.get('http://localhost:3000/api/v1/resources');
467
- check(res, {
468
- 'status is 200': (r) => r.status === 200,
469
- 'response time < 500ms': (r) => r.timings.duration < 500,
470
- });
471
- }
472
- EOF
473
-
474
- # Run test
475
- k6 run load-test.js
476
- ```
477
-
478
- ---
479
-
480
- ## Performance Monitoring
481
-
482
- ### 1. Response Time Tracking
483
-
484
- ```typescript
485
- // Already covered in observability.md
486
- app.addHook('onRequest', (request, reply, done) => {
487
- request.startTime = Date.now();
488
- done();
489
- });
490
-
491
- app.addHook('onResponse', (request, reply, done) => {
492
- const duration = Date.now() - request.startTime;
493
-
494
- logger.info({
495
- method: request.method,
496
- url: request.url,
497
- statusCode: reply.statusCode,
498
- duration,
499
- });
500
-
501
- done();
502
- });
503
- ```
504
-
505
- ### 2. Database Query Metrics
506
-
507
- ```typescript
508
- let queryCount = 0;
509
- let totalQueryTime = 0;
510
-
511
- prisma.$on('query', (e) => {
512
- queryCount++;
513
- totalQueryTime += e.duration;
514
- });
515
-
516
- app.get('/metrics/db', async (request, reply) => {
517
- return {
518
- totalQueries: queryCount,
519
- avgDuration: totalQueryTime / queryCount,
520
- };
521
- });
522
- ```
523
-
524
- ---
525
-
526
- ## Performance Checklist
527
-
528
- ### Database
529
- - [ ] Indexes on frequently queried fields
530
- - [ ] No N+1 queries
531
- - [ ] Pagination implemented
532
- - [ ] Select only needed fields
533
- - [ ] Connection pooling configured
534
- - [ ] Slow query logging enabled
535
-
536
- ### Caching
537
- - [ ] Redis caching for expensive queries
538
- - [ ] Cache invalidation strategy
539
- - [ ] TTL set appropriately
540
- - [ ] Cache hit/miss monitoring
541
-
542
- ### API
543
- - [ ] Response compression enabled
544
- - [ ] Background jobs for slow operations
545
- - [ ] Parallel execution where possible
546
- - [ ] Minimal response payloads
547
- - [ ] Rate limiting configured
548
-
549
- ### Monitoring
550
- - [ ] Response time tracking
551
- - [ ] Database metrics collected
552
- - [ ] Load testing performed
553
- - [ ] Error rates monitored
554
- - [ ] Memory usage monitored
555
-
556
- ---
557
-
558
- ## Performance Targets
559
-
560
- | Metric | Target |
561
- |--------|--------|
562
- | API Response Time (p95) | < 500ms |
563
- | API Response Time (p99) | < 1s |
564
- | Database Query Time (p95) | < 100ms |
565
- | Cache Hit Rate | > 80% |
566
- | Error Rate | < 0.1% |
567
- | Throughput | > 1000 req/s |