{"_id":"@averildwi/nest-common","_rev":"7-6f17350742baacdee5e677ead425c88b","name":"@averildwi/nest-common","dist-tags":{"latest":"1.0.6"},"versions":{"1.0.0":{"name":"@averildwi/nest-common","version":"1.0.0","keywords":[],"author":"","license":"ISC","_id":"@averildwi/nest-common@1.0.0","maintainers":[{"name":"averildwi","email":"averildwiy@gmail.com"}],"bin":{"nest-common":"index.js"},"dist":{"shasum":"3febb4c92dc6efc073427237c4b766efa4811c09","tarball":"https://registry.npmjs.org/@averildwi/nest-common/-/nest-common-1.0.0.tgz","fileCount":18,"integrity":"sha512-DV2a9pMwJemG2iO8xKKhIdrkOTkP9q/BszKoVJFj5Eysz0a8dzTeBSW1vguHl5t74fzMtpa6eLz7pUNKYCWG3A==","signatures":[{"sig":"MEQCICXadZniJymrzVJdRlWZaxucQYPA33iEPAYzDDKSLi7tAiBEM9OGwOofTKfrOHbPHv5VmvetXFV5AVqH2MMPFFPapg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":14712},"main":"index.js","type":"commonjs","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"averildwi","email":"averildwiy@gmail.com"},"_npmVersion":"11.7.0","description":"Generator otomatis untuk memasang folder common komplit ke proyek NestJS","directories":{},"_nodeVersion":"22.17.1","dependencies":{"fs-extra":"^11.3.6"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/nest-common_1.0.0_1784059061118_0.967701373361386","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@averildwi/nest-common","version":"1.0.1","keywords":[],"author":"","license":"ISC","_id":"@averildwi/nest-common@1.0.1","maintainers":[{"name":"averildwi","email":"averildwiy@gmail.com"}],"bin":{"nest-common":"index.js"},"dist":{"shasum":"d6c2a7745fcd2f9b31ae02c984da39c25e695604","tarball":"https://registry.npmjs.org/@averildwi/nest-common/-/nest-common-1.0.1.tgz","fileCount":20,"integrity":"sha512-S7RA0DhGCrsI4oWp6nqBzsuQHsHMC8tdFhgFJ9DVV+Qht6NaQwzTc2x4IoDmgzpeawSj8Kt+f7z8KvrZpWkHDA==","signatures":[{"sig":"MEUCIF++9FyM+Ef/XTx3wdck4w8lt8oE07XeuTmmWBQUy99vAiEA+Le5QjKyt/AtcLUzB8pWAla63Nquxs9skMsv0wJ2eM0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":28900},"main":"index.js","type":"commonjs","gitHead":"5d8b0fad342f559b14afc76fe216be2b2e6979e7","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"averildwi","email":"averildwiy@gmail.com"},"_npmVersion":"11.7.0","description":"Automated generator to inject a complete common folder into NestJS","directories":{},"_nodeVersion":"22.17.1","dependencies":{"fs-extra":"^11.3.6"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/nest-common_1.0.1_1784093501452_0.6141964623131433","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@averildwi/nest-common","version":"1.0.2","keywords":[],"author":"","license":"ISC","_id":"@averildwi/nest-common@1.0.2","maintainers":[{"name":"averildwi","email":"averildwiy@gmail.com"}],"bin":{"nest-common":"index.js"},"dist":{"shasum":"a30c0eba3b9432f8374c8592d6295a3e6b2744f8","tarball":"https://registry.npmjs.org/@averildwi/nest-common/-/nest-common-1.0.2.tgz","fileCount":20,"integrity":"sha512-J20W13lkYKE7ZwTPl3exsn3KCb2z+GnKKc7BWodcH5qrxe92cZ1dUDjeBCiykGW+Lldn8XMnRxtgL7UXq8kJdQ==","signatures":[{"sig":"MEUCIQCWJALZcwwhSoOFVCcN59QPUqzbVjivrNS0QVBwmVyrPAIgD5C+fayWN8q8zF3Pygc5yCYjZF/DjC6dENCT56s0wlU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":31430},"main":"index.js","type":"commonjs","gitHead":"0cfd8e75e90953c2a94996b0d5206aab66219eb5","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"averildwi","email":"averildwiy@gmail.com"},"_npmVersion":"11.7.0","description":"Automated generator to inject a complete common folder into NestJS","directories":{},"_nodeVersion":"22.17.1","dependencies":{"fs-extra":"^11.3.6"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/nest-common_1.0.2_1784096048623_0.6215739814754737","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@averildwi/nest-common","version":"1.0.3","keywords":[],"author":"","license":"ISC","_id":"@averildwi/nest-common@1.0.3","maintainers":[{"name":"averildwi","email":"averildwiy@gmail.com"}],"bin":{"nest-common":"index.js"},"dist":{"shasum":"34c3c790ab408912bb12e83109b8d1e5eb1e8188","tarball":"https://registry.npmjs.org/@averildwi/nest-common/-/nest-common-1.0.3.tgz","fileCount":20,"integrity":"sha512-zZAuB/TlI/BbRWypBlskz+082ECVcalGmXvX9NN/PlDXtBdbgHiGYXAolbO7thR7w/cGZMVT8wVvk2yWMegr/w==","signatures":[{"sig":"MEUCIDN9OXKRqRc+V5y2fUOcEU0TiYPNV0MSAXJDf+qjkK99AiEA4G7xOQPhu300YdSLZor9KRLkfGC3fjyW/xE/9j2/e68=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38795},"main":"index.js","type":"commonjs","gitHead":"3a98236a20cca2a554c370d9308f763051b8d90e","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"averildwi","email":"averildwiy@gmail.com"},"_npmVersion":"11.7.0","description":"Automated generator to inject a complete common folder into NestJS","directories":{},"_nodeVersion":"22.17.1","dependencies":{"fs-extra":"^11.3.6","inquirer":"^9.0.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/nest-common_1.0.3_1784097478594_0.1455791103288151","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@averildwi/nest-common","version":"1.0.4","keywords":[],"author":"","license":"ISC","_id":"@averildwi/nest-common@1.0.4","maintainers":[{"name":"averildwi","email":"averildwiy@gmail.com"}],"bin":{"nest-common":"index.js"},"dist":{"shasum":"a37ace5bd15ee1f28a4948617e07a91c295c5f6f","tarball":"https://registry.npmjs.org/@averildwi/nest-common/-/nest-common-1.0.4.tgz","fileCount":20,"integrity":"sha512-EvyfvAXUb2MvOyvW+YEMxbuW1P7KzPTiVCsSZmnZ2Fqj7gi7ey4I6i6lAXZ55RDrYEdJ5aCDT11GPcRrZwfUCQ==","signatures":[{"sig":"MEYCIQD55K7zTs+QB8X6v0tYpW1gR6fC7Gqd0QIgXC3cBaiTGwIhAPBkJq4p+lUBb/s5z+CJnfRLvFEXjnMOK39Fj7R7UJIQ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":41286},"main":"index.js","type":"commonjs","gitHead":"2a836c343c6b682e7cb9322cfd22403a7cf7fd35","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"averildwi","email":"averildwiy@gmail.com"},"_npmVersion":"11.7.0","description":"Automated generator to inject a complete common folder into NestJS","directories":{},"_nodeVersion":"22.17.1","dependencies":{"fs-extra":"^11.3.6","inquirer":"^9.0.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/nest-common_1.0.4_1784099536780_0.3507435302007824","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"@averildwi/nest-common","version":"1.0.5","keywords":[],"author":"","license":"ISC","_id":"@averildwi/nest-common@1.0.5","maintainers":[{"name":"averildwi","email":"averildwiy@gmail.com"}],"bin":{"nest-common":"index.js"},"dist":{"shasum":"f5d8512dfdf7c4ad091a938bc260dcedf338aa28","tarball":"https://registry.npmjs.org/@averildwi/nest-common/-/nest-common-1.0.5.tgz","fileCount":20,"integrity":"sha512-Xv0Y2wzOR6Zz1ntCGBnulIFVYfiEDmYjMoLC9uFBKV3qYN/TY83pA1gsUgMwqrkCJ0ws57CvmwAYkdFJ2VBs2A==","signatures":[{"sig":"MEYCIQDoci475lbgsR7obDn8NzHLVGLG/o1ZBA6KgaZyNyPaFgIhAPl9soYitiE1LgBNpqGvIXoKW7eLPAi1/zRgj0sopFP4","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":40517},"main":"index.js","type":"commonjs","gitHead":"18e7f974efc295a5fde4322456fa4fcff17dda3b","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"averildwi","email":"averildwiy@gmail.com"},"_npmVersion":"11.7.0","description":"Automated generator to inject a complete common folder into NestJS","directories":{},"_nodeVersion":"22.17.1","dependencies":{"fs-extra":"^11.3.6","inquirer":"^9.0.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/nest-common_1.0.5_1784099887093_0.33048453030735536","host":"s3://npm-registry-packages-npm-production"}},"1.0.6":{"_id":"@averildwi/nest-common@1.0.6","bin":{"nest-common":"index.js"},"dist":{"shasum":"7e31b973e4bedc91f254f6a725a8315df2d90577","tarball":"https://registry.npmjs.org/@averildwi/nest-common/-/nest-common-1.0.6.tgz","fileCount":20,"integrity":"sha512-ncXqqWusmcTcJZS9BP02nBtbTSz4ezyvCXrEdABIHTOcYJtiv/V/U8EPzqrhpHgg+kSKTPmCTU87MO370ITKPQ==","signatures":[{"sig":"MEUCIQCtYlR0BuDhmF5p2pUJ2ZC4RHJF9aQEATFfvCEnuv9TiQIgWg/A1BCulvlh+EKJp5ZIRW0R63DOdzkF/vvII+86N+0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIFGRjysNXdwdLjpS9ngGtueYFfYDcoBq6vionGBWbY2AAiA4EpWvH7qXbfZM8xBnhFrkOTzmrKXJw+alPxrtW4e4NA=="}],"unpackedSize":43558},"main":"index.js","name":"@averildwi/nest-common","type":"commonjs","author":"","gitHead":"b0f4863a259e6d1ccc3901095e447ff6245eaa00","license":"ISC","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"version":"1.0.6","_npmUser":{"name":"averildwi","email":"averildwiy@gmail.com"},"keywords":[],"_npmVersion":"11.7.0","description":"Automated generator to inject a complete common folder into NestJS","directories":{},"maintainers":[{"name":"averildwi","email":"averildwiy@gmail.com"}],"_nodeVersion":"22.17.1","dependencies":{"fs-extra":"^11.3.6","inquirer":"^9.0.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nest-common_1.0.6_1790063861170_0.49376250073018135"}}},"time":{"created":"2026-07-14T19:57:41.028Z","modified":"2026-09-22T07:57:41.422Z","1.0.0":"2026-07-14T19:57:41.267Z","1.0.1":"2026-07-15T05:31:41.603Z","1.0.2":"2026-07-15T06:14:08.755Z","1.0.3":"2026-07-15T06:37:58.747Z","1.0.4":"2026-07-15T07:12:16.947Z","1.0.5":"2026-07-15T07:18:07.241Z","1.0.6":"2026-09-22T07:57:41.259Z"},"license":"ISC","keywords":[],"description":"Automated generator to inject a complete common folder into NestJS","maintainers":[{"name":"averildwi","email":"averildwiy@gmail.com"}],"readme":"# @averildwi/nest-common\r\n\r\n[![npm version](https://img.shields.io/npm/v/@averildwi/nest-common.svg)](https://www.npmjs.com/package/@averildwi/nest-common)\r\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\r\n[![Node.js](https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen)](https://nodejs.org)\r\n[![NestJS](https://img.shields.io/badge/NestJS-v11-red)](https://nestjs.com)\r\n\r\nAn interactive CLI scaffolder that injects a collection of reusable modules\r\n(filters, guards, interceptors, pipes, decorators, config, helpers) into a\r\n[NestJS](https://nestjs.com/) project — plus automatic `main.ts` wiring\r\n(CORS, global pipes/interceptors/filters, optional Swagger setup) and\r\n`.env.example` generation. Built to avoid rewriting the same boilerplate for\r\nevery new backend: just run one command and you're ready to go.\r\n\r\n## Installation\r\n\r\n```bash\r\nnpx @averildwi/nest-common\r\n```\r\n\r\n### Peer dependencies\r\n\r\nThis package doesn't bundle its dependencies — the CLI installs them into\r\nyour project automatically:\r\n\r\n```bash\r\n# installed automatically by the CLI\r\nnpm install @nestjs/config @nestjs/passport @nestjs/swagger\r\nnpm install class-validator class-transformer joi\r\n```\r\n\r\nThe CLI reads the `@nestjs/common` version already present in your project and\r\npins each package to the matching major (Nest 10, 11, or 12), so a new\r\necosystem major never breaks your install with `ERESOLVE`. If the version\r\ncan't be detected, it falls back to `latest`, and any remaining peer conflict\r\nis retried once with `--legacy-peer-deps`.\r\n\r\nYou still need `@nestjs/common`, `@nestjs/core`, and `@prisma/client`\r\n(only if you use `PrismaExceptionFilter`) set up in your project beforehand.\r\n\r\n> If your ORM isn't Prisma, just skip `PrismaExceptionFilter` — everything\r\n> else works fine.\r\n\r\n## What the CLI Does\r\n\r\n```\r\nnpx @averildwi/nest-common\r\n   │\r\n   ▼\r\n[1/5] Copy common modules into src/common (existing files are never overwritten)\r\n   │\r\n   ▼\r\n[2/5] Register AppConfigModule + HashingModule into src/app.module.ts\r\n   │\r\n   ▼\r\n[3/5] Wire src/main.ts — CORS, global pipes/interceptors/filters,\r\n      and (optional, asked interactively) Swagger docs\r\n   │\r\n   ▼\r\n[4/5] Generate/patch .env.example with required Joi variables\r\n      (JWT_SECRET is randomly generated per project)\r\n   │\r\n   ▼\r\n[5/5] Install dependencies + auto-run lint fix if configured\r\n```\r\n\r\nThe CLI is **idempotent** — running it again on a project that already has\r\nthese files won't overwrite your changes; it only fills in what's missing\r\nand warns you about what it skipped.\r\n\r\n### Interactive prompts\r\n\r\n| Prompt | When it appears |\r\n|---|---|\r\n| Setup Swagger API Documentation? | Always |\r\n| Swagger title / description / version / docs path | Only if Swagger is enabled |\r\n\r\n## Package Contents\r\n\r\n| Folder | Contents | Purpose |\r\n|---|---|---|\r\n| `config/` | `AppConfigModule`, `baseEnvSchema` | Environment variable validation using Joi, extendable per project |\r\n| `decorators/` | `CurrentUser`, `Roles` | Extract user from request, specify roles allowed to access endpoints |\r\n| `dto/` | `PaginationDto` | Standard pagination query DTO (page, limit, skip) |\r\n| `filters/` | `GlobalExceptionFilter`, `PrismaExceptionFilter` | Standardize error response shape |\r\n| `guards/` | `JwtAuthGuard`, `RolesGuard` | JWT authentication + role-based access control |\r\n| `helpers/` | `buildErrorResponse`, `paginate` | Pure helpers, no dependency injection |\r\n| `hashing/` | `HashingModule`, `HashingService` | Hash & verify passwords using native scrypt |\r\n| `interceptors/` | `LoggerInterceptor`, `TransformInterceptor` | Log requests/responses, wrap successful responses in standard shape |\r\n| `pipes/` | `createValidationPipe` | Standard `ValidationPipe` configuration + per-field error messages |\r\n\r\n## Quick Start\r\n\r\n### 1. Run the scaffolder\r\n\r\n```bash\r\nnpx @averildwi/nest-common\r\n```\r\n\r\nAnswer the Swagger prompt (and the follow-up questions if you enable it).\r\nEverything else — copying modules, registering `AppModule`, wiring\r\n`main.ts`, generating `.env.example`, installing dependencies — is handled\r\nautomatically.\r\n\r\n### 2. Fill in project-specific env vars (optional)\r\n\r\n```typescript\r\n// src/config/app-config.module.ts\r\nimport * as Joi from 'joi';\r\nimport { AppConfigModule } from '../common/config/app-config.module';\r\n\r\nexport const ProjectConfigModule = AppConfigModule.forProject(\r\n  Joi.object({\r\n    // add project-specific env vars here\r\n    CLOUDINARY_CLOUD_NAME: Joi.string().required(),\r\n    CLOUDINARY_API_KEY: Joi.string().required(),\r\n    CLOUDINARY_API_SECRET: Joi.string().required(),\r\n  }),\r\n);\r\n```\r\n\r\n```typescript\r\n// src/app.module.ts — ProjectConfigModule needs to be added manually\r\n// if you defined extra env vars; AppConfigModule.forProject() (default,\r\n// no extra schema) is already registered by the CLI.\r\nimport { Module } from '@nestjs/common';\r\nimport { ProjectConfigModule } from './config/app-config.module';\r\n\r\n@Module({\r\n  imports: [ProjectConfigModule /* other modules */],\r\n})\r\nexport class AppModule {}\r\n```\r\n\r\n### 3. Copy values from `.env.example` into your `.env`\r\n\r\nThe CLI generates `.env.example` with the variables required by\r\n`baseEnvSchema`, using a randomly generated `JWT_SECRET`. Copy what you\r\nneed into your own `.env` (which should stay out of git — the CLI warns\r\nyou if `.env` isn't in `.gitignore`).\r\n\r\n### 4. Use in a controller\r\n\r\n```typescript\r\nimport { Controller, Get, UseGuards } from '@nestjs/common';\r\nimport { JwtAuthGuard } from '../common/guards/jwt-auth.guard';\r\nimport { RolesGuard } from '../common/guards/roles.guard';\r\nimport { Roles } from '../common/decorators/roles.decorator';\r\nimport { CurrentUser } from '../common/decorators/current-user.decorator';\r\nimport { PaginationDto } from '../common/dto/pagination.dto';\r\nimport { Paginated } from '../common/helpers/paginate.helper';\r\n\r\n@Controller('users')\r\nexport class UsersController {\r\n  @UseGuards(JwtAuthGuard, RolesGuard)\r\n  @Roles('ADMIN')\r\n  @Get()\r\n  async findAll(@Query() pagination: PaginationDto) {\r\n    const [data, total] = await this.usersService.findAll(pagination);\r\n    return new Paginated(data, {\r\n      page: pagination.page,\r\n      limit: pagination.limit,\r\n      total,\r\n    });\r\n  }\r\n\r\n  @UseGuards(JwtAuthGuard)\r\n  @Get('me')\r\n  getProfile(@CurrentUser() user: any) {\r\n    return user;\r\n  }\r\n}\r\n```\r\n\r\n## What Gets Generated in `main.ts`\r\n\r\n```typescript\r\nasync function bootstrap() {\r\n  const app = await NestFactory.create(AppModule);\r\n\r\n  // ── Injected by @averildwi/nest-common ──\r\n  const allowedOrigins = process.env.FRONTEND_URL ? process.env.FRONTEND_URL.split(',') : '*';\r\n  app.enableCors({\r\n    origin: allowedOrigins,\r\n    methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],\r\n  });\r\n  app.useGlobalPipes(createValidationPipe());\r\n  app.useGlobalInterceptors(new LoggerInterceptor(), new TransformInterceptor());\r\n  app.useGlobalFilters(new GlobalExceptionFilter(), new PrismaExceptionFilter());\r\n\r\n  // Only if Swagger is enabled during setup\r\n  const config = new DocumentBuilder()\r\n    .setTitle('My API')\r\n    .setDescription('API documentation')\r\n    .setVersion('1.0')\r\n    .addBearerAuth(/* ... */, 'access-token')\r\n    .build();\r\n  const document = SwaggerModule.createDocument(app, config);\r\n  SwaggerModule.setup('docs', app, document, {\r\n    swaggerOptions: { persistAuthorization: true },\r\n  });\r\n\r\n  await app.listen(process.env.PORT ?? 3000);\r\n}\r\nbootstrap();\r\n```\r\n\r\n## Response Shape\r\n\r\nAll responses (success or error) follow a consistent shape, so the\r\nfrontend doesn't need to handle different formats:\r\n\r\n**Success:**\r\n```json\r\n{\r\n  \"statusCode\": 200,\r\n  \"message\": \"Success\",\r\n  \"data\": { \"...\": \"...\" },\r\n  \"timestamp\": \"2026-07-15T10:00:00.000Z\"\r\n}\r\n```\r\n\r\n**Error:**\r\n```json\r\n{\r\n  \"statusCode\": 400,\r\n  \"message\": [\"email: email must be an email\"],\r\n  \"data\": null,\r\n  \"error\": \"BadRequestException\",\r\n  \"timestamp\": \"2026-07-15T10:00:00.000Z\"\r\n}\r\n```\r\n\r\n## Request Flow\r\n\r\n```\r\nRequest\r\n   │\r\n   ▼\r\nLoggerInterceptor (log \"-->\")\r\n   │\r\n   ▼\r\nGuards (JwtAuthGuard → RolesGuard)\r\n   │\r\n   ▼\r\nValidationPipe (createValidationPipe)\r\n   │\r\n   ▼\r\nController/Service\r\n   │\r\n   ├── Success ──► TransformInterceptor ──► Response\r\n   │\r\n   └── Throw ───► GlobalExceptionFilter / PrismaExceptionFilter ──► Response\r\n```\r\n\r\n## Important Notes\r\n\r\n- **The CLI never overwrites existing files.** If `src/common`,\r\n  `app.module.ts` registration, or `main.ts` wiring already exist, those\r\n  steps are skipped with a warning instead of silently replacing your code.\r\n- **`.env.example`, not `.env`, is generated/patched** — the CLI never\r\n  touches your real `.env`, so your actual credentials are never at risk.\r\n  `JWT_SECRET` is randomly generated per run, never hardcoded.\r\n- **`RolesGuard`** assumes `user.role` is a single string. If your project\r\n  needs multi-role per user (array), extend/override it yourself.\r\n- **`JwtAuthGuard`** must run before `RolesGuard` in the\r\n  `@UseGuards(...)` order, because `RolesGuard` requires `request.user` to be set.\r\n- Error messages in `PrismaExceptionFilter` are still hardcoded in Indonesian.\r\n  If you need multi-language support, override the messages in your project.\r\n- `baseEnvSchema` only covers universal env vars (DATABASE_URL, PORT,\r\n  NODE_ENV, FRONTEND_URL, JWT_SECRET, JWT_EXPIRES_IN). Project-specific env vars\r\n  are added via `AppConfigModule.forProject(extraSchema)`.\r\n- Not yet tested with `pnpm`/`yarn` — NPM is assumed.\r\n\r\n## License\r\n\r\nMIT License","readmeFilename":"README.md"}