nestforge-generator 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +24 -7
  2. package/README.pt-BR.md +24 -7
  3. package/dist/features/auth-strategy.js +7 -7
  4. package/dist/features/database.js +35 -0
  5. package/dist/features/database.js.map +1 -1
  6. package/dist/features/dependencies.js +3 -3
  7. package/dist/features/language.js +1 -1
  8. package/dist/features/language.js.map +1 -1
  9. package/dist/features/markers.js +11 -11
  10. package/dist/features/markers.js.map +1 -1
  11. package/dist/generator.js +14 -2
  12. package/dist/generator.js.map +1 -1
  13. package/dist/index.js +8 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/project-name.js +50 -0
  16. package/dist/project-name.js.map +1 -0
  17. package/dist/prompts.js +15 -11
  18. package/dist/prompts.js.map +1 -1
  19. package/package.json +2 -1
  20. package/templates/drizzle/README.md +2 -0
  21. package/templates/drizzle/README.pt-BR.md +2 -0
  22. package/templates/drizzle/drizzle.config.ts +2 -2
  23. package/templates/drizzle/src/auth/auth.controller.ts +35 -35
  24. package/templates/drizzle/src/auth/auth.service.spec.ts +4 -4
  25. package/templates/drizzle/src/auth/auth.service.ts +9 -9
  26. package/templates/drizzle/src/auth/dto/forgot-password.dto.ts +2 -2
  27. package/templates/drizzle/src/auth/dto/login.dto.ts +3 -3
  28. package/templates/drizzle/src/auth/dto/register.dto.ts +4 -4
  29. package/templates/drizzle/src/auth/dto/reset-password.dto.ts +3 -3
  30. package/templates/drizzle/src/auth/guards/github-auth.guard.ts +2 -2
  31. package/templates/drizzle/src/auth/guards/google-auth.guard.ts +2 -2
  32. package/templates/drizzle/src/auth/guards/session-auth.guard.spec.ts +4 -4
  33. package/templates/drizzle/src/auth/guards/session-auth.guard.ts +2 -2
  34. package/templates/drizzle/src/auth/session.service.spec.ts +5 -5
  35. package/templates/drizzle/src/auth/session.service.ts +5 -5
  36. package/templates/drizzle/src/auth/strategies/github.strategy.ts +3 -3
  37. package/templates/drizzle/src/auth/token.service.ts +3 -3
  38. package/templates/drizzle/src/common/filters/http-exception.filter.ts +1 -1
  39. package/templates/drizzle/src/common/guards/permissions.guard.spec.ts +7 -7
  40. package/templates/drizzle/src/common/guards/roles.guard.spec.ts +4 -4
  41. package/templates/drizzle/src/common/middleware/csrf.middleware.spec.ts +5 -5
  42. package/templates/drizzle/src/common/middleware/csrf.middleware.ts +2 -2
  43. package/templates/drizzle/src/common/utils/avatar-storage.util.ts +2 -2
  44. package/templates/drizzle/src/config/env.validation.ts +1 -1
  45. package/templates/drizzle/src/database/seed.ts +4 -4
  46. package/templates/drizzle/src/health/health.controller.ts +2 -2
  47. package/templates/drizzle/src/health/indicators/drizzle-health.indicator.spec.ts +5 -5
  48. package/templates/drizzle/src/health/indicators/drizzle-health.indicator.ts +2 -2
  49. package/templates/drizzle/src/health/indicators/redis-health.indicator.spec.ts +5 -5
  50. package/templates/drizzle/src/health/indicators/redis-health.indicator.ts +3 -3
  51. package/templates/drizzle/src/mail/mail.processor.ts +4 -4
  52. package/templates/drizzle/src/mail/templates/email-templates.ts +7 -7
  53. package/templates/drizzle/src/metrics/metrics.service.ts +3 -3
  54. package/templates/drizzle/src/users/dto/create-user.dto.ts +5 -5
  55. package/templates/drizzle/src/users/dto/find-users-query.dto.ts +3 -3
  56. package/templates/drizzle/src/users/users.controller.ts +21 -21
  57. package/templates/drizzle/src/users/users.service.spec.ts +12 -12
  58. package/templates/drizzle/src/users/users.service.ts +4 -4
  59. package/templates/drizzle/test/auth.e2e-spec.ts +8 -8
  60. package/templates/drizzle/test/session-auth.e2e-spec.ts +9 -9
  61. package/templates/drizzle/test/users.e2e-spec.ts +18 -18
  62. package/templates/prisma/.github/workflows/ci.yml +24 -1
  63. package/templates/prisma/ARCHITECTURE.md +7 -1
  64. package/templates/prisma/ARCHITECTURE.pt-BR.md +7 -1
  65. package/templates/prisma/README.md +11 -7
  66. package/templates/prisma/README.pt-BR.md +11 -7
  67. package/templates/prisma/ROADMAP.md +5 -1
  68. package/templates/prisma/ROADMAP.pt-BR.md +5 -1
  69. package/templates/prisma/TESTING.md +25 -3
  70. package/templates/prisma/TESTING.pt-BR.md +25 -3
  71. package/templates/prisma/docker-compose.yml +29 -1
  72. package/templates/prisma/docs/adding-a-module.md +246 -230
  73. package/templates/prisma/docs/features-markers.md +11 -1
  74. package/templates/prisma/prisma/schema.prisma +4 -0
  75. package/templates/prisma/prisma/seed.ts +46 -46
  76. package/templates/prisma/src/auth/auth.controller.ts +35 -35
  77. package/templates/prisma/src/auth/auth.service.spec.ts +3 -3
  78. package/templates/prisma/src/auth/auth.service.ts +11 -11
  79. package/templates/prisma/src/auth/dto/forgot-password.dto.ts +2 -2
  80. package/templates/prisma/src/auth/dto/login.dto.ts +3 -3
  81. package/templates/prisma/src/auth/dto/register.dto.ts +4 -4
  82. package/templates/prisma/src/auth/dto/reset-password.dto.ts +3 -3
  83. package/templates/prisma/src/auth/guards/github-auth.guard.ts +10 -10
  84. package/templates/prisma/src/auth/guards/google-auth.guard.ts +10 -10
  85. package/templates/prisma/src/auth/guards/session-auth.guard.spec.ts +4 -4
  86. package/templates/prisma/src/auth/guards/session-auth.guard.ts +2 -2
  87. package/templates/prisma/src/auth/session.service.spec.ts +5 -5
  88. package/templates/prisma/src/auth/session.service.ts +5 -5
  89. package/templates/prisma/src/auth/strategies/github.strategy.ts +3 -3
  90. package/templates/prisma/src/auth/token.service.ts +14 -5
  91. package/templates/prisma/src/common/filters/http-exception.filter.ts +34 -34
  92. package/templates/prisma/src/common/guards/permissions.guard.spec.ts +7 -7
  93. package/templates/prisma/src/common/guards/roles.guard.spec.ts +4 -4
  94. package/templates/prisma/src/common/middleware/csrf.middleware.spec.ts +5 -5
  95. package/templates/prisma/src/common/middleware/csrf.middleware.ts +2 -2
  96. package/templates/prisma/src/common/utils/avatar-storage.util.ts +32 -32
  97. package/templates/prisma/src/config/env.validation.ts +1 -1
  98. package/templates/prisma/src/health/health.controller.ts +2 -2
  99. package/templates/prisma/src/health/indicators/prisma-health.indicator.spec.ts +39 -22
  100. package/templates/prisma/src/health/indicators/prisma-health.indicator.ts +24 -19
  101. package/templates/prisma/src/health/indicators/redis-health.indicator.spec.ts +5 -5
  102. package/templates/prisma/src/health/indicators/redis-health.indicator.ts +3 -3
  103. package/templates/prisma/src/mail/mail.processor.ts +4 -4
  104. package/templates/prisma/src/mail/templates/email-templates.ts +7 -7
  105. package/templates/prisma/src/metrics/metrics.service.ts +34 -34
  106. package/templates/prisma/src/users/dto/create-user.dto.ts +12 -12
  107. package/templates/prisma/src/users/dto/find-users-query.dto.ts +12 -12
  108. package/templates/prisma/src/users/users.controller.ts +21 -21
  109. package/templates/prisma/src/users/users.service.spec.ts +11 -11
  110. package/templates/prisma/src/users/users.service.ts +4 -4
  111. package/templates/prisma/test/auth.e2e-spec.ts +8 -8
  112. package/templates/prisma/test/session-auth.e2e-spec.ts +9 -9
  113. package/templates/prisma/test/users.e2e-spec.ts +14 -14
  114. package/templates/typeorm/README.md +2 -0
  115. package/templates/typeorm/README.pt-BR.md +2 -0
  116. package/templates/typeorm/src/auth/auth.controller.ts +35 -35
  117. package/templates/typeorm/src/auth/auth.service.spec.ts +4 -4
  118. package/templates/typeorm/src/auth/auth.service.ts +9 -9
  119. package/templates/typeorm/src/auth/dto/forgot-password.dto.ts +2 -2
  120. package/templates/typeorm/src/auth/dto/login.dto.ts +3 -3
  121. package/templates/typeorm/src/auth/dto/register.dto.ts +4 -4
  122. package/templates/typeorm/src/auth/dto/reset-password.dto.ts +3 -3
  123. package/templates/typeorm/src/auth/guards/github-auth.guard.ts +2 -2
  124. package/templates/typeorm/src/auth/guards/google-auth.guard.ts +2 -2
  125. package/templates/typeorm/src/auth/guards/session-auth.guard.spec.ts +4 -4
  126. package/templates/typeorm/src/auth/guards/session-auth.guard.ts +2 -2
  127. package/templates/typeorm/src/auth/session.service.spec.ts +5 -5
  128. package/templates/typeorm/src/auth/session.service.ts +5 -5
  129. package/templates/typeorm/src/auth/strategies/github.strategy.ts +3 -3
  130. package/templates/typeorm/src/auth/token.service.ts +3 -3
  131. package/templates/typeorm/src/common/filters/http-exception.filter.ts +1 -1
  132. package/templates/typeorm/src/common/guards/permissions.guard.spec.ts +7 -7
  133. package/templates/typeorm/src/common/guards/roles.guard.spec.ts +4 -4
  134. package/templates/typeorm/src/common/middleware/csrf.middleware.spec.ts +5 -5
  135. package/templates/typeorm/src/common/middleware/csrf.middleware.ts +2 -2
  136. package/templates/typeorm/src/common/utils/avatar-storage.util.ts +2 -2
  137. package/templates/typeorm/src/config/env.validation.ts +1 -1
  138. package/templates/typeorm/src/database/data-source.ts +2 -2
  139. package/templates/typeorm/src/database/seed.ts +3 -3
  140. package/templates/typeorm/src/database/typeorm-options.ts +2 -2
  141. package/templates/typeorm/src/health/health.controller.ts +2 -2
  142. package/templates/typeorm/src/health/indicators/redis-health.indicator.spec.ts +5 -5
  143. package/templates/typeorm/src/health/indicators/redis-health.indicator.ts +3 -3
  144. package/templates/typeorm/src/health/indicators/typeorm-health.indicator.spec.ts +4 -4
  145. package/templates/typeorm/src/health/indicators/typeorm-health.indicator.ts +2 -2
  146. package/templates/typeorm/src/mail/mail.processor.ts +4 -4
  147. package/templates/typeorm/src/mail/templates/email-templates.ts +7 -7
  148. package/templates/typeorm/src/metrics/metrics.service.ts +3 -3
  149. package/templates/typeorm/src/users/dto/create-user.dto.ts +5 -5
  150. package/templates/typeorm/src/users/dto/find-users-query.dto.ts +3 -3
  151. package/templates/typeorm/src/users/users.controller.ts +21 -21
  152. package/templates/typeorm/src/users/users.service.spec.ts +12 -12
  153. package/templates/typeorm/src/users/users.service.ts +4 -4
  154. package/templates/typeorm/test/auth.e2e-spec.ts +8 -8
  155. package/templates/typeorm/test/session-auth.e2e-spec.ts +9 -9
  156. package/templates/typeorm/test/users.e2e-spec.ts +18 -18
