forgestack-os-cli 0.1.0 → 0.1.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/dist/commands/create.js +14 -0
- package/dist/commands/create.js.map +1 -1
- package/dist/generators/auth.js +121 -23
- package/dist/generators/auth.js.map +1 -1
- package/dist/generators/backend.js +160 -9
- package/dist/generators/backend.js.map +1 -1
- package/dist/generators/common.js +4 -1
- package/dist/generators/common.js.map +1 -1
- package/dist/generators/database.js +20 -14
- package/dist/generators/database.js.map +1 -1
- package/dist/generators/docker.js +14 -4
- package/dist/generators/docker.js.map +1 -1
- package/dist/utils/prompts.js +62 -7
- package/dist/utils/prompts.js.map +1 -1
- package/package.json +7 -2
- package/src/commands/create.ts +0 -82
- package/src/generators/api.ts +0 -353
- package/src/generators/auth.ts +0 -406
- package/src/generators/backend.ts +0 -927
- package/src/generators/common.ts +0 -377
- package/src/generators/database.ts +0 -165
- package/src/generators/docker.ts +0 -185
- package/src/generators/frontend.ts +0 -783
- package/src/generators/index.ts +0 -64
- package/src/index.ts +0 -27
- package/src/types.ts +0 -16
- package/src/utils/logger.ts +0 -31
- package/src/utils/prompts.ts +0 -105
- package/src/utils/validators.ts +0 -50
- package/tests/validators.test.ts +0 -69
- package/tsc_output.txt +0 -0
- package/tsconfig.json +0 -21
package/src/generators/common.ts
DELETED
|
@@ -1,377 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import fs from 'fs-extra';
|
|
3
|
-
import { StackConfig } from '../types';
|
|
4
|
-
|
|
5
|
-
export async function generateCommon(config: StackConfig, targetDir: string) {
|
|
6
|
-
// Generate root package.json
|
|
7
|
-
const rootPackageJson = {
|
|
8
|
-
name: config.projectName,
|
|
9
|
-
version: '0.1.0',
|
|
10
|
-
private: true,
|
|
11
|
-
workspaces: ['frontend', 'backend'],
|
|
12
|
-
scripts: {
|
|
13
|
-
dev: 'npm run dev --workspace=frontend & npm run dev --workspace=backend',
|
|
14
|
-
'dev:frontend': 'npm run dev --workspace=frontend',
|
|
15
|
-
'dev:backend': 'npm run dev --workspace=backend',
|
|
16
|
-
build: 'npm run build --workspaces',
|
|
17
|
-
test: 'npm run test --workspaces',
|
|
18
|
-
},
|
|
19
|
-
author: 'Generated by ForgeStack OS',
|
|
20
|
-
license: 'MIT',
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
await fs.writeJSON(path.join(targetDir, 'package.json'), rootPackageJson, { spaces: 2 });
|
|
24
|
-
|
|
25
|
-
// Generate .gitignore
|
|
26
|
-
const gitignore = `# Dependencies
|
|
27
|
-
node_modules/
|
|
28
|
-
.pnp
|
|
29
|
-
.pnp.js
|
|
30
|
-
|
|
31
|
-
# Testing
|
|
32
|
-
coverage/
|
|
33
|
-
|
|
34
|
-
# Production
|
|
35
|
-
build/
|
|
36
|
-
dist/
|
|
37
|
-
.next/
|
|
38
|
-
out/
|
|
39
|
-
|
|
40
|
-
# Environment
|
|
41
|
-
.env
|
|
42
|
-
.env.local
|
|
43
|
-
.env.*.local
|
|
44
|
-
|
|
45
|
-
# Logs
|
|
46
|
-
logs/
|
|
47
|
-
*.log
|
|
48
|
-
npm-debug.log*
|
|
49
|
-
yarn-debug.log*
|
|
50
|
-
yarn-error.log*
|
|
51
|
-
|
|
52
|
-
# OS
|
|
53
|
-
.DS_Store
|
|
54
|
-
Thumbs.db
|
|
55
|
-
|
|
56
|
-
# IDE
|
|
57
|
-
.vscode/
|
|
58
|
-
.idea/
|
|
59
|
-
*.swp
|
|
60
|
-
*.swo
|
|
61
|
-
|
|
62
|
-
# Database
|
|
63
|
-
*.db
|
|
64
|
-
*.sqlite
|
|
65
|
-
prisma/migrations/
|
|
66
|
-
|
|
67
|
-
# Docker
|
|
68
|
-
docker-compose.override.yml
|
|
69
|
-
`;
|
|
70
|
-
|
|
71
|
-
await fs.writeFile(path.join(targetDir, '.gitignore'), gitignore);
|
|
72
|
-
|
|
73
|
-
// Generate README.md
|
|
74
|
-
const readme = generateReadme(config);
|
|
75
|
-
await fs.writeFile(path.join(targetDir, 'README.md'), readme);
|
|
76
|
-
|
|
77
|
-
// Generate .env.example
|
|
78
|
-
const envExample = generateEnvExample(config);
|
|
79
|
-
await fs.writeFile(path.join(targetDir, '.env.example'), envExample);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function generateReadme(config: StackConfig): string {
|
|
83
|
-
return `# ${config.projectName}
|
|
84
|
-
|
|
85
|
-
Generated by **ForgeStack OS** - One platform. Any stack. Production-ready.
|
|
86
|
-
|
|
87
|
-
## Stack
|
|
88
|
-
|
|
89
|
-
- **Frontend:** ${config.frontend}
|
|
90
|
-
- **Backend:** ${config.backend}
|
|
91
|
-
- **Auth:** ${config.auth}
|
|
92
|
-
- **Database:** ${config.database}
|
|
93
|
-
- **API Style:** ${config.apiStyle}
|
|
94
|
-
- **Docker:** ${config.docker ? 'Yes' : 'No'}
|
|
95
|
-
- **Multi-Tenant:** ${config.multiTenant ? 'Yes' : 'No'}
|
|
96
|
-
|
|
97
|
-
## Getting Started
|
|
98
|
-
|
|
99
|
-
### Prerequisites
|
|
100
|
-
|
|
101
|
-
- Node.js 18+ (or Bun if using Bun backend)
|
|
102
|
-
${config.backend === 'go-fiber' ? '- Go 1.21+' : ''}
|
|
103
|
-
${config.docker ? '- Docker and Docker Compose' : ''}
|
|
104
|
-
${config.database === 'postgresql' ? '- PostgreSQL (or use Docker)' : ''}
|
|
105
|
-
${config.database === 'mongodb' ? '- MongoDB (or use Docker)' : ''}
|
|
106
|
-
|
|
107
|
-
### Installation
|
|
108
|
-
|
|
109
|
-
\`\`\`bash
|
|
110
|
-
# Install dependencies
|
|
111
|
-
npm install
|
|
112
|
-
|
|
113
|
-
# Copy environment variables
|
|
114
|
-
cp .env.example .env
|
|
115
|
-
|
|
116
|
-
# Update .env with your configuration
|
|
117
|
-
\`\`\`
|
|
118
|
-
|
|
119
|
-
### Database Setup
|
|
120
|
-
|
|
121
|
-
${getDatabaseSetupInstructions(config)}
|
|
122
|
-
|
|
123
|
-
### Development
|
|
124
|
-
|
|
125
|
-
\`\`\`bash
|
|
126
|
-
# Run both frontend and backend
|
|
127
|
-
npm run dev
|
|
128
|
-
|
|
129
|
-
# Or run separately
|
|
130
|
-
npm run dev:frontend
|
|
131
|
-
npm run dev:backend
|
|
132
|
-
\`\`\`
|
|
133
|
-
|
|
134
|
-
${config.docker ? `### Docker
|
|
135
|
-
|
|
136
|
-
\`\`\`bash
|
|
137
|
-
# Start all services
|
|
138
|
-
docker-compose up
|
|
139
|
-
|
|
140
|
-
# Start in detached mode
|
|
141
|
-
docker-compose up -d
|
|
142
|
-
|
|
143
|
-
# Stop services
|
|
144
|
-
docker-compose down
|
|
145
|
-
\`\`\`
|
|
146
|
-
` : ''}
|
|
147
|
-
|
|
148
|
-
## Project Structure
|
|
149
|
-
|
|
150
|
-
\`\`\`
|
|
151
|
-
${config.projectName}/
|
|
152
|
-
├── frontend/ # ${config.frontend} application
|
|
153
|
-
├── backend/ # ${config.backend} server
|
|
154
|
-
${config.docker ? '├── docker/ # Docker configuration' : ''}
|
|
155
|
-
├── .env.example # Environment variables template
|
|
156
|
-
└── README.md # This file
|
|
157
|
-
\`\`\`
|
|
158
|
-
|
|
159
|
-
## Authentication
|
|
160
|
-
|
|
161
|
-
${getAuthInstructions(config)}
|
|
162
|
-
|
|
163
|
-
${config.multiTenant ? `## Multi-Tenancy
|
|
164
|
-
|
|
165
|
-
This application is configured with multi-tenancy support. Each request is automatically scoped to a tenant based on:
|
|
166
|
-
|
|
167
|
-
${getTenantScopingInfo(config)}
|
|
168
|
-
|
|
169
|
-
All database queries include tenant isolation to ensure data security.
|
|
170
|
-
` : ''}
|
|
171
|
-
|
|
172
|
-
## Built With
|
|
173
|
-
|
|
174
|
-
- [ForgeStack OS](https://github.com/halloffame12/forgestack-os) - The meta-platform that generated this project
|
|
175
|
-
- Created by [Sumit Chauhan](https://github.com/halloffame12)
|
|
176
|
-
|
|
177
|
-
## License
|
|
178
|
-
|
|
179
|
-
MIT
|
|
180
|
-
`;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function getDatabaseSetupInstructions(config: StackConfig): string {
|
|
184
|
-
switch (config.database) {
|
|
185
|
-
case 'postgresql':
|
|
186
|
-
return `\`\`\`bash
|
|
187
|
-
# Using Docker
|
|
188
|
-
docker-compose up -d postgres
|
|
189
|
-
|
|
190
|
-
# Or install PostgreSQL locally and create a database
|
|
191
|
-
createdb ${config.projectName}
|
|
192
|
-
|
|
193
|
-
# Run migrations
|
|
194
|
-
cd backend
|
|
195
|
-
npx prisma migrate dev
|
|
196
|
-
\`\`\``;
|
|
197
|
-
|
|
198
|
-
case 'mongodb':
|
|
199
|
-
return `\`\`\`bash
|
|
200
|
-
# Using Docker
|
|
201
|
-
docker-compose up -d mongodb
|
|
202
|
-
|
|
203
|
-
# Or install MongoDB locally
|
|
204
|
-
# No migrations needed - Mongoose handles schema
|
|
205
|
-
\`\`\``;
|
|
206
|
-
|
|
207
|
-
case 'mysql':
|
|
208
|
-
return `\`\`\`bash
|
|
209
|
-
# Using Docker
|
|
210
|
-
docker-compose up -d mysql
|
|
211
|
-
|
|
212
|
-
# Or install MySQL locally and create a database
|
|
213
|
-
mysql -u root -p -e "CREATE DATABASE ${config.projectName};"
|
|
214
|
-
|
|
215
|
-
# Run migrations
|
|
216
|
-
cd backend
|
|
217
|
-
npx prisma migrate dev
|
|
218
|
-
\`\`\``;
|
|
219
|
-
|
|
220
|
-
case 'sqlite':
|
|
221
|
-
return `\`\`\`bash
|
|
222
|
-
# SQLite is file-based, no setup needed
|
|
223
|
-
# Database file will be created automatically
|
|
224
|
-
cd backend
|
|
225
|
-
npx prisma migrate dev
|
|
226
|
-
\`\`\``;
|
|
227
|
-
|
|
228
|
-
case 'supabase-db':
|
|
229
|
-
return `\`\`\`bash
|
|
230
|
-
# Create a Supabase project at https://supabase.com
|
|
231
|
-
# Copy your connection string to .env
|
|
232
|
-
# Run migrations through Supabase dashboard or CLI
|
|
233
|
-
\`\`\``;
|
|
234
|
-
|
|
235
|
-
default:
|
|
236
|
-
return 'See backend/README.md for database setup instructions.';
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function getAuthInstructions(config: StackConfig): string {
|
|
241
|
-
switch (config.auth) {
|
|
242
|
-
case 'jwt':
|
|
243
|
-
return `This project uses built-in JWT authentication. Users can register and login through the API endpoints:
|
|
244
|
-
|
|
245
|
-
- \`POST /api/auth/register\` - Create a new account
|
|
246
|
-
- \`POST /api/auth/login\` - Login and receive JWT token
|
|
247
|
-
- Include the token in requests: \`Authorization: Bearer <token>\``;
|
|
248
|
-
|
|
249
|
-
case 'clerk':
|
|
250
|
-
return `This project uses Clerk for authentication.
|
|
251
|
-
|
|
252
|
-
1. Create a Clerk account at https://clerk.com
|
|
253
|
-
2. Create a new application
|
|
254
|
-
3. Copy your API keys to \`.env\`
|
|
255
|
-
4. Configure allowed redirect URLs in Clerk dashboard`;
|
|
256
|
-
|
|
257
|
-
case 'supabase':
|
|
258
|
-
return `This project uses Supabase Auth.
|
|
259
|
-
|
|
260
|
-
1. Create a Supabase project at https://supabase.com
|
|
261
|
-
2. Copy your project URL and anon key to \`.env\`
|
|
262
|
-
3. Configure auth providers in Supabase dashboard`;
|
|
263
|
-
|
|
264
|
-
case 'authjs':
|
|
265
|
-
return `This project uses Auth.js (NextAuth).
|
|
266
|
-
|
|
267
|
-
1. Configure providers in \`backend/src/auth/config.ts\`
|
|
268
|
-
2. Add provider credentials to \`.env\`
|
|
269
|
-
3. See https://authjs.dev for provider setup guides`;
|
|
270
|
-
|
|
271
|
-
case 'firebase':
|
|
272
|
-
return `This project uses Firebase Auth.
|
|
273
|
-
|
|
274
|
-
1. Create a Firebase project at https://firebase.google.com
|
|
275
|
-
2. Enable authentication methods
|
|
276
|
-
3. Copy your config to \`.env\``;
|
|
277
|
-
|
|
278
|
-
default:
|
|
279
|
-
return 'See documentation for authentication setup.';
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
function getTenantScopingInfo(config: StackConfig): string {
|
|
284
|
-
switch (config.auth) {
|
|
285
|
-
case 'clerk':
|
|
286
|
-
return '- Clerk organization ID is used as tenant ID\n- Organization membership determines access';
|
|
287
|
-
case 'supabase':
|
|
288
|
-
return '- Supabase user metadata contains tenant_id\n- Row Level Security (RLS) policies enforce isolation';
|
|
289
|
-
case 'jwt':
|
|
290
|
-
return '- JWT token contains tenant_id claim\n- Middleware extracts and validates tenant context';
|
|
291
|
-
default:
|
|
292
|
-
return '- Authentication provider includes tenant information\n- Middleware enforces tenant isolation';
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function generateEnvExample(config: StackConfig): string {
|
|
297
|
-
let env = `# Database
|
|
298
|
-
DATABASE_URL="${getDatabaseUrl(config)}"
|
|
299
|
-
|
|
300
|
-
# Server
|
|
301
|
-
PORT=3000
|
|
302
|
-
NODE_ENV=development
|
|
303
|
-
|
|
304
|
-
`;
|
|
305
|
-
|
|
306
|
-
// Auth-specific variables
|
|
307
|
-
switch (config.auth) {
|
|
308
|
-
case 'jwt':
|
|
309
|
-
env += `# JWT Authentication
|
|
310
|
-
JWT_SECRET=your-super-secret-jwt-key-change-this
|
|
311
|
-
JWT_EXPIRES_IN=7d
|
|
312
|
-
`;
|
|
313
|
-
break;
|
|
314
|
-
|
|
315
|
-
case 'clerk':
|
|
316
|
-
env += `# Clerk Authentication
|
|
317
|
-
CLERK_PUBLISHABLE_KEY=pk_test_xxxxx
|
|
318
|
-
CLERK_SECRET_KEY=sk_test_xxxxx
|
|
319
|
-
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxxxx
|
|
320
|
-
`;
|
|
321
|
-
break;
|
|
322
|
-
|
|
323
|
-
case 'supabase':
|
|
324
|
-
env += `# Supabase
|
|
325
|
-
SUPABASE_URL=https://xxxxx.supabase.co
|
|
326
|
-
SUPABASE_ANON_KEY=xxxxx
|
|
327
|
-
SUPABASE_SERVICE_ROLE_KEY=xxxxx
|
|
328
|
-
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
|
|
329
|
-
NEXT_PUBLIC_SUPABASE_ANON_KEY=xxxxx
|
|
330
|
-
`;
|
|
331
|
-
break;
|
|
332
|
-
|
|
333
|
-
case 'authjs':
|
|
334
|
-
env += `# Auth.js
|
|
335
|
-
NEXTAUTH_URL=http://localhost:3000
|
|
336
|
-
NEXTAUTH_SECRET=your-secret-key-change-this
|
|
337
|
-
GOOGLE_CLIENT_ID=xxxxx
|
|
338
|
-
GOOGLE_CLIENT_SECRET=xxxxx
|
|
339
|
-
`;
|
|
340
|
-
break;
|
|
341
|
-
|
|
342
|
-
case 'firebase':
|
|
343
|
-
env += `# Firebase
|
|
344
|
-
FIREBASE_API_KEY=xxxxx
|
|
345
|
-
FIREBASE_AUTH_DOMAIN=xxxxx.firebaseapp.com
|
|
346
|
-
FIREBASE_PROJECT_ID=xxxxx
|
|
347
|
-
NEXT_PUBLIC_FIREBASE_API_KEY=xxxxx
|
|
348
|
-
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=xxxxx.firebaseapp.com
|
|
349
|
-
NEXT_PUBLIC_FIREBASE_PROJECT_ID=xxxxx
|
|
350
|
-
`;
|
|
351
|
-
break;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Frontend URL
|
|
355
|
-
env += `\n# Frontend
|
|
356
|
-
FRONTEND_URL=http://localhost:5173
|
|
357
|
-
`;
|
|
358
|
-
|
|
359
|
-
return env;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
function getDatabaseUrl(config: StackConfig): string {
|
|
363
|
-
switch (config.database) {
|
|
364
|
-
case 'postgresql':
|
|
365
|
-
return 'postgresql://user:password@localhost:5432/dbname';
|
|
366
|
-
case 'mongodb':
|
|
367
|
-
return 'mongodb://localhost:27017/dbname';
|
|
368
|
-
case 'mysql':
|
|
369
|
-
return 'mysql://user:password@localhost:3306/dbname';
|
|
370
|
-
case 'sqlite':
|
|
371
|
-
return 'file:./dev.db';
|
|
372
|
-
case 'supabase-db':
|
|
373
|
-
return 'postgresql://postgres:password@db.xxxxx.supabase.co:5432/postgres';
|
|
374
|
-
default:
|
|
375
|
-
return 'your-database-connection-string';
|
|
376
|
-
}
|
|
377
|
-
}
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import fs from 'fs-extra';
|
|
3
|
-
import { StackConfig } from '../types';
|
|
4
|
-
|
|
5
|
-
export async function generateDatabase(config: StackConfig, backendDir: string) {
|
|
6
|
-
switch (config.database) {
|
|
7
|
-
case 'postgresql':
|
|
8
|
-
case 'mysql':
|
|
9
|
-
case 'sqlite':
|
|
10
|
-
await generatePrisma(config, backendDir);
|
|
11
|
-
break;
|
|
12
|
-
case 'mongodb':
|
|
13
|
-
await generateMongoose(config, backendDir);
|
|
14
|
-
break;
|
|
15
|
-
case 'supabase-db':
|
|
16
|
-
await generateSupabase(config, backendDir);
|
|
17
|
-
break;
|
|
18
|
-
default:
|
|
19
|
-
throw new Error(`Unsupported database: ${config.database}`);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async function generatePrisma(config: StackConfig, backendDir: string) {
|
|
24
|
-
const prismaDir = path.join(backendDir, 'prisma');
|
|
25
|
-
await fs.ensureDir(prismaDir);
|
|
26
|
-
|
|
27
|
-
// Prisma schema
|
|
28
|
-
const schema = getPrismaSchema(config);
|
|
29
|
-
await fs.writeFile(path.join(prismaDir, 'schema.prisma'), schema);
|
|
30
|
-
|
|
31
|
-
// Prisma client initialization
|
|
32
|
-
const prismaClient = `import { PrismaClient } from '@prisma/client';
|
|
33
|
-
|
|
34
|
-
const globalForPrisma = globalThis as unknown as {
|
|
35
|
-
prisma: PrismaClient | undefined;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export const prisma =
|
|
39
|
-
globalForPrisma.prisma ??
|
|
40
|
-
new PrismaClient({
|
|
41
|
-
log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
|
|
45
|
-
|
|
46
|
-
export default prisma;
|
|
47
|
-
`;
|
|
48
|
-
|
|
49
|
-
const libDir = path.join(backendDir, 'src', 'lib');
|
|
50
|
-
await fs.ensureDir(libDir);
|
|
51
|
-
await fs.writeFile(path.join(libDir, 'prisma.ts'), prismaClient);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function getPrismaSchema(config: StackConfig): string {
|
|
55
|
-
const datasourceProvider = config.database === 'postgresql' ? 'postgresql'
|
|
56
|
-
: config.database === 'mysql' ? 'mysql'
|
|
57
|
-
: 'sqlite';
|
|
58
|
-
|
|
59
|
-
return `generator client {
|
|
60
|
-
provider = "prisma-client-js"
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
datasource db {
|
|
64
|
-
provider = "${datasourceProvider}"
|
|
65
|
-
url = env("DATABASE_URL")
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
${config.multiTenant ? `model Tenant {
|
|
69
|
-
id String @id @default(cuid())
|
|
70
|
-
name String
|
|
71
|
-
slug String @unique
|
|
72
|
-
createdAt DateTime @default(now())
|
|
73
|
-
updatedAt DateTime @updatedAt
|
|
74
|
-
users User[]
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
` : ''}model User {
|
|
78
|
-
id String @id @default(cuid())
|
|
79
|
-
email String @unique
|
|
80
|
-
name String?
|
|
81
|
-
password String? ${config.auth === 'jwt' ? '' : '// Only for JWT auth'}
|
|
82
|
-
${config.multiTenant ? 'tenantId String\n tenant Tenant @relation(fields: [tenantId], references: [id])\n ' : ''}createdAt DateTime @default(now())
|
|
83
|
-
updatedAt DateTime @updatedAt
|
|
84
|
-
}
|
|
85
|
-
`;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async function generateMongoose(config: StackConfig, backendDir: string) {
|
|
89
|
-
// Mongoose connection
|
|
90
|
-
const mongooseConnection = `import mongoose from 'mongoose';
|
|
91
|
-
|
|
92
|
-
const MONGODB_URI = process.env.DATABASE_URL || 'mongodb://localhost:27017/${config.projectName}';
|
|
93
|
-
|
|
94
|
-
let isConnected = false;
|
|
95
|
-
|
|
96
|
-
export async function connectDB() {
|
|
97
|
-
if (isConnected) {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
await mongoose.connect(MONGODB_URI);
|
|
103
|
-
isConnected = true;
|
|
104
|
-
console.log('✅ MongoDB connected');
|
|
105
|
-
} catch (error) {
|
|
106
|
-
console.error('❌ MongoDB connection error:', error);
|
|
107
|
-
process.exit(1);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export default mongoose;
|
|
112
|
-
`;
|
|
113
|
-
|
|
114
|
-
const libDir = path.join(backendDir, 'src', 'lib');
|
|
115
|
-
await fs.ensureDir(libDir);
|
|
116
|
-
await fs.writeFile(path.join(libDir, 'mongoose.ts'), mongooseConnection);
|
|
117
|
-
|
|
118
|
-
// User model
|
|
119
|
-
const modelsDir = path.join(backendDir, 'src', 'models');
|
|
120
|
-
await fs.ensureDir(modelsDir);
|
|
121
|
-
|
|
122
|
-
const userModel = `import mongoose, { Schema, Document } from 'mongoose';
|
|
123
|
-
|
|
124
|
-
export interface IUser extends Document {
|
|
125
|
-
email: string;
|
|
126
|
-
name?: string;
|
|
127
|
-
password?: string;
|
|
128
|
-
${config.multiTenant ? 'tenantId: string;' : ''}
|
|
129
|
-
createdAt: Date;
|
|
130
|
-
updatedAt: Date;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const UserSchema = new Schema<IUser>(
|
|
134
|
-
{
|
|
135
|
-
email: { type: String, required: true, unique: true },
|
|
136
|
-
name: { type: String },
|
|
137
|
-
password: { type: String },
|
|
138
|
-
${config.multiTenant ? 'tenantId: { type: String, required: true, index: true },' : ''}
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
timestamps: true,
|
|
142
|
-
}
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
export default mongoose.model<IUser>('User', UserSchema);
|
|
146
|
-
`;
|
|
147
|
-
|
|
148
|
-
await fs.writeFile(path.join(modelsDir, 'User.ts'), userModel);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async function generateSupabase(config: StackConfig, backendDir: string) {
|
|
152
|
-
const supabaseClient = `import { createClient } from '@supabase/supabase-js';
|
|
153
|
-
|
|
154
|
-
const supabaseUrl = process.env.SUPABASE_URL!;
|
|
155
|
-
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
|
156
|
-
|
|
157
|
-
export const supabase = createClient(supabaseUrl, supabaseKey);
|
|
158
|
-
|
|
159
|
-
export default supabase;
|
|
160
|
-
`;
|
|
161
|
-
|
|
162
|
-
const libDir = path.join(backendDir, 'src', 'lib');
|
|
163
|
-
await fs.ensureDir(libDir);
|
|
164
|
-
await fs.writeFile(path.join(libDir, 'supabase.ts'), supabaseClient);
|
|
165
|
-
}
|
package/src/generators/docker.ts
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import fs from 'fs-extra';
|
|
3
|
-
import { StackConfig } from '../types';
|
|
4
|
-
|
|
5
|
-
export async function generateDocker(config: StackConfig, targetDir: string) {
|
|
6
|
-
const dockerDir = path.join(targetDir, 'docker');
|
|
7
|
-
await fs.ensureDir(dockerDir);
|
|
8
|
-
|
|
9
|
-
// Frontend Dockerfile
|
|
10
|
-
const frontendDockerfile = `FROM node:20-alpine AS builder
|
|
11
|
-
|
|
12
|
-
WORKDIR /app
|
|
13
|
-
|
|
14
|
-
COPY package*.json ./
|
|
15
|
-
RUN npm install
|
|
16
|
-
|
|
17
|
-
COPY . .
|
|
18
|
-
RUN npm run build
|
|
19
|
-
|
|
20
|
-
FROM nginx:alpine
|
|
21
|
-
|
|
22
|
-
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
23
|
-
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
|
|
24
|
-
|
|
25
|
-
EXPOSE 80
|
|
26
|
-
|
|
27
|
-
CMD ["nginx", "-g", "daemon off;"]
|
|
28
|
-
`;
|
|
29
|
-
|
|
30
|
-
await fs.writeFile(path.join(dockerDir, 'frontend.Dockerfile'), frontendDockerfile);
|
|
31
|
-
|
|
32
|
-
// Backend Dockerfile
|
|
33
|
-
const backendDockerfile = `FROM node:20-alpine
|
|
34
|
-
|
|
35
|
-
WORKDIR /app
|
|
36
|
-
|
|
37
|
-
COPY package*.json ./
|
|
38
|
-
RUN npm install --only=production
|
|
39
|
-
|
|
40
|
-
COPY . .
|
|
41
|
-
RUN npm run build
|
|
42
|
-
|
|
43
|
-
EXPOSE 3000
|
|
44
|
-
|
|
45
|
-
CMD ["node", "dist/index.js"]
|
|
46
|
-
`;
|
|
47
|
-
|
|
48
|
-
await fs.writeFile(path.join(dockerDir, 'backend.Dockerfile'), backendDockerfile);
|
|
49
|
-
|
|
50
|
-
// Nginx config for frontend
|
|
51
|
-
const nginxConf = `server {
|
|
52
|
-
listen 80;
|
|
53
|
-
server_name localhost;
|
|
54
|
-
root /usr/share/nginx/html;
|
|
55
|
-
index index.html;
|
|
56
|
-
|
|
57
|
-
location / {
|
|
58
|
-
try_files $uri $uri/ /index.html;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
location /api {
|
|
62
|
-
proxy_pass http://backend:3000;
|
|
63
|
-
proxy_http_version 1.1;
|
|
64
|
-
proxy_set_header Upgrade $http_upgrade;
|
|
65
|
-
proxy_set_header Connection 'upgrade';
|
|
66
|
-
proxy_set_header Host $host;
|
|
67
|
-
proxy_cache_bypass $http_upgrade;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
`;
|
|
71
|
-
|
|
72
|
-
await fs.writeFile(path.join(dockerDir, 'nginx.conf'), nginxConf);
|
|
73
|
-
|
|
74
|
-
// Docker Compose
|
|
75
|
-
const dockerCompose = getDockerCompose(config);
|
|
76
|
-
await fs.writeFile(path.join(targetDir, 'docker-compose.yml'), dockerCompose);
|
|
77
|
-
|
|
78
|
-
// .dockerignore
|
|
79
|
-
const dockerignore = `node_modules
|
|
80
|
-
npm-debug.log
|
|
81
|
-
.env
|
|
82
|
-
.env.local
|
|
83
|
-
.git
|
|
84
|
-
.gitignore
|
|
85
|
-
README.md
|
|
86
|
-
.vscode
|
|
87
|
-
.idea
|
|
88
|
-
dist
|
|
89
|
-
build
|
|
90
|
-
coverage
|
|
91
|
-
`;
|
|
92
|
-
|
|
93
|
-
await fs.writeFile(path.join(targetDir, '.dockerignore'), dockerignore);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function getDockerCompose(config: StackConfig): string {
|
|
97
|
-
let services = `version: '3.8'
|
|
98
|
-
|
|
99
|
-
services:
|
|
100
|
-
frontend:
|
|
101
|
-
build:
|
|
102
|
-
context: ./frontend
|
|
103
|
-
dockerfile: ../docker/frontend.Dockerfile
|
|
104
|
-
ports:
|
|
105
|
-
- "80:80"
|
|
106
|
-
depends_on:
|
|
107
|
-
- backend
|
|
108
|
-
environment:
|
|
109
|
-
- VITE_API_URL=http://localhost:3000/api
|
|
110
|
-
|
|
111
|
-
backend:
|
|
112
|
-
build:
|
|
113
|
-
context: ./backend
|
|
114
|
-
dockerfile: ../docker/backend.Dockerfile
|
|
115
|
-
ports:
|
|
116
|
-
- "3000:3000"
|
|
117
|
-
environment:
|
|
118
|
-
- NODE_ENV=production
|
|
119
|
-
- PORT=3000
|
|
120
|
-
- DATABASE_URL=${config.database === 'postgresql' ? `postgresql://postgres:postgres@postgres:5432/${config.projectName}` : config.database === 'mongodb' ? `mongodb://mongo:mongo@mongodb:27017/${config.projectName}` : config.database === 'mysql' ? `mysql://root:mysql@mysql:3306/${config.projectName}` : '${DATABASE_URL}'}
|
|
121
|
-
- JWT_SECRET=\${JWT_SECRET}
|
|
122
|
-
depends_on:
|
|
123
|
-
`;
|
|
124
|
-
|
|
125
|
-
// Add database service
|
|
126
|
-
if (config.database === 'postgresql') {
|
|
127
|
-
services += ` - postgres
|
|
128
|
-
|
|
129
|
-
postgres:
|
|
130
|
-
image: postgres:16-alpine
|
|
131
|
-
ports:
|
|
132
|
-
- "5432:5432"
|
|
133
|
-
environment:
|
|
134
|
-
- POSTGRES_USER=postgres
|
|
135
|
-
- POSTGRES_PASSWORD=postgres
|
|
136
|
-
- POSTGRES_DB=${config.projectName}
|
|
137
|
-
volumes:
|
|
138
|
-
- postgres_data:/var/lib/postgresql/data
|
|
139
|
-
|
|
140
|
-
volumes:
|
|
141
|
-
postgres_data:
|
|
142
|
-
`;
|
|
143
|
-
} else if (config.database === 'mongodb') {
|
|
144
|
-
services += ` - mongodb
|
|
145
|
-
|
|
146
|
-
mongodb:
|
|
147
|
-
image: mongo:7
|
|
148
|
-
ports:
|
|
149
|
-
- "27017:27017"
|
|
150
|
-
environment:
|
|
151
|
-
- MONGO_INITDB_ROOT_USERNAME=mongo
|
|
152
|
-
- MONGO_INITDB_ROOT_PASSWORD=mongo
|
|
153
|
-
- MONGO_INITDB_DATABASE=${config.projectName}
|
|
154
|
-
volumes:
|
|
155
|
-
- mongodb_data:/data/db
|
|
156
|
-
|
|
157
|
-
volumes:
|
|
158
|
-
mongodb_data:
|
|
159
|
-
`;
|
|
160
|
-
} else if (config.database === 'mysql') {
|
|
161
|
-
services += ` - mysql
|
|
162
|
-
|
|
163
|
-
mysql:
|
|
164
|
-
image: mysql:8
|
|
165
|
-
ports:
|
|
166
|
-
- "3306:3306"
|
|
167
|
-
environment:
|
|
168
|
-
- MYSQL_ROOT_PASSWORD=mysql
|
|
169
|
-
- MYSQL_DATABASE=${config.projectName}
|
|
170
|
-
volumes:
|
|
171
|
-
- mysql_data:/var/lib/mysql
|
|
172
|
-
|
|
173
|
-
volumes:
|
|
174
|
-
mysql_data:
|
|
175
|
-
`;
|
|
176
|
-
} else {
|
|
177
|
-
services += ` # Add your database service here
|
|
178
|
-
|
|
179
|
-
volumes:
|
|
180
|
-
data:
|
|
181
|
-
`;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return services;
|
|
185
|
-
}
|