nodejs-quickstart-structure 1.3.5 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/docs/generateCase.md +54 -38
- package/docs/generatorFlow.md +171 -0
- package/lib/generator.js +46 -18
- package/lib/prompts.js +1 -1
- package/package.json +4 -3
- package/templates/clean-architecture/js/src/index.js.ejs +5 -0
- package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +11 -2
- package/templates/clean-architecture/ts/src/domain/user.ts +1 -1
- package/templates/clean-architecture/ts/src/index.ts.ejs +10 -5
- package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +13 -4
- package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts +5 -5
- package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +1 -1
- package/templates/clean-architecture/ts/src/usecases/createUser.ts +2 -2
- package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +1 -1
- package/templates/common/Dockerfile +1 -0
- package/templates/common/README.md.ejs +1 -1
- package/templates/common/database/js/models/User.js.mongoose.ejs +19 -0
- package/templates/common/database/js/mongoose.js.ejs +32 -0
- package/templates/common/database/ts/models/User.ts.ejs +1 -1
- package/templates/common/database/ts/models/User.ts.mongoose.ejs +25 -0
- package/templates/common/database/ts/mongoose.ts.ejs +27 -0
- package/templates/common/docker-compose.yml.ejs +31 -8
- package/templates/common/jest.config.js.ejs +4 -1
- package/templates/common/kafka/ts/services/kafkaService.ts.ejs +1 -1
- package/templates/common/migrate-mongo-config.js.ejs +31 -0
- package/templates/common/migrations/init.js.ejs +23 -0
- package/templates/common/package.json.ejs +12 -6
- package/templates/common/public/css/style.css +147 -0
- package/templates/common/tsconfig.json +5 -1
- package/templates/common/views/ejs/index.ejs +44 -20
- package/templates/common/views/pug/index.pug +32 -18
- package/templates/mvc/js/src/controllers/userController.js.ejs +3 -1
- package/templates/mvc/js/src/index.js.ejs +6 -1
- package/templates/mvc/ts/src/controllers/userController.ts.ejs +6 -4
- package/templates/mvc/ts/src/index.ts.ejs +11 -7
- package/templates/mvc/ts/src/routes/api.ts +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
const UserSchema = new mongoose.Schema({
|
|
4
|
+
name: {
|
|
5
|
+
type: String,
|
|
6
|
+
required: true
|
|
7
|
+
},
|
|
8
|
+
email: {
|
|
9
|
+
type: String,
|
|
10
|
+
required: true,
|
|
11
|
+
unique: true
|
|
12
|
+
},
|
|
13
|
+
createdAt: {
|
|
14
|
+
type: Date,
|
|
15
|
+
default: Date.now
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
module.exports = mongoose.model('User', UserSchema);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
let logger;
|
|
4
|
+
<% if (architecture === 'MVC') { %>
|
|
5
|
+
logger = require('../utils/logger');
|
|
6
|
+
<% } else { %>
|
|
7
|
+
logger = require('../log/logger');
|
|
8
|
+
<% } %>
|
|
9
|
+
|
|
10
|
+
const connectDB = async () => {
|
|
11
|
+
const dbHost = process.env.DB_HOST || 'localhost';
|
|
12
|
+
const mongoURI = process.env.MONGO_URI || `mongodb://${dbHost}:27017/<%= dbName %>`;
|
|
13
|
+
|
|
14
|
+
let retries = 5;
|
|
15
|
+
while (retries) {
|
|
16
|
+
try {
|
|
17
|
+
await mongoose.connect(mongoURI, {
|
|
18
|
+
useNewUrlParser: true,
|
|
19
|
+
useUnifiedTopology: true
|
|
20
|
+
});
|
|
21
|
+
logger.info('MongoDB Connected...');
|
|
22
|
+
break;
|
|
23
|
+
} catch (err) {
|
|
24
|
+
logger.error('MongoDB connection failed:', err);
|
|
25
|
+
retries -= 1;
|
|
26
|
+
logger.info(`Retries left: ${retries}. Waiting 5s...`);
|
|
27
|
+
await new Promise(res => setTimeout(res, 5000));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
module.exports = connectDB; // Export function to call in index.js
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DataTypes, Model } from 'sequelize';
|
|
2
|
-
<% if (architecture === 'MVC') { %>import sequelize from '
|
|
2
|
+
<% if (architecture === 'MVC') { %>import sequelize from '@/config/database';<% } else { %>import sequelize from '@/infrastructure/database/database';<% } %>
|
|
3
3
|
|
|
4
4
|
class User extends Model {
|
|
5
5
|
public id!: number;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import mongoose, { Schema, Document } from 'mongoose';
|
|
2
|
+
|
|
3
|
+
export interface IUser extends Document {
|
|
4
|
+
name: string;
|
|
5
|
+
email: string;
|
|
6
|
+
createdAt: Date;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const UserSchema: Schema = new Schema({
|
|
10
|
+
name: {
|
|
11
|
+
type: String,
|
|
12
|
+
required: true
|
|
13
|
+
},
|
|
14
|
+
email: {
|
|
15
|
+
type: String,
|
|
16
|
+
required: true,
|
|
17
|
+
unique: true
|
|
18
|
+
},
|
|
19
|
+
createdAt: {
|
|
20
|
+
type: Date,
|
|
21
|
+
default: Date.now
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export default mongoose.model<IUser>('User', UserSchema);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import mongoose from 'mongoose';
|
|
2
|
+
<% if (architecture === 'MVC') { %>
|
|
3
|
+
import logger from '@/utils/logger';
|
|
4
|
+
<% } else { %>
|
|
5
|
+
import logger from '@/infrastructure/log/logger';
|
|
6
|
+
<% } %>
|
|
7
|
+
|
|
8
|
+
const connectDB = async (): Promise<void> => {
|
|
9
|
+
const dbHost = process.env.DB_HOST || 'localhost';
|
|
10
|
+
const mongoURI = process.env.MONGO_URI || `mongodb://${dbHost}:27017/<%= dbName %>`;
|
|
11
|
+
|
|
12
|
+
let retries = 5;
|
|
13
|
+
while (retries) {
|
|
14
|
+
try {
|
|
15
|
+
await mongoose.connect(mongoURI);
|
|
16
|
+
logger.info('MongoDB Connected...');
|
|
17
|
+
break;
|
|
18
|
+
} catch (err) {
|
|
19
|
+
logger.error('MongoDB connection failed:', err);
|
|
20
|
+
retries -= 1;
|
|
21
|
+
logger.info(`Retries left: ${retries}. Waiting 5s...`);
|
|
22
|
+
await new Promise(res => setTimeout(res, 5000));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default connectDB;
|
|
@@ -18,7 +18,7 @@ services:
|
|
|
18
18
|
- DB_PASSWORD=root
|
|
19
19
|
- DB_NAME=<%= dbName %>
|
|
20
20
|
<% } %><% if (database === 'PostgreSQL') { %> - DB_USER=postgres
|
|
21
|
-
- DB_PASSWORD=
|
|
21
|
+
- DB_PASSWORD=root
|
|
22
22
|
- DB_NAME=<%= dbName %>
|
|
23
23
|
<% } -%>
|
|
24
24
|
<% } else { %>
|
|
@@ -29,30 +29,52 @@ services:
|
|
|
29
29
|
- DB_PASSWORD=root
|
|
30
30
|
- DB_NAME=<%= dbName %>
|
|
31
31
|
<% } %><% if (database === 'PostgreSQL') { %> - DB_USER=postgres
|
|
32
|
-
- DB_PASSWORD=
|
|
32
|
+
- DB_PASSWORD=root
|
|
33
33
|
- DB_NAME=<%= dbName %>
|
|
34
34
|
<% } -%>
|
|
35
35
|
<% } %>
|
|
36
36
|
db:
|
|
37
37
|
<% if (database === 'MySQL') { %> image: mysql:8.0
|
|
38
|
-
command: --default-authentication-plugin=mysql_native_password
|
|
39
38
|
restart: always
|
|
40
39
|
environment:
|
|
41
40
|
MYSQL_ROOT_PASSWORD: root
|
|
42
41
|
MYSQL_DATABASE: <%= dbName %>
|
|
43
42
|
ports:
|
|
44
43
|
- "${DB_PORT:-3306}:3306"
|
|
45
|
-
|
|
44
|
+
volumes:
|
|
45
|
+
- ./flyway/sql:/docker-entrypoint-initdb.d
|
|
46
|
+
<% } else if (database === 'PostgreSQL') { %> image: postgres:15
|
|
46
47
|
restart: always
|
|
47
48
|
environment:
|
|
48
49
|
POSTGRES_USER: postgres
|
|
49
|
-
POSTGRES_PASSWORD:
|
|
50
|
+
POSTGRES_PASSWORD: root
|
|
50
51
|
POSTGRES_DB: <%= dbName %>
|
|
51
52
|
ports:
|
|
52
53
|
- "${DB_PORT:-5432}:5432"
|
|
53
|
-
|
|
54
|
-
-
|
|
54
|
+
volumes:
|
|
55
|
+
- ./flyway/sql:/docker-entrypoint-initdb.d
|
|
56
|
+
<% } else if (database === 'MongoDB') { %> image: mongo:latest
|
|
57
|
+
restart: always
|
|
58
|
+
environment:
|
|
59
|
+
MONGO_INITDB_DATABASE: <%= dbName %>
|
|
60
|
+
ports:
|
|
61
|
+
- "${DB_PORT:-27017}:27017"
|
|
62
|
+
volumes:
|
|
63
|
+
- mongodb_data:/data/db
|
|
55
64
|
|
|
65
|
+
mongo-migrate:
|
|
66
|
+
image: node:18-alpine
|
|
67
|
+
working_dir: /app
|
|
68
|
+
volumes:
|
|
69
|
+
- .:/app
|
|
70
|
+
command: sh -c "npm install migrate-mongo && npm run migrate"
|
|
71
|
+
environment:
|
|
72
|
+
- DB_HOST=db
|
|
73
|
+
- DB_NAME=<%= dbName %>
|
|
74
|
+
depends_on:
|
|
75
|
+
- db
|
|
76
|
+
<% } %>
|
|
77
|
+
<% if (database !== 'MongoDB') { %>
|
|
56
78
|
flyway:
|
|
57
79
|
image: flyway/flyway
|
|
58
80
|
command: -connectRetries=60 migrate
|
|
@@ -64,9 +86,10 @@ services:
|
|
|
64
86
|
FLYWAY_PASSWORD: root
|
|
65
87
|
<% } %><% if (database === 'PostgreSQL') { %> FLYWAY_URL: jdbc:postgresql://db:5432/<%= dbName %>
|
|
66
88
|
FLYWAY_USER: postgres
|
|
67
|
-
FLYWAY_PASSWORD:
|
|
89
|
+
FLYWAY_PASSWORD: root
|
|
68
90
|
<% } %> depends_on:
|
|
69
91
|
- db
|
|
92
|
+
<% } %>
|
|
70
93
|
<% if (communication === 'Kafka') { %> zookeeper:
|
|
71
94
|
image: confluentinc/cp-zookeeper:7.4.0
|
|
72
95
|
environment:
|
|
@@ -3,7 +3,10 @@ module.exports = {
|
|
|
3
3
|
coverageDirectory: 'coverage',
|
|
4
4
|
collectCoverageFrom: ['src/**/*.{js,ts}'],
|
|
5
5
|
testMatch: ['**/*.test.ts', '**/*.test.js'],
|
|
6
|
-
<% if (language === 'TypeScript') { %>preset: 'ts-jest'
|
|
6
|
+
<% if (language === 'TypeScript') { %>preset: 'ts-jest',
|
|
7
|
+
moduleNameMapper: {
|
|
8
|
+
'^@/(.*)$': '<rootDir>/src/$1',
|
|
9
|
+
},<% } %>
|
|
7
10
|
coveragePathIgnorePatterns: [
|
|
8
11
|
"/node_modules/",
|
|
9
12
|
"/dist/"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const config = {
|
|
2
|
+
mongodb: {
|
|
3
|
+
url: process.env.MONGO_URI || `mongodb://${process.env.DB_HOST || 'localhost'}:27017`,
|
|
4
|
+
databaseName: process.env.DB_NAME || '<%= dbName %>',
|
|
5
|
+
|
|
6
|
+
options: {
|
|
7
|
+
// useNewUrlParser: true, // No longer needed in Node.js driver v4+
|
|
8
|
+
// useUnifiedTopology: true, // No longer needed in Node.js driver v4+
|
|
9
|
+
// connectTimeoutMS: 3600000, // increase connection timeout to 1 hour
|
|
10
|
+
// socketTimeoutMS: 3600000, // increase socket timeout to 1 hour
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
// The migrations dir, can be an relative or absolute path. Only edit this when really necessary.
|
|
15
|
+
migrationsDir: "migrations",
|
|
16
|
+
|
|
17
|
+
// The mongodb collection where the applied changes are stored. Only edit this when really necessary.
|
|
18
|
+
changelogCollectionName: "changelog",
|
|
19
|
+
|
|
20
|
+
// The file extension to create migrations and search for in migration dir
|
|
21
|
+
migrationFileExtension: ".js",
|
|
22
|
+
|
|
23
|
+
// Enable the algorithm to create a checksum of the file contents and use that in the comparison to determine
|
|
24
|
+
// if the file should be run. Requires that scripts are coded to be run multiple times.
|
|
25
|
+
useFileHash: false,
|
|
26
|
+
|
|
27
|
+
// Don't change this, unless you know what you are doing
|
|
28
|
+
moduleSystem: 'commonjs',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
module.exports = config;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
async up(db, client) {
|
|
3
|
+
const adminEmail = 'admin@example.com';
|
|
4
|
+
const existingAdmin = await db.collection('users').findOne({ email: adminEmail });
|
|
5
|
+
|
|
6
|
+
if (!existingAdmin) {
|
|
7
|
+
await db.collection('users').insertOne({
|
|
8
|
+
name: 'Admin User',
|
|
9
|
+
email: adminEmail,
|
|
10
|
+
createdAt: new Date(),
|
|
11
|
+
updatedAt: new Date()
|
|
12
|
+
});
|
|
13
|
+
console.log('Admin User seeded successfully');
|
|
14
|
+
} else {
|
|
15
|
+
console.log('Admin User already exists, skipping seed');
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
async down(db, client) {
|
|
20
|
+
// Optional: Undo the seed. Usually for seeds we might want to keep data, but strictly speaking 'down' should reverse 'up'.
|
|
21
|
+
// await db.collection('users').deleteOne({ email: 'admin@example.com' });
|
|
22
|
+
}
|
|
23
|
+
};
|
|
@@ -5,24 +5,29 @@
|
|
|
5
5
|
"main": "<% if (language === 'TypeScript') { %>dist/index.js<% } else { %>src/index.js<% } %>",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"start": "<% if (language === 'TypeScript') { %>node dist/index.js<% } else { %>node src/index.js<% } %>",
|
|
8
|
-
"dev": "<% if (language === 'TypeScript') { %>nodemon --exec ts-node src/index.ts<% } else { %>nodemon src/index.js<% } %>"<% if (language === 'TypeScript') { %>,
|
|
9
|
-
"build": "rimraf dist && tsc<% if (viewEngine && viewEngine !== 'None') { %> && copyfiles -u 1 \"src/views/**/*\" dist/<% } %>"<% } %>,
|
|
8
|
+
"dev": "<% if (language === 'TypeScript') { %>nodemon --exec ts-node -r tsconfig-paths/register src/index.ts<% } else { %>nodemon src/index.js<% } %>"<% if (language === 'TypeScript') { %>,
|
|
9
|
+
"build": "rimraf dist && tsc && tsc-alias<% if (viewEngine && viewEngine !== 'None') { %> && copyfiles -u 1 \"src/views/**/*\" dist/<% } %>"<% } %>,
|
|
10
10
|
"lint": "eslint . --ext .ts,.js",
|
|
11
11
|
"lint:fix": "eslint . --ext .ts,.js --fix",
|
|
12
12
|
"format": "prettier --write .",
|
|
13
13
|
"prepare": "husky install",
|
|
14
14
|
"test": "jest",
|
|
15
15
|
"test:watch": "jest --watch",
|
|
16
|
-
"test:coverage": "jest --coverage"
|
|
16
|
+
"test:coverage": "jest --coverage",
|
|
17
|
+
"migrate": "migrate-mongo up"
|
|
17
18
|
},
|
|
18
19
|
"dependencies": {
|
|
19
20
|
"express": "^4.18.2",
|
|
20
21
|
"dotenv": "^16.3.1",
|
|
21
22
|
<% if (database === 'MySQL') { %> "mysql2": "^3.6.5",
|
|
23
|
+
"sequelize": "^6.35.2",
|
|
22
24
|
<% } -%>
|
|
23
25
|
<% if (database === 'PostgreSQL') { %> "pg": "^8.11.3",
|
|
24
|
-
<% } -%>
|
|
25
26
|
"sequelize": "^6.35.2",
|
|
27
|
+
<% } -%>
|
|
28
|
+
<% if (database === 'MongoDB') { %> "mongoose": "^8.0.3",
|
|
29
|
+
"migrate-mongo": "^11.0.0",
|
|
30
|
+
<% } -%>
|
|
26
31
|
<% if (communication === 'Kafka') { %> "kafkajs": "^2.2.4",
|
|
27
32
|
<% } -%>
|
|
28
33
|
<% if (viewEngine === 'EJS') { %> "ejs": "^3.1.9",
|
|
@@ -35,8 +40,7 @@
|
|
|
35
40
|
"express-rate-limit": "^7.1.5",
|
|
36
41
|
"winston": "^3.11.0"<% if (communication === 'REST APIs') { %>,
|
|
37
42
|
"swagger-ui-express": "^5.0.0",
|
|
38
|
-
"swagger-jsdoc": "^6.2.8"
|
|
39
|
-
<% } %>
|
|
43
|
+
"swagger-jsdoc": "^6.2.8"<% } %>
|
|
40
44
|
},
|
|
41
45
|
"devDependencies": {
|
|
42
46
|
"nodemon": "^3.0.2"<% if (language === 'TypeScript') { %>,
|
|
@@ -65,6 +69,8 @@
|
|
|
65
69
|
"ts-jest": "^29.1.1",
|
|
66
70
|
"@types/jest": "^29.5.11",
|
|
67
71
|
"supertest": "^6.3.3",
|
|
72
|
+
"tsconfig-paths": "^4.2.0",
|
|
73
|
+
"tsc-alias": "^1.8.8",
|
|
68
74
|
"@types/supertest": "^6.0.2"<% } else { %>,
|
|
69
75
|
"jest": "^29.7.0",
|
|
70
76
|
"supertest": "^6.3.3"<% } %>
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--primary-color: #4f46e5;
|
|
3
|
+
--primary-hover: #4338ca;
|
|
4
|
+
--bg-color: #f9fafb;
|
|
5
|
+
--card-bg: #ffffff;
|
|
6
|
+
--text-main: #111827;
|
|
7
|
+
--text-muted: #6b7280;
|
|
8
|
+
--success-color: #10b981;
|
|
9
|
+
--border-color: #e5e7eb;
|
|
10
|
+
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
11
|
+
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
|
16
|
+
background-color: var(--bg-color);
|
|
17
|
+
color: var(--text-main);
|
|
18
|
+
margin: 0;
|
|
19
|
+
padding: 0;
|
|
20
|
+
line-height: 1.5;
|
|
21
|
+
display: flex;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
min-height: 100vh;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.container {
|
|
27
|
+
width: 100%;
|
|
28
|
+
max-width: 800px;
|
|
29
|
+
padding: 40px 20px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.header {
|
|
33
|
+
text-align: center;
|
|
34
|
+
margin-bottom: 40px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.logo {
|
|
38
|
+
font-size: 3rem;
|
|
39
|
+
margin-bottom: 10px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
h1 {
|
|
43
|
+
font-size: 2.5rem;
|
|
44
|
+
font-weight: 800;
|
|
45
|
+
color: var(--text-main);
|
|
46
|
+
margin: 0 0 10px 0;
|
|
47
|
+
letter-spacing: -0.025em;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.subtitle {
|
|
51
|
+
color: var(--text-muted);
|
|
52
|
+
font-size: 1.125rem;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.card-grid {
|
|
56
|
+
display: grid;
|
|
57
|
+
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
|
58
|
+
gap: 20px;
|
|
59
|
+
margin-bottom: 40px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.card {
|
|
63
|
+
background: var(--card-bg);
|
|
64
|
+
padding: 24px;
|
|
65
|
+
border-radius: 12px;
|
|
66
|
+
box-shadow: var(--shadow-sm);
|
|
67
|
+
border: 1px solid var(--border-color);
|
|
68
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.card:hover {
|
|
72
|
+
transform: translateY(-2px);
|
|
73
|
+
box-shadow: var(--shadow-md);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.card h3 {
|
|
77
|
+
margin-top: 0;
|
|
78
|
+
font-size: 0.875rem;
|
|
79
|
+
text-transform: uppercase;
|
|
80
|
+
letter-spacing: 0.05em;
|
|
81
|
+
color: var(--text-muted);
|
|
82
|
+
font-weight: 600;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.card p {
|
|
86
|
+
font-size: 1.25rem;
|
|
87
|
+
font-weight: 600;
|
|
88
|
+
color: var(--text-main);
|
|
89
|
+
margin: 5px 0 0 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.status-card {
|
|
93
|
+
background: var(--card-bg);
|
|
94
|
+
border-radius: 12px;
|
|
95
|
+
padding: 24px;
|
|
96
|
+
box-shadow: var(--shadow-md);
|
|
97
|
+
border-left: 6px solid var(--success-color);
|
|
98
|
+
display: flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
gap: 20px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.status-icon {
|
|
104
|
+
background: #d1fae5;
|
|
105
|
+
color: var(--success-color);
|
|
106
|
+
width: 48px;
|
|
107
|
+
height: 48px;
|
|
108
|
+
border-radius: 50%;
|
|
109
|
+
display: flex;
|
|
110
|
+
align-items: center;
|
|
111
|
+
justify-content: center;
|
|
112
|
+
font-size: 1.5rem;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.status-content h3 {
|
|
116
|
+
margin: 0;
|
|
117
|
+
font-size: 1.25rem;
|
|
118
|
+
font-weight: 700;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.status-content p {
|
|
122
|
+
margin: 5px 0 0 0;
|
|
123
|
+
color: var(--text-muted);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.action-btn {
|
|
127
|
+
display: inline-block;
|
|
128
|
+
margin-top: 40px;
|
|
129
|
+
background-color: var(--primary-color);
|
|
130
|
+
color: white;
|
|
131
|
+
padding: 12px 24px;
|
|
132
|
+
border-radius: 8px;
|
|
133
|
+
text-decoration: none;
|
|
134
|
+
font-weight: 600;
|
|
135
|
+
transition: background-color 0.2s;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.action-btn:hover {
|
|
139
|
+
background-color: var(--primary-hover);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
footer {
|
|
143
|
+
margin-top: 60px;
|
|
144
|
+
text-align: center;
|
|
145
|
+
color: var(--text-muted);
|
|
146
|
+
font-size: 0.875rem;
|
|
147
|
+
}
|
|
@@ -4,28 +4,52 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title><%= projectName %></title>
|
|
7
|
-
<style>
|
|
8
|
-
body { font-family: sans-serif; padding: 20px; }
|
|
9
|
-
h1 { color: #333; }
|
|
10
|
-
.status { margin-top: 20px; padding: 10px; background: #e0f7fa; border-left: 5px solid #00acc1; }
|
|
11
|
-
</style>
|
|
7
|
+
<link rel="stylesheet" href="/css/style.css">
|
|
12
8
|
</head>
|
|
13
9
|
<body>
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
<
|
|
22
|
-
|
|
10
|
+
<div class="container">
|
|
11
|
+
<header class="header">
|
|
12
|
+
<div class="logo">🚀</div>
|
|
13
|
+
<h1>Welcome to <%= projectName %></h1>
|
|
14
|
+
<p class="subtitle">A production-ready Node.js microservice starter.</p>
|
|
15
|
+
</header>
|
|
16
|
+
|
|
17
|
+
<div class="card-grid">
|
|
18
|
+
<div class="card">
|
|
19
|
+
<h3>Architecture</h3>
|
|
20
|
+
<p><%= architecture %></p>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="card">
|
|
23
|
+
<h3>Database</h3>
|
|
24
|
+
<p><%= database %></p>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="card">
|
|
27
|
+
<h3>Communication</h3>
|
|
28
|
+
<p><%= communication %></p>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<% if (communication === 'Kafka') { %>
|
|
33
|
+
<div class="status-card">
|
|
34
|
+
<div class="status-icon">🔄</div>
|
|
35
|
+
<div class="status-content">
|
|
36
|
+
<h3>Kafka Connected</h3>
|
|
37
|
+
<p>Connection to broker established successfully.</p>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
<% } else { %>
|
|
41
|
+
<div class="status-card">
|
|
42
|
+
<div class="status-icon">✅</div>
|
|
43
|
+
<div class="status-content">
|
|
44
|
+
<h3>API Active</h3>
|
|
45
|
+
<p>REST API is running and ready to accept requests.</p>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<% } %>
|
|
49
|
+
|
|
50
|
+
<footer>
|
|
51
|
+
<p>Generated with ❤️ by Node.js Quickstart Generator</p>
|
|
52
|
+
</footer>
|
|
23
53
|
</div>
|
|
24
|
-
<% } else { %>
|
|
25
|
-
<div class="status">
|
|
26
|
-
<h3>API Status</h3>
|
|
27
|
-
<p>REST API is active.</p>
|
|
28
|
-
</div>
|
|
29
|
-
<% } %>
|
|
30
54
|
</body>
|
|
31
55
|
</html>
|
|
@@ -4,23 +4,37 @@ html(lang="en")
|
|
|
4
4
|
meta(charset="UTF-8")
|
|
5
5
|
meta(name="viewport", content="width=device-width, initial-scale=1.0")
|
|
6
6
|
title= projectName
|
|
7
|
-
style.
|
|
8
|
-
body { font-family: sans-serif; padding: 20px; }
|
|
9
|
-
h1 { color: #333; }
|
|
10
|
-
.status { margin-top: 20px; padding: 10px; background: #e0f7fa; border-left: 5px solid #00acc1; }
|
|
7
|
+
link(rel="stylesheet", href="/css/style.css")
|
|
11
8
|
body
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
.container
|
|
10
|
+
header.header
|
|
11
|
+
.logo 🚀
|
|
12
|
+
h1 Welcome to #{projectName}
|
|
13
|
+
p.subtitle A production-ready Node.js microservice starter.
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
.card-grid
|
|
16
|
+
.card
|
|
17
|
+
h3 Architecture
|
|
18
|
+
p #{architecture}
|
|
19
|
+
.card
|
|
20
|
+
h3 Database
|
|
21
|
+
p #{database}
|
|
22
|
+
.card
|
|
23
|
+
h3 Communication
|
|
24
|
+
p #{communication}
|
|
25
|
+
|
|
26
|
+
if communication === 'Kafka'
|
|
27
|
+
.status-card
|
|
28
|
+
.status-icon 🔄
|
|
29
|
+
.status-content
|
|
30
|
+
h3 Kafka Connected
|
|
31
|
+
p Connection to broker established successfully.
|
|
32
|
+
else
|
|
33
|
+
.status-card
|
|
34
|
+
.status-icon ✅
|
|
35
|
+
.status-content
|
|
36
|
+
h3 API Active
|
|
37
|
+
p REST API is running and ready to accept requests.
|
|
38
|
+
|
|
39
|
+
footer
|
|
40
|
+
p Generated with ❤️ by Node.js Quickstart Generator
|
|
@@ -4,7 +4,9 @@ const logger = require('../utils/logger');
|
|
|
4
4
|
|
|
5
5
|
const getUsers = async (req, res) => {
|
|
6
6
|
try {
|
|
7
|
-
const users = await User.
|
|
7
|
+
<% if (database === 'MongoDB') { %> const users = await User.find();
|
|
8
|
+
<% } else { %> const users = await User.findAll();
|
|
9
|
+
<% } -%>
|
|
8
10
|
res.json(users);
|
|
9
11
|
} catch (error) {
|
|
10
12
|
logger.error('Error fetching users:', error);
|
|
@@ -24,7 +24,7 @@ app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
|
|
|
24
24
|
const path = require('path');
|
|
25
25
|
app.set('views', path.join(__dirname, 'views'));
|
|
26
26
|
app.set('view engine', '<%= viewEngine.toLowerCase() %>');
|
|
27
|
-
|
|
27
|
+
app.use(express.static(path.join(__dirname, '../public')));<% } -%>
|
|
28
28
|
|
|
29
29
|
// Routes
|
|
30
30
|
<% if (communication === 'REST APIs' || (viewEngine && viewEngine !== 'None')) { -%>
|
|
@@ -50,8 +50,13 @@ const syncDatabase = async () => {
|
|
|
50
50
|
let retries = 30;
|
|
51
51
|
while (retries) {
|
|
52
52
|
try {
|
|
53
|
+
<% if (database === 'MongoDB') { %>
|
|
54
|
+
const connectDB = require('./config/database');
|
|
55
|
+
await connectDB();
|
|
56
|
+
<% } else { %>
|
|
53
57
|
const sequelize = require('./config/database');
|
|
54
58
|
await sequelize.sync();
|
|
59
|
+
<% } %>
|
|
55
60
|
logger.info('Database synced');
|
|
56
61
|
|
|
57
62
|
// Start Server after DB is ready
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { Request, Response } from 'express';
|
|
2
|
-
import User from '
|
|
3
|
-
import { HTTP_STATUS } from '
|
|
4
|
-
import logger from '
|
|
2
|
+
import User from '@/models/User';
|
|
3
|
+
import { HTTP_STATUS } from '@/utils/httpCodes';
|
|
4
|
+
import logger from '@/utils/logger';
|
|
5
5
|
|
|
6
6
|
export class UserController {
|
|
7
7
|
async getUsers(req: Request, res: Response) {
|
|
8
8
|
try {
|
|
9
|
-
const users = await User.
|
|
9
|
+
<% if (database === 'MongoDB') { %> const users = await User.find();
|
|
10
|
+
<% } else { %> const users = await User.findAll();
|
|
11
|
+
<% } -%>
|
|
10
12
|
res.json(users);
|
|
11
13
|
} catch (error) {
|
|
12
14
|
logger.error('Error fetching users:', error);
|