@@ -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
+ });
@@ -64,6 +64,9 @@ jobs:
64
64
  # nestforge:feature:database:sqlite
65
65
  DATABASE_URL: file:./ci-dev.db
66
66
  # nestforge:feature:database:sqlite:end
67
+ # nestforge:feature:database:mongodb
68
+ DATABASE_URL: mongodb://localhost:27017/nestforge?replicaSet=rs0
69
+ # nestforge:feature:database:mongodb:end
67
70
  JWT_ACCESS_SECRET: ci-access-secret-0123456789
68
71
  JWT_REFRESH_SECRET: ci-refresh-secret-0123456789
69
72
 
@@ -77,14 +80,34 @@ jobs:
77
80
  node-version: 20
78
81
  cache: npm
79
82
 
83
+ # nestforge:feature:database:mongodb
84
+ - name: Start MongoDB replica set
85
+ run: |
86
+ docker run --detach --name nestforge-mongodb --publish 27017:27017 mongo:8 mongod --replSet rs0 --bind_ip_all
87
+ for attempt in {1..30}; do
88
+ if docker exec nestforge-mongodb mongosh --quiet --eval "try { rs.status().ok } catch (error) { rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'localhost:27017'}]}).ok }" | grep -q 1; then
89
+ exit 0
90
+ fi
91
+ sleep 2
92
+ done
93
+ exit 1
94
+ # nestforge:feature:database:mongodb:end
95
+
80
96
  - name: Instalar dependências
