create-wabck 1.1.0 → 1.1.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.
package/README.md CHANGED
@@ -23,7 +23,7 @@ npm create wabck@latest my-api
23
23
  | šŸ” Auth | JWT, Clerk, Firebase, None |
24
24
  | āœ… Validation | Zod, Joi, Express Validator |
25
25
  | šŸ”— API Style | REST or GraphQL (Apollo Server 4) |
26
- | šŸ“– Docs | Swagger / OpenAPI 3 |
26
+ | šŸ“– Docs | Swagger UI + openapi.yaml (OpenAPI 3.0) |
27
27
  | 🐳 Docker | Multi-stage Dockerfile + docker-compose |
28
28
  | ⚔ Package managers | npm, pnpm, yarn, bun |
29
29
 
@@ -53,6 +53,7 @@ my-api/
53
53
  │ ā”œā”€ā”€ graphql/ (GraphQL only)
54
54
  │ ā”œā”€ā”€ app.js
55
55
  │ └── server.js
56
+ ā”œā”€ā”€ openapi.yaml (optional, OpenAPI 3.0 YAML spec)
56
57
  ā”œā”€ā”€ .env.example
57
58
  ā”œā”€ā”€ .prettierrc
58
59
  ā”œā”€ā”€ eslint.config.js
@@ -74,6 +75,7 @@ my-api/
74
75
  | POST | `/api/v1/auth/login` | Login (JWT) |
75
76
  | GET | `/api/v1/auth/me` | Profile (JWT) |
76
77
  | GET | `/api-docs` | Swagger UI (Interactive Docs) |
78
+ | GET | `/api-docs.yaml` | OpenAPI 3.0 YAML Spec |
77
79
  | GET | `/api-docs.json` | OpenAPI 3.0 JSON Spec |
78
80
 
79
81
  ## šŸ“œ License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-wabck",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Scaffold production-ready Express.js backends in seconds",
5
5
  "type": "module",
