nestforge-generator 0.1.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/LICENSE +21 -0
- package/README.md +371 -0
- package/README.pt-BR.md +370 -0
- package/dist/features/auth-strategy.js +19 -0
- package/dist/features/auth-strategy.js.map +1 -0
- package/dist/features/database.js +59 -0
- package/dist/features/database.js.map +1 -0
- package/dist/features/dependencies.js +57 -0
- package/dist/features/dependencies.js.map +1 -0
- package/dist/features/language.js +172 -0
- package/dist/features/language.js.map +1 -0
- package/dist/features/markers.js +116 -0
- package/dist/features/markers.js.map +1 -0
- package/dist/generator.js +120 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts.js +137 -0
- package/dist/prompts.js.map +1 -0
- package/package.json +76 -0
- package/templates/drizzle/.env.example +45 -0
- package/templates/drizzle/.env.test +38 -0
- package/templates/drizzle/.github/workflows/ci.yml +119 -0
- package/templates/drizzle/ARCHITECTURE.md +227 -0
- package/templates/drizzle/ARCHITECTURE.pt-BR.md +225 -0
- package/templates/drizzle/CODE_OF_CONDUCT.md +29 -0
- package/templates/drizzle/CODE_OF_CONDUCT.pt-BR.md +27 -0
- package/templates/drizzle/CONTRIBUTING.md +57 -0
- package/templates/drizzle/CONTRIBUTING.pt-BR.md +54 -0
- package/templates/drizzle/Dockerfile +43 -0
- package/templates/drizzle/LICENSE +21 -0
- package/templates/drizzle/README.md +257 -0
- package/templates/drizzle/README.pt-BR.md +257 -0
- package/templates/drizzle/ROADMAP.md +143 -0
- package/templates/drizzle/ROADMAP.pt-BR.md +143 -0
- package/templates/drizzle/TESTING.md +136 -0
- package/templates/drizzle/TESTING.pt-BR.md +136 -0
- package/templates/drizzle/docker-compose.yml +82 -0
- package/templates/drizzle/docs/adding-a-module.md +585 -0
- package/templates/drizzle/docs/features-markers.md +457 -0
- package/templates/drizzle/drizzle.config.ts +49 -0
- package/templates/drizzle/nest-cli.json +8 -0
- package/templates/drizzle/package.json +96 -0
- package/templates/drizzle/src/app.module.ts +72 -0
- package/templates/drizzle/src/auth/auth.controller.ts +283 -0
- package/templates/drizzle/src/auth/auth.module.ts +81 -0
- package/templates/drizzle/src/auth/auth.service.spec.ts +111 -0
- package/templates/drizzle/src/auth/auth.service.ts +631 -0
- package/templates/drizzle/src/auth/drizzle-session.store.ts +263 -0
- package/templates/drizzle/src/auth/dto/forgot-password.dto.ts +9 -0
- package/templates/drizzle/src/auth/dto/login.dto.ts +10 -0
- package/templates/drizzle/src/auth/dto/refresh-token.dto.ts +9 -0
- package/templates/drizzle/src/auth/dto/register.dto.ts +11 -0
- package/templates/drizzle/src/auth/dto/reset-password.dto.ts +10 -0
- package/templates/drizzle/src/auth/guards/github-auth.guard.ts +10 -0
- package/templates/drizzle/src/auth/guards/google-auth.guard.ts +10 -0
- package/templates/drizzle/src/auth/guards/jwt-auth.guard.ts +25 -0
- package/templates/drizzle/src/auth/guards/session-auth.guard.spec.ts +77 -0
- package/templates/drizzle/src/auth/guards/session-auth.guard.ts +37 -0
- package/templates/drizzle/src/auth/session.service.spec.ts +74 -0
- package/templates/drizzle/src/auth/session.service.ts +96 -0
- package/templates/drizzle/src/auth/strategies/github.strategy.ts +41 -0
- package/templates/drizzle/src/auth/strategies/google.strategy.ts +43 -0
- package/templates/drizzle/src/auth/strategies/jwt.strategy.ts +25 -0
- package/templates/drizzle/src/auth/token.service.ts +175 -0
- package/templates/drizzle/src/common/constants/permissions.ts +8 -0
- package/templates/drizzle/src/common/constants/role-permissions.ts +9 -0
- package/templates/drizzle/src/common/constants/role.enum.ts +5 -0
- package/templates/drizzle/src/common/decorators/current-user.decorator.ts +8 -0
- package/templates/drizzle/src/common/decorators/permissions.decorator.ts +7 -0
- package/templates/drizzle/src/common/decorators/public.decorator.ts +4 -0
- package/templates/drizzle/src/common/decorators/roles.decorator.ts +6 -0
- package/templates/drizzle/src/common/filters/http-exception.filter.ts +34 -0
- package/templates/drizzle/src/common/guards/permissions.guard.spec.ts +54 -0
- package/templates/drizzle/src/common/guards/permissions.guard.ts +28 -0
- package/templates/drizzle/src/common/guards/roles.guard.spec.ts +37 -0
- package/templates/drizzle/src/common/guards/roles.guard.ts +24 -0
- package/templates/drizzle/src/common/interceptors/logging.interceptor.ts +23 -0
- package/templates/drizzle/src/common/middleware/csrf.middleware.spec.ts +97 -0
- package/templates/drizzle/src/common/middleware/csrf.middleware.ts +46 -0
- package/templates/drizzle/src/common/utils/avatar-storage.util.ts +32 -0
- package/templates/drizzle/src/common/utils/hash.util.ts +5 -0
- package/templates/drizzle/src/config/env.validation.ts +50 -0
- package/templates/drizzle/src/database/database-lifecycle.service.ts +30 -0
- package/templates/drizzle/src/database/database.constants.ts +2 -0
- package/templates/drizzle/src/database/database.decorators.ts +5 -0
- package/templates/drizzle/src/database/database.module.ts +96 -0
- package/templates/drizzle/src/database/database.types.ts +28 -0
- package/templates/drizzle/src/database/schema/index.ts +11 -0
- package/templates/drizzle/src/database/schema/mysql.schema.ts +215 -0
- package/templates/drizzle/src/database/schema/postgres.schema.ts +218 -0
- package/templates/drizzle/src/database/schema/sqlite.schema.ts +190 -0
- package/templates/drizzle/src/database/seed.ts +152 -0
- package/templates/drizzle/src/health/health.controller.ts +49 -0
- package/templates/drizzle/src/health/health.module.ts +19 -0
- package/templates/drizzle/src/health/indicators/drizzle-health.indicator.spec.ts +71 -0
- package/templates/drizzle/src/health/indicators/drizzle-health.indicator.ts +52 -0
- package/templates/drizzle/src/health/indicators/redis-health.indicator.spec.ts +54 -0
- package/templates/drizzle/src/health/indicators/redis-health.indicator.ts +33 -0
- package/templates/drizzle/src/mail/mail.module.ts +12 -0
- package/templates/drizzle/src/mail/mail.processor.ts +48 -0
- package/templates/drizzle/src/mail/mail.service.ts +24 -0
- package/templates/drizzle/src/mail/templates/email-templates.ts +28 -0
- package/templates/drizzle/src/main.ts +145 -0
- package/templates/drizzle/src/metrics/metrics.controller.ts +22 -0
- package/templates/drizzle/src/metrics/metrics.interceptor.ts +30 -0
- package/templates/drizzle/src/metrics/metrics.module.ts +12 -0
- package/templates/drizzle/src/metrics/metrics.service.ts +34 -0
- package/templates/drizzle/src/types/express-session.d.ts +13 -0
- package/templates/drizzle/src/users/dto/create-user.dto.ts +12 -0
- package/templates/drizzle/src/users/dto/find-users-query.dto.ts +12 -0
- package/templates/drizzle/src/users/dto/update-user.dto.ts +6 -0
- package/templates/drizzle/src/users/entities/user.entity.ts +23 -0
- package/templates/drizzle/src/users/users.controller.ts +165 -0
- package/templates/drizzle/src/users/users.module.ts +10 -0
- package/templates/drizzle/src/users/users.service.spec.ts +301 -0
- package/templates/drizzle/src/users/users.service.ts +213 -0
- package/templates/drizzle/test/auth.e2e-spec.ts +114 -0
- package/templates/drizzle/test/session-auth.e2e-spec.ts +163 -0
- package/templates/drizzle/test/users.e2e-spec.ts +212 -0
- package/templates/drizzle/test/utils/clean-database.ts +104 -0
- package/templates/drizzle/test/utils/e2e-setup.ts +77 -0
- package/templates/drizzle/tsconfig.build.json +4 -0
- package/templates/drizzle/tsconfig.json +25 -0
- package/templates/drizzle/vitest.config.ts +20 -0
- package/templates/drizzle/vitest.e2e.config.ts +19 -0
- package/templates/prisma/.env.example +44 -0
- package/templates/prisma/.env.test +37 -0
- package/templates/prisma/.github/workflows/ci.yml +109 -0
- package/templates/prisma/ARCHITECTURE.md +70 -0
- package/templates/prisma/ARCHITECTURE.pt-BR.md +63 -0
- package/templates/prisma/CODE_OF_CONDUCT.md +29 -0
- package/templates/prisma/CODE_OF_CONDUCT.pt-BR.md +27 -0
- package/templates/prisma/CONTRIBUTING.md +57 -0
- package/templates/prisma/CONTRIBUTING.pt-BR.md +54 -0
- package/templates/prisma/Dockerfile +33 -0
- package/templates/prisma/LICENSE +21 -0
- package/templates/prisma/README.md +267 -0
- package/templates/prisma/README.pt-BR.md +267 -0
- package/templates/prisma/ROADMAP.md +75 -0
- package/templates/prisma/ROADMAP.pt-BR.md +65 -0
- package/templates/prisma/TESTING.md +123 -0
- package/templates/prisma/TESTING.pt-BR.md +123 -0
- package/templates/prisma/docker-compose.yml +78 -0
- package/templates/prisma/docs/adding-a-module.md +230 -0
- package/templates/prisma/docs/features-markers.md +50 -0
- package/templates/prisma/nest-cli.json +8 -0
- package/templates/prisma/package.json +95 -0
- package/templates/prisma/prisma/schema.prisma +105 -0
- package/templates/prisma/prisma/seed.ts +46 -0
- package/templates/prisma/src/app.module.ts +72 -0
- package/templates/prisma/src/auth/auth.controller.ts +283 -0
- package/templates/prisma/src/auth/auth.module.ts +59 -0
- package/templates/prisma/src/auth/auth.service.spec.ts +53 -0
- package/templates/prisma/src/auth/auth.service.ts +224 -0
- package/templates/prisma/src/auth/dto/forgot-password.dto.ts +9 -0
- package/templates/prisma/src/auth/dto/login.dto.ts +10 -0
- package/templates/prisma/src/auth/dto/refresh-token.dto.ts +9 -0
- package/templates/prisma/src/auth/dto/register.dto.ts +11 -0
- package/templates/prisma/src/auth/dto/reset-password.dto.ts +10 -0
- package/templates/prisma/src/auth/guards/github-auth.guard.ts +10 -0
- package/templates/prisma/src/auth/guards/google-auth.guard.ts +10 -0
- package/templates/prisma/src/auth/guards/jwt-auth.guard.ts +25 -0
- package/templates/prisma/src/auth/guards/session-auth.guard.spec.ts +77 -0
- package/templates/prisma/src/auth/guards/session-auth.guard.ts +37 -0
- package/templates/prisma/src/auth/session.service.spec.ts +74 -0
- package/templates/prisma/src/auth/session.service.ts +96 -0
- package/templates/prisma/src/auth/strategies/github.strategy.ts +41 -0
- package/templates/prisma/src/auth/strategies/google.strategy.ts +43 -0
- package/templates/prisma/src/auth/strategies/jwt.strategy.ts +25 -0
- package/templates/prisma/src/auth/token.service.ts +84 -0
- package/templates/prisma/src/common/constants/permissions.ts +8 -0
- package/templates/prisma/src/common/constants/role-permissions.ts +9 -0
- package/templates/prisma/src/common/decorators/current-user.decorator.ts +8 -0
- package/templates/prisma/src/common/decorators/permissions.decorator.ts +7 -0
- package/templates/prisma/src/common/decorators/public.decorator.ts +4 -0
- package/templates/prisma/src/common/decorators/roles.decorator.ts +6 -0
- package/templates/prisma/src/common/filters/http-exception.filter.ts +34 -0
- package/templates/prisma/src/common/guards/permissions.guard.spec.ts +54 -0
- package/templates/prisma/src/common/guards/permissions.guard.ts +28 -0
- package/templates/prisma/src/common/guards/roles.guard.spec.ts +37 -0
- package/templates/prisma/src/common/guards/roles.guard.ts +24 -0
- package/templates/prisma/src/common/interceptors/logging.interceptor.ts +23 -0
- package/templates/prisma/src/common/middleware/csrf.middleware.spec.ts +97 -0
- package/templates/prisma/src/common/middleware/csrf.middleware.ts +46 -0
- package/templates/prisma/src/common/utils/avatar-storage.util.ts +32 -0
- package/templates/prisma/src/common/utils/hash.util.ts +5 -0
- package/templates/prisma/src/config/env.validation.ts +49 -0
- package/templates/prisma/src/database/prisma.module.ts +9 -0
- package/templates/prisma/src/database/prisma.service.ts +13 -0
- package/templates/prisma/src/health/health.controller.ts +49 -0
- package/templates/prisma/src/health/health.module.ts +19 -0
- package/templates/prisma/src/health/indicators/prisma-health.indicator.spec.ts +22 -0
- package/templates/prisma/src/health/indicators/prisma-health.indicator.ts +19 -0
- package/templates/prisma/src/health/indicators/redis-health.indicator.spec.ts +54 -0
- package/templates/prisma/src/health/indicators/redis-health.indicator.ts +33 -0
- package/templates/prisma/src/mail/mail.module.ts +12 -0
- package/templates/prisma/src/mail/mail.processor.ts +48 -0
- package/templates/prisma/src/mail/mail.service.ts +24 -0
- package/templates/prisma/src/mail/templates/email-templates.ts +28 -0
- package/templates/prisma/src/main.ts +92 -0
- package/templates/prisma/src/metrics/metrics.controller.ts +22 -0
- package/templates/prisma/src/metrics/metrics.interceptor.ts +30 -0
- package/templates/prisma/src/metrics/metrics.module.ts +12 -0
- package/templates/prisma/src/metrics/metrics.service.ts +34 -0
- package/templates/prisma/src/types/express-session.d.ts +13 -0
- package/templates/prisma/src/users/dto/create-user.dto.ts +12 -0
- package/templates/prisma/src/users/dto/find-users-query.dto.ts +12 -0
- package/templates/prisma/src/users/dto/update-user.dto.ts +6 -0
- package/templates/prisma/src/users/entities/user.entity.ts +20 -0
- package/templates/prisma/src/users/users.controller.ts +165 -0
- package/templates/prisma/src/users/users.module.ts +10 -0
- package/templates/prisma/src/users/users.service.spec.ts +104 -0
- package/templates/prisma/src/users/users.service.ts +114 -0
- package/templates/prisma/test/auth.e2e-spec.ts +75 -0
- package/templates/prisma/test/session-auth.e2e-spec.ts +163 -0
- package/templates/prisma/test/users.e2e-spec.ts +106 -0
- package/templates/prisma/test/utils/clean-database.ts +14 -0
- package/templates/prisma/test/utils/e2e-setup.ts +58 -0
- package/templates/prisma/tsconfig.build.json +4 -0
- package/templates/prisma/tsconfig.json +25 -0
- package/templates/prisma/vitest.config.ts +20 -0
- package/templates/prisma/vitest.e2e.config.ts +19 -0
- package/templates/typeorm/.env.example +45 -0
- package/templates/typeorm/.env.test +38 -0
- package/templates/typeorm/.github/workflows/ci.yml +116 -0
- package/templates/typeorm/ARCHITECTURE.md +158 -0
- package/templates/typeorm/ARCHITECTURE.pt-BR.md +156 -0
- package/templates/typeorm/CODE_OF_CONDUCT.md +29 -0
- package/templates/typeorm/CODE_OF_CONDUCT.pt-BR.md +27 -0
- package/templates/typeorm/CONTRIBUTING.md +57 -0
- package/templates/typeorm/CONTRIBUTING.pt-BR.md +54 -0
- package/templates/typeorm/Dockerfile +43 -0
- package/templates/typeorm/LICENSE +21 -0
- package/templates/typeorm/README.md +266 -0
- package/templates/typeorm/README.pt-BR.md +266 -0
- package/templates/typeorm/ROADMAP.md +79 -0
- package/templates/typeorm/ROADMAP.pt-BR.md +67 -0
- package/templates/typeorm/TESTING.md +114 -0
- package/templates/typeorm/TESTING.pt-BR.md +114 -0
- package/templates/typeorm/docker-compose.yml +78 -0
- package/templates/typeorm/docs/adding-a-module.md +369 -0
- package/templates/typeorm/docs/features-markers.md +50 -0
- package/templates/typeorm/nest-cli.json +8 -0
- package/templates/typeorm/package.json +98 -0
- package/templates/typeorm/src/app.module.ts +72 -0
- package/templates/typeorm/src/auth/auth.controller.ts +283 -0
- package/templates/typeorm/src/auth/auth.module.ts +86 -0
- package/templates/typeorm/src/auth/auth.service.spec.ts +111 -0
- package/templates/typeorm/src/auth/auth.service.ts +346 -0
- package/templates/typeorm/src/auth/dto/forgot-password.dto.ts +9 -0
- package/templates/typeorm/src/auth/dto/login.dto.ts +10 -0
- package/templates/typeorm/src/auth/dto/refresh-token.dto.ts +9 -0
- package/templates/typeorm/src/auth/dto/register.dto.ts +11 -0
- package/templates/typeorm/src/auth/dto/reset-password.dto.ts +10 -0
- package/templates/typeorm/src/auth/entities/email-verification-token.entity.ts +69 -0
- package/templates/typeorm/src/auth/entities/oauth-account.entity.ts +50 -0
- package/templates/typeorm/src/auth/entities/password-reset-token.entity.ts +69 -0
- package/templates/typeorm/src/auth/entities/refresh-token.entity.ts +69 -0
- package/templates/typeorm/src/auth/entities/session.entity.ts +50 -0
- package/templates/typeorm/src/auth/guards/github-auth.guard.ts +10 -0
- package/templates/typeorm/src/auth/guards/google-auth.guard.ts +10 -0
- package/templates/typeorm/src/auth/guards/jwt-auth.guard.ts +25 -0
- package/templates/typeorm/src/auth/guards/session-auth.guard.spec.ts +77 -0
- package/templates/typeorm/src/auth/guards/session-auth.guard.ts +37 -0
- package/templates/typeorm/src/auth/session.service.spec.ts +74 -0
- package/templates/typeorm/src/auth/session.service.ts +96 -0
- package/templates/typeorm/src/auth/strategies/github.strategy.ts +41 -0
- package/templates/typeorm/src/auth/strategies/google.strategy.ts +43 -0
- package/templates/typeorm/src/auth/strategies/jwt.strategy.ts +25 -0
- package/templates/typeorm/src/auth/token.service.ts +115 -0
- package/templates/typeorm/src/common/constants/permissions.ts +8 -0
- package/templates/typeorm/src/common/constants/role-permissions.ts +9 -0
- package/templates/typeorm/src/common/constants/role.enum.ts +5 -0
- package/templates/typeorm/src/common/decorators/current-user.decorator.ts +8 -0
- package/templates/typeorm/src/common/decorators/permissions.decorator.ts +7 -0
- package/templates/typeorm/src/common/decorators/public.decorator.ts +4 -0
- package/templates/typeorm/src/common/decorators/roles.decorator.ts +6 -0
- package/templates/typeorm/src/common/filters/http-exception.filter.ts +34 -0
- package/templates/typeorm/src/common/guards/permissions.guard.spec.ts +54 -0
- package/templates/typeorm/src/common/guards/permissions.guard.ts +28 -0
- package/templates/typeorm/src/common/guards/roles.guard.spec.ts +37 -0
- package/templates/typeorm/src/common/guards/roles.guard.ts +24 -0
- package/templates/typeorm/src/common/interceptors/logging.interceptor.ts +23 -0
- package/templates/typeorm/src/common/middleware/csrf.middleware.spec.ts +97 -0
- package/templates/typeorm/src/common/middleware/csrf.middleware.ts +46 -0
- package/templates/typeorm/src/common/utils/avatar-storage.util.ts +32 -0
- package/templates/typeorm/src/common/utils/hash.util.ts +5 -0
- package/templates/typeorm/src/config/env.validation.ts +50 -0
- package/templates/typeorm/src/database/data-source.ts +20 -0
- package/templates/typeorm/src/database/database.module.ts +39 -0
- package/templates/typeorm/src/database/seed.ts +81 -0
- package/templates/typeorm/src/database/typeorm-options.ts +49 -0
- package/templates/typeorm/src/health/health.controller.ts +49 -0
- package/templates/typeorm/src/health/health.module.ts +19 -0
- package/templates/typeorm/src/health/indicators/redis-health.indicator.spec.ts +54 -0
- package/templates/typeorm/src/health/indicators/redis-health.indicator.ts +33 -0
- package/templates/typeorm/src/health/indicators/typeorm-health.indicator.spec.ts +49 -0
- package/templates/typeorm/src/health/indicators/typeorm-health.indicator.ts +37 -0
- package/templates/typeorm/src/mail/mail.module.ts +12 -0
- package/templates/typeorm/src/mail/mail.processor.ts +48 -0
- package/templates/typeorm/src/mail/mail.service.ts +24 -0
- package/templates/typeorm/src/mail/templates/email-templates.ts +28 -0
- package/templates/typeorm/src/main.ts +107 -0
- package/templates/typeorm/src/metrics/metrics.controller.ts +22 -0
- package/templates/typeorm/src/metrics/metrics.interceptor.ts +30 -0
- package/templates/typeorm/src/metrics/metrics.module.ts +12 -0
- package/templates/typeorm/src/metrics/metrics.service.ts +34 -0
- package/templates/typeorm/src/types/express-session.d.ts +13 -0
- package/templates/typeorm/src/users/dto/create-user.dto.ts +12 -0
- package/templates/typeorm/src/users/dto/find-users-query.dto.ts +12 -0
- package/templates/typeorm/src/users/dto/update-user.dto.ts +6 -0
- package/templates/typeorm/src/users/entities/user.entity.ts +113 -0
- package/templates/typeorm/src/users/users.controller.ts +165 -0
- package/templates/typeorm/src/users/users.module.ts +13 -0
- package/templates/typeorm/src/users/users.service.spec.ts +183 -0
- package/templates/typeorm/src/users/users.service.ts +124 -0
- package/templates/typeorm/test/auth.e2e-spec.ts +111 -0
- package/templates/typeorm/test/session-auth.e2e-spec.ts +159 -0
- package/templates/typeorm/test/users.e2e-spec.ts +183 -0
- package/templates/typeorm/test/utils/clean-database.ts +65 -0
- package/templates/typeorm/test/utils/e2e-setup.ts +77 -0
- package/templates/typeorm/tsconfig.build.json +4 -0
- package/templates/typeorm/tsconfig.json +25 -0
- package/templates/typeorm/vitest.config.ts +20 -0
- package/templates/typeorm/vitest.e2e.config.ts +19 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build-test-lint:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
services:
|
|
14
|
+
# nestforge:feature:database:postgres
|
|
15
|
+
postgres:
|
|
16
|
+
image: postgres:16-alpine
|
|
17
|
+
env:
|
|
18
|
+
POSTGRES_USER: nestforge
|
|
19
|
+
POSTGRES_PASSWORD: nestforge
|
|
20
|
+
POSTGRES_DB: nestforge
|
|
21
|
+
ports:
|
|
22
|
+
- 5432:5432
|
|
23
|
+
options: >-
|
|
24
|
+
--health-cmd pg_isready
|
|
25
|
+
--health-interval 10s
|
|
26
|
+
--health-timeout 5s
|
|
27
|
+
--health-retries 5
|
|
28
|
+
# nestforge:feature:database:postgres:end
|
|
29
|
+
|
|
30
|
+
# nestforge:feature:database:mysql
|
|
31
|
+
mysql:
|
|
32
|
+
image: mysql:8
|
|
33
|
+
env:
|
|
34
|
+
MYSQL_USER: nestforge
|
|
35
|
+
MYSQL_PASSWORD: nestforge
|
|
36
|
+
MYSQL_ROOT_PASSWORD: nestforge
|
|
37
|
+
MYSQL_DATABASE: nestforge
|
|
38
|
+
ports:
|
|
39
|
+
- 3306:3306
|
|
40
|
+
options: >-
|
|
41
|
+
--health-cmd "mysqladmin ping -h localhost"
|
|
42
|
+
--health-interval 10s
|
|
43
|
+
--health-timeout 5s
|
|
44
|
+
--health-retries 5
|
|
45
|
+
# nestforge:feature:database:mysql:end
|
|
46
|
+
|
|
47
|
+
# nestforge:feature:redis
|
|
48
|
+
redis:
|
|
49
|
+
image: redis:7-alpine
|
|
50
|
+
ports:
|
|
51
|
+
- 6379:6379
|
|
52
|
+
options: >-
|
|
53
|
+
--health-cmd "redis-cli ping"
|
|
54
|
+
--health-interval 10s
|
|
55
|
+
--health-timeout 5s
|
|
56
|
+
--health-retries 5
|
|
57
|
+
# nestforge:feature:redis:end
|
|
58
|
+
|
|
59
|
+
env:
|
|
60
|
+
# nestforge:feature:database:postgres
|
|
61
|
+
DB_TYPE: postgres
|
|
62
|
+
DATABASE_URL: postgresql://nestforge:nestforge@localhost:5432/nestforge?schema=public
|
|
63
|
+
# nestforge:feature:database:postgres:end
|
|
64
|
+
|
|
65
|
+
# nestforge:feature:database:mysql
|
|
66
|
+
DB_TYPE: mysql
|
|
67
|
+
DATABASE_URL: mysql://nestforge:nestforge@localhost:3306/nestforge
|
|
68
|
+
# nestforge:feature:database:mysql:end
|
|
69
|
+
|
|
70
|
+
# nestforge:feature:database:sqlite
|
|
71
|
+
DB_TYPE: sqlite
|
|
72
|
+
DATABASE_URL: file:./ci-dev.db
|
|
73
|
+
# nestforge:feature:database:sqlite:end
|
|
74
|
+
|
|
75
|
+
# nestforge:feature:auth:token
|
|
76
|
+
JWT_ACCESS_SECRET: ci-access-secret-0123456789
|
|
77
|
+
JWT_REFRESH_SECRET: ci-refresh-secret-0123456789
|
|
78
|
+
# nestforge:feature:auth:token:end
|
|
79
|
+
|
|
80
|
+
steps:
|
|
81
|
+
- name: Checkout
|
|
82
|
+
uses: actions/checkout@v4
|
|
83
|
+
|
|
84
|
+
- name: Setup Node
|
|
85
|
+
uses: actions/setup-node@v4
|
|
86
|
+
with:
|
|
87
|
+
node-version: 20
|
|
88
|
+
cache: npm
|
|
89
|
+
|
|
90
|
+
- name: Instalar dependências
|
|
91
|
+
run: npm ci
|
|
92
|
+
|
|
93
|
+
- name: Gerar migrations
|
|
94
|
+
run: npx drizzle-kit generate
|
|
95
|
+
|
|
96
|
+
- name: Rodar migrations
|
|
97
|
+
run: npx drizzle-kit migrate
|
|
98
|
+
|
|
99
|
+
- name: Lint
|
|
100
|
+
run: npm run lint
|
|
101
|
+
|
|
102
|
+
- name: Build
|
|
103
|
+
run: npm run build
|
|
104
|
+
|
|
105
|
+
- name: Testes
|
|
106
|
+
run: npm run test
|
|
107
|
+
|
|
108
|
+
# nestforge:feature:database:postgres
|
|
109
|
+
- name: Criar banco de teste
|
|
110
|
+
run: PGPASSWORD=nestforge psql -h localhost -U nestforge -d nestforge -c "CREATE DATABASE nestforge_test;"
|
|
111
|
+
# nestforge:feature:database:postgres:end
|
|
112
|
+
|
|
113
|
+
# nestforge:feature:database:mysql
|
|
114
|
+
- name: Criar banco de teste
|
|
115
|
+
run: mysql -h 127.0.0.1 -u root -pnestforge -e "CREATE DATABASE IF NOT EXISTS nestforge_test;"
|
|
116
|
+
# nestforge:feature:database:mysql:end
|
|
117
|
+
|
|
118
|
+
- name: Testes e2e
|
|
119
|
+
run: npm run test:e2e
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
**English** | [Português](ARCHITECTURE.pt-BR.md)
|
|
4
|
+
|
|
5
|
+
This document explains how NestForge with Drizzle ORM is organized and why certain design decisions were made.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
Request → main.ts (global pipes, filters, and interceptors)
|
|
11
|
+
→ Authentication and authorization guards
|
|
12
|
+
→ Controller (receives a DTO and delegates)
|
|
13
|
+
→ Service (business rules)
|
|
14
|
+
→ DrizzleDatabase
|
|
15
|
+
→ PostgreSQL, MySQL, or SQLite
|
|
16
|
+
→ ClassSerializerInterceptor
|
|
17
|
+
→ Response
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Controllers do not access the database directly. Every operation goes through a service, keeping business rules centralized and testable.
|
|
21
|
+
|
|
22
|
+
## Module structure
|
|
23
|
+
|
|
24
|
+
A domain module normally follows this structure:
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
<module>/
|
|
28
|
+
├── dto/ # Zod schemas and DTOs
|
|
29
|
+
├── entities/ # response and serialization classes, when required
|
|
30
|
+
├── <module>.controller.ts # receives the request and calls the service
|
|
31
|
+
├── <module>.service.ts # business rules and Drizzle queries
|
|
32
|
+
├── <module>.service.spec.ts
|
|
33
|
+
└── <module>.module.ts # controllers, providers, and exports
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Tables are not located inside each module. They are defined in:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
src/database/schema/
|
|
40
|
+
├── postgres.schema.ts
|
|
41
|
+
├── mysql.schema.ts
|
|
42
|
+
├── sqlite.schema.ts
|
|
43
|
+
└── index.ts
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
During generation, the CLI keeps only the schema for the selected database.
|
|
47
|
+
|
|
48
|
+
## Database connection
|
|
49
|
+
|
|
50
|
+
The global connection is created by `DatabaseModule`.
|
|
51
|
+
|
|
52
|
+
It provides two tokens:
|
|
53
|
+
|
|
54
|
+
* `DATABASE_CLIENT`: the native database client;
|
|
55
|
+
* `DRIZZLE_DATABASE`: the typed Drizzle instance.
|
|
56
|
+
|
|
57
|
+
Services receive the database with:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
constructor(
|
|
61
|
+
@InjectDatabase()
|
|
62
|
+
private readonly database: DrizzleDatabase,
|
|
63
|
+
) {}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The `@InjectDatabase()` decorator centralizes the injection token and prevents domain modules from knowing details about how the connection is created.
|
|
67
|
+
|
|
68
|
+
The native client is used only when the driver-specific API is required, such as in the health check and application shutdown.
|
|
69
|
+
|
|
70
|
+
## Schemas by dialect
|
|
71
|
+
|
|
72
|
+
PostgreSQL, MySQL, and SQLite differ in types, defaults, UUIDs, dates, and upsert commands.
|
|
73
|
+
|
|
74
|
+
For this reason, the template keeps three schemas:
|
|
75
|
+
|
|
76
|
+
* `postgres.schema.ts`, using `drizzle-orm/pg-core`;
|
|
77
|
+
* `mysql.schema.ts`, using `drizzle-orm/mysql-core`;
|
|
78
|
+
* `sqlite.schema.ts`, using `drizzle-orm/sqlite-core`.
|
|
79
|
+
|
|
80
|
+
CLI markers remove schemas and imports for unselected databases. The generated project ends up with only one dialect and one driver.
|
|
81
|
+
|
|
82
|
+
## Design decisions
|
|
83
|
+
|
|
84
|
+
### Why Zod instead of class-validator?
|
|
85
|
+
|
|
86
|
+
With Zod, the schema is the primary source for validation and documentation.
|
|
87
|
+
|
|
88
|
+
`nestjs-zod` transforms schemas into DTOs, while `patchNestJsSwagger()` allows Swagger to interpret these schemas.
|
|
89
|
+
|
|
90
|
+
This reduces duplication between validation and documentation decorators.
|
|
91
|
+
|
|
92
|
+
### Why use Drizzle directly in services?
|
|
93
|
+
|
|
94
|
+
Drizzle's query builder already provides typed queries that remain close to SQL.
|
|
95
|
+
|
|
96
|
+
Creating an additional generic layer for every operation would add indirection without an immediate benefit for the starter.
|
|
97
|
+
|
|
98
|
+
A custom persistence layer can still be created when the domain requires multiple data sources or complex access rules.
|
|
99
|
+
|
|
100
|
+
In unit tests, the Drizzle instance is replaced with objects containing `vi.fn()`, without initializing a real database.
|
|
101
|
+
|
|
102
|
+
### Why use versioned migrations?
|
|
103
|
+
|
|
104
|
+
Schema changes must be recorded in SQL migrations so they can be reviewed and applied predictably.
|
|
105
|
+
|
|
106
|
+
The main commands are:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npm run drizzle:generate
|
|
110
|
+
npm run drizzle:migrate
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The first compares the schemas with existing snapshots and generates files in `drizzle/`. The second applies pending migrations to the configured database.
|
|
114
|
+
|
|
115
|
+
For rapid development, the following is also available:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npm run drizzle:push
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`push` is useful for prototypes, but versioned migrations are preferable in shared projects and production.
|
|
122
|
+
|
|
123
|
+
### Why are SQLite transactions different?
|
|
124
|
+
|
|
125
|
+
PostgreSQL and MySQL use asynchronous drivers. Their transactions receive asynchronous callbacks and queries executed with `await`.
|
|
126
|
+
|
|
127
|
+
`better-sqlite3` is synchronous. With this driver, the transaction callback cannot return a `Promise`, and operations are executed with methods such as `.run()`.
|
|
128
|
+
|
|
129
|
+
The template uses database markers to generate the correct implementation for each driver.
|
|
130
|
+
|
|
131
|
+
### Why are permissions a map in code?
|
|
132
|
+
|
|
133
|
+
The `ROLE_PERMISSIONS` map is suitable for projects with a few fixed roles and makes permissions easy to audit.
|
|
134
|
+
|
|
135
|
+
If the project needs dynamic roles, the map can be replaced with tables such as `roles`, `permissions`, and `role_permissions`.
|
|
136
|
+
|
|
137
|
+
### Why BullMQ for email delivery?
|
|
138
|
+
|
|
139
|
+
SMTP is an external operation that can fail or take time.
|
|
140
|
+
|
|
141
|
+
Putting delivery in a queue allows the request to respond after the work is queued, while the worker processes delivery and subsequent retries.
|
|
142
|
+
|
|
143
|
+
### Why store refresh token hashes?
|
|
144
|
+
|
|
145
|
+
A JWT cannot be revoked before it expires. Storing its hash enables:
|
|
146
|
+
|
|
147
|
+
* logout;
|
|
148
|
+
* refresh token rotation;
|
|
149
|
+
* invalidation after a password change;
|
|
150
|
+
* prevention of revoked token reuse.
|
|
151
|
+
|
|
152
|
+
The original token is not persisted. Each refresh token also receives a unique `jti` to prevent collisions when two tokens are issued in the same second.
|
|
153
|
+
|
|
154
|
+
### Why does `UserEntity` still exist?
|
|
155
|
+
|
|
156
|
+
In the Drizzle template, `UserEntity` is not a database entity.
|
|
157
|
+
|
|
158
|
+
It is a response class used by `ClassSerializerInterceptor`. The `@Exclude()` decorator prevents `passwordHash` from being sent by the API.
|
|
159
|
+
|
|
160
|
+
Tables and persistence types are located in the Drizzle schemas.
|
|
161
|
+
|
|
162
|
+
### Why does Session/Cookies use persistent storage?
|
|
163
|
+
|
|
164
|
+
The Session/Cookies strategy uses `express-session` with `DrizzleSessionStore`.
|
|
165
|
+
|
|
166
|
+
Sessions are stored in the `sessions` table instead of process memory. This allows the application to restart or scale without losing all active sessions.
|
|
167
|
+
|
|
168
|
+
The store implements reading, writing, updating, removal, and expiration using the selected database.
|
|
169
|
+
|
|
170
|
+
### How does CSRF protection work?
|
|
171
|
+
|
|
172
|
+
With Session/Cookies, the application uses a CSRF token associated with the session.
|
|
173
|
+
|
|
174
|
+
Requests that change state must send it through the header:
|
|
175
|
+
|
|
176
|
+
```http
|
|
177
|
+
x-csrf-token: <token>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The middleware compares the received value with the token stored in the session.
|
|
181
|
+
|
|
182
|
+
With JWT and a Bearer token, the browser does not automatically send the credential in a cookie. Therefore, this CSRF flow is not required.
|
|
183
|
+
|
|
184
|
+
## Authentication strategies
|
|
185
|
+
|
|
186
|
+
### JWT
|
|
187
|
+
|
|
188
|
+
1. Registration or login validates the user.
|
|
189
|
+
2. `TokenService` issues access and refresh tokens.
|
|
190
|
+
3. The refresh token hash is stored in the database.
|
|
191
|
+
4. `JwtAuthGuard` validates the Bearer token.
|
|
192
|
+
5. Refresh revokes the previous token and issues a new pair.
|
|
193
|
+
6. Logout revokes the refresh token.
|
|
194
|
+
|
|
195
|
+
### Session/Cookies
|
|
196
|
+
|
|
197
|
+
1. Registration or login validates the user.
|
|
198
|
+
2. The session is regenerated to prevent session fixation.
|
|
199
|
+
3. The user and CSRF token are stored in the session.
|
|
200
|
+
4. The browser receives the `nestforge.sid` cookie.
|
|
201
|
+
5. `SessionAuthGuard` protects the routes.
|
|
202
|
+
6. Logout destroys the session.
|
|
203
|
+
|
|
204
|
+
### OAuth
|
|
205
|
+
|
|
206
|
+
Google and GitHub are linked through the `oauth_accounts` table.
|
|
207
|
+
|
|
208
|
+
If the email has not been registered yet, a user is created and associated with the provider. The callback result follows the selected strategy: JWT tokens or a persistent session.
|
|
209
|
+
|
|
210
|
+
## Main tables
|
|
211
|
+
|
|
212
|
+
The schemas may include:
|
|
213
|
+
|
|
214
|
+
* `users`;
|
|
215
|
+
* `oauth_accounts`;
|
|
216
|
+
* `refresh_tokens`, when token authentication is enabled;
|
|
217
|
+
* `sessions`, when Session/Cookies is enabled;
|
|
218
|
+
* `password_reset_tokens`, when password recovery is enabled;
|
|
219
|
+
* `email_verification_tokens`, when email verification is enabled.
|
|
220
|
+
|
|
221
|
+
Conditional tables use markers so that only the selected features remain in the generated project.
|
|
222
|
+
|
|
223
|
+
## Where to add a module
|
|
224
|
+
|
|
225
|
+
To add a new domain according to the template conventions, see [Adding a Module](docs/adding-a-module.md).
|
|
226
|
+
|
|
227
|
+
---
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Arquitetura
|
|
2
|
+
|
|
3
|
+
[English](ARCHITECTURE.md) | **Português**
|
|
4
|
+
|
|
5
|
+
Este documento explica como o NestForge com Drizzle ORM está organizado e por que determinadas decisões de design foram tomadas.
|
|
6
|
+
|
|
7
|
+
## Visão geral
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
Request → main.ts (pipes, filters e interceptors globais)
|
|
11
|
+
→ Guards de autenticação e autorização
|
|
12
|
+
→ Controller (recebe DTO e delega)
|
|
13
|
+
→ Service (regra de negócio)
|
|
14
|
+
→ DrizzleDatabase
|
|
15
|
+
→ PostgreSQL, MySQL ou SQLite
|
|
16
|
+
→ ClassSerializerInterceptor
|
|
17
|
+
→ Response
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Controllers não acessam o banco diretamente. Toda operação passa por um service, mantendo as regras de negócio centralizadas e testáveis.
|
|
21
|
+
|
|
22
|
+
## Estrutura dos módulos
|
|
23
|
+
|
|
24
|
+
Um módulo de domínio normalmente segue esta estrutura:
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
<modulo>/
|
|
28
|
+
├── dto/ # schemas Zod e DTOs
|
|
29
|
+
├── entities/ # classes de resposta e serialização, quando necessárias
|
|
30
|
+
├── <modulo>.controller.ts # recebe a request e chama o service
|
|
31
|
+
├── <modulo>.service.ts # regras de negócio e consultas Drizzle
|
|
32
|
+
├── <modulo>.service.spec.ts
|
|
33
|
+
└── <modulo>.module.ts # controllers, providers e exports
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
As tabelas não ficam dentro de cada módulo. Elas são definidas em:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
src/database/schema/
|
|
40
|
+
├── postgres.schema.ts
|
|
41
|
+
├── mysql.schema.ts
|
|
42
|
+
├── sqlite.schema.ts
|
|
43
|
+
└── index.ts
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Durante a geração, a CLI mantém somente o schema correspondente ao banco escolhido.
|
|
47
|
+
|
|
48
|
+
## Conexão com o banco
|
|
49
|
+
|
|
50
|
+
A conexão global é criada pelo `DatabaseModule`.
|
|
51
|
+
|
|
52
|
+
Ele fornece dois tokens:
|
|
53
|
+
|
|
54
|
+
* `DATABASE_CLIENT`: cliente nativo do banco;
|
|
55
|
+
* `DRIZZLE_DATABASE`: instância tipada do Drizzle.
|
|
56
|
+
|
|
57
|
+
Os services recebem o banco com:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
constructor(
|
|
61
|
+
@InjectDatabase()
|
|
62
|
+
private readonly database: DrizzleDatabase,
|
|
63
|
+
) {}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
O decorator `@InjectDatabase()` centraliza o token de injeção e evita que os módulos de domínio conheçam detalhes da criação da conexão.
|
|
67
|
+
|
|
68
|
+
O cliente nativo é usado apenas quando a API específica do driver é necessária, como no health check e no encerramento da aplicação.
|
|
69
|
+
|
|
70
|
+
## Schemas por dialect
|
|
71
|
+
|
|
72
|
+
PostgreSQL, MySQL e SQLite possuem diferenças em tipos, defaults, UUIDs, datas e comandos de upsert.
|
|
73
|
+
|
|
74
|
+
Por isso o template mantém três schemas:
|
|
75
|
+
|
|
76
|
+
* `postgres.schema.ts`, usando `drizzle-orm/pg-core`;
|
|
77
|
+
* `mysql.schema.ts`, usando `drizzle-orm/mysql-core`;
|
|
78
|
+
* `sqlite.schema.ts`, usando `drizzle-orm/sqlite-core`.
|
|
79
|
+
|
|
80
|
+
Os marcadores da CLI removem os schemas e imports dos bancos não selecionados. O projeto gerado termina com apenas um dialect e um driver.
|
|
81
|
+
|
|
82
|
+
## Decisões de design
|
|
83
|
+
|
|
84
|
+
### Por que Zod em vez de class-validator?
|
|
85
|
+
|
|
86
|
+
Com Zod, o schema é a fonte principal para validação e documentação.
|
|
87
|
+
|
|
88
|
+
O `nestjs-zod` transforma schemas em DTOs, enquanto `patchNestJsSwagger()` permite que o Swagger interprete esses schemas.
|
|
89
|
+
|
|
90
|
+
Isso reduz a duplicação entre decorators de validação e documentação.
|
|
91
|
+
|
|
92
|
+
### Por que usar o Drizzle diretamente nos services?
|
|
93
|
+
|
|
94
|
+
O query builder do Drizzle já oferece consultas tipadas e próximas do SQL.
|
|
95
|
+
|
|
96
|
+
Criar uma camada genérica adicional para todas as operações aumentaria a indireção sem trazer benefício imediato para o boilerplate.
|
|
97
|
+
|
|
98
|
+
Uma camada de persistência própria ainda pode ser criada quando o domínio exigir múltiplas fontes de dados ou regras complexas de acesso.
|
|
99
|
+
|
|
100
|
+
Nos testes unitários, a instância do Drizzle é substituída por objetos com `vi.fn()`, sem inicializar um banco real.
|
|
101
|
+
|
|
102
|
+
### Por que usar migrations versionadas?
|
|
103
|
+
|
|
104
|
+
Alterações no schema devem ser registradas em migrations SQL para que possam ser revisadas e aplicadas de maneira previsível.
|
|
105
|
+
|
|
106
|
+
Os comandos principais são:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npm run drizzle:generate
|
|
110
|
+
npm run drizzle:migrate
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
O primeiro compara os schemas com os snapshots existentes e gera arquivos em `drizzle/`. O segundo aplica as migrations pendentes no banco configurado.
|
|
114
|
+
|
|
115
|
+
Para desenvolvimento rápido também existe:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npm run drizzle:push
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
O uso de `push` é útil em protótipos, mas migrations versionadas são preferíveis em projetos compartilhados e produção.
|
|
122
|
+
|
|
123
|
+
### Por que as transações SQLite são diferentes?
|
|
124
|
+
|
|
125
|
+
PostgreSQL e MySQL usam drivers assíncronos. Suas transações recebem callbacks assíncronos e consultas executadas com `await`.
|
|
126
|
+
|
|
127
|
+
O `better-sqlite3` é síncrono. Nesse driver, a callback da transação não pode retornar uma `Promise`, e as operações são executadas com métodos como `.run()`.
|
|
128
|
+
|
|
129
|
+
O template usa marcadores de banco para gerar a implementação correta para cada driver.
|
|
130
|
+
|
|
131
|
+
### Por que permissions são um mapa em código?
|
|
132
|
+
|
|
133
|
+
O mapa `ROLE_PERMISSIONS` atende projetos com poucas roles fixas e deixa as permissões fáceis de auditar.
|
|
134
|
+
|
|
135
|
+
Se o projeto precisar de roles dinâmicas, o mapa pode ser substituído por tabelas como `roles`, `permissions` e `role_permissions`.
|
|
136
|
+
|
|
137
|
+
### Por que BullMQ para envio de e-mails?
|
|
138
|
+
|
|
139
|
+
SMTP é uma operação externa que pode falhar ou demorar.
|
|
140
|
+
|
|
141
|
+
Colocar o envio em uma fila permite responder à requisição depois de enfileirar o trabalho, enquanto o worker processa o envio e suas tentativas posteriores.
|
|
142
|
+
|
|
143
|
+
### Por que armazenar o hash dos refresh tokens?
|
|
144
|
+
|
|
145
|
+
Um JWT não pode ser revogado antes de expirar. Armazenar seu hash permite:
|
|
146
|
+
|
|
147
|
+
* logout;
|
|
148
|
+
* rotação do refresh token;
|
|
149
|
+
* invalidação após troca de senha;
|
|
150
|
+
* bloqueio da reutilização de tokens revogados.
|
|
151
|
+
|
|
152
|
+
O token original não é persistido. Cada refresh token também recebe um `jti` único para impedir colisões quando duas emissões acontecem no mesmo segundo.
|
|
153
|
+
|
|
154
|
+
### Por que `UserEntity` ainda existe?
|
|
155
|
+
|
|
156
|
+
No template Drizzle, `UserEntity` não é uma entidade de banco.
|
|
157
|
+
|
|
158
|
+
Ela é uma classe de resposta usada pelo `ClassSerializerInterceptor`. O decorator `@Exclude()` impede que `passwordHash` seja enviado pela API.
|
|
159
|
+
|
|
160
|
+
As tabelas e os tipos de persistência ficam nos schemas Drizzle.
|
|
161
|
+
|
|
162
|
+
### Por que Session/Cookies usa armazenamento persistente?
|
|
163
|
+
|
|
164
|
+
A estratégia Session/Cookies usa `express-session` com o `DrizzleSessionStore`.
|
|
165
|
+
|
|
166
|
+
As sessões ficam na tabela `sessions`, em vez da memória do processo. Isso permite reiniciar ou escalar a aplicação sem perder todas as sessões ativas.
|
|
167
|
+
|
|
168
|
+
O store implementa leitura, escrita, atualização, remoção e expiração usando o banco escolhido.
|
|
169
|
+
|
|
170
|
+
### Como funciona a proteção CSRF?
|
|
171
|
+
|
|
172
|
+
Na estratégia Session/Cookies, a aplicação usa um token CSRF associado à sessão.
|
|
173
|
+
|
|
174
|
+
Requisições que alteram estado precisam enviá-lo pelo header:
|
|
175
|
+
|
|
176
|
+
```http
|
|
177
|
+
x-csrf-token: <token>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
O middleware compara o valor recebido com o token armazenado na sessão.
|
|
181
|
+
|
|
182
|
+
Na estratégia JWT com Bearer token, o navegador não envia automaticamente a credencial em um cookie. Por isso esse fluxo CSRF não é necessário.
|
|
183
|
+
|
|
184
|
+
## Estratégias de autenticação
|
|
185
|
+
|
|
186
|
+
### JWT
|
|
187
|
+
|
|
188
|
+
1. Cadastro ou login valida o usuário.
|
|
189
|
+
2. `TokenService` emite access e refresh tokens.
|
|
190
|
+
3. O hash do refresh token é armazenado no banco.
|
|
191
|
+
4. `JwtAuthGuard` valida o Bearer token.
|
|
192
|
+
5. O refresh revoga o token anterior e emite um novo par.
|
|
193
|
+
6. O logout revoga o refresh token.
|
|
194
|
+
|
|
195
|
+
### Session/Cookies
|
|
196
|
+
|
|
197
|
+
1. Cadastro ou login valida o usuário.
|
|
198
|
+
2. A sessão é regenerada para evitar session fixation.
|
|
199
|
+
3. O usuário e o token CSRF são armazenados na sessão.
|
|
200
|
+
4. O navegador recebe o cookie `nestforge.sid`.
|
|
201
|
+
5. `SessionAuthGuard` protege as rotas.
|
|
202
|
+
6. O logout destrói a sessão.
|
|
203
|
+
|
|
204
|
+
### OAuth
|
|
205
|
+
|
|
206
|
+
Google e GitHub são vinculados pela tabela `oauth_accounts`.
|
|
207
|
+
|
|
208
|
+
Se o e-mail ainda não estiver cadastrado, um usuário é criado e associado ao provedor. O resultado do callback segue a estratégia escolhida: tokens JWT ou sessão persistente.
|
|
209
|
+
|
|
210
|
+
## Principais tabelas
|
|
211
|
+
|
|
212
|
+
Os schemas podem incluir:
|
|
213
|
+
|
|
214
|
+
* `users`;
|
|
215
|
+
* `oauth_accounts`;
|
|
216
|
+
* `refresh_tokens`, quando autenticação por token estiver habilitada;
|
|
217
|
+
* `sessions`, quando Session/Cookies estiver habilitada;
|
|
218
|
+
* `password_reset_tokens`, quando recuperação de senha estiver habilitada;
|
|
219
|
+
* `email_verification_tokens`, quando verificação de e-mail estiver habilitada.
|
|
220
|
+
|
|
221
|
+
Tabelas condicionais usam marcadores para que apenas os recursos selecionados permaneçam no projeto gerado.
|
|
222
|
+
|
|
223
|
+
## Onde adicionar um módulo
|
|
224
|
+
|
|
225
|
+
Para adicionar um novo domínio seguindo as convenções do template, consulte [Adding a Module](docs/adding-a-module.md).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
**English** | [Português](CODE_OF_CONDUCT.pt-BR.md)
|
|
4
|
+
|
|
5
|
+
## Our commitment
|
|
6
|
+
|
|
7
|
+
We, as members, contributors, and maintainers, pledge to make participation in this project a harassment-free experience for everyone, regardless of age, body, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual orientation.
|
|
8
|
+
|
|
9
|
+
## Our standards
|
|
10
|
+
|
|
11
|
+
Examples of behavior that contributes to a positive environment:
|
|
12
|
+
|
|
13
|
+
- Using welcoming and inclusive language
|
|
14
|
+
- Respecting different viewpoints and experiences
|
|
15
|
+
- Gracefully accepting constructive criticism
|
|
16
|
+
- Focusing on what is best for the community
|
|
17
|
+
|
|
18
|
+
Examples of unacceptable behavior:
|
|
19
|
+
|
|
20
|
+
- The use of sexualized language or imagery
|
|
21
|
+
- Offensive comments or personal/political attacks
|
|
22
|
+
- Public or private harassment
|
|
23
|
+
- Publishing other people's private information without permission
|
|
24
|
+
|
|
25
|
+
## Enforcement
|
|
26
|
+
|
|
27
|
+
Instances of abusive behavior may be reported by opening an issue marked as confidential or by contacting the project maintainer directly. All complaints will be reviewed and investigated.
|
|
28
|
+
|
|
29
|
+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Código de Conduta
|
|
2
|
+
|
|
3
|
+
[English](CODE_OF_CONDUCT.md) | **Português**
|
|
4
|
+
|
|
5
|
+
## Nosso compromisso
|
|
6
|
+
|
|
7
|
+
Nós, como membros, contribuintes e mantenedores, nos comprometemos a fazer da participação neste projeto uma experiência livre de assédio para todos, independentemente de idade, corpo, deficiência, etnia, identidade e expressão de gênero, nível de experiência, nacionalidade, aparência pessoal, raça, religião ou orientação sexual.
|
|
8
|
+
|
|
9
|
+
## Nossos padrões
|
|
10
|
+
|
|
11
|
+
Exemplos de comportamento que contribuem para um ambiente positivo:
|
|
12
|
+
- Usar linguagem acolhedora e inclusiva
|
|
13
|
+
- Respeitar pontos de vista e experiências diferentes
|
|
14
|
+
- Aceitar críticas construtivas com elegância
|
|
15
|
+
- Focar no que é melhor para a comunidade
|
|
16
|
+
|
|
17
|
+
Exemplos de comportamento inaceitável:
|
|
18
|
+
- Uso de linguagem ou imagens sexualizadas
|
|
19
|
+
- Comentários ofensivos ou ataques pessoais/políticos
|
|
20
|
+
- Assédio público ou privado
|
|
21
|
+
- Publicar informações privadas de terceiros sem permissão
|
|
22
|
+
|
|
23
|
+
## Aplicação
|
|
24
|
+
|
|
25
|
+
Casos de comportamento abusivo podem ser reportados abrindo uma issue marcada como confidencial ou entrando em contato diretamente com o mantenedor do projeto. Todas as reclamações serão revisadas e investigadas.
|
|
26
|
+
|
|
27
|
+
Este Código de Conduta é adaptado do [Contributor Covenant](https://www.contributor-covenant.org), versão 2.1.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Contributing to NestForge
|
|
2
|
+
|
|
3
|
+
**English** | [Português](CONTRIBUTING.pt-BR.md)
|
|
4
|
+
|
|
5
|
+
Thank you for considering contributing! 🎉
|
|
6
|
+
|
|
7
|
+
## Getting started
|
|
8
|
+
|
|
9
|
+
1. Fork the repository
|
|
10
|
+
2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/nestforge.git`
|
|
11
|
+
3. Create a branch: `git checkout -b feat/feature-name`
|
|
12
|
+
4. Start the environment: `docker compose up` (or `npm install` + `npm run start:dev`)
|
|
13
|
+
5. Make your changes
|
|
14
|
+
6. Run tests and lint before committing: `npm run test && npm run lint`
|
|
15
|
+
7. Commit according to the convention below
|
|
16
|
+
8. Open a Pull Request describing what was changed and why
|
|
17
|
+
|
|
18
|
+
## Commit convention
|
|
19
|
+
|
|
20
|
+
We use Portuguese commit messages following [Conventional Commits](https://www.conventionalcommits.org/):
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
feat: adiciona autenticação via Google OAuth
|
|
24
|
+
fix: corrige validação do refresh token
|
|
25
|
+
docs: atualiza guia de instalação
|
|
26
|
+
test: adiciona testes de integração para users
|
|
27
|
+
refactor: extrai lógica de hash para utils
|
|
28
|
+
chore: atualiza dependências
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Code standards
|
|
32
|
+
|
|
33
|
+
- If your code is related to an optional CLI feature (Swagger, Redis, RBAC, etc.), mark it according to [`docs/feature-markers.md`](docs/feature-markers.md). Without this, the CLI cannot remove the code when someone disables the feature.
|
|
34
|
+
- Strict TypeScript (no unjustified `any`)
|
|
35
|
+
- Always validate input through Zod (DTOs)
|
|
36
|
+
- No business logic in controllers — controllers only orchestrate, services handle the logic
|
|
37
|
+
- Every new route requires Swagger decorators (`@ApiTags`, `@ApiOperation`, etc.)
|
|
38
|
+
- Every new feature requires tests (at least unit tests)
|
|
39
|
+
|
|
40
|
+
## Reporting bugs
|
|
41
|
+
|
|
42
|
+
Open an issue containing:
|
|
43
|
+
|
|
44
|
+
- A description of the problem
|
|
45
|
+
- Steps to reproduce it
|
|
46
|
+
- Expected versus actual behavior
|
|
47
|
+
- Node version / environment (Docker or local)
|
|
48
|
+
|
|
49
|
+
## Suggesting features
|
|
50
|
+
|
|
51
|
+
Before implementing, open an issue with the `enhancement` label describing the problem the feature solves. This avoids rework if the approach needs to be discussed.
|
|
52
|
+
|
|
53
|
+
## Code of Conduct
|
|
54
|
+
|
|
55
|
+
By contributing, you agree to follow the project's [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
56
|
+
|
|
57
|
+
---
|