81
97
  run: npm ci
82
98
 
83
99
  - name: Gerar Prisma Client
84
100
  run: npx prisma generate
85
101
 
102
+ # nestforge:feature:database:relational
86
103
  - name: Rodar migrations
87
104
  run: npx prisma migrate deploy
105
+ # nestforge:feature:database:relational:end
106
+
107
+ # nestforge:feature:database:mongodb
108
+ - name: Sincronizar schema do MongoDB
109
+ run: npx prisma db push
110
+ # nestforge:feature:database:mongodb:end
88
111
 
89
112
  - name: Lint
90
113
  run: npm run lint
@@ -106,4 +129,4 @@ jobs:
106
129
  # nestforge:feature:database:mysql:end
107
130
 
108
131
  - name: Testes e2e
109
- run: npm run test:e2e
132
+ run: npm run test:e2e
@@ -11,7 +11,7 @@ Request → main.ts (global pipes/filters/interceptors)
11
11
  → Guards (JwtAuthGuard → RolesGuard → PermissionsGuard)
12
12
  → Controller (validates through a Zod DTO, delegates to the service)
13
13
  → Service (business rules, calls Prisma)
14
- → Prisma → PostgreSQL
14
+ → Prisma → selected database
15
15
  → Response (passes through ClassSerializerInterceptor before becoming JSON)
