create-turbo-mono 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.
Files changed (54) hide show
  1. package/.claude/settings.local.json +14 -0
  2. package/README.md +182 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +118 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/scaffold.d.ts +8 -0
  8. package/dist/scaffold.d.ts.map +1 -0
  9. package/dist/scaffold.js +42 -0
  10. package/dist/scaffold.js.map +1 -0
  11. package/dist/templates/backend.d.ts +2 -0
  12. package/dist/templates/backend.d.ts.map +1 -0
  13. package/dist/templates/backend.js +424 -0
  14. package/dist/templates/backend.js.map +1 -0
  15. package/dist/templates/cicd.d.ts +3 -0
  16. package/dist/templates/cicd.d.ts.map +1 -0
  17. package/dist/templates/cicd.js +307 -0
  18. package/dist/templates/cicd.js.map +1 -0
  19. package/dist/templates/docker.d.ts +3 -0
  20. package/dist/templates/docker.d.ts.map +1 -0
  21. package/dist/templates/docker.js +458 -0
  22. package/dist/templates/docker.js.map +1 -0
  23. package/dist/templates/docs.d.ts +3 -0
  24. package/dist/templates/docs.d.ts.map +1 -0
  25. package/dist/templates/docs.js +71 -0
  26. package/dist/templates/docs.js.map +1 -0
  27. package/dist/templates/frontend.d.ts +2 -0
  28. package/dist/templates/frontend.d.ts.map +1 -0
  29. package/dist/templates/frontend.js +441 -0
  30. package/dist/templates/frontend.js.map +1 -0
  31. package/dist/templates/root.d.ts +3 -0
  32. package/dist/templates/root.d.ts.map +1 -0
  33. package/dist/templates/root.js +210 -0
  34. package/dist/templates/root.js.map +1 -0
  35. package/dist/templates/shared.d.ts +2 -0
  36. package/dist/templates/shared.d.ts.map +1 -0
  37. package/dist/templates/shared.js +696 -0
  38. package/dist/templates/shared.js.map +1 -0
  39. package/dist/utils.d.ts +5 -0
  40. package/dist/utils.d.ts.map +1 -0
  41. package/dist/utils.js +34 -0
  42. package/dist/utils.js.map +1 -0
  43. package/package.json +40 -0
  44. package/src/index.ts +138 -0
  45. package/src/scaffold.ts +51 -0
  46. package/src/templates/backend.ts +460 -0
  47. package/src/templates/cicd.ts +334 -0
  48. package/src/templates/docker.ts +503 -0
  49. package/src/templates/docs.ts +74 -0
  50. package/src/templates/frontend.ts +469 -0
  51. package/src/templates/root.ts +216 -0
  52. package/src/templates/shared.ts +820 -0
  53. package/src/utils.ts +31 -0
  54. package/tsconfig.json +20 -0
