express-backend-starter 1.0.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 +236 -0
- package/bin/cli.js +103 -0
- package/package.json +39 -0
- package/src/db-config.js +172 -0
- package/src/generators.js +143 -0
- package/src/installers.js +154 -0
- package/src/prompts.js +66 -0
- package/src/templates/index.js +817 -0
package/README.md
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# 🚀 Express Backend Starter CLI
|
|
2
|
+
|
|
3
|
+
A production-ready CLI tool to scaffold Express.js/Node.js backend projects in seconds.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
## ✨ Features
|
|
9
|
+
|
|
10
|
+
- 🎯 **Interactive Setup** - Guided prompts for project configuration
|
|
11
|
+
- 🗄️ **Multiple Databases** - MongoDB, PostgreSQL, or MySQL support
|
|
12
|
+
- 📚 **Swagger Docs** - Auto-generated API documentation
|
|
13
|
+
- ✅ **Zod Validation** - Type-safe request validation
|
|
14
|
+
- 📧 **Email Support** - Nodemailer integration
|
|
15
|
+
- 🔒 **Security First** - Helmet, CORS, rate limiting, JWT auth
|
|
16
|
+
- 📁 **Clean Architecture** - Professional folder structure
|
|
17
|
+
- ⚡ **Production Ready** - Best practices built-in
|
|
18
|
+
|
|
19
|
+
## 🚀 Quick Start
|
|
20
|
+
|
|
21
|
+
### Using npx (Recommended)
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx express-backend-starter
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Or Install Globally
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install -g express-backend-starter
|
|
31
|
+
express-backend-starter
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 📋 What Gets Generated?
|
|
35
|
+
|
|
36
|
+
### Always Included
|
|
37
|
+
|
|
38
|
+
- ✅ Express.js server setup
|
|
39
|
+
- ✅ JWT authentication middleware
|
|
40
|
+
- ✅ Error handling middleware
|
|
41
|
+
- ✅ CORS configuration
|
|
42
|
+
- ✅ Rate limiting
|
|
43
|
+
- ✅ Helmet security headers
|
|
44
|
+
- ✅ Cookie parser
|
|
45
|
+
- ✅ Bcrypt password hashing
|
|
46
|
+
- ✅ File upload with Multer
|
|
47
|
+
- ✅ Environment configuration
|
|
48
|
+
- ✅ Professional folder structure
|
|
49
|
+
|
|
50
|
+
### Database Options
|
|
51
|
+
|
|
52
|
+
- **MongoDB** → Mongoose ORM
|
|
53
|
+
- **PostgreSQL** → Prisma ORM
|
|
54
|
+
- **MySQL** → Prisma ORM
|
|
55
|
+
|
|
56
|
+
### Optional Features
|
|
57
|
+
|
|
58
|
+
- 📚 **Swagger** → API documentation UI
|
|
59
|
+
- ✅ **Zod** → Runtime validation
|
|
60
|
+
- 📧 **Nodemailer** → Email functionality
|
|
61
|
+
|
|
62
|
+
## 🎬 Demo
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
$ npx express-backend-starter
|
|
66
|
+
|
|
67
|
+
🚀 Welcome to Express Backend Starter CLI
|
|
68
|
+
|
|
69
|
+
Let's scaffold your backend project...
|
|
70
|
+
|
|
71
|
+
? What is your project name? my-awesome-api
|
|
72
|
+
? Which database do you want to use? MongoDB
|
|
73
|
+
? Include Swagger documentation? Yes
|
|
74
|
+
? Include Zod validation? Yes
|
|
75
|
+
? Include Nodemailer for email functionality? No
|
|
76
|
+
|
|
77
|
+
✅ Project created successfully!
|
|
78
|
+
|
|
79
|
+
Next steps:
|
|
80
|
+
cd my-awesome-api
|
|
81
|
+
npm run dev
|
|
82
|
+
|
|
83
|
+
Happy coding! 🎉
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 📁 Generated Project Structure
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
my-awesome-api/
|
|
90
|
+
├── .env.example
|
|
91
|
+
├── .gitignore
|
|
92
|
+
├── README.md
|
|
93
|
+
├── package.json
|
|
94
|
+
└── src/
|
|
95
|
+
├── app.js # Main application
|
|
96
|
+
├── config/
|
|
97
|
+
│ ├── db.js # Database connection
|
|
98
|
+
│ └── swagger.js # Swagger config (optional)
|
|
99
|
+
├── controllers/
|
|
100
|
+
│ └── healthController.js # Sample controller
|
|
101
|
+
├── middleware/
|
|
102
|
+
│ ├── auth.js # JWT authentication
|
|
103
|
+
│ └── errorHandler.js # Global error handler
|
|
104
|
+
├── models/
|
|
105
|
+
│ └── User.js # Sample model
|
|
106
|
+
├── routes/
|
|
107
|
+
│ └── healthRoutes.js # Sample routes
|
|
108
|
+
├── services/ # Business logic
|
|
109
|
+
└── utils/
|
|
110
|
+
└── validation.js # Zod schemas (optional)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## 🛠️ Tech Stack
|
|
114
|
+
|
|
115
|
+
- **Framework:** Express.js
|
|
116
|
+
- **Authentication:** JWT (jsonwebtoken)
|
|
117
|
+
- **Security:** Helmet, CORS, express-rate-limit
|
|
118
|
+
- **Password Hashing:** bcryptjs
|
|
119
|
+
- **File Upload:** Multer
|
|
120
|
+
- **Database ORMs:** Mongoose (MongoDB) or Prisma (PostgreSQL/MySQL)
|
|
121
|
+
- **Documentation:** Swagger (optional)
|
|
122
|
+
- **Validation:** Zod (optional)
|
|
123
|
+
- **Email:** Nodemailer (optional)
|
|
124
|
+
|
|
125
|
+
## 📖 Usage
|
|
126
|
+
|
|
127
|
+
### 1. Run the CLI
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npx express-backend-starter
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 2. Answer the Prompts
|
|
134
|
+
|
|
135
|
+
The CLI will ask you:
|
|
136
|
+
- Project name
|
|
137
|
+
- Database choice (MongoDB/PostgreSQL/MySQL)
|
|
138
|
+
- Include Swagger? (y/n)
|
|
139
|
+
- Include Zod? (y/n)
|
|
140
|
+
- Include Nodemailer? (y/n)
|
|
141
|
+
|
|
142
|
+
### 3. Navigate to Your Project
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
cd your-project-name
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 4. Configure Environment
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
cp .env.example .env
|
|
152
|
+
# Edit .env with your settings
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### 5. For Prisma (PostgreSQL/MySQL)
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
npx prisma migrate dev
|
|
159
|
+
npx prisma generate
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### 6. Start Development
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
npm run dev
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Your server will be running at `http://localhost:5000`
|
|
169
|
+
|
|
170
|
+
## 🌐 API Endpoints
|
|
171
|
+
|
|
172
|
+
Generated project includes:
|
|
173
|
+
|
|
174
|
+
- `GET /` - Welcome message
|
|
175
|
+
- `GET /api/health` - Health check
|
|
176
|
+
- `GET /api/health/info` - Server info
|
|
177
|
+
- `GET /api-docs` - Swagger UI (if enabled)
|
|
178
|
+
|
|
179
|
+
## 🔧 Available Scripts
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"dev": "nodemon src/app.js", // Development with auto-reload
|
|
184
|
+
"start": "node src/app.js" // Production start
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## 🔐 Environment Variables
|
|
189
|
+
|
|
190
|
+
The generated `.env.example` includes:
|
|
191
|
+
|
|
192
|
+
```env
|
|
193
|
+
PORT=5000
|
|
194
|
+
NODE_ENV=development
|
|
195
|
+
JWT_SECRET=your_secret_key
|
|
196
|
+
JWT_EXPIRE=7d
|
|
197
|
+
|
|
198
|
+
# Database URLs (based on your choice)
|
|
199
|
+
MONGO_URI=mongodb://localhost:27017/dbname
|
|
200
|
+
# or
|
|
201
|
+
DATABASE_URL=postgresql://user:pass@localhost:5432/dbname
|
|
202
|
+
|
|
203
|
+
# Optional
|
|
204
|
+
EMAIL_HOST=smtp.gmail.com
|
|
205
|
+
EMAIL_USER=your@email.com
|
|
206
|
+
# ... and more
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## 📚 Documentation
|
|
210
|
+
|
|
211
|
+
For detailed development guide, see [devGuide.md](./devGuide.md)
|
|
212
|
+
|
|
213
|
+
## 🤝 Contributing
|
|
214
|
+
|
|
215
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
216
|
+
|
|
217
|
+
## 📄 License
|
|
218
|
+
|
|
219
|
+
MIT License - see LICENSE file for details
|
|
220
|
+
|
|
221
|
+
## 🙏 Credits
|
|
222
|
+
|
|
223
|
+
Built with:
|
|
224
|
+
- [Commander.js](https://github.com/tj/commander.js)
|
|
225
|
+
- [Inquirer.js](https://github.com/SBoudrias/Inquirer.js)
|
|
226
|
+
- [Chalk](https://github.com/chalk/chalk)
|
|
227
|
+
- [Ora](https://github.com/sindresorhus/ora)
|
|
228
|
+
- [Execa](https://github.com/sindresorhus/execa)
|
|
229
|
+
|
|
230
|
+
## 💬 Support
|
|
231
|
+
|
|
232
|
+
If you have any questions or issues, please open an issue on GitHub.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
**Made with ❤️ for the Node.js community**
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Express Backend Starter CLI
|
|
5
|
+
* Main entry point for the CLI tool
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import { getUserInput } from '../src/prompts.js';
|
|
11
|
+
import { installDependencies } from '../src/installers.js';
|
|
12
|
+
import { generateProject } from '../src/generators.js';
|
|
13
|
+
import ora from 'ora';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import { fileURLToPath } from 'url';
|
|
16
|
+
import fs from 'fs-extra';
|
|
17
|
+
|
|
18
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
19
|
+
const __dirname = path.dirname(__filename);
|
|
20
|
+
|
|
21
|
+
// Read package.json for version
|
|
22
|
+
const packageJson = JSON.parse(
|
|
23
|
+
await fs.readFile(path.join(__dirname, '../package.json'), 'utf-8')
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const program = new Command();
|
|
27
|
+
|
|
28
|
+
program
|
|
29
|
+
.name('express-backend-starter')
|
|
30
|
+
.description('Scaffold a production-ready Express.js/Node.js backend project')
|
|
31
|
+
.version(packageJson.version)
|
|
32
|
+
.action(async () => {
|
|
33
|
+
console.log(chalk.cyan.bold('\n🚀 Welcome to Express Backend Starter CLI\n'));
|
|
34
|
+
console.log(chalk.gray('Let\'s scaffold your backend project...\n'));
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
// Step 1: Get user input through interactive prompts
|
|
38
|
+
const spinner = ora('Preparing questions...').start();
|
|
39
|
+
spinner.succeed('Ready!');
|
|
40
|
+
|
|
41
|
+
const answers = await getUserInput();
|
|
42
|
+
|
|
43
|
+
// Step 2: Create project directory
|
|
44
|
+
const projectPath = path.join(process.cwd(), answers.projectName);
|
|
45
|
+
|
|
46
|
+
const creatingSpinner = ora('Creating project directory...').start();
|
|
47
|
+
|
|
48
|
+
if (await fs.pathExists(projectPath)) {
|
|
49
|
+
creatingSpinner.fail(chalk.red(`Directory "${answers.projectName}" already exists!`));
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
await fs.ensureDir(projectPath);
|
|
54
|
+
creatingSpinner.succeed(chalk.green('Project directory created'));
|
|
55
|
+
|
|
56
|
+
// Step 3: Initialize npm project
|
|
57
|
+
const initSpinner = ora('Initializing npm project...').start();
|
|
58
|
+
await fs.writeJSON(path.join(projectPath, 'package.json'), {
|
|
59
|
+
name: answers.projectName,
|
|
60
|
+
version: '1.0.0',
|
|
61
|
+
description: 'Backend project generated by Express Backend Starter CLI',
|
|
62
|
+
main: 'src/app.js',
|
|
63
|
+
type: 'module',
|
|
64
|
+
scripts: {
|
|
65
|
+
dev: 'nodemon src/app.js',
|
|
66
|
+
start: 'node src/app.js'
|
|
67
|
+
},
|
|
68
|
+
keywords: [],
|
|
69
|
+
author: '',
|
|
70
|
+
license: 'ISC'
|
|
71
|
+
}, { spaces: 2 });
|
|
72
|
+
initSpinner.succeed(chalk.green('npm project initialized'));
|
|
73
|
+
|
|
74
|
+
// Step 4: Install dependencies
|
|
75
|
+
await installDependencies(projectPath, answers);
|
|
76
|
+
|
|
77
|
+
// Step 5: Generate project structure and files
|
|
78
|
+
await generateProject(projectPath, answers);
|
|
79
|
+
|
|
80
|
+
// Success message
|
|
81
|
+
console.log(chalk.green.bold('\n✅ Project created successfully!\n'));
|
|
82
|
+
console.log(chalk.cyan('Next steps:'));
|
|
83
|
+
console.log(chalk.white(` cd ${answers.projectName}`));
|
|
84
|
+
|
|
85
|
+
// Special instructions for Prisma databases
|
|
86
|
+
if (answers.database === 'postgresql' || answers.database === 'mysql') {
|
|
87
|
+
console.log(chalk.yellow('\n 📝 Configure your database:'));
|
|
88
|
+
console.log(chalk.white(' 1. Update DATABASE_URL in .env file'));
|
|
89
|
+
console.log(chalk.white(' 2. Run: npx prisma migrate dev'));
|
|
90
|
+
console.log(chalk.white(' 3. Then: npm run dev\n'));
|
|
91
|
+
} else {
|
|
92
|
+
console.log(chalk.white(' npm run dev\n'));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log(chalk.gray('Happy coding! 🎉\n'));
|
|
96
|
+
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.error(chalk.red.bold('\n❌ Error:'), error.message);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
program.parse(process.argv);
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "express-backend-starter",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "A production-ready CLI tool to scaffold Express.js/Node.js backend projects",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Aayush Sah",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "index.js",
|
|
9
|
+
"bin": {
|
|
10
|
+
"express-backend-starter": "./bin/cli.js"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"express",
|
|
14
|
+
"backend",
|
|
15
|
+
"cli",
|
|
16
|
+
"scaffold",
|
|
17
|
+
"nodejs",
|
|
18
|
+
"generator",
|
|
19
|
+
"starter"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"chalk": "^5.6.2",
|
|
26
|
+
"commander": "^14.0.2",
|
|
27
|
+
"execa": "^9.6.1",
|
|
28
|
+
"fs-extra": "^11.3.3",
|
|
29
|
+
"inquirer": "^8.2.6",
|
|
30
|
+
"ora": "^9.1.0"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"bin",
|
|
34
|
+
"src"
|
|
35
|
+
],
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18"
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/db-config.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database configuration templates
|
|
3
|
+
* Provides database connection setup for different databases
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get database configuration based on database type
|
|
8
|
+
* @param {string} database - Database type (mongodb, postgresql, mysql)
|
|
9
|
+
* @returns {string} Database configuration code
|
|
10
|
+
*/
|
|
11
|
+
export function getDbConfig(database) {
|
|
12
|
+
switch (database) {
|
|
13
|
+
case 'mongodb':
|
|
14
|
+
return getMongoDbConfig();
|
|
15
|
+
|
|
16
|
+
case 'postgresql':
|
|
17
|
+
return getPostgreSQLConfig();
|
|
18
|
+
|
|
19
|
+
case 'mysql':
|
|
20
|
+
return getMySQLConfig();
|
|
21
|
+
|
|
22
|
+
default:
|
|
23
|
+
return getMongoDbConfig();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* MongoDB configuration with Mongoose
|
|
29
|
+
*/
|
|
30
|
+
function getMongoDbConfig() {
|
|
31
|
+
return `/**
|
|
32
|
+
* MongoDB Database Configuration
|
|
33
|
+
* Using Mongoose ORM
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import mongoose from 'mongoose';
|
|
37
|
+
import chalk from 'chalk';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Connect to MongoDB database
|
|
41
|
+
*/
|
|
42
|
+
export async function connectDB() {
|
|
43
|
+
try {
|
|
44
|
+
const conn = await mongoose.connect(process.env.MONGO_URI, {
|
|
45
|
+
// Mongoose 6+ no longer needs these options:
|
|
46
|
+
// useNewUrlParser: true,
|
|
47
|
+
// useUnifiedTopology: true,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
console.log(chalk.green.bold(\`✅ MongoDB Connected: \${conn.connection.host}\`));
|
|
51
|
+
|
|
52
|
+
// Connection events
|
|
53
|
+
mongoose.connection.on('error', (err) => {
|
|
54
|
+
console.error(chalk.red('MongoDB connection error:'), err);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
mongoose.connection.on('disconnected', () => {
|
|
58
|
+
console.log(chalk.yellow('MongoDB disconnected'));
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Graceful shutdown
|
|
62
|
+
process.on('SIGINT', async () => {
|
|
63
|
+
await mongoose.connection.close();
|
|
64
|
+
console.log(chalk.yellow('MongoDB connection closed due to app termination'));
|
|
65
|
+
process.exit(0);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error(chalk.red.bold('❌ MongoDB connection failed:'), error.message);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* PostgreSQL configuration with Prisma
|
|
78
|
+
*/
|
|
79
|
+
function getPostgreSQLConfig() {
|
|
80
|
+
return `/**
|
|
81
|
+
* PostgreSQL Database Configuration
|
|
82
|
+
* Using Prisma ORM
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
import { PrismaClient } from '@prisma/client';
|
|
86
|
+
import chalk from 'chalk';
|
|
87
|
+
|
|
88
|
+
// Initialize Prisma Client
|
|
89
|
+
const prisma = new PrismaClient({
|
|
90
|
+
log: ['query', 'info', 'warn', 'error'],
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Connect to PostgreSQL database
|
|
95
|
+
*/
|
|
96
|
+
export async function connectDB() {
|
|
97
|
+
try {
|
|
98
|
+
await prisma.$connect();
|
|
99
|
+
console.log(chalk.green.bold('✅ PostgreSQL Connected via Prisma'));
|
|
100
|
+
|
|
101
|
+
// Graceful shutdown
|
|
102
|
+
process.on('SIGINT', async () => {
|
|
103
|
+
await prisma.$disconnect();
|
|
104
|
+
console.log(chalk.yellow('PostgreSQL connection closed due to app termination'));
|
|
105
|
+
process.exit(0);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
process.on('SIGTERM', async () => {
|
|
109
|
+
await prisma.$disconnect();
|
|
110
|
+
process.exit(0);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error(chalk.red.bold('❌ PostgreSQL connection failed:'), error.message);
|
|
115
|
+
await prisma.$disconnect();
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Export prisma instance for use in other modules
|
|
121
|
+
export { prisma };
|
|
122
|
+
`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* MySQL configuration with Prisma
|
|
127
|
+
*/
|
|
128
|
+
function getMySQLConfig() {
|
|
129
|
+
return `/**
|
|
130
|
+
* MySQL Database Configuration
|
|
131
|
+
* Using Prisma ORM
|
|
132
|
+
*/
|
|
133
|
+
|
|
134
|
+
import { PrismaClient } from '@prisma/client';
|
|
135
|
+
import chalk from 'chalk';
|
|
136
|
+
|
|
137
|
+
// Initialize Prisma Client
|
|
138
|
+
const prisma = new PrismaClient({
|
|
139
|
+
log: ['query', 'info', 'warn', 'error'],
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Connect to MySQL database
|
|
144
|
+
*/
|
|
145
|
+
export async function connectDB() {
|
|
146
|
+
try {
|
|
147
|
+
await prisma.$connect();
|
|
148
|
+
console.log(chalk.green.bold('✅ MySQL Connected via Prisma'));
|
|
149
|
+
|
|
150
|
+
// Graceful shutdown
|
|
151
|
+
process.on('SIGINT', async () => {
|
|
152
|
+
await prisma.$disconnect();
|
|
153
|
+
console.log(chalk.yellow('MySQL connection closed due to app termination'));
|
|
154
|
+
process.exit(0);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
process.on('SIGTERM', async () => {
|
|
158
|
+
await prisma.$disconnect();
|
|
159
|
+
process.exit(0);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.error(chalk.red.bold('❌ MySQL connection failed:'), error.message);
|
|
164
|
+
await prisma.$disconnect();
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Export prisma instance for use in other modules
|
|
170
|
+
export { prisma };
|
|
171
|
+
`;
|
|
172
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project structure and file generation
|
|
3
|
+
* Creates folders and files for the new project
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs-extra';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import { getDbConfig } from './db-config.js';
|
|
11
|
+
import * as templates from './templates/index.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Generate the complete project structure
|
|
15
|
+
* @param {string} projectPath - Path to the project directory
|
|
16
|
+
* @param {Object} answers - User's answers from prompts
|
|
17
|
+
*/
|
|
18
|
+
export async function generateProject(projectPath, answers) {
|
|
19
|
+
const spinner = ora('Generating project structure...').start();
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
// Create folder structure
|
|
23
|
+
await createFolderStructure(projectPath);
|
|
24
|
+
spinner.text = 'Folder structure created';
|
|
25
|
+
|
|
26
|
+
// Generate configuration files
|
|
27
|
+
await generateConfigFiles(projectPath, answers);
|
|
28
|
+
spinner.text = 'Configuration files created';
|
|
29
|
+
|
|
30
|
+
// Generate source files
|
|
31
|
+
await generateSourceFiles(projectPath, answers);
|
|
32
|
+
spinner.text = 'Source files created';
|
|
33
|
+
|
|
34
|
+
// Generate README
|
|
35
|
+
await generateReadme(projectPath, answers);
|
|
36
|
+
|
|
37
|
+
spinner.succeed(chalk.green('Project structure generated'));
|
|
38
|
+
} catch (error) {
|
|
39
|
+
spinner.fail(chalk.red('Failed to generate project structure'));
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Create the folder structure
|
|
46
|
+
* @param {string} projectPath - Path to the project directory
|
|
47
|
+
*/
|
|
48
|
+
async function createFolderStructure(projectPath) {
|
|
49
|
+
const folders = [
|
|
50
|
+
'src',
|
|
51
|
+
'src/controllers',
|
|
52
|
+
'src/routes',
|
|
53
|
+
'src/middleware',
|
|
54
|
+
'src/config',
|
|
55
|
+
'src/services',
|
|
56
|
+
'src/models',
|
|
57
|
+
'src/utils'
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
for (const folder of folders) {
|
|
61
|
+
await fs.ensureDir(path.join(projectPath, folder));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Generate configuration files
|
|
67
|
+
* @param {string} projectPath - Path to the project directory
|
|
68
|
+
* @param {Object} answers - User's answers
|
|
69
|
+
*/
|
|
70
|
+
async function generateConfigFiles(projectPath, answers) {
|
|
71
|
+
// .env.example
|
|
72
|
+
const envExample = templates.generateEnvExample(answers);
|
|
73
|
+
await fs.writeFile(path.join(projectPath, '.env.example'), envExample);
|
|
74
|
+
|
|
75
|
+
// .gitignore
|
|
76
|
+
const gitignore = templates.generateGitignore();
|
|
77
|
+
await fs.writeFile(path.join(projectPath, '.gitignore'), gitignore);
|
|
78
|
+
|
|
79
|
+
// Database configuration
|
|
80
|
+
const dbConfig = getDbConfig(answers.database);
|
|
81
|
+
await fs.writeFile(path.join(projectPath, 'src/config/db.js'), dbConfig);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Generate source files
|
|
86
|
+
* @param {string} projectPath - Path to the project directory
|
|
87
|
+
* @param {Object} answers - User's answers
|
|
88
|
+
*/
|
|
89
|
+
async function generateSourceFiles(projectPath, answers) {
|
|
90
|
+
// Main app.js
|
|
91
|
+
const appJs = templates.generateAppJs(answers);
|
|
92
|
+
await fs.writeFile(path.join(projectPath, 'src/app.js'), appJs);
|
|
93
|
+
|
|
94
|
+
// Sample controller
|
|
95
|
+
const sampleController = templates.generateSampleController();
|
|
96
|
+
await fs.writeFile(path.join(projectPath, 'src/controllers/healthController.js'), sampleController);
|
|
97
|
+
|
|
98
|
+
// Sample route
|
|
99
|
+
const sampleRoute = templates.generateSampleRoute();
|
|
100
|
+
await fs.writeFile(path.join(projectPath, 'src/routes/healthRoutes.js'), sampleRoute);
|
|
101
|
+
|
|
102
|
+
// Error middleware
|
|
103
|
+
const errorMiddleware = templates.generateErrorMiddleware();
|
|
104
|
+
await fs.writeFile(path.join(projectPath, 'src/middleware/errorHandler.js'), errorMiddleware);
|
|
105
|
+
|
|
106
|
+
// Auth middleware (JWT)
|
|
107
|
+
const authMiddleware = templates.generateAuthMiddleware();
|
|
108
|
+
await fs.writeFile(path.join(projectPath, 'src/middleware/auth.js'), authMiddleware);
|
|
109
|
+
|
|
110
|
+
// Swagger configuration (if selected)
|
|
111
|
+
if (answers.includeSwagger) {
|
|
112
|
+
const swaggerConfig = templates.generateSwaggerConfig(answers);
|
|
113
|
+
await fs.writeFile(path.join(projectPath, 'src/config/swagger.js'), swaggerConfig);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Nodemailer configuration (if selected)
|
|
117
|
+
if (answers.includeNodemailer) {
|
|
118
|
+
const nodemailerConfig = templates.generateNodemailerConfig();
|
|
119
|
+
await fs.writeFile(path.join(projectPath, 'src/config/nodemailer.js'), nodemailerConfig);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Zod validation example (if selected)
|
|
123
|
+
if (answers.includeZod) {
|
|
124
|
+
const zodExample = templates.generateZodValidation();
|
|
125
|
+
await fs.writeFile(path.join(projectPath, 'src/utils/validation.js'), zodExample);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Sample model (database-specific)
|
|
129
|
+
if (answers.database === 'mongodb') {
|
|
130
|
+
const userModel = templates.generateMongooseModel();
|
|
131
|
+
await fs.writeFile(path.join(projectPath, 'src/models/User.js'), userModel);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Generate README.md
|
|
137
|
+
* @param {string} projectPath - Path to the project directory
|
|
138
|
+
* @param {Object} answers - User's answers
|
|
139
|
+
*/
|
|
140
|
+
async function generateReadme(projectPath, answers) {
|
|
141
|
+
const readme = templates.generateReadme(answers);
|
|
142
|
+
await fs.writeFile(path.join(projectPath, 'README.md'), readme);
|
|
143
|
+
}
|