student-help 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.
- package/LICENSE +15 -0
- package/README.md +44 -0
- package/bin/student-help.js +14 -0
- package/cli.mjs +1415 -0
- package/commands/db.ts +59 -0
- package/commands/dev.ts +23 -0
- package/commands/generate/auth.ts +31 -0
- package/commands/generate/install.ts +34 -0
- package/commands/generate/resource.ts +184 -0
- package/commands/new.ts +179 -0
- package/package.json +62 -0
- package/templates/backend/controller.ts +41 -0
- package/templates/backend/dto.ts +20 -0
- package/templates/backend/module.ts +16 -0
- package/templates/backend/service.ts +52 -0
- package/templates/backend/student-help.controller.ts +332 -0
- package/templates/backend/student-help.module.ts +9 -0
- package/templates/backend/student-help.service.ts +697 -0
- package/templates/frontend/page.tsx +13 -0
package/commands/db.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
export async function dbInstall(feature: string) {
|
|
4
|
+
console.log(chalk.blue(`\n📦 Installing ${feature} database via Docker...\n`));
|
|
5
|
+
|
|
6
|
+
switch (feature.toLowerCase()) {
|
|
7
|
+
case 'postgres':
|
|
8
|
+
case 'postgresql':
|
|
9
|
+
console.log(chalk.green('✅ PostgreSQL is already included in docker-compose.yml'));
|
|
10
|
+
console.log(chalk.cyan('Access: localhost:5432'));
|
|
11
|
+
console.log(chalk.cyan('User: student'));
|
|
12
|
+
console.log(chalk.cyan('Password: student123\n'));
|
|
13
|
+
break;
|
|
14
|
+
|
|
15
|
+
case 'mongodb':
|
|
16
|
+
case 'mongo':
|
|
17
|
+
console.log(chalk.yellow('⚠️ To add MongoDB, edit docker-compose.yml\n'));
|
|
18
|
+
console.log(chalk.gray(`
|
|
19
|
+
services:
|
|
20
|
+
mongodb:
|
|
21
|
+
image: mongo:latest
|
|
22
|
+
container_name: project_mongodb
|
|
23
|
+
ports:
|
|
24
|
+
- "27017:27017"
|
|
25
|
+
environment:
|
|
26
|
+
MONGO_INITDB_ROOT_USERNAME: admin
|
|
27
|
+
MONGO_INITDB_ROOT_PASSWORD: password
|
|
28
|
+
volumes:
|
|
29
|
+
- mongodb_data:/data/db
|
|
30
|
+
|
|
31
|
+
volumes:
|
|
32
|
+
mongodb_data:
|
|
33
|
+
`));
|
|
34
|
+
break;
|
|
35
|
+
|
|
36
|
+
case 'redis':
|
|
37
|
+
console.log(chalk.yellow('⚠️ To add Redis, edit docker-compose.yml\n'));
|
|
38
|
+
console.log(chalk.gray(`
|
|
39
|
+
services:
|
|
40
|
+
redis:
|
|
41
|
+
image: redis:alpine
|
|
42
|
+
container_name: project_redis
|
|
43
|
+
ports:
|
|
44
|
+
- "6379:6379"
|
|
45
|
+
volumes:
|
|
46
|
+
- redis_data:/data
|
|
47
|
+
|
|
48
|
+
volumes:
|
|
49
|
+
redis_data:
|
|
50
|
+
`));
|
|
51
|
+
break;
|
|
52
|
+
|
|
53
|
+
default:
|
|
54
|
+
console.log(chalk.red(`❌ Database '${feature}' not recognized`));
|
|
55
|
+
console.log(chalk.cyan('Available options: postgres, mongodb, redis\n'));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log(chalk.yellow('Then, run: docker-compose up -d\n'));
|
|
59
|
+
}
|
package/commands/dev.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
|
|
5
|
+
export async function devCommand() {
|
|
6
|
+
try {
|
|
7
|
+
console.log(chalk.blue.bold('\n🐳 Starting Docker containers...\n'));
|
|
8
|
+
execSync('docker-compose up -d', { stdio: 'inherit' });
|
|
9
|
+
|
|
10
|
+
console.log(chalk.blue.bold('\n⏳ Waiting for containers to initialize...\n'));
|
|
11
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
12
|
+
|
|
13
|
+
console.log(chalk.green.bold('\n✅ Development environment started!\n'));
|
|
14
|
+
console.log(chalk.cyan('Backend: http://localhost:3000'));
|
|
15
|
+
console.log(chalk.cyan('Frontend: http://localhost:3001'));
|
|
16
|
+
console.log(chalk.cyan('Database: localhost:5432\n'));
|
|
17
|
+
|
|
18
|
+
console.log(chalk.yellow('To stop the environment, run: docker-compose down\n'));
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error(chalk.red('Error starting environment:'), error instanceof Error ? error.message : String(error));
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
|
|
4
|
+
export async function generateAuth() {
|
|
5
|
+
console.log(chalk.blue.bold('\n🔐 Creating Auth module...\n'));
|
|
6
|
+
|
|
7
|
+
try {
|
|
8
|
+
console.log(chalk.cyan('Backend:'));
|
|
9
|
+
console.log(' - Creating module...');
|
|
10
|
+
execSync('cd backend && nest g module auth', { stdio: 'inherit' });
|
|
11
|
+
|
|
12
|
+
console.log(' - Creating controller...');
|
|
13
|
+
execSync('cd backend && nest g controller auth', { stdio: 'inherit' });
|
|
14
|
+
|
|
15
|
+
console.log(' - Creating service...');
|
|
16
|
+
execSync('cd backend && nest g service auth', { stdio: 'inherit' });
|
|
17
|
+
|
|
18
|
+
console.log(chalk.cyan('\nInstalling authentication dependencies...'));
|
|
19
|
+
execSync('cd backend && npm install @nestjs/jwt @nestjs/passport passport passport-jwt @types/passport-jwt bcrypt --save', { stdio: 'inherit' });
|
|
20
|
+
execSync('cd backend && npm install -D @types/bcrypt', { stdio: 'inherit' });
|
|
21
|
+
|
|
22
|
+
console.log(chalk.green('\n✅ Auth module created successfully!\n'));
|
|
23
|
+
console.log(chalk.yellow('Next steps:'));
|
|
24
|
+
console.log(' 1. Configure JWT variables in .env');
|
|
25
|
+
console.log(' 2. Implement authentication logic in AuthService');
|
|
26
|
+
console.log(' 3. Configure passport strategies in auth.strategy.ts\n');
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error(chalk.red('Error generating auth:'), error instanceof Error ? error.message : String(error));
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
export async function installDependencies() {
|
|
6
|
+
const currentDir = process.cwd();
|
|
7
|
+
|
|
8
|
+
console.log("📦 Installing backend dependencies...");
|
|
9
|
+
try {
|
|
10
|
+
execSync('cd backend && npm install', { stdio: 'inherit' });
|
|
11
|
+
} catch (error) {
|
|
12
|
+
console.error('Error installing backend dependencies:', error instanceof Error ? error.message : String(error));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.log("📦 Installing frontend dependencies...");
|
|
16
|
+
try {
|
|
17
|
+
execSync('cd frontend && npm install', { stdio: 'inherit' });
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.error('Error installing frontend dependencies:', error instanceof Error ? error.message : String(error));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
console.log("✅ Dependencies installed successfully!");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function setupEnvironment() {
|
|
26
|
+
const envPath = '.env';
|
|
27
|
+
const envExamplePath = '.env.example';
|
|
28
|
+
|
|
29
|
+
if (!fs.existsSync(envPath) && fs.existsSync(envExamplePath)) {
|
|
30
|
+
console.log("📝 Creating .env file...");
|
|
31
|
+
fs.copyFileSync(envExamplePath, envPath);
|
|
32
|
+
console.log("✅ .env file created from .env.example");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
|
|
5
|
+
export async function generateResource(resourceName: string) {
|
|
6
|
+
const resourceLower = resourceName.toLowerCase();
|
|
7
|
+
const resourcePascal = resourceName.charAt(0).toUpperCase() + resourceName.slice(1);
|
|
8
|
+
|
|
9
|
+
console.log(chalk.blue.bold(`\n📦 Generating resource: ${resourcePascal}\n`));
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
// Backend
|
|
13
|
+
console.log(chalk.cyan('Backend:'));
|
|
14
|
+
const backendPath = path.join(process.cwd(), 'backend/src', resourceLower);
|
|
15
|
+
fs.ensureDirSync(backendPath);
|
|
16
|
+
|
|
17
|
+
// Helper function to replace template variables
|
|
18
|
+
const replaceContent = (content: string, name: string) => {
|
|
19
|
+
return content
|
|
20
|
+
.replace(/Resource/g, name)
|
|
21
|
+
.replace(/resource/g, name.toLowerCase());
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Copy and customize files
|
|
25
|
+
const primaryPath = path.resolve('.', 'node_modules/student-help/templates/backend/module.ts');
|
|
26
|
+
const fallbackPath = path.resolve(import.meta.url, '../../../templates/backend/module.ts');
|
|
27
|
+
|
|
28
|
+
let moduleTemplate: string;
|
|
29
|
+
try {
|
|
30
|
+
moduleTemplate = fs.readFileSync(primaryPath, 'utf-8');
|
|
31
|
+
} catch {
|
|
32
|
+
moduleTemplate = fs.readFileSync(fallbackPath, 'utf-8');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const backendDir = path.resolve('.', 'node_modules/student-help/templates/backend');
|
|
36
|
+
const templatesDir = path.resolve(import.meta.url, '../../../templates/backend');
|
|
37
|
+
|
|
38
|
+
// Try to find templates
|
|
39
|
+
let templateDir = null;
|
|
40
|
+
if (fs.existsSync(backendDir)) {
|
|
41
|
+
templateDir = backendDir;
|
|
42
|
+
} else if (fs.existsSync(templatesDir)) {
|
|
43
|
+
templateDir = templatesDir;
|
|
44
|
+
} else {
|
|
45
|
+
// Create from scratch if templates not found
|
|
46
|
+
console.log(chalk.yellow('⚠️ Templates not found, creating basic structure...\n'));
|
|
47
|
+
|
|
48
|
+
// Module
|
|
49
|
+
fs.writeFileSync(
|
|
50
|
+
path.join(backendPath, `${resourceLower}.module.ts`),
|
|
51
|
+
`import { Module } from '@nestjs/common';
|
|
52
|
+
import { ${resourcePascal}Service } from './${resourceLower}.service';
|
|
53
|
+
import { ${resourcePascal}Controller } from './${resourceLower}.controller';
|
|
54
|
+
|
|
55
|
+
@Module({
|
|
56
|
+
controllers: [${resourcePascal}Controller],
|
|
57
|
+
providers: [${resourcePascal}Service],
|
|
58
|
+
})
|
|
59
|
+
export class ${resourcePascal}Module {}
|
|
60
|
+
`);
|
|
61
|
+
|
|
62
|
+
// Service
|
|
63
|
+
fs.writeFileSync(
|
|
64
|
+
path.join(backendPath, `${resourceLower}.service.ts`),
|
|
65
|
+
`import { Injectable } from '@nestjs/common';
|
|
66
|
+
import { Create${resourcePascal}Dto, Update${resourcePascal}Dto } from './${resourceLower}.dto';
|
|
67
|
+
|
|
68
|
+
@Injectable()
|
|
69
|
+
export class ${resourcePascal}Service {
|
|
70
|
+
create(create${resourcePascal}Dto: Create${resourcePascal}Dto) {
|
|
71
|
+
return { message: 'Create endpoint for ${resourcePascal}' };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
findAll() {
|
|
75
|
+
return { message: 'Find all ${resourcePascal}' };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
findOne(id: number) {
|
|
79
|
+
return { message: \`Find ${resourcePascal} with id \${id}\` };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
update(id: number, update${resourcePascal}Dto: Update${resourcePascal}Dto) {
|
|
83
|
+
return { message: \`Update ${resourcePascal} with id \${id}\` };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
remove(id: number) {
|
|
87
|
+
return { message: \`Remove ${resourcePascal} with id \${id}\` };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
`);
|
|
91
|
+
|
|
92
|
+
// Controller
|
|
93
|
+
fs.writeFileSync(
|
|
94
|
+
path.join(backendPath, `${resourceLower}.controller.ts`),
|
|
95
|
+
`import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
|
|
96
|
+
import { ${resourcePascal}Service } from './${resourceLower}.service';
|
|
97
|
+
import { Create${resourcePascal}Dto, Update${resourcePascal}Dto } from './${resourceLower}.dto';
|
|
98
|
+
|
|
99
|
+
@Controller('${resourceLower}')
|
|
100
|
+
export class ${resourcePascal}Controller {
|
|
101
|
+
constructor(private readonly ${resourceLower}Service: ${resourcePascal}Service) {}
|
|
102
|
+
|
|
103
|
+
@Post()
|
|
104
|
+
create(@Body() create${resourcePascal}Dto: Create${resourcePascal}Dto) {
|
|
105
|
+
return this.${resourceLower}Service.create(create${resourcePascal}Dto);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@Get()
|
|
109
|
+
findAll() {
|
|
110
|
+
return this.${resourceLower}Service.findAll();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@Get(':id')
|
|
114
|
+
findOne(@Param('id') id: string) {
|
|
115
|
+
return this.${resourceLower}Service.findOne(+id);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@Patch(':id')
|
|
119
|
+
update(@Param('id') id: string, @Body() update${resourcePascal}Dto: Update${resourcePascal}Dto) {
|
|
120
|
+
return this.${resourceLower}Service.update(+id, update${resourcePascal}Dto);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@Delete(':id')
|
|
124
|
+
remove(@Param('id') id: string) {
|
|
125
|
+
return this.${resourceLower}Service.remove(+id);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
`);
|
|
129
|
+
|
|
130
|
+
// DTO
|
|
131
|
+
fs.writeFileSync(
|
|
132
|
+
path.join(backendPath, `${resourceLower}.dto.ts`),
|
|
133
|
+
`export class Create${resourcePascal}Dto {
|
|
134
|
+
title: string;
|
|
135
|
+
description?: string;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export class Update${resourcePascal}Dto {
|
|
139
|
+
title?: string;
|
|
140
|
+
description?: string;
|
|
141
|
+
}
|
|
142
|
+
`);
|
|
143
|
+
|
|
144
|
+
console.log(' ✅ Module created');
|
|
145
|
+
console.log(' ✅ Service created');
|
|
146
|
+
console.log(' ✅ Controller created');
|
|
147
|
+
console.log(' ✅ DTO created');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Frontend
|
|
151
|
+
console.log(chalk.cyan('\nFrontend:'));
|
|
152
|
+
const frontendPath = path.join(process.cwd(), 'app', resourceLower);
|
|
153
|
+
fs.ensureDirSync(frontendPath);
|
|
154
|
+
|
|
155
|
+
// Create a basic page component
|
|
156
|
+
fs.writeFileSync(
|
|
157
|
+
path.join(frontendPath, 'page.tsx'),
|
|
158
|
+
`'use client';
|
|
159
|
+
|
|
160
|
+
import React from 'react';
|
|
161
|
+
|
|
162
|
+
export default function ${resourcePascal}Page() {
|
|
163
|
+
return (
|
|
164
|
+
<div className="container mx-auto py-8">
|
|
165
|
+
<h1 className="text-3xl font-bold mb-4">${resourcePascal} Management</h1>
|
|
166
|
+
<p className="text-gray-600">This is the ${resourcePascal} CRUD page. Start implementing here!</p>
|
|
167
|
+
</div>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
`);
|
|
171
|
+
|
|
172
|
+
console.log(` ✅ Page created in app/${resourceLower}`);
|
|
173
|
+
|
|
174
|
+
console.log(chalk.green.bold(`\n✅ Resource ${resourcePascal} generated successfully!\n`));
|
|
175
|
+
console.log(chalk.yellow('Next steps:'));
|
|
176
|
+
console.log(` 1. Register the module in backend/src/app.module.ts`);
|
|
177
|
+
console.log(` 2. Implement service logic`);
|
|
178
|
+
console.log(` 3. Create frontend interface in Next.js\n`);
|
|
179
|
+
|
|
180
|
+
} catch (error) {
|
|
181
|
+
console.error(chalk.red('Error generating resource:'), error instanceof Error ? error.message : String(error));
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
}
|
package/commands/new.ts
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import { execSync } from 'child_process';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
export async function newCommand(projectName: string) {
|
|
6
|
+
const projectPath = path.join(process.cwd(), projectName);
|
|
7
|
+
fs.ensureDirSync(projectPath);
|
|
8
|
+
|
|
9
|
+
console.log("📦 Setting up NestJS backend...");
|
|
10
|
+
try {
|
|
11
|
+
execSync(`npx @nestjs/cli new backend --directory ${projectPath}/backend --package-manager npm`, { stdio: 'inherit' });
|
|
12
|
+
} catch (error) {
|
|
13
|
+
console.error('Error creating backend:', error instanceof Error ? error.message : String(error));
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
console.log("📦 Setting up Next.js frontend...");
|
|
18
|
+
try {
|
|
19
|
+
execSync(`npx create-next-app@latest ${projectPath}/frontend --typescript --use-npm --eslint --app --no-src-dir --import-alias '@/*'`, { stdio: 'inherit' });
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error('Error creating frontend:', error instanceof Error ? error.message : String(error));
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
console.log("📝 Creating Dockerfiles...");
|
|
26
|
+
fs.writeFileSync(path.join(projectPath, 'backend/Dockerfile'), `FROM node:18
|
|
27
|
+
WORKDIR /app
|
|
28
|
+
COPY package*.json ./
|
|
29
|
+
RUN npm install
|
|
30
|
+
COPY . .
|
|
31
|
+
RUN npm run build
|
|
32
|
+
CMD ["npm", "run", "start:prod"]
|
|
33
|
+
`);
|
|
34
|
+
|
|
35
|
+
fs.writeFileSync(path.join(projectPath, 'frontend/Dockerfile'), `FROM node:18
|
|
36
|
+
WORKDIR /app
|
|
37
|
+
COPY package*.json ./
|
|
38
|
+
RUN npm install
|
|
39
|
+
COPY . .
|
|
40
|
+
RUN npm run build
|
|
41
|
+
CMD ["npm", "run", "start"]
|
|
42
|
+
`);
|
|
43
|
+
|
|
44
|
+
console.log("📝 Creating docker-compose.yml...");
|
|
45
|
+
fs.writeFileSync(path.join(projectPath, 'docker-compose.yml'), `version: '3.8'
|
|
46
|
+
services:
|
|
47
|
+
backend:
|
|
48
|
+
build: ./backend
|
|
49
|
+
container_name: ${projectName}_backend
|
|
50
|
+
ports:
|
|
51
|
+
- "3000:3000"
|
|
52
|
+
environment:
|
|
53
|
+
NODE_ENV: development
|
|
54
|
+
DB_HOST: db
|
|
55
|
+
DB_PORT: 5432
|
|
56
|
+
DB_USER: student
|
|
57
|
+
DB_PASSWORD: student123
|
|
58
|
+
DB_NAME: ${projectName}
|
|
59
|
+
volumes:
|
|
60
|
+
- ./backend:/app
|
|
61
|
+
- /app/node_modules
|
|
62
|
+
depends_on:
|
|
63
|
+
- db
|
|
64
|
+
networks:
|
|
65
|
+
- app-network
|
|
66
|
+
|
|
67
|
+
frontend:
|
|
68
|
+
build: ./frontend
|
|
69
|
+
container_name: ${projectName}_frontend
|
|
70
|
+
ports:
|
|
71
|
+
- "3001:3000"
|
|
72
|
+
environment:
|
|
73
|
+
NODE_ENV: development
|
|
74
|
+
NEXT_PUBLIC_API_URL: http://localhost:3000/api
|
|
75
|
+
volumes:
|
|
76
|
+
- ./frontend:/app
|
|
77
|
+
- /app/node_modules
|
|
78
|
+
depends_on:
|
|
79
|
+
- backend
|
|
80
|
+
networks:
|
|
81
|
+
- app-network
|
|
82
|
+
|
|
83
|
+
db:
|
|
84
|
+
image: postgres:15-alpine
|
|
85
|
+
container_name: ${projectName}_postgres
|
|
86
|
+
environment:
|
|
87
|
+
POSTGRES_USER: student
|
|
88
|
+
POSTGRES_PASSWORD: student123
|
|
89
|
+
POSTGRES_DB: ${projectName}
|
|
90
|
+
ports:
|
|
91
|
+
- "5432:5432"
|
|
92
|
+
volumes:
|
|
93
|
+
- postgres_data:/var/lib/postgresql/data
|
|
94
|
+
networks:
|
|
95
|
+
- app-network
|
|
96
|
+
|
|
97
|
+
volumes:
|
|
98
|
+
postgres_data:
|
|
99
|
+
|
|
100
|
+
networks:
|
|
101
|
+
app-network:
|
|
102
|
+
driver: bridge
|
|
103
|
+
`);
|
|
104
|
+
|
|
105
|
+
console.log("📝 Creating .env.example...");
|
|
106
|
+
fs.writeFileSync(path.join(projectPath, '.env.example'), `# Backend
|
|
107
|
+
BACKEND_PORT=3000
|
|
108
|
+
NODE_ENV=development
|
|
109
|
+
|
|
110
|
+
# Frontend
|
|
111
|
+
FRONTEND_PORT=3001
|
|
112
|
+
NEXT_PUBLIC_API_URL=http://localhost:3000/api
|
|
113
|
+
|
|
114
|
+
# Database
|
|
115
|
+
DB_HOST=db
|
|
116
|
+
DB_PORT=5432
|
|
117
|
+
DB_USER=student
|
|
118
|
+
DB_PASSWORD=student123
|
|
119
|
+
DB_NAME=${projectName}
|
|
120
|
+
|
|
121
|
+
# JWT
|
|
122
|
+
JWT_SECRET=your_secret_key_change_this
|
|
123
|
+
JWT_EXPIRATION=7d
|
|
124
|
+
`);
|
|
125
|
+
|
|
126
|
+
console.log("📝 Creating .gitignore...");
|
|
127
|
+
fs.writeFileSync(path.join(projectPath, '.gitignore'), `# Dependencies
|
|
128
|
+
node_modules/
|
|
129
|
+
/.pnp
|
|
130
|
+
.pnp.js
|
|
131
|
+
|
|
132
|
+
# Testing
|
|
133
|
+
/coverage
|
|
134
|
+
|
|
135
|
+
# Production
|
|
136
|
+
/build
|
|
137
|
+
/dist
|
|
138
|
+
/out
|
|
139
|
+
|
|
140
|
+
# Misc
|
|
141
|
+
.DS_Store
|
|
142
|
+
.env
|
|
143
|
+
.env.local
|
|
144
|
+
.env.development.local
|
|
145
|
+
.env.test.local
|
|
146
|
+
.env.production.local
|
|
147
|
+
|
|
148
|
+
# Logs
|
|
149
|
+
npm-debug.log*
|
|
150
|
+
yarn-debug.log*
|
|
151
|
+
yarn-error.log*
|
|
152
|
+
pnpm-debug.log*
|
|
153
|
+
lerna-debug.log*
|
|
154
|
+
|
|
155
|
+
# IDE
|
|
156
|
+
.vscode
|
|
157
|
+
.idea
|
|
158
|
+
*.swp
|
|
159
|
+
*.swo
|
|
160
|
+
|
|
161
|
+
# Docker
|
|
162
|
+
docker-compose.override.yml
|
|
163
|
+
`);
|
|
164
|
+
|
|
165
|
+
console.log("🔧 Initializing git...");
|
|
166
|
+
try {
|
|
167
|
+
execSync(`cd ${projectPath} && git init && git add . && git commit -m "Initial project setup"`, { stdio: 'inherit' });
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.warn('Warning: Git not configured properly');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
console.log("\n✅ Project created successfully!");
|
|
173
|
+
console.log(`\n📂 Next steps:`);
|
|
174
|
+
console.log(` cd ${projectName}`);
|
|
175
|
+
console.log(` docker-compose up -d`);
|
|
176
|
+
console.log(`\n🚀 Project will be available at:`);
|
|
177
|
+
console.log(` Backend: http://localhost:3000`);
|
|
178
|
+
console.log(` Frontend: http://localhost:3001`);
|
|
179
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "student-help",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "🎓 Student Help Framework - Create full-stack projects in minutes with integrated StudentHelp utilities module",
|
|
5
|
+
"main": "cli.mjs",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"preferGlobal": true,
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"start": "node bin/student-help.js",
|
|
12
|
+
"dev": "node --loader ts-node/esm bin/student-help.js",
|
|
13
|
+
"prepare": "npm run build 2>/dev/null || true"
|
|
14
|
+
},
|
|
15
|
+
"bin": {
|
|
16
|
+
"student-help": "./bin/student-help.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"bin",
|
|
20
|
+
"cli.mjs",
|
|
21
|
+
"commands",
|
|
22
|
+
"templates",
|
|
23
|
+
"utils",
|
|
24
|
+
"package.json",
|
|
25
|
+
"README.md"
|
|
26
|
+
],
|
|
27
|
+
"keywords": [
|
|
28
|
+
"framework",
|
|
29
|
+
"nestjs",
|
|
30
|
+
"nextjs",
|
|
31
|
+
"cli",
|
|
32
|
+
"students",
|
|
33
|
+
"fullstack",
|
|
34
|
+
"generator",
|
|
35
|
+
"scaffold"
|
|
36
|
+
],
|
|
37
|
+
"author": "Student Help Team",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/guimelloo/StudentHelp.git"
|
|
42
|
+
},
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/guimelloo/StudentHelp/issues"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://github.com/guimelloo/StudentHelp#readme",
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=16.0.0"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"chalk": "^5.6.2",
|
|
52
|
+
"commander": "^14.0.3",
|
|
53
|
+
"fs-extra": "^11.3.4",
|
|
54
|
+
"ora": "^8.0.1"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/fs-extra": "^11.0.4",
|
|
58
|
+
"@types/node": "^20.10.0",
|
|
59
|
+
"ts-node": "^10.9.2",
|
|
60
|
+
"typescript": "^5.3.3"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ResourceController
|
|
3
|
+
* ================================
|
|
4
|
+
* Controlador que gerencia as requisições HTTP para o recurso Resource.
|
|
5
|
+
* Expansão:
|
|
6
|
+
* - Adicione validação com pipes
|
|
7
|
+
* - Adicione autenticação/autorização
|
|
8
|
+
*/
|
|
9
|
+
import { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common';
|
|
10
|
+
import { ResourceService } from './resource.service';
|
|
11
|
+
import { CreateResourceDto, UpdateResourceDto } from './resource.dto';
|
|
12
|
+
|
|
13
|
+
@Controller('api/resource')
|
|
14
|
+
export class ResourceController {
|
|
15
|
+
constructor(private readonly resourceService: ResourceService) {}
|
|
16
|
+
|
|
17
|
+
@Post()
|
|
18
|
+
create(@Body() createResourceDto: CreateResourceDto) {
|
|
19
|
+
return this.resourceService.create(createResourceDto);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@Get()
|
|
23
|
+
findAll() {
|
|
24
|
+
return this.resourceService.findAll();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Get(':id')
|
|
28
|
+
findOne(@Param('id') id: string) {
|
|
29
|
+
return this.resourceService.findOne(+id);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@Put(':id')
|
|
33
|
+
update(@Param('id') id: string, @Body() updateResourceDto: UpdateResourceDto) {
|
|
34
|
+
return this.resourceService.update(+id, updateResourceDto);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@Delete(':id')
|
|
38
|
+
remove(@Param('id') id: string) {
|
|
39
|
+
return this.resourceService.remove(+id);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource DTOs
|
|
3
|
+
* ================================
|
|
4
|
+
* Data Transfer Objects para validação de entrada do recurso Resource.
|
|
5
|
+
* Expansão:
|
|
6
|
+
* - Adicione validação com class-validator
|
|
7
|
+
* - Adicione transformação com class-transformer
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export class CreateResourceDto {
|
|
11
|
+
title: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
content?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class UpdateResourceDto {
|
|
17
|
+
title?: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
content?: string;
|
|
20
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ResourceModule
|
|
3
|
+
* ===============================
|
|
4
|
+
* Este módulo agrupa todos os componentes do recurso Resource.
|
|
5
|
+
* Expansão:
|
|
6
|
+
* - Adicione guards e interceptors
|
|
7
|
+
*/
|
|
8
|
+
import { Module } from '@nestjs/common';
|
|
9
|
+
import { ResourceService } from './resource.service';
|
|
10
|
+
import { ResourceController } from './resource.controller';
|
|
11
|
+
|
|
12
|
+
@Module({
|
|
13
|
+
controllers: [ResourceController],
|
|
14
|
+
providers: [ResourceService],
|
|
15
|
+
})
|
|
16
|
+
export class ResourceModule {}
|