create-stackflow 1.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/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # create-stackflow
2
+
3
+ Professional interactive npm CLI for generating modern full-stack MERN applications.
4
+
5
+ ```bash
6
+ npx create-stackflow
7
+ ```
8
+
9
+ ## What It Generates
10
+
11
+ - Root npm workspace with `frontend` and `backend` packages.
12
+ - React/Vite or Next.js frontend using the official generator.
13
+ - JavaScript or TypeScript project files.
14
+ - Tailwind CSS, shadcn-style component folders, dark mode, toast notifications, loading states.
15
+ - Auth screens, protected dashboard route, Axios service layer, and CRUD task UI.
16
+ - Express/MongoDB backend with JWT auth, bcryptjs, cookies, CORS, helmet, rate limiting, dotenv, Mongoose, and CRUD APIs.
17
+ - Optional Swagger, Socket.IO, Winston, Morgan, Cloudinary, and multer upload structure.
18
+
19
+ ## CLI Architecture
20
+
21
+ ```text
22
+ src/
23
+ cli.js # Commander entrypoint and bin target
24
+ commands/
25
+ create.js # Main orchestration and success/error handling
26
+ generators/
27
+ root.js # Root workspace, README, .gitignore
28
+ frontend.js # Official frontend scaffolding + StackFlow overlay
29
+ backend.js # Express/MongoDB API templates
30
+ utils/
31
+ prompts.js # Inquirer setup questions
32
+ names.js # Project naming helpers
33
+ template.js # Small template writer utilities
34
+ ```
35
+
36
+ ## Workflow
37
+
38
+ 1. Print a branded CLI banner.
39
+ 2. Ask setup questions with defaults for project, frontend folder, backend folder, framework, language, UI, state, validation, auth, and optional backend features.
40
+ 3. Validate the project name with npm naming rules.
41
+ 4. Create the root workspace package.
42
+ 5. Run the official frontend generator:
43
+ - Vite for React.
44
+ - `create-next-app` for Next.js.
45
+ 6. Persist frontend dependencies using `latest`, then install them unless `--skip-install` is passed.
46
+ 7. Overlay frontend auth, CRUD, API services, reusable components, protected routes, dark mode, and dashboard UI.
47
+ 8. Generate backend structure, env files, models, controllers, routes, middleware, services, and optional integrations.
48
+ 9. Install backend and root dependencies unless skipped.
49
+ 10. Show clean next-step instructions.
50
+
51
+ ## Implementation Order
52
+
53
+ 1. CLI entrypoint and prompts.
54
+ 2. Root workspace generator.
55
+ 3. Official frontend generator integration.
56
+ 4. Backend API generator.
57
+ 5. Frontend auth/dashboard overlay.
58
+ 6. Dependency persistence and install strategy.
59
+ 7. Smoke tests and generated-app build tests.
60
+ 8. npm packaging metadata.
61
+
62
+ ## Template Strategy
63
+
64
+ The current implementation keeps templates close to their generators so the package stays compact. As the project grows, move each template into a dedicated folder:
65
+
66
+ ```text
67
+ src/templates/
68
+ frontend/
69
+ react/
70
+ next/
71
+ backend/
72
+ base/
73
+ optional/
74
+ ```
75
+
76
+ Use placeholder replacement for stable values such as project name, database name, and enabled features. Keep feature generators modular so future stacks like Docker, Prisma, PostgreSQL, Redis, BullMQ, SaaS starters, AI starters, and React Native can be added without rewriting the base flow.
77
+
78
+ ## Dependency Strategy
79
+
80
+ - Generated `package.json` files use `latest` for app dependencies so npm resolves current stable versions at generation time.
81
+ - Official generators are invoked with `vite@latest` and `create-next-app@latest`.
82
+ - `--skip-install` still writes dependency declarations, so users can run `npm install` later.
83
+ - Root `npm run dev` uses npm workspaces and `concurrently`.
84
+
85
+ ## Auth Strategy
86
+
87
+ - Backend creates users with hashed passwords via bcryptjs.
88
+ - Login/register return JWT and set an HTTP-only cookie.
89
+ - Protected API routes use cookie or bearer token auth.
90
+ - Frontend stores the token for Authorization headers and redirects unauthenticated users away from protected pages.
91
+
92
+ ## CRUD Strategy
93
+
94
+ - Backend includes a `Task` model scoped to the authenticated user.
95
+ - API exposes list, create, update, and delete routes.
96
+ - Frontend dashboard consumes the API through a service layer and shows loading, empty, create, and delete states.
97
+
98
+ ## Local Testing
99
+
100
+ ```bash
101
+ npm run smoke
102
+ node ./src/cli.js demo-stackflow --yes --skip-install
103
+ cd demo-stackflow
104
+ npm install
105
+ npm run build --workspace frontend
106
+ npm run build --workspace backend
107
+ ```
108
+
109
+ For a full interactive test:
110
+
111
+ ```bash
112
+ node ./src/cli.js
113
+ ```
114
+
115
+ ## Publishing
116
+
117
+ 1. Confirm `package.json` name is available on npm.
118
+ 2. Run `npm pack --dry-run`.
119
+ 3. Log in with `npm login`.
120
+ 4. Publish with `npm publish --access public`.
121
+ 5. Test from a separate folder:
122
+
123
+ ```bash
124
+ npx create-stackflow@latest
125
+ ```
126
+
127
+ ## Naming Conventions
128
+
129
+ - CLI package: `create-stackflow`.
130
+ - Generated root package: kebab-case project name.
131
+ - Folders: default `frontend` and `backend`, user configurable.
132
+ - Backend files: `*.controller`, `*.routes`, `*.middleware`, `*.service`, `*.model`.
133
+ - Frontend files: feature-first folders under `features`, shared primitives under `components/ui`, API utilities under `lib`.
134
+
135
+ ## Best Practices
136
+
137
+ - Prefer official framework generators for baseline correctness.
138
+ - Keep generated code understandable for beginners.
139
+ - Keep feature generation modular and composable.
140
+ - Store env defaults locally but never commit real secrets in generated apps.
141
+ - Use npm workspaces for simple root-level development.
142
+ - Keep optional integrations isolated so they can be removed or expanded cleanly.
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "create-stackflow",
3
+ "version": "1.0.0",
4
+ "description": "Interactive CLI for generating modern full-stack MERN applications.",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-stackflow": "./src/cli.js"
8
+ },
9
+ "files": [
10
+ "src"
11
+ ],
12
+ "scripts": {
13
+ "start": "node ./src/cli.js",
14
+ "dev": "node ./src/cli.js",
15
+ "smoke": "node ./src/cli.js --help"
16
+ },
17
+ "keywords": [
18
+ "create",
19
+ "mern",
20
+ "cli",
21
+ "react",
22
+ "nextjs",
23
+ "express",
24
+ "mongodb",
25
+ "stackflow"
26
+ ],
27
+ "author": "",
28
+ "license": "MIT",
29
+ "dependencies": {
30
+ "chalk": "^5.6.2",
31
+ "commander": "^14.0.2",
32
+ "concurrently": "^9.2.1",
33
+ "execa": "^9.6.0",
34
+ "fs-extra": "^11.3.2",
35
+ "inquirer": "^12.10.0",
36
+ "ora": "^9.0.0",
37
+ "validate-npm-package-name": "^6.0.2"
38
+ },
39
+ "engines": {
40
+ "node": ">=18.18.0"
41
+ }
42
+ }
package/src/cli.js ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import chalk from "chalk";
4
+ import { createStackFlow } from "./commands/create.js";
5
+
6
+ const program = new Command();
7
+
8
+ program
9
+ .name("create-stackflow")
10
+ .description("Generate a production-minded MERN starter with frontend, backend, auth, CRUD, and dashboard UI.")
11
+ .version("1.0.0")
12
+ .argument("[project-name]", "project folder name")
13
+ .option("--skip-install", "generate files without installing dependencies")
14
+ .option("--yes", "use recommended defaults")
15
+ .action(async (projectName, options) => {
16
+ try {
17
+ await createStackFlow({ projectName, ...options });
18
+ } catch (error) {
19
+ console.error(chalk.red("\nStackFlow generation failed."));
20
+ console.error(chalk.dim(error?.stack || error?.message || error));
21
+ process.exit(1);
22
+ }
23
+ });
24
+
25
+ program.parse();
@@ -0,0 +1,149 @@
1
+ import path from "node:path";
2
+ import process from "node:process";
3
+ import chalk from "chalk";
4
+ import fs from "fs-extra";
5
+ import ora from "ora";
6
+ import validatePackageName from "validate-npm-package-name";
7
+ import { execa } from "execa";
8
+ import { askQuestions } from "../utils/prompts.js";
9
+ import { createRootFiles } from "../generators/root.js";
10
+ import { createBackend } from "../generators/backend.js";
11
+ import { createFrontend } from "../generators/frontend.js";
12
+ import { formatName } from "../utils/names.js";
13
+
14
+ export async function createStackFlow(options) {
15
+ printBanner();
16
+
17
+ const answers = options.yes
18
+ ? recommendedDefaults(options.projectName)
19
+ : await askQuestions(options.projectName);
20
+
21
+ const projectName = formatName(answers.projectName);
22
+ const validation = validatePackageName(projectName);
23
+ if (!validation.validForNewPackages) {
24
+ throw new Error(`Invalid project name "${projectName}": ${(validation.errors || validation.warnings || []).join(", ")}`);
25
+ }
26
+
27
+ const projectDir = path.resolve(process.cwd(), projectName);
28
+ if (await fs.pathExists(projectDir)) {
29
+ const existing = await fs.readdir(projectDir);
30
+ if (existing.length > 0) {
31
+ throw new Error(`Target folder already exists and is not empty: ${projectDir}`);
32
+ }
33
+ }
34
+
35
+ const context = {
36
+ ...answers,
37
+ projectName,
38
+ projectDir,
39
+ frontendDir: path.join(projectDir, answers.frontendName || "frontend"),
40
+ backendDir: path.join(projectDir, answers.backendName || "backend"),
41
+ skipInstall: Boolean(options.skipInstall),
42
+ databaseName: projectName.replace(/[^a-zA-Z0-9_-]/g, ""),
43
+ packageManager: "npm"
44
+ };
45
+
46
+ await fs.ensureDir(projectDir);
47
+
48
+ await step("Creating root workspace", () => createRootFiles(context));
49
+ await createFrontend(context);
50
+ await createBackend(context);
51
+
52
+ if (!context.skipInstall) {
53
+ await step("Installing root workspace dependencies", () =>
54
+ execa("npm", ["install"], { cwd: projectDir, stdio: "ignore" })
55
+ );
56
+ }
57
+
58
+ printSuccess(context);
59
+ }
60
+
61
+ function recommendedDefaults(projectName) {
62
+ return {
63
+ projectName: projectName || "stackflow-app",
64
+ frontendName: "frontend",
65
+ backendName: "backend",
66
+ frontend: "react",
67
+ language: "typescript",
68
+ backendLanguage: "javascript",
69
+ styling: "tailwind",
70
+ tailwind: true,
71
+ uiLibrary: "shadcn",
72
+ shadcn: true,
73
+ iconLibrary: "lucide-react",
74
+ router: true,
75
+ state: "zustand",
76
+ dataFetching: "axios",
77
+ tanstackQuery: false,
78
+ form: "react-hook-form",
79
+ validation: "zod",
80
+ axios: true,
81
+ authPages: true,
82
+ protectedRoutes: true,
83
+ darkMode: true,
84
+ animation: "none",
85
+ toast: "sonner",
86
+ chart: "none",
87
+ dragDropUpload: "none",
88
+ eslint: true,
89
+ prettier: true,
90
+ backendFramework: "Express.js",
91
+ database: "MongoDB",
92
+ orm: "Mongoose",
93
+ authStrategy: "JWT",
94
+ passwordHashing: "bcryptjs",
95
+ fileUpload: "Multer",
96
+ backendValidation: "None",
97
+ securityPackages: ["helmet", "cors", "express-rate-limit", "hpp"],
98
+ cookieParser: true,
99
+ logging: "Morgan",
100
+ swagger: true,
101
+ socketio: false,
102
+ winston: false,
103
+ morgan: true,
104
+ cloudinary: false,
105
+ multer: true,
106
+ helmet: true,
107
+ cors: true,
108
+ rateLimit: true,
109
+ hpp: true,
110
+ emailService: "None",
111
+ crudModules: ["users", "products", "categories", "orders", "blogs"],
112
+ authFeatures: ["login", "register", "forgot-password", "reset-password", "email-verification", "roles", "refresh-tokens"],
113
+ adminDashboard: true
114
+ };
115
+ }
116
+
117
+ async function step(text, task) {
118
+ const spinner = ora(text).start();
119
+ try {
120
+ await task();
121
+ spinner.succeed(text);
122
+ } catch (error) {
123
+ spinner.fail(text);
124
+ throw error;
125
+ }
126
+ }
127
+
128
+ function printBanner() {
129
+ console.log();
130
+ console.log(chalk.cyan.bold("create-stackflow"));
131
+ console.log(chalk.dim("Modern MERN app generator with auth, CRUD, dashboard, and production-ready structure."));
132
+ console.log();
133
+ }
134
+
135
+ function printSuccess(context) {
136
+ const frontend = path.basename(context.frontendDir);
137
+ const backend = path.basename(context.backendDir);
138
+ console.log();
139
+ console.log(chalk.green.bold("StackFlow app created successfully."));
140
+ console.log();
141
+ console.log(chalk.white("Next steps:"));
142
+ console.log(chalk.cyan(` cd ${context.projectName}`));
143
+ console.log(chalk.cyan(" npm run dev"));
144
+ console.log();
145
+ console.log(chalk.dim(`Frontend: ${frontend}`));
146
+ console.log(chalk.dim(`Backend: ${backend}`));
147
+ console.log(chalk.dim("MongoDB: mongodb://127.0.0.1:27017/" + context.databaseName));
148
+ console.log();
149
+ }