@urbansolv/create-nestjs-app 1.0.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/README.md +121 -0
- package/dist/cli.d.mts +2 -0
- package/dist/cli.mjs +18 -0
- package/dist/commands/create.d.ts +12 -0
- package/dist/commands/create.js +103 -0
- package/dist/templates/nestjs-app/.editorconfig +12 -0
- package/dist/templates/nestjs-app/.env.example +24 -0
- package/dist/templates/nestjs-app/.eslintrc.js +25 -0
- package/dist/templates/nestjs-app/.prettierrc +8 -0
- package/dist/templates/nestjs-app/README.md +133 -0
- package/dist/templates/nestjs-app/nest-cli.json +10 -0
- package/dist/templates/nestjs-app/package.json +83 -0
- package/dist/templates/nestjs-app/prisma/schema.prisma +79 -0
- package/dist/templates/nestjs-app/prisma/seed.ts +154 -0
- package/dist/templates/nestjs-app/src/app.module.ts +68 -0
- package/dist/templates/nestjs-app/src/common/constants/permissions.constant.ts +27 -0
- package/dist/templates/nestjs-app/src/common/decorators/api-response.decorator.ts +44 -0
- package/dist/templates/nestjs-app/src/common/decorators/get-user.decorator.ts +11 -0
- package/dist/templates/nestjs-app/src/common/decorators/permissions.decorator.ts +5 -0
- package/dist/templates/nestjs-app/src/common/decorators/public.decorator.ts +4 -0
- package/dist/templates/nestjs-app/src/common/dto/api-response.dto.ts +21 -0
- package/dist/templates/nestjs-app/src/common/dto/pagination.dto.ts +33 -0
- package/dist/templates/nestjs-app/src/common/filters/http-exception.filter.ts +56 -0
- package/dist/templates/nestjs-app/src/common/guards/jwt-auth.guard.ts +32 -0
- package/dist/templates/nestjs-app/src/common/guards/permissions.guard.ts +53 -0
- package/dist/templates/nestjs-app/src/common/interceptors/logging.interceptor.ts +37 -0
- package/dist/templates/nestjs-app/src/common/interceptors/transform.interceptor.ts +55 -0
- package/dist/templates/nestjs-app/src/common/prisma/prisma.module.ts +9 -0
- package/dist/templates/nestjs-app/src/common/prisma/prisma.service.ts +46 -0
- package/dist/templates/nestjs-app/src/common/utils/password.util.ts +13 -0
- package/dist/templates/nestjs-app/src/config/app.config.ts +10 -0
- package/dist/templates/nestjs-app/src/config/database.config.ts +5 -0
- package/dist/templates/nestjs-app/src/config/env.validation.ts +30 -0
- package/dist/templates/nestjs-app/src/config/jwt.config.ts +8 -0
- package/dist/templates/nestjs-app/src/config/swagger.config.ts +6 -0
- package/dist/templates/nestjs-app/src/main.ts +91 -0
- package/dist/templates/nestjs-app/src/modules/auth/auth.module.ts +27 -0
- package/dist/templates/nestjs-app/src/modules/auth/auth.service.ts +54 -0
- package/dist/templates/nestjs-app/src/modules/auth/controllers/v1/auth.controller.ts +33 -0
- package/dist/templates/nestjs-app/src/modules/auth/dto/auth-response.dto.ts +19 -0
- package/dist/templates/nestjs-app/src/modules/auth/dto/login.dto.ts +15 -0
- package/dist/templates/nestjs-app/src/modules/auth/dto/register.dto.ts +30 -0
- package/dist/templates/nestjs-app/src/modules/auth/interfaces/jwt-payload.interface.ts +7 -0
- package/dist/templates/nestjs-app/src/modules/auth/strategies/jwt.strategy.ts +54 -0
- package/dist/templates/nestjs-app/src/modules/health/health.controller.ts +29 -0
- package/dist/templates/nestjs-app/src/modules/health/health.module.ts +7 -0
- package/dist/templates/nestjs-app/src/modules/users/controllers/v1/users.controller.ts +114 -0
- package/dist/templates/nestjs-app/src/modules/users/core/dto/change-position.dto.ts +9 -0
- package/dist/templates/nestjs-app/src/modules/users/core/dto/create-user.dto.ts +35 -0
- package/dist/templates/nestjs-app/src/modules/users/core/dto/manage-permissions.dto.ts +13 -0
- package/dist/templates/nestjs-app/src/modules/users/core/dto/update-user.dto.ts +0 -0
- package/dist/templates/nestjs-app/src/modules/users/core/dto/user-query.dto.ts +22 -0
- package/dist/templates/nestjs-app/src/modules/users/core/entities/user.entity.ts +45 -0
- package/dist/templates/nestjs-app/src/modules/users/core/helpers/user-transform.helper.ts +31 -0
- package/dist/templates/nestjs-app/src/modules/users/users.module.ts +10 -0
- package/dist/templates/nestjs-app/src/modules/users/users.service.ts +340 -0
- package/dist/templates/nestjs-app/test/app.e2e-spec.ts +40 -0
- package/dist/templates/nestjs-app/test/jest-e2e.json +9 -0
- package/dist/templates/nestjs-app/tsconfig.json +26 -0
- package/dist/utils/file-utils.d.ts +5 -0
- package/dist/utils/file-utils.js +37 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.js +18 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# @urbansolv/create-nestjs-app
|
|
2
|
+
|
|
3
|
+
Official CLI tool to scaffold Urbansolv NestJS applications with built-in RBAC, Prisma ORM, and best practices.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
✅ Complete NestJS boilerplate following Urbansolv standards
|
|
8
|
+
✅ Role-Based Access Control (RBAC) pre-configured
|
|
9
|
+
✅ Prisma ORM with PostgreSQL
|
|
10
|
+
✅ JWT Authentication
|
|
11
|
+
✅ Auto-generated Swagger documentation
|
|
12
|
+
✅ Production-ready structure
|
|
13
|
+
✅ Comprehensive seed data
|
|
14
|
+
✅ Testing setup included
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
```bash
|
|
18
|
+
# Using npx (recommended)
|
|
19
|
+
npx @urbansolv/create-nestjs-app my-app
|
|
20
|
+
|
|
21
|
+
# Using npm
|
|
22
|
+
npm init @urbansolv/nestjs-app my-app
|
|
23
|
+
|
|
24
|
+
# Using yarn
|
|
25
|
+
yarn create @urbansolv/nestjs-app my-app
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
```bash
|
|
30
|
+
create-urbansolv-app [project-name] [options]
|
|
31
|
+
|
|
32
|
+
Options:
|
|
33
|
+
-p, --package-manager <manager> Package manager to use (npm, yarn, pnpm)
|
|
34
|
+
-d, --database <name> Database name
|
|
35
|
+
--skip-install Skip package installation
|
|
36
|
+
-h, --help Display help
|
|
37
|
+
-V, --version Display version
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Examples
|
|
41
|
+
```bash
|
|
42
|
+
# Create app with default settings
|
|
43
|
+
npx @urbansolv/create-nestjs-app my-awesome-app
|
|
44
|
+
|
|
45
|
+
# Create app with yarn and custom database
|
|
46
|
+
npx @urbansolv/create-nestjs-app my-app -p yarn -d my_database
|
|
47
|
+
|
|
48
|
+
# Create app without installing dependencies
|
|
49
|
+
npx @urbansolv/create-nestjs-app my-app --skip-install
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## After Installation
|
|
53
|
+
```bash
|
|
54
|
+
cd my-app
|
|
55
|
+
|
|
56
|
+
# Copy environment variables
|
|
57
|
+
cp .env.example .env
|
|
58
|
+
|
|
59
|
+
# Edit .env with your database credentials
|
|
60
|
+
|
|
61
|
+
# Run migrations
|
|
62
|
+
npm run prisma:migrate
|
|
63
|
+
|
|
64
|
+
# Seed database
|
|
65
|
+
npm run prisma:seed
|
|
66
|
+
|
|
67
|
+
# Start development server
|
|
68
|
+
npm run start:dev
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Default Credentials
|
|
72
|
+
|
|
73
|
+
After seeding:
|
|
74
|
+
|
|
75
|
+
**Admin:**
|
|
76
|
+
- Email: admin@urbansolv.co.id
|
|
77
|
+
- Password: password123
|
|
78
|
+
|
|
79
|
+
**Member:**
|
|
80
|
+
- Email: member@urbansolv.co.id
|
|
81
|
+
- Password: password123
|
|
82
|
+
|
|
83
|
+
## Documentation
|
|
84
|
+
|
|
85
|
+
For full documentation, visit: [Urbansolv Documentation](https://docs.urbansolv.co.id)
|
|
86
|
+
|
|
87
|
+
## Support
|
|
88
|
+
|
|
89
|
+
- Issues: https://github.com/godwimp/create-nestjs-app/issues
|
|
90
|
+
- Email: support@urbansolv.co.id
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT © Urbansolv
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 22.5 LICENSE File
|
|
98
|
+
|
|
99
|
+
**urbansolv-nestjs-cli/LICENSE**
|
|
100
|
+
```
|
|
101
|
+
MIT License
|
|
102
|
+
|
|
103
|
+
Copyright (c) 2024 Urbansolv
|
|
104
|
+
|
|
105
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
106
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
107
|
+
in the Software without restriction, including without limitation the rights
|
|
108
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
109
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
110
|
+
furnished to do so, subject to the following conditions:
|
|
111
|
+
|
|
112
|
+
The above copyright notice and this permission notice shall be included in all
|
|
113
|
+
copies or substantial portions of the Software.
|
|
114
|
+
|
|
115
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
116
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
117
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
118
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
119
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
120
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
121
|
+
SOFTWARE.
|
package/dist/cli.d.mts
ADDED
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { CreateCommand } from "./commands/create.js";
|
|
4
|
+
const program = new Command();
|
|
5
|
+
program
|
|
6
|
+
.name('urbansolv-nest')
|
|
7
|
+
.description('CLI to generate Urbansolv NestJS boilerplate projects')
|
|
8
|
+
.version('1.0.0');
|
|
9
|
+
program
|
|
10
|
+
.argument('[project-name', 'Name of the project')
|
|
11
|
+
.option('-p, --package-manager <manager>', 'Package manager to use (npm, yarn, pnpm)')
|
|
12
|
+
.option('-d, --database <name>', 'Database name')
|
|
13
|
+
.option('--skip-install', 'Skip package installation')
|
|
14
|
+
.action(async (projectName, options) => {
|
|
15
|
+
const createCommand = new CreateCommand();
|
|
16
|
+
await createCommand.execute(projectName, options);
|
|
17
|
+
});
|
|
18
|
+
program.parse();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface CreateOptions {
|
|
2
|
+
projectName: string;
|
|
3
|
+
database?: string;
|
|
4
|
+
packageManager?: "npm" | "yarn" | "pnpm";
|
|
5
|
+
skipInstall?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare class CreateCommand {
|
|
8
|
+
execute(projectName?: string, options?: Partial<CreateOptions>): Promise<void>;
|
|
9
|
+
private createProject;
|
|
10
|
+
private installDependencies;
|
|
11
|
+
private printSuccessMessage;
|
|
12
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
import { FileUtils } from "../utils/file-utils.js";
|
|
6
|
+
import { Logger } from "../utils/logger.js";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
export class CreateCommand {
|
|
11
|
+
async execute(projectName, options) {
|
|
12
|
+
Logger.title("Urbansolv NestJS Boilerplate Generator");
|
|
13
|
+
const answers = await inquirer.prompt([
|
|
14
|
+
{
|
|
15
|
+
type: "input",
|
|
16
|
+
name: "projectName",
|
|
17
|
+
message: "Project name:",
|
|
18
|
+
default: projectName || "my-urbansolv-app",
|
|
19
|
+
when: !projectName,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
type: "list",
|
|
23
|
+
name: "packageManager",
|
|
24
|
+
message: "Package manager:",
|
|
25
|
+
choices: ["npm", "yarn", "pnpm"],
|
|
26
|
+
default: options?.packageManager || "npm",
|
|
27
|
+
when: !options?.packageManager,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
type: "input",
|
|
31
|
+
name: "database",
|
|
32
|
+
message: "Database name:",
|
|
33
|
+
default: "urbansolv_db",
|
|
34
|
+
when: !options?.database,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
type: "confirm",
|
|
38
|
+
name: "skipInstall",
|
|
39
|
+
message: "Skip package installation?",
|
|
40
|
+
default: false,
|
|
41
|
+
when: !options?.skipInstall === undefined,
|
|
42
|
+
},
|
|
43
|
+
]);
|
|
44
|
+
const config = {
|
|
45
|
+
projectName: projectName || answers.projectName,
|
|
46
|
+
database: options?.database || answers.database,
|
|
47
|
+
packageManager: options?.packageManager || answers.packageManager,
|
|
48
|
+
skipInstall: options?.skipInstall ?? answers.skipInstall,
|
|
49
|
+
};
|
|
50
|
+
await this.createProject(config);
|
|
51
|
+
}
|
|
52
|
+
async createProject(config) {
|
|
53
|
+
const targetPath = path.join(process.cwd(), config.projectName);
|
|
54
|
+
if (await FileUtils.fileExists(targetPath)) {
|
|
55
|
+
Logger.error(`Directory ${config.projectName} already exists!`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
const spinner = ora("Creating project structure...").start();
|
|
59
|
+
try {
|
|
60
|
+
const templatePath = path.join(__dirname, "../../templates/nestjs-app");
|
|
61
|
+
await FileUtils.copyTemplate(templatePath, targetPath, {
|
|
62
|
+
__PROJECT_NAME__: config.projectName,
|
|
63
|
+
__DATABASE_NAME__: config.database || "urbansolv_db",
|
|
64
|
+
});
|
|
65
|
+
spinner.succeed("Project structure created.");
|
|
66
|
+
if (!config.skipInstall) {
|
|
67
|
+
await this.installDependencies(targetPath, config.packageManager);
|
|
68
|
+
}
|
|
69
|
+
this.printSuccessMessage(config);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
spinner.fail("Failed to create project.");
|
|
73
|
+
Logger.error(error instanceof Error ? error.message : "Unknown error");
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async installDependencies(projectPath, packageManager) {
|
|
78
|
+
const spinner = ora("Installing dependencies...").start();
|
|
79
|
+
try {
|
|
80
|
+
execSync(`cd ${projectPath} && ${packageManager} install`, {
|
|
81
|
+
stdio: "inherit",
|
|
82
|
+
});
|
|
83
|
+
spinner.succeed("Dependencies installed.");
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
spinner.fail("Failed to install dependencies.");
|
|
87
|
+
Logger.warning("You can install them manually later.");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async printSuccessMessage(config) {
|
|
91
|
+
Logger.success("\n Project Created Successfully! \n");
|
|
92
|
+
Logger.info("Next Steps:\n");
|
|
93
|
+
console.log(` cd ${config.projectName}`);
|
|
94
|
+
if (config.skipInstall) {
|
|
95
|
+
console.log(` ${config.packageManager} install`);
|
|
96
|
+
}
|
|
97
|
+
console.log(` cp .env.example .env`);
|
|
98
|
+
console.log(` # Update your .env file with database credentials`);
|
|
99
|
+
console.log(` npx prisma migrate dev`);
|
|
100
|
+
console.log(` npx prisma db seed`);
|
|
101
|
+
console.log(` npm run start:dev\n`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Application
|
|
2
|
+
NODE_ENV=development
|
|
3
|
+
PORT=3000
|
|
4
|
+
APP_NAME=__PROJECT_NAME__
|
|
5
|
+
|
|
6
|
+
# Database
|
|
7
|
+
DATABASE_URL="postgresql://username:password@localhost:5432/__DATABASE_NAME__?schema=public"
|
|
8
|
+
|
|
9
|
+
# JWT
|
|
10
|
+
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
|
|
11
|
+
JWT_EXPIRATION=7d
|
|
12
|
+
JWT_REFRESH_SECRET=your-super-secret-refresh-key-change-this-in-production
|
|
13
|
+
JWT_REFRESH_EXPIRATION=30d
|
|
14
|
+
|
|
15
|
+
# CORS
|
|
16
|
+
CORS_ORIGIN=http://localhost:3001
|
|
17
|
+
|
|
18
|
+
# API
|
|
19
|
+
API_PREFIX=api
|
|
20
|
+
API_VERSION=v1
|
|
21
|
+
|
|
22
|
+
# Swagger
|
|
23
|
+
SWAGGER_ENABLED=true
|
|
24
|
+
SWAGGER_PATH=api-docs
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
parser: '@typescript-eslint/parser',
|
|
3
|
+
parserOptions: {
|
|
4
|
+
project: 'tsconfig.json',
|
|
5
|
+
tsconfigRootDir: __dirname,
|
|
6
|
+
sourceType: 'module',
|
|
7
|
+
},
|
|
8
|
+
plugins: ['@typescript-eslint/eslint-plugin'],
|
|
9
|
+
extends: [
|
|
10
|
+
'plugin:@typescript-eslint/recommended',
|
|
11
|
+
'plugin:prettier/recommended',
|
|
12
|
+
],
|
|
13
|
+
root: true,
|
|
14
|
+
env: {
|
|
15
|
+
node: true,
|
|
16
|
+
jest: true,
|
|
17
|
+
},
|
|
18
|
+
ignorePatterns: ['.eslintrc.js'],
|
|
19
|
+
rules: {
|
|
20
|
+
'@typescript-eslint/interface-name-prefix': 'off',
|
|
21
|
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
22
|
+
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
23
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
24
|
+
},
|
|
25
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Urbansolv NestJS Backend
|
|
2
|
+
|
|
3
|
+
Backend application built with NestJS following Urbansolv standardization manual.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔐 JWT Authentication with RBAC
|
|
8
|
+
- 📝 Complete User Management
|
|
9
|
+
- 🎯 Permission-based Access Control
|
|
10
|
+
- 📚 Auto-generated Swagger Documentation
|
|
11
|
+
- ✅ Input Validation
|
|
12
|
+
- 🔄 API Versioning
|
|
13
|
+
- 📊 Structured Logging
|
|
14
|
+
- 🗃️ Prisma ORM with PostgreSQL
|
|
15
|
+
- 🧪 Testing Setup (Unit & E2E)
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
|
|
19
|
+
- Node.js >= 18.x
|
|
20
|
+
- PostgreSQL >= 14.x
|
|
21
|
+
- npm/yarn/pnpm
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
```bash
|
|
25
|
+
# Install dependencies
|
|
26
|
+
npm install
|
|
27
|
+
|
|
28
|
+
# Setup environment variables
|
|
29
|
+
cp .env.example .env
|
|
30
|
+
# Edit .env with your database credentials
|
|
31
|
+
|
|
32
|
+
# Generate Prisma Client
|
|
33
|
+
npm run prisma:generate
|
|
34
|
+
|
|
35
|
+
# Run migrations
|
|
36
|
+
npm run prisma:migrate
|
|
37
|
+
|
|
38
|
+
# Seed database
|
|
39
|
+
npm run prisma:seed
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Running the Application
|
|
43
|
+
```bash
|
|
44
|
+
# Development
|
|
45
|
+
npm run start:dev
|
|
46
|
+
|
|
47
|
+
# Production build
|
|
48
|
+
npm run build
|
|
49
|
+
npm run start:prod
|
|
50
|
+
|
|
51
|
+
# Debug mode
|
|
52
|
+
npm run start:debug
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Database Commands
|
|
56
|
+
```bash
|
|
57
|
+
# Generate Prisma Client
|
|
58
|
+
npm run prisma:generate
|
|
59
|
+
|
|
60
|
+
# Create migration
|
|
61
|
+
npm run prisma:migrate
|
|
62
|
+
|
|
63
|
+
# Seed database
|
|
64
|
+
npm run prisma:seed
|
|
65
|
+
|
|
66
|
+
# Open Prisma Studio
|
|
67
|
+
npm run prisma:studio
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Testing
|
|
71
|
+
```bash
|
|
72
|
+
# Unit tests
|
|
73
|
+
npm run test
|
|
74
|
+
|
|
75
|
+
# E2E tests
|
|
76
|
+
npm run test:e2e
|
|
77
|
+
|
|
78
|
+
# Test coverage
|
|
79
|
+
npm run test:cov
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## API Documentation
|
|
83
|
+
|
|
84
|
+
After starting the application, visit:
|
|
85
|
+
- Swagger UI: `http://localhost:3000/api-docs`
|
|
86
|
+
|
|
87
|
+
## Default Users
|
|
88
|
+
|
|
89
|
+
After seeding the database:
|
|
90
|
+
|
|
91
|
+
**Admin User:**
|
|
92
|
+
- Email: `admin@urbansolv.com`
|
|
93
|
+
- Password: `password123`
|
|
94
|
+
- All permissions granted
|
|
95
|
+
|
|
96
|
+
**Member User:**
|
|
97
|
+
- Email: `member@urbansolv.com`
|
|
98
|
+
- Password: `password123`
|
|
99
|
+
- Limited permissions (VIEW_USER only)
|
|
100
|
+
|
|
101
|
+
## Project Structure
|
|
102
|
+
```
|
|
103
|
+
src/
|
|
104
|
+
├── common/ # Shared resources
|
|
105
|
+
│ ├── decorators/ # Custom decorators
|
|
106
|
+
│ ├── filters/ # Exception filters
|
|
107
|
+
│ ├── guards/ # Auth & permission guards
|
|
108
|
+
│ ├── interceptors/ # Logging & transform
|
|
109
|
+
│ ├── prisma/ # Prisma service
|
|
110
|
+
│ └── utils/ # Helper functions
|
|
111
|
+
├── config/ # Configuration files
|
|
112
|
+
├── modules/ # Feature modules
|
|
113
|
+
│ ├── auth/ # Authentication
|
|
114
|
+
│ ├── users/ # User management
|
|
115
|
+
│ └── health/ # Health checks
|
|
116
|
+
├── app.module.ts # Root module
|
|
117
|
+
└── main.ts # Application entry point
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Environment Variables
|
|
121
|
+
|
|
122
|
+
See `.env.example` for all available configuration options.
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
Proprietary - Urbansolv
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 20.2 .gitkeep for migrations
|
|
130
|
+
|
|
131
|
+
**templates/nestjs-app/prisma/migrations/.gitkeep**
|
|
132
|
+
```
|
|
133
|
+
# This file keeps the migrations directory in git
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Urbansolv NestJS Application",
|
|
5
|
+
"author": "Urbansolv",
|
|
6
|
+
"private": true,
|
|
7
|
+
"license": "UNLICENSED",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "nest build",
|
|
10
|
+
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
11
|
+
"start": "nest start",
|
|
12
|
+
"start:dev": "nest start --watch",
|
|
13
|
+
"start:debug": "nest start --debug --watch",
|
|
14
|
+
"start:prod": "node dist/main",
|
|
15
|
+
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
|
16
|
+
"test": "jest",
|
|
17
|
+
"test:watch": "jest --watch",
|
|
18
|
+
"test:cov": "jest --coverage",
|
|
19
|
+
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
|
20
|
+
"test:e2e": "jest --config ./test/jest-e2e.json",
|
|
21
|
+
"prisma:generate": "prisma generate",
|
|
22
|
+
"prisma:migrate": "prisma migrate dev",
|
|
23
|
+
"prisma:studio": "prisma studio",
|
|
24
|
+
"prisma:seed": "ts-node prisma/seed.ts"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@nestjs/common": "^11.0.1",
|
|
28
|
+
"@nestjs/config": "^4.0.2",
|
|
29
|
+
"@nestjs/core": "^11.0.1",
|
|
30
|
+
"@nestjs/passport": "^11.0.5",
|
|
31
|
+
"@nestjs/platform-express": "^11.0.1",
|
|
32
|
+
"@nestjs/swagger": "^11.2.3",
|
|
33
|
+
"@prisma/client": "^6.19.0",
|
|
34
|
+
"bcryptjs": "^3.0.3",
|
|
35
|
+
"class-transformer": "^0.5.1",
|
|
36
|
+
"class-validator": "^0.14.0",
|
|
37
|
+
"joi": "^18.0.2",
|
|
38
|
+
"passport": "^0.7.0",
|
|
39
|
+
"passport-jwt": "^4.0.1",
|
|
40
|
+
"reflect-metadata": "^0.2.2",
|
|
41
|
+
"rxjs": "^7.8.1"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@nestjs/cli": "^11.0.0",
|
|
45
|
+
"@nestjs/schematics": "^11.0.0",
|
|
46
|
+
"@nestjs/testing": "^11.0.1",
|
|
47
|
+
"@types/bcrypt": "^6.0.0",
|
|
48
|
+
"@types/express": "^5.0.5",
|
|
49
|
+
"@types/jest": "^30.0.0",
|
|
50
|
+
"@types/node": "^22.10.7",
|
|
51
|
+
"@types/passport-jwt": "^4.0.1",
|
|
52
|
+
"@types/supertest": "^6.0.2",
|
|
53
|
+
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
54
|
+
"@typescript-eslint/parser": "^8.54.0",
|
|
55
|
+
"eslint": "^9.18.0",
|
|
56
|
+
"eslint-config-prettier": "^10.0.1",
|
|
57
|
+
"eslint-plugin-prettier": "^5.2.2",
|
|
58
|
+
"jest": "^30.0.0",
|
|
59
|
+
"prettier": "^3.4.2",
|
|
60
|
+
"prisma": "^6.19.0",
|
|
61
|
+
"source-map-support": "^0.5.21",
|
|
62
|
+
"supertest": "^7.0.0",
|
|
63
|
+
"ts-jest": "^29.2.5",
|
|
64
|
+
"ts-loader": "^9.5.2",
|
|
65
|
+
"ts-node": "^10.9.2",
|
|
66
|
+
"tsconfig-paths": "^4.2.0",
|
|
67
|
+
"typescript": "^5.7.3"
|
|
68
|
+
},
|
|
69
|
+
"prisma": {
|
|
70
|
+
"seed": "ts-node prisma/seed.ts"
|
|
71
|
+
},
|
|
72
|
+
"jest": {
|
|
73
|
+
"moduleFileExtensions": ["js", "json", "ts"],
|
|
74
|
+
"rootDir": "src",
|
|
75
|
+
"testRegex": ".*\\.spec\\.ts$",
|
|
76
|
+
"transform": {
|
|
77
|
+
"^.+\\.(t|j)s$": "ts-jest"
|
|
78
|
+
},
|
|
79
|
+
"collectCoverageFrom": ["**/*.(t|j)s"],
|
|
80
|
+
"coverageDirectory": "../coverage",
|
|
81
|
+
"testEnvironment": "node"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// This is your Prisma schema file,
|
|
2
|
+
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
3
|
+
|
|
4
|
+
generator client {
|
|
5
|
+
provider = "prisma-client-js"
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
datasource db {
|
|
9
|
+
provider = "postgresql"
|
|
10
|
+
url = env("DATABASE_URL")
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// ============================================
|
|
14
|
+
// RBAC Schema
|
|
15
|
+
// ============================================
|
|
16
|
+
|
|
17
|
+
model User {
|
|
18
|
+
id Int @id @default(autoincrement())
|
|
19
|
+
email String @unique
|
|
20
|
+
password String
|
|
21
|
+
first_name String
|
|
22
|
+
last_name String
|
|
23
|
+
is_active Boolean @default(true)
|
|
24
|
+
created_at DateTime @default(now())
|
|
25
|
+
updated_at DateTime @updatedAt
|
|
26
|
+
deleted_at DateTime?
|
|
27
|
+
|
|
28
|
+
// Relations
|
|
29
|
+
position_id Int
|
|
30
|
+
position Position @relation(fields: [position_id], references: [id])
|
|
31
|
+
|
|
32
|
+
@@map("users")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
model Position {
|
|
36
|
+
id Int @id @default(autoincrement())
|
|
37
|
+
name String @unique
|
|
38
|
+
description String?
|
|
39
|
+
is_active Boolean @default(true)
|
|
40
|
+
created_at DateTime @default(now())
|
|
41
|
+
updated_at DateTime @updatedAt
|
|
42
|
+
deleted_at DateTime?
|
|
43
|
+
|
|
44
|
+
// Relations
|
|
45
|
+
users User[]
|
|
46
|
+
position_permissions PositionPermission[]
|
|
47
|
+
|
|
48
|
+
@@map("positions")
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
model Permission {
|
|
52
|
+
id Int @id @default(autoincrement())
|
|
53
|
+
name String @unique
|
|
54
|
+
description String?
|
|
55
|
+
resource String // e.g., 'USER', 'TRANSACTION', 'REPORT'
|
|
56
|
+
action String // e.g., 'VIEW', 'ADD', 'UPDATE', 'DELETE'
|
|
57
|
+
created_at DateTime @default(now())
|
|
58
|
+
updated_at DateTime @updatedAt
|
|
59
|
+
deleted_at DateTime?
|
|
60
|
+
|
|
61
|
+
// Relations
|
|
62
|
+
position_permissions PositionPermission[]
|
|
63
|
+
|
|
64
|
+
@@map("permissions")
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
model PositionPermission {
|
|
68
|
+
id Int @id @default(autoincrement())
|
|
69
|
+
position_id Int
|
|
70
|
+
permission_id Int
|
|
71
|
+
created_at DateTime @default(now())
|
|
72
|
+
|
|
73
|
+
// Relations
|
|
74
|
+
position Position @relation(fields: [position_id], references: [id], onDelete: Cascade)
|
|
75
|
+
permission Permission @relation(fields: [permission_id], references: [id], onDelete: Cascade)
|
|
76
|
+
|
|
77
|
+
@@unique([position_id, permission_id])
|
|
78
|
+
@@map("position_permissions")
|
|
79
|
+
}
|