16
16
  ```
17
17
 
@@ -38,6 +38,12 @@ Controllers never communicate with Prisma directly — they always go through th
38
38
 
39
39
  Prisma Client is effectively already a type-safe repository. Adding an abstraction layer on top merely to “follow the pattern” would add indirection without a real benefit in this project (there is no plan to replace the ORM). Services call `this.prisma.<model>` directly.
40
40
 
41
+ ### How does MongoDB differ from the relational databases?
42
+
43
+ MongoDB documents use `_id`. The generated Prisma schema maps model IDs to `_id`, uses native `ObjectId` values where IDs are generated by MongoDB, and marks relation scalar fields with `@db.ObjectId`. The session store keeps its externally supplied string ID mapped directly to `_id`.
44
+
45
+ MongoDB uses `prisma db push` instead of Prisma Migrate. A replica set is required for transactional and nested-write behavior, so the generated Docker Compose starts a single-node replica set. The database health indicator uses MongoDB's `ping` command instead of executing `SELECT 1`.
46
+
41
47
  ### Why are permissions a fixed map in code (`ROLE_PERMISSIONS`) instead of a database table?
42
48
 
43
49
  A fully dynamic permission system (`roles`, `permissions`, and `role_permissions` tables) is overkill for a starter — most projects created from it will have 3–5 fixed roles. Keeping the mapping in `src/common/constants/role-permissions.ts` makes it explicitly auditable: the entire permission array for every role is visible in one file. If the project grows enough to require permissions configurable at runtime (for example, an administrator creating custom roles through the UI), then migrating to database tables becomes worthwhile.
@@ -11,7 +11,7 @@ Request → main.ts (pipes/filters/interceptors globais)
11
11
  → Guards (JwtAuthGuard → RolesGuard → PermissionsGuard)
12
12
  → Controller (valida via DTO Zod, delega pro service)
13
13
  → Service (regra de negócio, chama o Prisma)
14
- → Prisma → PostgreSQL
14
+ → Prisma → banco selecionado
15
15
  → Response (passa pelo ClassSerializerInterceptor antes de virar JSON)
16
16
  ```
17
17
 
@@ -36,6 +36,12 @@ Controllers nunca falam com o Prisma diretamente — sempre passam pelo service.
36
36
  ### Por que Prisma sem uma camada de "repository" por cima?
37
37
  Prisma Client já é, na prática, um repository type-safe — adicionar uma camada de abstração em cima dele só pra "seguir o padrão" adicionaria indireção sem trazer benefício real neste projeto (não há plano de trocar de ORM). Os services chamam `this.prisma.<model>` diretamente.
38
38
 
