create-nene 0.3.3 → 0.4.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/dist/index.js +36 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/default/_gitignore +4 -0
- package/templates/default/apps/api/_env +3 -0
- package/templates/default/apps/api/package.json +2 -0
- package/templates/default/apps/api/prisma/schema.prisma +22 -0
- package/templates/default/apps/api/src/app.module.ts +2 -0
- package/templates/default/apps/api/src/config/configuration.ts +3 -0
- package/templates/default/apps/api/src/health/health.service.ts +14 -1
- package/templates/default/apps/api/src/prisma/prisma.module.ts +9 -0
- package/templates/default/apps/api/src/prisma/prisma.service.ts +20 -0
- package/templates/default/apps/web/src/app/page.tsx +25 -1
- package/templates/default/docs/kanban/DONE/01-project-setup.md +4 -2
- package/templates/default/docs/kanban/DONE/02-database-integration.md +24 -0
- package/templates/default/docs/kanban/README.md +8 -3
- package/templates/default/docs/kanban/TODO/01-define-project.md +21 -0
- package/templates/default/docs/kanban/TODO/02-define-tech-stack.md +23 -0
- package/templates/default/docs/kanban/TODO/03-define-data-models.md +24 -0
- package/templates/default/docs/kanban/TODO/04-build-first-feature.md +24 -0
- package/templates/default/docs/kanban/TODO/05-setup-auth.md +25 -0
- package/templates/default/docs/kanban/TODO/06-customize-frontend.md +23 -0
- package/templates/default/packages/shared/src/types/index.ts +1 -0
- package/templates/default/docs/kanban/TODO/01-database-integration.md +0 -24
package/dist/index.js
CHANGED
|
@@ -176,6 +176,17 @@ function renameGitignore(projectPath) {
|
|
|
176
176
|
fs.renameSync(gitignorePath, targetPath);
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
|
+
function renameDotEnvFiles(projectPath) {
|
|
180
|
+
const envFiles = [
|
|
181
|
+
path.join(projectPath, "apps", "api", "_env")
|
|
182
|
+
];
|
|
183
|
+
for (const envPath of envFiles) {
|
|
184
|
+
const targetPath = envPath.replace("_env", ".env");
|
|
185
|
+
if (fs.existsSync(envPath)) {
|
|
186
|
+
fs.renameSync(envPath, targetPath);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
179
190
|
async function promptForOptions(projectName) {
|
|
180
191
|
const defaultProjectName = projectName || "my-nene-app";
|
|
181
192
|
const response = await prompts(
|
|
@@ -250,6 +261,7 @@ async function createProject(options) {
|
|
|
250
261
|
const templateDir = getTemplateDir();
|
|
251
262
|
copyDir(templateDir, projectPath);
|
|
252
263
|
renameGitignore(projectPath);
|
|
264
|
+
renameDotEnvFiles(projectPath);
|
|
253
265
|
updatePackageJson(projectPath, projectName);
|
|
254
266
|
updateSubPackageNames(projectPath, projectName);
|
|
255
267
|
const pmReady = ensurePackageManager(packageManager);
|
|
@@ -262,6 +274,7 @@ async function createProject(options) {
|
|
|
262
274
|
console.log(pc.dim(` cd ${projectName}`));
|
|
263
275
|
console.log(pc.dim(` ${packageManager === "npm" ? "npm install" : packageManager === "yarn" ? "yarn" : "pnpm install"}`));
|
|
264
276
|
console.log(pc.dim(` cd packages/shared && ${packageManager === "npm" ? "npm run build" : `${packageManager} build`}`));
|
|
277
|
+
console.log(pc.dim(` cd ../../apps/api && npx prisma generate && npx prisma migrate dev --name init`));
|
|
265
278
|
console.log();
|
|
266
279
|
} else {
|
|
267
280
|
console.log(pc.cyan("Installing dependencies..."));
|
|
@@ -299,6 +312,29 @@ Failed to build shared package. Run '${packageManager === "npm" ? "npm run build
|
|
|
299
312
|
)
|
|
300
313
|
);
|
|
301
314
|
}
|
|
315
|
+
console.log();
|
|
316
|
+
console.log(pc.cyan("Setting up database..."));
|
|
317
|
+
const apiPath = path.join(projectPath, "apps", "api");
|
|
318
|
+
try {
|
|
319
|
+
execSync("npx prisma generate", {
|
|
320
|
+
cwd: apiPath,
|
|
321
|
+
stdio: "inherit"
|
|
322
|
+
});
|
|
323
|
+
execSync("npx prisma migrate dev --name init --skip-seed", {
|
|
324
|
+
cwd: apiPath,
|
|
325
|
+
stdio: "inherit"
|
|
326
|
+
});
|
|
327
|
+
console.log(pc.green(" \u2713 Database ready (SQLite)"));
|
|
328
|
+
} catch {
|
|
329
|
+
console.log(
|
|
330
|
+
pc.yellow(
|
|
331
|
+
"\nFailed to setup database. Run the following manually:"
|
|
332
|
+
)
|
|
333
|
+
);
|
|
334
|
+
console.log(pc.dim(` cd apps/api`));
|
|
335
|
+
console.log(pc.dim(` npx prisma generate`));
|
|
336
|
+
console.log(pc.dim(` npx prisma migrate dev --name init`));
|
|
337
|
+
}
|
|
302
338
|
}
|
|
303
339
|
console.log();
|
|
304
340
|
console.log(
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { program } from \"commander\";\nimport prompts from \"prompts\";\nimport pc from \"picocolors\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { execSync } from \"node:child_process\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\ninterface ProjectOptions {\n projectName: string;\n packageManager: \"npm\" | \"yarn\" | \"pnpm\";\n}\n\nfunction validateProjectName(name: string): boolean {\n const validNameRegex =\n /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/;\n return validNameRegex.test(name);\n}\n\nfunction detectPackageManager(): \"npm\" | \"yarn\" | \"pnpm\" {\n const userAgent = process.env.npm_config_user_agent;\n if (userAgent) {\n if (userAgent.startsWith(\"yarn\")) return \"yarn\";\n if (userAgent.startsWith(\"pnpm\")) return \"pnpm\";\n }\n return \"pnpm\"; // Default to pnpm for monorepo\n}\n\nfunction isCommandAvailable(command: string): boolean {\n try {\n execSync(`${command} --version`, { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction ensurePackageManager(packageManager: \"npm\" | \"yarn\" | \"pnpm\"): boolean {\n if (isCommandAvailable(packageManager)) {\n return true;\n }\n\n console.log(\n pc.yellow(`\\n${packageManager} is not installed. Attempting to install...`)\n );\n\n // Try corepack first (built-in to Node.js 16.9+)\n if (isCommandAvailable(\"corepack\")) {\n try {\n console.log(pc.dim(` Using corepack to enable ${packageManager}...`));\n execSync(`corepack enable ${packageManager}`, { stdio: \"inherit\" });\n if (isCommandAvailable(packageManager)) {\n console.log(pc.green(` ✓ ${packageManager} installed via corepack\\n`));\n return true;\n }\n } catch {\n // corepack failed, try next method\n }\n }\n\n // Fallback: install via npm\n if (packageManager !== \"npm\" && isCommandAvailable(\"npm\")) {\n try {\n console.log(pc.dim(` Installing ${packageManager} globally via npm...`));\n execSync(`npm install -g ${packageManager}`, { stdio: \"inherit\" });\n if (isCommandAvailable(packageManager)) {\n console.log(pc.green(`\\n ✓ ${packageManager} installed via npm\\n`));\n return true;\n }\n } catch {\n // npm global install failed (possibly permission issue)\n }\n }\n\n // All methods failed\n console.log(\n pc.red(`\\n ✗ Failed to install ${packageManager} automatically.`)\n );\n console.log(\n pc.yellow(` Please install it manually:\\n`)\n );\n\n if (packageManager === \"pnpm\") {\n console.log(pc.dim(\" npm install -g pnpm\"));\n console.log(pc.dim(\" # or\"));\n console.log(pc.dim(\" corepack enable pnpm\"));\n console.log(pc.dim(\" # or\"));\n console.log(pc.dim(\" curl -fsSL https://get.pnpm.io/install.sh | sh -\"));\n } else if (packageManager === \"yarn\") {\n console.log(pc.dim(\" npm install -g yarn\"));\n console.log(pc.dim(\" # or\"));\n console.log(pc.dim(\" corepack enable yarn\"));\n }\n console.log();\n\n return false;\n}\n\nfunction copyDir(src: string, dest: string): void {\n fs.mkdirSync(dest, { recursive: true });\n const entries = fs.readdirSync(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n\n if (entry.isDirectory()) {\n copyDir(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\nfunction getTemplateDir(): string {\n // In development, templates are relative to src\n // In production (dist), templates are at the package root\n const devPath = path.resolve(__dirname, \"..\", \"templates\", \"default\");\n const prodPath = path.resolve(__dirname, \"..\", \"..\", \"templates\", \"default\");\n\n if (fs.existsSync(devPath)) return devPath;\n if (fs.existsSync(prodPath)) return prodPath;\n\n throw new Error(\"Template not found\");\n}\n\nfunction updatePackageJson(projectPath: string, projectName: string): void {\n const pkgPath = path.join(projectPath, \"package.json\");\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n pkg.name = projectName;\n fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + \"\\n\");\n}\n\nfunction updateSubPackageNames(projectPath: string, projectName: string): void {\n // Update apps/web package.json\n const webPkgPath = path.join(projectPath, \"apps\", \"web\", \"package.json\");\n if (fs.existsSync(webPkgPath)) {\n const pkg = JSON.parse(fs.readFileSync(webPkgPath, \"utf-8\"));\n pkg.name = `@${projectName}/web`;\n // Update shared package reference\n if (pkg.dependencies?.[\"@app/shared\"]) {\n pkg.dependencies[`@${projectName}/shared`] = pkg.dependencies[\"@app/shared\"];\n delete pkg.dependencies[\"@app/shared\"];\n }\n fs.writeFileSync(webPkgPath, JSON.stringify(pkg, null, 2) + \"\\n\");\n }\n\n // Update apps/api package.json\n const apiPkgPath = path.join(projectPath, \"apps\", \"api\", \"package.json\");\n if (fs.existsSync(apiPkgPath)) {\n const pkg = JSON.parse(fs.readFileSync(apiPkgPath, \"utf-8\"));\n pkg.name = `@${projectName}/api`;\n // Update shared package reference\n if (pkg.dependencies?.[\"@app/shared\"]) {\n pkg.dependencies[`@${projectName}/shared`] = pkg.dependencies[\"@app/shared\"];\n delete pkg.dependencies[\"@app/shared\"];\n }\n fs.writeFileSync(apiPkgPath, JSON.stringify(pkg, null, 2) + \"\\n\");\n }\n\n // Update packages/shared package.json\n const sharedPkgPath = path.join(projectPath, \"packages\", \"shared\", \"package.json\");\n if (fs.existsSync(sharedPkgPath)) {\n const pkg = JSON.parse(fs.readFileSync(sharedPkgPath, \"utf-8\"));\n pkg.name = `@${projectName}/shared`;\n fs.writeFileSync(sharedPkgPath, JSON.stringify(pkg, null, 2) + \"\\n\");\n }\n\n // Update import statements in apps/web/src/app/page.tsx\n const pagePath = path.join(projectPath, \"apps\", \"web\", \"src\", \"app\", \"page.tsx\");\n if (fs.existsSync(pagePath)) {\n let content = fs.readFileSync(pagePath, \"utf-8\");\n content = content.replace(/@app\\/shared/g, `@${projectName}/shared`);\n fs.writeFileSync(pagePath, content);\n }\n\n // Update cursor rules to use correct package names\n const cursorRulesDir = path.join(projectPath, \".cursor\", \"rules\");\n if (fs.existsSync(cursorRulesDir)) {\n const ruleFiles = fs.readdirSync(cursorRulesDir);\n for (const file of ruleFiles) {\n const filePath = path.join(cursorRulesDir, file);\n let content = fs.readFileSync(filePath, \"utf-8\");\n content = content.replace(/@app\\/shared/g, `@${projectName}/shared`);\n fs.writeFileSync(filePath, content);\n }\n }\n\n // Update agent rule files to use correct package names\n const agentRuleFiles = [\n path.join(projectPath, \"AI_CONTEXT.md\"),\n path.join(projectPath, \"CLAUDE.md\"),\n path.join(projectPath, \"AGENTS.md\"),\n path.join(projectPath, \".github\", \"copilot-instructions.md\"),\n path.join(projectPath, \"apps\", \"web\", \"CLAUDE.md\"),\n path.join(projectPath, \"apps\", \"web\", \"AGENTS.md\"),\n path.join(projectPath, \"apps\", \"api\", \"CLAUDE.md\"),\n path.join(projectPath, \"apps\", \"api\", \"AGENTS.md\"),\n ];\n for (const filePath of agentRuleFiles) {\n if (fs.existsSync(filePath)) {\n let content = fs.readFileSync(filePath, \"utf-8\");\n content = content.replace(/@app\\/shared/g, `@${projectName}/shared`);\n fs.writeFileSync(filePath, content);\n }\n }\n\n // Update turbo.json filter names\n const rootPkgPath = path.join(projectPath, \"package.json\");\n if (fs.existsSync(rootPkgPath)) {\n let content = fs.readFileSync(rootPkgPath, \"utf-8\");\n content = content.replace(/@app\\/web/g, `@${projectName}/web`);\n content = content.replace(/@app\\/api/g, `@${projectName}/api`);\n fs.writeFileSync(rootPkgPath, content);\n }\n}\n\nfunction renameGitignore(projectPath: string): void {\n const gitignorePath = path.join(projectPath, \"_gitignore\");\n const targetPath = path.join(projectPath, \".gitignore\");\n if (fs.existsSync(gitignorePath)) {\n fs.renameSync(gitignorePath, targetPath);\n }\n}\n\nasync function promptForOptions(projectName?: string): Promise<ProjectOptions> {\n const defaultProjectName = projectName || \"my-nene-app\";\n\n const response = await prompts(\n [\n {\n type: projectName ? null : \"text\",\n name: \"projectName\",\n message: \"Project name:\",\n initial: defaultProjectName,\n validate: (value: string) => {\n if (!value) return \"Project name is required\";\n if (!validateProjectName(value)) {\n return \"Invalid project name. Use lowercase letters, numbers, and hyphens only.\";\n }\n return true;\n },\n },\n {\n type: \"select\",\n name: \"packageManager\",\n message: \"Select a package manager:\",\n choices: [\n {\n title: isCommandAvailable(\"pnpm\")\n ? \"pnpm (recommended)\"\n : \"pnpm (recommended, will be installed)\",\n value: \"pnpm\",\n },\n {\n title: isCommandAvailable(\"npm\")\n ? \"npm\"\n : \"npm (not found)\",\n value: \"npm\",\n },\n {\n title: isCommandAvailable(\"yarn\")\n ? \"yarn\"\n : \"yarn (will be installed)\",\n value: \"yarn\",\n },\n ],\n initial: 0,\n },\n ],\n {\n onCancel: () => {\n console.log(pc.red(\"\\nOperation cancelled.\"));\n process.exit(0);\n },\n }\n );\n\n return {\n projectName: projectName || response.projectName,\n packageManager: response.packageManager,\n };\n}\n\nasync function createProject(options: ProjectOptions): Promise<void> {\n const { projectName, packageManager } = options;\n const projectPath = path.resolve(process.cwd(), projectName);\n\n // Check if directory exists\n if (fs.existsSync(projectPath)) {\n const { overwrite } = await prompts({\n type: \"confirm\",\n name: \"overwrite\",\n message: `Directory \"${projectName}\" already exists. Overwrite?`,\n initial: false,\n });\n\n if (!overwrite) {\n console.log(pc.red(\"Operation cancelled.\"));\n process.exit(0);\n }\n\n fs.rmSync(projectPath, { recursive: true, force: true });\n }\n\n console.log();\n console.log(\n pc.cyan(`Creating a new nene.js monorepo in ${pc.bold(projectPath)}`)\n );\n console.log();\n\n // Copy template\n const templateDir = getTemplateDir();\n copyDir(templateDir, projectPath);\n\n // Rename _gitignore to .gitignore\n renameGitignore(projectPath);\n\n // Update package.json with project name\n updatePackageJson(projectPath, projectName);\n\n // Update sub-package names\n updateSubPackageNames(projectPath, projectName);\n\n // Ensure package manager is available\n const pmReady = ensurePackageManager(packageManager);\n\n if (!pmReady) {\n console.log(\n pc.yellow(\n `Skipping dependency installation. After installing ${packageManager}, run:`\n )\n );\n console.log(pc.dim(` cd ${projectName}`));\n console.log(pc.dim(` ${packageManager === \"npm\" ? \"npm install\" : packageManager === \"yarn\" ? \"yarn\" : \"pnpm install\"}`));\n console.log(pc.dim(` cd packages/shared && ${packageManager === \"npm\" ? \"npm run build\" : `${packageManager} build`}`));\n console.log();\n } else {\n // Install dependencies\n console.log(pc.cyan(\"Installing dependencies...\"));\n console.log();\n\n const installCmd = {\n npm: \"npm install\",\n yarn: \"yarn\",\n pnpm: \"pnpm install\",\n }[packageManager];\n\n try {\n execSync(installCmd, {\n cwd: projectPath,\n stdio: \"inherit\",\n });\n } catch {\n console.log(\n pc.yellow(\n \"\\nFailed to install dependencies. You can install them manually.\"\n )\n );\n }\n\n // Build shared package first\n console.log();\n console.log(pc.cyan(\"Building shared package...\"));\n\n try {\n const buildCmd = packageManager === \"npm\" ? \"npm run build\" : `${packageManager} build`;\n execSync(buildCmd, {\n cwd: path.join(projectPath, \"packages\", \"shared\"),\n stdio: \"inherit\",\n });\n } catch {\n console.log(\n pc.yellow(\n `\\nFailed to build shared package. Run '${packageManager === \"npm\" ? \"npm run build\" : `${packageManager} build`}' in packages/shared manually.`\n )\n );\n }\n }\n\n // Success message\n console.log();\n console.log(\n pc.green(\"Success!\") + ` Created ${pc.bold(projectName)} at ${projectPath}`\n );\n console.log();\n console.log(\"Project structure:\");\n console.log();\n console.log(` ${pc.cyan(\"apps/web\")} - Next.js frontend (port 3000)`);\n console.log(` ${pc.cyan(\"apps/api\")} - NestJS backend (port 4000)`);\n console.log(` ${pc.cyan(\"packages/shared\")} - Shared types and constants`);\n console.log(` ${pc.cyan(\"docs/\")} - Project documentation`);\n console.log(` ${pc.cyan(\"AI_CONTEXT.md\")} - Universal AI context (single source of truth)`);\n console.log(` ${pc.cyan(\".cursor/rules/\")} - Cursor AI agent rules`);\n console.log(` ${pc.cyan(\".github/\")} - GitHub Copilot instructions`);\n console.log(` ${pc.cyan(\"CLAUDE.md\")} - Claude Code agent rules`);\n console.log(` ${pc.cyan(\"AGENTS.md\")} - OpenAI Codex agent rules`);\n console.log();\n console.log(\"Next steps:\");\n console.log();\n console.log(` ${pc.cyan(\"cd\")} ${projectName}`);\n console.log(\n ` ${pc.cyan(packageManager === \"npm\" ? \"npm run\" : packageManager)} dev`\n );\n console.log();\n console.log(\"This will start both the frontend (port 3000) and backend (port 4000).\");\n console.log();\n console.log(\"Happy coding!\");\n console.log();\n}\n\nexport async function main(): Promise<void> {\n program\n .name(\"create-nene\")\n .description(\"Create a new nene.js monorepo with Next.js and NestJS\")\n .version(\"0.2.0\")\n .argument(\"[project-name]\", \"Name of the project\")\n .action(async (projectName: string | undefined) => {\n console.log();\n console.log(\n pc.bold(pc.cyan(\" nene.js \") + \"- The AI-native full-stack framework\")\n );\n console.log(pc.dim(\" Next.js + NestJS monorepo for AI-assisted development\"));\n console.log();\n\n const options = await promptForOptions(projectName);\n await createProject(options);\n });\n\n await program.parseAsync(process.argv);\n}\n"],"mappings":";AAAA,SAAS,eAAe;AACxB,OAAO,aAAa;AACpB,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAC9B,SAAS,gBAAgB;AAEzB,IAAM,aAAa,cAAc,YAAY,GAAG;AAChD,IAAM,YAAY,KAAK,QAAQ,UAAU;AAOzC,SAAS,oBAAoB,MAAuB;AAClD,QAAM,iBACJ;AACF,SAAO,eAAe,KAAK,IAAI;AACjC;AAWA,SAAS,mBAAmB,SAA0B;AACpD,MAAI;AACF,aAAS,GAAG,OAAO,cAAc,EAAE,OAAO,SAAS,CAAC;AACpD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,qBAAqB,gBAAkD;AAC9E,MAAI,mBAAmB,cAAc,GAAG;AACtC,WAAO;AAAA,EACT;AAEA,UAAQ;AAAA,IACN,GAAG,OAAO;AAAA,EAAK,cAAc,6CAA6C;AAAA,EAC5E;AAGA,MAAI,mBAAmB,UAAU,GAAG;AAClC,QAAI;AACF,cAAQ,IAAI,GAAG,IAAI,8BAA8B,cAAc,KAAK,CAAC;AACrE,eAAS,mBAAmB,cAAc,IAAI,EAAE,OAAO,UAAU,CAAC;AAClE,UAAI,mBAAmB,cAAc,GAAG;AACtC,gBAAQ,IAAI,GAAG,MAAM,YAAO,cAAc;AAAA,CAA2B,CAAC;AACtE,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,MAAI,mBAAmB,SAAS,mBAAmB,KAAK,GAAG;AACzD,QAAI;AACF,cAAQ,IAAI,GAAG,IAAI,gBAAgB,cAAc,sBAAsB,CAAC;AACxE,eAAS,kBAAkB,cAAc,IAAI,EAAE,OAAO,UAAU,CAAC;AACjE,UAAI,mBAAmB,cAAc,GAAG;AACtC,gBAAQ,IAAI,GAAG,MAAM;AAAA,WAAS,cAAc;AAAA,CAAsB,CAAC;AACnE,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,UAAQ;AAAA,IACN,GAAG,IAAI;AAAA,6BAA2B,cAAc,iBAAiB;AAAA,EACnE;AACA,UAAQ;AAAA,IACN,GAAG,OAAO;AAAA,CAAiC;AAAA,EAC7C;AAEA,MAAI,mBAAmB,QAAQ;AAC7B,YAAQ,IAAI,GAAG,IAAI,yBAAyB,CAAC;AAC7C,YAAQ,IAAI,GAAG,IAAI,UAAU,CAAC;AAC9B,YAAQ,IAAI,GAAG,IAAI,0BAA0B,CAAC;AAC9C,YAAQ,IAAI,GAAG,IAAI,UAAU,CAAC;AAC9B,YAAQ,IAAI,GAAG,IAAI,sDAAsD,CAAC;AAAA,EAC5E,WAAW,mBAAmB,QAAQ;AACpC,YAAQ,IAAI,GAAG,IAAI,yBAAyB,CAAC;AAC7C,YAAQ,IAAI,GAAG,IAAI,UAAU,CAAC;AAC9B,YAAQ,IAAI,GAAG,IAAI,0BAA0B,CAAC;AAAA,EAChD;AACA,UAAQ,IAAI;AAEZ,SAAO;AACT;AAEA,SAAS,QAAQ,KAAa,MAAoB;AAChD,KAAG,UAAU,MAAM,EAAE,WAAW,KAAK,CAAC;AACtC,QAAM,UAAU,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAE3D,aAAW,SAAS,SAAS;AAC3B,UAAM,UAAU,KAAK,KAAK,KAAK,MAAM,IAAI;AACzC,UAAM,WAAW,KAAK,KAAK,MAAM,MAAM,IAAI;AAE3C,QAAI,MAAM,YAAY,GAAG;AACvB,cAAQ,SAAS,QAAQ;AAAA,IAC3B,OAAO;AACL,SAAG,aAAa,SAAS,QAAQ;AAAA,IACnC;AAAA,EACF;AACF;AAEA,SAAS,iBAAyB;AAGhC,QAAM,UAAU,KAAK,QAAQ,WAAW,MAAM,aAAa,SAAS;AACpE,QAAM,WAAW,KAAK,QAAQ,WAAW,MAAM,MAAM,aAAa,SAAS;AAE3E,MAAI,GAAG,WAAW,OAAO,EAAG,QAAO;AACnC,MAAI,GAAG,WAAW,QAAQ,EAAG,QAAO;AAEpC,QAAM,IAAI,MAAM,oBAAoB;AACtC;AAEA,SAAS,kBAAkB,aAAqB,aAA2B;AACzE,QAAM,UAAU,KAAK,KAAK,aAAa,cAAc;AACrD,QAAM,MAAM,KAAK,MAAM,GAAG,aAAa,SAAS,OAAO,CAAC;AACxD,MAAI,OAAO;AACX,KAAG,cAAc,SAAS,KAAK,UAAU,KAAK,MAAM,CAAC,IAAI,IAAI;AAC/D;AAEA,SAAS,sBAAsB,aAAqB,aAA2B;AAE7E,QAAM,aAAa,KAAK,KAAK,aAAa,QAAQ,OAAO,cAAc;AACvE,MAAI,GAAG,WAAW,UAAU,GAAG;AAC7B,UAAM,MAAM,KAAK,MAAM,GAAG,aAAa,YAAY,OAAO,CAAC;AAC3D,QAAI,OAAO,IAAI,WAAW;AAE1B,QAAI,IAAI,eAAe,aAAa,GAAG;AACrC,UAAI,aAAa,IAAI,WAAW,SAAS,IAAI,IAAI,aAAa,aAAa;AAC3E,aAAO,IAAI,aAAa,aAAa;AAAA,IACvC;AACA,OAAG,cAAc,YAAY,KAAK,UAAU,KAAK,MAAM,CAAC,IAAI,IAAI;AAAA,EAClE;AAGA,QAAM,aAAa,KAAK,KAAK,aAAa,QAAQ,OAAO,cAAc;AACvE,MAAI,GAAG,WAAW,UAAU,GAAG;AAC7B,UAAM,MAAM,KAAK,MAAM,GAAG,aAAa,YAAY,OAAO,CAAC;AAC3D,QAAI,OAAO,IAAI,WAAW;AAE1B,QAAI,IAAI,eAAe,aAAa,GAAG;AACrC,UAAI,aAAa,IAAI,WAAW,SAAS,IAAI,IAAI,aAAa,aAAa;AAC3E,aAAO,IAAI,aAAa,aAAa;AAAA,IACvC;AACA,OAAG,cAAc,YAAY,KAAK,UAAU,KAAK,MAAM,CAAC,IAAI,IAAI;AAAA,EAClE;AAGA,QAAM,gBAAgB,KAAK,KAAK,aAAa,YAAY,UAAU,cAAc;AACjF,MAAI,GAAG,WAAW,aAAa,GAAG;AAChC,UAAM,MAAM,KAAK,MAAM,GAAG,aAAa,eAAe,OAAO,CAAC;AAC9D,QAAI,OAAO,IAAI,WAAW;AAC1B,OAAG,cAAc,eAAe,KAAK,UAAU,KAAK,MAAM,CAAC,IAAI,IAAI;AAAA,EACrE;AAGA,QAAM,WAAW,KAAK,KAAK,aAAa,QAAQ,OAAO,OAAO,OAAO,UAAU;AAC/E,MAAI,GAAG,WAAW,QAAQ,GAAG;AAC3B,QAAI,UAAU,GAAG,aAAa,UAAU,OAAO;AAC/C,cAAU,QAAQ,QAAQ,iBAAiB,IAAI,WAAW,SAAS;AACnE,OAAG,cAAc,UAAU,OAAO;AAAA,EACpC;AAGA,QAAM,iBAAiB,KAAK,KAAK,aAAa,WAAW,OAAO;AAChE,MAAI,GAAG,WAAW,cAAc,GAAG;AACjC,UAAM,YAAY,GAAG,YAAY,cAAc;AAC/C,eAAW,QAAQ,WAAW;AAC5B,YAAM,WAAW,KAAK,KAAK,gBAAgB,IAAI;AAC/C,UAAI,UAAU,GAAG,aAAa,UAAU,OAAO;AAC/C,gBAAU,QAAQ,QAAQ,iBAAiB,IAAI,WAAW,SAAS;AACnE,SAAG,cAAc,UAAU,OAAO;AAAA,IACpC;AAAA,EACF;AAGA,QAAM,iBAAiB;AAAA,IACrB,KAAK,KAAK,aAAa,eAAe;AAAA,IACtC,KAAK,KAAK,aAAa,WAAW;AAAA,IAClC,KAAK,KAAK,aAAa,WAAW;AAAA,IAClC,KAAK,KAAK,aAAa,WAAW,yBAAyB;AAAA,IAC3D,KAAK,KAAK,aAAa,QAAQ,OAAO,WAAW;AAAA,IACjD,KAAK,KAAK,aAAa,QAAQ,OAAO,WAAW;AAAA,IACjD,KAAK,KAAK,aAAa,QAAQ,OAAO,WAAW;AAAA,IACjD,KAAK,KAAK,aAAa,QAAQ,OAAO,WAAW;AAAA,EACnD;AACA,aAAW,YAAY,gBAAgB;AACrC,QAAI,GAAG,WAAW,QAAQ,GAAG;AAC3B,UAAI,UAAU,GAAG,aAAa,UAAU,OAAO;AAC/C,gBAAU,QAAQ,QAAQ,iBAAiB,IAAI,WAAW,SAAS;AACnE,SAAG,cAAc,UAAU,OAAO;AAAA,IACpC;AAAA,EACF;AAGA,QAAM,cAAc,KAAK,KAAK,aAAa,cAAc;AACzD,MAAI,GAAG,WAAW,WAAW,GAAG;AAC9B,QAAI,UAAU,GAAG,aAAa,aAAa,OAAO;AAClD,cAAU,QAAQ,QAAQ,cAAc,IAAI,WAAW,MAAM;AAC7D,cAAU,QAAQ,QAAQ,cAAc,IAAI,WAAW,MAAM;AAC7D,OAAG,cAAc,aAAa,OAAO;AAAA,EACvC;AACF;AAEA,SAAS,gBAAgB,aAA2B;AAClD,QAAM,gBAAgB,KAAK,KAAK,aAAa,YAAY;AACzD,QAAM,aAAa,KAAK,KAAK,aAAa,YAAY;AACtD,MAAI,GAAG,WAAW,aAAa,GAAG;AAChC,OAAG,WAAW,eAAe,UAAU;AAAA,EACzC;AACF;AAEA,eAAe,iBAAiB,aAA+C;AAC7E,QAAM,qBAAqB,eAAe;AAE1C,QAAM,WAAW,MAAM;AAAA,IACrB;AAAA,MACE;AAAA,QACE,MAAM,cAAc,OAAO;AAAA,QAC3B,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,QACT,UAAU,CAAC,UAAkB;AAC3B,cAAI,CAAC,MAAO,QAAO;AACnB,cAAI,CAAC,oBAAoB,KAAK,GAAG;AAC/B,mBAAO;AAAA,UACT;AACA,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,UACP;AAAA,YACE,OAAO,mBAAmB,MAAM,IAC5B,uBACA;AAAA,YACJ,OAAO;AAAA,UACT;AAAA,UACA;AAAA,YACE,OAAO,mBAAmB,KAAK,IAC3B,QACA;AAAA,YACJ,OAAO;AAAA,UACT;AAAA,UACA;AAAA,YACE,OAAO,mBAAmB,MAAM,IAC5B,SACA;AAAA,YACJ,OAAO;AAAA,UACT;AAAA,QACF;AAAA,QACA,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA;AAAA,MACE,UAAU,MAAM;AACd,gBAAQ,IAAI,GAAG,IAAI,wBAAwB,CAAC;AAC5C,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,aAAa,eAAe,SAAS;AAAA,IACrC,gBAAgB,SAAS;AAAA,EAC3B;AACF;AAEA,eAAe,cAAc,SAAwC;AACnE,QAAM,EAAE,aAAa,eAAe,IAAI;AACxC,QAAM,cAAc,KAAK,QAAQ,QAAQ,IAAI,GAAG,WAAW;AAG3D,MAAI,GAAG,WAAW,WAAW,GAAG;AAC9B,UAAM,EAAE,UAAU,IAAI,MAAM,QAAQ;AAAA,MAClC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,cAAc,WAAW;AAAA,MAClC,SAAS;AAAA,IACX,CAAC;AAED,QAAI,CAAC,WAAW;AACd,cAAQ,IAAI,GAAG,IAAI,sBAAsB,CAAC;AAC1C,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,OAAG,OAAO,aAAa,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EACzD;AAEA,UAAQ,IAAI;AACZ,UAAQ;AAAA,IACN,GAAG,KAAK,sCAAsC,GAAG,KAAK,WAAW,CAAC,EAAE;AAAA,EACtE;AACA,UAAQ,IAAI;AAGZ,QAAM,cAAc,eAAe;AACnC,UAAQ,aAAa,WAAW;AAGhC,kBAAgB,WAAW;AAG3B,oBAAkB,aAAa,WAAW;AAG1C,wBAAsB,aAAa,WAAW;AAG9C,QAAM,UAAU,qBAAqB,cAAc;AAEnD,MAAI,CAAC,SAAS;AACZ,YAAQ;AAAA,MACN,GAAG;AAAA,QACD,sDAAsD,cAAc;AAAA,MACtE;AAAA,IACF;AACA,YAAQ,IAAI,GAAG,IAAI,QAAQ,WAAW,EAAE,CAAC;AACzC,YAAQ,IAAI,GAAG,IAAI,KAAK,mBAAmB,QAAQ,gBAAgB,mBAAmB,SAAS,SAAS,cAAc,EAAE,CAAC;AACzH,YAAQ,IAAI,GAAG,IAAI,2BAA2B,mBAAmB,QAAQ,kBAAkB,GAAG,cAAc,QAAQ,EAAE,CAAC;AACvH,YAAQ,IAAI;AAAA,EACd,OAAO;AAEL,YAAQ,IAAI,GAAG,KAAK,4BAA4B,CAAC;AACjD,YAAQ,IAAI;AAEZ,UAAM,aAAa;AAAA,MACjB,KAAK;AAAA,MACL,MAAM;AAAA,MACN,MAAM;AAAA,IACR,EAAE,cAAc;AAEhB,QAAI;AACF,eAAS,YAAY;AAAA,QACnB,KAAK;AAAA,QACL,OAAO;AAAA,MACT,CAAC;AAAA,IACH,QAAQ;AACN,cAAQ;AAAA,QACN,GAAG;AAAA,UACD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,YAAQ,IAAI;AACZ,YAAQ,IAAI,GAAG,KAAK,4BAA4B,CAAC;AAEjD,QAAI;AACF,YAAM,WAAW,mBAAmB,QAAQ,kBAAkB,GAAG,cAAc;AAC/E,eAAS,UAAU;AAAA,QACjB,KAAK,KAAK,KAAK,aAAa,YAAY,QAAQ;AAAA,QAChD,OAAO;AAAA,MACT,CAAC;AAAA,IACH,QAAQ;AACN,cAAQ;AAAA,QACN,GAAG;AAAA,UACD;AAAA,uCAA0C,mBAAmB,QAAQ,kBAAkB,GAAG,cAAc,QAAQ;AAAA,QAClH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,UAAQ,IAAI;AACZ,UAAQ;AAAA,IACN,GAAG,MAAM,UAAU,IAAI,YAAY,GAAG,KAAK,WAAW,CAAC,OAAO,WAAW;AAAA,EAC3E;AACA,UAAQ,IAAI;AACZ,UAAQ,IAAI,oBAAoB;AAChC,UAAQ,IAAI;AACZ,UAAQ,IAAI,KAAK,GAAG,KAAK,UAAU,CAAC,sCAAsC;AAC1E,UAAQ,IAAI,KAAK,GAAG,KAAK,UAAU,CAAC,oCAAoC;AACxE,UAAQ,IAAI,KAAK,GAAG,KAAK,iBAAiB,CAAC,+BAA+B;AAC1E,UAAQ,IAAI,KAAK,GAAG,KAAK,OAAO,CAAC,kCAAkC;AACnE,UAAQ,IAAI,KAAK,GAAG,KAAK,eAAe,CAAC,mDAAmD;AAC5F,UAAQ,IAAI,KAAK,GAAG,KAAK,gBAAgB,CAAC,0BAA0B;AACpE,UAAQ,IAAI,KAAK,GAAG,KAAK,UAAU,CAAC,sCAAsC;AAC1E,UAAQ,IAAI,KAAK,GAAG,KAAK,WAAW,CAAC,iCAAiC;AACtE,UAAQ,IAAI,KAAK,GAAG,KAAK,WAAW,CAAC,kCAAkC;AACvE,UAAQ,IAAI;AACZ,UAAQ,IAAI,aAAa;AACzB,UAAQ,IAAI;AACZ,UAAQ,IAAI,KAAK,GAAG,KAAK,IAAI,CAAC,IAAI,WAAW,EAAE;AAC/C,UAAQ;AAAA,IACN,KAAK,GAAG,KAAK,mBAAmB,QAAQ,YAAY,cAAc,CAAC;AAAA,EACrE;AACA,UAAQ,IAAI;AACZ,UAAQ,IAAI,wEAAwE;AACpF,UAAQ,IAAI;AACZ,UAAQ,IAAI,eAAe;AAC3B,UAAQ,IAAI;AACd;AAEA,eAAsB,OAAsB;AAC1C,UACG,KAAK,aAAa,EAClB,YAAY,uDAAuD,EACnE,QAAQ,OAAO,EACf,SAAS,kBAAkB,qBAAqB,EAChD,OAAO,OAAO,gBAAoC;AACjD,YAAQ,IAAI;AACZ,YAAQ;AAAA,MACN,GAAG,KAAK,GAAG,KAAK,YAAY,IAAI,sCAAsC;AAAA,IACxE;AACA,YAAQ,IAAI,GAAG,IAAI,yDAAyD,CAAC;AAC7E,YAAQ,IAAI;AAEZ,UAAM,UAAU,MAAM,iBAAiB,WAAW;AAClD,UAAM,cAAc,OAAO;AAAA,EAC7B,CAAC;AAEH,QAAM,QAAQ,WAAW,QAAQ,IAAI;AACvC;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { program } from \"commander\";\nimport prompts from \"prompts\";\nimport pc from \"picocolors\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { execSync } from \"node:child_process\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\ninterface ProjectOptions {\n projectName: string;\n packageManager: \"npm\" | \"yarn\" | \"pnpm\";\n}\n\nfunction validateProjectName(name: string): boolean {\n const validNameRegex =\n /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/;\n return validNameRegex.test(name);\n}\n\nfunction detectPackageManager(): \"npm\" | \"yarn\" | \"pnpm\" {\n const userAgent = process.env.npm_config_user_agent;\n if (userAgent) {\n if (userAgent.startsWith(\"yarn\")) return \"yarn\";\n if (userAgent.startsWith(\"pnpm\")) return \"pnpm\";\n }\n return \"pnpm\"; // Default to pnpm for monorepo\n}\n\nfunction isCommandAvailable(command: string): boolean {\n try {\n execSync(`${command} --version`, { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction ensurePackageManager(packageManager: \"npm\" | \"yarn\" | \"pnpm\"): boolean {\n if (isCommandAvailable(packageManager)) {\n return true;\n }\n\n console.log(\n pc.yellow(`\\n${packageManager} is not installed. Attempting to install...`)\n );\n\n // Try corepack first (built-in to Node.js 16.9+)\n if (isCommandAvailable(\"corepack\")) {\n try {\n console.log(pc.dim(` Using corepack to enable ${packageManager}...`));\n execSync(`corepack enable ${packageManager}`, { stdio: \"inherit\" });\n if (isCommandAvailable(packageManager)) {\n console.log(pc.green(` ✓ ${packageManager} installed via corepack\\n`));\n return true;\n }\n } catch {\n // corepack failed, try next method\n }\n }\n\n // Fallback: install via npm\n if (packageManager !== \"npm\" && isCommandAvailable(\"npm\")) {\n try {\n console.log(pc.dim(` Installing ${packageManager} globally via npm...`));\n execSync(`npm install -g ${packageManager}`, { stdio: \"inherit\" });\n if (isCommandAvailable(packageManager)) {\n console.log(pc.green(`\\n ✓ ${packageManager} installed via npm\\n`));\n return true;\n }\n } catch {\n // npm global install failed (possibly permission issue)\n }\n }\n\n // All methods failed\n console.log(\n pc.red(`\\n ✗ Failed to install ${packageManager} automatically.`)\n );\n console.log(\n pc.yellow(` Please install it manually:\\n`)\n );\n\n if (packageManager === \"pnpm\") {\n console.log(pc.dim(\" npm install -g pnpm\"));\n console.log(pc.dim(\" # or\"));\n console.log(pc.dim(\" corepack enable pnpm\"));\n console.log(pc.dim(\" # or\"));\n console.log(pc.dim(\" curl -fsSL https://get.pnpm.io/install.sh | sh -\"));\n } else if (packageManager === \"yarn\") {\n console.log(pc.dim(\" npm install -g yarn\"));\n console.log(pc.dim(\" # or\"));\n console.log(pc.dim(\" corepack enable yarn\"));\n }\n console.log();\n\n return false;\n}\n\nfunction copyDir(src: string, dest: string): void {\n fs.mkdirSync(dest, { recursive: true });\n const entries = fs.readdirSync(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n\n if (entry.isDirectory()) {\n copyDir(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\nfunction getTemplateDir(): string {\n // In development, templates are relative to src\n // In production (dist), templates are at the package root\n const devPath = path.resolve(__dirname, \"..\", \"templates\", \"default\");\n const prodPath = path.resolve(__dirname, \"..\", \"..\", \"templates\", \"default\");\n\n if (fs.existsSync(devPath)) return devPath;\n if (fs.existsSync(prodPath)) return prodPath;\n\n throw new Error(\"Template not found\");\n}\n\nfunction updatePackageJson(projectPath: string, projectName: string): void {\n const pkgPath = path.join(projectPath, \"package.json\");\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n pkg.name = projectName;\n fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + \"\\n\");\n}\n\nfunction updateSubPackageNames(projectPath: string, projectName: string): void {\n // Update apps/web package.json\n const webPkgPath = path.join(projectPath, \"apps\", \"web\", \"package.json\");\n if (fs.existsSync(webPkgPath)) {\n const pkg = JSON.parse(fs.readFileSync(webPkgPath, \"utf-8\"));\n pkg.name = `@${projectName}/web`;\n // Update shared package reference\n if (pkg.dependencies?.[\"@app/shared\"]) {\n pkg.dependencies[`@${projectName}/shared`] = pkg.dependencies[\"@app/shared\"];\n delete pkg.dependencies[\"@app/shared\"];\n }\n fs.writeFileSync(webPkgPath, JSON.stringify(pkg, null, 2) + \"\\n\");\n }\n\n // Update apps/api package.json\n const apiPkgPath = path.join(projectPath, \"apps\", \"api\", \"package.json\");\n if (fs.existsSync(apiPkgPath)) {\n const pkg = JSON.parse(fs.readFileSync(apiPkgPath, \"utf-8\"));\n pkg.name = `@${projectName}/api`;\n // Update shared package reference\n if (pkg.dependencies?.[\"@app/shared\"]) {\n pkg.dependencies[`@${projectName}/shared`] = pkg.dependencies[\"@app/shared\"];\n delete pkg.dependencies[\"@app/shared\"];\n }\n fs.writeFileSync(apiPkgPath, JSON.stringify(pkg, null, 2) + \"\\n\");\n }\n\n // Update packages/shared package.json\n const sharedPkgPath = path.join(projectPath, \"packages\", \"shared\", \"package.json\");\n if (fs.existsSync(sharedPkgPath)) {\n const pkg = JSON.parse(fs.readFileSync(sharedPkgPath, \"utf-8\"));\n pkg.name = `@${projectName}/shared`;\n fs.writeFileSync(sharedPkgPath, JSON.stringify(pkg, null, 2) + \"\\n\");\n }\n\n // Update import statements in apps/web/src/app/page.tsx\n const pagePath = path.join(projectPath, \"apps\", \"web\", \"src\", \"app\", \"page.tsx\");\n if (fs.existsSync(pagePath)) {\n let content = fs.readFileSync(pagePath, \"utf-8\");\n content = content.replace(/@app\\/shared/g, `@${projectName}/shared`);\n fs.writeFileSync(pagePath, content);\n }\n\n // Update cursor rules to use correct package names\n const cursorRulesDir = path.join(projectPath, \".cursor\", \"rules\");\n if (fs.existsSync(cursorRulesDir)) {\n const ruleFiles = fs.readdirSync(cursorRulesDir);\n for (const file of ruleFiles) {\n const filePath = path.join(cursorRulesDir, file);\n let content = fs.readFileSync(filePath, \"utf-8\");\n content = content.replace(/@app\\/shared/g, `@${projectName}/shared`);\n fs.writeFileSync(filePath, content);\n }\n }\n\n // Update agent rule files to use correct package names\n const agentRuleFiles = [\n path.join(projectPath, \"AI_CONTEXT.md\"),\n path.join(projectPath, \"CLAUDE.md\"),\n path.join(projectPath, \"AGENTS.md\"),\n path.join(projectPath, \".github\", \"copilot-instructions.md\"),\n path.join(projectPath, \"apps\", \"web\", \"CLAUDE.md\"),\n path.join(projectPath, \"apps\", \"web\", \"AGENTS.md\"),\n path.join(projectPath, \"apps\", \"api\", \"CLAUDE.md\"),\n path.join(projectPath, \"apps\", \"api\", \"AGENTS.md\"),\n ];\n for (const filePath of agentRuleFiles) {\n if (fs.existsSync(filePath)) {\n let content = fs.readFileSync(filePath, \"utf-8\");\n content = content.replace(/@app\\/shared/g, `@${projectName}/shared`);\n fs.writeFileSync(filePath, content);\n }\n }\n\n // Update turbo.json filter names\n const rootPkgPath = path.join(projectPath, \"package.json\");\n if (fs.existsSync(rootPkgPath)) {\n let content = fs.readFileSync(rootPkgPath, \"utf-8\");\n content = content.replace(/@app\\/web/g, `@${projectName}/web`);\n content = content.replace(/@app\\/api/g, `@${projectName}/api`);\n fs.writeFileSync(rootPkgPath, content);\n }\n}\n\nfunction renameGitignore(projectPath: string): void {\n const gitignorePath = path.join(projectPath, \"_gitignore\");\n const targetPath = path.join(projectPath, \".gitignore\");\n if (fs.existsSync(gitignorePath)) {\n fs.renameSync(gitignorePath, targetPath);\n }\n}\n\nfunction renameDotEnvFiles(projectPath: string): void {\n // Rename _env files to .env (npm publish strips .env files)\n const envFiles = [\n path.join(projectPath, \"apps\", \"api\", \"_env\"),\n ];\n\n for (const envPath of envFiles) {\n const targetPath = envPath.replace(\"_env\", \".env\");\n if (fs.existsSync(envPath)) {\n fs.renameSync(envPath, targetPath);\n }\n }\n}\n\nasync function promptForOptions(projectName?: string): Promise<ProjectOptions> {\n const defaultProjectName = projectName || \"my-nene-app\";\n\n const response = await prompts(\n [\n {\n type: projectName ? null : \"text\",\n name: \"projectName\",\n message: \"Project name:\",\n initial: defaultProjectName,\n validate: (value: string) => {\n if (!value) return \"Project name is required\";\n if (!validateProjectName(value)) {\n return \"Invalid project name. Use lowercase letters, numbers, and hyphens only.\";\n }\n return true;\n },\n },\n {\n type: \"select\",\n name: \"packageManager\",\n message: \"Select a package manager:\",\n choices: [\n {\n title: isCommandAvailable(\"pnpm\")\n ? \"pnpm (recommended)\"\n : \"pnpm (recommended, will be installed)\",\n value: \"pnpm\",\n },\n {\n title: isCommandAvailable(\"npm\")\n ? \"npm\"\n : \"npm (not found)\",\n value: \"npm\",\n },\n {\n title: isCommandAvailable(\"yarn\")\n ? \"yarn\"\n : \"yarn (will be installed)\",\n value: \"yarn\",\n },\n ],\n initial: 0,\n },\n ],\n {\n onCancel: () => {\n console.log(pc.red(\"\\nOperation cancelled.\"));\n process.exit(0);\n },\n }\n );\n\n return {\n projectName: projectName || response.projectName,\n packageManager: response.packageManager,\n };\n}\n\nasync function createProject(options: ProjectOptions): Promise<void> {\n const { projectName, packageManager } = options;\n const projectPath = path.resolve(process.cwd(), projectName);\n\n // Check if directory exists\n if (fs.existsSync(projectPath)) {\n const { overwrite } = await prompts({\n type: \"confirm\",\n name: \"overwrite\",\n message: `Directory \"${projectName}\" already exists. Overwrite?`,\n initial: false,\n });\n\n if (!overwrite) {\n console.log(pc.red(\"Operation cancelled.\"));\n process.exit(0);\n }\n\n fs.rmSync(projectPath, { recursive: true, force: true });\n }\n\n console.log();\n console.log(\n pc.cyan(`Creating a new nene.js monorepo in ${pc.bold(projectPath)}`)\n );\n console.log();\n\n // Copy template\n const templateDir = getTemplateDir();\n copyDir(templateDir, projectPath);\n\n // Rename _gitignore to .gitignore\n renameGitignore(projectPath);\n\n // Rename _env files to .env\n renameDotEnvFiles(projectPath);\n\n // Update package.json with project name\n updatePackageJson(projectPath, projectName);\n\n // Update sub-package names\n updateSubPackageNames(projectPath, projectName);\n\n // Ensure package manager is available\n const pmReady = ensurePackageManager(packageManager);\n\n if (!pmReady) {\n console.log(\n pc.yellow(\n `Skipping dependency installation. After installing ${packageManager}, run:`\n )\n );\n console.log(pc.dim(` cd ${projectName}`));\n console.log(pc.dim(` ${packageManager === \"npm\" ? \"npm install\" : packageManager === \"yarn\" ? \"yarn\" : \"pnpm install\"}`));\n console.log(pc.dim(` cd packages/shared && ${packageManager === \"npm\" ? \"npm run build\" : `${packageManager} build`}`));\n console.log(pc.dim(` cd ../../apps/api && npx prisma generate && npx prisma migrate dev --name init`));\n console.log();\n } else {\n // Install dependencies\n console.log(pc.cyan(\"Installing dependencies...\"));\n console.log();\n\n const installCmd = {\n npm: \"npm install\",\n yarn: \"yarn\",\n pnpm: \"pnpm install\",\n }[packageManager];\n\n try {\n execSync(installCmd, {\n cwd: projectPath,\n stdio: \"inherit\",\n });\n } catch {\n console.log(\n pc.yellow(\n \"\\nFailed to install dependencies. You can install them manually.\"\n )\n );\n }\n\n // Build shared package first\n console.log();\n console.log(pc.cyan(\"Building shared package...\"));\n\n try {\n const buildCmd = packageManager === \"npm\" ? \"npm run build\" : `${packageManager} build`;\n execSync(buildCmd, {\n cwd: path.join(projectPath, \"packages\", \"shared\"),\n stdio: \"inherit\",\n });\n } catch {\n console.log(\n pc.yellow(\n `\\nFailed to build shared package. Run '${packageManager === \"npm\" ? \"npm run build\" : `${packageManager} build`}' in packages/shared manually.`\n )\n );\n }\n\n // Setup database (Prisma generate + migrate)\n console.log();\n console.log(pc.cyan(\"Setting up database...\"));\n\n const apiPath = path.join(projectPath, \"apps\", \"api\");\n try {\n execSync(\"npx prisma generate\", {\n cwd: apiPath,\n stdio: \"inherit\",\n });\n execSync(\"npx prisma migrate dev --name init --skip-seed\", {\n cwd: apiPath,\n stdio: \"inherit\",\n });\n console.log(pc.green(\" ✓ Database ready (SQLite)\"));\n } catch {\n console.log(\n pc.yellow(\n \"\\nFailed to setup database. Run the following manually:\"\n )\n );\n console.log(pc.dim(` cd apps/api`));\n console.log(pc.dim(` npx prisma generate`));\n console.log(pc.dim(` npx prisma migrate dev --name init`));\n }\n }\n\n // Success message\n console.log();\n console.log(\n pc.green(\"Success!\") + ` Created ${pc.bold(projectName)} at ${projectPath}`\n );\n console.log();\n console.log(\"Project structure:\");\n console.log();\n console.log(` ${pc.cyan(\"apps/web\")} - Next.js frontend (port 3000)`);\n console.log(` ${pc.cyan(\"apps/api\")} - NestJS backend (port 4000)`);\n console.log(` ${pc.cyan(\"packages/shared\")} - Shared types and constants`);\n console.log(` ${pc.cyan(\"docs/\")} - Project documentation`);\n console.log(` ${pc.cyan(\"AI_CONTEXT.md\")} - Universal AI context (single source of truth)`);\n console.log(` ${pc.cyan(\".cursor/rules/\")} - Cursor AI agent rules`);\n console.log(` ${pc.cyan(\".github/\")} - GitHub Copilot instructions`);\n console.log(` ${pc.cyan(\"CLAUDE.md\")} - Claude Code agent rules`);\n console.log(` ${pc.cyan(\"AGENTS.md\")} - OpenAI Codex agent rules`);\n console.log();\n console.log(\"Next steps:\");\n console.log();\n console.log(` ${pc.cyan(\"cd\")} ${projectName}`);\n console.log(\n ` ${pc.cyan(packageManager === \"npm\" ? \"npm run\" : packageManager)} dev`\n );\n console.log();\n console.log(\"This will start both the frontend (port 3000) and backend (port 4000).\");\n console.log();\n console.log(\"Happy coding!\");\n console.log();\n}\n\nexport async function main(): Promise<void> {\n program\n .name(\"create-nene\")\n .description(\"Create a new nene.js monorepo with Next.js and NestJS\")\n .version(\"0.2.0\")\n .argument(\"[project-name]\", \"Name of the project\")\n .action(async (projectName: string | undefined) => {\n console.log();\n console.log(\n pc.bold(pc.cyan(\" nene.js \") + \"- The AI-native full-stack framework\")\n );\n console.log(pc.dim(\" Next.js + NestJS monorepo for AI-assisted development\"));\n console.log();\n\n const options = await promptForOptions(projectName);\n await createProject(options);\n });\n\n await program.parseAsync(process.argv);\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"@nestjs/config": "^4.0.0",
|
|
18
18
|
"@nestjs/core": "^11.0.0",
|
|
19
19
|
"@nestjs/platform-express": "^11.0.0",
|
|
20
|
+
"@prisma/client": "^6.0.0",
|
|
20
21
|
"class-transformer": "^0.5.1",
|
|
21
22
|
"class-validator": "^0.14.1",
|
|
22
23
|
"reflect-metadata": "^0.2.2",
|
|
@@ -28,6 +29,7 @@
|
|
|
28
29
|
"@nestjs/testing": "^11.0.0",
|
|
29
30
|
"@types/express": "^5.0.0",
|
|
30
31
|
"@types/node": "^22.0.0",
|
|
32
|
+
"prisma": "^6.0.0",
|
|
31
33
|
"ts-loader": "^9.5.1",
|
|
32
34
|
"ts-node": "^10.9.2",
|
|
33
35
|
"tsconfig-paths": "^4.2.0",
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Prisma schema - SQLite for local development
|
|
2
|
+
// Docs: https://pris.ly/d/prisma-schema
|
|
3
|
+
|
|
4
|
+
generator client {
|
|
5
|
+
provider = "prisma-client-js"
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
datasource db {
|
|
9
|
+
provider = "sqlite"
|
|
10
|
+
url = env("DATABASE_URL")
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Example model - customize or remove as needed
|
|
14
|
+
model User {
|
|
15
|
+
id String @id @default(cuid())
|
|
16
|
+
email String @unique
|
|
17
|
+
name String?
|
|
18
|
+
createdAt DateTime @default(now())
|
|
19
|
+
updatedAt DateTime @updatedAt
|
|
20
|
+
|
|
21
|
+
@@map("users")
|
|
22
|
+
}
|
|
@@ -3,6 +3,7 @@ import { ConfigModule } from '@nestjs/config';
|
|
|
3
3
|
import { AppController } from './app.controller';
|
|
4
4
|
import { AppService } from './app.service';
|
|
5
5
|
import { HealthModule } from './health/health.module';
|
|
6
|
+
import { PrismaModule } from './prisma/prisma.module';
|
|
6
7
|
import configuration from './config/configuration';
|
|
7
8
|
|
|
8
9
|
@Module({
|
|
@@ -11,6 +12,7 @@ import configuration from './config/configuration';
|
|
|
11
12
|
isGlobal: true,
|
|
12
13
|
load: [configuration],
|
|
13
14
|
}),
|
|
15
|
+
PrismaModule,
|
|
14
16
|
HealthModule,
|
|
15
17
|
],
|
|
16
18
|
controllers: [AppController],
|
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { PrismaService } from '../prisma/prisma.service';
|
|
2
3
|
|
|
3
4
|
@Injectable()
|
|
4
5
|
export class HealthService {
|
|
5
|
-
|
|
6
|
+
constructor(private readonly prisma: PrismaService) {}
|
|
7
|
+
|
|
8
|
+
async check() {
|
|
9
|
+
let dbStatus: 'connected' | 'disconnected' = 'disconnected';
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
await this.prisma.$queryRaw`SELECT 1`;
|
|
13
|
+
dbStatus = 'connected';
|
|
14
|
+
} catch {
|
|
15
|
+
dbStatus = 'disconnected';
|
|
16
|
+
}
|
|
17
|
+
|
|
6
18
|
return {
|
|
7
19
|
status: 'ok',
|
|
8
20
|
timestamp: new Date().toISOString(),
|
|
9
21
|
uptime: process.uptime(),
|
|
22
|
+
database: dbStatus,
|
|
10
23
|
};
|
|
11
24
|
}
|
|
12
25
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
|
2
|
+
import { PrismaClient } from '@prisma/client';
|
|
3
|
+
|
|
4
|
+
@Injectable()
|
|
5
|
+
export class PrismaService
|
|
6
|
+
extends PrismaClient
|
|
7
|
+
implements OnModuleInit, OnModuleDestroy
|
|
8
|
+
{
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async onModuleInit() {
|
|
14
|
+
await this.$connect();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async onModuleDestroy() {
|
|
18
|
+
await this.$disconnect();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -7,6 +7,7 @@ interface HealthStatus {
|
|
|
7
7
|
status: string;
|
|
8
8
|
timestamp: string;
|
|
9
9
|
uptime: number;
|
|
10
|
+
database: 'connected' | 'disconnected';
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
type ServiceStatus = 'checking' | 'active' | 'inactive';
|
|
@@ -58,7 +59,7 @@ export default function Home() {
|
|
|
58
59
|
return () => clearInterval(interval);
|
|
59
60
|
}, []);
|
|
60
61
|
|
|
61
|
-
const allOperational = apiStatus === 'active';
|
|
62
|
+
const allOperational = apiStatus === 'active' && health?.database === 'connected';
|
|
62
63
|
|
|
63
64
|
return (
|
|
64
65
|
<div className="bg-background-dark text-slate-200 min-h-screen flex flex-col items-center">
|
|
@@ -183,6 +184,29 @@ export default function Home() {
|
|
|
183
184
|
<StatusBadge status={apiStatus} />
|
|
184
185
|
</td>
|
|
185
186
|
</tr>
|
|
187
|
+
{/* Database */}
|
|
188
|
+
<tr className="group hover:bg-white/[0.02] transition-colors">
|
|
189
|
+
<td className="px-6 py-5 text-sm font-medium text-white flex items-center gap-3">
|
|
190
|
+
<span className="text-primary">●</span>
|
|
191
|
+
Database (SQLite)
|
|
192
|
+
</td>
|
|
193
|
+
<td className="px-6 py-5 text-sm font-mono text-slate-500">
|
|
194
|
+
—
|
|
195
|
+
</td>
|
|
196
|
+
<td className="px-6 py-5 text-right">
|
|
197
|
+
{apiStatus === 'checking' ? (
|
|
198
|
+
<StatusBadge status="checking" />
|
|
199
|
+
) : health?.database === 'connected' ? (
|
|
200
|
+
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-white/10 text-white">
|
|
201
|
+
Connected
|
|
202
|
+
</span>
|
|
203
|
+
) : (
|
|
204
|
+
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-500/20 text-red-400 border border-red-500/30">
|
|
205
|
+
Disconnected
|
|
206
|
+
</span>
|
|
207
|
+
)}
|
|
208
|
+
</td>
|
|
209
|
+
</tr>
|
|
186
210
|
{/* Shared Package */}
|
|
187
211
|
<tr className="group hover:bg-white/[0.02] transition-colors">
|
|
188
212
|
<td className="px-6 py-5 text-sm font-medium text-white flex items-center gap-3">
|
|
@@ -14,11 +14,13 @@ Initial project scaffolding with nene.js CLI.
|
|
|
14
14
|
- [x] Next.js frontend (apps/web)
|
|
15
15
|
- [x] NestJS backend (apps/api)
|
|
16
16
|
- [x] Shared package (packages/shared)
|
|
17
|
-
- [x] Health check endpoint
|
|
17
|
+
- [x] Health check endpoint (with database status)
|
|
18
|
+
- [x] Database integration (Prisma + SQLite)
|
|
18
19
|
- [x] CORS configuration
|
|
19
20
|
- [x] Request validation with class-validator
|
|
20
21
|
- [x] Development scripts (pnpm dev)
|
|
22
|
+
- [x] AI agent rule files (Cursor, Claude, Copilot, Codex)
|
|
21
23
|
|
|
22
24
|
## Notes
|
|
23
25
|
|
|
24
|
-
Project created with `
|
|
26
|
+
Project created with `npx create-nene@latest`.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Database Integration
|
|
2
|
+
|
|
3
|
+
- **Status**: DONE
|
|
4
|
+
- **Priority**: High
|
|
5
|
+
- **Created**: 2025-01-01
|
|
6
|
+
|
|
7
|
+
## Description
|
|
8
|
+
|
|
9
|
+
Set up database integration for the NestJS backend using Prisma + SQLite.
|
|
10
|
+
|
|
11
|
+
## Checklist
|
|
12
|
+
|
|
13
|
+
- [x] Install and configure Prisma ORM
|
|
14
|
+
- [x] Set up SQLite database connection in `apps/api`
|
|
15
|
+
- [x] Add DATABASE_URL to environment variables
|
|
16
|
+
- [x] Create initial migration
|
|
17
|
+
- [x] Add database health check to `/api/health`
|
|
18
|
+
- [x] Display database status in Live Status Panel
|
|
19
|
+
|
|
20
|
+
## Notes
|
|
21
|
+
|
|
22
|
+
- Completed automatically by `create-nene` scaffolding.
|
|
23
|
+
- SQLite is used by default for zero-config local development.
|
|
24
|
+
- To switch to PostgreSQL or another database, update `prisma/schema.prisma` and `.env`.
|
|
@@ -8,9 +8,9 @@ Task management board for this project.
|
|
|
8
8
|
|
|
9
9
|
| Status | Count |
|
|
10
10
|
| ------ | ----- |
|
|
11
|
-
| TODO |
|
|
11
|
+
| TODO | 6 |
|
|
12
12
|
| DOING | 0 |
|
|
13
|
-
| DONE |
|
|
13
|
+
| DONE | 2 |
|
|
14
14
|
|
|
15
15
|
## How It Works
|
|
16
16
|
|
|
@@ -57,4 +57,9 @@ Any relevant context or references.
|
|
|
57
57
|
|
|
58
58
|
## Priority Order
|
|
59
59
|
|
|
60
|
-
1. `TODO/01-
|
|
60
|
+
1. `TODO/01-define-project.md` - Define what this project is about
|
|
61
|
+
2. `TODO/02-define-tech-stack.md` - Finalize tech stack & configuration
|
|
62
|
+
3. `TODO/03-define-data-models.md` - Design database schema & types
|
|
63
|
+
4. `TODO/04-build-first-feature.md` - Build first full-stack feature
|
|
64
|
+
5. `TODO/05-setup-auth.md` - Add authentication
|
|
65
|
+
6. `TODO/06-customize-frontend.md` - Customize UI & branding
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Define Project Overview
|
|
2
|
+
|
|
3
|
+
- **Status**: TODO
|
|
4
|
+
- **Priority**: High
|
|
5
|
+
- **Created**: 2025-01-01
|
|
6
|
+
|
|
7
|
+
## Description
|
|
8
|
+
|
|
9
|
+
Define what this project is about. Update the overview documentation and AI context files so that both developers and AI agents understand the project's purpose.
|
|
10
|
+
|
|
11
|
+
## Checklist
|
|
12
|
+
|
|
13
|
+
- [ ] Write a project description in `AI_CONTEXT.md` (what the app does, who it's for)
|
|
14
|
+
- [ ] Update `docs/overview/ARCHITECTURE.md` with your project-specific architecture
|
|
15
|
+
- [ ] Update `README.md` with project description and getting started guide
|
|
16
|
+
- [ ] Define the core domain models in `packages/shared/src/types/index.ts`
|
|
17
|
+
|
|
18
|
+
## Notes
|
|
19
|
+
|
|
20
|
+
- `AI_CONTEXT.md` is the single source of truth for all AI agents (Cursor, Claude, Copilot, Codex).
|
|
21
|
+
- Being specific helps AI agents generate more accurate code. Instead of "a social app", write "a recipe-sharing platform where users can post, rate, and comment on recipes".
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Define Tech Stack & Configuration
|
|
2
|
+
|
|
3
|
+
- **Status**: TODO
|
|
4
|
+
- **Priority**: High
|
|
5
|
+
- **Created**: 2025-01-01
|
|
6
|
+
|
|
7
|
+
## Description
|
|
8
|
+
|
|
9
|
+
Review and finalize the tech stack for your project. The scaffolding provides defaults, but you may want to customize them.
|
|
10
|
+
|
|
11
|
+
## Checklist
|
|
12
|
+
|
|
13
|
+
- [ ] Decide on authentication strategy (JWT, session-based, OAuth, etc.)
|
|
14
|
+
- [ ] Decide on database (keep SQLite for dev, or switch to PostgreSQL/MySQL for production)
|
|
15
|
+
- [ ] Choose a deployment target (Vercel, AWS, Docker, etc.)
|
|
16
|
+
- [ ] Configure environment variables for each environment (`.env`, `.env.production`)
|
|
17
|
+
- [ ] Add any additional libraries needed (e.g., file upload, email, payments)
|
|
18
|
+
|
|
19
|
+
## Notes
|
|
20
|
+
|
|
21
|
+
- SQLite works great for development and small projects. For production, consider PostgreSQL.
|
|
22
|
+
- To switch databases, update `apps/api/prisma/schema.prisma` provider and `DATABASE_URL` in `.env`.
|
|
23
|
+
- Stack decisions should be documented in `docs/overview/ARCHITECTURE.md`.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Define Data Models & Schema
|
|
2
|
+
|
|
3
|
+
- **Status**: TODO
|
|
4
|
+
- **Priority**: High
|
|
5
|
+
- **Created**: 2025-01-01
|
|
6
|
+
|
|
7
|
+
## Description
|
|
8
|
+
|
|
9
|
+
Design the database schema for your application. Define models in Prisma and matching TypeScript types in the shared package.
|
|
10
|
+
|
|
11
|
+
## Checklist
|
|
12
|
+
|
|
13
|
+
- [ ] Design your data models (entities, relationships)
|
|
14
|
+
- [ ] Update `apps/api/prisma/schema.prisma` with your models
|
|
15
|
+
- [ ] Run `npx prisma migrate dev --name <description>` to apply changes
|
|
16
|
+
- [ ] Add matching TypeScript interfaces to `packages/shared/src/types/index.ts`
|
|
17
|
+
- [ ] Add DTOs with validation to `packages/shared/src/dto/` (if needed)
|
|
18
|
+
- [ ] Rebuild shared package: `pnpm --filter @app/shared build`
|
|
19
|
+
|
|
20
|
+
## Notes
|
|
21
|
+
|
|
22
|
+
- Keep Prisma models and shared TypeScript types in sync.
|
|
23
|
+
- Use `cuid()` for IDs (default in the template).
|
|
24
|
+
- Example: If you add a `Post` model in Prisma, also add a `Post` interface in `packages/shared`.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Build First Feature
|
|
2
|
+
|
|
3
|
+
- **Status**: TODO
|
|
4
|
+
- **Priority**: Medium
|
|
5
|
+
- **Created**: 2025-01-01
|
|
6
|
+
|
|
7
|
+
## Description
|
|
8
|
+
|
|
9
|
+
Build the first API endpoint and connect it to the frontend. This validates the full-stack workflow: backend -> shared types -> frontend.
|
|
10
|
+
|
|
11
|
+
## Checklist
|
|
12
|
+
|
|
13
|
+
- [ ] Create a NestJS module (`nest g module <feature>` or manually)
|
|
14
|
+
- [ ] Create controller, service, and wire up to Prisma
|
|
15
|
+
- [ ] Add API route constant to `packages/shared/src/constants/index.ts`
|
|
16
|
+
- [ ] Update `docs/API.md` with the new endpoint
|
|
17
|
+
- [ ] Build a frontend page/component that calls the API
|
|
18
|
+
- [ ] Verify end-to-end: data flows from DB -> API -> Frontend
|
|
19
|
+
|
|
20
|
+
## Notes
|
|
21
|
+
|
|
22
|
+
- Follow the NestJS module pattern: `{feature}.module.ts`, `{feature}.controller.ts`, `{feature}.service.ts`.
|
|
23
|
+
- Import types from `@app/shared`, never duplicate them.
|
|
24
|
+
- Tip: Paste your task description into Cursor AI to scaffold the feature automatically.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Set Up Authentication
|
|
2
|
+
|
|
3
|
+
- **Status**: TODO
|
|
4
|
+
- **Priority**: Medium
|
|
5
|
+
- **Created**: 2025-01-01
|
|
6
|
+
|
|
7
|
+
## Description
|
|
8
|
+
|
|
9
|
+
Add user authentication to protect API endpoints and frontend routes.
|
|
10
|
+
|
|
11
|
+
## Checklist
|
|
12
|
+
|
|
13
|
+
- [ ] Choose auth strategy (JWT, session, NextAuth, etc.)
|
|
14
|
+
- [ ] Implement login/register endpoints in `apps/api`
|
|
15
|
+
- [ ] Add auth middleware/guards for protected routes
|
|
16
|
+
- [ ] Add auth state management in `apps/web`
|
|
17
|
+
- [ ] Create login/register pages in `apps/web`
|
|
18
|
+
- [ ] Add protected route handling (redirect to login if unauthenticated)
|
|
19
|
+
- [ ] Update `docs/API.md` with auth endpoints
|
|
20
|
+
|
|
21
|
+
## Notes
|
|
22
|
+
|
|
23
|
+
- The User model is already included in the Prisma schema.
|
|
24
|
+
- API route constants for auth are pre-defined in `packages/shared/src/constants/index.ts`.
|
|
25
|
+
- Consider using `@nestjs/passport` with JWT strategy for the backend.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Customize Frontend
|
|
2
|
+
|
|
3
|
+
- **Status**: TODO
|
|
4
|
+
- **Priority**: Low
|
|
5
|
+
- **Created**: 2025-01-01
|
|
6
|
+
|
|
7
|
+
## Description
|
|
8
|
+
|
|
9
|
+
Replace the default landing page with your own design. Customize the look and feel of the application.
|
|
10
|
+
|
|
11
|
+
## Checklist
|
|
12
|
+
|
|
13
|
+
- [ ] Replace the default `apps/web/src/app/page.tsx` with your own landing page
|
|
14
|
+
- [ ] Update `apps/web/src/app/globals.css` with your brand colors
|
|
15
|
+
- [ ] Update `apps/web/src/app/layout.tsx` with your app title and metadata
|
|
16
|
+
- [ ] Add a navigation component
|
|
17
|
+
- [ ] Create main application pages
|
|
18
|
+
|
|
19
|
+
## Notes
|
|
20
|
+
|
|
21
|
+
- The default page includes a Live Status Panel — you can remove it once everything is confirmed working.
|
|
22
|
+
- Tailwind CSS is pre-configured. Use `tailwind.config.ts` to customize your theme.
|
|
23
|
+
- Components are Server Components by default. Add `'use client'` for interactive components.
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Database Integration
|
|
2
|
-
|
|
3
|
-
- **Status**: TODO
|
|
4
|
-
- **Priority**: High
|
|
5
|
-
- **Created**: 2025-01-01
|
|
6
|
-
|
|
7
|
-
## Description
|
|
8
|
-
|
|
9
|
-
Set up database integration for the NestJS backend. Choose and configure an ORM (e.g., Prisma, TypeORM) and connect it to a database.
|
|
10
|
-
|
|
11
|
-
## Checklist
|
|
12
|
-
|
|
13
|
-
- [ ] Choose database (PostgreSQL recommended)
|
|
14
|
-
- [ ] Install and configure ORM
|
|
15
|
-
- [ ] Set up database connection in `apps/api`
|
|
16
|
-
- [ ] Add DATABASE_URL to environment variables
|
|
17
|
-
- [ ] Create initial migration
|
|
18
|
-
- [ ] Update `docs/overview/ARCHITECTURE.md` with database details
|
|
19
|
-
- [ ] Update `docs/API.md` if new endpoints are added
|
|
20
|
-
|
|
21
|
-
## Notes
|
|
22
|
-
|
|
23
|
-
- Consider using Prisma for type-safe database access
|
|
24
|
-
- The shared package can export Prisma-generated types for frontend use
|