build-app-with 2.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.
Files changed (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +240 -0
  3. package/bin/cli.js +18 -0
  4. package/index.js +3 -0
  5. package/package.json +80 -0
  6. package/src/__tests__/core/error-handler.test.js +99 -0
  7. package/src/__tests__/core/logger.test.js +93 -0
  8. package/src/__tests__/e2e/cli-integration.test.js +220 -0
  9. package/src/__tests__/e2e/framework-generation.test.js +249 -0
  10. package/src/__tests__/setup.js +70 -0
  11. package/src/config/package-mappings.js +110 -0
  12. package/src/constants/index.js +42 -0
  13. package/src/core/error-handler.js +89 -0
  14. package/src/core/logger.js +89 -0
  15. package/src/core/package-manager.js +114 -0
  16. package/src/create-app.js +90 -0
  17. package/src/generators/express/index.js +52 -0
  18. package/src/generators/express/project-generator.js +367 -0
  19. package/src/generators/express/prompts.js +74 -0
  20. package/src/generators/express/simple-generator.js +275 -0
  21. package/src/generators/express/templates/app.js +73 -0
  22. package/src/generators/express/templates/config/database.js +122 -0
  23. package/src/generators/express/templates/config.js +37 -0
  24. package/src/generators/express/templates/controllers.js +49 -0
  25. package/src/generators/express/templates/docker.js +72 -0
  26. package/src/generators/express/templates/middleware/errorHandler.js +49 -0
  27. package/src/generators/express/templates/middleware.js +59 -0
  28. package/src/generators/express/templates/models.js +77 -0
  29. package/src/generators/express/templates/package-json.js +55 -0
  30. package/src/generators/express/templates/readme.js +310 -0
  31. package/src/generators/express/templates/routes.js +36 -0
  32. package/src/generators/express/templates/server.js +59 -0
  33. package/src/generators/express/templates/services.js +55 -0
  34. package/src/generators/express/templates/tests.js +46 -0
  35. package/src/generators/express/templates/utils/logger.js +54 -0
  36. package/src/generators/fastify/index.js +46 -0
  37. package/src/generators/fastify/project-generator.js +373 -0
  38. package/src/generators/fastify/prompts.js +76 -0
  39. package/src/generators/fastify/templates/app.js +179 -0
  40. package/src/generators/fastify/templates/config.js +33 -0
  41. package/src/generators/fastify/templates/docker.js +73 -0
  42. package/src/generators/fastify/templates/models.js +77 -0
  43. package/src/generators/fastify/templates/package-json.js +57 -0
  44. package/src/generators/fastify/templates/plugins.js +38 -0
  45. package/src/generators/fastify/templates/readme.js +328 -0
  46. package/src/generators/fastify/templates/routes.js +32 -0
  47. package/src/generators/fastify/templates/server.js +71 -0
  48. package/src/generators/fastify/templates/services.js +50 -0
  49. package/src/generators/fastify/templates/tests.js +60 -0
  50. package/src/generators/nextjs/dependency-manager.js +99 -0
  51. package/src/generators/nextjs/file-generator.js +256 -0
  52. package/src/generators/nextjs/nextjs-generator.js +177 -0
  53. package/src/generators/nextjs/nextjs-project-generator.js +896 -0
  54. package/src/generators/nextjs/package-mappings.js +51 -0
  55. package/src/generators/nextjs/templates.js +272 -0
  56. package/src/generators/package-json-generator.js +117 -0
  57. package/src/generators/vite/components/CreditComponent.jsx +41 -0
  58. package/src/generators/vite/components/app-component.js +359 -0
  59. package/src/generators/vite/components/main-file.js +88 -0
  60. package/src/generators/vite/eslint-config-generator.js +20 -0
  61. package/src/generators/vite/file-generator.js +796 -0
  62. package/src/generators/vite/prettier-config-generator.js +10 -0
  63. package/src/generators/vite/structures/domain-driven-structure.js +465 -0
  64. package/src/generators/vite/structures/feature-based-structure.js +342 -0
  65. package/src/generators/vite/structures/simple-structure.js +62 -0
  66. package/src/generators/vite/styles/index-css.js +130 -0
  67. package/src/generators/vite/tailwind-config-generator.js +14 -0
  68. package/src/generators/vite/vite-config-generator.js +22 -0
  69. package/src/generators/vite/vite-project-generator.js +263 -0
  70. package/src/generators/vite-project-generator.js +136 -0
  71. package/src/prompts/index.js +262 -0
  72. package/src/types/index.js +113 -0
  73. package/src/utils/answer-helpers.js +24 -0
  74. package/src/utils/credits.js +192 -0
  75. package/src/utils/dependencies.js +25 -0
  76. package/src/utils/messages.js +27 -0
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Simplified Express.js project generator
3
+ */
4
+
5
+ import fs from 'fs-extra';
6
+ import path from 'path';
7
+ import { logger } from '../../core/logger.js';
8
+ import { generateCreditsSection } from '../../utils/credits.js';
9
+
10
+ export async function generateSimpleExpressProject(projectPath, answers) {
11
+ try {
12
+ // Create project directory first
13
+ logger.debug('Creating project directory...');
14
+ await fs.ensureDir(projectPath);
15
+ logger.debug('Project directory created');
16
+
17
+ logger.debug('Generating package.json...');
18
+ const packageJson = {
19
+ name: answers.projectName,
20
+ version: '1.0.0',
21
+ description: `A production-ready Express.js application - ${answers.projectName}`,
22
+ main: 'src/server.js',
23
+ type: 'module',
24
+ scripts: {
25
+ start: 'node src/server.js',
26
+ dev: 'nodemon src/server.js',
27
+ test: 'jest'
28
+ },
29
+ keywords: ['express', 'nodejs', 'api', 'backend'],
30
+ author: 'Generated by build-app-with',
31
+ license: 'MIT',
32
+ engines: {
33
+ node: '>=18.0.0'
34
+ },
35
+ dependencies: {
36
+ 'express': '^4.18.2',
37
+ 'cors': '^2.8.5',
38
+ 'helmet': '^7.1.0',
39
+ 'morgan': '^1.10.0',
40
+ 'dotenv': '^16.3.1',
41
+ 'mongoose': '^8.0.3',
42
+ 'jsonwebtoken': '^9.0.2',
43
+ 'bcryptjs': '^2.4.3'
44
+ },
45
+ devDependencies: {
46
+ 'nodemon': '^3.0.2',
47
+ 'jest': '^29.7.0',
48
+ 'supertest': '^6.3.3'
49
+ }
50
+ };
51
+
52
+ await fs.writeJSON(path.join(projectPath, 'package.json'), packageJson, { spaces: 2 });
53
+
54
+ logger.info('Creating src directory...');
55
+ await fs.ensureDir(path.join(projectPath, 'src'));
56
+
57
+ logger.info('Generating app.js...');
58
+ const appJs = `import express from 'express';
59
+ import cors from 'cors';
60
+ import helmet from 'helmet';
61
+ import morgan from 'morgan';
62
+ import dotenv from 'dotenv';
63
+
64
+ // Load environment variables
65
+ dotenv.config();
66
+
67
+ const app = express();
68
+
69
+ // Security middleware
70
+ app.use(helmet());
71
+
72
+ // CORS configuration
73
+ app.use(cors({
74
+ origin: process.env.CORS_ORIGIN || 'http://localhost:3000',
75
+ credentials: true
76
+ }));
77
+
78
+ // Logging middleware
79
+ app.use(morgan('combined'));
80
+
81
+ // Body parsing middleware
82
+ app.use(express.json({ limit: '10mb' }));
83
+ app.use(express.urlencoded({ extended: true }));
84
+
85
+ // Health check endpoint
86
+ app.get('/health', (req, res) => {
87
+ res.status(200).json({
88
+ status: 'OK',
89
+ timestamp: new Date().toISOString(),
90
+ uptime: process.uptime(),
91
+ environment: process.env.NODE_ENV || 'development'
92
+ });
93
+ });
94
+
95
+ // API routes
96
+ app.get('/api', (req, res) => {
97
+ res.json({
98
+ message: 'Welcome to ${answers.projectName} API',
99
+ version: '1.0.0',
100
+ endpoints: {
101
+ health: '/health',
102
+ api: '/api'
103
+ }
104
+ });
105
+ });
106
+
107
+ // Error handling middleware
108
+ app.use((err, req, res, next) => {
109
+ console.error(err.stack);
110
+ res.status(500).json({
111
+ success: false,
112
+ error: 'Something went wrong!',
113
+ ...(process.env.NODE_ENV === 'development' && { stack: err.stack })
114
+ });
115
+ });
116
+
117
+ // 404 handler
118
+ app.use('*', (req, res) => {
119
+ res.status(404).json({
120
+ success: false,
121
+ error: \`Route \${req.originalUrl} not found\`
122
+ });
123
+ });
124
+
125
+ export default app;
126
+ `;
127
+
128
+ await fs.writeFile(path.join(projectPath, 'src', 'app.js'), appJs);
129
+
130
+ logger.info('Generating server.js...');
131
+ const serverJs = `import app from './app.js';
132
+
133
+ const PORT = process.env.PORT || 3000;
134
+ const NODE_ENV = process.env.NODE_ENV || 'development';
135
+
136
+ app.listen(PORT, () => {
137
+ console.log(\`🚀 Server running on port \${PORT} in \${NODE_ENV} mode\`);
138
+ console.log(\`📊 Health check: http://localhost:\${PORT}/health\`);
139
+ console.log(\`🔗 API endpoint: http://localhost:\${PORT}/api\`);
140
+ });
141
+ `;
142
+
143
+ await fs.writeFile(path.join(projectPath, 'src', 'server.js'), serverJs);
144
+
145
+ logger.info('Generating .env.example...');
146
+ const envExample = `# Server Configuration
147
+ PORT=3000
148
+ NODE_ENV=development
149
+
150
+ # Database Configuration
151
+ MONGODB_URI=mongodb://localhost:27017/${answers.projectName}
152
+
153
+ # Authentication
154
+ JWT_SECRET=your-super-secret-jwt-key
155
+ JWT_EXPIRES_IN=7d
156
+
157
+ # CORS
158
+ CORS_ORIGIN=http://localhost:3000
159
+ `;
160
+
161
+ await fs.writeFile(path.join(projectPath, '.env.example'), envExample);
162
+
163
+ logger.info('Generating .gitignore...');
164
+ const gitignore = `# Dependencies
165
+ node_modules/
166
+ npm-debug.log*
167
+ yarn-debug.log*
168
+ yarn-error.log*
169
+
170
+ # Environment variables
171
+ .env
172
+ .env.local
173
+ .env.development.local
174
+ .env.test.local
175
+ .env.production.local
176
+
177
+ # Logs
178
+ logs
179
+ *.log
180
+
181
+ # Runtime data
182
+ pids
183
+ *.pid
184
+ *.seed
185
+ *.pid.lock
186
+
187
+ # Coverage directory
188
+ coverage/
189
+
190
+ # IDE
191
+ .vscode/
192
+ .idea/
193
+
194
+ # OS
195
+ .DS_Store
196
+ Thumbs.db
197
+
198
+ # Build output
199
+ dist/
200
+ build/
201
+ `;
202
+
203
+ await fs.writeFile(path.join(projectPath, '.gitignore'), gitignore);
204
+
205
+ logger.info('Generating README...');
206
+
207
+ // Generate credits asynchronously
208
+ const allFeatures = ['express', 'mongodb', 'jwt', 'cors', 'helmet', 'morgan'];
209
+ const credits = await Promise.resolve(generateCreditsSection('express', allFeatures));
210
+
211
+ const readme = `# ${answers.projectName}
212
+
213
+ A production-ready Express.js application built with modern best practices.
214
+
215
+ ## 🚀 Features
216
+
217
+ - ⚡ **Express.js** - Fast, unopinionated web framework
218
+ - 🔒 **Security** - Helmet, CORS, JWT authentication
219
+ - 🗄️ **Database** - MongoDB with Mongoose
220
+ - 📝 **Logging** - Morgan HTTP request logger
221
+ - ✅ **Validation** - Request validation and sanitization
222
+ - 🧪 **Testing** - Jest and Supertest setup
223
+
224
+ ## 🚀 Getting Started
225
+
226
+ 1. **Install dependencies**
227
+ \`\`\`bash
228
+ npm install
229
+ \`\`\`
230
+
231
+ 2. **Set up environment variables**
232
+ \`\`\`bash
233
+ cp .env.example .env
234
+ # Edit .env with your configuration
235
+ \`\`\`
236
+
237
+ 3. **Start the development server**
238
+ \`\`\`bash
239
+ npm run dev
240
+ \`\`\`
241
+
242
+ The server will start on \`http://localhost:3000\`
243
+
244
+ ## 📚 API Endpoints
245
+
246
+ - **Health Check**: \`GET /health\`
247
+ - **API Info**: \`GET /api\`
248
+
249
+ ## 📝 Available Scripts
250
+
251
+ - \`npm start\` - Start production server
252
+ - \`npm run dev\` - Start development server with nodemon
253
+ - \`npm test\` - Run tests
254
+
255
+ ## License
256
+
257
+ MIT
258
+
259
+ ${credits}
260
+ `;
261
+
262
+ await fs.writeFile(path.join(projectPath, 'README.md'), readme);
263
+
264
+ logger.success('Project structure generated successfully!');
265
+
266
+ logger.info('Project structure created! Next steps:');
267
+ logger.info(` cd ${path.basename(projectPath)}`);
268
+ logger.info(' npm install');
269
+ logger.info(' npm run dev');
270
+
271
+ } catch (error) {
272
+ logger.error('Failed to generate project structure');
273
+ throw error;
274
+ }
275
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Generate main Express app.js file
3
+ */
4
+
5
+ import { FEATURES, DATABASES } from '../../../types/index.js';
6
+
7
+ export function generateAppJs(projectPath, answers) {
8
+ const isTypeScript = answers.typescript !== false;
9
+ const ext = isTypeScript ? 'ts' : 'js';
10
+
11
+ let content = `import express from 'express';
12
+ import cors from 'cors';
13
+ import helmet from 'helmet';
14
+ import morgan from 'morgan';
15
+ import dotenv from 'dotenv';
16
+ import { errorHandler } from './middleware/errorHandler.js';
17
+ import { notFound } from './middleware/notFound.js';
18
+ import { logger } from './utils/logger.js';
19
+
20
+ // Load environment variables
21
+ dotenv.config();
22
+
23
+ const app = express();
24
+
25
+ // Security middleware
26
+ app.use(helmet());
27
+
28
+ // CORS configuration
29
+ app.use(cors({
30
+ origin: process.env.CORS_ORIGIN || 'http://localhost:3000',
31
+ credentials: true
32
+ }));
33
+
34
+ // Logging middleware
35
+ app.use(morgan('combined', {
36
+ stream: { write: (message) => logger.info(message.trim()) }
37
+ }));
38
+
39
+ // Body parsing middleware
40
+ app.use(express.json({ limit: '10mb' }));
41
+ app.use(express.urlencoded({ extended: true }));
42
+
43
+ // Health check endpoint
44
+ app.get('/health', (req, res) => {
45
+ res.status(200).json({
46
+ status: 'OK',
47
+ timestamp: new Date().toISOString(),
48
+ uptime: process.uptime(),
49
+ environment: process.env.NODE_ENV || 'development'
50
+ });
51
+ });
52
+
53
+ // API routes
54
+ app.use('/api', (req, res) => {
55
+ res.json({
56
+ message: 'Welcome to ${answers.projectName} API',
57
+ version: '1.0.0',
58
+ endpoints: {
59
+ health: '/health',
60
+ api: '/api'
61
+ }
62
+ });
63
+ });
64
+
65
+ // Error handling middleware
66
+ app.use(notFound);
67
+ app.use(errorHandler);
68
+
69
+ export default app;
70
+ `;
71
+
72
+ return content;
73
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Database configuration template
3
+ */
4
+
5
+ import { DATABASES } from '../../../types/index.js';
6
+
7
+ export function generateDatabaseConfig(answers) {
8
+ if (answers.database === DATABASES.MONGODB) {
9
+ return `import mongoose from 'mongoose';
10
+ import { logger } from '../utils/logger.js';
11
+
12
+ export async function connectDatabase() {
13
+ try {
14
+ const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/${answers.projectName}';
15
+
16
+ await mongoose.connect(mongoUri, {
17
+ useNewUrlParser: true,
18
+ useUnifiedTopology: true,
19
+ });
20
+
21
+ logger.info('MongoDB connected successfully');
22
+ } catch (error) {
23
+ logger.error('MongoDB connection error:', error);
24
+ process.exit(1);
25
+ }
26
+ }
27
+
28
+ // Handle connection events
29
+ mongoose.connection.on('connected', () => {
30
+ logger.info('Mongoose connected to MongoDB');
31
+ });
32
+
33
+ mongoose.connection.on('error', (err) => {
34
+ logger.error('Mongoose connection error:', err);
35
+ });
36
+
37
+ mongoose.connection.on('disconnected', () => {
38
+ logger.warn('Mongoose disconnected');
39
+ });
40
+
41
+ // Graceful shutdown
42
+ process.on('SIGINT', async () => {
43
+ await mongoose.connection.close();
44
+ logger.info('Mongoose connection closed through app termination');
45
+ process.exit(0);
46
+ });
47
+ `;
48
+ } else if (answers.database === DATABASES.POSTGRESQL || answers.database === DATABASES.SQLITE) {
49
+ return `import { PrismaClient } from '@prisma/client';
50
+ import { logger } from '../utils/logger.js';
51
+
52
+ const prisma = new PrismaClient({
53
+ log: process.env.NODE_ENV === 'development' ? ['query', 'info', 'warn', 'error'] : ['error'],
54
+ });
55
+
56
+ export async function connectDatabase() {
57
+ try {
58
+ await prisma.$connect();
59
+ logger.info('Database connected successfully');
60
+ } catch (error) {
61
+ logger.error('Database connection error:', error);
62
+ process.exit(1);
63
+ }
64
+ }
65
+
66
+ // Graceful shutdown
67
+ process.on('SIGINT', async () => {
68
+ await prisma.$disconnect();
69
+ logger.info('Database connection closed');
70
+ process.exit(0);
71
+ });
72
+
73
+ export { prisma };
74
+ `;
75
+ } else if (answers.database === DATABASES.MYSQL) {
76
+ return `import { Sequelize } from 'sequelize';
77
+ import { logger } from '../utils/logger.js';
78
+
79
+ const sequelize = new Sequelize(
80
+ process.env.DB_NAME || '${answers.projectName}',
81
+ process.env.DB_USER || 'root',
82
+ process.env.DB_PASSWORD || 'password',
83
+ {
84
+ host: process.env.DB_HOST || 'localhost',
85
+ port: process.env.DB_PORT || 3306,
86
+ dialect: 'mysql',
87
+ logging: process.env.NODE_ENV === 'development' ? console.log : false,
88
+ }
89
+ );
90
+
91
+ export async function connectDatabase() {
92
+ try {
93
+ await sequelize.authenticate();
94
+ logger.info('MySQL connected successfully');
95
+
96
+ // Sync models in development
97
+ if (process.env.NODE_ENV === 'development') {
98
+ await sequelize.sync({ alter: true });
99
+ }
100
+ } catch (error) {
101
+ logger.error('MySQL connection error:', error);
102
+ process.exit(1);
103
+ }
104
+ }
105
+
106
+ // Graceful shutdown
107
+ process.on('SIGINT', async () => {
108
+ await sequelize.close();
109
+ logger.info('MySQL connection closed');
110
+ process.exit(0);
111
+ });
112
+
113
+ export { sequelize };
114
+ `;
115
+ } else {
116
+ return `// No database configuration needed
117
+ export async function connectDatabase() {
118
+ console.log('No database configured');
119
+ }
120
+ `;
121
+ }
122
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Generate config template
3
+ */
4
+
5
+ export function generateConfig(projectPath, answers) {
6
+ const configContent = `import dotenv from 'dotenv';
7
+
8
+ // Load environment variables
9
+ dotenv.config();
10
+
11
+ export const config = {
12
+ port: process.env.PORT || 3000,
13
+ nodeEnv: process.env.NODE_ENV || 'development',
14
+ corsOrigin: process.env.CORS_ORIGIN || 'http://localhost:3000',
15
+ database: {
16
+ url: process.env.DATABASE_URL || process.env.MONGODB_URI,
17
+ host: process.env.DB_HOST || 'localhost',
18
+ port: process.env.DB_PORT || 3306,
19
+ name: process.env.DB_NAME || '${answers.projectName}',
20
+ user: process.env.DB_USER || 'root',
21
+ password: process.env.DB_PASSWORD || 'password'
22
+ },
23
+ auth: {
24
+ jwtSecret: process.env.JWT_SECRET || 'your-secret-key',
25
+ jwtExpiresIn: process.env.JWT_EXPIRES_IN || '7d'
26
+ },
27
+ rateLimit: {
28
+ max: parseInt(process.env.RATE_LIMIT_MAX) || 100,
29
+ timeWindow: parseInt(process.env.RATE_LIMIT_TIME_WINDOW) || 60000
30
+ }
31
+ };
32
+
33
+ export default config;
34
+ `;
35
+
36
+ return configContent;
37
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Generate controllers template
3
+ */
4
+
5
+ export function generateControllers(projectPath, answers) {
6
+ const controllersContent = `import { logger } from '../utils/logger.js';
7
+
8
+ export class BaseController {
9
+ static async handleRequest(req, res, next, handler) {
10
+ try {
11
+ const result = await handler(req, res);
12
+ res.json({
13
+ success: true,
14
+ data: result
15
+ });
16
+ } catch (error) {
17
+ logger.error('Controller error:', error);
18
+ next(error);
19
+ }
20
+ }
21
+ }
22
+
23
+ export class HealthController extends BaseController {
24
+ static async check(req, res) {
25
+ return {
26
+ status: 'OK',
27
+ timestamp: new Date().toISOString(),
28
+ uptime: process.uptime(),
29
+ service: '${answers.projectName}'
30
+ };
31
+ }
32
+ }
33
+
34
+ export class ApiController extends BaseController {
35
+ static async getInfo(req, res) {
36
+ return {
37
+ message: 'Welcome to ${answers.projectName} API',
38
+ version: '1.0.0',
39
+ endpoints: {
40
+ health: '/health',
41
+ api: '/api'
42
+ }
43
+ };
44
+ }
45
+ }
46
+ `;
47
+
48
+ return controllersContent;
49
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Generate Docker template
3
+ */
4
+
5
+ export function generateDocker(projectPath, answers) {
6
+ const dockerfile = `# Use Node.js LTS version
7
+ FROM node:18-alpine
8
+
9
+ # Set working directory
10
+ WORKDIR /app
11
+
12
+ # Copy package files
13
+ COPY package*.json ./
14
+
15
+ # Install dependencies
16
+ RUN npm ci --only=production
17
+
18
+ # Copy source code
19
+ COPY . .
20
+
21
+ # Create non-root user
22
+ RUN addgroup -g 1001 -S nodejs
23
+ RUN adduser -S nextjs -u 1001
24
+
25
+ # Change ownership
26
+ RUN chown -R nextjs:nodejs /app
27
+ USER nextjs
28
+
29
+ # Expose port
30
+ EXPOSE 3000
31
+
32
+ # Health check
33
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
34
+ CMD curl -f http://localhost:3000/health || exit 1
35
+
36
+ # Start the application
37
+ CMD ["npm", "start"]
38
+ `;
39
+
40
+ const dockerCompose = `version: '3.8'
41
+
42
+ services:
43
+ app:
44
+ build: .
45
+ ports:
46
+ - "3000:3000"
47
+ environment:
48
+ - NODE_ENV=production
49
+ - PORT=3000
50
+ depends_on:
51
+ - db
52
+ restart: unless-stopped
53
+
54
+ db:
55
+ image: ${answers.database === 'mongodb' ? 'mongo:latest' : 'postgres:15-alpine'}
56
+ environment:
57
+ ${answers.database === 'mongodb'
58
+ ? 'MONGO_INITDB_DATABASE=myapp'
59
+ : 'POSTGRES_DB=myapp\n POSTGRES_USER=postgres\n POSTGRES_PASSWORD=password'
60
+ }
61
+ volumes:
62
+ - db_data:/data/db
63
+ ports:
64
+ - "${answers.database === 'mongodb' ? '27017:27017' : '5432:5432'}"
65
+ restart: unless-stopped
66
+
67
+ volumes:
68
+ db_data:
69
+ `;
70
+
71
+ return { dockerfile, dockerCompose };
72
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Error handling middleware template
3
+ */
4
+
5
+ export function generateErrorHandler() {
6
+ return `import { logger } from '../utils/logger.js';
7
+
8
+ export const errorHandler = (err, req, res, next) => {
9
+ let error = { ...err };
10
+ error.message = err.message;
11
+
12
+ // Log error
13
+ logger.error(err);
14
+
15
+ // Mongoose bad ObjectId
16
+ if (err.name === 'CastError') {
17
+ const message = 'Resource not found';
18
+ error = { message, statusCode: 404 };
19
+ }
20
+
21
+ // Mongoose duplicate key
22
+ if (err.code === 11000) {
23
+ const message = 'Duplicate field value entered';
24
+ error = { message, statusCode: 400 };
25
+ }
26
+
27
+ // Mongoose validation error
28
+ if (err.name === 'ValidationError') {
29
+ const message = Object.values(err.errors).map(val => val.message).join(', ');
30
+ error = { message, statusCode: 400 };
31
+ }
32
+
33
+ res.status(error.statusCode || 500).json({
34
+ success: false,
35
+ error: error.message || 'Server Error',
36
+ ...(process.env.NODE_ENV === 'development' && { stack: err.stack })
37
+ });
38
+ };
39
+ `;
40
+ }
41
+
42
+ export function generateNotFound() {
43
+ return `export const notFound = (req, res, next) => {
44
+ const error = new Error(\`Not found - \${req.originalUrl}\`);
45
+ res.status(404);
46
+ next(error);
47
+ };
48
+ `;
49
+ }