39
+ ### Como o MongoDB difere dos bancos relacionais?
40
+
41
+ Documentos MongoDB usam `_id`. O schema Prisma gerado mapeia os IDs dos models para `_id`, usa valores nativos `ObjectId` quando os IDs são gerados pelo MongoDB e marca os campos escalares de relação com `@db.ObjectId`. O armazenamento de sessão mantém seu ID textual fornecido externamente mapeado diretamente para `_id`.
42
+
43
+ MongoDB usa `prisma db push` no lugar do Prisma Migrate. Um replica set é necessário para transações e escritas aninhadas, então o Docker Compose gerado inicia um replica set de nó único. O indicador de saúde usa o comando `ping` do MongoDB em vez de executar `SELECT 1`.
44
+
39
45
  ### Por que permissions são um mapa fixo em código (`ROLE_PERMISSIONS`) e não uma tabela no banco?
40
46
  Um sistema de permissions 100% dinâmico (tabelas `roles`, `permissions`, `role_permissions`) é overkill pra um boilerplate — a maioria dos projetos que nascem daqui vai ter 3-5 roles fixas. Manter o mapeamento em `src/common/constants/role-permissions.ts` deixa auditável de forma explícita: dá pra ver o array inteiro de permissões de cada role em um arquivo só. Se o seu projeto crescer a ponto de precisar de permissions configuráveis em runtime (ex.: um admin criando roles customizadas pela UI), aí sim vale migrar pra tabela.
41
47
 
@@ -17,7 +17,7 @@ NestForge is a NestJS starter designed to accelerate the beginning of serious ba
17
17
  - 🌐 **OAuth** — Google and GitHub, integrated with the selected token or session strategy
18
18
  - 👥 **RBAC** — Roles (Admin, Manager, User) and granular Permissions
19
19
  - 🛡️ **Security** — Helmet, CORS, Rate Limiting, validation, and serialization with Zod
20
- - 🗄️ **Database** — Prisma with PostgreSQL, MySQL, or SQLite
20
+ - 🗄️ **Database** — Prisma with PostgreSQL, MySQL, SQLite, or MongoDB
21
21
  - 📨 **Email** — queues with BullMQ + Redis, locally tested with Mailpit
22
22
  - 📄 **Automatic documentation** — Swagger
23
23
  - 🪵 **Structured logs** — Pino
@@ -31,7 +31,7 @@ NestForge is a NestJS starter designed to accelerate the beginning of serious ba
31
31
  |---|---|
32
32
  | Framework | NestJS + TypeScript |
33
33
  | ORM | Prisma |
34
- | Database | PostgreSQL, MySQL, or SQLite |
34
+ | Database | PostgreSQL, MySQL, SQLite, or MongoDB |
35
35
  | Cache / Queues | Redis + BullMQ |
36
36
  | Authentication | JWT, Session/Cookies, or OAuth with Passport |
37
37
  | Validation | Zod + nestjs-zod (schemas automatically become DTOs + Swagger) |
@@ -73,14 +73,19 @@ cp .env.example .env
73
73
  docker compose up
74
74
  ```
75
75
 
76
- This starts the API, PostgreSQL, Redis, and Mailpit (email interface at `http://localhost:8025`).
76
+ This starts the API, the selected database, Redis, and Mailpit (email interface at `http://localhost:8025`). MongoDB runs as a single-node replica set for transaction support.
77
77
 
78
78
  ### Running locally
79
79
 
80
80
  ```bash
81
81
  npm install
82
82
  cp .env.example .env
83
+ # nestforge:feature:database:relational
83
84
  npx prisma migrate dev
85
+ # nestforge:feature:database:relational:end
86
+ # nestforge:feature:database:mongodb
87
+ npm run prisma:push
88
+ # nestforge:feature:database:mongodb:end
84
89
  npx prisma db seed
85
90
  npm run start:dev
86
91
  ```
@@ -234,15 +239,14 @@ npm run test:e2e # integration tests (E2E)
234
239
  npm run test:cov # coverage
