@urbansolv/create-nestjs-app 1.0.2 → 1.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.
- package/dist/templates/nestjs-app/.editorconfig +12 -12
- package/dist/templates/nestjs-app/.env.example +24 -24
- package/dist/templates/nestjs-app/.eslintrc.js +25 -25
- package/dist/templates/nestjs-app/package.json +40 -30
- package/dist/templates/nestjs-app/prisma/schema.prisma +79 -79
- package/dist/templates/nestjs-app/prisma/seed.ts +153 -154
- package/dist/templates/nestjs-app/src/app.module.ts +68 -68
- package/dist/templates/nestjs-app/src/common/constants/permissions.constant.ts +27 -27
- package/dist/templates/nestjs-app/src/common/decorators/api-response.decorator.ts +44 -44
- package/dist/templates/nestjs-app/src/common/decorators/get-user.decorator.ts +11 -11
- package/dist/templates/nestjs-app/src/common/decorators/permissions.decorator.ts +5 -5
- package/dist/templates/nestjs-app/src/common/decorators/public.decorator.ts +4 -4
- package/dist/templates/nestjs-app/src/common/dto/api-response.dto.ts +21 -21
- package/dist/templates/nestjs-app/src/common/dto/pagination.dto.ts +33 -33
- package/dist/templates/nestjs-app/src/common/filters/http-exception.filter.ts +56 -56
- package/dist/templates/nestjs-app/src/common/guards/jwt-auth.guard.ts +32 -32
- package/dist/templates/nestjs-app/src/common/guards/permissions.guard.ts +53 -53
- package/dist/templates/nestjs-app/src/common/interceptors/logging.interceptor.ts +37 -37
- package/dist/templates/nestjs-app/src/common/interceptors/transform.interceptor.ts +55 -55
- package/dist/templates/nestjs-app/src/common/prisma/prisma.module.ts +9 -9
- package/dist/templates/nestjs-app/src/common/prisma/prisma.service.ts +46 -46
- package/dist/templates/nestjs-app/src/common/utils/password.util.ts +13 -13
- package/dist/templates/nestjs-app/src/config/app.config.ts +10 -10
- package/dist/templates/nestjs-app/src/config/database.config.ts +5 -5
- package/dist/templates/nestjs-app/src/config/env.validation.ts +30 -30
- package/dist/templates/nestjs-app/src/config/jwt.config.ts +8 -8
- package/dist/templates/nestjs-app/src/config/swagger.config.ts +6 -6
- package/dist/templates/nestjs-app/src/main.ts +94 -91
- package/dist/templates/nestjs-app/src/modules/auth/auth.module.ts +28 -27
- package/dist/templates/nestjs-app/src/modules/auth/auth.service.ts +180 -54
- package/dist/templates/nestjs-app/src/modules/auth/controllers/v1/auth.controller.ts +33 -33
- package/dist/templates/nestjs-app/src/modules/auth/{dto → core/dto}/auth-response.dto.ts +19 -19
- package/dist/templates/nestjs-app/src/modules/auth/core/dto/login-response.dto.ts +10 -0
- package/dist/templates/nestjs-app/src/modules/auth/{dto → core/dto}/login.dto.ts +15 -15
- package/dist/templates/nestjs-app/src/modules/auth/{dto → core/dto}/register.dto.ts +30 -30
- package/dist/templates/nestjs-app/src/modules/auth/{interfaces → core/interfaces}/jwt-payload.interface.ts +7 -7
- package/dist/templates/nestjs-app/src/modules/auth/{strategies → core/strategies}/jwt.strategy.ts +54 -54
- package/dist/templates/nestjs-app/src/modules/health/health.controller.ts +29 -29
- package/dist/templates/nestjs-app/src/modules/health/health.module.ts +7 -7
- package/dist/templates/nestjs-app/src/modules/users/controllers/v1/users.controller.ts +118 -114
- package/dist/templates/nestjs-app/src/modules/users/core/dto/change-position.dto.ts +9 -9
- package/dist/templates/nestjs-app/src/modules/users/core/dto/create-user.dto.ts +35 -35
- package/dist/templates/nestjs-app/src/modules/users/core/dto/manage-permissions.dto.ts +13 -13
- package/dist/templates/nestjs-app/src/modules/users/core/dto/update-user.dto.ts +30 -30
- package/dist/templates/nestjs-app/src/modules/users/core/dto/user-query.dto.ts +22 -22
- package/dist/templates/nestjs-app/src/modules/users/core/dto/user-response.dto.ts +32 -0
- package/dist/templates/nestjs-app/src/modules/users/core/entities/user.entity.ts +45 -45
- package/dist/templates/nestjs-app/src/modules/users/core/helpers/user-transform.helper.ts +31 -31
- package/dist/templates/nestjs-app/src/modules/users/users.module.ts +10 -10
- package/dist/templates/nestjs-app/src/modules/users/users.service.ts +340 -340
- package/package.json +2 -2
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import { Injectable, OnModuleInit, OnModuleDestroy, Logger } from '@nestjs/common';
|
|
2
|
-
import { PrismaClient } from '@prisma/client';
|
|
3
|
-
|
|
4
|
-
@Injectable()
|
|
5
|
-
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
|
|
6
|
-
private readonly logger = new Logger(PrismaService.name);
|
|
7
|
-
|
|
8
|
-
constructor() {
|
|
9
|
-
super({
|
|
10
|
-
log: [
|
|
11
|
-
{ level: 'query', emit: 'event' },
|
|
12
|
-
{ level: 'error', emit: 'stdout' },
|
|
13
|
-
{ level: 'warn', emit: 'stdout' },
|
|
14
|
-
],
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
async onModuleInit() {
|
|
19
|
-
await this.$connect();
|
|
20
|
-
this.logger.log('✅ Database connected successfully');
|
|
21
|
-
|
|
22
|
-
// Log queries in development
|
|
23
|
-
if (process.env.NODE_ENV === 'development') {
|
|
24
|
-
// @ts-ignore
|
|
25
|
-
this.$on('query', (e) => {
|
|
26
|
-
this.logger.debug(`Query: ${e.query}`);
|
|
27
|
-
this.logger.debug(`Duration: ${e.duration}ms`);
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async onModuleDestroy() {
|
|
33
|
-
await this.$disconnect();
|
|
34
|
-
this.logger.log('Database disconnected');
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async cleanDatabase() {
|
|
38
|
-
if (process.env.NODE_ENV === 'production') {
|
|
39
|
-
throw new Error('Cannot clean database in production');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const models = Reflect.ownKeys(this).filter((key) => key[0] !== '_');
|
|
43
|
-
|
|
44
|
-
return Promise.all(models.map((modelKey) => (this as any)[modelKey].deleteMany()));
|
|
45
|
-
}
|
|
46
|
-
}
|
|
1
|
+
import { Injectable, OnModuleInit, OnModuleDestroy, Logger } from '@nestjs/common';
|
|
2
|
+
import { PrismaClient } from '@prisma/client';
|
|
3
|
+
|
|
4
|
+
@Injectable()
|
|
5
|
+
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
|
|
6
|
+
private readonly logger = new Logger(PrismaService.name);
|
|
7
|
+
|
|
8
|
+
constructor() {
|
|
9
|
+
super({
|
|
10
|
+
log: [
|
|
11
|
+
{ level: 'query', emit: 'event' },
|
|
12
|
+
{ level: 'error', emit: 'stdout' },
|
|
13
|
+
{ level: 'warn', emit: 'stdout' },
|
|
14
|
+
],
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async onModuleInit() {
|
|
19
|
+
await this.$connect();
|
|
20
|
+
this.logger.log('✅ Database connected successfully');
|
|
21
|
+
|
|
22
|
+
// Log queries in development
|
|
23
|
+
if (process.env.NODE_ENV === 'development') {
|
|
24
|
+
// @ts-ignore
|
|
25
|
+
this.$on('query', (e) => {
|
|
26
|
+
this.logger.debug(`Query: ${e.query}`);
|
|
27
|
+
this.logger.debug(`Duration: ${e.duration}ms`);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async onModuleDestroy() {
|
|
33
|
+
await this.$disconnect();
|
|
34
|
+
this.logger.log('Database disconnected');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async cleanDatabase() {
|
|
38
|
+
if (process.env.NODE_ENV === 'production') {
|
|
39
|
+
throw new Error('Cannot clean database in production');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const models = Reflect.ownKeys(this).filter((key) => key[0] !== '_');
|
|
43
|
+
|
|
44
|
+
return Promise.all(models.map((modelKey) => (this as any)[modelKey].deleteMany()));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import * as bcrypt from '
|
|
2
|
-
|
|
3
|
-
export class PasswordUtil {
|
|
4
|
-
private static readonly SALT_ROUNDS = 10;
|
|
5
|
-
|
|
6
|
-
static async hash(password: string): Promise<string> {
|
|
7
|
-
return bcrypt.hash(password, this.SALT_ROUNDS);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
static async compare(password: string, hashedPassword: string): Promise<boolean> {
|
|
11
|
-
return bcrypt.compare(password, hashedPassword);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
1
|
+
import * as bcrypt from 'bcryptjs';
|
|
2
|
+
|
|
3
|
+
export class PasswordUtil {
|
|
4
|
+
private static readonly SALT_ROUNDS = 10;
|
|
5
|
+
|
|
6
|
+
static async hash(password: string): Promise<string> {
|
|
7
|
+
return bcrypt.hash(password, this.SALT_ROUNDS);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
static async compare(password: string, hashedPassword: string): Promise<boolean> {
|
|
11
|
+
return bcrypt.compare(password, hashedPassword);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { registerAs } from '@nestjs/config';
|
|
2
|
-
|
|
3
|
-
export default registerAs('app', () => ({
|
|
4
|
-
env: process.env.NODE_ENV || 'development',
|
|
5
|
-
port: parseInt(process.env.PORT, 10) || 3000,
|
|
6
|
-
name: process.env.APP_NAME,
|
|
7
|
-
apiPrefix: process.env.API_PREFIX || 'api',
|
|
8
|
-
apiVersion: process.env.API_VERSION || 'v1',
|
|
9
|
-
corsOrigin: process.env.CORS_ORIGIN || '*',
|
|
10
|
-
}));
|
|
1
|
+
import { registerAs } from '@nestjs/config';
|
|
2
|
+
|
|
3
|
+
export default registerAs('app', () => ({
|
|
4
|
+
env: process.env.NODE_ENV || 'development',
|
|
5
|
+
port: parseInt(process.env.PORT, 10) || 3000,
|
|
6
|
+
name: process.env.APP_NAME,
|
|
7
|
+
apiPrefix: process.env.API_PREFIX || 'api',
|
|
8
|
+
apiVersion: process.env.API_VERSION || 'v1',
|
|
9
|
+
corsOrigin: process.env.CORS_ORIGIN || '*',
|
|
10
|
+
}));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { registerAs } from '@nestjs/config';
|
|
2
|
-
|
|
3
|
-
export default registerAs('database', () => ({
|
|
4
|
-
url: process.env.DATABASE_URL,
|
|
5
|
-
}));
|
|
1
|
+
import { registerAs } from '@nestjs/config';
|
|
2
|
+
|
|
3
|
+
export default registerAs('database', () => ({
|
|
4
|
+
url: process.env.DATABASE_URL,
|
|
5
|
+
}));
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import * as Joi from 'joi';
|
|
2
|
-
|
|
3
|
-
export const validationSchema = Joi.object({
|
|
4
|
-
// Application
|
|
5
|
-
NODE_ENV: Joi.string()
|
|
6
|
-
.valid('development', 'production', 'test', 'staging')
|
|
7
|
-
.default('development'),
|
|
8
|
-
PORT: Joi.number().default(3000),
|
|
9
|
-
APP_NAME: Joi.string().required(),
|
|
10
|
-
|
|
11
|
-
// Database
|
|
12
|
-
DATABASE_URL: Joi.string().required(),
|
|
13
|
-
|
|
14
|
-
// JWT
|
|
15
|
-
JWT_SECRET: Joi.string().required(),
|
|
16
|
-
JWT_EXPIRATION: Joi.string().default('7d'),
|
|
17
|
-
JWT_REFRESH_SECRET: Joi.string().required(),
|
|
18
|
-
JWT_REFRESH_EXPIRATION: Joi.string().default('30d'),
|
|
19
|
-
|
|
20
|
-
// CORS
|
|
21
|
-
CORS_ORIGIN: Joi.string().default('*'),
|
|
22
|
-
|
|
23
|
-
// API
|
|
24
|
-
API_PREFIX: Joi.string().default('api'),
|
|
25
|
-
API_VERSION: Joi.string().default('v1'),
|
|
26
|
-
|
|
27
|
-
// Swagger
|
|
28
|
-
SWAGGER_ENABLED: Joi.boolean().default(true),
|
|
29
|
-
SWAGGER_PATH: Joi.string().default('api-docs'),
|
|
30
|
-
});
|
|
1
|
+
import * as Joi from 'joi';
|
|
2
|
+
|
|
3
|
+
export const validationSchema = Joi.object({
|
|
4
|
+
// Application
|
|
5
|
+
NODE_ENV: Joi.string()
|
|
6
|
+
.valid('development', 'production', 'test', 'staging')
|
|
7
|
+
.default('development'),
|
|
8
|
+
PORT: Joi.number().default(3000),
|
|
9
|
+
APP_NAME: Joi.string().required(),
|
|
10
|
+
|
|
11
|
+
// Database
|
|
12
|
+
DATABASE_URL: Joi.string().required(),
|
|
13
|
+
|
|
14
|
+
// JWT
|
|
15
|
+
JWT_SECRET: Joi.string().required(),
|
|
16
|
+
JWT_EXPIRATION: Joi.string().default('7d'),
|
|
17
|
+
JWT_REFRESH_SECRET: Joi.string().required(),
|
|
18
|
+
JWT_REFRESH_EXPIRATION: Joi.string().default('30d'),
|
|
19
|
+
|
|
20
|
+
// CORS
|
|
21
|
+
CORS_ORIGIN: Joi.string().default('*'),
|
|
22
|
+
|
|
23
|
+
// API
|
|
24
|
+
API_PREFIX: Joi.string().default('api'),
|
|
25
|
+
API_VERSION: Joi.string().default('v1'),
|
|
26
|
+
|
|
27
|
+
// Swagger
|
|
28
|
+
SWAGGER_ENABLED: Joi.boolean().default(true),
|
|
29
|
+
SWAGGER_PATH: Joi.string().default('api-docs'),
|
|
30
|
+
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { registerAs } from '@nestjs/config';
|
|
2
|
-
|
|
3
|
-
export default registerAs('jwt', () => ({
|
|
4
|
-
secret: process.env.JWT_SECRET,
|
|
5
|
-
expiresIn: process.env.JWT_EXPIRATION || '7d',
|
|
6
|
-
refreshSecret: process.env.JWT_REFRESH_SECRET,
|
|
7
|
-
refreshExpiresIn: process.env.JWT_REFRESH_EXPIRATION || '30d',
|
|
8
|
-
}));
|
|
1
|
+
import { registerAs } from '@nestjs/config';
|
|
2
|
+
|
|
3
|
+
export default registerAs('jwt', () => ({
|
|
4
|
+
secret: process.env.JWT_SECRET,
|
|
5
|
+
expiresIn: process.env.JWT_EXPIRATION || '7d',
|
|
6
|
+
refreshSecret: process.env.JWT_REFRESH_SECRET,
|
|
7
|
+
refreshExpiresIn: process.env.JWT_REFRESH_EXPIRATION || '30d',
|
|
8
|
+
}));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { registerAs } from '@nestjs/config';
|
|
2
|
-
|
|
3
|
-
export default registerAs('swagger', () => ({
|
|
4
|
-
enabled: process.env.SWAGGER_ENABLED === 'true',
|
|
5
|
-
path: process.env.SWAGGER_PATH || '
|
|
6
|
-
}));
|
|
1
|
+
import { registerAs } from '@nestjs/config';
|
|
2
|
+
|
|
3
|
+
export default registerAs('swagger', () => ({
|
|
4
|
+
enabled: process.env.SWAGGER_ENABLED === 'true',
|
|
5
|
+
path: process.env.SWAGGER_PATH || 'docs',
|
|
6
|
+
}));
|
|
@@ -1,91 +1,94 @@
|
|
|
1
|
-
import { NestFactory, Reflector } from '@nestjs/core';
|
|
2
|
-
import { ValidationPipe, VersioningType, ClassSerializerInterceptor } from '@nestjs/common';
|
|
3
|
-
import { ConfigService } from '@nestjs/config';
|
|
4
|
-
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
|
5
|
-
import { AppModule } from './app.module';
|
|
6
|
-
|
|
7
|
-
async function bootstrap() {
|
|
8
|
-
const app = await NestFactory.create(AppModule);
|
|
9
|
-
|
|
10
|
-
const configService = app.get(ConfigService);
|
|
11
|
-
|
|
12
|
-
// Get configurations
|
|
13
|
-
const port = configService.get<number>('app.port');
|
|
14
|
-
const apiPrefix = configService.get<string>('app.apiPrefix');
|
|
15
|
-
const corsOrigin = configService.get<string>('app.corsOrigin');
|
|
16
|
-
const swaggerEnabled = configService.get<boolean>('swagger.enabled');
|
|
17
|
-
const swaggerPath = configService.get<string>('swagger.path');
|
|
18
|
-
|
|
19
|
-
// Enable CORS
|
|
20
|
-
app.enableCors({
|
|
21
|
-
origin: corsOrigin,
|
|
22
|
-
credentials: true,
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// Global prefix
|
|
26
|
-
app.setGlobalPrefix(apiPrefix);
|
|
27
|
-
|
|
28
|
-
// API Versioning
|
|
29
|
-
app.enableVersioning({
|
|
30
|
-
type: VersioningType.URI,
|
|
31
|
-
defaultVersion: '1',
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// Global validation pipe
|
|
35
|
-
app.useGlobalPipes(
|
|
36
|
-
new ValidationPipe({
|
|
37
|
-
whitelist: true,
|
|
38
|
-
forbidNonWhitelisted: true,
|
|
39
|
-
transform: true,
|
|
40
|
-
transformOptions: {
|
|
41
|
-
enableImplicitConversion: true,
|
|
42
|
-
},
|
|
43
|
-
}),
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
// Class serializer for excluding fields (like password)
|
|
47
|
-
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
|
|
48
|
-
|
|
49
|
-
// Swagger Documentation
|
|
50
|
-
if (swaggerEnabled) {
|
|
51
|
-
const config = new DocumentBuilder()
|
|
52
|
-
.setTitle('Urbansolv API')
|
|
53
|
-
.setDescription('Urbansolv NestJS Backend API Documentation')
|
|
54
|
-
.setVersion('1.0')
|
|
55
|
-
.addBearerAuth(
|
|
56
|
-
{
|
|
57
|
-
type: 'http',
|
|
58
|
-
scheme: 'bearer',
|
|
59
|
-
bearerFormat: 'JWT',
|
|
60
|
-
name: 'JWT',
|
|
61
|
-
description: 'Enter JWT token',
|
|
62
|
-
in: 'header',
|
|
63
|
-
},
|
|
64
|
-
'JWT-auth',
|
|
65
|
-
)
|
|
66
|
-
.addTag('Authentication', 'Authentication endpoints')
|
|
67
|
-
.addTag('Users', 'User management endpoints')
|
|
68
|
-
.addTag('Health', 'Health check endpoints')
|
|
69
|
-
.build();
|
|
70
|
-
|
|
71
|
-
const document = SwaggerModule.createDocument(app, config);
|
|
72
|
-
SwaggerModule.setup(swaggerPath, app, document, {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
console.log(
|
|
87
|
-
console.log(
|
|
88
|
-
console.log(
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
1
|
+
import { NestFactory, Reflector } from '@nestjs/core';
|
|
2
|
+
import { ValidationPipe, VersioningType, ClassSerializerInterceptor } from '@nestjs/common';
|
|
3
|
+
import { ConfigService } from '@nestjs/config';
|
|
4
|
+
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
|
5
|
+
import { AppModule } from './app.module';
|
|
6
|
+
|
|
7
|
+
async function bootstrap() {
|
|
8
|
+
const app = await NestFactory.create(AppModule);
|
|
9
|
+
|
|
10
|
+
const configService = app.get(ConfigService);
|
|
11
|
+
|
|
12
|
+
// Get configurations
|
|
13
|
+
const port = configService.get<number>('app.port');
|
|
14
|
+
const apiPrefix = configService.get<string>('app.apiPrefix');
|
|
15
|
+
const corsOrigin = configService.get<string>('app.corsOrigin');
|
|
16
|
+
const swaggerEnabled = configService.get<boolean>('swagger.enabled');
|
|
17
|
+
const swaggerPath = configService.get<string>('swagger.path');
|
|
18
|
+
|
|
19
|
+
// Enable CORS
|
|
20
|
+
app.enableCors({
|
|
21
|
+
origin: corsOrigin,
|
|
22
|
+
credentials: true,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Global prefix
|
|
26
|
+
app.setGlobalPrefix(apiPrefix);
|
|
27
|
+
|
|
28
|
+
// API Versioning
|
|
29
|
+
app.enableVersioning({
|
|
30
|
+
type: VersioningType.URI,
|
|
31
|
+
defaultVersion: '1',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Global validation pipe
|
|
35
|
+
app.useGlobalPipes(
|
|
36
|
+
new ValidationPipe({
|
|
37
|
+
whitelist: true,
|
|
38
|
+
forbidNonWhitelisted: true,
|
|
39
|
+
transform: true,
|
|
40
|
+
transformOptions: {
|
|
41
|
+
enableImplicitConversion: true,
|
|
42
|
+
},
|
|
43
|
+
}),
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
// Class serializer for excluding fields (like password)
|
|
47
|
+
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
|
|
48
|
+
|
|
49
|
+
// Swagger Documentation
|
|
50
|
+
if (swaggerEnabled) {
|
|
51
|
+
const config = new DocumentBuilder()
|
|
52
|
+
.setTitle('Urbansolv API')
|
|
53
|
+
.setDescription('Urbansolv NestJS Backend API Documentation')
|
|
54
|
+
.setVersion('1.0')
|
|
55
|
+
.addBearerAuth(
|
|
56
|
+
{
|
|
57
|
+
type: 'http',
|
|
58
|
+
scheme: 'bearer',
|
|
59
|
+
bearerFormat: 'JWT',
|
|
60
|
+
name: 'JWT',
|
|
61
|
+
description: 'Enter JWT token',
|
|
62
|
+
in: 'header',
|
|
63
|
+
},
|
|
64
|
+
'JWT-auth',
|
|
65
|
+
)
|
|
66
|
+
.addTag('Authentication', 'Authentication endpoints')
|
|
67
|
+
.addTag('Users', 'User management endpoints')
|
|
68
|
+
.addTag('Health', 'Health check endpoints')
|
|
69
|
+
.build();
|
|
70
|
+
|
|
71
|
+
const document = SwaggerModule.createDocument(app, config);
|
|
72
|
+
SwaggerModule.setup(swaggerPath, app, document, {
|
|
73
|
+
useGlobalPrefix: true,
|
|
74
|
+
swaggerOptions: {
|
|
75
|
+
persistAuthorization: true,
|
|
76
|
+
tagsSorter: 'alpha',
|
|
77
|
+
operationsSorter: 'alpha',
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
console.log(`\n📚 Swagger documentation available at: http://localhost:${port}/${swaggerPath}\n`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
await app.listen(port);
|
|
85
|
+
|
|
86
|
+
console.log(`\n🚀 Application is running on: http://localhost:${port}/${apiPrefix}`);
|
|
87
|
+
console.log(`🌍 Environment: ${configService.get<string>('app.env')}`);
|
|
88
|
+
console.log(`📊 Health check: http://localhost:${port}/health`);
|
|
89
|
+
console.log(`🏓 Ping endpoint: http://localhost:${port}/ping\n`);
|
|
90
|
+
console.log(apiPrefix, swaggerPath, swaggerEnabled);
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
bootstrap();
|
|
@@ -1,27 +1,28 @@
|
|
|
1
|
-
import { Module } from '@nestjs/common';
|
|
2
|
-
import { JwtModule } from '@nestjs/jwt';
|
|
3
|
-
import { PassportModule } from '@nestjs/passport';
|
|
4
|
-
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
5
|
-
import { AuthService } from './auth.service';
|
|
6
|
-
import { AuthController } from './controllers/v1/auth.controller';
|
|
7
|
-
import { JwtStrategy } from './strategies/jwt.strategy';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { JwtModule } from '@nestjs/jwt';
|
|
3
|
+
import { PassportModule } from '@nestjs/passport';
|
|
4
|
+
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
5
|
+
import { AuthService } from './auth.service';
|
|
6
|
+
import { AuthController } from './controllers/v1/auth.controller';
|
|
7
|
+
import { JwtStrategy } from './core/strategies/jwt.strategy';
|
|
8
|
+
import type { StringValue } from 'ms';
|
|
9
|
+
|
|
10
|
+
@Module({
|
|
11
|
+
imports: [
|
|
12
|
+
PassportModule.register({ defaultStrategy: 'jwt' }),
|
|
13
|
+
JwtModule.registerAsync({
|
|
14
|
+
imports: [ConfigModule],
|
|
15
|
+
inject: [ConfigService],
|
|
16
|
+
useFactory: (configService: ConfigService) => ({
|
|
17
|
+
secret: configService.get<string>('jwt.secret'),
|
|
18
|
+
signOptions: {
|
|
19
|
+
expiresIn: configService.get('jwt.expiresIn', '7d') as StringValue,
|
|
20
|
+
},
|
|
21
|
+
}),
|
|
22
|
+
}),
|
|
23
|
+
],
|
|
24
|
+
controllers: [AuthController],
|
|
25
|
+
providers: [AuthService, JwtStrategy],
|
|
26
|
+
exports: [JwtStrategy, PassportModule, JwtModule],
|
|
27
|
+
})
|
|
28
|
+
export class AuthModule {}
|