@@ -0,0 +1,469 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { toPascalCase, toKebabCase } from '../utils';
4
+
5
+ export async function createFrontendApp(
6
+ targetDir: string,
7
+ appName: string
8
+ ): Promise<void> {
9
+ const kebabName = toKebabCase(appName);
10
+ const pascalName = toPascalCase(appName);
11
+ const appDir = path.join(targetDir, 'apps', 'frontend', kebabName);
12
+
13
+ // Create full Next.js structure (matching create-next-app with Page Router)
14
+ await fs.ensureDir(path.join(appDir, 'pages'));
15
+ await fs.ensureDir(path.join(appDir, 'pages', 'api'));
16
+ await fs.ensureDir(path.join(appDir, 'public'));
17
+ await fs.ensureDir(path.join(appDir, 'styles'));
18
+
19
+ // package.json
20
+ const packageJson = {
21
+ name: `@repo/${kebabName}`,
22
+ version: '0.1.0',
23
+ private: true,
24
+ scripts: {
25
+ dev: 'next dev',
26
+ build: 'next build',
27
+ start: 'next start',
28
+ lint: 'next lint',
29
+ 'type-check': 'tsc --noEmit',
30
+ clean: 'rm -rf .next',
31
+ },
32
+ dependencies: {
33
+ next: '14.0.4',
34
+ react: '^18',
35
+ 'react-dom': '^18',
36
+ '@repo/shared-frontend': 'workspace:*',
37
+ '@repo/shared-common': 'workspace:*',
38
+ },
39
+ devDependencies: {
40
+ typescript: '^5',
41
+ '@types/node': '^20',
42
+ '@types/react': '^18',
43
+ '@types/react-dom': '^18',
44
+ '@repo/tsconfig': 'workspace:*',
45
+ eslint: '^8',
46
+ 'eslint-config-next': '14.0.4',
47
+ },
48
+ };
49
+
50
+ await fs.writeJson(path.join(appDir, 'package.json'), packageJson, {
51
+ spaces: 2,
52
+ });
53
+
54
+ // tsconfig.json
55
+ const tsConfig = {
56
+ compilerOptions: {
57
+ lib: ['dom', 'dom.iterable', 'esnext'],
58
+ allowJs: true,
59
+ skipLibCheck: true,
60
+ strict: true,
61
+ noEmit: true,
62
+ esModuleInterop: true,
63
+ module: 'esnext',
64
+ moduleResolution: 'bundler',
65
+ resolveJsonModule: true,
66
+ isolatedModules: true,
67
+ jsx: 'preserve',
68
+ incremental: true,
69
+ paths: {
70
+ '@/*': ['./*'],
71
+ },
72
+ },
73
+ include: ['next-env.d.ts', '**/*.ts', '**/*.tsx'],
74
+ exclude: ['node_modules'],
75
+ };
76
+
77
+ await fs.writeJson(path.join(appDir, 'tsconfig.json'), tsConfig, {
78
+ spaces: 2,
79
+ });
80
+
81
+ // next.config.js
82
+ const nextConfig = `/** @type {import('next').NextConfig} */
83
+ const nextConfig = {
84
+ reactStrictMode: true,
85
+ transpilePackages: ['@repo/shared-frontend', '@repo/shared-common'],
86
+ }
87
+
88
+ module.exports = nextConfig
89
+ `;
90
+
91
+ await fs.writeFile(path.join(appDir, 'next.config.js'), nextConfig);
92
+
93
+ // .eslintrc.json
94
+ const eslintConfig = {
95
+ extends: 'next/core-web-vitals',
96
+ };
97
+
98
+ await fs.writeJson(path.join(appDir, '.eslintrc.json'), eslintConfig, {
99
+ spaces: 2,
100
+ });
101
+
102
+ // pages/_app.tsx
103
+ const appTsx = `import '@/styles/globals.css'
104
+ import type { AppProps } from 'next/app'
105
+
106
+ export default function App({ Component, pageProps }: AppProps) {
107
+ return <Component {...pageProps} />
108
+ }
109
+ `;
110
+
111
+ await fs.writeFile(path.join(appDir, 'pages', '_app.tsx'), appTsx);
112
+
113
+ // pages/_document.tsx
114
+ const documentTsx = `import { Html, Head, Main, NextScript } from 'next/document'
115
+
116
+ export default function Document() {
117
+ return (
118
+ <Html lang="en">
119
+ <Head />
120
+ <body>
121
+ <Main />
122
+ <NextScript />
123
+ </body>
124
+ </Html>
125
+ )
126
+ }
127
+ `;
128
+
129
+ await fs.writeFile(path.join(appDir, 'pages', '_document.tsx'), documentTsx);
130
+
131
+ // pages/index.tsx
132
+ const indexTsx = `import Head from 'next/head'
133
+ import Image from 'next/image'
134
+ import { Inter } from 'next/font/google'
135
+ import styles from '@/styles/Home.module.css'
136
+
137
+ const inter = Inter({ subsets: ['latin'] })
138
+
139
+ export default function Home() {
140
+ return (
141
+ <>
142
+ <Head>
143
+ <title>Create Next App</title>
144
+ <meta name="description" content="Generated by create next app" />
145
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
146
+ <link rel="icon" href="/favicon.ico" />
147
+ </Head>
148
+ <main className={\`\${styles.main} \${inter.className}\`}>
149
+ <div className={styles.description}>
150
+ <p>
151
+ Get started by editing&nbsp;
152
+ <code className={styles.code}>pages/index.tsx</code>
153
+ </p>
154
+ <div>
155
+ <a
156
+ href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
157
+ target="_blank"
158
+ rel="noopener noreferrer"
159
+ >
160
+ By{' '}
161
+ <Image
162
+ src="/vercel.svg"
163
+ alt="Vercel Logo"
164
+ className={styles.vercelLogo}
165
+ width={100}
166
+ height={24}
167
+ priority
168
+ />
169
+ </a>
170
+ </div>
171
+ </div>
172
+
173
+ <div className={styles.center}>
174
+ <Image
175
+ className={styles.logo}
176
+ src="/next.svg"
177
+ alt="Next.js Logo"
178
+ width={180}
179
+ height={37}
180
+ priority
181
+ />
182
+ </div>
183
+
184
+ <div className={styles.grid}>
185
+ <a
186
+ href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
187
+ className={styles.card}
188
+ target="_blank"
189
+ rel="noopener noreferrer"
190
+ >
191
+ <h2>
192
+ Docs <span>-&gt;</span>
193
+ </h2>
194
+ <p>
195
+ Find in-depth information about Next.js features and&nbsp;API.
196
+ </p>
197
+ </a>
198
+
199
+ <a
200
+ href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
201
+ className={styles.card}
202
+ target="_blank"
203
+ rel="noopener noreferrer"
204
+ >
205
+ <h2>
206
+ Learn <span>-&gt;</span>
207
+ </h2>
208
+ <p>
209
+ Learn about Next.js in an interactive course with&nbsp;quizzes!
210
+ </p>
211
+ </a>
212
+
213
+ <a
214
+ href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
215
+ className={styles.card}
216
+ target="_blank"
217
+ rel="noopener noreferrer"
218
+ >
219
+ <h2>
220
+ Templates <span>-&gt;</span>
221
+ </h2>
222
+ <p>
223
+ Discover and deploy boilerplate example Next.js&nbsp;projects.
224
+ </p>
225
+ </a>
226
+
227
+ <a
228
+ href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
229
+ className={styles.card}
230
+ target="_blank"
231
+ rel="noopener noreferrer"
232
+ >
233
+ <h2>
234
+ Deploy <span>-&gt;</span>
235
+ </h2>
236
+ <p>
237
+ Instantly deploy your Next.js site to a shareable URL with&nbsp;Vercel.
238
+ </p>
239
+ </a>
240
+ </div>
241
+ </main>
242
+ </>
243
+ )
244
+ }
245
+ `;
246
+
247
+ await fs.writeFile(path.join(appDir, 'pages', 'index.tsx'), indexTsx);
248
+
249
+ // pages/api/hello.ts
250
+ const helloApiTs = `import type { NextApiRequest, NextApiResponse } from 'next'
251
+
252
+ type Data = {
253
+ name: string
254
+ }
255
+
256
+ export default function handler(
257
+ req: NextApiRequest,
258
+ res: NextApiResponse<Data>
259
+ ) {
260
+ res.status(200).json({ name: 'John Doe' })
261
+ }
262
+ `;
263
+
264
+ await fs.writeFile(path.join(appDir, 'pages', 'api', 'hello.ts'), helloApiTs);
265
+
266
+ // styles/globals.css - Abbreviated for length
267
+ const globalsCss = `:root {
268
+ --max-width: 1100px;
269
+ --border-radius: 12px;
270
+ --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Code', 'Segoe UI Mono',
271
+ 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro',
272
+ 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace;
273
+
274
+ --foreground-rgb: 0, 0, 0;
275
+ --background-start-rgb: 214, 219, 220;
276
+ --background-end-rgb: 255, 255, 255;
277
+ }
278
+
279
+ * {
280
+ box-sizing: border-box;
281
+ padding: 0;
282
+ margin: 0;
283
+ }
284
+
285
+ html,
286
+ body {
287
+ max-width: 100vw;
288
+ overflow-x: hidden;
289
+ }
290
+
291
+ body {
292
+ color: rgb(var(--foreground-rgb));
293
+ background: linear-gradient(
294
+ to bottom,
295
+ transparent,
296
+ rgb(var(--background-end-rgb))
297
+ )
298
+ rgb(var(--background-start-rgb));
299
+ }
300
+
301
+ a {
302
+ color: inherit;
303
+ text-decoration: none;
304
+ }
305
+
306
+ @media (prefers-color-scheme: dark) {
307
+ html {
308
+ color-scheme: dark;
309
+ }
310
+ }
311
+ `;
312
+
313
+ await fs.writeFile(path.join(appDir, 'styles', 'globals.css'), globalsCss);
314
+
315
+ // styles/Home.module.css - Abbreviated for length
316
+ const homeModuleCss = `.main {
317
+ display: flex;
318
+ flex-direction: column;
319
+ justify-content: space-between;
320
+ align-items: center;
321
+ padding: 6rem;
322
+ min-height: 100vh;
323
+ }
324
+
325
+ .description {
326
+ display: inherit;
327
+ justify-content: inherit;
328
+ align-items: inherit;
329
+ font-size: 0.85rem;
330
+ max-width: var(--max-width);
331
+ width: 100%;
332
+ z-index: 2;
333
+ font-family: var(--font-mono);
334
+ }
335
+
336
+ .code {
337
+ font-weight: 700;
338
+ font-family: var(--font-mono);
339
+ }
340
+
341
+ .grid {
342
+ display: grid;
343
+ grid-template-columns: repeat(4, minmax(25%, auto));
344
+ max-width: 100%;
345
+ width: var(--max-width);
346
+ }
347
+
348
+ .card {
349
+ padding: 1rem 1.2rem;
350
+ border-radius: var(--border-radius);
351
+ background: rgba(var(--card-rgb), 0);
352
+ border: 1px solid rgba(var(--card-border-rgb), 0);
353
+ transition: background 200ms, border 200ms;
354
+ }
355
+
356
+ .center {
357
+ display: flex;
358
+ justify-content: center;
359
+ align-items: center;
360
+ position: relative;
361
+ padding: 4rem 0;
362
+ }
363
+
364
+ @media (max-width: 700px) {
365
+ .grid {
366
+ grid-template-columns: 1fr;
367
+ margin-bottom: 120px;
368
+ max-width: 320px;
369
+ text-align: center;
370
+ }
371
+ }
372
+ `;
373
+
374
+ await fs.writeFile(path.join(appDir, 'styles', 'Home.module.css'), homeModuleCss);
375
+
376
+ // public/next.svg
377
+ const nextSvg = `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>`;
378
+
379
+ await fs.writeFile(path.join(appDir, 'public', 'next.svg'), nextSvg);
380
+
381
+ // public/vercel.svg
382
+ const vercelSvg = `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>`;
383
+
384
+ await fs.writeFile(path.join(appDir, 'public', 'vercel.svg'), vercelSvg);
385
+
386
+ // .gitignore
387
+ const gitignore = `# dependencies
388
+ /node_modules
389
+ /.pnp
390
+ .pnp.js
391
+
392
+ # testing
393
+ /coverage
394
+
395
+ # next.js
396
+ /.next/
397
+ /out/
398
+
399
+ # production
400
+ /build
401
+
402
+ # misc
403
+ .DS_Store
404
+ *.pem
405
+
406
+ # debug
407
+ npm-debug.log*
408
+ yarn-debug.log*
409
+ yarn-error.log*
410
+
411
+ # local env files
412
+ .env*.local
413
+
414
+ # vercel
415
+ .vercel
416
+
417
+ # typescript
418
+ *.tsbuildinfo
419
+ next-env.d.ts
420
+ `;
421
+
422
+ await fs.writeFile(path.join(appDir, '.gitignore'), gitignore);
423
+
424
+ // .env.local.example and .env.local
425
+ const envExample = `NEXT_PUBLIC_API_URL=http://localhost:3000
426
+ `;
427
+
428
+ await fs.writeFile(path.join(appDir, '.env.local.example'), envExample);
429
+ await fs.writeFile(path.join(appDir, '.env.local'), envExample);
430
+
431
+ // README.md
432
+ const readme = `This is a [Next.js](https://nextjs.org/) project bootstrapped with [\`create-next-app\`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
433
+
434
+ ## Getting Started
435
+
436
+ First, run the development server:
437
+
438
+ \`\`\`bash
439
+ pnpm dev
440
+ \`\`\`
441
+
442
+ Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
443
+
444
+ You can start editing the page by modifying \`pages/index.tsx\`. The page auto-updates as you edit the file.
445
+
446
+ [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in \`pages/api/hello.ts\`.
447
+
448
+ The \`pages/api\` directory is mapped to \`/api/*\`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
449
+
450
+ This project uses [\`next/font\`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
451
+
452
+ ## Learn More
453
+
454
+ To learn more about Next.js, take a look at the following resources:
455
+
456
+ - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
457
+ - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
458
+
459
+ You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
460
+
461
+ ## Deploy on Vercel
462
+
463
+ The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
464
+
465
+ Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
466
+ `;
467
+
468
+ await fs.writeFile(path.join(appDir, 'README.md'), readme);
469
+ }
@@ -0,0 +1,216 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { ProjectConfig } from '../scaffold';
4
+
5
+ export async function createRootFiles(config: ProjectConfig): Promise<void> {
6
+ const { targetDir, projectName } = config;
7
+
8
+ // Root package.json
9
+ const rootPackageJson = {
10
+ name: projectName,
11
+ version: '1.0.0',
12
+ private: true,
13
+ scripts: {
14
+ dev: 'turbo run dev',
15
+ build: 'turbo run build',
16
+ 'type-check': 'turbo run type-check',
17
+ lint: 'turbo run lint',
18
+ clean: 'turbo run clean',
19
+ 'db:generate': 'turbo run db:generate',
20
+ 'db:migrate': 'cd packages/database && pnpm prisma migrate dev',
21
+ 'db:studio': 'cd packages/database && pnpm prisma studio',
22
+ },
23
+ devDependencies: {
24
+ turbo: '^1.11.2',
25
+ typescript: '^5.3.3',
26
+ },
27
+ packageManager: 'pnpm@8.15.0',
28
+ engines: {
29
+ node: '>=18.0.0',
30
+ pnpm: '>=8.0.0',
31
+ },
32
+ };
33
+
34
+ await fs.writeJson(path.join(targetDir, 'package.json'), rootPackageJson, {
35
+ spaces: 2,
36
+ });
37
+
38
+ // pnpm-workspace.yaml
39
+ const workspaceYaml = `packages:
40
+ - 'apps/backend/*'
41
+ - 'apps/frontend/*'
42
+ - 'packages/*'
43
+ `;
44
+ await fs.writeFile(path.join(targetDir, 'pnpm-workspace.yaml'), workspaceYaml);
45
+
46
+ // turbo.json
47
+ const turboConfig = {
48
+ $schema: 'https://turbo.build/schema.json',
49
+ globalDependencies: ['**/.env.*local'],
50
+ pipeline: {
51
+ 'db:generate': {
52
+ cache: false,
53
+ },
54
+ build: {
55
+ dependsOn: ['^build', 'db:generate'],
56
+ outputs: ['dist/**', '.next/**', 'build/**'],
57
+ },
58
+ dev: {
59
+ cache: false,
60
+ persistent: true,
61
+ },
62
+ lint: {
63
+ dependsOn: ['^lint'],
64
+ },
65
+ 'type-check': {
66
+ dependsOn: ['^type-check'],
67
+ },
68
+ clean: {
69
+ cache: false,
70
+ },
71
+ },
72
+ };
73
+
74
+ await fs.writeJson(path.join(targetDir, 'turbo.json'), turboConfig, {
75
+ spaces: 2,
76
+ });
77
+
78
+ // .gitignore
79
+ const gitignore = `# Dependencies
80
+ node_modules
81
+ .pnp
82
+ .pnp.js
83
+
84
+ # Testing
85
+ coverage
86
+
87
+ # Next.js
88
+ .next/
89
+ out/
90
+ build
91
+
92
+ # Production
93
+ dist
94
+
95
+ # Misc
96
+ .DS_Store
97
+ *.pem
98
+
99
+ # Debug
100
+ npm-debug.log*
101
+ yarn-debug.log*
102
+ yarn-error.log*
103
+ .pnpm-debug.log*
104
+
105
+ # Local env files
106
+ .env
107
+ .env*.local
108
+
109
+ # Turbo
110
+ .turbo
111
+
112
+ # IDEs
113
+ .idea
114
+ .vscode
115
+ *.swp
116
+ *.swo
117
+ *~
118
+
119
+ # Prisma
120
+ prisma/migrations
121
+ `;
122
+
123
+ await fs.writeFile(path.join(targetDir, '.gitignore'), gitignore);
124
+
125
+ // README.md
126
+ const readme = `# ${projectName}
127
+
128
+ A monorepo project with NestJS backends and Next.js frontends.
129
+
130
+ ## Getting Started
131
+
132
+ ### Prerequisites
133
+
134
+ - Node.js >= 18
135
+ - pnpm >= 8
136
+
137
+ ### Installation
138
+
139
+ \`\`\`bash
140
+ pnpm install
141
+ \`\`\`
142
+
143
+ ### Development
144
+
145
+ \`\`\`bash
146
+ # Start all apps in development mode
147
+ pnpm dev
148
+
149
+ # Build all apps
150
+ pnpm build
151
+
152
+ # Type checking
153
+ pnpm type-check
154
+
155
+ # Generate Prisma client
156
+ pnpm db:generate
157
+
158
+ # Run database migrations
159
+ pnpm db:migrate
160
+
161
+ # Open Prisma Studio
162
+ pnpm db:studio
163
+ \`\`\`
164
+
165
+ ## Project Structure
166
+
167
+ \`\`\`
168
+ ${projectName}/
169
+ ├── apps/
170
+ │ ├── backend/ # NestJS backend apps
171
+ │ └── frontend/ # Next.js frontend apps
172
+ ├── packages/
173
+ │ ├── database/ # Prisma schema and client
174
+ │ ├── shared-backend/ # Backend utilities and types
175
+ │ ├── shared-frontend/ # Frontend components and hooks
176
+ │ ├── shared-common/ # Universal utilities
177
+ │ └── tsconfig/ # Shared TypeScript configs
178
+ └── turbo.json # Turborepo configuration
179
+ \`\`\`
180
+
181
+ ## Packages
182
+
183
+ ### @repo/database
184
+ Prisma schema, migrations, and database client.
185
+
186
+ ### @repo/shared-backend
187
+ Shared backend utilities, middleware, and types.
188
+
189
+ ### @repo/shared-frontend
190
+ Shared frontend components, hooks, and utilities.
191
+
192
+ ### @repo/shared-common
193
+ Universal utilities that can be used by both frontend and backend.
194
+
195
+ ## Adding New Apps
196
+
197
+ ### Backend App
198
+ Create a new NestJS app in \`apps/backend/\` and add it to \`pnpm-workspace.yaml\`.
199
+
200
+ ### Frontend App
201
+ Create a new Next.js app in \`apps/frontend/\` and add it to \`pnpm-workspace.yaml\`.
202
+
203
+ ## License
204
+
205
+ MIT
206
+ `;
207
+
208
+ await fs.writeFile(path.join(targetDir, 'README.md'), readme);
209
+
210
+ // .npmrc
211
+ const npmrc = `auto-install-peers=true
212
+ strict-peer-dependencies=false
213
+ `;
214
+
215
+ await fs.writeFile(path.join(targetDir, '.npmrc'), npmrc);
216
+ }