235
240
  ```
236
241
 
237
- E2E tests (`test/*.e2e-spec.ts`) start the real application (Nest + Prisma + Redis) and call its endpoints with `supertest`, using an isolated database (`.env.test`, the `nestforge_test` database — never the development database). Before running them for the first time:
242
+ E2E tests (`test/*.e2e-spec.ts`) start the real application (Nest + Prisma + Redis) and call its endpoints with `supertest`, using an isolated database (`.env.test`, the `nestforge_test` database — never the development database). Before running them for the first time, start the selected database and Redis:
238
243
 
239
244
  ```bash
240
- createdb nestforge_test # or: psql -U nestforge -c "CREATE DATABASE nestforge_test;"
241
- docker compose up -d postgres redis
245
+ docker compose up -d
242
246
  npm run test:e2e
243
247
  ```
244
248
 
245
- The `pretest:e2e` script automatically applies migrations to this database before every run. Each test cleans the tables before running (`test/utils/clean-database.ts`), so nothing needs to be reset manually between runs. Current coverage includes the complete authentication flow (registration, login, refresh, logout, duplicate email, invalid credentials) and user CRUD with RBAC (ADMIN can do everything, USER can read but cannot create, `/users/me`, and access without a token).
249
+ The `pretest:e2e` script automatically applies migrations for relational databases or pushes the Prisma schema for MongoDB before every run. Each test cleans the database before running (`test/utils/clean-database.ts`), so nothing needs to be reset manually between runs. Current coverage includes the complete authentication flow (registration, login, refresh, logout, duplicate email, invalid credentials) and user CRUD with RBAC (ADMIN can do everything, USER can read but cannot create, `/users/me`, and access without a token).
246
250
 
247
251
  Unit tests (`src/**/*.spec.ts`) run in isolation with Prisma and `ioredis` mocked (`vi.fn()` / `vi.mock()`), so they do not require a real database or Redis. Current coverage includes `AuthService` (registration/login), `UsersService` (complete CRUD + pagination + confirmation through `instanceToPlain` that `passwordHash` is not leaked during serialization), `RolesGuard` and `PermissionsGuard` (allowing/blocking, including multiple permissions required at the same time), and health indicators (`PrismaHealthIndicator`, `RedisHealthIndicator`).
248
252
 
@@ -17,7 +17,7 @@ NestForge é um boilerplate de NestJS pensado para acelerar o início de projeto
17
17
  - 🌐 **OAuth** — Google e GitHub, integrado à estratégia de token ou sessão escolhida
18
18
  - 👥 **RBAC** — Roles (Admin, Manager, User) e Permissions granulares
19
19
  - 🛡️ **Segurança** — Helmet, CORS, Rate Limiting, validação e serialização com Zod
20
- - 🗄️ **Banco de dados** — Prisma com PostgreSQL, MySQL ou SQLite
20
+ - 🗄️ **Banco de dados** — Prisma com PostgreSQL, MySQL, SQLite ou MongoDB
21
21
  - 📨 **E-mails** — filas com BullMQ + Redis, testado localmente com Mailpit
22
22
  - 📄 **Documentação automática** — Swagger
23
23
  - 🪵 **Logs estruturados** — Pino
@@ -31,7 +31,7 @@ NestForge é um boilerplate de NestJS pensado para acelerar o início de projeto
31
31
  |---|---|
32
32
  | Framework | NestJS + TypeScript |
33
33
  | ORM | Prisma |
34
- | Banco | PostgreSQL, MySQL ou SQLite |
34
+ | Banco | PostgreSQL, MySQL, SQLite ou MongoDB |
35
35
  | Cache / Filas | Redis + BullMQ |
36
36
  | Autenticação | JWT, Session/Cookies ou OAuth com Passport |
37
37
  | Validação | Zod + nestjs-zod (schemas viram DTO + Swagger automaticamente) |
@@ -73,14 +73,19 @@ cp .env.example .env
73
73
  docker compose up
74
74
  ```
75
75
 
76
- Isso sobe: API, PostgreSQL, Redis e Mailpit (interface de e-mail em `http://localhost:8025`).
76
+ Isso sobe a API, o banco selecionado, Redis e Mailpit (interface de e-mail em `http://localhost:8025`). O MongoDB funciona como replica set de nó único para permitir transações.
77
77
 
78
78
  ### Rodando localmente
79
79
 
80
80
  ```bash
81
81
  npm install
82
82
  cp .env.example .env
83
+ # nestforge:feature:database:relational
83
84
  npx prisma migrate dev
85
+ # nestforge:feature:database:relational:end
86
+ # nestforge:feature:database:mongodb
87
+ npm run prisma:push
88
+ # nestforge:feature:database:mongodb:end
84
89
  npx prisma db seed
85
90
  npm run start:dev
86
91
  ```
@@ -234,15 +239,14 @@ npm run test:e2e # integração (e2e)
234
239
  npm run test:cov # cobertura
