create-charcole 2.0.4 → 2.2.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 (100) hide show
  1. package/CHANGELOG.md +290 -14
  2. package/README.md +258 -312
  3. package/bin/index.js +392 -55
  4. package/bin/lib/pkgManager.js +8 -25
  5. package/bin/lib/templateHandler.js +5 -42
  6. package/create-charcole-2.1.0.tgz +0 -0
  7. package/package.json +2 -2
  8. package/packages/swagger/BACKWARD_COMPATIBILITY.md +145 -0
  9. package/packages/swagger/CHANGELOG.md +404 -0
  10. package/packages/swagger/README.md +578 -0
  11. package/packages/swagger/charcole-swagger-1.0.0.tgz +0 -0
  12. package/packages/swagger/package-lock.json +1715 -0
  13. package/packages/swagger/package.json +44 -0
  14. package/packages/swagger/src/helpers.js +427 -0
  15. package/packages/swagger/src/index.d.ts +126 -0
  16. package/packages/swagger/src/index.js +12 -0
  17. package/packages/swagger/src/setup.js +100 -0
  18. package/template/js/.env.example +8 -0
  19. package/template/js/README.md +128 -5
  20. package/template/js/basePackage.json +11 -13
  21. package/template/js/src/app.js +8 -2
  22. package/template/js/src/config/swagger.config.js +15 -0
  23. package/template/js/src/lib/swagger/SWAGGER_GUIDE.md +561 -0
  24. package/template/js/src/modules/auth/auth.constants.js +3 -0
  25. package/template/js/src/modules/auth/auth.controller.js +29 -0
  26. package/template/js/src/modules/auth/auth.middlewares.js +19 -0
  27. package/template/js/src/modules/auth/auth.routes.js +131 -0
  28. package/template/js/src/modules/auth/auth.schemas.js +60 -0
  29. package/template/js/src/modules/auth/auth.service.js +67 -0
  30. package/template/js/src/modules/auth/package.json +6 -0
  31. package/template/js/src/modules/health/controller.js +104 -3
  32. package/template/js/src/modules/swagger/charcole-swagger-1.0.0.tgz +0 -0
  33. package/template/js/src/modules/swagger/package.json +5 -0
  34. package/template/js/src/repositories/user.repo.js +19 -0
  35. package/template/js/src/routes/index.js +25 -0
  36. package/template/js/src/routes/protected.js +57 -0
  37. package/template/ts/.env.example +8 -0
  38. package/template/ts/README.md +128 -5
  39. package/template/ts/basePackage.json +19 -15
  40. package/template/ts/build.js +46 -0
  41. package/template/ts/src/app.ts +12 -7
  42. package/template/ts/src/config/swagger.config.ts +30 -0
  43. package/template/ts/src/lib/swagger/SWAGGER_GUIDE.md +561 -0
  44. package/template/ts/src/middlewares/errorHandler.ts +15 -23
  45. package/template/ts/src/middlewares/requestLogger.ts +1 -1
  46. package/template/ts/src/middlewares/validateRequest.ts +1 -1
  47. package/template/ts/src/modules/auth/auth.constants.ts +6 -0
  48. package/template/ts/src/modules/auth/auth.controller.ts +32 -0
  49. package/template/ts/src/modules/auth/auth.middlewares.ts +46 -0
  50. package/template/ts/src/modules/auth/auth.routes.ts +52 -0
  51. package/template/ts/src/modules/auth/auth.schemas.ts +73 -0
  52. package/template/ts/src/modules/auth/auth.service.ts +106 -0
  53. package/template/ts/src/modules/auth/package.json +10 -0
  54. package/template/ts/src/modules/health/controller.ts +61 -45
  55. package/template/ts/src/modules/swagger/charcole-swagger-1.0.0.tgz +0 -0
  56. package/template/ts/src/modules/swagger/package.json +5 -0
  57. package/template/ts/src/repositories/user.repo.ts +33 -0
  58. package/template/ts/src/routes/index.ts +24 -0
  59. package/template/ts/src/routes/protected.ts +46 -0
  60. package/template/ts/src/server.ts +3 -4
  61. package/template/ts/src/utils/logger.ts +1 -1
  62. package/template/ts/tsconfig.json +14 -7
  63. package/tmpclaude-1049-cwd +1 -0
  64. package/tmpclaude-3e37-cwd +1 -0
  65. package/tmpclaude-4d73-cwd +1 -0
  66. package/tmpclaude-8a8e-cwd +1 -0
  67. package/template/js/ARCHITECTURE_DIAGRAMS.md +0 -283
  68. package/template/js/CHECKLIST.md +0 -279
  69. package/template/js/COMPLETE.md +0 -405
  70. package/template/js/ERROR_HANDLING.md +0 -393
  71. package/template/js/IMPLEMENTATION.md +0 -368
  72. package/template/js/IMPLEMENTATION_COMPLETE.md +0 -363
  73. package/template/js/INDEX.md +0 -290
  74. package/template/js/QUICK_REFERENCE.md +0 -270
  75. package/template/js/package.json +0 -28
  76. package/template/js/src/routes.js +0 -17
  77. package/template/js/test-api.js +0 -100
  78. package/template/ts/ARCHITECTURE_DIAGRAMS.md +0 -283
  79. package/template/ts/CHECKLIST.md +0 -279
  80. package/template/ts/COMPLETE.md +0 -405
  81. package/template/ts/ERROR_HANDLING.md +0 -393
  82. package/template/ts/IMPLEMENTATION.md +0 -368
  83. package/template/ts/IMPLEMENTATION_COMPLETE.md +0 -363
  84. package/template/ts/INDEX.md +0 -290
  85. package/template/ts/QUICK_REFERENCE.md +0 -270
  86. package/template/ts/package.json +0 -32
  87. package/template/ts/src/app.js +0 -75
  88. package/template/ts/src/config/constants.js +0 -20
  89. package/template/ts/src/config/env.js +0 -26
  90. package/template/ts/src/middlewares/errorHandler.js +0 -180
  91. package/template/ts/src/middlewares/requestLogger.js +0 -33
  92. package/template/ts/src/middlewares/validateRequest.js +0 -42
  93. package/template/ts/src/modules/health/controller.js +0 -50
  94. package/template/ts/src/routes.js +0 -17
  95. package/template/ts/src/routes.ts +0 -16
  96. package/template/ts/src/server.js +0 -38
  97. package/template/ts/src/utils/AppError.js +0 -182
  98. package/template/ts/src/utils/logger.js +0 -73
  99. package/template/ts/src/utils/response.js +0 -51
  100. package/template/ts/test-api.js +0 -100