6
6
  "bin": {
package/src/generator.js CHANGED
@@ -94,6 +94,9 @@ export async function generate(options) {
94
94
  await write('.prettierrc', T.prettierrc());
95
95
  await write('eslint.config.js', T.eslintConfig(options));
96
96
  await write('README.md', T.readme(options));
97
+ if (hasSwagger) {
98
+ await write('openapi.yaml', T.swaggerYaml(options));
99
+ }
97
100
 
98
101
  // ── TypeScript extras ─────────────────────────────────────────────────
99
102
  if (isTS) {
package/src/index.js CHANGED
@@ -85,7 +85,7 @@ function printSuccessSummary(options, projectDir) {
85
85
  log.label(' Database', database === 'none' ? 'None' : database);
86
86
  log.label(' Auth', auth === 'none' ? 'None' : auth);
87
87
  if (validation && validation !== 'none') log.label(' Validation', validation);
88
- if (swagger) log.label(' API Docs', 'Swagger UI → /api-docs');
88
+ if (swagger) log.label(' OpenAPI Docs', 'Swagger UI → /api-docs (openapi.yaml)');
89
89
  if (docker) log.label(' Docker', 'Dockerfile + docker-compose.yml');
90
90
  log.blank();
91
91
 
@@ -103,7 +103,7 @@ export function server(options) {
103
103
  const dbImport = hasDB ? `import connectDB from './config/db.js';\n` : '';
104
104
  const dbConnect = hasDB ? ` await connectDB();\n` : '';
105
105
  const swaggerLog = hasSwagger
106
- ? ` console.log(\` āžœ Docs: http://localhost:\${PORT}/api-docs\`);\n`
106
+ ? ` console.log(\` āžœ Docs: http://localhost:\${PORT}/api-docs\`);\n console.log(\` āžœ OpenAPI: http://localhost:\${PORT}/api-docs.yaml (or openapi.yaml)\`);\n`
107
107
  : '';
108
108
 
109
109
  return `import 'dotenv/config';
@@ -346,7 +346,10 @@ ${pm} run dev
346
346
  \`\`\`
347
347
 
348
348
  The API will be available at **http://localhost:5000**
349
- ${swagger ? `\nšŸ“– **API Documentation (Swagger UI):** http://localhost:5000/api-docs\n` : ''}
349
+ ${swagger ? `\nšŸ“– **API Documentation:**
350
+ - **Swagger UI:** http://localhost:5000/api-docs
351
+ - **OpenAPI 3.0 YAML:** \`openapi.yaml\` or http://localhost:5000/api-docs.yaml
352
+ - **OpenAPI 3.0 JSON:** http://localhost:5000/api-docs.json\n` : ''}
350
353
  ## šŸ“ Project Structure
351
354
 
352
355
  \`\`\`
@@ -363,7 +366,7 @@ ${validation !== 'none' ? `│ ā”œā”€ā”€ validators/ # Input validation\n
363
366
  │ ā”œā”€ā”€ constants/ # App-wide constants
364
367
  │ ā”œā”€ā”€ app.${isTS ? 'ts' : 'js'} # Express app
365
368
  │ └── server.${isTS ? 'ts' : 'js'} # Entry point
366
- ā”œā”€ā”€ .env.example
369
+ ${swagger ? 'ā”œā”€ā”€ openapi.yaml # OpenAPI 3.0 specification (YAML)\n' : ''}ā”œā”€ā”€ .env.example
367
370
  ā”œā”€ā”€ .prettierrc
368
371
  └── eslint.config.js
369
372
  \`\`\`
@@ -376,7 +379,7 @@ ${validation !== 'none' ? `│ ā”œā”€ā”€ validators/ # Input validation\n
376
379
  | Database | ${database === 'none' ? '—' : database} |
377
380
  | Auth | ${auth === 'none' ? '—' : auth} |
378
381
  ${validation !== 'none' ? `| Validation | ${validation} |\n` : ''}| API Style | ${apiStyle === 'graphql' ? 'GraphQL (Apollo Server 4)' : 'REST'} |
379
- ${swagger ? '| API Docs | āœ” Swagger / OpenAPI 3.0 (/api-docs) |\n' : ''}| Docker | ${docker ? 'āœ” Dockerfile + docker-compose' : '—'} |
382
+ ${swagger ? '| API Docs | āœ” Swagger / OpenAPI 3.0 (/api-docs + openapi.yaml) |\n' : ''}| Docker | ${docker ? 'āœ” Dockerfile + docker-compose' : '—'} |
380
383
 
381
384
  ## šŸ”— Endpoints
382
385
 
@@ -390,7 +393,7 @@ ${swagger ? '| API Docs | āœ” Swagger / OpenAPI 3.0 (/api-docs)
390
393
  | PUT | \`/api/v1/users/:id\` | Update user |
391
394
  | DELETE | \`/api/v1/users/:id\` | Delete user |
392
395
  ${auth === 'jwt' ? `| POST | \`/api/v1/auth/register\` | Register |\n| POST | \`/api/v1/auth/login\` | Login |` : ''}
393
- ${swagger ? `| GET | \`/api-docs\` | Swagger UI (interactive) |\n| GET | \`/api-docs.json\` | Raw OpenAPI JSON spec |\n` : ''}
396
+ ${swagger ? `| GET | \`/api-docs\` | Swagger UI (interactive) |\n| GET | \`/api-docs.yaml\` | OpenAPI 3.0 YAML spec |\n| GET | \`/api-docs.json\` | OpenAPI 3.0 JSON spec |\n` : ''}
394
397
  ${docker ? `## 🐳 Docker\n\n\`\`\`bash\ndocker compose up --build\n\`\`\`\n` : ''}
395
398
  ${isTS ? `## šŸ— Build\n\n\`\`\`bash\n${pm} run build\n${pm} start\n\`\`\`\n` : ''}
396
399
  ## šŸ“œ License
@@ -1,5 +1,5 @@
1
1
  // ─────────────────────────────────────────────────────────────────────────────
2
- // Config Templates — db.js, env.js, swagger.js
2
+ // Config Templates — db.js & env.js
3
3
  // ─────────────────────────────────────────────────────────────────────────────
4
4
 
5
5
  /** Generate src/config/db.js or db.ts */
@@ -215,108 +215,3 @@ ${database === 'mongodb' ? " mongoUri: process.env.MONGODB_URI || '',\n" : '
215
215
  `;
216
216
  }
217
217
 
218
- /** Generate src/config/swagger.js or swagger.ts */
219
- export function swaggerConfig(options) {
220
- const { projectName, language } = options;
221
- const isTS = language === 'typescript';
222
- const ext = isTS ? 'ts' : 'js';
223
-
224
- return `import swaggerJsdoc from 'swagger-jsdoc';
225
- import swaggerUi from 'swagger-ui-express';
226
- import { readFileSync } from 'fs';
227
- import { fileURLToPath } from 'url';
228
- import path from 'path';
229
- ${isTS ? `import type { Express } from 'express';\n` : ''}
230
- const __filename = fileURLToPath(import.meta.url);
231
- const __dirname = path.dirname(__filename);
232
-
233
- // ─────────────────────────────────────────────────────────────────────────────
234
- // Swagger / OpenAPI 3.0 Configuration
235
- // ─────────────────────────────────────────────────────────────────────────────
236
-
237
- // Read version from package.json
238
- let version = '1.0.0';
239
- try {
240
- const pkg = JSON.parse(readFileSync(path.join(__dirname, '..', '..', 'package.json'), 'utf-8'));
241
- version = pkg.version;
242
- } catch { /* use default */ }
243
-
244
- const swaggerDefinition = {
245
- openapi: '3.0.0',
246
- info: {
247
- title: '${projectName} API',
248
- version,
249
- description: 'REST API documentation for ${projectName}',
250
- license: { name: 'MIT' },
251
- contact: { name: '${projectName} Team' },
252
- },
253
- servers: [
254
- { url: \`http://localhost:\${process.env.PORT || 5000}/api/v1\`, description: 'Development' },
255
- { url: '/api/v1', description: 'Relative (proxy-friendly)' },
256
- ],
257
- components: {
258
- securitySchemes: {
259
- bearerAuth: {
260
- type: 'http',
261
- scheme: 'bearer',
262
- bearerFormat: 'JWT',
263
- description: 'Enter your JWT token. Example: Bearer eyJhbGci...',
264
- },
265
- },
266
- schemas: {
267
- ApiResponse: {
268
- type: 'object',
269
- properties: {
270
- success: { type: 'boolean' },
271
- statusCode: { type: 'integer' },
272
- message: { type: 'string' },
273
- data: { },
274
- },
275
- },
276
- ApiError: {
277
- type: 'object',
278
- properties: {
279
- success: { type: 'boolean', example: false },
280
- statusCode: { type: 'integer' },
281
- message: { type: 'string' },
282
- errors: { type: 'array', items: { type: 'string' } },
283
- },
284
- },
285
- },
286
- },
287
- security: [{ bearerAuth: [] }],
288
- };
289
-
290
- const swaggerOptions = {
291
- definition: swaggerDefinition,
292
- // Scans all route files for @swagger JSDoc annotations
293
- apis: [
294
- path.join(__dirname, '../routes/*.js'),
295
- path.join(__dirname, '../routes/*.ts'),
296
- ],
297
- };
298
-
299
- export const swaggerSpec = swaggerJsdoc(swaggerOptions);
300
-
301
- /**
302
- * Mounts the Swagger UI at /api-docs
303
- * @param {${isTS ? 'Express' : 'import("express").Express'}} app
304
- */
305
- export function setupSwagger(app${isTS ? ': Express' : ''}) {
306
- app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec, {
307
- customSiteTitle: '${projectName} API Docs',
308
- swaggerOptions: {
309
- persistAuthorization: true,
310
- docExpansion: 'list',
311
- filter: true,
312
- },
313
- }));
314
-
315
- // Raw JSON spec endpoint (useful for Postman / code-gen)
316
- app.get('/api-docs.json', (_req, res) => {
317
- res.setHeader('Content-Type', 'application/json');
318
- res.send(swaggerSpec);
319
- });
320
- }
321
- `;
322
- }
@@ -16,9 +16,13 @@ export {
16
16
  export {
17
17
  db,
18
18
  envConfig,
19
- swaggerConfig,
20
19
  } from './config.js';
21
20
 
21
+ export {
22
+ swaggerConfig,
23
+ swaggerYaml,
24
+ } from './swagger.js';
25
+
22
26
 
23
27
  export {
24
28
  routesIndex,
@@ -0,0 +1,601 @@
1
+ // ─────────────────────────────────────────────────────────────────────────────
2
+ // Swagger / OpenAPI Templates — src/config/swagger.js/ts & openapi.yaml
3
+ // ─────────────────────────────────────────────────────────────────────────────
4
+
5
+ /** Generate src/config/swagger.js or src/config/swagger.ts */
6
+ export function swaggerConfig(options) {
7
+ const { projectName, language, auth } = options;
8
+ const isTS = language === 'typescript';
9
+ const hasJwt = auth === 'jwt';
10
+
11
+ return `import swaggerJsdoc from 'swagger-jsdoc';
12
+ import swaggerUi from 'swagger-ui-express';
13
+ import { readFileSync, existsSync } from 'fs';
14
+ import { fileURLToPath } from 'url';
15
+ import path from 'path';
16
+ ${isTS ? `import type { Express } from 'express';\n` : ''}
17
+ const __filename = fileURLToPath(import.meta.url);
18
+ const __dirname = path.dirname(__filename);
19
+
20
+ // ─────────────────────────────────────────────────────────────────────────────
21
+ // Production Swagger / OpenAPI 3.0 Specification
22
+ // ─────────────────────────────────────────────────────────────────────────────
23
+
24
+ // Dynamically read version from package.json
25
+ let version = '1.0.0';
26
+ try {
27
+ const pkgPath = path.resolve(__dirname, '../../package.json');
28
+ if (existsSync(pkgPath)) {
29
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
30
+ version = pkg.version || '1.0.0';
31
+ }
32
+ } catch { /* use fallback version */ }
33
+
34
+ const swaggerDefinition = {
35
+ openapi: '3.0.3',
36
+ info: {
37
+ title: '${projectName} API',
38
+ version,
39
+ description: 'Production-ready REST API documentation with interactive Swagger UI and OpenAPI 3.0 specification.',
40
+ license: {
41
+ name: 'MIT',
42
+ url: 'https://opensource.org/licenses/MIT',
43
+ },
44
+ contact: {
45
+ name: '${projectName} Team',
46
+ },
47
+ },
48
+ servers: [
49
+ {
50
+ url: \`http://localhost:\${process.env.PORT || 5000}/api/v1\`,
51
+ description: 'Local development server',
52
+ },
53
+ {
54
+ url: '/api/v1',
55
+ description: 'Current host / Reverse proxy relative path',
56
+ },
57
+ ],
58
+ tags: [
59
+ { name: 'Health', description: 'System health & diagnostic endpoints' },
60
+ { name: 'Users', description: 'User management and CRUD operations' },
61
+ ${hasJwt ? " { name: 'Auth', description: 'Authentication, sessions, and token issuance' },\n" : ''} ],
62
+ components: {
63
+ securitySchemes: {
64
+ bearerAuth: {
65
+ type: 'http',
66
+ scheme: 'bearer',
67
+ bearerFormat: 'JWT',
68
+ description: 'Provide your Bearer token in the format: \`Bearer <token>\`',
69
+ },
70
+ },
71
+ schemas: {
72
+ ApiResponse: {
73
+ type: 'object',
74
+ properties: {
75
+ success: { type: 'boolean', example: true },
76
+ statusCode: { type: 'integer', example: 200 },
77
+ message: { type: 'string', example: 'Success' },
78
+ data: { type: 'object' },
79
+ },
80
+ },
81
+ ApiError: {
82
+ type: 'object',
83
+ properties: {
84
+ success: { type: 'boolean', example: false },
85
+ statusCode: { type: 'integer', example: 400 },
86
+ message: { type: 'string', example: 'Validation or operation error' },
87
+ errors: { type: 'array', items: { type: 'string' } },
88
+ },
89
+ },
90
+ User: {
91
+ type: 'object',
92
+ properties: {
93
+ _id: { type: 'string', example: '661fae4e5bc24a1b8c9d0123' },
94
+ name: { type: 'string', example: 'Alex Mercer' },
95
+ email: { type: 'string', format: 'email', example: 'alex@example.com' },
96
+ role: { type: 'string', enum: ['user', 'admin'], example: 'user' },
97
+ isActive: { type: 'boolean', example: true },
98
+ createdAt: { type: 'string', format: 'date-time' },
99
+ updatedAt: { type: 'string', format: 'date-time' },
100
+ },
101
+ },
102
+ },
103
+ },
104
+ security: [
105
+ { bearerAuth: [] },
106
+ ],
107
+ };
108
+
109
+ const swaggerOptions = {
110
+ definition: swaggerDefinition,
111
+ apis: [
112
+ path.join(__dirname, '../routes/*.js'),
113
+ path.join(__dirname, '../routes/*.ts'),
114
+ ],
115
+ };
116
+
117
+ export const swaggerSpec = swaggerJsdoc(swaggerOptions);
118
+
119
+ /**
120
+ * Configure and mount Swagger UI and OpenAPI endpoints on the Express application.
121
+ * @param {${isTS ? 'Express' : 'import("express").Express'}} app
122
+ */
123
+ export function setupSwagger(app${isTS ? ': Express' : ''}) {
124
+ // Custom dark-accent styling for modern presentation
125
+ const customCss = \`
126
+ .swagger-ui .topbar { display: none }
127
+ .swagger-ui .info { margin: 25px 0 }
128
+ .swagger-ui .info .title { font-family: system-ui, sans-serif; font-weight: 700 }
129
+ .swagger-ui .scheme-container { background: #f8fafc; padding: 15px; border-radius: 8px; margin-bottom: 20px }
130
+ \`;
131
+
132
+ // Interactive Swagger UI
133
+ app.use(
134
+ '/api-docs',
135
+ swaggerUi.serve,
136
+ swaggerUi.setup(swaggerSpec, {
137
+ customSiteTitle: '${projectName} API Documentation',
138
+ customCss,
139
+ swaggerOptions: {
140
+ persistAuthorization: true,
141
+ docExpansion: 'list',
142
+ filter: true,
143
+ tryItOutEnabled: true,
144
+ displayRequestDuration: true,
145
+ },
146
+ })
147
+ );
148
+
149
+ // Raw OpenAPI 3.0 JSON specification (for Postman, Insomnia, or code generators)
150
+ app.get('/api-docs.json', (_req, res) => {
151
+ res.setHeader('Content-Type', 'application/json');
152
+ res.send(swaggerSpec);
153
+ });
154
+
155
+ // Raw OpenAPI 3.0 YAML specification file
156
+ app.get('/api-docs.yaml', (_req, res) => {
157
+ const yamlPath = path.resolve(__dirname, '../../openapi.yaml');
158
+ if (existsSync(yamlPath)) {
159
+ res.setHeader('Content-Type', 'text/yaml; charset=utf-8');
160
+ return res.sendFile(yamlPath);
161
+ }
162
+ // Fallback: send JSON representation if yaml file is relocated
163
+ res.setHeader('Content-Type', 'application/json');
164
+ res.send(swaggerSpec);
165
+ });
166
+ }
167
+ `;
168
+ }
169
+
170
+ /** Generate openapi.yaml for the root directory of the scaffolded project */
171
+ export function swaggerYaml(options) {
172
+ const { projectName, auth } = options;
173
+ const hasJwt = auth === 'jwt';
174
+
175
+ return `openapi: 3.0.3
176
+ info:
177
+ title: ${projectName} API
178
+ description: Production-grade REST API specification for ${projectName}. Auto-generated by wabck.
179
+ version: 1.0.0
180
+ license:
181
+ name: MIT
182
+ url: https://opensource.org/licenses/MIT
183
+ contact:
184
+ name: ${projectName} Team
185
+
186
+ servers:
187
+ - url: http://localhost:5000/api/v1
188
+ description: Local development server
189
+ - url: /api/v1
190
+ description: Current host / Reverse proxy relative path
191
+
192
+ tags:
193
+ - name: Health
194
+ description: System health & diagnostic endpoints
195
+ - name: Users
196
+ description: User management and CRUD operations
197
+ ${hasJwt ? ` - name: Auth
198
+ description: Authentication, sessions, and token issuance
199
+ ` : ''}
200
+ paths:
201
+ /health:
202
+ get:
203
+ tags:
204
+ - Health
205
+ summary: Health check & server diagnostics
206
+ description: Returns service uptime, memory metrics, runtime environment, and current version.
207
+ responses:
208
+ '200':
209
+ description: Service is healthy and responding
210
+ content:
211
+ application/json:
212
+ schema:
213
+ type: object
214
+ properties:
215
+ status:
216
+ type: string
217
+ example: ok
218
+ uptime:
219
+ type: integer
220
+ example: 120
221
+ version:
222
+ type: string
223
+ example: 1.0.0
224
+ env:
225
+ type: string
226
+ example: development
227
+ timestamp:
228
+ type: string
229
+ format: date-time
230
+ example: '2026-01-01T00:00:00.000Z'
231
+ memory:
232
+ type: object
233
+ properties:
234
+ used:
235
+ type: string
236
+ example: 32 MB
237
+ total:
238
+ type: string
239
+ example: 64 MB
240
+
241
+ /users:
242
+ get:
243
+ tags:
244
+ - Users
245
+ summary: Retrieve all users
246
+ description: Fetches a list of registered users.
247
+ responses:
248
+ '200':
249
+ description: Users retrieved successfully
250
+ content:
251
+ application/json:
252
+ schema:
253
+ type: object
254
+ properties:
255
+ success:
256
+ type: boolean
257
+ example: true
258
+ data:
259
+ type: array
260
+ items:
261
+ $ref: '#/components/schemas/User'
262
+ post:
263
+ tags:
264
+ - Users
265
+ summary: Create a new user
266
+ description: Adds a new user record to the database.
267
+ requestBody:
268
+ required: true
269
+ content:
270
+ application/json:
271
+ schema:
272
+ $ref: '#/components/schemas/CreateUserInput'
273
+ responses:
274
+ '201':
275
+ description: User created successfully
276
+ content:
277
+ application/json:
278
+ schema:
279
+ $ref: '#/components/schemas/ApiResponse'
280
+ '400':
281
+ description: Bad request or validation failure
282
+ content:
283
+ application/json:
284
+ schema:
285
+ $ref: '#/components/schemas/ApiError'
286
+
287
+ /users/{id}:
288
+ get:
289
+ tags:
290
+ - Users
291
+ summary: Get user by ID
292
+ parameters:
293
+ - name: id
294
+ in: path
295
+ required: true
296
+ description: Unique identifier of the user
297
+ schema:
298
+ type: string
299
+ responses:
300
+ '200':
301
+ description: User found
302
+ content:
303
+ application/json:
304
+ schema:
305
+ $ref: '#/components/schemas/ApiResponse'
306
+ '404':
307
+ description: User not found
308
+ content:
309
+ application/json:
310
+ schema:
311
+ $ref: '#/components/schemas/ApiError'
312
+ put:
313
+ tags:
314
+ - Users
315
+ summary: Update an existing user
316
+ parameters:
317
+ - name: id
318
+ in: path
319
+ required: true
320
+ description: Unique identifier of the user
321
+ schema:
322
+ type: string
323
+ requestBody:
324
+ required: true
325
+ content:
326
+ application/json:
327
+ schema:
328
+ $ref: '#/components/schemas/UpdateUserInput'
329
+ responses:
330
+ '200':
331
+ description: User updated successfully
332
+ content:
333
+ application/json:
334
+ schema:
335
+ $ref: '#/components/schemas/ApiResponse'
336
+ '404':
337
+ description: User not found
338
+ delete:
339
+ tags:
340
+ - Users
341
+ summary: Delete a user by ID
342
+ security:
343
+ - bearerAuth: []
344
+ parameters:
345
+ - name: id
346
+ in: path
347
+ required: true
348
+ description: Unique identifier of the user
349
+ schema:
350
+ type: string
351
+ responses:
352
+ '200':
353
+ description: User deleted successfully
354
+ content:
355
+ application/json:
356
+ schema:
357
+ $ref: '#/components/schemas/ApiResponse'
358
+ '404':
359
+ description: User not found
360
+ ${hasJwt ? `
361
+ /auth/register:
362
+ post:
363
+ tags:
364
+ - Auth
365
+ summary: Register a new account
366
+ description: Creates a new user profile and returns access tokens.
367
+ requestBody:
368
+ required: true
369
+ content:
370
+ application/json:
371
+ schema:
372
+ $ref: '#/components/schemas/RegisterInput'
373
+ responses:
374
+ '201':
375
+ description: User successfully registered
376
+ content:
377
+ application/json:
378
+ schema:
379
+ $ref: '#/components/schemas/AuthResponse'
380
+ '400':
381
+ description: Validation error or email already in use
382
+ content:
383
+ application/json:
384
+ schema:
385
+ $ref: '#/components/schemas/ApiError'
386
+
387
+ /auth/login:
388
+ post:
389
+ tags:
390
+ - Auth
391
+ summary: Authenticate user & issue tokens
392
+ description: Validates email and password, issuing access & refresh tokens.
393
+ requestBody:
394
+ required: true
395
+ content:
396
+ application/json:
397
+ schema:
398
+ $ref: '#/components/schemas/LoginInput'
399
+ responses:
400
+ '200':
401
+ description: Login successful
402
+ content:
403
+ application/json:
404
+ schema:
405
+ $ref: '#/components/schemas/AuthResponse'
406
+ '401':
407
+ description: Invalid credentials
408
+ content:
409
+ application/json:
410
+ schema:
411
+ $ref: '#/components/schemas/ApiError'
412
+
413
+ /auth/logout:
414
+ post:
415
+ tags:
416
+ - Auth
417
+ summary: Invalidate user session
418
+ security:
419
+ - bearerAuth: []
420
+ responses:
421
+ '200':
422
+ description: Logged out successfully
423
+ content:
424
+ application/json:
425
+ schema:
426
+ $ref: '#/components/schemas/ApiResponse'
427
+
428
+ /auth/me:
429
+ get:
430
+ tags:
431
+ - Auth
432
+ summary: Retrieve current authenticated user profile
433
+ security:
434
+ - bearerAuth: []
435
+ responses:
436
+ '200':
437
+ description: Profile retrieved successfully
438
+ content:
439
+ application/json:
440
+ schema:
441
+ $ref: '#/components/schemas/ApiResponse'
442
+ '401':
443
+ description: Unauthorized
444
+ ` : ''}
445
+ components:
446
+ securitySchemes:
447
+ bearerAuth:
448
+ type: http
449
+ scheme: bearer
450
+ bearerFormat: JWT
451
+ description: Supply your JSON Web Token as 'Bearer <token>'
452
+
453
+ schemas:
454
+ ApiResponse:
455
+ type: object
456
+ properties:
457
+ success:
458
+ type: boolean
459
+ example: true
460
+ statusCode:
461
+ type: integer
462
+ example: 200
463
+ message:
464
+ type: string
465
+ example: Success
466
+ data:
467
+ type: object
468
+
469
+ ApiError:
470
+ type: object
471
+ properties:
472
+ success:
473
+ type: boolean
474
+ example: false
475
+ statusCode:
476
+ type: integer
477
+ example: 400
478
+ message:
479
+ type: string
480
+ example: Error occurred
481
+ errors:
482
+ type: array
483
+ items:
484
+ type: string
485
+
486
+ User:
487
+ type: object
488
+ properties:
489
+ _id:
490
+ type: string
491
+ example: 661fae4e5bc24a1b8c9d0123
492
+ name:
493
+ type: string
494
+ example: Alex Mercer
495
+ email:
496
+ type: string
497
+ format: email
498
+ example: alex@example.com
499
+ role:
500
+ type: string
501
+ enum: [user, admin]
502
+ example: user
503
+ isActive:
504
+ type: boolean
505
+ example: true
506
+ createdAt:
507
+ type: string
508
+ format: date-time
509
+ updatedAt:
510
+ type: string
511
+ format: date-time
512
+
513
+ CreateUserInput:
514
+ type: object
515
+ required:
516
+ - name
517
+ - email
518
+ - password
519
+ properties:
520
+ name:
521
+ type: string
522
+ example: Alex Mercer
523
+ email:
524
+ type: string
525
+ format: email
526
+ example: alex@example.com
527
+ password:
528
+ type: string
529
+ format: password
530
+ example: SecurePass123!
531
+
532
+ UpdateUserInput:
533
+ type: object
534
+ properties:
535
+ name:
536
+ type: string
537
+ example: Alex Mercer
538
+ email:
539
+ type: string
540
+ format: email
541
+ example: alex@example.com
542
+
543
+ RegisterInput:
544
+ type: object
545
+ required:
546
+ - name
547
+ - email
548
+ - password
549
+ properties:
550
+ name:
551
+ type: string
552
+ example: Jane Doe
553
+ email:
554
+ type: string
555
+ format: email
556
+ example: jane@example.com
557
+ password:
558
+ type: string
559
+ format: password
560
+ example: SecretPass123!
561
+
562
+ LoginInput:
563
+ type: object
564
+ required:
565
+ - email
566
+ - password
567
+ properties:
568
+ email:
569
+ type: string
570
+ format: email
571
+ example: jane@example.com
572
+ password:
573
+ type: string
574
+ format: password
575
+ example: SecretPass123!
576
+
577
+ AuthResponse:
578
+ type: object
579
+ properties:
580
+ success:
581
+ type: boolean
582
+ example: true
583
+ statusCode:
584
+ type: integer
585
+ example: 200
586
+ message:
587
+ type: string
588
+ example: Authenticated
589
+ data:
590
+ type: object
591
+ properties:
592
+ user:
593
+ $ref: '#/components/schemas/User'
594
+ accessToken:
595
+ type: string
596
+ example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
597
+ refreshToken:
598
+ type: string
599
+ example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
600
+ `;
601
+ }