235
240
  ```
236
241
 
237
- Os testes e2e (`test/*.e2e-spec.ts`) sobem a aplicação real (Nest + Prisma + Redis) e batem nos endpoints com `supertest`, usando um banco isolado (`.env.test`, banco `nestforge_test` — nunca o de desenvolvimento). Antes de rodar pela primeira vez:
242
+ Os testes e2e (`test/*.e2e-spec.ts`) sobem a aplicação real (Nest + Prisma + Redis) e batem nos endpoints com `supertest`, usando um banco isolado (`.env.test`, banco `nestforge_test` — nunca o de desenvolvimento). Antes de rodar pela primeira vez, inicie o banco selecionado e o Redis:
238
243
 
239
244
  ```bash
240
- createdb nestforge_test # ou: psql -U nestforge -c "CREATE DATABASE nestforge_test;"
241
- docker compose up -d postgres redis
245
+ docker compose up -d
242
246
  npm run test:e2e
243
247
  ```
244
248
 
245
- O script `pretest:e2e` já aplica as migrations nesse banco automaticamente antes de cada rodada. Cada teste limpa as tabelas antes de rodar (`test/utils/clean-database.ts`), então não precisa zerar nada manualmente entre execuções. Hoje cobrem o fluxo de autenticação completo (registro, login, refresh, logout, e-mail duplicado, credenciais inválidas) e o CRUD de usuários com RBAC (ADMIN consegue tudo, USER lê mas não cria, `/users/me`, acesso sem token).
249
+ O script `pretest:e2e` aplica as migrations nos bancos relacionais ou envia o schema Prisma ao MongoDB antes de cada rodada. Cada teste limpa o banco antes de rodar (`test/utils/clean-database.ts`), então não precisa zerar nada manualmente entre execuções. Hoje cobrem o fluxo de autenticação completo (registro, login, refresh, logout, e-mail duplicado, credenciais inválidas) e o CRUD de usuários com RBAC (ADMIN consegue tudo, USER lê mas não cria, `/users/me`, acesso sem token).
246
250
 
247
251
  Os testes unitários (`src/**/*.spec.ts`) rodam isolados, com Prisma e `ioredis` mockados (`vi.fn()` / `vi.mock()`) — não precisam de banco nem Redis de verdade. Hoje cobrem: `AuthService` (registro/login), `UsersService` (CRUD completo + paginação + confirma que o `passwordHash` não vaza na serialização via `instanceToPlain`), `RolesGuard` e `PermissionsGuard` (liberação/bloqueio, inclusive com múltiplas permissões exigidas ao mesmo tempo) e os indicadores de saúde (`PrismaHealthIndicator`, `RedisHealthIndicator`).
248
252
 
@@ -41,7 +41,11 @@ This roadmap makes it clear what is ready and where contributions are possible.
41
41
 
42
42
  - [x] Prisma
43
43
  - [x] PostgreSQL
44
- - [x] Migrations
44
+ - [x] MySQL
45
+ - [x] SQLite
46
+ - [x] MongoDB
47
+ - [x] Migrations for relational databases
48
+ - [x] Schema synchronization with `prisma db push` for MongoDB
45
49
  - [x] Complete seed (roles, permissions, administrator user)
46
50
 
47
51
  ## Infrastructure
@@ -36,7 +36,11 @@ Este roadmap existe para deixar claro o que já está pronto e onde dá pra cont
36
36
  ## Banco de dados
37
37
  - [x] Prisma
38
38
  - [x] PostgreSQL
39
- - [x] Migrations
39
+ - [x] MySQL
40
+ - [x] SQLite
41
+ - [x] MongoDB
42
+ - [x] Migrations para bancos relacionais
43
+ - [x] Sincronização do schema com `prisma db push` para MongoDB
40
44
  - [x] Seed completo (roles, permissions, usuário admin)
41
45
 
42
46
  ## Infra
@@ -8,7 +8,7 @@ This guide validates a project generated from the NestForge Prisma template.
8
8
 
9
9
  * Node.js 20 or later
10
10
  * npm 10 or later
11
- * Docker when testing PostgreSQL, MySQL, Redis, or Mailpit
11
+ * Docker when testing PostgreSQL, MySQL, MongoDB, Redis, or Mailpit
12
12
 
13
13
  SQLite can be tested without Docker.
14
14
 
@@ -30,10 +30,18 @@ npm run prisma:generate
30
30
 
31
31
  ## Apply the development schema
32
32
 
33
+ For PostgreSQL, MySQL, or SQLite:
34
+
33
35
  ```bash
34
36
  npm run prisma:migrate -- --name init
