create-pnpm-custom-app 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 +217 -0
- package/bin/cli.js +185 -0
- package/package.json +39 -0
- package/templates/.github/copilot-instructions.md +184 -0
- package/templates/.nvmrc +1 -0
- package/templates/.vscode/settings.json +51 -0
- package/templates/CONTRIBUTING.md +184 -0
- package/templates/LICENSE +21 -0
- package/templates/README.md +324 -0
- package/templates/apps/api/.env.example +36 -0
- package/templates/apps/api/.prettierrc.json +7 -0
- package/templates/apps/api/eslint.config.js +17 -0
- package/templates/apps/api/gitignore +45 -0
- package/templates/apps/api/jest.config.ts +22 -0
- package/templates/apps/api/package.json +49 -0
- package/templates/apps/api/src/app.ts +121 -0
- package/templates/apps/api/src/config/config.ts +38 -0
- package/templates/apps/api/src/config/logger.ts +57 -0
- package/templates/apps/api/src/db/mongo.ts +30 -0
- package/templates/apps/api/src/index.ts +40 -0
- package/templates/apps/api/src/middlewares/middleware.ts +75 -0
- package/templates/apps/api/src/models/example.model.ts +89 -0
- package/templates/apps/api/src/routes/routes.ts +54 -0
- package/templates/apps/api/src/schemas/swagger.schema.ts +58 -0
- package/templates/apps/api/src/services/example.service.ts +63 -0
- package/templates/apps/api/src/tests/health.test.ts +90 -0
- package/templates/apps/api/src/tests/helpers/test-helpers.ts +40 -0
- package/templates/apps/api/src/tests/mocks/mocks.ts +29 -0
- package/templates/apps/api/src/tests/setup.ts +11 -0
- package/templates/apps/api/src/types/fastify.d.ts +44 -0
- package/templates/apps/api/tsconfig.json +24 -0
- package/templates/apps/web/.env.example +25 -0
- package/templates/apps/web/.prettierignore +7 -0
- package/templates/apps/web/.prettierrc +9 -0
- package/templates/apps/web/app/ICONS.md +42 -0
- package/templates/apps/web/app/[locale]/(routes)/layout.tsx +13 -0
- package/templates/apps/web/app/[locale]/(routes)/page.tsx +49 -0
- package/templates/apps/web/app/[locale]/[...not-found]/page.tsx +8 -0
- package/templates/apps/web/app/[locale]/layout.tsx +35 -0
- package/templates/apps/web/app/[locale]/not-found.tsx +12 -0
- package/templates/apps/web/app/components/layout/Footer.component.tsx +30 -0
- package/templates/apps/web/app/components/layout/Nav.component.tsx +34 -0
- package/templates/apps/web/app/components/ui/README.md +39 -0
- package/templates/apps/web/app/components/ui/atoms/README.md +55 -0
- package/templates/apps/web/app/components/ui/molecules/README.md +51 -0
- package/templates/apps/web/app/globals.css +104 -0
- package/templates/apps/web/app/icon.svg +5 -0
- package/templates/apps/web/app/layout.tsx +37 -0
- package/templates/apps/web/app/manifest.json +22 -0
- package/templates/apps/web/app/providers.tsx +25 -0
- package/templates/apps/web/app/robots.ts +12 -0
- package/templates/apps/web/app/sitemap.ts +18 -0
- package/templates/apps/web/eslint.config.mjs +16 -0
- package/templates/apps/web/gitignore +56 -0
- package/templates/apps/web/hooks/README.md +25 -0
- package/templates/apps/web/i18n/config.ts +9 -0
- package/templates/apps/web/i18n/request.ts +15 -0
- package/templates/apps/web/interfaces/README.md +5 -0
- package/templates/apps/web/lib/README.md +45 -0
- package/templates/apps/web/lib/utils.ts +18 -0
- package/templates/apps/web/messages/en.json +34 -0
- package/templates/apps/web/messages/es.json +34 -0
- package/templates/apps/web/next.config.ts +50 -0
- package/templates/apps/web/package.json +34 -0
- package/templates/apps/web/postcss.config.mjs +7 -0
- package/templates/apps/web/proxy.ts +17 -0
- package/templates/apps/web/public/README.md +7 -0
- package/templates/apps/web/tsconfig.json +27 -0
- package/templates/apps/web/types/README.md +3 -0
- package/templates/docs/README.md +13 -0
- package/templates/gitignore-root +51 -0
- package/templates/package.json +30 -0
- package/templates/packages/shared/eslint.config.js +26 -0
- package/templates/packages/shared/package.json +22 -0
- package/templates/packages/shared/src/index.ts +39 -0
- package/templates/packages/shared/tsconfig.json +19 -0
- package/templates/pnpm-workspace.yaml +3 -0
package/README.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# create-pnpm-custom-app
|
|
2
|
+
|
|
3
|
+
> A professional CLI to scaffold full-stack monorepo projects with Next.js, Fastify, and pnpm workspaces
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Next.js 16**: Latest Next.js with App Router and React 19
|
|
8
|
+
- **Fastify 5**: High-performance backend API
|
|
9
|
+
- **MongoDB**: Mongoose ODM for database operations
|
|
10
|
+
- **JWT Authentication**: Secure authentication out of the box
|
|
11
|
+
- **i18n Ready**: Internationalization with next-intl (English/Spanish)
|
|
12
|
+
- **Tailwind CSS 4**: Modern utility-first styling
|
|
13
|
+
- **Swagger/OpenAPI**: Auto-generated API documentation
|
|
14
|
+
- **Testing Ready**: Jest configured for both frontend and backend
|
|
15
|
+
- **Monorepo**: pnpm workspaces for efficient dependency management
|
|
16
|
+
- **Shared Types**: TypeScript interfaces shared between apps
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Using npx (recommended)
|
|
22
|
+
npx create-pnpm-custom-app my-project
|
|
23
|
+
|
|
24
|
+
# Or with pnpm
|
|
25
|
+
pnpm create pnpm-custom-app my-project
|
|
26
|
+
|
|
27
|
+
# Or install globally
|
|
28
|
+
pnpm add -g create-pnpm-custom-app
|
|
29
|
+
create-pnpm-custom-app my-project
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Project Structure
|
|
33
|
+
|
|
34
|
+
```txt
|
|
35
|
+
my-project/
|
|
36
|
+
├── apps/
|
|
37
|
+
│ ├── web/ # Next.js frontend
|
|
38
|
+
│ │ ├── app/
|
|
39
|
+
│ │ ├── i18n/
|
|
40
|
+
│ │ ├── messages/
|
|
41
|
+
│ │ └── package.json
|
|
42
|
+
│ └── api/ # Fastify backend
|
|
43
|
+
│ ├── src/
|
|
44
|
+
│ ├── tests/
|
|
45
|
+
│ └── package.json
|
|
46
|
+
├── packages/
|
|
47
|
+
│ └── shared/ # Shared types
|
|
48
|
+
├── docs/
|
|
49
|
+
├── .github/
|
|
50
|
+
│ └── copilot-instructions.md
|
|
51
|
+
└── package.json
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## What's Included
|
|
55
|
+
|
|
56
|
+
### Frontend (Next.js)
|
|
57
|
+
|
|
58
|
+
- React 19 with Server Components
|
|
59
|
+
- TypeScript strict mode
|
|
60
|
+
- Tailwind CSS 4 with custom design system
|
|
61
|
+
- i18n with next-intl (Spanish/English)
|
|
62
|
+
- Fully responsive with mobile-first approach
|
|
63
|
+
- Accessibility-first components
|
|
64
|
+
|
|
65
|
+
### Backend (Fastify)
|
|
66
|
+
|
|
67
|
+
- Fastify 5 with TypeScript
|
|
68
|
+
- MongoDB with Mongoose
|
|
69
|
+
- JWT authentication (@fastify/jwt)
|
|
70
|
+
- Swagger/OpenAPI documentation
|
|
71
|
+
- CORS, rate limiting, multipart support
|
|
72
|
+
- Pino logger (pretty mode in dev)
|
|
73
|
+
- Input validation schemas
|
|
74
|
+
- Jest + Supertest for testing
|
|
75
|
+
|
|
76
|
+
### Monorepo Setup
|
|
77
|
+
|
|
78
|
+
- pnpm workspaces
|
|
79
|
+
- Shared TypeScript types
|
|
80
|
+
- Consistent linting and formatting
|
|
81
|
+
- Comprehensive documentation
|
|
82
|
+
- GitHub Copilot instructions
|
|
83
|
+
|
|
84
|
+
## After Creating Your Project
|
|
85
|
+
|
|
86
|
+
1. **Navigate to your project:**
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
cd my-project
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
2. **Configure environment variables:**
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Frontend
|
|
96
|
+
cp apps/web/.env.example apps/web/.env.local
|
|
97
|
+
|
|
98
|
+
# Backend
|
|
99
|
+
cp apps/api/.env.example apps/api/.env
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
3. **Edit the environment files with your values:**
|
|
103
|
+
- `apps/web/.env.local` - API URL and frontend config
|
|
104
|
+
- `apps/api/.env` - MongoDB URI, JWT secret, CORS origin
|
|
105
|
+
|
|
106
|
+
4. **Start development servers:**
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Terminal 1: Frontend (http://localhost:3000)
|
|
110
|
+
pnpm --filter web dev
|
|
111
|
+
|
|
112
|
+
# Terminal 2: Backend (http://localhost:3002)
|
|
113
|
+
pnpm --filter api dev
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
5. **Access Swagger documentation:**
|
|
117
|
+
- Open <http://localhost:3002/docs>
|
|
118
|
+
|
|
119
|
+
## Available Scripts
|
|
120
|
+
|
|
121
|
+
### Root Level
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
pnpm install # Install all dependencies
|
|
125
|
+
pnpm run dev # Start both apps in parallel
|
|
126
|
+
pnpm run build # Build all apps
|
|
127
|
+
pnpm run lint # Lint all apps
|
|
128
|
+
pnpm run test # Run all tests
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Frontend
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
pnpm --filter web dev # Development server
|
|
135
|
+
pnpm --filter web build # Production build
|
|
136
|
+
pnpm --filter web start # Production server
|
|
137
|
+
pnpm --filter web lint # Lint code
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Backend
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
pnpm --filter api dev # Development server
|
|
144
|
+
pnpm --filter api build # Build TypeScript
|
|
145
|
+
pnpm --filter api start # Production server
|
|
146
|
+
pnpm --filter api test # Run tests
|
|
147
|
+
pnpm --filter api test:watch # Tests in watch mode
|
|
148
|
+
pnpm --filter api lint # Lint code
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Tech Stack
|
|
152
|
+
|
|
153
|
+
| Category | Technologies |
|
|
154
|
+
| ---------- | ------------- |
|
|
155
|
+
| **Frontend** | Next.js 16, React 19, TypeScript, Tailwind CSS 4, next-intl |
|
|
156
|
+
| **Backend** | Fastify 5, TypeScript, MongoDB, Mongoose, Pino |
|
|
157
|
+
| **Auth** | @fastify/jwt, bcrypt |
|
|
158
|
+
| **Testing** | Jest, Supertest |
|
|
159
|
+
| **Tooling** | pnpm, ESLint, Prettier, TypeScript |
|
|
160
|
+
| **Docs** | Swagger/OpenAPI, JSDoc |
|
|
161
|
+
|
|
162
|
+
## Requirements
|
|
163
|
+
|
|
164
|
+
- **Node.js** 20.0.0 or higher
|
|
165
|
+
- **pnpm** 9.0.0 or higher
|
|
166
|
+
- **MongoDB** (local or remote instance)
|
|
167
|
+
|
|
168
|
+
## Documentation
|
|
169
|
+
|
|
170
|
+
After creating your project, check:
|
|
171
|
+
|
|
172
|
+
- `README.md` - Project overview and setup
|
|
173
|
+
- `CONTRIBUTING.md` - Contribution guidelines
|
|
174
|
+
- `.github/copilot-instructions.md` - AI coding assistant guidelines
|
|
175
|
+
- `docs/` - Additional documentation
|
|
176
|
+
|
|
177
|
+
## Tips
|
|
178
|
+
|
|
179
|
+
### MongoDB Setup
|
|
180
|
+
|
|
181
|
+
**Local MongoDB:**
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# macOS (Homebrew)
|
|
185
|
+
brew install mongodb-community
|
|
186
|
+
brew services start mongodb-community
|
|
187
|
+
|
|
188
|
+
# Your connection string:
|
|
189
|
+
MONGODB_URI=mongodb://localhost:27017/your-database
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**MongoDB Atlas (Cloud):**
|
|
193
|
+
|
|
194
|
+
1. Sign up at <https://www.mongodb.com/cloud/atlas>
|
|
195
|
+
2. Create a cluster
|
|
196
|
+
3. Get your connection string
|
|
197
|
+
4. Add to `.env`: `MONGODB_URI=mongodb+srv://...`
|
|
198
|
+
|
|
199
|
+
### Customization
|
|
200
|
+
|
|
201
|
+
- **Colors**: Edit `apps/web/app/globals.css`
|
|
202
|
+
- **i18n**: Add/edit translations in `apps/web/messages/`
|
|
203
|
+
- **API Routes**: Add routes in `apps/api/src/routes/`
|
|
204
|
+
- **Models**: Create models in `apps/api/src/models/`
|
|
205
|
+
- **Components**: Add to `apps/web/app/components/`
|
|
206
|
+
|
|
207
|
+
## License
|
|
208
|
+
|
|
209
|
+
MIT
|
|
210
|
+
|
|
211
|
+
## Author
|
|
212
|
+
|
|
213
|
+
Created by Pelayo Trives
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
**Happy coding!**
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import prompts from 'prompts';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import ora from 'ora';
|
|
7
|
+
import fs from 'fs-extra';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import { execSync } from 'child_process';
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = path.dirname(__filename);
|
|
14
|
+
|
|
15
|
+
const program = new Command();
|
|
16
|
+
|
|
17
|
+
program
|
|
18
|
+
.name('create-pnpm-custom-app')
|
|
19
|
+
.description('Scaffold a professional full-stack monorepo with Next.js, Fastify, and pnpm workspaces')
|
|
20
|
+
.version('1.0.0')
|
|
21
|
+
.argument('[project-name]', 'Name of the project')
|
|
22
|
+
.parse(process.argv);
|
|
23
|
+
|
|
24
|
+
const args = program.args;
|
|
25
|
+
|
|
26
|
+
async function main() {
|
|
27
|
+
console.log(chalk.bold.cyan('\n🚀 Create PNPM Custom App\n'));
|
|
28
|
+
|
|
29
|
+
let projectName = args[0];
|
|
30
|
+
let githubUser = '';
|
|
31
|
+
|
|
32
|
+
if (!projectName) {
|
|
33
|
+
const response = await prompts({
|
|
34
|
+
type: 'text',
|
|
35
|
+
name: 'projectName',
|
|
36
|
+
message: 'What is your project name?',
|
|
37
|
+
initial: 'my-app',
|
|
38
|
+
validate: (value) => (value.length > 0 ? true : 'Project name is required'),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (!response.projectName) {
|
|
42
|
+
console.log(chalk.red('\n❌ Project creation cancelled.'));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
projectName = response.projectName;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Ask for GitHub username
|
|
50
|
+
const githubResponse = await prompts({
|
|
51
|
+
type: 'text',
|
|
52
|
+
name: 'githubUser',
|
|
53
|
+
message: 'What is your GitHub username? (optional, used only for repository links)',
|
|
54
|
+
initial: projectName,
|
|
55
|
+
validate: (value) => true, // Optional field
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
githubUser = githubResponse.githubUser || projectName;
|
|
59
|
+
|
|
60
|
+
const projectPath = path.resolve(process.cwd(), projectName);
|
|
61
|
+
|
|
62
|
+
if (fs.existsSync(projectPath)) {
|
|
63
|
+
console.log(chalk.red(`\n❌ Directory "${projectName}" already exists.`));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
console.log(chalk.gray(`\n📁 Creating project at: ${projectPath}\n`));
|
|
68
|
+
|
|
69
|
+
const spinner = ora('Creating project structure...').start();
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
// Create project directory
|
|
73
|
+
fs.mkdirSync(projectPath, { recursive: true });
|
|
74
|
+
|
|
75
|
+
// Copy all templates
|
|
76
|
+
const templatesDir = path.join(__dirname, '../templates');
|
|
77
|
+
fs.copySync(templatesDir, projectPath);
|
|
78
|
+
|
|
79
|
+
// Rename gitignore files (npm publish removes .gitignore)
|
|
80
|
+
const gitignoreRootPath = path.join(projectPath, 'gitignore-root');
|
|
81
|
+
if (fs.existsSync(gitignoreRootPath)) {
|
|
82
|
+
fs.renameSync(gitignoreRootPath, path.join(projectPath, '.gitignore'));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const webGitignorePath = path.join(projectPath, 'apps/web/gitignore');
|
|
86
|
+
if (fs.existsSync(webGitignorePath)) {
|
|
87
|
+
fs.renameSync(webGitignorePath, path.join(projectPath, 'apps/web/.gitignore'));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const apiGitignorePath = path.join(projectPath, 'apps/api/gitignore');
|
|
91
|
+
if (fs.existsSync(apiGitignorePath)) {
|
|
92
|
+
fs.renameSync(apiGitignorePath, path.join(projectPath, 'apps/api/.gitignore'));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Replace project name in package.json files
|
|
96
|
+
const packageJsonPaths = [
|
|
97
|
+
path.join(projectPath, 'package.json'),
|
|
98
|
+
path.join(projectPath, 'apps/web/package.json'),
|
|
99
|
+
path.join(projectPath, 'apps/api/package.json'),
|
|
100
|
+
path.join(projectPath, 'packages/shared/package.json'),
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
packageJsonPaths.forEach((pkgPath) => {
|
|
104
|
+
if (fs.existsSync(pkgPath)) {
|
|
105
|
+
const content = fs.readFileSync(pkgPath, 'utf-8');
|
|
106
|
+
const updated = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
|
|
107
|
+
fs.writeFileSync(pkgPath, updated);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Replace project name in all other files (tsx, ts, md, json, etc.)
|
|
112
|
+
const filesToReplace = [
|
|
113
|
+
path.join(projectPath, 'README.md'),
|
|
114
|
+
path.join(projectPath, 'CONTRIBUTING.md'),
|
|
115
|
+
path.join(projectPath, 'apps/web/app/layout.tsx'),
|
|
116
|
+
path.join(projectPath, 'apps/web/app/manifest.json'),
|
|
117
|
+
path.join(projectPath, 'apps/web/app/components/layout/Nav.component.tsx'),
|
|
118
|
+
path.join(projectPath, 'apps/web/app/components/layout/Footer.component.tsx'),
|
|
119
|
+
path.join(projectPath, 'apps/web/app/[locale]/(routes)/page.tsx'),
|
|
120
|
+
path.join(projectPath, 'apps/web/app/opengraph-image.tsx'),
|
|
121
|
+
path.join(projectPath, 'apps/web/app/twitter-image.tsx'),
|
|
122
|
+
path.join(projectPath, 'apps/web/app/apple-icon.tsx'),
|
|
123
|
+
path.join(projectPath, 'apps/web/app/icon.tsx'),
|
|
124
|
+
path.join(projectPath, 'apps/web/messages/en.json'),
|
|
125
|
+
path.join(projectPath, 'apps/web/messages/es.json'),
|
|
126
|
+
path.join(projectPath, 'apps/api/src/app.ts'),
|
|
127
|
+
path.join(projectPath, 'packages/shared/src/index.ts'),
|
|
128
|
+
path.join(projectPath, '.github/copilot-instructions.md'),
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
filesToReplace.forEach((filePath) => {
|
|
132
|
+
if (fs.existsSync(filePath)) {
|
|
133
|
+
let content = fs.readFileSync(filePath, 'utf-8');
|
|
134
|
+
content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
|
|
135
|
+
content = content.replace(/\{\{GITHUB_USER\}\}/g, githubUser);
|
|
136
|
+
fs.writeFileSync(filePath, content);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
spinner.succeed(chalk.green('Project structure created!'));
|
|
141
|
+
|
|
142
|
+
// Install dependencies
|
|
143
|
+
spinner.start('Installing dependencies with pnpm... This may take a few minutes.');
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
execSync('pnpm install', { cwd: projectPath, stdio: 'ignore' });
|
|
147
|
+
spinner.succeed(chalk.green('Dependencies installed successfully!'));
|
|
148
|
+
} catch (error) {
|
|
149
|
+
spinner.warn(chalk.yellow('Could not install dependencies automatically.'));
|
|
150
|
+
console.log(chalk.gray(' Run `pnpm install` manually inside the project.'));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Success message
|
|
154
|
+
console.log(chalk.bold.green(`\n✅ Project "${projectName}" created successfully!\n`));
|
|
155
|
+
console.log(chalk.cyan('📦 Project structure:'));
|
|
156
|
+
console.log(chalk.gray(' ├── apps/'));
|
|
157
|
+
console.log(chalk.gray(' │ ├── web/ (Next.js 16 + TypeScript + Tailwind 4)'));
|
|
158
|
+
console.log(chalk.gray(' │ └── api/ (Fastify + MongoDB + TypeScript)'));
|
|
159
|
+
console.log(chalk.gray(' ├── packages/'));
|
|
160
|
+
console.log(chalk.gray(' │ └── shared/ (Shared types and interfaces)'));
|
|
161
|
+
console.log(chalk.gray(' └── docs/ (Project documentation)\n'));
|
|
162
|
+
|
|
163
|
+
console.log(chalk.cyan('🚀 Next steps:'));
|
|
164
|
+
console.log(chalk.white(` 1. cd ${projectName}`));
|
|
165
|
+
console.log(chalk.white(' 2. Copy .env.example files and configure:'));
|
|
166
|
+
console.log(chalk.gray(' - apps/web/.env.local'));
|
|
167
|
+
console.log(chalk.gray(' - apps/api/.env'));
|
|
168
|
+
console.log(chalk.white(' 3. Start development:'));
|
|
169
|
+
console.log(chalk.gray(' - Frontend: pnpm --filter web dev'));
|
|
170
|
+
console.log(chalk.gray(' - Backend: pnpm --filter api dev'));
|
|
171
|
+
console.log(chalk.white(' 4. Read the README.md for more information\n'));
|
|
172
|
+
|
|
173
|
+
console.log(chalk.bold.magenta('Happy coding! 🎉\n'));
|
|
174
|
+
|
|
175
|
+
} catch (error) {
|
|
176
|
+
spinner.fail(chalk.red('Failed to create project'));
|
|
177
|
+
console.error(error);
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
main().catch((error) => {
|
|
183
|
+
console.error(chalk.red('An error occurred:'), error);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-pnpm-custom-app",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A professional CLI to scaffold full-stack monorepo projects with Next.js, Fastify, and pnpm workspaces",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-pnpm-custom-app": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Run: npx create-pnpm-custom-app my-project\" && exit 0"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"cli",
|
|
14
|
+
"scaffold",
|
|
15
|
+
"boilerplate",
|
|
16
|
+
"monorepo",
|
|
17
|
+
"pnpm",
|
|
18
|
+
"nextjs",
|
|
19
|
+
"fastify",
|
|
20
|
+
"typescript",
|
|
21
|
+
"tailwind"
|
|
22
|
+
],
|
|
23
|
+
"author": "Pelayo Trives",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=20.0.0"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"chalk": "^5.3.0",
|
|
30
|
+
"commander": "^12.1.0",
|
|
31
|
+
"fs-extra": "^11.2.0",
|
|
32
|
+
"ora": "^8.1.1",
|
|
33
|
+
"prompts": "^2.4.2"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"bin",
|
|
37
|
+
"templates"
|
|
38
|
+
]
|
|
39
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# GitHub Copilot Instructions for [Project Name]
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
|
|
5
|
+
[Brief description of your project]
|
|
6
|
+
|
|
7
|
+
**Tech Stack:**
|
|
8
|
+
- **Frontend**: Next.js 16+ (App Router), React 19+, TypeScript
|
|
9
|
+
- **Backend**: Fastify API with MongoDB
|
|
10
|
+
- **Monorepo**: pnpm workspace (apps/web, apps/api, packages/shared)
|
|
11
|
+
- **Styling**: Tailwind CSS 4 with custom design system
|
|
12
|
+
- **i18n**: next-intl (English/Spanish)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Architecture Patterns
|
|
17
|
+
|
|
18
|
+
### Component Structure (Atomic Design)
|
|
19
|
+
|
|
20
|
+
- **Atoms**: `/app/components/ui/atoms/` - Basic UI elements (Button, Input, etc.)
|
|
21
|
+
- **Molecules**: `/app/components/ui/molecules/` - Composite components
|
|
22
|
+
- **Layout**: `/app/components/layout/` - Navigation, Footer, etc.
|
|
23
|
+
|
|
24
|
+
### Component Guidelines
|
|
25
|
+
|
|
26
|
+
1. **All Typography components MUST use `forwardRef`** for animation library compatibility
|
|
27
|
+
2. **Interactive components MUST have `'use client'`** directive
|
|
28
|
+
3. **Server components by default** - only add 'use client' when necessary
|
|
29
|
+
4. Use **TypeScript strictly** - avoid `any` types, define all interfaces
|
|
30
|
+
5. **Tailwind only** - no inline styles or CSS modules
|
|
31
|
+
6. Use **cn()** utility for className merging
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## File Naming Conventions
|
|
36
|
+
|
|
37
|
+
- Components: `ComponentName.component.tsx`
|
|
38
|
+
- Pages: `page.tsx` (Next.js App Router)
|
|
39
|
+
- Layouts: `layout.tsx`
|
|
40
|
+
- Interfaces: `name.interface.ts`
|
|
41
|
+
- Utilities: `name.ts`
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Code Style
|
|
46
|
+
|
|
47
|
+
### TypeScript
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// Prefer interfaces over types
|
|
51
|
+
interface ButtonProps {
|
|
52
|
+
variant?: "primary" | "secondary";
|
|
53
|
+
children: React.ReactNode;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Use Record for variant mappings
|
|
57
|
+
const variantClasses: Record<string, string> = {
|
|
58
|
+
primary: "bg-primary",
|
|
59
|
+
secondary: "bg-secondary",
|
|
60
|
+
};
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### React Patterns
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
// Use forwardRef for components that need refs
|
|
67
|
+
export const Component = forwardRef<HTMLDivElement, Props>(
|
|
68
|
+
({ children, className, ...props }, ref) => (
|
|
69
|
+
<div ref={ref} className={cn("base-class", className)} {...props}>
|
|
70
|
+
{children}
|
|
71
|
+
</div>
|
|
72
|
+
)
|
|
73
|
+
);
|
|
74
|
+
Component.displayName = "Component";
|
|
75
|
+
|
|
76
|
+
// Use 'use client' for interactive components
|
|
77
|
+
("use client");
|
|
78
|
+
import { useState } from "react";
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Tailwind CSS
|
|
82
|
+
|
|
83
|
+
- Use responsive prefixes: `sm:`, `md:`, `lg:`
|
|
84
|
+
- Dark mode support with theme provider
|
|
85
|
+
- Custom colors: Use design tokens (bg-primary, text-muted-foreground, etc.)
|
|
86
|
+
- Spacing: Use Tailwind scale (p-4, gap-6, etc.)
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Translations (next-intl)
|
|
91
|
+
|
|
92
|
+
- Files: `/messages/en.json` and `/messages/es.json`
|
|
93
|
+
- Usage: `const t = useTranslations('namespace');`
|
|
94
|
+
- Structure: Nested keys `{ "auth": { "login": { "title": "Sign in" } } }`
|
|
95
|
+
- Always add both English and Spanish translations
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## API Integration
|
|
100
|
+
|
|
101
|
+
- Services in `/lib/` (e.g., auth.ts, api.ts)
|
|
102
|
+
- Use `fetch` with proper error handling
|
|
103
|
+
- Handle errors with toast notifications
|
|
104
|
+
- Types from `@{{PROJECT_NAME}}/shared` package
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## State Management
|
|
109
|
+
|
|
110
|
+
- Use React hooks for local state
|
|
111
|
+
- Global state: Context API or state management library of choice
|
|
112
|
+
- Keep state management simple and predictable
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Performance
|
|
117
|
+
|
|
118
|
+
- Use `loading.tsx` for loading states
|
|
119
|
+
- Implement proper error boundaries
|
|
120
|
+
- Lazy load heavy components when possible
|
|
121
|
+
- Optimize images with Next.js Image component
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Common Mistakes to Avoid
|
|
126
|
+
|
|
127
|
+
❌ DON'T use inline styles - only Tailwind classes
|
|
128
|
+
❌ DON'T forget 'use client' on interactive components
|
|
129
|
+
❌ DON'T use `any` type
|
|
130
|
+
❌ DON'T mix Spanish and English in same file
|
|
131
|
+
❌ DON'T create CSS modules - Tailwind only
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## When Making Changes
|
|
136
|
+
|
|
137
|
+
1. Read existing file structure first
|
|
138
|
+
2. Follow established patterns
|
|
139
|
+
3. Update translations if adding new text
|
|
140
|
+
4. Run `pnpm run lint` to verify
|
|
141
|
+
5. Run `pnpm run build` for final verification
|
|
142
|
+
6. Check for TypeScript errors
|
|
143
|
+
7. Ensure mobile responsiveness
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Priority Order for Edits
|
|
148
|
+
|
|
149
|
+
1. Fix TypeScript errors
|
|
150
|
+
2. Fix build errors
|
|
151
|
+
3. Add missing 'use client' directives
|
|
152
|
+
4. Improve accessibility
|
|
153
|
+
5. Optimize performance
|
|
154
|
+
6. Enhance UX
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Documentation & Communication
|
|
159
|
+
|
|
160
|
+
- **All code comments and JSDoc must be in English**
|
|
161
|
+
- Code itself (variable names, function names) in English
|
|
162
|
+
- Translation files (en.json, es.json) in their respective languages
|
|
163
|
+
- Add JSDoc comments for all functions/components:
|
|
164
|
+
- Description of purpose
|
|
165
|
+
- `@param` for each parameter
|
|
166
|
+
- `@returns` for return value
|
|
167
|
+
- `@example` for complex usage
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Backend API Guidelines
|
|
172
|
+
|
|
173
|
+
- When creating new API routes, update Swagger documentation
|
|
174
|
+
- Follow existing Swagger schema patterns
|
|
175
|
+
- Include request/response examples
|
|
176
|
+
- Document all query parameters, headers, and body fields
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Other Notes
|
|
181
|
+
|
|
182
|
+
- ALWAYS prioritize accessibility (a11y)
|
|
183
|
+
- AVOID using emojis in code comments or documentation
|
|
184
|
+
- Update this file when project standards or patterns change
|
package/templates/.nvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
v20.18.1
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"editor.formatOnSave": true,
|
|
3
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
4
|
+
"editor.codeActionsOnSave": {
|
|
5
|
+
"source.fixAll.eslint": "explicit"
|
|
6
|
+
},
|
|
7
|
+
"typescript.tsdk": "node_modules/typescript/lib",
|
|
8
|
+
"typescript.enablePromptUseWorkspaceTsdk": true,
|
|
9
|
+
"files.associations": {
|
|
10
|
+
"*.css": "tailwindcss"
|
|
11
|
+
},
|
|
12
|
+
"tailwindCSS.experimental.classRegex": [
|
|
13
|
+
["cn\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
|
|
14
|
+
],
|
|
15
|
+
"editor.quickSuggestions": {
|
|
16
|
+
"strings": "on"
|
|
17
|
+
},
|
|
18
|
+
"files.exclude": {
|
|
19
|
+
"**/.git": true,
|
|
20
|
+
"**/.DS_Store": true,
|
|
21
|
+
"**/node_modules": true,
|
|
22
|
+
"**/.next": true,
|
|
23
|
+
"**/dist": true,
|
|
24
|
+
"**/build": true
|
|
25
|
+
},
|
|
26
|
+
"search.exclude": {
|
|
27
|
+
"**/node_modules": true,
|
|
28
|
+
"**/.next": true,
|
|
29
|
+
"**/dist": true,
|
|
30
|
+
"**/build": true,
|
|
31
|
+
"**/pnpm-lock.yaml": true
|
|
32
|
+
},
|
|
33
|
+
"[typescript]": {
|
|
34
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
35
|
+
},
|
|
36
|
+
"[typescriptreact]": {
|
|
37
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
38
|
+
},
|
|
39
|
+
"[javascript]": {
|
|
40
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
41
|
+
},
|
|
42
|
+
"[json]": {
|
|
43
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
44
|
+
},
|
|
45
|
+
"eslint.validate": [
|
|
46
|
+
"javascript",
|
|
47
|
+
"javascriptreact",
|
|
48
|
+
"typescript",
|
|
49
|
+
"typescriptreact"
|
|
50
|
+
]
|
|
51
|
+
}
|