nestforge-generator 0.3.0 → 0.4.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.
Files changed (137) hide show
  1. package/README.md +13 -1
  2. package/README.pt-BR.md +13 -1
  3. package/dist/features/auth-strategy.js +7 -7
  4. package/dist/features/dependencies.js +3 -3
  5. package/dist/features/language.js +1 -1
  6. package/dist/features/language.js.map +1 -1
  7. package/dist/features/markers.js +11 -11
  8. package/dist/features/markers.js.map +1 -1
  9. package/dist/generator.js +7 -1
  10. package/dist/generator.js.map +1 -1
  11. package/dist/index.js +4 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/project-name.js +50 -0
  14. package/dist/project-name.js.map +1 -0
  15. package/dist/prompts.js +12 -10
  16. package/dist/prompts.js.map +1 -1
  17. package/package.json +1 -1
  18. package/templates/drizzle/drizzle.config.ts +2 -2
  19. package/templates/drizzle/src/auth/auth.controller.ts +35 -35
  20. package/templates/drizzle/src/auth/auth.service.spec.ts +4 -4
  21. package/templates/drizzle/src/auth/auth.service.ts +9 -9
  22. package/templates/drizzle/src/auth/dto/forgot-password.dto.ts +2 -2
  23. package/templates/drizzle/src/auth/dto/login.dto.ts +3 -3
  24. package/templates/drizzle/src/auth/dto/register.dto.ts +4 -4
  25. package/templates/drizzle/src/auth/dto/reset-password.dto.ts +3 -3
  26. package/templates/drizzle/src/auth/guards/github-auth.guard.ts +2 -2
  27. package/templates/drizzle/src/auth/guards/google-auth.guard.ts +2 -2
  28. package/templates/drizzle/src/auth/guards/session-auth.guard.spec.ts +4 -4
  29. package/templates/drizzle/src/auth/guards/session-auth.guard.ts +2 -2
  30. package/templates/drizzle/src/auth/session.service.spec.ts +5 -5
  31. package/templates/drizzle/src/auth/session.service.ts +5 -5
  32. package/templates/drizzle/src/auth/strategies/github.strategy.ts +3 -3
  33. package/templates/drizzle/src/auth/token.service.ts +3 -3
  34. package/templates/drizzle/src/common/filters/http-exception.filter.ts +1 -1
  35. package/templates/drizzle/src/common/guards/permissions.guard.spec.ts +7 -7
  36. package/templates/drizzle/src/common/guards/roles.guard.spec.ts +4 -4
  37. package/templates/drizzle/src/common/middleware/csrf.middleware.spec.ts +5 -5
  38. package/templates/drizzle/src/common/middleware/csrf.middleware.ts +2 -2
  39. package/templates/drizzle/src/common/utils/avatar-storage.util.ts +2 -2
  40. package/templates/drizzle/src/config/env.validation.ts +1 -1
  41. package/templates/drizzle/src/database/seed.ts +4 -4
  42. package/templates/drizzle/src/health/health.controller.ts +2 -2
  43. package/templates/drizzle/src/health/indicators/drizzle-health.indicator.spec.ts +5 -5
  44. package/templates/drizzle/src/health/indicators/drizzle-health.indicator.ts +2 -2
  45. package/templates/drizzle/src/health/indicators/redis-health.indicator.spec.ts +5 -5
  46. package/templates/drizzle/src/health/indicators/redis-health.indicator.ts +3 -3
  47. package/templates/drizzle/src/mail/mail.processor.ts +4 -4
  48. package/templates/drizzle/src/mail/templates/email-templates.ts +7 -7
  49. package/templates/drizzle/src/metrics/metrics.service.ts +3 -3
  50. package/templates/drizzle/src/users/dto/create-user.dto.ts +5 -5
  51. package/templates/drizzle/src/users/dto/find-users-query.dto.ts +3 -3
  52. package/templates/drizzle/src/users/users.controller.ts +21 -21
  53. package/templates/drizzle/src/users/users.service.spec.ts +12 -12
  54. package/templates/drizzle/src/users/users.service.ts +4 -4
  55. package/templates/drizzle/test/auth.e2e-spec.ts +8 -8
  56. package/templates/drizzle/test/session-auth.e2e-spec.ts +9 -9
  57. package/templates/drizzle/test/users.e2e-spec.ts +18 -18
  58. package/templates/prisma/prisma/seed.ts +46 -46
  59. package/templates/prisma/src/auth/auth.controller.ts +35 -35
  60. package/templates/prisma/src/auth/auth.service.spec.ts +3 -3
  61. package/templates/prisma/src/auth/auth.service.ts +11 -11
  62. package/templates/prisma/src/auth/dto/forgot-password.dto.ts +2 -2
  63. package/templates/prisma/src/auth/dto/login.dto.ts +3 -3
  64. package/templates/prisma/src/auth/dto/register.dto.ts +4 -4
  65. package/templates/prisma/src/auth/dto/reset-password.dto.ts +3 -3
  66. package/templates/prisma/src/auth/guards/github-auth.guard.ts +10 -10
  67. package/templates/prisma/src/auth/guards/google-auth.guard.ts +10 -10
  68. package/templates/prisma/src/auth/guards/session-auth.guard.spec.ts +4 -4
  69. package/templates/prisma/src/auth/guards/session-auth.guard.ts +2 -2
  70. package/templates/prisma/src/auth/session.service.spec.ts +5 -5
  71. package/templates/prisma/src/auth/session.service.ts +5 -5
  72. package/templates/prisma/src/auth/strategies/github.strategy.ts +3 -3
  73. package/templates/prisma/src/auth/token.service.ts +2 -2
  74. package/templates/prisma/src/common/filters/http-exception.filter.ts +34 -34
  75. package/templates/prisma/src/common/guards/permissions.guard.spec.ts +7 -7
  76. package/templates/prisma/src/common/guards/roles.guard.spec.ts +4 -4
  77. package/templates/prisma/src/common/middleware/csrf.middleware.spec.ts +5 -5
  78. package/templates/prisma/src/common/middleware/csrf.middleware.ts +2 -2
  79. package/templates/prisma/src/common/utils/avatar-storage.util.ts +32 -32
  80. package/templates/prisma/src/config/env.validation.ts +1 -1
  81. package/templates/prisma/src/health/health.controller.ts +2 -2
  82. package/templates/prisma/src/health/indicators/prisma-health.indicator.spec.ts +4 -4
  83. package/templates/prisma/src/health/indicators/prisma-health.indicator.ts +1 -1
  84. package/templates/prisma/src/health/indicators/redis-health.indicator.spec.ts +5 -5
  85. package/templates/prisma/src/health/indicators/redis-health.indicator.ts +3 -3
  86. package/templates/prisma/src/mail/mail.processor.ts +4 -4
  87. package/templates/prisma/src/mail/templates/email-templates.ts +7 -7
  88. package/templates/prisma/src/metrics/metrics.service.ts +34 -34
  89. package/templates/prisma/src/users/dto/create-user.dto.ts +12 -12
  90. package/templates/prisma/src/users/dto/find-users-query.dto.ts +12 -12
  91. package/templates/prisma/src/users/users.controller.ts +21 -21
  92. package/templates/prisma/src/users/users.service.spec.ts +11 -11
  93. package/templates/prisma/src/users/users.service.ts +4 -4
  94. package/templates/prisma/test/auth.e2e-spec.ts +8 -8
  95. package/templates/prisma/test/session-auth.e2e-spec.ts +9 -9
  96. package/templates/prisma/test/users.e2e-spec.ts +14 -14
  97. package/templates/typeorm/src/auth/auth.controller.ts +35 -35
  98. package/templates/typeorm/src/auth/auth.service.spec.ts +4 -4
  99. package/templates/typeorm/src/auth/auth.service.ts +9 -9
  100. package/templates/typeorm/src/auth/dto/forgot-password.dto.ts +2 -2
  101. package/templates/typeorm/src/auth/dto/login.dto.ts +3 -3
  102. package/templates/typeorm/src/auth/dto/register.dto.ts +4 -4
  103. package/templates/typeorm/src/auth/dto/reset-password.dto.ts +3 -3
  104. package/templates/typeorm/src/auth/guards/github-auth.guard.ts +2 -2
  105. package/templates/typeorm/src/auth/guards/google-auth.guard.ts +2 -2
  106. package/templates/typeorm/src/auth/guards/session-auth.guard.spec.ts +4 -4
  107. package/templates/typeorm/src/auth/guards/session-auth.guard.ts +2 -2
  108. package/templates/typeorm/src/auth/session.service.spec.ts +5 -5
  109. package/templates/typeorm/src/auth/session.service.ts +5 -5
  110. package/templates/typeorm/src/auth/strategies/github.strategy.ts +3 -3
  111. package/templates/typeorm/src/auth/token.service.ts +3 -3
  112. package/templates/typeorm/src/common/filters/http-exception.filter.ts +1 -1
  113. package/templates/typeorm/src/common/guards/permissions.guard.spec.ts +7 -7
  114. package/templates/typeorm/src/common/guards/roles.guard.spec.ts +4 -4
  115. package/templates/typeorm/src/common/middleware/csrf.middleware.spec.ts +5 -5
  116. package/templates/typeorm/src/common/middleware/csrf.middleware.ts +2 -2
  117. package/templates/typeorm/src/common/utils/avatar-storage.util.ts +2 -2
  118. package/templates/typeorm/src/config/env.validation.ts +1 -1
  119. package/templates/typeorm/src/database/data-source.ts +2 -2
  120. package/templates/typeorm/src/database/seed.ts +3 -3
  121. package/templates/typeorm/src/database/typeorm-options.ts +2 -2
  122. package/templates/typeorm/src/health/health.controller.ts +2 -2
  123. package/templates/typeorm/src/health/indicators/redis-health.indicator.spec.ts +5 -5
  124. package/templates/typeorm/src/health/indicators/redis-health.indicator.ts +3 -3
  125. package/templates/typeorm/src/health/indicators/typeorm-health.indicator.spec.ts +4 -4
  126. package/templates/typeorm/src/health/indicators/typeorm-health.indicator.ts +2 -2
  127. package/templates/typeorm/src/mail/mail.processor.ts +4 -4
  128. package/templates/typeorm/src/mail/templates/email-templates.ts +7 -7
  129. package/templates/typeorm/src/metrics/metrics.service.ts +3 -3
  130. package/templates/typeorm/src/users/dto/create-user.dto.ts +5 -5
  131. package/templates/typeorm/src/users/dto/find-users-query.dto.ts +3 -3
  132. package/templates/typeorm/src/users/users.controller.ts +21 -21
  133. package/templates/typeorm/src/users/users.service.spec.ts +12 -12
  134. package/templates/typeorm/src/users/users.service.ts +4 -4
  135. package/templates/typeorm/test/auth.e2e-spec.ts +8 -8
  136. package/templates/typeorm/test/session-auth.e2e-spec.ts +9 -9
  137. package/templates/typeorm/test/users.e2e-spec.ts +18 -18
