create-tigra 1.0.0 → 1.0.2

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.
@@ -1,25 +1,14 @@
1
1
  /**
2
2
  * Authentication Routes
3
- *
3
+ *
4
4
  * Fastify route definitions for authentication endpoints.
5
- * Includes Swagger documentation and rate limiting.
6
- *
7
- * @see /mnt/project/09-api-documentation-v2.md
5
+ * Includes rate limiting for security.
6
+ *
8
7
  * @see /mnt/project/11-rate-limiting-v2.md
9
8
  */
10
9
 
11
10
  import type { FastifyInstance } from 'fastify';
12
- import { toJsonSchema, getDefinition } from '@/libs/swagger-schemas';
13
11
  import * as authController from './auth.controller';
14
- import {
15
- RegisterSchema,
16
- LoginSchema,
17
- RefreshTokenSchema,
18
- AuthResponseSchema,
19
- UserResponseSchema,
20
- TokenResponseSchema,
21
- ErrorResponseSchema,
22
- } from './auth.schemas';
23
12
 
24
13
  /**
25
14
  * Register authentication routes
@@ -29,27 +18,10 @@ import {
29
18
  export async function authRoutes(fastify: FastifyInstance): Promise<void> {
30
19
  /**
31
20
  * POST /auth/register
32
- *
21
+ *
33
22
  * Register a new user account
34
23
  */