@@ -0,0 +1,131 @@
1
+ import { Router } from "express";
2
+ import { AuthController } from "./auth.controller.js";
3
+
4
+ const router = Router();
5
+
6
+ /**
7
+ * @swagger
8
+ * /api/auth/register:
9
+ * post:
10
+ * summary: Register a new user
11
+ * description: Create a new user account with email and password
12
+ * tags:
13
+ * - Authentication
14
+ * requestBody:
15
+ * required: true
16
+ * content:
17
+ * application/json:
18
+ * schema:
19
+ * type: object
20
+ * required:
21
+ * - email
22
+ * - password
23
+ * - name
24
+ * properties:
25
+ * email:
26
+ * type: string
27
+ * format: email
28
+ * example: user@example.com
29
+ * password:
30
+ * type: string
31
+ * format: password
32
+ * minLength: 8
33
+ * example: SecurePassword123
34
+ * name:
35
+ * type: string
36
+ * example: John Doe
37
+ * responses:
38
+ * 201:
39
+ * description: User registered successfully
40
+ * content:
41
+ * application/json:
42
+ * schema:
43
+ * type: object
44
+ * properties:
45
+ * success:
46
+ * type: boolean
47
+ * example: true
48
+ * message:
49
+ * type: string
50
+ * example: User registered successfully
51
+ * data:
52
+ * type: object
53
+ * properties:
54
+ * id:
55
+ * type: string
56
+ * example: user_123abc
57
+ * email:
58
+ * type: string
59
+ * example: user@example.com
60
+ * token:
61
+ * type: string
62
+ * example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
63
+ * 400:
64
+ * description: Validation error or user already exists
65
+ * 500:
66
+ * description: Internal server error
67
+ */
68
+ router.post("/register", AuthController.register);
69
+
70
+ /**
71
+ * @swagger
72
+ * /api/auth/login:
73
+ * post:
74
+ * summary: Login user
75
+ * description: Authenticate user with email and password
76
+ * tags:
77
+ * - Authentication
78
+ * requestBody:
79
+ * required: true
80
+ * content:
81
+ * application/json:
82
+ * schema:
83
+ * type: object
84
+ * required:
85
+ * - email
86
+ * - password
87
+ * properties:
88
+ * email:
89
+ * type: string
90
+ * format: email
91
+ * example: user@example.com
92
+ * password:
93
+ * type: string
94
+ * format: password
95
+ * example: SecurePassword123
96
+ * responses:
97
+ * 200:
98
+ * description: Login successful
99
+ * content:
100
+ * application/json:
101
+ * schema:
102
+ * type: object
103
+ * properties:
104
+ * success:
105
+ * type: boolean
106
+ * example: true
107
+ * message:
108
+ * type: string
109
+ * example: Login successful
110
+ * data:
111
+ * type: object
112
+ * properties:
113
+ * id:
114
+ * type: string
115
+ * example: user_123abc
116
+ * email:
117
+ * type: string
118
+ * example: user@example.com
119
+ * token:
120
+ * type: string
121
+ * example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
122
+ * 401:
123
+ * description: Invalid credentials
124
+ * 400:
125
+ * description: Validation error
126
+ * 500:
127
+ * description: Internal server error
128
+ */
129
+ router.post("/login", AuthController.login);
130
+
131
+ export default router;
@@ -0,0 +1,60 @@
1
+ import { z } from "zod";
2
+ import { USER_ROLES, AUTH_PROVIDERS } from "./auth.constants.js";
3
+
4
+ export const emailSchema = z
5
+ .string()
6
+ .email("Invalid email address")
7
+ .toLowerCase();
8
+
9
+ export const passwordSchema = z
10
+ .string()
11
+ .min(8, "Password must be at least 8 characters")
12
+ .max(72, "Password too long");
13
+
14
+ export const userSchema = z.object({
15
+ id: z.string().uuid(),
16
+ email: emailSchema,
17
+ name: z.string().min(1).max(100),
18
+ role: z.enum(USER_ROLES).default("user"),
19
+ provider: z.enum(AUTH_PROVIDERS).default("credentials"),
20
+
21
+ passwordHash: z.string().optional(), // credentials only
22
+ isEmailVerified: z.boolean().default(false),
23
+
24
+ createdAt: z.date(),
25
+ updatedAt: z.date(),
26
+ });
27
+
28
+ export const registerSchema = z.object({
29
+ name: z.string().min(1, "Name is required"),
30
+ email: emailSchema,
31
+ password: passwordSchema,
32
+ });
33
+
34
+ export const loginSchema = z.object({
35
+ email: emailSchema,
36
+ password: z.string().min(1, "Password is required"),
37
+ });
38
+
39
+ export const jwtPayloadSchema = z.object({
40
+ sub: z.string().uuid(), // user id
41
+ email: emailSchema,
42
+ role: z.enum(USER_ROLES),
43
+ });
44
+
45
+ export const forgotPasswordSchema = z.object({
46
+ email: emailSchema,
47
+ });
48
+
49
+ export const resetPasswordSchema = z.object({
50
+ token: z.string().min(1),
51
+ newPassword: passwordSchema,
52
+ });
53
+
54
+ export const publicUserSchema = userSchema.omit({
55
+ passwordHash: true,
56
+ });
57
+
58
+ export const validate = (schema, data) => {
59
+ return schema.parse(data);
60
+ };
@@ -0,0 +1,67 @@
1
+ import bcrypt from "bcryptjs";
2
+ import jwt from "jsonwebtoken";
3
+ import { registerSchema, loginSchema } from "./auth.schemas.js";
4
+
5
+ const SALT_ROUNDS = 10;
6
+ const JWT_EXPIRES_IN = "7d";
7
+
8
+ export const AuthService = {
9
+ async hashPassword(password) {
10
+ return bcrypt.hash(password, SALT_ROUNDS);
11
+ },
12
+
13
+ async comparePassword(password, hash) {
14
+ return bcrypt.compare(password, hash);
15
+ },
16
+
17
+ signToken(payload) {
18
+ return jwt.sign(payload, process.env.JWT_SECRET, {
19
+ expiresIn: JWT_EXPIRES_IN,
20
+ });
21
+ },
22
+
23
+ async register(data, userRepo) {
24
+ const input = registerSchema.parse(data);
25
+
26
+ const existingUser = await userRepo.findByEmail(input.email);
27
+ if (existingUser) {
28
+ throw new Error("Email already in use");
29
+ }
30
+
31
+ const passwordHash = await this.hashPassword(input.password);
32
+
33
+ const user = await userRepo.create({
34
+ email: input.email,
35
+ name: input.name,
36
+ passwordHash,
37
+ });
38
+
39
+ return user;
40
+ },
41
+
42
+ async login(data, userRepo) {
43
+ const input = loginSchema.parse(data);
44
+
45
+ const user = await userRepo.findByEmail(input.email);
46
+ if (!user || !user.passwordHash) {
47
+ throw new Error("Invalid credentials");
48
+ }
49
+
50
+ const isValid = await this.comparePassword(
51
+ input.password,
52
+ user.passwordHash,
53
+ );
54
+
55
+ if (!isValid) {
56
+ throw new Error("Invalid credentials");
57
+ }
58
+
59
+ const token = this.signToken({
60
+ sub: user.id,
61
+ email: user.email,
62
+ role: user.role,
63
+ });
64
+
65
+ return { user, token };
66
+ },
67
+ };
@@ -0,0 +1,6 @@
1
+ {
2
+ "dependencies": {
3
+ "bcryptjs": "^3.0.3",
4
+ "jsonwebtoken": "^9.0.3"
5
+ }
6
+ }
@@ -3,8 +3,39 @@ import { sendSuccess } from "../../utils/response.js";
3
3
  import { asyncHandler } from "../../middlewares/errorHandler.js";