@@ -14,7 +14,7 @@ vi.mock('ioredis', () => ({
14
14
  })),
15
15
  }));
16
16
 
17
- // precisa ser importado depois do vi.mock, senão pega o ioredis real
17
+ // Must be imported after vi.mock; otherwise it loads the real ioredis package.
18
18
  const { RedisHealthIndicator } = await import('./redis-health.indicator');
19
19
 
20
20
  describe('RedisHealthIndicator', () => {
@@ -24,7 +24,7 @@ describe('RedisHealthIndicator', () => {
24
24
  disconnectMock.mockReset();
25
25
  });
26
26
 
27
- it('retorna status up quando o PING responde PONG', async () => {
27
+ it('returns an up status when PING returns PONG', async () => {
28
28
  connectMock.mockResolvedValue(undefined);
29
29
  pingMock.mockResolvedValue('PONG');
30
30
 
@@ -35,7 +35,7 @@ describe('RedisHealthIndicator', () => {
35
35
  expect(disconnectMock).toHaveBeenCalled();
36
36
  });
37
37
 
38
- it('lança HealthCheckError quando o PING não responde PONG', async () => {
38
+ it('throws HealthCheckError when PING does not return PONG', async () => {
39
39
  connectMock.mockResolvedValue(undefined);
40
40
  pingMock.mockResolvedValue('ALGO_INESPERADO');
41
41
 
@@ -44,11 +44,11 @@ describe('RedisHealthIndicator', () => {
44
44
  await expect(indicator.isHealthy('redis')).rejects.toBeInstanceOf(HealthCheckError);
45
45
  });
46
46
 
47
- it('lança HealthCheckError quando a conexão falha', async () => {
47
+ it('throws HealthCheckError when the connection fails', async () => {
48
48
  connectMock.mockRejectedValue(new Error('ECONNREFUSED'));
49
49
 
50
50
  const indicator = new RedisHealthIndicator();
51
51
 
52
52
  await expect(indicator.isHealthy('redis')).rejects.toBeInstanceOf(HealthCheckError);
53
53
  });
54
- });
54
+ });
@@ -18,16 +18,16 @@ export class RedisHealthIndicator {
18
18
  const response = await client.ping();
19
19
 
20
20
  if (response !== 'PONG') {
21
- throw new Error('Resposta inesperada do Redis');
21
+ throw new Error('Unexpected Redis response');
22
22
  }
23
23
 
24
24
  return { [key]: { status: 'up' } };
25
25
  } catch (error) {
26
- throw new HealthCheckError('Redis indisponível', {
26
+ throw new HealthCheckError('Redis unavailable', {
27
27
  [key]: { status: 'down', message: (error as Error).message },
28
28
  });
29
29
  } finally {
30
30
  client.disconnect();
31
31
  }
32
32
  }
33
- }
33
+ }
@@ -27,13 +27,13 @@ export class MailProcessor extends WorkerHost {
27
27
 
28
28
  switch (job.name) {
29
29
  case MailJob.VerifyEmail:
30
- await this.send(to, 'Confirme seu e-mail', verifyEmailTemplate(name, token));
30
+ await this.send(to, 'Confirm your email', verifyEmailTemplate(name, token));
31
31
  break;
32
32
  case MailJob.ResetPassword:
33
- await this.send(to, 'Redefinição de senha', resetPasswordTemplate(name, token));
33
+ await this.send(to, 'Password reset', resetPasswordTemplate(name, token));
34
34
  break;
35
35
  default:
36
- this.logger.warn(`Job de e-mail desconhecido: ${job.name}`);
36
+ this.logger.warn(`Unknown email job: ${job.name}`);
37
37
  }
38
38
  }
39
39
 
@@ -45,4 +45,4 @@ export class MailProcessor extends WorkerHost {
45
45
  html,
46
46
  });
47
47
  }
48
- }
48
+ }
@@ -6,10 +6,10 @@ export function verifyEmailTemplate(name: string, token: string): string {
6
6
 
7
7
  return `
8
8
  <div style="font-family: sans-serif; line-height: 1.5;">
9
- <h2>Olá, ${name}!</h2>
10
- <p>Confirme seu e-mail clicando no link abaixo:</p>
9
+ <h2>Hello, ${name}!</h2>
10
+ <p>Confirm your email by clicking the link below:</p>
11
11
  <p><a href="${link}">${link}</a></p>
12
- <p>Esse link expira em 24 horas.</p>
12
+ <p>This link expires in 24 hours.</p>
13
13
  </div>
14
14
  `;
15
15
  }
@@ -19,10 +19,10 @@ export function resetPasswordTemplate(name: string, token: string): string {
19
19
 
20
20
  return `
21
21
  <div style="font-family: sans-serif; line-height: 1.5;">
22
- <h2>Olá, ${name}!</h2>
23
- <p>Recebemos um pedido para redefinir sua senha. Clique no link abaixo para continuar:</p>
22
+ <h2>Hello, ${name}!</h2>
23
+ <p>We received a request to reset your password. Click the link below to continue:</p>
24
24
  <p><a href="${link}">${link}</a></p>
25
- <p>Se você não pediu isso, pode ignorar este e-mail. O link expira em 1 hora.</p>
25
+ <p>If you did not request this, you can ignore this email. The link expires in 1 hour.</p>
26
26
  </div>
27
27
  `;
28
- }
28
+ }
@@ -7,7 +7,7 @@ export class MetricsService {
7
7
 
8
8
  readonly httpRequestDuration = new client.Histogram({
9
9
  name: 'http_request_duration_seconds',
10
- help: 'Duração das requisições HTTP em segundos',
10
+ help: 'HTTP request duration in seconds',
11
11
  labelNames: ['method', 'route', 'status_code'],
12
12
  buckets: [0.05, 0.1, 0.3, 0.5, 1, 2, 5],
13
13
  registers: [this.registry],
@@ -15,7 +15,7 @@ export class MetricsService {
15
15
 
16
16
  readonly httpRequestsTotal = new client.Counter({
17
17
  name: 'http_requests_total',
18
- help: 'Total de requisições HTTP recebidas',
18
+ help: 'Total number of HTTP requests received',
19
19
  labelNames: ['method', 'route', 'status_code'],
20
20
  registers: [this.registry],
21
21
  });
@@ -31,4 +31,4 @@ export class MetricsService {
31
31
  getContentType(): string {
32
32
  return this.registry.contentType;
33
33
  }
34
- }
34
+ }
@@ -3,10 +3,10 @@ import { createZodDto } from 'nestjs-zod';
3
3
  import { Role } from '../../common/constants/role.enum';
4
4
 
5
5
  export const createUserSchema = z.object({
6
- name: z.string().min(2).describe('Nome completo'),
7
- email: z.string().email().describe('E-mail do usuário'),
8
- password: z.string().min(8).describe('Senha (mínimo 8 caracteres)'),
9
- role: z.nativeEnum(Role).optional().describe('Role do usuário (padrão: USER)'),
6
+ name: z.string().min(2).describe('Full name'),
7
+ email: z.string().email().describe('User email'),
8
+ password: z.string().min(8).describe('Password (minimum 8 characters)'),
9
+ role: z.nativeEnum(Role).optional().describe('User role (default: USER)'),
10
10
  });
11
11
 
12
- export class CreateUserDto extends createZodDto(createUserSchema) { }
12
+ export class CreateUserDto extends createZodDto(createUserSchema) { }
@@ -3,10 +3,10 @@ import { createZodDto } from 'nestjs-zod';
3
3
  import { Role } from '../../common/constants/role.enum';
4
4
 
5
5
  export const findUsersQuerySchema = z.object({
6
- page: z.coerce.number().int().min(1).default(1).describe('Página atual'),
7
- limit: z.coerce.number().int().min(1).max(100).default(10).describe('Itens por página (máx. 100)'),
6
+ page: z.coerce.number().int().min(1).default(1).describe('Current page'),
7
+ limit: z.coerce.number().int().min(1).max(100).default(10).describe('Items per page (maximum 100)'),
8
8
  search: z.string().optional().describe('Busca por nome ou e-mail'),
9
9
  role: z.nativeEnum(Role).optional().describe('Filtra por role'),
10
10
  });
11
11
 
12
- export class FindUsersQueryDto extends createZodDto(findUsersQuerySchema) { }
12
+ export class FindUsersQueryDto extends createZodDto(findUsersQuerySchema) { }
@@ -57,9 +57,9 @@ export class UsersController {
57
57
  @Permissions(Permission.UserCreate)
58
58
  // nestforge:feature:rbac:end
59
59
  // nestforge:feature:swagger
60
- @ApiOperation({ summary: 'Cria um usuário (requer permissão user:create)' })
61
- @ApiResponse({ status: 201, description: 'Usuário criado', schema: { example: USER_EXAMPLE } })
62
- @ApiResponse({ status: 403, description: 'Sem a permissão user:create', schema: { example: FORBIDDEN_EXAMPLE } })
60
+ @ApiOperation({ summary: 'Creates a user (requires the user:create permission)' })
61
+ @ApiResponse({ status: 201, description: 'User created', schema: { example: USER_EXAMPLE } })
62
+ @ApiResponse({ status: 403, description: 'Missing the user:create permission', schema: { example: FORBIDDEN_EXAMPLE } })
63
63
  // nestforge:feature:swagger:end
64
64
  create(@Body() dto: CreateUserDto) {
65
65
  return this.usersService.create(dto);
@@ -70,10 +70,10 @@ export class UsersController {
70
70
  @Permissions(Permission.UserRead)
71
71
  // nestforge:feature:rbac:end
72
72
  // nestforge:feature:swagger
73
- @ApiOperation({ summary: 'Lista usuários com paginação e filtros (requer permissão user:read)' })
73
+ @ApiOperation({ summary: 'Lists users with pagination and filters (requires the user:read permission)' })
74
74
  @ApiResponse({
75
75
  status: 200,
76
- description: 'Lista paginada',
76
+ description: 'Paginated list',
77
77
  schema: {
78
78
  example: {
79
79
  data: [USER_EXAMPLE],
@@ -88,8 +88,8 @@ export class UsersController {
88
88
 
89
89
  @Get('me')
90
90
  // nestforge:feature:swagger
91
- @ApiOperation({ summary: 'Retorna o usuário autenticado' })
92
- @ApiResponse({ status: 200, description: 'Usuário autenticado', schema: { example: USER_EXAMPLE } })
91
+ @ApiOperation({ summary: 'Returns the authenticated user' })
92
+ @ApiResponse({ status: 200, description: 'Authenticated user', schema: { example: USER_EXAMPLE } })
93
93
  // nestforge:feature:swagger:end
94
94
  findMe(@CurrentUser() user: { id: string }) {
95
95
  return this.usersService.findOne(user.id);
@@ -97,17 +97,17 @@ export class UsersController {
97
97
 
98
98
  @Post('me/avatar')
99
99
  // nestforge:feature:swagger
100
- @ApiOperation({ summary: 'Faz upload do avatar do usuário autenticado' })
100
+ @ApiOperation({ summary: 'Uploads an avatar for the authenticated user' })
101
101
  @ApiConsumes('multipart/form-data')
102
102
  @ApiResponse({
103
103
  status: 201,
104
- description: 'Avatar atualizado',
104
+ description: 'Avatar updated',
105
105
  schema: { example: { ...USER_EXAMPLE, avatarUrl: '/uploads/avatars/f47ac10b.png' } },
106
106
  })
107
107
  @ApiResponse({
108
108
  status: 400,
109
- description: 'Formato de imagem não suportado ou arquivo maior que 2MB',
110
- schema: { example: { statusCode: 400, message: 'Formato de imagem não suportado (use PNG, JPEG ou WEBP)' } },
109
+ description: 'Unsupported image format or file larger than 2 MB',
110
+ schema: { example: { statusCode: 400, message: 'Unsupported image format (use PNG, JPEG, or WEBP)' } },
111
111
  })
112
112
  // nestforge:feature:swagger:end
113
113
  @UseInterceptors(
@@ -129,9 +129,9 @@ export class UsersController {
129
129
  @Permissions(Permission.UserRead)
130
130
  // nestforge:feature:rbac:end
131
131
  // nestforge:feature:swagger
132
- @ApiOperation({ summary: 'Busca um usuário por id (requer permissão user:read)' })
133
- @ApiResponse({ status: 200, description: 'Usuário encontrado', schema: { example: USER_EXAMPLE } })
134
- @ApiResponse({ status: 404, description: 'Usuário não encontrado', schema: { example: { statusCode: 404, message: 'Usuário não encontrado' } } })
132
+ @ApiOperation({ summary: 'Finds a user by ID (requires the user:read permission)' })
133
+ @ApiResponse({ status: 200, description: 'User found', schema: { example: USER_EXAMPLE } })
134
+ @ApiResponse({ status: 404, description: 'User not found', schema: { example: { statusCode: 404, message: 'User not found' } } })
135
135
  // nestforge:feature:swagger:end
136
136
  findOne(@Param('id') id: string) {
137
137
  return this.usersService.findOne(id);
@@ -142,9 +142,9 @@ export class UsersController {
142
142
  @Permissions(Permission.UserUpdate)
143
143
  // nestforge:feature:rbac:end
144
144
  // nestforge:feature:swagger
145
- @ApiOperation({ summary: 'Atualiza um usuário (requer permissão user:update)' })
146
- @ApiResponse({ status: 200, description: 'Usuário atualizado', schema: { example: USER_EXAMPLE } })
147
- @ApiResponse({ status: 403, description: 'Sem a permissão user:update', schema: { example: FORBIDDEN_EXAMPLE } })
145
+ @ApiOperation({ summary: 'Updates a user (requires the user:update permission)' })
146
+ @ApiResponse({ status: 200, description: 'User updated', schema: { example: USER_EXAMPLE } })
147
+ @ApiResponse({ status: 403, description: 'Missing the user:update permission', schema: { example: FORBIDDEN_EXAMPLE } })
148
148
  // nestforge:feature:swagger:end
149
149
  update(@Param('id') id: string, @Body() dto: UpdateUserDto) {
150
150
  return this.usersService.update(id, dto);
@@ -155,11 +155,11 @@ export class UsersController {
155
155
  @Permissions(Permission.UserDelete)
156
156
  // nestforge:feature:rbac:end
157
157
  // nestforge:feature:swagger
158
- @ApiOperation({ summary: 'Remove um usuário (requer permissão user:delete)' })
159
- @ApiResponse({ status: 200, description: 'Usuário removido', schema: { example: { message: 'Usuário removido com sucesso' } } })
160
- @ApiResponse({ status: 403, description: 'Sem a permissão user:delete', schema: { example: FORBIDDEN_EXAMPLE } })
158
+ @ApiOperation({ summary: 'Deletes a user (requires the user:delete permission)' })
159
+ @ApiResponse({ status: 200, description: 'User deleted', schema: { example: { message: 'User deleted successfully' } } })
160
+ @ApiResponse({ status: 403, description: 'Missing the user:delete permission', schema: { example: FORBIDDEN_EXAMPLE } })
161
161
  // nestforge:feature:swagger:end
162
162
  remove(@Param('id') id: string) {
163
163
  return this.usersService.remove(id);
164
164
  }
165
- }
165
+ }
@@ -81,7 +81,7 @@ describe('UsersService', () => {
81
81
  );
82
82
  });
83
83
 
84
- it('deve lançar ConflictException se o e-mail já existir ao criar', async () => {
84
+ it('throws ConflictException when the email already exists during creation', async () => {
85
85
  database.select.mockReturnValueOnce(
86
86
  createSelectBuilder([
87
87
  {
@@ -94,14 +94,14 @@ describe('UsersService', () => {
94
94
  usersService.create({
95
95
  name: 'Jeiel',
96
96
  email: 'jeiel@example.com',
97
- password: 'senhaForte123',
97
+ password: 'strongPassword123',
98
98
  }),
99
99
  ).rejects.toBeInstanceOf(ConflictException);
100
100
 
101
101
  expect(database.insert).not.toHaveBeenCalled();
102
102
  });
103
103
 
104
- it('deve criar um usuário e esconder o passwordHash na serialização', async () => {
104
+ it('creates a user and hides passwordHash during serialization', async () => {
105
105
  database.select
106
106
  .mockReturnValueOnce(createSelectBuilder([]))
107
107
  .mockReturnValueOnce(
@@ -111,7 +111,7 @@ describe('UsersService', () => {
111
111
  const result = await usersService.create({
112
112
  name: 'Jeiel',
113
113
  email: 'jeiel@example.com',
114
- password: 'senhaForte123',
114
+ password: 'strongPassword123',
115
115
  });
116
116
 
117
117
  expect(result.email).toBe(
@@ -133,7 +133,7 @@ describe('UsersService', () => {
133
133
  );
134
134
  });
135
135
 
136
- it('deve lançar NotFoundException se o usuário não existir', async () => {
136
+ it('throws NotFoundException when the user does not exist', async () => {
137
137
  database.select.mockReturnValueOnce(
138
138
  createSelectBuilder([]),
139
139
  );
@@ -143,7 +143,7 @@ describe('UsersService', () => {
143
143
  ).rejects.toBeInstanceOf(NotFoundException);
144
144
  });
145
145
 
146
- it('deve retornar dados paginados em findAll', async () => {
146
+ it('returns paginated data from findAll', async () => {
147
147
  const usersBuilder = createSelectBuilder([
148
148
  mockUser,
149
149
  ]);
@@ -179,7 +179,7 @@ describe('UsersService', () => {
179
179
  );
180
180
  });
181
181
 
182
- it('deve aplicar busca e filtro por role em findAll', async () => {
182
+ it('applies search and role filters in findAll', async () => {
183
183
  const usersBuilder = createSelectBuilder([
184
184
  mockUser,
185
185
  ]);
@@ -214,7 +214,7 @@ describe('UsersService', () => {
214
214
  );
215
215
  });
216
216
 
217
- it('deve atualizar um usuário existente', async () => {
217
+ it('updates an existing user', async () => {
218
218
  const updatedUser = new UserEntity({
219
219
  ...mockUser,
220
220
  name: 'Novo Nome',
@@ -248,7 +248,7 @@ describe('UsersService', () => {
248
248
  expect(updateWhere).toHaveBeenCalled();
249
249
  });
250
250
 
251
- it('deve remover um usuário existente', async () => {
251
+ it('deletes an existing user', async () => {
252
252
  database.select.mockReturnValueOnce(
253
253
  createSelectBuilder([mockUser]),
254
254
  );
@@ -261,11 +261,11 @@ describe('UsersService', () => {
261
261
  expect(deleteWhere).toHaveBeenCalled();
262
262
 
263
263
  expect(result).toEqual({
264
- message: 'Usuário removido com sucesso',
264
+ message: 'User deleted successfully',
265
265
  });
266
266
  });
267
267
 
268
- it('deve atualizar o avatar de um usuário', async () => {
268
+ it('updates a user avatar', async () => {
269
269
  const updatedUser = new UserEntity({
270
270
  ...mockUser,
271
271
  avatarUrl: '/uploads/avatars/x.png',
@@ -298,4 +298,4 @@ describe('UsersService', () => {
298
298
 
299
299
  expect(updateWhere).toHaveBeenCalled();
300
300
  });
301
- });
301
+ });
@@ -44,7 +44,7 @@ export class UsersService {
44
44
 
45
45
  if (existing) {
46
46
  throw new ConflictException(
47
- 'E-mail já cadastrado',
47
+ 'Email already registered',
48
48
  );
49
49
  }
50
50
 
@@ -144,7 +144,7 @@ export class UsersService {
144
144
 
145
145
  if (!user) {
146
146
  throw new NotFoundException(
147
- 'Usuário não encontrado',
147
+ 'User not found',
148
148
  );
149
149
  }
150
150
 
@@ -190,7 +190,7 @@ export class UsersService {
190
190
  .where(eq(users.id, id));
191
191
 
192
192
  return {
193
- message: 'Usuário removido com sucesso',
193
+ message: 'User deleted successfully',
194
194
  };
195
195
  }
196
196
 
@@ -210,4 +210,4 @@ export class UsersService {
210
210
 
211
211
  return this.findOne(id);
212
212
  }
213
- }
213
+ }
@@ -25,7 +25,7 @@ describe('Auth (e2e)', () => {
25
25
  await app.close();
26
26
  });
27
27
 
28
- it('deve registrar, logar, renovar e revogar o token', async () => {
28
+ it('registers, logs in, refreshes, and revokes the token', async () => {
29
29
  const server = app.getHttpServer();
30
30
 
31
31
  const registerResponse = await request(server)
@@ -33,7 +33,7 @@ describe('Auth (e2e)', () => {
33
33
  .send({
34
34
  name: 'Jeiel',
35
35
  email: 'jeiel.e2e@example.com',
36
- password: 'senhaForte123',
36
+ password: 'strongPassword123',
37
37
  })
38
38
  .expect(201);
39
39
 
@@ -49,7 +49,7 @@ describe('Auth (e2e)', () => {
49
49
  .post('/auth/login')
50
50
  .send({
51
51
  email: 'jeiel.e2e@example.com',
52
- password: 'senhaForte123',
52
+ password: 'strongPassword123',
53
53
  })
54
54
  .expect(200);
55
55
 
@@ -82,13 +82,13 @@ describe('Auth (e2e)', () => {
82
82
  .expect(401);
83
83
  });
84
84
 
85
- it('não deve permitir cadastro com e-mail duplicado', async () => {
85
+ it('rejects registration with a duplicate email', async () => {
86
86
  const server = app.getHttpServer();
87
87
 
88
88
  const payload = {
89
89
  name: 'Jeiel',
90
- email: 'duplicado.e2e@example.com',
91
- password: 'senhaForte123',
90
+ email: 'duplicate.e2e@example.com',
91
+ password: 'strongPassword123',
92
92
  };
93
93
 
94
94
  await request(server)
@@ -102,7 +102,7 @@ describe('Auth (e2e)', () => {
102
102
  .expect(409);
103
103
  });
104
104
 
105
- it('deve rejeitar login com credenciais inválidas', async () => {
105
+ it('rejects login with invalid credentials', async () => {
106
106
  await request(app.getHttpServer())
107
107
  .post('/auth/login')
108
108
  .send({
@@ -111,4 +111,4 @@ describe('Auth (e2e)', () => {
111
111
  })
112
112
  .expect(401);
113
113
  });
114
- });
114
+ });
@@ -28,7 +28,7 @@ describe('Session auth (e2e)', () => {
28
28
  }
29
29
  });
30
30
 
31
- it('registra, autentica e encerra uma sessão protegida por CSRF', async () => {
31
+ it('registers, authenticates, and closes a CSRF-protected session', async () => {
32
32
  const agent = request.agent(app.getHttpServer());
33
33
 
34
34
  await agent
@@ -43,13 +43,13 @@ describe('Session auth (e2e)', () => {
43
43
 
44
44
  expect(csrfToken).toMatch(/^[a-f0-9]{64}$/);
45
45
 
46
- // Requisições que alteram estado devem ser rejeitadas sem o token.
46
+ // State-changing requests must be rejected without the token.
47
47
  await agent
48
48
  .post('/auth/register')
49
49
  .send({
50
50
  name: 'Jeiel',
51
51
  email: 'jeiel.session@example.com',
52
- password: 'senhaForte123',
52
+ password: 'strongPassword123',
53
53
  })
54
54
  .expect(403);
55
55
 
@@ -59,7 +59,7 @@ describe('Session auth (e2e)', () => {
59
59
  .send({
60
60
  name: 'Jeiel',
61
61
  email: 'jeiel.session@example.com',
62
- password: 'senhaForte123',
62
+ password: 'strongPassword123',
63
63
  })
64
64
  .expect(201);
65
65
 
@@ -97,7 +97,7 @@ describe('Session auth (e2e)', () => {
97
97
  .expect(401);
98
98
  });
99
99
 
100
- it('realiza login e renova o token CSRF da sessão', async () => {
100
+ it('logs in and refreshes the session CSRF token', async () => {
101
101
  const registrationAgent = request.agent(
102
102
  app.getHttpServer(),
103
103
  );
@@ -113,9 +113,9 @@ describe('Session auth (e2e)', () => {
113
113
  .post('/auth/register')
114
114
  .set('x-csrf-token', registrationCsrfToken)
115
115
  .send({
116
- name: 'Usuário de sessão',
116
+ name: 'Session User',
117
117
  email: 'login.session@example.com',
118
- password: 'senhaForte123',
118
+ password: 'strongPassword123',
119
119
  })
120
120
  .expect(201);
121
121
 
@@ -141,7 +141,7 @@ describe('Session auth (e2e)', () => {
141
141
  .set('x-csrf-token', loginCsrfToken)
142
142
  .send({
143
143
  email: 'login.session@example.com',
144
- password: 'senhaForte123',
144
+ password: 'strongPassword123',
145
145
  })
146
146
  .expect(200);
147
147
 
@@ -160,4 +160,4 @@ describe('Session auth (e2e)', () => {
160
160
  .get('/users/me')
161
161
  .expect(200);
162
162
  });
163
- });
163
+ });
@@ -28,7 +28,7 @@ describe('Users (e2e)', () => {
28
28
 
29
29
  await database.insert(users).values({
30
30
  id: randomUUID(),
31
- name: 'Usuário de teste',
31
+ name: 'Test User',
32
32
  email,
33
33
  passwordHash,
34
34
  role,
@@ -70,22 +70,22 @@ describe('Users (e2e)', () => {
70
70
  await app.close();
71
71
  });
72
72
 
73
- it('rejeita acesso sem token', async () => {
73
+ it('rejects access without a token', async () => {
74
74
  await request(app.getHttpServer())
75
75
  .get('/users')
76
76
  .expect(401);
77
77
  });
78
78
 
79
- it('ADMIN consegue criar, listar, atualizar e remover um usuário', async () => {
79
+ it('allows ADMIN to create, list, update, and delete a user', async () => {
80
80
  await createUserWithRole(
81
81
  'admin.e2e@example.com',
82
- 'senhaForte123',
82
+ 'strongPassword123',
83
83
  Role.ADMIN,
84
84
  );
85
85
 
86
86
  const token = await loginAndGetToken(
87
87
  'admin.e2e@example.com',
88
- 'senhaForte123',
88
+ 'strongPassword123',
89
89
  );
90
90
 
91
91
  const server = app.getHttpServer();
@@ -99,9 +99,9 @@ describe('Users (e2e)', () => {
99
99
  `Bearer ${token}`,
100
100
  )
101
101
  .send({
102
- name: 'Novo Usuário',
103
- email: 'novo.e2e@example.com',
104
- password: 'senhaForte123',
102
+ name: 'New User',
103
+ email: 'new.e2e@example.com',
104
+ password: 'strongPassword123',
105
105
  })
106
106
  .expect(201);
107
107
 
@@ -146,16 +146,16 @@ describe('Users (e2e)', () => {
146
146
  });
147
147
 
148
148
  // nestforge:feature:rbac
149
- it('USER consegue ler mas não consegue criar usuário', async () => {
149
+ it('allows USER to read but not create users', async () => {
150
150
  await createUserWithRole(
151
151
  'user.e2e@example.com',
152
- 'senhaForte123',
152
+ 'strongPassword123',
153
153
  Role.USER,
154
154
  );
155
155
 
156
156
  const token = await loginAndGetToken(
157
157
  'user.e2e@example.com',
158
- 'senhaForte123',
158
+ 'strongPassword123',
159
159
  );
160
160
 
161
161
  const server = app.getHttpServer();
@@ -175,24 +175,24 @@ describe('Users (e2e)', () => {
175
175
  `Bearer ${token}`,
176
176
  )
177
177
  .send({
178
- name: 'Não deveria criar',
179
- email: 'bloqueado.e2e@example.com',
180
- password: 'senhaForte123',
178
+ name: 'Should Not Be Created',
179
+ email: 'blocked.e2e@example.com',
180
+ password: 'strongPassword123',
181
181
  })
182
182
  .expect(403);
183
183
  });
184
184
  // nestforge:feature:rbac:end
185
185
 
186
- it('GET /users/me retorna o usuário autenticado', async () => {
186
+ it('returns the authenticated user from GET /users/me', async () => {
187
187
  await createUserWithRole(
188
188
  'me.e2e@example.com',
189
- 'senhaForte123',
189
+ 'strongPassword123',
190
190
  Role.USER,
191
191
  );
192
192
 
193
193
  const token = await loginAndGetToken(
194
194
  'me.e2e@example.com',
195
- 'senhaForte123',
195
+ 'strongPassword123',
196
196
  );
197
197
 
198
198
  const response = await request(
@@ -209,4 +209,4 @@ describe('Users (e2e)', () => {
209
209
  'me.e2e@example.com',
210
210
  );
211
211
  });
212
- });
212
+ });