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,186 +0,0 @@
1
- ---
2
- trigger: always_on
3
- globs: "server/**/*"
4
- ---
5
-
6
- > **SCOPE**: These rules apply specifically to the **server** directory.
7
-
8
- # Background Jobs & Queue Processing
9
-
10
- ## Stack
11
-
12
- ```json
13
- {
14
- "dependencies": {
15
- "bullmq": "^5.0.0",
16
- "ioredis": "^5.3.0"
17
- }
18
- }
19
- ```
20
-
21
- ## Redis Setup
22
-
23
- ```typescript
24
- // libs/redis.ts
25
- import Redis from 'ioredis';
26
-
27
- export const redis = new Redis({
28
- host: process.env.REDIS_HOST || 'localhost',
29
- port: parseInt(process.env.REDIS_PORT || '6379'),
30
- maxRetriesPerRequest: null, // Required for BullMQ
31
- });
32
- ```
33
-
34
- ## Queue Setup
35
-
36
- ```typescript
37
- // libs/queue.ts
38
- import { Queue, Worker, QueueEvents } from 'bullmq';
39
- import { redis } from './redis';
40
-
41
- export const emailQueue = new Queue('emails', {
42
- connection: redis,
43
- defaultJobOptions: {
44
- attempts: 3,
45
- backoff: { type: 'exponential', delay: 2000 },
46
- removeOnComplete: { age: 3600, count: 100 },
47
- removeOnFail: { age: 86400 },
48
- },
49
- });
50
- ```
51
-
52
- ## Worker Pattern
53
-
54
- ```typescript
55
- // workers/email.worker.ts
56
- import { Worker, Job } from 'bullmq';
57
-
58
- interface EmailJobData {
59
- to: string;
60
- subject: string;
61
- body: string;
62
- }
63
-
64
- export const emailWorker = new Worker<EmailJobData>(
65
- 'emails',
66
- async (job: Job<EmailJobData>) => {
67
- const { to, subject, body } = job.data;
68
-
69
- logger.info({ jobId: job.id, to }, 'Processing email');
70
-
71
- await sendEmail({ to, subject, body });
72
-
73
- return { success: true, sentAt: new Date().toISOString() };
74
- },
75
- {
76
- connection: redis,
77
- concurrency: 5,
78
- limiter: { max: 100, duration: 60000 }, // 100 jobs/minute
79
- }
80
- );
81
- ```
82
-
83
- ## Job Patterns
84
-
85
- ### 1. Immediate Background Job
86
- ```typescript
87
- // Add to queue (non-blocking)
88
- await emailQueue.add('welcome-email', {
89
- to: user.email,
90
- subject: 'Welcome!',
91
- body: 'Thanks for signing up',
92
- });
93
- ```
94
-
95
- ### 2. Delayed Job
96
- ```typescript
97
- // Send after 24 hours
98
- await emailQueue.add(
99
- 'reminder-email',
100
- { to: user.email, subject: 'Reminder', body: 'Complete your profile' },
101
- { delay: 24 * 60 * 60 * 1000 }
102
- );
103
- ```
104
-
105
- ### 3. Scheduled Job (Cron)
106
- ```typescript
107
- // Daily at 2 AM
108
- await cleanupQueue.add(
109
- 'daily-cleanup',
110
- {},
111
- { repeat: { pattern: '0 2 * * *' } }
112
- );
113
- ```
114
-
115
- ### 4. Priority Job
116
- ```typescript
117
- await paymentQueue.add(
118
- 'process-payment',
119
- { orderId, amount },
120
- { priority: 1 } // Lower = higher priority
121
- );
122
- ```
123
-
124
- ## Error Handling
125
-
126
- ```typescript
127
- emailWorker.on('failed', (job, error) => {
128
- logger.error({ jobId: job?.id, error }, 'Job failed');
129
-
130
- // Move to dead letter queue after all retries
131
- if (job && job.attemptsMade >= job.opts.attempts!) {
132
- deadLetterQueue.add('failed-email', {
133
- originalJob: job.data,
134
- failedReason: error.message,
135
- });
136
- }
137
- });
138
- ```
139
-
140
- ## Graceful Shutdown
141
-
142
- ```typescript
143
- // server.ts
144
- const workers = [emailWorker, fileWorker];
145
-
146
- async function gracefulShutdown() {
147
- logger.info('Shutting down workers...');
148
- await Promise.all(workers.map((w) => w.close()));
149
- process.exit(0);
150
- }
151
-
152
- process.on('SIGTERM', gracefulShutdown);
153
- process.on('SIGINT', gracefulShutdown);
154
- ```
155
-
156
- ## Use Cases
157
-
158
- - **Email sending** (welcome, verification, notifications)
159
- - **File processing** (image thumbnails, video encoding)
160
- - **Report generation** (PDFs, exports)
161
- - **Data cleanup** (expired records, temp files)
162
- - **External API calls** (webhooks, third-party sync)
163
-
164
- ## Best Practices
165
-
166
- ### ✅ DO:
167
- - Use background jobs for slow operations (>1s)
168
- - Set appropriate retry strategies
169
- - Implement rate limiting for external APIs
170
- - Monitor job failures
171
- - Clean up old jobs
172
-
173
- ### ❌ DON'T:
174
- - Block HTTP responses with heavy processing
175
- - Forget error handling
176
- - Skip monitoring
177
- - Use queues for everything (simple tasks can run inline)
178
-
179
- ## Checklist
180
-
181
- - [ ] BullMQ and Redis installed
182
- - [ ] Queues created with retry config
183
- - [ ] Workers implemented with error handling
184
- - [ ] Graceful shutdown configured
185
- - [ ] Job monitoring in place
186
- - [ ] Dead letter queue for failures
@@ -1,211 +0,0 @@
1
- ---
2
- trigger: always_on
3
- globs: "server/**/*"
4
- ---
5
-
6
- > **SCOPE**: These rules apply specifically to the **server** directory.
7
-
8
- # Rate Limiting & Throttling
9
-
10
- ## Stack
11
-
12
- ```json
13
- {
14
- "dependencies": {
15
- "@fastify/rate-limit": "^9.0.0",
16
- "ioredis": "^5.3.0"
17
- }
18
- }
19
- ```
20
-
21
- ## Basic Setup
22
-
23
- ```typescript
24
- // app.ts
25
- import rateLimit from '@fastify/rate-limit';
26
- import { redis } from './libs/redis';
27
-
28
- await app.register(rateLimit, {
29
- global: true,
30
- max: 100,
31
- timeWindow: '15 minutes',
32
- redis,
33
- nameSpace: 'rate-limit:',
34
- addHeaders: {
35
- 'x-ratelimit-limit': true,
36
- 'x-ratelimit-remaining': true,
37
- 'x-ratelimit-reset': true,
38
- 'retry-after': true,
39
- },
40
- errorResponseBuilder: (request, context) => ({
41
- success: false,
42
- error: {
43
- code: 'RATE_LIMIT_EXCEEDED',
44
- message: `Rate limit exceeded. Retry in ${Math.ceil(context.ttl / 1000)}s.`,
45
- },
46
- }),
47
- });
48
- ```
49
-
50
- ## Per-Route Limits
51
-
52
- ```typescript
53
- // Disable global, configure per route
54
- await app.register(rateLimit, { global: false, redis });
55
-
56
- // Strict limit for login
57
- app.post('/auth/login', {
58
- config: {
59
- rateLimit: {
60
- max: 5,
61
- timeWindow: '15 minutes',
62
- },
63
- },
64
- handler: authController.login,
65
- });
66
-
67
- // Generous limit for authenticated routes
68
- app.get('/resources', {
69
- preHandler: [app.authenticate],
70
- config: {
71
- rateLimit: {
72
- max: 1000,
73
- timeWindow: '15 minutes',
74
- },
75
- },
76
- handler: resourceController.listResources,
77
- });
78
- ```
79
-
80
- ## Custom Rate Limit Keys
81
-
82
- ```typescript
83
- await app.register(rateLimit, {
84
- redis,
85
- keyGenerator: (request) => {
86
- // Authenticated: rate limit by user ID
87
- if (request.user) {
88
- return `user:${request.user.id}`;
89
- }
90
- // Anonymous: rate limit by IP
91
- return `ip:${request.ip}`;
92
- },
93
- });
94
- ```
95
-
96
- ## User-Based Tiered Limits
97
-
98
- ```typescript
99
- await app.register(rateLimit, {
100
- redis,
101
- max: async (request) => {
102
- if (!request.user) return 100; // Anonymous
103
- if (request.user.role === 'ADMIN') return 10000;
104
- if (request.user.tier === 'PREMIUM') return 5000;
105
- return 1000; // Standard
106
- },
107
- });
108
- ```
109
-
110
- ## Rate Limit Tiers
111
-
112
- ```typescript
113
- // lib/constants/rate-limits.ts
114
- export const RATE_LIMITS = {
115
- LOGIN: { max: 5, timeWindow: '15 minutes' },
116
- REGISTER: { max: 3, timeWindow: '1 hour' },
117
- PASSWORD_RESET: { max: 3, timeWindow: '1 hour' },
118
- PUBLIC: { max: 100, timeWindow: '15 minutes' },
119
- AUTHENTICATED: { max: 1000, timeWindow: '15 minutes' },
120
- PREMIUM: { max: 5000, timeWindow: '15 minutes' },
121
- ADMIN: { max: 10000, timeWindow: '15 minutes' },
122
- FILE_UPLOAD: { max: 10, timeWindow: '1 hour' },
123
- } as const;
124
- ```
125
-
126
- ## Monitoring
127
-
128
- ```typescript
129
- await app.register(rateLimit, {
130
- redis,
131
- onExceeding: (request, key) => {
132
- logger.warn({ key, ip: request.ip, url: request.url }, 'Approaching limit');
133
- },
134
- onExceeded: (request, key) => {
135
- logger.error({ key, ip: request.ip, url: request.url }, 'Limit exceeded');
136
- },
137
- });
138
- ```
139
-
140
- ## Whitelist IPs
141
-
142
- ```typescript
143
- app.addHook('preHandler', async (request, reply) => {
144
- const whitelistedIPs = ['127.0.0.1', '::1'];
145
- if (whitelistedIPs.includes(request.ip)) {
146
- // @ts-ignore
147
- request.bypassRateLimit = true;
148
- }
149
- });
150
-
151
- await app.register(rateLimit, {
152
- redis,
153
- skip: (request) => request.bypassRateLimit === true,
154
- });
155
- ```
156
-
157
- ## Check Rate Limit Status
158
-
159
- ```typescript
160
- app.get('/me/rate-limit', {
161
- preHandler: [app.authenticate],
162
- handler: async (request, reply) => {
163
- const key = `user:${request.user.id}`;
164
- const current = await redis.get(`rate-limit:${key}`);
165
- const ttl = await redis.ttl(`rate-limit:${key}`);
166
-
167
- return {
168
- limit: 1000,
169
- used: parseInt(current || '0'),
170
- remaining: 1000 - parseInt(current || '0'),
171
- resetIn: ttl,
172
- };
173
- },
174
- });
175
- ```
176
-
177
- ## Strategy Summary
178
-
179
- | Endpoint | Max | Window | Key |
180
- |----------|-----|--------|-----|
181
- | Login | 5 | 15 min | IP |
182
- | Register | 3 | 1 hour | IP + email |
183
- | Public API | 100 | 15 min | IP |
184
- | Authenticated | 1000 | 15 min | User ID |
185
- | Premium | 5000 | 15 min | User ID |
186
- | Admin | 10000 | 15 min | User ID |
187
-
188
- ## Best Practices
189
-
190
- ### ✅ DO:
191
- - Use Redis for distributed rate limiting
192
- - Set stricter limits for auth endpoints
193
- - Return helpful error messages with retry time
194
- - Log rate limit violations
195
- - Add rate limit headers to responses
196
- - Whitelist localhost for testing
197
-
198
- ### ❌ DON'T:
199
- - Use in-memory rate limiting in production
200
- - Apply same limits to all endpoints
201
- - Block users permanently without investigation
202
- - Forget to test rate limits
203
-
204
- ## Checklist
205
-
206
- - [ ] Rate limiting configured with Redis
207
- - [ ] Per-route limits set appropriately
208
- - [ ] Custom error responses implemented
209
- - [ ] Rate limit headers enabled
210
- - [ ] Monitoring and logging in place
211
- - [ ] Whitelist configured for testing