35
24
  fastify.post('/register', {
36
- schema: {
37
- description: 'Register a new user account',
38
- tags: ['auth'],
39
- summary: 'Register user',
40
- body: toJsonSchema(RegisterSchema, 'RegisterRequest'),
41
- response: {
42
- 201: getDefinition(AuthResponseSchema, 'AuthResponse'),
43
- 400: {
44
- description: 'Validation error',
45
- ...getDefinition(ErrorResponseSchema, 'ErrorResponse'),
46
- },
47
- 409: {
48
- description: 'Email already registered',
49
- ...getDefinition(ErrorResponseSchema, 'ErrorResponse'),
50
- },
51
- },
52
- },
53
25
  config: {
54
26
  rateLimit: {
55
27
  max: 3,
@@ -61,23 +33,10 @@ export async function authRoutes(fastify: FastifyInstance): Promise<void> {
61
33
 
62
34
  /**
63
35
  * POST /auth/login
64
- *
36
+ *
65
37
  * Login with email and password
66
38
  */
67
39
  fastify.post('/login', {
68
- schema: {
69
- description: 'Login with email and password',
70
- tags: ['auth'],
71
- summary: 'Login user',
72
- body: toJsonSchema(LoginSchema, 'LoginRequest'),
73
- response: {
74
- 200: getDefinition(AuthResponseSchema, 'AuthResponse'),
75
- 401: {
76
- description: 'Invalid credentials',
77
- ...getDefinition(ErrorResponseSchema, 'ErrorResponse'),
78
- },
79
- },
80
- },
81
40
  config: {
82
41
  rateLimit: {
83
42
  max: 5,
@@ -89,37 +48,10 @@ export async function authRoutes(fastify: FastifyInstance): Promise<void> {
89
48
 
90
49
  /**
91
50
  * POST /auth/refresh
92
- *
51
+ *
93
52
  * Refresh access token using refresh token
94
53
  */
95
54
  fastify.post('/refresh', {
96
- schema: {
97
- description: 'Refresh access token using refresh token',
98
- tags: ['auth'],
99
- summary: 'Refresh tokens',
100
- body: toJsonSchema(RefreshTokenSchema, 'RefreshTokenRequest'),
101
- response: {
102
- 200: {
103
- description: 'Tokens refreshed successfully',
104
- type: 'object',
105
- properties: {
106
- success: { type: 'boolean', enum: [true] },
107
- message: { type: 'string' },
108
- data: {
109
- type: 'object',
110
- properties: {
111
- accessToken: { type: 'string' },
112
- refreshToken: { type: 'string' },
113
- },
114
- },
115
- },
116
- },
117
- 401: {
118
- description: 'Invalid or expired refresh token',
119
- ...getDefinition(ErrorResponseSchema, 'ErrorResponse'),
120
- },
121
- },
122
- },
123
55
  config: {
124
56
  rateLimit: {
125
57
  max: 10,
@@ -131,73 +63,20 @@ export async function authRoutes(fastify: FastifyInstance): Promise<void> {
131
63
 
132
64
  /**
133
65
  * POST /auth/logout
134
- *
66
+ *
135
67
  * Logout user by invalidating refresh token
136
68
  */
137
69
  fastify.post('/logout', {
138
- schema: {
139
- description: 'Logout user by invalidating refresh token',
140
- tags: ['auth'],
141
- summary: 'Logout user',
142
- body: toJsonSchema(RefreshTokenSchema, 'RefreshTokenRequest'),
143
- response: {
144
- 200: {
145
- description: 'Logout successful',
146
- type: 'object',
147
- properties: {
148
- success: { type: 'boolean', enum: [true] },
149
- message: { type: 'string' },
150
- data: { type: 'null' },
151
- },
152
- },
153
- },
154
- },
155
70
  handler: authController.logout,
156
71
  });
157
72
 
158
73
  /**
159
74
  * GET /auth/me
160
- *
75
+ *
161
76
  * Get current authenticated user information
162
77
  * Requires authentication
163
78
  */
164
79
  fastify.get('/me', {
165
- schema: {
166
- description: 'Get current authenticated user information',
167
- tags: ['auth'],
168
- summary: 'Get current user',
169
- security: [{ bearerAuth: [] }],
170
- response: {
171
- 200: {
172
- description: 'User retrieved successfully',
173
- type: 'object',
174
- properties: {
175
- success: { type: 'boolean', enum: [true] },
176
- message: { type: 'string' },
177
- data: {
178
- type: 'object',
179
- properties: {
180
- id: { type: 'string', format: 'uuid' },
181
- email: { type: 'string', format: 'email' },
182
- name: { type: 'string', nullable: true },
183
- role: { type: 'string' },
184
- emailVerified: { type: 'boolean' },
185
- createdAt: { type: 'string', format: 'date-time' },
186
- updatedAt: { type: 'string', format: 'date-time' },
187
- },
188
- },
189
- },
190
- },
191
- 401: {
192
- description: 'Unauthorized - Invalid or missing token',
193
- ...getDefinition(ErrorResponseSchema, 'ErrorResponse'),
194
- },
195
- 404: {
196
- description: 'User not found',
197
- ...getDefinition(ErrorResponseSchema, 'ErrorResponse'),
198
- },
199
- },
200
- },
201
80
  preHandler: [fastify.authenticate],
202
81
  handler: authController.getMe,
203
82
  });
@@ -1,127 +1,27 @@
1
1
  /**
2
2
  * Resources Routes
3
- *
3
+ *
4
4
  * Fastify route definitions for resources endpoints.
5
- * Includes comprehensive Swagger documentation and rate limiting.
6
- *
7
- * @see /mnt/project/09-api-documentation-v2.md
5
+ * Includes rate limiting for security.
6
+ *
8
7
  * @see /mnt/project/11-rate-limiting-v2.md
9
8
  */
10
9
 
11
10
  import type { FastifyInstance } from 'fastify';
12
- import { toJsonSchema, getDefinition } from '@/libs/swagger-schemas';
13
11
  import * as resourceController from './resources.controller';
14
- import {
15
- CreateResourceSchema,
16
- UpdateResourceSchema,
17
- ResourceFiltersSchema,
18
- PaginationSchema,
19
- ResourceResponseSchema,
20
- ResourceWithOwnerResponseSchema,
21
- } from './resources.schemas';
22
-
23
- /**
24
- * Error response schema for Swagger
25
- */
26
- const ErrorResponseSchema = {
27
- type: 'object',
28
- properties: {
29
- success: { type: 'boolean', enum: [false] },
30
- error: {
31
- type: 'object',
32
- properties: {
33
- code: { type: 'string' },
34
- message: { type: 'string' },
35
- },
36
- },
37
- },
38
- };
39
-
40
- /**
41
- * Paginated resources response schema
42
- */
43
- const PaginatedResourcesResponseSchema = {
44
- type: 'object',
45
- properties: {
46
- success: { type: 'boolean', enum: [true] },
47
- message: { type: 'string' },
48
- data: {
49
- type: 'object',
50
- properties: {
51
- items: {
52
- type: 'array',
53
- items: getDefinition(ResourceResponseSchema, 'ResourceResponseSchema'),
54
- },
55
- pagination: {
56
- type: 'object',
57
- properties: {
58
- page: { type: 'integer' },
59
- limit: { type: 'integer' },
60
- totalItems: { type: 'integer' },
61
- totalPages: { type: 'integer' },
62
- hasNextPage: { type: 'boolean' },
63
- hasPreviousPage: { type: 'boolean' },
64
- },
65
- },
66
- },
67
- },
68
- },
69
- };
70
-
71
- /**
72
- * Single resource response schema
73
- */
74
- const ResourceSuccessResponseSchema = {
75
- type: 'object',
76
- properties: {
77
- success: { type: 'boolean', enum: [true] },
78
- message: { type: 'string' },
79
- data: getDefinition(ResourceResponseSchema, 'ResourceResponseSchema'),
80
- },
81
- };
82
-
83
- /**
84
- * Resource with owner response schema
85
- */
86
- const ResourceWithOwnerSuccessResponseSchema = {
87
- type: 'object',
88
- properties: {
89
- success: { type: 'boolean', enum: [true] },
90
- message: { type: 'string' },
91
- data: getDefinition(ResourceWithOwnerResponseSchema, 'ResourceWithOwnerResponseSchema'),
92
- },
93
- };
94
12
 
95
13
  /**
96
14
  * Register resources routes
97
- *
15
+ *
98
16
  * @param fastify - Fastify instance
99
17
  */
100
18
  export async function resourceRoutes(fastify: FastifyInstance): Promise<void> {
101
19
  /**
102
20
  * GET /resources
103
- *
21
+ *
104
22
  * Get paginated list of resources with optional filters
105
23
  */
106
24
  fastify.get('/', {
107
- schema: {
108
- description: 'Get paginated list of resources with optional filters',
109
- tags: ['resources'],
110
- summary: 'List resources',
111
- querystring: {
112
- type: 'object',
113
- properties: {
114
- ...(toJsonSchema(ResourceFiltersSchema, 'ResourceFiltersSchema') as any).properties,
115
- ...(toJsonSchema(PaginationSchema, 'PaginationSchema') as any).properties,
116
- },
117
- },
118
- response: {
119
- 200: {
120
- description: 'Resources retrieved successfully',
121
- ...PaginatedResourcesResponseSchema,
122
- },
123
- },
124
- },
125
25
  config: {
126
26
  rateLimit: {
127
27
  max: 100,
@@ -133,28 +33,11 @@ export async function resourceRoutes(fastify: FastifyInstance): Promise<void> {
133
33
 
134
34
  /**
135
35
  * GET /resources/my
136
- *
36
+ *
137
37
  * Get current user's resources
138
38
  * Requires authentication
139
39
  */
140
40
  fastify.get('/my', {
141
- schema: {
142
- description: "Get current user's resources",
143
- tags: ['resources'],
144
- summary: 'Get my resources',
145
- security: [{ bearerAuth: [] }],
146
- querystring: toJsonSchema(PaginationSchema, 'PaginationSchema'),
147
- response: {
148
- 200: {
149
- description: 'User resources retrieved successfully',
150
- ...PaginatedResourcesResponseSchema,
151
- },
152
- 401: {
153
- description: 'Unauthorized - Invalid or missing token',
154
- ...ErrorResponseSchema,
155
- },
156
- },
157
- },
158
41
  config: {
159
42
  rateLimit: {
160
43
  max: 1000,
@@ -167,36 +50,10 @@ export async function resourceRoutes(fastify: FastifyInstance): Promise<void> {
167
50
 
168
51
  /**
169
52
  * GET /resources/:id
170
- *
53
+ *
171
54
  * Get single resource by ID with owner information
172
55
  */
173
56
  fastify.get('/:id', {
174
- schema: {
175
- description: 'Get single resource by ID with owner information',
176
- tags: ['resources'],
177
- summary: 'Get resource by ID',
178
- params: {
179
- type: 'object',
180
- properties: {
181
- id: {
182
- type: 'string',
183
- format: 'uuid',
184
- description: 'Resource ID',
185
- },
186
- },
187
- required: ['id'],
188
- },
189
- response: {
190
- 200: {
191
- description: 'Resource retrieved successfully',
192
- ...ResourceWithOwnerSuccessResponseSchema,
193
- },
194
- 404: {
195
- description: 'Resource not found',
196
- ...ErrorResponseSchema,
197
- },
198
- },
199
- },
200
57
  config: {
201
58
  rateLimit: {
202
59
  max: 100,
@@ -208,32 +65,11 @@ export async function resourceRoutes(fastify: FastifyInstance): Promise<void> {
208
65
 
209
66
  /**
210
67
  * POST /resources
211
- *
68
+ *
212
69
  * Create a new resource
213
70
  * Requires authentication
214
71
  */
215
72
  fastify.post('/', {
216
- schema: {
217
- description: 'Create a new resource',
218
- tags: ['resources'],
219
- summary: 'Create resource',
220
- security: [{ bearerAuth: [] }],
221
- body: toJsonSchema(CreateResourceSchema, 'CreateResourceRequest'),
222
- response: {
223
- 201: {
224
- description: 'Resource created successfully',
225
- ...ResourceSuccessResponseSchema,
226
- },
227
- 400: {
228
- description: 'Validation error',
229
- ...ErrorResponseSchema,
230
- },
231
- 401: {
232
- description: 'Unauthorized - Invalid or missing token',
233
- ...ErrorResponseSchema,
234
- },
235
- },
236
- },
237
73
  config: {
238
74
  rateLimit: {
239
75
  max: 1000,
@@ -246,51 +82,11 @@ export async function resourceRoutes(fastify: FastifyInstance): Promise<void> {
246
82
 
247
83
  /**
248
84
  * PATCH /resources/:id
249
- *
85
+ *
250
86
  * Update a resource (owner only)
251
87
  * Requires authentication
252
88
  */
253
89
  fastify.patch('/:id', {
254
- schema: {
255
- description: 'Update a resource (owner only)',
256
- tags: ['resources'],
257
- summary: 'Update resource',
258
- security: [{ bearerAuth: [] }],
259
- params: {
260
- type: 'object',
261
- properties: {
262
- id: {
263
- type: 'string',
264
- format: 'uuid',
265
- description: 'Resource ID',
266
- },
267
- },
268
- required: ['id'],
269
- },
270
- body: toJsonSchema(UpdateResourceSchema, 'UpdateResourceRequest'),
271
- response: {
272
- 200: {
273
- description: 'Resource updated successfully',
274
- ...ResourceSuccessResponseSchema,
275
- },
276
- 400: {
277
- description: 'Validation error',
278
- ...ErrorResponseSchema,
279
- },
280
- 401: {
281
- description: 'Unauthorized - Invalid or missing token',
282
- ...ErrorResponseSchema,
283
- },
284
- 403: {
285
- description: 'Forbidden - You do not own this resource',
286
- ...ErrorResponseSchema,
287
- },
288
- 404: {
289
- description: 'Resource not found',
290
- ...ErrorResponseSchema,
291
- },
292
- },
293
- },
294
90
  config: {
295
91
  rateLimit: {
296
92
  max: 1000,
@@ -303,46 +99,11 @@ export async function resourceRoutes(fastify: FastifyInstance): Promise<void> {
303
99
 
304
100
  /**
305
101
  * DELETE /resources/:id
306
- *
102
+ *
307
103
  * Delete a resource (owner only, soft delete)
308
104
  * Requires authentication
309
105
  */
310
106
  fastify.delete('/:id', {
311
- schema: {
312
- description: 'Delete a resource (owner only, soft delete)',
313
- tags: ['resources'],
314
- summary: 'Delete resource',
315
- security: [{ bearerAuth: [] }],
316
- params: {
317
- type: 'object',
318
- properties: {
319
- id: {
320
- type: 'string',
321
- format: 'uuid',
322
- description: 'Resource ID',
323
- },
324
- },
325
- required: ['id'],
326
- },
327
- response: {
328
- 200: {
329
- description: 'Resource deleted successfully',
330
- ...ResourceSuccessResponseSchema,
331
- },
332
- 401: {
333
- description: 'Unauthorized - Invalid or missing token',
334
- ...ErrorResponseSchema,
335
- },
336
- 403: {
337
- description: 'Forbidden - You do not own this resource',
338
- ...ErrorResponseSchema,
339
- },
340
- 404: {
341
- description: 'Resource not found',
342
- ...ErrorResponseSchema,
343
- },
344
- },
345
- },
346
107
  config: {
347
108
  rateLimit: {
348
109
  max: 1000,
@@ -1,168 +0,0 @@
1
- ---
2
- trigger: always_on
3
- ---
4
-
5
- > **SCOPE**: These rules apply specifically to the **server** directory.
6
-
7
- # API Documentation
8
-
9
- ## Stack
10
-
11
- ```json
12
- {
13
- "dependencies": {
14
- "@fastify/swagger": "^8.12.0",
15
- "@fastify/swagger-ui": "^2.0.0",
16
- "zod-to-json-schema": "^3.22.0"
17
- }
18
- }
19
- ```
20
-
21
- ## Setup
22
-
23
- ```typescript
24
- // app.ts
25
- import swagger from '@fastify/swagger';
26
- import swaggerUI from '@fastify/swagger-ui';
27
-
28
- await app.register(swagger, {
29
- openapi: {
30
- info: {
31
- title: 'API Server',
32
- version: '1.0.0',
33
- },
34
- servers: [
35
- { url: 'http://localhost:3000', description: 'Development' },
36
- ],
37
- tags: [
38
- { name: 'auth', description: 'Authentication' },
39
- { name: 'resources', description: 'Resource operations' },
40
- ],
41
- components: {
42
- securitySchemes: {
43
- bearerAuth: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
44
- },
45
- },
46
- },
47
- });
48
-
49
- await app.register(swaggerUI, {
50
- routePrefix: '/docs',
51
- uiConfig: { docExpansion: 'list', deepLinking: true },
52
- });
53
- ```
54
-
55
- **Access:** `http://localhost:3000/docs`
56
-
57
- ## Route Documentation Pattern
58
-
59
- ```typescript
60
- // modules/resources/resources.schemas.ts
61
- import { z } from 'zod';
62
-
63
- export const CreateResourceSchema = z.object({
64
- title: z.string().min(1).max(200),
65
- price: z.number().positive(),
66
- });
67
-
68
- export const ResourceResponseSchema = z.object({
69
- success: z.literal(true),
70
- message: z.string(),
71
- data: z.object({
72
- id: z.string().uuid(),
73
- title: z.string(),
74
- price: z.number(),
75
- }),
76
- });
77
- ```
78
-
79
- ```typescript
80
- // modules/resources/resources.routes.ts
81
- import { zodToJsonSchema } from 'zod-to-json-schema';
82
- import * as schemas from './resources.schemas';
83
-
84
- app.post('/resources', {
85
- schema: {
86
- description: 'Create a new resource',
87
- tags: ['resources'],
88
- summary: 'Create resource',
89
- body: zodToJsonSchema(schemas.CreateResourceSchema, 'CreateResource'),
90
- response: {
91
- 201: zodToJsonSchema(schemas.ResourceResponseSchema, 'ResourceResponse'),
92
- 400: {
93
- description: 'Validation error',
94
- type: 'object',
95
- properties: {
96
- success: { type: 'boolean', enum: [false] },
97
- error: {
98
- type: 'object',
99
- properties: {
100
- code: { type: 'string' },
101
- message: { type: 'string' },
102
- },
103
- },
104
- },
105
- },
106
- },
107
- security: [{ bearerAuth: [] }],
108
- },
109
- handler: resourceController.createResource,
110
- });
111
- ```
112
-
113
- ## Document All Responses
114
-
115
- ```typescript
116
- response: {
117
- 200: successSchema,
118
- 400: validationErrorSchema,
119
- 401: unauthorizedSchema,
120
- 404: notFoundSchema,
121
- 500: internalErrorSchema,
122
- }
123
- ```
124
-
125
- ## Production Config
126
-
127
- ```typescript
128
- if (process.env.NODE_ENV === 'production') {
129
- // Option 1: Disable docs
130
- // Don't register swagger-ui
131
-
132
- // Option 2: Require auth for docs
133
- await app.register(swaggerUI, {
134
- routePrefix: '/docs',
135
- transformSpecification: (swaggerObject, request, reply) => {
136
- if (!request.headers.authorization) {
137
- reply.code(401).send({ error: 'Unauthorized' });
138
- }
139
- return swaggerObject;
140
- },
141
- });
142
- }
143
- ```
144
-
145
- ## Best Practices
146
-
147
- ### ✅ DO:
148
- - Use Zod schemas for all routes
149
- - Document all error responses
150
- - Add descriptions and summaries
151
- - Include security requirements
152
- - Tag routes by domain
153
-
154
- ### ❌ DON'T:
155
- - Skip documentation on routes
156
- - Forget error response schemas
157
- - Expose docs publicly in production
158
- - Use generic descriptions
159
-
160
- ## Checklist
161
-
162
- - [ ] Swagger and Swagger UI registered
163
- - [ ] All routes have schemas
164
- - [ ] Zod schemas converted to JSON Schema
165
- - [ ] Error responses documented
166
- - [ ] Tags used for grouping
167
- - [ ] Security requirements documented
168
- - [ ] Production docs secured