35
37
  ```
36
38
 
39
+ For MongoDB:
40
+
41
+ ```bash
42
+ npm run prisma:push
43
+ ```
44
+
37
45
  Run the seed when the generated project includes password authentication:
38
46
 
39
47
  ```bash
@@ -67,7 +75,7 @@ Unit tests mock Prisma and Redis, so they do not require real services.
67
75
  npm run test:e2e
68
76
  ```
69
77
 
70
- The `pretest:e2e` script runs `prisma migrate deploy` with `.env.test` before the suite starts.
78
+ The `pretest:e2e` script runs `prisma migrate deploy` for relational databases or `prisma db push` for MongoDB with `.env.test` before the suite starts.
71
79
 
72
80
  Depending on the generated authentication strategy, the suite may cover:
73
81
 
@@ -110,11 +118,25 @@ npm test
110
118
  npm run test:e2e
111
119
  ```
112
120
 
121
+ ### MongoDB
122
+
123
+ MongoDB must run as a replica set because Prisma uses transactions for nested writes. The generated Docker Compose configures a single-node replica set:
124
+
125
+ ```bash
126
+ docker compose up -d mongodb
127
+ npm run prisma:push
128
+ npm run build
129
+ npm test
130
+ npm run test:e2e
131
+ ```
132
+
133
+ Use different database names in `.env` and `.env.test`, such as `nestforge` and `nestforge_test`.
134
+
113
135
  ## Final checklist
114
136
 
115
137
  * [ ] Dependencies install successfully
116
138
  * [ ] Prisma Client is generated
117
- * [ ] Migrations are applied
139
+ * [ ] Migrations are applied, or the MongoDB schema is pushed
118
140
  * [ ] Seed runs when applicable
119
141
  * [ ] Build passes
120
142
  * [ ] Lint passes
@@ -8,7 +8,7 @@ Este guia valida um projeto gerado a partir do template Prisma do NestForge.
8
8
 
9
9
  * Node.js 20 ou superior
10
10
  * npm 10 ou superior
11
- * Docker para testar PostgreSQL, MySQL, Redis ou Mailpit
11
+ * Docker para testar PostgreSQL, MySQL, MongoDB, Redis ou Mailpit
12
12
 
13
13
  SQLite pode ser testado sem Docker.
14
14
 
@@ -30,10 +30,18 @@ npm run prisma:generate
30
30
 
31
31
  ## Aplicar o schema de desenvolvimento
32
32
 
33
+ Para PostgreSQL, MySQL ou SQLite:
34
+
33
35
  ```bash
34
36
  npm run prisma:migrate -- --name init
35
37
  ```
36
38
 
39
+ Para MongoDB:
40
+
41
+ ```bash
42
+ npm run prisma:push
43
+ ```
44
+
37
45
  Execute o seed quando o projeto gerado incluir autenticação por senha:
38
46
 
39
47
  ```bash
@@ -67,7 +75,7 @@ Os testes unitários simulam Prisma e Redis, portanto não exigem serviços reai
67
75
  npm run test:e2e
68
76
  ```
69
77
 
70
- O script `pretest:e2e` executa `prisma migrate deploy` com `.env.test` antes do início da suíte.
78
+ O script `pretest:e2e` executa `prisma migrate deploy` nos bancos relacionais ou `prisma db push` no MongoDB com `.env.test` antes do início da suíte.
71
79
 
72
80
  Dependendo da estratégia de autenticação gerada, a suíte pode cobrir:
73
81
 
@@ -110,11 +118,25 @@ npm test
110
118
  npm run test:e2e
111
119
  ```
112
120
 
121
+ ### MongoDB
122
+
123
+ O MongoDB deve funcionar como replica set porque o Prisma usa transações em escritas aninhadas. O Docker Compose gerado configura um replica set de nó único:
124
+
125
+ ```bash
126
+ docker compose up -d mongodb
127
+ npm run prisma:push
128
+ npm run build
129
+ npm test
130
+ npm run test:e2e
131
+ ```
132
+
133
+ Use nomes de banco diferentes em `.env` e `.env.test`, como `nestforge` e `nestforge_test`.
134
+
113
135
  ## Checklist final
114
136
 
115
137
  * [ ] As dependências são instaladas corretamente
116
138
  * [ ] O Prisma Client é gerado
117
- * [ ] As migrations são aplicadas
139
+ * [ ] As migrations são aplicadas ou o schema MongoDB é enviado
118
140
  * [ ] O seed executa quando aplicável
119
141
  * [ ] O build passa
120
142
  * [ ] O lint passa