Files
pos-system/services/iam-service/src/docs/swagger.ts

611 lines
19 KiB
TypeScript

import { Application } from 'express';
import swaggerJSDoc from 'swagger-jsdoc';
import swaggerUi from 'swagger-ui-express';
import { appConfig } from '../config/app.config';
/**
* EN: Swagger/OpenAPI configuration for API documentation
* VI: Cấu hình Swagger/OpenAPI cho tài liệu API
*/
const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'Microservice Template API',
version: '1.0.0',
description: 'A production-ready microservice template with comprehensive features',
contact: {
name: 'Development Team',
email: 'dev@goodgo.com',
},
license: {
name: 'MIT',
url: 'https://opensource.org/licenses/MIT',
},
},
servers: [
{
url: 'http://localhost:{port}',
description: 'Development server',
variables: {
port: {
default: String(appConfig.port),
description: 'Port number for the development server',
},
},
},
{
url: 'https://api.example.com',
description: 'Production server',
},
],
components: {
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
description: 'JWT Authorization header using the Bearer scheme',
},
},
schemas: {
ApiResponse: {
type: 'object',
properties: {
success: {
type: 'boolean',
description: 'Indicates if the request was successful',
},
data: {
description: 'Response data (varies by endpoint)',
},
message: {
type: 'string',
description: 'Human-readable message',
},
timestamp: {
type: 'string',
format: 'date-time',
description: 'ISO 8601 timestamp of the response',
},
},
required: ['success', 'timestamp'],
},
ErrorResponse: {
type: 'object',
properties: {
success: {
type: 'boolean',
example: false,
},
error: {
type: 'object',
properties: {
code: {
type: 'string',
description: 'Error code for programmatic handling',
example: 'VALIDATION_ERROR',
},
message: {
type: 'string',
description: 'Human-readable error message',
example: 'Validation failed',
},
details: {
description: 'Additional error details (optional)',
},
},
required: ['code', 'message'],
},
timestamp: {
type: 'string',
format: 'date-time',
},
},
required: ['success', 'error', 'timestamp'],
},
RegisterRequest: {
type: 'object',
properties: {
email: { type: 'string', format: 'email', example: 'user@example.com' },
password: { type: 'string', minLength: 8, example: 'StrongP@ssw0rd!' },
username: { type: 'string', minLength: 3, example: 'johndoe' },
},
required: ['email', 'password'],
},
RegisterResponse: {
type: 'object',
properties: {
user: { $ref: '#/components/schemas/User' },
token: { type: 'string' },
},
},
LoginRequest: {
type: 'object',
properties: {
email: { type: 'string', format: 'email', example: 'user@example.com' },
password: { type: 'string', example: 'StrongP@ssw0rd!' },
},
required: ['email', 'password'],
},
LoginResponse: {
type: 'object',
properties: {
accessToken: { type: 'string' },
refreshToken: { type: 'string' },
user: { $ref: '#/components/schemas/User' },
},
},
User: {
type: 'object',
properties: {
id: { type: 'string', example: 'cuid12345' },
email: { type: 'string', format: 'email' },
username: { type: 'string' },
firstName: { type: 'string' },
lastName: { type: 'string' },
isActive: { type: 'boolean' },
isEmailVerified: { type: 'boolean' },
createdAt: { type: 'string', format: 'date-time' },
updatedAt: { type: 'string', format: 'date-time' },
},
},
CreateUserRequest: {
type: 'object',
properties: {
email: { type: 'string', format: 'email' },
username: { type: 'string' },
firstName: { type: 'string' },
lastName: { type: 'string' },
phone: { type: 'string' },
},
required: ['email'],
},
Organization: {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' },
domain: { type: 'string' },
isActive: { type: 'boolean' },
parentId: { type: 'string' },
createdAt: { type: 'string', format: 'date-time' },
updatedAt: { type: 'string', format: 'date-time' },
},
},
CreateOrganizationRequest: {
type: 'object',
properties: {
name: { type: 'string' },
domain: { type: 'string' },
parentId: { type: 'string' },
settings: { type: 'object' },
},
required: ['name'],
},
UpdateOrganizationRequest: {
type: 'object',
properties: {
name: { type: 'string' },
domain: { type: 'string' },
parentId: { type: 'string' },
settings: { type: 'object' },
isActive: { type: 'boolean' },
},
},
Group: {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' },
description: { type: 'string' },
organizationId: { type: 'string' },
isActive: { type: 'boolean' },
createdAt: { type: 'string', format: 'date-time' },
updatedAt: { type: 'string', format: 'date-time' },
},
},
CreateGroupRequest: {
type: 'object',
properties: {
name: { type: 'string' },
description: { type: 'string' },
organizationId: { type: 'string' },
},
required: ['name'],
},
UpdateGroupRequest: {
type: 'object',
properties: {
name: { type: 'string' },
description: { type: 'string' },
isActive: { type: 'boolean' },
},
},
UserProfile: {
type: 'object',
properties: {
id: { type: 'string' },
userId: { type: 'string' },
avatarUrl: { type: 'string' },
bio: { type: 'string' },
phoneNumber: { type: 'string' },
address: { type: 'string' },
preferences: { type: 'object' },
},
},
UpdateProfileRequest: {
type: 'object',
properties: {
firstName: { type: 'string' },
lastName: { type: 'string' },
phone: { type: 'string' },
avatarUrl: { type: 'string' },
preferences: { type: 'object' },
},
},
UpdateUserRequest: {
type: 'object',
properties: {
username: { type: 'string' },
email: { type: 'string', format: 'email' },
isActive: { type: 'boolean' },
organizationId: { type: 'string' },
},
},
AccessRequest: {
type: 'object',
properties: {
id: { type: 'string' },
resource: { type: 'string' },
action: { type: 'string' },
status: { type: 'string', enum: ['PENDING', 'APPROVED', 'REJECTED'] },
reason: { type: 'string' },
requesterId: { type: 'string' },
createdAt: { type: 'string', format: 'date-time' },
},
},
CreateAccessRequest: {
type: 'object',
properties: {
resource: { type: 'string' },
action: { type: 'string' },
reason: { type: 'string' },
expiresAt: { type: 'string', format: 'date-time' },
},
required: ['resource', 'action'],
},
AccessReview: {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' },
status: { type: 'string' },
type: { type: 'string' },
startDate: { type: 'string', format: 'date-time' },
endDate: { type: 'string', format: 'date-time' },
},
},
CreateAccessReviewRequest: {
type: 'object',
properties: {
name: { type: 'string' },
type: { type: 'string', enum: ['PERIODIC', 'ADHOC'] },
startDate: { type: 'string', format: 'date-time' },
endDate: { type: 'string', format: 'date-time' },
},
required: ['name', 'type'],
},
Policy: {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' },
type: { type: 'string' },
content: { type: 'object' },
isActive: { type: 'boolean' },
},
},
ComplianceReport: {
type: 'object',
properties: {
id: { type: 'string' },
type: { type: 'string' },
status: { type: 'string' },
generatedAt: { type: 'string', format: 'date-time' },
url: { type: 'string' },
},
},
GenerateComplianceReportRequest: {
type: 'object',
properties: {
type: { type: 'string' },
periodStart: { type: 'string', format: 'date-time' },
periodEnd: { type: 'string', format: 'date-time' },
},
required: ['type'],
},
Session: {
type: 'object',
properties: {
id: { type: 'string' },
userId: { type: 'string' },
deviceId: { type: 'string' },
deviceName: { type: 'string' },
ipAddress: { type: 'string' },
userAgent: { type: 'string' },
isActive: { type: 'boolean' },
expiresAt: { type: 'string', format: 'date-time' },
createdAt: { type: 'string', format: 'date-time' },
lastActivityAt: { type: 'string', format: 'date-time' },
},
},
Feature: {
type: 'object',
properties: {
id: {
type: 'string',
description: 'Unique identifier',
example: 'clh1x8qkq0000abcdefghijk',
},
name: {
type: 'string',
description: 'Unique feature name',
example: 'user-management',
},
title: {
type: 'string',
description: 'Human-readable title',
example: 'User Management',
},
description: {
type: 'string',
description: 'Detailed description',
example: 'Complete user management system',
},
config: {
type: 'object',
description: 'Feature-specific configuration',
example: { enabled: true, priority: 1 },
},
enabled: {
type: 'boolean',
description: 'Whether the feature is enabled',
example: true,
},
version: {
type: 'string',
description: 'Feature version',
example: '1.0.0',
},
tags: {
type: 'array',
items: { type: 'string' },
description: 'Categorization tags',
example: ['auth', 'users'],
},
createdAt: {
type: 'string',
format: 'date-time',
description: 'Creation timestamp',
},
updatedAt: {
type: 'string',
format: 'date-time',
description: 'Last update timestamp',
},
},
required: ['id', 'name', 'enabled', 'tags', 'createdAt', 'updatedAt'],
},
CreateFeatureRequest: {
type: 'object',
properties: {
name: {
type: 'string',
minLength: 1,
maxLength: 100,
description: 'Unique feature name',
example: 'new-feature',
},
title: {
type: 'string',
maxLength: 200,
description: 'Human-readable title',
example: 'New Feature',
},
description: {
type: 'string',
maxLength: 1000,
description: 'Detailed description',
example: 'A new feature for the system',
},
config: {
type: 'object',
description: 'Feature configuration',
example: { enabled: true },
},
tags: {
type: 'array',
items: { type: 'string' },
description: 'Categorization tags',
example: ['feature', 'new'],
},
},
required: ['name'],
},
UpdateFeatureRequest: {
type: 'object',
properties: {
title: {
type: 'string',
maxLength: 200,
description: 'Human-readable title',
},
description: {
type: 'string',
maxLength: 1000,
description: 'Detailed description',
},
config: {
type: 'object',
description: 'Feature configuration',
},
enabled: {
type: 'boolean',
description: 'Whether the feature is enabled',
},
tags: {
type: 'array',
items: { type: 'string' },
description: 'Categorization tags',
},
},
},
UserInfo: {
type: 'object',
properties: {
userId: {
type: 'string',
description: 'Unique user identifier',
example: 'user-123',
},
email: {
type: 'string',
format: 'email',
description: 'User email address',
example: 'user@example.com',
},
role: {
type: 'string',
description: 'User role',
example: 'admin',
enum: ['admin', 'user', 'moderator'],
},
iat: {
type: 'number',
description: 'Token issued at timestamp',
},
exp: {
type: 'number',
description: 'Token expiration timestamp',
},
},
required: ['userId', 'email', 'role'],
},
HealthResponse: {
type: 'object',
properties: {
success: { type: 'boolean', example: true },
data: {
type: 'object',
properties: {
status: { type: 'string', example: 'ok' },
timestamp: { type: 'string', format: 'date-time' },
},
},
timestamp: { type: 'string', format: 'date-time' },
},
},
ReadinessResponse: {
type: 'object',
properties: {
success: { type: 'boolean', example: true },
data: {
type: 'object',
properties: {
status: { type: 'string', example: 'ready' },
},
},
timestamp: { type: 'string', format: 'date-time' },
},
},
LivenessResponse: {
type: 'object',
properties: {
success: { type: 'boolean', example: true },
data: {
type: 'object',
properties: {
status: { type: 'string', example: 'live' },
},
},
timestamp: { type: 'string', format: 'date-time' },
},
},
},
},
security: [
{
bearerAuth: [],
},
],
},
apis: [
'./src/routes/*.ts',
'./src/modules/auth/*.routes.ts',
'./src/modules/session/*.routes.ts',
'./src/modules/oidc/*.routes.ts',
'./src/modules/rbac/*.routes.ts',
'./src/modules/mfa/*.routes.ts',
'./src/modules/identity/*.routes.ts',
'./src/modules/access/*.routes.ts',
'./src/modules/governance/*.routes.ts'
],
};
/**
* EN: Generate OpenAPI specification
* VI: Tạo OpenAPI specification
*/
const specs = swaggerJSDoc(options);
/**
* EN: Setup Swagger UI middleware
* VI: Thiết lập Swagger UI middleware
*/
export const setupSwagger = (app: Application, basePath: string = '/api-docs') => {
// EN: Swagger page
// VI: Trang Swagger
app.use(basePath, swaggerUi.serve, swaggerUi.setup(specs, {
explorer: true,
swaggerOptions: {
persistAuthorization: true,
displayRequestDuration: true,
docExpansion: 'none',
filter: true,
showExtensions: true,
showCommonExtensions: true,
syntaxHighlight: {
activate: true,
theme: 'arta',
},
},
customCss: `
.swagger-ui .topbar { display: none }
.swagger-ui .info .title { color: #3b4151 }
`,
customSiteTitle: 'Microservice Template API Documentation',
customfavIcon: '/favicon.ico',
}));
// EN: Swagger JSON endpoint
// VI: Endpoint Swagger JSON
app.get(`${basePath}.json`, (_req, res) => {
res.setHeader('Content-Type', 'application/json');
res.send(specs);
});
// EN: Swagger YAML endpoint
// VI: Endpoint Swagger YAML
app.get(`${basePath}.yaml`, (_req, res) => {
res.setHeader('Content-Type', 'application/yaml');
// Note: Would need yaml package for full YAML support
res.send(JSON.stringify(specs, null, 2));
});
console.log(`📚 Swagger documentation available at: http://localhost:${appConfig.port}${basePath}`);
};
export { specs };
export default specs;