4
4
 
5
5
  /**
6
- * Health check endpoint
7
- * Always returns healthy status (ping endpoint)
6
+ * @swagger
7
+ * /api/health:
8
+ * get:
9
+ * summary: Health check endpoint
10
+ * description: Returns the health status of the API
11
+ * tags:
12
+ * - Health
13
+ * responses:
14
+ * 200:
15
+ * description: Service is healthy
16
+ * content:
17
+ * application/json:
18
+ * schema:
19
+ * type: object
20
+ * properties:
21
+ * success:
22
+ * type: boolean
23
+ * example: true
24
+ * message:
25
+ * type: string
26
+ * example: Service is healthy
27
+ * data:
28
+ * type: object
29
+ * properties:
30
+ * status:
31
+ * type: string
32
+ * example: healthy
33
+ * uptime:
34
+ * type: number
35
+ * example: 123.45
36
+ * timestamp:
37
+ * type: string
38
+ * format: date-time
8
39
  */
9
40
  export const getHealth = asyncHandler(async (req, res) => {
10
41
  sendSuccess(
@@ -30,8 +61,78 @@ export const createItemSchema = z.object({
30
61
  }),
31
62
  });
32
63
 
64
+ /**
65
+ * @swagger
66
+ * /api/items:
67
+ * post:
68
+ * summary: Create a new item
69
+ * description: Example endpoint demonstrating validation with Zod
70
+ * tags:
71
+ * - Items
72
+ * requestBody:
73
+ * required: true
74
+ * content:
75
+ * application/json:
76
+ * schema:
77
+ * type: object
78
+ * required:
79
+ * - name
80
+ * properties:
81
+ * name:
82
+ * type: string
83
+ * minLength: 1
84
+ * maxLength: 100
85
+ * example: My Item
86
+ * description:
87
+ * type: string
88
+ * example: This is an example item
89
+ * responses:
90
+ * 201:
91
+ * description: Item created successfully
92
+ * content:
93
+ * application/json:
94
+ * schema:
95
+ * type: object
96
+ * properties:
97
+ * success:
98
+ * type: boolean
99
+ * example: true
100
+ * message:
101
+ * type: string
102
+ * example: Item created successfully
103
+ * data:
104
+ * type: object
105
+ * properties:
106
+ * id:
107
+ * type: string
108
+ * example: abc123def
109
+ * name:
110
+ * type: string
111
+ * example: My Item
112
+ * description:
113
+ * type: string
114
+ * nullable: true
115
+ * example: This is an example item
116
+ * createdAt:
117
+ * type: string
118
+ * format: date-time
119
+ * 400:
120
+ * description: Validation error
121
+ * content:
122
+ * application/json:
123
+ * schema:
124
+ * type: object
125
+ * properties:
126
+ * success:
127
+ * type: boolean
128
+ * example: false
129
+ * message:
130
+ * type: string
131
+ * example: Validation failed
132
+ */
33
133
  export const createItem = asyncHandler(async (req, res) => {
34
- const { name, description } = req.validatedData.body;
134
+ const parsedData = createItemSchema.parse({ body: req.body });
135
+ const { name, description } = parsedData.body;
35
136
 
36
137
  // Simulate some async work
37
138
  await new Promise((resolve) => setTimeout(resolve, 10));
@@ -0,0 +1,5 @@
1
+ {
2
+ "dependencies": {
3
+ "@charcoles/swagger": "file:./charcole-swagger-1.0.0.tgz"
4
+ }
5
+ }
@@ -0,0 +1,19 @@
1
+ import { randomUUID } from "crypto";
2
+
3
+ const users = [];
4
+
5
+ export const userRepo = {
6
+ async findByEmail(email) {
7
+ return users.find((u) => u.email === email);
8
+ },
9
+
10
+ async create(data) {
11
+ const user = {
12
+ id: randomUUID(),
13
+ role: "user",
14
+ ...data,
15
+ };
16
+ users.push(user);
17
+ return user;
18
+ },
19
+ };
@@ -0,0 +1,25 @@
1
+ import { Router } from "express";
2
+ import {
3
+ getHealth,
4
+ createItem,
5
+ createItemSchema,
6
+ } from "../modules/health/controller.js";
7
+ import { validateRequest } from "../middlewares/validateRequest.js";
8
+ import { requireAuth } from "../modules/auth/auth.middlewares.js";
9
+ import protectedRoutes from "./protected.js";
10
+ import authRoutes from "../modules/auth/auth.routes.js";
11
+ const router = Router();
12
+
13
+ // Health check
14
+ router.get("/health", getHealth);
15
+
16
+ // Example: Create item with validation
17
+ router.post("/items", validateRequest(createItemSchema), createItem);
18
+
19
+ // 🔐 Auth routes
20
+ router.use("/auth", authRoutes);
21
+
22
+ // 🔐 Protected routes (REQUIRED BEARER TOKEN FOR THEM)
23
+ router.use("/protected", protectedRoutes);
24
+
25
+ export default router;
@@ -0,0 +1,57 @@
1
+ import { Router } from "express";
2
+ import { requireAuth } from "../modules/auth/auth.middlewares.js";
3
+
4
+ const router = Router();
5
+
6
+ /**
7
+ * @swagger
8
+ * /api/protected/me:
9
+ * get:
10
+ * summary: Get current user profile
11
+ * description: Returns the authenticated user's information
12
+ * tags:
13
+ * - Protected
14
+ * security:
15
+ * - bearerAuth: []
16
+ * responses:
17
+ * 200:
18
+ * description: User profile retrieved successfully
19
+ * content:
20
+ * application/json:
21
+ * schema:
22
+ * type: object
23
+ * properties:
24
+ * message:
25
+ * type: string
26
+ * example: You are authenticated
27
+ * user:
28
+ * type: object
29
+ * properties:
30
+ * id:
31
+ * type: string
32
+ * example: user_123abc
33
+ * email:
34
+ * type: string
35
+ * example: user@example.com
36
+ * 401:
37
+ * description: Unauthorized - Invalid or missing token
38
+ * content:
39
+ * application/json:
40
+ * schema:
41
+ * type: object
42
+ * properties:
43
+ * success:
44
+ * type: boolean
45
+ * example: false
46
+ * message:
47
+ * type: string
48
+ * example: Unauthorized
49
+ */
50
+ router.get("/me", requireAuth, (req, res) => {
51
+ res.json({
52
+ message: "You are authenticated",
53
+ user: req.user,
54
+ });
55
+ });
56
+
57
+ export default router;
@@ -1,8 +1,16 @@
1
+ # Server Configuration
1
2
  NODE_ENV=development
2
3
  PORT=3000
3
4
 
5
+ # Logging
4
6
  LOG_LEVEL=info
5
7
 
8
+ # CORS
6
9
  CORS_ORIGIN=*
7
10
 
11
+ # Request
8
12
  REQUEST_TIMEOUT=30000
13
+
14
+
15
+ # Authentication
16
+ JWT_SECRET=your-secret-key-here
@@ -8,11 +8,12 @@ Welcome! This guide will help you set up and start using the Charcole API framew
8
8
  2. [Project Structure](#project-structure)
9
9
  3. [Configuration](#configuration)
10
10
  4. [Creating Your First Endpoint](#creating-your-first-endpoint)
11
- 5. [Error Handling](#error-handling)
12
- 6. [Validation](#validation)
13
- 7. [Logging](#logging)
14
- 8. [Running Your API](#running-your-api)
15
- 9. [Troubleshooting](#troubleshooting)
11
+ 5. [API Documentation with Swagger](#api-documentation-with-swagger)
12
+ 6. [Error Handling](#error-handling)
13
+ 7. [Validation](#validation)
14
+ 8. [Logging](#logging)
15
+ 9. [Running Your API](#running-your-api)
16
+ 10. [Troubleshooting](#troubleshooting)
16
17
 
17
18
  ---
18
19
 
@@ -396,6 +397,128 @@ router.get("/users/:id", async (req, res) => {
396
397
 
397
398
  ---
398
399
 
400
+ ## 📖 API Documentation with Swagger
401
+
402
+ Your API comes with **automatic interactive documentation** powered by Swagger UI!
403
+
404
+ ### Accessing the Documentation
405
+
406
+ 1. Start your server: `npm run dev`
407
+ 2. Visit: **http://localhost:3000/api-docs**
408
+
409
+ You'll see all your APIs automatically documented and can test them directly from the browser!
410
+
411
+ ### How It Works
412
+
413
+ All built-in APIs are already documented. When you create new endpoints, simply add JSDoc comments with `@swagger` annotations:
414
+
415
+ ```typescript
416
+ /**
417
+ * @swagger
418
+ * /api/users:
419
+ * get:
420
+ * summary: Get all users
421
+ * tags:
422
+ * - Users
423
+ * responses:
424
+ * 200:
425
+ * description: Success
426
+ */
427
+ export const getAllUsers = asyncHandler(async (req: Request, res: Response) => {
428
+ // Your code here
429
+ });
430
+ ```
431
+
432
+ That's it! Your new endpoint will automatically appear in Swagger UI.
433
+
434
+ ### Quick Example: Documenting a POST Endpoint
435
+
436
+ ```typescript
437
+ /**
438
+ * @swagger
439
+ * /api/posts:
440
+ * post:
441
+ * summary: Create a new post
442
+ * tags:
443
+ * - Posts
444
+ * requestBody:
445
+ * required: true
446
+ * content:
447
+ * application/json:
448
+ * schema:
449
+ * type: object
450
+ * required:
451
+ * - title
452
+ * properties:
453
+ * title:
454
+ * type: string
455
+ * example: My First Post
456
+ * content:
457
+ * type: string
458
+ * example: This is the post content
459
+ * responses:
460
+ * 201:
461
+ * description: Post created successfully
462
+ * 400:
463
+ * description: Validation error
464
+ */
465
+ export const createPost = asyncHandler(async (req: Request, res: Response) => {
466
+ // Your implementation
467
+ });
468
+ ```
469
+
470
+ ### Protected Endpoints (with Authentication)
471
+
472
+ For endpoints that require authentication, add the `security` field:
473
+
474
+ ```typescript
475
+ /**
476
+ * @swagger
477
+ * /api/profile:
478
+ * get:
479
+ * summary: Get user profile
480
+ * tags:
481
+ * - Profile
482
+ * security:
483
+ * - bearerAuth: []
484
+ * responses:
485
+ * 200:
486
+ * description: Profile retrieved
487
+ * 401:
488
+ * description: Unauthorized
489
+ */
490
+ router.get("/profile", requireAuth, getProfile);
491
+ ```
492
+
493
+ ### 📘 Complete Guide
494
+
495
+ For comprehensive examples including:
496
+
497
+ - Path and query parameters
498
+ - File uploads
499
+ - Complex schemas
500
+ - Error responses
501
+ - CRUD operations
502
+
503
+ See the **[Complete Swagger Documentation Guide](src/lib/swagger/SWAGGER_GUIDE.md)**
504
+
505
+ ### Testing APIs in Swagger UI
506
+
507
+ 1. Open http://localhost:3000/api-docs
508
+ 2. Click on any endpoint to expand it
509
+ 3. Click "Try it out"
510
+ 4. Fill in the parameters
511
+ 5. Click "Execute"
512
+ 6. See the response!
513
+
514
+ For protected endpoints:
515
+
516
+ 1. Click the "Authorize" button at the top
517
+ 2. Enter your JWT token
518
+ 3. Now you can test protected endpoints
519
+
520
+ ---
521
+
399
522
  ## ✔️ Validation
400
523
 
401
524
  ### Zod Schema Basics